diff --git a/rtl/verilog/mor1kx_immu.v b/rtl/verilog/mor1kx_immu.v index c284ef6f..06d9632c 100644 --- a/rtl/verilog/mor1kx_immu.v +++ b/rtl/verilog/mor1kx_immu.v @@ -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; @@ -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]; @@ -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];