16ビットマイコンボードの製作
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第30回]
●0 DIVIDE
この2〜3日の作業でかなり機能が充実してきました。
まだ動くのはマシンランゲージのみですが、マシン語ツールとしてはここまでできれば十分実用になります。
実際にシステムプログラムを作り上げていく中でデバッグに随分役立っています。
当初はAM188用のシステムプログラムの作成は適当なところで切り上げておいて、先にKL5C80A12用のシステムプログラムを完成させるつもりでした。
8086用のシステムプログラムを、KL5C80A12版と同時に供給するのは、さすがに無理だろうという至極当然の判断からでした。
でもまあ全然手をつけないでおくわけにもいきませんから、とりあえず入口のあたりだけでもさわっておこうと考えて、AM188用システムプログラムの作成にとりかかったのでした。
しかし、いざ作業を始めてみますと、だんだん面白くなってきました。
おそらく多くの方はZ80や8080のマシン語に比べると8086のマシン語は桁違いに難しい(だろう)、と思われるでしょうけれど。
確かにそういう面もあります。
ありますけれど、ある程度慣れてきますと、それほど難しくはありません。
ひょっとすると8080やZ80のマシン語(アセンブラ)より簡単かもしれません。
ま、それはちょっと言いすぎかもしれませんが。
たとえば。
8080の XCHG はHLレジスタとDEレジスタを交換する命令です。
Z80ニーモニックでは EX DE,HL です。
しかし EX HL,BC とか EX DE,BC はありません。
ところが。
8086の場合はこんな感じです。
2018/6/2 7:226 xchgtest.LST [00001] ;;;XCHG [00002] ; [00003] ORG=8000 [00004] 8000 93 XCHG AX,BX [00005] 8001 93 XCHG BX,AX [00006] 8002 91 XCHG AX,CX [00007] 8003 92 XCHG AX,DX [00008] 8004 87D9 XCHG BX,CX [00009] 8006 87DA XCHG BX,DX [00010] 8008 87CA XCHG CX,DX [00011] 800A 96 XCHG AX,SI [00012] 800B 87DE XCHG BX,SI [00013] 800D 87CE XCHG CX,SI [00014] 800F 87D6 XCHG DX,SI [00015] 8011 97 XCHG DI,AX [00016] 8012 87FB XCHG DI,BX [00017] 8014 873C XCHG DI,[SI] [00018] 8016 8715 XCHG DX,[DI] [00019] ; [00020] ; |
とても全部は書ききれないので適当にはしょって一部のみアセンブラにかけてみました。
XCHG AX,BX と書いても XCHG BX,AX と書いてもどちらでもOKです。
まこれは8086アセンブラのキャパシティとも言えますが。
XCHG DX,[DI] のようにレジスタとメモリの交換もできます。
いかがでしょうか?
おお、これはひょっとしたら8ビットのマシン語では難しかったプログラムでも楽に書けるのでは?
とお思いになりませんでしょうか?
8086も今では過去のCPUですけれど、今でもWindowsマシンの中で生きています。
コマントプロンプトの中で実行することもできますけれど、それはあくまで仮想8086マシンです。
ここはぜひ本物の8086(AM188は8086上位互換です)を動かしてみてください。
きっと8080やZ80では味わえなかったより大きな感動が得られるに違いありません。
余談になってしまいました。
本題に戻ります。
8086には乗算命令MULと除算命令DIVがあります。
DIVでは0で割るとエラーが発生します。
Fatal error(致命的なエラー)です。
0 DIVIDEの割込みが発生します。
INT 0hの割込みです。
AM188の割込みテーブルは[第22回]で説明しました。
DIV命令を実行する前に除数が0でないことを確認しておくべきですが、プログラムのバグなどで0での除算が実行されてしまうかもしれません。
もしもINT 0hの割込みに対してシステムプログラムが何も対策してなかった場合、そこでシステムはハングアップしてしまいます。
ちょっと作業が進みましたので、この機会に0 DIVIDEエラーをシステムプログラムに組み込みました。
下はテストプログラムです。
2018/5/31 7:226 divtest.LST [00001] ;;;DIV TEST [00002] ; [00003] ORG=8000 [00004] 8000 BA3412 MOV DX,1234 [00005] 8003 B8FFFF MOV AX,FFFF [00006] 8006 BB0300 MOV BX,0003 [00007] 8009 F7F3 DIV BX [00008] 800B 90 NOP [00009] ;END |
DIVには16ビット除算と8ビット除算があります。
オペランドに置いた除数のレジスタが16ビットのとき、16ビットの除算が行なわれます。
被除数はDXとAXを連結した32ビットになります。
結果はDXに余りが、AXに商が入れられます。
上のプログラム例(1234FFFF/3)ではオーバーフローかと思ったのですが多分被除数に対して除数が小さすぎるからでしょうか、0 DIVIDEが発生しました。
このプログラムは簡単なテストプログラムとして書きましたので終わりがありません。
このまま実行すると最後に暴走してしまいます。
BPの機能が使えますから、800Bにブレークポイントを設定して実行します。
ブレークすると計算の実行結果を確認することができます。
実行中の様子です。
最初の実行では0 DIVIDE!と表示されました。
次にDX=0000にして実行しました。
0000FFFF/0003=5555です。
今回はエラー表示はありません。
AXレジスタに5555が入っています。
なおどちらもブレークしたように表示されていますが、上の0 DIVIDEの場合にはブレークポイントでのブレークではなくて0 DIVIDE割込みの処理プログラムの中でレジスタダンプをしたものです。
2回目に実行したエラーなしの場合にはPC=800Bですが、1回目のエラー発生時はPC=800Aになっています。
あ。
今気が付きました。この場合にはPC=8009にすべきでした。
あとでプログラムを直しておくことにします。
今度はBX=0000にして実行してみました。
当然0 DIVIDEエラーになりました。
このときも念のためにブレークポイントを800Bに設定してから実行したのですが、次にはブレークポイントを設定しないで実行しました。
同じ結果になりました。
レジスタの表示がブレークポイントの設定によるものではないことの確認です。
説明の途中ですが、ちょっと長くなってしまいましたので、続きは次回にいたします。
16ビットマイコンボードの製作[第30回]
2018.6.2upload
前へ
次へ
ホームページトップへ戻る