../src/lowrisc_ip_flash_ctrl_0.1/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: // Flash phy represents the top level open source wrapper for a proprietary flash
9: // module.
10: // The top level flash_phy is only responsible for dispatching transactions and
11: // correctly collecting the responses in order.
12:
13: module flash_phy import flash_ctrl_pkg::*; (
14: input clk_i,
15: input rst_ni,
16: input host_req_i,
17: input [AddrW-1:0] host_addr_i,
18: output logic host_req_rdy_o,
19: output logic host_req_done_o,
20: output logic [BusWidth-1:0] host_rdata_o,
21: input flash_ctrl_pkg::flash_req_t flash_ctrl_i,
22: output flash_ctrl_pkg::flash_rsp_t flash_ctrl_o
23: );
24:
25: // Flash macro outstanding refers to how many reads we allow a macro to move ahead of an
26: // in order blocking read. Since the data cannot be returned out of order, this simply
27: // does the reads in advance and store them in a FIFO
28: localparam int FlashMacroOustanding = 1;
29: localparam int SeqFifoDepth = FlashMacroOustanding * NumBanks;
30:
31: // flash_phy forwards incoming host transactions to the appropriate bank but is not aware of
32: // any controller / host arbitration within the bank. This means it is possible for
33: // flash_phy to forward one transaction to bank N and another to bank N+1 only for bank N+1
34: // to finish its transaction first (if for example a controller operation were ongoing in bank
35: // N).
36: // This implies that even though transactions are received in-order, they can complete out of
37: // order. Thus it is the responsibility of the flash_phy to sequence the responses correctly.
38: // For banks that have finished ahead of time, it is also important to hold its output until
39: // consumed.
40:
41: // host to flash_phy interface
42: logic [BankW-1:0] host_bank_sel;
43: logic [BankW-1:0] rsp_bank_sel;
44: logic [NumBanks-1:0] host_req_rdy;
45: logic [NumBanks-1:0] host_req_done;
46: logic [NumBanks-1:0] host_rsp_avail;
47: logic [NumBanks-1:0] host_rsp_vld;
48: logic [NumBanks-1:0] host_rsp_ack;
49: logic [BusWidth-1:0] host_rsp_data [NumBanks];
50: logic seq_fifo_rdy;
51: logic seq_fifo_pending;
52:
53:
54: // flash_ctrl to flash_phy interface
55: logic [BankW-1:0] ctrl_bank_sel;
56: logic [NumBanks-1:0] rd_done;
57: logic [NumBanks-1:0] prog_done;
58: logic [NumBanks-1:0] erase_done;
59: logic [NumBanks-1:0] init_busy;
60:
61: // common interface
62: logic [BusWidth-1:0] rd_data [NumBanks];
63:
64: // select which bank each is operating on
65: assign host_bank_sel = host_req_i ? host_addr_i[BankAddrW +: BankW] : '0;
66: assign ctrl_bank_sel = flash_ctrl_i.addr[BankAddrW +: BankW];
67:
68: // accept transaction if bank is ready and previous response NOT pending
69: assign host_req_rdy_o = host_req_rdy[host_bank_sel] & host_rsp_avail[host_bank_sel] &
70: seq_fifo_rdy;
71:
72: assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
73: assign host_rdata_o = host_rsp_data[rsp_bank_sel];
74:
75: assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
76: assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
77: assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
78: assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
79: assign flash_ctrl_o.init_busy = |init_busy;
80:
81: // This fifo holds the expected return order
82: prim_fifo_sync #(
83: .Width (BankW),
84: .Pass (0),
85: .Depth (SeqFifoDepth)
86: ) i_bank_sequence_fifo (
87: .clk_i,
88: .rst_ni,
89: .clr_i (1'b0),
90: .wvalid (host_req_i & host_req_rdy_o),
91: .wready (seq_fifo_rdy),
92: .wdata (host_bank_sel),
93: .depth (),
94: .rvalid (seq_fifo_pending),
95: .rready (host_req_done_o),
96: .rdata (rsp_bank_sel)
97: );
98:
99: for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_flash_banks
100:
101: // pop if the response came from the appropriate fifo
102: assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
103:
104: prim_fifo_sync #(
105: .Width (BusWidth),
106: .Pass (1'b1),
107: .Depth (FlashMacroOustanding)
108: ) i_host_rsp_fifo (
109: .clk_i,
110: .rst_ni,
111: .clr_i (1'b0),
112: .wvalid (host_req_done[bank]),
113: .wready (host_rsp_avail[bank]),
114: .wdata (rd_data[bank]),
115: .depth (),
116: .rvalid (host_rsp_vld[bank]),
117: .rready (host_rsp_ack[bank]),
118: .rdata (host_rsp_data[bank])
119: );
120:
121: flash_phy_core i_core (
122: .clk_i,
123: .rst_ni,
124: .req_i(flash_ctrl_i.req & (ctrl_bank_sel == bank)),
125: // host request must be suppressed if response fifo cannot hold more
126: // otherwise the flash_phy_core and flash_phy will get out of sync
127: .host_req_i(host_req_i & (host_bank_sel == bank) & host_rsp_avail[bank]),
128: .host_addr_i(host_addr_i[0 +: BankAddrW]),
129: .rd_i(flash_ctrl_i.rd),
130: .prog_i(flash_ctrl_i.prog),
131: .pg_erase_i(flash_ctrl_i.pg_erase),
132: .bk_erase_i(flash_ctrl_i.bk_erase),
133: .addr_i(flash_ctrl_i.addr[0 +: BankAddrW]),
134: .prog_data_i(flash_ctrl_i.prog_data),
135: .host_req_rdy_o(host_req_rdy[bank]),
136: .host_req_done_o(host_req_done[bank]),
137: .rd_done_o(rd_done[bank]),
138: .prog_done_o(prog_done[bank]),
139: .erase_done_o(erase_done[bank]),
140: .rd_data_o(rd_data[bank]),
141: .init_busy_o(init_busy[bank])
142: );
143: end
144:
145: endmodule // flash_phy
146: