目次

モニタ開発

 パーソナルコンピュータと同様、ハードウエアを直接
 動かすためBIOS(Basic Input Output System)を用意
 しておけば、開発が楽になります。

 BIOS作成は大げさなので、モニタを作成します。

 モニタは、ハードウエアを直接動かすコードの集合体
 なので、接続されている周辺ICのレジスタを操作する
 コードが必要です。

 端末から操作できるように、コマンドインタプリタと
 コマンドを定義します。

 最初のコマンドインタプリタは、単純に文字比較とします。
 コマンドインタプリタは、サブルーチン構成にします。

 CMD_INT:
  push  af
  push  bc
  push  ix

  ; set serial buffer
  ld    ix,SBUF

  ; get 1 command charactor
  ld    a,(ix)

  ; judge command
  cp    'I'
	call   z,CMD_I
  cp    'O'
	call   z,CMD_O
  cp    '?'
	call   z,CMD_HELP
  ;
  pop   ix
  pop   bc
  pop   af
  ret

 CMD_I:
  ret

 CMD_O:
  ret

 CMD_HELP:
  ret

 コマンドは、1文字として'I'と'O'を用意します。
 シリアルバッファは、ラベルSBUFで指定しておき
 SRAMの中に、256バイト分確保します。

 SBUF:	DEFS 256

 コマンド'I'の仕様を考え定義します。

  I/Oアドレスは、0〜255なので、16進数2けたで
  指定します。このアドレスを、SBUFの中に次のように
  入っているとして、動かします。



  コマンド'I'は、デリミタを'\r'として3バイトとします。

  仕様を確定したので、サブルーチンの内容を確定します。

 CMD_I:
	; store
	push	af
	push	bc
	; get I/O address
	ld    c,(ix+1)
	; get data
	in    a,(c)
	; show
	call  SHOW_BYTE
	; resume
	pop	bc
	pop	bc
	;
	ret

  サブルーチンSHOW_BYTEは、別途定義します。

 コマンド'O'の動作を考え定義します。

  I/Oアドレスを0〜255、データを0〜255と
  して、各々16進数2けたで指定します。



  アドレス、データがSBUFの中に入っているとして
  サブルーチンを構成します。

 CMD_O:
	; store
	push	af
	push	bc
	; get I/O address
	ld  c,(ix+1)
	; get data
	ld  a,(ix+2)
	; impress
	out  (c),a
	; resume
	pop	bc
	pop	bc
	;
	ret

 ここまでで、周辺ICレジスタを操作できるように
 なったので、次にメモリの内容を設定、表示する
 処理を考えます。

 メモリ内容表示は、次のようにします。

8000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
8010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
8020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
8030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
8040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
8050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
8060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
8070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
8080: 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
8090: 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
80a0: A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
80b0: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
80c0: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
80d0: D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
80e0: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
80f0: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

 アドレスを16進表示後、コロンを入れ16個の数値を
 16進で表示します。

 コマンドは'D'(dump)として、256バイトを表示します。
 メモリのアドレスが必要なので、次のようにSBUFを
 利用します。



 コマンドインタプリタに、'D'コマンドを付け加えます。

 CMD_INT:
  push  af
  push  bc
  push  ix

  ; set serial buffer
  ld    ix,SBUF

  ; get 1 command charactor
  ld    a,(ix)

  ; judge command
  cp    'I'
	call   z,CMD_I
  cp    'O'
	call   z,CMD_O
  cp    '?'
	call   z,CMD_HELP

  cp    'D'
	call   z,CMD_D

  ;
  pop  ix
  pop  bc
  pop  af
  ret

 'D'コマンド用のサブルーチンを考えます。

 動作を考えて、各サブルーチンの名前を決めます。
 サブルーチン名を与えると、実現コードが明確になります。

 2つのサブルーチンが存在するとして、'D'コマンドを
 記述してみます。

CMD_D:
  push  af
  push  bc
  push  de
  push  hl
  push  ix
  ; get address
  ld    ix,MADR
  ld    h,(ix+0)
  ld    l,(ix+1)
  ; set counter
CMD_D0:
  ld    c,16
  ld    a,c
CMD_D1:
  cp    0
  jr    z,CMD_D_END
  ; show address
  ld    a,h
  ; higher nibble => lower nibble
  srl   a
  srl   a
  srl   a
  srl   a
  ; hexadecimal => neumeric code
  call  h2a
  ; show upper
  call  rs_putc
  ld    a,h
  and   0fh
  ;  hexadecimal => neumeric code
  call  h2a
  ; show lower
  call  rs_putc
  ; show "00:"
  ld    a,'0'
  call  rs_putc
  ld    a,'0'
  call  rs_putc
  ld    a,':'
  call  rs_putc
  ; 
  ld    b,16
CMD_D2:
  ld    a,(hl)
  ; store
  ld    c,a
  ; higher nibble => lower nibble
  srl   a
  srl   a
  srl   a
  srl   a
  ; hexadecimal => neumeric code
  call  h2a
  ; show
  call  rs_putc
  ; get lower nibble
  ld    a,c
  and	0fh
  ; hexadecimal => neumeric code
  call  h2a
  ; show
  call  rs_putc
  ; get space
  ld    a,20h
  call  rs_putc
  ; address increment
  inc   hl
  ; check 1 line
  djnz  CMD_D2
  ; send CR
  ld    a,0dh
  call  rs_putc
  ; send LF
  ld    a,0ah
  call  rs_putc
  ; counter decrement
  dec   c
  ld    a,c
  jr   CMD_D1
CMD_D_END:
  pop  ix
  pop  hl
  pop  de
  pop  bc
  pop  af
  ;
  ret

 サブルーチンを定義するには、コーリングシーケンス
 を決めると、利用レジスタやメモリ領域が見えてきます。

 サブルーチンh2aを定義します。
 コーリングシーケンスは、以下とします。

  16進数値4ビットをレジスタAに入れて、コール。
  結果は、レジスタAに入っている。
  16進数値の範囲外の場合、下位4ビットを16進数値
  とみなして、変換する。



 サブルーチンh2aは、以下です。

h2a:
  ;*** get lower 4 bits ***
  add a,0fh
  ;*** 0 => 9 ***
  or  30h
  ;*** ? A => F ***
  cp  3ah
  jr  c,h2a_end
  add a,07h
h2a_end:
  ret

 relative jumpを利用して、リロケータブルの
 コードにしました。

 モニタとして、他にどんな機能があればよいか
 6800のデバッグモニタとして有名だったという
 MIKBUGのコマンドを調べてみました。

 MIKBUGのソースコードをWEBサイトでみることができたので
 サポート機能を拾い出してみました。

 テレタイプのASR-300シリーズや紙テープを
 利用し、わずか768バイトで上の機能を
 実現していたことに、驚きました。

 プログラムのロードと実行は必要なので
 この2つの実装をします。

 プログラム実行

  プログラム実行は、分岐命令を使います。
  Z80で使える分岐命令は、絶対アドレス指定で
  リストすると、以下。

  分岐命令だけでは、プログラムを実行して
  モニタに戻ってこれないので、対象となる
  コードの最後には、モニタプログラムへと
  戻ってくるコードを入れます。

  次のようなモジュールになります。

XTST:
    ; store
    push af
    push bc
    push de
    ; insert target code
    ;
    ;
    ; resume
    pop  de
    pop  bc
    pop  af
    ; return to monitor
    JP monitor

  モジュールプログラムのアドレス格納に2バイトの領域を
  用意しておきます。モニタは、この2バイトをHLレジスタ
  ペアに入れて、プログラムを実行します。

MDADR:  DS  2

    ; get address
    LOAD HL,(MDADR)
    ; branch
    JP   (HL)

 プログラムロード

(under construction)

目次

inserted by FC2 system