../src/lowrisc_ip_flash_ctrl_0.1/rtl/flash_phy_core.sv Cov: 98.5%
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 Core Module
6: //
7: //
8: // This module wraps every single flash bank and contains most of the region attribute,
9: // scramble, ECC, security and arbitration logic.
10: // Most of the items are TODO, at the moment only arbitration logic exists.
11:
12: module flash_phy_core import flash_phy_pkg::*; #(
13: parameter bit SkipInit = 1 // this is an option to reset flash to all F's at reset
14: ) (
15: input clk_i,
16: input rst_ni,
17: input host_req_i, // host request - read only
18: input [BankAddrW-1:0] host_addr_i,
19: input req_i, // controller request
20: input rd_i,
21: input prog_i,
22: input pg_erase_i,
23: input bk_erase_i,
24: input [BankAddrW-1:0] addr_i,
25: input [BusWidth-1:0] prog_data_i,
26: output logic host_req_rdy_o,
27: output logic host_req_done_o,
28: output logic rd_done_o,
29: output logic prog_done_o,
30: output logic erase_done_o,
31: output logic [BusWidth-1:0] rd_data_o,
32: output logic init_busy_o
33: );
34:
35: typedef enum logic [1:0] {
36: StIdle,
37: StHostRead,
38: StCtrlRead,
39: StCtrl
40: } arb_state_e;
41:
42: arb_state_e state_q, state_d;
43:
44: // request signals to flash macro
45: logic [PhyOps-1:0] reqs;
46:
47: // host select for address
48: logic host_sel;
49:
50: // qualifier for host responses
51: logic host_rsp;
52:
53: // controller response valid
54: logic ctrl_rsp_vld;
55:
56: // ack to phy operations from flash macro
57: logic ack;
58:
59: // interface with flash macro
60: logic [BankAddrW-1:0] muxed_addr;
61:
62: // entire read stage is idle, inclusive of all stages
63: logic rd_stage_idle;
64:
65: // the read stage is ready to accept a new transaction
66: logic rd_stage_rdy;
67:
68: // the read stage has valid data return
69: logic rd_stage_data_valid;
70:
71:
72: assign host_req_done_o = host_rsp & rd_stage_data_valid;
73:
74: always_ff @(posedge clk_i or negedge rst_ni) begin
75: if (!rst_ni) begin
76: state_q <= StIdle;
77: end else begin
78: state_q <= state_d;
79: end
80: end
81:
82: always_comb begin
83: state_d = state_q;
84:
85: reqs = '0;
86: host_sel = 1'b0;
87: host_rsp = 1'b0;
88: ctrl_rsp_vld = 1'b0;
89: host_req_rdy_o = 1'b0;
90:
91: unique case (state_q)
92: StIdle: begin
93: if (host_req_i) begin
94: reqs[PhyRead] = 1'b1;
95: host_sel = 1'b1;
96: host_req_rdy_o = rd_stage_rdy;
97: state_d = host_req_rdy_o ? StHostRead : state_q;
98: end else if (req_i && rd_i) begin
99: reqs[PhyRead] = 1'b1;
100: state_d = rd_stage_rdy ? StCtrlRead : state_q;
101: end else if (req_i) begin
102: reqs[PhyProg] = prog_i;
103: reqs[PhyPgErase] = pg_erase_i;
104: reqs[PhyBkErase] = bk_erase_i;
105: state_d = StCtrl;
106: end
107: end
108:
109: // The host priority may be dangerous, as it could lock-out controller initiated
110: // operations. Need to think about whether this should be made round-robin.
111: StHostRead: begin
112: host_rsp = 1'b1;
113: if (host_req_i) begin
114: reqs[PhyRead] = 1'b1;
115: host_sel = 1'b1;
116: host_req_rdy_o = rd_stage_rdy;
117: end else if (rd_stage_idle) begin
118: // once in pipelined reads, need to wait for the entire pipeline
119: // to drain before returning to perform other operations
120: state_d = StIdle;
121: end
122: end
123:
124: // Controller reads are very slow.
125: // Need to update controller end to take advantage of read pipeline.
126: // Once that is done, the two read states can merge.
127: StCtrlRead: begin
128: if (rd_stage_data_valid) begin
129: ctrl_rsp_vld = 1'b1;
130: state_d = StIdle;
131: end
132: end
133:
134: // other controller operations directly interface with flash
135: StCtrl: begin
136: if (ack) begin
137: ctrl_rsp_vld = 1'b1;
138: state_d = StIdle;
139: end
140: end
141:
142: // state is terminal, no flash transactions are ever accepted again
143: // until reboot
144: default:;
145: endcase // unique case (state_q)
146: end
147:
148: assign muxed_addr = host_sel ? host_addr_i : addr_i;
149: assign rd_done_o = ctrl_rsp_vld & rd_i;
150: assign prog_done_o = ctrl_rsp_vld & prog_i;
151: assign erase_done_o = ctrl_rsp_vld & (pg_erase_i | bk_erase_i);
152:
153: ////////////////////////
154: // read pipeline
155: ////////////////////////
156:
157: logic flash_rd_req;
158: logic [DataWidth-1:0] flash_rdata;
159:
160: flash_phy_rd i_rd (
161: .clk_i,
162: .rst_ni,
163: .req_i(reqs[PhyRead]),
164: .prog_i(reqs[PhyProg]),
165: .pg_erase_i(reqs[PhyPgErase]),
166: .bk_erase_i(reqs[PhyBkErase]),
167: .addr_i(muxed_addr),
168: .rdy_o(rd_stage_rdy),
169: .data_valid_o(rd_stage_data_valid),
170: .data_o(rd_data_o),
171: .idle_o(rd_stage_idle),
172: .req_o(flash_rd_req),
173: .ack_i(ack),
174: .data_i(flash_rdata)
175: );
176:
177: ////////////////////////
178: // program pipeline
179: ////////////////////////
180:
181: // Below code is temporary and does not account for scrambling
182: logic [DataWidth-1:0] prog_data;
183:
184: if (WidthMultiple == 1) begin : gen_single_prog_data
185: assign prog_data = prog_data_i;
186: end else begin : gen_prog_data
187: logic [WidthMultiple-1:0][BusWidth-1:0] prog_data_packed;
188:
189: always_comb begin
190: prog_data_packed = {DataWidth{1'b1}};
191: for (int i = 0; i < WidthMultiple; i++) begin
192: if (addr_i[0 +: WordSelW] == i) begin
193: prog_data_packed[i] = prog_data_i;
194: end
195: end
196: end
197:
198: assign prog_data = prog_data_packed;
199: end
200:
201: ////////////////////////
202: // scrambling / de-scrambling primitive
203: ////////////////////////
204:
205:
206: ////////////////////////
207: // Actual connection to flash phy
208: ////////////////////////
209:
210: // The actual flash macro wrapper
211: // The size of a page is fixed. However, depending on the sizing of the word,
212: // the number of words within a page will change.
213: prim_flash #(
214: .PagesPerBank(PagesPerBank),
215: .WordsPerPage(WordsPerPage / WidthMultiple),
216: .DataWidth(DataWidth),
217: .SkipInit(SkipInit)
218: ) i_flash (
219: .clk_i,
220: .rst_ni,
221: .rd_i(flash_rd_req),
222: .prog_i(reqs[PhyProg]),
223: .pg_erase_i(reqs[PhyPgErase]),
224: .bk_erase_i(reqs[PhyBkErase]),
225: //.addr_i(muxed_addr[0 +: PageW + WordW]),
226: .addr_i(muxed_addr[BankAddrW-1:LsbAddrBit]),
227: .prog_data_i(prog_data),
228: .ack_o(ack),
229: .rd_data_o(flash_rdata),
230: .init_busy_o // TBD this needs to be looked at later. What init do we need to do,
231: // and where does it make the most sense?
232: );
233:
234: /////////////////////////////////
235: // Assertions
236: /////////////////////////////////
237:
238: // requests to flash must always be one hot
239: `ASSERT(OneHotReqs_A, $onehot0(reqs))
240: `ASSERT_INIT(NoRemainder_A, AddrBitsRemain == 0)
241: `ASSERT_INIT(Pow2Multiple_A, $onehot(WidthMultiple))
242:
243: endmodule // flash_phy_core
244: