| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // | |
| // The mux to select between ROM inputs | |
| // | |
| module rom_ctrl_mux | |
| import prim_mubi_pkg::mubi4_t; | |
| #( | |
| parameter int AW = 8, | |
| parameter int DW = 39 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| // Select signal saying whether access is granted to the bus. This module raises an alert (by | |
| // setting alert_o) if the signal isn't an allowed value or if the selection switches back from | |
| // the bus to the checker. | |
| input mubi4_t sel_bus_i, | |
| // Interface for bus | |
| input logic [AW-1:0] bus_rom_addr_i, | |
| input logic [AW-1:0] bus_prince_addr_i, | |
| input logic bus_req_i, | |
| output logic bus_gnt_o, | |
| output logic [DW-1:0] bus_rdata_o, | |
| output logic bus_rvalid_o, | |
| // Interface for ROM checker | |
| input logic [AW-1:0] chk_addr_i, | |
| input logic chk_req_i, | |
| output logic [DW-1:0] chk_rdata_o, | |
| // Interface for ROM | |
| output logic [AW-1:0] rom_rom_addr_o, | |
| output logic [AW-1:0] rom_prince_addr_o, | |
| output logic rom_req_o, | |
| input logic [DW-1:0] rom_scr_rdata_i, | |
| input logic [DW-1:0] rom_clr_rdata_i, | |
| input logic rom_rvalid_i, | |
| // Alert output | |
| // | |
| // This isn't latched in this module because it feeds into a fatal alert at top-level, whose | |
| // sender will latch it anyway. | |
| output logic alert_o | |
| ); | |
| import prim_mubi_pkg::*; | |
| // Track the state of the mux up to the current cycle. This is a "1-way" mux, which means that | |
| // we never switch from the bus back to the checker. | |
| // | |
| // We also have a version that's delayed by a single cycle to allow a check that sel_bus_q is | |
| // never reset from True to False. | |
| logic [3:0] sel_bus_q_raw, sel_bus_qq_raw; | |
| mubi4_t sel_bus_q, sel_bus_qq; | |
| prim_flop #(.Width (4), .ResetValue ({MuBi4False})) | |
| u_sel_bus_q_flop ( | |
| .clk_i, | |
| .rst_ni, | |
| .d_i (mubi4_or_hi(sel_bus_q, sel_bus_i)), | |
| .q_o (sel_bus_q_raw) | |
| ); | |
| assign sel_bus_q = mubi4_t'(sel_bus_q_raw); | |
| prim_flop #(.Width (4), .ResetValue ({MuBi4False})) | |
| u_sel_bus_qq_flop ( | |
| .clk_i, | |
| .rst_ni, | |
| .d_i (sel_bus_q), | |
| .q_o (sel_bus_qq_raw) | |
| ); | |
| assign sel_bus_qq = mubi4_t'(sel_bus_qq_raw); | |
| // Spot if the sel_bus_i signal or its register version has a corrupt value. | |
| // | |
| // SEC_CM: MUX.MUBI | |
| logic sel_invalid; | |
| assign sel_invalid = mubi4_test_invalid(sel_bus_i) || mubi4_test_invalid(sel_bus_q); | |
| // Spot if the select signal switches back to the checker once we've switched to the bus. Doing so | |
| // will have no lasting effect because of how we calculate sel_bus_q) but isn't supposed to | |
| // happen, so we want to trigger an alert. | |
| // | |
| // SEC_CM: MUX.CONSISTENCY | |
| logic sel_reverted; | |
| assign sel_reverted = mubi4_test_true_loose(sel_bus_q) & mubi4_test_false_loose(sel_bus_i); | |
| // Spot if the sel_bus_q signal has reverted somehow. | |
| // | |
| // SEC_CM: MUX.CONSISTENCY | |
| logic sel_q_reverted; | |
| assign sel_q_reverted = mubi4_test_true_loose(sel_bus_qq) & mubi4_test_false_loose(sel_bus_q); | |
| logic alert_q, alert_d; | |
| assign alert_d = sel_invalid | sel_reverted | sel_q_reverted; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| alert_q <= 0; | |
| end else begin | |
| alert_q <= alert_q | alert_d; | |
| end | |
| end | |
| assign alert_o = alert_q; | |
| // The bus can have access every cycle, from when the select signal switches to the bus. | |
| assign bus_gnt_o = mubi4_test_true_strict(sel_bus_i); | |
| assign bus_rdata_o = rom_clr_rdata_i; | |
| // A high rom_rvalid_i is a response to a bus request if the select signal pointed at the bus on | |
| // the previous cycle. | |
| assign bus_rvalid_o = mubi4_test_true_strict(sel_bus_q) & rom_rvalid_i; | |
| assign chk_rdata_o = rom_scr_rdata_i; | |
| assign rom_req_o = mubi4_test_true_strict(sel_bus_i) ? bus_req_i : chk_req_i; | |
| assign rom_rom_addr_o = mubi4_test_true_strict(sel_bus_i) ? bus_rom_addr_i : chk_addr_i; | |
| assign rom_prince_addr_o = mubi4_test_true_strict(sel_bus_i) ? bus_prince_addr_i : chk_addr_i; | |
| endmodule |