mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 05:07:21 -04:00
Implement address translation data interface
This commit is contained in:
parent
e860cc4c91
commit
3d6d3e912f
3 changed files with 80 additions and 41 deletions
111
src/mmu.sv
111
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue