2021-03-03 23:58 — asano
カテゴリー:
SH7045ボードへのUniversal Monitorの移植に着手したのですが、その前にMC68000系で動くようになっていますのでそのあたりの話を何回かに分けて書こうと思います。
MC68000自体は30年ほど前にいじっていて(だから未経験のプロセッサを優先して後回しになっていました)サクサク書いていたのですが、これまで書いたことがなかったのがプロセッサの識別です。
当時からMC68010は載せていましたがモニタは専用にアセンブルしていました。
ですからMPUを載せかえる時はROMも一緒に交換です。
今回は基本部分がすんなり動作したので識別ルーチンに挑戦することにします。
識別の原理はもちろんプロセッサによる挙動の違いを検出するわけですが、これにはいくつかのパターンがあります。
- 識別のための命令・機能
PentiumのCPUID
のような命令があれば簡単です。あるいはリセット直後に特定のレジスタに識別用の情報が入っている場合もあります。 - 命令の動作の違い
命令互換のプロセッサでも通常問題にならないような動作の違いがあることがあります。あまり使われない(命令の目的と関係ない)フラグの変化であったり、無意味な動作(8ビットレジスタを8ビット以上シフトするとか)などです。設計上の都合などでこれらの違いが生じても普通問題にならないのでそのままになっていたりします。あるいはあるプロセッサを元に別メーカが異なる拡張を行なった場合などはまったく違った動作をすることもあります。 - 片方にしかない命令
8080に対してZ80で追加された命令などがこれに当たります。片方のプロセッサでは未定義な命令を実行することになるので副作用に注意が必要です。たとえば6800のHCF
のようにソフトウェアで回復できないような命令は使用できませんし、互換プロセッサで何が起きるかわからないリスクもあります。
まず1.に相当する命令等はありません。
2.だといくつか思い当たるものがあります。まずMOVE SR,<ea>
がMC68010では特権命令になっているのでユーザモードで実行してみる方法が考えられます。例外を発生させた時にスタックに積まれる量が異なるのでSSP
の変化を見る方法もあります。
数は少ないですが追加された命令もあるので3.も使えます。幸い未定義命令を実行すると不当命令例外になるので副作用の心配はあまりありません。
いずれにしても例外処理が絡むので6800やZ80などのようなシンプルな分岐ではすみません。今回は68010にしかないMOVEC VBR,D0
命令を実行して不当命令例外が発生するかチェックすることにしました。
まずはメインルーチンを抜き出してみます。
140/ 30014E : =>TRUE IF USE_IDENT
141/ 30014E :
142/ 30014E : 41F9 0030 0C17 LEA IM000,A0
143/ 300154 : SAVE
144/ 300154 : CPU 68010
145/ 300154 : 4E7A 0801 ID0: MOVEC VBR,D0 ; Try MC68010 instruction
146/ 300158 : ALL RESTORE
147/ 300158 : 41F9 0030 0C21 LEA IM010,A0
148/ 30015E : 13FC 0001 0009 MOVE.B #1,PSPEC
300164 : FF2C
149/ 300166 : ID1:
150/ 300166 : 6100 05EC BSR STROUT
151/ 30016A :
152/ 30016A : [140] ENDIF
145行で問題の命令を実行します。68010であれば正常に実行されD0
にはVBR
の初期値である0が入ります。
続いて147,148行で文字列"MC68010",CR,LF,0
のアドレスとMC68010を表す1を設定します。
150行で文字列を表示して終了です。
68000/68008の場合は145行で不当命令例外が発生して例外ハンドラに処理が移ります。このハンドラは次のようになっています。
992/ 3008BC : ;; 04 Illegal Instruction
993/ 3008BC : ILLINS_H:
994/ 3008BC : ;; Check IDENT
995/ 3008BC : =>TRUE IF USE_IDENT
996/ 3008BC :
997/ 3008BC : 0CAF 0030 0154 CMP.L #ID0,2(A7) ; Check PC on system stack
3008C2 : 0002
998/ 3008C4 : 660C BNE ILLINS0 ; PC is not IDENT routine
999/ 3008C6 :
1000/ 3008C6 : 5C4F ADDQ #6,A7 ; Drop stack frame
1001/ 3008C8 : 4239 0009 FF2C CLR.B PSPEC
1002/ 3008CE : 6000 F896 BRA ID1
1003/ 3008D2 :
1004/ 3008D2 : [995] ENDIF
1005/ 3008D2 :
1006/ 3008D2 : ILLINS0:
1007/ 3008D2 : =>TRUE IF USE_REGCMD
1008/ 3008D2 : 48F9 7FFF 0009 MOVEM.L D0-D7/A0-A6,REGD0
3008D8 : FF38
1009/ 3008DA : =>FALSE ELSE
1010/ 3008DA : MOVEM.L D0-D3,REGD0
1011/ 3008DA : MOVEM.L A0-A3,REGA0
1012/ 3008DA : [1007] ENDIF
まず997行でスタックに積まれている戻りアドレスが判別ルーチン内のMOVEC VBR,D0
命令のアドレスであることを確認します。異なっていれば998行で通常の不当命令例外の処理に戻してやります。
1000行ではA7
(これは例外ハンドラ内では常にSSP
)に6を加えていますが、例外発生時にPC
とSR
が計6バイト分スタックに積まれているのでこれを取り除きます。
1001行では68000/68008を表す0を設定します。
1002行でメインルーチンに戻ります。かなり乱暴な戻り方ですが発生場所が特定されているので問題ありません。
次回はブレーク処理についてを予定しています。
コメントを追加