../src/lowrisc_prim_generic_flash_0/rtl/prim_generic_flash.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: // prim flash module - Emulated using memory
6: //
7:
8: module prim_generic_flash #(
9: parameter int PagesPerBank = 256, // pages per bank
10: parameter int WordsPerPage = 256, // words per page
11: parameter int DataWidth = 32, // bits per word
12: parameter bit SkipInit = 1, // this is an option to reset flash to all F's at reset
13:
14: // Derived parameters
15: localparam int PageW = $clog2(PagesPerBank),
16: localparam int WordW = $clog2(WordsPerPage),
17: localparam int AddrW = PageW + WordW
18: ) (
19: input clk_i,
20: input rst_ni,
21: input rd_i,
22: input prog_i,
23: input pg_erase_i,
24: input bk_erase_i,
25: input [AddrW-1:0] addr_i,
26: input [DataWidth-1:0] prog_data_i,
27: output logic ack_o,
28: output logic [DataWidth-1:0] rd_data_o,
29: output logic init_busy_o
30: );
31:
32: // Emulated flash macro values
33: localparam int ReadCycles = 1;
34: localparam int ProgCycles = 50;
35: localparam int PgEraseCycles = 200;
36: localparam int BkEraseCycles = 2000;
37:
38: // Locally derived values
39: localparam int WordsPerBank = PagesPerBank * WordsPerPage;
40:
41: typedef enum logic [2:0] {
42: StReset = 'h0,
43: StInit = 'h1,
44: StIdle = 'h2,
45: StRead = 'h3,
46: StProg = 'h4,
47: StErase = 'h5
48: } state_e;
49:
50: state_e st_q, st_d;
51:
52: logic [31:0] time_cnt;
53: logic [31:0] index_cnt;
54: logic time_cnt_inc ,time_cnt_clr, time_cnt_set1;
55: logic index_cnt_inc, index_cnt_clr;
56: logic [31:0] index_limit_q, index_limit_d;
57: logic [31:0] time_limit_q, time_limit_d;
58: logic prog_pend_q, prog_pend_d;
59: logic mem_req;
60: logic mem_wr;
61: logic [AddrW-1:0] mem_addr;
62: logic [DataWidth-1:0] held_rdata;
63: logic [DataWidth-1:0] held_wdata;
64: logic [DataWidth-1:0] mem_wdata;
65: logic hold_cmd;
66: logic [AddrW-1:0] held_addr;
67:
68: // insert a fifo here to break the large fanout from inputs to memories on reads
69: logic rd_q;
70: logic [AddrW-1:0] addr_q;
71:
72: prim_fifo_sync #(
73: .Width (AddrW),
74: .Pass (0),
75: .Depth (2)
76: ) i_slice (
77: .clk_i,
78: .rst_ni,
79: .clr_i (1'b0),
80: .wvalid (rd_i),
81: .wready (),
82: .wdata (addr_i),
83: .depth (),
84: .rvalid (rd_q),
85: .rready (hold_cmd), //whenver command is held, pop
86: .rdata (addr_q)
87: );
88:
89:
90: always_ff @(posedge clk_i or negedge rst_ni) begin
91: if (!rst_ni) st_q <= StReset;
92: else st_q <= st_d;
93: end
94:
95: always_ff @(posedge clk_i or negedge rst_ni) begin
96: if (!rst_ni) begin
97: held_addr <= '0;
98: held_wdata <= '0;
99: end else if (hold_cmd) begin
100: held_addr <= rd_q ? addr_q : addr_i;
101: held_wdata <= prog_data_i;
102: end
103: end
104:
105: always_ff @(posedge clk_i or negedge rst_ni) begin
106: if (!rst_ni) begin
107: time_limit_q <= 32'h0;
108: index_limit_q <= 32'h0;
109: prog_pend_q <= 1'h0;
110: end else begin
111: time_limit_q <= time_limit_d;
112: index_limit_q <= index_limit_d;
113: prog_pend_q <= prog_pend_d;
114: end
115: end
116:
117: // prog_pend_q is necessary to emulate flash behavior that a bit written to 0 cannot be written
118: // back to 1 without an erase
119: always_ff @(posedge clk_i or negedge rst_ni) begin
120: if (!rst_ni) begin
121: time_cnt <= 32'h0;
122: index_cnt <= 32'h0;
123: held_rdata <= 'h0;
124: end else begin
125: if (time_cnt_inc) time_cnt <= time_cnt + 1'b1;
126: else if (time_cnt_set1) time_cnt <= 32'h1;
127: else if (time_cnt_clr) time_cnt <= 32'h0;
128:
129: if (index_cnt_inc) index_cnt <= index_cnt + 1'b1;
130: else if (index_cnt_clr) index_cnt <= 32'h0;
131:
132: if (prog_pend_q) held_rdata <= rd_data_o;
133:
134: end
135: end
136:
137:
138: always_comb begin
139: // state
140: st_d = st_q;
141:
142: // internally consumed signals
143: index_limit_d = index_limit_q;
144: time_limit_d = time_limit_q;
145: prog_pend_d = prog_pend_q;
146: mem_req = 'h0;
147: mem_wr = 'h0;
148: mem_addr = 'h0;
149: mem_wdata = 'h0;
150: time_cnt_inc = 1'h0;
151: time_cnt_clr = 1'h0;
152: time_cnt_set1 = 1'h0;
153: index_cnt_inc = 1'h0;
154: index_cnt_clr = 1'h0;
155: hold_cmd = 1'h0;
156:
157: // i/o
158: init_busy_o = 1'h0;
159: ack_o = 1'h0;
160:
161: unique case (st_q)
162: StReset: begin
163: init_busy_o = 1'h1;
164: st_d = StInit;
165: end
166: // Emulate flash power up to all 1's
167: // This implies this flash will not survive a reset
168: // Might need a different RESET for FPGA purposes
169: StInit: begin
170: init_busy_o = 1'h1;
171: if (index_cnt < WordsPerBank && !SkipInit) begin
172: st_d = StInit;
173: index_cnt_inc = 1'b1;
174: mem_req = 1'h0;
175: mem_wr = 1'h0;
176: mem_addr = index_cnt[AddrW-1:0];
177: mem_wdata = {DataWidth{1'b1}};
178: end else begin
179: st_d = StIdle;
180: index_cnt_clr = 1'b1;
181: end
182: end
183: StIdle: begin
184: if (rd_q) begin
185: // reads begin immediately
186: hold_cmd = 1'b1;
187: mem_addr = addr_q;
188: mem_req = 1'b1;
189: time_cnt_inc = 1'b1;
190: st_d = StRead;
191: end else if (prog_i) begin
192: hold_cmd = 1'b1;
193: st_d = StRead;
194: prog_pend_d = 1'b1;
195: end else if (pg_erase_i) begin
196: hold_cmd = 1'b1;
197: st_d = StErase;
198: index_limit_d = WordsPerPage;
199: time_limit_d = PgEraseCycles;
200: end else if (bk_erase_i) begin
201: hold_cmd = 1'b1;
202: st_d = StErase;
203: index_limit_d = WordsPerBank;
204: time_limit_d = BkEraseCycles;
205: end
206: end
207: StRead: begin
208: mem_addr = held_addr;
209: if (time_cnt < ReadCycles) begin
210: mem_req = 1'b1;
211: time_cnt_inc = 1'b1;
212: end else if (!prog_pend_q) begin
213: ack_o = 1'b1; //finish up transaction
214:
215: // if another request already pending
216: if (rd_q) begin
217: hold_cmd = 1'b1;
218: mem_addr = addr_q;
219: mem_req = 1'b1;
220: time_cnt_set1 = 1'b1;
221: st_d = StRead;
222: end else begin
223: time_cnt_clr = 1'b1;
224: st_d = StIdle;
225: end
226: end else if (prog_pend_q) begin
227: // this is the read performed before a program operation
228: prog_pend_d = 1'b0;
229: time_cnt_clr = 1'b1;
230: st_d = StProg;
231: end
232: end
233: StProg: begin
234: mem_addr = held_addr;
235:
236: // if data is already 0, cannot program to 1 without erase
237: mem_wdata = held_wdata & held_rdata;
238: if (time_cnt < ProgCycles) begin
239: mem_req = 1'b1;
240: mem_wr = 1'b1;
241: time_cnt_inc = 1'b1;
242: end else begin
243: st_d = StIdle;
244: ack_o = 1'b1;
245: time_cnt_clr = 1'b1;
246: end
247: end
248: StErase: begin
249: // Actual erasing of the page
250: if (index_cnt < index_limit_q || time_cnt < time_limit_q) begin
251: mem_req = 1'b1;
252: mem_wr = 1'b1;
253: mem_wdata = {DataWidth{1'b1}};
254:
255: mem_addr = held_addr + index_cnt[AddrW-1:0];
256: time_cnt_inc = (time_cnt < time_limit_q);
257: index_cnt_inc = (index_cnt < index_limit_q);
258: end else begin
259: st_d = StIdle;
260: ack_o = 1'b1;
261: time_cnt_clr = 1'b1;
262: index_cnt_clr = 1'b1;
263: end
264: end
265: default: begin
266: st_d = StIdle;
267: end
268: endcase // unique case (st_q)
269: end // always_comb
270:
271: prim_ram_1p #(
272: .Width(DataWidth),
273: .Depth(WordsPerBank),
274: .DataBitsPerMask(DataWidth)
275: ) u_mem (
276: .clk_i,
277: .req_i (mem_req),
278: .write_i (mem_wr),
279: .addr_i (mem_addr),
280: .wdata_i (mem_wdata),
281: .wmask_i ({DataWidth{1'b1}}),
282: .rdata_o (rd_data_o)
283: );
284:
285: endmodule // prim_generic_flash
286: