[rtl] Add Icache ECC

- Add modules for ecc generation and checking
- Add supporting logic to icache module

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2020-03-13 11:53:57 +00:00 committed by Tom Roberts
parent fe00eb46e9
commit ef17d4fcc2
7 changed files with 536 additions and 43 deletions

View file

@ -43,6 +43,9 @@ The following table describes the available configuration parameters.
+-------------------------+-----------+-----------------------------------------------+
| ``CacheSizeBytes`` | ``4kB`` | Size of cache in bytes. |
+-------------------------+-----------+-----------------------------------------------+
| ``CacheECC`` | ``1'b0`` | Enable SECDED ECC protection in tag and data |
| | | RAMs. |
+-------------------------+-----------+-----------------------------------------------+
| ``LineSize`` | ``64`` | The width of one cache line in bits. |
| | | Line sizes smaller than 64 bits may give |
| | | compilation errors. |
@ -82,18 +85,21 @@ RAM Arrangement
---------------
The data RAMs are arranged as ``NumWays`` banks of ``LineSize`` width.
If ECC is configured, the tag and data banks will be wider to accomodate the extra checkbits.
Indicative RAM sizes for common configurations are given in the table below:
+-------------------------+-----------------+-----------------+
| Cache config | Tag RAMs | Data RAMs |
+=========================+=================+=================+
| 4kB, 2 way, 64bit line | 2 x 256 x 21bit | 4 x 256 x 32bit |
+-------------------------+-----------------+-----------------+
| 4kB, 2 way, 128bit line | 2 x 128 x 21bit | 8 x 128 x 32bit |
+-------------------------+-----------------+-----------------+
| 4kB, 4 way, 64bit line | 4 x 128 x 21bit | 8 x 128 x 32bit |
+-------------------------+-----------------+-----------------+
+------------------------------+-----------------+------------------+
| Cache config | Tag RAMs | Data RAMs |
+==============================+=================+==================+
| 4kB, 2 way, 64bit line | 2 x 256 x 22bit | 2 x 256 x 64bit |
+------------------------------+-----------------+------------------+
| 4kB, 2 way, 64bit line w/ECC | 2 x 256 x 28bit | 2 x 256 x 72bit |
+------------------------------+-----------------+------------------+
| 4kB, 2 way, 128bit line | 2 x 128 x 22bit | 2 x 128 x 128bit |
+------------------------------+-----------------+------------------+
| 4kB, 4 way, 64bit line | 4 x 128 x 22bit | 4 x 128 x 64bit |
+------------------------------+-----------------+------------------+
Sub Unit Description
--------------------
@ -160,6 +166,36 @@ The remaining data from hits is buffered in the fill buffer data storage and sup
To deal with misalignment caused by compressed instructions, there is a 16bit skid buffer to store the upper halfword.
Cache ECC protection
^^^^^^^^^^^^^^^^^^^^
When ECC protection is enabled, extra checkbits are appended to the top of the tag and data RAM write data as follows:
For the Tag RAMs (4kB cache):
+---------------+-----------+--------+
| ECC checkbits | Valid bit | Tag |
+---------------+-----------+--------+
| [27:22] | [21] | [20:0] |
+---------------+-----------+--------+
For the Data RAMs (64bit line):
+---------------+--------+
| ECC checkbits | Data |
+---------------+--------+
| [71:64] | [63:0] |
+---------------+--------+
The checkbits are generated by dedicated modules in IC0 before the RAMs are written.
In IC1, the RAM read data and checkbits are fed into dedicated modules which output whether there was an error.
Although the modules used have the required outputs to allow inline correction of single bit errors, the I$ does not make use of them since it never performs corrections.
Any error (single or double bit) in any RAM will effectively cancel a cache hit in IC1.
The request which observed an error will fetch it's data from the main instruction memory as normal for a cache miss.
The cache index and way (or ways) with errors are stored in IC1, and a cache write is forced the next cycle to invalidate that line.
Lookup requests will be blocked in IC0 while the invalidation write is performed.
Cache invalidation
^^^^^^^^^^^^^^^^^^

View file

@ -14,12 +14,13 @@ module ibex_icache #(
// Cache arrangement parameters
parameter int unsigned BusWidth = 32,
parameter int unsigned CacheSizeBytes = 4*1024,
parameter bit CacheECC = 1'b0,
parameter int unsigned LineSize = 64,
parameter int unsigned NumWays = 2,
// Always make speculative bus requests in parallel with lookups
parameter bit SpecRequest = 1'b0,
parameter bit SpecRequest = 1'b0,
// Only cache branch targets
parameter bit BranchCache = 1'b0
parameter bit BranchCache = 1'b0
) (
// Clock and reset
input logic clk_i,
@ -55,7 +56,6 @@ module ibex_icache #(
);
// NOTE RTL IS DRAFT
// TODO different RAM primitives?
// Local constants
localparam int unsigned ADDR_W = 32;
@ -64,6 +64,7 @@ module ibex_icache #(
// Request throttling threshold
localparam int unsigned FB_THRESHOLD = NUM_FB - 2;
// Derived parameters
localparam int unsigned LINE_SIZE_ECC = CacheECC ? (LineSize + 8) : LineSize;
localparam int unsigned LINE_SIZE_BYTES = LineSize/8;
localparam int unsigned LINE_W = $clog2(LINE_SIZE_BYTES);
localparam int unsigned BUS_BYTES = BusWidth/8;
@ -74,6 +75,7 @@ module ibex_icache #(
localparam int unsigned INDEX_W = $clog2(NUM_LINES);
localparam int unsigned INDEX_HI = INDEX_W + LINE_W - 1;
localparam int unsigned TAG_SIZE = ADDR_W - INDEX_W - LINE_W + 1; // 1 valid bit
localparam int unsigned TAG_SIZE_ECC = CacheECC ? (TAG_SIZE + 6) : TAG_SIZE;
localparam int unsigned OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
// Prefetch signals
@ -87,7 +89,7 @@ module ibex_icache #(
logic [INDEX_W-1:0] lookup_index_ic0;
logic fill_req_ic0;
logic [INDEX_W-1:0] fill_index_ic0;
logic [31:INDEX_HI+1] fill_tag_ic0;
logic [TAG_SIZE-1:0] fill_tag_ic0;
logic [LineSize-1:0] fill_wdata_ic0;
logic lookup_grant_ic0;
logic lookup_actual_ic0;
@ -96,16 +98,16 @@ module ibex_icache #(
logic [INDEX_W-1:0] tag_index_ic0;
logic [NumWays-1:0] tag_banks_ic0;
logic tag_write_ic0;
logic [TAG_SIZE-1:0] tag_wdata_ic0;
logic [TAG_SIZE_ECC-1:0] tag_wdata_ic0;
logic data_req_ic0;
logic [INDEX_W-1:0] data_index_ic0;
logic [NumWays-1:0] data_banks_ic0;
logic data_write_ic0;
logic [LineSize-1:0] data_wdata_ic0;
logic [LINE_SIZE_ECC-1:0] data_wdata_ic0;
// Cache pipelipe IC1 signals
logic [TAG_SIZE-1:0] tag_rdata_ic1 [NumWays];
logic [LineSize-1:0] data_rdata_ic1 [NumWays];
logic [LineSize-1:0] hit_data_ic1;
logic [TAG_SIZE_ECC-1:0] tag_rdata_ic1 [NumWays];
logic [LINE_SIZE_ECC-1:0] data_rdata_ic1 [NumWays];
logic [LINE_SIZE_ECC-1:0] hit_data_ic1;
logic lookup_valid_ic1;
logic [ADDR_W-1:INDEX_HI+1] lookup_addr_ic1;
logic [NumWays-1:0] tag_match_ic1;
@ -114,6 +116,10 @@ module ibex_icache #(
logic [NumWays-1:0] lowest_invalid_way_ic1;
logic [NumWays-1:0] round_robin_way_ic1, round_robin_way_q;
logic [NumWays-1:0] sel_way_ic1;
logic ecc_err_ic1;
logic ecc_write_req;
logic [NumWays-1:0] ecc_write_ways;
logic [INDEX_W-1:0] ecc_write_index;
// Fill buffer signals
logic gnt_or_pmp_err;
logic [$clog2(NUM_FB)-1:0] fb_fill_level;
@ -133,6 +139,7 @@ module ibex_icache #(
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_rvd_cnt_d, fill_rvd_cnt_q;
logic [NUM_FB-1:0] fill_rvd_done;
logic [NUM_FB-1:0] fill_ram_done_d, fill_ram_done_q;
logic [NUM_FB-1:0] fill_out_grant;
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_out_cnt_d, fill_out_cnt_q;
logic [NUM_FB-1:0] fill_out_done;
logic [NUM_FB-1:0] fill_ext_req, fill_rvd_exp, fill_ram_req, fill_out_req;
@ -214,7 +221,7 @@ module ibex_icache #(
// Cache lookup
assign lookup_throttle = (fb_fill_level > FB_THRESHOLD[$clog2(NUM_FB)-1:0]);
assign lookup_req_ic0 = req_i & ~&fill_busy_q & (branch_i | ~lookup_throttle);
assign lookup_req_ic0 = req_i & ~&fill_busy_q & (branch_i | ~lookup_throttle) & ~ecc_write_req;
assign lookup_addr_ic0 = branch_i ? addr_i :
prefetch_addr_q;
assign lookup_index_ic0 = lookup_addr_ic0[INDEX_HI:LINE_W];
@ -222,30 +229,61 @@ module ibex_icache #(
// Cache write
assign fill_req_ic0 = (|fill_ram_req);
assign fill_index_ic0 = fill_ram_req_addr[INDEX_HI:LINE_W];
assign fill_tag_ic0 = fill_ram_req_addr[ADDR_W-1:INDEX_HI+1];
assign fill_tag_ic0 = {(~inval_prog_q & ~ecc_write_req),fill_ram_req_addr[ADDR_W-1:INDEX_HI+1]};
assign fill_wdata_ic0 = fill_ram_req_data;
// Arbitrated signals - lookups have highest priority
assign lookup_grant_ic0 = lookup_req_ic0;
assign fill_grant_ic0 = fill_req_ic0 & ~lookup_req_ic0 & ~inval_prog_q;
assign fill_grant_ic0 = fill_req_ic0 & ~lookup_req_ic0 & ~inval_prog_q & ~ecc_write_req;
// Qualified lookup grant to mask ram signals in IC1 if access was not made
assign lookup_actual_ic0 = lookup_grant_ic0 & icache_enable_i & ~inval_prog_q;
// Tagram
assign tag_req_ic0 = lookup_req_ic0 | fill_req_ic0 | inval_prog_q;
assign tag_req_ic0 = lookup_req_ic0 | fill_req_ic0 | inval_prog_q | ecc_write_req;
assign tag_index_ic0 = inval_prog_q ? inval_index_q :
ecc_write_req ? ecc_write_index :
fill_grant_ic0 ? fill_index_ic0 :
lookup_index_ic0;
assign tag_banks_ic0 = fill_grant_ic0 ? fill_ram_req_way : {NumWays{1'b1}};
assign tag_write_ic0 = fill_grant_ic0 | inval_prog_q;
assign tag_wdata_ic0 = {~inval_prog_q,fill_tag_ic0};
assign tag_banks_ic0 = ecc_write_req ? ecc_write_ways :
fill_grant_ic0 ? fill_ram_req_way :
{NumWays{1'b1}};
assign tag_write_ic0 = fill_grant_ic0 | inval_prog_q | ecc_write_req;
// Dataram
assign data_req_ic0 = lookup_req_ic0 | fill_req_ic0;
assign data_index_ic0 = tag_index_ic0;
assign data_banks_ic0 = tag_banks_ic0;
assign data_write_ic0 = tag_write_ic0;
assign data_wdata_ic0 = fill_wdata_ic0;
// Append ECC checkbits to write data if required
if (CacheECC) begin : gen_ecc_wdata
// Tagram ECC
// Reuse the same ecc encoding module for larger cache sizes by padding with zeros
logic [21:0] tag_ecc_input_padded;
logic [27:0] tag_ecc_output_padded;
logic [22-TAG_SIZE:0] tag_ecc_output_unused;
assign tag_ecc_input_padded = {{22-TAG_SIZE{1'b0}},fill_tag_ic0};
assign tag_ecc_output_unused = tag_ecc_output_padded[21:TAG_SIZE-1];
prim_secded_28_22_enc tag_ecc_enc (
.in (tag_ecc_input_padded),
.out (tag_ecc_output_padded)
);
assign tag_wdata_ic0 = {tag_ecc_output_padded[27:22],tag_ecc_output_padded[TAG_SIZE-1:0]};
// Dataram ECC
prim_secded_72_64_enc data_ecc_enc (
.in (fill_wdata_ic0),
.out (data_wdata_ic0)
);
end else begin : gen_noecc_wdata
assign tag_wdata_ic0 = fill_tag_ic0;
assign data_wdata_ic0 = fill_wdata_ic0;
end
////////////////
// IC0 -> IC1 //
@ -254,14 +292,14 @@ module ibex_icache #(
for (genvar way = 0; way < NumWays; way++) begin : gen_rams
// Tag RAM instantiation
prim_generic_ram_1p #(
.Width (TAG_SIZE),
.Width (TAG_SIZE_ECC),
.Depth (NUM_LINES)
) tag_bank (
.clk_i (clk_i),
.rst_ni (rst_ni),
.req_i (tag_req_ic0 & tag_banks_ic0[way]),
.write_i (tag_write_ic0),
.wmask_i ({TAG_SIZE{1'b1}}),
.wmask_i ({TAG_SIZE_ECC{1'b1}}),
.addr_i (tag_index_ic0),
.wdata_i (tag_wdata_ic0),
.rvalid_o (),
@ -269,14 +307,14 @@ module ibex_icache #(
);
// Data RAM instantiation
prim_generic_ram_1p #(
.Width (LineSize),
.Width (LINE_SIZE_ECC),
.Depth (NUM_LINES)
) data_bank (
.clk_i (clk_i),
.rst_ni (rst_ni),
.req_i (data_req_ic0 & data_banks_ic0[way]),
.write_i (data_write_ic0),
.wmask_i ({LineSize{1'b1}}),
.wmask_i ({LINE_SIZE_ECC{1'b1}}),
.addr_i (data_index_ic0),
.wdata_i (data_wdata_ic0),
.rvalid_o (),
@ -305,10 +343,11 @@ module ibex_icache #(
// Tag matching
for (genvar way = 0; way < NumWays; way++) begin : gen_tag_match
assign tag_match_ic1[way] = (tag_rdata_ic1[way] ==
assign tag_match_ic1[way] = (tag_rdata_ic1[way][TAG_SIZE-1:0] ==
{1'b1,lookup_addr_ic1[ADDR_W-1:INDEX_HI+1]});
assign tag_invalid_ic1[way] = ~tag_rdata_ic1[way][TAG_SIZE-1];
end
assign tag_hit_ic1 = |tag_match_ic1;
// Hit data mux
@ -342,6 +381,83 @@ module ibex_icache #(
assign sel_way_ic1 = |tag_invalid_ic1 ? lowest_invalid_way_ic1 :
round_robin_way_q;
// ECC checking logic
if (CacheECC) begin : gen_data_ecc_checking
logic [NumWays-1:0] tag_err_ic1;
logic [1:0] data_err_ic1;
logic ecc_correction_write_d, ecc_correction_write_q;
logic [NumWays-1:0] ecc_correction_ways_d, ecc_correction_ways_q;
logic [INDEX_W-1:0] lookup_index_ic1, ecc_correction_index_q;
// Tag ECC checking
for (genvar way = 0; way < NumWays; way++) begin : gen_tag_ecc
logic [1:0] tag_err_bank_ic1;
logic [27:0] tag_rdata_padded_ic1;
// Expand the tag rdata with extra padding if the tag size is less than the maximum
assign tag_rdata_padded_ic1 = {tag_rdata_ic1[way][TAG_SIZE_ECC-1-:6],
{22-TAG_SIZE{1'b0}},
tag_rdata_ic1[way][TAG_SIZE-1:0]};
prim_secded_28_22_dec data_ecc_dec (
.in (tag_rdata_padded_ic1),
.d_o (),
.syndrome_o (),
.err_o (tag_err_bank_ic1)
);
assign tag_err_ic1[way] = |tag_err_bank_ic1;
end
// Data ECC checking
// Note - could generate for all ways and mux after
prim_secded_72_64_dec data_ecc_dec (
.in (hit_data_ic1),
.d_o (),
.syndrome_o (),
.err_o (data_err_ic1)
);
assign ecc_err_ic1 = lookup_valid_ic1 & ((|data_err_ic1) | (|tag_err_ic1));
// Error correction
// The way(s) producing the error will be invalidated in the next cycle.
assign ecc_correction_ways_d = tag_err_ic1 | (tag_match_ic1 & {NumWays{|data_err_ic1}});
assign ecc_correction_write_d = ecc_err_ic1;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ecc_correction_write_q <= 1'b0;
end else begin
ecc_correction_write_q <= ecc_correction_write_d;
end
end
// The index is required in IC1 only when ECC is configured so is registered here
always_ff @(posedge clk_i) begin
if (lookup_grant_ic0) begin
lookup_index_ic1 <= lookup_addr_ic0[INDEX_HI-:INDEX_W];
end
end
// Store the ways with errors to be invalidated
always_ff @(posedge clk_i) begin
if (ecc_err_ic1) begin
ecc_correction_ways_q <= ecc_correction_ways_d;
ecc_correction_index_q <= lookup_index_ic1;
end
end
assign ecc_write_req = ecc_correction_write_q;
assign ecc_write_ways = ecc_correction_ways_q;
assign ecc_write_index = ecc_correction_index_q;
end else begin : gen_no_data_ecc
assign ecc_err_ic1 = 1'b0;
assign ecc_write_req = 1'b0;
assign ecc_write_ways = '0;
assign ecc_write_index = '0;
end
///////////////////////////////
// Cache allocation decision //
///////////////////////////////
@ -436,7 +552,7 @@ module ibex_icache #(
(fill_cache_q[fb] & fill_busy_q[fb]);
// Record whether the request hit in the cache
assign fill_hit_ic1[fb] = lookup_valid_ic1 & fill_in_ic1[fb] & tag_hit_ic1;
assign fill_hit_d[fb] = fill_hit_ic1[fb] |
assign fill_hit_d[fb] = (fill_hit_ic1[fb] & ~ecc_err_ic1) |
(fill_hit_q[fb] & fill_busy_q[fb]);
///////////////////////////////////////////
@ -454,10 +570,10 @@ module ibex_icache #(
// External request must be held until granted
assign fill_ext_hold_d[fb] = (fill_alloc[fb] & fill_spec_hold) |
(fill_ext_arb[fb] & ~gnt_or_pmp_err);
// Extneral requests are completed when the counter is filled or when the request is cancelled
// External requests are completed when the counter is filled or when the request is cancelled
assign fill_ext_done[fb] = (fill_ext_cnt_q[fb][LINE_BEATS_W] |
// external requests are considered complete if the request hit
fill_hit_ic1[fb] | fill_hit_q[fb] |
(fill_hit_ic1[fb] & ~ecc_err_ic1) | fill_hit_q[fb] |
// cancel if the line is stale and won't be cached
(~fill_cache_q[fb] & (branch_i | fill_stale_q[fb]))) &
// can't cancel while we are waiting for a grant on the bus
@ -485,11 +601,13 @@ module ibex_icache #(
(fill_hit_ic1[fb] | fill_hit_q[fb] |
(fill_rvd_cnt_q[fb] > fill_out_cnt_q[fb]) | fill_rvd_arb[fb]);
// Calculate when a beat of data is output. Any ECC error squashes the output that cycle.
assign fill_out_grant[fb] = fill_out_arb[fb] & output_ready & ~ecc_err_ic1;
// Count the beats of data output to the IF stage
assign fill_out_cnt_d[fb] = fill_alloc[fb] ? {1'b0,lookup_addr_ic0[LINE_W-1:BUS_W]} :
(fill_out_cnt_q[fb] +
{{LINE_BEATS_W{1'b0}},(fill_out_arb[fb] &
output_ready)});
{{LINE_BEATS_W{1'b0}},fill_out_grant[fb]});
// Data output complete when the counter fills
assign fill_out_done[fb] = fill_out_cnt_q[fb][LINE_BEATS_W];
@ -531,6 +649,7 @@ module ibex_icache #(
fill_older_q[fb]);
// Arbitrate the request which has data available to send, and is the oldest outstanding
assign fill_out_arb[fb] = fill_out_req[fb] & fill_data_sel[fb];
// Assign incoming rvalid data to the oldest fill buffer expecting it
assign fill_rvd_arb[fb] = instr_rvalid_i & fill_rvd_exp[fb] & ~|(fill_rvd_exp & fill_older_q[fb]);
/////////////////////////////
@ -604,9 +723,10 @@ module ibex_icache #(
end
end
// Data either comes from the cache or the bus
assign fill_data_d[fb] = fill_hit_ic1[fb] ? hit_data_ic1 :
{LINE_BEATS{instr_rdata_i}};
// Data either comes from the cache or the bus. If there was an ECC error, we must take
// the incoming bus data since the cache hit data is corrupted.
assign fill_data_d[fb] = (fill_hit_ic1[fb] & ~ecc_err_ic1) ? hit_data_ic1[LineSize-1:0] :
{LINE_BEATS{instr_rdata_i}};
for (genvar b = 0; b < LINE_BEATS; b++) begin : gen_data_buf
// Error tracking (per beat)
@ -698,8 +818,8 @@ module ibex_icache #(
////////////////////////
// Mux between line-width data sources
assign line_data = |fill_data_hit ? hit_data_ic1 : fill_out_data;
assign line_err = |fill_data_hit ? '0 : fill_out_err;
assign line_data = |fill_data_hit ? hit_data_ic1[LineSize-1:0] : fill_out_data;
assign line_err = |fill_data_hit ? {LINE_BEATS{1'b0}} : fill_out_err;
// Mux the relevant beat of line data, based on the output address
always_comb begin
@ -722,7 +842,8 @@ module ibex_icache #(
// Output data is valid (from any of the three possible sources). Note that fill_out_arb
// must be used here rather than fill_out_req because data can become valid out of order
// (e.g. cache hit data can become available ahead of an older outstanding miss).
assign data_valid = |fill_out_arb;
// Any ECC error suppresses the output that cycle.
assign data_valid = |fill_out_arb & ~ecc_err_ic1;
// Skid buffer data
assign skid_data_d = output_data[31:16];
@ -855,6 +976,10 @@ module ibex_icache #(
// Assertions //
////////////////
`ASSERT_INIT(param_legal, (LineSize > 32))
`ASSERT_INIT(size_param_legal, (LineSize > 32))
// ECC primitives will need to be changed for different sizes
`ASSERT_INIT(ecc_tag_param_legal, (TAG_SIZE <= 27))
`ASSERT_INIT(ecc_data_param_legal, (LineSize <= 121))
endmodule

View file

@ -0,0 +1,59 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by secded_gen.py
module prim_secded_28_22_dec (
input [27:0] in,
output logic [21:0] d_o,
output logic [5:0] syndrome_o,
output logic [1:0] err_o
);
logic single_error;
// Syndrome calculation
assign syndrome_o[0] = in[22] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7]
^ in[8] ^ in[9] ^ in[20] ^ in[21];
assign syndrome_o[1] = in[23] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[10] ^ in[11] ^ in[12] ^ in[13]
^ in[14] ^ in[15] ^ in[20] ^ in[21];
assign syndrome_o[2] = in[24] ^ in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[10] ^ in[11] ^ in[12] ^ in[16]
^ in[17] ^ in[18] ^ in[20];
assign syndrome_o[3] = in[25] ^ in[1] ^ in[4] ^ in[7] ^ in[8] ^ in[10] ^ in[13] ^ in[14] ^ in[16]
^ in[17] ^ in[19] ^ in[21];
assign syndrome_o[4] = in[26] ^ in[2] ^ in[5] ^ in[7] ^ in[9] ^ in[11] ^ in[13] ^ in[15] ^ in[16]
^ in[18] ^ in[19] ^ in[20] ^ in[21];
assign syndrome_o[5] = in[27] ^ in[3] ^ in[6] ^ in[8] ^ in[9] ^ in[12] ^ in[14] ^ in[15] ^ in[17]
^ in[18] ^ in[19] ^ in[20] ^ in[21];
// Corrected output calculation
assign d_o[0] = (syndrome_o == 6'h7) ^ in[0];
assign d_o[1] = (syndrome_o == 6'hb) ^ in[1];
assign d_o[2] = (syndrome_o == 6'h13) ^ in[2];
assign d_o[3] = (syndrome_o == 6'h23) ^ in[3];
assign d_o[4] = (syndrome_o == 6'hd) ^ in[4];
assign d_o[5] = (syndrome_o == 6'h15) ^ in[5];
assign d_o[6] = (syndrome_o == 6'h25) ^ in[6];
assign d_o[7] = (syndrome_o == 6'h19) ^ in[7];
assign d_o[8] = (syndrome_o == 6'h29) ^ in[8];
assign d_o[9] = (syndrome_o == 6'h31) ^ in[9];
assign d_o[10] = (syndrome_o == 6'he) ^ in[10];
assign d_o[11] = (syndrome_o == 6'h16) ^ in[11];
assign d_o[12] = (syndrome_o == 6'h26) ^ in[12];
assign d_o[13] = (syndrome_o == 6'h1a) ^ in[13];
assign d_o[14] = (syndrome_o == 6'h2a) ^ in[14];
assign d_o[15] = (syndrome_o == 6'h32) ^ in[15];
assign d_o[16] = (syndrome_o == 6'h1c) ^ in[16];
assign d_o[17] = (syndrome_o == 6'h2c) ^ in[17];
assign d_o[18] = (syndrome_o == 6'h34) ^ in[18];
assign d_o[19] = (syndrome_o == 6'h38) ^ in[19];
assign d_o[20] = (syndrome_o == 6'h37) ^ in[20];
assign d_o[21] = (syndrome_o == 6'h3b) ^ in[21];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;
assign err_o[0] = single_error;
assign err_o[1] = ~single_error & (|syndrome_o);
endmodule

View file

@ -0,0 +1,47 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by secded_gen.py
module prim_secded_28_22_enc (
input [21:0] in,
output logic [27:0] out
);
assign out[0] = in[0] ;
assign out[1] = in[1] ;
assign out[2] = in[2] ;
assign out[3] = in[3] ;
assign out[4] = in[4] ;
assign out[5] = in[5] ;
assign out[6] = in[6] ;
assign out[7] = in[7] ;
assign out[8] = in[8] ;
assign out[9] = in[9] ;
assign out[10] = in[10] ;
assign out[11] = in[11] ;
assign out[12] = in[12] ;
assign out[13] = in[13] ;
assign out[14] = in[14] ;
assign out[15] = in[15] ;
assign out[16] = in[16] ;
assign out[17] = in[17] ;
assign out[18] = in[18] ;
assign out[19] = in[19] ;
assign out[20] = in[20] ;
assign out[21] = in[21] ;
assign out[22] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9]
^ in[20] ^ in[21];
assign out[23] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14]
^ in[15] ^ in[20] ^ in[21];
assign out[24] = in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[10] ^ in[11] ^ in[12] ^ in[16] ^ in[17]
^ in[18] ^ in[20];
assign out[25] = in[1] ^ in[4] ^ in[7] ^ in[8] ^ in[10] ^ in[13] ^ in[14] ^ in[16] ^ in[17]
^ in[19] ^ in[21];
assign out[26] = in[2] ^ in[5] ^ in[7] ^ in[9] ^ in[11] ^ in[13] ^ in[15] ^ in[16] ^ in[18]
^ in[19] ^ in[20] ^ in[21];
assign out[27] = in[3] ^ in[6] ^ in[8] ^ in[9] ^ in[12] ^ in[14] ^ in[15] ^ in[17] ^ in[18]
^ in[19] ^ in[20] ^ in[21];
endmodule

View file

@ -0,0 +1,121 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by secded_gen.py
module prim_secded_72_64_dec (
input [71:0] in,
output logic [63:0] d_o,
output logic [7:0] syndrome_o,
output logic [1:0] err_o
);
logic single_error;
// Syndrome calculation
assign syndrome_o[0] = in[64] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7]
^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15]
^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[57] ^ in[58] ^ in[61]
^ in[62] ^ in[63];
assign syndrome_o[1] = in[65] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22]
^ in[23] ^ in[24] ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30]
^ in[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[58] ^ in[59] ^ in[60]
^ in[62] ^ in[63];
assign syndrome_o[2] = in[66] ^ in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22]
^ in[23] ^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40]
^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[59]
^ in[60] ^ in[63];
assign syndrome_o[3] = in[67] ^ in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21]
^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39]
^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[57]
^ in[58] ^ in[61] ^ in[63];
assign syndrome_o[4] = in[68] ^ in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22]
^ in[26] ^ in[30] ^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42]
^ in[46] ^ in[47] ^ in[48] ^ in[52] ^ in[53] ^ in[54] ^ in[56] ^ in[58]
^ in[59] ^ in[61] ^ in[62];
assign syndrome_o[5] = in[69] ^ in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23]
^ in[27] ^ in[30] ^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44]
^ in[46] ^ in[49] ^ in[50] ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57]
^ in[59] ^ in[60] ^ in[61];
assign syndrome_o[6] = in[70] ^ in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24]
^ in[28] ^ in[31] ^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45]
^ in[47] ^ in[49] ^ in[51] ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[59]
^ in[60] ^ in[61] ^ in[62];
assign syndrome_o[7] = in[71] ^ in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25]
^ in[29] ^ in[32] ^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45]
^ in[48] ^ in[50] ^ in[51] ^ in[53] ^ in[54] ^ in[55] ^ in[57] ^ in[58]
^ in[60] ^ in[62] ^ in[63];
// Corrected output calculation
assign d_o[0] = (syndrome_o == 8'h7) ^ in[0];
assign d_o[1] = (syndrome_o == 8'hb) ^ in[1];
assign d_o[2] = (syndrome_o == 8'h13) ^ in[2];
assign d_o[3] = (syndrome_o == 8'h23) ^ in[3];
assign d_o[4] = (syndrome_o == 8'h43) ^ in[4];
assign d_o[5] = (syndrome_o == 8'h83) ^ in[5];
assign d_o[6] = (syndrome_o == 8'hd) ^ in[6];
assign d_o[7] = (syndrome_o == 8'h15) ^ in[7];
assign d_o[8] = (syndrome_o == 8'h25) ^ in[8];
assign d_o[9] = (syndrome_o == 8'h45) ^ in[9];
assign d_o[10] = (syndrome_o == 8'h85) ^ in[10];
assign d_o[11] = (syndrome_o == 8'h19) ^ in[11];
assign d_o[12] = (syndrome_o == 8'h29) ^ in[12];
assign d_o[13] = (syndrome_o == 8'h49) ^ in[13];
assign d_o[14] = (syndrome_o == 8'h89) ^ in[14];
assign d_o[15] = (syndrome_o == 8'h31) ^ in[15];
assign d_o[16] = (syndrome_o == 8'h51) ^ in[16];
assign d_o[17] = (syndrome_o == 8'h91) ^ in[17];
assign d_o[18] = (syndrome_o == 8'h61) ^ in[18];
assign d_o[19] = (syndrome_o == 8'ha1) ^ in[19];
assign d_o[20] = (syndrome_o == 8'hc1) ^ in[20];
assign d_o[21] = (syndrome_o == 8'he) ^ in[21];
assign d_o[22] = (syndrome_o == 8'h16) ^ in[22];
assign d_o[23] = (syndrome_o == 8'h26) ^ in[23];
assign d_o[24] = (syndrome_o == 8'h46) ^ in[24];
assign d_o[25] = (syndrome_o == 8'h86) ^ in[25];
assign d_o[26] = (syndrome_o == 8'h1a) ^ in[26];
assign d_o[27] = (syndrome_o == 8'h2a) ^ in[27];
assign d_o[28] = (syndrome_o == 8'h4a) ^ in[28];
assign d_o[29] = (syndrome_o == 8'h8a) ^ in[29];
assign d_o[30] = (syndrome_o == 8'h32) ^ in[30];
assign d_o[31] = (syndrome_o == 8'h52) ^ in[31];
assign d_o[32] = (syndrome_o == 8'h92) ^ in[32];
assign d_o[33] = (syndrome_o == 8'h62) ^ in[33];
assign d_o[34] = (syndrome_o == 8'ha2) ^ in[34];
assign d_o[35] = (syndrome_o == 8'hc2) ^ in[35];
assign d_o[36] = (syndrome_o == 8'h1c) ^ in[36];
assign d_o[37] = (syndrome_o == 8'h2c) ^ in[37];
assign d_o[38] = (syndrome_o == 8'h4c) ^ in[38];
assign d_o[39] = (syndrome_o == 8'h8c) ^ in[39];
assign d_o[40] = (syndrome_o == 8'h34) ^ in[40];
assign d_o[41] = (syndrome_o == 8'h54) ^ in[41];
assign d_o[42] = (syndrome_o == 8'h94) ^ in[42];
assign d_o[43] = (syndrome_o == 8'h64) ^ in[43];
assign d_o[44] = (syndrome_o == 8'ha4) ^ in[44];
assign d_o[45] = (syndrome_o == 8'hc4) ^ in[45];
assign d_o[46] = (syndrome_o == 8'h38) ^ in[46];
assign d_o[47] = (syndrome_o == 8'h58) ^ in[47];
assign d_o[48] = (syndrome_o == 8'h98) ^ in[48];
assign d_o[49] = (syndrome_o == 8'h68) ^ in[49];
assign d_o[50] = (syndrome_o == 8'ha8) ^ in[50];
assign d_o[51] = (syndrome_o == 8'hc8) ^ in[51];
assign d_o[52] = (syndrome_o == 8'h70) ^ in[52];
assign d_o[53] = (syndrome_o == 8'hb0) ^ in[53];
assign d_o[54] = (syndrome_o == 8'hd0) ^ in[54];
assign d_o[55] = (syndrome_o == 8'he0) ^ in[55];
assign d_o[56] = (syndrome_o == 8'h7c) ^ in[56];
assign d_o[57] = (syndrome_o == 8'had) ^ in[57];
assign d_o[58] = (syndrome_o == 8'h9b) ^ in[58];
assign d_o[59] = (syndrome_o == 8'h76) ^ in[59];
assign d_o[60] = (syndrome_o == 8'he6) ^ in[60];
assign d_o[61] = (syndrome_o == 8'h79) ^ in[61];
assign d_o[62] = (syndrome_o == 8'hd3) ^ in[62];
assign d_o[63] = (syndrome_o == 8'h8f) ^ in[63];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;
assign err_o[0] = single_error;
assign err_o[1] = ~single_error & (|syndrome_o);
endmodule

View file

@ -0,0 +1,101 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by secded_gen.py
module prim_secded_72_64_enc (
input [63:0] in,
output logic [71:0] out
);
assign out[0] = in[0] ;
assign out[1] = in[1] ;
assign out[2] = in[2] ;
assign out[3] = in[3] ;
assign out[4] = in[4] ;
assign out[5] = in[5] ;
assign out[6] = in[6] ;
assign out[7] = in[7] ;
assign out[8] = in[8] ;
assign out[9] = in[9] ;
assign out[10] = in[10] ;
assign out[11] = in[11] ;
assign out[12] = in[12] ;
assign out[13] = in[13] ;
assign out[14] = in[14] ;
assign out[15] = in[15] ;
assign out[16] = in[16] ;
assign out[17] = in[17] ;
assign out[18] = in[18] ;
assign out[19] = in[19] ;
assign out[20] = in[20] ;
assign out[21] = in[21] ;
assign out[22] = in[22] ;
assign out[23] = in[23] ;
assign out[24] = in[24] ;
assign out[25] = in[25] ;
assign out[26] = in[26] ;
assign out[27] = in[27] ;
assign out[28] = in[28] ;
assign out[29] = in[29] ;
assign out[30] = in[30] ;
assign out[31] = in[31] ;
assign out[32] = in[32] ;
assign out[33] = in[33] ;
assign out[34] = in[34] ;
assign out[35] = in[35] ;
assign out[36] = in[36] ;
assign out[37] = in[37] ;
assign out[38] = in[38] ;
assign out[39] = in[39] ;
assign out[40] = in[40] ;
assign out[41] = in[41] ;
assign out[42] = in[42] ;
assign out[43] = in[43] ;
assign out[44] = in[44] ;
assign out[45] = in[45] ;
assign out[46] = in[46] ;
assign out[47] = in[47] ;
assign out[48] = in[48] ;
assign out[49] = in[49] ;
assign out[50] = in[50] ;
assign out[51] = in[51] ;
assign out[52] = in[52] ;
assign out[53] = in[53] ;
assign out[54] = in[54] ;
assign out[55] = in[55] ;
assign out[56] = in[56] ;
assign out[57] = in[57] ;
assign out[58] = in[58] ;
assign out[59] = in[59] ;
assign out[60] = in[60] ;
assign out[61] = in[61] ;
assign out[62] = in[62] ;
assign out[63] = in[63] ;
assign out[64] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9]
^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] ^ in[18]
^ in[19] ^ in[20] ^ in[57] ^ in[58] ^ in[61] ^ in[62] ^ in[63];
assign out[65] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22] ^ in[23] ^ in[24]
^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] ^ in[33]
^ in[34] ^ in[35] ^ in[58] ^ in[59] ^ in[60] ^ in[62] ^ in[63];
assign out[66] = in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22] ^ in[23]
^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[41] ^ in[42]
^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[59] ^ in[60] ^ in[63];
assign out[67] = in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21] ^ in[26] ^ in[27]
^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[46] ^ in[47] ^ in[48]
^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[57] ^ in[58] ^ in[61] ^ in[63];
assign out[68] = in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22] ^ in[26] ^ in[30]
^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42] ^ in[46] ^ in[47] ^ in[48]
^ in[52] ^ in[53] ^ in[54] ^ in[56] ^ in[58] ^ in[59] ^ in[61] ^ in[62];
assign out[69] = in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23] ^ in[27] ^ in[30]
^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44] ^ in[46] ^ in[49] ^ in[50]
^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] ^ in[59] ^ in[60] ^ in[61];
assign out[70] = in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24] ^ in[28] ^ in[31]
^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45] ^ in[47] ^ in[49] ^ in[51]
^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[59] ^ in[60] ^ in[61] ^ in[62];
assign out[71] = in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25] ^ in[29] ^ in[32]
^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45] ^ in[48] ^ in[50] ^ in[51]
^ in[53] ^ in[54] ^ in[55] ^ in[57] ^ in[58] ^ in[60] ^ in[62] ^ in[63];
endmodule

View file

@ -11,6 +11,10 @@ filesets:
files:
- ./rtl/prim_clock_gating.sv
- ./rtl/prim_generic_ram_1p.sv
- ./rtl/prim_secded_28_22_enc.sv
- ./rtl/prim_secded_28_22_dec.sv
- ./rtl/prim_secded_72_64_enc.sv
- ./rtl/prim_secded_72_64_dec.sv
- ./rtl/ram_1p.sv
- ./rtl/ram_2p.sv
- ./rtl/bus.sv