目次
前
次
マイコン版ROMシーケンサ作成
最近のワンチップマイコンは、EEPROMを内蔵しています。
ROMシーケンサは、アドレスを入力情報としたデコーダと次の
状態出力をする回路と考え、マイコンでエミュレートします。
ROMの開始アドレスを与え、内容を取出し、解釈して動くように
マイコンのプログラムを書くと、ROMシーケンサに変身。
Personal ComputerのC言語で、動作をシミュレートすると
次のようになります。
#include <stdio.h>
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
UBYTE xx[16] ;
void init_array(void)
{
*(xx+ 0)= 0x18 ; *(xx+ 1)= 0x20 ;
*(xx+ 2)= 0x31 ; *(xx+ 3)= 0x41 ;
*(xx+ 4)= 0x52 ; *(xx+ 5)= 0x62 ;
*(xx+ 6)= 0x73 ; *(xx+ 7)= 0x83 ;
*(xx+ 8)= 0x94 ; *(xx+ 9)= 0xa4 ;
*(xx+10)= 0xb5 ; *(xx+11)= 0xc5 ;
*(xx+12)= 0xd6 ; *(xx+13)= 0xe6 ;
*(xx+14)= 0xf7 ; *(xx+15)= 0x07 ;
}
void binary_display(UBYTE x,UBYTE sb)
{
int i ;
for ( i = sb ; i > -1 ; i-- ) {
putchar('0'+((x >> i) & 1));
}
}
void main(void)
{
UBYTE i ;
UBYTE tmp ;
UBYTE adr ;
init_array();
for ( i = 0 ; i < 16 ; i++ ) {
/* get lower nibble */
tmp = *(xx+i) & 15 ;
/* get upper nibble */
adr = *(xx+i) & 0xf0 ;
adr >>= 4 ;
/* show signal */
binary_display( tmp , 3 ) ;
putchar(' ');
binary_display( tmp ^ 0x07 , 2 ) ;
printf(" next => %d \t %2x\n",adr,*(xx+adr) & 7 );
}
}
実行すると、次のようになります。
最左端の4ビットが、そのときのROMシーケンサから
出力する信号。下位3ビットを利用する信号。
その右が利用する信号を反転して表示。
矢印の右の10進数は、次のデータが入っているアドレス
とその内容を左から右に表示。
ROMシーケンサは、アドレスと信号を配列に入れていると
みなしていけばよいとわかります。
シリアルインタフェースで、配列の添字とアドレス、データを
渡せばROMシーケンサにデータを書き込むことと等価。
端末ソフトでコマンドを与えるときは、次のように入力。
配列に情報が格納されれば、マイコンではタイマー割込みを
利用して、配列から情報を引き出し、出力することを繰返し
して行くだけ。
マイコンでROMシーケンサを実現できるとわかると思います。
シリアルインタフェースのコマンドを用意します。
- ? help
- E set data to array
- e show array data
- G simulate ROM sequencer
- g stop simulate
- S store array context to EEPROM
- L load array context from EEPROM
コマンドインタプリタを用意したなら、実現方法を考えます。
信号を出力するのが基本なので、そこから設計していきます。
配列用のインデックスを変数idxに割当てて、信号を出力した
ならば変数idxにアドレス部の値を代入します。
配列をromxとすると、初期化とタイマー割込み処理の2種の
コードを用意すれば実現できます。
/* initialize */
idx = 0 ;
/* timer handling */
if ( TFLAG == ON ) {
/* clear */
TFLAG = OFF ;
/* get informations from ROM table */
tmp = *(romx+idx);
/* get address */
xadr = (tmp >> 4) & 15 ;
/* set signal */
PORTC = tmp & 15 ;
/* update index */
idx = xadr ;
}
コマンドインタプリタで、1文字コマンドごとに
処理を記述していきます。
/* command interpreter */
if ( UFLAG == ON ) {
/* clear */
UFLAG = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* E set data to array */
if ( cmd == 'E' ) {
/* get address */
xadr = get_hex( *(sbuf+1) ) ;
xadr <<= 4 ;
xadr |= get_hex( *(sbuf+2) ) ;
/* get data */
tmp = get_hex( *(sbuf+3) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+4) ) ;
/* store */
*(romx+xadr) = tmp ;
}
/* e show array context */
if ( cmd == 'e' ) {
*(msg+2) = ' ' ;
*(msg+3) = '\0' ;
for ( int i = 0 ; i < 256 ; i++ ) {
tmp = EEPROM.read( i ) ;
*(msg+0) = conv_hex( (tmp >> 4) & 15 ) ;
*(msg+1) = conv_hex( tmp & 15 ) ;
rs_puts( msg );
/* new line */
if ( (i % 8) == 7 ) { crlf(); }
}
}
/* G run simulate */
if ( cmd == 'G' ) {
idx = 0 ;
EFLAG = ON ;
}
/* g stop simulate */
if ( cmd == 'g' ) { EFLAG = OFF ; }
/* S store */
if ( cmd == 'S' ) {
for ( int i = 0 ; i < 256 ; i++ ) {
tmp = EEPROM.write( i , *(romx+i)) ;
}
}
/* L load */
if ( cmd == 'L' ) {
for ( int i = 0 ; i < 256 ; i++ ) {
*(romx+i) = EEPROM.read( i ) ;
}
}
}
タイマー割込みで信号を出力するには、フラグを2個
参照します。
/* timer handling */
if ( TFLAG == ON ) {
/* clear */
TFLAG = OFF ;
/* execute */
if ( EFLAG == ON ) {
/* get informations from ROM table */
tmp = *(romx+idx);
/* get address */
xadr = (tmp >> 4) & 15 ;
/* set signal */
PORTC = tmp & 15 ;
/* update index */
idx = xadr ;
}
}
Arduinoのスケッチとすると以下。
#include <EEPROM.h>
#include <MsTimer2.h>
#define OFF 0
#define ON 1
#define BSIZE 8
#define MASK0F 0x0f
#define MASKF0 0xf0
byte sbuf[BSIZE] ;
byte sindex ;
byte cmd ;
byte timcnt ;
byte romx[256] ;
char ch ;
byte idx ;
byte xadr ;
byte tmp ;
char msg[4];
boolean UFLAG ;
boolean EFLAG ;
boolean TFLAG ;
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *x)
{
while ( *x ) {
rs_putchar( *x ) ;
x++ ;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_help()
{
rs_puts("? help"); crlf();
rs_puts("E set data to array"); crlf();
rs_puts("e show array data"); crlf();
rs_puts("G simulate ROM sequencer"); crlf();
rs_puts("g stop simulate"); crlf();
rs_puts("S store array context to EEPROM"); crlf();
rs_puts("L load array context from EEPROM"); crlf();
}
byte get_hex(char x)
{
byte result ;
/* default */
result = 0 ;
/* judge */
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x + 10 - 'A' ; }
if ( 'a' <= x && x <= 'f' ) { result = x + 10 - 'a' ; }
return result ;
}
char conv_hex(byte x)
{
char result ;
/* default */
result = '0' ;
/* judge */
if ( x < 10 ) { result = x + '0' ; }
else { result = x - 10 + 'A' ; }
return result ;
}
void put_eeprom(byte xadr,byte xdat)
{
EEPROM.write(xadr,xdat);
}
byte get_eeprom(byte xadr)
{
return( EEPROM.read(xadr) );
}
void update_trigger()
{
/* impress LED */
if ( timcnt & 1 ) { PORTB |= 0x20 ; }
else { PORTB &= ~0x20 ; }
/* update */
timcnt++ ;
/* set flag */
TFLAG = ON ;
}
void setup()
{
/* set communication speed */
Serial.begin(9600);
sindex = 0 ;
/* port value */
PORTD = 0x01 ;
PORTC = 0x00 ;
PORTB = 0x00 ;
/* port direction */
DDRD = 0xfe ;
DDRC = 0xff ;
DDRB = 0xff ;
/* clera flags */
TFLAG = OFF ;
UFLAG = OFF ;
EFLAG = OFF ;
/* others */
timcnt = 0 ;
/* message */
rs_puts("Hello");
crlf();
/* 1000ms period */
MsTimer2::set(1000,update_trigger);
/* enable */
MsTimer2::start();
}
void loop()
{
byte i ;
byte ii ;
/* timer handler */
if ( TFLAG == ON ) {
/* clear */
TFLAG = OFF ;
/* execute */
if ( EFLAG == ON ) {
/* get informations from ROM table */
tmp = *(romx+idx);
/* get address */
xadr = (tmp >> 4) & MASK0F ;
/* set signal */
PORTC = tmp & MASK0F ;
/* update index */
idx = xadr ;
}
}
/* command interpreter */
if ( UFLAG == ON ) {
/* clear flag */
UFLAG = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* new line */
crlf();
/* help */
if ( cmd == '?' ) { show_help(); }
/* E set data to array */
if ( cmd == 'E' ) {
/* get address */
xadr = get_hex( *(sbuf+1) ) ;
xadr <<= 4 ;
xadr |= get_hex( *(sbuf+2) ) ;
/* get data */
tmp = get_hex( *(sbuf+3) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+4) ) ;
/* store */
*(romx+xadr) = tmp ;
}
/* e show array context */
if ( cmd == 'e' ) {
*(msg+2) = ' ' ;
*(msg+3) = '\0' ;
for ( ii = 0 ; ii < 256 ; ii++ ) {
tmp = get_eeprom( ii ) ;
*(msg+0) = conv_hex( (tmp >> 4) & MASK0F ) ;
*(msg+1) = conv_hex( tmp & MASK0F ) ;
rs_puts( msg );
/* new line */
if ( (ii % 8) == 7 ) { crlf(); }
}
}
/* G run simulate */
if ( cmd == 'G' ) {
idx = 0 ;
EFLAG = ON ;
}
/* g stop simulate */
if ( cmd == 'g' ) { EFLAG = OFF ; }
/* S store */
if ( cmd == 'S' ) {
for ( ii = 0 ; ii < 256 ; ii++ ) { put_eeprom(ii,*(romx+ii)) ; }
}
/* L load */
if ( cmd == 'L' ) {
for ( ii = 0 ; ii < 256 ; ii++ ) { *(romx+ii) = get_eeprom( ii ) ; }
}
}
}
/* receive interrupt */
void serialEvent()
{
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
UFLAG = ON ;
}
}
}
アドレス、データとも4ビットの場合ですが
8ビットに拡張するのは、簡単です。
ROMシーケンサの情報は、シリアルインタフェースを
使い書き込みます。
目次
前
次