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;
};
};
};
Related
I made 2 loggers, one for each thread like this(THREAD=2):
lsd_logger[THREADS] : list of message_logger is instance;
keep for each in lsd_logger {
soft it.tags == {appendf("DBG%d",index).as_a(message_tag)};
it.to_file == appendf("lsd%d.elog", index);
soft it.verbosity == HIGH;
it.to_screen == FALSE;
};
Now I have a checker that I want to sent a message to each logger according to the thread currently running, like this:
messagef(appendf("DBG%d",thread).as_a(message_tag), MEDIUM, "this is a message to logger %d",thread);
But I keep getting this error about how this is not a constant verbosity.
Is there a way to give the message_tag like this instead of creating a func to handle the printing?
Thank you,
No, this is impossible. The tag of the message must be hard-coded, thus it should be a constant tag, and not any expression that returns a tag.
You could possibly solve the issue by defining a method like this:
my_message() is {
case thread {
0: {
messagef(DBG0, MEDIUM, "this is a message to logger 0");
};
1: {
messagef(DBG1, MEDIUM, "this is a message to logger 1");
};
};
};
Then if you want to avoid writing this very long method with repeating code (which you even need to modify every time the number of threads changes), you can use a define as computed macro instead, such as:
define <my_message'action> "my_message" as computed {
items: list of string;
for i from 0 to THREADS-1 do {
items.add(appendf("%d: {messagef(DBG%d, MEDIUM, \"this is a message to logger %d\")}", i, i, i));
};
result = appendf("case thread { %s }", str_join(items, ";"));
};
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.
(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.
first time long time here.
I just started programming in javascript recently, I'm running into a question of design.
I have some working code that:
1. Waits for specific input from the serial port,
2. When input is found it moves to the next function.
3. The next function sends a command(s) over the serial port and then waits for input again.
Now I have 9 functions defined as stepone() steptwo() etc.... There has to be a better way to do this. Each function is the same except with different variables for input and output desired.
However, I do not want the program to skip steps. It needs to wait for the correct serial input before sending the next command.
I've tried using callback functions referencing each other, it just seems...wrong?
Also, it doesn't work. It doesn't wait for the right input before sending commands.
var waitforinput = function(input, regex, callback)
{
if (regex.search != -1)
callback();
};
var sendcommand = function(command,callback)
{
port.writeline(command);
if (callback)
callback();
};
var connect = function()
{
var int = setInterval(function()
{
waitforinput(input, "Please choose:", function()
{
sendcommand("1", function()
{
waitforinput(input, "You choosed", function()
{
sendcommand("saveenv 1");
});
});
});
},50);
};
I ended up using switch() with cases and keeping track of a variable called step:
step = 1;
switch(step)
{
case 1:
if (inputbuffer.search('Please choose') !== -1)
{
if (!waitdisplaystarted)
{
waitdisplaystarted = true;
waitint = setInterval(showwait,1000);
}
window.$("#instructions").hide();
window.$("#status").html("Step 1: Choosing boot option.");
SELF.sendserialcommand("1");
step = 2;
}
break;
case 2:
if (inputbuffer.search('You choosed 1') !== -1)
{
SELF.sendserialcommand('setenv bootargs "board=ALFA console=ttyATH0,115200 rootfstype=squashfs,jffs2 noinitrd"\r');
setTimeout(function(){SELF.sendserialcommand('saveenv\r');}, 50);
window.$("#status").html("Step 2: Transferring new kernel.");
setTimeout(function(){SELF.sendserialcommand('tftp 0x80600000 kernel.bin\r');}, 2000);
step = 3;
}
break;
case 3:
if (inputbuffer.search('Bytes transferred = ' + 878938) !== -1)
{
window.$("#status").html("Step 3: Erasing old kernel.");
SELF.sendserialcommand('erase 0x9f650000 +0x190000\r');
step = 'finished';
}
}
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.