Transaction-Level Testbenches for FPGA Simulation

,

I am following the track “FPGA Verification Capabilities” by Ray Salemi, where he goes over 7 steps to convert a rudimentary testbench to a transaction level testbench with self checking and automatic stimulus generation. From my understanding, it is a “UVM-like” testbench, but without using any of the UVM base classes except for TLM FIFOs to manage threads, which is great for someone like me who is just starting out with learning verification.

In the playlist, the driver is a SystemVerilog module, and Input_transaction is a custom SystemVerilog class that holds all the relevant transaction fields

module driver(ref uvm_tlm_fifo #(Input_transaction) in_f,
                         // output ports to be connected to the DUT
                         ...
);
    Input_transaction t;
    always @(negedge clk) begin
         if(in_f.try_get(t)) 
             // drive the output signals using non-blocking assignments
              ....
    end
endmodule

The input transaction is completed in one clock tick

I’m trying to extend this same concept to a more complex transaction defined as follows:

  1. Assume that the DUT has an interface with - data, valid and last
  2. Define one transaction as one “packet” - i.e., one data packet between the first valid and last.

Now, the same concept does not seem to work when writing the driver, as the transaction spans multiple clock ticks:

module driver(ref uvm_tlm_fifo #(Input_transaction) in_f,
                         output logic valid,
                         output logic [7:0] data,
                         output logic last);
Input_transaction t;
always @(negedge clk) begin
    if(in_f.try_get(t) begin
        valid <= 1;
        // what I want to do, but does it work with the always block???
        foreach(t.payload[i]) data <= t.payload[i];
    end
end

The above does not work the way that I expect - from what I can tell, the always block will trigger every negedge, and thus once the TLM FIFO is read, it will be empty and the foreach block will never drive the other words in the payload.

What might be the best way to extend the driver module to do something like this? Will I have to make a state machine inside the driver module as well? Or is there a cleaner way?
I would prefer not using the UVM constructs as my simulator (Xilinx Simulator) does not support it very well as far as I know.

You can use concepts from my VMM book (donated, see below) to design automatic sequencer and driver tasks.
These can be done without VMM or UVM.
The setups can be done in an initial statement.

A Pragmatic Approach to VMM Adoption … a SV Framework for Testbenches 2007

Dealing with these approaches is wasting time and efforts. A FPGA design might be complex and you should use a complete UVM testbench. Do ease the generation of such a testbench you should use a UVM testbench generator which generates a UVM testbench automatically.