目次
前
次
ROMエミュレータ設計開発
単体のROMにプログラムを格納するには、ROMライターが
必要になるので、何度もプログラムを修正するやり方は
時間がかかり過ぎます。
ROMエミュレータを作って、ROMの消去とライトの時間を
なくしていきます。
回路図は、以下。
プログラムの内容を変更するには、シリアルインタフェースを
利用して、内蔵EEPROMの値を変えます。
シリアルインタフェースを使うので、1文字コマンドを定義しておきます。
- ? ヘルプ
- E 1バイトのデータ設定
- e 16バイトのデータ表示
1文字コマンドを定義したので、より細かく仕様を決めます。
ヘルプ
ヘルプは、1文字コマンドと簡単な説明を表示します。
1バイトのデータ設定
1バイトのデータを設定するには、アドレスとデータが必要です。
アドレスは16バイトでよいので、16進数で0からFと1けたで
指定します。データは16進数2けたで指定します。
(例) EA12{enter}
データを設定したなら、逆アセンブルして表示します。
16バイトのデータ表示
16バイトのデータ表示は、1文字eを入力したならば
一気に表示します。同時に逆アセンブルしておきます。
(例) e{enter}
30= MOV A,0
01= ADD A,1
40= MOV B,A
90= OUT B
f1= JMP 1
3コマンドを実現するインタプリタは、次のようになります。
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* store data */
if ( cmd == 'E' ) {
/* get address */
xadr = get_hex( *(sbuf+1) );
/* get data */
xdat = get_hex( *(sbuf+2) );
xdat <<= 4 ;
xdat |= get_hex( *(sbuf+3) );
/* store */
*(xrom+xadr) = xdat ;
store_eeprom( xadr , xdat );
/* show */
show_code( xdat );
}
/* show store data */
if ( cmd == 'e' ) {
for ( xadr = 0 ; xadr < 16 ; xadr++ ) {
/* get code */
xdat = load_eeprom( xadr ) ;
/* store address */
*(xmsg+0) = get_asc(xadr >> 4) ;
*(xmsg+1) = get_asc(xadr & MASK0F) ;
/* store machine code */
*(xmsg+3) = get_asc(xdat >> 4) ;
*(xmsg+4) = get_asc(xdat & MASK0F) ;
/* show */
rs_puts( (UBYTE *)xmsg );
show_code( xdat );
}
}
}
ROMのアドレスを与えられたときの動作は、アドレスを
読込んでひとつ前と異なれば、指定アドレスの内容を
出力します。
/* get address */
eadr = PIND ;
eadr >>= 2 ;
eadr &= MASK0F ;
/* judge */
if ( eadr != padr ) {
/* update address */
padr = eadr ;
/* get data and impress */
PORTB = *(xrom+padr);
}
EEPROMからのデータを取得すると時間がかかるので
同一内容を配列に取出しておきます。
通信プロトコルは、以下とします。
- データ転送速度 9600bps
- データ長 8ビット
- ストップビット 1ビット
- パリティ なし
- フロー制御 なし
ソースコードにまとめます。
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#define OFF 0
#define ON OFF+1
#define MASKFF 0xff
#define MASK0F 0x0f
#define FOSC 5000000
#define BAUD 9600
#define MYUBRR (FOSC/16/BAUD)-1
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
volatile UBYTE uflag ;
volatile UBYTE cmd ;
volatile UBYTE xadr ;
volatile UBYTE xdat ;
volatile UBYTE sbuf[8];
volatile UBYTE sindex ;
volatile UBYTE xrom[16] ;
volatile UBYTE eadr ;
volatile UBYTE padr ;
volatile UBYTE xmsg[8];
const prog_char msg_h[] PROGMEM = "? help" ;
const prog_char msg_le[] PROGMEM = "E set" ;
const prog_char msg_se[] PROGMEM = "e show" ;
const prog_char msg_c0[] PROGMEM = "ADD A," ;
const prog_char msg_c1[] PROGMEM = "MOV A,B" ;
const prog_char msg_c2[] PROGMEM = "IN A" ;
const prog_char msg_c3[] PROGMEM = "MOV A," ;
const prog_char msg_c4[] PROGMEM = "MOV B,A" ;
const prog_char msg_c5[] PROGMEM = "ADD B," ;
const prog_char msg_c6[] PROGMEM = "IN B" ;
const prog_char msg_c7[] PROGMEM = "MOV B," ;
const prog_char msg_c9[] PROGMEM = "OUT B" ;
const prog_char msg_c11[] PROGMEM = "OUT " ;
const prog_char msg_c14[] PROGMEM = "JNC " ;
const prog_char msg_c15[] PROGMEM = "JMP " ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
UBYTE get_hex(UBYTE x);
UBYTE get_asc(UBYTE x);
void store_eeprom(UBYTE xa,UBYTE xd);
UBYTE load_eeprom(UBYTE xa);
void show_help(void);
void rs_putchar(UBYTE x);
void rs_puts(UBYTE *x);
void crlf(void);
void show_code(UBYTE x);
UBYTE is_no_operand(UBYTE x);
void show_omsg(void);
/*------*/
/* main */
/*------*/
int main(void)
{
/* initialize port and variables */
user_initialize();
/* enable interrupt */
sei();
/* opening message */
show_omsg();
/* endless loop */
while ( ON ) {
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* store data */
if ( cmd == 'E' ) {
/* get address */
xadr = get_hex( *(sbuf+1) );
/* get data */
xdat = get_hex( *(sbuf+2) );
xdat <<= 4 ;
xdat |= get_hex( *(sbuf+3) );
/* store */
*(xrom+xadr) = xdat ;
store_eeprom( xadr , xdat );
/* show */
show_code( xdat );
}
/* show store data */
if ( cmd == 'e' ) {
for ( xadr = 0 ; xadr < 16 ; xadr++ ) {
/* get code */
xdat = load_eeprom( xadr ) ;
/* store address */
*(xmsg+0) = get_asc(xadr >> 4) ;
*(xmsg+1) = get_asc(xadr & MASK0F) ;
/* store machine code */
*(xmsg+3) = get_asc(xdat >> 4) ;
*(xmsg+4) = get_asc(xdat & MASK0F) ;
/* show */
rs_puts( (UBYTE *)xmsg );
show_code( xdat );
}
}
}
/* ROM handling */
{
/* get address */
eadr = PIND ;
eadr >>= 2 ;
eadr &= MASK0F ;
/* judge */
if ( eadr != padr ) {
/* update address */
padr = eadr ;
/* get data and impress */
PORTB = *(xrom+padr);
}
}
}
/* dummy */
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
UWORD tmp ;
/* PORT B */
PORTB = 0b00000000 ; /* 00000000 */
DDRB = 0b11111111 ; /* oooooooo */
/* PORT D */
PORTD = 0b00111101 ; /* 00111101 */
DDRD = 0b11000010 ; /* ooiiiioi */
/* set uart */
{
/* set Baud Rate Registers */
tmp = MYUBRR ;
UBRRH = (tmp >> 8) & MASKFF ;
UBRRL = tmp & MASKFF;
/* Enable receive interrupt , receive module and transmit module */
UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN) ;
}
/* clear flag */
uflag = OFF ;
/* */
sindex = 0 ;
eadr = 0 ;
padr = 0 ;
/* message */
*(xmsg+2) = ':' ;
*(xmsg+5) = '=' ;
*(xmsg+6) = ' ' ;
*(xmsg+7) = '\0' ;
/* get previous code */
for ( xadr = 0 ; xadr < 16 ; xadr++ ) {
*(xrom+xadr) = load_eeprom( xadr ) ;
}
PORTB = *(xrom+0) ;
}
UBYTE get_hex(UBYTE x)
{
UBYTE result ;
/* default */
result = 0 ;
/* judge */
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
return result ;
}
UBYTE get_asc(UBYTE x)
{
UBYTE result ;
/* default */
result = '0' ;
/* judge */
if ( 0 <= x && x <= 9 ) { result = x + '0' ; }
if ( 10 <= x && x <= 15 ) { result = x - 10 + 'A' ; }
return result ;
}
void store_eeprom(UBYTE xa,UBYTE xd)
{
UBYTE adr ;
adr = xa ^ 0x7f ;
eeprom_write_byte( adr , xd );
}
UBYTE load_eeprom(UBYTE xa)
{
UBYTE adr ;
adr = xa ^ 0x7f ;
return eeprom_read_byte( adr );
}
void show_help(void)
{
char msg[16];
strcpy_P(msg,msg_h) ; rs_puts((UBYTE *)msg); crlf();
strcpy_P(msg,msg_le); rs_puts((UBYTE *)msg); crlf();
strcpy_P(msg,msg_se); rs_puts((UBYTE *)msg); crlf();
}
void rs_putchar(UBYTE x)
{
while ( !(UCSRA & (1 << UDRE)) ) {}
UDR = x ;
}
void rs_puts(UBYTE *x)
{
while ( *x != '\0' ) {
rs_putchar( *x );
x++ ;
}
}
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_code(UBYTE x)
{
UBYTE xh ;
UBYTE xl ;
char msg[8];
/* clear */
for ( xh = 0 ; xh < 8 ; xh++ ) { *(msg+0) = 0 ; }
/* separate */
xh = (x >> 4) & MASK0F ;
xl = get_asc(x & MASK0F) ;
/* have operand */
if ( is_no_operand(xh) == OFF ) {
/* MOV A,Im */
if ( xh == 3 ) {
strcpy_P(msg,msg_c3) ;
rs_puts((UBYTE *)msg);
}
/* ADD A,Im */
if ( xh == 0 ) {
strcpy_P(msg,msg_c0) ;
rs_puts((UBYTE *)msg);
}
/* MOV B,Im */
if ( xh == 7 ) {
strcpy_P(msg,msg_c7) ;
rs_puts((UBYTE *)msg);
}
/* ADD B,Im */
if ( xh == 5 ) {
strcpy_P(msg,msg_c5) ;
rs_puts((UBYTE *)msg);
}
/* OUT Im */
if ( xh == 11 ) {
strcpy_P(msg,msg_c11) ;
rs_puts((UBYTE *)msg);
}
/* JMP Im */
if ( xh == 15 ) {
strcpy_P(msg,msg_c15) ;
rs_puts((UBYTE *)msg);
}
/* JNC Im */
if ( xh == 14 ) {
strcpy_P(msg,msg_c14) ;
rs_puts((UBYTE *)msg);
}
rs_putchar( xl );
} else {
/* MOV A,B */
if ( xh == 1 ) {
strcpy_P(msg,msg_c1) ;
rs_puts((UBYTE *)msg);
}
/* IN A */
if ( xh == 2 ) {
strcpy_P(msg,msg_c2) ;
rs_puts((UBYTE *)msg);
}
/* MOV B,A */
if ( xh == 4 ) {
strcpy_P(msg,msg_c4) ;
rs_puts((UBYTE *)msg);
}
/* IN B */
if ( xh == 6 ) {
strcpy_P(msg,msg_c6) ;
rs_puts((UBYTE *)msg);
}
/* OUT B */
if ( xh == 9 ) {
strcpy_P(msg,msg_c9) ;
rs_puts((UBYTE *)msg);
}
}
/* new line */
crlf();
}
UBYTE is_no_operand(UBYTE x)
{
UBYTE result ;
/* default */
result = OFF ;
/* judge */
if ( x == 1 ) { result = ON ; }
if ( x == 2 ) { result = ON ; }
if ( x == 4 ) { result = ON ; }
if ( x == 6 ) { result = ON ; }
if ( x == 9 ) { result = ON ; }
return result ;
}
void show_omsg(void)
{
rs_puts((UBYTE *)"Hello !");
crlf();
}
/* UART receive interrupt */
ISR(USART_RX_vect)
{
volatile UBYTE ch ;
/* get 1 charactoer */
ch = UDR ;
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
ATTiny2313を利用した場合、ほぼフラッシュROMの90%近く
まで使っています。
操作は、次のようにします。
ROMの内容を確認
機械語入力
再度ROMの内容を確認
最大プログラムサイズは16バイトなので、ハンドアセンブルでも
16進数コードにできますが、ROMエミュレータがコンピュータに
接続されるので、スクリプトでアセンブルを楽にします。
ニモニックから16進数に変換するアセンブラを
AWKで作成しておきます。
BEGIN {
printf("TD4 assembler\n")
printf(" adr data ------------------------\n")
}
{
# get code
instructionx = tolower($1)
oprandx = tolower($2)
# split
idx = index(oprandx,",")
if ( idx == 0 ) {
oprand0 = oprandx
} else {
oprand0 = substr(oprandx,idx-1,1)
oprand1 = substr(oprandx,idx+1,1)
}
# conversion
opcode = 15
oprand = 15
# add
if ( instructionx == "add" ) {
oprand = oprand1
if ( oprand0 == "a" ) { opcode = 0 }
if ( oprand0 == "b" ) { opcode = 5 }
}
# mov
if ( instructionx == "mov" ) {
oprand = oprand1
if ( oprand0 == "a" ) {
opcode = 3
oprand = oprand1
if ( oprand1 == "b" ) {
opcode = 1
oprand = 0
}
}
if ( oprand0 == "b" ) {
opcode = 7
oprand = oprand1
if ( oprand1 == "a" ) {
opcode = 4
oprand = 0
}
}
}
# in
if ( instructionx == "in" ) {
oprand = 0
if ( oprand0 == "a" ) { opcode = 2 }
if ( oprand0 == "b" ) { opcode = 6 }
}
# out
if ( instructionx == "out" ) {
oprand = 0
opcode = 11
if ( oprand0 == "b" ) {
opcode = 9
}
}
# JNC
if ( instructionx == "jnc" ) {
opcode = 14
oprand = oprand0
}
# JMP
if ( instructionx == "jmp" ) {
opcode = 15
oprand = oprand0
}
# generate code
result = opcode * 16 + oprand
# show
printf(" 0x%02X 0x%02X => %s\n",NR-1,result,$0)
}
END {
printf("---------------------------------------\n")
}
CUIで動かすので、テキストファイルにニモニックを
入れておき、アセンブルした結果をI/Oリダイレクト
で保存します。
c:\>gawk -f td4asm.awk test.txt > tout.txt
I/Oリダイレクトでテキストファイルにすると以下となります。
TD4 assembler
adr data ------------------------
0x00 0x30 => MOV A,0
0x01 0x01 => ADD A,1
0x02 0x40 => MOV B,A
0x03 0x90 => OUT B
0x04 0xF1 => JMP 1
---------------------------------------
16進数の2けたで、左にアドレス、右に機械語を
おいてあるので、さらにAWKのスクリプトで入力
するコマンドを生成することもできます。
目次
前
次