../src/lowrisc_ip_spi_device_0.1/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: st_next = StIdle;
88: sram_req_d = 1'b0;
89: update_rptr = 1'b0;
90: latch_wptr = 1'b0;
91: fifo_valid = 1'b0;
92: txf_sel = 1'b0; // 0: sram_rdata, 1:sram_rdata_q
93: cnt_rst = 1'b0; // reset pos to rptr
94: cnt_incr = 1'b0;
95: unique case (st)
96: StIdle: begin
97: latch_wptr = 1'b1;
98: if (!sramf_empty && fifo_ready) begin
99: st_next = StRead;
100: sram_req_d = 1'b1;
101: end else begin
102: st_next = StIdle;
103: end
104: end
105:
106: StRead: begin
107: if (sram_gnt) begin
108: st_next = StLatch;
109: cnt_rst = 1'b1;
110: sram_req_d = 1'b0;
111: end else begin
112: st_next = StRead;
113: sram_req_d = 1'b1;
114: end
115: end
116:
117: StLatch: begin
118: if (sram_rvalid) begin
119: st_next = StPush;
120: fifo_valid = 1'b1;
121: txf_sel = 1'b0; // select current sram_rdata
122: cnt_incr = 1'b1; // increase pos to next byte
123: end else begin
124: st_next = StLatch;
125: end
126: end
127:
128: StPush: begin
129: if (abort) begin
130: st_next = StUpdate;
131: end else if (!fifo_ready) begin
132: st_next = StPush;
133: end else if (fifo_ready && !cnt_eq_end) begin
134: st_next = StPush;
135: fifo_valid = 1'b1;
136: txf_sel = 1'b1; // select sram_rdata_q
137: cnt_incr = 1'b1;
138: end else begin //if (fifo_ready && cnt_eq_end) begin
139: // current SRAM word is written to FIFO
140: st_next = StUpdate;
141: end
142: end
143:
144: StUpdate: begin
145: st_next = StIdle;
146: update_rptr = 1'b1;
147: end
148:
149: default: begin
150: st_next = StIdle;
151: end
152: endcase
153: end
154:
155: always_ff @(posedge clk_i or negedge rst_ni) begin
156: if (!rst_ni) begin
157: pos <= '0;
158: end else if (cnt_rst) begin
159: // Reset to rptr to select bytes among fifo_wdata_d
160: pos <= rptr[SDW-1:0];
161: end else if (cnt_incr) begin
162: // Increase position
163: pos <= pos + 1'b1;
164: end
165: end
166:
167: always_ff @(posedge clk_i or negedge rst_ni) begin
168: if (!rst_ni) begin
169: wptr_q <= '0;
170: end else if (latch_wptr) begin
171: wptr_q <= wptr;
172: end
173: end
174:
175: always_ff @(posedge clk_i or negedge rst_ni) begin
176: if (!rst_ni) begin
177: rptr <= '0;
178: end else if (update_rptr) begin
179: if (pos == '0) begin
180: // full sram word is written.
181: if (rptr[PtrW-2:SDW] != sramf_limit) begin
182: rptr[PtrW-1:SDW] <= rptr[PtrW-1:SDW] + 1'b1;
183: rptr[SDW-1:0] <= '0;
184: end else begin
185: rptr[PtrW-1] <= ~rptr[PtrW-1];
186: rptr[PtrW-2:SDW] <= '0;
187: rptr[SDW-1:0] <= '0;
188: end
189: end else begin
190: // Abort, or partial update (fifo_full), or wptr_q is at the same entry
191: rptr[SDW-1:0] <= pos;
192: end
193: end
194: end
195:
196: // Depth
197: always_comb begin
198: if (wptr[PtrW-1] == rptr[PtrW-1]) begin
199: // Same phase
200: depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
201: end else begin
202: depth = {1'b0, wptr[PtrW-2:0]}
203: + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
204: end
205: end
206:
207: assign cnt_eq_end = (wptr_q[PtrW-1:SDW] == rptr[PtrW-1:SDW]) ? wptr_q[SDW-1:0] == pos :
208: pos == '0;
209:
210:
211: // Datapath
212: assign sram_addr = base_index_i + rptr[PtrW-2:SDW];
213: assign sram_write = 1'b0;
214: assign sram_wdata = '0;
215:
216: always_ff @(posedge clk_i or negedge rst_ni) begin
217: if (!rst_ni) sram_req <= 1'b0;
218: else sram_req <= sram_req_d;
219: end
220:
221: always_ff @(posedge clk_i or negedge rst_ni) begin
222: if (!rst_ni) sram_rdata_q <= '0;
223: else if (sram_rvalid) sram_rdata_q <= sram_rdata;
224: end
225:
226: assign fifo_wdata_d = (txf_sel) ? sram_rdata_q : sram_rdata ;
227:
228: always_comb begin
229: fifo_wdata = '0;
230: for (int i = 0 ; i < NumBytes ; i++) begin
231: if (pos == i) fifo_wdata = fifo_wdata_d[8*i+:8];
232: end
233: end
234:
235: endmodule
236: