diff --git a/src/mmu.sv b/src/mmu.sv index a0789186e..763570358 100644 --- a/src/mmu.sv +++ b/src/mmu.sv @@ -78,32 +78,26 @@ module mmu #( input logic data_rvalid_i, input logic [63:0] data_rdata_i ); - // assignments necessary to use interfaces here - // only done for the few signals of the instruction interface - logic [63:0] fetch_paddr; - - assign instr_if_address_o = fetch_paddr; - assign fetch_rdata_o = instr_if_data_rdata_i; // instruction error // instruction error valid signal and exception, delayed one cycle logic ierr_valid_q, ierr_valid_n; exception fetch_ex_q, fetch_ex_n; - logic iaccess_err; - logic ptw_active; - logic walking_instr; - logic ptw_error; + logic iaccess_err; // insufficient privilege to access this instruction page + logic daccess_err; // insufficient privilege to access this data page + 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 update_is_2M; - logic update_is_1G; + logic update_is_2M; + logic update_is_1G; logic [26:0] update_vpn; - logic [0:0] update_asid; - pte_t update_content; + logic [0:0] update_asid; + pte_t update_content; logic itlb_update; logic itlb_lu_access; pte_t itlb_content; - logic itlb_is_2M; logic itlb_is_1G; logic itlb_lu_hit; @@ -111,11 +105,16 @@ module mmu #( logic dtlb_update; logic dtlb_lu_access; pte_t dtlb_content; - logic dtlb_is_2M; logic dtlb_is_1G; logic dtlb_lu_hit; + // Assignments + assign itlb_lu_access = fetch_req_i; + assign dtlb_lu_access = lsu_req_i; + assign fetch_rdata_o = instr_if_data_rdata_i; + assign fetch_ex_o = fetch_ex_q; + tlb #( .TLB_ENTRIES ( INSTR_TLB_ENTRIES ), .ASID_WIDTH ( ASID_WIDTH ) @@ -194,12 +193,6 @@ module mmu #( .* ); - assign itlb_lu_access = fetch_req_i; - assign dtlb_lu_access = lsu_req_i; - // Check whether we are allowed to access this memory region from a fetch perspective - assign iaccess_err = fetch_req_i && (((priv_lvl_i == PRIV_LVL_U) && ~itlb_content.u) - || ((priv_lvl_i == PRIV_LVL_S) && itlb_content.u)); - //----------------------- // Instruction Interface //----------------------- @@ -208,13 +201,16 @@ module mmu #( always_comb begin : instr_interface // MMU disabled: just pass through instr_if_data_req_o = fetch_req_i; - fetch_paddr = fetch_vaddr_i; // play through in case we disabled address translation + instr_if_address_o = fetch_vaddr_i; // play through in case we disabled address translation fetch_gnt_o = instr_if_data_gnt_i; // two potential exception sources: // 1. HPTW threw an exception -> signal with a page fault exception // 2. We got an access error because of insufficient permissions -> throw an access exception fetch_ex_n = '0; ierr_valid_n = 1'b0; // we keep a separate valid signal in case of an error + // Check whether we are allowed to access this memory region from a fetch perspective + iaccess_err = fetch_req_i && (((priv_lvl_i == PRIV_LVL_U) && ~itlb_content.u) + || ((priv_lvl_i == PRIV_LVL_S) && itlb_content.u)); // MMU enabled: address from TLB, request delayed until hit. Error when TLB // hit and no access right or TLB hit and translated address not valid (e.g. @@ -224,14 +220,14 @@ module mmu #( instr_if_data_req_o = 1'b0; // 4K page - fetch_paddr = {itlb_content.ppn, fetch_vaddr_i[11:0]}; + instr_if_address_o = {itlb_content.ppn, fetch_vaddr_i[11:0]}; // Mega page if (itlb_is_2M) begin - fetch_paddr[20:12] = fetch_vaddr_i[20:12]; + instr_if_address_o[20:12] = fetch_vaddr_i[20:12]; end // Giga page if (itlb_is_1G) begin - fetch_paddr[29:12] = fetch_vaddr_i[29:12]; + instr_if_address_o[29:12] = fetch_vaddr_i[29:12]; end // --------- @@ -249,7 +245,7 @@ module mmu #( // throw a page fault fetch_ex_n = {INSTR_PAGE_FAULT, fetch_vaddr_i, 1'b1}; end - end + end else // --------- // ITLB Miss // --------- @@ -270,15 +266,60 @@ module mmu #( //----------------------- // The data interface is simpler and only consists of a request/response interface always_comb begin : data_interface - // stub - // lsu_req_i - // lsu_vaddr_i - // lsu_valid_o - // lsu_paddr_o - lsu_paddr_o = (enable_translation_i) ? {16'b0, dtlb_content} : lsu_vaddr_i; - lsu_valid_o = lsu_req_i; - // TODO: Assign access exception + lsu_paddr_o = lsu_vaddr_i; + lsu_valid_o = lsu_req_i; lsu_exception_o = misaligned_ex_i; + // Check if the User flag is set, then we may only access it in supervisor mode + // if SUM is enabled + daccess_err = (ld_st_priv_lvl_i == PRIV_LVL_S && !sum_i && dtlb_content.u) || // SUM is not set and we are trying to access a user page in supervisor mode + (ld_st_priv_lvl_i == PRIV_LVL_U && !dtlb_content.u); // this is not a user page but we are in user mode and trying to access it + // translation is enabled and no misaligned exception occurred + if (enable_translation_i && !misaligned_ex_i.valid) begin + // 4K page + lsu_paddr_o = {dtlb_content.ppn, lsu_vaddr_i[11:0]}; + // Mega page + if (dtlb_is_2M) begin + lsu_paddr_o[20:12] = lsu_vaddr_i[20:12]; + end + // Giga page + if (dtlb_is_1G) begin + lsu_paddr_o[29:12] = lsu_vaddr_i[29:12]; + end + // --------- + // DTLB Hit + // -------- + if (dtlb_lu_hit && lsu_req_i) begin + // this is a store + if (lsu_is_store_i) begin + // check if the page is write-able and we are not violating privileges + if (dtlb_content.w || daccess_err) begin + lsu_exception_o = {ST_ACCESS_FAULT, lsu_vaddr_i, 1'b1}; + end + // this is a load, check for sufficient access privileges + end else if (daccess_err) begin + lsu_exception_o = {LD_ACCESS_FAULT, lsu_vaddr_i, 1'b1}; + end + end else + // --------- + // DTLB Miss + // --------- + // watch out for exception + if (ptw_active && !walking_instr) begin + // when we walk a page table the output is not ready + lsu_valid_o = 1'b0; + // page table walker threw an exception + if (ptw_error) begin + // an error makes the translation valid + lsu_valid_o = 1'b1; + // the page table walker can only throw page faults + if (lsu_is_store_i) begin + lsu_exception_o = {STORE_PAGE_FAULT, lsu_vaddr_i, 1'b1}; + end else begin + lsu_exception_o = {LOAD_PAGE_FAULT, lsu_vaddr_i, 1'b1}; + end + end + end + end end // ---------- // Registers diff --git a/src/ptw.sv b/src/ptw.sv index 4e7fcd7dd..057d9e26b 100644 --- a/src/ptw.sv +++ b/src/ptw.sv @@ -164,7 +164,7 @@ module ptw #( tlb_update_asid_n = tlb_update_asid_q; tlb_update_vpn_n = tlb_update_vpn_q; - unique case (ptw_state_q) + case (ptw_state_q) PTW_READY: begin global_mapping_n = 1'b0; @@ -278,14 +278,12 @@ module ptw #( end // we've got a data grant so tell the cache that the tag is valid end - // TODO: propagate error + // Propagate error to MMU/LSU PTW_PROPAGATE_ERROR: begin ptw_state_n = PTW_READY; ptw_error_o = 1'b1; end - - - endcase // ptw_state_q + endcase end // sequential process diff --git a/tb/wave/wave_core.do b/tb/wave/wave_core.do index 8aad52bf3..4289d8933 100644 --- a/tb/wave/wave_core.do +++ b/tb/wave/wave_core.do @@ -21,7 +21,7 @@ add wave -noupdate -group ex_stage -group lsu -group load_unit /core_tb/dut/ex_s add wave -noupdate -group ex_stage -group lsu -group load_unit -group fifo /core_tb/dut/ex_stage_i/lsu_i/load_unit_i/fifo_i/* add wave -noupdate -group ex_stage -group lsu -group lsu_arbiter /core_tb/dut/ex_stage_i/lsu_i/lsu_arbiter_i/* add wave -noupdate -group ex_stage -group branch_unit /core_tb/dut/ex_stage_i/branch_unit_i/* -add wave -noupdate -group ex_stage -expand -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/* +add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/* add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/* add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/* add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/*