PDP-11のSXT命令を 8086のアセンブリ言語に変換しようとしたメモ
作成中の、PDP-11アセンブリ -> 8086アセンブリ のトランスレーター(https://github.com/kusabanachi/p11trans)で、 SXT命令の変換部分を書いた
SXT命令とは
対応するような命令が8086にないけど、割とシンプルな命令なのですぐ実装できる気がして取りかかった
最初の実装 *1
mov dest, #0 ! オペランドのdestに0を入れておく jns 8f ! SFが立ってなければ、先の'8'ラベルへジャンプ not dest ! 飛ばされなければ(SFが立ってれば)destを反転 -> 0xffff 8: ! 分岐のためのラベル
あまりラベルを使いたくないけど、まぁしょうがないかと *2
実装後、試してみて問題が見つかる
- オペランドにデクリメントのメモリアドレスが指定された場合が問題に
- 8086ではそのようなオペランドの指定がないので、まずレジスタの値を減算してから演算をするように変換していた
- 例えば
sxt -(r3)
なら *3
sub si, 2 ! ここの減算でフラグが上書きされる... mov (si), #0 jns 8f ! ここの分岐はsub命令の結果次第 not (si) 8:
- 呼び出し時点のフラグの状態で結果の値が決まる命令なのに、おかしなことに...
考えた代わりの案
- フラグは元の値に戻そう案
movb tmp, ah ! tmpという名の領域にahの値を退避 lahf ! フラグがahにロードされる命令 sub si, 2 ! フラグが上書きされるが sahf ! 元のフラグの状態に戻す movb ah, tmp ! ahの値を復元 mov (si), #0 jns 8f not (si) 8:
- ジャンプ後にデクリメントしよう案
js 8f ! SF立っていたら8までジャンプ ! SF立っていない時のみ来る sub si, 2 mov (si), #0 jmp 9f ! 9までジャンプ 8: ! SF立っている時のみ来る sub si, 2 mov (si), #0xff 9:
- 分岐しなければいいじゃん案
movb tmp, ah ! tmpという名の領域にahの値を退避 lahf ! フラグがahにロードされる命令 rol ax, #1 ! SFのbitが0bit目(一番右の位置に来る) and ax, #1 ! SFのbit以外クリア neg ax ! 2の補数をとる 1 -> 0xffff. 0 -> 0 sub si, 2 mov (si), ax movb ah, tmp ! ahの値を復元
結局は
- インクリメント・デクリメントはlea命令を使うことにした
- lea命令はメモリのアドレスをレジスタにロードする
- lea命令はフラグの変更が起こらない
lea si, -2(si) ! ([si - 2]が指すメモリ、のアドレス) = si - 2 が、siに入る mov (si), #0 jns 8f not (si) 8:
mov bx, ax ! メモリ参照ができないのでbxにコピー lea ax, -2(bx) ! ([bx - 2]が指すメモリ、のアドレス) = bx - 2 が、axに入る mov bx, ax mov (bx), #0 jns 8f not (bx) 8: