mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Merge pull request #3403 from KrystalDelusion/mem-tests
This commit is contained in:
commit
c8966722d2
|
@ -22,7 +22,6 @@ module sync_ram_sp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
endmodule // sync_ram_sp
|
endmodule // sync_ram_sp
|
||||||
|
|
||||||
|
|
||||||
`default_nettype none
|
|
||||||
module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
(input wire clk, write_enable,
|
(input wire clk, write_enable,
|
||||||
input wire [DATA_WIDTH-1:0] data_in,
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
@ -45,3 +44,33 @@ module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
|
|
||||||
endmodule // sync_ram_sdp
|
endmodule // sync_ram_sdp
|
||||||
|
|
||||||
|
|
||||||
|
module sync_ram_tdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
|
(input wire clk_a, clk_b,
|
||||||
|
input wire write_enable_a, write_enable_b,
|
||||||
|
input wire read_enable_a, read_enable_b,
|
||||||
|
input wire [DATA_WIDTH-1:0] write_data_a, write_data_b,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] addr_a, addr_b,
|
||||||
|
output reg [DATA_WIDTH-1:0] read_data_a, read_data_b);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] mem [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk_a) begin
|
||||||
|
if (write_enable_a)
|
||||||
|
mem[addr_a] <= write_data_a;
|
||||||
|
else
|
||||||
|
read_data_a <= mem[addr_a];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk_b) begin
|
||||||
|
if (write_enable_b)
|
||||||
|
mem[addr_b] <= write_data_b;
|
||||||
|
else
|
||||||
|
read_data_b <= mem[addr_b];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule // sync_ram_tdp
|
||||||
|
|
||||||
|
|
32
tests/arch/ecp5/bug1836.mem
Normal file
32
tests/arch/ecp5/bug1836.mem
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
0x8000,0x8324,0x8647,0x896a,0x8c8b,0x8fab,0x92c7,0x95e1,
|
||||||
|
0x98f8,0x9c0b,0x9f19,0xa223,0xa527,0xa826,0xab1f,0xae10,
|
||||||
|
0xb0fb,0xb3de,0xb6b9,0xb98c,0xbc56,0xbf17,0xc1cd,0xc47a,
|
||||||
|
0xc71c,0xc9b3,0xcc3f,0xcebf,0xd133,0xd39a,0xd5f5,0xd842,
|
||||||
|
0xda82,0xdcb3,0xded7,0xe0eb,0xe2f1,0xe4e8,0xe6cf,0xe8a6,
|
||||||
|
0xea6d,0xec23,0xedc9,0xef5e,0xf0e2,0xf254,0xf3b5,0xf504,
|
||||||
|
0xf641,0xf76b,0xf884,0xf989,0xfa7c,0xfb5c,0xfc29,0xfce3,
|
||||||
|
0xfd89,0xfe1d,0xfe9c,0xff09,0xff61,0xffa6,0xffd8,0xfff5,
|
||||||
|
0xffff,0xfff5,0xffd8,0xffa6,0xff61,0xff09,0xfe9c,0xfe1d,
|
||||||
|
0xfd89,0xfce3,0xfc29,0xfb5c,0xfa7c,0xf989,0xf884,0xf76b,
|
||||||
|
0xf641,0xf504,0xf3b5,0xf254,0xf0e2,0xef5e,0xedc9,0xec23,
|
||||||
|
0xea6d,0xe8a6,0xe6cf,0xe4e8,0xe2f1,0xe0eb,0xded7,0xdcb3,
|
||||||
|
0xda82,0xd842,0xd5f5,0xd39a,0xd133,0xcebf,0xcc3f,0xc9b3,
|
||||||
|
0xc71c,0xc47a,0xc1cd,0xbf17,0xbc56,0xb98c,0xb6b9,0xb3de,
|
||||||
|
0xb0fb,0xae10,0xab1f,0xa826,0xa527,0xa223,0x9f19,0x9c0b,
|
||||||
|
0x98f8,0x95e1,0x92c7,0x8fab,0x8c8b,0x896a,0x8647,0x8324,
|
||||||
|
0x8000,0x7cdb,0x79b8,0x7695,0x7374,0x7054,0x6d38,0x6a1e,
|
||||||
|
0x6707,0x63f4,0x60e6,0x5ddc,0x5ad8,0x57d9,0x54e0,0x51ef,
|
||||||
|
0x4f04,0x4c21,0x4946,0x4673,0x43a9,0x40e8,0x3e32,0x3b85,
|
||||||
|
0x38e3,0x364c,0x33c0,0x3140,0x2ecc,0x2c65,0x2a0a,0x27bd,
|
||||||
|
0x257d,0x234c,0x2128,0x1f14,0x1d0e,0x1b17,0x1930,0x1759,
|
||||||
|
0x1592,0x13dc,0x1236,0x10a1,0xf1d,0xdab,0xc4a,0xafb,
|
||||||
|
0x9be,0x894,0x77b,0x676,0x583,0x4a3,0x3d6,0x31c,
|
||||||
|
0x276,0x1e2,0x163,0xf6,0x9e,0x59,0x27,0xa,
|
||||||
|
0x0,0xa,0x27,0x59,0x9e,0xf6,0x163,0x1e2,
|
||||||
|
0x276,0x31c,0x3d6,0x4a3,0x583,0x676,0x77b,0x894,
|
||||||
|
0x9be,0xafb,0xc4a,0xdab,0xf1d,0x10a1,0x1236,0x13dc,
|
||||||
|
0x1592,0x1759,0x1930,0x1b17,0x1d0e,0x1f14,0x2128,0x234c,
|
||||||
|
0x257d,0x27bd,0x2a0a,0x2c65,0x2ecc,0x3140,0x33c0,0x364c,
|
||||||
|
0x38e3,0x3b85,0x3e32,0x40e8,0x43a9,0x4673,0x4946,0x4c21,
|
||||||
|
0x4f04,0x51ef,0x54e0,0x57d9,0x5ad8,0x5ddc,0x60e6,0x63f4,
|
||||||
|
0x6707,0x6a1e,0x6d38,0x7054,0x7374,0x7695,0x79b8,0x7cdb,
|
23
tests/arch/ecp5/bug1836.ys
Normal file
23
tests/arch/ecp5/bug1836.ys
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module top(
|
||||||
|
input clk,
|
||||||
|
output reg [15:0] sig1, sig2
|
||||||
|
);
|
||||||
|
reg [7:0] ptr1, ptr2;
|
||||||
|
reg [15:0] mem [0:255];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$readmemh("bug1836.mem", mem);
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
sig1 <= mem[ptr1];
|
||||||
|
ptr1 <= ptr1 + 3;
|
||||||
|
sig2 <= mem[ptr2];
|
||||||
|
ptr2 <= ptr2 + 7;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_ecp5 -top top
|
||||||
|
select -assert-count 1 t:DP16KD
|
|
@ -260,3 +260,13 @@ setattr -set logic_block 1 m:memory
|
||||||
synth_ecp5 -top sync_rom; cd sync_rom
|
synth_ecp5 -top sync_rom; cd sync_rom
|
||||||
select -assert-count 0 t:DP16KD # requested LUTROM explicitly
|
select -assert-count 0 t:DP16KD # requested LUTROM explicitly
|
||||||
select -assert-min 9 t:LUT4
|
select -assert-min 9 t:LUT4
|
||||||
|
|
||||||
|
# ============================== TDP RAM ==============================
|
||||||
|
# RAM bits <= 18K; Data width <= 18x2; Address width <= 9: -> DP16KD
|
||||||
|
|
||||||
|
design -reset; read_verilog -defer ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 18 sync_ram_tdp
|
||||||
|
hierarchy -top sync_ram_tdp
|
||||||
|
synth_ecp5 -top sync_ram_tdp; cd sync_ram_tdp
|
||||||
|
select -assert-count 1 t:DP16KD
|
||||||
|
select -assert-none t:LUT4
|
||||||
|
|
|
@ -6,6 +6,14 @@ cd sync_ram_sdp
|
||||||
select -assert-count 1 t:CC_BUFG
|
select -assert-count 1 t:CC_BUFG
|
||||||
select -assert-count 1 t:CC_BRAM_20K
|
select -assert-count 1 t:CC_BRAM_20K
|
||||||
|
|
||||||
|
# 512 x 20 bit x 2 -> CC_BRAM_20K TDP RAM
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 20 sync_ram_tdp
|
||||||
|
synth_gatemate -top sync_ram_tdp -noiopad
|
||||||
|
select -assert-count 2 t:CC_BUFG
|
||||||
|
select -assert-count 1 t:CC_BRAM_20K
|
||||||
|
|
||||||
# 512 x 80 bit -> CC_BRAM_40K SDP RAM
|
# 512 x 80 bit -> CC_BRAM_40K SDP RAM
|
||||||
design -reset
|
design -reset
|
||||||
read_verilog ../common/blockram.v
|
read_verilog ../common/blockram.v
|
||||||
|
|
22
tests/arch/ice40/spram.v
Normal file
22
tests/arch/ice40/spram.v
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
module top (clk, write_enable, read_enable, write_data, addr, read_data);
|
||||||
|
parameter DATA_WIDTH = 8;
|
||||||
|
parameter ADDR_WIDTH = 8;
|
||||||
|
parameter SKIP_RDEN = 1;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input write_enable, read_enable;
|
||||||
|
input [DATA_WIDTH - 1 : 0] write_data;
|
||||||
|
input [ADDR_WIDTH - 1 : 0] addr;
|
||||||
|
output [DATA_WIDTH - 1 : 0] read_data;
|
||||||
|
|
||||||
|
(* ram_style = "huge" *)
|
||||||
|
reg [DATA_WIDTH - 1 : 0] mem [2**ADDR_WIDTH - 1 : 0];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
mem[addr] <= write_data;
|
||||||
|
else if (SKIP_RDEN || read_enable)
|
||||||
|
read_data <= mem[addr];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
15
tests/arch/ice40/spram.ys
Normal file
15
tests/arch/ice40/spram.ys
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
read_verilog spram.v
|
||||||
|
hierarchy -top top
|
||||||
|
synth_ice40
|
||||||
|
select -assert-count 1 t:SB_SPRAM256KA
|
||||||
|
select -assert-none t:SB_SPRAM256KA %% t:* %D
|
||||||
|
|
||||||
|
# Testing with pattern as described in pattern document
|
||||||
|
design -reset
|
||||||
|
read_verilog spram.v
|
||||||
|
chparam -set SKIP_RDEN 0
|
||||||
|
hierarchy -top top
|
||||||
|
synth_ice40
|
||||||
|
select -assert-count 1 t:SB_SPRAM256KA
|
||||||
|
# Below fails due to extra SB_LUT4
|
||||||
|
# select -assert-none t:SB_SPRAM256KA %% t:* %D
|
|
@ -1,6 +1,6 @@
|
||||||
read_verilog ../common/blockram.v
|
read_verilog ../common/blockram.v
|
||||||
chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp
|
chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp
|
||||||
synth_intel_alm -family cyclonev -noiopad -noclkbuf
|
synth_intel_alm -top sync_ram_sdp -family cyclonev -noiopad -noclkbuf
|
||||||
cd sync_ram_sdp
|
cd sync_ram_sdp
|
||||||
select -assert-count 1 t:MISTRAL_NOT
|
select -assert-count 1 t:MISTRAL_NOT
|
||||||
select -assert-count 1 t:MISTRAL_M10K
|
select -assert-count 1 t:MISTRAL_M10K
|
||||||
|
|
50
tests/arch/xilinx/asym_ram_sdp.ys
Normal file
50
tests/arch/xilinx/asym_ram_sdp.ys
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Memory bits <= 18K; Data width <= 36; Address width <= 14: -> RAMB18E1
|
||||||
|
|
||||||
|
# w4b | r16b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_read_wider.v
|
||||||
|
synth_xilinx -top asym_ram_sdp_read_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w8b | r16b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_read_wider.v
|
||||||
|
chparam -set WIDTHA 8 -set SIZEA 512 -set ADDRWIDTHA 9 asym_ram_sdp_read_wider
|
||||||
|
synth_xilinx -top asym_ram_sdp_read_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w4b | r32b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_read_wider.v
|
||||||
|
chparam -set WIDTHB 32 -set SIZEB 128 -set ADDRWIDTHB 7 asym_ram_sdp_read_wider
|
||||||
|
synth_xilinx -top asym_ram_sdp_read_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w16b | r4b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_write_wider.v
|
||||||
|
synth_xilinx -top asym_ram_sdp_write_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w16b | r8b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_write_wider.v
|
||||||
|
chparam -set WIDTHB 8 -set SIZEB 512 -set ADDRWIDTHB 9 asym_ram_sdp_read_wider
|
||||||
|
synth_xilinx -top asym_ram_sdp_write_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w32b | r4b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_write_wider.v
|
||||||
|
chparam -set WIDTHA 32 -set SIZEA 128 -set ADDRWIDTHA 7 asym_ram_sdp_read_wider
|
||||||
|
synth_xilinx -top asym_ram_sdp_write_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# w4b | r24b
|
||||||
|
design -reset
|
||||||
|
read_verilog asym_ram_sdp_read_wider.v
|
||||||
|
chparam -set SIZEA 768
|
||||||
|
chparam -set WIDTHB 24 -set SIZEB 128 -set ADDRWIDTHB 7 asym_ram_sdp_read_wider
|
||||||
|
synth_xilinx -top asym_ram_sdp_read_wider -noiopad
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
72
tests/arch/xilinx/asym_ram_sdp_read_wider.v
Normal file
72
tests/arch/xilinx/asym_ram_sdp_read_wider.v
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Asymmetric port RAM
|
||||||
|
// Read Wider than Write. Read Statement in loop
|
||||||
|
//asym_ram_sdp_read_wider.v
|
||||||
|
module asym_ram_sdp_read_wider (clkA, clkB, enaA, weA, enaB, addrA, addrB, diA, doB);
|
||||||
|
parameter WIDTHA = 4;
|
||||||
|
parameter SIZEA = 1024;
|
||||||
|
parameter ADDRWIDTHA = 10;
|
||||||
|
|
||||||
|
parameter WIDTHB = 16;
|
||||||
|
parameter SIZEB = 256;
|
||||||
|
parameter ADDRWIDTHB = 8;
|
||||||
|
|
||||||
|
input clkA;
|
||||||
|
input clkB;
|
||||||
|
input weA;
|
||||||
|
input enaA, enaB;
|
||||||
|
input [ADDRWIDTHA-1:0] addrA;
|
||||||
|
input [ADDRWIDTHB-1:0] addrB;
|
||||||
|
input [WIDTHA-1:0] diA;
|
||||||
|
output [WIDTHB-1:0] doB;
|
||||||
|
|
||||||
|
`define max(a,b) {(a) > (b) ? (a) : (b)}
|
||||||
|
`define min(a,b) {(a) < (b) ? (a) : (b)}
|
||||||
|
|
||||||
|
function integer log2;
|
||||||
|
input integer value;
|
||||||
|
reg [31:0] shifted;
|
||||||
|
integer res;
|
||||||
|
begin
|
||||||
|
if (value < 2)
|
||||||
|
log2 = value;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
shifted = value-1;
|
||||||
|
for (res=0; shifted>0; res=res+1)
|
||||||
|
shifted = shifted>>1;
|
||||||
|
log2 = res;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
localparam maxSIZE = `max(SIZEA, SIZEB);
|
||||||
|
localparam maxWIDTH = `max(WIDTHA, WIDTHB);
|
||||||
|
localparam minWIDTH = `min(WIDTHA, WIDTHB);
|
||||||
|
|
||||||
|
localparam RATIO = maxWIDTH / minWIDTH;
|
||||||
|
localparam log2RATIO = log2(RATIO);
|
||||||
|
|
||||||
|
reg [minWIDTH-1:0] RAM [0:maxSIZE-1];
|
||||||
|
reg [WIDTHB-1:0] readB;
|
||||||
|
|
||||||
|
always @(posedge clkA)
|
||||||
|
begin
|
||||||
|
if (enaA) begin
|
||||||
|
if (weA)
|
||||||
|
RAM[addrA] <= diA;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clkB)
|
||||||
|
begin : ramread
|
||||||
|
integer i;
|
||||||
|
reg [log2RATIO-1:0] lsbaddr;
|
||||||
|
if (enaB) begin
|
||||||
|
for (i = 0; i < RATIO; i = i+1) begin
|
||||||
|
lsbaddr = i;
|
||||||
|
readB[(i+1)*minWIDTH-1 -: minWIDTH] <= RAM[{addrB, lsbaddr}];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assign doB = readB;
|
||||||
|
endmodule
|
71
tests/arch/xilinx/asym_ram_sdp_write_wider.v
Normal file
71
tests/arch/xilinx/asym_ram_sdp_write_wider.v
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Asymmetric port RAM
|
||||||
|
// Write wider than Read. Write Statement in a loop.
|
||||||
|
// asym_ram_sdp_write_wider.v
|
||||||
|
module asym_ram_sdp_write_wider (clkA, clkB, weA, enaA, enaB, addrA, addrB, diA, doB);
|
||||||
|
parameter WIDTHB = 4;
|
||||||
|
parameter SIZEB = 1024;
|
||||||
|
parameter ADDRWIDTHB = 10;
|
||||||
|
|
||||||
|
parameter WIDTHA = 16;
|
||||||
|
parameter SIZEA = 256;
|
||||||
|
parameter ADDRWIDTHA = 8;
|
||||||
|
|
||||||
|
input clkA;
|
||||||
|
input clkB;
|
||||||
|
input weA;
|
||||||
|
input enaA, enaB;
|
||||||
|
input [ADDRWIDTHA-1:0] addrA;
|
||||||
|
input [ADDRWIDTHB-1:0] addrB;
|
||||||
|
input [WIDTHA-1:0] diA;
|
||||||
|
output [WIDTHB-1:0] doB;
|
||||||
|
|
||||||
|
`define max(a,b) {(a) > (b) ? (a) : (b)}
|
||||||
|
`define min(a,b) {(a) < (b) ? (a) : (b)}
|
||||||
|
|
||||||
|
function integer log2;
|
||||||
|
input integer value;
|
||||||
|
reg [31:0] shifted;
|
||||||
|
integer res;
|
||||||
|
begin
|
||||||
|
if (value < 2)
|
||||||
|
log2 = value;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
shifted = value-1;
|
||||||
|
for (res=0; shifted>0; res=res+1)
|
||||||
|
shifted = shifted>>1;
|
||||||
|
log2 = res;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
localparam maxSIZE = `max(SIZEA, SIZEB);
|
||||||
|
localparam maxWIDTH = `max(WIDTHA, WIDTHB);
|
||||||
|
localparam minWIDTH = `min(WIDTHA, WIDTHB);
|
||||||
|
|
||||||
|
localparam RATIO = maxWIDTH / minWIDTH;
|
||||||
|
localparam log2RATIO = log2(RATIO);
|
||||||
|
|
||||||
|
reg [minWIDTH-1:0] RAM [0:maxSIZE-1];
|
||||||
|
reg [WIDTHB-1:0] readB;
|
||||||
|
|
||||||
|
always @(posedge clkB) begin
|
||||||
|
if (enaB) begin
|
||||||
|
readB <= RAM[addrB];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assign doB = readB;
|
||||||
|
|
||||||
|
always @(posedge clkA)
|
||||||
|
begin : ramwrite
|
||||||
|
integer i;
|
||||||
|
reg [log2RATIO-1:0] lsbaddr;
|
||||||
|
for (i=0; i< RATIO; i= i+ 1) begin : write1
|
||||||
|
lsbaddr = i;
|
||||||
|
if (enaA) begin
|
||||||
|
if (weA)
|
||||||
|
RAM[{addrA, lsbaddr}] <= diA[(i+1)*minWIDTH-1 -: minWIDTH];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
122
tests/arch/xilinx/priority_memory.v
Normal file
122
tests/arch/xilinx/priority_memory.v
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
module priority_memory (
|
||||||
|
clk, wren_a, rden_a, addr_a, wdata_a, rdata_a,
|
||||||
|
wren_b, rden_b, addr_b, wdata_b, rdata_b
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter ABITS = 12;
|
||||||
|
parameter WIDTH = 72;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input wren_a, rden_a, wren_b, rden_b;
|
||||||
|
input [ABITS-1:0] addr_a, addr_b;
|
||||||
|
input [WIDTH-1:0] wdata_a, wdata_b;
|
||||||
|
output reg [WIDTH-1:0] rdata_a, rdata_b;
|
||||||
|
|
||||||
|
`ifdef USE_HUGE
|
||||||
|
(* ram_style = "huge" *)
|
||||||
|
`endif
|
||||||
|
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
rdata_a <= 'h0;
|
||||||
|
rdata_b <= 'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
`ifndef FLIP_PORTS
|
||||||
|
always @(posedge clk) begin
|
||||||
|
// A port
|
||||||
|
if (wren_a)
|
||||||
|
mem[addr_a] <= wdata_a;
|
||||||
|
else if (rden_a)
|
||||||
|
rdata_a <= mem[addr_a];
|
||||||
|
|
||||||
|
// B port
|
||||||
|
if (wren_b)
|
||||||
|
mem[addr_b] <= wdata_b;
|
||||||
|
else if (rden_b)
|
||||||
|
if (wren_a && addr_a == addr_b)
|
||||||
|
rdata_b <= wdata_a;
|
||||||
|
else
|
||||||
|
rdata_b <= mem[addr_b];
|
||||||
|
end
|
||||||
|
`else // FLIP PORTS
|
||||||
|
always @(posedge clk) begin
|
||||||
|
// A port
|
||||||
|
if (wren_b)
|
||||||
|
mem[addr_b] <= wdata_b;
|
||||||
|
else if (rden_b)
|
||||||
|
rdata_b <= mem[addr_b];
|
||||||
|
|
||||||
|
// B port
|
||||||
|
if (wren_a)
|
||||||
|
mem[addr_a] <= wdata_a;
|
||||||
|
else if (rden_a)
|
||||||
|
if (wren_b && addr_a == addr_b)
|
||||||
|
rdata_a <= wdata_b;
|
||||||
|
else
|
||||||
|
rdata_a <= mem[addr_a];
|
||||||
|
end
|
||||||
|
`endif
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sp_write_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
|
|
||||||
|
parameter ABITS = 12;
|
||||||
|
parameter WIDTH = 72;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input wren_a, rden_a;
|
||||||
|
input [ABITS-1:0] addr_a;
|
||||||
|
input [WIDTH-1:0] wdata_a;
|
||||||
|
output reg [WIDTH-1:0] rdata_a;
|
||||||
|
|
||||||
|
(* ram_style = "huge" *)
|
||||||
|
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
rdata_a <= 'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
// A port
|
||||||
|
if (wren_a)
|
||||||
|
mem[addr_a] <= wdata_a;
|
||||||
|
if (rden_a)
|
||||||
|
if (wren_a)
|
||||||
|
rdata_a <= wdata_a;
|
||||||
|
else
|
||||||
|
rdata_a <= mem[addr_a];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
|
|
||||||
|
parameter ABITS = 12;
|
||||||
|
parameter WIDTH = 72;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input wren_a, rden_a;
|
||||||
|
input [ABITS-1:0] addr_a;
|
||||||
|
input [WIDTH-1:0] wdata_a;
|
||||||
|
output reg [WIDTH-1:0] rdata_a;
|
||||||
|
|
||||||
|
(* ram_style = "huge" *)
|
||||||
|
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
rdata_a <= 'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
// A port
|
||||||
|
if (wren_a)
|
||||||
|
mem[addr_a] <= wdata_a;
|
||||||
|
if (rden_a)
|
||||||
|
rdata_a <= mem[addr_a];
|
||||||
|
end
|
||||||
|
endmodule
|
60
tests/arch/xilinx/priority_memory.ys
Normal file
60
tests/arch/xilinx/priority_memory.ys
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
# no uram by default
|
||||||
|
design -reset
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top priority_memory
|
||||||
|
select -assert-none t:URAM288
|
||||||
|
|
||||||
|
# uram parameter
|
||||||
|
design -reset
|
||||||
|
read -define USE_HUGE
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top priority_memory -noiopad
|
||||||
|
select -assert-count 1 t:URAM288
|
||||||
|
|
||||||
|
# uram option
|
||||||
|
design -reset
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top priority_memory -noiopad -uram
|
||||||
|
# check for URAM block
|
||||||
|
select -assert-count 1 t:URAM288
|
||||||
|
# check port A in code maps to port A in hardware:
|
||||||
|
# %co:+[DOUT_A] selects everything connected to a URAM288.DOUT_A port
|
||||||
|
# w:rdata_a selects the wire rdata_a
|
||||||
|
# %i finds the intersection of the two above selections
|
||||||
|
# if the result is 1 then the wire rdata_a is connected to Port A correctly
|
||||||
|
select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
|
||||||
|
# we expect no more than 2 LUT2s to control the hardware priority
|
||||||
|
# if there are extra LUTs, then it is likely emulating logic it shouldn't
|
||||||
|
# ignore anything using blif, since that doesn't seem to support priority logic
|
||||||
|
# and is indicative of using verific/tabby
|
||||||
|
select -assert-max 2 t:LUT* n:*blif* %d
|
||||||
|
|
||||||
|
# reverse priority
|
||||||
|
design -reset
|
||||||
|
read -define FLIP_PORTS
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top priority_memory -noiopad -uram
|
||||||
|
# test priority is mapped correctly, rdata_a should now be connected to Port B
|
||||||
|
# see above for details
|
||||||
|
select -assert-count 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
|
||||||
|
|
||||||
|
# sp write first
|
||||||
|
design -reset
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top sp_write_first -noiopad
|
||||||
|
select -assert-count 1 t:URAM288
|
||||||
|
# write first connects rdata_a to port B
|
||||||
|
# similar to above, but also tests that rdata_a *isn't* connected to port A
|
||||||
|
select -assert-none 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
|
||||||
|
select -assert-count 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
|
||||||
|
|
||||||
|
# sp read first
|
||||||
|
design -reset
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top sp_read_first -noiopad
|
||||||
|
select -assert-count 1 t:URAM288
|
||||||
|
# read first connects rdata_a to port A
|
||||||
|
# see above for details
|
||||||
|
select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
|
||||||
|
select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
|
|
@ -1,13 +1,6 @@
|
||||||
# TODO:
|
# TODO:
|
||||||
|
|
||||||
# - memory initialization
|
|
||||||
# - clock polarity combinations
|
|
||||||
# - CE/srst/rdwr/be interactions
|
|
||||||
# - priority logic
|
# - priority logic
|
||||||
# - byte enables, wrbe_separate
|
|
||||||
# - duplication for read ports
|
|
||||||
# - abits/dbits determination
|
|
||||||
# - mixed width
|
|
||||||
# - swizzles for weird width progressions
|
# - swizzles for weird width progressions
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +15,7 @@ class Test:
|
||||||
TESTS = []
|
TESTS = []
|
||||||
|
|
||||||
### basic sanity tests
|
### basic sanity tests
|
||||||
|
# Asynchronous-read RAM
|
||||||
|
|
||||||
ASYNC = """
|
ASYNC = """
|
||||||
module top(clk, ra, wa, rd, wd, we);
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
@ -56,6 +50,7 @@ TESTS += [
|
||||||
Test("async_small_block", ASYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}),
|
Test("async_small_block", ASYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Synchronous SDP read first
|
||||||
SYNC = """
|
SYNC = """
|
||||||
module top(clk, ra, wa, rd, wd, we);
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
@ -95,6 +90,261 @@ TESTS += [
|
||||||
Test("sync_small_block_attr", SYNC_SMALL_BLOCK, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 1}),
|
Test("sync_small_block_attr", SYNC_SMALL_BLOCK, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 1}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
### initialization values testing
|
||||||
|
LUT_INIT = """
|
||||||
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] ra, wa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output wire [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial
|
||||||
|
for (i = 0; i < 2**ABITS-1; i = i + 1)
|
||||||
|
mem[i] = {ival};
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
assign rd = mem[ra];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
INIT_LUT_ZEROS = LUT_INIT.format(abits=4, dbits=4, ival=0);
|
||||||
|
INIT_LUT_VAL = LUT_INIT.format(abits=4, dbits=4, ival=5);
|
||||||
|
INIT_LUT_VAL2 = LUT_INIT.format(abits=6, dbits=6, ival="6'h12");
|
||||||
|
INIT_LUT_X = LUT_INIT.format(abits=4, dbits=4, ival="4'hx")
|
||||||
|
|
||||||
|
TESTS += [
|
||||||
|
Test("init_lut_zeros_zero", INIT_LUT_ZEROS, ["lut"], ["INIT_ZERO"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_zeros_any", INIT_LUT_ZEROS, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_val_zero", INIT_LUT_VAL, ["lut"], ["INIT_ZERO"], {"RAM_LUT":0}), #CHECK: no emulation?
|
||||||
|
Test("init_lut_val_any", INIT_LUT_VAL, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_val_no_undef", INIT_LUT_VAL, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_val2_any", INIT_LUT_VAL2, ["lut"], ["INIT_ANY"], {"RAM_LUT":8}),
|
||||||
|
Test("init_lut_val2_no_undef", INIT_LUT_VAL2, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":8}),
|
||||||
|
Test("init_lut_x_none", INIT_LUT_X, ["lut"], ["INIT_NONE"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_x_zero", INIT_LUT_X, ["lut"], ["INIT_ZERO"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_x_any", INIT_LUT_X, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}),
|
||||||
|
Test("init_lut_x_no_undef", INIT_LUT_X, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":1}),
|
||||||
|
]
|
||||||
|
|
||||||
|
### width testing 9-bit-per-byte
|
||||||
|
RAM_9b1B = """
|
||||||
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] ra, wa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output reg [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
rd <= mem[ra];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
RAM_18b2B = RAM_9b1B.format(abits=3, dbits=18);
|
||||||
|
RAM_9b1B = RAM_9b1B.format(abits=4, dbits=9);
|
||||||
|
RAM_4b1B = RAM_9b1B.format(abits=5, dbits=4);
|
||||||
|
RAM_2b1B = RAM_9b1B.format(abits=6, dbits=2);
|
||||||
|
RAM_1b1B = RAM_9b1B.format(abits=7, dbits=1);
|
||||||
|
|
||||||
|
TESTS += [
|
||||||
|
Test("ram_18b2B", RAM_18b2B, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("ram_9b1B", RAM_9b1B, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("ram_4b1B", RAM_4b1B, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("ram_2b1B", RAM_2b1B, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("ram_1b1B", RAM_1b1B, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
]
|
||||||
|
|
||||||
|
### initializing 9-bits-per-byte
|
||||||
|
RAM_9b1B_init = """
|
||||||
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] ra, wa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output reg [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial
|
||||||
|
for (i = 0; i < 2**ABITS-1; i = i + 1)
|
||||||
|
mem[i] = {ival};
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
rd <= mem[ra];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
INIT_9b1B_ZEROS = RAM_9b1B_init.format(abits=4, dbits=9, ival=0);
|
||||||
|
INIT_9b1B_VAL = RAM_9b1B_init.format(abits=4, dbits=9, ival=275);
|
||||||
|
INIT_13b2B_VAL = RAM_9b1B_init.format(abits=3, dbits=13, ival="13'h01f3")
|
||||||
|
INIT_18b2B_VAL = RAM_9b1B_init.format(abits=4, dbits=18, ival="18'h1f39a");
|
||||||
|
INIT_4b1B_X = RAM_9b1B_init.format(abits=5, dbits=4, ival="4'hx")
|
||||||
|
|
||||||
|
TESTS += [
|
||||||
|
Test("init_9b1B_zeros_zero", INIT_9b1B_ZEROS, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_9b1B_zeros_any", INIT_9b1B_ZEROS, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_9b1B_val_zero", INIT_9b1B_VAL, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":0}), #CHECK: no emulation?
|
||||||
|
Test("init_9b1B_val_any", INIT_9b1B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_9b1B_val_no_undef", INIT_9b1B_VAL, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_13b2B_val_any", INIT_13b2B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_18b2B_val_any", INIT_18b2B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":2}),
|
||||||
|
Test("init_18b2B_val_no_undef", INIT_18b2B_VAL, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":2}),
|
||||||
|
Test("init_4b1B_x_none", INIT_4b1B_X, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_4b1B_x_zero", INIT_4b1B_X, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_4b1B_x_any", INIT_4b1B_X, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}),
|
||||||
|
Test("init_4b1B_x_no_undef", INIT_4b1B_X, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":1}),
|
||||||
|
]
|
||||||
|
|
||||||
|
### Clock polarity combinations
|
||||||
|
# I'm not entirely convinced auto-test is correctly testing clock edging
|
||||||
|
# but they do at least all gen/synth
|
||||||
|
SYNCCLOCK = """
|
||||||
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = 8;
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] ra, wa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output reg [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
rd <= mem[ra];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
for (abits, cnt, wclk, rclk, shared) in [
|
||||||
|
(4, 1, "ANY","ANY", False),
|
||||||
|
(4, 1, "ANY","NEG", False),
|
||||||
|
(4, 1, "ANY","POS", False),
|
||||||
|
(4, 1, "NEG","ANY", False),
|
||||||
|
(4, 1, "NEG","POS", False),
|
||||||
|
(4, 1, "NEG","NEG", False),
|
||||||
|
(4, 1, "POS","ANY", False),
|
||||||
|
(4, 1, "POS","NEG", False),
|
||||||
|
(4, 1, "POS","POS", False),
|
||||||
|
(4, 1, "ANY","ANY", True),
|
||||||
|
(4, 0, "NEG","POS", True), # FF mapping
|
||||||
|
(4, 1, "NEG","NEG", True),
|
||||||
|
(4, 0, "POS","NEG", True), # FF mapping
|
||||||
|
(4, 1, "POS","POS", True),
|
||||||
|
# cannot combine "ANY" with "POS|NEG" when using shared clock
|
||||||
|
]:
|
||||||
|
name = f"clock_a{abits}_w{wclk}r{rclk}s{shared}"
|
||||||
|
defs = ["WCLK_" + wclk, "RCLK_" + rclk]
|
||||||
|
if (shared):
|
||||||
|
defs.append("SHARED_CLK")
|
||||||
|
TESTS.append(Test(
|
||||||
|
name, SYNCCLOCK.format(abits=abits),
|
||||||
|
["clock_sdp"], defs, {"RAM_CLOCK_SDP": cnt}
|
||||||
|
))
|
||||||
|
|
||||||
|
### mixed width testing
|
||||||
|
# Wide write port
|
||||||
|
MIXED_WRITE = """
|
||||||
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam WABITS = {wabits};
|
||||||
|
localparam WDBITS = {wdbits};
|
||||||
|
|
||||||
|
localparam RABITS = {rabits};
|
||||||
|
localparam RDBITS = {rdbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [WABITS-1:0] wa;
|
||||||
|
input wire [WDBITS-1:0] wd;
|
||||||
|
input wire [RABITS-1:0] ra;
|
||||||
|
output reg [RDBITS-1:0] rd;
|
||||||
|
|
||||||
|
localparam DEPTH = (2**WABITS);
|
||||||
|
|
||||||
|
localparam OFFSET = RABITS-WABITS;
|
||||||
|
|
||||||
|
(* syn_ramstyle = "block_ram" *)
|
||||||
|
reg [WDBITS-1:0] mem [0:DEPTH-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
if (OFFSET > 0) begin
|
||||||
|
reg [WDBITS-1:0] mem_read;
|
||||||
|
reg [OFFSET-1:0] subaddr_r;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
mem_read <= mem[ra[RABITS-1:OFFSET]];
|
||||||
|
subaddr_r <= ra[OFFSET-1:0];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(mem_read, subaddr_r)
|
||||||
|
rd <= mem_read[subaddr_r*RDBITS+:RDBITS];
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
always @(posedge clk)
|
||||||
|
case (OFFSET)
|
||||||
|
0: rd <= mem[ra];
|
||||||
|
-1: rd <= {{ mem[ra], mem[ra+1] }};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
UNMIXED = MIXED_WRITE.format(wabits=4, wdbits=9, rabits=4, rdbits=9)
|
||||||
|
MIXED_9_18 = MIXED_WRITE.format(wabits=5, wdbits=9, rabits=4, rdbits=18)
|
||||||
|
MIXED_18_9 = MIXED_WRITE.format(wabits=3, wdbits=18, rabits=4, rdbits=9)
|
||||||
|
MIXED_36_9 = MIXED_WRITE.format(wabits=3, wdbits=36, rabits=5, rdbits=9)
|
||||||
|
MIXED_4_2 = MIXED_WRITE.format(wabits=5, wdbits=4, rabits=6, rdbits=2);
|
||||||
|
|
||||||
|
TESTS += [
|
||||||
|
Test("unmixed", UNMIXED, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("mixed_9_18", MIXED_9_18, ["9b1B"], [], {"RAM_9b1B":4}), #CHECK: only using half the memory
|
||||||
|
Test("mixed_18_9", MIXED_18_9, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
Test("mixed_36_9", MIXED_36_9, ["9b1B"], [], {"RAM_9b1B":2}),
|
||||||
|
Test("mixed_4_2", MIXED_4_2, ["9b1B"], [], {"RAM_9b1B":1}),
|
||||||
|
]
|
||||||
|
|
||||||
### basic TDP test
|
### basic TDP test
|
||||||
|
|
||||||
TDP = """
|
TDP = """
|
||||||
|
@ -131,7 +381,7 @@ TESTS += [
|
||||||
]
|
]
|
||||||
|
|
||||||
# shared clock
|
# shared clock
|
||||||
|
# Synchronous SDP with clock domain crossing
|
||||||
SYNC_2CLK = """
|
SYNC_2CLK = """
|
||||||
module top(rclk, wclk, ra, wa, rd, wd, we);
|
module top(rclk, wclk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
@ -163,7 +413,7 @@ TESTS += [
|
||||||
]
|
]
|
||||||
|
|
||||||
# inter-port transparency
|
# inter-port transparency
|
||||||
|
# Synchronous SDP with write-first behaviour
|
||||||
SYNC_TRANS = """
|
SYNC_TRANS = """
|
||||||
module top(clk, ra, wa, rd, wd, we);
|
module top(clk, ra, wa, rd, wd, we);
|
||||||
|
|
||||||
|
@ -201,7 +451,7 @@ TESTS += [
|
||||||
]
|
]
|
||||||
|
|
||||||
# rdwr checks
|
# rdwr checks
|
||||||
|
# Synchronous single-port RAM with mutually exclusive read/write
|
||||||
SP_NO_CHANGE = """
|
SP_NO_CHANGE = """
|
||||||
module top(clk, addr, rd, wd, we);
|
module top(clk, addr, rd, wd, we);
|
||||||
|
|
||||||
|
@ -247,6 +497,7 @@ end
|
||||||
endmodule
|
endmodule
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Synchronous single-port RAM with write-first behaviour
|
||||||
SP_NEW = """
|
SP_NEW = """
|
||||||
module top(clk, addr, rd, wd, we);
|
module top(clk, addr, rd, wd, we);
|
||||||
|
|
||||||
|
@ -295,6 +546,7 @@ end
|
||||||
endmodule
|
endmodule
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Synchronous single-port RAM with read-first behaviour
|
||||||
SP_OLD = """
|
SP_OLD = """
|
||||||
module top(clk, addr, rd, wd, we);
|
module top(clk, addr, rd, wd, we);
|
||||||
|
|
||||||
|
@ -373,6 +625,7 @@ TESTS += [
|
||||||
Test("sp_old_auto_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}),
|
Test("sp_old_auto_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Synchronous read port with initial value
|
||||||
SP_INIT = """
|
SP_INIT = """
|
||||||
module top(clk, addr, rd, wd, we, re);
|
module top(clk, addr, rd, wd, we, re);
|
||||||
|
|
||||||
|
@ -418,6 +671,7 @@ TESTS += [
|
||||||
Test("sp_init_v_any_re", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
Test("sp_init_v_any_re", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Synchronous read port with asynchronous reset
|
||||||
SP_ARST = """
|
SP_ARST = """
|
||||||
module top(clk, addr, rd, wd, we, re, ar);
|
module top(clk, addr, rd, wd, we, re, ar);
|
||||||
|
|
||||||
|
@ -488,6 +742,7 @@ TESTS += [
|
||||||
Test("sp_arst_n_init_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
Test("sp_arst_n_init_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Synchronous read port with synchronous reset (reset priority over enable)
|
||||||
SP_SRST = """
|
SP_SRST = """
|
||||||
module top(clk, addr, rd, wd, we, re, sr);
|
module top(clk, addr, rd, wd, we, re, sr);
|
||||||
|
|
||||||
|
@ -515,6 +770,7 @@ end
|
||||||
endmodule
|
endmodule
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Synchronous read port with synchronous reet (enable priority over reset)
|
||||||
SP_SRST_G = """
|
SP_SRST_G = """
|
||||||
module top(clk, addr, rd, wd, we, re, sr);
|
module top(clk, addr, rd, wd, we, re, sr);
|
||||||
|
|
||||||
|
@ -602,6 +858,180 @@ TESTS += [
|
||||||
Test("sp_srst_gv_init_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
Test("sp_srst_gv_init_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Byte enables, wrbe_separate
|
||||||
|
SYNC_ENABLE = """
|
||||||
|
module top(clk, rwa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] rwa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output reg [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (we)
|
||||||
|
mem[rwa] <= wd;
|
||||||
|
else
|
||||||
|
rd <= mem[rwa];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
for (abits, dbits, sep, defs, cells) in [
|
||||||
|
(4, 4, False, ["NO_BYTE"], {"RAM_WREN": 1}),
|
||||||
|
(5, 4, False, ["NO_BYTE"], {"RAM_WREN": 2}),
|
||||||
|
(6, 4, False, ["NO_BYTE"], {"RAM_WREN": 4}),
|
||||||
|
# (4, 4, True, ["NO_BYTE"], {"RAM_WREN": 1}), # should throw an error
|
||||||
|
(3, 8, False, ["NO_BYTE"], {"RAM_WREN": 2}), # needs two write ports
|
||||||
|
(4, 8, False, ["NO_BYTE"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, False, ["W4_B4"], {"RAM_WREN": 1}),
|
||||||
|
(4, 8, True, ["W4_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4, 8, False, ["W8_B4"], {"RAM_WREN": 1}),
|
||||||
|
(4, 8, True, ["W8_B4"], {"RAM_WREN": 1}),
|
||||||
|
(4, 8, False, ["W8_B8"], {"RAM_WREN": 1}),
|
||||||
|
(4, 8, True, ["W8_B8"], {"RAM_WREN": 1}),
|
||||||
|
|
||||||
|
]:
|
||||||
|
name = f"wren_a{abits}d{dbits}_{defs[0]}"
|
||||||
|
if (sep):
|
||||||
|
defs.append("WRBE_SEPARATE")
|
||||||
|
name += "_separate"
|
||||||
|
|
||||||
|
TESTS.append(Test(
|
||||||
|
name, SYNC_ENABLE.format(abits=abits, dbits=dbits),
|
||||||
|
["wren"], defs, cells
|
||||||
|
))
|
||||||
|
|
||||||
|
# Write port with byte enables
|
||||||
|
ENABLES = """
|
||||||
|
module top(clk, we, be, rwa, wd, rd);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam WBITS = {wbits};
|
||||||
|
localparam WORDS = {words};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [WORDS-1:0] be;
|
||||||
|
input wire [ABITS-1:0] rwa;
|
||||||
|
input wire [(WBITS*WORDS)-1:0] wd;
|
||||||
|
output reg [(WBITS*WORDS)-1:0] rd;
|
||||||
|
|
||||||
|
reg [(WBITS*WORDS)-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
always @(posedge clk)
|
||||||
|
for (i=0; i<WORDS; i=i+1)
|
||||||
|
if (we && be[i])
|
||||||
|
mem[rwa][i*WBITS+:WBITS] <= wd[i*WBITS+:WBITS];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (!we)
|
||||||
|
rd <= mem[rwa];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
for (abits, wbits, words, defs, cells) in [
|
||||||
|
(4, 2, 8, ["W16_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, 4, ["W16_B4"], {"RAM_WREN": 1}),
|
||||||
|
(5, 4, 2, ["W16_B4"], {"RAM_WREN": 1}),
|
||||||
|
(5, 4, 4, ["W16_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4, 8, 2, ["W16_B4"], {"RAM_WREN": 1}),
|
||||||
|
(5, 8, 1, ["W16_B4"], {"RAM_WREN": 1}),
|
||||||
|
(5, 8, 2, ["W16_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4,16, 1, ["W16_B4"], {"RAM_WREN": 1}),
|
||||||
|
(4, 4, 2, ["W8_B8"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, 1, ["W8_B8"], {"RAM_WREN": 1}),
|
||||||
|
(4, 8, 2, ["W8_B8"], {"RAM_WREN": 2}),
|
||||||
|
(3, 8, 2, ["W8_B8"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, 2, ["W8_B4"], {"RAM_WREN": 1}),
|
||||||
|
(4, 2, 4, ["W8_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, 4, ["W8_B4"], {"RAM_WREN": 2}),
|
||||||
|
(4, 4, 4, ["W4_B4"], {"RAM_WREN": 4}),
|
||||||
|
(4, 4, 5, ["W4_B4"], {"RAM_WREN": 5}),
|
||||||
|
|
||||||
|
]:
|
||||||
|
name = f"wren_a{abits}d{wbits}w{words}_{defs[0]}"
|
||||||
|
TESTS.append(Test(
|
||||||
|
name, ENABLES.format(abits=abits, wbits=wbits, words=words),
|
||||||
|
["wren"], defs, cells
|
||||||
|
))
|
||||||
|
|
||||||
|
defs.append("WRBE_SEPARATE")
|
||||||
|
name += "_separate"
|
||||||
|
TESTS.append(Test(
|
||||||
|
name, ENABLES.format(abits=abits, wbits=wbits, words=words),
|
||||||
|
["wren"], defs, cells
|
||||||
|
))
|
||||||
|
|
||||||
|
# abits/dbits determination (aka general geometry picking)
|
||||||
|
GEOMETRIC = """
|
||||||
|
module top(clk, rwa, rd, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] rwa;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output reg [DBITS-1:0] rd;
|
||||||
|
|
||||||
|
(* ram_style="block" *)
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[rwa] <= wd;
|
||||||
|
else
|
||||||
|
rd <= mem[rwa];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
for (abits,dbits, libs, defs, cells) in [
|
||||||
|
# W64_B8 gives 16 * 64 = 1024 bits of memory with up to 8x8b rw ports
|
||||||
|
( 4, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 5, 32, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 5, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 2}),
|
||||||
|
( 6, 16, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 6, 30, ["wren"], ["W64_B8"], {"RAM_WREN": 2}),
|
||||||
|
( 6, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 4}),
|
||||||
|
( 7, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 7, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 7, 8, ["wren"], ["W64_B8"], {"RAM_WREN": 1}),
|
||||||
|
( 7, 17, ["wren"], ["W64_B8"], {"RAM_WREN": 3}),
|
||||||
|
( 8, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 2}),
|
||||||
|
( 8, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 2}),
|
||||||
|
( 9, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 4}),
|
||||||
|
( 9, 8, ["wren"], ["W64_B8"], {"RAM_WREN": 4}),
|
||||||
|
( 9, 5, ["wren"], ["W64_B8"], {"RAM_WREN": 4}),
|
||||||
|
( 9, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 4}),
|
||||||
|
# 9b1B gives 128 bits of memory with 1 2 or 4 bit read and write ports
|
||||||
|
# or 144 bits with 9 or 18 bit read and write ports
|
||||||
|
( 3, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 1}),
|
||||||
|
( 4, 4, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 1}),
|
||||||
|
( 4, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 2}),
|
||||||
|
( 5, 32, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 8}),
|
||||||
|
( 6, 4, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 2}),
|
||||||
|
( 7, 11, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 11}),
|
||||||
|
( 7, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 16}),
|
||||||
|
( 11, 1, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 16}),
|
||||||
|
]:
|
||||||
|
name = f"geom_a{abits}d{dbits}_{libs[0]}"
|
||||||
|
TESTS.append(Test(
|
||||||
|
name, GEOMETRIC.format(abits=abits, dbits=dbits),
|
||||||
|
libs, defs, cells
|
||||||
|
))
|
||||||
|
|
||||||
|
# Mixed width testing
|
||||||
WIDE_SDP = """
|
WIDE_SDP = """
|
||||||
module top(rclk, ra, rd, re, rr, wclk, wa, wd, we);
|
module top(rclk, ra, rd, re, rr, wclk, wa, wd, we);
|
||||||
|
|
||||||
|
@ -857,6 +1287,233 @@ for (aw, rw, ww, bw, cntww, cntwr) in [
|
||||||
{"RAM_WIDE_WRITE": cntww}
|
{"RAM_WIDE_WRITE": cntww}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# Multiple read ports
|
||||||
|
# 1rw port plus 3 (or 7) r ports
|
||||||
|
QUAD_PORT = """
|
||||||
|
module top(clk, rwa, r0a, r1a, r2a, rd, r0d, r1d, r2d, wd, we);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam DBITS = {dbits};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] rwa;
|
||||||
|
input wire [ABITS-1:0] r0a;
|
||||||
|
input wire [ABITS-1:0] r1a;
|
||||||
|
input wire [ABITS-1:0] r2a;
|
||||||
|
input wire [DBITS-1:0] wd;
|
||||||
|
output wire [DBITS-1:0] rd;
|
||||||
|
output wire [DBITS-1:0] r0d;
|
||||||
|
output wire [DBITS-1:0] r1d;
|
||||||
|
output wire [DBITS-1:0] r2d;
|
||||||
|
|
||||||
|
reg [DBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[rwa] <= wd;
|
||||||
|
|
||||||
|
assign rd = mem[rwa];
|
||||||
|
assign r0d = mem[r0a];
|
||||||
|
assign r1d = mem[r1a];
|
||||||
|
assign r2d = mem[r2a];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
for (abits, dbits, cnt) in [
|
||||||
|
(2, 2, 1),
|
||||||
|
(4, 2, 1),
|
||||||
|
(5, 2, 2),
|
||||||
|
(4, 4, 2),
|
||||||
|
(6, 2, 4),
|
||||||
|
(4, 8, 4),
|
||||||
|
]:
|
||||||
|
TESTS.append(Test(
|
||||||
|
f"quad_port_a{abits}d{dbits}",
|
||||||
|
QUAD_PORT.format(abits=abits, dbits=dbits),
|
||||||
|
["multilut"], ["PORTS_QUAD"],
|
||||||
|
{"LUT_MULTI": cnt}
|
||||||
|
))
|
||||||
|
|
||||||
|
# Wide asynchronous read port
|
||||||
|
WIDE_READ = """
|
||||||
|
module top(clk, we, rwa, wd, rd);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam WBITS = {wbits};
|
||||||
|
localparam RWORDS = {rwords};
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire we;
|
||||||
|
input wire [ABITS-1:0] rwa;
|
||||||
|
input wire [WBITS-1:0] wd;
|
||||||
|
output wire [(WBITS*RWORDS)-1:0] rd;
|
||||||
|
|
||||||
|
reg [WBITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (we)
|
||||||
|
mem[rwa] <= wd;
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
generate
|
||||||
|
for (i = 0; i < RWORDS; i = i + 1)
|
||||||
|
assign rd[i*WBITS+:WBITS] = mem[rwa + i];
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
|
||||||
|
for (abits, wbits, rwords, cntquad, cntoct) in [
|
||||||
|
(4, 2, 1, 1, 1),
|
||||||
|
(4, 2, 2, 1, 1),
|
||||||
|
(4, 2, 3, 1, 1),
|
||||||
|
(4, 2, 4, 1, 1),
|
||||||
|
(4, 2, 5, 2, 1),
|
||||||
|
(4, 2, 6, 2, 1),
|
||||||
|
(4, 2, 7, 2, 1), # Write port needs to be duplicated, so only 3 extra read
|
||||||
|
(4, 2, 8, 3, 1), # ports per quad port LUT (i.e. 7 ports in 2, 8 ports in 3)
|
||||||
|
(4, 2, 9, 3, 2),
|
||||||
|
(4, 4, 1, 2, 2),
|
||||||
|
(4, 4, 4, 2, 2),
|
||||||
|
(4, 4, 6, 4, 2),
|
||||||
|
(4, 4, 9, 6, 4),
|
||||||
|
(5, 2, 1, 2, 2),
|
||||||
|
(5, 2, 4, 2, 2),
|
||||||
|
(5, 2, 9, 6, 4),
|
||||||
|
]:
|
||||||
|
TESTS.append(Test(
|
||||||
|
f"wide_quad_a{abits}w{wbits}r{rwords}",
|
||||||
|
WIDE_READ.format(abits=abits, wbits=wbits, rwords=rwords),
|
||||||
|
["multilut"], ["PORTS_QUAD"],
|
||||||
|
{"LUT_MULTI": cntquad}
|
||||||
|
))
|
||||||
|
TESTS.append(Test(
|
||||||
|
f"wide_oct_a{abits}w{wbits}r{rwords}",
|
||||||
|
WIDE_READ.format(abits=abits, wbits=wbits, rwords=rwords),
|
||||||
|
["multilut"], ["PORTS_OCT"],
|
||||||
|
{"LUT_MULTI": cntoct}
|
||||||
|
))
|
||||||
|
|
||||||
|
# signal priorities & pattern testing
|
||||||
|
PRIORITY = """
|
||||||
|
module top(clk, clken, wren, wben, rden, rst, addr, wdata, rdata);
|
||||||
|
|
||||||
|
localparam ABITS = {abits};
|
||||||
|
localparam WBITS = {wbits};
|
||||||
|
localparam WORDS = {words};
|
||||||
|
|
||||||
|
localparam BITS = WBITS * WORDS;
|
||||||
|
|
||||||
|
input wire clk, clken;
|
||||||
|
input wire wren, rden, rst;
|
||||||
|
input wire [WORDS-1:0] wben;
|
||||||
|
input wire [ABITS-1:0] addr;
|
||||||
|
input wire [BITS-1:0] wdata;
|
||||||
|
output reg [BITS-1:0] rdata;
|
||||||
|
|
||||||
|
reg [BITS-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
{code}
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
"""
|
||||||
|
#reset_gate in ["ungated", "rst", "rden && rst"]
|
||||||
|
#clk_en in [True, False]
|
||||||
|
#rdwr in ["nc", "old", "new", "undef", "newdef"]
|
||||||
|
|
||||||
|
for (testname, reset_gate, rdwr, clk_en, add_logic) in [
|
||||||
|
("no_reset", "", "old", False, 0),
|
||||||
|
("gclken", "rst", "old", False, 0),
|
||||||
|
("ungated", "ungated", "old", False, 1), # muxes wren with rst
|
||||||
|
("gclken_ce", "rst", "old", True, 3), # AND to simulate CLK_EN
|
||||||
|
("grden", "rden && rst", "old", False, 1), # selects _clken, simulates _rden
|
||||||
|
("grden_ce", "rden && rst", "old", True, 4), # both of the above
|
||||||
|
("exclwr", "", "nc", False, 2), # selects new_only and simulates
|
||||||
|
("excl_rst", "rst", "nc", False, 3), # as above, extra gate for rst
|
||||||
|
("transwr", "", "new", False, 0),
|
||||||
|
("trans_rst", "rst", "new", False, 0),
|
||||||
|
]:
|
||||||
|
write = "if (wren) \n\t\tmem[addr] <= wdata;"
|
||||||
|
|
||||||
|
if rdwr == "new":
|
||||||
|
read = """if (rden)
|
||||||
|
if (wren)
|
||||||
|
rdata <= wdata;
|
||||||
|
else
|
||||||
|
rdata <= mem[addr];"""
|
||||||
|
else:
|
||||||
|
read = "if (rden) \n\t\trdata <= mem[addr];"
|
||||||
|
|
||||||
|
if "rst" in reset_gate:
|
||||||
|
read = f"if ({reset_gate})\n\t\trdata <= 0; \n\telse {read}"
|
||||||
|
|
||||||
|
if reset_gate == "ungated":
|
||||||
|
outer = "if (rst)\n\trdata <= 0;\nelse "
|
||||||
|
else:
|
||||||
|
outer = ""
|
||||||
|
|
||||||
|
if clk_en:
|
||||||
|
outer = f"{outer}if (clken) "
|
||||||
|
|
||||||
|
code = f"""{outer}begin
|
||||||
|
{write}
|
||||||
|
{"else " if rdwr == "nc" else ""}{read}
|
||||||
|
end"""
|
||||||
|
|
||||||
|
TESTS.append(Test(
|
||||||
|
testname, PRIORITY.format(code=code, abits=4, wbits=8, words=2),
|
||||||
|
["block_sp_full"], ["USE_SRST"],
|
||||||
|
{"RAM_BLOCK_SP": 1, "$*": add_logic}
|
||||||
|
))
|
||||||
|
|
||||||
|
for (testname, reset_gate, defs, rdwr, add_logic) in [
|
||||||
|
("wr_byte", "", ["USE_SRST_BLOCKING"], "old", 0),
|
||||||
|
("trans_byte", "", ["USE_SRST_BLOCKING"], "new", 0),
|
||||||
|
("wr_rst_byte", "rst", ["USE_SRST"], "old", 2), # expected mux to emulate blocking
|
||||||
|
("rst_wr_byte", "rst", ["USE_SRST_BLOCKING"], "old", 2), # should use hardware blocking, doesn't
|
||||||
|
("rdenrst_wr_byte", "rden && rst", ["USE_SRST"], "old", 3),
|
||||||
|
]:
|
||||||
|
wordsloop = "for (i=0; i<WORDS; i=i+1)"
|
||||||
|
if rdwr == "old":
|
||||||
|
read_write = f"""if (rden)
|
||||||
|
rdata = mem[addr];
|
||||||
|
{wordsloop}
|
||||||
|
if (wben[i])
|
||||||
|
mem[addr][i] <= wdata[i];"""
|
||||||
|
else:
|
||||||
|
read_write = f"""{wordsloop}
|
||||||
|
if (wben[i]) begin
|
||||||
|
mem[addr][i] <= wdata[i];
|
||||||
|
rdata[i] <= wdata[i];
|
||||||
|
end else
|
||||||
|
rdata[i] <= mem[addr][i];"""
|
||||||
|
|
||||||
|
if "rst" in reset_gate:
|
||||||
|
reset_rw = f"""if ({reset_gate})
|
||||||
|
rdata <= 0;
|
||||||
|
else begin
|
||||||
|
{read_write}
|
||||||
|
end"""
|
||||||
|
else:
|
||||||
|
reset_rw = read_write
|
||||||
|
|
||||||
|
if reset_gate == "ungated":
|
||||||
|
outer = "if (rst)\n\trdata <= 0;\nelse "
|
||||||
|
else:
|
||||||
|
outer = ""
|
||||||
|
|
||||||
|
code = f"{outer}\n{reset_rw}"
|
||||||
|
|
||||||
|
TESTS.append(Test(
|
||||||
|
testname, PRIORITY.format(code=code, abits=4, wbits=1, words=2),
|
||||||
|
["block_sp_full"], defs,
|
||||||
|
{"RAM_BLOCK_SP": 1, "$*": add_logic}
|
||||||
|
))
|
||||||
|
|
||||||
with open("run-test.mk", "w") as mf:
|
with open("run-test.mk", "w") as mf:
|
||||||
mf.write("ifneq ($(strip $(SEED)),)\n")
|
mf.write("ifneq ($(strip $(SEED)),)\n")
|
||||||
mf.write("SEEDOPT=-S$(SEED)\n")
|
mf.write("SEEDOPT=-S$(SEED)\n")
|
||||||
|
|
31
tests/memlib/memlib_9b1B.txt
Normal file
31
tests/memlib/memlib_9b1B.txt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
ram block \RAM_9b1B {
|
||||||
|
cost 64;
|
||||||
|
abits 7;
|
||||||
|
widths 1 2 4 9 18 per_port;
|
||||||
|
byte 9;
|
||||||
|
|
||||||
|
ifdef INIT_NONE {
|
||||||
|
option "INIT" "NONE" {
|
||||||
|
init none;
|
||||||
|
}
|
||||||
|
} else ifdef INIT_ZERO {
|
||||||
|
option "INIT" "ZERO" {
|
||||||
|
init zero;
|
||||||
|
}
|
||||||
|
} else ifdef INIT_NO_UNDEF {
|
||||||
|
option "INIT" "NO_UNDEF" {
|
||||||
|
init no_undef;
|
||||||
|
}
|
||||||
|
} else ifdef INIT_ANY {
|
||||||
|
option "INIT" "ANY" {
|
||||||
|
init any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
port sw "W" {
|
||||||
|
clock anyedge;
|
||||||
|
}
|
||||||
|
port sr "R" {
|
||||||
|
clock anyedge;
|
||||||
|
}
|
||||||
|
}
|
68
tests/memlib/memlib_9b1B.v
Normal file
68
tests/memlib/memlib_9b1B.v
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
module RAM_9b1B (
|
||||||
|
input PORT_R_CLK,
|
||||||
|
input [6:0] PORT_R_ADDR,
|
||||||
|
output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA,
|
||||||
|
input PORT_W_CLK,
|
||||||
|
input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN,
|
||||||
|
input [6:0] PORT_W_ADDR,
|
||||||
|
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter OPTION_INIT = "UNDEFINED";
|
||||||
|
parameter PORT_R_WIDTH = 9;
|
||||||
|
parameter PORT_W_WIDTH = 9;
|
||||||
|
parameter PORT_R_CLK_POL = 0;
|
||||||
|
parameter PORT_W_CLK_POL = 0;
|
||||||
|
parameter PORT_W_WR_EN_WIDTH = 1;
|
||||||
|
|
||||||
|
reg [8:0] mem [0:15];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial
|
||||||
|
for (i = 0; i < 16; i += 1)
|
||||||
|
case (OPTION_INIT)
|
||||||
|
"NONE": mem[i] = mem[i]; //?
|
||||||
|
"ZERO": mem[i] = 9'h0;
|
||||||
|
"ANY": mem[i] = INIT[i*9+:9];
|
||||||
|
"NO_UNDEF": mem[i] = INIT[i*9+:9];
|
||||||
|
"UNDEFINED": mem[i] = 9'hx;
|
||||||
|
endcase
|
||||||
|
|
||||||
|
wire [3:0] addr_r;
|
||||||
|
assign addr_r = PORT_R_ADDR[6:3];
|
||||||
|
reg [17:0] mem_read;
|
||||||
|
reg [2:0] subaddr_r;
|
||||||
|
always @(negedge (PORT_R_CLK ^ PORT_R_CLK_POL)) begin
|
||||||
|
subaddr_r <= PORT_R_ADDR[2:0];
|
||||||
|
mem_read[8:0] <= mem[addr_r];
|
||||||
|
if (PORT_R_WIDTH == 18)
|
||||||
|
mem_read[17:9] <= mem[addr_r + 1];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(mem_read, subaddr_r) begin
|
||||||
|
case (PORT_R_WIDTH)
|
||||||
|
18: PORT_R_RD_DATA <= mem_read;
|
||||||
|
9: PORT_R_RD_DATA <= mem_read[8:0];
|
||||||
|
4: PORT_R_RD_DATA <= mem_read[subaddr_r[2]*4+:4];
|
||||||
|
2: PORT_R_RD_DATA <= mem_read[subaddr_r[2:1]*2+:2];
|
||||||
|
1: PORT_R_RD_DATA <= mem_read[subaddr_r];
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
wire [3:0] addr_w;
|
||||||
|
assign addr_w = PORT_W_ADDR[6:3];
|
||||||
|
always @(negedge (PORT_W_CLK ^ PORT_W_CLK_POL)) begin
|
||||||
|
if (PORT_W_WR_EN[0])
|
||||||
|
case (PORT_W_WIDTH)
|
||||||
|
18,
|
||||||
|
9: mem[addr_w] <= PORT_W_WR_DATA[8:0];
|
||||||
|
4: mem[addr_w][PORT_W_ADDR[2]*4+:4] <= PORT_W_WR_DATA;
|
||||||
|
2: mem[addr_w][PORT_W_ADDR[2:1]*2+:2] <= PORT_W_WR_DATA;
|
||||||
|
1: mem[addr_w][PORT_W_ADDR[2:0]] <= PORT_W_WR_DATA;
|
||||||
|
endcase
|
||||||
|
if (PORT_W_WR_EN[1])
|
||||||
|
mem[addr_w + 1] <= PORT_W_WR_DATA[17:9];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
61
tests/memlib/memlib_block_sp_full.txt
Normal file
61
tests/memlib/memlib_block_sp_full.txt
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
ram block \RAM_BLOCK_SP {
|
||||||
|
cost 2;
|
||||||
|
abits 4;
|
||||||
|
width 16;
|
||||||
|
byte 8;
|
||||||
|
port srsw "A" {
|
||||||
|
clock posedge;
|
||||||
|
clken;
|
||||||
|
rden;
|
||||||
|
|
||||||
|
option "RDWR" "NO_CHANGE" {
|
||||||
|
rdwr no_change;
|
||||||
|
}
|
||||||
|
option "RDWR" "OLD" {
|
||||||
|
rdwr old;
|
||||||
|
}
|
||||||
|
option "RDWR" "NEW" {
|
||||||
|
rdwr new;
|
||||||
|
}
|
||||||
|
option "RDWR" "NEW_ONLY" {
|
||||||
|
rdwr new_only;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifdef USE_ARST {
|
||||||
|
option "RDARST" "ZERO" {
|
||||||
|
rdarst zero;
|
||||||
|
}
|
||||||
|
option "RDARST" "ANY" {
|
||||||
|
rdarst any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ifdef USE_SRST {
|
||||||
|
option "SRST_BLOCK" 0 {
|
||||||
|
option "SRST_GATE" 0 {
|
||||||
|
rdsrst zero ungated;
|
||||||
|
}
|
||||||
|
option "SRST_GATE" 1 {
|
||||||
|
rdsrst zero gated_clken;
|
||||||
|
}
|
||||||
|
option "SRST_GATE" 2 {
|
||||||
|
rdsrst zero gated_rden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ifdef USE_SRST_BLOCKING {
|
||||||
|
option "SRST_BLOCK" 1 {
|
||||||
|
option "SRST_GATE" 0 {
|
||||||
|
rdsrst zero ungated block_wr;
|
||||||
|
}
|
||||||
|
option "SRST_GATE" 1 {
|
||||||
|
rdsrst zero gated_clken block_wr;
|
||||||
|
}
|
||||||
|
option "SRST_GATE" 2 {
|
||||||
|
rdsrst zero gated_rden block_wr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
tests/memlib/memlib_block_sp_full.v
Normal file
82
tests/memlib/memlib_block_sp_full.v
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
module RAM_BLOCK_SP(
|
||||||
|
input PORT_A_CLK,
|
||||||
|
input PORT_A_CLK_EN,
|
||||||
|
input PORT_A_RD_EN,
|
||||||
|
input PORT_A_RD_ARST,
|
||||||
|
input PORT_A_RD_SRST,
|
||||||
|
input [1:0] PORT_A_WR_EN,
|
||||||
|
input [3:0] PORT_A_ADDR,
|
||||||
|
output reg [15:0] PORT_A_RD_DATA,
|
||||||
|
input [15:0] PORT_A_WR_DATA
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter OPTION_RDWR = "UNDEFINED";
|
||||||
|
parameter OPTION_RDINIT = "UNDEFINED";
|
||||||
|
parameter OPTION_RDARST = "UNDEFINED";
|
||||||
|
parameter OPTION_RDSRST = "ZERO";
|
||||||
|
parameter OPTION_SRST_GATE = 0;
|
||||||
|
parameter OPTION_SRST_BLOCK = 0;
|
||||||
|
parameter PORT_A_RD_INIT_VALUE = 16'hxxxx;
|
||||||
|
parameter PORT_A_RD_ARST_VALUE = 16'hxxxx;
|
||||||
|
parameter PORT_A_RD_SRST_VALUE = 16'hxxxx;
|
||||||
|
|
||||||
|
reg [15:0] mem [0:15];
|
||||||
|
|
||||||
|
initial
|
||||||
|
if (OPTION_RDINIT == "ZERO")
|
||||||
|
PORT_A_RD_DATA = 0;
|
||||||
|
else if (OPTION_RDINIT == "ANY")
|
||||||
|
PORT_A_RD_DATA = PORT_A_RD_INIT_VALUE;
|
||||||
|
|
||||||
|
localparam ARST_VALUE =
|
||||||
|
(OPTION_RDARST == "ZERO") ? 16'h0000 :
|
||||||
|
(OPTION_RDARST == "INIT") ? PORT_A_RD_INIT_VALUE :
|
||||||
|
(OPTION_RDARST == "ANY") ? PORT_A_RD_ARST_VALUE :
|
||||||
|
16'hxxxx;
|
||||||
|
|
||||||
|
localparam SRST_VALUE =
|
||||||
|
(OPTION_RDSRST == "ZERO") ? 16'h0000 :
|
||||||
|
(OPTION_RDSRST == "INIT") ? PORT_A_RD_INIT_VALUE :
|
||||||
|
(OPTION_RDSRST == "ANY") ? PORT_A_RD_SRST_VALUE :
|
||||||
|
16'hxxxx;
|
||||||
|
|
||||||
|
pulldown (PORT_A_RD_ARST);
|
||||||
|
pulldown (PORT_A_RD_SRST);
|
||||||
|
|
||||||
|
always @(posedge PORT_A_CLK) begin
|
||||||
|
if (PORT_A_CLK_EN) begin
|
||||||
|
if (!(PORT_A_RD_SRST && OPTION_SRST_BLOCK)) begin
|
||||||
|
if (PORT_A_WR_EN[0])
|
||||||
|
mem[PORT_A_ADDR][7:0] <= PORT_A_WR_DATA[7:0];
|
||||||
|
if (PORT_A_WR_EN[1])
|
||||||
|
mem[PORT_A_ADDR][15:8] <= PORT_A_WR_DATA[15:8];
|
||||||
|
end
|
||||||
|
if (PORT_A_RD_EN && (!PORT_A_WR_EN || OPTION_RDWR != "NO_CHANGE")) begin
|
||||||
|
PORT_A_RD_DATA <= mem[PORT_A_ADDR];
|
||||||
|
if (PORT_A_WR_EN && OPTION_RDWR == "NEW_ONLY")
|
||||||
|
PORT_A_RD_DATA <= 16'hx;
|
||||||
|
if (PORT_A_WR_EN[0])
|
||||||
|
case (OPTION_RDWR)
|
||||||
|
"NEW": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0];
|
||||||
|
"NEW_ONLY": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0];
|
||||||
|
"UNDEFINED": PORT_A_RD_DATA[7:0] <= 8'hx;
|
||||||
|
endcase
|
||||||
|
if (PORT_A_WR_EN[1])
|
||||||
|
case (OPTION_RDWR)
|
||||||
|
"NEW": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8];
|
||||||
|
"NEW_ONLY": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8];
|
||||||
|
"UNDEFINED": PORT_A_RD_DATA[15:8] <= 8'hx;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (PORT_A_RD_SRST && (!OPTION_SRST_GATE || (OPTION_SRST_GATE == 2 && PORT_A_RD_EN) || (OPTION_SRST_GATE == 1 && PORT_A_CLK_EN)))
|
||||||
|
PORT_A_RD_DATA <= SRST_VALUE;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(PORT_A_RD_ARST)
|
||||||
|
if (PORT_A_RD_ARST)
|
||||||
|
force PORT_A_RD_DATA = ARST_VALUE;
|
||||||
|
else
|
||||||
|
release PORT_A_RD_DATA;
|
||||||
|
|
||||||
|
endmodule
|
76
tests/memlib/memlib_clock_sdp.txt
Normal file
76
tests/memlib/memlib_clock_sdp.txt
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
ram block \RAM_CLOCK_SDP {
|
||||||
|
cost 64;
|
||||||
|
abits 10;
|
||||||
|
widths 1 2 4 8 16 per_port;
|
||||||
|
init any;
|
||||||
|
port sw "W" {
|
||||||
|
ifdef SHARED_CLK {
|
||||||
|
ifdef WCLK_ANY {
|
||||||
|
option "WCLK" "ANY" {
|
||||||
|
clock anyedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef WCLK_POS {
|
||||||
|
option "WCLK" "POS" {
|
||||||
|
clock posedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef WCLK_NEG {
|
||||||
|
option "WCLK" "NEG" {
|
||||||
|
clock negedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ifdef WCLK_ANY {
|
||||||
|
option "WCLK" "ANY" {
|
||||||
|
clock anyedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef WCLK_POS {
|
||||||
|
option "WCLK" "POS" {
|
||||||
|
clock posedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef WCLK_NEG {
|
||||||
|
option "WCLK" "NEG" {
|
||||||
|
clock negedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port sr "R" {
|
||||||
|
ifdef SHARED_CLK {
|
||||||
|
ifdef RCLK_ANY {
|
||||||
|
option "RCLK" "ANY" {
|
||||||
|
clock anyedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef RCLK_POS {
|
||||||
|
option "RCLK" "POS" {
|
||||||
|
clock posedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef RCLK_NEG {
|
||||||
|
option "RCLK" "NEG" {
|
||||||
|
clock negedge "CLK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ifdef RCLK_ANY {
|
||||||
|
option "RCLK" "ANY" {
|
||||||
|
clock anyedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef RCLK_POS {
|
||||||
|
option "RCLK" "POS" {
|
||||||
|
clock posedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifdef RCLK_NEG {
|
||||||
|
option "RCLK" "NEG" {
|
||||||
|
clock negedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
tests/memlib/memlib_clock_sdp.v
Normal file
36
tests/memlib/memlib_clock_sdp.v
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
module RAM_CLOCK_SDP(
|
||||||
|
input CLK_CLK,
|
||||||
|
input PORT_R_CLK,
|
||||||
|
input [9:0] PORT_R_ADDR,
|
||||||
|
output reg [15:0] PORT_R_RD_DATA,
|
||||||
|
input PORT_W_CLK,
|
||||||
|
input PORT_W_WR_EN,
|
||||||
|
input [9:0] PORT_W_ADDR,
|
||||||
|
input [15:0] PORT_W_WR_DATA
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter PORT_R_WIDTH = 1;
|
||||||
|
parameter PORT_W_WIDTH = 1;
|
||||||
|
parameter CLK_CLK_POL = 0;
|
||||||
|
parameter PORT_R_CLK_POL = 0;
|
||||||
|
parameter PORT_W_CLK_POL = 0;
|
||||||
|
parameter OPTION_WCLK = "ANY";
|
||||||
|
parameter OPTION_RCLK = "ANY";
|
||||||
|
|
||||||
|
reg [2**10-1:0] mem = INIT;
|
||||||
|
|
||||||
|
wire RCLK;
|
||||||
|
case (OPTION_RCLK)
|
||||||
|
"ANY": assign RCLK = PORT_R_CLK == PORT_R_CLK_POL;
|
||||||
|
"POS": assign RCLK = PORT_R_CLK;
|
||||||
|
"NEG": assign RCLK = ~PORT_R_CLK;
|
||||||
|
endcase
|
||||||
|
always @(posedge RCLK)
|
||||||
|
PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH];
|
||||||
|
|
||||||
|
always @(negedge PORT_W_CLK ^ (PORT_W_CLK_POL || OPTION_WCLK == "POS"))
|
||||||
|
if (PORT_W_WR_EN)
|
||||||
|
mem[PORT_W_ADDR+:PORT_W_WIDTH] <= PORT_W_WR_DATA;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,7 +1,23 @@
|
||||||
ram distributed \RAM_LUT {
|
ram distributed \RAM_LUT {
|
||||||
abits 4;
|
abits 4;
|
||||||
width 4;
|
width 4;
|
||||||
init any;
|
ifdef INIT_NONE {
|
||||||
|
option "INIT" "NONE" {
|
||||||
|
init none;
|
||||||
|
}
|
||||||
|
} else ifdef INIT_ZERO {
|
||||||
|
option "INIT" "ZERO" {
|
||||||
|
init zero;
|
||||||
|
}
|
||||||
|
} else ifdef INIT_NO_UNDEF {
|
||||||
|
option "INIT" "NO_UNDEF" {
|
||||||
|
init no_undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
option "INIT" "ANY" {
|
||||||
|
init any;
|
||||||
|
}
|
||||||
|
}
|
||||||
cost 4;
|
cost 4;
|
||||||
port ar "R" {
|
port ar "R" {
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ module RAM_LUT(
|
||||||
);
|
);
|
||||||
|
|
||||||
parameter INIT = 0;
|
parameter INIT = 0;
|
||||||
|
parameter OPTION_INIT = "UNDEFINED";
|
||||||
parameter PORT_RW_CLK_POL = 1;
|
parameter PORT_RW_CLK_POL = 1;
|
||||||
|
|
||||||
reg [3:0] mem [0:15];
|
reg [3:0] mem [0:15];
|
||||||
|
@ -16,7 +17,13 @@ reg [3:0] mem [0:15];
|
||||||
integer i;
|
integer i;
|
||||||
initial
|
initial
|
||||||
for (i = 0; i < 16; i += 1)
|
for (i = 0; i < 16; i += 1)
|
||||||
mem[i] = INIT[i*4+:4];
|
case (OPTION_INIT)
|
||||||
|
"NONE": mem[i] = mem[i]; //?
|
||||||
|
"ZERO": mem[i] = 4'h0;
|
||||||
|
"ANY": mem[i] = INIT[i*4+:4];
|
||||||
|
"NO_UNDEF": mem[i] = INIT[i*4+:4];
|
||||||
|
"UNDEFINED": mem[i] = 4'hx;
|
||||||
|
endcase
|
||||||
|
|
||||||
assign PORT_R_RD_DATA = mem[PORT_R_ADDR];
|
assign PORT_R_RD_DATA = mem[PORT_R_ADDR];
|
||||||
assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR];
|
assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR];
|
||||||
|
|
19
tests/memlib/memlib_multilut.txt
Normal file
19
tests/memlib/memlib_multilut.txt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
ram distributed \LUT_MULTI {
|
||||||
|
abits 4;
|
||||||
|
width 2;
|
||||||
|
init any;
|
||||||
|
port arsw "RW" {
|
||||||
|
clock posedge;
|
||||||
|
}
|
||||||
|
ifdef PORTS_QUAD {
|
||||||
|
option "PORTS" "QUAD" {
|
||||||
|
port ar "R0" "R1" "R2" {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else ifdef PORTS_OCT {
|
||||||
|
option "PORTS" "OCT" {
|
||||||
|
port ar "R0" "R1" "R2" "R3" "R4" "R5" "R6" {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
tests/memlib/memlib_multilut.v
Normal file
45
tests/memlib/memlib_multilut.v
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
module LUT_MULTI(
|
||||||
|
input [3:0] PORT_R0_ADDR,
|
||||||
|
input [3:0] PORT_R1_ADDR,
|
||||||
|
input [3:0] PORT_R2_ADDR,
|
||||||
|
input [3:0] PORT_R3_ADDR,
|
||||||
|
input [3:0] PORT_R4_ADDR,
|
||||||
|
input [3:0] PORT_R5_ADDR,
|
||||||
|
input [3:0] PORT_R6_ADDR,
|
||||||
|
input [3:0] PORT_RW_ADDR,
|
||||||
|
input PORT_RW_CLK,
|
||||||
|
input PORT_RW_WR_EN,
|
||||||
|
input [1:0] PORT_RW_WR_DATA,
|
||||||
|
output [1:0] PORT_R0_RD_DATA,
|
||||||
|
output [1:0] PORT_R1_RD_DATA,
|
||||||
|
output [1:0] PORT_R2_RD_DATA,
|
||||||
|
output [1:0] PORT_R3_RD_DATA,
|
||||||
|
output [1:0] PORT_R4_RD_DATA,
|
||||||
|
output [1:0] PORT_R5_RD_DATA,
|
||||||
|
output [1:0] PORT_R6_RD_DATA,
|
||||||
|
output [1:0] PORT_RW_RD_DATA
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter OPTION_PORTS = "UNDEFINED";
|
||||||
|
|
||||||
|
reg [1:0] mem [0:15];
|
||||||
|
integer i;
|
||||||
|
initial
|
||||||
|
for (i = 0; i < 16; i += 1)
|
||||||
|
mem[i] = INIT[i*4+:4];
|
||||||
|
|
||||||
|
assign PORT_R0_RD_DATA = mem[PORT_R0_ADDR];
|
||||||
|
assign PORT_R1_RD_DATA = mem[PORT_R1_ADDR];
|
||||||
|
assign PORT_R2_RD_DATA = mem[PORT_R2_ADDR];
|
||||||
|
assign PORT_R3_RD_DATA = mem[PORT_R3_ADDR];
|
||||||
|
assign PORT_R4_RD_DATA = mem[PORT_R4_ADDR];
|
||||||
|
assign PORT_R5_RD_DATA = mem[PORT_R5_ADDR];
|
||||||
|
assign PORT_R6_RD_DATA = mem[PORT_R6_ADDR];
|
||||||
|
assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR];
|
||||||
|
|
||||||
|
always @(posedge PORT_RW_CLK)
|
||||||
|
if (PORT_RW_WR_EN)
|
||||||
|
mem[PORT_RW_ADDR] <= PORT_RW_WR_DATA;
|
||||||
|
|
||||||
|
endmodule
|
37
tests/memlib/memlib_wren.txt
Normal file
37
tests/memlib/memlib_wren.txt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
ram block \RAM_WREN {
|
||||||
|
abits 4;
|
||||||
|
init none;
|
||||||
|
|
||||||
|
ifdef NO_BYTE {
|
||||||
|
# single enable signal
|
||||||
|
widths 4 8 global;
|
||||||
|
} else ifdef W4_B4 {
|
||||||
|
widths 4 global;
|
||||||
|
byte 4;
|
||||||
|
} else ifdef W8_B4 {
|
||||||
|
widths 8 global;
|
||||||
|
option "BYTESIZE" 4 {
|
||||||
|
byte 4;
|
||||||
|
}
|
||||||
|
} else ifdef W8_B8 {
|
||||||
|
width 8;
|
||||||
|
byte 8;
|
||||||
|
} else ifdef W16_B4 {
|
||||||
|
widths 16 global;
|
||||||
|
option "BYTESIZE" 4 {
|
||||||
|
byte 4;
|
||||||
|
}
|
||||||
|
} else ifdef W64_B8 {
|
||||||
|
widths 64 global;
|
||||||
|
option "BYTESIZE" 8 {
|
||||||
|
byte 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
port srsw "A" {
|
||||||
|
clock posedge;
|
||||||
|
ifdef WRBE_SEPARATE {
|
||||||
|
wrbe_separate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
tests/memlib/memlib_wren.v
Normal file
33
tests/memlib/memlib_wren.v
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
module RAM_WREN (
|
||||||
|
input PORT_A_CLK,
|
||||||
|
input [ABITS-1:0] PORT_A_ADDR,
|
||||||
|
input [WIDTH-1:0] PORT_A_WR_DATA,
|
||||||
|
output reg [WIDTH-1:0] PORT_A_RD_DATA,
|
||||||
|
input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN,
|
||||||
|
input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter ABITS=4;
|
||||||
|
parameter WIDTH=8;
|
||||||
|
parameter PORT_A_WR_EN_WIDTH=1;
|
||||||
|
parameter PORT_A_WR_BE_WIDTH=0;
|
||||||
|
parameter OPTION_BYTESIZE=WIDTH;
|
||||||
|
parameter WB=OPTION_BYTESIZE;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
always @(posedge PORT_A_CLK) begin
|
||||||
|
for (i=0; i<PORT_A_WR_EN_WIDTH; i=i+1) // use PORT_A_WR_EN
|
||||||
|
if (!PORT_A_WR_BE_WIDTH && PORT_A_WR_EN[i])
|
||||||
|
mem[PORT_A_ADDR][i*WB+:WB] <= PORT_A_WR_DATA[i*WB+:WB];
|
||||||
|
for (i=0; i<PORT_A_WR_BE_WIDTH; i=i+1) // use PORT_A_WR_BE
|
||||||
|
if (PORT_A_WR_EN[0] && PORT_A_WR_BE[i])
|
||||||
|
mem[PORT_A_ADDR][i*WB+:WB] <= PORT_A_WR_DATA[i*WB+:WB];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge PORT_A_CLK)
|
||||||
|
if (!PORT_A_WR_EN[0])
|
||||||
|
PORT_A_RD_DATA <= mem[PORT_A_ADDR];
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in a new issue