blob: e0695ce827ca75ca3799d5a00912c90326184731 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Flash Phy Module
//
//
// This module is an early attempt to model what a custom phy module might look like
// Long term, it is expected this module will split into its own entity under hw/ip
// with its own set of register that support technology / node specific flash settings
// More of those details will be worked out with future partner engagement
module flash_phy #(
parameter int NumBanks = 2,
parameter int PagesPerBank = 256, // pages per bank
parameter int WordsPerPage = 256, // words per page
parameter int DataWidth = 32, // bits per word
//Do not touch - Derived parameters
localparam int BankW = $clog2(NumBanks),
localparam int PageW = $clog2(PagesPerBank),
localparam int WordW = $clog2(WordsPerPage),
localparam int AddrW = BankW + PageW + WordW
) (
input clk_i,
input rst_ni,
input host_req_i,
input [AddrW-1:0] host_addr_i,
output logic host_req_rdy_o,
output logic host_req_done_o,
output logic [DataWidth-1:0] host_rdata_o,
input flash_ctrl_pkg::flash_c2m_t flash_ctrl_i,
output flash_ctrl_pkg::flash_m2c_t flash_ctrl_o
);
// Flash macro outstanding refers to how many reads we allow a macro to move ahead of an
// in order blocking read. Since the data cannot be returned out of order, this simply
// does the reads in advance and store them in a FIFO
localparam int FlashMacroOustanding = 1;
localparam int SeqFifoDepth = FlashMacroOustanding * NumBanks;
// flash_phy forwards incoming host transactions to the appropriate bank but is not aware of
// any controller / host arbitration within the bank. This means it is possible for
// flash_phy to forward one transaction to bank N and another to bank N+1 only for bank N+1
// to finish its transaction first (if for example a controller operation were ongoing in bank
// N).
// This implies that even though transactions are received in-order, they can complete out of
// order. Thus it is the responsibility of the flash_phy to sequence the responses correctly.
// For banks that have finished ahead of time, it is also important to hold its output until
// consumed.
// host to flash_phy interface
logic [BankW-1:0] host_bank_sel;
logic [BankW-1:0] rsp_bank_sel;
logic [NumBanks-1:0] host_req_rdy;
logic [NumBanks-1:0] host_req_done;
logic [NumBanks-1:0] host_rsp_avail;
logic [NumBanks-1:0] host_rsp_vld;
logic [NumBanks-1:0] host_rsp_ack;
logic [DataWidth-1:0] host_rsp_data [NumBanks];
logic seq_fifo_rdy;
logic seq_fifo_pending;
// flash_ctrl to flash_phy interface
logic [BankW-1:0] ctrl_bank_sel;
logic [NumBanks-1:0] rd_done;
logic [NumBanks-1:0] prog_done;
logic [NumBanks-1:0] erase_done;
logic [NumBanks-1:0] init_busy;
// common interface
logic [DataWidth-1:0] rd_data [NumBanks];
// select which bank each is operating on
assign host_bank_sel = host_req_i ? host_addr_i[PageW + WordW +: BankW] : '0;
assign ctrl_bank_sel = flash_ctrl_i.addr[PageW + WordW +: BankW];
// accept transaction if bank is ready and previous response NOT pending
assign host_req_rdy_o = host_req_rdy[host_bank_sel] & host_rsp_avail[host_bank_sel] &
seq_fifo_rdy;
assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
assign host_rdata_o = host_rsp_data[rsp_bank_sel];
assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
assign flash_ctrl_o.init_busy = |init_busy;
// This fifo holds the expected return order
prim_fifo_sync #(
.Width (BankW),
.Pass (0),
.Depth (SeqFifoDepth)
) bank_sequence_fifo (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid (host_req_i & host_req_rdy_o),
.wready (seq_fifo_rdy),
.wdata (host_bank_sel),
.depth (),
.rvalid (seq_fifo_pending),
.rready (host_req_done_o),
.rdata (rsp_bank_sel)
);
for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_flash_banks
// pop if the response came from the appropriate fifo
assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
prim_fifo_sync #(
.Width (DataWidth),
.Pass (1'b1),
.Depth (FlashMacroOustanding)
) host_rsp_fifo (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid (host_req_done[bank]),
.wready (host_rsp_avail[bank]),
.wdata (rd_data[bank]),
.depth (),
.rvalid (host_rsp_vld[bank]),
.rready (host_rsp_ack[bank]),
.rdata (host_rsp_data[bank])
);
prim_flash #(
.PagesPerBank(PagesPerBank),
.WordsPerPage(WordsPerPage),
.DataWidth(DataWidth)
) u_flash (
.clk_i,
.rst_ni,
.req_i(flash_ctrl_i.req & (ctrl_bank_sel == bank)),
.host_req_i(host_req_i & host_req_rdy_o & (host_bank_sel == bank)),
.host_addr_i(host_addr_i[0 +: PageW + WordW]),
.rd_i(flash_ctrl_i.rd),
.prog_i(flash_ctrl_i.prog),
.pg_erase_i(flash_ctrl_i.pg_erase),
.bk_erase_i(flash_ctrl_i.bk_erase),
.addr_i(flash_ctrl_i.addr[0 +: PageW + WordW]),
.prog_data_i(flash_ctrl_i.prog_data),
.host_req_rdy_o(host_req_rdy[bank]),
.host_req_done_o(host_req_done[bank]),
.rd_done_o(rd_done[bank]),
.prog_done_o(prog_done[bank]),
.erase_done_o(erase_done[bank]),
.rd_data_o(rd_data[bank]),
.init_busy_o(init_busy[bank])
);
end
endmodule // flash_phy