[spi_device] Add payloadptr (last written) and overflow event
Add last written payloadptr and overflow event and synchronization logic
to SYS clock domain.
Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/spi_device/rtl/spi_device.sv b/hw/ip/spi_device/rtl/spi_device.sv
index c4daeb2..af26cf6 100644
--- a/hw/ip/spi_device/rtl/spi_device.sv
+++ b/hw/ip/spi_device/rtl/spi_device.sv
@@ -163,6 +163,7 @@
logic addrfifo_notempty;
logic payload_notempty;
+ logic payload_overflow;
localparam int unsigned CmdFifoPtrW = $clog2(SramCmdFifoDepth+1);
localparam int unsigned AddrFifoPtrW = $clog2(SramAddrFifoDepth+1);
@@ -173,9 +174,14 @@
logic [CmdFifoPtrW-1:0] cmdfifo_depth;
logic [AddrFifoPtrW-1:0] addrfifo_depth;
logic [PayloadDepthW-1:0] payload_depth;
+ logic [PayloadDepthW-1:0] last_written_payload_idx;
assign payload_notempty = payload_depth != '0;
+ // TODO: Implement CSR
+ logic unused_last_written_payload_idx;
+ assign unused_last_written_payload_idx = ^last_written_payload_idx;
+
/////////////////////
// Control signals //
/////////////////////
@@ -311,6 +317,7 @@
// Interrupts in Flash mode
logic intr_upload_cmdfifo_not_empty, intr_upload_payload_not_empty;
+ logic intr_upload_payload_overflow;
logic intr_readbuf_watermark, intr_readbuf_flip;
logic flash_sck_readbuf_watermark, flash_sck_readbuf_flip;
@@ -583,16 +590,17 @@
);
prim_edge_detector #(
- .Width (2),
+ .Width (3),
.EnSync(1'b 0)
) u_intr_upload_edge (
.clk_i,
.rst_ni,
- .d_i ({cmdfifo_notempty, payload_notempty}),
+ .d_i ({cmdfifo_notempty, payload_notempty, payload_overflow}),
.q_sync_o (),
.q_posedge_pulse_o ({intr_upload_cmdfifo_not_empty,
- intr_upload_payload_not_empty}),
+ intr_upload_payload_not_empty,
+ intr_upload_payload_overflow}),
.q_negedge_pulse_o ()
);
@@ -622,6 +630,22 @@
.intr_o (intr_upload_payload_not_empty_o )
);
+ logic unused_intr_payload_overflow;
+ assign unused_intr_payload_overflow = intr_upload_payload_overflow;
+ //prim_intr_hw #(.Width(1)) u_intr_payload_overflow (
+ // .clk_i,
+ // .rst_ni,
+ // .event_intr_i (intr_upload_payload_overflow ),
+ // .reg2hw_intr_enable_q_i (reg2hw.intr_enable.upload_payload_overflow.q),
+ // .reg2hw_intr_test_q_i (reg2hw.intr_test.upload_payload_overflow.q ),
+ // .reg2hw_intr_test_qe_i (reg2hw.intr_test.upload_payload_overflow.qe ),
+ // .reg2hw_intr_state_q_i (reg2hw.intr_state.upload_payload_overflow.q ),
+ // .hw2reg_intr_state_d_o (hw2reg.intr_state.upload_payload_overflow.d ),
+ // .hw2reg_intr_state_de_o (hw2reg.intr_state.upload_payload_overflow.de),
+ // .intr_o (intr_upload_payload_overflow_o )
+ //);
+
+
prim_pulse_sync u_flash_readbuf_watermark_pulse_sync (
.clk_src_i (clk_spi_in_buf ),
.rst_src_ni (rst_ni ),
@@ -1462,10 +1486,12 @@
.sys_cmdfifo_full_o (), // not used
.sys_addrfifo_notempty_o (addrfifo_notempty),
.sys_addrfifo_full_o (), // not used
+ .sys_payload_overflow_o (payload_overflow),
- .sys_cmdfifo_depth_o (cmdfifo_depth),
- .sys_addrfifo_depth_o (addrfifo_depth),
- .sys_payload_depth_o (payload_depth)
+ .sys_cmdfifo_depth_o (cmdfifo_depth),
+ .sys_addrfifo_depth_o (addrfifo_depth),
+ .sys_payload_depth_o (payload_depth),
+ .sys_last_written_payload_idx_o (last_written_payload_idx)
);
// FIFO connect
assign cmdfifo_rready = reg2hw.upload_cmdfifo.re;
@@ -1924,6 +1950,8 @@
intr_upload_cmdfifo_not_empty_o)
`ASSERT_KNOWN(IntrUploadPayloadNotEmptyOKnown,
intr_upload_payload_not_empty_o)
+ //`ASSERT_KNOWN(IntrUploadPayloadOverflowOKnown,
+ // intr_upload_payload_overflow_o)
`ASSERT_KNOWN(IntrReadbufWatermarkOKnown, intr_readbuf_watermark_o)
`ASSERT_KNOWN(IntrReadbufFlipOKnown, intr_readbuf_flip_o)
`ASSERT_KNOWN(IntrTpmHeaderNotEmptyOKnown, intr_tpm_header_not_empty_o)
diff --git a/hw/ip/spi_device/rtl/spid_upload.sv b/hw/ip/spi_device/rtl/spid_upload.sv
index 58ac87a..5fd1692 100644
--- a/hw/ip/spi_device/rtl/spid_upload.sv
+++ b/hw/ip/spi_device/rtl/spid_upload.sv
@@ -107,10 +107,12 @@
output logic sys_cmdfifo_full_o,
output logic sys_addrfifo_notempty_o,
output logic sys_addrfifo_full_o,
+ output logic sys_payload_overflow_o,
output logic [CmdPtrW-1:0] sys_cmdfifo_depth_o,
output logic [AddrPtrW-1:0] sys_addrfifo_depth_o,
- output logic [PayloadPtrW-1:0] sys_payload_depth_o
+ output logic [PayloadPtrW-1:0] sys_payload_depth_o,
+ output logic [PayloadPtrW-1:0] sys_last_written_payload_idx_o
);
localparam int unsigned CmdFifoWidth = 8;
@@ -290,6 +292,58 @@
.dst_pulse_o (sys_payloadptr_clr_posedge)
);
+ // last_written_payloadptr: in contrast to payloadptr,
+ // `last_written_payloadptr` provides a location that the HW lastly wrote to
+ // the payload buffer.
+ //
+ // This is useful when the host system sends more than 256B of payload. The
+ // HW wraps around the payload buffer when it receives more than 256B. The
+ // SW, with last_written_payloadptr, is able to know the exact offset to
+ // start to read.
+ //
+ // TODO: Handle 257, ... , 511 case (reduce bit by 1?)
+ logic [PayloadPtrW-1:0] last_written_payloadptr;
+ always_ff @(posedge clk_i or negedge sys_rst_ni) begin
+ if (!sys_rst_ni) last_written_payloadptr <= '0;
+ else if (payloadptr_clr) last_written_payloadptr <= '0;
+ else if (payloadptr_inc) begin
+ last_written_payloadptr <= last_written_payloadptr + PayloadPtrW'(1);
+ end
+ end
+
+ // Latch last_written_payloadptr @ CSb events
+ always_ff @(posedge sys_clk_i or negedge sys_rst_ni) begin
+ if (!sys_rst_ni) sys_last_written_payload_idx_o <= '0;
+ else if (sys_payloadptr_clr_posedge) sys_last_written_payload_idx_o <= '0;
+ else if (sys_csb_deasserted_pulse_i) begin
+ sys_last_written_payload_idx_o <= last_written_payloadptr;
+ end
+ end
+
+ // Overflow event
+ // When the SPI host system issues more than 256B payload, HW stores the
+ // overflow event in SCK then notify to SW when CSb is deasserted
+ logic event_payload_overflow;
+ always_ff @(posedge clk_i or negedge sys_rst_ni) begin
+ if (!sys_rst_ni) event_payload_overflow <= 1'b 0;
+ else if (payloadptr_clr) event_payload_overflow <= 1'b 0;
+ else if (payloadptr_inc && (payloadptr == PayloadPtrW'(PayloadByte))) begin
+ event_payload_overflow <= 1'b 1;
+ end
+ end
+
+ // Sync to SYSCLK when CSb release. Edge detection on the spi_device top
+ logic sys_event_payload_overflow;
+ always_ff @(posedge sys_clk_i or negedge sys_rst_ni) begin
+ if (!sys_rst_ni) sys_event_payload_overflow <= 1'b 0;
+ else if (sys_payloadptr_clr_posedge) sys_event_payload_overflow <= 1'b 0;
+ else if (sys_csb_deasserted_pulse_i) begin
+ sys_event_payload_overflow <= event_payload_overflow;
+ end
+ end
+
+ assign sys_payload_overflow_o = sys_event_payload_overflow;
+
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
st_q <= StIdle;