openc910源码LSU系列之<84>

ct_lsu_amr

module ct_lsu_amr(
  amr_l2_mem_set,
  amr_wa_cancel,
  cp0_lsu_amr,
  cp0_lsu_amr2,
  cp0_lsu_icg_en,
  cp0_lsu_no_op_req,
  cp0_yy_clk_en,
  cpurst_b,
  forever_cpuclk,
  icc_idle,
  lsu_had_amr_state,
  pad_yy_icg_scan_en,
  wmb_ce_addr,
  wmb_ce_bytes_vld,
  wmb_ce_ca_st_inst,
  wmb_ce_pop_vld,
  wmb_ce_vld
);

AMR(Address Matching and Retry)模块。AMR 模块的作用是处理地址匹配和重试逻辑,尤其是针对写缓冲器(Write Merge Buffer, WMB)中的操作

  1. 输入信号

    • cp0_lsu_amr, cp0_lsu_amr2:来自 CP0(协处理器 0)的 AMR 配置寄存器,用于控制 AMR 模块的行为。
    • cp0_lsu_icg_en, cp0_yy_clk_en:时钟门控使能信号,用于电源管理。
    • cpurst_b:复位信号。
    • forever_cpuclk:持续的 CPU 时钟信号。
    • icc_idle:表明指令缓存一致性检查(Instruction Cache Coherency Check)是否空闲。
    • pad_yy_icg_scan_en:扫描测试时用于内部时钟门控的使能信号。
    • wmb_ce_addr, wmb_ce_bytes_vld, wmb_ce_ca_st_inst, wmb_ce_pop_vld, wmb_ce_vld:来自写缓冲器的信号,提供关于缓冲器条目的地址、有效字节、缓存一致性和状态信息。
  2. 输出信号

    • amr_l2_mem_set:指示是否设置 L2 内存操作。
    • amr_wa_cancel:指示是否取消写分配(Write Allocate)操作。
    • lsu_had_amr_state:输出 AMR 模块的状态供硬件抽象层(Hardware Abstraction Layer, HAD)使用。
    • cp0_lsu_no_op_req:向 CP0 发送无操作请求的信号。

AMR 模块的主要职责是根据系统配置和当前操作情况,管理地址匹配逻辑和重试策略,特别是在处理写缓冲器中的数据时。这对于维护数据一致性和优化内存访问性能至关重要。通过与 CP0 和写缓冲器的交互,AMR 模块能够根据系统的当前状态和配置动态调整其行为。

parameter JUDGE     = 3'b000,
          MEM_SET_0 = 3'b001,//0 means write 1 dcache line
          MEM_SET_1 = 3'b011,//1 add cancel write allocate
          MEM_SET_2 = 3'b111;//2 add cancel l2 write allocate
//==========================================================
//                 Instance of Gated Cell  
//==========================================================
//amr pop clk is for addr and bytes_vld when sq pops a entry
assign amr_clk_en     = cp0_lsu_amr
                        ? (wmb_ce_vld
                          ||  amr_cnt_met_set
                          ||  amr_not_idle)
//                              &&  (!icc_idle
//                                  ||  amr_cnt_met_set_1
//                                  ||  amr_cnt_met_set_2
//                                  ||  cp0_lsu_no_op_req))
//                                  ||  wmb_amr_cancel_gateclk))
                        : amr_not_idle;
// &Instance("gated_clk_cell", "x_lsu_amr_gated_clk"); @47
gated_clk_cell  x_lsu_amr_gated_clk (
  .clk_in             (forever_cpuclk    ),
  .clk_out            (amr_clk           ),
  .external_en        (1'b0              ),
  .global_en          (cp0_yy_clk_en     ),
  .local_en           (amr_clk_en        ),
  .module_en          (cp0_lsu_icg_en    ),
  .pad_yy_icg_scan_en (pad_yy_icg_scan_en)
);

// &Connect(.clk_in        (forever_cpuclk     ), @48
//          .external_en   (1'b0               ), @49
//          .global_en     (cp0_yy_clk_en      ), @50
//          .module_en     (cp0_lsu_icg_en     ), @51
//          .local_en      (amr_clk_en         ), @52
//          .clk_out       (amr_clk            )); @53


assign amr_update_clk_en  = amr_update_vld;
// &Instance("gated_clk_cell", "x_lsu_amr_update_gated_clk"); @57
gated_clk_cell  x_lsu_amr_update_gated_clk (
  .clk_in             (forever_cpuclk    ),
  .clk_out            (amr_update_clk    ),
  .external_en        (1'b0              ),
  .global_en          (cp0_yy_clk_en     ),
  .local_en           (amr_update_clk_en ),
  .module_en          (cp0_lsu_icg_en    ),
  .pad_yy_icg_scan_en (pad_yy_icg_scan_en)
);
  1. 参数定义

    • 定义了 JUDGE, MEM_SET_0, MEM_SET_1, MEM_SET_2 三个状态,用于管理 AMR 模块的内存设置和写分配取消逻辑。
  2. AMR 门控时钟实例化

    • amr_clk_en:这个信号根据 CP0 的配置和写缓冲器的状态来使能或禁用 AMR 模块的时钟。如果 CP0 的 AMR 配置寄存器被激活,则在写缓冲器有效、计数器满足设置条件或 AMR 不空闲时使能时钟。
    • x_lsu_amr_gated_clk:门控时钟单元实例,用于管理 AMR 模块的主时钟 amr_clk
  3. AMR 更新门控时钟

    • amr_update_clk_en:当有有效的 AMR 更新时,使能该时钟。
    • x_lsu_amr_update_gated_clk:门控时钟单元实例,用于管理 AMR 更新的时钟 amr_update_clk
//==========================================================
//                      Registers
//==========================================================
//+-------+
//| state |
//+-------+
always @(posedge amr_clk or negedge cpurst_b)
begin
  if (!cpurst_b)
    amr_state[2:0]        <=  JUDGE;
  else
    amr_state[2:0]        <=  amr_next_state[2:0];
end
//assign amr_mem_set    = amr_state[0];
assign amr_wa_cancel  = amr_state[0];
assign amr_l2_mem_set = amr_state[2]
                        &&  cp0_lsu_amr2;

//+------+-----------+-----+-----+
//| addr | bytes_vld | cnt | neg |
//+------+-----------+-----+-----+
always @(posedge amr_clk or negedge cpurst_b)
begin
  if (!cpurst_b)
    amr_cnt[5:0]          <=  6'b0;
  else if(amr_judge_cancel)
    amr_cnt[5:0]          <=  6'b0;
  else if(amr_judge_fail)
    amr_cnt[5:0]          <=  6'b0;
  else if(amr_update_vld &&  amr_bytes_vld_full)
    amr_cnt[5:0]          <=  amr_cnt[5:0]+6'b1;
  else if(amr_update_vld)
    amr_cnt[5:0]          <=  amr_cnt[5:0];
end

assign amr_from_wmb_ce_addr[`PA_WIDTH-1:0] = wmb_ce_addr[`PA_WIDTH-1:0];
always @(posedge amr_update_clk or negedge cpurst_b)
begin
  if (!cpurst_b)
    amr_bytes_vld[15:0]   <=  16'b0;
//  else if(amr_judge_fail && wmb_ce_bytes_vld_full)
//    amr_bytes_vld[15:0]   <=  16'b0;
  else if(amr_judge_fail || amr_update_vld && amr_bytes_vld_full)
    amr_bytes_vld[15:0]   <=  wmb_ce_bytes_vld[15:0];
//  else if(amr_update_vld &&  amr_bytes_vld_next_full)
//    amr_bytes_vld[15:0]   <=  16'b0;
  else if(amr_update_vld)
    amr_bytes_vld[15:0]   <=  amr_bytes_vld_next[15:0];
end

always @(posedge amr_update_clk)
begin
//  if(amr_judge_fail && wmb_ce_bytes_vld_full)
//    amr_addr_tto4[`PA_WIDTH-5:0]   <=  amr_from_wmb_ce_addr_tto4_cal[`PA_WIDTH-5:0];
  if(amr_update_vld)
    amr_addr_tto4[`PA_WIDTH-5:0]   <=  amr_from_wmb_ce_addr[`PA_WIDTH-1:4];
//  else if(amr_update_vld &&  amr_bytes_vld_next_full)
//    amr_addr_tto4[`PA_WIDTH-5:0]   <=  amr_addr_tto4_cal[`PA_WIDTH-5:0];
end
  1. 状态寄存器(amr_state

    • 在 AMR 模块的时钟边沿或复位信号激活时更新。状态机的初始状态是 JUDGE。之后根据 amr_next_state 更新当前状态。
  2. 状态派生信号

    • amr_wa_cancelamr_l2_mem_set 信号基于当前状态决定是否取消写分配或设置 L2 内存操作。这些信号由 AMR 状态的特定位决定。
  3. 计数器寄存器(amr_cnt

    • 这个计数器用于追踪特定条件下的事件次数。在特定条件下(如 amr_judge_cancelamr_judge_fail)清零,或者在更新有效时递增。
  4. 地址和有效字节寄存器

    • amr_bytes_vld 寄存器在特定更新时从写缓冲器接收有效字节信息。这是 AMR 用来跟踪哪些字节在缓冲器条目中有效的方式。
    • amr_addr_tto4 寄存器存储地址信息,仅在特定条件下更新。
//==========================================================
//                 Generate next state
//==========================================================
// &CombBeg; @137
always @( amr_cnt[5:0]
       or amr_cnt_met_set
       or amr_state[2:0]
       or amr_judge_flush)
begin
amr_next_state[2:0] = JUDGE;
case(amr_state[2:0])
  JUDGE:
    if(amr_cnt_met_set)
      amr_next_state[2:0] = MEM_SET_0;
    else
      amr_next_state[2:0] = JUDGE;
  MEM_SET_0:
    if(amr_judge_flush)
      amr_next_state[2:0] = JUDGE;
    else if(amr_cnt[5:0] ==  6'd16)
      amr_next_state[2:0] = MEM_SET_1;
    else
      amr_next_state[2:0] = MEM_SET_0;
  MEM_SET_1:
    if(amr_judge_flush)
      amr_next_state[2:0] = MEM_SET_0;
    else if(amr_cnt[5:0] ==  6'd48)
      amr_next_state[2:0] = MEM_SET_2;
    else
      amr_next_state[2:0] = MEM_SET_1;
  MEM_SET_2:
    if(amr_judge_flush)
      amr_next_state[2:0] = MEM_SET_1;
    else
      amr_next_state[2:0] = MEM_SET_2;
  default:amr_next_state[2:0] = JUDGE;
endcase
// &CombEnd; @166
end

//==========================================================
//                        Wires
//==========================================================
//---------------------amr cnt state change-----------------
assign amr_cnt_met_set = (amr_cnt[5:0] ==  6'd8);
//---------------------pop_judge_vld------------------------
assign amr_update_vld = wmb_ce_pop_vld;
//------------------------addr hit--------------------------
assign amr_addr_hit    = amr_bytes_vld_full
                         ? amr_addr_hit_normal_update
                         : amr_addr_hit_eq;

assign amr_addr_distance[`PA_WIDTH-5:0] = amr_from_wmb_ce_addr[`PA_WIDTH-1:4] - amr_addr_tto4[`PA_WIDTH-5:0];

//distance equal to 0
assign amr_addr_hit_eq = !(|amr_addr_distance[`PA_WIDTH-5:0]); 

//distance equal to +1 or -1 means normal update
assign amr_addr_hit_normal_update = amr_addr_distance[0]
                                    && (&amr_addr_distance[`PA_WIDTH-5:1]
                                        || !(|amr_addr_distance[`PA_WIDTH-5:1]));
//---------------------next bytes_vld-----------------------
assign amr_bytes_vld_next[15:0] = amr_bytes_vld[15:0] | wmb_ce_bytes_vld[15:0];
//assign amr_bytes_vld_next_full  = &amr_bytes_vld_next[15:0];
assign amr_bytes_vld_full       = &amr_bytes_vld[15:0];
//assign wmb_ce_bytes_vld_full    = &wmb_ce_bytes_vld[15:0];

//---------------------next addr----------------------------
//assign amr_from_wmb_ce_addr_tto4_cal[`PA_WIDTH-5:0] =
//                amr_neg
//                ? amr_from_wmb_ce_addr[`PA_WIDTH-1:4]
//                  + {{`PA_WIDTH-5{1'b0}},1'b1}
//                : amr_from_wmb_ce_addr[`PA_WIDTH-1:4]
//                  - {{`PA_WIDTH-5{1'b0}},1'b1};
//assign amr_addr_tto4_cal[`PA_WIDTH-5:0]  =
//                amr_neg
//                ? amr_addr_tto4[`PA_WIDTH-5:0]
//                  - {{`PA_WIDTH-5{1'b0}},1'b1}
//                : amr_addr_tto4[`PA_WIDTH-5:0]
//                  + {{`PA_WIDTH-5{1'b0}},1'b1};

//cross hit means there is a common bit 1 both in 
//amr_bytes_vld and wmb_ce_bytes_vld 
assign amr_bytes_vld_cross  = |(amr_bytes_vld[15:0] & wmb_ce_bytes_vld[15:0]);

//---------------------judge flush--------------------------
//cancel means it need to clear all the tags
assign amr_judge_cancel = !icc_idle
                          ||  !cp0_lsu_amr
                          ||  amr_update_vld &&  !wmb_ce_ca_st_inst
                          ||  cp0_lsu_no_op_req;

//fail means it need to set all the tags to the pop st inst
assign amr_judge_fail   = amr_update_vld
                          &&  (!amr_addr_hit
                              ||  amr_bytes_vld_cross
                                  && !amr_bytes_vld_full);

assign amr_judge_flush  = amr_judge_cancel  ||  amr_judge_fail;

assign amr_not_idle     = (amr_state[2:0] !=  JUDGE)
                          ||  (amr_cnt[5:0] !=  6'b0);

//==========================================================
//              Interface to other module
//==========================================================
assign lsu_had_amr_state[2:0] = amr_state[2:0];

  1. 状态机逻辑

    • 根据当前状态(amr_state)和其他条件,决定下一个状态(amr_next_state)。状态机从 JUDGE 开始,根据计数器 amr_cnt 的值和其他条件,可能转换到 MEM_SET_0, MEM_SET_1, MEM_SET_2 等状态。
  2. 计数器状态改变信号(amr_cnt_met_set

    • 当计数器达到特定值时(例如 6’d8),这个信号被置位。
  3. 更新有效信号(amr_update_vld

    • 当写缓冲器弹出有效时,这个信号被置位。
  4. 地址命中逻辑

    • amr_addr_hit:根据地址和有效字节的匹配情况决定是否命中。
    • amr_addr_distance:计算当前地址和写缓冲器地址之间的距离。
  5. 下一个有效字节寄存器(amr_bytes_vld_next

    • 根据当前有效字节和写缓冲器的有效字节更新下一个有效字节。
  6. 判断逻辑

    • amr_judge_cancel:在特定条件下,如指令缓存一致性检查空闲或无操作请求,需要取消判断。
    • amr_judge_fail:在地址不命中或存在交叉命中时失败。
    • amr_judge_flush:将 amr_judge_cancelamr_judge_fail 的结果组合以决定是否需要刷新。
  7. 非空闲信号(amr_not_idle

    • 根据状态和计数器决定 AMR 是否空闲。
  8. 与其他模块的接口

    • lsu_had_amr_state:输出 AMR 模块的当前状态供硬件抽象层(Hardware Abstraction Layer, HAD)使用。