CPU実験室

誰も見向きもしない古いCPUをいじって動かしてみようというプロジェクトです

リセットベクタ

これまでの簡単なプログラムはリセットベクタFFFF0からいきなり書いて電源ONで直接実行されるようにしていましたがリセットベクタからだとメモリの終端まであと16バイトしかありません。
それより長い、複雑な処理をするにはリセットベクタにはジャンプ命令のみ置いて
プログラム本体の先頭(ふつうはROMの先頭番地)へ制御を移すわけですが、
ここではROMに書くデータが一目で眺められるようにROMの最後の256バイトに収まるよう飛び先を$FFF00番地としました


イメージ 1
 
 
アセンブラではこう記述しました。
リセットベクタのオフセットFFF0番地からオフセットFF00番地へのジャンプ。
相対ジャンプ命令(ディスプレートメント16ビット)が生成されて、
実際のコードは 「E9/0D/FF」 (FF0D=243バイト戻り)となりました。
 
イメージ 2
 
ところがこの単純なコードが全く動作しません。
 
おそらくmainじゃないアドレスに飛んで暴走してしてしまうのですがわけがわかりません。ROMに正しいアドレスが与えられてないのだと思いハードも確認しましたが問題なさそう。
これで1日悩みました。
ま、わかってしまえば当たり前なんですがセグメントの呪いですね
 
セグメントがあることはわかっていますがリセット時のアドレス$FFFF0というと無意識に
 コードセグメント       CS:F000
 インストラクションポインタ  IP:FFF0
物理アドレスFFFF0が生成されると思い込んでました。
 
これであれば上のコードは正しくジャンプできますが、実際リセット時のレジスタの初期値はマニュアルに明記されていて
 コードセグメント       CS:FFFF
 インストラクションポインタ  IP:0000
が正解です。
この状態で3バイトのコードをフェッチしてから相対ジャンプFF0Dを実行してしまうと
 CS:FFFF
 IP: FF10(0003+FF0D)
-----------
   10FF00
・・・とぐるっと一周回ってSRAMのアドレスにジャンプすることになります 
 
これを防ぐにはどんなに至近距離であろうがFARジャンプ(セグメント間ジャンプ)を使ってコードセグメントCSとインストラクションポインタIPを同時にセットしなければならない、ということです。
 
 
イメージ 3