2021年12月14日星期二

用dff还是dffe(with functional enable)是不是做流水线时的一种选择?

遇到这种情况,以前是用sram,所以一clock肯定能读出数据,所以后面的流水线都是一拍一拍的走,遇到转移指令就stall和清流水线。

 

reg  [31:0] pc_cur    ;
wire [31:0] pc_next   ;
wire        pc_next_en;
wire [29:0] pc_seq    ;
assign bt_pc   = pc_cur;
assign pc_next = wb_cancel ? wb_target :
                 br_cancel ? br_target :
                 pr_cancel ? pr_target :
                 bt_cancel ? bt_target : {pc_seq,2'h0};
assign pc_next_en = pc_go || pr_cancel || br_cancel || wb_cancel;
assign pc_seq     = pc_cur[4:2] >= 3'h4 ? {pc_cur[31:5] + 27'h0000001,3'h0} : {pc_cur[31:5],pc_cur[4:2] + 3'h4};
assign fe_target  = fe_valid ? fe_cur[31:2] : pc_cur[31:2];
assign inst_addr  = pc_cur;
always@(posedge clock)
begin
    if(reset)
    begin
        pc_cur<=pc_init;
    end
    else
    if(pc_next_en)
    begin
        pc_cur<=pc_next;
    end
end


比如龙芯里这段代码,pc_cur是reg

其实是一个带enable的dff, dffe_s()


只有当pc_next_en为1时,pc_cur寄存器才会更新。而pc_next_en需要等pc_go或者br_branch等其中任何一种情况发生才更新pc_cur,而不是每拍pc_cur都要走。




在OpenSPARC T1里也有这样的用法,只是不是在pc path里,而是在instruction path。


   // Thread Next Instruction Register
   wire   clk_nir0;
`ifdef FPGA_SYN_CLK_EN
`else

   bw_u1_ckenbuf_6x  ckennir0(.rclk (rclk),
                              .clk  (clk_nir0),
                              .en_l (fcl_fdp_thr_s1_l[0]),
                              .tm_l (~se));
`endif
`ifdef FPGA_SYN_CLK_DFF
   dffe_s #(33) t0nir_reg(.din (icd_fdp_topdata_s1[32:0]),
                                   .q    (t0nir),
                                   .en  (~(fcl_fdp_thr_s1_l[0])), .clk(rclk), .se(se), .si(), .so());
`else

   dff_s #(33) t0nir_reg(.din  (icd_fdp_topdata_s1[32:0]),
                                   .q    (t0nir),
                                   .clk  (clk_nir0), .se(se), .si(), .so());
`endif


这里还发现个有意思的事,如果是在fpga里,就用dffe。而正式版本里是用信号控制一个clk_nir0,然后这个clk再控制dff。

没有评论:

发表评论