[ spi_host, rtl ] Split DATA memory window into separate RO and WO windows
- Creates two new windows TXDATA and RXDATA
- RXDATA is RO, TXDATA is WO
- Fixes #5484
- Signals an error back to TLUL if the RXDATA is written or TXDATA is read
Signed-off-by: Martin Lueker-Boden <martin.lueker-boden@wdc.com>
diff --git a/hw/ip/spi_host/data/spi_host.hjson b/hw/ip/spi_host/data/spi_host.hjson
index 7c7cca3..b0c5611 100644
--- a/hw/ip/spi_host/data/spi_host.hjson
+++ b/hw/ip/spi_host/data/spi_host.hjson
@@ -354,14 +354,37 @@
]
},
{ window: {
- name: "DATA",
+ name: "RXDATA",
+ items: "1",
+ validbits: "32",
+ desc: '''SPI Receive Data.
+
+ Reads from this window pull data from the RXFIFO.
+
+ The serial order of bit transmission
+ is chosen to match SPI flash devices. Individual bytes
+ are always transmitted with the most significant bit first.
+ Only four-bute reads are supported. If ByteOrder = 0,
+ the first byte received is packed in the MSB of !!RXDATA.
+ For some processor architectures, this could lead to shuffling
+ of flash data as compared to how it is written in memory.
+ In which case, choosing ByteOrder = 1 can reverse the
+ byte-order of each data read, causing the first byte
+ received to be packed into the LSB of !!RXDATA. (Though within
+ each byte the most significant bit is always pulled
+ from the bus first.)
+ '''
+ swaccess: "ro",
+ }
+ },
+ { window: {
+ name: "TXDATA",
items: "1",
validbits: "32",
byte-write: "true",
- desc: '''SPI Transmit and Receive Data.
+ desc: '''SPI Transmit Data.
- Write data to this window to place it in the TXFIFO.
- Reads from this register pull data from the RXFIFO.
+ Data written to this window is placed into the TXFIFO.
Byte-enables are supported for writes.
The serial order of bit transmission
diff --git a/hw/ip/spi_host/rtl/spi_host.sv b/hw/ip/spi_host/rtl/spi_host.sv
index 325fb5a..4ed838e 100644
--- a/hw/ip/spi_host/rtl/spi_host.sv
+++ b/hw/ip/spi_host/rtl/spi_host.sv
@@ -49,8 +49,8 @@
spi_host_reg2hw_t reg2hw;
spi_host_hw2reg_t hw2reg;
- tlul_pkg::tl_h2d_t fifo_win_h2d;
- tlul_pkg::tl_d2h_t fifo_win_d2h;
+ tlul_pkg::tl_h2d_t fifo_win_h2d [2];
+ tlul_pkg::tl_d2h_t fifo_win_d2h [2];
// Register module
logic [NumAlerts-1:0] alert_test, alerts;
@@ -297,8 +297,10 @@
spi_host_window u_window (
.clk_i,
.rst_ni,
- .win_i (fifo_win_h2d),
- .win_o (fifo_win_d2h),
+ .rx_win_i (fifo_win_h2d[0]),
+ .rx_win_o (fifo_win_d2h[0]),
+ .tx_win_i (fifo_win_h2d[1]),
+ .tx_win_o (fifo_win_d2h[1]),
.tx_data_o (tx_data),
.tx_be_o (tx_be),
.tx_valid_o (tx_valid),
diff --git a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
index 95334bc..f5d606d 100644
--- a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
+++ b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
@@ -294,9 +294,9 @@
parameter logic [BlockAw-1:0] SPI_HOST_CONFIGOPTS_OFFSET = 6'h 18;
parameter logic [BlockAw-1:0] SPI_HOST_CSID_OFFSET = 6'h 1c;
parameter logic [BlockAw-1:0] SPI_HOST_COMMAND_OFFSET = 6'h 20;
- parameter logic [BlockAw-1:0] SPI_HOST_ERROR_ENABLE_OFFSET = 6'h 28;
- parameter logic [BlockAw-1:0] SPI_HOST_ERROR_STATUS_OFFSET = 6'h 2c;
- parameter logic [BlockAw-1:0] SPI_HOST_EVENT_ENABLE_OFFSET = 6'h 30;
+ parameter logic [BlockAw-1:0] SPI_HOST_ERROR_ENABLE_OFFSET = 6'h 2c;
+ parameter logic [BlockAw-1:0] SPI_HOST_ERROR_STATUS_OFFSET = 6'h 30;
+ parameter logic [BlockAw-1:0] SPI_HOST_EVENT_ENABLE_OFFSET = 6'h 34;
// Reset values for hwext registers and their fields
parameter logic [1:0] SPI_HOST_INTR_TEST_RESVAL = 2'h 0;
@@ -311,8 +311,10 @@
parameter logic [1:0] SPI_HOST_COMMAND_DIRECTION_RESVAL = 2'h 0;
// Window parameters
- parameter logic [BlockAw-1:0] SPI_HOST_DATA_OFFSET = 6'h 24;
- parameter int unsigned SPI_HOST_DATA_SIZE = 'h 4;
+ parameter logic [BlockAw-1:0] SPI_HOST_RXDATA_OFFSET = 6'h 24;
+ parameter int unsigned SPI_HOST_RXDATA_SIZE = 'h 4;
+ parameter logic [BlockAw-1:0] SPI_HOST_TXDATA_OFFSET = 6'h 28;
+ parameter int unsigned SPI_HOST_TXDATA_SIZE = 'h 4;
// Register index
typedef enum int {
diff --git a/hw/ip/spi_host/rtl/spi_host_reg_top.sv b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
index 26df29a..75dc0bc 100644
--- a/hw/ip/spi_host/rtl/spi_host_reg_top.sv
+++ b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
@@ -13,8 +13,8 @@
output tlul_pkg::tl_d2h_t tl_o,
// Output port for window
- output tlul_pkg::tl_h2d_t tl_win_o,
- input tlul_pkg::tl_d2h_t tl_win_i,
+ output tlul_pkg::tl_h2d_t tl_win_o [2],
+ input tlul_pkg::tl_d2h_t tl_win_i [2],
// To HW
output spi_host_reg_pkg::spi_host_reg2hw_t reg2hw, // Write
@@ -81,29 +81,31 @@
.tl_o(tl_o)
);
- tlul_pkg::tl_h2d_t tl_socket_h2d [2];
- tlul_pkg::tl_d2h_t tl_socket_d2h [2];
+ tlul_pkg::tl_h2d_t tl_socket_h2d [3];
+ tlul_pkg::tl_d2h_t tl_socket_d2h [3];
logic [1:0] reg_steer;
// socket_1n connection
- assign tl_reg_h2d = tl_socket_h2d[1];
- assign tl_socket_d2h[1] = tl_reg_d2h;
+ assign tl_reg_h2d = tl_socket_h2d[2];
+ assign tl_socket_d2h[2] = tl_reg_d2h;
- assign tl_win_o = tl_socket_h2d[0];
- assign tl_socket_d2h[0] = tl_win_i;
+ assign tl_win_o[0] = tl_socket_h2d[0];
+ assign tl_socket_d2h[0] = tl_win_i[0];
+ assign tl_win_o[1] = tl_socket_h2d[1];
+ assign tl_socket_d2h[1] = tl_win_i[1];
// Create Socket_1n
tlul_socket_1n #(
- .N (2),
+ .N (3),
.HReqPass (1'b1),
.HRspPass (1'b1),
- .DReqPass ({2{1'b1}}),
- .DRspPass ({2{1'b1}}),
+ .DReqPass ({3{1'b1}}),
+ .DRspPass ({3{1'b1}}),
.HReqDepth (4'h0),
.HRspDepth (4'h0),
- .DReqDepth ({2{4'h0}}),
- .DRspDepth ({2{4'h0}})
+ .DReqDepth ({3{4'h0}}),
+ .DRspDepth ({3{4'h0}})
) u_socket (
.clk_i (clk_i),
.rst_ni (rst_ni),
@@ -116,15 +118,18 @@
// Create steering logic
always_comb begin
- reg_steer = 1; // Default set to register
+ reg_steer = 2; // Default set to register
// TODO: Can below codes be unique case () inside ?
if (tl_i.a_address[AW-1:0] >= 36 && tl_i.a_address[AW-1:0] < 40) begin
reg_steer = 0;
end
- if (intg_err) begin
+ if (tl_i.a_address[AW-1:0] >= 40 && tl_i.a_address[AW-1:0] < 44) begin
reg_steer = 1;
end
+ if (intg_err) begin
+ reg_steer = 2;
+ end
end
tlul_adapter_reg #(
diff --git a/hw/ip/spi_host/rtl/spi_host_window.sv b/hw/ip/spi_host/rtl/spi_host_window.sv
index 2af9cda..6cf0d61 100644
--- a/hw/ip/spi_host/rtl/spi_host_window.sv
+++ b/hw/ip/spi_host/rtl/spi_host_window.sv
@@ -8,41 +8,64 @@
module spi_host_window (
input clk_i,
input rst_ni,
- input tlul_pkg::tl_h2d_t win_i,
- output tlul_pkg::tl_d2h_t win_o,
+ input tlul_pkg::tl_h2d_t rx_win_i,
+ output tlul_pkg::tl_d2h_t rx_win_o,
+ input tlul_pkg::tl_h2d_t tx_win_i,
+ output tlul_pkg::tl_d2h_t tx_win_o,
output logic [31:0] tx_data_o,
output logic [3:0] tx_be_o,
output logic tx_valid_o,
input [31:0] rx_data_i,
- output rx_ready_o
+ output logic rx_ready_o
);
- localparam int AW=spi_host_reg_pkg::BlockAw;
- localparam int DW=32;
+ localparam int AW = spi_host_reg_pkg::BlockAw;
+ localparam int DW = 32;
- logic [AW-1:0] addr;
+ logic rx_we, tx_re;
- // Only support reads/writes to the data fifo window
- logic win_error;
- assign win_error = (tx_valid_o || rx_ready_o) &&
- (addr != spi_host_reg_pkg::SPI_HOST_DATA_OFFSET);
+ // Only support reads from the data RX fifo window
+ logic rx_access_error;
+ assign rx_access_error = rx_we;
tlul_adapter_reg #(
- .RegAw(AW),
- .RegDw(DW)
- ) u_adapter (
+ .RegAw (AW),
+ .RegDw (DW)
+ ) u_adapter_rx (
.clk_i,
.rst_ni,
- .tl_i (win_i),
- .tl_o (win_o),
- .we_o (tx_valid_o),
- .re_o (rx_ready_o),
- .addr_o (addr),
- .wdata_o (tx_data_o),
- .be_o (tx_be_o),
- .busy_i ('0),
- .rdata_i (rx_data_i),
- .error_i (win_error)
+ .tl_i (rx_win_i),
+ .tl_o (rx_win_o),
+ .we_o (rx_we),
+ .re_o (rx_ready_o),
+ .addr_o (),
+ .wdata_o (),
+ .be_o (),
+ .rdata_i (rx_data_i),
+ .error_i (rx_access_error),
+ .busy_i ('0)
+ );
+
+ // Only support writes to the data TX fifo window
+ logic tx_access_error;
+ assign tx_access_error = tx_re;
+
+ tlul_adapter_reg #(
+ .RegAw (AW),
+ .RegDw (DW)
+ ) u_adapter_tx (
+ .clk_i,
+ .rst_ni,
+ .tl_i (tx_win_i),
+ .tl_o (tx_win_o),
+ .we_o (tx_valid_o),
+ .re_o (tx_re),
+ .addr_o (),
+ .wdata_o (tx_data_o),
+ .be_o (tx_be_o),
+ .rdata_i ({DW{1'b0}}),
+ .error_i (tx_access_error),
+ .busy_i ('0)
);
endmodule : spi_host_window