| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // SPI FW Mode: Intention of this mode is to download FW image. Doesn't parse Commands |
| // |
| |
| module spi_fwmode |
| import spi_device_pkg::*; |
| #( |
| parameter int FifoWidth = $bits(spi_byte_t), |
| parameter int FifoDepth = 8, |
| localparam int SDW = $clog2(SramDw/FifoWidth), |
| localparam int PtrW = SramAw + 1 + SDW, |
| localparam int AsFifoDepthW = $clog2(FifoDepth+1) |
| ) ( |
| // clk |
| input clk_i, // main peripheral clock |
| input rst_ni, |
| |
| input clk_spi_in_i, |
| input rst_rxfifo_ni, |
| |
| input clk_spi_out_i, |
| input rst_txfifo_ni, |
| |
| input spi_mode_e spi_mode_i, |
| |
| // Configurations |
| // No sync logic. Configuration should be static when SPI operating |
| |
| output logic rxf_overflow_o, |
| output logic txf_underflow_o, |
| |
| // SRAM interface |
| output logic fwm_req_o, |
| output logic fwm_write_o, |
| output sram_addr_t fwm_addr_o, |
| output sram_data_t fwm_wdata_o, |
| output sram_strb_t fwm_wstrb_o, |
| input fwm_rvalid_i, |
| input sram_data_t fwm_rdata_i, |
| input sram_err_t fwm_rerror_i, |
| |
| // Serial to Parallel |
| input rx_data_valid_i, |
| input spi_byte_t rx_data_i, |
| output io_mode_e io_mode_o, |
| |
| // Parallel to SPI |
| output logic tx_wvalid_o, |
| output spi_byte_t tx_data_o, |
| input tx_wready_i, |
| |
| // CSRs |
| input [7:0] timer_v_i, // Wait timer inside rxf control |
| input [SramAw-1:0] sram_rxf_bindex_i, |
| input [SramAw-1:0] sram_txf_bindex_i, |
| input [SramAw-1:0] sram_rxf_lindex_i, |
| input [SramAw-1:0] sram_txf_lindex_i, |
| |
| input abort_i, |
| |
| // pointers |
| input [PtrW-1:0] sram_rxf_rptr_i, |
| output logic [PtrW-1:0] sram_rxf_wptr_o, |
| output logic [PtrW-1:0] sram_txf_rptr_o, |
| input [PtrW-1:0] sram_txf_wptr_i, |
| output logic [PtrW-1:0] sram_rxf_depth_o, |
| output logic [PtrW-1:0] sram_txf_depth_o, |
| output logic sram_rxf_full_o, |
| |
| output logic [AsFifoDepthW-1:0] as_txfifo_depth_o, |
| output logic [AsFifoDepthW-1:0] as_rxfifo_depth_o, |
| |
| // FIFO Status |
| output logic rxf_empty_o, |
| output logic rxf_full_o, |
| output logic txf_empty_o, |
| output logic txf_full_o |
| |
| ); |
| |
| ///////////// |
| // Signals // |
| ///////////// |
| logic active; |
| assign active = (spi_mode_i == FwMode); |
| |
| // RX Async FIFO Signals |
| // Write: SCK positive edge |
| logic rxf_wvalid, rxf_wready; |
| spi_byte_t rxf_wdata; |
| // Read: Main clock |
| logic rxf_rvalid, rxf_rready; |
| spi_byte_t rxf_rdata; |
| |
| // TX Async FIFO Signals |
| // Read: SCK negative edge |
| logic txf_rvalid, txf_rready; |
| spi_byte_t txf_rdata; |
| // Write: Main clock |
| logic txf_wvalid, txf_wready; |
| spi_byte_t txf_wdata; |
| |
| // SRAM FIFO control |
| typedef enum logic { |
| FwModeRxFifo = 1'b0, |
| FwModeTxFifo = 1'b1 |
| } fwm_fifo_e; |
| |
| logic [1:0] fwm_sram_req; |
| logic [SramAw-1:0] fwm_sram_addr [2]; |
| logic [1:0] fwm_sram_write; |
| logic [SramDw-1:0] fwm_sram_wdata [2]; |
| logic [SramDw-1:0] fwm_sram_wmask [2]; |
| logic [1:0] fwm_sram_gnt; |
| logic [1:0] fwm_sram_rvalid; // RXF doesn't use |
| logic [SramDw-1:0] fwm_sram_rdata [2]; // RXF doesn't use |
| logic [1:0] fwm_sram_error [2]; |
| |
| |
| // Allow Async FIFO update only when the SpiMode is FwMode |
| assign rxf_wvalid = rx_data_valid_i && active; |
| assign rxf_wdata = rx_data_i; |
| |
| assign tx_wvalid_o = 1'b 1; |
| assign txf_rready = tx_wready_i; // not updated if !FwMode |
| assign tx_data_o = txf_rdata; |
| |
| // Generic Mode only uses SingleIO. s_i[0] is MOSI, s_o[1] is MISO. |
| assign io_mode_o = SingleIO; |
| |
| // Events: rx_overflow, tx_underflow |
| // Reminder: Those events are not 100% accurate. If the event happens at |
| // the end of the transaction right before CSb de-assertion, the event |
| // cannot be propagated to the main clock domain due to the reset and lack |
| // of SCK after CSb de-assertion. |
| // |
| // For these events to be propagated to the main clock domain, it needds |
| // one more clock edge to creates toggle signal in the pulse synchronizer. |
| assign rxf_overflow_o = rxf_wvalid & ~rxf_wready; |
| assign txf_underflow_o = txf_rready & ~txf_rvalid; |
| |
| assign rxf_empty_o = ~rxf_rvalid; |
| assign rxf_full_o = ~rxf_wready; |
| assign txf_empty_o = ~txf_rvalid; |
| assign txf_full_o = ~txf_wready; |
| /////////////// |
| // Instances // |
| /////////////// |
| |
| // FIFO: Connecting FwMode to SRAM CTRLs |
| prim_fifo_async #( |
| .Width (FifoWidth), |
| .Depth (FifoDepth) |
| ) u_rx_fifo ( |
| .clk_wr_i (clk_spi_in_i), |
| .rst_wr_ni (rst_rxfifo_ni), |
| |
| .clk_rd_i (clk_i), |
| .rst_rd_ni (rst_rxfifo_ni), |
| |
| .wvalid_i (rxf_wvalid), |
| .wready_o (rxf_wready), |
| .wdata_i (rxf_wdata), |
| |
| .rvalid_o (rxf_rvalid), |
| .rready_i (rxf_rready), |
| .rdata_o (rxf_rdata), |
| |
| .wdepth_o (), |
| .rdepth_o (as_rxfifo_depth_o) |
| ); |
| |
| prim_fifo_async #( |
| .Width (FifoWidth), |
| .Depth (FifoDepth) |
| ) u_tx_fifo ( |
| .clk_wr_i (clk_i), |
| .rst_wr_ni (rst_txfifo_ni), |
| |
| .clk_rd_i (clk_spi_out_i), |
| .rst_rd_ni (rst_txfifo_ni), |
| |
| .wvalid_i (txf_wvalid), |
| .wready_o (txf_wready), |
| .wdata_i (txf_wdata), |
| |
| .rvalid_o (txf_rvalid), |
| .rready_i (txf_rready), |
| .rdata_o (txf_rdata), |
| |
| .wdepth_o (as_txfifo_depth_o), |
| .rdepth_o () |
| ); |
| |
| // RX Fifo control (FIFO Read port --> SRAM request) |
| spi_fwm_rxf_ctrl #( |
| .FifoDw (FifoWidth), |
| .SramAw (SramAw), |
| .SramDw (SramDw) |
| ) u_rxf_ctrl ( |
| .clk_i, |
| .rst_ni, |
| |
| .spi_mode_i, |
| |
| .base_index_i (sram_rxf_bindex_i), |
| .limit_index_i (sram_rxf_lindex_i), |
| .timer_v (timer_v_i), |
| .rptr (sram_rxf_rptr_i), // Given by FW |
| .wptr (sram_rxf_wptr_o), // to Register interface |
| .depth (sram_rxf_depth_o), |
| .full (sram_rxf_full_o), |
| |
| .fifo_valid (rxf_rvalid), |
| .fifo_ready (rxf_rready), |
| .fifo_rdata (rxf_rdata), |
| |
| .sram_req (fwm_sram_req [FwModeRxFifo]), |
| .sram_write (fwm_sram_write [FwModeRxFifo]), |
| .sram_addr (fwm_sram_addr [FwModeRxFifo]), |
| .sram_wdata (fwm_sram_wdata [FwModeRxFifo]), |
| .sram_wmask (fwm_sram_wmask [FwModeRxFifo]), |
| .sram_gnt (fwm_sram_gnt [FwModeRxFifo]), |
| .sram_rvalid (fwm_sram_rvalid[FwModeRxFifo]), |
| .sram_rdata (fwm_sram_rdata [FwModeRxFifo]), |
| .sram_error (fwm_sram_error [FwModeRxFifo]) |
| ); |
| |
| // TX Fifo control (SRAM read request --> FIFO write) |
| spi_fwm_txf_ctrl #( |
| .FifoDw (FifoWidth), |
| .SramAw (SramAw), |
| .SramDw (SramDw) |
| ) u_txf_ctrl ( |
| .clk_i, |
| .rst_ni, |
| |
| .spi_mode_i, |
| |
| .base_index_i (sram_txf_bindex_i), |
| .limit_index_i (sram_txf_lindex_i), |
| |
| .abort (abort_i), |
| .rptr (sram_txf_rptr_o), |
| .wptr (sram_txf_wptr_i), |
| .depth (sram_txf_depth_o), |
| |
| .fifo_valid (txf_wvalid), |
| .fifo_ready (txf_wready), |
| .fifo_wdata (txf_wdata), |
| |
| .sram_req (fwm_sram_req [FwModeTxFifo]), |
| .sram_write (fwm_sram_write [FwModeTxFifo]), |
| .sram_addr (fwm_sram_addr [FwModeTxFifo]), |
| .sram_wdata (fwm_sram_wdata [FwModeTxFifo]), |
| .sram_gnt (fwm_sram_gnt [FwModeTxFifo]), |
| .sram_rvalid (fwm_sram_rvalid[FwModeTxFifo]), |
| .sram_rdata (fwm_sram_rdata [FwModeTxFifo]), |
| .sram_error (fwm_sram_error [FwModeTxFifo]) |
| ); |
| assign fwm_sram_wmask [FwModeTxFifo] = '1; |
| |
| // Arbiter for FIFOs : Connecting between SRAM Ctrls and SRAM interface |
| logic [SramDw-1:0] fwm_wmask; |
| |
| assign fwm_wstrb_o = sram_mask2strb(fwm_wmask); |
| |
| prim_sram_arbiter #( |
| .N (2), // RXF, TXF |
| .SramDw (SramDw), |
| .SramAw (SramAw) // 2kB |
| ) u_fwmode_arb ( |
| .clk_i, |
| .rst_ni, |
| |
| .req_i (fwm_sram_req), |
| .req_addr_i (fwm_sram_addr), |
| .req_write_i (fwm_sram_write), |
| .req_wdata_i (fwm_sram_wdata), |
| .req_wmask_i (fwm_sram_wmask), |
| .gnt_o (fwm_sram_gnt), |
| |
| .rsp_rvalid_o (fwm_sram_rvalid), |
| .rsp_rdata_o (fwm_sram_rdata), |
| .rsp_error_o (fwm_sram_error), |
| |
| .sram_req_o (fwm_req_o), |
| .sram_addr_o (fwm_addr_o), |
| .sram_write_o (fwm_write_o), |
| .sram_wdata_o (fwm_wdata_o), |
| .sram_wmask_o (fwm_wmask), |
| |
| .sram_rvalid_i(fwm_rvalid_i), |
| .sram_rdata_i (fwm_rdata_i), |
| .sram_rerror_i(fwm_rerror_i) |
| ); |
| |
| |
| endmodule |