u@home:~$

chiplab的cache

为了解决取值和读数据都要5个cycle的问题,要先把chiplab的cache看懂些。

myCPU/cache.vh


  // way
`define I_WAY_NUM4
`ifdef I_WAY_NUM4
  `define I_WAY_LEN          2
`endif
`define I_WAY_NUM           (1 << `I_WAY_LEN)
`define I_WAY_BITS          `I_WAY_LEN - 1 : 0


...



  // WAY
//`define D_WAY_NUM1
//`define D_WAY_NUM2
`define D_WAY_NUM4

`ifdef D_WAY_NUM1
  `define D_WAY_LEN 0
`endif

`ifdef D_WAY_NUM2
  `define D_WAY_LEN 1
`endif

`ifdef D_WAY_NUM4
  `define D_WAY_LEN 2
`endif

`define D_WAY_NUM            (1 << `D_WAY_LEN)
`define D_WAY_BITS           `D_WAY_LEN - 1 : 0

可以看出icache和dcache都是4 way associative。

这样说icache和dcache就应该都是16KB。

4-way associative就是4个direct-mapped的cache,最后mux。

A 4Kbyte page, for example, limits a direct-mapped cache to a maximum size of 4 Kbytes, a 2-way set-associative ache to a maximum size of 8 Kbytes, and so on.


cache.vh:`define PIPELINE2DCACHE_BUS_ADDR       `WSTRB_WIDTH + `GRLEN * 1 + 1 : `WSTRB_WIDTH + 2
dcache.v:assign pipeline_data_addr  = pipeline2dcache_bus[`PIPELINE2DCACHE_BUS_ADDR     ];
lsoc1000_mainpipe.v:assign pipeline2dcache_bus[`PIPELINE2DCACHE_BUS_ADDR     ] = data_addr      ;
mycpu_top.v:    assign cache_op_addr               = pipeline2dcache_bus[`PIPELINE2DCACHE_BUS_ADDR     ];

cache_op_addr是data_addr。

myCPU/icache.v


assign inst_tlb_vaddr      = cache_op_addr_ok? cache_op_addr : inst_addr;

看了下,cache_hit一直都没有,都是cache_miss,所以cache没起作用。

chiplab的,cpu7也是这样,得跟下哪里的问题。

screenshot0


看这个cache_hit,里面主要是tlb_uncache一直是1,tlb_hit也是1。

chipab里mmu都去掉了,所以tlb没什么用,只要把virtual address直接取高位给出tag就行。

看了下tlb_ptag[19:0],取virtual address高20位,给出的是1c000,也都对。

//  ---------------- Look Up in Icache Tag ----------------
assign cache_hit   =   |way_hit && !tlb_uncache  && tlb_valid_ret;
assign cache_miss  =(!(|way_hit) || tlb_uncache) && tlb_valid_ret;

把icache的tlb_uncache写成1’b0,结果成下面这样了。

screenshot1

cache似乎是起作用了,变成2个cycle取到一次指令了。

而且每隔0x20个字节,也就是32个字节的地方,会有7个cycle的一次取指,应该是cache miss。

看了下头文件,LA32时cache line确实时32字节(256 bit)。

`ifdef LA64
  `define I_LINE_SIZE_b      512    // bit
  `define I_OFFSET_LEN       4
  `define I_INDEX_LEN        7
  `define I_IO_WDATA_LEN    (64 * `I_BANK_NUM)
  //`define I_BANK_BITS       5 : 3
  `define BUS_DATA_WIDTH     128
`elsif LA32
  `define I_LINE_SIZE_b      256    // bit
  `define I_OFFSET_LEN       3
  `define I_INDEX_LEN        8
  `define I_IO_WDATA_LEN    (32 * `I_BANK_NUM)
  //`define I_BANK_BITS       4 : 2
  `define BUS_DATA_WIDTH     64
`endif

但是始终还是cache_miss,cache_hit一次也没出现,而且4个line_tag也一直都是0,还不知道为什么会这样。

跟了几个信号,比如这面这个。

assign inst_rdata = {`INST_OUT_LEN{tlb_finish & way_hit[0]        }} & data_way_sel[0] |
                    {`INST_OUT_LEN{tlb_finish & way_hit[1]        }} & data_way_sel[1] |
                    {`INST_OUT_LEN{tlb_finish & way_hit[2]        }} & data_way_sel[2] |
                    {`INST_OUT_LEN{tlb_finish & way_hit[3]        }} & data_way_sel[3] |
                    {`INST_OUT_LEN{|miss_data_ok | uncache_data_ok}} & miss_ret_data   ;

screenshot2

tlb_finish每隔一个cycle为1,但way_hit始终都为0。

所有取回来的数据都是最后 miss_data_ok选的miss_ret_data。
// inst return
wire [`INST_OUT_LEN-1 :0] data_way_sel [`I_WAY_NUM-1:0];
wire [`INST_OUT_LEN-1 :0] miss_ret_data;


....


  assign data_wdata_o = {rfil_data[ 7], rfil_data[ 6], rfil_data[ 5], rfil_data[ 4],
                         rfil_data[ 3], rfil_data[ 2], rfil_data[ 1], rfil_data[ 0]};

  assign miss_ret_data = {`INST_OUT_LEN{                         rfil_uncache}} & {32'b0        , 32'b0        , 32'b0        , rfil_data[ 0]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b000 & !rfil_uncache}} & {rfil_data[ 3], rfil_data[ 2], rfil_data[ 1], rfil_data[ 0]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b001 & !rfil_uncache}} & {rfil_data[ 4], rfil_data[ 3], rfil_data[ 2], rfil_data[ 1]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b010 & !rfil_uncache}} & {rfil_data[ 5], rfil_data[ 4], rfil_data[ 3], rfil_data[ 2]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b011 & !rfil_uncache}} & {rfil_data[ 6], rfil_data[ 5], rfil_data[ 4], rfil_data[ 3]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b100 & !rfil_uncache}} & {rfil_data[ 7], rfil_data[ 6], rfil_data[ 5], rfil_data[ 4]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b101 & !rfil_uncache}} & {32'b0        , rfil_data[ 7], rfil_data[ 6], rfil_data[ 5]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b110 & !rfil_uncache}} & {32'b0        , 32'b0        , rfil_data[ 7], rfil_data[ 6]} |
                         {`INST_OUT_LEN{rfil_offset == 3'b111 & !rfil_uncache}} & {32'b0        , 32'b0        , 32'b0        , rfil_data[ 7]} ;

....


always @(posedge clk) begin
  if(ret_valid) begin
  `ifdef LA64
    {rfil_data[15], rfil_data[14], rfil_data[13], rfil_data[12]} <= (!rfil_record[3] & rfil_record[2])? ret_data        : {rfil_data[15], rfil_data[14], rfil_data[13], rfil_data[12]};
    {rfil_data[11], rfil_data[10], rfil_data[ 9], rfil_data[ 8]} <= (!rfil_record[2] & rfil_record[1])? ret_data        : {rfil_data[11], rfil_data[10], rfil_data[ 9], rfil_data[ 8]};
    {rfil_data[ 7], rfil_data[ 6], rfil_data[ 5], rfil_data[ 4]} <= (!rfil_record[1] & rfil_record[0])? ret_data        : {rfil_data[ 7], rfil_data[ 6], rfil_data[ 5], rfil_data[ 4]};
    {rfil_data[ 3], rfil_data[ 2], rfil_data[ 1]               } <= (!rfil_record[0]                 )? ret_data[127:32]: {rfil_data[ 3], rfil_data[ 2], rfil_data[ 1]               };
  `elsif LA32
    {rfil_data[ 7], rfil_data[ 6]} <= (!rfil_record[3] & rfil_record[2])? ret_data       : {rfil_data[ 7], rfil_data[ 6]};
    {rfil_data[ 5], rfil_data[ 4]} <= (!rfil_record[2] & rfil_record[1])? ret_data       : {rfil_data[ 5], rfil_data[ 4]};
    {rfil_data[ 3], rfil_data[ 2]} <= (!rfil_record[1] & rfil_record[0])? ret_data       : {rfil_data[ 3], rfil_data[ 2]};
    {rfil_data[ 1]               } <= (!rfil_record[0]                 )? ret_data[63:32]: {rfil_data[ 1]               };
  `endif
  end
end

miss_ret_data来自于ret_data,和ret_valid一起,是cache_interface通过AXI协议从外面的memory取得的数据。

    icache u_icache
    (
        .clk(aclk),
        .resetn(aresetn),

        .cache_op_req     (icache_op_req       ),
        .cache_op         (icache_op           ),
        .cache_op_tag     (cache_op_tag        ),
        .cache_op_addr    (cache_op_addr       ),
        .cache_op_addr_ok (icache_op_addr_ok   ),
        .cache_op_ok      (icache_op_ok        ),
        .cache_op_error   (icache_op_error     ),
        .cache_op_badvaddr(icache_op_badvaddr  ),

        .tlb_ptag         (itlb_paddr[`I_TAG_BITS]),
        .tlb_finish       (itlb_finish         ),
        .tlb_hit          (itlb_hit            ),
        .tlb_cache_recv   (itlb_cache_recv     ),
        //.tlb_uncache      (itlb_uncache        ), // uty: test
        .tlb_uncache      (1'b0                ), // uty: test
        .tlb_exccode      (itlb_exccode        ),

        ////cpu_control
        //------inst request interface-------
        .inst_req          (cpu_inst_req & icache_init_finish),
        .inst_addr         (cpu_inst_addr      ),
        .inst_cancel       (cpu_inst_cancel    ),
        .inst_addr_ok      (cpu_inst_addr_ok   ),
        .inst_rdata        (cpu_inst_rdata     ),
        .inst_valid        (cpu_inst_valid     ),
        .inst_count        (cpu_inst_count     ),
        .inst_uncache      (cpu_inst_uncache   ),
        .inst_exccode      (cpu_inst_exccode   ),
        .inst_exception    (cpu_inst_exception ),

        .inst_tlb_req      (cpu_inst_tlb_req   ),
        .inst_tlb_vaddr    (cpu_inst_tlb_vaddr ),
        .inst_tlb_cacop    (cpu_inst_tlb_cacop ),

        // interact with MISS queue
        .rd_req            (i_rd_req           ),
        .rd_addr           (i_rd_addr          ),
        .rd_arcmd          (i_rd_arcmd         ),
        .rd_uncache        (i_rd_uncache       ),
        .rd_ready          (i_rd_ready         ),
        .ret_valid         (i_ret_valid        ),    <--
        .ret_last          (i_ret_last         ),


    cache_interface u_cache_interface
    (
        ////basic  
        .clk              (aclk               ), 
        .resetn           (aresetn            ),

        .test_pc (debug0_wb_pc), 

         // icache
        .i_rd_req         (i_rd_req           ),
        .i_rd_addr        (i_rd_addr          ),
        .i_rd_arcmd       (i_rd_arcmd         ),
        .i_rd_uncache     (i_rd_uncache       ),
        .i_rd_ready       (i_rd_ready         ),
        .i_ret_valid      (i_ret_valid        ),     <--
        .i_ret_last       (i_ret_last         ),
        .i_ret_data       (i_ret_data         ),
        .i_ret_rstate     (i_ret_rstate       ),

现在的问题是要追踪ret_valid和ret_data,看看读进数据以后为什么没有进到cache里。

screenshot3

从外部memory每个周期可以读进64bit,连续4个cycle,一共256 bit,8条指令,一个cache line。

这就是为什么cache miss了也可以每2个cycle能取值一条指令。

icache里的这几个输出的信号应该是写cache的。

    output reg [`I_WAY_NUM-1  :0] data_clk_en_o,
    output [`I_IO_EN_LEN-1    :0] data_en_o    ,
    output [`I_WAY_NUM-1      :0] data_wen_o   ,
    output [`I_INDEX_LEN-1    :0] data_addr_o  ,
    output [`I_IO_WDATA_LEN-1 :0] data_wdata_o ,
    input  [`I_IO_RDATA_LEN-1 :0] data_rdata_i ,

现在的情况是因为cache miss,icache refill的时候虽然一次从外memory读64bit,但不知道为什么ifu取值的时候只能每两个cycle取值一次。

不知道cache存没存上,写了个测试的例子test_case_loop。loop回去,看看再次执行的时候能不能从cache里直接取。

screenshot4

果然是这样,loop回1c000000以后,后面的指令都是每个cycle都可以fetch一条。

看下面的cache_hit,也都有了。

这样就能满足后面写bypass模块的需求了。

不过,要是每次代码都是前几条指令循环一遍,也很不方便。

看看能不能把TLB去掉,cache似乎能正常工作,问题可能出在TLB上。