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)使用。