From e6a94449ce1b13569f76e116d097fdc15bdbf2e9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 23 Oct 2021 22:06:24 -0400 Subject: [PATCH] Modified the housekeeping SPI to generate a read strobe (or rather status) so that between rdstb and wrstb, the SPI signals when it is about to read or write a byte. The back-door wishbone interface then stalls the CPU during these periods. That allows the CPU to continue running while the SPI is being accessed without data collisions and without having to stall for the entire time CSB is held low. Because SCK is asynchronous to the clock, rare collisions are still possible; this is not expected to be an issue but might be worth investigating. --- verilog/rtl/housekeeping.v | 33 ++++++++++++++++++++++++--------- verilog/rtl/housekeeping_spi.v | 25 +++++++++++++++---------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/verilog/rtl/housekeeping.v b/verilog/rtl/housekeeping.v index f734a59c..d699b802 100644 --- a/verilog/rtl/housekeeping.v +++ b/verilog/rtl/housekeeping.v @@ -653,7 +653,12 @@ module housekeeping #( wbbd_data <= wb_dat_i[7:0]; end wbbd_write <= wb_sel_i[0] & wb_we_i; - wbbd_state <= `WBBD_RW0; + + // If the SPI is being accessed and about to read or + // write a byte, then stall until the SPI is ready. + if (!spi_is_busy) begin + wbbd_state <= `WBBD_RW0; + end end `WBBD_RW0: begin wbbd_sck <= 1'b1; @@ -667,7 +672,9 @@ module housekeeping #( wbbd_data <= wb_dat_i[15:8]; end wbbd_write <= wb_sel_i[1] & wb_we_i; - wbbd_state <= `WBBD_RW1; + if (!spi_is_busy) begin + wbbd_state <= `WBBD_RW1; + end end `WBBD_RW1: begin wbbd_sck <= 1'b1; @@ -681,7 +688,9 @@ module housekeeping #( wbbd_data <= wb_dat_i[23:16]; end wbbd_write <= wb_sel_i[2] & wb_we_i; - wbbd_state <= `WBBD_RW2; + if (!spi_is_busy) begin + wbbd_state <= `WBBD_RW2; + end end `WBBD_RW2: begin wbbd_sck <= 1'b1; @@ -695,7 +704,9 @@ module housekeeping #( wbbd_data <= wb_dat_i[31:24]; end wbbd_write <= wb_sel_i[3] & wb_we_i; - wbbd_state <= `WBBD_RW3; + if (!spi_is_busy) begin + wbbd_state <= `WBBD_RW3; + end end `WBBD_RW3: begin wbbd_sck <= 1'b1; @@ -736,9 +747,13 @@ module housekeeping #( ); // SPI is considered active when the GPIO for CSB is set to input and - // CSB is low. + // CSB is low. SPI is considered "busy" when rdstb or wrstb are high, + // indicating that the SPI will read or write a byte on the next SCK + // transition. + wire spi_is_enabled = (~gpio_configure[3][INP_DIS]) & (~hkspi_disable); wire spi_is_active = spi_is_enabled && (mgmt_gpio_in[3] == 1'b0); + wire spi_is_busy = spi_is_active && (rdstb || wrstb); // GPIO data handling to and from the management SoC @@ -952,10 +967,10 @@ module housekeeping #( // not an input). To do: Provide an independent way to disable // the SPI. - assign caddr = (spi_is_active) ? iaddr : wbbd_addr; - assign csclk = (spi_is_active) ? mgmt_gpio_in[4] : wbbd_sck; - assign cdata = (spi_is_active) ? idata : wbbd_data; - assign cwstb = (spi_is_active) ? wrstb : wbbd_write; + assign caddr = (spi_is_busy) ? iaddr : wbbd_addr; + assign csclk = (spi_is_busy) ? mgmt_gpio_in[4] : wbbd_sck; + assign cdata = (spi_is_busy) ? idata : wbbd_data; + assign cwstb = (spi_is_busy) ? wrstb : wbbd_write; assign odata = fdata(caddr); // Register mapping and I/O to SPI interface module diff --git a/verilog/rtl/housekeeping_spi.v b/verilog/rtl/housekeeping_spi.v index 84645e3e..1a5c7379 100644 --- a/verilog/rtl/housekeeping_spi.v +++ b/verilog/rtl/housekeeping_spi.v @@ -35,7 +35,7 @@ // idata --- Data from chip to transmit out, in 8 bits // odata --- Input data to chip, in 8 bits // addr --- Decoded address to upstream circuits -// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata +// rdstb --- Read strobe, tells upstream circuit that data will be latched. // wrstb --- Write strobe, tells upstream circuit to latch odata. // Data format (general purpose): @@ -158,6 +158,7 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO, end else begin wrstb <= 1'b0; end + end else if (state == `MGMTPASS || state == `USERPASS) begin wrstb <= 1'b0; sdoenb <= 1'b0; @@ -172,7 +173,7 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO, if (csb_reset == 1'b1) begin // Default state on reset addr <= 8'h00; - rdstb <= 1'b0; + rdstb <= 1'b0; predata <= 7'b0000000; state <= `COMMAND; count <= 3'b000; @@ -188,7 +189,7 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO, end else begin // After csb_reset low, 1st SCK starts command if (state == `COMMAND) begin - rdstb <= 1'b0; + rdstb <= 1'b0; count <= count + 1; if (count == 3'b000) begin writemode <= SDI; @@ -217,13 +218,14 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO, count <= count + 1; addr <= {addr[6:0], SDI}; if (count == 3'b111) begin - if (readmode == 1'b1) begin - rdstb <= 1'b1; - end state <= `DATA; + if (readmode == 1'b1) begin + rdstb <= 1'b1; + end end else begin - rdstb <= 1'b0; - end + rdstb <= 1'b0; + end + end else if (state == `DATA) begin predata <= {predata[6:0], SDI}; count <= count + 1; @@ -236,9 +238,12 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO, end else begin addr <= addr + 1; // Auto increment address (streaming) end + if (readmode == 1'b1) begin + rdstb <= 1'b1; + end end else begin - rdstb <= 1'b0; - end + rdstb <= 1'b0; + end end else if (state == `MGMTPASS) begin pass_thru_mgmt <= 1'b1; end else if (state == `USERPASS) begin