From 0ff8e5fb9e432655dc345b90506c59c4e7a9829b Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 27 Feb 2026 22:08:14 -0800 Subject: [PATCH] prim: Add RAM primitives Signed-off-by: Alex Forencich --- src/prim/rtl/taxi_ram_1r1w_1c.sv | 72 +++++++++++++++++++++++ src/prim/rtl/taxi_ram_1r1w_2c.sv | 74 ++++++++++++++++++++++++ src/prim/rtl/taxi_ram_1rw.sv | 70 ++++++++++++++++++++++ src/prim/rtl/taxi_ram_2rw_1c.sv | 97 +++++++++++++++++++++++++++++++ src/prim/rtl/taxi_ram_2rw_2c.sv | 99 ++++++++++++++++++++++++++++++++ 5 files changed, 412 insertions(+) create mode 100644 src/prim/rtl/taxi_ram_1r1w_1c.sv create mode 100644 src/prim/rtl/taxi_ram_1r1w_2c.sv create mode 100644 src/prim/rtl/taxi_ram_1rw.sv create mode 100644 src/prim/rtl/taxi_ram_2rw_1c.sv create mode 100644 src/prim/rtl/taxi_ram_2rw_2c.sv diff --git a/src/prim/rtl/taxi_ram_1r1w_1c.sv b/src/prim/rtl/taxi_ram_1r1w_1c.sv new file mode 100644 index 0000000..0af3d90 --- /dev/null +++ b/src/prim/rtl/taxi_ram_1r1w_1c.sv @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Simple dual-port RAM + */ +module taxi_ram_1r1w_1c # +( + parameter ADDR_W = 16, + parameter DATA_W = 16, + parameter logic STRB_EN = 1'b1, + parameter STRB_W = DATA_W/8 +) +( + input wire logic clk, + + input wire logic wr_en, + input wire logic [ADDR_W-1:0] wr_addr, + input wire logic [DATA_W-1:0] wr_data, + input wire logic [STRB_W-1:0] wr_strb = '1, + + input wire logic rd_en, + input wire logic [ADDR_W-1:0] rd_addr, + output wire logic [DATA_W-1:0] rd_data +); + +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (STRB_EN && BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: Data width not evenly divisible (instance %m)"); + +reg [DATA_W-1:0] rd_data_reg = '0; + +assign rd_data = rd_data_reg; + +// (* RAM_STYLE="BLOCK" *) +logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0}; + +always_ff @(posedge clk) begin + if (wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (wr_strb[i]) begin + mem[wr_addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[wr_addr] <= wr_data; + end + end + + if (rd_en) begin + rd_data_reg <= mem[rd_addr]; + end +end + +endmodule + +`resetall diff --git a/src/prim/rtl/taxi_ram_1r1w_2c.sv b/src/prim/rtl/taxi_ram_1r1w_2c.sv new file mode 100644 index 0000000..a4c3f7a --- /dev/null +++ b/src/prim/rtl/taxi_ram_1r1w_2c.sv @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Simple dual-port, dual-clock RAM + */ +module taxi_ram_1r1w_2c # +( + parameter ADDR_W = 16, + parameter DATA_W = 16, + parameter logic STRB_EN = 1'b1, + parameter STRB_W = DATA_W/8 +) +( + input wire logic wr_clk, + input wire logic wr_en, + input wire logic [ADDR_W-1:0] wr_addr, + input wire logic [DATA_W-1:0] wr_data, + input wire logic [STRB_W-1:0] wr_strb = '1, + + input wire logic rd_clk, + input wire logic rd_en, + input wire logic [ADDR_W-1:0] rd_addr, + output wire logic [DATA_W-1:0] rd_data +); + +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (STRB_EN && BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: Data width not evenly divisible (instance %m)"); + +reg [DATA_W-1:0] rd_data_reg = '0; + +assign rd_data = rd_data_reg; + +// (* RAM_STYLE="BLOCK" *) +logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0}; + +always_ff @(posedge wr_clk) begin + if (wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (wr_strb[i]) begin + mem[wr_addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[wr_addr] <= wr_data; + end + end +end + +always_ff @(posedge rd_clk) begin + if (rd_en) begin + rd_data_reg <= mem[rd_addr]; + end +end + +endmodule + +`resetall diff --git a/src/prim/rtl/taxi_ram_1rw.sv b/src/prim/rtl/taxi_ram_1rw.sv new file mode 100644 index 0000000..09a8747 --- /dev/null +++ b/src/prim/rtl/taxi_ram_1rw.sv @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Single-port RAM + */ +module taxi_ram_1rw # +( + parameter ADDR_W = 16, + parameter DATA_W = 16, + parameter logic STRB_EN = 1'b1, + parameter STRB_W = DATA_W/8 +) +( + input wire logic clk, + + input wire logic en, + input wire logic [ADDR_W-1:0] addr, + input wire logic wr_en, + input wire logic [DATA_W-1:0] wr_data, + input wire logic [STRB_W-1:0] wr_strb = '0, + output wire logic [DATA_W-1:0] rd_data +); + +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (STRB_EN && BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: Data width not evenly divisible (instance %m)"); + +reg [DATA_W-1:0] rd_data_reg = '0; + +assign rd_data = rd_data_reg; + +// (* RAM_STYLE="BLOCK" *) +logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0}; + +always_ff @(posedge clk) begin + if (en) begin + if (wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (wr_strb[i]) begin + mem[addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[addr] <= wr_data; + end + end else begin + rd_data_reg <= mem[addr]; + end + end +end + +endmodule + +`resetall diff --git a/src/prim/rtl/taxi_ram_2rw_1c.sv b/src/prim/rtl/taxi_ram_2rw_1c.sv new file mode 100644 index 0000000..f79b5ff --- /dev/null +++ b/src/prim/rtl/taxi_ram_2rw_1c.sv @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * True dual-port RAM + */ +module taxi_ram_2rw_1c # +( + parameter ADDR_W = 16, + parameter DATA_W = 16, + parameter logic STRB_EN = 1'b1, + parameter STRB_W = DATA_W/8 +) +( + input wire logic clk, + + input wire logic a_en, + input wire logic [ADDR_W-1:0] a_addr, + input wire logic a_wr_en, + input wire logic [DATA_W-1:0] a_wr_data, + input wire logic [STRB_W-1:0] a_wr_strb = '1, + output wire logic [DATA_W-1:0] a_rd_data, + + input wire logic b_en, + input wire logic [ADDR_W-1:0] b_addr, + input wire logic b_wr_en, + input wire logic [DATA_W-1:0] b_wr_data, + input wire logic [STRB_W-1:0] b_wr_strb = '1, + output wire logic [DATA_W-1:0] b_rd_data +); + +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (STRB_EN && BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: Data width not evenly divisible (instance %m)"); + +reg [DATA_W-1:0] a_rd_data_reg = '0; +reg [DATA_W-1:0] b_rd_data_reg = '0; + +assign a_rd_data = a_rd_data_reg; +assign b_rd_data = b_rd_data_reg; + +// verilator lint_off MULTIDRIVEN +// (* RAM_STYLE="BLOCK" *) +logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0}; +// verilator lint_on MULTIDRIVEN + +always_ff @(posedge clk) begin + if (a_en) begin + if (a_wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (a_wr_strb[i]) begin + mem[a_addr][BYTE_W*i +: BYTE_W] <= a_wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[a_addr] <= a_wr_data; + end + end else begin + a_rd_data_reg <= mem[a_addr]; + end + end + + if (b_en) begin + if (b_wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (b_wr_strb[i]) begin + mem[b_addr][BYTE_W*i +: BYTE_W] <= b_wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[b_addr] <= b_wr_data; + end + end else begin + b_rd_data_reg <= mem[b_addr]; + end + end +end + +endmodule + +`resetall diff --git a/src/prim/rtl/taxi_ram_2rw_2c.sv b/src/prim/rtl/taxi_ram_2rw_2c.sv new file mode 100644 index 0000000..e59e938 --- /dev/null +++ b/src/prim/rtl/taxi_ram_2rw_2c.sv @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * True dual-port, dual-clock RAM + */ +module taxi_ram_2rw_2c # +( + parameter ADDR_W = 16, + parameter DATA_W = 16, + parameter logic STRB_EN = 1'b1, + parameter STRB_W = DATA_W/8 +) +( + input wire logic a_clk, + input wire logic a_en, + input wire logic [ADDR_W-1:0] a_addr, + input wire logic a_wr_en, + input wire logic [DATA_W-1:0] a_wr_data, + input wire logic [STRB_W-1:0] a_wr_strb = '1, + output wire logic [DATA_W-1:0] a_rd_data, + + input wire logic b_clk, + input wire logic b_en, + input wire logic [ADDR_W-1:0] b_addr, + input wire logic b_wr_en, + input wire logic [DATA_W-1:0] b_wr_data, + input wire logic [STRB_W-1:0] b_wr_strb = '1, + output wire logic [DATA_W-1:0] b_rd_data +); + +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (STRB_EN && BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: Data width not evenly divisible (instance %m)"); + +reg [DATA_W-1:0] a_rd_data_reg = '0; +reg [DATA_W-1:0] b_rd_data_reg = '0; + +assign a_rd_data = a_rd_data_reg; +assign b_rd_data = b_rd_data_reg; + +// verilator lint_off MULTIDRIVEN +// (* RAM_STYLE="BLOCK" *) +logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0}; +// verilator lint_on MULTIDRIVEN + +always_ff @(posedge a_clk) begin + if (a_en) begin + if (a_wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (a_wr_strb[i]) begin + mem[a_addr][BYTE_W*i +: BYTE_W] <= a_wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[a_addr] <= a_wr_data; + end + end else begin + a_rd_data_reg <= mem[a_addr]; + end + end +end + +always_ff @(posedge b_clk) begin + if (b_en) begin + if (b_wr_en) begin + if (STRB_EN) begin + for (integer i = 0; i < BYTE_LANES; i = i + 1) begin + if (b_wr_strb[i]) begin + mem[b_addr][BYTE_W*i +: BYTE_W] <= b_wr_data[BYTE_W*i +: BYTE_W]; + end + end + end else begin + mem[b_addr] <= b_wr_data; + end + end else begin + b_rd_data_reg <= mem[b_addr]; + end + end +end + +endmodule + +`resetall