|  | // 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, | 
|  |  | 
|  | // 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 | 
|  |  | 
|  | ); | 
|  |  | 
|  | import spi_device_pkg::*; | 
|  |  | 
|  | ///////////// | 
|  | // Signals // | 
|  | ///////////// | 
|  | // 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]; | 
|  |  | 
|  |  | 
|  |  | 
|  | assign rxf_wvalid = rx_data_valid_i; | 
|  | assign rxf_wdata  = rx_data_i; | 
|  |  | 
|  | assign tx_wvalid_o = 1'b 1; | 
|  | assign txf_rready  = tx_wready_i; | 
|  | 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, | 
|  |  | 
|  | .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_gnt    (fwm_sram_gnt   [FwModeRxFifo]), | 
|  | .sram_rvalid (fwm_sram_rvalid[FwModeRxFifo]), | 
|  | .sram_rdata  (fwm_sram_rdata [FwModeRxFifo]), | 
|  | .sram_error  (fwm_sram_error [FwModeRxFifo]) | 
|  | ); | 
|  | assign fwm_sram_wmask [FwModeRxFifo] = '1; | 
|  |  | 
|  | // 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, | 
|  |  | 
|  | .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); | 
|  |  | 
|  | // TODO: Assume other 7bits in a byte are same to the first bit | 
|  |  | 
|  | 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 |