Specman UVM: How update a value of a register when the value was written to another register? - specman

(in my verification environment we use vr_ad package.). I try to implement the next:
When data is written to one of the registers (timer_load), another register (timer_bgload) should be updated with the same data.
I've found the next example in UVM User Guide:
// Attaching the target register file to the broadcasted register
extend ex_c_bus_env {
post_generate() is also {
xcore_regs.vr_ad_rx_data.attach(xbus_regs);
};
};
// Implement the broadcast:
// When writing to register VR_AD_RX_DATA in XCORE vr_ad_reg_file,
// propagate the value to the VR_AD_XBUS_DATA register in ACTIVE_XBUS.
extend ACTIVE_XBUS vr_ad_reg_file {
indirect_access( direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if ad_item is a VR_AD_RX_DATA vr_ad_reg (d) {
vr_ad_xbus_data.write_reg_val(d.get_cur_value());
};
};
};
My registers:
reg_def TIMER_LOAD_0 TIMER 20'h00010 {
reg_fld timer_load : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD_0 TIMER 20'h00014 {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD_1 TIMER 20'h00028 {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
//another reg with the same instance name
};
My code for updating the timer_bgload register after a data was written to tiemr_load:
extend TIMER vr_ad_reg_file {
indirect_access( direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if ad_item is a TIMER_LOAD_0 vr_ad_reg (d) {
timer_bgload.write_reg_val(d.get_cur_value());
};
};
};
unit timer_env_u like any_env {
post_generate() is also {
timer_regs.timer_load_0.attach(timer_regs.timer_bgload_0.timer_bgload);
};
};
I get a compilation error:
*** Error: No such variable 'timer_bgload'
at line 17 in #timer_reg_db
timer_bgload.write_reg_val(d.get_cur_value());
I really appreciate any help.

You can attach the timer_load register to the timer_bgload register directly and implement indirect_access(...) there:
// attach the regs
extend TIMER vr_ad_reg_file {
post_generate() is also {
timer_load_0.attach(timer_bgload_0);
};
};
// implement indirect_access()
extend TIMER_BGLOAD_0 vr_ad_reg {
indirect_access(direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if direction == WRITE and ad_item is a TIMER_LOAD_0 vr_ad_reg (d) {
write_reg_val(d.get_cur_value());
};
};
};
I don't know why the Cadence example took the long route of attaching the register file to the indirect register.
Also, if you have more than one TIMER_LOAD/BGLOAD registers (seems like you may have 2), then the best thing to do is define the types first:
// define register types without instantiation in reg_file
reg_def TIMER_LOAD {
reg_fld timer_load : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
};
After you define the types, you instantiate them in the register file manually as many times as you need to. Have a look in the manual, there is an example showing you exactly how to do it.
This means that it's enough to implement the indirect_access(...) method in the TIMER_BGLOAD subtype (only once) as opposed to two times (for TIMER_BGLOAD_0 and TIMER_BGLOAD_1).

I'd implement it with post_access, something like that:
extend TIMER_LOAD_0 TIMER vr_ad_reg {
post_access(operation : vr_ad_rw_t) is {
if operation == WRITE {
var rgf := get_access_path()[0].as_a(TIMER vr_ad_reg_file);
rgf.timer_bgload_0.timer_bgload = timer_load;
};
};
};
Pay attention, that it might not work on first hit. If it's not, I'd build it gradually, starting with 'empty' code like this:
extend TIMER_LOAD_0 TIMER vr_ad_reg {
post_access(operation : vr_ad_rw_t) is {
print me, operation;
};
};
And putting a breakpoint in the print statement, opening a data browser, looking what are the exact names of the fields we got there, try to access them from Specman CLI - and when it works - code it back.

Related

Specman-e: Generate all possible solutions?

When re-generating a particular structure is there an easy way to make it not generate a previous value until all possible values satisfying the constraints have been generated?
For example, when (re)generating:
Start as:
specman -c 'define TRIES 16; load x;run;'
<'
struct x {
data[2] : list of uint(bits:2);
};
extend sys {
fu : x;
run() is also {
for i from 1 to TRIES do {
gen fu;
print fu.data;
};
};
};
'>
There are a possible 4*4 = 16 combinations of data and the question is about being able to gen 16 times and get 16 different values.
Thanks.
all_different() can help here. It's a bit tricky, because the field is a list. So this can be done using an auxiliary field. For example:
struct x {
data[2] : list of uint(bits:2);
data_as_one : uint(bits:4);
keep data[0] == data_as_one[1:0];
keep data[1] == data_as_one[3:2];
};
extend sys {
fu : x;
fus[TRIES] : list of x;
keep fus.all_different(.data_as_one);
run() is also {
for each in fus {
out(it.data);
};
};
};

Is there "parallel all of" in Specman?

Let’s assume I have this unit
unit agent {
init_all_regs() #clock is {…};
};
I have a list of agents, the number of agents vary. I want to call the method init_all_regs() all of the agents, so that all of them run in parallel.
Is there some combination of “all of” and “for each” syntax?
There is no "all of for each" syntax, but there is easy to implement with existing syntax. For example, you can use objections. Define an objection_kind, and use it to synchronize.
for example:
extend objection_kind :[AGNETS_CHECK_REGS];
unit agent {
init_all_regs()#clk is {
raise_objection(AGNETS_CHECK_REGS);
//...
drop_objection(AGNETS_CHECK_REGS);
};
};
extend env {
my_method() #clock is {
for each in agents {
start it.init_all_regs();
};
wait cycle;
while get_objection_total(AGNETS_CHECK_REGS) > 0 {
wait cycle;
};
};
};
Another option is to use a counter, implemented with static member. One disadvantage is that it needs more lines.
Something like this -
unit agent {
static active_counter : int = 0;
static increase_active_counter() is {
active_counter += 1;
};
////....
init_all_regs()#clk is {
increase_active_counter();
//....
decrease_active_counter();
};
};
extend env {
scenario() #any is {
agent::init_active_counter();
for each in agents {
start it.init_all_regs();
};
wait cycle;
while agent::get_active_counter() > 0 {
wait cycle;
};
};
};

Specman macros: How to use optional tags?

I have a macro for defining ports:
-- Create simple port
define <p_def'struct_member> "p_def <name'name> <type'type>" as {
<name'name> : inout simple_port of <type'type> is instance;
keep bind(<name'name>,empty);
};
I would like to extend the macro to support a list of ports. I would like to use for it an optional tag [<len'name>] that defines the list size, something like this:
-- Create simple port OR list of simple ports
define <p_def'struct_member> "p_def <name'name> [\[<len'name>\] ] <type'type>" as {
if len does not exist { // How to implement it?
<name'name> : inout simple_port of <type'type> is instance;
keep bind(<name'name>,empty);
} else { // len exists
<name'name>[<len'name>] : list of inout simple_port of <type'type> is instance;
keep for each in <name'name> {
bind(it,empty);
};
};
};
** For example, defining a list of ports of size 10 will look this way:
p_def my_list_of_ports[10] bit;
I cannot find in Specman e Language Reference how can I know if the optional tag ([<len'name>]) is defined or not.. Do you know how to implement the "if len does not exist" statement in macro?
Thank you for your help
In case someone is interested what is the answer:
define <p_def'struct_member> "p_def <name'name>[\[<len'name>\]] <type'type>" as computed {
if <len'name> == NULL {
result = appendf("%s : inout simple_port of %s is instance; \n keep bind(%s,empty);", <name'name>, <type'type>, <name'name>);
} else { // list
result = appendf("%s[%s] : list of inout simple_port of %s is instance; keep for each in %s { bind(it,empty); };", <name'name>, <len'name>, <type'type>, <name'name>);
};
};

Invoking write/read_reg vr_ad macro from a virtual sequence in Specman

Is there a way that a virtual sequence can directly call a vr_ad write_reg or read_reg macro without me having to create a vr_ad_sequence that does the same thing?
To illustrate more clearly, here is my current implementation:
<'
extend vr_ad_sequence_kind : [WR_DMA_POLL];
extend WR_DMA_POLL vr_ad_sequence {
!dma_poll : DMA_POLL vr_ad_reg;
body() #driver.clock is only {
write_reg dma_poll val 0xdeadbeef;
};
};
extend MAIN soc_tb_virtual_sequence {
!write_dma_poll : WR_DMA_POLL vr_ad_sequence;
body() #driver.clock is only {
message(LOW, "TEST START");
do write_dma_poll on driver.reg_driver;
};
};
'>
Why can't it be, or is it possible to implement this way?
extend MAIN soc_tb_virtual_sequence {
!dma_poll : DMA_POLL vr_ad_reg;
body() #driver.clock is only {
message(LOW, "TEST START");
write_reg {.dest_driver == driver.reg_driver} dma_poll;
read_reg {.dest_driver == driver.reg_driver} dma_poll;
};
};
Thank you in advance for any explanation.
This is possible starting with vr_ad 13.20 (or maybe slightly older). You almost had it in your question. The correct syntax is:
extend MAIN soc_tb_virtual_sequence {
!dma_poll : DMA_POLL vr_ad_reg;
body() #driver.clock is only {
message(LOW, "TEST START");
write_reg {.driver == driver.reg_driver} dma_poll;
read_reg {.driver == driver.reg_driver} dma_poll;
};
};
The first set of {...} delimits the operation generate block, where you can constrain how to access the register. These constraints will be passed to the vr_ad_operation that gets generated as part of the access.

specman: Assign multiple struct member in one expression

Hy,
I expanding an existing specman test where some code like this appears:
struct dataset {
!register : int (bits:16);
... other members
}
...
data : list of dataset;
foo : dataset;
gen foo;
foo.register = 0xfe;
... assign other foo members ...
data.push(foo.copy());
is there a way to assign to the members of the struct in one line? like:
foo = { 0xff, ... };
I currently can't think of a direct way of setting all members as you want, but there is a way to initialize variables (I'm not sure if it works on struct members as well). Anyway something like the following may fit for you:
myfunc() is {
var foo : dataset = new dataset with {
.register = 0xff;
.bar = 0xfa;
}
data.push(foo.copy());
}
You can find more information about new with help new struct from the specman prompt.
Hope it helps!
the simple beuty of assigning fields by name is one language feature i've always found usefull , safe to code and readable.
this is how i'd go about it:
struct s {
a : int;
b : string;
c : bit;
};
extend sys {
ex() is {
var s := new s with {.a = 0x0; .b = "zero"; .c = 0;};
};
run() is also {
var s;
gen s keeping {.a == 0x0; .b == "zero"; .c == 0;};
};
};
i even do data.push(new dataset with {.reg = 0xff; bar = 0x0;}); but you may raise the readablity flag if you want.
warning: using unpack() is perfectly correct (see ross's answer), however error prone IMO. i recommend to verify (with code that actually runs) every place you opt to use unpack().
You can directly use the pack and unpack facility of Specman with "physical fields" ( those instance members prefixed with the modifier %).
Example:
define FLOODLES_WIDTH 47;
type floodles_t : uint(bits:FLOODLES_WIDTH);
define FLABNICKERS_WIDTH 28;
type flabnickers_t : uint(bits:FLABNICKERS_WIDTH);
struct foo_s {
%!floodle : floodles_t;
%!flabnicker : flabnickers_t;
};
extend sys {
run() is also {
var f : foo_s = new;
unpack(packing.low,64'hdeadbeefdeadbeef,f);
print f;
unpack(packing.low,64'hacedacedacedaced,f);
print f;
};
setup() is also {
set_config(print,radix,hex);
};
};
When this run, it prints:
Loading /nfs/pdx/home/rbroger1/tmp.e ...
read...parse...update...patch...h code...code...clean...
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
f = foo_s-#0: foo_s of unit: sys
---------------------------------------------- #tmp
0 !%floodle: 0x3eefdeadbeef
1 !%flabnicker: 0x001bd5b
f = foo_s-#0: foo_s of unit: sys
---------------------------------------------- #tmp
0 !%floodle: 0x2cedacedaced
1 !%flabnicker: 0x00159db
Look up packing, unpacking, physical fields, packing.low, packing.high in your Specman docs.
You can still use physical fields even if the struct doesn't map to the DUT. If your struct is already using physical fields for some other purpose then you'll need to pursue some sort of set* method for that struct.