//==========================================================
// Pass data to data entry
//==========================================================
//------------------judge r signal--------------------------
//----------r id------------------------
assign lfb_biu_r_id_hit = biu_lsu_r_vld
&& (biu_lsu_r_id[4:3] == BIU_LFB_ID_T);
assign lfb_biu_id_2to0[2:0] = biu_lsu_r_id[2:0];
assign lfb_addr_entry_resp_set[LFB_ADDR_ENTRY-1:0] =
{
LFB_ADDR_ENTRY{
lfb_biu_r_id_hit && lfb_data_not_full}}
& lfb_r_id_hit_addr_ptr[LFB_ADDR_ENTRY-1:0];
//----------r resp----------------------
// &Force("bus","biu_lsu_r_resp",3,0); @359
assign lfb_r_resp_share = biu_lsu_r_resp[3];
assign lfb_r_resp_err = (biu_lsu_r_resp[1:0] == DECERR)
|| (biu_lsu_r_resp[1:0] == SLVERR);
//------------------create ptr------------------------------
// &CombBeg; @365
always @( lfb_data_entry_vld[1:0])
begin
lfb_data_create_ptr[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
1'b0}};
casez(lfb_data_entry_vld[LFB_DATA_ENTRY-1:0])
2'b?0:lfb_data_create_ptr[0] = 1'b1;
2'b01:lfb_data_create_ptr[1] = 1'b1;
default:lfb_data_create_ptr[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
1'b0}};
endcase
// &CombEnd; @372
end
//------------------create signal---------------------------
//if no vld, or only one vld and full, then create
assign lfb_data_wait_surplus = |lfb_data_entry_wait_surplus[LFB_DATA_ENTRY-1:0];
assign lfb_data_create_vld = lfb_biu_r_id_hit
&& !lfb_data_wait_surplus;
assign lfb_data_create_dp_vld = lfb_data_create_vld;
assign lfb_data_create_gateclk_en = lfb_data_create_vld;
assign lfb_data_entry_create_vld[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
lfb_data_create_vld}}
& lfb_data_create_ptr[LFB_DATA_ENTRY-1:0];
assign lfb_data_entry_create_dp_vld[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
lfb_data_create_dp_vld}}
& lfb_data_create_ptr[LFB_DATA_ENTRY-1:0];
assign lfb_data_entry_create_gateclk_en[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
lfb_data_create_gateclk_en}}
& lfb_data_create_ptr[LFB_DATA_ENTRY-1:0];
//------------------first pass ptr--------------------------
// &CombBeg; @393
always @( lfb_biu_id_2to0[2:0])
begin
lfb_r_id_hit_addr_ptr[LFB_ADDR_ENTRY-1:0] = {
LFB_ADDR_ENTRY{
1'b0}};
case(lfb_biu_id_2to0[2:0])
3'd0:lfb_r_id_hit_addr_ptr[0] = 1'b1;
3'd1:lfb_r_id_hit_addr_ptr[1] = 1'b1;
3'd2:lfb_r_id_hit_addr_ptr[2] = 1'b1;
3'd3:lfb_r_id_hit_addr_ptr[3] = 1'b1;
3'd4:lfb_r_id_hit_addr_ptr[4] = 1'b1;
3'd5:lfb_r_id_hit_addr_ptr[5] = 1'b1;
3'd6:lfb_r_id_hit_addr_ptr[6] = 1'b1;
3'd7:lfb_r_id_hit_addr_ptr[7] = 1'b1;
default:lfb_r_id_hit_addr_ptr[LFB_ADDR_ENTRY-1:0] = {
LFB_ADDR_ENTRY{
1'b0}};
endcase
// &CombEnd; @406
end
assign lfb_pass_addr_5to4[1:0] = {
2{
lfb_r_id_hit_addr_ptr[0]}} & lfb_addr_entry_addr_tto4_0[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[1]}} & lfb_addr_entry_addr_tto4_1[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[2]}} & lfb_addr_entry_addr_tto4_2[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[3]}} & lfb_addr_entry_addr_tto4_3[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[4]}} & lfb_addr_entry_addr_tto4_4[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[5]}} & lfb_addr_entry_addr_tto4_5[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[6]}} & lfb_addr_entry_addr_tto4_6[1:0]
| {
2{
lfb_r_id_hit_addr_ptr[7]}} & lfb_addr_entry_addr_tto4_7[1:0];
//lfb first pass ptr is used to assign data_entry pass_ptr
// &CombBeg; @418
always @( lfb_pass_addr_5to4[1:0])
begin
lfb_first_pass_ptr[3:0] = 4'b0;
case(lfb_pass_addr_5to4[1:0])
2'd0:lfb_first_pass_ptr[0] = 1'b1;
2'd1:lfb_first_pass_ptr[1] = 1'b1;
2'd2:lfb_first_pass_ptr[2] = 1'b1;
2'd3:lfb_first_pass_ptr[3] = 1'b1;
default:lfb_first_pass_ptr[3:0] = 4'b0;
endcase
// &CombEnd; @427
end
这部分代码主要处理从BIU(Bus Interface Unit)接收的数据,并将其传递给加载填充缓冲区(Load Fill Buffer, LFB)的数据条目。关键部分包括:
处理BIU返回的响应信号(Judging BIU Response Signal):
lfb_biu_r_id_hit
:检测BIU返回的ID是否与LFB期望的ID匹配。lfb_biu_id_2to0
:获取BIU返回数据的ID的低3位。
生成数据创建指针(Generate Data Creation Pointer):
lfb_data_create_ptr
:根据LFB数据条目的有效性,生成一个指向创建位置的指针。
创建数据条目信号(Create Data Entry Signal):
lfb_data_create_vld
、lfb_data_create_dp_vld
、lfb_data_create_gateclk_en
:基于BIU的响应和LFB的状态生成数据条目的创建信号。
传递地址到数据条目(Pass Address to Data Entry):
lfb_pass_addr_5to4
:从地址条目传递地址到数据条目。lfb_first_pass_ptr
:根据传递的地址生成第一次传递指针。
处理BIU返回的数据:
- 判断BIU的返回数据是否有错误(如DECERR或SLVERR)。
- 根据BIU返回的ID和响应,更新LFB的相应地址条目。
更新LFB状态:
- 根据BIU的响应和LFB内部逻辑,更新LFB的状态,如是否有额外的等待(
lfb_data_wait_surplus
)。
- 根据BIU的响应和LFB内部逻辑,更新LFB的状态,如是否有额外的等待(
总体而言,这部分代码负责处理从BIU返回的数据,并将其正确地安置在LFB的数据条目中,以保证数据缓存的一致性和处理器对内存的有效访问。
//==========================================================
// Linefill state machine
//==========================================================
//----------------------registers---------------------------
//+-----+
//| vld |
//+-----+
always @(posedge lfb_lf_sm_clk or negedge cpurst_b)
begin
if (!cpurst_b)
lfb_lf_sm_vld <= 1'b0;
else if(lfb_lf_sm_req)
lfb_lf_sm_vld <= 1'b1;
else if(lfb_lf_sm_cnt)
lfb_lf_sm_vld <= 1'b0;
end
//+------------+---------+---------+------+
//| refill way | addr_id | data_id | addr |
//+------------+---------+---------+------+
always @(posedge lfb_lf_sm_req_clk or negedge cpurst_b)
begin
if (!cpurst_b)
begin
lfb_lf_sm_dcache_share <= 1'b0;
lfb_lf_sm_refill_way <= 1'b0;
lfb_lf_sm_addr_id[LFB_ADDR_ENTRY-1:0] <= {
LFB_ADDR_ENTRY{
1'b0}};
lfb_lf_sm_data_id[LFB_DATA_ENTRY-1:0] <= {
LFB_DATA_ENTRY{
1'b0}};
lfb_lf_sm_addr_tto6[`PA_WIDTH-7:0] <= {
`PA_WIDTH-6{
1'b0}};
end
else if(lfb_lf_sm_req && lfb_lf_sm_permit)
begin
lfb_lf_sm_dcache_share <= lfb_lf_sm_data_dcache_share;
lfb_lf_sm_refill_way <= lfb_lf_sm_req_refill_way;
lfb_lf_sm_addr_id[LFB_ADDR_ENTRY-1:0] <= lfb_lf_sm_req_addr_ptr[LFB_ADDR_ENTRY-1:0];
lfb_lf_sm_data_id[LFB_DATA_ENTRY-1:0] <= lfb_lf_sm_req_data_ptr[LFB_DATA_ENTRY-1:0];
lfb_lf_sm_addr_tto6[`PA_WIDTH-7:0] <= lfb_lf_sm_req_addr_tto6[`PA_WIDTH-7:0];
end
end
//+-----+------+
//| cnt | bias |
//+-----+------+
//cnt is used for control path, bias is used for data path
always @(posedge lfb_lf_sm_clk or negedge cpurst_b)
begin
if (!cpurst_b)
lfb_lf_sm_cnt <= 1'b0;
else if(lfb_lf_sm_create_vld)
lfb_lf_sm_cnt <= 1'b0;
else if(dcache_arb_lfb_ld_grnt)
lfb_lf_sm_cnt <= !lfb_lf_sm_cnt;
end
这段代码是负责处理加载填充缓冲区(Load Fill Buffer, LFB)中的linefill状态机(Linefill State Machine)。状态机管理着从外部内存加载数据到LFB的过程。主要组成部分如下:
Valid Register (
lfb_lf_sm_vld
):- 这个寄存器指示状态机是否处于有效状态。它在接收到linefill请求(
lfb_lf_sm_req
)时被设置,当计数器(lfb_lf_sm_cnt
)活跃时被重置。
- 这个寄存器指示状态机是否处于有效状态。它在接收到linefill请求(
State Machine Registers:
这些寄存器存储状态机的当前状态,包括:
lfb_lf_sm_dcache_share
:指示当前linefill是否与数据缓存共享。lfb_lf_sm_refill_way
:存储linefill操作的方式。lfb_lf_sm_addr_id
:地址条目的ID。lfb_lf_sm_data_id
:数据条目的ID。lfb_lf_sm_addr_tto6
:当前操作地址的部分字段。
这些寄存器在状态机接收到有效的linefill请求且被允许执行时更新。
Count Register (
lfb_lf_sm_cnt
):- 这个寄存器用于控制状态机的路径,当数据缓存向LFB发出加载授权(
dcache_arb_lfb_ld_grnt
)时,它会改变其值。这有助于控制状态机的流程,确保正确地处理加载操作。
- 这个寄存器用于控制状态机的路径,当数据缓存向LFB发出加载授权(
综上所述,这部分代码是实现LFB功能的关键,它控制着从内存到LFB的数据加载过程,确保数据以正确的方式被加载和更新。通过这种方式,LFB有效地协调了缓存和内存之间的数据交换
//------------------create singal---------------------------
assign lfb_lf_sm_permit = !lfb_lf_sm_vld || lfb_lf_sm_cnt;
assign lfb_lf_sm_req = |lfb_data_entry_lf_sm_req[LFB_DATA_ENTRY-1:0];
assign lfb_lf_sm_create_vld = lfb_lf_sm_req
&& lfb_lf_sm_permit;
//------------------create info-----------------------------
// &CombBeg; @490
always @( lfb_data_entry_lf_sm_req[1:0])
begin
lfb_lf_sm_req_data_ptr[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
1'b0}};
casez(lfb_data_entry_lf_sm_req[LFB_DATA_ENTRY-1:0])
2'b?1:lfb_lf_sm_req_data_ptr[0] = 1'b1;
2'b10:lfb_lf_sm_req_data_ptr[1] = 1'b1;
default:lfb_lf_sm_req_data_ptr[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
1'b0}};
endcase
// &CombEnd; @497
end
assign lfb_lf_sm_data_grnt[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
lfb_lf_sm_create_vld}}
& lfb_lf_sm_req_data_ptr[LFB_DATA_ENTRY-1:0];
assign lfb_lf_sm_req_addr_ptr[LFB_ADDR_ENTRY-1:0] = {
LFB_ADDR_ENTRY{
lfb_lf_sm_req_data_ptr[0]}}
& lfb_data_entry_addr_id_0[LFB_ADDR_ENTRY-1:0]
| {
LFB_ADDR_ENTRY{
lfb_lf_sm_req_data_ptr[1]}}
& lfb_data_entry_addr_id_1[LFB_ADDR_ENTRY-1:0];
assign lfb_lf_sm_req_addr_tto6[`PA_WIDTH-7:0] =
{
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[0]}} & lfb_addr_entry_addr_tto4_0[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[1]}} & lfb_addr_entry_addr_tto4_1[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[2]}} & lfb_addr_entry_addr_tto4_2[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[3]}} & lfb_addr_entry_addr_tto4_3[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[4]}} & lfb_addr_entry_addr_tto4_4[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[5]}} & lfb_addr_entry_addr_tto4_5[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[6]}} & lfb_addr_entry_addr_tto4_6[`PA_WIDTH-5:2]
| {
`PA_WIDTH-6{
lfb_lf_sm_req_addr_ptr[7]}} & lfb_addr_entry_addr_tto4_7[`PA_WIDTH-5:2];
assign lfb_lf_sm_req_depd = |(lfb_lf_sm_req_addr_ptr[LFB_ADDR_ENTRY-1:0] & lfb_addr_entry_depd[LFB_ADDR_ENTRY-1:0]);
assign lfb_lf_sm_req_refill_way = |(lfb_lf_sm_req_addr_ptr[LFB_ADDR_ENTRY-1:0] & lfb_addr_entry_refill_way[LFB_ADDR_ENTRY-1:0]);
assign lfb_lf_sm_data_dcache_share = |(lfb_lf_sm_req_data_ptr[LFB_DATA_ENTRY-1:0] & lfb_data_entry_dcache_share[LFB_DATA_ENTRY-1:0]);
//------------------refill wakeup req-----------------------
assign lfb_lf_sm_refill_wakeup = lfb_lf_sm_req_depd
&& lfb_lf_sm_create_vld;
//----------------------settle addr-------------------------
//-----------------data-----------------
assign lfb_lf_sm_data512[511:0] = {
512{
lfb_lf_sm_data_id[0]}} & lfb_data_entry_data_0[511:0]
| {
512{
lfb_lf_sm_data_id[1]}} & lfb_data_entry_data_1[511:0];
assign lfb_lf_sm_data256[255:0] = lfb_lf_sm_cnt
? lfb_lf_sm_data512[511:256]
: lfb_lf_sm_data512[255:0];
assign lfb_lf_sm_data_settle[255:0] = lfb_lf_sm_refill_way
? {
lfb_lf_sm_data256[127:0],lfb_lf_sm_data256[255:128]}
: lfb_lf_sm_data256[255:0];
这段代码详细描述了加载填充缓冲区(Load Fill Buffer, LFB)中的linefill状态机逻辑。这个状态机负责管理数据从内存到LFB的加载过程。
状态机创建信号 (
lfb_lf_sm_permit
,lfb_lf_sm_req
,lfb_lf_sm_create_vld
):lfb_lf_sm_permit
:当状态机处于非激活状态或计数器激活时,允许创建新的linefill请求。lfb_lf_sm_req
:如果有任何数据条目需要linefill请求,则设置。lfb_lf_sm_create_vld
:当存在有效的linefill请求且允许执行时设置。
创建信息 (
lfb_lf_sm_req_data_ptr
):- 此段代码识别发起linefill请求的数据条目,并生成相应的指针。
linefill状态机寄存器:
- 包括缓存共享标记(
lfb_lf_sm_dcache_share
)、要填充的方式(lfb_lf_sm_refill_way
)、地址ID和数据ID。
- 包括缓存共享标记(
linefill唤醒请求 (
lfb_lf_sm_refill_wakeup
):- 当linefill请求与依赖项相关联且有效时,产生唤醒信号。
数据安置 (
lfb_lf_sm_data_settle
):- 此段代码处理从数据条目接收的512位数据,根据当前的计数器状态和填充方式,选择适当的256位数据进行处理。
综上所述,这部分代码的主要功能是协调和管理LFB中的linefill操作,确保数据以正确的顺序和方式从内存加载到LFB中。
//----------------------cache interface---------------------
assign lfb_dcache_arb_ld_req = lfb_lf_sm_vld;
assign lfb_dcache_arb_st_req = lfb_lf_sm_vld;
assign lfb_dcache_arb_serial_req = lfb_lf_sm_vld && !lfb_lf_sm_cnt;
//---------------tag array--------------
// &Force("output", "lfb_dcache_arb_ld_tag_req"); @644
assign lfb_dcache_arb_ld_tag_req = lfb_lf_sm_vld && lfb_lf_sm_cnt;
assign lfb_dcache_arb_ld_tag_gateclk_en = lfb_dcache_arb_ld_tag_req;
// &Force("output", "lfb_dcache_arb_ld_tag_idx"); @647
assign lfb_dcache_arb_ld_tag_idx[8:0] = lfb_lf_sm_addr_tto6[8:0];
assign lfb_dcache_arb_ld_tag_din[53:0] = {
1'b1,lfb_lf_sm_addr_tto6[`PA_WIDTH-7:8],1'b1,lfb_lf_sm_addr_tto6[`PA_WIDTH-7:8]};
// &Force("output", "lfb_dcache_arb_ld_tag_wen"); @654
assign lfb_dcache_arb_ld_tag_wen[1:0] = lfb_lf_sm_cnt
? {
lfb_lf_sm_refill_way,!lfb_lf_sm_refill_way}
: 2'b0;
assign lfb_dcache_arb_st_tag_req = lfb_dcache_arb_ld_tag_req;
assign lfb_dcache_arb_st_tag_gateclk_en = lfb_dcache_arb_ld_tag_req;
assign lfb_dcache_arb_st_tag_idx[8:0] = lfb_dcache_arb_ld_tag_idx[8:0];
assign lfb_dcache_arb_st_tag_din[51:0] = {
lfb_lf_sm_addr_tto6[`PA_WIDTH-7:8],lfb_lf_sm_addr_tto6[`PA_WIDTH-7:8]};
assign lfb_dcache_arb_st_tag_wen[1:0] = lfb_dcache_arb_ld_tag_wen[1:0];
//---------------dirty array------------
assign lfb_dcache_arb_st_dirty_req = lfb_dcache_arb_ld_tag_req;
assign lfb_dcache_arb_st_dirty_gateclk_en = lfb_dcache_arb_ld_tag_req;
assign lfb_dcache_arb_st_dirty_idx[8:0] = lfb_lf_sm_addr_tto6[8:0];
assign lfb_dcache_arb_st_dirty_din[6:0] = {
!lfb_lf_sm_refill_way,1'b0,lfb_lf_sm_dcache_share,1'b1,1'b0,lfb_lf_sm_dcache_share,1'b1};
assign lfb_dcache_arb_st_dirty_wen[6:0] = {
1'b1,{
3{
lfb_lf_sm_refill_way}},{
3{
!lfb_lf_sm_refill_way}}};
//---------------data array-------------
assign lfb_dcache_arb_ld_data_gateclk_en[7:0] = {
8{
lfb_lf_sm_vld}};
assign lfb_dcache_arb_ld_data_idx[10:0] = {
lfb_lf_sm_addr_tto6[8:0],lfb_lf_sm_cnt,lfb_lf_sm_refill_way};
assign lfb_dcache_arb_ld_data_low_din[127:0] = lfb_lf_sm_data_settle[127:0];
assign lfb_dcache_arb_ld_data_high_din[127:0] = lfb_lf_sm_data_settle[255:128];
//assign lsu_dcache_ld_data_wen[31:0] = 32'hffff_ffff;
//----------------------pop signal--------------------------
assign lfb_lf_sm_addr_pop_req[LFB_ADDR_ENTRY-1:0] = {
LFB_ADDR_ENTRY{
lfb_lf_sm_vld && lfb_lf_sm_cnt}}
& lfb_lf_sm_addr_id[LFB_ADDR_ENTRY-1:0];
assign lfb_lf_sm_data_pop_req[LFB_DATA_ENTRY-1:0] = {
LFB_DATA_ENTRY{
lfb_lf_sm_vld && lfb_lf_sm_cnt}}
& lfb_lf_sm_data_id[LFB_DATA_ENTRY-1:0];
assign lfb_data_addr_pop_req[LFB_ADDR_ENTRY-1:0] = lfb_data_entry_addr_pop_req_0[LFB_ADDR_ENTRY-1:0]
| lfb_data_entry_addr_pop_req_1[LFB_ADDR_ENTRY-1:0];
这段代码展示了加载填充缓冲区(LFB)与缓存(例如数据缓存)接口的逻辑。关键部分包括:
缓存接口信号:
lfb_dcache_arb_ld_req
和lfb_dcache_arb_st_req
:当状态机有效时,向缓存发送加载(ld)和存储(st)请求。lfb_dcache_arb_serial_req
:状态机有效且计数器未激活时,发送序列请求。
标签数组(Tag Array)接口:
- 管理数据缓存中的标签部分,包括读取和写入操作。当状态机有效且计数器激活时,生成相关的控制信号。
脏位数组(Dirty Array)接口:
- 用于标记缓存中脏数据(已被修改但尚未写回到内存)。控制信号与标签数组接口类似。
数据数组(Data Array)接口:
- 管理缓存中的数据部分。根据状态机的当前状态和需要填充的方式,选择适当的数据进行处理。
弹出信号(Pop Signal):
- 当状态机完成一次操作并准备进行下一步操作时,生成相应的弹出信号。
//==========================================================
// Maintain wakeup queue
//==========================================================
//----------------------registers---------------------------
//+--------------+
//| wakeup_queue |
//+--------------+
//the queue stores the instructions waiting for wakeup
//the 12 bit of wakeup_queue is for mcic
always @(posedge lfb_wakeup_queue_clk or negedge cpurst_b)
begin
if (!cpurst_b)
lfb_wakeup_queue[LSIQ_ENTRY:0] <= {
LSIQ_ENTRY+1{
1'b0}};
else if(rtu_yy_xx_flush)
lfb_wakeup_queue[LSIQ_ENTRY:0] <= {
LSIQ_ENTRY+1{
1'b0}};
else if(ld_da_lfb_set_wakeup_queue || lfb_pop_depd_ff)
lfb_wakeup_queue[LSIQ_ENTRY:0] <= lfb_wakeup_queue_next[LSIQ_ENTRY:0];
end
//+-------------+
//| depd_pop_ff |
//+-------------+
//if depd pop, this will set to 1, and clear wakeup_queue next cycle
// &Force("output","lfb_pop_depd_ff"); @720
always @(posedge lfb_clk or negedge cpurst_b)
begin
if (!cpurst_b)
lfb_pop_depd_ff <= 1'b0;
else if(lfb_addr_pop_depd
|| lfb_addr_pop_discard_vld
|| rb_lfb_boundary_depd_wakeup
|| lfb_lf_sm_refill_wakeup
|| lm_lfb_depd_wakeup)
lfb_pop_depd_ff <= 1'b1;
else
lfb_pop_depd_ff <= 1'b0;
end
//----------------forward to depd_pop_ff------------------
assign lfb_addr_pop_depd = |(lfb_addr_entry_pop_vld[LFB_ADDR_ENTRY-1:0]
& lfb_addr_entry_depd[LFB_ADDR_ENTRY-1:0]);
assign lfb_addr_pop_discard_vld = |(lfb_addr_entry_pop_vld[LFB_ADDR_ENTRY-1:0]
& lfb_addr_entry_discard_vld[LFB_ADDR_ENTRY-1:0]);
//------------------update wakeup queue---------------------
assign lfb_wakeup_queue_after_pop[LSIQ_ENTRY:0] = lfb_pop_depd_ff
? {
LSIQ_ENTRY+1{
1'b0}}
: lfb_wakeup_queue[LSIQ_ENTRY:0];
assign lfb_wakeup_queue_next[LSIQ_ENTRY:0] = lfb_wakeup_queue_after_pop[LSIQ_ENTRY:0]
| {
LSIQ_ENTRY+1{
ld_da_lfb_set_wakeup_queue}}
& ld_da_lfb_wakeup_queue_next[LSIQ_ENTRY:0];
//------------------------wakeup----------------------------
assign lfb_depd_wakeup[LSIQ_ENTRY-1:0] = lfb_pop_depd_ff
? lfb_wakeup_queue[LSIQ_ENTRY-1:0]
: {
LSIQ_ENTRY{
1'b0}};
assign lfb_mcic_wakeup = (lfb_pop_depd_ff || rtu_yy_xx_flush)
? lfb_wakeup_queue[LSIQ_ENTRY]
: 1'b0;
//==========================================================
// for avoid deadlock with no rready
//==========================================================
assign lfb_addr_create_vld = lfb_addr_rb_create_vld || lfb_addr_pfu_create_vld;
assign lfb_no_rcl_cnt_create[3:0] = {
3'b0,lfb_addr_create_vld && cp0_lsu_dcache_en};
assign lfb_no_rcl_cnt_pop[3:0] = {
3'b0,vb_lfb_rcl_done}
+ {
3'b0,snq_lfb_bypass_invalid[0]}
+ {
3'b0,snq_lfb_bypass_invalid[1]};
assign lfb_no_rcl_cnt_updt_vld = lfb_addr_create_vld && cp0_lsu_dcache_en
|| vb_lfb_rcl_done
|| |snq_lfb_bypass_invalid[1:0];
assign lfb_no_rcl_cnt_updt_val[3:0] = lfb_no_rcl_cnt[3:0]
+ lfb_no_rcl_cnt_create[3:0]
- lfb_no_rcl_cnt_pop[3:0];
always @(posedge lfb_clk or negedge cpurst_b)
begin
if (!cpurst_b)
lfb_no_rcl_cnt[3:0] <= 4'b0;
else if(lfb_no_rcl_cnt_updt_vld)
lfb_no_rcl_cnt[3:0] <= lfb_no_rcl_cnt_updt_val[3:0];
end
assign lfb_nc_rready_grnt = (lfb_no_rcl_cnt[3:0] <= 4'd1);
assign lfb_ca_rready_grnt = (lfb_no_rcl_cnt[3:0] < 4'd1);
assign lfb_rb_nc_rready_grnt = lfb_nc_rready_grnt;
assign lfb_rb_ca_rready_grnt = lfb_ca_rready_grnt;
assign lfb_pfu_rready_grnt = lfb_ca_rready_grnt;
//for rready,if all addr entry has resp,then not deassert rready
assign lfb_addr_all_resp = !(|lfb_addr_entry_not_resp[LFB_ADDR_ENTRY-1:0]);
//==========================================================
// Interface to other module
//==========================================================
//---------------------hit idx------------------------------
assign lfb_ld_da_hit_idx = |lfb_addr_entry_ld_da_hit_idx[LFB_ADDR_ENTRY-1:0];
assign lfb_st_da_hit_idx = |lfb_addr_entry_st_da_hit_idx[LFB_ADDR_ENTRY-1:0];
assign lfb_rb_biu_req_hit_idx = |lfb_addr_entry_rb_biu_req_hit_idx[LFB_ADDR_ENTRY-1:0];
assign lfb_pfu_biu_req_hit_idx = |lfb_addr_entry_pfu_biu_req_hit_idx[LFB_ADDR_ENTRY-1:0];
//assign lfb_snq_stall = |lfb_addr_entry_snq_create_hit_idx[LFB_ADDR_ENTRY-1:0];
assign lfb_wmb_read_req_hit_idx = |lfb_addr_entry_wmb_read_req_hit_idx[LFB_ADDR_ENTRY-1:0];
assign lfb_wmb_write_req_hit_idx= |lfb_addr_entry_wmb_write_req_hit_idx[LFB_ADDR_ENTRY-1:0];
//for snq
// &Force("output","lfb_snq_bypass_data_id"); @804
assign lfb_snq_bypass_hit = |lfb_addr_entry_snq_bypass_hit[LFB_ADDR_ENTRY-1:0];
assign lfb_snq_bypass_data_id[1:0] = lfb_data_entry_vld[LFB_DATA_ENTRY-1:0]
& {
lfb_addr_entry_snq_bypass_hit[LFB_ADDR_ENTRY-1:0] == lfb_data_entry_addr_id_1[LFB_ADDR_ENTRY-1:0],
lfb_addr_entry_snq_bypass_hit[LFB_ADDR_ENTRY-1:0] == lfb_data_entry_addr_id_0[LFB_ADDR_ENTRY-1:0]};
assign lfb_snq_bypass_share = |(lfb_snq_bypass_data_id[1:0] & lfb_data_entry_dcache_share[1:0]);
//----------------interface to biu--------------------------
assign lfb_data_not_full = !(&lfb_data_entry_full[LFB_DATA_ENTRY-1:0]);
assign lsu_biu_r_linefill_ready = lfb_data_not_full || lfb_addr_all_resp;
//------------------full/empty signal-----------------------
assign lfb_addr_empty = !(|lfb_addr_entry_vld[LFB_ADDR_ENTRY-1:0]);
assign lfb_data_empty = !(|lfb_data_entry_vld[LFB_DATA_ENTRY-1:0]);
// &Force("output","lfb_empty"); @816
assign lfb_empty = lfb_addr_empty && lfb_data_empty && !lfb_vb_req_unmask;
// &Force("output","lfb_addr_full"); @818
assign lfb_addr_full = &lfb_addr_entry_vld[LFB_ADDR_ENTRY-1:0];
assign lfb_addr_less2 = &(lfb_addr_entry_vld[LFB_ADDR_ENTRY-1:0]
| lfb_addr_create_ptr[LFB_ADDR_ENTRY-1:0]);
assign lsu_had_lfb_addr_entry_vld[LFB_ADDR_ENTRY-1:0] = lfb_addr_entry_vld[LFB_ADDR_ENTRY-1:0];
assign lsu_had_lfb_addr_entry_rcl_done[LFB_ADDR_ENTRY-1:0] = lfb_addr_entry_rcl_done[LFB_ADDR_ENTRY-1:0];
assign lsu_had_lfb_addr_entry_dcache_hit[LFB_ADDR_ENTRY-1:0]= lfb_addr_entry_dcache_hit[LFB_ADDR_ENTRY-1:0];
assign lsu_had_lfb_data_entry_vld[LFB_DATA_ENTRY-1:0] = lfb_data_entry_vld[LFB_DATA_ENTRY-1:0];
assign lsu_had_lfb_data_entry_last[LFB_DATA_ENTRY-1:0] = lfb_data_entry_last[LFB_DATA_ENTRY-1:0];
assign lsu_had_lfb_wakeup_queue[LSIQ_ENTRY:0] = lfb_wakeup_queue[LSIQ_ENTRY:0];
assign lsu_had_lfb_lf_sm_vld = lfb_lf_sm_vld;
//==========================================================
// interface to hpcp
//==========================================================
assign ld_hit_prefetch = |ld_hit_prefetch_first[LFB_ADDR_ENTRY-1:0];
这段代码涉及多个关键部分,主要是关于加载填充缓冲区(LFB)的唤醒队列管理、避免死锁、与其他模块的接口以及性能计数器的接口。具体来说:
唤醒队列管理:
lfb_wakeup_queue
:存储等待唤醒的指令。lfb_pop_depd_ff
:当有依赖项被弹出时设置为1,随后清除唤醒队列。- 唤醒信号被发送到相关的部分,以通知等待的指令可以继续执行。
避免死锁:
lfb_no_rcl_cnt
:追踪当前没有接收到响应的LFB创建请求的数量。- 根据当前的未响应请求数量,控制是否授予
rready
信号。
与其他模块的接口:
- 提供一系列信号,如
lfb_ld_da_hit_idx
和lfb_st_da_hit_idx
,用于指示LFB中是否有与特定请求相匹配的项。 - 处理来自BIU(总线接口单元)的响应,判断数据是否完整。
- 提供一系列信号,如
性能计数器接口:
ld_hit_prefetch
:指示是否有加载操作命中预取。