tinyriscv/rtl/utils/prim_subreg_arb.sv

80 lines
2.8 KiB
Systemverilog

// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Write enable and data arbitration logic for register slice conforming to Comportibility guide.
module prim_subreg_arb #(
parameter int DW = 32 ,
parameter SWACCESS = "RW" // {RW, RO, WO, W1C, W1S, W0C, RC}
) (
// From SW: valid for RW, WO, W1C, W1S, W0C, RC.
// In case of RC, top connects read pulse to we.
input we,
input [DW-1:0] wd,
// From HW: valid for HRW, HWO.
input de,
input [DW-1:0] d,
// From register: actual reg value.
input [DW-1:0] q,
// To register: actual write enable and write data.
output logic wr_en,
output logic [DW-1:0] wr_data
);
if ((SWACCESS == "RW") || (SWACCESS == "WO")) begin : gen_w
assign wr_en = we | de;
assign wr_data = (we == 1'b1) ? wd : d; // SW higher priority
// Unused q - Prevent lint errors.
logic [DW-1:0] unused_q;
assign unused_q = q;
end else if (SWACCESS == "RO") begin : gen_ro
assign wr_en = de;
assign wr_data = d;
// Unused we, wd, q - Prevent lint errors.
logic unused_we;
logic [DW-1:0] unused_wd;
logic [DW-1:0] unused_q;
assign unused_we = we;
assign unused_wd = wd;
assign unused_q = q;
end else if (SWACCESS == "W1S") begin : gen_w1s
// If SWACCESS is W1S, then assume hw tries to clear.
// So, give a chance HW to clear when SW tries to set.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de;
assign wr_data = (de ? d : q) | (we ? wd : '0);
end else if (SWACCESS == "W1C") begin : gen_w1c
// If SWACCESS is W1C, then assume hw tries to set.
// So, give a chance HW to set when SW tries to clear.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? ~wd : '1);
end else if (SWACCESS == "W0C") begin : gen_w0c
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? wd : '1);
end else if (SWACCESS == "RC") begin : gen_rc
// This swtype is not recommended but exists for compatibility.
// WARN: we signal is actually read signal not write enable.
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? '0 : '1);
// Unused wd - Prevent lint errors.
logic [DW-1:0] unused_wd;
assign unused_wd = wd;
end else begin : gen_hw
assign wr_en = de;
assign wr_data = d;
// Unused we, wd, q - Prevent lint errors.
logic unused_we;
logic [DW-1:0] unused_wd;
logic [DW-1:0] unused_q;
assign unused_we = we;
assign unused_wd = wd;
assign unused_q = q;
end
endmodule