[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.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