Skip to content

Commit

Permalink
immu: Change busy logic to not use ack
Browse files Browse the repository at this point in the history
Issue #122

An additional fix for back to back spr writes.  I was seeing that during
back to back writes the busy_o signal would go low after the first spr
write complete. This caused the fetch to proceed and present bad data to
the bus caused by the second in-progress write.  This is because ack
goes high during the first write and stays high as long as we are
writing.

Introducing a busy tracker based on the assuming that spr transactions
take 2 clocks to complete.
  • Loading branch information
stffrdhrn authored and skristiansson committed Jul 1, 2021
1 parent 040a89f commit b234f27
Showing 1 changed file with 29 additions and 9 deletions.
38 changes: 29 additions & 9 deletions rtl/verilog/mor1kx_immu.v
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ module mor1kx_immu
wire itlb_trans_spr_cs;
reg itlb_trans_spr_cs_r;

wire itlb_match_spr_tx;
reg itlb_match_spr_tx_r;
wire itlb_match_spr_tx_busy;
wire itlb_trans_spr_tx;
reg itlb_trans_spr_tx_r;
wire itlb_trans_spr_tx_busy;

wire immucr_spr_cs;
reg immucr_spr_cs_r;
reg [OPTION_OPERAND_WIDTH-1:0] immucr;
Expand Down Expand Up @@ -174,22 +181,35 @@ endgenerate
if (itlb_match_reload_we & !tlb_reload_huge)
itlb_match_we[j] = 1;
if (j[WAYS_WIDTH-1:0] == spr_way_idx)
itlb_match_we[j] = itlb_match_spr_cs & spr_bus_we_i & !itlb_match_spr_cs_r;
itlb_match_we[j] = itlb_match_spr_tx & spr_bus_we_i;

itlb_trans_we[j] = 0;
if (itlb_trans_reload_we & !tlb_reload_huge)
itlb_trans_we[j] = 1;
if (j[WAYS_WIDTH-1:0] == spr_way_idx)
itlb_trans_we[j] = itlb_trans_spr_cs & spr_bus_we_i & !itlb_trans_spr_cs_r;
itlb_trans_we[j] = itlb_trans_spr_tx & spr_bus_we_i;
end
end

assign pagefault_o = (supervisor_mode_i ? !sxe : !uxe) &
!tlb_reload_busy_o & !busy_o;

assign busy_o = ((itlb_match_spr_cs | itlb_trans_spr_cs) & !spr_bus_ack |
(itlb_match_spr_cs_r | itlb_trans_spr_cs_r) &
spr_bus_ack & !spr_bus_ack_r) & enable_i;
// itlb_*_spr_tx - signals to indicate the start of a read/write
// transaction
// itlb_*_spr_cs_r is registered 1 clock cycle delay of itlb_*_spr_cs
assign itlb_match_spr_tx = itlb_match_spr_cs & !itlb_match_spr_cs_r;
assign itlb_trans_spr_tx = itlb_trans_spr_cs & !itlb_trans_spr_cs_r;

// When we have SPR writes they cause the immu to output bad data for
// 2 clock cycles. For 2 clocks we signal busy so fetch does not proceed.
always @(posedge clk) begin
itlb_match_spr_tx_r <= itlb_match_spr_tx;
itlb_trans_spr_tx_r <= itlb_trans_spr_tx;
end
assign itlb_match_spr_tx_busy = itlb_match_spr_tx | itlb_match_spr_tx_r;
assign itlb_trans_spr_tx_busy = itlb_trans_spr_tx | itlb_trans_spr_tx_r;

assign busy_o = enable_i & (itlb_match_spr_tx_busy | itlb_trans_spr_tx_busy);

assign spr_way_idx_full = {spr_bus_addr_i[10], spr_bus_addr_i[8]};
assign spr_way_idx = spr_way_idx_full[WAYS_WIDTH-1:0];
Expand Down Expand Up @@ -231,16 +251,16 @@ endgenerate
assign itlb_trans_spr_cs = spr_bus_stb_i & (spr_bus_addr_i[15:11] == 5'd2) &
|spr_bus_addr_i[10:9] & spr_bus_addr_i[7];

assign itlb_match_addr = itlb_match_spr_cs & !itlb_match_spr_cs_r ?
assign itlb_match_addr = itlb_match_spr_tx ?
spr_bus_addr_i[OPTION_IMMU_SET_WIDTH-1:0] :
virt_addr_i[13+(OPTION_IMMU_SET_WIDTH-1):13];
assign itlb_trans_addr = itlb_trans_spr_cs & !itlb_trans_spr_cs_r ?
assign itlb_trans_addr = itlb_trans_spr_tx ?
spr_bus_addr_i[OPTION_IMMU_SET_WIDTH-1:0] :
virt_addr_i[13+(OPTION_IMMU_SET_WIDTH-1):13];

assign itlb_match_din = itlb_match_spr_cs & spr_bus_we_i & !itlb_match_spr_cs_r ?
assign itlb_match_din = itlb_match_spr_tx & spr_bus_we_i ?
spr_bus_dat_i : itlb_match_reload_din;
assign itlb_trans_din = itlb_trans_spr_cs & spr_bus_we_i & !itlb_trans_spr_cs_r ?
assign itlb_trans_din = itlb_trans_spr_tx & spr_bus_we_i ?
spr_bus_dat_i : itlb_trans_reload_din;

assign itlb_match_huge_addr = virt_addr_i[24+(OPTION_IMMU_SET_WIDTH-1):24];
Expand Down

0 comments on commit b234f27

Please sign in to comment.