Adapt PTW to D$ interface, clean-up

This commit is contained in:
Florian Zaruba 2017-06-16 17:47:39 +02:00
parent aec6cb0ded
commit 837bf492ef
7 changed files with 102 additions and 73 deletions

View file

@ -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 ),

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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/*