Make the naming convention for the top-level testbench consistent with the top-level design. Prefix this with
, i.e.
. By adopting this naming convention the process of identifying the top-level testbench module becomes much easier for the
script. At present it seems Vivado struggles to automatically identify the testbench top-level.
Relocate source file in the repository & file system.
//
// File .......... tb_zedboard_leds_switches.sv
// Author ........ Steve Haywood
// Website ....... http://www.spacewire.co.uk
// Project ....... Zedboard LEDs & Switches (SpaceWire UK Tutorial)
// Date .......... 25 Jun 2025
// Version ....... 4.0
// History .......
// 3.0 zedboard_leds_switches/fw/src/testbench/testbench.sv
// Description ...
// Very simple testbench to check correct connectivity of the block
// diagram. Uses the Zynq Verification IP suite to read & write to & from
// the various peripherals (Identification, GPIO Zed & Register Bank).
//
module tb_zedboard_leds_switches;
// Time unit & precision
timeunit 1ns;
timeprecision 1ps;
// Identification base address, local addresses & constants
localparam bit [31:0] base_identification = 32'h40000000;
localparam int id_fields [6:0][1:0] =
'{
'{12'h180, 128}, // id_unknown
'{12'h140, 64}, // id_hash
'{12'h120, 32}, // id_timestamp
'{12'h100, 32}, // id_version
'{12'h0C0, 64}, // id_author
'{12'h080, 64}, // id_company
'{12'h000, 128} // id_description
};
localparam string id_strings [6:0] =
'{
"Unknown",
"Hash",
"Timestamp",
"Version",
"Author",
"Company",
"Description"
};
// GPIO base address, local addresses & constants
localparam bit [31:0] base_gpio_zed = 32'h40010000;
localparam bit [7:0] gpio_led = 8'h00;
localparam bit [7:0] gpio_dip_switches = 8'h08;
localparam bit [7:0] gpio_push_buttons = 8'h10;
// Register Bank base address, local addresses & constants
localparam bit [31:0] base_register_bank = 32'h40020000;
// Signals
wire ps_clk;
wire ps_porb;
wire ps_srstb;
bit [ 7:0] leds;
bit [ 7:0] switches;
bit [ 4:0] buttons;
bit clk;
bit resetn;
bit bresp;
bit [31:0] rdata;
bit rresp;
// 50MHz Clock
always #10 clk = !clk;
// Reset
initial begin
repeat(20)
@(posedge clk);
resetn = 1'b1;
end
// Drive PL Clock & Reset
assign ps_clk = clk;
assign ps_porb = resetn;
assign ps_srstb = resetn;
// Stimulus
initial begin
// AXI Address & Data
bit [31:0] addr;
bit [31:0] data;
// ID string
string name;
// Scoreboard
int tests;
int fails;
// Allow reset time to work
@(posedge resetn);
repeat(10)
@(posedge clk);
// Minimise VIP debug messages
uut.system_i.processing_system7_0.inst.set_debug_level_info(0);
// Reset PL
uut.system_i.processing_system7_0.inst.fpga_soft_reset(1);
uut.system_i.processing_system7_0.inst.fpga_soft_reset(0);
// Read GPIO LED Register
addr = base_gpio_zed + gpio_led;
data = 8'h18;
uut.system_i.processing_system7_0.inst.read_data(addr, 4, rdata, rresp);
$display ("Read from GPIO LED Register: Address = 32'h%x, Expected Data = 32'h%x, Received Data = 32'h%x (%s)", addr, data, rdata, (rdata == data) ? "Passed" : "Failed");
if (rdata != data)
fails++;
tests++;
// Write to GPIO LED Register
addr = base_gpio_zed + gpio_led;
data = 8'h81;
uut.system_i.processing_system7_0.inst.write_data(addr, 4, data, bresp);
// Read from GPIO LED Register
addr = base_gpio_zed + gpio_led;
uut.system_i.processing_system7_0.inst.read_data(addr, 4, rdata, rresp);
$display ("Read from GPIO LED Register: Address = 32'h%x, Expected Data = 32'h%x, Received Data = 32'h%x (%s)", addr, data, rdata, (rdata == data) ? "Passed" : "Failed");
if (rdata != data)
fails++;
tests++;
// Set some of the switches to 'on'
switches = 8'b11000011;
// Wait for switch debounce
#656000ns;
// Read GPIO Switch Register
addr = base_gpio_zed + gpio_dip_switches;
data = switches;
uut.system_i.processing_system7_0.inst.read_data(addr, 4, rdata, rresp);
$display ("Read from GPIO Switch Register: Address = 32'h%x, Expected Data = 32'h%x, Received Data = 32'h%x (%s)", addr, data, rdata, (rdata == data) ? "Passed" : "Failed");
if (rdata != data)
fails++;
tests++;
// Write to Register Bank
for (int i = 0; i < 4; i++) begin
addr = base_register_bank + i * 4;
data = 65536 + i;
$display("Write to Register Bank: Address = 32'h%x, Data = 32'h%x", addr, data);
uut.system_i.processing_system7_0.inst.write_data(addr, 4, data, bresp);
end
// Read from Register Bank
for (int i = 3; i >= 0; i--) begin
addr = base_register_bank + i * 4;
data = 65536 + i;
uut.system_i.processing_system7_0.inst.read_data(addr, 4, rdata, rresp);
$display ("Read from Register Bank: Address = 32'h%x, Expected Data = 32'h%x, Received Data = 32'h%x (%s)", addr, data, rdata, (rdata == data) ? "Passed" : "Failed");
if (rdata != data)
fails++;
tests++;
end
// Read from Identification
for (int h = 0; h < 6; h++) begin
name = "";
for (int i = 0; i < id_fields[h][0]; i = i + 4) begin
addr = base_identification + id_fields[h][1] + i;
uut.system_i.processing_system7_0.inst.read_data(addr, 4, rdata, rresp);
for (int j = 0; j < 4; j++) begin
if (rdata[8*j+:8] != 8'h00)
name = {name, rdata[8*j+:8]};
end
end
$display ("Read from Identification: Address = 32'h%x, Expected Data = %s, Received Data = %s (%s)", id_fields[h][1], id_strings[h], name, (id_strings[h] == name) ? "Passed" : "Failed");
if (id_strings[h] != name)
fails++;
tests++;
end
// Scoreboard
$display;
$display("Performed %0d tests, %0d passed, %0d failed.", tests, tests-fails, fails);
// All done
$display;
$display ("That's all folks!");
$display;
$stop;
end
// Unit Under Test
zedboard_leds_switches #
(
// Parameters
.id_description ( id_strings[0] ), // P:Firmware Description ... Max 128 Characters
.id_company ( id_strings[1] ), // P:Company ................ Max 64 Characters
.id_author ( id_strings[2] ), // P:Author ................. Max 64 Characters
.id_version ( id_strings[3] ), // P:Version Number ......... Max 16 Characters
.id_timestamp ( id_strings[4] ), // P:Build Timestamp ........ Max 32 Characters
.id_hash ( id_strings[5] ) // P:Build Timestamp ........ Max 32 Characters
)
uut
(
// LEDs
.leds ( leds ), // O:LEDs
// Switches
.switches ( switches ), // I:Switches
// Push Buttons
.buttons ( buttons ), // I:Push Buttons
// System
.DDR_addr ( ), // B:Address
.DDR_ba ( ), // B:Bank Address
.DDR_cas_n ( ), // B:Column Address Select
.DDR_ck_n ( ), // B:Clock (Neg)
.DDR_ck_p ( ), // B:Clock (Pos)
.DDR_cke ( ), // B:Clock Enable
.DDR_cs_n ( ), // B:Chip Select
.DDR_dm ( ), // B:Data Mask
.DDR_dq ( ), // B:Data Input/Output
.DDR_dqs_n ( ), // B:Data Strobe (Neg)
.DDR_dqs_p ( ), // B:Data Strobe (Pos)
.DDR_odt ( ), // B:Output Dynamic Termination
.DDR_ras_n ( ), // B:Row Address Select
.DDR_reset_n ( ), // B:Reset
.DDR_we_n ( ), // B:Write Enable
.FIXED_IO_ddr_vrn ( ), // B:Termination Voltage
.FIXED_IO_ddr_vrp ( ), // B:Termination Voltage
.FIXED_IO_mio ( ), // B:Peripheral Input/Output
.FIXED_IO_ps_clk ( ps_clk ), // B:System Reference Clock
.FIXED_IO_ps_porb ( ps_porb ), // B:Power On Reset
.FIXED_IO_ps_srstb ( ps_srstb ) // B:External System Reset
);
endmodule
Check out the changes.