aboutsummaryrefslogblamecommitdiff
path: root/src/tb/tb_fmc.v
blob: 20b602c5dbc58dcb260738c142099cfb65e6fcd5 (plain) (tree)








































































































































































































































































                                                                                                        
//------------------------------------------------------------------------------
//
// 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
//------------------------------------------------------------------------------