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