I am new to Systemverilog (but coming from C/C++) and definitely fiddling with the language here.
Could you tell me why the referenced variable is not updated in the module sub?
I thought that changing the ref value would send an event to the module.
module sub(ref int toto);
int res = 0;
int foo = 0;
int bar = 0;
int count = 0;
initial
forever // plain forever to try full async event logic (no clock desired)
begin
unique case (toto)
3:
begin
if (foo == 0)
begin
foo++;
res = 5;
$display("Show %d %d",res,count);
end
end
5:
begin
if (bar == 0)
begin
bar++;
res = 89;
$display("--- Breaking from module. Show %d %d",res,count);
break;
end
end
default:
count++;
endcase
end
endmodule
module main();
int ki = 0;
sub ju(ki);
initial
begin
#50 ki = 3; // first update
#50 ki = 5; // should break the sub module loop
$finish;
end
endmodule
What results are you seeing? What results do you expect to see?
Just by looking at your code, I’m going to guess that you are experiencing an infinite loop in your initial-forever block. SystemVerilog will execute the forever loop in 0 time until there is a blocking event which allows time to advance. Without this, you will never get past time 0.
In your sub-module, you want to have an always @(ki) so that your module will react to changes in ki.
Thanks: actually, I was looking at this piece of code Tiempo CPU
And I was trying to check/simulate an event the same way they did.
module FSM(
push_channel_opcode_t.out OP,
push_channel_event_type.out ST,
push_channel_go_t.in GO,
push_channel_bit.in AB);
always
begin: fsm_process
go_t go;
bit ab;
opcode_t op;
static state_t state = S0;
unique case(state)
S0:
GO.Read(go);
unique case(go)
SEQ1:
state = S1; //why not non blocking here?
SEQ2:
state = S2;
endcase
S1,S2:
/* do smthg */
S3:
/* do smthg */
endcase
end: fsm_process
endmodule
And they said
An asynchronous process specifies a dataflow network relating a set of channels read by the process to another set of channels written by the process. The synchronization is exclusively done through channel handshake operations. Signal event statements (e.g., posedge, negedge) are not used. An asynchronous process is implemented by a SystemVerilog always process statement containing neither event control nor event expression. As they imply event control statements, the always_ff, always_latch and always_comb processes cannot be used to model asynchronous processes.
So I tried the bare forever (+break statement) since I cannot simulate a plain always (infinite loop). And nothing happened.
My expected result is:
“Show res 5 C” (C being a decimal count value)
followed by
“— Breaking from module. Show 89 C” (C being a decimal count value)
Is it a mistake in their code?
Why aren’t the assignments non blocking (state <= S1; instead of state = S1;), since the goal is to be fully decoupled?
The example you are looking at is atypical from the way most RTL is written today. Most state machines (FSMs) execute with a synchronous clock; advancing to the next state every clock cycle.
The code in the Tiempo CPU is asynchronous. It does not get into an infinite loop because there are calls to tasks like read and write that wait for other events.
I don’t think this is a good example for someone just learning SystemVerilog.
And for the sake of completeness, a piece of working code.
I put the wait in each case statement because I wanted to simulate a function call.
module sub(ref int toto, input event my_ev);
int ml = 0;
int fou = 0;
int kol = 0;
int count = 0;
always
begin
case (toto)
3:
begin
ml++;
fou = 54;
$display("hh %d %d",fou,count);
#5 wait(my_ev.triggered);
$display("out of 3 case");
end
5:
begin
kol++;
fou = 89;
$display("polo %d %d",fou,count);
#5 wait(my_ev.triggered);
$display("out of 5 case");
end
default:
begin
count++;
$display("default case %d",toto);
#5 wait(my_ev.triggered);
$display("out of default case %d fin",toto,$time);
end
endcase
end
endmodule
module main();
int ki = 0;
event my_ev;
sub sub(ki,my_ev);
initial
begin
#5 ki = 4;
->my_ev;
#5 ki = 3;
->my_ev;
#5 ki = 5;
->my_ev;
$display("FINISH");
end
endmodule
I don’t understand why you are trying to make things more complex than necessary. Instead of trying to simulate a function call, why don’t you use an actual function call? Modules are designed for time-based hardware constructs. Functions are for zero time processing, just like in C.
function void sub(int toto);
automatic int ml = 0;
automatic int fou = 0;
automatic int kol = 0;
automatic int count = 0;
begin
case (toto)
3:
begin
ml++;
fou = 54;
$display("hh %d %d",fou,count);
$display("out of 3 case");
end
5:
begin
kol++;
fou = 89;
$display("polo %d %d",fou,count);
$display("out of 5 case");
end
default:
begin
count++;
$display("default case %d",toto);
$display("out of default case %d fin",toto,$time);
end
endcase
end
endfunction
module main();
int ki = 0;
initial
begin
#5 ki = 4;
sub(ki);
#5 ki = 3;
sub(ki);
#5 ki = 5;
sub(ki);
$display("FINISH");
end
endmodule
Actually, I meant the “wait” in the sub module were simulating a function call. The wait could be replaced by a synchronous read/write event of some sort to get away from a global clock and try to be as asynchronous as possible. But to keep it contrived in this example, this was the option I chose.
The module will run in parallel all by itself doing stuff by itself.
The sub module will consume time (event based).
But maybe there is a detail I missed in my understanding of SystemVerilog.