[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