Newer
Older

Dimitris Lampridis
committed
//------------------------------------------------------------------------------
// CERN BE-CO-HT
// GN4124 core for PCIe FMC carrier
// http://www.ohwr.org/projects/gn4124-core
//------------------------------------------------------------------------------
//
// unit name: main
//

Dimitris Lampridis
committed
// description: This is a simple example testbench, to demonstrate how to use

Dimitris Lampridis
committed
// the SystemVerilog BFM of the GN4124 to perform simple accesses over wishbone.
//
// The testbench simply connects the wishbone master of the GN4124 to its own

Dimitris Lampridis
committed
// DMA configuration wishbone slave and attaches a pre-initialised dummy RAM
// with a wishbone interface to the pipelined DMA interface in order to perform
// a DMA read.

Dimitris Lampridis
committed
//
//------------------------------------------------------------------------------
// Copyright CERN 2019
//------------------------------------------------------------------------------
// Copyright and related rights are licensed under the Solderpad Hardware
// 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://solderpad.org/licenses/SHL-2.0.
// Unless required by applicable law or agreed to in writing, software,
// hardware and materials distributed under this 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.
//------------------------------------------------------------------------------
`timescale 1ns/1ps
`include "gn4124_bfm.svh"
import wishbone_pkg::*;
module main;
reg clk_125m = 0;

Dimitris Lampridis
committed
logic gn4124_irq;
t_wishbone_master_in wb_in, wb_dma_in, wb_mem_in;
t_wishbone_master_out wb_out, wb_dma_out, wb_mem_out;

Dimitris Lampridis
committed
always #4ns clk_125m <= ~clk_125m;
logic rst_125m_n;
initial begin
rst_125m_n = 0;
#80ns rst_125m_n = 1;
end

Dimitris Lampridis
committed
IGN4124PCIMaster i_gn4124 ();
xwb_gn4124_core
DUT (
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
.rst_n_a_i (i_gn4124.rst_n),
.p2l_clk_p_i (i_gn4124.p2l_clk_p),
.p2l_clk_n_i (i_gn4124.p2l_clk_n),
.p2l_data_i (i_gn4124.p2l_data),
.p2l_dframe_i (i_gn4124.p2l_dframe),
.p2l_valid_i (i_gn4124.p2l_valid),
.p2l_rdy_o (i_gn4124.p2l_rdy),
.p_wr_req_i (i_gn4124.p_wr_req),
.p_wr_rdy_o (i_gn4124.p_wr_rdy),
.rx_error_o (i_gn4124.rx_error),
.vc_rdy_i (i_gn4124.vc_rdy),
.l2p_clk_p_o (i_gn4124.l2p_clk_p),
.l2p_clk_n_o (i_gn4124.l2p_clk_n),
.l2p_data_o (i_gn4124.l2p_data),
.l2p_dframe_o (i_gn4124.l2p_dframe),
.l2p_valid_o (i_gn4124.l2p_valid),
.l2p_edb_o (i_gn4124.l2p_edb),
.l2p_rdy_i (i_gn4124.l2p_rdy),
.l_wr_rdy_i (i_gn4124.l_wr_rdy),
.p_rd_d_rdy_i (i_gn4124.p_rd_d_rdy),
.tx_error_i (i_gn4124.tx_error),
.dma_irq_o (dma_irq),
.irq_p_i (1'b0),
.irq_p_o (gn4124_irq),
.status_o (),
.wb_master_clk_i (clk_125m),
.wb_master_rst_n_i (rst_125m_n),
.wb_master_i (wb_in),
.wb_master_o (wb_out),
.wb_dma_cfg_clk_i (clk_125m),
.wb_dma_cfg_rst_n_i (rst_125m_n),
.wb_dma_cfg_i (wb_out),
.wb_dma_cfg_o (wb_in),
.wb_dma_dat_clk_i (clk_125m),
.wb_dma_dat_rst_n_i (rst_125m_n),
.wb_dma_dat_i (wb_dma_in),
.wb_dma_dat_o (wb_dma_out)
);

Dimitris Lampridis
committed

Dimitris Lampridis
committed
xwb_dpram #
(
.g_size (32),
.g_init_file ("mem_init.bram"),
.g_slave1_interface_mode (1), // 1 = PIPELINED
.g_slave2_interface_mode (1),
.g_slave1_granularity (1), // 1 = WORD
.g_slave2_granularity (1)
)
MEM (
.rst_n_i (1'b1),
.clk_sys_i (clk_125m),
.slave1_i (wb_dma_out),
.slave1_o (wb_dma_in),
.slave2_i (wb_mem_out),
.slave2_o (wb_mem_in)
);

Dimitris Lampridis
committed

Dimitris Lampridis
committed
CBusAccessor acc;
task val_check(string name, uint32_t addr, val, expected);

Dimitris Lampridis
committed
if (val != expected)
begin
$display();
$display("Simulation FAILED");
$fatal(1, "%s error at address 0x%.2x. Expected 0x%.8x, got 0x%.8x",
name, addr, expected, val);
end

Dimitris Lampridis
committed
endtask // val_check
task reg_check(uint32_t addr, expected);

Dimitris Lampridis
committed
uint64_t val;
acc.read(addr, val);
val_check("Register read-back", addr, val, expected);

Dimitris Lampridis
committed
endtask // reg_check

Dimitris Lampridis
committed
task mem_check(uint32_t addr, expected);
uint64_t val;
i_gn4124.host_mem_read(addr, val);
val_check("Memory read-back", addr, val, expected);
endtask // reg_check
task check_irq_status;
// Check irq status
reg_check('h04, 'h04);
if (dma_irq != 1'b1)
$fatal(1, "dma irq should be 1");
endtask
task clear_irq;
acc.write('h04, 'h04);
reg_check('h04, 'h00);
if (dma_irq != 1'b0)
$fatal(1, "dma irq should be 0");
endtask

Dimitris Lampridis
committed
initial begin
automatic int ntest = 1;
const int tests = 7;
uint32_t addr, val, expected;

Dimitris Lampridis
committed
@(posedge i_gn4124.ready);
acc = i_gn4124.get_accessor();
acc.set_default_xfer_size(4);
@(posedge clk_125m);
$write("Test %0d/%0d: simple read/write accesses over Wishbone: ",
ntest++, tests);

Dimitris Lampridis
committed
// Verify simple read/writes over wishbone

Dimitris Lampridis
committed
reg_check('h0, 'h0);
acc.write('h0c, 'hffacce55);
acc.write('h10, 'h1badcafe);

Dimitris Lampridis
committed
reg_check('h0c, 'hffacce55);
reg_check('h10, 'h1badcafe);

Dimitris Lampridis
committed

Dimitris Lampridis
committed
// Reset all DMA config registers

Dimitris Lampridis
committed
for (addr = 'h00; addr <= 'h20; addr += 4)
begin
acc.write(addr, 'h0);
end
$write("PASS\n");
$write("Test %0d/%0d: 32 reads over DMA, abort after first read: ",
ntest++, tests);

Dimitris Lampridis
committed
if (dma_irq != 1'b0)
$fatal(1, "dma irq should be 0");
acc.write('h14, 'h80); // count
acc.write('h00, 'h01); // start

Dimitris Lampridis
committed
// Check values read from memory
@(posedge i_gn4124.l2p_valid); // skip header
@(posedge i_gn4124.l2p_valid);
expected = 32'h8000001f;
val = i_gn4124.l2p_data;
@(posedge i_gn4124.l2p_clk_n);
val |= i_gn4124.l2p_data << 16;
val_check("DMA read-back", 'h20, val, expected);
repeat(2) @(posedge clk_125m);
// Test abort feature
acc.write('h00, 'h02);
reg_check('h04, 'h03);
acc.write('h00, 'h00);
repeat(2) @(posedge clk_125m);
$write("PASS\n");

Dimitris Lampridis
committed
$write("Test %0d/%0d: 2x32 chained reads over DMA: ",
ntest++, tests);
// Setup DMA chain info in BFM memory
i_gn4124.host_mem_write('h20000, 'h00000000); // remote address
i_gn4124.host_mem_write('h20004, 'h20000100); // hstartL
i_gn4124.host_mem_write('h20008, 'h00000000); // hstartH
i_gn4124.host_mem_write('h2000C, 'h80); // count
i_gn4124.host_mem_write('h20010, 'h00); // nextL
i_gn4124.host_mem_write('h20014, 'h00); // nextH
i_gn4124.host_mem_write('h20018, 'h00); // attrib
acc.write('h14, 'h80); // count
acc.write('h20, 'h02); // attrib
acc.write('h0c, 'h20000000); // hstartL
acc.write('h10, 'h00000000); // hstartH
// Point to chain info in BFM memory
acc.write('h18, 'h20020000); // nextL
acc.write('h1C, 'h00000000); // nextH
acc.write('h00, 'h01); // start
@(posedge dma_irq);
check_irq_status;

Dimitris Lampridis
committed
for (addr = 'h00; addr < 'h20; addr += 1)
begin
expected = 32'h80000000 + 'h20 - addr - 1;
mem_check(4 * addr, expected);
mem_check('h100 + 4 * addr, expected);
end
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
clear_irq;
repeat(4) @(posedge clk_125m);
$write("PASS\n");
// ---------------------------------
$write("Test %0d/%0d: 128 reads over DMA: ",
ntest++, tests);
// Setup DMA
acc.write('h14, 'h100); // count
acc.write('h20, 'h00); // attrib
acc.write('h0c, 'h20000000); // hstartL
acc.write('h10, 'h00000000); // hstartH
acc.write('h00, 'h01); // start
@(posedge dma_irq);
check_irq_status;
for (addr = 'h00; addr < 'h40; addr += 1)
begin
expected = 32'h80000000 + 'h20 - addr - 1;
mem_check(4 * addr, expected);
end
clear_irq;

Dimitris Lampridis
committed
repeat(4) @(posedge clk_125m);
$write("PASS\n");
// Check all four byte swap settings
// ---------------------------------
for (int i = 0; i < 4; i++) begin
$write("Test %0d/%0d: 16KB reads over DMA (byte swap = %0d): ",
ntest++, tests, i);
// Restart
acc.write('h14, 'h4000); // count

Dimitris Lampridis
committed
acc.write('h20, 'h00); // attrib
acc.write('h0c, 'h20000000 + i * 'h1000); // hstartL
acc.write('h10, 'h00000000); // hstartH
acc.write('h00, (i << 2) | 'h01); // start

Dimitris Lampridis
committed
@(posedge dma_irq);
check_irq_status;
for (addr = 'h00; addr < 'h1000; addr += 1)

Dimitris Lampridis
committed
expected = 32'h80000000 + 'h20 - (addr % 'h20) - 1;
$write("ex: %x", expected);
if (i == 1)
expected = {<<8{expected}};
else if (i == 2)
expected = {<<16{expected}};
else if (i == 3)
expected = {<<16{{<<8{expected}}}};
$display("ex: %x", expected);

Dimitris Lampridis
committed
mem_check((i * 'h1000) + 4 * addr, expected);

Dimitris Lampridis
committed
repeat(4) @(posedge clk_125m);
$write("PASS\n");
#1us;
end

Dimitris Lampridis
committed

Dimitris Lampridis
committed
$display();
$display("Simulation PASSED");
$finish;
end
endmodule // main