Sometimes I do things just to see them work. This is one of those times.
This testbench uses the layered sequence approach to connect a CPU complex (CPU) to a Sensor Control Unit (SCU). Between those two are an interconnect (XBR) and a Peripherial Control Unit (PCU). The CPU complex speaks AXI to the XBR, the XBR speaks APB to the PCU, the PCU speaks RS-232(ish) to the SCU. Translator sequences replace only the necessary functions in the CPU, XBR, and PCU.
The most recent code is on EDAplayground here:
// ----------------------------------------------- class CPU_XBR_xlator_agent extends uvm_component#(SCU_txn); `uvm_component_utils(CPU_XBR_xlator_agent) uvm_sequencer#(CPU_txn) cpu_sequencer ; XBR_PCU_xlator_agent xbr_agent ; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); cpu_sequencer = uvm_sequencer#(CPU_txn)::type_id::create("cpu_sequencer", this); endfunction // connect the agents function void connect_to_XBR_PCU_xlator_agent( XBR_PCU_xlator_agent c ); xbr_agent = c; endfunction virtual task run_phase (uvm_phase phase) ; // declare the translator sequences CPU_XBR_xlator_irq_seq xlator_irq_seq ; CPU_XBR_xlator_data_seq xlator_data_seq ; // create the translator sequences xlator_irq_seq = CPU_XBR_xlator_irq_seq::type_id::create("xlator_irq_seq") ; xlator_data_seq = CPU_XBR_xlator_data_seq::type_id::create("xlator_data_seq") ; // connect translation sequences to the upstream sequencers xlator_irq_seq.cpu_sequencer = cpu_sequencer ; xlator_data_seq.cpu_sequencer = cpu_sequencer ; // forking start the translation sequences on the downstream sequencer fork xlator_irq_seq.start(xbr_agent.xbr_sequencer) ; xlator_data_seq.start(xbr_agent.xbr_sequencer) ; join_none endtask endclass : CPU_XBR_xlator_agent
get_next_item
from the upstream sequencer,start_item
of that on the downstream sequencer,finish_item
and when that returns, item_done
on the upstream item. virtual task body(); The blue color represents the upstream activity, the PCU. The green color represents the downstream activity, the SCU. PCU_txn p_txn; SCU_txn s_txn; forever begin pcu_token.get(1) ; pcu_sequencer.get_next_item(p_txn); s_txn = SCU_txn::type_id::create(.name("s_txn"), .contxt(get_full_name())); start_item(s_txn); s_txn.go = ~p_txn.PWRITE ; finish_item(s_txn); p_txn.PRDATA = {7'b0,s_txn.txdata} ; parity = ((s_txn.txdata[0] ^ s_txn.txdata[1]) ^ (s_txn.txdata[2] ^ s_txn.txdata[3]) ^ (s_txn.txdata[4] ^ s_txn.txdata[5]) ^ (s_txn.txdata[6] ^ s_txn.txdata[7])) ; p_txn.PSLVERR = ( parity != s_txn.parity) ? 1 : 0 ; `uvm_info("PCU_SCU_xlator_data_seq", $sformatf("PRDATA = %h", p_txn.PRDATA), UVM_MEDIUM) `uvm_info("PCU_SCU_xlator_data_seq", $sformatf("PSLVERR = %h", p_txn.PSLVERR), UVM_MEDIUM) pcu_sequencer.item_done ; pcu_token.put(1) ; end endtask: body |
pcu_token.put/get(1)
are for access control of via a simple 1 item semaphore.
virtual task body(); The blue color represents the upstream activity, the XBR. The green color represents the downstream activity, the PCU. XBR_txn x_txn; PCU_txn p_txn; forever begin xbr_token.get(1) ; xbr_sequencer.get_next_item(x_txn); p_txn = PCU_txn::type_id::create(.name("p_txn"), .contxt(get_full_name())); start_item(p_txn); p_txn.PWRITE = 1'b1 ; p_txn.PADDR = x_txn.ARADDR ; finish_item(p_txn) x_txn.RRESP = (p_txn.PSLVERR) ? 2'b10 : 2'b00 ; x_txn.RDATA = {16'b0,p_txn.PRDATA} ; `uvm_info("XBR_PCU_xlator_data_seq", $sformatf("RDATA = %h", x_txn.RDATA), UVM_MEDIUM) `uvm_info("XBR_PCU_xlator_data_seq", $sformatf("RRESP = %h", x_txn.RRESP), UVM_MEDIUM) xbr_sequencer.item_done ; xbr_token.put(1); end endtask: body |
virtual task body(); The blue color represents the upstream activity, the CPU. The green color represents the downstream activity, the XBR. CPU_txn c_txn; XBR_txn x_txn; forever begin cpu_token.get(1) ; cpu_sequencer.get_next_item(c_txn); x_txn = XBR_txn::type_id::create(.name("x_txn"), .contxt(get_full_name())); start_item(x_txn); x_txn.ARADDR = c_txn.rAddr ; finish_item(x_txn); c_txn.rData = {16'b0,x_txn.RDATA} ; c_txn.errorStatus = x_txn.RRESP ; `uvm_info("CPU_XBR_xlator_data_seq F", $sformatf("txdata = %h", c_txn.rData), UVM_MEDIUM) `uvm_info("CPU_XBR_xlator_data_seq F", $sformatf("errorStatus = %h", c_txn.errorStatus), UVM_MEDIUM) cpu_sequencer.item_done ; cpu_token.put(1) ; end endtask: body |