[flash_ctrl] Add ECC to program / erase datapaths
- New parameters are defined to represent the "metadata" of flas
- Software only has direct access to data portion
- Metadata area is used for empty detection as well as ECC
- There are currently no plans to make metadata directly accessible to
software, although that can be done.
- ECC and scramble are always disabled / enabled at the same time.
- ECC is calculated on the scrambled data.
- There is no good DV / verilator support yet, To get around the issue,
prim_generic_flash instantiates a memory for main, and another for metadata.
- long term there will need to be a better backdoor solution to flash.
- ECC uncorrectable errors are forwarded up to both the host / controller
- When an uncorrectable error occurs, all F's are returned to the reading agent.
Signed-off-by: Timothy Chen <timothytim@google.com>
[flash_ctrl] update for review comments
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/flash_ctrl.core b/hw/ip/flash_ctrl/flash_ctrl.core
index cb5b6d0..f0ad240 100644
--- a/hw/ip/flash_ctrl/flash_ctrl.core
+++ b/hw/ip/flash_ctrl/flash_ctrl.core
@@ -10,6 +10,7 @@
depend:
- lowrisc:ip:tlul
- lowrisc:prim:all
+ - lowrisc:prim:secded
- lowrisc:prim:flash
- lowrisc:prim:gf_mult
- lowrisc:ip:flash_ctrl_pkg
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index d5bbda4..c3162c1 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -101,11 +101,12 @@
logic [BusAddrW-1:0] flash_addr;
logic flash_req;
logic flash_rd_done, flash_prog_done, flash_erase_done;
- logic flash_error;
+ logic flash_mp_error;
logic [BusWidth-1:0] flash_prog_data;
logic flash_prog_last;
flash_prog_e flash_prog_type;
logic [BusWidth-1:0] flash_rd_data;
+ logic flash_rd_err;
logic flash_phy_busy;
logic rd_op;
logic prog_op;
@@ -358,7 +359,7 @@
.flash_last_o (flash_prog_last),
.flash_type_o (flash_prog_type),
.flash_done_i (flash_prog_done),
- .flash_error_i (flash_error)
+ .flash_error_i (flash_mp_error)
);
// Read FIFO
@@ -433,7 +434,7 @@
.flash_ovfl_o (rd_flash_ovfl),
.flash_data_i (flash_rd_data),
.flash_done_i (flash_rd_done),
- .flash_error_i (flash_error)
+ .flash_error_i (flash_mp_error | flash_rd_err)
);
// Erase handler does not consume fifo
@@ -450,7 +451,7 @@
.flash_addr_o (erase_flash_addr),
.flash_op_o (erase_flash_type),
.flash_done_i (flash_erase_done),
- .flash_error_i (flash_error)
+ .flash_error_i (flash_mp_error)
);
// Final muxing to flash macro module
@@ -551,7 +552,7 @@
.rd_done_o(flash_rd_done),
.prog_done_o(flash_prog_done),
.erase_done_o(flash_erase_done),
- .error_o(flash_error),
+ .error_o(flash_mp_error),
.err_addr_o(err_addr),
// flash phy interface
@@ -608,6 +609,7 @@
assign flash_o.scramble_en = reg2hw.scramble_en.q;
assign flash_o.addr_key = otp_i.addr_key;
assign flash_o.data_key = otp_i.data_key;
+ assign flash_rd_err = flash_i.rd_err;
assign flash_rd_data = flash_i.rd_data;
assign flash_phy_busy = flash_i.init_busy;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
index ffdbc88..0ed379e 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
@@ -239,6 +239,7 @@
logic rd_done;
logic prog_done;
logic erase_done;
+ logic rd_err;
logic [BusWidth-1:0] rd_data;
logic init_busy;
} flash_rsp_t;
@@ -249,6 +250,7 @@
rd_done: 1'b0,
prog_done: 1'b0,
erase_done: 1'b0,
+ rd_err: '0,
rd_data: '0,
init_busy: 1'b0
};
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
index 583a425..2f9545b 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
@@ -14,7 +14,7 @@
input [11:0] op_num_words_i,
output logic op_done_o,
output logic op_err_o,
- input [BusAddrW-1:0] op_addr_i,
+ input [BusAddrW-1:0] op_addr_i,
// FIFO Interface
input data_rdy_i,
@@ -25,7 +25,7 @@
output logic flash_req_o,
output logic [BusAddrW-1:0] flash_addr_o,
output logic flash_ovfl_o,
- input [BusWidth-1:0] flash_data_i,
+ input [BusWidth-1:0] flash_data_i,
input flash_done_i,
input flash_error_i
);
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy.sv b/hw/ip/flash_ctrl/rtl/flash_phy.sv
index 8f52256..c58ee21 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy.sv
@@ -18,6 +18,7 @@
output logic host_req_rdy_o,
output logic host_req_done_o,
output logic [BusWidth-1:0] host_rdata_o,
+ output logic host_rderr_o,
input flash_req_t flash_ctrl_i,
output flash_rsp_t flash_ctrl_o
);
@@ -47,6 +48,7 @@
logic [NumBanks-1:0] host_rsp_vld;
logic [NumBanks-1:0] host_rsp_ack;
logic [BusWidth-1:0] host_rsp_data [NumBanks];
+ logic [NumBanks-1:0] host_rsp_err;
logic seq_fifo_rdy;
logic seq_fifo_pending;
@@ -61,6 +63,7 @@
// common interface
logic [BusWidth-1:0] rd_data [NumBanks];
+ logic [NumBanks-1:0] rd_err;
// select which bank each is operating on
assign host_bank_sel = host_req_i ? host_addr_i[BusAddrW-1 -: BankW] : '0;
@@ -71,6 +74,7 @@
seq_fifo_rdy;
assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
+ assign host_rderr_o = host_rsp_err[rsp_bank_sel];
assign host_rdata_o = host_rsp_data[rsp_bank_sel];
// all banks are assumed to be the same in terms of prog_type support
@@ -79,6 +83,7 @@
assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
+ assign flash_ctrl_o.rd_err = rd_err[ctrl_bank_sel];
assign flash_ctrl_o.init_busy = |init_busy;
// This fifo holds the expected return order
@@ -105,7 +110,7 @@
assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
prim_fifo_sync #(
- .Width (BusWidth),
+ .Width (BusWidth + 1),
.Pass (1'b1),
.Depth (FlashMacroOustanding)
) i_host_rsp_fifo (
@@ -114,11 +119,11 @@
.clr_i (1'b0),
.wvalid_i(host_req_done[bank]),
.wready_o(host_rsp_avail[bank]),
- .wdata_i (rd_data[bank]),
+ .wdata_i ({rd_err[bank], rd_data[bank]}),
.depth_o (),
.rvalid_o(host_rsp_vld[bank]),
.rready_i(host_rsp_ack[bank]),
- .rdata_o (host_rsp_data[bank])
+ .rdata_o ({host_rsp_err[bank], host_rsp_data[bank]})
);
logic host_req;
@@ -161,6 +166,7 @@
.prog_done_o(prog_done[bank]),
.erase_done_o(erase_done[bank]),
.rd_data_o(rd_data[bank]),
+ .rd_err_o(rd_err[bank]),
.init_busy_o(init_busy[bank])
);
end
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
index bf57e16..746464f 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
@@ -37,6 +37,7 @@
output logic prog_done_o,
output logic erase_done_o,
output logic [BusWidth-1:0] rd_data_o,
+ output logic rd_err_o,
output logic init_busy_o
);
@@ -81,7 +82,7 @@
// the read stage is ready to accept a new transaction
logic rd_stage_rdy;
- // the read stage has valid data return
+ // the read stage has valid response
logic rd_stage_data_valid;
// arbitration counter
@@ -220,7 +221,7 @@
////////////////////////
logic flash_rd_req;
- logic [DataWidth-1:0] flash_rdata;
+ logic [FullDataWidth-1:0] flash_rdata;
logic rd_calc_req;
logic [BankAddrW-1:0] rd_calc_addr;
logic rd_op_req;
@@ -239,6 +240,7 @@
.part_i(muxed_part),
.rdy_o(rd_stage_rdy),
.data_valid_o(rd_stage_data_valid),
+ .data_err_o(rd_err_o),
.data_o(rd_data_o),
.idle_o(rd_stage_idle),
.req_o(flash_rd_req),
@@ -259,7 +261,9 @@
// program pipeline
////////////////////////
- logic [DataWidth-1:0] prog_data, prog_scrambled_data;
+ logic [FullDataWidth-1:0] prog_full_data;
+ logic [DataWidth-1:0] prog_scrambled_data;
+ logic [DataWidth-1:0] prog_data;
logic flash_prog_req;
logic prog_calc_req;
logic prog_op_req;
@@ -286,7 +290,8 @@
.scramble_req_o(prog_op_req),
.req_o(flash_prog_req),
.ack_o(prog_ack),
- .data_o(prog_data)
+ .block_data_o(prog_data),
+ .data_o(prog_full_data)
);
end
@@ -335,7 +340,8 @@
.InfosPerBank(InfosPerBank),
.PagesPerBank(PagesPerBank),
.WordsPerPage(WordsPerPage),
- .DataWidth(DataWidth),
+ .DataWidth(FullDataWidth),
+ .MetaDataWidth(MetaDataWidth),
.SkipInit(SkipInit)
) i_flash (
.clk_i,
@@ -347,7 +353,7 @@
.bk_erase_i(reqs[PhyBkErase]),
.addr_i(muxed_addr[BusBankAddrW-1:LsbAddrBit]),
.part_i(muxed_part),
- .prog_data_i(prog_data),
+ .prog_data_i(prog_full_data),
.prog_type_avail_o(prog_type_avail_o),
.ack_o(ack),
.rd_data_o(flash_rdata),
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
index 738ff86..949b151 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
@@ -17,10 +17,14 @@
parameter int WordW = flash_ctrl_pkg::WordW;
parameter int BankAddrW = flash_ctrl_pkg::BankAddrW;
parameter int DataWidth = flash_ctrl_pkg::DataWidth;
+ parameter int EccWidth = 8;
+ parameter int MetaDataWidth = top_pkg::FLASH_METADATA_WIDTH;
parameter int WidthMultiple = flash_ctrl_pkg::WidthMultiple;
parameter int NumBuf = 4; // number of flash read buffers
parameter int RspOrderDepth = 2; // this should be DataWidth / BusWidth
// will switch to this after bus widening
+ parameter int ScrDataWidth = DataWidth + EccWidth;
+ parameter int FullDataWidth = DataWidth + MetaDataWidth;
// flash ctrl / bus parameters
parameter int BusWidth = flash_ctrl_pkg::BusWidth;
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
index d64cf8f..cf273e9 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
@@ -39,7 +39,9 @@
output logic scramble_req_o,
output logic req_o,
output logic ack_o,
- output logic [DataWidth-1:0] data_o
+ // block data does not contain ecc / metadata portion
+ output logic [DataWidth-1:0] block_data_o,
+ output logic [FullDataWidth-1:0] data_o
);
typedef enum logic [2:0] {
@@ -49,7 +51,8 @@
StPostPack,
StWaitFlash,
StCalcMask,
- StScrambleData
+ StScrambleData,
+ StCalcEcc
} prog_state_e;
typedef enum logic [1:0] {
@@ -167,10 +170,14 @@
scramble_req_o = 1'b1;
if (scramble_ack_i) begin
- state_d = StWaitFlash;
+ state_d = StCalcEcc;
end
end
+ StCalcEcc: begin
+ state_d = StWaitFlash;
+ end
+
StWaitFlash: begin
req_o = 1'b1;
@@ -196,16 +203,24 @@
packed_data <= packed_data ^ mask_i;
mask_q <= mask_i;
end else if (scramble_req_o && scramble_ack_i) begin
- packed_data <= scrambled_data_i ^ mask_q;
+ packed_data <= scrambled_data_i[DataWidth-1:0] ^ mask_q;
end else if (pack_valid) begin
packed_data[idx] <= pack_data;
end
end
+ assign block_data_o = packed_data;
+ // ECC handling
+ logic [ScrDataWidth-1:0] ecc_data;
+ prim_secded_72_64_enc u_enc (
+ .in(packed_data),
+ .out(ecc_data)
+ );
- assign data_o = packed_data;
+ // pad the remaining bits to '0', this effectively "programs" them.
+ assign data_o = scramble_i ? FullDataWidth'(ecc_data) : FullDataWidth'(packed_data);
/////////////////////////////////
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv b/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
index 14855ae..9e00073 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
@@ -40,6 +40,7 @@
input flash_ctrl_pkg::flash_part_e part_i,
output logic rdy_o,
output logic data_valid_o,
+ output logic data_err_o,
output logic [BusWidth-1:0] data_o,
output logic idle_o, // the entire read pipeline is idle
@@ -56,7 +57,7 @@
// interface to actual flash primitive
output logic req_o,
input ack_i,
- input [DataWidth-1:0] data_i
+ input [FullDataWidth-1:0] data_i
);
/////////////////////////////////
@@ -65,6 +66,7 @@
// muxed de-scrambled and plain-data
logic [DataWidth-1:0] muxed_data;
+ logic muxed_err;
// muxed data valid signal that takes scrambling into consideration
logic data_valid;
@@ -187,7 +189,7 @@
.clk_i,
.rst_ni,
.alloc_i(rdy_o & alloc[i]),
- .update_i(update[i]),
+ .update_i(update[i] & ~muxed_err),
.wipe_i(data_hazard[i]),
.addr_i(flash_word_addr),
.part_i(part_i),
@@ -286,10 +288,49 @@
// issue a transaction to flash
assign req_o = req_i & rdy_o & no_match;
+
+ /////////////////////////////////
+ // Handling ECC
+ /////////////////////////////////
+
+ // only uncorrectable errors are passed on to the fabric
+ logic ecc_single_err;
+ logic ecc_err;
+ logic unused_err;
+ logic data_err;
+
+ // scrambled data must pass through ECC first
+ logic [DataWidth-1:0] data_ecc_chk;
+ logic [DataWidth-1:0] data_int;
+ logic data_erased;
+
+ // When all bits are 1, the data has been erased
+ // This check is only valid when read data returns.
+ assign data_erased = rd_done & (data_i == {FullDataWidth{1'b1}});
+
+ prim_secded_72_64_dec u_dec (
+ .in(data_i[ScrDataWidth-1:0]),
+ .d_o(data_ecc_chk),
+ .syndrome_o(),
+ .err_o({ecc_err, ecc_single_err})
+ );
+ assign unused_err = ecc_single_err;
+
+ // If data needs to be de-scrambled and has not been erased, pass through ecc decoder.
+ // Otherwise, pass the data through untouched.
+ // Likewise, ecc error is only observed if the data needs to be de-scrambled and has not been
+ // erased.
+ // rd_done signal below is duplicated (already in data_erased) to show clear intent of the code.
+ assign data_int = (rd_done && rd_attrs.descramble && !data_erased) ? data_ecc_chk :
+ data_i[DataWidth-1:0];
+ assign data_err = (rd_done && rd_attrs.descramble && !data_erased) ? ecc_err : 1'b0;
+
/////////////////////////////////
// De-scrambling stage
/////////////////////////////////
+ // Even on ECC error, progress through the stage normally
+
logic fifo_data_ready;
logic fifo_data_valid;
logic mask_valid;
@@ -297,9 +338,11 @@
logic [DataWidth-1:0] mask;
logic data_fifo_rdy;
logic mask_fifo_rdy;
+ logic descram;
logic forward;
logic hint_forward;
logic hint_descram;
+ logic data_err_q;
logic [NumBuf-1:0] alloc_q2;
assign scramble_stage_rdy = data_fifo_rdy & mask_fifo_rdy;
@@ -308,14 +351,15 @@
// 1. When descrambling completes
// 2. Immediately consumed when descrambling not required
// 3. In both cases, when data has not already been forwarded
- assign fifo_data_ready = hint_descram ? descramble_req_o & descramble_ack_i & ~hint_forward :
- fifo_data_valid & !hint_forward;
+ assign fifo_data_ready = hint_descram ? descramble_req_o & descramble_ack_i :
+ fifo_data_valid;
- // data is forwarded whenever it does not require descrambling or if it has been erased
- // but forwarding is only possible if there are no entries in the FIFO to ensure the current
- // read cannot run ahead of the descramble.
- assign forward = rd_done & !fifo_data_valid &
- ((data_i == {DataWidth{1'b1}}) | !rd_attrs.descramble);
+ // descramble is only required if the location is scramble enabled AND it is not erased.
+ assign descram = rd_done & rd_attrs.descramble & ~data_erased;
+
+ // data is forwarded whenever it does not require descrambling and there are no entries in the
+ // FIFO to ensure the current read cannot run ahead of the descramble.
+ assign forward = rd_done & ~descram & ~fifo_data_valid;
// storage for read outputs
// This storage element can be fully merged with the fifo below if the time it takes
@@ -331,28 +375,33 @@
// All these problems could be resolved if the timings matched exactly, however
// the user would need to correctly setup constraints on either flash / gf_mult
// timing change.
+ logic fifo_forward_pop;
+ assign fifo_forward_pop = hint_forward & fifo_data_valid;
+
prim_fifo_sync #(
- .Width (DataWidth + 2 + NumBuf),
+ .Width (DataWidth + 3 + NumBuf),
.Pass (0),
- .Depth (2)
+ .Depth (2),
+ .OutputZeroIfEmpty (1)
) u_rd_storage (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid_i(rd_done),
.wready_o(data_fifo_rdy),
- .wdata_i ({alloc_q, rd_attrs.descramble,forward,data_i}),
+ .wdata_i ({alloc_q, descram, forward, data_err, data_int}),
.depth_o (),
.rvalid_o(fifo_data_valid),
- .rready_i(fifo_data_ready | hint_forward),
- .rdata_o ({alloc_q2, hint_descram,hint_forward,fifo_data})
+ .rready_i(fifo_data_ready | fifo_forward_pop),
+ .rdata_o ({alloc_q2, hint_descram, hint_forward, data_err_q, fifo_data})
);
// storage for mask calculations
prim_fifo_sync #(
.Width (DataWidth),
.Pass (0),
- .Depth (2)
+ .Depth (2),
+ .OutputZeroIfEmpty (1)
) u_mask_storage (
.clk_i,
.rst_ni,
@@ -362,11 +411,12 @@
.wdata_i (mask_i),
.depth_o (),
.rvalid_o(mask_valid),
- .rready_i(fifo_data_ready | hint_forward),
+ .rready_i(fifo_data_ready | fifo_forward_pop),
.rdata_o (mask)
);
// generate the mask calculation request
+ // mask calculation is done in parallel to the read stage
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
calc_req_o <= '0;
@@ -382,13 +432,17 @@
// generate the descramble request whenever both stages are available
// and there is a need to descramble
- assign descramble_req_o = fifo_data_valid & mask_valid & !hint_forward;
+ assign descramble_req_o = fifo_data_valid & mask_valid & hint_descram;
// scrambled data to de-scramble
assign scrambled_data_o = fifo_data ^ mask;
- // muxed data
- assign muxed_data = hint_descram ? descrambled_data_i ^ mask : data_i;
+ // muxed responses
+ // When "forward" is true, hint_descram is always 0.
+ // This is because forward cannot set unless fifo is empty. If FIFO is
+ // empty, hint_descram is automatically 0.
+ assign muxed_data = hint_descram ? descrambled_data_i ^ mask : data_int;
+ assign muxed_err = hint_descram ? data_err_q : data_err;
// muxed data valid
// if no de-scramble required, return data on read complete
@@ -409,7 +463,6 @@
// When forwarding, update entry stored in alloc_q
// When de-scrambling however, the contents of alloc_q may have already updated to the next read,
// so a different pointer is used.
- // assign update = data_valid ? alloc_q : '0;
assign update = forward ? alloc_q :
fifo_data_ready ? alloc_q2 : '0;
@@ -434,18 +487,21 @@
if (WidthMultiple == 1) begin : gen_width_one_rd
// When multiple is 1, just pass the read through directly
logic unused_word_sel;
- assign data_o = |buf_rsp_match ? buf_rsp_data : muxed_data;
+ assign data_o = data_err_o ? {BusWidth{1'b1}} :
+ |buf_rsp_match ? buf_rsp_data : muxed_data;
assign unused_word_sel = rsp_fifo_rdata.word_sel;
end else begin : gen_rd
// Re-arrange data into packed array to pick the correct one
logic [WidthMultiple-1:0][BusWidth-1:0] bus_words_packed;
assign bus_words_packed = |buf_rsp_match ? buf_rsp_data : muxed_data;
- assign data_o = bus_words_packed[rsp_fifo_rdata.word_sel];
+ assign data_o = data_err_o ? {BusWidth{1'b1}} : bus_words_packed[rsp_fifo_rdata.word_sel];
end
+ // whenever the response is coming from the buffer, the error is never set
assign data_valid_o = flash_rsp_match | |buf_rsp_match;
+ assign data_err_o = muxed_err;
// the entire read pipeline is idle when there are no responses to return and no
assign idle_o = ~rsp_fifo_vld;
@@ -478,5 +534,10 @@
// unless the pipeline is idle, we should not have non-read trasnactions
`ASSERT(IdleCheck_A, !idle_o |-> {prog_i,pg_erase_i,bk_erase_i} == '0)
+ // Whenever forward is true, hint_descram should always be 0
+ `ASSERT(ForwardCheck_A, forward |-> hint_descram == '0)
+
+ // Whenever response is coming from buffer, ecc error cannot be set
+ `ASSERT(BufferMatchEcc_A, |buf_rsp_match |-> muxed_err == '0)
endmodule // flash_phy_core
diff --git a/hw/ip/prim/rtl/prim_secded_72_64_dec.sv b/hw/ip/prim/rtl/prim_secded_72_64_dec.sv
index 02b1822..eb4ad3e 100644
--- a/hw/ip/prim/rtl/prim_secded_72_64_dec.sv
+++ b/hw/ip/prim/rtl/prim_secded_72_64_dec.sv
@@ -16,36 +16,36 @@
// 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];
+ ^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60]
+ ^ in[61] ^ in[62];
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[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ 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];
+ ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58]
+ ^ in[61] ^ in[62];
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];
+ ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58]
+ ^ in[59] ^ in[62] ^ 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];
+ ^ in[46] ^ in[47] ^ in[48] ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59]
+ ^ in[60] ^ in[61] ^ in[63];
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];
+ ^ in[58] ^ in[60] ^ in[63];
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];
+ ^ in[47] ^ in[49] ^ in[51] ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57]
+ ^ in[59] ^ in[61] ^ in[63];
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];
+ ^ in[48] ^ in[50] ^ in[51] ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59]
+ ^ in[60] ^ in[61] ^ in[62];
// Corrected output calculation
assign d_o[0] = (syndrome_o == 8'h7) ^ in[0];
@@ -104,14 +104,14 @@
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];
+ assign d_o[56] = (syndrome_o == 8'h6e) ^ in[56];
+ assign d_o[57] = (syndrome_o == 8'h67) ^ in[57];
+ assign d_o[58] = (syndrome_o == 8'hbc) ^ in[58];
+ assign d_o[59] = (syndrome_o == 8'hd9) ^ in[59];
+ assign d_o[60] = (syndrome_o == 8'hb3) ^ in[60];
+ assign d_o[61] = (syndrome_o == 8'hd5) ^ in[61];
+ assign d_o[62] = (syndrome_o == 8'h8f) ^ in[62];
+ assign d_o[63] = (syndrome_o == 8'h7a) ^ in[63];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;
diff --git a/hw/ip/prim/rtl/prim_secded_72_64_enc.sv b/hw/ip/prim/rtl/prim_secded_72_64_enc.sv
index 207c45c..cf89f37 100644
--- a/hw/ip/prim/rtl/prim_secded_72_64_enc.sv
+++ b/hw/ip/prim/rtl/prim_secded_72_64_enc.sv
@@ -75,27 +75,27 @@
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];
+ ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60] ^ in[61] ^ in[62];
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];
+ ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ 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];
+ ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58] ^ in[61] ^ in[62];
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];
+ ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58] ^ in[59] ^ in[62] ^ 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];
+ ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[63];
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];
+ ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] ^ in[58] ^ in[60] ^ in[63];
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];
+ ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57] ^ in[59] ^ in[61] ^ in[63];
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];
+ ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62];
endmodule
diff --git a/hw/ip/prim_generic/rtl/prim_generic_flash.sv b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
index b6962d7..718c1b9 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_flash.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
@@ -10,6 +10,7 @@
parameter int PagesPerBank = 256, // data pages per bank
parameter int WordsPerPage = 256, // words per page
parameter int DataWidth = 32, // bits per word
+ parameter int MetaDataWidth = 12, // this is a temporary parameter to work around ECC issues
parameter bit SkipInit = 1, // this is an option to reset flash to all F's at reset
// Derived parameters
@@ -297,36 +298,70 @@
endcase // unique case (st_q)
end // always_comb
+ localparam int MemWidth = DataWidth - MetaDataWidth;
+
logic [DataWidth-1:0] rd_data_main, rd_data_info;
+ logic [MemWidth-1:0] rd_nom_data_main, rd_nom_data_info;
+ logic [MetaDataWidth-1:0] rd_meta_data_main, rd_meta_data_info;
prim_ram_1p #(
- .Width(DataWidth),
+ .Width(MemWidth),
.Depth(WordsPerBank),
- .DataBitsPerMask(DataWidth)
+ .DataBitsPerMask(MemWidth)
) u_mem (
.clk_i,
.req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)),
.write_i (mem_wr),
.addr_i (mem_addr),
- .wdata_i (mem_wdata),
- .wmask_i ({DataWidth{1'b1}}),
- .rdata_o (rd_data_main)
+ .wdata_i (mem_wdata[MemWidth-1:0]),
+ .wmask_i ({MemWidth{1'b1}}),
+ .rdata_o (rd_nom_data_main)
);
prim_ram_1p #(
- .Width(DataWidth),
+ .Width(MetaDataWidth),
+ .Depth(WordsPerBank),
+ .DataBitsPerMask(MetaDataWidth)
+ ) u_mem_meta (
+ .clk_i,
+ .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)),
+ .write_i (mem_wr),
+ .addr_i (mem_addr),
+ .wdata_i (mem_wdata[MemWidth +: MetaDataWidth]),
+ .wmask_i ({MetaDataWidth{1'b1}}),
+ .rdata_o (rd_meta_data_main)
+ );
+
+ prim_ram_1p #(
+ .Width(MemWidth),
.Depth(WordsPerInfoBank),
- .DataBitsPerMask(DataWidth)
+ .DataBitsPerMask(MemWidth)
) u_info_mem (
.clk_i,
.req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)),
.write_i (mem_wr),
.addr_i (mem_addr[0 +: InfoAddrW]),
- .wdata_i (mem_wdata),
- .wmask_i ({DataWidth{1'b1}}),
- .rdata_o (rd_data_info)
+ .wdata_i (mem_wdata[MemWidth-1:0]),
+ .wmask_i ({MemWidth{1'b1}}),
+ .rdata_o (rd_nom_data_info)
);
+ prim_ram_1p #(
+ .Width(MetaDataWidth),
+ .Depth(WordsPerInfoBank),
+ .DataBitsPerMask(MetaDataWidth)
+ ) u_info_mem_meta (
+ .clk_i,
+ .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)),
+ .write_i (mem_wr),
+ .addr_i (mem_addr[0 +: InfoAddrW]),
+ .wdata_i (mem_wdata[MemWidth +: MetaDataWidth]),
+ .wmask_i ({MetaDataWidth{1'b1}}),
+ .rdata_o (rd_meta_data_info)
+ );
+
+ assign rd_data_main = {rd_meta_data_main, rd_nom_data_main};
+ assign rd_data_info = {rd_meta_data_info, rd_nom_data_info};
assign rd_data_o = held_part == flash_ctrl_pkg::FlashPartData ? rd_data_main : rd_data_info;
// hard-wire assignment for now
diff --git a/hw/top_earlgrey/data/top_earlgrey.sv.tpl b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
index 37c6612..b7c98a3 100644
--- a/hw/top_earlgrey/data/top_earlgrey.sv.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
@@ -406,6 +406,7 @@
logic flash_host_req;
logic flash_host_req_rdy;
logic flash_host_req_done;
+ logic flash_host_rderr;
logic [flash_ctrl_pkg::BusWidth-1:0] flash_host_rdata;
logic [flash_ctrl_pkg::BusAddrW-1:0] flash_host_addr;
@@ -434,7 +435,7 @@
.wmask_o (),
.rdata_i (flash_host_rdata),
.rvalid_i (flash_host_req_done),
- .rerror_i (2'b00)
+ .rerror_i ({flash_host_rderr,1'b0})
);
flash_phy u_flash_${m["name"]} (
@@ -448,6 +449,7 @@
.host_addr_i (flash_host_addr),
.host_req_rdy_o (flash_host_req_rdy),
.host_req_done_o (flash_host_req_done),
+ .host_rderr_o (flash_host_rderr),
.host_rdata_o (flash_host_rdata),
.flash_ctrl_i (${m["inter_signal_list"][0]["top_signame"]}_req),
.flash_ctrl_o (${m["inter_signal_list"][0]["top_signame"]}_rsp)
diff --git a/hw/top_earlgrey/rtl/top_pkg.sv b/hw/top_earlgrey/rtl/top_pkg.sv
index 50269e2..58a8438 100644
--- a/hw/top_earlgrey/rtl/top_pkg.sv
+++ b/hw/top_earlgrey/rtl/top_pkg.sv
@@ -17,6 +17,7 @@
localparam int FLASH_WORDS_PER_PAGE=128;
localparam int FLASH_INFO_PER_BANK=4;
localparam int FLASH_DATA_WIDTH=64;
+localparam int FLASH_METADATA_WIDTH=12;
localparam int NUM_AST_ALERTS=7;
localparam int NUM_IO_RAILS=2;
localparam int ENTROPY_STREAM=4;