MIX (プログラミング)

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

MIX とは、ドナルド・クヌースが著書 The Art of Computer Programming (TAOCP) で使った仮想計算機である。MIX のモデル番号は 1009 であり、これは当時著者が重要と考えた各種商用コンピュータのモデル番号や名称にある番号を組み合わせて得られた数字である。また、MIX をローマ数字で解釈すると 1009 になる。

1960年代に生まれた MIX は、今後の TAOCP の版では MMIX という新たな(仮想の)コンピュータアーキテクチャで置換される予定である。MIX と MMIX のソフトウェア実装(MIXware および MMIXware)はクヌースが開発しており、自由に利用可能となっている。

クヌースの MIX/MMIX エミュレータからの派生版も存在する。GNU MDK がその一例で、フリーソフトウェアとして幅広いプラットフォーム上で動作する。

アーキテクチャ[編集]

MIX は二進法十進法のハイブリッド型コンピュータである。二進法でプログラムする場合、各バイトは6ビットで構成される(値は 0 から 63 まで)。十進法では、1バイトは2桁の十進数字で構成される(値は 0 から 99 まで)。5バイトと符号で1ワードが構成される。MIX 用プログラムの多くは二進法でも十進法でも動作する(1バイトに63より大きい値を格納しようとしない限り)。

1ワードで表せる範囲は、二進モードでは −1,073,741,823 から 1,073,741,823 まで(これらの値を含む)、十進モードでは −9,999,999,999 から 9,999,999,999 まで(これらの値を含む)である。符号-仮数表現であるため、MIX では “−0” と “+0” が表現上区別される。これは、現代のコンピュータの多くが採用している2の補数表現とは大きく異なる点であり、後者ではゼロの表現は一つである。また、後者では負の数値のほうが一個だけ正の数値よりも多く表現できる。

レジスタ[編集]

MIX ではレジスタは9本存在する。

  • rA: アキュムレータ(1ワード、すなわち5バイトと符号)
  • rX: 拡張レジスタ(1ワード)
  • rI1, rI2, rI3, rI4, rI5, rI6: インデックスレジスタ(2バイトと符号)
  • rJ: ジャンプアドレスレジスタ(2バイト。常に正なので符号なし)

バイトは最低でも6ビットで構成される。命令ではバイト単位にレジスタ上の操作位置を指定でき、(first:last) の形式で表される(命令の修飾部)。0番目のフィールドは1ビットの符号を指す。

MIX では、直前の操作によってオーバフローが発生したかどうかを記録するフィールドと、比較結果を3種類の値(大きい、等しい、小さい)で示すフィールドも持っている。以下の図では、各レジスタをフィールドに分割して表示している。

± A1 A2 A3 A4 A5
± X1 X2 X3 X4 X5
+ J4 J5
OV?
<=>?
± I1.4 I1.5
± I2.4 I2.5
± I3.4 I3.5
± I4.4 I4.5
± I5.4 I5.5
± I6.4 I6.5

メモリと入出力[編集]

MIXマシンには、4000ワードのストレージ(メモリ)があり、アドレスは 0 から 3999 までである。以下のような各種入出力機器も含まれる。

  • 磁気テープ装置(デバイス番号 0 から 7)
  • 磁気ディスクまたは磁気ドラム装置(デバイス番号 8 から 15)
  • カードリーダ(デバイス番号 16)
  • カードパンチ(デバイス番号 17)
  • ラインプリンタ(デバイス番号 18)
  • タイプライタ端末(デバイス番号 19)
  • 紙テープ装置(デバイス番号 20)

命令[編集]

各命令はメモリ上の1ワードに格納され、4つの部分から構成される。メモリアドレス部(2バイトと符号ビット)、インデックス指定部(1バイト、rIx レジスタの番号を指定)、修飾部(1バイト)、命令コード(1バイト)である。修飾部はアドレス指定されたワード内のフィールド位置の指定に使われる。全ての命令コードにはニーモニックが対応している。

MIX では自己書き換えコードをよく使う。特にサブルーチンからの自動復帰機能(リターンスタック)が命令セット上考慮されていないので、その場合も自己書き換えコードを使う。自己書き換えの際には、命令の中の修飾部を駆使して、命令ワード内の特定の部分だけを書き換える(例えば、アドレス部だけを書き換えるなどする)。

MIXプログラムを書く場合、MIXAL というアセンブリ言語を使う。MIXAL のコード例は、Hello worldプログラムの一覧#MIXALにある。

LDA ADDR,i (0:5) rA := memory[ADDR + rIi];
LDX ADDR,i (0:5) rX := memory[ADDR + rIi];
LD? ADDR,i (0:5) rI? := memory[ADDR + rIi];
LDAN ADDR,i (0:5) rA := - memory[ADDR + rIi];
LDXN ADDR,i (0:5) rX := - memory[ADDR + rIi];
LD?N ADDR,i (0:5) rI? := - memory[ADDR + rIi];
STA ADDR,i (0:5) memory[ADDR + rIi] := rA;
STX ADDR,i (0:5) memory[ADDR + rIi] := rX;
ST? ADDR,i (0:5) memory[ADDR + rIi] := rI?;
STJ ADDR,i (0:5) memory[ADDR + rIi] := rJ;
STZ ADDR,i (0:5) memory[ADDR + rIi] := 0;
ADD ADDR,i (0:5) rA := rA + memory[ADDR + rIi];
SUB ADDR,i (0:5) rA := rA - memory[ADDR + rIi];
MUL ADDR,i (0:5) (rA,rX) := rA * memory[ADDR + rIi];
DIV ADDR,i (0:5) rA := int( (rA,rX) / memory[ADDR + rIi]);
rX := (rA,rX) mod memory[ADDR + rIi];
ENTA ADDR,i rA := ADDR + rIi;
ENTX ADDR,i rX := ADDR + rIi;
ENT? ADDR,i rI? := ADDR + rIi;
ENNA ADDR,i rA := - ADDR - rIi;
ENNX ADDR,i rX := - ADDR - rIi;
ENN? ADDR,i rI? := - ADDR - rIi;
INCA ADDR,i rA := rA + ADDR + rIi;
INCX ADDR,i rX := rX + ADDR + rIi;
INC? ADDR,i rI? := ADDR + rIi;
DECA ADDR,i rA := rA - ADDR - rIi;
DECX ADDR,i rX := rX -ADDR - rIi;
DEC? ADDR,i rI? := rI? - ADDR - rIi;
CMPA ADDR,i (0:5) rA を memory[ADDR + rIi] と比較;
CMPX ADDR,i (0:5) rX を memory[ADDR + rIi] と比較;
CMP? ADDR,i (0:5) rI? を memory[rIi + ADDR] と比較;
JMP ADDR,i goto ADDR + rIi;
JSJ ADDR,i rJ := 次の命令のアドレス;
goto ADDR + rIi;
JOV ADDR,i if (overflow) then
   overflow := false; goto ADDR + rIi;
JNOV ADDR,i if (no overflow) then
   goto ADDR + rIi;
else overflow := false;
JL, JE, JG ADDR,i
JGE, JNE, JLE ADDR,i
if (less, equal, greater) then goto ADDR + rIi;
if (no less, unequal, no greater) then goto ADDR + rIi;
JAN, JAZ, JAP ADDR,i
JANN, JANZ, JANP ADDR,i
if (a<0 / a==0 / a>0) then goto ADDR + rIi;
if (a>=0 / a!=0 / a<=0) then goto ADDR + rIi;
JXN, JXZ, JXP ADDR,i
JXNN, JXNZ, JXNP ADDR,i
if (x<0 / x==0 / x>0) then goto ADDR + rIi;
if (x>=0 / x!=0 / x<=0) then goto ADDR + rIi;
J?N, J?Z, J?P ADDR,i
J?NN, J?NZ, J?NP ADDR,i
if (rI?<0 / rI?==0 / rI?>0) then goto ADDR + rIi;
if (rI?>=0 / rI?!=0 / rI?<=0) then goto ADDR + rIi;
MOVE ADDR,i(F) for (n=1; n<=F; n++, rI1++)
   memory[ADDR + rIi + n] := memory[rI1];
SLA, SRA ADDR,i
SLAX, SRAX ADDR,i
SLC, SRC ADDR,i
a を左(L)/右(R)に ADDR+rIi バイトだけシフト
ax を左(L)/右(R)に ADDR+rIi バイトだけシフト
ax を左(L)/右(R)に ADDR+rIi バイトだけローテート
NOP 何もしない;
HLT 実行停止;
IN ADDR,i(F) 入力装置 F から1ブロック読み取り
memory[ADDR + rIi] を始点として格納;
OUT ADDR,i(F) 出力装置 F に memory[ADDR + rIi]
を始点として1ブロックを書き込み;
IOC ADDR,i(F) 入出力装置 F に制御命令を送る;
JRED ADDR,i(F) if (入出力装置 F はレディ状態) then goto ADDR + rIi;
JBUS ADDR,i(F) if (入出力装置 F はビジー状態) then goto ADDR + rIi;
NUM rA := (rA,rX) にある文字列を数値化した値;
CHAR (rA,rX) := rA の内容を数値として文字列(文字コード)で表したもの;

なお、シフト命令を見てもわかるとおり、MIXではバイトの内部構造が影響するような命令を持たない(例えばビット演算)。このため、二進法でも十進法でも同じプログラムが動作するのである。

外部リンク[編集]