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)中的操作
-
输入信号:
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 :来自写缓冲器的信号,提供关于缓冲器条目的地址、有效字节、缓存一致性和状态信息。
-
输出信号:
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) );
-
参数定义:
- 定义了
JUDGE ,MEM_SET_0 ,MEM_SET_1 ,MEM_SET_2 三个状态,用于管理 AMR 模块的内存设置和写分配取消逻辑。
- 定义了
-
AMR 门控时钟实例化:
amr_clk_en :这个信号根据 CP0 的配置和写缓冲器的状态来使能或禁用 AMR 模块的时钟。如果 CP0 的 AMR 配置寄存器被激活,则在写缓冲器有效、计数器满足设置条件或 AMR 不空闲时使能时钟。x_lsu_amr_gated_clk :门控时钟单元实例,用于管理 AMR 模块的主时钟amr_clk 。
-
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
-
状态寄存器(
amr_state ):- 在 AMR 模块的时钟边沿或复位信号激活时更新。状态机的初始状态是
JUDGE 。之后根据amr_next_state 更新当前状态。
- 在 AMR 模块的时钟边沿或复位信号激活时更新。状态机的初始状态是
-
状态派生信号:
amr_wa_cancel 和amr_l2_mem_set 信号基于当前状态决定是否取消写分配或设置 L2 内存操作。这些信号由 AMR 状态的特定位决定。
-
计数器寄存器(
amr_cnt ):- 这个计数器用于追踪特定条件下的事件次数。在特定条件下(如
amr_judge_cancel 或amr_judge_fail )清零,或者在更新有效时递增。
- 这个计数器用于追踪特定条件下的事件次数。在特定条件下(如
-
地址和有效字节寄存器:
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];
-
状态机逻辑:
- 根据当前状态(
amr_state )和其他条件,决定下一个状态(amr_next_state )。状态机从JUDGE 开始,根据计数器amr_cnt 的值和其他条件,可能转换到MEM_SET_0 ,MEM_SET_1 ,MEM_SET_2 等状态。
- 根据当前状态(
-
计数器状态改变信号(
amr_cnt_met_set ):- 当计数器达到特定值时(例如 6’d8),这个信号被置位。
-
更新有效信号(
amr_update_vld ):- 当写缓冲器弹出有效时,这个信号被置位。
-
地址命中逻辑:
amr_addr_hit :根据地址和有效字节的匹配情况决定是否命中。amr_addr_distance :计算当前地址和写缓冲器地址之间的距离。
-
下一个有效字节寄存器(
amr_bytes_vld_next ):- 根据当前有效字节和写缓冲器的有效字节更新下一个有效字节。
-
判断逻辑:
amr_judge_cancel :在特定条件下,如指令缓存一致性检查空闲或无操作请求,需要取消判断。amr_judge_fail :在地址不命中或存在交叉命中时失败。amr_judge_flush :将amr_judge_cancel 和amr_judge_fail 的结果组合以决定是否需要刷新。
-
非空闲信号(
amr_not_idle ):- 根据状态和计数器决定 AMR 是否空闲。
-
与其他模块的接口:
lsu_had_amr_state :输出 AMR 模块的当前状态供硬件抽象层(Hardware Abstraction Layer, HAD)使用。