hw/ip/flash_ctrl/rtl/flash_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: // Faux Flash Controller Module
6: //
7: //
8:
9: module flash_ctrl (
10: input clk_i,
11: input rst_ni,
12:
13: // Bus Interface
14: input tlul_pkg::tl_h2d_t tl_i,
15: output tlul_pkg::tl_d2h_t tl_o,
16:
17: // Flash Interface
18: input flash_ctrl_pkg::flash_m2c_t flash_i,
19: output flash_ctrl_pkg::flash_c2m_t flash_o,
20:
21: // Interrupts
22: output logic intr_prog_empty_o, // Program fifo is empty
23: output logic intr_prog_lvl_o, // Program fifo is empty
24: output logic intr_rd_full_o, // Read fifo is full
25: output logic intr_rd_lvl_o, // Read fifo is full
26: output logic intr_op_done_o, // Requested flash operation (wr/erase) done
27: output logic intr_op_error_o // Requested flash operation (wr/erase) done
28: );
29:
30: import flash_ctrl_pkg::*;
31: import flash_ctrl_reg_pkg::*;
32:
33: localparam int NumBanks = top_pkg::FLASH_BANKS;
34: localparam int PagesPerBank = top_pkg::FLASH_PAGES_PER_BANK;
35: localparam int WordsPerPage = top_pkg::FLASH_WORDS_PER_PAGE;
36: localparam int BankW = top_pkg::FLASH_BKW;
37: localparam int PageW = top_pkg::FLASH_PGW;
38: localparam int WordW = top_pkg::FLASH_WDW;
39: localparam int AllPagesW = BankW + PageW;
40: localparam int AddrW = top_pkg::FLASH_AW;
41: localparam int DataWidth = top_pkg::FLASH_DW;
42: localparam int DataBitWidth = $clog2(DataWidth/8);
43: localparam int EraseBitWidth = $bits(flash_erase_op_e);
44: localparam int FifoDepth = 16;
45: localparam int FifoDepthW = $clog2(FifoDepth+1);
46: localparam int MpRegions = 8;
47:
48:
49: flash_ctrl_reg2hw_t reg2hw;
50: flash_ctrl_hw2reg_t hw2reg;
51:
52: tlul_pkg::tl_h2d_t tl_fifo_h2d [2];
53: tlul_pkg::tl_d2h_t tl_fifo_d2h [2];
54:
55: // Register module
56: flash_ctrl_reg_top u_reg (
57: .clk_i,
58: .rst_ni,
59:
60: .tl_i,
61: .tl_o,
62:
63: .tl_win_o (tl_fifo_h2d),
64: .tl_win_i (tl_fifo_d2h),
65:
66: .reg2hw,
67: .hw2reg,
68:
69: .devmode_i (1'b1)
70: );
71:
72: // FIFO Connections
73: logic prog_fifo_wready;
74: logic prog_fifo_rvalid;
75: logic prog_fifo_req;
76: logic prog_fifo_wen;
77: logic prog_fifo_ren;
78: logic [DataWidth-1:0] prog_fifo_wdata;
79: logic [DataWidth-1:0] prog_fifo_rdata;
80: logic [FifoDepthW-1:0] prog_fifo_depth;
81: logic rd_fifo_wready;
82: logic rd_fifo_rvalid;
83: logic rd_fifo_wen;
84: logic rd_fifo_ren;
85: logic [DataWidth-1:0] rd_fifo_wdata;
86: logic [DataWidth-1:0] rd_fifo_rdata;
87: logic [FifoDepthW-1:0] rd_fifo_depth;
88:
89: // Program Control Connections
90: logic prog_flash_req;
91: logic prog_flash_ovfl;
92: logic [AddrW-1:0] prog_flash_addr;
93:
94: // Read Control Connections
95: logic rd_flash_req;
96: logic rd_flash_ovfl;
97: logic [AddrW-1:0] rd_flash_addr;
98:
99: // Erase Control Connections
100: logic erase_flash_req;
101: logic [AddrW-1:0] erase_flash_addr;
102: logic [EraseBitWidth-1:0] erase_flash_type;
103:
104: // Done / Error signaling from ctrl modules
105: logic [2:0] ctrl_done, ctrl_err;
106:
107: // Flash Memory Protection Connections
108: logic flash_req;
109: logic flash_rd_done, flash_prog_done, flash_erase_done;
110: logic flash_error;
111: logic [AddrW-1:0] flash_addr;
112: logic [DataWidth-1:0] flash_prog_data;
113: logic [DataWidth-1:0] flash_rd_data;
114: logic init_busy;
115: logic rd_op;
116: logic prog_op;
117: logic erase_op;
118: logic [AllPagesW-1:0] err_page;
119: logic [BankW-1:0] err_bank;
120:
121: assign rd_op = reg2hw.control.op.q == FlashRead;
122: assign prog_op = reg2hw.control.op.q == FlashProg;
123: assign erase_op = reg2hw.control.op.q == FlashErase;
124:
125: // Program FIFO
126: // Since the program and read FIFOs are never used at the same time, it should really be one
127: // FIFO with muxed inputs and outputs. This should be addressed once the flash integration
128: // strategy has been identified
129: tlul_adapter_sram #(
130: .SramAw(1), //address unused
131: .SramDw(DataWidth),
132: .ByteAccess(0), //flash may not support byte access
133: .ErrOnRead(1) //reads not supported
134: ) u_to_prog_fifo (
135: .clk_i,
136: .rst_ni,
137: .tl_i (tl_fifo_h2d[0]),
138: .tl_o (tl_fifo_d2h[0]),
139: .req_o (prog_fifo_req),
140: .gnt_i (prog_fifo_wready),
141: .we_o (prog_fifo_wen),
142: .addr_o (),
143: .wmask_o (),
144: .wdata_o (prog_fifo_wdata),
145: .rdata_i (DataWidth'(0)),
146: .rvalid_i (1'b0),
147: .rerror_i (2'b0)
148: );
149:
150: prim_fifo_sync #(
151: .Width(DataWidth),
152: .Depth(FifoDepth)
153: ) u_prog_fifo (
154: .clk_i,
155: .rst_ni (rst_ni),
156: .clr_i (reg2hw.control.fifo_rst.q),
157: .wvalid (prog_fifo_req & prog_fifo_wen),
158: .wready (prog_fifo_wready),
159: .wdata (prog_fifo_wdata),
160: .depth (prog_fifo_depth),
161: .rvalid (prog_fifo_rvalid),
162: .rready (prog_fifo_ren),
163: .rdata (prog_fifo_rdata)
164: );
165:
166: // Program handler is consumer of prog_fifo
167: flash_prog_ctrl #(
168: .DataW(DataWidth),
169: .AddrW(AddrW)
170: ) u_flash_prog_ctrl (
171: .clk_i,
172: .rst_ni,
173:
174: // Software Interface
175: .op_start_i (reg2hw.control.start.q & prog_op),
176: .op_num_words_i (reg2hw.control.num.q),
177: .op_done_o (ctrl_done[0]),
178: .op_err_o (ctrl_err[0]),
179: .op_addr_i (reg2hw.addr.q[DataBitWidth +: AddrW]),
180:
181: // FIFO Interface
182: .data_i (prog_fifo_rdata),
183: .data_rdy_i (prog_fifo_rvalid),
184: .data_rd_o (prog_fifo_ren),
185:
186: // Flash Macro Interface
187: .flash_req_o (prog_flash_req),
188: .flash_addr_o (prog_flash_addr),
189: .flash_ovfl_o (prog_flash_ovfl),
190: .flash_data_o (flash_prog_data),
191: .flash_done_i (flash_prog_done),
192: .flash_error_i (flash_error)
193: );
194:
195: // Read FIFO
196: logic adapter_rvalid;
197: always_ff @(posedge clk_i or negedge rst_ni) begin
198: if (!rst_ni) begin
199: adapter_rvalid <= 1'b0;
200: end else begin
201: adapter_rvalid <= rd_fifo_ren && rd_fifo_rvalid;
202: end
203: end
204:
205: tlul_adapter_sram #(
206: .SramAw(1), //address unused
207: .SramDw(DataWidth),
208: .ByteAccess(0), //flash may not support byte access
209: .ErrOnWrite(1) //writes not supported
210: ) u_to_rd_fifo (
211: .clk_i,
212: .rst_ni,
213: .tl_i (tl_fifo_h2d[1]),
214: .tl_o (tl_fifo_d2h[1]),
215: .req_o (rd_fifo_ren),
216: .gnt_i (rd_fifo_rvalid),
217: .we_o (),
218: .addr_o (),
219: .wmask_o (),
220: .wdata_o (),
221: .rdata_i (rd_fifo_rdata),
222: .rvalid_i (adapter_rvalid),
223: .rerror_i (2'b0)
224: );
225:
226: prim_fifo_sync #(
227: .Width(DataWidth),
228: .Depth(FifoDepth)
229: ) u_rd_fifo (
230: .clk_i,
231: .rst_ni (rst_ni),
232: .clr_i (reg2hw.control.fifo_rst.q),
233: .wvalid (rd_fifo_wen),
234: .wready (rd_fifo_wready),
235: .wdata (rd_fifo_wdata),
236: .depth (rd_fifo_depth),
237: .rvalid (rd_fifo_rvalid),
238: //adapter_rvalid is used here because adapter_sram does not accept data the same cycle.
239: //It expects an sram like interface where data arrives during the next cycle
240: .rready (adapter_rvalid),
241: .rdata (rd_fifo_rdata)
242: );
243:
244: // Read handler is consumer of rd_fifo
245: flash_rd_ctrl #(
246: .DataW(DataWidth),
247: .AddrW(AddrW)
248: ) u_flash_rd_ctrl (
249: .clk_i,
250: .rst_ni,
251:
252: // Software Interface
253: .op_start_i (reg2hw.control.start.q & rd_op),
254: .op_num_words_i (reg2hw.control.num.q),
255: .op_done_o (ctrl_done[1]),
256: .op_err_o (ctrl_err[1]),
257: .op_addr_i (reg2hw.addr.q[DataBitWidth +: AddrW]),
258:
259: // FIFO Interface
260: .data_rdy_i (rd_fifo_wready),
261: .data_o (rd_fifo_wdata),
262: .data_wr_o (rd_fifo_wen),
263:
264: // Flash Macro Interface
265: .flash_req_o (rd_flash_req),
266: .flash_addr_o (rd_flash_addr),
267: .flash_ovfl_o (rd_flash_ovfl),
268: .flash_data_i (flash_rd_data),
269: .flash_done_i (flash_rd_done),
270: .flash_error_i (flash_error)
271: );
272:
273: // Erase handler does not consume fifo
274: flash_erase_ctrl #(
275: .AddrW(AddrW),
276: .PagesPerBank(PagesPerBank),
277: .WordsPerPage(WordsPerPage),
278: .EraseBitWidth(EraseBitWidth)
279: ) u_flash_erase_ctrl (
280: // Software Interface
281: .op_start_i (reg2hw.control.start.q & erase_op),
282: .op_type_i (reg2hw.control.erase_sel.q),
283: .op_done_o (ctrl_done[2]),
284: .op_err_o (ctrl_err[2]),
285: .op_addr_i (reg2hw.addr.q[DataBitWidth +: AddrW]),
286:
287: // Flash Macro Interface
288: .flash_req_o (erase_flash_req),
289: .flash_addr_o (erase_flash_addr),
290: .flash_op_o (erase_flash_type),
291: .flash_done_i (flash_erase_done),
292: .flash_error_i (flash_error)
293: );
294:
295: // Final muxing to flash macro module
296: always_comb begin
297: unique case (reg2hw.control.op.q)
298: FlashRead: begin
299: flash_req = rd_flash_req;
300: flash_addr = rd_flash_addr;
301: end
302: FlashProg: begin
303: flash_req = prog_flash_req;
304: flash_addr = prog_flash_addr;
305: end
306: FlashErase: begin
307: flash_req = erase_flash_req;
308: flash_addr = erase_flash_addr;
309: end
310: default: begin
311: flash_req = 1'b0;
312: flash_addr = '0;
313: end
314: endcase // unique case (flash_op_e'(reg2hw.control.op.q))
315: end
316:
317: // extra region is the default region
318: flash_ctrl_reg2hw_mp_region_cfg_mreg_t [MpRegions:0] region_cfgs;
319:
320: assign region_cfgs[MpRegions-1:0] = reg2hw.mp_region_cfg[MpRegions-1:0];
321:
322: //last region
323: assign region_cfgs[MpRegions].base.q = '0;
324: assign region_cfgs[MpRegions].size.q = {AllPagesW{1'b1}};
325: assign region_cfgs[MpRegions].en.q = 1'b1;
326: assign region_cfgs[MpRegions].rd_en.q = reg2hw.default_region.rd_en.q;
327: assign region_cfgs[MpRegions].prog_en.q = reg2hw.default_region.prog_en.q;
328: assign region_cfgs[MpRegions].erase_en.q = reg2hw.default_region.erase_en.q;
329:
330: // Flash memory protection
331: flash_mp #(
332: .MpRegions(MpRegions),
333: .NumBanks(NumBanks),
334: .AllPagesW(AllPagesW)
335: ) u_flash_mp (
336: .clk_i,
337: .rst_ni,
338:
339: // sw configuration
340: .region_cfgs_i(region_cfgs),
341: .bank_cfgs_i(reg2hw.mp_bank_cfg),
342:
343: // read / prog / erase controls
344: .req_i(flash_req),
345: .req_addr_i(flash_addr[WordW +: AllPagesW]),
346: .addr_ovfl_i(rd_flash_ovfl | prog_flash_ovfl),
347: .req_bk_i(flash_addr[WordW + PageW +: BankW]),
348: .rd_i(rd_op),
349: .prog_i(prog_op),
350: .pg_erase_i(erase_op & (erase_flash_type == PageErase)),
351: .bk_erase_i(erase_op & (erase_flash_type == BankErase)),
352: .rd_done_o(flash_rd_done),
353: .prog_done_o(flash_prog_done),
354: .erase_done_o(flash_erase_done),
355: .error_o(flash_error),
356: .err_addr_o(err_page),
357: .err_bank_o(err_bank),
358:
359: // flash phy interface
360: .req_o(flash_o.req),
361: .rd_o(flash_o.rd),
362: .prog_o(flash_o.prog),
363: .pg_erase_o(flash_o.pg_erase),
364: .bk_erase_o(flash_o.bk_erase),
365: .rd_done_i(flash_i.rd_done),
366: .prog_done_i(flash_i.prog_done),
367: .erase_done_i(flash_i.erase_done)
368: );
369:
370:
371: assign hw2reg.op_status.done.d = 1'b1;
372: assign hw2reg.op_status.done.de = |ctrl_done;
373: assign hw2reg.op_status.err.d = 1'b1;
374: assign hw2reg.op_status.err.de = |ctrl_err;
375: assign hw2reg.status.rd_full.d = ~rd_fifo_wready;
376: assign hw2reg.status.rd_empty.d = ~rd_fifo_rvalid;
377: assign hw2reg.status.prog_full.d = ~prog_fifo_wready;
378: assign hw2reg.status.prog_empty.d = ~prog_fifo_rvalid;
379: assign hw2reg.status.init_wip.d = init_busy;
380: assign hw2reg.status.error_page.d = err_page;
381: assign hw2reg.status.error_bank.d = err_bank;
382: assign hw2reg.control.start.d = 1'b0;
383: assign hw2reg.control.start.de = |ctrl_done;
384:
385: // Flash Interface
386: assign flash_o.addr = flash_addr;
387: assign flash_o.prog_data = flash_prog_data;
388: assign flash_rd_data = flash_i.rd_data;
389: assign init_busy = flash_i.init_busy;
390:
391: // Interrupts
392: // Generate edge triggered signals for sources that are level
393: logic [3:0] intr_src;
394: logic [3:0] intr_src_q;
395: logic [3:0] intr_assert;
396:
397: assign intr_src = { ~prog_fifo_rvalid,
398: reg2hw.fifo_lvl.prog.q == prog_fifo_depth,
399: ~rd_fifo_wready,
400: reg2hw.fifo_lvl.rd.q == rd_fifo_depth
401: };
402:
403: always_ff @(posedge clk_i or negedge rst_ni) begin
404: if (!rst_ni) begin
405: intr_src_q <= 'h0;
406: end else begin
407: intr_src_q <= intr_src;
408: end
409: end
410:
411: assign intr_assert = ~intr_src_q & intr_src;
412:
413:
414: assign intr_prog_empty_o = reg2hw.intr_enable.prog_empty.q & reg2hw.intr_state.prog_empty.q;
415: assign intr_prog_lvl_o = reg2hw.intr_enable.prog_lvl.q & reg2hw.intr_state.prog_lvl.q;
416: assign intr_rd_full_o = reg2hw.intr_enable.rd_full.q & reg2hw.intr_state.rd_full.q;
417: assign intr_rd_lvl_o = reg2hw.intr_enable.rd_lvl.q & reg2hw.intr_state.rd_lvl.q;
418: assign intr_op_done_o = reg2hw.intr_enable.op_done.q & reg2hw.intr_state.op_done.q;
419: assign intr_op_error_o = reg2hw.intr_enable.op_error.q & reg2hw.intr_state.op_error.q;
420:
421: assign hw2reg.intr_state.prog_empty.d = 1'b1;
422: assign hw2reg.intr_state.prog_empty.de = intr_assert[3] |
423: (reg2hw.intr_test.prog_empty.qe &
424: reg2hw.intr_test.prog_empty.q);
425:
426: assign hw2reg.intr_state.prog_lvl.d = 1'b1;
427: assign hw2reg.intr_state.prog_lvl.de = intr_assert[2] |
428: (reg2hw.intr_test.prog_lvl.qe &
429: reg2hw.intr_test.prog_lvl.q);
430:
431: assign hw2reg.intr_state.rd_full.d = 1'b1;
432: assign hw2reg.intr_state.rd_full.de = intr_assert[1] |
433: (reg2hw.intr_test.rd_full.qe &
434: reg2hw.intr_test.rd_full.q);
435:
436: assign hw2reg.intr_state.rd_lvl.d = 1'b1;
437: assign hw2reg.intr_state.rd_lvl.de = intr_assert[0] |
438: (reg2hw.intr_test.rd_lvl.qe &
439: reg2hw.intr_test.rd_lvl.q);
440:
441:
442: assign hw2reg.intr_state.op_done.d = 1'b1;
443: assign hw2reg.intr_state.op_done.de = |ctrl_done |
444: (reg2hw.intr_test.op_done.qe &
445: reg2hw.intr_test.op_done.q);
446:
447: assign hw2reg.intr_state.op_error.d = 1'b1;
448: assign hw2reg.intr_state.op_error.de = |ctrl_err |
449: (reg2hw.intr_test.op_error.qe &
450: reg2hw.intr_test.op_error.q);
451:
452:
453:
454: // Unused bits
455: logic [DataBitWidth-1:0] unused_byte_sel;
456: logic [31-AddrW:0] unused_higher_addr_bits;
457: logic [31:0] unused_scratch;
458:
459:
460: // Unused signals
461: assign unused_byte_sel = reg2hw.addr.q[DataBitWidth-1:0];
462: assign unused_higher_addr_bits = reg2hw.addr.q[31:AddrW];
463: assign unused_scratch = reg2hw.scratch;
464:
465:
466: // Assertions
467:
468: `ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid, clk_i, !rst_ni)
469: `ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready, clk_i, !rst_ni)
470: `ASSERT_KNOWN(FlashKnownO_A, {flash_o.req, flash_o.rd, flash_o.prog, flash_o.pg_erase,
471: flash_o.bk_erase}, clk_i, !rst_ni)
472: `ASSERT_VALID_DATA(FlashAddrKnown_A, flash_o.req, flash_o.addr, clk_i, !rst_ni)
473: `ASSERT_VALID_DATA(FlashProgKnown_A, flash_o.prog & flash_o.req, flash_o.prog_data,
474: clk_i, !rst_ni)
475: `ASSERT_KNOWN(IntrProgEmptyKnownO_A, intr_prog_empty_o, clk_i, !rst_ni)
476: `ASSERT_KNOWN(IntrProgLvlKnownO_A, intr_prog_lvl_o, clk_i, !rst_ni)
477: `ASSERT_KNOWN(IntrProgRdFullKnownO_A, intr_rd_full_o, clk_i, !rst_ni)
478: `ASSERT_KNOWN(IntrRdLvlKnownO_A, intr_rd_lvl_o, clk_i, !rst_ni)
479: `ASSERT_KNOWN(IntrOpDoneKnownO_A, intr_op_done_o, clk_i, !rst_ni)
480: `ASSERT_KNOWN(IntrOpErrorKnownO_A, intr_op_error_o, clk_i, !rst_ni)
481:
482: endmodule
483: