| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| `include "prim_assert.sv" |
| |
| module rom_ctrl |
| import rom_ctrl_reg_pkg::NumAlerts; |
| import prim_rom_pkg::rom_cfg_t; |
| #( |
| parameter BootRomInitFile = "", |
| parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}} |
| ) ( |
| input clk_i, |
| input rst_ni, |
| |
| // ROM configuration parameters |
| input rom_cfg_t rom_cfg_i, |
| |
| input tlul_pkg::tl_h2d_t rom_tl_i, |
| output tlul_pkg::tl_d2h_t rom_tl_o, |
| |
| input tlul_pkg::tl_h2d_t regs_tl_i, |
| output tlul_pkg::tl_d2h_t regs_tl_o, |
| |
| // Alerts |
| input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i, |
| output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o |
| ); |
| |
| import rom_ctrl_pkg::*; |
| import rom_ctrl_reg_pkg::*; |
| import prim_util_pkg::vbits; |
| |
| // TL interface ============================================================== |
| |
| tlul_pkg::tl_h2d_t tl_rom_h2d [1]; |
| tlul_pkg::tl_d2h_t tl_rom_d2h [1]; |
| |
| logic rom_reg_integrity_error; |
| |
| rom_ctrl_rom_reg_top u_rom_top ( |
| .clk_i (clk_i), |
| .rst_ni (rst_ni), |
| .tl_i (rom_tl_i), |
| .tl_o (rom_tl_o), |
| .tl_win_o (tl_rom_h2d), |
| .tl_win_i (tl_rom_d2h), |
| |
| .intg_err_o (rom_reg_integrity_error), |
| |
| .devmode_i (1'b1) |
| ); |
| |
| // The ROM =================================================================== |
| |
| // ROM_CTRL_ROM_SIZE is auto-generated by regtool and comes from the bus window size, measured in |
| // bytes of content (i.e. 4 times the number of 32 bit words). |
| localparam int unsigned RomSizeByte = ROM_CTRL_ROM_SIZE; |
| localparam int unsigned RomSizeWords = RomSizeByte >> 2; |
| localparam int unsigned RomIndexWidth = vbits(RomSizeWords); |
| |
| logic rom_req; |
| logic [RomIndexWidth-1:0] rom_index; |
| logic [39:0] rom_rdata; |
| logic rom_rvalid; |
| |
| logic rom_integrity_error; |
| |
| tlul_adapter_sram #( |
| .SramAw(RomIndexWidth), |
| .SramDw(32), |
| .Outstanding(2), |
| .ByteAccess(0), |
| .ErrOnWrite(1), |
| .EnableRspIntgGen(1), |
| .EnableDataIntgGen(1) // TODO: Needs to be updated for integrity passthrough |
| ) u_tl_adapter_rom ( |
| .clk_i (clk_i), |
| .rst_ni (rst_ni), |
| |
| .tl_i (tl_rom_h2d[0]), |
| .tl_o (tl_rom_d2h[0]), |
| .en_ifetch_i (tlul_pkg::InstrEn), |
| .req_o (rom_req), |
| .req_type_o (), |
| .gnt_i (1'b1), |
| .we_o (), |
| .addr_o (rom_index), |
| .wdata_o (), |
| .wmask_o (), |
| .intg_error_o (rom_integrity_error), |
| .rdata_i (rom_rdata[31:0]), |
| .rvalid_i (rom_rvalid), |
| .rerror_i (2'b00) |
| ); |
| |
| prim_rom_adv #( |
| .Width (40), |
| .Depth (RomSizeWords), |
| .MemInitFile (BootRomInitFile) |
| ) u_rom |
| ( |
| .clk_i (clk_i), |
| .rst_ni (rst_ni), |
| .req_i (rom_req), |
| .addr_i (rom_index), |
| .rdata_o (rom_rdata), |
| .rvalid_o (rom_rvalid), |
| .cfg_i (rom_cfg_i) |
| ); |
| |
| // TODO: The ROM has been expanded to 40 bits wide to allow us to add 9 ECC check bits. At the |
| // moment, however, we're actually generating the ECC data in u_tl_adapter_rom. That should |
| // go away soonish but, until then, waive the fact that we're not looking at the top bits of |
| // rom_rdata. |
| logic unused_rom_rdata_top; |
| assign unused_rom_rdata_top = &{1'b0, rom_rdata[39:32]}; |
| |
| // Registers ================================================================= |
| |
| rom_ctrl_regs_reg2hw_t reg2hw; |
| rom_ctrl_regs_hw2reg_t hw2reg; |
| logic reg_integrity_error; |
| |
| rom_ctrl_regs_reg_top u_reg_regs ( |
| .clk_i (clk_i), |
| .rst_ni (rst_ni), |
| .tl_i (regs_tl_i), |
| .tl_o (regs_tl_o), |
| .reg2hw (reg2hw), |
| .hw2reg (hw2reg), |
| .intg_err_o (reg_integrity_error), |
| .devmode_i (1'b1) |
| ); |
| |
| logic bus_integrity_error; |
| assign bus_integrity_error = rom_reg_integrity_error | rom_integrity_error | reg_integrity_error; |
| |
| // FATAL_ALERT_CAUSE register |
| assign hw2reg.fatal_alert_cause.integrity_error.d = bus_integrity_error; |
| assign hw2reg.fatal_alert_cause.integrity_error.de = bus_integrity_error; |
| assign hw2reg.fatal_alert_cause.dummy.d = 1'b0; |
| assign hw2reg.fatal_alert_cause.dummy.de = 1'b0; |
| |
| // Alert generation ========================================================== |
| |
| logic [NumAlerts-1:0] alert_test; |
| assign alert_test[AlertFatal] = reg2hw.alert_test.q & |
| reg2hw.alert_test.qe; |
| |
| logic [NumAlerts-1:0] alerts; |
| assign alerts[AlertFatal] = reg_integrity_error; |
| |
| for (genvar i = 0; i < NumAlerts; i++) begin: gen_alert_tx |
| prim_alert_sender #( |
| .AsyncOn(AlertAsyncOn[i]), |
| .IsFatal(i == AlertFatal) |
| ) u_alert_sender ( |
| .clk_i, |
| .rst_ni, |
| .alert_test_i ( alert_test[i] ), |
| .alert_req_i ( alerts[i] ), |
| .alert_ack_o ( ), |
| .alert_state_o ( ), |
| .alert_rx_i ( alert_rx_i[i] ), |
| .alert_tx_o ( alert_tx_o[i] ) |
| ); |
| end |
| |
| // Asserts =================================================================== |
| |
| // All outputs should be known value after reset |
| `ASSERT_KNOWN(RomTlODValidKnown_A, rom_tl_o.d_valid) |
| `ASSERT_KNOWN(RomTlOAReadyKnown_A, rom_tl_o.a_ready) |
| `ASSERT_KNOWN(RegTlODValidKnown_A, regs_tl_o.d_valid) |
| `ASSERT_KNOWN(RegTlOAReadyKnown_A, regs_tl_o.a_ready) |
| `ASSERT_KNOWN(AlertTxOKnown_A, alert_tx_o) |
| |
| endmodule |