diff --git a/src/ariane.sv b/src/ariane.sv index bca66ae49..1c05ae5ee 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -187,7 +187,6 @@ module ariane logic fetch_valid_ex_if; logic [31:0] fetch_rdata_ex_if; exception fetch_ex_ex_if; - logic fetch_err_ex_if; logic [63:0] fetch_vaddr_if_ex; // -------------- // CSR <-> * @@ -195,7 +194,7 @@ module ariane logic enable_translation_csr_ex; logic sum_csr_ex; logic mxr_csr_ex; - logic [37:0] pd_ppn_csr_ex; + logic [43:0] satp_ppn_csr_ex; logic [0:0] asid_csr_ex; logic [11:0] csr_addr_ex_csr; fu_op csr_op_commit_csr; @@ -376,14 +375,13 @@ module ariane .fetch_req_i ( fetch_req_if_ex ), .fetch_gnt_o ( fetch_gnt_ex_if ), .fetch_valid_o ( fetch_valid_ex_if ), - .fetch_err_o ( fetch_err_ex_if ), .fetch_vaddr_i ( fetch_vaddr_if_ex ), .fetch_rdata_o ( fetch_rdata_ex_if ), .fetch_ex_o ( fetch_ex_ex_if ), // fetch exception to IF .priv_lvl_i ( priv_lvl ), // from CSR .sum_i ( sum_csr_ex ), // from CSR .mxr_i ( mxr_csr_ex ), // from CSR - .pd_ppn_i ( pd_ppn_csr_ex ), // from CSR + .satp_ppn_i ( satp_ppn_csr_ex ), // from CSR .asid_i ( asid_csr_ex ), // from CSR .flush_tlb_i ( flush_tlb ), @@ -436,7 +434,7 @@ module ariane .enable_translation_o ( enable_translation_csr_ex ), .sum_o ( sum_csr_ex ), .mxr_o ( mxr_csr_ex ), - .pd_ppn_o ( pd_ppn_csr_ex ), + .satp_ppn_o ( satp_ppn_csr_ex ), .asid_o ( asid_csr_ex ), .tvm_o ( tvm_csr_id ), .tw_o ( tw_csr_id ), diff --git a/src/csr_regfile.sv b/src/csr_regfile.sv index 75e5c32e4..19b0b5069 100644 --- a/src/csr_regfile.sv +++ b/src/csr_regfile.sv @@ -54,7 +54,7 @@ module csr_regfile #( output logic sum_o, output logic mxr_o, // input logic flag_mprv_i, - output logic [37:0] pd_ppn_o, + output logic [43:0] satp_ppn_o, output logic [ASID_WIDTH-1:0] asid_o, // external interrupts input logic [1:0] irq_i, // external interrupt in @@ -507,7 +507,7 @@ module csr_regfile #( assign csr_rdata_o = csr_rdata; assign priv_lvl_o = priv_lvl_q; // MMU outputs - assign pd_ppn_o = satp_q.ppn; + assign satp_ppn_o = satp_q.ppn; assign asid_o = satp_q.asid[ASID_WIDTH-1:0]; assign sum_o = mstatus_q.sum; // we support bare memory addressing and SV39 diff --git a/src/ex_stage.sv b/src/ex_stage.sv index 0c3539835..875d01852 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -74,14 +74,13 @@ module ex_stage #( input logic fetch_req_i, output logic fetch_gnt_o, output logic fetch_valid_o, - output logic fetch_err_o, input logic [63:0] fetch_vaddr_i, output logic [31:0] fetch_rdata_o, output exception fetch_ex_o, input priv_lvl_t priv_lvl_i, input logic sum_i, input logic mxr_i, - input logic [37:0] pd_ppn_i, + input logic [43:0] satp_ppn_i, input logic [ASID_WIDTH-1:0] asid_i, input logic flush_tlb_i, diff --git a/src/lsu.sv b/src/lsu.sv index 3a3845d51..03930aebe 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -43,7 +43,6 @@ module lsu #( input logic fetch_req_i, // Instruction fetch interface output logic fetch_gnt_o, // Instruction fetch interface output logic fetch_valid_o, // Instruction fetch interface - output logic fetch_err_o, // Instruction fetch interface input logic [63:0] fetch_vaddr_i, // Instruction fetch interface output logic [31:0] fetch_rdata_o, // Instruction fetch interface output exception fetch_ex_o, // Instruction fetch interface @@ -51,7 +50,7 @@ module lsu #( input priv_lvl_t priv_lvl_i, // From CSR register file input logic sum_i, // From CSR register file input logic mxr_i, // From CSR register file - input logic [37:0] pd_ppn_i, // From CSR register file + input logic [43:0] satp_ppn_i, // From CSR register file input logic [ASID_WIDTH-1:0] asid_i, // From CSR register file input logic flush_tlb_i, // Instruction memory/cache diff --git a/src/mmu.sv b/src/mmu.sv index af995e9e0..e0143705e 100644 --- a/src/mmu.sv +++ b/src/mmu.sv @@ -34,7 +34,6 @@ module mmu #( input logic fetch_req_i, output logic fetch_gnt_o, output logic fetch_valid_o, - output logic fetch_err_o, input logic [63:0] fetch_vaddr_i, output logic [31:0] fetch_rdata_o, // pass-through because of interfaces output exception fetch_ex_o, // write-back fetch exceptions (e.g.: bus faults, page faults, etc.) @@ -53,7 +52,7 @@ module mmu #( input logic sum_i, input logic mxr_i, // input logic flag_mprv_i, - input logic [37:0] pd_ppn_i, + input logic [43:0] satp_ppn_i, input logic [ASID_WIDTH-1:0] asid_i, input logic flush_tlb_i, // Memory interfaces @@ -81,8 +80,6 @@ module mmu #( // only done for the few signals of the instruction interface logic [63:0] fetch_paddr; - logic fetch_req; - assign instr_if_data_req_o = fetch_req; assign instr_if_address_o = fetch_paddr; assign fetch_rdata_o = instr_if_data_rdata_i; // instruction error @@ -194,10 +191,8 @@ module mmu #( assign itlb_lu_access = fetch_req_i; assign dtlb_lu_access = lsu_req_i; - assign iaccess_err = fetch_req_i & ( - ((priv_lvl_i == PRIV_LVL_U) & ~itlb_content.u) - | (sum_i & (priv_lvl_i == PRIV_LVL_S) & itlb_content.u) - ); + assign iaccess_err = fetch_req_i & (((priv_lvl_i == PRIV_LVL_U) && ~itlb_content.u) + || (sum_i && (priv_lvl_i == PRIV_LVL_S) && itlb_content.u)); //----------------------- // Instruction interface @@ -205,19 +200,17 @@ module mmu #( always_comb begin : instr_interface // MMU disabled: just pass through automatic logic fetch_valid = instr_if_data_rvalid_i; - fetch_req = fetch_req_i; + instr_if_data_req_o = fetch_req_i; fetch_paddr = fetch_vaddr_i; fetch_gnt_o = instr_if_data_gnt_i; - fetch_err_o = 1'b0; ierr_valid_n = 1'b0; - fetch_ex_o = '{default: 0}; // 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. // AXI decode error), or when PTW performs walk due to itlb miss and raises // an error. if (enable_translation_i) begin - fetch_req = 1'b0; + instr_if_data_req_o = 1'b0; /* verilator lint_off WIDTH */ fetch_paddr = {itlb_content.ppn, fetch_vaddr_i[11:0]}; /* verilator lint_on WIDTH */ @@ -233,26 +226,32 @@ module mmu #( // TODO the following two ifs should be mutually exclusive if (itlb_lu_hit) begin - fetch_req = fetch_req_i; + instr_if_data_req_o = fetch_req_i; + if (iaccess_err) begin // Play through an instruction fetch with error signaled with rvalid - fetch_req = 1'b0; - fetch_gnt_o = 1'b1; // immediate grant + instr_if_data_req_o = 1'b0; + fetch_gnt_o = 1'b1; // immediate grant //fetch_valid = 1'b0; NOTE: valid from previous fetch: pass through // NOTE: back-to-back transfers: We only get a request if previous // transfer is completed, or completes in this cycle) ierr_valid_n = 1'b1; // valid signaled in next cycle end end - if (ptw_active & walking_instr) begin + if (ptw_active && walking_instr) begin // On error pass through fetch with error signaled with valid fetch_gnt_o = ptw_error; ierr_valid_n = ptw_error; // signal valid/error on next cycle end end - fetch_err_o = ierr_valid_q; fetch_valid_o = fetch_valid || ierr_valid_q; end + // ---------------------------- + // Instruction Fetch Exception + // ---------------------------- + always_comb begin : fetch_exception + fetch_ex_o = '{default: 0}; + end // registers always_ff @(posedge clk_i or negedge rst_ni) begin diff --git a/src/ptw.sv b/src/ptw.sv index edd8de358..e39f4a580 100644 --- a/src/ptw.sv +++ b/src/ptw.sv @@ -65,13 +65,13 @@ module ptw #( input logic dtlb_miss_i, input logic [63:0] dtlb_vaddr_i, // from CSR file - input logic [37:0] pd_ppn_i, // ppn from sptbr + input logic [43:0] satp_ppn_i, // ppn from satp input logic mxr_i ); - pte_t ptw_pte_i; - assign ptw_pte_i = pte_t'(data_rdata_i); + pte_t pte; + assign pte = pte_t'(data_rdata_i); enum logic[1:0] { PTW_READY, @@ -86,7 +86,10 @@ module ptw #( } ptw_lvl_q, ptw_lvl_n; // is this an instruction page table walk? - logic is_instr_ptw_q, is_instr_ptw_n; + logic is_instr_ptw_q, is_instr_ptw_n; + logic global_mapping_q, global_mapping_n; + // latched tag signal + logic tag_valid_n, tag_valid_q; assign ptw_active_o = (ptw_state_q != PTW_READY); assign walking_instr_o = is_instr_ptw_q; @@ -96,24 +99,27 @@ module ptw #( // register the VPN we need to walk logic [26:0] tlb_update_vpn_q, tlb_update_vpn_n; // 4 byte aligned physical pointer - logic[45:0] ptw_pptr_q, ptw_pptr_n; + logic[55:0] ptw_pptr_q, ptw_pptr_n; // directly output the correct physical address // ------ // TODO // ------- // assign address_o = {ptw_pptr_q, 4'b0}; TODO - assign address_index_o = '0; - assign address_tag_o = '0; - assign tag_valid_o = '0; + assign address_index_o = ptw_pptr_q[11:0]; + assign address_tag_o = ptw_pptr_q[55:12]; + // we are never going to kill this request assign kill_req_o = '0; + // we are never going to write with the HPTW + assign data_wdata_o = 64'b0; // update the correct page table level assign update_is_2M_o = (ptw_lvl_q == LVL2); assign update_is_1G_o = (ptw_lvl_q == LVL1); // output the correct VPN and ASID assign update_vpn_o = tlb_update_vpn_q; assign update_asid_o = tlb_update_asid_q; - - assign update_content_o = ptw_pte_i; + // set the global mapping bit + assign update_content_o = pte || (global_mapping_q << 5); + assign tag_valid_o = tag_valid_q; //------------------- // Page table walker @@ -141,10 +147,10 @@ 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; - data_wdata_o = 64'b0; ptw_error_o = 1'b0; itlb_update_o = 1'b0; dtlb_update_o = 1'b0; @@ -152,6 +158,7 @@ module ptw #( ptw_lvl_n = ptw_lvl_q; ptw_pptr_n = ptw_pptr_q; ptw_state_n = ptw_state_q; + global_mapping_n = global_mapping_q; // input registers tlb_update_asid_n = tlb_update_asid_q; tlb_update_vpn_n = tlb_update_vpn_q; @@ -159,16 +166,17 @@ module ptw #( unique case (ptw_state_q) PTW_READY: begin + global_mapping_n = 1'b0; // if we got an ITLB miss if (enable_translation_i & itlb_access_i & itlb_miss_i & ~dtlb_access_i) begin - ptw_pptr_n = {pd_ppn_i, itlb_vaddr_i[38:30]}; + ptw_pptr_n = {satp_ppn_i, itlb_vaddr_i[38:30], 3'b0}; is_instr_ptw_n = 1'b1; tlb_update_asid_n = asid_i; tlb_update_vpn_n = itlb_vaddr_i[38:12]; ptw_state_n = PTW_WAIT_GRANT; - // we got a DTLB miss + // we got an DTLB miss end else if (enable_translation_i & dtlb_access_i & dtlb_miss_i) begin - ptw_pptr_n = {pd_ppn_i, dtlb_vaddr_i[38:30]}; + ptw_pptr_n = {satp_ppn_i, dtlb_vaddr_i[38:30], 3'b0}; is_instr_ptw_n = 1'b0; tlb_update_asid_n = asid_i; tlb_update_vpn_n = dtlb_vaddr_i[38:12]; @@ -181,6 +189,8 @@ module ptw #( data_req_o = 1'b1; // wait for the grant if (data_gnt_i) begin + // send the tag valid signal one cycle later + tag_valid_n = 1'b1; ptw_state_n = PTW_PTE_LOOKUP; end // we could potentially error out here @@ -189,61 +199,77 @@ module ptw #( PTW_PTE_LOOKUP: begin // we wait for the valid signal if (data_rvalid_i) begin + // check if the global mapping bit is set + if (pte.g) + global_mapping_n = 1'b1; + // depending on the current level send the right address if (ptw_lvl_q == LVL2) - ptw_pptr_n = {ptw_pte_i.ppn[17:9], tlb_update_vpn_q[17:9]}; + ptw_pptr_n = {pte.ppn, tlb_update_vpn_q[17:9], 3'b0}; if (ptw_lvl_q == LVL3) - ptw_pptr_n = {ptw_pte_i.ppn[8:0], tlb_update_vpn_q[8:0]}; + ptw_pptr_n = {pte.ppn, tlb_update_vpn_q[8:0], 3'b0}; - // it is an invalid PTE - if (~ptw_pte_i.v | (~ptw_pte_i.r & ptw_pte_i.w)) begin + // ------------- + // Invalid PTE + // ------------- + // If pte.v = 0, or if pte.r = 0 and pte.w = 1, stop and raise a page-fault exception. + if (!pte.v || (!pte.r && pte.w)) ptw_state_n = PTW_PROPAGATE_ERROR; - end else begin + // ----------- + // Valid PTE + // ----------- + else begin ptw_state_n = PTW_READY; // it is a valid PTE - if (ptw_pte_i.r | ptw_pte_i.x) begin - // Valid translation found (either 4M or 4K entry) + // if pte.r = 1 or pte.x = 1 it is a valid PTE + if (pte.r || pte.x) begin + // Valid translation found (either 1G, 2M or 4K entry) if (is_instr_ptw_q) begin - // Update instruction-TLB + // ------------ + // Update ITLB + // ------------ // If page is not executable, we can directly raise an error. This // saves the 'x' bits in the ITLB otherwise needed for access // right checks and doesn't put a useless entry into the TLB. - if (~ptw_pte_i.x) begin + if (~pte.x) ptw_state_n = PTW_PROPAGATE_ERROR; - end else begin + else itlb_update_o = 1'b1; - end + end else begin - // Update data-TLB + // ------------ + // Update DTLB + // ------------ // If page is not readable (there are no write-only pages), or the // access that triggered the PTW is a write, but the page is not - // writeable, we can directly raise an error. This saves the 'r' + // write-able, we can directly raise an error. This saves the 'r' // bits in the TLB otherwise needed for access right checks and // doesn't put a useless entry into the TLB. - if ( (~ptw_pte_i.r & ~(ptw_pte_i.x & mxr_i)) - | (~ptw_pte_i.w)) begin + if ((~pte.r && ~(pte.x && mxr_i)) || (~pte.w)) begin ptw_state_n = PTW_PROPAGATE_ERROR; end else begin dtlb_update_o = 1'b1; end end + // this is a pointer to the next TLB level + end else begin + // pointer to next level of page table + if (ptw_lvl_q == LVL1) + ptw_lvl_n = LVL2; + + if (ptw_lvl_q == LVL2) + ptw_lvl_n = LVL3; + + ptw_state_n = PTW_WAIT_GRANT; + + if (ptw_lvl_q == LVL3) begin + // Should already be the last level page table => Error + ptw_lvl_n = LVL3; + ptw_state_n = PTW_PROPAGATE_ERROR; + end end end - // ~data_rvalid_i - end else begin - // Pointer to next level of page table - if (ptw_lvl_q == LVL1) - ptw_lvl_n = LVL2; - if (ptw_lvl_q == LVL2) - ptw_lvl_n = LVL3; - - ptw_state_n = PTW_WAIT_GRANT; - - if (ptw_lvl_q == LVL3) begin - // Should already be the last level page table => Error - ptw_lvl_n = LVL3; - ptw_state_n = PTW_PROPAGATE_ERROR; - end end + // we've got a data grant so tell the cache that the tag is valid end // TODO: propagate error PTW_PROPAGATE_ERROR: begin @@ -261,16 +287,20 @@ module ptw #( ptw_state_q <= PTW_READY; is_instr_ptw_q <= 1'b0; ptw_lvl_q <= LVL1; + tag_valid_q <= 1'b0; tlb_update_asid_q <= '{default: 0}; tlb_update_vpn_q <= '{default: 0}; ptw_pptr_q <= '{default: 0}; + global_mapping_q <= 1'b0; end else begin ptw_state_q <= ptw_state_n; ptw_pptr_q <= ptw_pptr_n; is_instr_ptw_q <= is_instr_ptw_n; ptw_lvl_q <= ptw_lvl_n; + tag_valid_q <= tag_valid_n; tlb_update_asid_q <= tlb_update_asid_n; tlb_update_vpn_q <= tlb_update_vpn_n; + global_mapping_q <= global_mapping_n; end end diff --git a/tb/wave/wave_core.do b/tb/wave/wave_core.do index f8590b78f..8aad52bf3 100644 --- a/tb/wave/wave_core.do +++ b/tb/wave/wave_core.do @@ -7,7 +7,11 @@ add wave -noupdate -group id_stage -group scoreboard /core_tb/dut/id_stage_i/sco add wave -noupdate -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/* add wave -noupdate -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/* add wave -noupdate -group id_stage /core_tb/dut/id_stage_i/* -add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/* +add wave -noupdate -group ex_stage -group alu /core_tb/dut/ex_stage_i/alu_i/* +add wave -noupdate -group ex_stage -group lsu -group mmu /core_tb/dut/ex_stage_i/lsu_i/mmu_i/* +add wave -noupdate -group ex_stage -group lsu -group mmu -group itlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/itlb_i/* +add wave -noupdate -group ex_stage -group lsu -group mmu -group dtlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/dtlb_i/* +add wave -noupdate -group ex_stage -group lsu -group mmu -group ptw /core_tb/dut/ex_stage_i/lsu_i/mmu_i/ptw_i/* add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/* add wave -noupdate -group ex_stage -group lsu -group mem_arbiter /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/* add wave -noupdate -group ex_stage -group lsu -group mem_arbiter -group arbiter_fifo /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/fifo_i/*