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
|