mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 06:07:19 -04:00
Add MMU implementation incl PTW and TLBs
This commit is contained in:
parent
c15ef3d1b7
commit
c4edf3de3d
9 changed files with 277 additions and 216 deletions
2
Makefile
2
Makefile
|
@ -15,7 +15,7 @@ agents = tb/agents/fu_if/fu_if.sv tb/agents/fu_if/fu_if_agent_pkg.sv \
|
|||
interfaces = include/debug_if.svh include/mem_if.svh tb/agents/fifo_if/fifo_if.sv
|
||||
# this list contains the standalone components
|
||||
src = alu.sv tb/sequences/alu_sequence_pkg.sv tb/env/alu_env_pkg.sv tb/test/alu_lib_pkg.sv tb/alu_tb.sv \
|
||||
tb/scoreboard_tb.sv ptw.sv \
|
||||
tb/scoreboard_tb.sv ptw.sv tlb.sv \
|
||||
if_stage.sv compressed_decoder.sv fetch_fifo.sv commit_stage.sv prefetch_buffer.sv \
|
||||
mmu.sv lsu.sv fifo.sv tb/fifo_tb.sv mem_arbiter.sv \
|
||||
scoreboard.sv issue_read_operands.sv decoder.sv id_stage.sv util/cluster_clock_gating.sv regfile.sv ex_stage.sv ariane.sv \
|
||||
|
|
|
@ -93,7 +93,7 @@ module ariane
|
|||
priv_lvl_t priv_lvl_i;
|
||||
logic flag_pum_i;
|
||||
logic flag_mxr_i;
|
||||
logic [19:0] pd_ppn_i;
|
||||
logic [37:0] pd_ppn_i;
|
||||
logic [0:0] asid_i;
|
||||
logic flush_tlb_i;
|
||||
|
||||
|
@ -184,7 +184,7 @@ module ariane
|
|||
.lsu_valid_o ( lsu_valid_o ),
|
||||
|
||||
// memory management
|
||||
.enable_translation_i ( enable_translation_i ), // from CSR
|
||||
.enable_translation_i ( 1'b0 ), // from CSR
|
||||
.fetch_req_i ( fetch_req_i ),
|
||||
.fetch_gnt_o ( fetch_gnt_o ),
|
||||
.fetch_valid_o ( fetch_valid_o ),
|
||||
|
|
106
btb.sv
106
btb.sv
|
@ -1,106 +0,0 @@
|
|||
// Author: Florian Zaruba, ETH Zurich
|
||||
// Date: 19.04.2017
|
||||
// Description: Branch Target Buffer implementation
|
||||
//
|
||||
// Copyright (C) 2017 ETH Zurich, University of Bologna
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code is under development and not yet released to the public.
|
||||
// Until it is released, the code is under the copyright of ETH Zurich and
|
||||
// the University of Bologna, and may contain confidential and/or unpublished
|
||||
// work. Any reuse/redistribution is strictly forbidden without written
|
||||
// permission from ETH Zurich.
|
||||
//
|
||||
// Bug fixes and contributions will eventually be released under the
|
||||
// SolderPad open hardware license in the context of the PULP platform
|
||||
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
|
||||
// University of Bologna.
|
||||
//
|
||||
import ariane_pkg::*;
|
||||
|
||||
module btb #(
|
||||
parameter int NR_ENTRIES = 64,
|
||||
parameter int BITS_SATURATION_COUNTER = 2
|
||||
)
|
||||
(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i, // flush the btb
|
||||
|
||||
input logic [63:0] vpc_i, // virtual PC from IF stage
|
||||
input misspredict misspredict_i, // a miss-predict happened -> update data structure
|
||||
|
||||
output logic is_branch_o, // instruction at vpc_i is a branch
|
||||
output logic predict_taken_o, // the branch is taken
|
||||
output logic [63:0] branch_target_address_o // instruction has the following target address
|
||||
);
|
||||
// number of bits which are not used for indexing
|
||||
localparam OFFSET = 2;
|
||||
|
||||
// typedef for all branch target entries
|
||||
// we may want to try to put a tag field that fills the rest of the PC in-order to mitigate aliasing effects
|
||||
struct packed {
|
||||
logic valid;
|
||||
logic [63:0] target_address;
|
||||
logic [BITS_SATURATION_COUNTER-1:0] saturation_counter;
|
||||
} btb_n [NR_ENTRIES-1:0], btb_q [NR_ENTRIES-1:0];
|
||||
|
||||
logic [$clog2(NR_ENTRIES)-1:0] index, update_pc;
|
||||
logic [BITS_SATURATION_COUNTER-1:0] saturation_counter;
|
||||
|
||||
// get actual index positions
|
||||
// we ignore the 0th bit since all instructions are aligned on
|
||||
// a half word boundary
|
||||
assign update_pc = misspredict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
|
||||
assign index = vpc_i[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
|
||||
|
||||
// we combinatorially predict the branch and the target address
|
||||
assign is_branch_o = btb_q[$unsigned(index)].valid;
|
||||
assign predict_taken_o = btb_q[$unsigned(index)].saturation_counter[BITS_SATURATION_COUNTER-1];
|
||||
assign branch_target_address_o = btb_q[$unsigned(index)].target_address;
|
||||
|
||||
// update on a miss-predict
|
||||
always_comb begin : update_misspredict
|
||||
btb_n = btb_q;
|
||||
saturation_counter = btb_q[$unsigned(update_pc)].saturation_counter;
|
||||
|
||||
if (misspredict_i.valid) begin
|
||||
btb_n[$unsigned(update_pc)].valid = 1'b1;
|
||||
// update saturation counter
|
||||
// first check if counter is already saturated in the positive regime e.g.: branch taken
|
||||
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}} && ~misspredict_i.is_taken) begin
|
||||
// we can safely decrease it
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
|
||||
// then check if it saturated in the negative regime e.g.: branch not taken
|
||||
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}} && misspredict_i.is_taken) begin
|
||||
// we can safely increase it
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
|
||||
end else begin // otherwise we are not in any boundaries and can decrease or increase it
|
||||
if (misspredict_i.is_taken)
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
|
||||
else
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
|
||||
end
|
||||
// the target address is simply updated
|
||||
btb_n[$unsigned(update_pc)].target_address = misspredict_i.target_address;
|
||||
end
|
||||
end
|
||||
|
||||
// sequential process
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
// TODO: think about the reset value
|
||||
btb_q <= '{default: 0};
|
||||
end else begin
|
||||
// evict all entries
|
||||
if (flush_i) begin
|
||||
for (int i = 0; i < NR_ENTRIES; i++) begin
|
||||
btb_q[i].valid <= 1'b0;
|
||||
btb_q[i].saturation_counter <= '{default: 0};
|
||||
end
|
||||
end else begin
|
||||
btb_q <= btb_n;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -55,7 +55,7 @@ module ex_stage #(
|
|||
input priv_lvl_t priv_lvl_i,
|
||||
input logic flag_pum_i,
|
||||
input logic flag_mxr_i,
|
||||
input logic [19:0] pd_ppn_i,
|
||||
input logic [37:0] pd_ppn_i,
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
input logic flush_tlb_i,
|
||||
mem_if.Slave instr_if,
|
||||
|
|
|
@ -153,6 +153,7 @@ package ariane_pkg;
|
|||
PRIV_LVL_S = 2'b01,
|
||||
PRIV_LVL_U = 2'b00
|
||||
} priv_lvl_t;
|
||||
|
||||
// memory management, pte
|
||||
typedef struct packed {
|
||||
logic[37:0] ppn;
|
||||
|
@ -166,6 +167,7 @@ package ariane_pkg;
|
|||
logic r;
|
||||
logic v;
|
||||
} pte_t;
|
||||
|
||||
// Bits required for representation of physical address space as 4K pages
|
||||
// (e.g. 27*4K == 39bit address space).
|
||||
localparam PPN4K_WIDTH = 38;
|
||||
|
|
122
lsu.sv
122
lsu.sv
|
@ -21,58 +21,100 @@ import ariane_pkg::*;
|
|||
module lsu #(
|
||||
parameter int ASID_WIDTH = 1
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] imm_i,
|
||||
output logic lsu_ready_o, // FU is ready e.g. not busy
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
input logic lsu_trans_id_i, // transaction id, needed for WB
|
||||
output logic [4:0] lsu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic lsu_valid_o, // transaction id for which the output is the requested one
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] imm_i,
|
||||
output logic lsu_ready_o, // FU is ready e.g. not busy
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
input logic [TRANS_ID_BITS-1:0] lsu_trans_id_i, // transaction id, needed for WB
|
||||
output logic [TRANS_ID_BITS-1:0] lsu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic lsu_valid_o, // transaction id for which the output is the requested one
|
||||
|
||||
input logic enable_translation_i,
|
||||
input logic enable_translation_i,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
input priv_lvl_t priv_lvl_i,
|
||||
input logic flag_pum_i,
|
||||
input logic flag_mxr_i,
|
||||
input logic [19:0] pd_ppn_i,
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
input logic flush_tlb_i,
|
||||
mem_if.Slave instr_if,
|
||||
mem_if.Slave data_if,
|
||||
input priv_lvl_t priv_lvl_i,
|
||||
input logic flag_pum_i,
|
||||
input logic flag_mxr_i,
|
||||
input logic [37:0] pd_ppn_i,
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
input logic flush_tlb_i,
|
||||
|
||||
output exception lsu_exception_o // to WB, signal exception status LD/ST exception
|
||||
mem_if.Slave instr_if,
|
||||
mem_if.Slave data_if,
|
||||
|
||||
output exception lsu_exception_o // to WB, signal exception status LD/ST exception
|
||||
|
||||
);
|
||||
assign lsu_trans_id_o = lsu_trans_id_i;
|
||||
assign lsu_valid_o = 1'b0;
|
||||
|
||||
logic [63:0] vaddr;
|
||||
|
||||
// dummy implementation
|
||||
// instruction interface
|
||||
assign instr_if.data_req = fetch_req_i;
|
||||
assign fetch_gnt_o = instr_if.data_gnt;
|
||||
assign fetch_valid_o = instr_if.data_rvalid;
|
||||
assign instr_if.address = fetch_vaddr_i;
|
||||
assign fetch_rdata_o = instr_if.data_rdata;
|
||||
assign fetch_err_o = 1'b0;
|
||||
|
||||
// -------------------
|
||||
// MMU e.g.: TLBs/PTW
|
||||
// -------------------
|
||||
|
||||
// ---------------
|
||||
// Memory Arbiter
|
||||
// ---------------
|
||||
logic [2:0][63:0] address_i;
|
||||
logic [2:0][63:0] data_wdata_i;
|
||||
logic [2:0] data_req_i;
|
||||
logic [2:0] data_we_i;
|
||||
logic [2:0][7:0] data_be_i;
|
||||
logic [2:0] data_gnt_o;
|
||||
logic [2:0] data_rvalid_o;
|
||||
logic [2:0][63:0] data_rdata_o;
|
||||
|
||||
mem_arbiter i_mem_arbiter (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
||||
// to D$
|
||||
.address_o ( data_if.address ),
|
||||
.data_wdata_o ( data_if.data_wdata ),
|
||||
.data_req_o ( data_if.data_req ),
|
||||
.data_we_o ( data_if.data_we ),
|
||||
.data_be_o ( data_if.data_be ),
|
||||
.data_gnt_i ( data_if.data_gnt ),
|
||||
.data_rvalid_i( data_if.data_rvalid ),
|
||||
.data_rdata_i ( data_if.data_rdata ),
|
||||
|
||||
// from PTW, Load logic and store queue
|
||||
.address_i ( address_i ),
|
||||
.data_wdata_i ( data_wdata_i ),
|
||||
.data_req_i ( data_req_i ),
|
||||
.data_we_i ( data_we_i ),
|
||||
.data_be_i ( data_be_i ),
|
||||
.data_gnt_o ( data_gnt_o ),
|
||||
.data_rvalid_o( data_rvalid_o ),
|
||||
.data_rdata_o ( data_rdata_o )
|
||||
);
|
||||
|
||||
// -------------------
|
||||
// MMU e.g.: TLBs/PTW
|
||||
// -------------------
|
||||
logic lsu_req_i;
|
||||
logic [63:0] lsu_vaddr_i;
|
||||
logic lsu_ready_wb_i;
|
||||
|
||||
mmu #(
|
||||
.INSTR_TLB_ENTRIES ( 16 ),
|
||||
.DATA_TLB_ENTRIES ( 16 ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
) i_mmu (
|
||||
.lsu_req_i ( lsu_req_i ),
|
||||
.lsu_vaddr_i ( lsu_vaddr_i ),
|
||||
.lsu_valid_o ( ),
|
||||
.*
|
||||
);
|
||||
|
||||
// ---------------
|
||||
// Store Queue
|
||||
|
|
184
mmu.sv
184
mmu.sv
|
@ -38,21 +38,18 @@ module mmu #(
|
|||
input logic [63:0] fetch_vaddr_i,
|
||||
output logic [31:0] fetch_rdata_o, // pass-through because of interfaces
|
||||
// LSU interface
|
||||
// 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 logic lsu_req_i,
|
||||
output logic lsu_gnt_o,
|
||||
output logic lsu_valid_o,
|
||||
input logic lsu_we_i,
|
||||
input logic [7:0] lsu_be_i,
|
||||
output logic lsu_err_o,
|
||||
input logic [63:0] lsu_vaddr_i,
|
||||
input logic [63:0] lsu_wdata_i, // pass-through because of interfaces
|
||||
output logic [63:0] lsu_rdata_o, // pass-through because of interfaces
|
||||
// if we need to walk the page table we can't grant in the same cycle
|
||||
output logic lsu_valid_o, // translation is valid
|
||||
// General control signals
|
||||
input priv_lvl_t priv_lvl_i,
|
||||
input logic flag_pum_i,
|
||||
input logic flag_mxr_i,
|
||||
// input logic flag_mprv_i,
|
||||
input logic [19:0] pd_ppn_i,
|
||||
input logic [37:0] pd_ppn_i,
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
input logic flush_tlb_i,
|
||||
input logic lsu_ready_wb_i,
|
||||
|
@ -62,13 +59,168 @@ module mmu #(
|
|||
// Data memory interface
|
||||
mem_if.Slave data_if
|
||||
);
|
||||
|
||||
// dummy implementation
|
||||
// instruction interface
|
||||
assign instr_if.data_req = fetch_req_i;
|
||||
assign fetch_gnt_o = instr_if.data_gnt;
|
||||
assign fetch_valid_o = instr_if.data_rvalid;
|
||||
assign instr_if.address = fetch_vaddr_i;
|
||||
// assignments necessary to use interfaces here
|
||||
// only done for the few signals of the instruction interface
|
||||
logic [63:0] fetch_paddr;
|
||||
logic fetch_req;
|
||||
assign instr_if.data_req = fetch_req;
|
||||
assign instr_if.address = fetch_paddr;
|
||||
assign fetch_rdata_o = instr_if.data_rdata;
|
||||
assign fetch_err_o = 1'b0;
|
||||
// instruction error
|
||||
logic ierr_valid_q, ierr_valid_n;
|
||||
logic iaccess_err;
|
||||
logic ptw_active;
|
||||
logic walking_instr;
|
||||
logic ptw_error;
|
||||
|
||||
logic flush_i;
|
||||
logic update_is_2M;
|
||||
logic update_is_1G;
|
||||
logic [26:0] update_vpn;
|
||||
logic [0:0] update_asid;
|
||||
pte_t update_content;
|
||||
logic itlb_update;
|
||||
logic itlb_lu_access;
|
||||
logic [0:0] lu_asid_i;
|
||||
logic [63:0] lu_vaddr_i;
|
||||
pte_t itlb_content;
|
||||
|
||||
logic itlb_is_2M;
|
||||
logic itlb_is_1G;
|
||||
logic itlb_lu_hit;
|
||||
|
||||
tlb #(
|
||||
.TLB_ENTRIES ( INSTR_TLB_ENTRIES ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
) itlb_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.update_is_2M_i ( update_is_2M ),
|
||||
.update_is_1G_i ( update_is_1G ),
|
||||
.update_vpn_i ( update_vpn ),
|
||||
.update_asid_i ( update_asid ),
|
||||
.update_content_i ( update_content ),
|
||||
.update_tlb_i ( itlb_update_i ),
|
||||
|
||||
.lu_access_i ( itlb_lu_access ),
|
||||
.lu_asid_i ( lu_asid_i ),
|
||||
.lu_vaddr_i ( lu_vaddr_i ),
|
||||
.lu_content_o ( itlb_content ),
|
||||
.lu_is_2M_o ( itlb_is_2M ),
|
||||
.lu_is_1G_o ( itlb_is_1G ),
|
||||
.lu_hit_o ( itlb_lu_hit )
|
||||
);
|
||||
|
||||
ptw #(
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
) ptw_i
|
||||
(
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( ),
|
||||
.ptw_active_o ( ptw_active ),
|
||||
.walking_instr_o ( walking_instr ),
|
||||
.ptw_error_o ( ptw_error ),
|
||||
.enable_translation_i ( enable_translation_i ),
|
||||
|
||||
.address_o ( data_if.address ),
|
||||
.data_wdata_o ( data_if.data_wdata ),
|
||||
.data_req_o ( data_if.data_req ),
|
||||
.data_we_o ( data_if.data_we ),
|
||||
.data_be_o ( data_if.data_be ),
|
||||
.data_gnt_i ( data_if.data_gnt ),
|
||||
.data_rvalid_i ( data_if.data_rvalid ),
|
||||
.data_rdata_i ( data_if.data_rdata ),
|
||||
.itlb_update_o ( itlb_update ),
|
||||
.dtlb_update_o ( ),
|
||||
.update_content_o ( update_content ),
|
||||
.update_is_2M_o ( update_is_2M ),
|
||||
.update_is_1G_o ( update_is_1G ),
|
||||
.update_vpn_o ( update_vpn ),
|
||||
.update_asid_o ( update_asid ),
|
||||
|
||||
.itlb_access_i ( itlb_lu_access ),
|
||||
.itlb_miss_i ( ~itlb_lu_hit ),
|
||||
.itlb_vaddr_i ( fetch_vaddr_i ),
|
||||
|
||||
.dtlb_access_i ( ),
|
||||
.dtlb_miss_i ( ),
|
||||
.dtlb_vaddr_i ( ),
|
||||
|
||||
.*
|
||||
);
|
||||
|
||||
|
||||
assign iaccess_err = fetch_req_i & (
|
||||
((priv_lvl_i == PRIV_LVL_U) & ~itlb_content.u)
|
||||
| (flag_pum_i & (priv_lvl_i == PRIV_LVL_S) & itlb_content.u)
|
||||
);
|
||||
|
||||
//-----------------------
|
||||
// Instruction interface
|
||||
//-----------------------
|
||||
always_comb begin
|
||||
// MMU disabled: just pass through
|
||||
automatic logic fetch_valid = instr_if.data_rvalid;
|
||||
fetch_req = fetch_req_i;
|
||||
fetch_paddr = fetch_vaddr_i;
|
||||
fetch_gnt_o = instr_if.data_gnt;
|
||||
fetch_err_o = 1'b0;
|
||||
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
|
||||
// an error.
|
||||
if (enable_translation_i) begin
|
||||
fetch_req = 1'b0;
|
||||
fetch_paddr = {itlb_content.ppn, fetch_vaddr_i[11:0]};
|
||||
|
||||
if (itlb_is_2M) begin
|
||||
fetch_paddr[20:12] = fetch_vaddr_i[20:12];
|
||||
end
|
||||
|
||||
if (itlb_is_1G) begin
|
||||
fetch_paddr[29:12] = fetch_vaddr_i[29:12];
|
||||
end
|
||||
|
||||
fetch_gnt_o = instr_if.data_gnt;
|
||||
|
||||
// TODO the following two ifs should be mutually exclusive
|
||||
if (itlb_lu_hit) begin
|
||||
fetch_req = 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
|
||||
//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
|
||||
// On error play 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
|
||||
|
||||
// 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
|
||||
//-----------------------
|
||||
|
||||
endmodule
|
61
ptw.sv
61
ptw.sv
|
@ -21,8 +21,7 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module ptw #(
|
||||
parameter int ASID_WIDTH = 1,
|
||||
parameter int CONTENT_SIZE = 24 // data: ppn + u + g + w + x_only , instr: ppn + u + g
|
||||
parameter int ASID_WIDTH = 1
|
||||
)
|
||||
(
|
||||
input logic clk_i, // Clock
|
||||
|
@ -30,6 +29,9 @@ module ptw #(
|
|||
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 [63:0] address_o,
|
||||
|
@ -43,23 +45,21 @@ module ptw #(
|
|||
// to TLBs, update logic
|
||||
output logic itlb_update_o,
|
||||
output logic dtlb_update_o,
|
||||
output logic [CONTENT_SIZE-1:0] itlb_update_content_o,
|
||||
output logic [CONTENT_SIZE-1:0] dtlb_update_content_o,
|
||||
output pte_t update_content_o,
|
||||
|
||||
output logic update_is_2M_o,
|
||||
output logic update_is_1G_o,
|
||||
output logic [26:0] update_vpn_o,
|
||||
output logic [ASID_WIDTH-1:0] update_asid_o,
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
// from TLBs
|
||||
// did we miss?
|
||||
input logic itlb_access_i,
|
||||
input logic itlb_miss_i,
|
||||
input logic [ASID_WIDTH-1:0] itlb_asid_i,
|
||||
input logic [63:0] itlb_vaddr_i,
|
||||
|
||||
input logic dtlb_access_i,
|
||||
input logic dtlb_miss_i,
|
||||
input logic [ASID_WIDTH-1:0] dtlb_asid_i,
|
||||
input logic [63:0] dtlb_vaddr_i,
|
||||
// from CSR file
|
||||
input logic [37:0] pd_ppn_i, // ppn from sptbr
|
||||
|
@ -77,15 +77,17 @@ module ptw #(
|
|||
PTW_PROPAGATE_ERROR
|
||||
} ptw_state_q, ptw_state_n;
|
||||
|
||||
// RV39 defines three levels of page tables
|
||||
// SV39 defines three levels of page tables
|
||||
enum logic [1:0] {
|
||||
LVL1, LVL2, LVL3
|
||||
} ptw_lvl_q, ptw_lvl_n;
|
||||
|
||||
logic ptw_active;
|
||||
assign ptw_active = (ptw_state_q != PTW_READY);
|
||||
// is this an instruction page table walk?
|
||||
logic is_instr_ptw_q, is_instr_ptw_n;
|
||||
|
||||
assign ptw_active_o = (ptw_state_q != PTW_READY);
|
||||
assign walking_instr_o = is_instr_ptw_q;
|
||||
|
||||
// register the ASID
|
||||
logic [ASID_WIDTH-1:0] tlb_update_asid_q, tlb_update_asid_n;
|
||||
// register the VPN we need to walk
|
||||
|
@ -101,40 +103,7 @@ module ptw #(
|
|||
assign update_vpn_o = tlb_update_vpn_q;
|
||||
assign update_asid_o = tlb_update_asid_q;
|
||||
|
||||
struct packed {
|
||||
// logic r; don't care
|
||||
// logic w; don't care
|
||||
// logic x; If page isn't executable it isn't put in the instruction TLB
|
||||
logic u;
|
||||
logic g;
|
||||
logic[PPN4K_WIDTH-1:0] ppn;
|
||||
} itlb_content;
|
||||
|
||||
struct packed {
|
||||
// logic r; If page isn't readable it isn't put in the data TLB (unless it
|
||||
// is executable and the MXR flag is set)
|
||||
logic x_only; // Because of the MXR flag we need an indication if the page
|
||||
// is actually not readable, but executable
|
||||
logic w;
|
||||
logic u;
|
||||
logic g;
|
||||
logic[PPN4K_WIDTH-1:0] ppn;
|
||||
} dtlb_content;
|
||||
|
||||
always_comb begin
|
||||
itlb_update_content_o = '{
|
||||
u : ptw_pte_i.u,
|
||||
g : ptw_pte_i.g,
|
||||
ppn : ptw_pte_i.ppn[37:0]
|
||||
};
|
||||
dtlb_update_content_o = '{
|
||||
x_only : ptw_pte_i.x & ~ptw_pte_i.r,
|
||||
w : ptw_pte_i.w,
|
||||
u : ptw_pte_i.u,
|
||||
g : ptw_pte_i.g,
|
||||
ppn : ptw_pte_i.ppn[37:0]
|
||||
};
|
||||
end
|
||||
assign update_content_o = ptw_pte_i;
|
||||
|
||||
//-------------------
|
||||
// Page table walker
|
||||
|
@ -162,6 +131,7 @@ module ptw #(
|
|||
always_comb begin : ptw
|
||||
// default assignments
|
||||
data_req_o = 1'b0;
|
||||
ptw_error_o = 1'b0;
|
||||
itlb_update_o = 1'b0;
|
||||
dtlb_update_o = 1'b0;
|
||||
is_instr_ptw_n = is_instr_ptw_q;
|
||||
|
@ -178,14 +148,14 @@ module ptw #(
|
|||
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]};
|
||||
is_instr_ptw_n = 1'b0;
|
||||
tlb_update_asid_n = itlb_asid_i;
|
||||
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
|
||||
end else if (enable_translation_i & dtlb_access_i & dtlb_miss_i) begin
|
||||
ptw_pptr_n = {pd_ppn_i, dtlb_vaddr_i[38:30]};
|
||||
is_instr_ptw_n = 1'b0;
|
||||
tlb_update_asid_n = dtlb_asid_i;
|
||||
tlb_update_asid_n = asid_i;
|
||||
tlb_update_vpn_n = dtlb_vaddr_i[38:12];
|
||||
ptw_state_n = PTW_WAIT_GRANT;
|
||||
end
|
||||
|
@ -263,6 +233,7 @@ module ptw #(
|
|||
// TODO: propagate error
|
||||
PTW_PROPAGATE_ERROR: begin
|
||||
ptw_state_n = PTW_READY;
|
||||
ptw_error_o = 1'b1;
|
||||
end
|
||||
|
||||
default:
|
||||
|
|
10
tlb.sv
10
tlb.sv
|
@ -17,11 +17,11 @@
|
|||
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
|
||||
// University of Bologna.
|
||||
//
|
||||
import ariane_pkg::*;
|
||||
|
||||
module tlb #(
|
||||
parameter int TLB_ENTRIES = 4,
|
||||
parameter int ASID_WIDTH = 1,
|
||||
parameter int CONTENT_SIZE = 24 // data: ppn + u + g + w + x_only , instr: ppn + u + g
|
||||
parameter int ASID_WIDTH = 1
|
||||
)
|
||||
(
|
||||
input logic clk_i, // Clock
|
||||
|
@ -33,14 +33,14 @@ module tlb #(
|
|||
input logic update_is_1G_i,
|
||||
input logic [26:0] update_vpn_i,
|
||||
input logic [ASID_WIDTH-1:0] update_asid_i,
|
||||
input logic [CONTENT_SIZE-1:0] update_content_i,
|
||||
input pte_t update_content_i,
|
||||
input logic update_tlb_i,
|
||||
|
||||
// Lookup signals
|
||||
input logic lu_access_i,
|
||||
input logic [ASID_WIDTH-1:0] lu_asid_i,
|
||||
input logic [63:0] lu_vaddr_i,
|
||||
output logic [CONTENT_SIZE-1:0] lu_content_o,
|
||||
output pte_t lu_content_o,
|
||||
output logic lu_is_2M_o,
|
||||
output logic lu_is_1G_o,
|
||||
output logic lu_hit_o
|
||||
|
@ -57,7 +57,7 @@ module tlb #(
|
|||
logic valid;
|
||||
} [TLB_ENTRIES-1:0] tags_q, tags_n;
|
||||
|
||||
logic [TLB_ENTRIES-1:0][CONTENT_SIZE-1:0] content_q, content_n;
|
||||
pte_t [TLB_ENTRIES-1:0] content_q, content_n;
|
||||
logic [8:0] vpn0, vpn1, vpn2;
|
||||
logic [TLB_ENTRIES-1:0] lu_hit; // to replacement logic
|
||||
logic [TLB_ENTRIES-1:0] replace_en; // replace the following entry, set by replacement strategy
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue