Skip to content

Commit

Permalink
Add error correction to TLB (only SV39x4).
Browse files Browse the repository at this point in the history
  • Loading branch information
Yvan Tortorella committed May 27, 2024
1 parent 2f0d702 commit 90228e9
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dependencies:
fpnew: { git: "https://github.com/pulp-platform/cvfpu.git", rev: pulp-v0.1.1 }
tech_cells_generic:
{ git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.13 }
redundancy_cells:
{ git: "https://github.com/pulp-platform/redundancy_cells.git", rev: "c44ff735" } # branch: astral-v0

frozen: true

Expand Down
4 changes: 3 additions & 1 deletion core/cva6.sv
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module cva6
// CVA6 config
parameter config_pkg::cva6_cfg_t CVA6Cfg = cva6_config_pkg::cva6_cfg,
parameter bit IsRVFI = bit'(cva6_config_pkg::CVA6ConfigRvfiTrace),
parameter bit EccEnable = 1'b0,
// RVFI
parameter type rvfi_probes_t = struct packed {
logic [TRANS_ID_BITS-1:0] issue_pointer;
Expand Down Expand Up @@ -745,7 +746,8 @@ module cva6
ex_stage #(
.CVA6Cfg (CVA6ExtendCfg),
.ASID_WIDTH(ASID_WIDTH),
.VMID_WIDTH(VMID_WIDTH)
.VMID_WIDTH(VMID_WIDTH),
.EccEnable (EccEnable)
) ex_stage_i (
.clk_i(clk_i),
.rst_ni(rst_uarch_n),
Expand Down
6 changes: 4 additions & 2 deletions core/ex_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module ex_stage
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter int unsigned ASID_WIDTH = 1,
parameter int unsigned VMID_WIDTH = 1
parameter int unsigned VMID_WIDTH = 1,
parameter bit EccEnable = 1'b0
) (
// Subsystem Clock - SUBSYSTEM
input logic clk_i,
Expand Down Expand Up @@ -411,7 +412,8 @@ module ex_stage
load_store_unit #(
.CVA6Cfg (CVA6Cfg),
.ASID_WIDTH(ASID_WIDTH),
.VMID_WIDTH(VMID_WIDTH)
.VMID_WIDTH(VMID_WIDTH),
.EccEnable (EccEnable)
) lsu_i (
.clk_i,
.rst_ni,
Expand Down
6 changes: 4 additions & 2 deletions core/load_store_unit.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ module load_store_unit
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter int unsigned ASID_WIDTH = 1,
parameter int unsigned VMID_WIDTH = 1
parameter int unsigned VMID_WIDTH = 1,
parameter bit EccEnable = 1'b0
) (
// Subsystem Clock - SUBSYSTEM
input logic clk_i,
Expand Down Expand Up @@ -214,7 +215,8 @@ module load_store_unit
.INSTR_TLB_ENTRIES(ariane_pkg::INSTR_TLB_ENTRIES),
.DATA_TLB_ENTRIES (ariane_pkg::DATA_TLB_ENTRIES),
.ASID_WIDTH (ASID_WIDTH),
.VMID_WIDTH (VMID_WIDTH)
.VMID_WIDTH (VMID_WIDTH),
.EccEnable (EccEnable)
) i_cva6_mmu (
// misaligned bypass
.misaligned_ex_i(misaligned_exception),
Expand Down
9 changes: 6 additions & 3 deletions core/mmu_sv39x4/cva6_mmu_sv39x4.sv
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ module cva6_mmu_sv39x4
parameter int unsigned INSTR_TLB_ENTRIES = 4,
parameter int unsigned DATA_TLB_ENTRIES = 4,
parameter int unsigned ASID_WIDTH = 1,
parameter int unsigned VMID_WIDTH = 1
parameter int unsigned VMID_WIDTH = 1,
parameter bit EccEnable = 1'b0
) (
input logic clk_i,
input logic rst_ni,
Expand Down Expand Up @@ -140,7 +141,8 @@ module cva6_mmu_sv39x4
.CVA6Cfg (CVA6Cfg),
.TLB_ENTRIES(INSTR_TLB_ENTRIES),
.ASID_WIDTH (ASID_WIDTH),
.VMID_WIDTH (VMID_WIDTH)
.VMID_WIDTH (VMID_WIDTH),
.EccEnable (EccEnable)
) i_itlb (
.clk_i (clk_i),
.rst_ni (rst_ni),
Expand Down Expand Up @@ -175,7 +177,8 @@ module cva6_mmu_sv39x4
.CVA6Cfg (CVA6Cfg),
.TLB_ENTRIES(DATA_TLB_ENTRIES),
.ASID_WIDTH (ASID_WIDTH),
.VMID_WIDTH (VMID_WIDTH)
.VMID_WIDTH (VMID_WIDTH),
.EccEnable (EccEnable)
) i_dtlb (
.clk_i (clk_i),
.rst_ni (rst_ni),
Expand Down
104 changes: 89 additions & 15 deletions core/mmu_sv39x4/cva6_tlb_sv39x4.sv
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ module cva6_tlb_sv39x4
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter int unsigned TLB_ENTRIES = 4,
parameter int unsigned ASID_WIDTH = 1,
parameter int unsigned VMID_WIDTH = 1
parameter int unsigned VMID_WIDTH = 1,
parameter bit EccEnable = 1'b0
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
Expand Down Expand Up @@ -54,6 +55,9 @@ module cva6_tlb_sv39x4
output logic lu_hit_o
);

localparam int unsigned PteCorrSize = EccEnable ? $clog2($bits(riscv::pte_t)) + 2 : 0;
localparam int unsigned PteSize = $bits(riscv::pte_t) + PteCorrSize;

// SV39 defines three levels of page tables
struct packed {
logic [ASID_WIDTH-1:0] asid;
Expand All @@ -72,11 +76,28 @@ module cva6_tlb_sv39x4
} [TLB_ENTRIES-1:0]
tags_q, tags_n;

struct packed {
logic [PteSize-1:0] pte;
logic [PteSize-1:0] gpte;
} tlb_content_n;

struct packed {
logic [PteSize-1:0] pte;
logic [PteSize-1:0] gpte;
} [TLB_ENTRIES-1:0]
content_q, content_n;

struct packed {
logic [$bits(riscv::pte_t)-1:0] pte;
logic [$bits(riscv::pte_t)-1:0] gpte;
} [TLB_ENTRIES-1:0]
tlb_content_dec;

struct packed {
riscv::pte_t pte;
riscv::pte_t gpte;
} [TLB_ENTRIES-1:0]
content_q, content_n;
tlb_content_q;

logic [8:0] vpn0, vpn1;
logic [riscv::GPPN2:0] vpn2;
Expand All @@ -88,6 +109,59 @@ module cva6_tlb_sv39x4
logic [TLB_ENTRIES-1:0] is_2M;
logic [TLB_ENTRIES-1:0] match_stage;
riscv::pte_t g_content;

if (EccEnable) begin: gen_tlb_ecc
hsiao_ecc_enc #(
.DataWidth ( $bits(riscv::pte_t) ),
.ProtWidth ( PteCorrSize )
) i_ecc_pte_enc (
.in ( update_i.content ),
.out ( tlb_content_n.pte)
);

hsiao_ecc_enc #(
.DataWidth ( $bits(riscv::pte_t) ),
.ProtWidth ( PteCorrSize )
) i_ecc_gpte_enc (
.in ( update_i.g_content ),
.out ( tlb_content_n.gpte)
);

for (genvar i = 0; i < TLB_ENTRIES; i++) begin
hsiao_ecc_dec #(
.DataWidth ( $bits(riscv::pte_t) ),
.ProtWidth ( PteCorrSize )
) i_ecc_pte_dec (
.in (content_q[i].pte),
.out (tlb_content_dec[i].pte),
.syndrome_o (),
.err_o ()
);

hsiao_ecc_dec #(
.DataWidth ( $bits(riscv::pte_t) ),
.ProtWidth ( PteCorrSize )
) i_ecc_gpte_dec (
.in (content_q[i].gpte),
.out (tlb_content_dec[i].gpte),
.syndrome_o (),
.err_o ()
);
end
end else begin: gen_no_tlb_ecc
assign tlb_content_n.pte = update_i.content;
assign tlb_content_n.gpte = update_i.g_content;
for (genvar i = 0; i < TLB_ENTRIES; i++) begin
assign tlb_content_dec[i].pte = content_q[i].pte;
assign tlb_content_dec[i].gpte = content_q[i].gpte;
end
end

for (genvar i = 0; i < TLB_ENTRIES; i++) begin
assign tlb_content_q[i].pte = riscv::pte_t'(tlb_content_dec[i].pte);
assign tlb_content_q[i].gpte = riscv::pte_t'(tlb_content_dec[i].gpte);
end

//-------------
// Translation
//-------------
Expand Down Expand Up @@ -117,7 +191,7 @@ module cva6_tlb_sv39x4
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 the entry is associated to a global address, don't match the ASID (ASID is don't care)
match_asid[i] = (((lu_asid_i == tags_q[i].asid) || content_q[i].pte.g) && s_st_enbl_i) || !s_st_enbl_i;
match_asid[i] = (((lu_asid_i == tags_q[i].asid) || tlb_content_q[i].pte.g) && s_st_enbl_i) || !s_st_enbl_i;
match_vmid[i] = (lu_vmid_i == tags_q[i].vmid && g_st_enbl_i) || !g_st_enbl_i;
is_1G[i] = is_trans_1G(s_st_enbl_i, g_st_enbl_i, tags_q[i].is_s_1G, tags_q[i].is_g_1G);
is_2M[i] = is_trans_2M(
Expand All @@ -132,11 +206,11 @@ module cva6_tlb_sv39x4
match_stage[i] = (tags_q[i].v == v_i) && (tags_q[i].g_st_enbl == g_st_enbl_i) && (tags_q[i].s_st_enbl == s_st_enbl_i);
if (tags_q[i].valid && match_asid[i] && match_vmid[i] && match_stage[i] && (vpn2 == (tags_q[i].vpn2 & mask_pn2))) begin
lu_gpaddr_o = make_gpaddr(s_st_enbl_i, tags_q[i].is_s_1G, tags_q[i].is_s_2M, lu_vaddr_i,
content_q[i].pte);
tlb_content_q[i].pte);
if (is_1G[i]) begin
lu_is_1G_o = is_1G[i];
lu_content_o = content_q[i].pte;
lu_g_content_o = content_q[i].gpte;
lu_content_o = tlb_content_q[i].pte;
lu_g_content_o = tlb_content_q[i].gpte;
lu_hit_o = 1'b1;
lu_hit[i] = 1'b1;
// not a giga page hit so check further
Expand All @@ -146,12 +220,12 @@ module cva6_tlb_sv39x4
if (is_2M[i] || vpn0 == tags_q[i].vpn0) begin
lu_is_2M_o = is_2M[i];
// Compute G-Stage PPN based on the gpaddr
g_content = content_q[i].gpte;
g_content = tlb_content_q[i].gpte;
if (tags_q[i].is_g_2M) g_content.ppn[8:0] = lu_gpaddr_o[20:12];
if (tags_q[i].is_g_1G) g_content.ppn[17:0] = lu_gpaddr_o[29:12];
// Output G-stage and S-stage content
lu_g_content_o = g_content;
lu_content_o = content_q[i].pte;
lu_content_o = tlb_content_q[i].pte;
lu_hit_o = 1'b1;
lu_hit[i] = 1'b1;
end
Expand Down Expand Up @@ -200,7 +274,7 @@ module cva6_tlb_sv39x4
{
tags_q[i].vpn2, tags_q[i].vpn1, tags_q[i].vpn0
},
content_q[i].pte
tlb_content_q[i].pte
);
gpaddr_gppn0_match[i] = (gpaddr_to_be_flushed_i[20:12] == gppn[i][8:0]);
gpaddr_gppn1_match[i] = (gpaddr_to_be_flushed_i[29:21] == gppn[i][17:9]);
Expand All @@ -215,10 +289,10 @@ module cva6_tlb_sv39x4
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_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_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].pte.g) && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_2M)) && (asid_to_be_flushed_i == tags_q[i].asid) && (!vaddr_to_be_flushed_is0) && (!asid_to_be_flushed_is0))
else if ((!tlb_content_q[i].pte.g) && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_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].pte.g) && (vaddr_to_be_flushed_is0) && (asid_to_be_flushed_i == tags_q[i].asid) && (!asid_to_be_flushed_is0))
else if ((!tlb_content_q[i].pte.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;
end
end else if (flush_vvma_i) begin
Expand All @@ -231,10 +305,10 @@ module cva6_tlb_sv39x4
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_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_2M) ) && (~vaddr_to_be_flushed_is0) && ((tags_q[i].g_st_enbl && lu_vmid_i == tags_q[i].vmid) || !tags_q[i].g_st_enbl))
tags_n[i].valid = 1'b0;
// the entry is flushed if it's not global and asid and vaddr and current VMID matches with the entry to be flushed ("SFENCE.VMA/HFENCE.VVMA vaddr asid" case)
else if ((!content_q[i].pte.g) && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_2M)) && (asid_to_be_flushed_i == tags_q[i].asid && ((tags_q[i].g_st_enbl && lu_vmid_i == tags_q[i].vmid) || !tags_q[i].g_st_enbl)) && (!vaddr_to_be_flushed_is0) && (!asid_to_be_flushed_is0))
else if ((!tlb_content_q[i].pte.g) && ((vaddr_vpn0_match[i] && vaddr_vpn1_match[i] && vaddr_vpn2_match[i]) || (vaddr_vpn2_match[i] && tags_q[i].is_s_1G) || (vaddr_vpn1_match[i] && vaddr_vpn2_match[i] && tags_q[i].is_s_2M)) && (asid_to_be_flushed_i == tags_q[i].asid && ((tags_q[i].g_st_enbl && lu_vmid_i == tags_q[i].vmid) || !tags_q[i].g_st_enbl)) && (!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 and the current VMID matches and vaddr is 0. ("SFENCE.VMA/HFENCE.VVMA 0 asid" case)
else if ((!content_q[i].pte.g) && (vaddr_to_be_flushed_is0) && (asid_to_be_flushed_i == tags_q[i].asid && ((tags_q[i].g_st_enbl && lu_vmid_i == tags_q[i].vmid) || !tags_q[i].g_st_enbl)) && (!asid_to_be_flushed_is0))
else if ((!tlb_content_q[i].pte.g) && (vaddr_to_be_flushed_is0) && (asid_to_be_flushed_i == tags_q[i].asid && ((tags_q[i].g_st_enbl && lu_vmid_i == tags_q[i].vmid) || !tags_q[i].g_st_enbl)) && (!asid_to_be_flushed_is0))
tags_n[i].valid = 1'b0;
end
end else if (flush_gvma_i) begin
Expand Down Expand Up @@ -271,8 +345,8 @@ module cva6_tlb_sv39x4
valid: 1'b1
};
// and content as well
content_n[i].pte = update_i.content;
content_n[i].gpte = update_i.g_content;
content_n[i].pte = tlb_content_n.pte;
content_n[i].gpte = tlb_content_n.gpte;
end
end
end
Expand Down

0 comments on commit 90228e9

Please sign in to comment.