//------------------------------------------------------------------------------
//
// tb_fmc.v
// -----------------------------------------------------------------------------
// Testbench for fixed latency FMC arbiter.
//
// Authors: Pavel Shatov
//
// Copyright (c) 2018, NORDUnet A/S
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the NORDUnet nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
`timescale 1ns / 1ps
//------------------------------------------------------------------------------
module tb_fmc;
//
// Clock (100 MHz)
//
localparam CLOCK_PERIOD = 10.0;
localparam HALF_CLOCK_PERIOD = 0.5 * CLOCK_PERIOD;
reg clk_fmc = 1'b0;
//reg clk_45 = 1'b0;
//reg clk_90 = 1'b0;
initial begin
forever #HALF_CLOCK_PERIOD clk_fmc = ~clk_fmc;
end
wire clk_45 = clk_fmc;
wire clk_90 = clk_fmc;
//initial begin
//#1.25;
//forever #HALF_CLOCK_PERIOD clk_45 = ~clk_45;
//end
//initial begin
//#2.5;
//forever #HALF_CLOCK_PERIOD clk_90 = ~clk_90;
//end
//
// FMC Arbiter - FPGA Side
//
wire [23: 0] sys_fmc_addr;
wire sys_fmc_wren;
wire sys_fmc_rden;
wire [31: 0] sys_fmc_dout;
reg [31: 0] sys_fmc_din;
reg [23: 0] fmc_a = {24{1'bX}};
reg [31: 0] fmc_d_drive;
wire [31: 0] fmc_d_bidir;
reg fmc_ne1 = 1'b1;
reg fmc_noe = 1'b1;
reg fmc_nwe = 1'b1;
reg fmc_nl = 1'b1;
wire fmc_nwait_dummy;
assign fmc_d_bidir = fmc_noe ? fmc_d_drive : 32'hZZZZZZZZ;
fmc_arbiter #(.NUM_ADDR_BITS(24))
uut
(
// fmc bus
.fmc_a (fmc_a),
.fmc_d (fmc_d_bidir),
.fmc_ne1 (fmc_ne1),
.fmc_nl (fmc_nl),
.fmc_nwe (fmc_nwe),
.fmc_noe (fmc_noe),
.fmc_nwait (fmc_nwait_dummy),
// system clock
.sys_clk (clk_45),
.fmc_clk_aux (clk_90),
// user bus
.sys_addr (sys_fmc_addr),
.sys_wr_en (sys_fmc_wren),
.sys_data_out (sys_fmc_dout),
.sys_rd_en (sys_fmc_rden),
.sys_data_in (sys_fmc_din)
);
//
// Helper Tasks
//
task wait_ticks;
input integer num_ticks;
integer cnt;
begin
for (cnt=0; cnt<num_ticks; cnt=cnt+1)
#CLOCK_PERIOD;
end
endtask
task wait_half_tick;
begin
#HALF_CLOCK_PERIOD;
end
endtask
task fmc_write;
input [23: 0] addr;
input [31: 0] data;
begin
fmc_ne1 = 1'b0; // select
fmc_nl = 1'b0; // set latch flag
fmc_a = addr; // set address
fmc_nwe = 1'b0; // set write-enable
wait_ticks(1); // mimic latency
fmc_nl = 1'b1; // clear latch flag
fmc_a = {24{1'bX}}; // clear address
wait_ticks(3); // mimic latency
fmc_d_drive = data; // set data
wait_ticks(1); // mimic latency
fmc_ne1 = 1'b1; // deselect
fmc_nwe = 1'b1; // clear write-enable
fmc_d_drive = 32'hXXXXXXXX; // clear data
wait_ticks(1); // pause
end
endtask
task fmc_read;
input [23: 0] addr;
output [31: 0] data;
begin
fmc_ne1 = 1'b0; // select
fmc_nl = 1'b0; // set latch flag
fmc_a = addr; // set address
wait_ticks(1); // mimic latency
fmc_nl = 1'b1; // clear latch flag
fmc_a = {24{1'bX}}; // clear address
wait_ticks(1); // mimic latency
fmc_noe = 1'b0; // tri-state bus
wait_ticks(3); // mimic latency
wait_half_tick(); // mimic latency
data = fmc_d_bidir; // sample data
wait_half_tick(); // mimic latency
wait_ticks(2); // mimic bus turnaround
fmc_ne1 = 1'b1; // deselect
fmc_noe = 1'b1; // drive bus
wait_ticks(1); // pause
end
endtask
//
// Script
//
reg [31:0] data;
initial begin
wait_ticks(200);
fmc_write(24'h223344, 32'hCCAA5533);
fmc_write(24'h667788, 32'hEDCBEDCB);
fmc_write(24'h223344, 32'hCCAA5533);
fmc_write(24'h667788, 32'hEDCBEDCB);
fmc_read(24'h223344, data);
fmc_read(24'h667788, data);
fmc_read(24'h223344, data);
fmc_read(24'h667788, data);
fmc_write(24'h223344, 32'hCCAA5533);
fmc_write(24'h667788, 32'hEDCBEDCB);
fmc_write(24'h223344, 32'hCCAA5533);
fmc_write(24'h667788, 32'hEDCBEDCB);
fmc_read(24'h223344, data);
fmc_read(24'h667788, data);
fmc_read(24'h223344, data);
fmc_read(24'h667788, data);
end
//
// Demo Registers
//
reg [31: 0] reg_test_a;
reg [31: 0] reg_test_b;
reg [31: 0] reg_test_c;
always @(posedge clk_45)
//
if (sys_fmc_wren)
//
case (sys_fmc_addr)
24'h000000: reg_test_a <= sys_fmc_dout;
24'hFFFFFF: reg_test_c <= sys_fmc_dout;
default: reg_test_b <= sys_fmc_dout;
endcase
always @(posedge clk_45)
//
if (sys_fmc_rden)
//
case (sys_fmc_addr)
24'h000000: sys_fmc_din <= reg_test_a;
24'hFFFFFF: sys_fmc_din <= reg_test_c;
default: sys_fmc_din <= reg_test_b;
endcase
//
else
//
sys_fmc_din <= 32'hXXXXXXXX;
endmodule
//------------------------------------------------------------------------------
// End-of-File
//------------------------------------------------------------------------------