|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // Faux Flash Read Control | 
|  | // | 
|  |  | 
|  | module flash_ctrl_rd import flash_ctrl_pkg::*; ( | 
|  | input clk_i, | 
|  | input rst_ni, | 
|  |  | 
|  | // Software Interface | 
|  | input                    op_start_i, | 
|  | input  [11:0]            op_num_words_i, | 
|  | output logic             op_done_o, | 
|  | output logic             op_err_o, | 
|  | input [BusAddrW-1:0]     op_addr_i, | 
|  |  | 
|  | // FIFO Interface | 
|  | input                    data_rdy_i, | 
|  | output logic [BusWidth-1:0] data_o, | 
|  | output logic             data_wr_o, | 
|  |  | 
|  | // Flash Macro Interface | 
|  | output logic             flash_req_o, | 
|  | output logic [BusAddrW-1:0] flash_addr_o, | 
|  | output logic             flash_ovfl_o, | 
|  | input [BusWidth-1:0]     flash_data_i, | 
|  | input                    flash_done_i, | 
|  | input                    flash_error_i | 
|  | ); | 
|  |  | 
|  | typedef enum logic { | 
|  | StNorm  = 'h0, | 
|  | StErr   = 'h1 | 
|  | } state_e; | 
|  |  | 
|  | state_e st, st_nxt; | 
|  | logic [11:0] cnt, cnt_nxt; | 
|  | logic cnt_hit; | 
|  | logic [BusAddrW:0] int_addr; | 
|  | logic txn_done; | 
|  | logic err_sel; //1 selects error data, 0 selects normal data | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | cnt <= '0; | 
|  | st <= StNorm; | 
|  | end else begin | 
|  | cnt <= cnt_nxt; | 
|  | st <= st_nxt; | 
|  | end | 
|  | end | 
|  |  | 
|  | assign txn_done = flash_req_o & flash_done_i; | 
|  | assign cnt_hit = (cnt == op_num_words_i); | 
|  |  | 
|  | // when error'd, continue to complete existing read transaction but fill in with all 1's | 
|  | // if this is not done, software may continue to attempt to read out of the fifo | 
|  | // and eventually cause a bus deadlock as the fifo would be empty | 
|  | // This scheme is similar to burst completion up an error | 
|  | always_comb begin | 
|  | st_nxt = st; | 
|  | cnt_nxt = cnt; | 
|  | flash_req_o = 1'b0; | 
|  | data_wr_o = 1'b0; | 
|  | op_done_o = 1'b0; | 
|  | op_err_o = 1'b0; | 
|  | err_sel = 1'b0; | 
|  |  | 
|  | unique case (st) | 
|  | StNorm: begin | 
|  | flash_req_o = op_start_i & data_rdy_i; | 
|  |  | 
|  | if (txn_done && cnt_hit) begin | 
|  | cnt_nxt = '0; | 
|  | data_wr_o = 1'b1; | 
|  | op_done_o = 1'b1; | 
|  | op_err_o = flash_error_i; | 
|  | end else if (txn_done) begin | 
|  | cnt_nxt = cnt + 1'b1; | 
|  | data_wr_o = 1'b1; | 
|  | err_sel = flash_error_i; | 
|  | st_nxt = flash_error_i ? StErr : StNorm; | 
|  | end | 
|  | end | 
|  | StErr: begin | 
|  | data_wr_o = data_rdy_i; | 
|  | err_sel = 1'b1; | 
|  |  | 
|  | if (data_rdy_i && cnt_hit) begin | 
|  | st_nxt = StNorm; | 
|  | cnt_nxt = '0; | 
|  | op_done_o = 1'b1; | 
|  | op_err_o = 1'b1; | 
|  | end else if (data_rdy_i) begin | 
|  | cnt_nxt = cnt + 1'b1; | 
|  | end | 
|  | end | 
|  | default:; | 
|  | endcase // unique case (st) | 
|  | end | 
|  |  | 
|  | // overflow error detection is not here, but instead handled at memory protection | 
|  | assign int_addr = op_addr_i + BusAddrW'(cnt); | 
|  | assign flash_addr_o = int_addr[0 +: BusAddrW]; | 
|  | assign flash_ovfl_o = int_addr[BusAddrW]; | 
|  | // if error, return "empty" data | 
|  | assign data_o = err_sel ? {BusWidth{1'b1}} : flash_data_i; | 
|  |  | 
|  |  | 
|  | endmodule // flash_ctrl_rd |