In the previous post, we looked at an overview of the TLM 1 classes. This post will give you a sample code using some of the TLM 1 classes.
Components
We created the following components to demonstrate different kinds of TLM 1 interface. The jelly_bean_sequencer
(the leftmost component) creates an object of the jelly_bean_transaction
, called jb_req
. The jb_req
is transferred all the way to the right (jelly_bean_transporter
) via several TLM 1 interfaces. The jelly_bean_transporter
evaluates the flavor of the jb_req
and returns another jelly_bean_transaction
called jb_rsp
(jelly-bean response) with the updated taste
property. The jb_rsp
is transferred back to the jelly_bean_subscriber
at the end. Though this example is artificial, it will show you a variety of TLM 1 interfaces.
Sample TLM 1 Connections
jelly_bean_sequencer
The jelly_bean_sequencer
is a uvm_sequencer
specialized with the jelly_bean_transaction
.
typedef uvm_sequencer#(jelly_bean_transaction) jelly_bean_sequencer;
jelly_bean_put_driver
The jelly_bean_put_driver
is a uvm_driver
, which means it has a seq_item_port
. The line 4 declares another port (put_port
). The run_phase
gets a jb_req
from the seq_item_port
(line 19) then puts it to the put_port
(line 21).
class jelly_bean_put_driver extends uvm_driver#( jelly_bean_transaction );
`uvm_component_utils( jelly_bean_put_driver )
uvm_put_port#( jelly_bean_transaction ) put_port;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
put_port = new( .name( "put_port" ), .parent( this ) );
endfunction: build_phase
task run_phase( uvm_phase phase );
jelly_bean_transaction jb_req;
forever begin
seq_item_port.get_next_item( jb_req );
`uvm_info( get_type_name(), "[seq_item_port]-->{jb_req}-->[put_port]", UVM_NONE )
put_port.put( jb_req );
seq_item_port.item_done();
end
endtask: run_phase
endclass: jelly_bean_put_driver
jelly_bean_master
The jelly_bean_master
has one uvm_get_port
(get_port
, line 4), one uvm_master_port
(master_port
, lines 5 and 6), and one uvm_analysis_port
(rsp_ap
, line 7). The run_phase
gets a jb_req
from the get_port
(line 25), then puts it to the master_port
(line 27). The jelly_bean_master
waits for a jelly-bean response (jb_rsp
, line 29), then writes it to the rsp_ap
(line 31).
class jelly_bean_master extends uvm_component;
`uvm_component_utils( jelly_bean_master )
uvm_get_port#( jelly_bean_transaction ) get_port;
uvm_master_port#( .REQ( jelly_bean_transaction ),
.RSP( jelly_bean_transaction ) ) master_port;
uvm_analysis_port#( jelly_bean_transaction ) rsp_ap;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
get_port = new( .name( "get_port" ), .parent( this ) );
master_port = new( .name( "master_port" ), .parent( this ) );
rsp_ap = new( .name( "rsp_ap" ), .parent( this ) );
endfunction: build_phase
task run_phase( uvm_phase phase );
jelly_bean_transaction jb_req;
jelly_bean_transaction jb_rsp;
forever begin
get_port.get( jb_req );
`uvm_info( get_type_name(), "[get_port]-->{jb_req}-->[master_port]", UVM_NONE )
master_port.put( jb_req );
`uvm_info( get_type_name(), "{jb_rsp}< --[master_port]", UVM_NONE )
master_port.get( jb_rsp );
`uvm_info( get_type_name(), "{jb_rsp}-->[rsp_ap]", UVM_NONE )
rsp_ap.write( jb_rsp );
end
endtask: run_phase
endclass: jelly_bean_master
jelly_bean_slave
The jelly_bean_slave
has one uvm_master_imp
(master_export
, lines 4 to 6), and one uvm_transport_port
(trans_port
, lines 7 and 8). The jelly_bean_slave
also has two queues; the req_q
stores the jb_req
s and the rsp_q
stores the jb_rsp
s. The jelly_bean_slave
implements the access methods of a uvm_master_imp
; namely put
, try_put
, can_put
, get
, try_get
, can_get
, peek
, try_peek
, and can_peek
(lines 34 to 81). The run_phase
gets a jb_req
from the req_q
if available, then calls transport
of the trans_port
(line 28).
class jelly_bean_slave extends uvm_component;
`uvm_component_utils( jelly_bean_slave )
uvm_master_imp#( .REQ( jelly_bean_transaction ),
.RSP( jelly_bean_transaction ),
.IMP( jelly_bean_slave ) ) master_export;
uvm_transport_port#( .REQ( jelly_bean_transaction ),
.RSP( jelly_bean_transaction ) ) trans_port;
jelly_bean_transaction req_q[$];
jelly_bean_transaction rsp_q[$];
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
master_export = new( "master_export", this );
trans_port = new( .name( "trans_port" ), .parent( this ) );
endfunction: build_phase
task run_phase( uvm_phase phase );
jelly_bean_transaction jb_rsp;
forever begin
wait ( req_q.size() > 0 );
`uvm_info( get_type_name(), "(master_export)---{jb_req}-->[trans_port]", UVM_NONE )
trans_port.transport( req_q.pop_front(), jb_rsp );
`uvm_info( get_type_name(), "{jb_rsp}< --[trans_port]", UVM_NONE )
rsp_q.push_back( jb_rsp );
end
endtask: run_phase
virtual task put( input jelly_bean_transaction t );
req_q.push_back( t );
endtask: put
virtual function bit try_put( input jelly_bean_transaction t );
req_q.push_back( t );
return 1;
endfunction: try_put
virtual function bit can_put();
return 1;
endfunction: can_put
virtual task get( output jelly_bean_transaction t );
wait ( rsp_q.size() > 0 );
t = rsp_q.pop_front();
endtask: get
virtual function bit try_get( output jelly_bean_transaction t );
if ( rsp_q.size() > 0 ) begin
t = rsp_q.pop_front();
return 1;
end else begin
return 0;
end
endfunction: try_get
virtual function bit can_get();
return rsp_q.size() > 0;
endfunction: can_get
virtual task peek( output jelly_bean_transaction t );
wait ( rsp_q.size() > 0 );
t = rsp_q[0];
endtask: peek
virtual function bit try_peek( output jelly_bean_transaction t );
if ( rsp_q.size() > 0 ) begin
t = rsp_q[0];
return 1;
end else begin
return 0;
end
endfunction: try_peek
virtual function bit can_peek();
return rsp_q.size() > 0;
endfunction: can_peek
endclass: jelly_bean_slave
jelly_bean_transporter
The jelly_bean_transporter
has one uvm_transport_imp
(trans_export
, lines 4 to 6) and implements its access methods; namely transport
and nb_transport
(lines 17 to 32). These methods create a jelly-bean response (jb_rsp
, line 24), evaluate the flavor of a jelly-bean request and update the taste
property of the jb_rsp
accordingly (lines 26 to 29).
class jelly_bean_transporter extends uvm_component;
`uvm_component_utils( jelly_bean_transporter )
uvm_transport_imp#( .REQ( jelly_bean_transaction ),
.RSP( jelly_bean_transaction ),
.IMP( jelly_bean_transporter ) ) trans_export;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
trans_export = new( "trans_export", this );
endfunction: build_phase
virtual task transport( input jelly_bean_transaction jb_req,
output jelly_bean_transaction jb_rsp );
assert( nb_transport( jb_req, jb_rsp ) );
endtask: transport
virtual function bit nb_transport( input jelly_bean_transaction jb_req,
output jelly_bean_transaction jb_rsp );
jb_rsp = jelly_bean_transaction::type_id::create( "jb_rsp" );
jb_rsp.copy( jb_req );
if ( jb_req.flavor == jelly_bean_transaction::CHOCOLATE && jb_req.sour )
jb_rsp.taste = jelly_bean_transaction::YUCKY;
else
jb_rsp.taste = jelly_bean_transaction::YUMMY;
`uvm_info( get_type_name(), { "Returning:\n", jb_rsp.sprint() }, UVM_NONE )
return 1;
endfunction: nb_transport
endclass: jelly_bean_transporter
jelly_bean_subscriber
The jelly_bean_subscriber
is a uvm_subscriber
, which means it has an analysis_export
. The jelly_bean_subscriber
implements the write
method of the analysis_export
(lines 8 to 10).
class jelly_bean_subscriber extends uvm_subscriber#( jelly_bean_transaction );
`uvm_component_utils( jelly_bean_subscriber )
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void write( jelly_bean_transaction t );
`uvm_info( get_type_name(), { "Received:\n", t.sprint() }, UVM_NONE )
endfunction: write
endclass: jelly_bean_subscriber
jelly_bean_agent
The jelly_bean_agent
instantiates all the components and connect them together.
class jelly_bean_agent extends uvm_agent;
`uvm_component_utils( jelly_bean_agent )
jelly_bean_sequencer jb_seqr;
jelly_bean_put_driver jb_put_drvr;
uvm_tlm_fifo#( jelly_bean_transaction ) jb_fifo;
jelly_bean_master jb_master;
jelly_bean_slave jb_slave;
jelly_bean_transporter jb_trans;
jelly_bean_subscriber jb_sub;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
jb_seqr = jelly_bean_sequencer ::type_id::create( .name( "jb_seqr" ), .parent( this ) );
jb_put_drvr = jelly_bean_put_driver ::type_id::create( .name( "jb_put_drvr" ), .parent( this ) );
jb_fifo = new( .name( "jb_fifo" ), .parent( this ) );
jb_master = jelly_bean_master ::type_id::create( .name( "jb_master" ), .parent( this ) );
jb_slave = jelly_bean_slave ::type_id::create( .name( "jb_slave" ), .parent( this ) );
jb_trans = jelly_bean_transporter::type_id::create( .name( "jb_trans" ), .parent( this ) );
jb_sub = jelly_bean_subscriber ::type_id::create( .name( "jb_sub" ), .parent( this ) );
endfunction: build_phase
function void connect_phase( uvm_phase phase );
super.connect_phase( phase );
jb_put_drvr.seq_item_port.connect( jb_seqr.seq_item_export );
jb_put_drvr. put_port.connect( jb_fifo.put_export );
jb_master. get_port.connect( jb_fifo.get_peek_export );
jb_master. master_port.connect( jb_slave.master_export );
jb_slave. trans_port.connect( jb_trans.trans_export );
jb_master. rsp_ap.connect( jb_sub.analysis_export );
endfunction: connect_phase
endclass: jelly_bean_agent
Simulation
Here is an excerpt of a simulation output.
# UVM_INFO ../src/tutorial_20.sv(118) @ 0: uvm_test_top.jb_env.jb_agent.jb_seqr@@jb_seq [one_jelly_bean_sequence] Generated:
# UVM_INFO ../src/tutorial_20.sv(152) @ 0: uvm_test_top.jb_env.jb_agent.jb_put_drvr [jelly_bean_put_driver] [seq_item_port]-->{jb_req}-->[put_port]
# UVM_INFO ../src/tutorial_20.sv(188) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] [get_port]-->{jb_req}-->[master_port]
# UVM_INFO ../src/tutorial_20.sv(223) @ 0: uvm_test_top.jb_env.jb_agent.jb_slave [jelly_bean_slave] (master_export)---{jb_req}-->[trans_port]
# UVM_INFO ../src/tutorial_20.sv(282) @ 0: uvm_test_top.jb_env.jb_agent.jb_trans [jelly_bean_transporter] Returning:
# UVM_INFO ../src/tutorial_20.sv(225) @ 0: uvm_test_top.jb_env.jb_agent.jb_slave [jelly_bean_slave] {jb_rsp}< --[trans_port]
# UVM_INFO ../src/tutorial_20.sv(190) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] {jb_rsp}<--[master_port]
# UVM_INFO ../src/tutorial_20.sv(192) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] {jb_rsp}-->[rsp_ap]
# UVM_INFO ../src/tutorial_20.sv(298) @ 0: uvm_test_top.jb_env.jb_agent.jb_sub [jelly_bean_subscriber] Received: