How to save SystemC variables during vcs simulation and restore back based on stimulus change - system-calls

My tests are in SystemC env and for all my tests i run a common routine(basically its my init sequence which doesn't vary much based on seed). This common routine is followed by my actual test.
It looks something like this:
Test_MAIN
init_seq();
my_test();;
Here init_seq() is that common routine and my_test() is my actual test that have actual test sequence which initiate multiple SC threads, for initiating various kind of traffic.
Now, my problem is that i want a way to avoid init_seq() for every run. The entire test should run for one time and the next time i should have a mechanism to directly run from my_test()(which is basically skipping/preloading init_seq() part to the simulator).
VCS save and restore can't be used directly as in this case we also will have to restore the SystemC variables.
Could you please direct me on this..!!
Thanks
ByreddyNaresh

I tried with a SystemC test with init() and run() routine, and use VCS save/restart to restore the test. It seems OK to me that a member variable 'cnt' in test is restored successfully.
This is my test:
// test.h
#ifndef TEST_H
#define TEST_H
#include <systemc.h>
class test: public sc_module{
public:
sc_in<bool> init_start;
sc_in<bool> run_start;
void init();
void run();
int cnt;
SC_CTOR(test){
SC_THREAD(init);
sensitive_pos << init_start;
dont_initialize();
SC_THREAD(run);
sensitive_pos << run_start;
dont_initialize();
}
};
#endif
and
// test.cpp
#include "test.h"
void test::init(){
printf("test init:\n");
while(1){
cnt = 10;
printf("init cnt to %d\n", cnt);
wait();
}
}
void test::run(){
printf("test run:\n");
while(1){
cnt++;
printf("cnt = %d\n", cnt);
wait();
}
}
and the top:
// tb.v
module tb;
reg init_start;
reg run_start;
initial begin
init_start = 0;
run_start = 0;
#100
init_start = 1;
#100
$save("save.chk");
#100
run_start = 1;
#100
$finish;
end
test u_test(
.init_start(init_start),
.run_start(run_start)
);
endmodule
After 'save.chk' is generated, I run it directly and the output is:
$ save.chk
Chronologic VCS simulator copyright 1991-2012
Contains Synopsys proprietary information.
Compiler version G-2012.09; Runtime version G-2012.09; Mar 5 18:01 2014
test run:
cnt = 11
$finish called from file "tb.v", line 17.
$finish at simulation time 1300
V C S S i m u l a t i o n R e p o r t
Time: 1300 ps
CPU Time: 0.260 seconds; Data structure size: 0.0Mb
Wed Mar 5 18:01:08 2014
It seems variable 'cnt' is restored from '10', as is done in init() routine.
Don't know if this is the case you met?

Related

Cross-module reference resolution error from SV wait statement

I wanted to wait on the output variable of a task.
eg: wait(user_defined_task_name(output_variable_type_name) == 1)
In this example shown below, my intention is to make wait statement to be active from 0ns to 3ns (basically from the beginning of timestamp till t2=1)
Here is a working example;
class cl;
task run(output bit t);
$display("time=%0t , t=%0b",$realtime, t);
#1;
$display("time=%0t , t=%0b",$realtime, t);
#2;
t = 1;
$display("time=%0t , t=%0b",$realtime, t);
endtask
endclass
class c2 extends cl;
bit t2;
task run1();
wait(run(t2) == 1); // error from this line, what am i violating here?
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
endclass
module tmp;
c2 c2_h=new;
initial begin
c2_h.run1();
$display("test msg");
end
endmodule
eda output log:
Top Level Modules:
tmp TimeScale is 1 ns / 1 ns
Error-[XMREF] Cross-module reference resolution error testbench.sv, 19
Cross-module reference resolution error is found. Function is
expected, but actual target is not a function. Source info:
run(this.t2)
1 error CPU time: .116 seconds to compile Exit code expected: 0,
received: 1
A couple of problems with your code. A task does not return a value and cannot be used in an expression. You can only call it as a stand alone statement. But if you change run to a function functions cannot consume time.
In your particular example, you do not change the value of the t argument until the end of the task, and output arguments are copied out upon exiting the task, so you might as well just call the task run(t2) as a statement and it will block until returning.
task run1();
run(t2);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
If on the otherhand run set the t argument somewhere in the middle of the task, and you want to continue the run1 task as soon as that happened, the you would have use a fork/join_none and a ref argument instead.
class cl;
task run(ref bit t);
$display("time=%0t , t=%0b",$realtime, t);
#1;
$display("time=%0t , t=%0b",$realtime, t);
#2;
t = 1;
#2;
$display("time=%0t , t=%0b",$realtime, t);
endtask
endclass
class c2 extends cl;
bit t2;
task run1();
fork
run(t2);
join_none
wait(t2 == 1);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
endclass
When I run your code on the Cadence simulator, I get a different message:
xmvlog: *E,INVCTX The task 'run' cannot be used in this context.
Using the nchelp utility to get more information on that message:
A task or void function cannot be passed as an actual argument
because they do not return a value that can be used. They also cannot
be used as part of an expression.
In your simple example, there seems to be no need to use wait. You can simply call the task on its own:
task run1();
run(t2);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask

Delays within tasks in system verilog

I am trying to call 4 tasks within another task as follows:
task execute();
logic [0:3] req1, port_select;
logic [0:3] req2;
logic [0:3] req3;
logic [0:3] req4;
logic [0:31] data11, data21;
logic [0:31] data12, data22;
logic [0:31] data13, data23;
logic [0:31] data14, data24;
bfm.reset_task();
//drive multiple ports
//repeat(1)
//begin: random_stimulus
port_select = generate_combination();
repeat(1)
begin: per_combination_iteration
//port1
req1 = port_select[0]? generate_command() : 0;
data11 = generate_data();
data21 = generate_data();
//bfm.drive_ip_port1(req,data1,data2);
//port2
req2 = port_select[1]? generate_command() : 0;
data12 = generate_data();
data22 = generate_data();
//bfm.drive_ip_port2(req,data1,data2);
//port3
req3 = port_select[2]? generate_command() : 0;
data13 = generate_data();
data23 = generate_data();
//bfm.drive_ip_port3(req,data1,data2);
//port4
req4 = port_select[3]? generate_command() : 0;
data14 = generate_data();
data24 = generate_data();
//bfm.drive_ip_port4(req,data1,data2);
fork
bfm.drive_ip_port1(req1,data11,data21);
bfm.drive_ip_port2(req2,data12,data22);
bfm.drive_ip_port3(req3,data13,data23);
bfm.drive_ip_port4(req4,data14,data24);
join
end: per_combination_iteration
//end: random_stimulus
$stop;
endtask: execute
And one of my drive_ip_port function is as follows:
//driving port2
task drive_ip_port2(input logic [0:3] req2, input logic [0:31] data1_port2, data2_port2);
req2_cmd_in = req2; //req2 command
req2_data_in = data1_port2; //req2 first operand
#200;
req2_cmd_in = 0;
req2_data_in = data2_port2; //req2 second operand
#1000;
endtask: drive_ip_port2
This is what I am trying to achieve:
I want the execute task to drive 4 ports randomly. On the first clock, I want them to send a command and data. And then on the next clock, the command should be 0 and only data need to be sent.
This is what I have tried:
As shown in my code, I have written the above code. The thought behind this code was that since tasks can handle time delays, I can call the task once and pass the data and the command and let task handle all the work.
The problem I have:
After the first clock period, I have a delay of #200(equal to my clock). Thereafter, the wire should become 0 and should remain 0 for #1000. However, I am never getting the value 0 on command. It looks like the command gets driven by this task again. I have tried using Local variables, using the watch feature, using breakpoint but still couldn't debug it. Can anyone suggest what's wrong?
I don't know why req2_cmd_in does not get set to zero. Maybe there is somewhere else an overriding assignment like a typo in another task. (Try call only one task and see what that does.)
I do know that if you want something to happen at or after a clock, wait for that clock, do not use a delay. Safest is also to make sure you start at a determined point from a clock edge. Therefore I prefer to use in my test-benches code like this:
task drive_ip_port2(input logic [0:3] req2,
input logic [0:31] data1_port2, data2_port2);
// Use this or make sure you call the task at a
// determined point from the clock
# (posedge clk) ;
// Signals here change as if they come from a clocked register
req2_cmd_in <= req2; //req2 command
req2_data_in <= data1_port2; //req2 first operand
# (posedge clk) ;
req2_cmd_in <= 0; // No command
req2_data_in <= data2_port2; // only req2 second operand
repeat (4) // 4 or 5 depends on if you wait for clock at top
# (posedge clk) ;
endtask: drive_ip_port2

can packed arrays be passed by reference to the task in systemverilog

Can s_clk be passed as argument to xyz task in below code?
module test(input logic m_clk, output [1:0] logic s_clk);
...
xyz (m_clk,s_clk);//assuming m_clks and s_clks are generated from top
...
task automatic xyz (ref logic clk1, ref [1:0] logic clk2);
...
endtask
endmodule
I have read your problem, first of all you have typo mistake
module test(input logic m_clk, output [1:0] logic s_clk);
task automatic xyz (ref logic clk1, ref [1:0] logic clk2);
instead of this you have to write
module test(input logic m_clk, output logic [1:0] s_clk);
task automatic xyz (ref logic clk1, ref logic [1:0] clk2);
For better understanding I have also share one demo code for packed arrays can be passed by reference to the task in systemverilog.
Here is code :
program main();
bit [31:0] a = 25;
initial
begin
#10 a = 7;
#10 a = 20;
#10 a = 3;
#10 $finish;
end
task pass_by_val(int i);
$monitor("===============================================%d",i);
forever
#a $display("pass_by_val: I is %0d",i);
endtask
task pass_by_ref(ref bit [31:0]i);
forever
begin
#a $display("pass_by_ref: I is %0d",i[0]);
$display("This is pass_by value a ====== %d \n a[0] ====== %0d ",a,a[0]);
end
endtask
initial
begin
pass_by_val(a);
end
initial
pass_by_ref(a);
endprogram
By running this example you can observe that packed arrays can be passed by reference to the task in systemverilog and its value is also reflected to it.
pass_by_val task will register the value of the variables
only once at the time when task is called. Subsequently when the variable changes its value, pass_by_val task cannot see the newer values. On the other hand, 'ref' variables in a task are registered whenever its value changes. As a result, when the variable 'a' value changes, the pass_by_ref task can register and display the value correctly.
I simulated Ashutosh Rawal's code and the output display is given below:
=============================================== 25
pass_by_val: I is 25
pass_by_ref: I is 1
This is pass_by value a ====== 7
a[0] ====== 1
pass_by_val: I is 25
pass_by_ref: I is 0
This is pass_by value a ====== 20
a[0] ====== 0
pass_by_val: I is 25
pass_by_ref: I is 1
This is pass_by value a ====== 3
a[0] ====== 1
$finish called from file "testbench.sv", line 13.
$finish at simulation time 40
V C S S i m u l a t i o n R e p o r t

Running Program from Call Doesn't Seg Fault

My program writenotes keeps seg faulting when I try to write a note that is too long.
./writenotes lolololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololo
[ * ] Writing notes
Segmentation fault
Anyways, I was trying to write a python script that calls the program and curiously enough, calling it from a python script doesn't bring a seg fault, which I thought was rather peculiar.
Heres this code:
#!/usr/bin/python
from subprocess import call
call(["./writenotes", "lolololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololololo"])
Which returns
[ * ] Writing notes
Is this because of parent processing or something like such? How would calling a program through subprocess save a program from a segfault though? Are there other ways to call programs from a script that suffer seg faults?
As a note, the writenotes program was written in C. The other script is python.
You'll almost certainly find your C program is crashing but that Python is hiding that from you. Try instead with:
print call(["./writenotes", "lolololol..."])
and see what you get as a return value.
For example, this program tries to modify a string literal and, when run normally dumps core:
int main (void) {
*"xyzzy" = 'X';
return 0;
}
However, when run from the following script:
from subprocess import call
print call(["./testprog"])
I get the output -11, indicating that signal 11 (usually SIGSEGV) was raised, as per the documentation discussing Popen.returncode which subprocess.call() uses under the covers:
A negative value -N indicates that the child was terminated by signal N (Unix only).
An alternative to checking the return code is to import check_call and CalledProcessError instead of call and then use that function. It will raise an exception if the return code is non-zero.
That's probably not so important if you're only calling one executable (just get the return value in that case) but, if you're doing a lot in sequence, catching an exception from the entire group may be more readable.
Changing the C program to only crash when the first argument is 3:
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]) {
if (argc > 1) {
printf ("hello there %s\n", argv[1]);
if (strcmp (argv[1], "3") == 0)
*"xyzzy" = 'X';
}
return 0;
}
and the script to call it with several different arguments:
from subprocess import check_call, CalledProcessError
try:
check_call(["./testprog", "0"])
check_call(["./testprog", "1"])
check_call(["./testprog", "2"])
check_call(["./testprog", "3"])
check_call(["./testprog", "4"])
check_call(["./testprog", "5"])
check_call(["./testprog", "6"])
check_call(["./testprog", "7"])
check_call(["./testprog", "8"])
check_call(["./testprog", "9"])
except CalledProcessError as e:
print e.cmd, "failed with", e.returncode
else:
print "Everything went well"
shows that in action:
hello there 0
hello there 1
hello there 2
hello there 3
['./testprog', '3'] failed with -11

Not understanding types in Verilog

I am trying to make a block for an 8-bit multiplier, and the testbench is giving me a result that basically says that I don't know what I'm doing with my wires and regs. To make this easier to answer, I'm going to display my code, and then the parts that I think are important:
module multiplier_result(
input ADD_cmd,
input LOAD_cmd,
input SHIFT_cmd,
input reset,
input [7:0] B_in,
input [7:0] Add_out,
input cout,
output wire [7:0] RB,
output wire [15:0] RC,
output wire [8:0] temp_reg,
output wire LSB
);
wire [8:0] from_mux;
reg[16:0] balreg;
reg tempadd;
//assign the outputs. all combinational
assign RB = balreg[15:8];
assign RC = balreg[15:0];
assign LSB = balreg[0];
assign temp_reg = balreg[16:8];
mux_9 mux(
.sel(~ADD_cmd),
.Add_out(Add_out),
.cout(cout),
.mux_out(from_mux),
.temp_reg(temp_reg)
);
always # (*) begin
if(reset) begin
balreg[16:0] = 17'd0;
tempadd = 1'b0;
end
else
begin
if(LOAD_cmd)
begin
balreg[16:8] = 9'b000000000;
balreg[7:0] = B_in;
end
if(SHIFT_cmd)
begin
balreg[16:8] = from_mux;
balreg = balreg >> 1;
end
end
end
endmodule
Now, here is what's troubling me:
Here I'm assigning wires to different bits of the balreg register (in black). What is going on in my head (please excuse my paint skills):
But for some reason, LSB gets what it's supposed to, while RB and RC get high impedance. Here is the simulate result, followed by the code I used (just a simple test case)
module multiplier_result_tb(
);
reg ADD_cmd;
reg LOAD_cmd;
reg SHIFT_cmd;
reg reset;
reg [7:0] B_in;
reg [8:0] Add_out;
wire [7:0] RB;
wire [15:0] RC;
wire [8:0] temp_reg; //size 9
wire LSB;
multiplier_result dut(ADD_cmd,LOAD_cmd,SHIFT_cmd,reset,B_in,Add_out,RB,RC,temp_reg,LSB);
initial begin
LOAD_cmd = 0;
#10;
LOAD_cmd = 1;
reset = 0;
B_in = 8'b00001010;
Add_out = 9'd0;
ADD_cmd = 0;
SHIFT_cmd = 0;
end
endmodule
I'm not following these results at all. The balreg register is all set up, so the RB and RC wires MUST be defined, but according to the simulation, they are high impedance.
The only conclusion that I get at, is that I really don't know what's going on with the types (the model I had in my had worked for me so far).
Any help, ideas, tips are much appreciated.
You only connected 10 of the 11 ports of the dut. Didn't you get a warning? You are making connections by position, not by name. You connected RB to input cout. You need to drive cout in your testbench.
Another way to make connections is by name. This is more verbose, but it can make your code clearer:
multiplier_result dut (
// Inputs:
.ADD_cmd (ADD_cmd),
.Add_out (Add_out),
.B_in (B_in),
.LOAD_cmd (LOAD_cmd),
.SHIFT_cmd (SHIFT_cmd),
.cout (cout),
.reset (reset),
// Outputs:
.LSB (LSB),
.RB (RB),
.RC (RC),
.temp_reg (temp_reg)
);