blob: 5749129650eb1bdf84cf64c97d5500b9ac812cbd [file] [log] [blame]
// 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