計算機構成: トップダウンの解説

PICOのパイプライン化
慶應義塾大学 理工学部
天野
PICOの構成(前期の図を若干変更)
aluout
regc
outc
MUX
MUX
pc
op
com
ir
op2
op
110
ALU
001
alubin
Expander
MUX
‘2’
op2
dest
idata
src
regb
aluain
MUX
rega
adrA
adrB
regfile
ddataout
MUX
iadr
Instruction
Memory
we_
dadr
Data
Memory
ddatain
パイプライン処理の設計
• 大きな処理を一定の同じ大きさの小さな段階(ス
テージ)に分解
• それぞれのステージにそれぞれの処理装置を設け
る
• 順にデータを流してやり、自分の処理が終わったら
すぐ次のステージに渡す
• 流れ作業と基本は同じ
• ステージ数をSとすると、理想の場合は性能はS倍
– ステージの処理量が均等でないと、最も重いものに律速
される
– ステージ間の受け渡しで大概ロスがある
パイプライン処理
組合せ回路
ステージ
1
ステージ
2
ステージ
3
ステージ
4
時間
ステージステージステージステージ
2
3
4
1
ステージステージステージステージ
2
3
4
1
ステージステージステージステージ
2
3
4
1
ステージステージステージステージ
2
3
4
1
流れ作業(パイプライン処理) vs 多人数による並列処理
• S人居れば最大S倍、これは同じ
• 流れ作業は、各人がそのステージの処理だけでき
れば良い ⇔並列処理は、すべての人が全作業を
する能力がなければならない
• 流れ作業は、各人がそのステージの処理をするの
に必要な工具(リソース)を持てば良い⇔並列処理
は、すべての人がすべての工具、場所を持つ必要
がある
• このため、日常的な作業効率向上、工場のオート
メーションなどもまずは流れ作業を導入する
状態遷移→ステージ
結果を書き込む命令
それ以外:分岐、STなど
IF
irに命令を
フェッチ
RF
レジスタ
読み出し
PC←PC+2
EX
WB
演算実行
結果の格納
飛び先セット
メモリからの読み
書き込み
パイプライン化されていない設計が良くできていれば、それぞれの状態は
遅延時間がほぼ均等に分割されているはず。このため、状態をそのまま
パイプラインのステージに割り当ててしまうのが基本的な設計手法
PICOのパイプライン構造
IF
RF
RFPC
WB
EX
a
2
regc
ALU
+
rega
IFPC
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
LDLI r1,#1
IF
RF
RFPC
EX
WB
a
2
regc
ALU
+
rega
IFPC
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
LDLI r2,#2
LDLI r1,#1
IF
RF
RFPC
EX
WB
a
2
regc
ALU
+
rega
IFPC
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
LDLI r3,#3
LDLI r2,#2
IF
RF
LDLI r1,#1
RFPC
EX
WB
a
2
ALU
+
rega
IFPC
1
regc
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
ADD r1,#2
LDLI r3,#3
IF
RF
LDLI r2,#2
RFPC
LDLI r1,#1
EX
WB
a
2
ALU
+
rega
IFPC
2
regc
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
1
ADD r2,r2
ADD r1,#2
IF
RF
LDLI r3,#3
RFPC
LDLI r2,#2
EX
WB
a
2
ALU
+
rega
IFPC
3
regc
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
2
ADD r2,r2
IF
RF
ADD r1,#2
RFPC
LDLI r3,#3
EX
WB
a
2
ALU
+
rega
IFPC
3
regc
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
3
ADD r2,r2
IF
RF
RFPC
ADD r1,#2
EX
WB
a
2
ALU
+
rega
IFPC
4
regc
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
3
ADD r2,r2
IF
RF
RFPC
EX
WB
a
2
regc
ALU
+
rega
IFPC
regb
c
b
IFIR
Instruction
Memory
Imm.
wadr
RFIR
Data
Memory
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.v
module 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;
assignifpc = pc;
assignifir = ir;
always @( posedge clk ) begin
if ( reset_ == Enable_ ) begin
pc <= NULL; ir <= NULL;
pcsetが1ならば分岐先ア
end else begin
ドレスのセット
ir
<=
idata;
if( pcset == Enable ) begin
そうでなければ+2
pc
<=
badr; end
(バイトアドレスなので)
else begin
pc
<=
ifpc + 2; end
end
end
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 Data
input
[RegNum-1:0]
rwadr;
// Destination Register No
output
[DataBus-1:0]
rfpc;
// PC ( RFstage output )
output
[DataBus-1:0]
rfir;
// IR ( RFstage output )
output
[DataBus-1:0]
a;
// Source Data A
output
[DataBus-1:0]
b;
// Source Data B
output
[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
assignrfir = reg_ir;
assignrfpc = reg_pc;
assigna = reg_a;
assignb = reg_b;
assignimm = 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]
input
[DataBus-1:0]
input
[DataBus-1:0]
input
[DataBus-1:0]
input
[DataBus-1:0]
input
[DataBus-1:0]
rfir;
rfim;
a;
b;
ddatain;
rfpc;
output
[DataBus-1:0]
output
[DataBus-1:0]
output
[AddrBus-1:0]
output
[RegNum-1:0]
output
dmwe;
output
rwe;
output pcset;
c;
// Operation Result
ddataout; // Write Data to D-Memory
address; // Address for D-Memory access
rwadr;
// Destination Register No
// D-Memory Write Enable
// Register Write Enable
// PC branch address set
// IR ( RF stage output )
// Immediate Data
// Source Data A
// Source Data B
// Read Data from D-Memory
// PC (RF stage output )
ex_stage.v レジスタと簡単な論理部の接続
// Pipeline Registers
reg
reg
reg
reg
[DataBus-1:0]
[RegNum-1:0]
reg_rwe;
pcsetr;
// Temporary Wire
wire
[DataBus-1:0]
wire
[ComNum-1:0]
wire
[DataBus-1:0]
wire
[DataBus-1:0]
wire rwen;
wire pcsett;
wire [Opcode-1:0] op, op2;
wire [RegNum-1:0] dest;
reg_c;
reg_rwadr;
aluout;
// ALU Output
aluope;
// ALU Operation
alu_ina, alu_inb;// Temporary Wire for ALU Source B
result;
// Temporary Wire for results
// 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 operation
assignaluout = 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_stagef.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_ ) begin
if ( 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;
end
end
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;
Memory
// Fetch Addr to Instruction
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.prg
11100_001_00000001
11100_010_00000010
11100_011_00000011
00110_001_00000010
00000_010_010_00110
00000_000_00000000
00000_000_00000000
00000_000_00000000
00000_000_00000000
00000_000_00000000
// LDLI r1,#1
// LDLI r2,#2
// LDLI r3,#3
// ADDI r1#2
// ADD r2,r2
// NOP
// NOP
// NOP
// NOP
// NOP
ikarus verilog で実行してgtkwaveで波形を見てみよう
演習
• LDHI2 rd,#X
rdの上位8ビットにXをセットし、下位8ビットは
rdのままにする命令を付け加えてみよ。