コンピュータアーキテクチャ
コンピュータシステムの理論と実践の学習内容のダンプ。
プログラム内蔵方式
コンピュータがプログラムのコードをデータのようにメモリに格納して操作される方式。同じハードウェアでも別のプログラムを読み込むと全くことなる動作をすることが可能
ノイマン型アーキテクチャ
抽象化された論理的なコンピュータをuniversal Turing machineと呼び、実用的なコンピュータアーキテクチャは von Neumann machine とよばれる。
ノイマン型アーキテクチャの登場人物は4つ
- CPU: ALU、レジスタ、制御ユニットからなり、計算をおこなう
- メモリ: データと命令を格納し、CPUからRead / Writeされる
- 入力デバイス: データのinput
- 出力デバイス: データのoutput
ポイントは、メモリに命令が格納されていること
メモリ
データと命令は別のメモリ空間に保存される。両者ともにバイナリで表現され、RAMに保存される。RAMはレジスタの集合である。
例えば、「メモリアドレスjのデータをフェッチせよ」という命令がある時、以下のようにレジスタは使われる
- CPUからRAMのaddress入力へ
j
が送られる。 - RAMのタイレクトアクセス回路が対象のレジスタを選ぶ
- RAM[j]のデータをCPUに送る
HDLで記述すると以下のようになる
CHIP Memory {
IN in[16], load, address[15];
OUT out[16];
PARTS:
DMux(in=load, sel=address[14], a=ramload, b=screenload);
RAM16K(in=in, load=ramload, address=address[0..13], out=ramOut);
Screen(in=in, load=screenload, address=address[0..12], out=screenOut);
Keyboard(out=KbdOut);
Mux4Way16(a=ramOut, b=ramOut, c=screenOut, d=KbdOut, sel=address[13..14], out=out);
}
address[14]でロードしてくる情報の先を決定し、inで入力データを決定する
データメモリ
データを格納するメモリ。
一般的にRAMと呼ばれる
命令メモリ
コンピュータが命令を実行するたびに、CPUが命令メモリから命令をFetchし、デコードする。
一般的にROMと呼ばれる
CPU
中央演算装置。メモリから命令やデータをロードしたりwriteしたりする
HDLで記述すると以下のようになる
CHIP CPU {
IN inM[16], // M value input (M = contents of RAM[A])
instruction[16], // Instruction for execution
reset; // Signals whether to re-start the current
// program (reset==1) or continue executing
// the current program (reset==0).
OUT outM[16], // M value output
writeM, // Write to M?
addressM[15], // Address in data memory (of M)
pc[15]; // address of next instruction
PARTS:
And(a=instruction[15], b=true, out=Corder);
Not(in=Corder, out=Aorder);
/*
Destination
*/
// saveToA
And(a=instruction[5], b=instruction[15], out=saveToA);
// saveToD
And(a=instruction[4], b=instruction[15], out=saveToD);
// saveToM
And(a=instruction[3], b=instruction[15], out=writeM); // write to M
/*
Jump
*/
Not(in=zr, out=notZr);
Not(in=ng, out=notNg);
And(a=notZr, b=notNg, out=GT); // out > 0
And(a=notZr, b=ng, out=LT); // out < 0
And(a=zr, b=true, out=EQ); // out == 0
Not(in=zr,out=NE); // out != 0
Or(a=GT, b=EQ, out=GE); // out >= 0
Or(a=LT, b=EQ, out=LE); // out =< 0
And(a=instruction[0], b=true, out=J3);
And(a=instruction[1], b=true, out=J2);
And(a=instruction[2], b=true, out=J1);
Not(in=J3, out=notJ3);
Not(in=J2, out=notJ2);
Not(in=J1, out=notJ1);
// No jump 000
And(a=notJ3, b=notJ2, out=maybeNojump);
And(a=maybeNojump, b=notJ1, out=NoJump1);
And(a=NoJump1, b=instruction[15], out=NoJump);
// JGT 001
And(a=J3, b=notJ2, out=maybeJGT);
And(a=maybeJGT, b=notJ1, out=JGT);
And(a=JGT, b=GT, out=jump1);
// JEQ 010
And(a=notJ3, b=J2, out=maybeJEQ);
And(a=maybeJEQ, b=notJ1, out=JEQ);
And(a=JEQ, b=EQ, out=jump2);
// JGE 011
And(a=J3, b=J2, out=maybeJGE);
And(a=maybeJGE, b=notJ1, out=JGE);
And(a=JGE, b=GE, out=jump3);
// JLT 100
And(a=notJ3, b=notJ2, out=maybeJLT);
And(a=maybeJLT, b=J1, out=JLT);
And(a=JLT, b=LT, out=jump4);
// JNE 101
And(a=J3, b=notJ2, out=maybeJNE);
And(a=maybeJNE, b=J1, out=JNE);
And(a=JNE, b=NE, out=jump5);
// JLE 110
And(a=notJ3, b=J2, out=maybeJLE);
And(a=maybeJLE, b=J1, out=JLE);
And(a=JLE, b=LE, out=jump6);
// JMP 111
And(a=J3, b=J2, out=maybeJMP);
And(a=maybeJMP, b=J1, out=jump7);
Or8Way(
in[0]=jump1,
in[1]=jump2,
in[2]=jump3,
in[3]=jump4,
in[4]=jump5,
in[5]=jump6,
in[6]=jump7,
in[7]=false,
out=mayBejump
);
And(a=instruction[15], b=mayBejump, out=jump);
Not(in=jump, out=inc);
PC(in=ARegisterOut, load=jump, inc=inc, reset=reset, out[0..14]=pc);
/*
Data Flow
*/
Mux16(a=instruction, b=aluOut, sel=instruction[15], out=ToARegister);
Not(in=instruction[15], out=noti15);
Or(a=noti15, b=saveToA, out=loadA);
ARegister(in=ToARegister, load=loadA, out=ARegisterOut, out[0..14]=addressM);
Mux16(a=ARegisterOut, b=inM, sel=instruction[12], out=AorMOut);
ALU(x=DRegisterOut, y=AorMOut, zx=instruction[11], nx=instruction[10], zy=instruction[9], ny=instruction[8], f=instruction[7], no=instruction[6], out=outM, out=aluOut, zr=zr, ng=ng);
DRegister(in=aluOut, load=saveToD, out=DRegisterOut);
}
ALU
算術演算と論理演算を行う論理回路。
レジスタ
CPUの近くにある一時記憶装置。高速に読み書きが可能。各レジスタはそのサイズに合わせて1ワードを保存する。
注目ポイント2つ
- CPU回路の中に存在するためアクセスが爆速
- レジスタは数えるほどしか存在しない。そのため、機械語でレジスタを指定するために必要なビットが少なくすみ、短くなる
データレジスタ
簡易的なメモリのように扱われる。計算結果の一時保存場所として使われがち
アドレスレジスタ
データの読み書きのため、メモリのどのワードにアクセスすべきかを保存するレジスタ。
プログラムカウンタレジスタ
次にフェッチすべき命令アドレスを格納するレジスタ。PCと呼ばれる。PCにはアドレスが格納されており、このアドレスは命令メモリからフェッチを行うアドレス。
- 現在の命令に
goto
がなければ、プログラムはPCをインクリメントして命令をロードする -
goto n
があれば、PCにn
を書き込みその値を次に読む。
入出力
様々な入出力デバイスの中で一番単純なのは、メモリマップドI/O。I/Oデバイスのためのメモリ領域を割り当てて、CPUからは通常のメモリ領域かのように見せることができる。
こうすることで、CPU・プラットフォーム全体の設計はI/Oデバイスとは分離できる。通常、デバイスへのメモリマップの割当とその先頭メモリの保存はOSが行う。
Hackデバイスの動き
HackデバイスをHDLで記述すると以下のようになる。
CHIP Computer {
IN reset;
PARTS:
ROM32K(address=pcOut, out=romOut);
CPU(inM=Mout, instruction=romOut, reset=reset, outM=Mvalue, writeM=writeM, addressM=addressM, pc=pcOut);
Memory(in=Mvalue, load=writeM, address=addressM, out=Mout);
}
電源を入れると、ROMに書き込まれた制御プログラムが
クロックサイクル中の動きは以下2つの構成要素からなる
-
実行
現在命令を構成するビットを元に、ALUとレジスタを使用して計算を実行したり値をレジスタに保存したりする -
フェッチ
次にどの命令をフェッチするかをALUの出力と現在命令のジャンプbitから行う。
ジャンプを行うなら、PCにAレジスタの値をセットする
しないならPCの値をインクリメントするのみ
メモリ空間を2つに分けているのはHackの特徴でかなり単純化している。
CPUのパフォーマンス構造のため2つの道がとられた
- CISC (Complex Instruction Set Computing): 複雑な命令セットを提供しパフォーマンスを上げようとする試み
- RISC(Reduced Instruction Set Computing): 単純な命令セットでできるかぎり高速なハードウェア実装を行う試み。
制御ユニット
次にどの命令をフェッチしてデコードし実行することを担う。ループ、レジスタ・メモリのRead / Write、次の命令へのジャンプなど
Discussion