2018.10.14
前へ
次へ
ホームページトップへ戻る


16ビットマイコンボードの製作

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

[第97回]



●システムサブルーチンを直接CALLしたい(2)

前回からの続きです。
前回書いたことの繰り返しですが、マシン語プログラムを直接16進コードで入力することが前提のND80KL/86ボードのマシン語モニタでシステムサブルーチンをコールするのにINT xx方式はなんとなく面白くありませんし、またシステムプログラムを作るうえでもちょっと作りづらい面があります。
なんとかシステムサブルーチンを直接コールしたいものだと思案しました。
というところで前回は終わってしまいました。

さてそのなんとかする方法なのですが。
そのヒントについては[第48回]に書いておりました。
問題はユーザープログラムがRAMにあって、CSも一時的にRAMになっているのにシステムプログラムはROMにあるので、ユーザープログラムからはROMのシステムプログラムがコールできない、というただ一点の問題でした。
システムプログラムをRAMにコピーしてしまえば問題は解消してしまうのでした。
思いついてしまえばなんてこともない簡単なことでした。

ROMからRAMへのコピーですが、マシン語モニタプログラムだけでしたら0100〜09FFまでのわずか2KB余りですから、起動時に実行すればほとんど瞬時に終ってしまいます。
どうせコピーするのでしたら、マシン語モニタプログラムだけではなくて、[第71回][第82回]で書きましたBASICのシステムサブルーチンも一緒にコピーしてしまえばさらに使い勝手がよくなります。
その場合には0100〜1FFFの8KBほどをコピーすることになりますが、AM188にはMOVSBという便利な命令がありますから、わずか数行のプログラムを追加するだけで済んでしまいます。

ということで、86モニタプログラムの起動部分にシステムコピープログラムを追加しました。

[00083]                     ; copy 0100-1fff to ram
[00084] 0135  BE0001            MOV SI,100
[00085] 0138  BF0001            MOV DI,100
[00086] 013B  B90020            MOV CX,2000
[00087] 013E  FC                CLD
[00088] 013F  F3                REPZ
[00089] 0140  2E                CS:
[00090] 0141  A4                MOVSB

あ。
今気が付きました。
0100〜1FFFならCX=1F00でした。
CX=2000では20FFまでコピーしてしまいます。
ま。
特に問題になることではありませんが、あとで直しておくことにいたしましょう。
MOVSBはDS:SIで示すメモリ内容をES:DIで示すメモリにコピーしたあと、SI、DIをそれぞれ+1する命令です(それより前にCLDが実行されていたとき)。
それより前にSTDが実行されているとSI、DIは−1されます。
REPZはそれに続くMOVSB/MOVSWなどのストリング命令をCX=0になるまで繰り返すプリフィクス(前置)命令です。
ここではCSのプログラムをコピーすることが目的ですからCS:プリフィクスをMOVSBの前に置いてDS:SIをCS:SIに一時的に置き換えています。
なおMOVSB/MOVSWなどのストリング命令の前にセグメント変更プリフィクスを置いた場合に置き換えられるセグメントは第一項のDS:でES:を置き換えることはできません。

●INT 2Aに変更しました

[第85回]でINT 22からINT B0に変更したシステムサブルーチンコールですが、今回のシステムプログラムのコピーを受けて、INT 2Aに再度変更しました。
INT B0の場合INTテーブルはRAMの002C0〜002C3に置かれます。
そこは今回のシステムプログラムのコピーによってシステムプログラムに占有されてしまうので、INT B0は使えなくなってしまいます。
使えるのは00000〜000FFの256バイトだけになりますから、INT 0〜INT 3Fに限定されます。
その中でMSDOSでは使っていないらしいbニしてINT 2Aを選びました。
今回のシステムプログラムのコピーによって、INT 2Aを使うほかにシステムサブルーチンのアドレスを直接指定してコールすることも可能になりますから、INT 2Aしか方法がないというところから選択肢が増えたことになります。

システムプログラムをRAMにコピーした効果を実際に試してみました。
今回のシステムプログラムコピーの本来の目的は86モニタのマシン語サブルーチンをコールすることだったのですが、7セグメントを使ったマシン語プログラムでそれを試すよりは、86BASICシステムを起動して、そこでマシン語プログラムを使って試すほうが楽ですので、まずはそのようにしてみました。

まずは今回変更したINT 2Aを試してみました。
下はテストプログラムINT2AT1のプログラムリストです。
[第85回]で使ったINTB0T1のINT B0をINT 2Aに変更しただけでほかは変更していません。

2018/10/8  20:26  int2at1.LST
[00001]                     ;;; int 22 test
[00002]                     ;18/9/7 10/8
[00003]                         ORG=8000
[00004] 8000  B041              MOV AL,41
[00005] 8002  B11A              MOV CL,1A
[00006] 8004  B407              MOV AH,07
[00007] 8006  50            LOOP:PUSH AX
[00008] 8007  CD2A              INT 2A
[00009] 8009  58                POP AX
[00010] 800A  FEC0              INC AL
[00011] 800C  FEC9              DEC CL
[00012] 800E  75F6              JNZ LOOP <8006>
[00013] 8010  B409              MOV AH,09
[00014] 8012  CD2A              INT 2A
[00015] 8014  CB                RETF
[00016]                     ;
LOOP         =8006  

こちらがログです。

logfile nd80klog\10090919.txt open
nd80kl/86 2018.9.22 by Chunichidenko
version no. bs861f

ND80KL/86に接続しました
0001 001E - z
0003 0339 - 
*** nd80kl/86(am188) basic ****
>/ld int2at1.com,8000
loading INT2AT1.COM ...0015(21)bytes loaded,from 8000 to 8014
>jp 8000
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>

問題なく実行できました。
それではいよいよアドレスを直接指定してのシステムプログラムコールのテストです。
下はテストプログラム86SUBT1のプログラムリストです。

2018/10/9  8:51  86subt1.LST
[00001]                     ;;; system sobroutine call test
[00002]                     ;18/9/7 10/8
[00003]                         ORG=8000
[00004]                         ADISP=1015
[00005]                         CRLF=101B
[00006]                         REENT=1033
[00007]                     ;
[00008] 8000  B041              MOV AL,41
[00009] 8002  B11A              MOV CL,1A
[00010] 8004  50            LOOP:PUSH AX
[00011] 8005  E80D90            CALL ADISP <1015>
[00012] 8008  58                POP AX
[00013] 8009  FEC0              INC AL
[00014] 800B  FEC9              DEC CL
[00015] 800D  75F5              JNZ LOOP <8004>
[00016] 800F  E80990            CALL CRLF <101B>
[00017] 8012  E91E90            JMP REENT <1033>
[00018]                     ;
ADISP        =1015  CRLF         =101B  LOOP         =8004  REENT        =1033  

8086は8080やZ80と違ってJMP、CALL命令のアドレス指定は相対アドレス指定です。
この方式はプログラムをどのアドレスに置いても実行可能(リロケータブル)という利点がありますが、16進コードでのプログラミングは極めて困難になります。
簡単なテストプログラム程度ならともかく、少しまとまったプログラムは86アセンブラに依らざるを得ないでしょう。
上のプログラムリストでCALL ADISP、CALL CRLF、JMP REENTはシステムサブルーチンのアドレスを直接指定していますが、マシン語コードのアドレスは相対アドレス(指定アドレスからその命令の次のアドレスを引いた値)になっています。
それはともかくとして、果たしてうまくシステムサブルーチンがコールできましたでしょうか。
下が実行結果です。

>/ld 86subt1.com,8000
loading 86SUBT1.COM ...0015(21)bytes loaded,from 8000 to 8014
>jp 8000
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>

正しく実行できました。
テストとしてはこれでよいのですが、念のためにもう少しテストを続けてみました。
今度はシステムプログラムの先頭にブレークポイントを設定しました。
ブレークポイントはRAMにしか設定できません。
8080、Z80で命令をFFで置き換えることでRST7を利用しているのと同じように、コードCC(INT 3)で置き換えてブレーク処理を行ないますからRAM上のプログラムにしか使えません。

>bp 1015
>jp 8000
 AX   BX   CX   DX   SP   PC   SI   DI   BP   FR      ODITSZ A P C
0041 8000 001A 8000 F7F6 1015 0C24 F007 0000 F046 1111000001000110
>

実行した結果はアドレス1015でブレークしました。
これでシステムプログラムが間違いなくRAMにあることが確認できました。
なおシステムがROMにあってRAMにコピーされていない場合ブレークできないだけではなくて、上のプログラムでは暴走してしまいます。
暴走してしまうのでログは取れていませんがそのことは実際に確認済みです。

さてもうひとつ念のために同じことをINT 2Aを使ったプログラムでも試してみました。
同じように1015にブレークポイントを設定してさきほどのINT2AT1を実行してみました。

>/ld int2at1.com,8000
loading INT2AT1.COM ...0015(21)bytes loaded,from 8000 to 8014
>bp 1015
>jp 8000
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>bp d
1015
>bp 0
>/exit
0003 037C - 
リモート接続を終了しました
logfile closed at Tue Oct 09 09:49:07 2018

こんどはブレークしないで、プログラムが普通に実行終了してしまいました。
BP Dで確認したところまだ(RAMの)1015にブレークポイントが設定されたままになっていました。
INT 2Aの実行ではRAMではなくてROMのシステムプログラムが実行された結果です(INT 2Aはそのように働くようにプログラムしてあります)。

16ビットマイコンボードの製作[第97回]
2018.10.14upload

前へ
次へ
ホームページトップへ戻る