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