hw/ip/prim_generic/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 req_i,
22: input host_req_i,
23: input [AddrW-1:0] host_addr_i,
24: input rd_i,
25: input prog_i,
26: input pg_erase_i,
27: input bk_erase_i,
28: input [AddrW-1:0] addr_i,
29: input [DataWidth-1:0] prog_data_i,
30: output logic host_req_rdy_o,
31: output logic host_req_done_o,
32: output logic rd_done_o,
33: output logic prog_done_o,
34: output logic erase_done_o,
35: output logic [DataWidth-1:0] rd_data_o,
36: output logic init_busy_o
37: );
38:
39: // Emulated flash macro values
40: localparam int ReadCycles = 1;
41: localparam int ProgCycles = 50;
42: localparam int PgEraseCycles = 200;
43: localparam int BkEraseCycles = 2000;
44:
45: // Locally derived values
46: localparam int WordsPerBank = PagesPerBank * WordsPerPage;
47:
48: typedef enum logic [2:0] {
49: StReset = 'h0,
50: StInit = 'h1,
51: StIdle = 'h2,
52: StHostRead = 'h3,
53: StRead = 'h4,
54: StProg = 'h5,
55: StErase = 'h6
56: } state_e;
57:
58: state_e st_next, st;
59:
60: logic [31:0] time_cnt;
61: logic [31:0] index_cnt;
62: logic time_cnt_inc ,time_cnt_clr, time_cnt_set1;
63: logic index_cnt_inc, index_cnt_clr;
64: logic [31:0] index_limit, index_limit_next;
65: logic [31:0] time_limit, time_limit_next;
66: logic prog_pend, prog_pend_next;
67: logic mem_req;
68: logic mem_wr;
69: logic [AddrW-1:0] mem_addr;
70: logic [DataWidth-1:0] held_data;
71: logic [DataWidth-1:0] mem_wdata;
72: logic hold_rd_cmd;
73: logic [AddrW-1:0] held_rd_addr;
74:
75: always_ff @(posedge clk_i or negedge rst_ni) begin
76: if (!rst_ni) st <= StReset;
77: else st <= st_next;
78: end
79:
80: always_ff @(posedge clk_i or negedge rst_ni) begin
81: if (!rst_ni) held_rd_addr <= '0;
82: else if (hold_rd_cmd) held_rd_addr <= host_addr_i;
83: end
84:
85: // prog_pend is necessary to emulate flash behavior that a bit written to 0 cannot be written
86: // back to 1 without an erase
87: always_ff @(posedge clk_i or negedge rst_ni) begin
88: if (!rst_ni) begin
89: time_cnt <= 32'h0;
90: index_cnt <= 32'h0;
91: time_limit <= 32'h0;
92: index_limit <= 32'h0;
93: held_data <= 'h0;
94: prog_pend <= 1'h0;
95: end else begin
96:
97: time_limit <= time_limit_next;
98: index_limit <= index_limit_next;
99: prog_pend <= prog_pend_next;
100:
101: if (time_cnt_inc) time_cnt <= time_cnt + 1'b1;
102: else if (time_cnt_set1) time_cnt <= 32'h1;
103: else if (time_cnt_clr) time_cnt <= 32'h0;
104:
105: if (index_cnt_inc) index_cnt <= index_cnt + 1'b1;
106: else if (index_cnt_clr) index_cnt <= 32'h0;
107:
108: if (prog_pend) held_data <= rd_data_o;
109:
110: end
111: end
112:
113:
114: always_comb begin
115: st_next = st;
116: index_limit_next = index_limit;
117: time_limit_next = time_limit;
118: prog_pend_next = prog_pend;
119: mem_req = 'h0;
120: mem_wr = 'h0;
121: mem_addr = 'h0;
122: mem_wdata = 'h0;
123: time_cnt_inc = 1'h0;
124: time_cnt_clr = 1'h0;
125: time_cnt_set1 = 1'h0;
126: index_cnt_inc = 1'h0;
127: index_cnt_clr = 1'h0;
128: rd_done_o = 1'h0;
129: prog_done_o = 1'h0;
130: erase_done_o = 1'h0;
131: init_busy_o = 1'h0;
132: host_req_rdy_o = 1'h1;
133: host_req_done_o = 1'h0;
134: hold_rd_cmd = 1'h0;
135:
136: unique case (st)
137: StReset: begin
138: host_req_rdy_o = 1'b0;
139: init_busy_o = 1'h1;
140: st_next = StInit;
141: end
142: // Emulate flash power up to all 1's
143: // This implies this flash will not survive a reset
144: // Might need a different RESET for FPGA purposes
145: StInit: begin
146: host_req_rdy_o = 1'b0;
147: init_busy_o = 1'h1;
148: if (index_cnt < WordsPerBank && !SkipInit) begin
149: st_next = StInit;
150: index_cnt_inc = 1'b1;
151: mem_req = 1'h0;
152: mem_wr = 1'h0;
153: mem_addr = index_cnt[AddrW-1:0];
154: mem_wdata = {DataWidth{1'b1}};
155: end else begin
156: st_next = StIdle;
157: index_cnt_clr = 1'b1;
158: end
159: end
160: StIdle: begin
161: // host reads will always take priority over controller operations. However ongoing
162: // controller operations will not be interrupted
163: if (host_req_i) begin
164: // reads begin immediately
165: hold_rd_cmd = 1'b1;
166: mem_addr = host_addr_i;
167: mem_req = 1'b1;
168: time_cnt_inc = 1'b1;
169: st_next = StHostRead;
170: end else if (req_i && rd_i) begin
171: st_next = StRead;
172: end else if (req_i && prog_i) begin
173: st_next = StRead;
174: prog_pend_next = 1'b1;
175: end else if (req_i && pg_erase_i) begin
176: st_next = StErase;
177: index_limit_next = WordsPerPage;
178: time_limit_next = PgEraseCycles;
179: end else if (req_i && bk_erase_i) begin
180: st_next = StErase;
181: index_limit_next = WordsPerBank;
182: time_limit_next = BkEraseCycles;
183: end
184: end
185: StHostRead: begin
186: mem_addr = held_rd_addr;
187: if (time_cnt < ReadCycles) begin
188: mem_req = 1'b1;
189: time_cnt_inc = 1'b1;
190: host_req_rdy_o = 1'b0;
191: end else begin
192: host_req_done_o = 1'b1; //finish up transaction
193:
194: // if another request already pending
195: if (host_req_i) begin
196: hold_rd_cmd = 1'b1;
197: mem_addr = host_addr_i;
198: mem_req = 1'b1;
199: time_cnt_set1 = 1'b1;
200: st_next = StHostRead;
201: end else begin
202: time_cnt_clr = 1'b1;
203: st_next = StIdle;
204: end
205: end
206: end
207: StRead: begin
208: host_req_rdy_o = 1'b0;
209: mem_addr = addr_i;
210: if (time_cnt < ReadCycles) begin
211: mem_req = 1'b1;
212: time_cnt_inc = 1'b1;
213: end else begin
214: prog_pend_next = 1'b0;
215: rd_done_o = 1'b1;
216: time_cnt_clr = 1'b1;
217: st_next = prog_pend ? StProg : StIdle;
218: end
219: end
220: StProg: begin
221: host_req_rdy_o = 1'b0;
222: mem_addr = addr_i;
223:
224: // if data is already 0, cannot program to 1 without erase
225: mem_wdata = prog_data_i & held_data;
226: if (time_cnt < ProgCycles) begin
227: mem_req = 1'b1;
228: mem_wr = 1'b1;
229: time_cnt_inc = 1'b1;
230: end else begin
231: st_next = StIdle;
232: prog_done_o = 1'b1;
233: time_cnt_clr = 1'b1;
234: end
235: end
236: StErase: begin
237: host_req_rdy_o = 1'b0;
238:
239: // Actual erasing of the page
240: if (index_cnt < index_limit || time_cnt < time_limit) begin
241: mem_req = 1'b1;
242: mem_wr = 1'b1;
243: mem_wdata = {DataWidth{1'b1}};
244:
245: mem_addr = addr_i + index_cnt[AddrW-1:0];
246: time_cnt_inc = (time_cnt < time_limit);
247: index_cnt_inc = (index_cnt < index_limit);
248: end else begin
249: st_next = StIdle;
250: erase_done_o = 1'b1;
251: time_cnt_clr = 1'b1;
252: index_cnt_clr = 1'b1;
253: end
254: end
255: default: begin
256: host_req_rdy_o = 1'b0;
257: st_next = StIdle;
258: end
259: endcase // unique case (st)
260: end // always_comb
261:
262: prim_ram_1p #(
263: .Width(DataWidth),
264: .Depth(WordsPerBank),
265: .DataBitsPerMask(DataWidth)
266: ) u_mem (
267: .clk_i,
268: .rst_ni,
269: .req_i (mem_req),
270: .write_i (mem_wr),
271: .addr_i (mem_addr),
272: .wdata_i (mem_wdata),
273: .wmask_i ({DataWidth{1'b1}}),
274: .rvalid_o (),
275: .rdata_o (rd_data_o)
276: );
277:
278:
279:
280: endmodule // prim_generic_flash
281: