Scheduling semantic of a task in Verilog - verilog

The execution of this code under iverilog simulator
module top();
reg clk;
reg[31:0] counter;
reg[19:0] in;
reg[31:0] out;
reg[19:0] xxx;
reg[19:0] yyy;
always #5 clk = ~clk;
initial begin
clk <= 0;
counter <= 0;
out <= 0;
end
always #(posedge(clk)) begin
decode_inst(counter);
$strobe("pre-counter is %0t",counter);
counter = counter + 1;
out <= counter;
$strobe("time is %0t",$time);
$strobe("counter is %0t",counter);
$strobe("out is %0t",out);
decode_inst(counter);
if (counter == 2) $finish();
end
task decode_inst(input xxx);
begin
$strobe("task_time is %0t",$time);
$strobe("task_counter is %0t",xxx);
end
endtask
endmodule
produces the following output:
task_time is 5
task_counter is 1
pre-counter is 1
time is 5
counter is 1
out is 1
task_time is 5
task_counter is 1
task_time is 15
task_counter is 0
pre-counter is 2
time is 15
counter is 2
out is 2
task_time is 15
task_counter is 0
Even studing the semantic of Verilog scheduling,
I'm not able to explain to myself the result.
In particular, how it is possible
task_counter = 0 when task_time = 15 and
task_counter = 1 when task_time = 5.
My question: is this output compliant with Verilog scheduling semantic?

The behavior described in the post is compliant with Verilog and its scheduling semantics.
The unexpected behavior (task_counter = 0 at the end) is caused by an error in the task argument.
The argument type is omitted; the default type is one-bit wide.
One bit can't represent the integer 2.
To correct this, change the task argument type to a vector as below:
task decode_inst(input [31:0] xxx);
begin
$strobe("task_time is %0t",$time);
$strobe("task_counter is %0d",xxx);
end
endtask
Also added some time after the clock to let the printing occur before the simulation ends. Without this the test is stopping and printing at the same time which can be confusing and lead to figuring out who wins the race.
Add #1 delay:
if (counter == 2) #1 $finish();
Produces the result in two simulators on EDA Playground:
# pre-counter is 1
# time is 5
# counter is 1
# out is 1
# task_time is 5
# task_counter is 1
# pre-counter is 2
# time is 15
# counter is 2
# out is 2
# task_time is 15
# task_counter is 2

Related

Task does not pass the output right

I have been trying to design a task for my testbench to make my life easier. The task seems to be doing fine when I check the internal signals using $display. However, when I hook the task up in my initial block, the simulation output shown on the waveform is NOT the same as the display result. Thank you in advance
===========Code===========
`timescale 1ns/1ps
/*----------Macros----------*/
`define FullCycle 20
`define HalfCycle 10
`define CLK_Cycle(CycleNum) (`FullCycle*CycleNum)
module syncronization_tb();
/*----------DUT I/O----------*/
logic reset_n, clk4m, ppm_data, output_valid_flag;
logic [7: 0] data_out_DUT;
logic flag;
/*----------TX I/O----------*/
logic bit_stream, clk50m;
logic [1: 0] ppm_out;
/*----------RX I/O----------*/
logic clk50mREC;
logic data_out;
assign ppm_data = data_out;
Syncronization DUT
(
reset_n,
clk4m_out,
ppm_data,
data_out_DUT,
output_valid_flag
);
PPM_top TX
(
reset_n,
clk50m,
bit_stream,
ppm_out
);
CLK_Recovery RX
(
clk50mREC,
reset_n,
ppm_out[1],
data_out,
clk4m_out
);
logic [7:0] data;
logic Taskflag;
integer index;
initial forever #`HalfCycle clk50m = ~ clk50m;
initial #17 forever #`HalfCycle clk50mREC = ~clk50mREC;
initial begin
{reset_n, clk50m, bit_stream, clk50mREC} = 0;
#`CLK_Cycle(5);
{reset_n} = 1;
data = 8'haa;
generateBITstream(.data(data), .bit_stream_out(bit_stream),.index(index));
// data = 8'he3;
// generateBITstream(data, bit_stream);
//data = 8'h5b;
//generateBITstream(data, bit_stream);
#`CLK_Cycle(800);
$stop;
end
task automatic generateBITstream;
parameter integer width = 8;
input [width - 1: 0] data;
output logic bit_stream_out;
output integer index;
begin
for(index = 0; index < width; index = index + 1 ) begin
#(posedge TX.clk1m) bit_stream_out = data[index];
$display("%d and time is %t with %b",index, $time, bit_stream_out);
#`CLK_Cycle(10);
end
end
endtask
endmodule
===========Console Display [Correct Result]===========
run -all
# 0 and time is 1870000ps with 0
# 1 and time is 2870000ps with 1
# 2 and time is 3870000ps with 0
# 3 and time is 4870000ps with 1
# 4 and time is 5870000ps with 0
# 5 and time is 6870000ps with 1
# 6 and time is 7870000ps with 0
# 7 and time is 8870000ps with 1
# Break in Module syncronization_tb at G:/Work/PPM/src/Syncronization RTL Simulation/src/syncronization_tb.sv line 74
===========Waveform [Wrong Result]===========
[]
===========A minimal reproducible example===========
`timescale 1ns/1ps
/*----------Macros----------*/
`define FullCycle 20
`define HalfCycle 10
`define CLK_Cycle(CycleNum) (`FullCycle*CycleNum)
module syncronization_tb();
logic [7:0] data;
logic bit_stream, clk50m;
integer index;
initial forever #`HalfCycle clk50m =~ clk50m;
initial begin
clk50m = 0; #`CLK_Cycle(10);
data = 8'haa;
generateBITstream(.data(data), .bit_stream_out(bit_stream),.index(index));
#`CLK_Cycle(800);
$stop;
end
task automatic generateBITstream;
parameter integer width = 8;
input [width - 1: 0] data;
output logic bit_stream_out;
output integer index;
begin
for(index = 0; index < width; index = index + 1 ) begin
#(posedge clk50m) bit_stream_out = data[index];
$display("%d and time is %t with %b",index, $time, bit_stream_out);
#`CLK_Cycle(10);
end
end
endtask
endmodule
===========Console Display [Correct Result]===========
# 0 and time is 210000 with 0
# 1 and time is 410000 with 1
# 2 and time is 610000 with 0
# 3 and time is 810000 with 1
# 4 and time is 1010000 with 0
# 5 and time is 1210000 with 1
# 6 and time is 1410000 with 0
# 7 and time is 1610000 with 1
# Break in Module syncronization_tb at G:/Work/PPM/src/Syncronization RTL Simulation/src/syncronization_tb.sv line 22
The problem is that the signal connected to the task output port (bit_stream) only gets updated in the testbench once the task completes (after the for loop). It does not get updated every time the $display is called in the for loop.
One way to fix this is to get rid of the task output port, and directly update the bit_stream signal inside the task:
task automatic generateBITstream;
parameter integer width = 8;
input [width - 1: 0] data;
output integer index;
begin
for(index = 0; index < width; index = index + 1 ) begin
#(posedge TX.clk1m) bit_stream = data[index];
$display("%d and time is %t with %b",index, $time, bit_stream);
#`CLK_Cycle(10);
end
end
endtask
Then call the task as:
generateBITstream(.data(data), .index(index));

How to generate PWL or pulse in verilog without using clock

I am working on a piece of code in which I need to generate output as per the condition-
1. if input is X/Z output should be X.
2. if input is 0 output should be 0 with a delay of 0.75us.
3. if input is 1 output should be 5 high going pulses of 1.5us with 50% duty cycle
with a delay of 0.75us.
I am confused How to write it in verilog?
You can use SystemVerilog's fork/join_none for this
logic in, out;
always begin
fork
case (in)
0: out <= #0.75us 0;
1: repeat (5) begin
#0.75us out <= 1;
#0.75us out <= 0;
end
default: out <= 'x;
endcase
join_none;
#in
disable fork; // kill repeat loop if still active
end

Take the sum of 3 adc data for 3 sampling

Hi everyone,
I am a newbie in programming FPGA by verilog language. At the present, I am trying to design the firmware to calculate the sum of adc data at 3 sampling. Firstly, I will explain about one adc at one sampling in my code. When you look at the code, you can see that with rising-edge of clkr clock and adcIfEnb == 1, the adc_data will get the value from adcIfData and this is the data for one sampling. In the next rising-edge of clkr clock and adcIfEnb == 1, this data is stored in iradcTrg. Finally, I will have the 3 data of adc_data for 3 sampling which are stored in iradcTrg and then I summarize 3 these data.
wire adcIfData[79:0];
reg
always #(posedge clkr) begin
if(adcIfEnb) begin
adc_data[9:0] <= adcIfData[9:0];
end
end
reg [29:0] iradcTrg;
reg [9:0] adcTrg;
always #(posedge clkr) begin
if (adcIfEnb) begin
iradcTrg[29:0] <= {adc_trg[19:10],adc_trg[9:0],adc_data[9:0]};
adcTrg[9:0] <= adc_trg[29:20] + adc_trg[19:10] + adc_trg[9:0];
end
end
However, there are 2 problems which I do not know how to solve.
Firstly, at the beginning time, when the first data of adc_data is stored at iradcTrg and adcTrg also take the sum. It means that adcTrg = 0 + 0 + first_adc_data but this sum need to be avoided.
Secondly, according to my design, I see that adc_data is serialized into iradcTrg. It means that the adc_data will be stored like this:
[1 2 3] 4 5 6 => 1 [2 3 4] 5 6=> 1 2 [3 4 5] 6
But in my case, I would like that the adc_data will be stored like this to get the sum
[1 2 3] 4 5 6 => 1 2 3 [4 5 6]
Therefore, how should I repair my code to get the result that I expected or are there any documents can help me in this case ?
To start: make sure your code is correctly indented when you put it on stackexchange. Secondly: I assume you have edited the code before posting it here because that code will not compile e.g. there is a floating 'reg' at the top and no module declaration.Thirdly: you have defined a wire adcIfData[79:0] I am going to assume you meant that to be [9:0].Forthly: You use variables which are not defined: adc_data, adc_trg.
Fifthly: I suggest you give your variables more meaningfull names like: gater_samples, sum_off_samples.
Now lets look at the core of the code. You want to take samples and shift them into a 30 bit register. There is no need to write "adc_trg[19:10],adc_trg[9:0]" adc_trg[19:0] will suffice. Also there is no need to put it in a different register beforehand. I would just use:
always #(posedge clkr)
if (adcIfEnb)
iradcTrg[29:0] <= {iradcTrg[19:0],adcIfData[9:0]};
As to your basic problem of gathering samples and not using the first two: all you have to do is add a counter which counts to three. Then you add the result on the third count. You will need a reset to give the counter a known value at startup but I don't see a reset signal. I always try to use minimal logic so I would make iradcTrg 20 bits wide to only store the intermediate result and at the count of three add it up with the latest sample. Saves another 10 registers. Here is some code. I wrote this without simulating or compiling. It is just a guide of how it all should look like.
reg [ 1:0] count;
reg [19:0] gather_samples;
reg [ 9:0] sum_of_samples;
reg sum_valid;
always #(posedge clkr)
begin
if (some_reset)
count <= 2'd0;
else
if (adcIfEnb)
begin
if (count==2'd2)
begin // third sample arriving, add it to the previous 2
sum_of_samples <= gather_samples[19:10] + gather_samples[9:0] + adcIfData;
count <= 2'd0;
else
begin // intermediate: gather samples
gather_samples <= {gather_samples[9:0],adcIfData};
count <= count + 2'd1;
end
sum_valid <= (count==2'd2);
end // if (adcIfEnb)
end // clocked
Your job will be much easier if you use a state machine. Here's a small (and incomplete) example of a state machine.
parameter FIRST_DATA=0, SECOND_DATA=1, THIRD_DATA=2, OUTPUT=3;
reg [2:0] current_state = FIRST_DATA;
reg [9:0] adc_data1;
reg [9:0] adc_data2;
reg [9:0] adc_data3;
reg [11:0] adc_data_sum;
always # (posedge clk)
begin
// TODO: use proper reset
case (current_state):
FIRST_DATA:
if(adcIfEnb):
current_state <= SECOND_DATA;
SECOND_DATA:
if(adcIfEnb):
current_state <= THIRD_DATA;
THIRD_DATA:
if(adcIfEnb):
current_state <= OUTPUT;
OUTPUT:
if(adcIfEnb):
current_state <= FIRST_DATA;
endcase
end
always # (negedge clk)
begin
if (current_state == FIRST_DATA && adcIfEnb)
adc_data1 <= adcIfData;
end
always # (negedge clk)
begin
if (current_state == SECOND_DATA && adcIfEnb)
adc_data2 <= adcIfData;
end
always # (negedge clk)
begin
if (current_state == THIRD_DATA && adcIfEnb)
adc_data3 <= adcIfData;
end
always # (negedge clk)
begin
if (current_state == OUTPUT)
adc_data_sum <= adc_data1 + adc_data2 + adc_data3;
end
Few comments first:
1) I don't know why do you introduce so many variables with strange names. You only need a adc_buffer and adc_sum. Is iradcTrg the same as adc_trg? Why is there an empty reg statement? Why adcIfData has 80 bits and you only use 8 LSB bits? I'm confused.
2) Since adc_sum will be a sum of 3 (adcTrg in your case), think about possible overflow. What should be the width of adc_sum if you want to add 3 10-bit numbers?
3) Shouldn't you reset your design to a known state using asynchronous or synchronous reset first?
You can use a 2 bit counter with async reset and a logic for wrapping back to 0:
reg [1:0] adc_buffer_counter_reg;
always #(posedge clkr or negedge rst_n) begin
if (!rst_n)
adc_buffer_counter_reg <= 2'd0;
else if (adcIfEnb) begin
if (adc_buffer_counter_reg == 2'd2) //trigger calc of the sum here
adc_buffer_counter_reg <= 2'd0;
else
adc_buffer_counter_reg <= adc_buffer_counter_reg + 2'd1;
end
You can use this counter to trigger a calculation of the sum every 3rd valid data.

calculation of simulation time in verilog

I want to calculate the simulation time of a calculation of one prime number, which is the number of clock cycle to calculate one prime number. As we know, the calculation of a large prime number takes more clock cycles than a small prime number.
I used $time in Verilog whenever a prime is calculated and captured it in a time_s register. I calculated the difference of calculation after another prime number. Here is my code where you can see time_s1 captured the time when a prime is calculated. time_s2 is the time to calculate the difference.
module prime_number_count(
input clk
);
//for count 1
parameter N =100; // size of array
parameter N_bits = 32;
reg [N_bits-1:0] prime_number[0:N-1]; // memory array for prime_number
reg [N_bits-1:0] prime_aftr50 [0:49]; // memory array to get
integer k; // counter variable
integer k1; // counter variable
integer count;
integer test;
integer time_s1;
integer time_s2;
integer check; //Counts 1 to k
localparam S_INC = 2'b01;
localparam S_CHECK = 2'b10;
reg [1:0] state;
initial begin
prime_number[0] = 'd1;
prime_number[1] = 'd2;
//prime_aftr50[0] = 'd0;
state = S_CHECK; //Check set count first
count = 'd3;
k = 'd2; //0,1 preloaded
check = 'd1;
test = 'd1;
time_s1 = 'd0;
time_s2 = 'd0;
k1 = 'd0;
end
always #(posedge clk )
begin
$display ("time of clock %d ", $time );
if(state == S_INC)
begin // if state is 1
//$display("State: Incrementing Number to check %d", count+1);
count <= count+1 ;
state <= S_CHECK ; // chang the state to 2
check <= 'd1; // Do not check against [0] value 1
test <= 'd1; // Safe default
end
else if (state == S_CHECK) begin
if (test == 0) begin
// Failed Prime test (exact divisor found)
$display("Reject %3d", count);
state <= S_INC ;
end
else
if (time_s2>30000)begin
prime_number[k]=prime_number[k-1];
time_s1 <=$realtime ;
state <= S_INC ;
k <= k + 1;
$display("Found %1d th Prime_1 %1d", k, count);
$display("display of simulation time" , time_s2);
end // end of simulation time
else
if (check == k) begin
//Passed Prime check
time_s1 <=$time ;
prime_number[k] <= count;
k <= k + 1;
state <= S_INC ;
$display("Found %1d th Prime_1 %1d", k, count);
$display("display of simulation time" , time_s2);
end
else begin
//$display("Check");
test <= count % prime_number[check] ;
check <= check + 1;
//$display("Checking %1d against %1d prime %1d : %1d", count, check, prime_number[check], count % prime_number[check]);
end
end
end
//////////////////////////////////////////////////////////////////
always #(posedge clk )
begin
if(check==k-1)
begin
time_s2 <=$realtime-time_s1;
// $display("display of simulation time" , time_s2) ;
end
end
always # (posedge clk) begin
if ( k==51+(50*k1)) begin
prime_aftr50[k1] <= count;
k1 <= k1+1;
end
end
endmodule
Background on time
Semantically I would recommend using time over integer, behind the scenes they are the same thing. But as it is only an integer it is limited to the accuracy of the timescale time_unit*. Therefore I would suggest you actually use realtime which is a real behind the scenes.
For displaying time %t can be used instead of %d decimal of %f for reals. The formatting of this can be controlled through $timeformat.
realtime capture = 0.0;
//To change the way (below) is displayed
initial begin
#80.1ns;
capture = $realtime;
$display("%t", capture);
end
To control how %t is displayed :
//$timeformat(unit#, prec#, "unit", minwidth);
$timeformat(-3, 2, " ms", 10); // -3 and " ms" give useful display msg
unit is the base that time is to be displayed in, from 0 to -15
precision is the number of decimal points to display.
"unit" is a string appended to the time, such as " ns".
minwidth is the minimum number of characters that will be displayed.
unit: recommended "unit" text
0 = 1 sec
-1 = 100 ms
-2 = 10 ms
-3 = 1 ms
-4 = 100 us
-5 = 10 us
-6 = 1 us
-7 = 100 ns
-8 = 10 ns
-9 = 1 ns
-10 = 100 ps
-11 = 10 ps
-12 = 1 ps
-13 = 100 fs
-14 = 10 fs
-15 = 1 fs
With these changes: realtime types, $realtime captures and displaying with %t analysing simulation time becomes a little easier.
Solution
Now to calculate the time between finding primes:
Add to your the following to intial begin:
$timeformat(-9, 2, " ns", 10);
Then in the state which adds the prime to the list you just need to add the following:
//Passed Prime check
time_s2 = time_s1; //Last Prime
time_s1 = $realtime ;
$display("Found %1d th Prime_1 %1d", k, count);
$display("Found at time : %t", time_s1);
$display("Time Diff : %t", time_s1 - time_s2);
Working example on EDA Playground.
timescale
*: time scales for verilog simulations are set by, the time_unit sets the decimal point so any further accuracy from the precision is lost when using time or integer to record timestamps.
`timescale <time_unit>/ <time_precision>
See section 22.7 of IEEE 1800-1012 for more info.

Upsample with Verilog

I need to upsample(2x) my data using Verilog. I think to use three ports for input and one port for output. Input ports are filterin, reset and clock. Output port is filterout. Also I need dynamic input size. How can I realize this with Verilog.
Edit1:
My input and output datas are 16 bit long. I just need a Verilog code to do this:
If Input: 1 2 3,
Then Output: 1 0 2 0 3 0.
If Input: 1 2 3 4 5,
Then Output: 1 0 2 0 3 0 4 0 5 0.
Edit2:
I created a verilog file to solve this but it didn't solve my problem.
US1.v file
`timescale 1ns / 1ps
module US1 (filterin,clk,filterinus);
input [15:0] filterin;
input clk;
output reg [15:0] filterinus;
integer i=0;
always # (posedge clk) begin
if (i==0) begin
filterinus <= filterin;
end
else begin
filterinus <= 0;
end
i=~i;
end
endmodule
I tested this code with the following Test bench:
Test.v file
`timescale 1ps/1ps
module Test;
reg [15:0] filterin;
reg clk;
wire [15:0] filterinus;
US1 uut (
.filterin(filterin),
.clk(clk),
.filterinus(filterinus)
);
initial begin
clk = 1;
filterin = 1;
#2 filterin = 2;
#2 filterin = 3;
#2 filterin = 4;
#2 filterin = 5;
#30 $finish;
end
always #1 clk = ~clk;
endmodule
As is seen, my input is: 1 2 3 4 5.
My output is: 1 0 3 0 5 0 5 0 5 0...
I need to see: 1 0 2 0 3 0 4 0 5 0 0 0 0 0...
A few comments on your code, assuming this is for synthesis.
Don't initialize the variable 'i' in a declaration. This is not always synthesizable.
Don't use an integer type for a single toggle bit. This makes your code less clear and makes the tools work harder.
Never mix blocking and non-blocking assignments in the same always block.
Given your description, I'm not sure what operation you're trying to implement here. You said upsampling but this isn't a typical approach such as linear or cubic interpolation methods.
Problem solved. I changed filterin input period from my testbench like this:
filterin = 1;
#4 filterin = 2;
#4 filterin = 3;
#4 filterin = 4;
#4 filterin = 5;
#4 filterin = 0;
And I got my output: 1 0 2 0 3 0 4 0 5 0 0 0...

Resources