Update PTW to latest specification (1.11 WIP)

This commit is contained in:
Florian Zaruba 2017-06-17 10:49:13 +02:00
parent 837bf492ef
commit 74901ae86e
6 changed files with 99 additions and 67 deletions

View file

@ -370,7 +370,7 @@ module ariane
.csr_valid_o ( csr_valid_ex_id ),
.csr_addr_o ( csr_addr_ex_csr ),
.csr_commit_i ( csr_commit_commit_ex ), // from commit
// memory management
// Memory Management
.enable_translation_i ( enable_translation_csr_ex ), // from CSR
.fetch_req_i ( fetch_req_if_ex ),
.fetch_gnt_o ( fetch_gnt_ex_if ),
@ -379,6 +379,7 @@ module ariane
.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
.ld_st_priv_lvl_i ( ld_st_priv_lvl_csr_ex ), // from CSR
.sum_i ( sum_csr_ex ), // from CSR
.mxr_i ( mxr_csr_ex ), // from CSR
.satp_ppn_i ( satp_ppn_csr_ex ), // from CSR
@ -430,7 +431,7 @@ module ariane
.eret_o ( eret ),
.trap_vector_base_o ( trap_vector_base_commit_pcgen ),
.priv_lvl_o ( priv_lvl ),
.ld_st_priv_lvl_o ( ld_st_priv_lvl_csr_ex ),
.enable_translation_o ( enable_translation_csr_ex ),
.sum_o ( sum_csr_ex ),
.mxr_o ( mxr_csr_ex ),

View file

@ -51,6 +51,7 @@ module csr_regfile #(
output priv_lvl_t priv_lvl_o, // Current privilege level the CPU is in
// MMU
output logic enable_translation_o, // Enable VA translation
output priv_lvl_t ld_st_priv_lvl_o, // Privilege level at which load and stores should happen
output logic sum_o,
output logic mxr_o,
// input logic flag_mprv_i,
@ -76,6 +77,12 @@ module csr_regfile #(
logic csr_we, csr_read;
logic [63:0] csr_wdata, csr_rdata;
priv_lvl_t trap_to_priv_lvl;
// ----------------------
// LD/ST Privilege Level
// ----------------------
assign ld_st_priv_lvl_o = (mstatus_q.mprv) ? mstatus_q.mpp : priv_lvl_o;
// ----------------
// CSR Registers
// ----------------

View file

@ -78,6 +78,7 @@ module ex_stage #(
output logic [31:0] fetch_rdata_o,
output exception fetch_ex_o,
input priv_lvl_t priv_lvl_i,
input priv_lvl_t ld_st_priv_lvl_i,
input logic sum_i,
input logic mxr_i,
input logic [43:0] satp_ppn_i,

View file

@ -48,6 +48,7 @@ module lsu #(
output exception fetch_ex_o, // Instruction fetch interface
input priv_lvl_t priv_lvl_i, // From CSR register file
input priv_lvl_t ld_st_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 [43:0] satp_ppn_i, // From CSR register file
@ -193,6 +194,7 @@ module lsu #(
) mmu_i (
// misaligned bypass
.misaligned_ex_i ( misaligned_exception ),
.lsu_is_store_i ( st_translation_req ),
.lsu_req_i ( translation_req ),
.lsu_vaddr_i ( mmu_vaddr ),
.lsu_valid_o ( translation_valid ),

View file

@ -41,14 +41,16 @@ module mmu #(
// this is a more minimalistic interface because the actual addressing logic is handled
// in the LSU as we distinguish load and stores, what we do here is simple address translation
input exception misaligned_ex_i,
input logic lsu_req_i,
input logic [63:0] lsu_vaddr_i,
input logic lsu_req_i, // request address translation
input logic [63:0] lsu_vaddr_i, // virtual address in
input logic lsu_is_store_i, // the translation is requested by a store
// if we need to walk the page table we can't grant in the same cycle
output logic lsu_valid_o, // translation is valid
output logic [63:0] lsu_paddr_o, // translated address
output exception lsu_exception_o,
output logic lsu_valid_o, // translation is valid
output logic [63:0] lsu_paddr_o, // translated address
output exception lsu_exception_o, // address translation threw an exception
// General control signals
input priv_lvl_t priv_lvl_i,
input priv_lvl_t ld_st_priv_lvl_i,
input logic sum_i,
input logic mxr_i,
// input logic flag_mprv_i,
@ -83,7 +85,10 @@ module mmu #(
assign instr_if_address_o = fetch_paddr;
assign fetch_rdata_o = instr_if_data_rdata_i;
// instruction error
logic ierr_valid_q, ierr_valid_n;
// 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;
@ -191,77 +196,75 @@ 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));
// 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
// Instruction Interface
//-----------------------
// This is a full memory interface, e.g.: it handles all signals to the I$
// Exceptions are always signaled together with the fetch_valid_o signal
always_comb begin : instr_interface
// MMU disabled: just pass through
automatic logic fetch_valid = instr_if_data_rvalid_i;
instr_if_data_req_o = fetch_req_i;
fetch_paddr = fetch_vaddr_i;
fetch_paddr = fetch_vaddr_i; // play through in case we disabled address translation
fetch_gnt_o = instr_if_data_gnt_i;
// two potential error 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;
// 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
// AXI decode error), or when PTW performs walk due to ITLB miss and raises
// an error.
if (enable_translation_i) begin
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 */
// 4K page
fetch_paddr = {itlb_content.ppn, fetch_vaddr_i[11:0]};
// this is a mega page
if (itlb_is_2M) begin
fetch_paddr[20:12] = fetch_vaddr_i[20:12];
end
// this is a giga page
if (itlb_is_1G) begin
fetch_paddr[29:12] = fetch_vaddr_i[29:12];
end
fetch_gnt_o = instr_if_data_gnt_i;
// TODO the following two ifs should be mutually exclusive
// ---------
// ITLB Hit
// --------
// if we hit the ITLB output the request signal immediately
if (itlb_lu_hit) begin
instr_if_data_req_o = fetch_req_i;
// we got an access error
if (iaccess_err) begin
// Play through an instruction fetch with error signaled with rvalid
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
// immediately grant a fetch which threw an exception, and stop the request from happening
instr_if_data_req_o = 1'b0;
fetch_gnt_o = 1'b1;
ierr_valid_n = 1'b1;
// throw a page fault
fetch_ex_n = {INSTR_PAGE_FAULT, fetch_vaddr_i, 1'b1};
end
end
// ---------
// ITLB Miss
// ---------
// watch out for exceptions happening during walking the page table
if (ptw_active && walking_instr) begin
// On error pass through fetch with error signaled with valid
// 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
fetch_ex_n = {INSTR_ACCESS_FAULT, fetch_vaddr_i, 1'b1};
end
end
fetch_valid_o = fetch_valid || ierr_valid_q;
// the fetch is valid if we either got an error in the previous cycle or the I$ gave us a valid signal.
fetch_valid_o = instr_if_data_rvalid_i || 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
if(~rst_ni) begin
ierr_valid_q <= 1'b0;
end else begin
ierr_valid_q <= ierr_valid_n;
end
end
//-----------------------
// Data interface
//-----------------------
@ -276,5 +279,16 @@ module mmu #(
// TODO: Assign access exception
lsu_exception_o = misaligned_ex_i;
end
// ----------
// Registers
// ----------
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
ierr_valid_q <= 1'b0;
fetch_ex_q <= '0;
end else begin
ierr_valid_q <= ierr_valid_n;
fetch_ex_q <= fetch_ex_n;
end
end
endmodule

View file

@ -24,16 +24,17 @@ module ptw #(
parameter int ASID_WIDTH = 1
)
(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush everything, we need to do this because
// actually everything we do is speculative at this stage
// e.g.: there could be a CSR instruction that changes everything
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush everything, we need to do this because
// actually everything we do is speculative at this stage
// e.g.: there could be a CSR instruction that changes everything
output logic ptw_active_o,
output logic walking_instr_o, // set when walking for TLB
output logic ptw_error_o, // set when an error occured
input logic enable_translation_i,
// memory port
output logic walking_instr_o, // set when walking for TLB
output logic ptw_error_o, // set when an error occurred
input logic enable_translation_i, // CSRs indicate to enable SV39
input logic lsu_is_store_i, // this translation was triggered by a store
// PTW Memory Port
output logic [11:0] address_index_o,
output logic [43:0] address_tag_o,
output logic [63:0] data_wdata_o,
@ -193,7 +194,6 @@ module ptw #(
tag_valid_n = 1'b1;
ptw_state_n = PTW_PTE_LOOKUP;
end
// we could potentially error out here
end
PTW_PTE_LOOKUP: begin
@ -228,9 +228,9 @@ module ptw #(
// 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 (~pte.x)
// doesn't put a useless entry into the TLB. The same idea applies
// to the access flag since we let the access flag be managed by SW.
if (!pte.x || !pte.a)
ptw_state_n = PTW_PROPAGATE_ERROR;
else
itlb_update_o = 1'b1;
@ -239,15 +239,22 @@ module ptw #(
// ------------
// 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
// 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 ((~pte.r && ~(pte.x && mxr_i)) || (~pte.w)) begin
ptw_state_n = PTW_PROPAGATE_ERROR;
end else begin
// Check if the access flag has been set, otherwise throw a page-fault
// and let the software handle those bits.
// If page is not readable (there are no write-only pages)
// we can directly raise an error. This doesn't put a useless
// entry into the TLB.
if (pte.a && (pte.r || (pte.x && mxr_i))) begin
dtlb_update_o = 1'b1;
end else begin
ptw_state_n = PTW_PROPAGATE_ERROR;
end
// Request is a store: perform some additional checks
// If the request was a store and the page is not write-able, raise an error
// the same applies if the dirty flag is not set
if (lsu_is_store_i && (!pte.w || !pte.d)) begin
dtlb_update_o = 1'b0;
ptw_state_n = PTW_PROPAGATE_ERROR;
end
end
// this is a pointer to the next TLB level