先日、PDP-11から8086へのトランスレータを試作しました。
簡単なプログラムを変換して大まかなABIが見えてきたので、仮にまとめます。詳細についてはV6移植ハッカソンで作業しながら決めていこうと思います。
ABI
今回提示するのは標準的な8086のABIとは異なりますが、当面は変換の都合を優先します。標準的なABIへの対応は、移植が完了した後の課題とします。
以下、8086のアセンブリはIntel記法(NASM)で示します。
システムコール
PDP-11に割り込みベクタを合わせるため、int 7をシステムコールに使用します。これは実機では予約されていて勝手に使えない割り込み番号ですが、仮です。
カーネルは直接PC/ATには移植しないで、PDP-11のCPUだけを8086に置き換えたような仮想マシン(仮称キメラ)を経由する予定です。そのときまでの仮です。移植の作業フローについては次の記事を参照してください。
システムコール番号はint 7に即値を後置します。引数はUNIX V6と同様に後置します。
PDP-11 | 8086 |
---|---|
mov $1, r0 sys 4 0 6 |
mov ax, 1 int 7 db 4 dw 0, 6 |
これは標準的な8086のABIとは異なりますが、前述の通り移植完了まで棚上げします。
レジスタ
基本的にPDP-11と8086のレジスタは1対1で変換します。
PDP-11 | 8086 |
---|---|
R0 | AX |
R1 | DX |
R2 | CX |
R3 | SI |
R4 | DI |
R5 | BP |
R6(SP) | SP |
R7(PC) | (IP) |
8086ではPCが汎用レジスタではないため単純に変換できません。PCをレジスタとして扱っている箇所は少数ですが存在するため、個別に対応を検討します。
mov
PDP-11は命令の直交性が高く、すべてのレジスタが同じようにアドレス指定に使用できます。
8086はアドレス指定に使用できるレジスタが限られています。
- [BX+SI+d], [BX+DI+d], [BP+SI+d], [BP+DI+d], [SI+d], [DI+d], [BP+d], [BX+d]
(dはディスプレースメント)
PDP-11ではアドレス指定に1つのレジスタしか使いません。今回は機械的に変換するため[BX+SI+d]のような組み合わせは使いません。
8086への変換で対応するレジスタがアドレッシングに使えない場合、一時レジスタとしたBXで対応します。
PDP-11 | 8086 |
---|---|
mov (r1), r0 | mov bx, dx mov ax, [bx] |
PDP-11ではソースとデスティネーションが同じ自由度で指定できるため、メモリ間の直接movも可能です。8086では不可能です。アドレス指定に使われているレジスタのうち変換が必要なものが片方だけなら一時レジスタBXで、両方ならスタックを使って対応します。
PDP-11 | 8086 |
---|---|
mov (r1), 4(r5) | mov bx, dx mov bx, [bx] mov [bp+4], bx |
mov (r1), (r0) | mov bx, dx push [bx] mov bx, ax pop [bx] |
V6のコンパイラは関数呼び出しでの引数用のスタックとしてあらかじめ2バイトを確保しているため、デスティネーションに(SP)が多用されます。当面は効率に目をつむり、SPを巻き戻してのpushで対応します。
PDP-11 | 8086 |
---|---|
mov (r1), (sp) | add sp, 2 mov bx, dx mov bx, [bx] push bx |
PDP-11はmov命令でスタックの操作が行えるためpush/pop命令がありません。スタック操作を認識してpush/pop命令に変換します。
PDP-11 | 8086 |
---|---|
mov r0, -(sp) | push ax |
mov (sp)+, r0 | pop ax |
mov (r0), -(sp) | mov bx, ax push [bx] |