blob: 2339f17bddfbcbac161aab61ea1c7dce1af156c5 [file] [log] [blame]
// 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