[flash] update flash program to support ack / done / last

- a beat of program will not be signaled 'done' until all beats are complete.
- all other beats will get an 'ack' to mean its trasnaction was accepted by
  the flash wrapper

Signed-off-by: Timothy Chen <timothytim@google.com>

[flash] update assertion location

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
index d2f6a01..4f4faba 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
@@ -70,6 +70,9 @@
   // ack to phy operations from flash macro
   logic ack;
 
+  // done to phy operations from flash macro
+  logic done;
+
   // ack from flash_phy_prog to controller
   logic prog_ack;
 
@@ -198,7 +201,7 @@
 
       // other controller operations directly interface with flash
       StCtrl: begin
-        if (ack) begin
+        if (done) begin
           ctrl_rsp_vld = 1'b1;
           state_d = StIdle;
         end
@@ -245,7 +248,7 @@
     .data_o(rd_data_o),
     .idle_o(rd_stage_idle),
     .req_o(flash_rd_req),
-    .ack_i(ack),
+    .ack_i(done), // temporary hack and use done
     .data_i(flash_rdata),
     //scramble unit interface
     .calc_req_o(rd_calc_req),
@@ -265,6 +268,7 @@
   logic [FullDataWidth-1:0] prog_full_data;
   logic [DataWidth-1:0] prog_scrambled_data;
   logic [DataWidth-1:0] prog_data;
+  logic prog_last;
   logic flash_prog_req;
   logic prog_calc_req;
   logic prog_op_req;
@@ -283,6 +287,7 @@
       .data_i(prog_data_i),
       .last_i(prog_last_i),
       .ack_i(ack),
+      .done_i(done),
       .calc_ack_i(calc_ack),
       .scramble_ack_i(op_ack),
       .mask_i(scramble_mask),
@@ -290,6 +295,7 @@
       .calc_req_o(prog_calc_req),
       .scramble_req_o(prog_op_req),
       .req_o(flash_prog_req),
+      .last_o(prog_last),
       .ack_o(prog_ack),
       .block_data_o(prog_data),
       .data_o(prog_full_data)
@@ -349,6 +355,7 @@
     .rst_ni,
     .rd_i(flash_rd_req),
     .prog_i(flash_prog_req),
+    .prog_last_i(prog_last),
     .prog_type_i(prog_type_i),
     .pg_erase_i(reqs[PhyPgErase]),
     .bk_erase_i(reqs[PhyBkErase]),
@@ -356,8 +363,8 @@
     .part_i(muxed_part),
     .prog_data_i(prog_full_data),
     .prog_type_avail_o(prog_type_avail_o),
-    .ack_o(), // temporary hack
-    .done_o(ack),
+    .ack_o(ack),
+    .done_o(done),
     .rd_data_o(flash_rdata),
     .init_busy_o, // TBD this needs to be looked at later. What init do we need to do,
                   // and where does it make the most sense?
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
index 5048456..caeac92 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
@@ -30,7 +30,8 @@
   input [WordSelW-1:0] sel_i,
   input [BusWidth-1:0] data_i,
   input last_i,
-  input ack_i,
+  input ack_i,  // ack means request has been accepted by flash
+  input done_i, // done means requested transaction has completed
   input calc_ack_i,
   input scramble_ack_i,
   input [DataWidth-1:0] mask_i,
@@ -38,6 +39,7 @@
   output logic calc_req_o,
   output logic scramble_req_o,
   output logic req_o,
+  output logic last_o, // last beat of an incoming transaction
   output logic ack_o,
   // block data does not contain ecc / metadata portion
   output logic [DataWidth-1:0] block_data_o,
@@ -112,6 +114,7 @@
     data_sel = Filler;
     req_o = 1'b0;
     ack_o = 1'b0;
+    last_o = 1'b0;
     calc_req_o = 1'b0;
     scramble_req_o = 1'b0;
 
@@ -181,12 +184,23 @@
 
       StReqFlash: begin
         req_o = 1'b1;
-        state_d = StWaitFlash;
+        last_o = last_i;
+
+        // if this is the last beat of the program burst
+        //   - wait for done
+        // if this is NOT the last beat
+        //   - ack the upstream request and accept more beats
+        if (last_i) begin
+          state_d = ack_i ? StWaitFlash : StReqFlash;
+        end else begin
+          ack_o = ack_i;
+          state_d = ack_i ? StIdle : StReqFlash;
+        end
       end
 
       StWaitFlash: begin
 
-        if (ack_i) begin
+        if (done_i) begin
           ack_o = 1'b1;
           state_d = StIdle;
         end
@@ -227,15 +241,36 @@
   // pad the remaining bits to '0', this effectively "programs" them.
   assign data_o = scramble_i ? FullDataWidth'(ecc_data) : FullDataWidth'(packed_data);
 
-
   /////////////////////////////////
   // Assertions
   /////////////////////////////////
 
+`ifndef SYNTHESIS
+  logic txn_done;
+  logic [15:0] done_cnt;
+
+  assign txn_done = req_i && ack_o && last_i;
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (rst_ni) begin
+      done_cnt <= '0;
+    end else if (txn_done) begin
+      done_cnt <= '0;
+    end else if (done_i) begin
+      done_cnt <= done_cnt + 1'b1;
+    end
+  end
+
+  // We can only observe one done per transaction.
+  `ASSERT(OneDonePerTxn_A,  txn_done |-> done_cnt == '0)
+
+`endif
+
   // Prepack state can only pack up to WidthMultiple - 1
   `ASSERT(PrePackRule_A, state_q == StPrePack && pack_valid |-> idx < (WidthMultiple - 1))
 
   // Postpack states should never pack the first index (as it would be aligned in that case)
   `ASSERT(PostPackRule_A, state_q == StPostPack && pack_valid |-> idx != '0)
 
+
+
 endmodule // flash_phy_prog
diff --git a/hw/ip/prim_generic/rtl/prim_generic_flash.sv b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
index fffb449..3b9f9ca 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_flash.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
@@ -22,6 +22,7 @@
   input                              rst_ni,
   input                              rd_i,
   input                              prog_i,
+  input                              prog_last_i,
   // the generic model does not make use of program types
   input flash_ctrl_pkg::flash_prog_e prog_type_i,
   input                              pg_erase_i,
@@ -86,6 +87,7 @@
   typedef struct packed {
     logic                        rd;
     logic                        prog;
+    logic                        prog_last;
     flash_ctrl_pkg::flash_prog_e prog_type;
     logic                        pg_erase;
     logic                        bk_erase;
@@ -102,6 +104,7 @@
   assign cmd_d = '{
     rd :       rd_i,
     prog:      prog_i,
+    prog_last: prog_last_i,
     prog_type: prog_type_i,
     pg_erase:  pg_erase_i,
     bk_erase:  bk_erase_i,
@@ -311,7 +314,7 @@
         end else begin
           st_d = StIdle;
           pop_cmd = 1'b1;
-          done_o = 1'b1;
+          done_o = cmd_q.prog_last;
           time_cnt_clr = 1'b1;
         end
       end
@@ -411,4 +414,20 @@
   assign prog_type_avail_o[flash_ctrl_pkg::FlashProgNormal] = 1'b1;
   assign prog_type_avail_o[flash_ctrl_pkg::FlashProgRepair] = 1'b1;
 
+  logic unused_flash_power_down_hi;
+  logic unused_flash_power_ready_hi;
+  logic unused_scan_reset_ni;
+  logic unused_tck;
+  logic unused_tms;
+  logic unused_tdi;
+  flash_ctrl_pkg::flash_prog_e unused_prog_type;
+  assign unused_prog_type = cmd_q.prog_type;
+  assign unused_flash_power_down_hi = flash_power_down_hi;
+  assign unused_flash_power_ready_hi = flash_power_ready_hi;
+  assign unused_scan_reset_ni = scan_reset_ni;
+  assign unused_scanmode_i = scanmode_i;
+  assign unused_tck = tck_i;
+  assign unused_tdi = tdi_i;
+  assign unused_tms = tms_i;
+
 endmodule // prim_generic_flash