PICO のパイプライン化
慶應義塾大学 理工学部天野
PICO の構成(前期の図を若干変更)
ALUir
InstructionMemory
DataMemory
we_ddataout
dadr
idata
iadr
pc
MUX MUX
MU
X
MU
X
MUX
ddatain
dest
src
adrA
adrB
regbrega
Expander ‘2’
op
op2
opop2
110001
regc
regfile
com
aluoutoutc
aluainalubin
パイプライン処理の設計• 大きな処理を一定の同じ大きさの小さな段階
(ステージ)に分解• それぞれのステージにそれぞれの処理装置を設
ける• 順にデータを流してやり、自分の処理が終わっ
たらすぐ次のステージに渡す• 流れ作業と基本は同じ• ステージ数を S とすると、理想の場合は性能は
S 倍– ステージの処理量が均等でないと、最も重いものに
律速される– ステージ間の受け渡しで大概ロスがある
パイプライン処理組合せ回路
ステージ1
ステージ2
ステージ3
ステージ4
ステージ1
ステージ2
ステージ3
ステージ4
ステージ1
ステージ2
ステージ3
ステージ4
ステージ1
ステージ2
ステージ3
ステージ4
ステージ1
ステージ2
ステージ3
ステージ4
時間
流れ作業(パイプライン処理 ) vs 多人数による並列処理
• S 人居れば最大 S 倍、これは同じ• 流れ作業は、各人がそのステージの処理だけで
きれば良い ⇔並列処理は、すべての人が全作業をする能力がなければならない
• 流れ作業は、各人がそのステージの処理をするのに必要な工具(リソース)を持てば良い⇔並列処理は、すべての人がすべての工具、場所を持つ必要がある
• このため、日常的な作業効率向上、工場のオートメーションなどもまずは流れ作業を導入する
状態遷移→ステージ
IF RF EX WB
結果を書き込む命令
それ以外:分岐、 ST など
ir に命令をフェッチ
レジスタ読み出しPC←PC+2
演算実行飛び先セットメモリからの読み書き込み
結果の格納
パイプライン化されていない設計が良くできていれば、それぞれの状態は遅延時間がほぼ均等に分割されているはず。このため、状態をそのままパイプラインのステージに割り当ててしまうのが基本的な設計手法
PICO のパイプライン構造
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
LDLI r1,#1
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
LDLI r2,#2 LDLI r1,#1
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
LDLI r3,#3 LDLI r2,#2 LDLI r1,#1
1
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
ADD r1,#2 LDLI r2,#2 LDLI r1,#1
21
LDLI r3,#3
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
ADD r2,r2 LDLI r3,#3 LDLI r2,#2
32
ADD r1,#2
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
ADD r2,r2 LDLI r3,#3
33
ADD r1,#2
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
ADD r2,r2
43
ADD r1,#2
InstructionMemory
+
DataMemory
AL
U
2
IF RF EX WB
IFPC
RFPC
IFIR RFIRwadr
rega
regb
regc
a
bc
Imm.
ADD r2,r2
4
今回の verilog 記述
ppico16_test.v テストベンチmemory.v メモリppico16.v CPU
if_stage.v 命令フェッチrf_stage.v レジスタフェッチex_stagef.v (ex_stage.v) 実行
パイプライン化はしてあるData Hazard, Control Hazard の除去はしてない→ これは来週
合成対象
if_stage.vmodule if_stage ( clk, reset_, idata, pcset, badr, ifpc, ifir);
`include "pico.h"
input clk, reset_;
input [DataBus-1:0] idata; // Data from I-Cache
input pcset; // Branch Taken Signal
input [AddrBus-1:0] badr; // Branch Addr
output [AddrBus-1:0] ifpc; // PC ( IFstage output )
output [DataBus-1:0] ifir; // IR ( IFstage output )
reg [AddrBus-1:0] pc;
reg [DataBus-1:0] ir;
assign ifpc = pc;
assign ifir = ir;
always @( posedge clk ) begin
if ( reset_ == Enable_ ) begin
pc <= NULL; ir <= NULL;
end else begin
ir <= idata;
if( pcset == Enable ) begin
pc <= badr; end
else begin
pc <= ifpc + 2; end
end
end
endmodule
pcset が1ならば分岐先アドレスのセット
そうでなければ+2(バイトアドレスなの
で)
pico.h コードの定義parameter Enable = 1'b1;parameter Disable = 1'b0;parameter Enable_ = 1'b0;parameter Disable_ = 1'b1;parameter AddrBus = 16;parameter DataBus = 16;parameter ComNum = 3;parameter RegNum = 3;parameter StateNum = 4;parameter MemSize = 32768;parameter Opcode = 5;parameter NULL = 16'h0000;
parameter ROP = 5'b00000;parameter LDLI = 5'b11100;parameter LDHI = 5'b11101;parameter BNEZ = 5'b01001;parameter BEQZ = 5'b01010;parameter JMP = 5'b01111;
parameter LD = 5'b01000;parameter ST = 5'b01001;parameter NOP = 5'b00000;
parameter THA = 3'b000;parameter THB = 3'b001;parameter ANDOP = 3'b010;parameter OROP = 3'b011;parameter SLOP = 3'b100;parameter SROP = 3'b101;parameter ADDOP = 3'b110;parameter SUBOP = 3'b111;
rf_stage.v 1 入出力と定義module rf_stage ( clk, reset_, ifir, ifpc, rwe, c, rwadr, rfpc, rfir, a, b, imm );`include "pico.h"input clk;input reset_;input [DataBus-1:0] ifir; // IR ( IF stage output )input [AddrBus-1:0] ifpc; // PC ( IF state output )input rwe; // Register Write Enable (c)input [DataBus-1:0] c; // Destination Datainput [RegNum-1:0] rwadr; // Destination Register Nooutput [DataBus-1:0] rfpc; // PC ( RFstage output )output [DataBus-1:0] rfir; // IR ( RFstage output )output [DataBus-1:0] a; // Source Data Aoutput [DataBus-1:0] b; // Source Data Boutput [DataBus-1:0] imm; // Immediate Data// Pipeline Registers
reg [DataBus-1:0] reg_a;reg [DataBus-1:0] reg_b;reg [DataBus-1:0] reg_im;reg [DataBus-1:0] reg_ir;reg [AddrBus-1:0] reg_pc;
// Outputs assign rfir = reg_ir;assign rfpc = reg_pc;assign a = reg_a;assign b = reg_b;assign imm = reg_im;
rf_stage.v 2 レジスタファイルとレジスタセット// Register File
wire [DataBus-1:0] dout1; // Register File Output for Source A (Rd)
wire [DataBus-1:0] dout2; // Register File Output for Source B (Rs)
regfile regfile ( // See regfile.v
.clk( clk ),
.adrA( ifir[10:8] ), // Read Address for Source A
.adrB( ifir[7:5] ), // Read Address for Source B
.adrC( rwadr ), // Write Address
.inc( c ), // Write Data
.outa( dout1 ),
.outb( dout2 ),
.rwe( rwe ) // Write Enable
);
always @( posedge clk ) begin
if ( reset_ == Enable_ ) begin
reg_ir <= NULL; reg_pc <= NULL;
reg_a <= NULL; reg_b <= NULL; end
else begin
reg_ir <= ifir; reg_pc <= ifpc;
reg_a <= dout1; reg_b <= dout2;
reg_im <= {{8{ifir[7]}},ifir[7:0]}; end
end
endmodule
module regfile (clk, adrA, adrB, adrC, inc, outa, outb, rwe);
`include "pico.h"
input clk;
input [RegNum-1:0] adrA, adrB, adrC;
input [DataBus-1:0] inc;
output [DataBus-1:0] outa, outb;
input rwe;
reg [DataBus-1:0] rfile [0:7];
assign outa = rfile[adrA];
assign outb = rfile[adrB];
always @(posedge clk)
if (rwe) rfile[adrC] <= inc;
endmodule
レジスタファイル本体
データ入力用 C ポートを独立
ex_stage.v 入出力
module ex_stage (clk, reset_, rfir, rfim, a, b, ddatain, rfpc, c, ddataout, address, rwadr, dmwe, rwe, pcset );
`include "pico.h"input clk;input reset_;input [DataBus-1:0] rfir; // IR ( RF stage output )input [DataBus-1:0] rfim; // Immediate Datainput [DataBus-1:0] a; // Source Data Ainput [DataBus-1:0] b; // Source Data Binput [DataBus-1:0] ddatain; // Read Data from D-Memoryinput [DataBus-1:0] rfpc; // PC (RF stage output )
output [DataBus-1:0] c; // Operation Resultoutput [DataBus-1:0] ddataout; // Write Data to D-Memoryoutput [AddrBus-1:0] address; // Address for D-Memory accessoutput [RegNum-1:0] rwadr; // Destination Register Nooutput dmwe; // D-Memory Write Enableoutput rwe; // Register Write Enableoutput pcset; // PC branch address set
ex_stage.v レジスタと簡単な論理部の接続// Pipeline Registers
reg [DataBus-1:0] reg_c;reg [RegNum-1:0] reg_rwadr;reg reg_rwe;reg pcsetr;
// Temporary Wirewire [DataBus-1:0] aluout; // ALU Outputwire [ComNum-1:0] aluope; // ALU Operationwire [DataBus-1:0] alu_ina, alu_inb;// Temporary Wire for ALU Source Bwire [DataBus-1:0] result; // Temporary Wire for resultswire rwen;wire pcsett;wire [Opcode-1:0] op, op2;wire [RegNum-1:0] dest;
// Output
assign rwadr = reg_rwadr;assign rwe = reg_rwe;assign c = reg_c;assign pcset = pcsetr;assign address = (op ==ROP) & (op2 == ST)? a : b;assign ddataout = b;assign op = rfir[15:11];assign dest = rfir[10:8];assign op2 = rfir[4:0];assign dmwe = ( op == ROP )& (op2 == ST) ? Enable : Disable;
ex_stage.v ALU
// ALU operationassign aluout = alu ( alu_ina, alu_inb, aluope );
// ALU ( ThrohghA, ThrohghB, And, Or, ShiftLeft, ShiftRight, Add, Sub )
function [DataBus-1:0] alu ;input [DataBus-1:0] a, b;input [ComNum-1:0] com;
case(com)THA: alu = a ;THB: alu = b ;ANDOP: alu = a & b;OROP: alu = a | b;SLOP: alu = a << b[3:0];SROP: alu = a >> b[3:0];ADDOP: alu = a + b;SUBOP: alu = a - b;endcase
endfunction
ex_stage.v ALU 周辺中間信号線
// Intermediate wires
assign alu_ina = (op == BNEZ) | (op == BEQZ) ? rfpc: a;
assign alu_inb = // Sign extended immediate
( rfir[15:13] == 3‘b001 ) | (op == BEQZ) | (op == BNEZ) | (op == LDLI) ? rfim:
(op == ROP) ? b:
(op == LDHI) ? {rfir[7:0],8'b0}: // LDHI
{8'b0,rfir[7:0]}; // Sign unextended immediate
assign aluope = // Braches
(op == BEQZ) | (op == BNEZ) ? ADDOP:
(op == LDLI) | (op == LDHI) ? THB: // LDLI, LDHI
(op == ROP) ? rfir[2:0]: rfir[13:11];
assign rwen = // Disable when Braches or ST
(op == BEQZ) | (op == BNEZ) |
((op == ROP) & (op2 == ST)) |
((op == ROP) & (op2 == NOP)) ? Disable : Enable;
assign result = // when LD datain
((op == ROP) & (op2 == LD)) ? ddatain : aluout;
assign pcsett = ( op == BEQZ )& (a==16'h0000) |
( op == BNEZ )& (a!=16'h0000) ;
やや見にくい
ex_stage f .v function の利用// Intermediate wires
assign alu_ina = (op == BNEZ) | (op == BEQZ) ? rfpc: a;
function [DataBus-1:0] aluinb;
input [Opcode-1:0] ope;
input [7:0] imm;
input [DataBus-1:0] rfim, b;
if(ope[4:2]==3'b001) aluinb = rfim;
else
case(ope)
BEQZ, BNEZ, LDLI : aluinb = rfim;
ROP: aluinb = b;
LDHI: aluinb = {imm,8'b0};
default: aluinb = {8'b0,imm};
endcase
endfunction
assign alu_inb = aluinb(op,rfir[7:0],rfim,b);
function [ComNum-1:0] aluope;
input [Opcode-1:0] ope;
input [ComNum-1:0] func;
case (ope)
BEQZ, BNEZ : aluope = ADDOP;
LDLI, LDHI : aluope = THB;
ROP: aluope = func;
default: aluope = ope[ComNum-1:0];
endcase
endfunction
assign alu_ope = aluope(op,op2[ComNum-1:0]);
複雑な記述を function文で置き換える
簡単なものは今まで通り
ex_stage.v レジスタのセット
always @ ( posedge clk or negedge reset_ ) beginif ( reset_ == Enable_ ) begin
reg_c <= NULL;reg_rwadr <= NULL;reg_rwe <= Disable;pcsetr <= Disable;
end else begin// See Figure
reg_c <= result;reg_rwadr <= dest;reg_rwe <= rwen;pcsetr <= pcsett;
endend
ppico.v 入出力と接続信号線module ppico16 ( clk, reset_, idata, ddatain, iaddr, daddr, ddataout, dmwe );
`include "pico.h"
input clk, reset_;
input [DataBus-1:0] idata; // Instruction Data from I-Memory
input [DataBus-1:0] ddatain; // Read Data from D-Memory
output [AddrBus-1:0] iaddr; // Instruction Addr to I-Memory
output [AddrBus-1:0] daddr; // Data Addr to D-Memory
output [DataBus-1:0] ddataout; // Write Data to D-Memory
output dmwe; // D-Memory Write Enable
// IF & RF stage
wire pcset; // Branch Taken Signal
wire [AddrBus-1:0] ifpc; // PC ( IFstage output )
wire [DataBus-1:0] ifir; // IR ( IFstage output )
// RF stage
wire rwe; // Register Write Enable
wire rwen; // RWE for Next Clock Cycle
// RF & EX stage
wire [DataBus-1:0] a; // Source Data A
wire [DataBus-1:0] b; // Source Data B
wire [DataBus-1:0] c; // Destination Data
wire [DataBus-1:0] imm; // Immediate Data
wire [ComNum-1:0] rwadr; // Destination Register No
wire [DataBus-1:0] rfir; // IR ( RFstage output )
wire [AddrBus-1:0] rfpc; // PC ( RFstage output )
ppico.v ステージ間接続
assign iaddr = ifpc; // Fetch Addr to Instruction Memory
if_stage if_stage ( .clk( clk ), .reset_( reset_ ), .idata( idata ), .pcset( pcset ),.badr( c ), .ifpc( ifpc ), .ifir( ifir )
);
rf_stage rf_stage ( .clk( clk ), .reset_( reset_ ), .ifir( ifir ), .ifpc( ifpc ),.rwe( rwe ), .c( c ), .rwadr( rwadr ), .rfpc( rfpc ), .rfir( rfir ),.a( a ), .b( b ), .imm( imm )
);
ex_stage ex_stage ( .clk( clk ) .reset_( reset_ ),.rfir( rfir ), .a( a ), .b( b ),.rfim( imm ), .ddatain( ddatain ), .rfpc(rfpc),
.c( c ), .ddataout( ddataout ), .address( daddr ),.rwadr( rwadr ), .dmwe( dmwe ), .rwe( rwe ), .pcset(pcset)
);
test.prg11100_001_00000001 // LDLI r1,#111100_010_00000010 // LDLI r2,#211100_011_00000011 // LDLI r3,#300110_001_00000010 // ADDI r1#200000_010_010_00110 // ADD r2,r200000_000_00000000 // NOP00000_000_00000000 // NOP00000_000_00000000 // NOP00000_000_00000000 // NOP00000_000_00000000 // NOP
ikarus verilog で実行して gtkwave で波形を見てみよう
演習
• LDHI2 rd,#Xrd の上位 8 ビットに X をセットし、下位
8ビットは rd のままにする命令を付け加えてみよ。