u@home:~$

CSR模块

 387    cpu7_csr csr(                                                                                                                             
 388       .clk               (clk               ),                                                                                               
 389       .resetn            (resetn            ),                                                                                               
 390       .csr_rdata         (csr_byp_rdata_d   ),                                                                                               
 391       .csr_raddr         (ecl_csr_raddr_d   ),                                                                                               
 392       .csr_waddr         (ecl_csr_waddr_m   ),                                                                                               
 393       .csr_wdata         (byp_csr_wdata_m   ),                                                                                               
 394       .csr_wen           (ecl_csr_wen_m     )                                                                                                
 395       ); 

在_d的时候读csr寄存器的内容。

处理csrwr csrxchg的时候需要读rd的内容,写到csr寄存器里。因为读到的rd的内容需要经过byp处理,所以在_e写csr寄存器来不及,只能在_m写。

 695    assign csr_wdata_e = byp_rs2_data_e;

并且_e的时候还要处理csrxchg里的mask。

但这样就出现个问题,csr寄存器也需要byp。

比如csrwr后面紧跟着csrrd,csrwr在_m时写csr寄存器,而csrrd在_d的时候就去读了,比如下面这段代码。

        addi.w   $r4, $r0, -1            # r4 = ffffffff
        csrwr    $r4, 0x0                # only crmd.ie (bit 2) can be set
#       nop
        csrrd    $r5, 0x0                # crmd
        addi.w   $r5, $r5, 0x56

没有nop隔开的话,csrrd读到的还是0。


csr寄存器还不能直接做bypass,因为很多寄存器里很多bit都相当于是只读的0。

比如csrwr刚写ffffffff到crmd,而crmd现在只有ie位有寄存器实现,所以ffffffff写进crmd,再读出来的时候就变成00000004了。

如果后面的csrrd读的时候做data forwarding,则csrrd得到的是csrwr的ffffffff,这样结果就不对了。

具体的写在这里了:

pipeline bypass


现在的办法是和lsu一样,request IFU stall。

因为这是个RAW,Read-After-Write,所以只有csrrw csrxchg需要stall IFU。

按说只需要在csrrw csrxchg后面是csrrd,并且只有csr_num一致才需要把csrrd这条指令stall一下。

不过实现这样判断有点复杂,不过又不能不管,因为结果必须正确。

csr指令用的并不多,所以就csrwr csrxchg就stall IFU吧。


stall IFU

 794    //                                                                                                                                        
 795    // csr stall req                                                                                                                          
 796                                                                                                                                              
 797    wire csr_stall_req;                                                                                                                       
 798    wire csr_stall_req_next;                                                                                                                  
 799                                                                                                                                              
 800    assign csr_stall_req_next = (csr_wen_d) | (csr_stall_req & ~csr_wen_m);                                                                   
 801                                                                                                                                              
 802    dffr_s #(1) csr_stall_req_reg (                                                                                                           
 803       .din (csr_stall_req_next),                                                                                                             
 804       .clk (clk),                                                                                                                            
 805       .q   (csr_stall_req),                                                                                                                  
 806       .se(), .si(), .so(), .rst (~resetn));  

csr_wen_d是stall开始的信号,csr_wen_m是stall结束的信号。

和lsu用的方法一样,设置开始和结束的信号,上面的逻辑 csr_stall_req_next就能保持1在这两个信号中间。

最后用这个信号去req IFU stall。

 1009    //                                                                                                                                       
 1010    // exu_ifu_stall_req                                                                                                                     
 1011    //                                                                                                                                       
 1012    assign exu_ifu_stall_req = lsu_stall_req_next | csr_stall_req_next; 

用csr_stall_req_next还是csr_stall_req,在起始位值上略有不同。

screenshot0

为了一遇到csrwr指令就尽快stall住IFU,用csr_stall_req_next。

因为差一个cycle的话,IFU的下一条指令就进来了。


又加了个测试例子 func_uty14_csrwr1cycle,测下一个cycle一个指令的时候行不行。

obj/main.elf:     file format elf32-loongarch
obj/main.elf


Disassembly of section .text:

1c000000 <_start>:
kernel_entry():
1c000000:       02800803        addi.w  $r3,$r0,2(0x2)
1c000004:       02800004        addi.w  $r4,$r0,0

1c000008 <again>:
again():
1c000008:       02800484        addi.w  $r4,$r4,1(0x1)
1c00000c:       02bffc06        addi.w  $r6,$r0,-1(0xfff)
1c000010:       04000026        csrwr   $r6,0x0
1c000014:       04000005        csrrd   $r5,0x0
1c000018:       028158a5        addi.w  $r5,$r5,86(0x56)
1c00001c:       02800000        addi.w  $r0,$r0,0
1c000020:       02800000        addi.w  $r0,$r0,0
1c000024:       5fffe464        bne     $r3,$r4,-28(0x3ffe4) # 1c000008 <again>

screenshot1

黄色框里pc_bf由于exu_ifu_stall_req的控制,一直停在1c000014,这段和下面csr_stall_req_next是一致的。

红色框里pc_f也一直停在1c000014。

 76    assign fdp_dec_valid = inst_valid & ~exu_ifu_stall_req & ~br_taken; // pc_f shoudl not be passed to pc_d if a branch is taken at _e.       


 135    wire pc_f2d_en = fdp_dec_valid;                                                                                                           
 136                                                                                                                                              
 137    dffe_s #(`GRLEN) pc_f2d_reg (                                                                                                             
 138       .din (pc_f),                                                                                                                           
 139       .clk (clock),                                                                                                                          
 140       .q   (pc_d),                                                                                                                           
 141       .en  (pc_f2d_en),                                                                                                                      
 142       .se(), .si(), .so()); 


 195    assign ifu_pcbf_sel_old_bf_l = (inst_valid || reset || br_taken) & (~exu_ifu_stall_req);                                                  
 196                                                                                                                                              
 197    //assign ifu_pcbf_sel_pcinc_bf_l = ~(inst_valid && ~br_taken);  /// ??? br_taken never comes along with inst_valid, br_taken_e            
 198    assign ifu_pcbf_sel_pcinc_bf_l = ~(inst_valid && ~br_taken) | exu_ifu_stall_req;  /// ??? br_taken never comes along with inst_valid, br_\
     taken_e   

exu_ifu_stall_req影响fdp_dec_valid,这样pc_f的指令不会走到后面的_d阶段。