hw/ip/flash_ctrl/rtl/flash_phy.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: // Flash Phy Module
6: //
7: //
8: // This module is an early attempt to model what a custom phy module might look like
9: // Long term, it is expected this module will split into its own entity under hw/ip
10: // with its own set of register that support technology / node specific flash settings
11: // More of those details will be worked out with future partner engagement
12:
13: module flash_phy #(
14: parameter int NumBanks = 2,
15: parameter int PagesPerBank = 256, // pages per bank
16: parameter int WordsPerPage = 256, // words per page
17: parameter int DataWidth = 32, // bits per word
18:
19: //Do not touch - Derived parameters
20: localparam int BankW = $clog2(NumBanks),
21: localparam int PageW = $clog2(PagesPerBank),
22: localparam int WordW = $clog2(WordsPerPage),
23: localparam int AddrW = BankW + PageW + WordW
24: ) (
25: input clk_i,
26: input rst_ni,
27: input host_req_i,
28: input [AddrW-1:0] host_addr_i,
29: output logic host_req_rdy_o,
30: output logic host_req_done_o,
31: output logic [DataWidth-1:0] host_rdata_o,
32: input flash_ctrl_pkg::flash_c2m_t flash_ctrl_i,
33: output flash_ctrl_pkg::flash_m2c_t flash_ctrl_o
34: );
35:
36: // Flash macro outstanding refers to how many reads we allow a macro to move ahead of an
37: // in order blocking read. Since the data cannot be returned out of order, this simply
38: // does the reads in advance and store them in a FIFO
39: localparam int FlashMacroOustanding = 1;
40: localparam int SeqFifoDepth = FlashMacroOustanding * NumBanks;
41:
42: // flash_phy forwards incoming host transactions to the appropriate bank but is not aware of
43: // any controller / host arbitration within the bank. This means it is possible for
44: // flash_phy to forward one transaction to bank N and another to bank N+1 only for bank N+1
45: // to finish its transaction first (if for example a controller operation were ongoing in bank
46: // N).
47: // This implies that even though transactions are received in-order, they can complete out of
48: // order. Thus it is the responsibility of the flash_phy to sequence the responses correctly.
49: // For banks that have finished ahead of time, it is also important to hold its output until
50: // consumed.
51:
52: // host to flash_phy interface
53: logic [BankW-1:0] host_bank_sel;
54: logic [BankW-1:0] rsp_bank_sel;
55: logic [NumBanks-1:0] host_req_rdy;
56: logic [NumBanks-1:0] host_req_done;
57: logic [NumBanks-1:0] host_rsp_avail;
58: logic [NumBanks-1:0] host_rsp_vld;
59: logic [NumBanks-1:0] host_rsp_ack;
60: logic [DataWidth-1:0] host_rsp_data [NumBanks];
61: logic seq_fifo_rdy;
62: logic seq_fifo_pending;
63:
64:
65: // flash_ctrl to flash_phy interface
66: logic [BankW-1:0] ctrl_bank_sel;
67: logic [NumBanks-1:0] rd_done;
68: logic [NumBanks-1:0] prog_done;
69: logic [NumBanks-1:0] erase_done;
70: logic [NumBanks-1:0] init_busy;
71:
72: // common interface
73: logic [DataWidth-1:0] rd_data [NumBanks];
74:
75: // select which bank each is operating on
76: assign host_bank_sel = host_req_i ? host_addr_i[PageW + WordW +: BankW] : '0;
77: assign ctrl_bank_sel = flash_ctrl_i.addr[PageW + WordW +: BankW];
78:
79: // accept transaction if bank is ready and previous response NOT pending
80: assign host_req_rdy_o = host_req_rdy[host_bank_sel] & host_rsp_avail[host_bank_sel] &
81: seq_fifo_rdy;
82:
83: assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
84: assign host_rdata_o = host_rsp_data[rsp_bank_sel];
85:
86: assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
87: assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
88: assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
89: assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
90: assign flash_ctrl_o.init_busy = |init_busy;
91:
92: // This fifo holds the expected return order
93: prim_fifo_sync #(
94: .Width (BankW),
95: .Pass (0),
96: .Depth (SeqFifoDepth)
97: ) bank_sequence_fifo (
98: .clk_i,
99: .rst_ni,
100: .clr_i (1'b0),
101: .wvalid (host_req_i & host_req_rdy_o),
102: .wready (seq_fifo_rdy),
103: .wdata (host_bank_sel),
104: .depth (),
105: .rvalid (seq_fifo_pending),
106: .rready (host_req_done_o),
107: .rdata (rsp_bank_sel)
108: );
109:
110: for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_flash_banks
111:
112: // pop if the response came from the appropriate fifo
113: assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
114:
115: prim_fifo_sync #(
116: .Width (DataWidth),
117: .Pass (1'b1),
118: .Depth (FlashMacroOustanding)
119: ) host_rsp_fifo (
120: .clk_i,
121: .rst_ni,
122: .clr_i (1'b0),
123: .wvalid (host_req_done[bank]),
124: .wready (host_rsp_avail[bank]),
125: .wdata (rd_data[bank]),
126: .depth (),
127: .rvalid (host_rsp_vld[bank]),
128: .rready (host_rsp_ack[bank]),
129: .rdata (host_rsp_data[bank])
130: );
131:
132: prim_flash #(
133: .PagesPerBank(PagesPerBank),
134: .WordsPerPage(WordsPerPage),
135: .DataWidth(DataWidth)
136: ) u_flash (
137: .clk_i,
138: .rst_ni,
139: .req_i(flash_ctrl_i.req & (ctrl_bank_sel == bank)),
140: .host_req_i(host_req_i & host_req_rdy_o & (host_bank_sel == bank)),
141: .host_addr_i(host_addr_i[0 +: PageW + WordW]),
142: .rd_i(flash_ctrl_i.rd),
143: .prog_i(flash_ctrl_i.prog),
144: .pg_erase_i(flash_ctrl_i.pg_erase),
145: .bk_erase_i(flash_ctrl_i.bk_erase),
146: .addr_i(flash_ctrl_i.addr[0 +: PageW + WordW]),
147: .prog_data_i(flash_ctrl_i.prog_data),
148: .host_req_rdy_o(host_req_rdy[bank]),
149: .host_req_done_o(host_req_done[bank]),
150: .rd_done_o(rd_done[bank]),
151: .prog_done_o(prog_done[bank]),
152: .erase_done_o(erase_done[bank]),
153: .rd_data_o(rd_data[bank]),
154: .init_busy_o(init_busy[bank])
155: );
156: end
157:
158: endmodule // flash_phy
159: