Last Updated: February 14, 2015
This post will explain how to use analysis FIFOs. Let’s assume I wanted a scoreboard that compares two streams of jelly beans; one stream is for “expected” jelly beans, the other is for “actual” jelly beans. Also assume the jelly beans are fed to the scoreboard asynchronously. To synchronize the jelly beans, I used two analysis FIFOs:
This is a sample code to implement the above scoreboard. The code should be self-explanatory. One note is that the get
is a blocking task to get the next item from the FIFO (lines 43 and 44). Somehow this task is not documented in the UVM Class Reference, though.
February 14, 2015: Changed to explicitly use the
get_peek_export
instead of using undocumentedget
task.
When both the expected jelly bean and the actual jelly bean become available, the scoreboard compares them (line 45). Before finishing a simulation (extract_phase
), the scoreboard checks whether there are leftover jelly beans in either FIFO. Isn’t it easy?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | class asynchronous_jelly_bean_scoreboard extends uvm_component; `uvm_component_utils( asynchronous_jelly_bean_scoreboard ) uvm_analysis_export #( jelly_bean_transaction ) expected_analysis_export; uvm_analysis_export #( jelly_bean_transaction ) actual_analysis_export; uvm_tlm_analysis_fifo#( jelly_bean_transaction ) expected_jelly_bean_fifo; uvm_tlm_analysis_fifo#( jelly_bean_transaction ) actual_jelly_bean_fifo; // Function: new //------------------------------------------------------------------------- function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new // Function: build_phase //------------------------------------------------------------------------- virtual function void build_phase( uvm_phase phase ); super.build_phase( phase ); expected_analysis_export = new( "expected_analysis_export", this ); actual_analysis_export = new( "actual_analysis_export", this ); expected_jelly_bean_fifo = new( "expected_jelly_bean_fifo", this ); actual_jelly_bean_fifo = new( "actual_jelly_bean_fifo", this ); endfunction: build_phase // Function: connect_phase //------------------------------------------------------------------------- virtual function void connect_phase( uvm_phase phase ); super.connect_phase( phase ); expected_analysis_export.connect( expected_jelly_bean_fifo.analysis_export ); actual_analysis_export.connect( actual_jelly_bean_fifo.analysis_export ); endfunction: connect_phase // Task: main_phase //------------------------------------------------------------------------- virtual task main_phase( uvm_phase phase ); jelly_bean_transaction expected_jelly_bean; jelly_bean_transaction actual_jelly_bean; super.main_phase( phase ); forever begin expected_jelly_bean_fifo.get_peek_export.get( expected_jelly_bean ); actual_jelly_bean_fifo.get_peek_export.get( actual_jelly_bean ); if ( expected_jelly_bean.compare( actual_jelly_bean ) == 0 ) begin `uvm_error( "main_phase", { "jelly bean mismatch: ", "expected:", expected_jelly_bean.convert2string(), "actual:", actual_jelly_bean.convert2string() } ) end end endtask: main_phase // Function: extract_phase - checks leftover jelly beans in the FIFOs //------------------------------------------------------------------------- virtual function void extract_phase( uvm_phase phase ); jelly_bean_transaction jelly_bean; super.extract_phase( phase ); if ( expected_jelly_bean_fifo.try_get( jelly_bean ) ) begin `uvm_error( "expected_jelly_bean_fifo", { "found a leftover jelly bean: ", jelly_bean.convert2string() } ) end if ( actual_jelly_bean_fifo.try_get( jelly_bean ) ) begin `uvm_error( "actual_jelly_bean_fifo", { "found a leftover jelly bean: ", jelly_bean.convert2string() } ) end endfunction: extract_phase endclass: asynchronous_jelly_bean_scoreboard |
You can view and compile the code on EDA Playground.
Hi Keisuke,
Thank you very much for your responses and solutions..!
Though I have developed so much confidance in this env, I have some trouble in writing the scoreboard. In the examples you have provided, the expected values are known. But,
1) If we have to compare the values that are obtained as a result of C-Code, then how do we do that. I know how to use DPI’s, but how do we synchronize the results,
2) I am also interested to know how a generic scoreboard is written using predictors and compares.
Can you please provide some different ways of implementing scoreboards along with their corresponding subscribers.
I am sure this helps a lot of engineers who wish to really understand the key benifits of UVM.
Thank You in Advance…!
Sorry for this late reply. I was busy preparing my presentation for DVCon next week.
Calling a C-function is nothing different from calling a SystemVerilog function from the caller’s point of view. You can call a C-function as if it is implemented in SystemVerilog. You can use any synchronization mechanisms for the C-function. For example, you can push the expected values generated by the C-function to a queue, then pop the values when actual values become available.
Regarding your second question, I will post a blog article about a scoreboard using the
uvm_tlm_generic_payload
after DVCon.Hi Keisuke san,
Thanks for your wonderful post. I want to compare the analysis port and with analysis_ffio. My understanding is analysis_port allows 1 port to many exports, and many ports to 1 export connection. Is this true for analysis_fifo?
1. If it is true, what is the ordering of the fifo. Let’s say we have 2 producer’s port connects to the analysis_fifo. How do we use it?
2. Can you give me a case where using analysis port is better than using analysis_fifo?
3. In this example, you check if there are left-over in the fifo. For the case of analysis port, do we also need to check if the write function is completed before end of simulation
Many thanks.
Hi Loren,
The
uvm_analysis_port
and theuvm_tlm_analysis_fifo
are different things. Please see the diagram below. Although theuvm_tlm_analysis_fifo
is not auvm_component
, it looks like auvm_subscriber
. Bothuvm_tlm_analysis_fifo
anduvm_subscriber
have oneuvm_analysis_imp
. Here are my answers to your questions. 1) You could connect twouvm_analysis_port
s to theuvm_analysis_imp
of the FIFO, but in this case, whoever calledwrite()
first puts a transaction to the FIFO. 2) Since thewrite()
is a function, you cannot consume time. Theuvm_tlm_analysis_fifo
is usually used when you want to process the written transactions later. 3) Left-over check depends on how a subscriber is implemented.Hi Keisuke san,
Thanks again for answering many of my questions.
1. I am a bit confused on the uvm_phase. For example, in your example, the scoreboard is in forever loop. Also many times, driver is in forever loop waiting for the get_next_item. How did we reach to extract phase?
2. How do we control when to terminate simulation. In your main phase, when we detect error, will the simulation be terminated? Can I let it run until I reach 10 errors?
Many thanks.
uvm_phase
monitors the number of objections. When nobody is raising an objection, all the processes started in therun_phase
are killed and move to the next phase. This is how theforever
loop is exited. For more detail, please see my new article inspired by your question!+UVM_MAX_QUIT_COUNT
option when you run a simulation. For example, if you set+UVM_MAX_QUIT_COUNT=10
, then the simulation continues until it hits 10 errors.Hi Keisuke San,
I really enjoyed this site. I learned a lot.
1. I have a subtle question on the connect between agent and monitor. Since the agent is pasting monitor’s analysis_port, can I skip the analysis_port::type_id::create step in build and assign agent’s analysis_port = mon.analysis_port. Would that work also?
2. In this example, does the main_phase requires to raise_objection at the beginning? Since the testbench is asynchronous, the line 44 get might take longer to complete. Will the simulation go to extract_phase before we get the actual result?
3. In the TLM_analysis_fifo example, I saw the use of put_port, get_port, and analysis_port( mainly for put the item in fifo). In the case of analysis_port, I assume the write function is provided the by class. Is that right?
4. In the tlm_analysis_fifo example, what is the use of the put_ap, and get_ap port in fifo?
Many thanks.
Loren
uvm_analysis_port
, whereas in your case, there is only oneuvm_analysis_port
object. The analysis port of the agent merely points to the analysis port of the monitor.raise/drop_objection
in themain_phase
.uvm_analysis_port
has thewrite
function.put_export
are sent out to theput_ap
. Similarly, transactions passed through theget_peek_export
are sent out to theget_ap
. You can monitor the transactions passing through the FIFO via these analysis ports.Hello Keisuke Shimizu,
I your reply to : In the tlm_analysis_fifo example, what is the use of the put_ap, and get_ap port in fifo?
I didn’t understood the meaning of monitoring transactions passing through fifo? Can you please explain with in brief or provide some example. Basically I want to know how to use them.
Thanks in advance.
Shreemant
You could connect a subscriber to one of these analysis ports to collect functional coverage, for example.
Hi there,
Does the item get popped out automatically when using “get_peek_export.get(item)”, or need to manually delete it from the fifo? If so, how?
Thanks,
Bayshore
The
get
method removes the item from the FIFO.Hi Keisuke ,
I want to know that there is no write implementation in the scoreboard. then how we will get the data from the monitors?
Thanks in Advance
Regards,
Jayaprakash
The
uvm_tlm_analysis_fifo
provides thewrite
function.Hi Keisuke San,
Thanks for this easily understandable example. I’m following this to implement a generic scoreboard for use across testbenches in our project.
I would like to extend this example to implement a simple out-of-order scoreboard. Basically, an element from the expected_fifo has to be compared against a maximum of ‘N’ elements of the actual_fifo, by which time a match is expected to be found. I’m not sure how to do this using the limited methods that come with the uvm_tlm_analysis_fifo class.
What approach would you recommend?
Many thanks,
Sharanya
I would probably use a SystemVerilog queue instead of
uvm_analysis_fifo
. Here’s a skeleton.Hi Keisuke ,
can you please provide me a scoreboard template for if we are getting expected data as from C-function , how to call C in sv?
and how to connect and how to compare the actual as from SV and expected as from C .
Please provide me the source
Regards,
Jayprakash
Sorry for the very slow reply. You might have already seen this, but Using a C-Model has information about how to use a C function. Let me know if you have further questions.
Hi Keisuke,
I am not clearly able to understand below points
1. How the FIFO is getting the transaction.
2. Where the expected_analysis_export and actual_analysis_export is connected with analysis_port in testbench. Do they get transaction first and then it is put to FIFO
3. What does get_peek_export.get task do
Please answer these.
write
function.get
task gets a transaction from the FIFO. If no transaction is available, then the task is blocked.Hi,
Can you tell me how can we increase the depth of the uvm_tlm_analysis_fifo.
Thanks in advance !
The
uvm_tlm_analysis_fifo
has an unbounded size.Hi Keisuke…
I have a doubt that… suppose we are having two monitor , one is for actual item and one is for expected. In the both monitor we call the write function like mon_port.write(data_item) … means there will be two write function one is for actual and one is for expected monitor transaction.
In line 43 and 44, you are taking the transaction.
My question is how can we know that , which monitor’s write function is connected to which fifo.
In other way we can say that, which jelly bean, expected or actual (from line 43 & 44) is connected to which monitor write function(expected monitor write function or actual monitor write function).
You need to specify the connection. Suppose you instantiate the
asynchronous_jelly_bean_scoreboard
,expected_monitor
, andactual_monitor
inyour_env
. In theconnect_phase
function, specify the connection like this: