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.
This commit is contained in:
Tim Edwards 2021-10-23 22:06:24 -04:00
parent e5c90daddd
commit e6a94449ce
2 changed files with 39 additions and 19 deletions

View File

@ -653,8 +653,13 @@ module housekeeping #(
wbbd_data <= wb_dat_i[7:0]; wbbd_data <= wb_dat_i[7:0];
end end
wbbd_write <= wb_sel_i[0] & wb_we_i; wbbd_write <= wb_sel_i[0] & wb_we_i;
// 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; wbbd_state <= `WBBD_RW0;
end end
end
`WBBD_RW0: begin `WBBD_RW0: begin
wbbd_sck <= 1'b1; wbbd_sck <= 1'b1;
wb_dat_o[7:0] <= odata; wb_dat_o[7:0] <= odata;
@ -667,8 +672,10 @@ module housekeeping #(
wbbd_data <= wb_dat_i[15:8]; wbbd_data <= wb_dat_i[15:8];
end end
wbbd_write <= wb_sel_i[1] & wb_we_i; wbbd_write <= wb_sel_i[1] & wb_we_i;
if (!spi_is_busy) begin
wbbd_state <= `WBBD_RW1; wbbd_state <= `WBBD_RW1;
end end
end
`WBBD_RW1: begin `WBBD_RW1: begin
wbbd_sck <= 1'b1; wbbd_sck <= 1'b1;
wb_dat_o[15:8] <= odata; wb_dat_o[15:8] <= odata;
@ -681,8 +688,10 @@ module housekeeping #(
wbbd_data <= wb_dat_i[23:16]; wbbd_data <= wb_dat_i[23:16];
end end
wbbd_write <= wb_sel_i[2] & wb_we_i; wbbd_write <= wb_sel_i[2] & wb_we_i;
if (!spi_is_busy) begin
wbbd_state <= `WBBD_RW2; wbbd_state <= `WBBD_RW2;
end end
end
`WBBD_RW2: begin `WBBD_RW2: begin
wbbd_sck <= 1'b1; wbbd_sck <= 1'b1;
wb_dat_o[23:16] <= odata; wb_dat_o[23:16] <= odata;
@ -695,8 +704,10 @@ module housekeeping #(
wbbd_data <= wb_dat_i[31:24]; wbbd_data <= wb_dat_i[31:24];
end end
wbbd_write <= wb_sel_i[3] & wb_we_i; wbbd_write <= wb_sel_i[3] & wb_we_i;
if (!spi_is_busy) begin
wbbd_state <= `WBBD_RW3; wbbd_state <= `WBBD_RW3;
end end
end
`WBBD_RW3: begin `WBBD_RW3: begin
wbbd_sck <= 1'b1; wbbd_sck <= 1'b1;
wb_dat_o[31:24] <= odata; wb_dat_o[31:24] <= odata;
@ -736,9 +747,13 @@ module housekeeping #(
); );
// SPI is considered active when the GPIO for CSB is set to input and // 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_enabled = (~gpio_configure[3][INP_DIS]) & (~hkspi_disable);
wire spi_is_active = spi_is_enabled && (mgmt_gpio_in[3] == 1'b0); 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 // 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 // not an input). To do: Provide an independent way to disable
// the SPI. // the SPI.
assign caddr = (spi_is_active) ? iaddr : wbbd_addr; assign caddr = (spi_is_busy) ? iaddr : wbbd_addr;
assign csclk = (spi_is_active) ? mgmt_gpio_in[4] : wbbd_sck; assign csclk = (spi_is_busy) ? mgmt_gpio_in[4] : wbbd_sck;
assign cdata = (spi_is_active) ? idata : wbbd_data; assign cdata = (spi_is_busy) ? idata : wbbd_data;
assign cwstb = (spi_is_active) ? wrstb : wbbd_write; assign cwstb = (spi_is_busy) ? wrstb : wbbd_write;
assign odata = fdata(caddr); assign odata = fdata(caddr);
// Register mapping and I/O to SPI interface module // Register mapping and I/O to SPI interface module

View File

@ -35,7 +35,7 @@
// idata --- Data from chip to transmit out, in 8 bits // idata --- Data from chip to transmit out, in 8 bits
// odata --- Input data to chip, in 8 bits // odata --- Input data to chip, in 8 bits
// addr --- Decoded address to upstream circuits // 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. // wrstb --- Write strobe, tells upstream circuit to latch odata.
// Data format (general purpose): // Data format (general purpose):
@ -158,6 +158,7 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO,
end else begin end else begin
wrstb <= 1'b0; wrstb <= 1'b0;
end end
end else if (state == `MGMTPASS || state == `USERPASS) begin end else if (state == `MGMTPASS || state == `USERPASS) begin
wrstb <= 1'b0; wrstb <= 1'b0;
sdoenb <= 1'b0; sdoenb <= 1'b0;
@ -217,13 +218,14 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO,
count <= count + 1; count <= count + 1;
addr <= {addr[6:0], SDI}; addr <= {addr[6:0], SDI};
if (count == 3'b111) begin if (count == 3'b111) begin
state <= `DATA;
if (readmode == 1'b1) begin if (readmode == 1'b1) begin
rdstb <= 1'b1; rdstb <= 1'b1;
end end
state <= `DATA;
end else begin end else begin
rdstb <= 1'b0; rdstb <= 1'b0;
end end
end else if (state == `DATA) begin end else if (state == `DATA) begin
predata <= {predata[6:0], SDI}; predata <= {predata[6:0], SDI};
count <= count + 1; count <= count + 1;
@ -236,6 +238,9 @@ module housekeeping_spi(reset, SCK, SDI, CSB, SDO,
end else begin end else begin
addr <= addr + 1; // Auto increment address (streaming) addr <= addr + 1; // Auto increment address (streaming)
end end
if (readmode == 1'b1) begin
rdstb <= 1'b1;
end
end else begin end else begin
rdstb <= 1'b0; rdstb <= 1'b0;
end end