blob: 8d91922d87224edbabc636975cf234275148754b [file] [log] [blame]
// Copyright 2020-2022 F4PGA Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
`timescale 1ns/1ps
`define STRINGIFY(x) `"x`"
module TB;
localparam PERIOD = 50;
localparam ADDR_INCR = 1;
reg clk_0;
reg rce_0;
reg [`ADDR_WIDTH0-1:0] ra_0;
wire [`DATA_WIDTH0-1:0] rq_0;
reg wce_0;
reg [`ADDR_WIDTH0-1:0] wa_0;
reg [`DATA_WIDTH0-1:0] wd_0;
reg clk_1;
reg rce_1;
reg [`ADDR_WIDTH1-1:0] ra_1;
wire [`DATA_WIDTH1-1:0] rq_1;
reg wce_1;
reg [`ADDR_WIDTH1-1:0] wa_1;
reg [`DATA_WIDTH1-1:0] wd_1;
initial clk_0 = 0;
initial clk_1 = 0;
initial ra_0 = 0;
initial ra_1 = 0;
initial rce_0 = 0;
initial rce_1 = 0;
initial forever #(PERIOD / 2.0) clk_0 = ~clk_0;
initial begin
#(PERIOD / 4.0);
forever #(PERIOD / 2.0) clk_1 = ~clk_1;
end
initial begin
$dumpfile(`STRINGIFY(`VCD));
$dumpvars;
end
integer a;
integer b;
reg done_0;
reg done_1;
initial done_0 = 1'b0;
initial done_1 = 1'b0;
wire done_sim = done_0 & done_1;
reg [`DATA_WIDTH0-1:0] expected_0;
reg [`DATA_WIDTH1-1:0] expected_1;
reg read_test_0;
reg read_test_1;
initial read_test_0 = 0;
initial read_test_1 = 0;
always @(posedge clk_0) begin
expected_0 <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH0{1'b1}};
end
always @(posedge clk_1) begin
expected_1 <= ((b+1) | ((b+1) << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
end
wire error_0 = ((a != 0) && read_test_0) ? (rq_0 !== expected_0) : 0;
wire error_1 = ((b != (1<<`ADDR_WIDTH1) / 2) && read_test_1) ? (rq_1 !== expected_1) : 0;
integer error_0_cnt = 0;
integer error_1_cnt = 0;
always @ (posedge clk_0)
begin
if (error_0)
error_0_cnt <= error_0_cnt + 1'b1;
end
always @ (posedge clk_1)
begin
if (error_1)
error_1_cnt <= error_1_cnt + 1'b1;
end
// PART 0
initial #(1) begin
// Write data
for (a = 0; a < (1<<`ADDR_WIDTH0) / 2; a = a + ADDR_INCR) begin
@(negedge clk_0) begin
wa_0 = a;
wd_0 = a | (a << 20) | 20'h55000;
wce_0 = 1;
end
@(posedge clk_0) begin
#(PERIOD/10) wce_0 = 0;
end
end
// Read data
read_test_0 = 1;
for (a = 0; a < (1<<`ADDR_WIDTH0) / 2; a = a + ADDR_INCR) begin
@(negedge clk_0) begin
ra_0 = a;
rce_0 = 1;
end
@(posedge clk_0) begin
#(PERIOD/10) rce_0 = 0;
if ( rq_0 !== expected_0) begin
$display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq_0, expected_0, a);
end else begin
$display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq_0, expected_0, a);
end
end
end
done_0 = 1'b1;
a = 0;
end
// PART 1
initial #(1) begin
// Write data
for (b = (1<<`ADDR_WIDTH1) / 2; b < (1<<`ADDR_WIDTH1); b = b + ADDR_INCR) begin
@(negedge clk_1) begin
wa_1 = b;
wd_1 = (b+1) | ((b+1) << 20) | 20'h55000;
wce_1 = 1;
end
@(posedge clk_1) begin
#(PERIOD/10) wce_1 = 0;
end
end
// Read data
read_test_1 = 1;
for (b = (1<<`ADDR_WIDTH1) / 2; b < (1<<`ADDR_WIDTH1); b = b + ADDR_INCR) begin
@(negedge clk_1) begin
ra_1 = b;
rce_1 = 1;
end
@(posedge clk_1) begin
#(PERIOD/10) rce_1 = 0;
if ( rq_1 !== expected_1) begin
$display("%d: PORT 1: FAIL: mismatch act=%x exp=%x at %x", $time, rq_1, expected_1, b);
end else begin
$display("%d: PORT 1: OK: act=%x exp=%x at %x", $time, rq_1, expected_1, b);
end
end
end
done_1 = 1'b1;
b = (1<<`ADDR_WIDTH1) / 2;
end
// Scan for simulation finish
always @(posedge clk_0, posedge clk_1) begin
if (done_sim)
$finish_and_return( (error_0_cnt == 0 & error_1_cnt == 0) ? 0 : -1 );
end
case (`STRINGIFY(`TOP))
"spram_18x1024_2x": begin
spram_18x1024_2x #() bram (
.clock0(clk_0),
.REN0_i(rce_0),
.RD_ADDR0_i(ra_0),
.RDATA0_o(rq_0),
.WEN0_i(wce_0),
.WR_ADDR0_i(wa_0),
.WDATA0_i(wd_0),
.clock1(clk_1),
.REN1_i(rce_1),
.RD_ADDR1_i(ra_1),
.RDATA1_o(rq_1),
.WEN1_i(wce_1),
.WR_ADDR1_i(wa_1),
.WDATA1_i(wd_1)
);
end
"spram_9x2048_x2": begin
spram_9x2048_x2 #() bram (
.clock0(clk_0),
.REN0_i(rce_0),
.RD_ADDR0_i(ra_0),
.RDATA0_o(rq_0),
.WEN0_i(wce_0),
.WR_ADDR0_i(wa_0),
.WDATA0_i(wd_0),
.clock1(clk_1),
.REN1_i(rce_1),
.RD_ADDR1_i(ra_1),
.RDATA1_o(rq_1),
.WEN1_i(wce_1),
.WR_ADDR1_i(wa_1),
.WDATA1_i(wd_1)
);
end
"spram_9x2048_18x1024": begin
spram_9x2048_18x1024 #() bram (
.clock0(clk_0),
.REN0_i(rce_0),
.RD_ADDR0_i(ra_0),
.RDATA0_o(rq_0),
.WEN0_i(wce_0),
.WR_ADDR0_i(wa_0),
.WDATA0_i(wd_0),
.clock1(clk_1),
.REN1_i(rce_1),
.RD_ADDR1_i(ra_1),
.RDATA1_o(rq_1),
.WEN1_i(wce_1),
.WR_ADDR1_i(wa_1),
.WDATA1_i(wd_1)
);
end
endcase
endmodule