目次

マイコン版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シーケンサを実現できるとわかると思います。

 シリアルインタフェースのコマンドを用意します。

 コマンドインタプリタを用意したなら、実現方法を考えます。

 信号を出力するのが基本なので、そこから設計していきます。

 配列用のインデックスを変数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シーケンサの情報は、シリアルインタフェースを
 使い書き込みます。


目次

inserted by FC2 system