[flash_ctrl] Handle invalid software input
- The software is able to supply an address that is way too
big for flash. Normally this is handled through address
truncation, but this could still result in unexpected
behavior.
- This PR expclitily checks to make sure the supplied address
is not too large for the flash to handle.
Signed-off-by: Timothy Chen <timothytim@google.com>
[flash_ctrl] Add to out of bounds to err code
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Auto generate
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Autogen
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
index f4b0817..6c800cb 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
@@ -1403,14 +1403,18 @@
desc: "interrupt mask for flash alert"
},
{ bits: "2",
+ name: "oob_err",
+ desc: "interrupt mask for software address out of bounds error"
+ },
+ { bits: "3",
name: "mp_err",
desc: "interrupt mask for memory properties error"
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: "interrupt mask for single bit ecc error"
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: "interrupt mask for multiple bits ecc error"
},
@@ -1440,20 +1444,26 @@
'''
},
{ bits: "2",
+ name: "oob_err",
+ desc: '''
+ The supplied address !!ADDR is invalid and out of bounds.
+ '''
+ },
+ { bits: "3",
name: "mp_err",
desc: '''
Flash access has encountered an access permission error.
Please see !!ERR_ADDR for exact address.
'''
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: '''
Flash access has encountered a single bit ECC error.
Please see !!ECC_SINGLE_ERR_ADDR for exact address.
'''
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: '''
Flash access has encountered a multi bit ECC error.
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
index 4575253..9a91548 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
@@ -919,14 +919,18 @@
desc: "interrupt mask for flash alert"
},
{ bits: "2",
+ name: "oob_err",
+ desc: "interrupt mask for software address out of bounds error"
+ },
+ { bits: "3",
name: "mp_err",
desc: "interrupt mask for memory properties error"
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: "interrupt mask for single bit ecc error"
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: "interrupt mask for multiple bits ecc error"
},
@@ -956,20 +960,26 @@
'''
},
{ bits: "2",
+ name: "oob_err",
+ desc: '''
+ The supplied address !!ADDR is invalid and out of bounds.
+ '''
+ },
+ { bits: "3",
name: "mp_err",
desc: '''
Flash access has encountered an access permission error.
Please see !!ERR_ADDR for exact address.
'''
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: '''
Flash access has encountered a single bit ECC error.
Please see !!ECC_SINGLE_ERR_ADDR for exact address.
'''
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: '''
Flash access has encountered a multi bit ECC error.
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
index 96dfcfe..925a158 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
@@ -136,11 +136,16 @@
logic rd_flash_req;
logic rd_flash_ovfl;
logic [BusAddrW-1:0] rd_flash_addr;
+ logic rd_op_valid;
// Erase Control Connections
logic erase_flash_req;
logic [BusAddrW-1:0] erase_flash_addr;
flash_erase_e erase_flash_type;
+ logic erase_op_valid;
+
+ // combined indication that an operation has started
+ logic op_valid;
// Done / Error signaling from ctrl modules
logic prog_done, rd_done, erase_done;
@@ -194,6 +199,8 @@
logic op_start;
logic [11:0] op_num_words;
logic [BusAddrW-1:0] op_addr;
+ // SW or HW supplied address is out of bounds
+ logic op_addr_oob;
flash_op_e op_type;
flash_part_e op_part;
logic [InfoTypesWidth-1:0] op_info_sel;
@@ -371,6 +378,9 @@
assign op_erase_type = flash_erase_e'(muxed_ctrl.erase_sel.q);
assign op_prog_type = flash_prog_e'(muxed_ctrl.prog_sel.q);
assign op_addr = muxed_addr[BusByteWidth +: BusAddrW];
+ // The supplied address by software is completely beyond the flash
+ // and will wrap. Instead of allowing this, explicitly error back.
+ assign op_addr_oob = muxed_addr >= EndAddr;
assign op_type = flash_op_e'(muxed_ctrl.op.q);
assign op_part = flash_part_e'(muxed_ctrl.partition_sel.q);
assign op_info_sel = muxed_ctrl.info_sel.q;
@@ -378,6 +388,7 @@
assign prog_op = op_type == FlashOpProgram;
assign erase_op = op_type == FlashOpErase;
assign sw_sel = if_sel == SwSel;
+ assign op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
// software privilege to creator seed
assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -510,6 +521,7 @@
.op_done_o (prog_done),
.op_err_o (prog_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
.op_type_i (op_prog_type),
.type_avail_i (prog_type_en),
@@ -580,16 +592,18 @@
);
// Read handler is consumer of rd_fifo
+ assign rd_op_valid = op_start & rd_op;
flash_ctrl_rd u_flash_ctrl_rd (
.clk_i,
.rst_ni,
// To arbiter Interface
- .op_start_i (op_start & rd_op),
+ .op_start_i (rd_op_valid),
.op_num_words_i (op_num_words),
.op_done_o (rd_done),
.op_err_o (rd_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// FIFO Interface
.data_rdy_i (rd_fifo_wready),
@@ -606,13 +620,15 @@
);
// Erase handler does not consume fifo
+ assign erase_op_valid = op_start & erase_op;
flash_ctrl_erase u_flash_ctrl_erase (
// Software Interface
- .op_start_i (op_start & erase_op),
+ .op_start_i (erase_op_valid),
.op_type_i (op_erase_type),
.op_done_o (erase_done),
.op_err_o (erase_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// Flash Macro Interface
.flash_req_o (erase_flash_req),
@@ -902,11 +918,13 @@
// Errors and Interrupts
//////////////////////////////////////
+ assign hw2reg.err_code.oob_err.d = 1'b1;
assign hw2reg.err_code.mp_err.d = 1'b1;
assign hw2reg.err_code.ecc_single_err.d = 1'b1;
assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
assign hw2reg.err_code.flash_err.d = 1'b1;
assign hw2reg.err_code.flash_alert.d = 1'b1;
+ assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
assign hw2reg.err_code.mp_err.de = flash_mp_error;
assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
@@ -1106,7 +1124,10 @@
.scan_rst_ni
);
+ /////////////////////////////////
// Assertions
+ /////////////////////////////////
+
`ASSERT_KNOWN(TlDValidKnownO_A, core_tl_o.d_valid )
`ASSERT_KNOWN(TlAReadyKnownO_A, core_tl_o.a_ready )
`ASSERT_KNOWN(PrimTlDValidKnownO_A, prim_tl_o.d_valid )
@@ -1124,4 +1145,11 @@
`ASSERT_KNOWN(IntrOpDoneKnownO_A, intr_op_done_o )
`ASSERT_KNOWN(IntrErrO_A, intr_err_o )
+
+
+ // if there is an out of bounds error, flash request should never assert
+ `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+
+ // add more assertions
+
endmodule
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
index 5cd6057..545e2ec 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
@@ -7,6 +7,9 @@
package flash_ctrl_pkg;
+ // End address of flash
+ parameter logic [top_pkg::TL_AW-1:0] EndAddr = 'h${format(int(cfg.end_addr), "x")};
+
// design parameters that can be altered through topgen
parameter int unsigned NumBanks = flash_ctrl_reg_pkg::RegNumBanks;
parameter int unsigned PagesPerBank = flash_ctrl_reg_pkg::RegPagesPerBank;
diff --git a/hw/ip/flash_ctrl/doc/_index.md b/hw/ip/flash_ctrl/doc/_index.md
index a700b9d..0e9af71 100644
--- a/hw/ip/flash_ctrl/doc/_index.md
+++ b/hw/ip/flash_ctrl/doc/_index.md
@@ -197,6 +197,14 @@
As a result, software does not need to define a start and end page for information partitions.
See {{< regref "BANK0_INFO_PAGE_CFG0" >}} as an example.
+#### Address Out of Bounds Check
+In addition to memory protection, the flash controller also explicitly checks to ensure the supplied input is not too large.
+Normally, if software supplies an address that is larger than the flash, the address bits are truncated and the operation wraps.
+However, this can lead to unintentional side effects where it seems like the controller is erasing, programming or reading the wrong location.
+
+Instead the controller explicitly creates an error when the address is out of bounds.
+This terminates the transaction immediately and notifies software of the error.
+
#### Memory Protection for Key Manager and Life Cycle
While memory protection is largely under software control, certain behavior is hardwired to support key manager secret partitions and life cycle functions.
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index 9e8deab..029a5dd 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -136,11 +136,16 @@
logic rd_flash_req;
logic rd_flash_ovfl;
logic [BusAddrW-1:0] rd_flash_addr;
+ logic rd_op_valid;
// Erase Control Connections
logic erase_flash_req;
logic [BusAddrW-1:0] erase_flash_addr;
flash_erase_e erase_flash_type;
+ logic erase_op_valid;
+
+ // combined indication that an operation has started
+ logic op_valid;
// Done / Error signaling from ctrl modules
logic prog_done, rd_done, erase_done;
@@ -194,6 +199,8 @@
logic op_start;
logic [11:0] op_num_words;
logic [BusAddrW-1:0] op_addr;
+ // SW or HW supplied address is out of bounds
+ logic op_addr_oob;
flash_op_e op_type;
flash_part_e op_part;
logic [InfoTypesWidth-1:0] op_info_sel;
@@ -371,6 +378,9 @@
assign op_erase_type = flash_erase_e'(muxed_ctrl.erase_sel.q);
assign op_prog_type = flash_prog_e'(muxed_ctrl.prog_sel.q);
assign op_addr = muxed_addr[BusByteWidth +: BusAddrW];
+ // The supplied address by software is completely beyond the flash
+ // and will wrap. Instead of allowing this, explicitly error back.
+ assign op_addr_oob = muxed_addr >= EndAddr;
assign op_type = flash_op_e'(muxed_ctrl.op.q);
assign op_part = flash_part_e'(muxed_ctrl.partition_sel.q);
assign op_info_sel = muxed_ctrl.info_sel.q;
@@ -378,6 +388,7 @@
assign prog_op = op_type == FlashOpProgram;
assign erase_op = op_type == FlashOpErase;
assign sw_sel = if_sel == SwSel;
+ assign op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
// software privilege to creator seed
assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -510,6 +521,7 @@
.op_done_o (prog_done),
.op_err_o (prog_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
.op_type_i (op_prog_type),
.type_avail_i (prog_type_en),
@@ -580,16 +592,18 @@
);
// Read handler is consumer of rd_fifo
+ assign rd_op_valid = op_start & rd_op;
flash_ctrl_rd u_flash_ctrl_rd (
.clk_i,
.rst_ni,
// To arbiter Interface
- .op_start_i (op_start & rd_op),
+ .op_start_i (rd_op_valid),
.op_num_words_i (op_num_words),
.op_done_o (rd_done),
.op_err_o (rd_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// FIFO Interface
.data_rdy_i (rd_fifo_wready),
@@ -606,13 +620,15 @@
);
// Erase handler does not consume fifo
+ assign erase_op_valid = op_start & erase_op;
flash_ctrl_erase u_flash_ctrl_erase (
// Software Interface
- .op_start_i (op_start & erase_op),
+ .op_start_i (erase_op_valid),
.op_type_i (op_erase_type),
.op_done_o (erase_done),
.op_err_o (erase_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// Flash Macro Interface
.flash_req_o (erase_flash_req),
@@ -903,11 +919,13 @@
// Errors and Interrupts
//////////////////////////////////////
+ assign hw2reg.err_code.oob_err.d = 1'b1;
assign hw2reg.err_code.mp_err.d = 1'b1;
assign hw2reg.err_code.ecc_single_err.d = 1'b1;
assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
assign hw2reg.err_code.flash_err.d = 1'b1;
assign hw2reg.err_code.flash_alert.d = 1'b1;
+ assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
assign hw2reg.err_code.mp_err.de = flash_mp_error;
assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
@@ -1107,7 +1125,10 @@
.scan_rst_ni
);
+ /////////////////////////////////
// Assertions
+ /////////////////////////////////
+
`ASSERT_KNOWN(TlDValidKnownO_A, core_tl_o.d_valid )
`ASSERT_KNOWN(TlAReadyKnownO_A, core_tl_o.a_ready )
`ASSERT_KNOWN(PrimTlDValidKnownO_A, prim_tl_o.d_valid )
@@ -1125,4 +1146,11 @@
`ASSERT_KNOWN(IntrOpDoneKnownO_A, intr_op_done_o )
`ASSERT_KNOWN(IntrErrO_A, intr_err_o )
+
+
+ // if there is an out of bounds error, flash request should never assert
+ `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+
+ // add more assertions
+
endmodule
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
index 79e7001..00db429 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
@@ -913,6 +913,8 @@
logic err_code_intr_en_flash_err_en_wd;
logic err_code_intr_en_flash_alert_en_qs;
logic err_code_intr_en_flash_alert_en_wd;
+ logic err_code_intr_en_oob_err_qs;
+ logic err_code_intr_en_oob_err_wd;
logic err_code_intr_en_mp_err_qs;
logic err_code_intr_en_mp_err_wd;
logic err_code_intr_en_ecc_single_err_qs;
@@ -924,6 +926,8 @@
logic err_code_flash_err_wd;
logic err_code_flash_alert_qs;
logic err_code_flash_alert_wd;
+ logic err_code_oob_err_qs;
+ logic err_code_oob_err_wd;
logic err_code_mp_err_qs;
logic err_code_mp_err_wd;
logic err_code_ecc_single_err_qs;
@@ -9934,7 +9938,33 @@
);
- // F[mp_err]: 2:2
+ // F[oob_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h0)
+ ) u_err_code_intr_en_oob_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (err_code_intr_en_we),
+ .wd (err_code_intr_en_oob_err_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.err_code_intr_en.oob_err.q),
+
+ // to register interface (read)
+ .qs (err_code_intr_en_oob_err_qs)
+ );
+
+
+ // F[mp_err]: 3:3
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -9960,7 +9990,7 @@
);
- // F[ecc_single_err]: 3:3
+ // F[ecc_single_err]: 4:4
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -9986,7 +10016,7 @@
);
- // F[ecc_multi_err]: 4:4
+ // F[ecc_multi_err]: 5:5
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -10066,7 +10096,33 @@
);
- // F[mp_err]: 2:2
+ // F[oob_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0)
+ ) u_err_code_oob_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (err_code_we),
+ .wd (err_code_oob_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.err_code.oob_err.de),
+ .d (hw2reg.err_code.oob_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.err_code.oob_err.q),
+
+ // to register interface (read)
+ .qs (err_code_oob_err_qs)
+ );
+
+
+ // F[mp_err]: 3:3
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -10092,7 +10148,7 @@
);
- // F[ecc_single_err]: 3:3
+ // F[ecc_single_err]: 4:4
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -10118,7 +10174,7 @@
);
- // F[ecc_multi_err]: 4:4
+ // F[ecc_multi_err]: 5:5
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -11603,22 +11659,26 @@
assign err_code_intr_en_flash_alert_en_wd = reg_wdata[1];
- assign err_code_intr_en_mp_err_wd = reg_wdata[2];
+ assign err_code_intr_en_oob_err_wd = reg_wdata[2];
- assign err_code_intr_en_ecc_single_err_wd = reg_wdata[3];
+ assign err_code_intr_en_mp_err_wd = reg_wdata[3];
- assign err_code_intr_en_ecc_multi_err_wd = reg_wdata[4];
+ assign err_code_intr_en_ecc_single_err_wd = reg_wdata[4];
+
+ assign err_code_intr_en_ecc_multi_err_wd = reg_wdata[5];
assign err_code_we = addr_hit[85] & reg_we & !reg_error;
assign err_code_flash_err_wd = reg_wdata[0];
assign err_code_flash_alert_wd = reg_wdata[1];
- assign err_code_mp_err_wd = reg_wdata[2];
+ assign err_code_oob_err_wd = reg_wdata[2];
- assign err_code_ecc_single_err_wd = reg_wdata[3];
+ assign err_code_mp_err_wd = reg_wdata[3];
- assign err_code_ecc_multi_err_wd = reg_wdata[4];
+ assign err_code_ecc_single_err_wd = reg_wdata[4];
+
+ assign err_code_ecc_multi_err_wd = reg_wdata[5];
assign ecc_single_err_cnt_we = addr_hit[87] & reg_we & !reg_error;
assign ecc_single_err_cnt_wd = reg_wdata[7:0];
@@ -12247,17 +12307,19 @@
addr_hit[84]: begin
reg_rdata_next[0] = err_code_intr_en_flash_err_en_qs;
reg_rdata_next[1] = err_code_intr_en_flash_alert_en_qs;
- reg_rdata_next[2] = err_code_intr_en_mp_err_qs;
- reg_rdata_next[3] = err_code_intr_en_ecc_single_err_qs;
- reg_rdata_next[4] = err_code_intr_en_ecc_multi_err_qs;
+ reg_rdata_next[2] = err_code_intr_en_oob_err_qs;
+ reg_rdata_next[3] = err_code_intr_en_mp_err_qs;
+ reg_rdata_next[4] = err_code_intr_en_ecc_single_err_qs;
+ reg_rdata_next[5] = err_code_intr_en_ecc_multi_err_qs;
end
addr_hit[85]: begin
reg_rdata_next[0] = err_code_flash_err_qs;
reg_rdata_next[1] = err_code_flash_alert_qs;
- reg_rdata_next[2] = err_code_mp_err_qs;
- reg_rdata_next[3] = err_code_ecc_single_err_qs;
- reg_rdata_next[4] = err_code_ecc_multi_err_qs;
+ reg_rdata_next[2] = err_code_oob_err_qs;
+ reg_rdata_next[3] = err_code_mp_err_qs;
+ reg_rdata_next[4] = err_code_ecc_single_err_qs;
+ reg_rdata_next[5] = err_code_ecc_multi_err_qs;
end
addr_hit[86]: begin
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
index 2c93a70..b20e22b 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
@@ -10,6 +10,7 @@
input op_start_i,
input flash_erase_e op_type_i,
input [BusAddrW-1:0] op_addr_i,
+ input op_addr_oob_i,
output logic op_done_o,
output logic op_err_o,
@@ -36,12 +37,16 @@
localparam logic[BusAddrW-1:0] PageAddrMask = ~(('h1 << WordsBitWidth) - 1'b1);
localparam logic[BusAddrW-1:0] BankAddrMask = ~(('h1 << (PagesBitWidth + WordsBitWidth)) - 1'b1);
+ // out of bounds condition, the initial starting address is beyond the flash
+ logic oob_err;
+ assign oob_err = op_start_i & op_addr_oob_i;
+
// IO assignments
- assign op_done_o = flash_req_o & flash_done_i;
- assign op_err_o = flash_req_o & flash_error_i;
+ assign op_done_o = flash_req_o & flash_done_i | oob_err;
+ assign op_err_o = flash_req_o & flash_error_i | oob_err;
// Flash Interface assignments
- assign flash_req_o = op_start_i;
+ assign flash_req_o = op_start_i & ~op_addr_oob_i;
assign flash_op_o = op_type_i;
assign flash_addr_o = (op_type_i == FlashErasePage) ?
op_addr_i & PageAddrMask :
@@ -51,4 +56,5 @@
logic [WordsBitWidth-1:0] unused_addr_i;
assign unused_addr_i = op_addr_i[WordsBitWidth-1:0];
+
endmodule // flash_ctrl_erase
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
index 231f780..46b6a37 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
@@ -7,6 +7,9 @@
package flash_ctrl_pkg;
+ // End address of flash
+ parameter logic [top_pkg::TL_AW-1:0] EndAddr = 'h20100000;
+
// design parameters that can be altered through topgen
parameter int unsigned NumBanks = flash_ctrl_reg_pkg::RegNumBanks;
parameter int unsigned PagesPerBank = flash_ctrl_reg_pkg::RegPagesPerBank;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
index 1fecb35..6c5f714 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
@@ -15,6 +15,7 @@
output logic op_done_o,
output logic op_err_o,
input [BusAddrW-1:0] op_addr_i,
+ input op_addr_oob_i,
input flash_prog_e op_type_i,
input [ProgTypes-1:0] type_avail_i,
@@ -73,7 +74,7 @@
assign end_addr = op_addr_i + BusAddrW'(op_num_words_i);
assign start_window = op_addr_i[BusAddrW-1:BusPgmResWidth];
assign end_window = end_addr[BusAddrW-1:BusPgmResWidth];
- assign win_err = start_window != end_window;
+ assign win_err = (start_window != end_window) | op_addr_oob_i;
// when error'd, continue to drain all program fifo contents like normal operation
// if this is not done, software may fill up the fifo without anyone
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
index 2f9545b..80d7f99 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
@@ -15,6 +15,7 @@
output logic op_done_o,
output logic op_err_o,
input [BusAddrW-1:0] op_addr_i,
+ input op_addr_oob_i,
// FIFO Interface
input data_rdy_i,
@@ -30,9 +31,10 @@
input flash_error_i
);
- typedef enum logic {
- StNorm = 'h0,
- StErr = 'h1
+ typedef enum logic [1:0] {
+ StIdle,
+ StNorm,
+ StErr
} state_e;
state_e st, st_nxt;
@@ -45,7 +47,7 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
cnt <= '0;
- st <= StNorm;
+ st <= StIdle;
end else begin
cnt <= cnt_nxt;
st <= st_nxt;
@@ -69,6 +71,14 @@
err_sel = 1'b0;
unique case (st)
+ StIdle: begin
+ if (op_start_i && op_addr_oob_i) begin
+ st_nxt = StErr;
+ end else if (op_start_i) begin
+ st_nxt = StNorm;
+ end
+ end
+
StNorm: begin
flash_req_o = op_start_i & data_rdy_i;
@@ -81,15 +91,16 @@
cnt_nxt = cnt + 1'b1;
data_wr_o = 1'b1;
err_sel = flash_error_i;
- st_nxt = flash_error_i ? StErr : StNorm;
+ st_nxt = flash_error_i ? StErr : StIdle;
end
end
+
StErr: begin
data_wr_o = data_rdy_i;
err_sel = 1'b1;
if (data_rdy_i && cnt_hit) begin
- st_nxt = StNorm;
+ st_nxt = StIdle;
cnt_nxt = '0;
op_done_o = 1'b1;
op_err_o = 1'b1;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
index 576c8d7..7955b1f 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
@@ -376,6 +376,9 @@
} flash_alert_en;
struct packed {
logic q;
+ } oob_err;
+ struct packed {
+ logic q;
} mp_err;
struct packed {
logic q;
@@ -394,6 +397,9 @@
} flash_alert;
struct packed {
logic q;
+ } oob_err;
+ struct packed {
+ logic q;
} mp_err;
struct packed {
logic q;
@@ -530,6 +536,10 @@
struct packed {
logic d;
logic de;
+ } oob_err;
+ struct packed {
+ logic d;
+ logic de;
} mp_err;
struct packed {
logic d;
@@ -583,27 +593,27 @@
// Register -> HW type for core interface
typedef struct packed {
- flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [558:553]
- flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [552:547]
- flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [546:535]
- flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [534:527]
- flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [526:526]
- flash_ctrl_reg2hw_init_reg_t init; // [525:525]
- flash_ctrl_reg2hw_control_reg_t control; // [524:505]
- flash_ctrl_reg2hw_addr_reg_t addr; // [504:473]
- flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [472:471]
- flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [470:470]
- flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [469:262]
- flash_ctrl_reg2hw_default_region_reg_t default_region; // [261:256]
- flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [255:186]
- flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [185:179]
- flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [178:165]
- flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [164:95]
- flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [94:88]
- flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [87:74]
- flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [73:72]
- flash_ctrl_reg2hw_err_code_intr_en_reg_t err_code_intr_en; // [71:67]
- flash_ctrl_reg2hw_err_code_reg_t err_code; // [66:62]
+ flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [560:555]
+ flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [554:549]
+ flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [548:537]
+ flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [536:529]
+ flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [528:528]
+ flash_ctrl_reg2hw_init_reg_t init; // [527:527]
+ flash_ctrl_reg2hw_control_reg_t control; // [526:507]
+ flash_ctrl_reg2hw_addr_reg_t addr; // [506:475]
+ flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [474:473]
+ flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [472:472]
+ flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [471:264]
+ flash_ctrl_reg2hw_default_region_reg_t default_region; // [263:258]
+ flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [257:188]
+ flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [187:181]
+ flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [180:167]
+ flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [166:97]
+ flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [96:90]
+ flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [89:76]
+ flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [75:74]
+ flash_ctrl_reg2hw_err_code_intr_en_reg_t err_code_intr_en; // [73:68]
+ flash_ctrl_reg2hw_err_code_reg_t err_code; // [67:62]
flash_ctrl_reg2hw_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [61:54]
flash_ctrl_reg2hw_ecc_multi_err_cnt_reg_t ecc_multi_err_cnt; // [53:46]
flash_ctrl_reg2hw_phy_err_cfg_reg_t phy_err_cfg; // [45:45]
@@ -615,13 +625,13 @@
// HW -> register type for core interface
typedef struct packed {
- flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [158:147]
- flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [146:146]
- flash_ctrl_hw2reg_control_reg_t control; // [145:144]
- flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [143:142]
- flash_ctrl_hw2reg_op_status_reg_t op_status; // [141:138]
- flash_ctrl_hw2reg_status_reg_t status; // [137:128]
- flash_ctrl_hw2reg_err_code_reg_t err_code; // [127:118]
+ flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [160:149]
+ flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [148:148]
+ flash_ctrl_hw2reg_control_reg_t control; // [147:146]
+ flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [145:144]
+ flash_ctrl_hw2reg_op_status_reg_t op_status; // [143:140]
+ flash_ctrl_hw2reg_status_reg_t status; // [139:130]
+ flash_ctrl_hw2reg_err_code_reg_t err_code; // [129:118]
flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [117:108]
flash_ctrl_hw2reg_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [107:99]
flash_ctrl_hw2reg_ecc_single_err_addr_mreg_t [1:0] ecc_single_err_addr; // [98:57]
diff --git a/hw/ip/flash_ctrl/util/flash_ctrl_gen.py b/hw/ip/flash_ctrl/util/flash_ctrl_gen.py
index 84b51dd..c9786d8 100755
--- a/hw/ip/flash_ctrl/util/flash_ctrl_gen.py
+++ b/hw/ip/flash_ctrl/util/flash_ctrl_gen.py
@@ -22,7 +22,8 @@
max_banks = 4
max_pages_per_bank = 1024
- def __init__(self, mem):
+ def __init__(self, mem, base_addr):
+ self.base_addr = int(base_addr, 16)
self.banks = mem.get('banks', 2)
self.pages_per_bank = mem.get('pages_per_bank', 8)
self.program_resolution = mem.get('program_resolution', 128)
@@ -39,7 +40,10 @@
self.bytes_per_page = self.word_bytes * self.words_per_page
self.bytes_per_bank = self.bytes_per_page * self.pages_per_bank
self.total_bytes = self.bytes_per_bank * self.banks
- self.size = hex(int(self.total_bytes))
+
+ size_int = int(self.total_bytes)
+ self.size = hex(size_int)
+ self.end_addr = self.base_addr + size_int
def is_pow2(self, n):
return (n != 0) and (n & (n - 1) == 0)
@@ -86,7 +90,8 @@
log.error("This design does not currently support multiple flashes")
return
- cfg = Flash(flash_mems[0]['memory']['mem']['config'])
+ cfg = Flash(flash_mems[0]['memory']['mem']['config'],
+ flash_mems[0]['base_addrs']['mem'])
# generate hjson
hjson_out.write_text(hjson_tpl.render(cfg=cfg))
diff --git a/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson b/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
index 536d48b..91b3573 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
+++ b/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
@@ -1409,14 +1409,18 @@
desc: "interrupt mask for flash alert"
},
{ bits: "2",
+ name: "oob_err",
+ desc: "interrupt mask for software address out of bounds error"
+ },
+ { bits: "3",
name: "mp_err",
desc: "interrupt mask for memory properties error"
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: "interrupt mask for single bit ecc error"
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: "interrupt mask for multiple bits ecc error"
},
@@ -1446,20 +1450,26 @@
'''
},
{ bits: "2",
+ name: "oob_err",
+ desc: '''
+ The supplied address !!ADDR is invalid and out of bounds.
+ '''
+ },
+ { bits: "3",
name: "mp_err",
desc: '''
Flash access has encountered an access permission error.
Please see !!ERR_ADDR for exact address.
'''
},
- { bits: "3",
+ { bits: "4",
name: "ecc_single_err",
desc: '''
Flash access has encountered a single bit ECC error.
Please see !!ECC_SINGLE_ERR_ADDR for exact address.
'''
},
- { bits: "4",
+ { bits: "5",
name: "ecc_multi_err",
desc: '''
Flash access has encountered a multi bit ECC error.
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
index 7b39d24..c90b487 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
@@ -142,11 +142,16 @@
logic rd_flash_req;
logic rd_flash_ovfl;
logic [BusAddrW-1:0] rd_flash_addr;
+ logic rd_op_valid;
// Erase Control Connections
logic erase_flash_req;
logic [BusAddrW-1:0] erase_flash_addr;
flash_erase_e erase_flash_type;
+ logic erase_op_valid;
+
+ // combined indication that an operation has started
+ logic op_valid;
// Done / Error signaling from ctrl modules
logic prog_done, rd_done, erase_done;
@@ -200,6 +205,8 @@
logic op_start;
logic [11:0] op_num_words;
logic [BusAddrW-1:0] op_addr;
+ // SW or HW supplied address is out of bounds
+ logic op_addr_oob;
flash_op_e op_type;
flash_part_e op_part;
logic [InfoTypesWidth-1:0] op_info_sel;
@@ -377,6 +384,9 @@
assign op_erase_type = flash_erase_e'(muxed_ctrl.erase_sel.q);
assign op_prog_type = flash_prog_e'(muxed_ctrl.prog_sel.q);
assign op_addr = muxed_addr[BusByteWidth +: BusAddrW];
+ // The supplied address by software is completely beyond the flash
+ // and will wrap. Instead of allowing this, explicitly error back.
+ assign op_addr_oob = muxed_addr >= EndAddr;
assign op_type = flash_op_e'(muxed_ctrl.op.q);
assign op_part = flash_part_e'(muxed_ctrl.partition_sel.q);
assign op_info_sel = muxed_ctrl.info_sel.q;
@@ -384,6 +394,7 @@
assign prog_op = op_type == FlashOpProgram;
assign erase_op = op_type == FlashOpErase;
assign sw_sel = if_sel == SwSel;
+ assign op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
// software privilege to creator seed
assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -516,6 +527,7 @@
.op_done_o (prog_done),
.op_err_o (prog_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
.op_type_i (op_prog_type),
.type_avail_i (prog_type_en),
@@ -586,16 +598,18 @@
);
// Read handler is consumer of rd_fifo
+ assign rd_op_valid = op_start & rd_op;
flash_ctrl_rd u_flash_ctrl_rd (
.clk_i,
.rst_ni,
// To arbiter Interface
- .op_start_i (op_start & rd_op),
+ .op_start_i (rd_op_valid),
.op_num_words_i (op_num_words),
.op_done_o (rd_done),
.op_err_o (rd_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// FIFO Interface
.data_rdy_i (rd_fifo_wready),
@@ -612,13 +626,15 @@
);
// Erase handler does not consume fifo
+ assign erase_op_valid = op_start & erase_op;
flash_ctrl_erase u_flash_ctrl_erase (
// Software Interface
- .op_start_i (op_start & erase_op),
+ .op_start_i (erase_op_valid),
.op_type_i (op_erase_type),
.op_done_o (erase_done),
.op_err_o (erase_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// Flash Macro Interface
.flash_req_o (erase_flash_req),
@@ -909,11 +925,13 @@
// Errors and Interrupts
//////////////////////////////////////
+ assign hw2reg.err_code.oob_err.d = 1'b1;
assign hw2reg.err_code.mp_err.d = 1'b1;
assign hw2reg.err_code.ecc_single_err.d = 1'b1;
assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
assign hw2reg.err_code.flash_err.d = 1'b1;
assign hw2reg.err_code.flash_alert.d = 1'b1;
+ assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
assign hw2reg.err_code.mp_err.de = flash_mp_error;
assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
@@ -1113,7 +1131,10 @@
.scan_rst_ni
);
+ /////////////////////////////////
// Assertions
+ /////////////////////////////////
+
`ASSERT_KNOWN(TlDValidKnownO_A, core_tl_o.d_valid )
`ASSERT_KNOWN(TlAReadyKnownO_A, core_tl_o.a_ready )
`ASSERT_KNOWN(PrimTlDValidKnownO_A, prim_tl_o.d_valid )
@@ -1131,4 +1152,11 @@
`ASSERT_KNOWN(IntrOpDoneKnownO_A, intr_op_done_o )
`ASSERT_KNOWN(IntrErrO_A, intr_err_o )
+
+
+ // if there is an out of bounds error, flash request should never assert
+ `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+
+ // add more assertions
+
endmodule
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
index 79e7001..00db429 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
@@ -913,6 +913,8 @@
logic err_code_intr_en_flash_err_en_wd;
logic err_code_intr_en_flash_alert_en_qs;
logic err_code_intr_en_flash_alert_en_wd;
+ logic err_code_intr_en_oob_err_qs;
+ logic err_code_intr_en_oob_err_wd;
logic err_code_intr_en_mp_err_qs;
logic err_code_intr_en_mp_err_wd;
logic err_code_intr_en_ecc_single_err_qs;
@@ -924,6 +926,8 @@
logic err_code_flash_err_wd;
logic err_code_flash_alert_qs;
logic err_code_flash_alert_wd;
+ logic err_code_oob_err_qs;
+ logic err_code_oob_err_wd;
logic err_code_mp_err_qs;
logic err_code_mp_err_wd;
logic err_code_ecc_single_err_qs;
@@ -9934,7 +9938,33 @@
);
- // F[mp_err]: 2:2
+ // F[oob_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h0)
+ ) u_err_code_intr_en_oob_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (err_code_intr_en_we),
+ .wd (err_code_intr_en_oob_err_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.err_code_intr_en.oob_err.q),
+
+ // to register interface (read)
+ .qs (err_code_intr_en_oob_err_qs)
+ );
+
+
+ // F[mp_err]: 3:3
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -9960,7 +9990,7 @@
);
- // F[ecc_single_err]: 3:3
+ // F[ecc_single_err]: 4:4
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -9986,7 +10016,7 @@
);
- // F[ecc_multi_err]: 4:4
+ // F[ecc_multi_err]: 5:5
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
@@ -10066,7 +10096,33 @@
);
- // F[mp_err]: 2:2
+ // F[oob_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0)
+ ) u_err_code_oob_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (err_code_we),
+ .wd (err_code_oob_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.err_code.oob_err.de),
+ .d (hw2reg.err_code.oob_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.err_code.oob_err.q),
+
+ // to register interface (read)
+ .qs (err_code_oob_err_qs)
+ );
+
+
+ // F[mp_err]: 3:3
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -10092,7 +10148,7 @@
);
- // F[ecc_single_err]: 3:3
+ // F[ecc_single_err]: 4:4
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -10118,7 +10174,7 @@
);
- // F[ecc_multi_err]: 4:4
+ // F[ecc_multi_err]: 5:5
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -11603,22 +11659,26 @@
assign err_code_intr_en_flash_alert_en_wd = reg_wdata[1];
- assign err_code_intr_en_mp_err_wd = reg_wdata[2];
+ assign err_code_intr_en_oob_err_wd = reg_wdata[2];
- assign err_code_intr_en_ecc_single_err_wd = reg_wdata[3];
+ assign err_code_intr_en_mp_err_wd = reg_wdata[3];
- assign err_code_intr_en_ecc_multi_err_wd = reg_wdata[4];
+ assign err_code_intr_en_ecc_single_err_wd = reg_wdata[4];
+
+ assign err_code_intr_en_ecc_multi_err_wd = reg_wdata[5];
assign err_code_we = addr_hit[85] & reg_we & !reg_error;
assign err_code_flash_err_wd = reg_wdata[0];
assign err_code_flash_alert_wd = reg_wdata[1];
- assign err_code_mp_err_wd = reg_wdata[2];
+ assign err_code_oob_err_wd = reg_wdata[2];
- assign err_code_ecc_single_err_wd = reg_wdata[3];
+ assign err_code_mp_err_wd = reg_wdata[3];
- assign err_code_ecc_multi_err_wd = reg_wdata[4];
+ assign err_code_ecc_single_err_wd = reg_wdata[4];
+
+ assign err_code_ecc_multi_err_wd = reg_wdata[5];
assign ecc_single_err_cnt_we = addr_hit[87] & reg_we & !reg_error;
assign ecc_single_err_cnt_wd = reg_wdata[7:0];
@@ -12247,17 +12307,19 @@
addr_hit[84]: begin
reg_rdata_next[0] = err_code_intr_en_flash_err_en_qs;
reg_rdata_next[1] = err_code_intr_en_flash_alert_en_qs;
- reg_rdata_next[2] = err_code_intr_en_mp_err_qs;
- reg_rdata_next[3] = err_code_intr_en_ecc_single_err_qs;
- reg_rdata_next[4] = err_code_intr_en_ecc_multi_err_qs;
+ reg_rdata_next[2] = err_code_intr_en_oob_err_qs;
+ reg_rdata_next[3] = err_code_intr_en_mp_err_qs;
+ reg_rdata_next[4] = err_code_intr_en_ecc_single_err_qs;
+ reg_rdata_next[5] = err_code_intr_en_ecc_multi_err_qs;
end
addr_hit[85]: begin
reg_rdata_next[0] = err_code_flash_err_qs;
reg_rdata_next[1] = err_code_flash_alert_qs;
- reg_rdata_next[2] = err_code_mp_err_qs;
- reg_rdata_next[3] = err_code_ecc_single_err_qs;
- reg_rdata_next[4] = err_code_ecc_multi_err_qs;
+ reg_rdata_next[2] = err_code_oob_err_qs;
+ reg_rdata_next[3] = err_code_mp_err_qs;
+ reg_rdata_next[4] = err_code_ecc_single_err_qs;
+ reg_rdata_next[5] = err_code_ecc_multi_err_qs;
end
addr_hit[86]: begin
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
index eaafe60..07e2a76 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
@@ -13,6 +13,9 @@
package flash_ctrl_pkg;
+ // End address of flash
+ parameter logic [top_pkg::TL_AW-1:0] EndAddr = 'h20100000;
+
// design parameters that can be altered through topgen
parameter int unsigned NumBanks = flash_ctrl_reg_pkg::RegNumBanks;
parameter int unsigned PagesPerBank = flash_ctrl_reg_pkg::RegPagesPerBank;
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
index 25c2708..a069b9f 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
@@ -376,6 +376,9 @@
} flash_alert_en;
struct packed {
logic q;
+ } oob_err;
+ struct packed {
+ logic q;
} mp_err;
struct packed {
logic q;
@@ -394,6 +397,9 @@
} flash_alert;
struct packed {
logic q;
+ } oob_err;
+ struct packed {
+ logic q;
} mp_err;
struct packed {
logic q;
@@ -530,6 +536,10 @@
struct packed {
logic d;
logic de;
+ } oob_err;
+ struct packed {
+ logic d;
+ logic de;
} mp_err;
struct packed {
logic d;
@@ -583,27 +593,27 @@
// Register -> HW type for core interface
typedef struct packed {
- flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [558:553]
- flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [552:547]
- flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [546:535]
- flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [534:527]
- flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [526:526]
- flash_ctrl_reg2hw_init_reg_t init; // [525:525]
- flash_ctrl_reg2hw_control_reg_t control; // [524:505]
- flash_ctrl_reg2hw_addr_reg_t addr; // [504:473]
- flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [472:471]
- flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [470:470]
- flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [469:262]
- flash_ctrl_reg2hw_default_region_reg_t default_region; // [261:256]
- flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [255:186]
- flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [185:179]
- flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [178:165]
- flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [164:95]
- flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [94:88]
- flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [87:74]
- flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [73:72]
- flash_ctrl_reg2hw_err_code_intr_en_reg_t err_code_intr_en; // [71:67]
- flash_ctrl_reg2hw_err_code_reg_t err_code; // [66:62]
+ flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [560:555]
+ flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [554:549]
+ flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [548:537]
+ flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [536:529]
+ flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [528:528]
+ flash_ctrl_reg2hw_init_reg_t init; // [527:527]
+ flash_ctrl_reg2hw_control_reg_t control; // [526:507]
+ flash_ctrl_reg2hw_addr_reg_t addr; // [506:475]
+ flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [474:473]
+ flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [472:472]
+ flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [471:264]
+ flash_ctrl_reg2hw_default_region_reg_t default_region; // [263:258]
+ flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [257:188]
+ flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [187:181]
+ flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [180:167]
+ flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [166:97]
+ flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [96:90]
+ flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [89:76]
+ flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [75:74]
+ flash_ctrl_reg2hw_err_code_intr_en_reg_t err_code_intr_en; // [73:68]
+ flash_ctrl_reg2hw_err_code_reg_t err_code; // [67:62]
flash_ctrl_reg2hw_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [61:54]
flash_ctrl_reg2hw_ecc_multi_err_cnt_reg_t ecc_multi_err_cnt; // [53:46]
flash_ctrl_reg2hw_phy_err_cfg_reg_t phy_err_cfg; // [45:45]
@@ -615,13 +625,13 @@
// HW -> register type for core interface
typedef struct packed {
- flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [158:147]
- flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [146:146]
- flash_ctrl_hw2reg_control_reg_t control; // [145:144]
- flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [143:142]
- flash_ctrl_hw2reg_op_status_reg_t op_status; // [141:138]
- flash_ctrl_hw2reg_status_reg_t status; // [137:128]
- flash_ctrl_hw2reg_err_code_reg_t err_code; // [127:118]
+ flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [160:149]
+ flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [148:148]
+ flash_ctrl_hw2reg_control_reg_t control; // [147:146]
+ flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [145:144]
+ flash_ctrl_hw2reg_op_status_reg_t op_status; // [143:140]
+ flash_ctrl_hw2reg_status_reg_t status; // [139:130]
+ flash_ctrl_hw2reg_err_code_reg_t err_code; // [129:118]
flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [117:108]
flash_ctrl_hw2reg_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [107:99]
flash_ctrl_hw2reg_ecc_single_err_addr_mreg_t [1:0] ecc_single_err_addr; // [98:57]
diff --git a/util/topgen/validate.py b/util/topgen/validate.py
index 8e3d729..53413f4 100644
--- a/util/topgen/validate.py
+++ b/util/topgen/validate.py
@@ -266,7 +266,8 @@
max_banks = 4
max_pages_per_bank = 1024
- def __init__(self, mem):
+ def __init__(self, mem, base_addr=0):
+ self.base_addr = int(base_addr, 16)
self.banks = mem.get('banks', 2)
self.pages_per_bank = mem.get('pages_per_bank', 8)
self.program_resolution = mem.get('program_resolution', 128)
@@ -283,7 +284,10 @@
self.bytes_per_page = self.word_bytes * self.words_per_page
self.bytes_per_bank = self.bytes_per_page * self.pages_per_bank
self.total_bytes = self.bytes_per_bank * self.banks
- self.size = hex(int(self.total_bytes))
+
+ size_int = int(self.total_bytes)
+ self.size = hex(size_int)
+ self.end_addr = self.base_addr + size_int
def is_pow2(self, n):
return (n != 0) and (n & (n - 1) == 0)
@@ -794,7 +798,7 @@
if mem_type == "flash":
check_keys(value['config'], eflash_required, eflash_optional,
eflash_added, "Eflash")
- flash = Flash(value['config'])
+ flash = Flash(value['config'], m['base_addrs'][intf])
value['size'] = flash.size
value['config'] = flash
else: