平成26年4月 9日
モニタプログラムの雛形
割り込み処理への対応方針が固まったことで、ほぼモニタプログラムの必要な機能は出揃いました。残りはモニタプログラムからユーザープログラムへ制御を移すGoコマンドの実装だけになります。
最初に割り込み処理を終わらせます。モニタプログラムでは0番地からを除くROMアドレスからの割り込み実行を0x8000番地に配置したジャンプテーブルにジャンプさせます。0x8000番地にジャンプ命令を置くのはユーザープログラムで行います(理由はこのアドレス領域はユーザー領域だからです)。スタートアップルーチンstart.xasを下記のように変更します。重要な変更箇所は太字で示してあります。
変更後のstart.xasリスト
EXTNAL _DATA_SIZE ; 初期値のあるデータのサイズ
EXTNAL _DATA_TOP ; 初期値のあるデータのアドレス(RAM)上
EXTNAL _BSS_SIZE ; 初期値のないデータのサイズ
EXTNAL _BSS_TOP ; 初期値のないデータのアドレス(RAM)上
EXTNAL _main
;
;-------------------------------+
; Stack (RAM) +
;-------------------------------+
_STACK sect stak
ds 100h
_STACK_END:
;-------------------------------+
; init section (ROM) +
;-------------------------------+
_INIT_DATA SECT COMM ; 初期値のあるデータの配置されたセクション(ROM)上
;-------------------------------+
; Control data (RAM) +
;-------------------------------+
D_DATA sect comm
global _errno
_errno dw 0 ;for math lib
;
;----------------------------------------------------------------
; Interrupt table
;----------------------------------------------------------------
INIT SECT CODE,ORG=0 ; nmi
JP START
JMP_TBL EQU 8000H ;ジャンプテーブル
AORG 08H
JP JMP_TBL+3
AORG 10H
JP JMP_TBL+6
AORG 18H
JP JMP_TBL+9
AORG 20H
JP JMP_TBL+0CH
AORG 28H
JP JMP_TBL+10H
AORG 30H
JP JMP_TBL+13H
AORG 38H
JP JMP_TBL+16H
AORG 66H
JP JMP_TBL+19H
C_START SECT CODE,ORG=80H
START:
ld HL,_STACK_END ;Set Stack Pointer
ld SP,HL
;
; 初期値のあるデータをROMからRAMへ転送する
;
LD HL, _INIT_DATA
LD DE, _DATA_TOP
LD BC, _DATA_SIZE
LDIR
;
; 初期値のないRAMエリアを0クリアする
;
LD IX, _BSS_TOP
LD HL, _BSS_SIZE
LD DE,1
CP_BSS1:
SBC HL,DE
JP C,CP_BSS2
LD (IX),0
INC IX
JP CP_BSS1
CP_BSS2:
;
; main 関数を呼び出す
;
CALL _main
JR START
HALT
;
END START
アセンブラでの記述になるので少しわかり難いですが、ジャンプテーブルの先頭アドレスをJMP_TBLと命名し、このアドレスとのオフセットを加算することでジャンプ先アドレスを指定しています。AORGというアセンブラ擬似命令が使用されていますが、これは基本的にはORG命令と同じで命令コードを記憶させる開始アドレスを変更します。したがって各ジャンプ命令はINT割り込みで実行される8の倍数のアドレスに正しく配置されます。
次はリンクパラメータファイルの変更です。RAMの開始アドレスを0xfe00に変更します。
変更後のリンクパラメータファイルのリスト
;-------------------------------+
;RAM Area|
;-------------------------------+
/ADDR=fe00
/SECT=D_*|COMM(data=_DATA)
/SECT=B_*|COMM(bss=_BSS)
/SECT=_STACK
;-------------------------------+
;ROM Area|
;-------------------------------+
/ADDR=0
/SECT=C_*|CODE
/SECT=I_*
;-------------------------------+
;init data section+
;-------------------------------+
/init_section = _INIT_DATA(_DATA)
;-------------------------------+
;linkage module|
;-------------------------------+
/Name=z80mon
/Module=START.xao
/Module=z80mon.xao
/slib=C:\PROGRA~1\AKIZ80\lib\z80\cs\csze1
最後はモニタプログラムからユーザープログラムへ制御を移すGoコマンドの実装です。ユーザープログラムはロードコマンドによってRAM上に配置されます。プログラムの開始アドレスは0x8000番地です。このアドレスにはユーザープログラムの開始アドレスへのジャンプ命令が配置されています。これは仕様として決めたものです。
Goコマンドでは通信を介してPCから"g <開始アドレス>"と入力されると、指定された開始アドレスにジャンプします。しかし、ほとんどはプログラムの開始アドレスから実行しますので開始アドレスを省略した場合は0x8000番地にジャンプするようにしておきます。
ユーザープログラムへの移動は下記になります。
uint startAddr=0x8000; //開始アドレスを記憶。PCからアドレスの指定があれば書き換えられている
void commandGo(void)
{
#asm
LD BC,(_startAddr)
PUSH BC
RET
#endasm
}
逆にユーザープログラムからモニタプログラムに戻るときは下記のようにします。つまりリセットと同じ処理を行います。
#asm
DI
JP 0
#endasm
これで「取り合えず」ですが、ユーザープログラムをRAM上にロードし、それを実行できる環境が出来ます。