Skip to content

Commit

Permalink
cva6: Add ASIDs (#504)
Browse files Browse the repository at this point in the history
* ASID 16-BIT implementation
* merge error corrected

Signed-off-by: Marco Sabatano <marco.sabatano@hensoldt-cyber.com>
  • Loading branch information
marcosabatano committed Sep 2, 2020
1 parent 38c08c5 commit 1055ccd
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 16 deletions.
2 changes: 1 addition & 1 deletion include/ariane_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ package ariane_pkg;
localparam NR_SB_ENTRIES = 8; // number of scoreboard entries
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
// to uniquely identify the entry in the scoreboard
localparam ASID_WIDTH = 1;
localparam ASID_WIDTH = 16;
localparam BITS_SATURATION_COUNTER = 2;
localparam NR_COMMIT_PORTS = 2;

Expand Down
12 changes: 10 additions & 2 deletions src/ariane.sv
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ module ariane import ariane_pkg::*; #(
// --------------
// ISSUE <-> EX
// --------------
logic [63:0] rs1_forwarding_id_ex; // unregistered version of fu_data_o.operanda
logic [63:0] rs2_forwarding_id_ex; // unregistered version of fu_data_o.operandb

fu_data_t fu_data_id_ex;
logic [riscv::VLEN-1:0] pc_id_ex;
logic is_compressed_instr_id_ex;
Expand Down Expand Up @@ -166,7 +169,7 @@ module ariane import ariane_pkg::*; #(
logic sum_csr_ex;
logic mxr_csr_ex;
logic [43:0] satp_ppn_csr_ex;
logic [0:0] asid_csr_ex;
logic [ASID_WIDTH-1:0] asid_csr_ex;
logic [11:0] csr_addr_ex_csr;
fu_op csr_op_commit_csr;
logic [63:0] csr_wdata_commit_csr;
Expand Down Expand Up @@ -307,6 +310,8 @@ module ariane import ariane_pkg::*; #(
.is_ctrl_flow_i ( is_ctrl_fow_id_issue ),
.decoded_instr_ack_o ( issue_instr_issue_id ),
// Functional Units
.rs1_forwarding_o ( rs1_forwarding_id_ex ),
.rs2_forwarding_o ( rs2_forwarding_id_ex ),
.fu_data_o ( fu_data_id_ex ),
.pc_o ( pc_id_ex ),
.is_compressed_instr_o ( is_compressed_instr_id_ex ),
Expand Down Expand Up @@ -350,12 +355,15 @@ module ariane import ariane_pkg::*; #(
// EX
// ---------
ex_stage #(
.ArianeCfg ( ArianeCfg )
.ASID_WIDTH ( ASID_WIDTH ),
.ArianeCfg ( ArianeCfg )
) ex_stage_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.debug_mode_i ( debug_mode ),
.flush_i ( flush_ctrl_ex ),
.rs1_forwarding_i ( rs1_forwarding_id_ex ),
.rs2_forwarding_i ( rs2_forwarding_id_ex ),
.fu_data_i ( fu_data_id_ex ),
.pc_i ( pc_id_ex ),
.is_compressed_instr_i ( is_compressed_instr_id_ex ),
Expand Down
10 changes: 5 additions & 5 deletions src/csr_regfile.sv
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,11 @@ module csr_regfile import ariane_pkg::*; #(
// ---------------------------
logic [63:0] mask;
always_comb begin : csr_update
automatic riscv::satp_t sapt;
automatic riscv::satp_t satp;
automatic logic [63:0] instret;


sapt = satp_q;
satp = satp_q;
instret = instret_q;

// --------------------
Expand Down Expand Up @@ -486,11 +486,11 @@ module csr_regfile import ariane_pkg::*; #(
if (priv_lvl_o == riscv::PRIV_LVL_S && mstatus_q.tvm)
update_access_exception = 1'b1;
else begin
sapt = riscv::satp_t'(csr_wdata);
satp = riscv::satp_t'(csr_wdata);
// only make ASID_LEN - 1 bit stick, that way software can figure out how many ASID bits are supported
sapt.asid = sapt.asid & {{(16-AsidWidth){1'b0}}, {AsidWidth{1'b1}}};
satp.asid = satp.asid & {{(16-AsidWidth){1'b0}}, {AsidWidth{1'b1}}};
// only update if we actually support this mode
if (sapt.mode == MODE_OFF || sapt.mode == MODE_SV39) satp_d = sapt;
if (satp.mode == MODE_OFF || satp.mode == MODE_SV39) satp_d = satp;
end
// changing the mode can have side-effects on address translation (e.g.: other instructions), re-fetch
// the next instruction by executing a flush
Expand Down
1 change: 1 addition & 0 deletions src/decoder.sv
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ module decoder import ariane_pkg::*; (
riscv::OpcodeSystem: begin
instruction_o.fu = CSR;
instruction_o.rs1[4:0] = instr.itype.rs1;
instruction_o.rs2[4:0] = instr.rtype.rs2; //TODO: needs to be checked if better way is available
instruction_o.rd[4:0] = instr.itype.rd;

unique case (instr.itype.funct3)
Expand Down
40 changes: 39 additions & 1 deletion src/ex_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@


module ex_stage import ariane_pkg::*; #(
parameter int unsigned ASID_WIDTH = 1,
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i,
input logic debug_mode_i,

input logic [riscv::VLEN-1:0] rs1_forwarding_i,
input logic [riscv::VLEN-1:0] rs2_forwarding_i,
input fu_data_t fu_data_i,
input logic [riscv::VLEN-1:0] pc_i, // PC of current instruction
input logic is_compressed_instr_i, // we need to know if this was a compressed instruction
Expand Down Expand Up @@ -125,6 +128,13 @@ module ex_stage import ariane_pkg::*; #(
// they will simply block the issue of all other
// instructions.


logic current_instruction_is_sfence_vma;
// These two register store the rs1 and rs2 parameters in case of `SFENCE_VMA`
// instruction to be used for TLB flush in the next clock cycle.
logic [ASID_WIDTH-1:0] asid_to_be_flushed;
logic [riscv::VLEN-1:0] vaddr_to_be_flushed;

// from ALU to branch unit
logic alu_branch_res; // branch comparison result
logic [63:0] alu_result, csr_result, mult_result;
Expand Down Expand Up @@ -262,7 +272,8 @@ module ex_stage import ariane_pkg::*; #(
assign lsu_data = lsu_valid_i ? fu_data_i : '0;

load_store_unit #(
.ArianeCfg ( ArianeCfg )
.ASID_WIDTH ( ASID_WIDTH ),
.ArianeCfg ( ArianeCfg )
) lsu_i (
.clk_i,
.rst_ni,
Expand Down Expand Up @@ -292,6 +303,8 @@ module ex_stage import ariane_pkg::*; #(
.mxr_i,
.satp_ppn_i,
.asid_i,
.asid_to_be_flushed_i (asid_to_be_flushed),
.vaddr_to_be_flushed_i (vaddr_to_be_flushed),
.flush_tlb_i,
.itlb_miss_o,
.dtlb_miss_o,
Expand All @@ -306,4 +319,29 @@ module ex_stage import ariane_pkg::*; #(
.pmpaddr_i
);


always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
current_instruction_is_sfence_vma <= 1'b0;
end else begin
if (flush_i) begin
current_instruction_is_sfence_vma <= 1'b0;
end else if ((fu_data_i.operator == SFENCE_VMA) && csr_valid_i) begin
current_instruction_is_sfence_vma <= 1'b1;
end
end
end

// This process stores the rs1 and rs2 parameters of a SFENCE_VMA instruction.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
asid_to_be_flushed <= '0;
vaddr_to_be_flushed <= '0;
// if the current instruction in EX_STAGE is a sfence.vma, in the next cycle no writes will happen
end else if ((~current_instruction_is_sfence_vma) && (~((fu_data_i.operator == SFENCE_VMA) && csr_valid_i))) begin
vaddr_to_be_flushed <= rs1_forwarding_i;
asid_to_be_flushed <= rs2_forwarding_i[ASID_WIDTH-1:0];
end
end

endmodule
10 changes: 8 additions & 2 deletions src/issue_read_operands.sv
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ module issue_read_operands import ariane_pkg::*; #(
input fu_t [2**REG_ADDR_SIZE-1:0] rd_clobber_fpr_i,
// To FU, just single issue for now
output fu_data_t fu_data_o,
output logic [riscv::VLEN-1:0] rs1_forwarding_o, // unregistered version of fu_data_o.operanda
output logic [riscv::VLEN-1:0] rs2_forwarding_o, // unregistered version of fu_data_o.operandb
output logic [riscv::VLEN-1:0] pc_o,
output logic is_compressed_instr_o,
// ALU 1
Expand Down Expand Up @@ -100,6 +102,10 @@ module issue_read_operands import ariane_pkg::*; #(
assign orig_instr = riscv::instruction_t'(issue_instr_i.ex.tval[31:0]);

// ID <-> EX registers

assign rs1_forwarding_o = operand_a_n[riscv::VLEN-1:0]; //forwarding or unregistered rs1 value
assign rs2_forwarding_o = operand_b_n[riscv::VLEN-1:0]; //forwarding or unregistered rs2 value

assign fu_data_o.operand_a = operand_a_q;
assign fu_data_o.operand_b = operand_b_q;
assign fu_data_o.fu = fu_q;
Expand Down Expand Up @@ -160,7 +166,7 @@ module issue_read_operands import ariane_pkg::*; #(
// check if the clobbering instruction is not a CSR instruction, CSR instructions can only
// be fetched through the register file since they can't be forwarded
// if the operand is available, forward it. CSRs don't write to/from FPR
if (rs1_valid_i && (is_rs1_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs1] != CSR)) begin
if (rs1_valid_i && (is_rs1_fpr(issue_instr_i.op) ? 1'b1 : ((rd_clobber_gpr_i[issue_instr_i.rs1] != CSR) || (issue_instr_i.op == SFENCE_VMA)))) begin
forward_rs1 = 1'b1;
end else begin // the operand is not available -> stall
stall = 1'b1;
Expand All @@ -170,7 +176,7 @@ module issue_read_operands import ariane_pkg::*; #(
if (is_rs2_fpr(issue_instr_i.op) ? rd_clobber_fpr_i[issue_instr_i.rs2] != NONE
: rd_clobber_gpr_i[issue_instr_i.rs2] != NONE) begin
// if the operand is available, forward it. CSRs don't write to/from FPR
if (rs2_valid_i && (is_rs2_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs2] != CSR)) begin
if (rs2_valid_i && (is_rs2_fpr(issue_instr_i.op) ? 1'b1 : ( (rd_clobber_gpr_i[issue_instr_i.rs2] != CSR) || (issue_instr_i.op == SFENCE_VMA)))) begin
forward_rs2 = 1'b1;
end else begin // the operand is not available -> stall
stall = 1'b1;
Expand Down
2 changes: 2 additions & 0 deletions src/issue_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ module issue_stage import ariane_pkg::*; #(
input logic is_ctrl_flow_i,
output logic decoded_instr_ack_o,
// to EX
output [63:0] rs1_forwarding_o, // unregistered version of fu_data_o.operanda
output [63:0] rs2_forwarding_o, // unregistered version of fu_data_o.operandb
output fu_data_t fu_data_o,
output logic [riscv::VLEN-1:0] pc_o,
output logic is_compressed_instr_o,
Expand Down
4 changes: 4 additions & 0 deletions src/load_store_unit.sv
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ module load_store_unit import ariane_pkg::*; #(
input logic mxr_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 [ASID_WIDTH-1:0] asid_to_be_flushed_i,
input logic [63:0] vaddr_to_be_flushed_i,
input logic flush_tlb_i,
// Performance counters
output logic itlb_miss_o,
Expand Down Expand Up @@ -149,6 +151,8 @@ module load_store_unit import ariane_pkg::*; #(
.req_port_o ( dcache_req_ports_o [0] ),
// icache address translation requests
.icache_areq_i ( icache_areq_i ),
.asid_to_be_flushed_i,
.vaddr_to_be_flushed_i,
.icache_areq_o ( icache_areq_o ),
.pmpcfg_i,
.pmpaddr_i,
Expand Down
6 changes: 6 additions & 0 deletions src/mmu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ module mmu import ariane_pkg::*; #(
// input logic flag_mprv_i,
input logic [43:0] satp_ppn_i,
input logic [ASID_WIDTH-1:0] asid_i,
input logic [ASID_WIDTH-1:0] asid_to_be_flushed_i,
input logic [63:0] vaddr_to_be_flushed_i,
input logic flush_tlb_i,
// Performance counters
output logic itlb_miss_o,
Expand Down Expand Up @@ -105,6 +107,8 @@ module mmu import ariane_pkg::*; #(

.lu_access_i ( itlb_lu_access ),
.lu_asid_i ( asid_i ),
.asid_to_be_flushed_i ( asid_to_be_flushed_i ),
.vaddr_to_be_flushed_i ( vaddr_to_be_flushed_i ),
.lu_vaddr_i ( icache_areq_i.fetch_vaddr ),
.lu_content_o ( itlb_content ),

Expand All @@ -125,6 +129,8 @@ module mmu import ariane_pkg::*; #(

.lu_access_i ( dtlb_lu_access ),
.lu_asid_i ( asid_i ),
.asid_to_be_flushed_i ( asid_to_be_flushed_i ),
.vaddr_to_be_flushed_i ( vaddr_to_be_flushed_i ),
.lu_vaddr_i ( lsu_vaddr_i ),
.lu_content_o ( dtlb_content ),

Expand Down
36 changes: 31 additions & 5 deletions src/tlb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ module tlb import ariane_pkg::*; #(
input logic [ASID_WIDTH-1:0] lu_asid_i,
input logic [riscv::VLEN-1:0] lu_vaddr_i,
output riscv::pte_t lu_content_o,
input logic [ASID_WIDTH-1:0] asid_to_be_flushed_i,
input logic [riscv::VLEN-1:0] vaddr_to_be_flushed_i,
output logic lu_is_2M_o,
output logic lu_is_1G_o,
output logic lu_hit_o
Expand Down Expand Up @@ -66,7 +68,8 @@ module tlb import ariane_pkg::*; #(

for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin
// first level match, this may be a giga page, check the ASID flags as well
if (tags_q[i].valid && lu_asid_i == tags_q[i].asid && vpn2 == tags_q[i].vpn2) begin
// if the entry is associated to a global address, don't match the ASID (ASID is don't care)
if (tags_q[i].valid && ((lu_asid_i == tags_q[i].asid) || content_q[i].g) && vpn2 == tags_q[i].vpn2) begin
// second level
if (tags_q[i].is_1G) begin
lu_is_1G_o = 1'b1;
Expand All @@ -88,21 +91,44 @@ module tlb import ariane_pkg::*; #(
end
end

// ------------------


logic asid_to_be_flushed_is0; // indicates that the ASID provided by SFENCE.VMA (rs2)is 0, active high
logic vaddr_to_be_flushed_is0; // indicates that the VADDR provided by SFENCE.VMA (rs1)is 0, active high
logic [TLB_ENTRIES-1:0] vaddr_vpn0_match;
logic [TLB_ENTRIES-1:0] vaddr_vpn1_match;
logic [TLB_ENTRIES-1:0] vaddr_vpn2_match;

assign asid_to_be_flushed_is0 = ~(|asid_to_be_flushed_i);
assign vaddr_to_be_flushed_is0 = ~(|vaddr_to_be_flushed_i);

// ------------------
// Update and Flush
// ------------------
always_comb begin : update_flush
tags_n = tags_q;
content_n = content_q;

for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin

vaddr_vpn0_match[i] = (vaddr_to_be_flushed_i[20:12] == tags_q[i].vpn0);
vaddr_vpn1_match[i] = (vaddr_to_be_flushed_i[29:21] == tags_q[i].vpn1);
vaddr_vpn2_match[i] = (vaddr_to_be_flushed_i[38:30] == tags_q[i].vpn2);

if (flush_i) begin
// invalidate logic
if (lu_asid_i == 1'b0) // flush everything if ASID is 0
// flush everything if ASID is 0 and vaddr is 0 ("SFENCE.VMA x0 x0" case)
if (asid_to_be_flushed_is0 && vaddr_to_be_flushed_is0 )
tags_n[i].valid = 1'b0;
else if (lu_asid_i == tags_q[i].asid) // just flush entries from this ASID
// flush vaddr in all addressing space ("SFENCE.VMA vaddr x0" case), it should happen only for leaf pages
else if (asid_to_be_flushed_is0 && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_2M) ) && (~vaddr_to_be_flushed_is0))
tags_n[i].valid = 1'b0;

// the entry is flushed if it's not global and asid and vaddr both matches with the entry to be flushed ("SFENCE.VMA vaddr asid" case)
else if ((!content_q[i].g) && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_2M)) && (asid_to_be_flushed_i == tags_q[i].asid) && (!vaddr_to_be_flushed_is0) && (!asid_to_be_flushed_is0))
tags_n[i].valid = 1'b0;
// the entry is flushed if it's not global, and the asid matches and vaddr is 0. ("SFENCE.VMA 0 asid" case)
else if ((!content_q[i].g) && (vaddr_to_be_flushed_is0) && (asid_to_be_flushed_i == tags_q[i].asid) && (!asid_to_be_flushed_is0))
tags_n[i].valid = 1'b0;
// normal replacement
end else if (update_i.valid & replace_en[i]) begin
// update tag array
Expand Down

0 comments on commit 1055ccd

Please sign in to comment.