hw/ip/spi_device/rtl/spi_fwmode.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // SPI FW Mode: Intention of this mode is to download FW image. Doesn't parse Commands
6: //
7:
8: module spi_fwmode (
9: // MOSI
10: input clk_in_i,
11: input rst_in_ni,
12:
13: // MISO
14: input clk_out_i,
15: input rst_out_ni,
16:
17: // Configurations
18: // No sync logic. Configuration should be static when SPI operating
19: input cpha_i,
20: input cfg_rxorder_i, // 1: 0->7 , 0:7->0
21: input cfg_txorder_i, // 1: 0->7 , 0:7->0
22: input spi_device_pkg::spi_mode_e mode_i, // Only works at mode_i == FwMode
23:
24: // RX, TX FIFO interface
25: output logic rx_wvalid_o,
26: input rx_wready_i,
27: output spi_device_pkg::spi_byte_t rx_data_o,
28:
29: input tx_rvalid_i,
30: output logic tx_rready_o,
31: input spi_device_pkg::spi_byte_t tx_data_i,
32:
33: output logic rx_overflow_o,
34: output logic tx_underflow_o,
35:
36: // SPI Interface: clock is given (ckl_in_i, clk_out_i)
37: input csb_i,
38: input mosi,
39: output logic miso,
40: output logic miso_oe
41: );
42:
43: import spi_device_pkg::*;
44:
45: localparam int unsigned BITS = $bits(spi_byte_t);
46: localparam int unsigned BITWIDTH = $clog2(BITS);
47:
48: logic [BITWIDTH-1:0] rx_bitcount;
49:
50: typedef enum logic {
51: TxIdle,
52: TxActive
53: } tx_state_e;
54: tx_state_e tx_state; // Only for handling CPHA
55:
56: spi_byte_t rx_data_d, rx_data_q;
57:
58: // Serial to Parallel
59: always_comb begin
60: if (cfg_rxorder_i) begin
61: rx_data_d = {mosi, rx_data_q[BITS-1:1]};
62: end else begin
63: rx_data_d = {rx_data_q[BITS-2:0], mosi};
64: end
65: end
66:
67: always_ff @(posedge clk_in_i) begin
68: rx_data_q <= rx_data_d;
69: end
70:
71: // As SCK shut off right after bytes are transferred,
72: // HW should give current MOSI and latched version of rx_data
73: // if not, FIFO request should be generated next cycle but it cannot be (as no clock exist)
74: // It means RX_FIFO should latch the write request at negedge of clk_in_i
75: assign rx_data_o = rx_data_d;
76:
77: // Counter to generate write signal
78: always_ff @(posedge clk_in_i or negedge rst_in_ni) begin
79: if (!rst_in_ni) begin
80: rx_bitcount <= BITWIDTH'(BITS-1);
81: end else begin
82: if (rx_bitcount == '0) begin
83: rx_bitcount <= BITWIDTH'(BITS-1);
84: end else begin
85: rx_bitcount <= rx_bitcount -1;
86: end
87: end
88: end
89:
90: assign rx_wvalid_o = (rx_bitcount == '0);
91:
92: // TX Serialize
93: logic [BITWIDTH-1:0] tx_bitcount;
94: logic first_bit, last_bit;
95: spi_byte_t miso_shift;
96:
97: assign first_bit = (tx_bitcount == BITWIDTH'(BITS-1)) ? 1'b1 : 1'b0;
98: assign last_bit = (tx_bitcount == '0) ? 1'b1 : 1'b0;
99: // Pop the entry from the FIFO at bit 1.
100: // This let the module pop the entry correctly when CPHA == 1 If CPHA is set, there is no clock
101: // posedge after bitcnt is 0 right before CSb is de-asserted. So TX Async FIFO pop signal
102: // cannot be latched inside FIFO. It is safe to pop between bitcnt 6 to 1. If pop signal is
103: // asserted when bitcnt 7 it can pop twice if CPHA is 1.
104: assign tx_rready_o = (tx_bitcount == BITWIDTH'(1)); // Pop at second bit transfer
105: always_ff @(posedge clk_out_i or negedge rst_out_ni) begin
106: if (!rst_out_ni) begin
107: tx_bitcount <= BITWIDTH'(BITS-1);
108: end else begin
109: if (last_bit) begin
110: tx_bitcount <= BITWIDTH'(BITS-1);
111: end else if (tx_state != TxIdle || cpha_i == 1'b0) begin
112: tx_bitcount <= tx_bitcount - 1'b1;
113: end
114: end
115: end
116: always_ff @(posedge clk_out_i or negedge rst_out_ni) begin
117: if (!rst_out_ni) begin
118: tx_state <= TxIdle;
119: end else begin
120: tx_state <= TxActive;
121: end
122: end
123:
124: assign miso = (cfg_txorder_i) ? ((~first_bit) ? miso_shift[0] : tx_data_i[0]) :
125: (~first_bit) ? miso_shift[7] : tx_data_i[7] ;
126: assign miso_oe = ~csb_i;
127:
128: always_ff @(posedge clk_out_i) begin
129: if (cfg_txorder_i) begin
130: if (first_bit) begin
131: miso_shift <= {1'b0, tx_data_i[7:1]};
132: end else begin
133: miso_shift <= {1'b0, miso_shift[7:1]};
134: end
135: end else begin
136: if (first_bit) begin
137: // Dummy byte cannot be used. empty signal could be delayed two clocks to cross
138: // async clock domain. It means even FW writes value to FIFO, empty signal deasserts
139: // after two negative edge of SCK. HW module already in the middle of sending DUMMY.
140: miso_shift <= {tx_data_i[6:0], 1'b0};
141: end else begin
142: miso_shift <= {miso_shift[6:0], 1'b0};
143: end
144: end
145: end
146:
147: // Events: rx_overflow, tx_underflow
148: // Reminder: Those events are not 100% accurate. If the event happens at
149: // the end of the transaction right before CSb de-assertion, the event
150: // cannot be propagated to the main clock domain due to the reset and lack
151: // of SCK after CSb de-assertion.
152: //
153: // For these events to be propagated to the main clock domain, it needds
154: // one more clock edge to creates toggle signal in the pulse synchronizer.
155: assign rx_overflow_o = rx_wvalid_o & ~rx_wready_i;
156: assign tx_underflow_o = tx_rready_o & ~tx_rvalid_i;
157:
158: endmodule
159: