Skip to content

Commit a2f5704

Browse files
committed
Added original DP RAM templates from Quartus and Vivado
1 parent 4563fe0 commit a2f5704

File tree

3 files changed

+244
-0
lines changed

3 files changed

+244
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Quartus Prime SystemVerilog Template
2+
//
3+
// True Dual-Port RAM with different read/write addresses and single read/write clock
4+
// and with a control for writing single bytes into the memory word; byte enable
5+
6+
// Read during write produces old data on ports A and B and old data on mixed ports
7+
// For device families that do not support this mode (e.g. Stratix V) the ram is not inferred
8+
9+
module byte_enabled_true_dual_port_ram
10+
#(
11+
parameter int
12+
BYTE_WIDTH = 8,
13+
ADDRESS_WIDTH = 6,
14+
BYTES = 4,
15+
DATA_WIDTH_R = BYTE_WIDTH * BYTES
16+
)
17+
(
18+
input [ADDRESS_WIDTH-1:0] addr1,
19+
input [ADDRESS_WIDTH-1:0] addr2,
20+
input [BYTES-1:0] be1,
21+
input [BYTES-1:0] be2,
22+
input [BYTE_WIDTH-1:0] data_in1,
23+
input [BYTE_WIDTH-1:0] data_in2,
24+
input we1, we2, clk,
25+
output [DATA_WIDTH_R-1:0] data_out1,
26+
output [DATA_WIDTH_R-1:0] data_out2);
27+
localparam RAM_DEPTH = 1 << ADDRESS_WIDTH;
28+
29+
// model the RAM with two dimensional packed array
30+
logic [BYTES-1:0][BYTE_WIDTH-1:0] ram[0:RAM_DEPTH-1];
31+
32+
reg [DATA_WIDTH_R-1:0] data_reg1;
33+
reg [DATA_WIDTH_R-1:0] data_reg2;
34+
35+
// port A
36+
always@(posedge clk)
37+
begin
38+
if(we1) begin
39+
// edit this code if using other than four bytes per word
40+
if(be1[0]) ram[addr1][0] <= data_in1;
41+
if(be1[1]) ram[addr1][1] <= data_in1;
42+
if(be1[2]) ram[addr1][2] <= data_in1;
43+
if(be1[3]) ram[addr1][3] <= data_in1;
44+
end
45+
data_reg1 <= ram[addr1];
46+
end
47+
48+
assign data_out1 = data_reg1;
49+
50+
// port B
51+
always@(posedge clk)
52+
begin
53+
if(we2) begin
54+
// edit this code if using other than four bytes per word
55+
if(be2[0]) ram[addr2][0] <= data_in2;
56+
if(be2[1]) ram[addr2][1] <= data_in2;
57+
if(be2[2]) ram[addr2][2] <= data_in2;
58+
if(be2[3]) ram[addr2][3] <= data_in2;
59+
end
60+
data_reg2 <= ram[addr2];
61+
end
62+
63+
assign data_out2 = data_reg2;
64+
65+
endmodule : byte_enabled_true_dual_port_ram
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Quartus Prime Verilog Template
2+
// True Dual Port RAM with dual clocks
3+
4+
module true_dual_port_ram_dual_clock
5+
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
6+
(
7+
input [(DATA_WIDTH-1):0] data_a, data_b,
8+
input [(ADDR_WIDTH-1):0] addr_a, addr_b,
9+
input we_a, we_b, clk_a, clk_b,
10+
output reg [(DATA_WIDTH-1):0] q_a, q_b
11+
);
12+
13+
// Declare the RAM variable
14+
reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
15+
16+
always @ (posedge clk_a)
17+
begin
18+
// Port A
19+
if (we_a)
20+
begin
21+
ram[addr_a] <= data_a;
22+
q_a <= data_a;
23+
end
24+
else
25+
begin
26+
q_a <= ram[addr_a];
27+
end
28+
end
29+
30+
always @ (posedge clk_b)
31+
begin
32+
// Port B
33+
if (we_b)
34+
begin
35+
ram[addr_b] <= data_b;
36+
q_b <= data_b;
37+
end
38+
else
39+
begin
40+
q_b <= ram[addr_b];
41+
end
42+
end
43+
44+
endmodule
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
2+
// Xilinx True Dual Port RAM, Read First, Dual Clock
3+
// This code implements a parameterizable true dual port memory (both ports can read and write).
4+
// The behavior of this RAM is when data is written, the prior memory contents at the write
5+
// address are presented on the output port. If the output data is
6+
// not needed during writes or the last read value is desired to be retained,
7+
// it is suggested to use a no change RAM as it is more power efficient.
8+
// If a reset or enable is not necessary, it may be tied off or removed from the code.
9+
10+
module xilinx_true_dual_port_read_first_2_clock_ram #(
11+
parameter RAM_WIDTH = 18, // Specify RAM data width
12+
parameter RAM_DEPTH = 1024, // Specify RAM depth (number of entries)
13+
parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY"
14+
parameter INIT_FILE = "" // Specify name/location of RAM initialization file if using one (leave blank if not)
15+
) (
16+
input [clogb2(RAM_DEPTH-1)-1:0] addra, // Port A address bus, width determined from RAM_DEPTH
17+
input [clogb2(RAM_DEPTH-1)-1:0] addrb, // Port B address bus, width determined from RAM_DEPTH
18+
input [RAM_WIDTH-1:0] dina, // Port A RAM input data
19+
input [RAM_WIDTH-1:0] dinb, // Port B RAM input data
20+
input clka, // Port A clock
21+
input clkb, // Port B clock
22+
input wea, // Port A write enable
23+
input web, // Port B write enable
24+
input ena, // Port A RAM Enable, for additional power savings, disable port when not in use
25+
input enb, // Port B RAM Enable, for additional power savings, disable port when not in use
26+
input rsta, // Port A output reset (does not affect memory contents)
27+
input rstb, // Port B output reset (does not affect memory contents)
28+
input regcea, // Port A output register enable
29+
input regceb, // Port B output register enable
30+
output [RAM_WIDTH-1:0] douta, // Port A RAM output data
31+
output [RAM_WIDTH-1:0] doutb // Port B RAM output data
32+
);
33+
34+
reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0];
35+
reg [RAM_WIDTH-1:0] ram_data_a = {RAM_WIDTH{1'b0}};
36+
reg [RAM_WIDTH-1:0] ram_data_b = {RAM_WIDTH{1'b0}};
37+
38+
// The following code either initializes the memory values to a specified file or to all zeros to match hardware
39+
generate
40+
if (INIT_FILE != "") begin: use_init_file
41+
initial
42+
$readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1);
43+
end else begin: init_bram_to_zero
44+
integer ram_index;
45+
initial
46+
for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1)
47+
BRAM[ram_index] = {RAM_WIDTH{1'b0}};
48+
end
49+
endgenerate
50+
51+
always @(posedge clka)
52+
if (ena) begin
53+
if (wea)
54+
BRAM[addra] <= dina;
55+
ram_data_a <= BRAM[addra];
56+
end
57+
58+
always @(posedge clkb)
59+
if (enb) begin
60+
if (web)
61+
BRAM[addrb] <= dinb;
62+
ram_data_b <= BRAM[addrb];
63+
end
64+
65+
// The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register)
66+
generate
67+
if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register
68+
69+
// The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing
70+
assign douta = ram_data_a;
71+
assign doutb = ram_data_b;
72+
73+
end else begin: output_register
74+
75+
// The following is a 2 clock cycle read latency with improve clock-to-out timing
76+
77+
reg [RAM_WIDTH-1:0] douta_reg = {RAM_WIDTH{1'b0}};
78+
reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}};
79+
80+
always @(posedge clka)
81+
if (rsta)
82+
douta_reg <= {RAM_WIDTH{1'b0}};
83+
else if (regcea)
84+
douta_reg <= ram_data_a;
85+
86+
always @(posedge clkb)
87+
if (rstb)
88+
doutb_reg <= {RAM_WIDTH{1'b0}};
89+
else if (regceb)
90+
doutb_reg <= ram_data_b;
91+
92+
assign douta = douta_reg;
93+
assign doutb = doutb_reg;
94+
95+
end
96+
endgenerate
97+
98+
// The following function calculates the address width based on specified RAM depth
99+
function integer clogb2;
100+
input integer depth;
101+
for (clogb2=0; depth>0; clogb2=clogb2+1)
102+
depth = depth >> 1;
103+
endfunction
104+
105+
endmodule
106+
107+
// The following is an instantiation template for xilinx_true_dual_port_read_first_2_clock_ram
108+
/*
109+
// Xilinx True Dual Port RAM, Read First, Dual Clock
110+
xilinx_true_dual_port_read_first_2_clock_ram #(
111+
.RAM_WIDTH(18), // Specify RAM data width
112+
.RAM_DEPTH(1024), // Specify RAM depth (number of entries)
113+
.RAM_PERFORMANCE("HIGH_PERFORMANCE"), // Select "HIGH_PERFORMANCE" or "LOW_LATENCY"
114+
.INIT_FILE("") // Specify name/location of RAM initialization file if using one (leave blank if not)
115+
) your_instance_name (
116+
.addra(addra), // Port A address bus, width determined from RAM_DEPTH
117+
.addrb(addrb), // Port B address bus, width determined from RAM_DEPTH
118+
.dina(dina), // Port A RAM input data, width determined from RAM_WIDTH
119+
.dinb(dinb), // Port B RAM input data, width determined from RAM_WIDTH
120+
.clka(clka), // Port A clock
121+
.clkb(clkb), // Port B clock
122+
.wea(wea), // Port A write enable
123+
.web(web), // Port B write enable
124+
.ena(ena), // Port A RAM Enable, for additional power savings, disable port when not in use
125+
.enb(enb), // Port B RAM Enable, for additional power savings, disable port when not in use
126+
.rsta(rsta), // Port A output reset (does not affect memory contents)
127+
.rstb(rstb), // Port B output reset (does not affect memory contents)
128+
.regcea(regcea), // Port A output register enable
129+
.regceb(regceb), // Port B output register enable
130+
.douta(douta), // Port A RAM output data, width determined from RAM_WIDTH
131+
.douta(douta) // Port B RAM output data, width determined from RAM_WIDTH
132+
);
133+
*/
134+
135+

0 commit comments

Comments
 (0)