../src/lowrisc_ip_spi_device_0.1/rtl/spi_fwm_rxf_ctrl.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: // Serial Peripheral Interface (SPI) Device module.
6: //
7:
8: module spi_fwm_rxf_ctrl #(
9: parameter int unsigned FifoDw = 8,
10: parameter int unsigned SramAw = 11,
11: parameter int unsigned SramDw = 32,
12: // Do not touch below
13: // SramDw should be multiple of FifoDw
14: localparam int unsigned NumBytes = SramDw/FifoDw, // derived parameter
15: localparam int unsigned SDW = $clog2(NumBytes), // derived parameter
16: localparam int unsigned PtrW = SramAw + SDW + 1 // derived parameter
17: ) (
18: input clk_i,
19: input rst_ni,
20:
21: // Configuration
22: input [SramAw-1:0] base_index_i,
23: input [SramAw-1:0] limit_index_i,
24: input [7:0] timer_v,
25: input [PtrW-1:0] rptr,
26: output logic [PtrW-1:0] wptr,
27: output logic [PtrW-1:0] depth,
28:
29: output logic full,
30:
31: input fifo_valid,
32: output logic fifo_ready,
33: input [FifoDw-1:0] fifo_rdata,
34:
35: output logic sram_req,
36: output logic sram_write,
37: output logic [SramAw-1:0] sram_addr,
38: output logic [SramDw-1:0] sram_wdata,
39: input sram_gnt,
40: input sram_rvalid,
41: input [SramDw-1:0] sram_rdata,
42: input [1:0] sram_error
43: );
44:
45: // Internal variable
46: logic [NumBytes-1:0] byte_enable;
47: logic [SDW-1:0] pos; // current byte position
48: logic [7:0] cur_timer;
49: logic [SramAw-1:0] sramf_limit;
50:
51: // State input
52: logic sramf_full; // SRAM Fifo full
53: logic full_sramwidth; // Write data filled full SRAM
54: logic timer_expired;
55:
56: // State output
57: logic update_wdata;
58: logic clr_byte_enable;
59: logic sram_req_d;
60: logic sram_write_d;
61: logic sram_wdata_sel;
62: logic timer_rst;
63: logic update_wptr;
64:
65: typedef enum logic [2:0] {
66: StIdle = 'h0,
67: StPop = 'h1,
68: StWait = 'h2,
69: StRead = 'h3,
70: StModify = 'h4,
71: StWrite = 'h5,
72: StUpdate = 'h6
73: } state_e;
74:
75: state_e st_next, st;
76:
77: always_ff @(posedge clk_i or negedge rst_ni) begin
78: if (!rst_ni) st <= StIdle;
79: else st <= st_next;
80: end
81:
82:
83: logic [PtrW-1:0] ptr_cmp;
84: assign ptr_cmp = rptr ^ wptr;
85: // TODO: Check partial SRAM width read condition
86: assign sramf_full = (ptr_cmp[PtrW-1] == 1'b1) && (ptr_cmp[PtrW-2:SDW] == '0);
87: assign full = sramf_full;
88:
89: assign sramf_limit = limit_index_i - base_index_i;
90:
91: // Write pointer update
92: always_ff @(posedge clk_i or negedge rst_ni) begin
93: if (!rst_ni) begin
94: wptr <= '0;
95: end else if (update_wptr) begin
96: if (byte_enable == '0) begin
97: // as byte enable is cleared, it means full write was done
98: if (wptr[PtrW-2:SDW] == sramf_limit) begin
99: wptr[PtrW-1] <= ~wptr[PtrW-1];
100: wptr[PtrW-2:0] <= '0;
101: end else begin
102: wptr[PtrW-2:SDW] <= wptr[PtrW-2:SDW] + 1'b1;
103: wptr[SDW-1:0] <= '0;
104: end
105: end else begin
106: wptr[SDW-1:0] <= pos;
107: end
108: end
109: end
110:
111: // Full check
112: assign full_sramwidth = (1'b1 == &byte_enable);
113:
114: // Depth
115: always_comb begin
116: if (wptr[PtrW-1] == rptr[PtrW-1]) begin
117: // Same phase
118: depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
119: end else begin
120: depth = {1'b0, wptr[PtrW-2:0]}
121: + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
122: end
123: end
124:
125: //timer
126: always_ff @(posedge clk_i or negedge rst_ni) begin
127: if (!rst_ni) begin
128: cur_timer <= '1;
129: end else if (timer_rst) begin
130: cur_timer <= timer_v;
131: end else if (st == StWait) begin
132: if (cur_timer != '0) cur_timer <= cur_timer - 1'b1;
133: end
134: end
135: assign timer_expired = (cur_timer == '0);
136:
137: // Data output
138: assign sram_addr = base_index_i + wptr[PtrW-2:SDW];
139:
140: // Byte Enable control
141: always_ff @(posedge clk_i or negedge rst_ni) begin
142: if (!rst_ni) begin
143: byte_enable <= '0;
144: pos <= '0;
145: end else if (update_wdata) begin
146: byte_enable[pos] <= 1'b1;
147: if (pos == SDW'(NumBytes-1)) pos <= '0;
148: else pos <= pos + 1'b1;
149: end else if (clr_byte_enable) begin
150: byte_enable <= '0;
151: pos <= '0;
152: end
153: end
154:
155: always_ff @(posedge clk_i or negedge rst_ni) begin
156: if (!rst_ni) begin
157: sram_wdata <= '0;
158: end else if (update_wdata) begin
159: sram_wdata[8*pos+:8] <= fifo_rdata;
160: end else if (sram_wdata_sel == 1'b1) begin
161: for (int i = 0 ; i < NumBytes ; i++) begin
162: if (!byte_enable[i]) begin
163: sram_wdata[8*i+:8] <= sram_rdata[8*i+:8];
164: end
165: end
166: end
167: end
168:
169: `COVER(partialWriteCover, st == StModify, clk_i, !rst_ni)
170:
171: // If FIFO is not empty, initiate SRAM write.
172: // As FIFOWidth and SRAM Width are different, RMW is required.
173: // If host writes always DWord size, it is easy but it is not guaranteed.
174: //
175:
176: // Next State & output logic
177: always_comb begin
178: fifo_ready = 1'b0;
179: update_wdata = 1'b0;
180: clr_byte_enable = 1'b0;
181: sram_req_d = 1'b0;
182: sram_write_d = 1'b0;
183: sram_wdata_sel = 1'b0;
184: timer_rst = 1'b0;
185: update_wptr = 1'b0;
186:
187: unique case (st)
188: StIdle: begin
189: // Out of reset state. If SRAM Fifo is not full and RX Fifo is not empty,
190: // state machine starts process incoming data
191: if (fifo_valid && !sramf_full) begin
192: st_next = StPop;
193: fifo_ready = 1'b1;
194: update_wdata = 1'b1;
195: end else begin
196: st_next = StIdle;
197: end
198: end
199:
200: StPop: begin
201: // Pop entries from FIFO. It moves to WAIT if Fifo is empty and still not
202: // filled up full sram data width. If anytime while popping the entries
203: // and full sram data width is filled, it directly moves to Write state
204: if (fifo_valid && !full_sramwidth) begin
205: st_next = StPop;
206: fifo_ready = 1'b1;
207: update_wdata = 1'b1;
208: end else if (full_sramwidth) begin
209: st_next = StWrite;
210: clr_byte_enable = 1'b1;
211: sram_req_d = 1'b1;
212: sram_write_d = 1'b1;
213: end else begin
214: st_next = StWait;
215: timer_rst = 1'b1;
216: end
217: end
218:
219: StWait: begin
220: // Wait up to X clocks. This state is useful to reduce traffic to SRAM.
221: // State machine gathers up to SramDw then tries to write at once.
222: // If not, it needs to Read-Modify-Write for every byte
223: if (fifo_valid) begin
224: st_next = StPop;
225: fifo_ready = 1'b1;
226: update_wdata = 1'b1;
227: end else if (!fifo_valid && timer_expired) begin
228: st_next = StRead;
229: sram_req_d = 1'b1;
230: sram_write_d = 1'b0;
231: end else begin
232: st_next = StWait;
233: end
234: end
235:
236: StRead: begin
237: // As counter expires, RMW is only option. State machine reads from current
238: // write pointer address (chopping lower bits).
239: if (sram_gnt) begin
240: st_next = StModify;
241: end else begin
242: st_next = StRead;
243: sram_req_d = 1'b1;
244: sram_write_d = 1'b0;
245: end
246: end
247:
248: StModify: begin
249: // Waits until read data arrives.
250: if (sram_rvalid) begin
251: st_next = StWrite;
252: sram_req_d = 1'b1;
253: sram_write_d = 1'b1;
254: sram_wdata_sel = 1'b1;
255: end else begin
256: st_next = StModify;
257: end
258: end
259:
260: StWrite: begin
261: // Regardless of RMW or just full Words write, statemachine writes data
262: // into SRAM Fifo
263: if (sram_gnt) begin
264: st_next = StUpdate;
265: end else begin
266: st_next = StWrite;
267: sram_req_d = 1'b1;
268: sram_write_d = 1'b1;
269: end
270: end
271:
272: StUpdate: begin
273: // Now, update write pointer then goes back to StIdle.
274: // It can goes to StPop state directly but doesn't have to as SPI is slower
275: st_next = StIdle;
276: update_wptr = 1'b1;
277: end
278:
279: default: begin
280: st_next = StIdle;
281: end
282: endcase
283: end
284:
285: always_ff @(posedge clk_i or negedge rst_ni) begin
286: if (!rst_ni) begin
287: sram_req <= 1'b0;
288: sram_write <= 1'b0;
289: end else begin
290: sram_req <= sram_req_d;
291: sram_write <= sram_write_d;
292: end
293: end
294:
295: endmodule
296: