We often use a C-model as a reference model. Thanks to the direct programming interface (DPI) of SystemVerilog, using C-model has never been easier. We will show you how to use a C-model in our jelly bean scoreboard.
Original Scoreboard
This is our original scoreboard used in Jelly Bean Taster in UVM 1.2. The scoreboard checks if the combination of flavor
, sour
, and taste
are as expected or not (lines 9 and 10).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class jelly_bean_sb_subscriber extends uvm_subscriber#( jelly_bean_transaction ); `uvm_component_utils( jelly_bean_sb_subscriber ) function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void write( jelly_bean_transaction t ); if ( t.flavor == CHOCOLATE && t.sour && t.taste == YUMMY || ! ( t.flavor == CHOCOLATE && t.sour ) && t.taste == YUCKY ) begin `uvm_error( get_name(), { "You lost sense of taste!", t.convert2string() } ) end else begin `uvm_info( get_name(), { "You have a good sense of taste.", t.convert2string() }, UVM_LOW ) end endfunction: write endclass: jelly_bean_sb_subscriber |
Let’s delegate this checking to a C-model.
C-model
We defined a function called check_taste_in_c
which takes the flavor
, sour
, and taste
as arguments and returns 0 if the combination is as expected. Otherwise it returns 1. For clarity, we defined the same enums as defined in SystemVerilog (lines 5 and 6). Since C does not know about the bit
type of SystemVerilog, we replaced it with the svBit
type, which is type-defined in the svdpi.h
(line 8). The svdpi.h
also provides other types and a number of helper macros and constants. For more information, please see Annex I of IEEE Std 1800-2012. Note that we added extern "C"
because we defined this model in a C++ file. If you define this model in a C file, you don’t need the extern "C"
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include "svdpi.h" // same enums as defined in jelly_bean_pkg.sv enum flavor_e { NO_FLAVOR, APPLE, BLUEBERRY, BUBBLE_GUM, CHOCOLATE }; enum taste_e { UNKNOWN, YUMMY, YUCKY }; extern "C" int check_taste_in_c( flavor_e flavor, svBit sour, taste_e taste ) { if ( flavor == CHOCOLATE && sour == 1 && taste == YUMMY || ! ( flavor == CHOCOLATE && sour == 1 ) && taste == YUCKY ) return 1; // error else return 0; // OK } |
Scoreboard Using the C-model
Here is the new scoreboard that uses the C-model. In order to call a function implemented in C, we import the function (line 8). Once we import the function, we can call it as if it is a SystemVerilog function (line 11).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class jelly_bean_sb_subscriber extends uvm_subscriber#( jelly_bean_transaction ); `uvm_component_utils( jelly_bean_sb_subscriber ) function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new import "DPI-C" function bit check_taste_in_c( flavor_e flavor, bit sour, taste_e taste ); function void write( jelly_bean_transaction t ); if ( check_taste_in_c( t.flavor, t.sour, t.taste ) ) begin `uvm_error( get_name(), { "You lost sense of taste!", t.convert2string() } ) end else begin `uvm_info( get_name(), { "You have a good sense of taste.", t.convert2string() }, UVM_LOW ) end endfunction: write endclass: jelly_bean_sb_subscriber |
You can view and run the code on EDA Playground.
Do you have any recommendations on where to find a real life example of C-modeling for a processor subsystem?
C-modeling is not really in my line, so I don’t have any recommendations, I’m afraid.
Hi Keisuke Shimiz, I am wondering that most of functions can be implemented in the system verilog, in what situation, we will use “C-Model” ?
Thanks you
One obvious case is when you already have a C-model for software development, for example. Another case is when a model requires computationally intensive calculation such as image processing.
Where you want to stub out a processor by VIPs but still want to use C Driver code