🐛 Fix delivery of faulting address exception

The page table walker was unconditionally delivering
exceptions even when the instruction fetch stage
wasn't any longer interested in it.
This commit is contained in:
Florian Zaruba 2017-08-29 14:20:13 +02:00
parent 38ea32047b
commit 2b97d2b4b9
2 changed files with 32 additions and 22 deletions

View file

@ -93,6 +93,7 @@ module mmu #(
logic ptw_active; // PTW is currently walking a page table
logic walking_instr; // PTW is walking because of an ITLB miss
logic ptw_error; // PTW threw an exception
logic [63:0] faulting_address;
logic update_is_2M;
logic update_is_1G;
@ -175,6 +176,7 @@ module mmu #(
.ptw_active_o ( ptw_active ),
.walking_instr_o ( walking_instr ),
.ptw_error_o ( ptw_error ),
.faulting_address_o ( faulting_address ),
.enable_translation_i ( enable_translation_i ),
.itlb_update_o ( itlb_update ),
@ -261,9 +263,14 @@ module mmu #(
// ---------
// watch out for exceptions happening during walking the page table
if (ptw_active && walking_instr) begin
// on an error pass through fetch with an error signaled
fetch_gnt_o = ptw_error;
ierr_valid_n = ptw_error; // signal valid/error on next cycle
// check that the fetch address is equal with the faulting address as it could be that the page table walker
// has walked an instruction the instruction fetch stage is no longer interested in as we didn't give a grant
// we should not propagate back the exception when the request is no longer high
if (faulting_address == fetch_vaddr_i && fetch_req_i) begin
// on an error pass through fetch with an error signaled
fetch_gnt_o = ptw_error;
ierr_valid_n = ptw_error; // signal valid/error on next cycle
end
fetch_exception = {INSTR_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1};
end
end
@ -273,14 +280,14 @@ module mmu #(
// ---------------------------
// Fetch exception register
// ---------------------------
// We can have two oustanding transactions
// We can have two outstanding transactions
fifo #(
.dtype ( exception ),
.DEPTH ( 2 )
) i_exception_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( ),
.flush_i ( 1'b0 ),
.full_o ( ),
.empty_o ( ),
.single_element_o ( ),

View file

@ -32,6 +32,7 @@ module ptw #(
output logic ptw_active_o,
output logic walking_instr_o, // set when walking for TLB
output logic ptw_error_o, // set when an error occurred
output logic [63:0] faulting_address_o, // the address which threw the page-fault exception
input logic enable_translation_i, // CSRs indicate to enable SV39
input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
@ -97,7 +98,7 @@ module ptw #(
// register the ASID
logic [ASID_WIDTH-1:0] tlb_update_asid_q, tlb_update_asid_n;
// register the VPN we need to walk, SV39 defines a 39 bit virtual address
logic [38:0] vaddr_q, vaddr_n;
logic [63:0] vaddr_q, vaddr_n;
// 4 byte aligned physical pointer
logic[55:0] ptw_pptr_q, ptw_pptr_n;
@ -147,22 +148,22 @@ module ptw #(
always_comb begin : ptw
// default assignments
// PTW memory interface
tag_valid_n = 1'b0;
data_req_o = 1'b0;
data_be_o = 8'hFF;
data_we_o = 1'b0;
ptw_error_o = 1'b0;
itlb_update_o = 1'b0;
dtlb_update_o = 1'b0;
is_instr_ptw_n = is_instr_ptw_q;
ptw_lvl_n = ptw_lvl_q;
ptw_pptr_n = ptw_pptr_q;
NS = CS;
global_mapping_n = global_mapping_q;
tag_valid_n = 1'b0;
data_req_o = 1'b0;
data_be_o = 8'hFF;
data_we_o = 1'b0;
ptw_error_o = 1'b0;
itlb_update_o = 1'b0;
dtlb_update_o = 1'b0;
is_instr_ptw_n = is_instr_ptw_q;
ptw_lvl_n = ptw_lvl_q;
ptw_pptr_n = ptw_pptr_q;
NS = CS;
global_mapping_n = global_mapping_q;
// input registers
tlb_update_asid_n = tlb_update_asid_q;
vaddr_n = vaddr_q;
tlb_update_asid_n = tlb_update_asid_q;
vaddr_n = vaddr_q;
faulting_address_o = '0;
case (CS)
@ -297,7 +298,8 @@ module ptw #(
// Propagate error to MMU/LSU
PROPAGATE_ERROR: begin
NS = IDLE;
ptw_error_o = 1'b1;
ptw_error_o = 1'b1;
faulting_address_o = vaddr_q;
end
// wait for the rvalid before going back to IDLE
WAIT_RVALID: begin
@ -305,6 +307,7 @@ module ptw #(
NS = IDLE;
end
endcase
// -------
// Flush
// -------