hw/ip/spi_device/rtl/spi_fwm_txf_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_txf_ctrl #(
9: parameter int FifoDw = 8,
10: parameter int SramAw = 11,
11: parameter int SramDw = 32,
12: // SramDw should be multiple of FifoDw
13: localparam int NumBytes = SramDw/FifoDw, // derived parameter
14: localparam int SDW = $clog2(NumBytes), // derived parameter
15: localparam int PtrW = SramAw + SDW + 1 // derived parameter
16: ) (
17: input clk_i,
18: input rst_ni,
19:
20: // Configuration
21: input [SramAw-1:0] base_index_i,
22: input [SramAw-1:0] limit_index_i,
23:
24: input abort, // Abort State Machine if TX Async at stuck
25: input [PtrW-1:0] wptr,
26: output logic [PtrW-1:0] rptr,
27: output logic [PtrW-1:0] depth,
28:
29: output logic fifo_valid,
30: input fifo_ready,
31: output logic [FifoDw-1:0] fifo_wdata,
32:
33: output logic sram_req,
34: output logic sram_write,
35: output logic [SramAw-1:0] sram_addr,
36: output logic [SramDw-1:0] sram_wdata,
37: input sram_gnt,
38: input sram_rvalid,
39: input [SramDw-1:0] sram_rdata,
40: input [1:0] sram_error
41: );
42:
43: logic [SDW-1:0] pos; // Current write position
44: logic [SramAw-1:0] sramf_limit;
45:
46: logic [SramDw-1:0] sram_rdata_q;
47: logic [SramDw-1:0] fifo_wdata_d;
48:
49: logic [PtrW-1:0] wptr_q;
50:
51:
52: // State input
53: logic sramf_empty;
54: logic cnt_eq_end; // pos goes 0 -> 1 -> 2 -> 3 -> then 0
55:
56: // State output
57: logic sram_req_d;
58: logic update_rptr;
59: logic latch_wptr;
60: logic cnt_rst; // Reset pos to rptr[SDW-1:0] or 0
61: logic cnt_incr;
62: logic txf_sel; // 0: sram_rdata, 1: sram_rdata_q
63:
64:
65: typedef enum logic [2:0] {
66: StIdle = 'h0,
67: StRead = 'h1,
68: StLatch = 'h2,
69: StPush = 'h3,
70: StUpdate = 'h4
71: } state_e;
72:
73: state_e st_next, st;
74:
75: always_ff @(posedge clk_i or negedge rst_ni) begin
76: if (!rst_ni) st <= StIdle;
77: else st <= st_next;
78: end
79:
80: assign sramf_empty = (rptr == wptr_q);
81:
82: assign sramf_limit = limit_index_i - base_index_i;
83:
84: // State Machine next , output logic
85: always_comb begin
86: // default output value
87: sram_req_d = 1'b0;
88: update_rptr = 1'b0;
89: latch_wptr = 1'b0;
90: fifo_valid = 1'b0;
91: txf_sel = 1'b0; // 0: sram_rdata, 1:sram_rdata_q
92: cnt_rst = 1'b0; // reset pos to rptr
93: cnt_incr = 1'b0;
94: unique case (st)
95: StIdle: begin
96: latch_wptr = 1'b1;
97: if (!sramf_empty && fifo_ready) begin
98: st_next = StRead;
99: sram_req_d = 1'b1;
100: end else begin
101: st_next = StIdle;
102: end
103: end
104:
105: StRead: begin
106: if (sram_gnt) begin
107: st_next = StLatch;
108: cnt_rst = 1'b1;
109: sram_req_d = 1'b0;
110: end else begin
111: st_next = StRead;
112: sram_req_d = 1'b1;
113: end
114: end
115:
116: StLatch: begin
117: if (sram_rvalid) begin
118: st_next = StPush;
119: fifo_valid = 1'b1;
120: txf_sel = 1'b0; // select current sram_rdata
121: cnt_incr = 1'b1; // increase pos to next byte
122: end else begin
123: st_next = StLatch;
124: end
125: end
126:
127: StPush: begin
128: if (abort) begin
129: st_next = StUpdate;
130: end else if (!fifo_ready) begin
131: st_next = StPush;
132: end else if (fifo_ready && !cnt_eq_end) begin
133: st_next = StPush;
134: fifo_valid = 1'b1;
135: txf_sel = 1'b1; // select sram_rdata_q
136: cnt_incr = 1'b1;
137: end else if (fifo_ready && cnt_eq_end) begin
138: // current SRAM word is written to FIFO
139: st_next = StUpdate;
140: end
141: end
142:
143: StUpdate: begin
144: st_next = StIdle;
145: update_rptr = 1'b1;
146: end
147:
148: default: begin
149: st_next = StIdle;
150: end
151: endcase
152: end
153:
154: always_ff @(posedge clk_i or negedge rst_ni) begin
155: if (!rst_ni) begin
156: pos <= '0;
157: end else if (cnt_rst) begin
158: // Reset to rptr to select bytes among fifo_wdata_d
159: pos <= rptr[SDW-1:0];
160: end else if (cnt_incr) begin
161: // Increase position
162: pos <= pos + 1'b1;
163: end
164: end
165:
166: always_ff @(posedge clk_i or negedge rst_ni) begin
167: if (!rst_ni) begin
168: wptr_q <= '0;
169: end else if (latch_wptr) begin
170: wptr_q <= wptr;
171: end
172: end
173:
174: always_ff @(posedge clk_i or negedge rst_ni) begin
175: if (!rst_ni) begin
176: rptr <= '0;
177: end else if (update_rptr) begin
178: if (pos == '0) begin
179: // full sram word is written.
180: if (rptr[PtrW-2:SDW] != sramf_limit) begin
181: rptr[PtrW-1:SDW] <= rptr[PtrW-1:SDW] + 1'b1;
182: rptr[SDW-1:0] <= '0;
183: end else begin
184: rptr[PtrW-1] <= ~rptr[PtrW-1];
185: rptr[PtrW-2:SDW] <= '0;
186: rptr[SDW-1:0] <= '0;
187: end
188: end else begin
189: // Abort, or partial update (fifo_full), or wptr_q is at the same entry
190: rptr[SDW-1:0] <= pos;
191: end
192: end
193: end
194:
195: // Depth
196: always_comb begin
197: if (wptr[PtrW-1] == rptr[PtrW-1]) begin
198: // Same phase
199: depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
200: end else begin
201: depth = {1'b0, wptr[PtrW-2:0]}
202: + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
203: end
204: end
205:
206: assign cnt_eq_end = (wptr_q[PtrW-1:SDW] == rptr[PtrW-1:SDW]) ? wptr_q[SDW-1:0] == pos :
207: pos == '0;
208:
209:
210: // Datapath
211: assign sram_addr = base_index_i + rptr[PtrW-2:SDW];
212: assign sram_write = 1'b0;
213: assign sram_wdata = '0;
214:
215: always_ff @(posedge clk_i or negedge rst_ni) begin
216: if (!rst_ni) sram_req <= 1'b0;
217: else sram_req <= sram_req_d;
218: end
219:
220: always_ff @(posedge clk_i or negedge rst_ni) begin
221: if (!rst_ni) sram_rdata_q <= '0;
222: else if (sram_rvalid) sram_rdata_q <= sram_rdata;
223: end
224:
225: assign fifo_wdata_d = (txf_sel) ? sram_rdata_q : sram_rdata ;
226:
227: always_comb begin
228: fifo_wdata = '0;
229: for (int i = 0 ; i < NumBytes ; i++) begin
230: if (pos == i) fifo_wdata = fifo_wdata_d[8*i+:8];
231: end
232: end
233:
234: endmodule
235: