I would like to understand how tasks in System Verilog work. I thought that a task was just a way of naming and parametrising a bit of code that could otherwise appear enclosed between a begin and an end. However, the way that the parameters work is non-obvious.
Say I want to factor out instances of non-blocking assignments from a module. I might do something like the following, thus reaching the point where there are two instances of the same task that differ just in the parameters (ff_0 and ff_1).
module test_inlined;
bit clk;
int count = 0;
logic [7:0] x, y, z;
task automatic ff_0;
#(posedge clk);
y <= x;
endtask
task automatic ff_1; // really same task as ff_0 to within variable renaming
#(posedge clk);
z <= y;
endtask
always
ff_0;
always
ff_1;
always #(posedge clk)
$strobe("%d: x=%d, y=%d, z=%d", count, x, y, z);
always
#5 clk = !clk;
always #(posedge clk)
begin
x <= count;
count ++;
if (count > 20) $finish;
end
endmodule
It would be trivial to instead place the factored out assignments (aka flip-flops) into two instantiations of the same module, so it would make sense for it to be also possible to express the same functionality in terms of two instances of the same task.
The following does not work because out is supposedly automatic, or that is what Modelsim claims. I do not see why it would be since it is fairly obviously a reference to a static member of a module?
task automatic ff (ref logic [7:0] out, ref logic [7:0] inp, ref bit clk);
#(posedge clk);
out <= inp;
endtask
module test_broken;
bit clk;
int count = 0;
logic [7:0] x, y, z;
always
ff(y, x, clk);
always
ff(z, y, clk);
// .... same as before
endmodule
It does make sense that the tasks need to be automatic to use ref parameters because then there is no need to worry about their lifetime. It is less clear why only blocking assignments to an automatic variable would be allowed. It is not like there is any obvious need for auto variables to go away while there are pending non-blocking assignments?
How do I factor out non-blocking assignments into a task, please? Many thanks in advance.
The problem is that task cannot assume anything about the storage classification of the variable passed to it. The code generated for the task has to work for any kind of storage, so passing by ref has to take on the pessimistic set of restrictions.
Related
Here I have a simple example below.
module A(o,clk,rst,i);
output o;
input i,clk,rst;
...
endmodule
and here is an interface class definition below.
interface my_if(input bit clk);
logic o,rst,i;
wire clk;
clocking cb#(posedge clk);
input o; // why input here ?
output i,rst; // why output here ?
endclocking
...
endinterface
My question is how to decide the signal inside cb is input or output ??
Thank you !
There are many uses of input/output in SystemVerilog, which can be confusing.
For ports, they the flow of data across a boundary. For a clocking block, they represent whether a signal is passively being sampled, or actively driven. Depending on the situation, it is perfectly reasonable to have a port declared as an output, and the same signal declared as a clocking block input.
I'm trying to implement inertial delay in SystemVerilog to generate a signal valid_inputs with following criterion
1. valid_inputs should go to '1' after some delay (say 15 units) if no inputs are X/Z
2. valid_inputs should go to '0' immediately if atleast one input becomes X/Z.
I am trying the above with 2 implementations:
module test (a, b, y);
input a, b;
output y;
wire temp;
assign temp = ^{a,b};
bit valid_inputs_temp, valid_inputs_2;
wire valid_inputs;
always #(temp)
begin
if (temp === 1'b1 || temp === 1'b0)
begin
valid_inputs_temp <= 1'b1;
end
else
begin
valid_inputs_temp <= 1'b0;
end
end
assign #(15,0) valid_inputs = valid_inputs_temp;
always #(temp)
begin
if (temp === 1'b1 || temp === 1'b0)
begin
#15 valid_inputs_2 <= 1'b1;
end
else
begin
valid_inputs_2 <= 1'b0;
end
end
endmodule
While the signal valid_inputs works perfectly, but I'm not quite sure why valid_inputs_2 doesn't work exactly the same? Is there a way I can implement the inertial delay using always-begin procedural code?
Please note that while I could modify the assign statement in the above code such that I totally eliminate the corresponding always-begin block, for some reason I need to use the always-begin style of coding.
Thanks,
Vinayak
The reason the second always block does not work is that you have a blocking #15 delay. That suspends the always process and misses a change on temp if it occurs in less that 15 time units. You need to move the delay to the other side of the <= so it becomes a non-blocking assignment delay.
valid_inputs_2 <= #15 1'b1;
And if you are confused about how an always block executes, see this link.
This is not a good example of inertial delay. The reason is that any 0->1 or 1->0 transition makes the output as 1. So pulses do not logically cause any difference in the output.
So there is no way to distinguish it from transport delay.
Moreover, the output turns 0 immediately for z. So there is no delay in that either.
Hence the signal "valid_inputs_2" is transport delay (<= #15).
To my knowledge there is no way to create inertial delay using always block.
I am still a bit confused about how SystemVerilog's 2012 rule 4.7 is implemented.
The rule states that in a situation like this:
module test;
logic a;
integer cnt;
initial begin
cnt = 0;
#100;
a <= 0;
a <= 1;
a <= 0;
a <= 1;
a <= 0;
end
always #(posedge a)
begin
cnt <= cnt + 1;
end
endmodule
all assignments would be scheduled on the Non Blocking Assignment queue, and must then be executed in order. The last value wins.
Up to here, it's all clear.
What happens next though is not the same for all simulators.
iverilog and Modelsim (at least the Vivado 2016/3 edition) create one event on 'a', which causes cnt to increment. This seems to also match the behaviour as illustrated by Mr Cummings at SNUG 2000
VCS however filters out the intermediate values and applies only the last one, which by the way is also the way that real flip flops work.
In this case it is not a purely hypothetical discussion, the simulation results are different, and the iverilog/modelsim behaviour could cause bugs that are very difficult to catch, because the flop toggles but no value change is seen in the waveforms.
The other point is this: if iverilog/modelsim are correct, why then are they creating one event and not two?
EDIT:
Additional note.
The example above is indeed not very meaningful.
A more realistic case would be
always #(posedge clk)
begin
clk2 <= 1'b1;
if (somecondition)
clk2 <= 1'b0;
end
always #(posedge clk2, negedge rst_n)
begin
if (!rst_n)
q <= 1'b0;
else
q <= ~q;
end
this is perfectly legal and in real hardware would never glitch.
the first always is actually logically identical to
always #(posedge clk)
begin
if (somecondition)
clk2 <= 1'b0;
else
clk2 <= 1'b1;
end
However, if you simulate the first version with ModelSim, you'll see your q happily toggling away, with clk2 constant 0. This would be a debugging nightmare.
Your last question is easy to explain. It's not that simulators create only one event, they don't- it's that only the first event schedules the #(posedge) to resume the always process and the other events happen in the NBA region before the always block resumes execution in the next active event region.
I can't justify the behavior of other simulators. You are not allowed to make multiple assignments to the same flip-flop in real hardware, so you analogy in not that simple. It's possible to have an un-timed description and get multiple (#posedge's) without time passing. So filtering would prevent that coding style.
If I have both alwas_comb and always_ff in a single module, which one executed first?.
for example, I have seen this code in a book but I am confused about the functionality. for example, if WE=0 what will be the value of Qout?
module SyncRAM #(parameter M = 4, N = 8)(output logic [N-1:0] Qout,
input logic [M-1:0] Address, input logic [N-1:0] Data, input logic clk, WE);
logic [N-1:0] mem [0:(1<<M)-1];
always_comb
Qout = mem[Address];
always_ff #(posedge clk)
if (~WE)
mem[Address] <= Data;
endmodule
Any help about the truth table of this code is appreciated,
regards
The specific answer to your question is that Qout will just track the value of mem[Address]. In other words, on the rising edge of the clock, if WE is 0, Qout will be driven with the value written to the memory. This is because the memory will behave like a bank of flip-flops, while the Qout output will behave as if it is directly connected to the Q output of a bank of flip-flops.
The order of the execution of the two always blocks is deterministic, because Qout is driven using a blocking assignment (=), whereas the memory is written to using a non-blocking assignment (<=). See the answer here for much more detail.
I been assigned to manually convert the below RTL into its structural equivalent. I don't understand how you'd convert it. What's the structural description for this code in verilog? What steps should I take?
module cou(
output reg [7:0] out,
input [7:0] in,
input iti,
input c,
input clock);
always #(posedge clock)
if (iti == 1)
out <= in;
else if (c == 1)
out <= out + 1;
endmodule
Here is the basic process:
always #(posedge clock) tells you you have positive-edge D-flip-flops without an asynchronous reset or set.
out is the only value being assigned within the always statment. The size of out tells you the number of flops needed.
Drawing a component level schematic diagram can help visualize the structural logic.
Now all that is needed to figure out is the combination logic to the flop's D pin. I'll give you a clue that it can be done using only muxes and an adder.