430 likes | 723 Views
マイクロプロセッサ. 第10回. Hardwar Description Language. 関根 優年. 単一サイクルの制御ユニットを加えたデータパス. 加算. M U X. 4. 0. RegDst. 制御. Branch. 加算. MemRead. 命令 [31:26]. 2 ビット 左に シフト. 1. MemtoReg. ALUOp. 命令 メモリ. 命令アドレス. MemWrite. PC. AND. ALUSrc. RegWrite. 命令 [25:21]. 読出 reg1. 読出 reg1.
E N D
マイクロプロセッサ 第10回 Hardwar Description Language 関根 優年
単一サイクルの制御ユニットを加えたデータパス単一サイクルの制御ユニットを加えたデータパス 加算 M U X 4 0 RegDst 制御 Branch 加算 MemRead 命令 [31:26] 2ビット 左に シフト 1 MemtoReg ALUOp 命令 メモリ 命令アドレス MemWrite PC AND ALUSrc RegWrite 命令 [25:21] 読出 reg1 読出 reg1 レジスタ ゼロ判定 命令 [20:16] 読出 reg2 命令[31:0] 1 ALU ALU結果 M U X M U X 読出 reg2 読出 データ データ メモリ M U X 書込 reg 0 アドレス 0 ALU操作 1 書込 データ 0 3 命令 [15:11] 1 書込 データ 符号 拡張 命令 [15:0] 32 16 ALU 制御 命令 [5:0]
マルチサイクル方式で実現した全データバスと必要な制御線 PCWriteCond PCWrite PCSource IorD ALUOp MemRead ALUSrcB 制御 MemWrite ALUSrcA MemtoReg RegWrite PC [31-28] RegDst IRWrite Op[5:0] 26 28 0 2ビット 左シフト M U X M U X 1 ジャンプ先 アドレス[31-0] 0 0 命令 レジスタ 命令 [31-26] M U X 2 メモリ アドレス PC 読出 レジスタ1 A 命令 [25-21] 読出 データ1 1 読出 レジスタ2 1 命令 [20-16] ゼロ 判定 0 命令 [15-11] M U X 書込 レジスタ 命令 [15-0] データ 0 読出 データ2 M U X ALU Out B ALU 結果6 書込 データ 1 1 4 2 書込み データ 0 レジスタ M U X 命令 [15-0] 3 ALU 符号 拡張 1 2ビット 左シフト 32 16 メモリ・ データ レジスタ 命令 [5-0] ALU 制御
命令実行過程のクロック・サイクルへの分割 各クロックサイクルにおける作業量のバランスをとり、クロックサイクル時間を最小にする 1クロックサイクルには、1) メモリアクセス、2)レジスタアクセス、3)ALU操作 のうち1つの操作しかしないものとして、データパスを設計する。 5段のステップ(制御信号については省略) 1.命令フェッチステップ IR = メモリ[PC]; PC=PC+4; (命令フェッチとPCの計算) 2.命令デコードとレジスタフェッチのステップ A=レジスタ[IR[25-21]]; B=レジスタ[IR[25-21]]; (rs,rtフィールドの読込み) ALUOut = PC+(符号拡張(IR[15-0] <<2)); (分岐先の計算) 3.実行、メモリアドレスの計算または分岐の完了ステップ ALUOut = A+符号拡張(IR[15-0]); (メモリ参照の場合) ALUOut = A 演算子 B; (R形式命令の場合) if(A==B) PC=Target; (分岐) PC=PC[31-28] || (IR[25-0]<<2); (ジャンプ) 4.メモリアクセス、またはR形式命令完了ステップ MDR = メモリ[ALUOut]; または メモリ[ALUOut]=B; (メモリ参照の場合) レジスタ[IR[15-11]]=ALUOut; (R形式命令の場合) 5.メモリ読出し完了ステップ レジスタ[IR[15-11]]=MDR; (ロード)
回路図から記述へ • ブロック図,論理回路図:作成が大変 • 回路の動作は明記されていない • 動作を読み解く必要がある. • 同時に多数のブロックの動作理解が必要 • ソフトの様に記述したい • 逐次的な動作順序の記述 • 並列的な動作の記述 • 階層的な記述 • データーの流れを記述
Hardware Description Language(HDL) • LSI設計を計算機で処理するために考案されてきた • 1960年頃,大型計算機の設計時に提案された.Design Description Language (DDL) ⇒ 当時は,計算機の能力が乏しく提案だけで終わってしまった. • 1980年代,LSI設計自動化ツールに使用され急速に発展 • 配置配線ツール,論理合成,RTLシミュレータ • ソフトからの高位合成,テスト生成 • 各企業毎に独自の言語, • 例)Hierarchical Hardware Design Language(H2DL) 東芝 • Verilog-HDL, VHDL: • 90年代,米国のEDAベンダーが市場を席捲.2つの言語が支配. 技術的理由より政治的,経済的に米国製言語が選択された.
モジュールの記述(Verilog) • 回路は入力出力があり,内部と外部との境界が必ずある. module LSI_A (in1, in2, in3, …, out1,out2,out3,…,); input in1,in2,in3,…, ; output out1,out2,out3,…,; 内部の回路構造の記述 endmodule
抽象レベルの異なる記述方法 module AND2 (in1, in2, out); input in1,in2; output out; wire in1, in2, out; //---------------------------------------------------// and u1 ( out, in1, in2 ); // 構造記述 //---------------------------------------------------// assign out = in1 & in2 ;//Register Transfer Level 記述 //---------------------------------------------------// reg out; always @(in1, in2) //Behavior (動作) 記述 out = in1 & in2 ; //---------------------------------------------------// endmodule;
initial , for, while, repeat(テスト・ベッド用) module initial_statement; integeri; initial begin i =0; #10 i =1; #10 i =0; end endmodule for( i=0; i<256; i =i+1;) m[i] = 4’h0; while (i<256)begin m[i] = 4’h0; End repeat (256)begin m[i] = 4’h0; i=i+1; end
forever, task 呼び出し,parameter foever initial begin CK =0; forever #(STEP/2) CK = ~CK; Wait(<式>) <ステートメント> <タスク名>; <タスク名> (<式>, <式>, ・・・); parameter STEP =20;
Case と fork modulecase_statement; integeri; initial i =0; always begin case (i) 0: i = i + 2; 1: i = i + 7; 2: i = i - 1; default: $stop; end endmodule module fork_join; event a, b; initial fork @a; @b; join endmodule
Function と task • functionには、戻り値があり、処理時間は0で、遅延#やイベント制御は書けない。 i= func(a);assign x = func(y) • taskはtask名で文として呼び出され、戻り値はない。 tsk( out, i1,i2); function func; input i; reg [7:0] rg; begin rg = i1 +1; func = rg; end endfunction task tsk; input i1, i2; output o1, o2; $display(“tsk, i=%0b,%0b”, i1,i2); #1 01 = i1 & i2 ; #1 02 = i1 | i2 ; endtask
加算器 module adder4( in1, in2, sum, zero); endmodule input [3:0] in1, in2; output [4:0] sum; output zero; reg [4:0] sum; assign zero = (sum == 0)? 1 : 0; initial sum = 0; always @(in1 or in2) sum = in1 + in2;
4bit fulladder 構造記述 module adder4( in1, in2, sum, zero); endmodule input [3:0] in1, in2; output [4:0] s; output zero; reg [4:0] s; fulladd u1 ( in1[0], in2[0], 1’b0, s[0], c0); fulladd u2 ( in1[1], in2[1], c0, s[1], c1); fulladd u3 ( in1[2], in2[2], c1, s[2], c2); fulladd u4 ( in1[3], in2[3], c2, s[3], s[4]); nor u5 ( zero, s[0], s[1], s[2], s[3], s[4] );
4bit fulladder 動作記述混在 module adder4( in1, in2, sum, zero); endmodule input [3:0] in1, in2; output [4:0] s; output zero; reg [4:0] s; fulladd u1 ( in1[0], in2[0], 1’b0, s[0], c0); fulladd u2 ( in1[1], in2[1], c0, s[1], c1); fulladd u3 ( in1[2], in2[2], c1, s[2], c2); fulladd u4 ( in1[3], in2[3], c2, s[3], s[4]); always @ s if( s = = 0 ) zero <= 1; else zero <= 0;
ミップス・プロセッサの記述例 module mips( input clk, reset, input [31:0] i, adr, output[31:0] o ); reg [31:0] PC, ALUout, mem[0:255]; reg [3:0] stateReg; wire[31:0] wPC, wInsAdr, wAccm, wa, wb, wb0; wire RegDst, Branch, MemRead, MemtoReg, MemWrite, ALUSrc, RegWrite; wire [1:0] ALUOp; wire wZeroFlg; // -- beqの分岐 -- always @( posedge clk) begin PC <= wZero? wNxtPC : wPC; end end
//--- 下位のモジュールの記述 (1) ---// //-- 命令メモリ -- mem instMem(.iAdr(wInsAdr), .oData(Inst)); //-- 命令アドレス -- assign wInsAdr = PC; //-- 命令コード -- assign wOpcode = Inst[31:26]; //-- RS,RT レジスタ 番号 -- assign rs = Inst[25:21]; assign rt =Inst[20:16]; //-- RDレジスタ 番号 -- assign rd= RegDst ? Inst[15:11] : Inst[20:16]; //-- レジスタファイル -- register Register0(.iRs(rs), .iRt(rt), .iRd(rd), .iData(wData), .oA(wa), .oB(wb0) , .iRegWrite(RegWrite) );
//--- 下位のモジュールの記述 (2) ---// //-- ALU 次命令アドレス計算 -- ALU Alu0(.iA(PC), .iB(32’b4), .iAluCntl(3’b010), .oAccm(wPC)); //-- ALU 分岐アドレス計算 -- ALU Alu1(.iA(wPC), iB(wAdrXpnd<<2’b10), .iAluCntl(3’b010), .oAccm( wNxtPC) ); //-- ALU 演算用 -- ALU Alu2(.iA(wa), .iB(wb), .oAcum(wAccm), .oZflg(wZeroFlg), .iAluCtl(wAluCtl) )
//--- 下位のモジュールの記述 (3) ---// //データメモリ mem DataMem ( .iAdr(AluOut), .iData(wb0), .oData(wDout), .iMemWrite(wMW), .iMemRead(wMR) ); // MUX assign wb = ALUSrc ? adrXpnd : wb0; //ALU操作 assign wAluCtl = aluCntrl(.ifncCode(Inst[5:0]), .iAluOp(AluOp) ); //符号拡張 assign wAdrXpnd = fugouKakucho( Inst[15:0]); //MUX assignwData = MemtoReg ? wAccm : wDout; //分岐制御 assign wZero = wBrnch & wZeroFlg ;
//--- 下位のモジュールの記述 (4) ---// //-- 主制御部 --// MainControl mCTL( .iInst(wOpcode), .oRegDst(RegDst), .oBranch(wBrnch), .oMemRead(MemRead), .oMemtoReg(MemtoReg), .oALUOp(ALUOp), .oMemWrite(MemWrite), .oALUSrc(ALUSrc), .oRegWrite(RegWrite) ); emdmodule
ALU制御ユニットIV ALU制御入力<0> = (ALUOp1)’ & 0 ALU制御入力<1> = (ALUOp1)’ & 1 ALU制御入力<2> = (ALUOp1)’ & ALUOp2 論理式を作る
ALU制御ユニットV ALU制御入力<0> = (ALUOp1) & {(F3)’F2(F1)’F0 + F3(F2)’F1(F0)’} ALU制御入力<1> = (ALUOp1) & { (F3)’(F2)’(F1)’(F0)’+(F3)’(F2)’F1(F0)’+F3(F2)’F1(F0)’} ALU制御入力<2> = (ALUOp1) & {(F3)’(F2)’F1(F0)’+F3(F2)’F1(F0)’} 論理式を作る
ALU制御 function [2:0] aluCntrl( input [5:0] F, input[1:2] ALUOp ); aluCntrl ={ //-- 2ビット目 -- AluOp[1]&( (!F[3])&(!F[2])&F[1]&(!F[0]) | ( F[3])&(!F[2])&F[1]&(!F[0]) ) | (!AluOp[1])&AluOp[2] , //-- 1ビット目 -- AluOp[1]&( (!F[3])&(!F[2])&F[1]&(!F[0]) | ( F[3])&(!F[2])&F[1]&(!F[0]) ) | (!AluOp[1]), //-- 0ビット目 – AluOp[1]&( (!F[3])&F[2])&(!F[1])&F[0] | ( F[3])&(!F[2])&F[1]&(!F[0]) ) }; endfunction
符号拡張 function [31:0] fugouKakucho( input [15:0 ] In ); // -- 算術左シフト -- // // -- 符号ビットで上位を埋めるシフト演算 --// fugouKakucho = In <<< 5’h10; endfunction
制御ユニットの仕上げ 制御関数の真理値表
主制御部の記述(1) module MainControl ( input [5:0] iInst, input oRegDst, output oBranch, oMemRead, oMemtoReg, oALUOp, oMemWrite, oALUSrc, oRegWrite ); // 制御ユニット真理値表の記述 parameter [5:0] Rformat = 6’b000000, lw = 6’b100011, sw = 6’b101011, beq = 6’b000100;
主制御部の記述(2) // 制御ユニット真理値表の記述 case(inst[31:26]) Rformat : begin RegDst = 1; ALUSrc = 0; MemtoReg = 0; RegWrite = 1; MemRead = 0; MemWrite = 0; Branch = 0; ALUOp1 = 1; ALUOp0 = 0; end lw : begin ……. end sw : begin ……. end beq : begin ……. end endcase endmodule
マルチ・サイクルの記述例 • 単一サイクルの記述は構造記述的 • 部品同士を接続する. • 部品の動作はカプセル化して見せない. • マルチサイクルの記述はRT風 • 状態を念頭において動作を主眼にして記述する • 慣れれば,ソフトと同じ様に記述できる. • 各状態で,どの様にデータの流れを制御するかを考えればよい.
命令実行過程のクロック・サイクルへの分割 各クロックサイクルにおける作業量のバランスをとり、クロックサイクル時間を最小にする 1クロックサイクルには、1) メモリアクセス、2)レジスタアクセス、3)ALU操作 のうち1つの操作しかしないものとして、データパスを設計する。 5段のステップ(制御信号については省略) 1.命令フェッチステップ IR = メモリ[PC]; PC=PC+4; (命令フェッチとPCの計算) 2.命令デコードとレジスタフェッチのステップ A=レジスタ[IR[25-21]]; B=レジスタ[IR[25-21]]; (rs,rtフィールドの読込み) ALUOut = PC+(符号拡張(IR[15-0] <<2)); (分岐先の計算) 3.実行、メモリアドレスの計算または分岐の完了ステップ ALUOut = A+符号拡張(IR[15-0]); (メモリ参照の場合) ALUOut = A 演算子 B; (R形式命令の場合) if(A==B) PC=Target; (分岐) PC=PC[31-28] || (IR[25-0]<<2); (ジャンプ) 4.メモリアクセス、またはR形式命令完了ステップ MDR = メモリ[ALUOut]; または メモリ[ALUOut]=B; (メモリ参照の場合) レジスタ[IR[15-11]]=ALUOut; (R形式命令の場合) 5.メモリ読出し完了ステップ レジスタ[IR[15-11]]=MDR; (ロード)
1.命令フェッチステップ // IR = メモリ[PC]; PC=PC+4; (命令フェッチとPCの計算) case(stateReg) fetch: begin IR < = mem[PC]; PC <= PC+ 32’h0004; stateReg <= decode; end ….. ….. …..
1.命令デコードとレジスタフェッチ A=レジスタ[IR[25-21]]; B=レジスタ[IR[25-21]]; (rs,rtフィールドの読込み) ALUOut = PC+(符号拡張(IR[15-0] <<2)); (分岐先の計算) case(stateReg) ….. decode: begin A <= RFILE[IR[25:21]]; B<=RFILE[IR[20:16]]; fugouKakuchou <= {IR[15],IR[15],…,IR[15:0]}; ALUOut <= PC + (fugouKakuchou<<2); stateReg <= execute; end …..
実行,メモリアドレス計算,分岐完了 ALUOut = A+符号拡張(IR[15-0]); (メモリ参照の場合) ALUOut = A 演算子 B; (R形式命令の場合) if(A==B) PC=Target; (分岐) PC=PC[31-28] || (IR[25-0]<<2); (ジャンプ) switch(stateReg)begin ….. execute: begin fugouKakuchou <= {IR[15],IR[15],…,IR[15:0]}; case(IR[31:26]) lwd: begin ALUOut <= A + (fugouKakuchou<<2); end add: begin ALUOut <= A + B; end and: begin ALUOut <= A & B; end beq: begin if(A==B) PC <= Target; end jmp: begin PC <= {PC[31:28], (IR[25:0] <<2)}; end end stateReg <= memAccess; end …..
メモリアクセス,R形式完了 MDR = メモリ[ALUOut]; または メモリ[ALUOut]=B; (メモリ参照の場合) レジスタ[IR[15-11]]=ALUOut; (R形式命令の場合) case(stateReg) memAccess: begin case(IR[31:26]) ldw:MDR <= mem[ALUOut]; stw: mem[ALUOut] <=B; Rtype: RFILE[IR[15:11]] <= ALUOut; endcase stateReg <= memComp; end …..
メモリ読み出し完了ステップ レジスタ[IR[15-11]]=MDR; (ロード) case(stateReg) ….. memComp: begin RFILE[IR[15:11]] <= MDR; stateReg <= fetch; end ….. …..
マルチサイクルからパイプライン動作へ • マルチサイクルでは,1命令の処理が終わるまで次の命令は実行できない. • 実行しているステージより前のステージは空回り状態 • 空いているステージで,次の命令の処理を行えないか? • パイプラインで次から次へと処理を受け渡す事を考える.
Pipelineの時の記述例I module pipeline; reg [15:0] MEM[0:31], IR_Queue[0:7],RFILE[0:31], ADDR,result, ir,pc, fptr,eptr; reg clock, reset, fetched, executed; reg mem_access,fetch_ready, exec_ready, write_ready; reg [3:0] opCode; event do_fetch, do_execute, do_write; `define BRA 4'b0001 `define LD 4'b0010 `define STR 4'b0011 `define NOP 4'b0000 initial begin clock = 1; reset=0; fetched=0; executed = 0; fetch_ready=1; exec_ready=1; write_ready=1; ADDR=0; forever begin #10 clock = ~clock; end end
Pipelineの時の記述例II initial #300 $stop; always @(posedge clock) begin $display("%d : 1stLoop",$time); if(!reset)begin end else begin ->do_fetch; ->do_execute; ->do_write; end end always @(negedge clock) begin $display("%d : 2ndLoop", $time); end
Pipelineの時の記述例III /* task */ task fetch; begin if(fetch_ready)begin fetch_ready = 0; IR_Queue[fptr] = MEM[pc]; #2 $display("%d : fetch",$time); fetched = 1; end end endtask
Pipelineの時の記述例IV task execute; begin if(fetched)begin if(!mem_access) ir = IR_Queue[eptr]; exec_ready = 0; case(opCode) `NOP : $display("Nop"); `BRA : $display("BRA"); `LD : $display("LD "); `STR : $display("STR"); default : $display ("%d ---- WrongCode ----", $time); endcase #4 $display("%d : execute",$time); fetched = 0; fetch_ready =1; executed = 1; endend endtask
Pipelineの時の記述例V task write_back; begin if(executed)begin executed = 0; #2 RFILE[ADDR] = result; #4 $display("%d : write_back", $time) ; end exec_ready = 1; end endtask
制御信号の生成 /* fetch */ always @(do_fetch) begin: fetch_block #2 fetch; end /*execute */ always @(do_execute) begin : execute_block #2 execute; end /* write */ always @(do_write) begin : write_block #2 write_back; end endmodule
中間 レポート 符号なし数の乗算器(図8) をverilog HDL で 記述 せよ.