You are here

[UniMon] 内部ルーチンの新しい呼び方を試す(その1)


カテゴリー:

以前[UniMon] 固定エントリポイントで機能ごとに固定したエントリポイントを用意することでユーザプログラムから内部ルーチンを使えるようにする方法を用意しました。

でもよく考えるとこれはあまりよい方法ではなかった気がしてきました。

MC68000を考えるとサブルーチンコールではなくTRAPを使いたいですし、MC68000のTRAP命令は16通りしかありません。今のところ足りるとはいえ、できればエントリポイントは1つにしたいところです。

また世のOSなどを見ても機能コードを引数にしてエントリポイントは1つというのが主流に思います。かなり古いCP/Mですら、BDOSコールはCレジスタに機能コードを入れてCALL 0005H(BIOSは機能ごとのエントリですが)でした。MS-DOSもAHレジスタに機能コードを入れてINT 21Hですし、NetBSD(x86)のシステムコールはEAXに機能コードを入れてINT 80Hです。

なんでメジャーなWindowsを挙げないかというと、私がABIなどの深いところを知らないから。

そういえばX68000のIOCSコールもそうだったかな、と思って調べたら未実装命令例外使っていました。機能コードは命令の中に埋め込まれていますが、例外ベクタは1つなのでエントリポイントは1つです。

ということで手始めに8080, Z80版に追加してみました。

Cレジスタに機能コード(0からCSTART, WSTART, CONOUT, ...)を入れてRST 30H(8080ではRST 6、以後Z80ニーモニックのみ書くので8080には置き換えて読んでください)です。入出力のパラメータは固定エントリポイントから変更はありません。

これまで3バイトのCALL命令だったのが、2バイトのLD C,nと1バイトのRST 30Hになるので呼び出しコストはあまり変わりません。Cレジスタの保存が必要だとちょっと面倒ですが...

追加したコードはこれだけ(他に0030HにJP RST30Hがあるだけ)です。

    1387/     835 :                     ;;;
    1388/     835 :                     ;;; RST 30H Handler
    1389/     835 :                     ;;;
    1390/     835 :                     
    1391/     835 :                     RST30H:
    1392/     835 : =>TRUE              	IF USE_NEWAPI
    1393/     835 :                     
    1394/     835 : E5                  	PUSH	HL
    1395/     836 : C5                  	PUSH	BC
    1396/     837 : 21 45 08            	LD	HL,APITBL
    1397/     83A : 06 00               	LD	B,0
    1398/     83C : 09                  	ADD	HL,BC
    1399/     83D : 09                  	ADD	HL,BC
    1400/     83E : 46                  	LD	B,(HL)
    1401/     83F : 23                  	INC	HL
    1402/     840 : 66                  	LD	H,(HL)
    1403/     841 : 68                  	LD	L,B
    1404/     842 : C1                  	POP	BC
    1405/     843 : E3                  	EX	(SP),HL		; Restore HL, jump address on stack top
    1406/     844 : C9                  	RET
    1407/     845 :                     
    1408/     845 :                     APITBL:
    1409/     845 : 53 08               	DW	API00		; 00: CSTART
    1410/     847 : 58 08               	DW	API01		; 01: WSTART
    1411/     849 : 8D 0B               	DW	CONOUT		; 02: CONOUT
    1412/     84B : 49 07               	DW	STROUT		; 03: STROUT
    1413/     84D : 7F 0B               	DW	CONIN		; 04: CONIN
    1414/     84F : 88 0B               	DW	CONST		; 05: CONST
    1415/     851 : 5C 08               	DW	API06		; 06: PSPEC
    1416/     853 :                     
    1417/     853 :                     	;; CSTART
    1418/     853 :                     API00:
    1419/     853 : E1                  	POP	HL		; Drop return address
    1420/     854 : F3                  	DI
    1421/     855 : C3 00 01            	JP	CSTART
    1422/     858 :                     
    1423/     858 :                     	;; WSTART
    1424/     858 :                     API01:
    1425/     858 : E1                  	POP	HL		; Drop return address
    1426/     859 : C3 64 01            	JP	WSTART
    1427/     85C :                     
    1428/     85C :                     	;; PSPEC
    1429/     85C :                     API06:
    1430/     85C : 3A 1B FF            	LD	A,(PSPEC)
    1431/     85F : C9                  	RET
    1432/     860 :                     
    1433/     860 : =>FALSE             	ELSE			; USE_NEWAPI
    1434/     860 :                     
    1435/     860 :                     	RET
    1436/     860 :                     
    1437/     860 : [1392]              	ENDIF			; USE_NEWAPI

まず1394,1395行目でレジスタを保存しておきます。HLはSTROUTの引数なので必ず保存しなくてはなりません。

1396~1399行目まででHL=テーブル先頭アドレス+C×2を求めます。BCを2倍するより2度足すほうが短く速いはず。あと本来はCのレンジチェックをすべきですがAレジスタの保存が必要になったり結構面倒なので省略しています。

1400~1403行でテーブルから飛び先アドレスを取得します。

1404行でBCレジスタを復帰させます。この時点でスタックトップには保存したHLレジスタの内容、その下にはユーザプログラムへの戻りアドレスがあります。

1405行でスタックトップとHLレジスタを交換、これで飛び先がスタックトップに置かれHLレジスタを復帰できました。

1406行のRETは元のルーチンへの復帰ではなく、処理ルーチンへのジャンプです。HLレジスタに任意の値を入れてテーブルジャンプするときの定石ですね。

1408行からは各処理ルーチンへのジャンプテーブルです。

1417~1421行はCSTARTの処理、RST 30H命令を使う都合上どうしても戻りアドレスがスタックにつまれてしまうのですが戻る必要はないので捨てています。

1423~1426行も同様にWSTARTの処理です。

1428~1431行、プロセッサ判別の結果を取得する機能を追加してみました。

次は他のプロセッサへの展開なのですが、まだちょっと考えがまとまらないので...

参考文献・関連図書: 
伊藤英明(1986)『CP/M活用モジュール・ハンドブック』CQ出版社.
富田靖(1987)「X68000ハッカーズ・マニュアル」,『I/O』1987年7月号, pp.257-263, 工学社.

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
※ コメントは原則公開です。個別のご相談などは「ご意見・ご要望」からお願いします。