blob: a9e25cf03fe205d4e09ec7ca220ecf27c3573647 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// xbar_${xbar.name}_tb module generated by `tlgen.py` tool for smoke check
<%
import random
%>
module xbar_${xbar.name}_tb;
import tlul_pkg::*;
// Clock generator
% for clock in xbar.clocks:
localparam CLK_${clock.upper()}_PERIOD = ${random.randint(10,40)};
% endfor
% for clock in xbar.clocks:
logic clk_${clock};
initial begin
clk_${clock} = 1'b0;
forever begin
#(CLK_${clock.upper()}_PERIOD/2)
clk_${clock} = ~clk_${clock};
end
end
% endfor
// One reset but synchronized to multiple reset
logic rst_n ;
initial begin
rst_n = 1'b0;
#117ns
rst_n = 1'b1;
end
% for clock in xbar.clocks:
logic rst_${clock}_n;
initial begin
rst_${clock}_n = 1'b0;
wait(rst_n == 1'b1);
@(negedge clk_${clock});
rst_${clock}_n = 1'b1;
end
% endfor
// Signals
% for node in xbar.hosts + xbar.devices:
tl_h2d_t tl_${node.name}_h2d ;
tl_d2h_t tl_${node.name}_d2h ;
% endfor
// Instance of xbar_${xbar.name}
xbar_${xbar.name} dut (
% for clock in xbar.clocks:
.clk_${clock}_i (clk_${clock}),
.rst_${clock}_ni (rst_${clock}_n),
% endfor
// Host interfaces
% for node in xbar.hosts:
.tl_${node.name}_i (tl_${node.name}_h2d),
.tl_${node.name}_o (tl_${node.name}_d2h),
% endfor
// Device interfaces
% for node in xbar.devices:
.tl_${node.name}_o (tl_${node.name}_h2d),
.tl_${node.name}_i (tl_${node.name}_d2h),
% endfor
.scanmode_i (1'b0)
);
task automatic tl_write(ref clk, ref tl_h2d_t tl_h2d, ref tl_d2h_t tl_d2h,
input [31:0] addr, input [31:0] wdata);
tl_h2d.a_address = addr;
tl_h2d.a_opcode = PutFullData;
tl_h2d.a_param = '0;
tl_h2d.a_size = 2'h2;
tl_h2d.a_user = '0;
tl_h2d.a_data = wdata;
tl_h2d.a_mask = 'hF;
tl_h2d.a_source = 0;
tl_h2d.a_valid = 1'b1;
@(posedge clk iff tl_d2h.a_ready == 1'b1);
tl_h2d.a_valid = 1'b0;
tl_h2d.d_ready = 1'b1;
@(posedge clk iff tl_d2h.d_valid == 1'b1);
if (tl_d2h.d_error == 1'b1) $error("TL-UL interface error occurred");
tl_h2d.d_ready = 1'b0;
endtask : tl_write
task automatic tl_read(ref clk, ref tl_h2d_t tl_h2d, ref tl_d2h_t tl_d2h,
input [31:0] addr, output logic [31:0] rdata);
tl_h2d.a_address = addr;
tl_h2d.a_opcode = Get;
tl_h2d.a_param = '0;
tl_h2d.a_size = 2'h2;
tl_h2d.a_user = '0;
tl_h2d.a_source = 0;
tl_h2d.a_valid = 1'b1;
@(posedge clk iff tl_d2h.a_ready == 1'b1);
tl_h2d.a_valid = 1'b0;
tl_h2d.d_ready = 1'b1;
@(posedge clk iff tl_d2h.d_valid == 1'b1);
if (tl_d2h.d_error == 1'b1) $error("TL-UL interface error occurred");
rdata = tl_d2h.d_data;
tl_h2d.d_ready = 1'b0;
endtask : tl_read
task automatic tl_compare(ref clk, ref tl_h2d_t tl_h2d, ref tl_d2h_t tl_d2h,
input [31:0] addr, input [31:0] wdata);
automatic logic [31:0] rdata;
tl_write(clk, tl_h2d, tl_d2h, addr, wdata);
tl_read(clk, tl_h2d, tl_d2h, addr, rdata);
if (wdata != rdata) $error("Addr(%x) mismatch: Exp(%x), Got(%x)", addr, wdata, rdata);
endtask : tl_compare
// Transaction generator
//
// Goal: Each host creates random sequence
// 1. select random device
// 2. select random burst (not implemented)
// 3. select random address range within the device
// 4. Write and read then compare
// Note: There's chance that another host updates content at the same address location when a host
// reads. This is unavoidable but the change is unlikely. But remind that it is possible.
typedef struct {
logic [31:0] addr_from;
logic [31:0] addr_to;
} addr_range_t;
% for host in xbar.hosts:
<%
clkname = "clk_" + host.clocks[0]
rstname = "rst_" + host.clocks[0] + "_n"
num_dev = len(xbar.get_s1n_if_exist(host).ds)
addrs = list(map(xbar.get_addr, xbar.get_devices_from_host(host)))
%>\
addr_range_t ${host.name}_map [${num_dev}] = '{
% for addr in addrs:
% if loop.last:
'{addr_from: 32'h${"%x"%(addr[0])}, addr_to: 32'h${"%x" %(addr[1])}}
% else:
'{addr_from: 32'h${"%x"%(addr[0])}, addr_to: 32'h${"%x" %(addr[1])}},
% endif
% endfor
};
initial begin
// Wait until reset is released
tl_${host.name}_h2d.a_valid = 1'b0;
tl_${host.name}_h2d.d_ready = 1'b0;
wait(${rstname} == 1'b1);
@(negedge ${clkname});
forever begin
// choose among the device
automatic int dev_sel = $urandom_range(${num_dev-1},0);
// determine address
automatic logic [31:0] addr = $urandom_range(${host.name}_map[dev_sel].addr_to,
${host.name}_map[dev_sel].addr_from);
addr = addr & 32'h FFFF_FFFC;
// compare
tl_compare(${clkname}, tl_${host.name}_h2d, tl_${host.name}_d2h, addr, $urandom());
end
end
% endfor
// Instantiate generic TL-UL sram
% for device in xbar.devices:
<%
tl_h2d_sig = "tl_" + device.name + "_h2d"
tl_d2h_sig = "tl_" + device.name + "_d2h"
%>
device_sram u_device_${device.name} (
.clk_i (clk_${device.clocks[0]}),
.tl_i (${tl_h2d_sig}),
.tl_o (${tl_d2h_sig})
);
% endfor
initial begin
#100us
$finish(1);
end
endmodule