80 lines
2.8 KiB
Systemverilog
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
|