/*****************************************************************************\
|                      Copyright (C) 2021-2022 Luke Wren                      |
|                     SPDX-License-Identifier: Apache-2.0                     |
\*****************************************************************************/

// Register file
// Single write port, dual read port

`default_nettype none

module hazard3_regfile_1w2r #(
`include "hazard3_config.vh"
) (
	input wire clk,
	input wire rst_n,

	input wire [4:0]        raddr1,
	output reg [W_DATA-1:0] rdata1,

	input wire [4:0]        raddr2,
	output reg [W_DATA-1:0] rdata2,

	input wire [4:0]        waddr,
	input wire [W_DATA-1:0] wdata,
	input wire              wen
);

localparam       N_REGS      = EXTENSION_E == 0 ? 32 : 16;
localparam [4:0] REGNUM_MASK = {~|EXTENSION_E, 4'hf};

wire [4:0] raddr1_masked = raddr1 & REGNUM_MASK;
wire [4:0] raddr2_masked = raddr2 & REGNUM_MASK;
wire [4:0] waddr_masked  = waddr  & REGNUM_MASK;

generate
if (RESET_REGFILE) begin: real_dualport_reset
	// This will presumably always be implemented with flops
	reg [W_DATA-1:0] mem [0:N_REGS-1];

	integer i;
	always @ (posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			for (i = 0; i < N_REGS; i = i + 1) begin
				mem[i] <= {W_DATA{1'b0}};
			end
			rdata1 <= {W_DATA{1'b0}};
			rdata2 <= {W_DATA{1'b0}};
		end else begin
			if (wen) begin
				mem[waddr_masked] <= wdata;
			end
			rdata1 <= mem[raddr1_masked];
			rdata2 <= mem[raddr2_masked];
		end
	end
end else begin: real_dualport_noreset
	// This should be inference-compatible on FPGAs with dual-port (or 1R1W) BRAMs
	`ifdef YOSYS
	`ifdef FPGA_ICE40
	// We do not require write-to-read bypass logic on the BRAM
	(* no_rw_check *)
	`endif
	`endif
	// Optionally force use of distributed RAM on Xilinx for better timing
	`ifdef HAZARD3_REGFILE_RAM_STYLE_DISTRIBUTED
	(* ram_style = "distributed" *)
	`endif
	reg [W_DATA-1:0] mem [0:N_REGS-1];

	always @ (posedge clk) begin
		if (wen) begin
			mem[waddr_masked] <= wdata;
		end
		rdata1 <= mem[raddr1_masked];
		rdata2 <= mem[raddr2_masked];
	end
end
endgenerate

endmodule

`ifndef YOSYS
`default_nettype wire
`endif
