mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-07 12:38:44 -07:00
prim: Add RAM primitives
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
72
src/prim/rtl/taxi_ram_1r1w_1c.sv
Normal file
72
src/prim/rtl/taxi_ram_1r1w_1c.sv
Normal file
@@ -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
|
||||||
74
src/prim/rtl/taxi_ram_1r1w_2c.sv
Normal file
74
src/prim/rtl/taxi_ram_1r1w_2c.sv
Normal file
@@ -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
|
||||||
70
src/prim/rtl/taxi_ram_1rw.sv
Normal file
70
src/prim/rtl/taxi_ram_1rw.sv
Normal file
@@ -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
|
||||||
97
src/prim/rtl/taxi_ram_2rw_1c.sv
Normal file
97
src/prim/rtl/taxi_ram_2rw_1c.sv
Normal file
@@ -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
|
||||||
99
src/prim/rtl/taxi_ram_2rw_2c.sv
Normal file
99
src/prim/rtl/taxi_ram_2rw_2c.sv
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user