五级流水线整体图示:
Verilog代码综合得到的总框图:
某些指令执行的流水线级数:
如上图所见,很多指令存在着某些stage保持原数据不必刷新寄存器数据的情况(NOP),而刷新计数器数据无疑会产生动态功率损耗,之前的CPU基本设计中无论数据改不改变都刷新寄存器数据,造成了不必要的动态功率损耗。基于此动机,我们可以尝试将某些原本不需要刷新数据但实际刷新了数据的情况消除,而实现消除的方法是:时钟门控(clock gating)。门控基本原理就是通过关闭芯片上暂时用不到的功能和它的时钟,从而实现节省电流消耗的目的。一般而言,门控时一般选择那些不经常使用或者变化的寄存器,观察可以发现除了LOAD指令和STORE指令,流水线的第四级DATA_MEMORY的三个数据d_addr,d_we,d_dataout不必刷新,因此可以通过门控来减少功率损耗。
代码实现如下:
`define idle 1'b0
`define exec 1'b1
`define NOP 5'b00000
`define HALT 5'b00001
`define LOAD 5'b00010
`define STORE 5'b00011
`define LDIH 5'b00100
`define ADD 5'b00101
`define ADDI 5'b00110
`define ADDC 5'b00111
`define SUB 5'b01000
`define SUBI 5'b01001
`define SUBC 5'b01010
`define CMP 5'b01011
`define AND 5'b01100
`define OR 5'b01101
`define XOR 5'b01110
`define SLL 5'b01111
`define SRL 5'b10000
`define SLA 5'b10001
`define SRA 5'b10010
`define JUMP 5'b10011
`define JMPR 5'b10100
`define BZ 5'b10101
`define BNZ 5'b10110
`define BN 5'b10111
`define BNN 5'b11000
`define BC 5'b11001
`define BNC 5'b11010
module clock_gating(
input clk,reset,enable,start,
input [15:0] d_datain,i_datain,
output wire [7:0] i_addr,
output reg [7:0] d_addr,pc,
output reg [15:0] d_dataout,
output reg d_we
);
reg state,nextstate;
reg [15:0] gr[0:7];
reg [15:0] id_ir,ex_ir,mem_ir,reg_A,reg_B,reg_C,ALUo,smdr,smdr1,reg_C1,wb_ir;
reg dw,zf,nf,cf;
assign i_addr = pc;
//************* CPU control *************//
always @(posedge clk or negedge reset)
begin
if (!reset)
state <= `idle;
else
state <= nextstate;
end
always @(*)
begin
case (state)
`idle : begin
if ((enable == 1'b1) && (start == 1'b1))
nextstate <= `exec;
else
nextstate <= `idle;
end
`exec : begin
if ((enable == 1'b0) || (wb_ir[15:11] == `HALT))//HALT
nextstate <= `idle;
else
nextstate <= `exec;
end
endcase
end
//************* IF : Instruction fetch *************//
always @(posedge clk or negedge reset)
begin
if (!reset)
begin
id_ir <= 16'b0000_0000_0000_0000;
pc <= 8'b0000_0000;
end
else if (state ==`exec)
begin
if( ((mem_ir[15:11] == `BZ) && (zf == 1'b1)) || ((mem_ir[15:11] == `BN) && (nf == 1'b1))
|| ((mem_ir[15:11] == `BNZ) && (zf == 1'b0)) || ((mem_ir[15:11] == `BNN) && (nf == 1'b0))
|| ((mem_ir[15:11] == `BC) && (cf == 1'b1)) || ((mem_ir[15:11] == `BNC) && (cf == 1'b0))
|| (mem_ir[15:11] == `JMPR) )
begin
pc <= reg_C[7:0];
id_ir <= i_datain;
end
//JUMP指令
else if(i_datain[15:11] == `JUMP)
begin
pc <= i_datain[7:0];
id_ir <= i_datain;
end
//********上一条指令为LOAD与当前指令的寄存器相同时会引起数据冒险与阻塞stall:引入气泡(延迟一个周期)"*******//
else if((id_ir[1