calculation of simulation time in verilog - 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.

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));

Verilog Minimum Bit Width

I'm looking for a clean way to declare Verilog/SystemVerilog types with a parameterised bit width. This is what I've got so far and was wondering if there is a better way to do it. I've looked through the system functions in the LRM 1800-2009 and -2017. The closest I could find is $bits, but I would like something like $minbits. Have I overlooked something?
In VHDL, it's done by simply specifying the range:
signal counter: integer range 0 to MAX_COUNT;
...and the compiler will calculate the minimum bit width to hold that range.
For the parameter values of 20 ns and 125 ms, the counter should be 23 bits with MAX_COUNT being 6,250,000.
module Debounce
#(
parameter CLOCK_PERIOD_ns = 20, // nanoseconds.
parameter DEBOUNCE_PERIOD_ms = 125 // milliseconds.
)
. . .
function int MinBitWidth([1023:0] value);
begin
for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
begin
value = value >> 1;
end
end
endfunction
localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns; // Default type of 32-bits.
localparam COUNTER_BITS = MinBitWidth(MAX_COUNT_32BITS); // Calculate actual bit width needed.
typedef logic [COUNTER_BITS - 1 : 0] TCounter;
localparam TCounter MAX_COUNT = MAX_COUNT_32BITS; // Assign to a type of the actual bit width (truncation warning from Quartus).
localparam TCounter ONE = 1;
TCounter counter;
. . .
always #(posedge clock)
begin
. . .
if (counter == MAX_COUNT_32BITS - 1) // Synthesises a 32-bit comparer no matter how many bits are needed with unused bits tied to ground.
. . .
if (counter == MAX_COUNT - ONE) // Synthesises a 23-bit comparer as expected.
. . .
counter <= counter + 1; // Synthesises a 23-bit counter as expected.
. . .
counter <= counter + ONE; // Synthesises a 23-bit counter as expected.
Incorrect Algorithm
I considered $clog2 which is the correct way to obtain an address bus width from a RAM depth parameter. However, this is not the same as the minimum bit width of a value. Let me explain...
Consider a value of 4 which is 100 base-2 (3 bits wide).
The $clog2 algorithm calculates a value of 2, which is incorrect. It should be 3. The reason for this miscalculation is because $clog2 subtracts 1 from the value before it starts to compute the number of bits, i.e. 4 becomes 3, then it calculates the minimum bit width of the value 3, giving 2 bits. While this is mathematically correct for the ceiling of log base-2, it is not the bit width of the original value.
Here is the clogb2 algorithm from the LRM:
function integer clogb2;
input [31:0] value;
begin
value = value - 1; // GOTCHA!
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) begin
value = value >> 1;
end
end
endfunction
Correct Algorithm
The correct algorithm is to calculate the minimum bit width of the original value, which is the algorithm given by #jonathan-mayer in his first answer before he edited it.
Here is the correct algorithm as a function:
function integer MinBitWidth;
input [1023:0] value;
begin
for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
begin
value = value >> 1;
end
end
endfunction
Just do +1 to get correct values for powers of 2.
$clog2(MAX_COUNT_32BITS + 1);
$clog2 from IEEE Std 1800-2017, section 20.8.1 Integer math functions:
The system function $clog2 shall return the ceiling of the log base 2
of the argument (the log rounded up to an integer value).
module tb;
parameter CLOCK_PERIOD_ns = 20; // nanoseconds.
parameter DEBOUNCE_PERIOD_ms = 125; // milliseconds.
localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns; // Default type of 32-bits.
localparam COUNTER_BITS = $clog2(MAX_COUNT_32BITS); // Calculate actual bit width needed.
initial begin
$display("MAX_COUNT_32BITS = %0d, COUNTER_BITS = %0d", MAX_COUNT_32BITS, COUNTER_BITS);
end
endmodule
Outputs:
MAX_COUNT_32BITS = 6250000, COUNTER_BITS = 23

Substraction in Verilog

I am working on a Verilog fixed point adder, using which I will also do the subtraction. When I do the subtraction not always I get the correct result.
For example, 1-1=0, but I get -0.
Kindly have a look on the below mentioned code:
`timescale 1ns/1ps
module adder #(
//Parameterized values
parameter Q = 27,
parameter N = 32
)
(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] c
);
reg [N-1:0] res;
assign c = res;
always #(a,b) begin
// both negative or both positive
if(a[N-1] == b[N-1]) begin //Since they have the same sign, absolute magnitude increases
res[N-2:0] = a[N-2:0] + b[N-2:0]; //So just the two numbers are added
res[N-1] = a[N-1]; //and the sign is set appropriately...
end
// one of them is negative...
else if(a[N-1] == 0 && b[N-1] == 1) begin // subtracts a-b
if( a[N-2:0] > b[N-2:0] ) begin // if a is greater than b,
res[N-2:0] = a[N-2:0] - b[N-2:0];
res[N-1] = 0; // manually the sign is set to positive
end
else begin // if a is less than b,
res[N-2:0] = b[N-2:0] - a[N-2:0]; // subtracting a from b to avoid a 2's complement answer
if (res[N-2:0] == 0)
res[N-1] = 0; // To remove negative zero....
else
res[N-1] = 1; // and manually the sign is set to negative
end
end
else begin // subtract b-a (a negative, b positive)
if( a[N-2:0] > b[N-2:0] ) begin // if a is greater than b,
res[N-2:0] = a[N-2:0] - b[N-2:0]; // subtracting b from a to avoid a 2's complement answer
if (res[N-2:0] == 0)
res[N-1] = 0;
else
res[N-1] = 1; // and manually the sign is set to negative
end
else begin // if a is less than b,
res[N-2:0] = b[N-2:0] - a[N-2:0];
res[N-1] = 0;
end
end
end
endmodule
Testbench for the adder is below:
`timescale 1ns/1ps
module tb_adder (
);
reg clk;
reg [ 31 : 0 ] a;
reg [ 31 : 0 ] b;
wire [ 31: 0 ] c;
adder adder_i (
.a(a),
.b(b),
.c(c)
);
parameter CLKPERIODE = 100;
initial clk = 1'b1;
always #(CLKPERIODE/2) clk = !clk;
initial begin
$monitor ("adder=%h", c);
#1
a = 32'h08000000;
b = 32'hF8000000;
#(CLKPERIODE)
$finish();
end
endmodule
I am having a hard time to find where did I go wrong as I am a newbie in Verilog. I am using this module to calculate Taylor Series in Fixed Point arithmetic. Any suggestions?
The only case I could find where your code produces the dirty zero is when both inputs are the dirty zero themselves. i.e.
a = b = 32'h80000000 = "-0"
It looks like this happens because in this case your code takes the branch at
if(a[N-1] == b[N-1]) begin //Since they have the same sign, absolute magnitude increases
and this branch doesn't have the same check as the others that specifically avoids it. You could fix this by moving that code to the end of the always block so it runs no matter what branch is taken earlier.

Sum of Values based on bits enabled Verilog

I am new to Verilog, I was trying to write a simple code but I am not sure how to do it in a expert way.
I have a 12 bit register "data", each bit of that register have a specific value. e.g.
Bit 0 = 12;
Bit 1 = 16;
Bit 2 = 33;
......
Bit 11 = 180;
Now if any bit of "data" register is 1 then the result should be the sum of all value that coresponds to that bit value. e.g.
data = 12'b100000000101
result = 225 (180+33+12)
Right now i am checking each bit of data, if it is 1 then i register that corresponding value and add it to previous registered value. This method takes number of cycles.
How can i do it in a fast way in verilog.
thank you
It depends on what you mean by "fast". Presumably you mean time, but remember that time=cycles/frequency - reducing the number of cycles will often reduce the maximum frequency your circuit can operate at.
For example, here's a circuit that does the entire add in one cycle:
always#(*) begin
tempsum = 0;
tempsum = tempsum + (data[0]? 12:0);
tempsum = tempsum + (data[1]? 16:0);
tempsum = tempsum + (data[2]? 33:0);
//...
end
always#(posedge clock)
result <= tempsum;
If you synthesized this circuit, you'd see a long chain of adders. In could calculate the result in a single cycle, but would have a long critical path, and therefore have a lower fMax. Whether this would be "faster" is impossible to know until you synthesize it (there are too many factors to guess).
A better multi-cycle approach could be to use a tree, i.e.:
reg [31:0] sum [29:0];
always # (posedge clock) begin
// level 0
sum[0] <= (data[0]? 12:0) + (data[1]? 16:0);
sum[1] <= (data[2]? 33:0) + (data[3]? 40:0);
// ...
sum[15] <= (data[30]? 160:0) + (data[31]? 180:0);
// level 1
sum[16] <= sum [0] + sum [1];
sum[17] <= sum [2] + sum [3];
// ...
sum[23] <= sum [14] + sum [15];
// level 2
sum[24] <= sum [16] + sum [17];
sum[25] <= sum [18] + sum [19];
// ...
// level 3
sum[28] <= sum [24] + sum [25];
sum[29] <= sum [26] + sum [27];
result <= sum [28] + sum [29];
end
All that said, ultimately the "fastest" approach will also depend on the other requirements of your system, what you're implementing it on, etc.
you can try something like below :-
reg [15:0] sum;
always #(*)begin
for (i=0;i<12;i++)begin
if (data[i])
sum = sum+Bit[i];
end //for
end //always
assign finalSum = |data ? finalSum: 'h0;

Can't fit settability in counter Verilog

I have written up/down counter and created code for settable starting point. So far so good but I can't think of how to add it to the counter. I have to highlight that I'm completely new to Verilog and similar languages.
//UTILS
reg [2:0] delay;
wire clock;
reg[3:0] tens;
reg[3:0] units;
wire[5:0] number;
reg[13:0] shift;
integer i;
//ASSIGNS
assign number[5:0] = SW[5:0];
assign up = SW[7];
assign start = SW[6];
//PRESCALER
always# (posedge MCLK)
begin
delay <= delay + 1;
end
assign clock = &delay;
//MAIN COUNTER
always# (posedge clock)
begin
if (start)
begin
if (up) //going up
begin
if (units == 4'd3 && tens == 4'd6)
begin //63 reached
units <= 0;
tens <=0;
end
if (units==4'd9)
begin //x9 reached
units <= 0;
tens <= tens + 1;
end
else
units <= units + 1; //typical case
end
else //goin down
begin
if (units == 4'd0)
if ( tens ==4'd0) //00 reached back to 63
begin
units <= 4'd3;
tens <= 4'd6;
end
else
begin //x0 reached
tens <= tens-1;
units <= 4'd9;
end
else
begin //typical case
units <= units -1;
end
end
end
end //MAIN COUNTER END
Here I don't know how to merge this two pieces, I would love to have it like this
if start
always# posedge clock
/counting/
else
/* change number nearly functionally(immediately when change occurs)*/
Adding it into if(start) else seems to do the work but only on positive edge of quite low frequency clock. As far as I know i can't use one reg in two different ALWAYS#.
/* // Clear previous number and store new number in shift register
shift[13:6] = 0;
shift[5:0] = number;
//BINARY TO BCD
for (i=0; i<6; i=i+1)
begin
if (shift[9:6] >= 5)
shift[9:6] = shift[9:6] + 3;
if (shift[13:10] >= 5)
shift[13:10] = shift[13:10] + 3;
shift = shift << 1;
end
units <= shift[9:6];
tens <= shift[13:10];
*/
dek7seg Is 7-segment display which is 100% fine (professor's code).
dek7seg ss1(
.bits(units[3:0]),
.seg(DISP1[6:0])
);
dek7seg ss10(
.bits(tens[3:0]),
.seg(DISP2[6:0])
);
endmodule
You are using a derived clock to control your MAIN COUNTER. Instead use the main clock MCLK and use the logic for delay as a conditional statement.
Since you want store an new values on the change of number, then you will need to store the the previous number value and compare.
Based on your description, your code should look something like this:
//MAIN COUNTER
always# (posedge MCLK)
begin
if (start && &delay)
begin
/* your up/down logic here */
end
else if (number != prev_number)
begin // Clear previous number and store new number
prev_number <= number;
units <= new_units;
tens <= new_tens;
end
end
// Calculate new units and tens from number
always #* begin
shift[13:6] = 0;
shift[5:0] = number;
//BINARY TO BCD
for (i=0; i<6; i=i+1) begin
if (shift[9:6] >= 5)
shift[9:6] = shift[9:6] + 3;
if (shift[13:10] >= 5)
shift[13:10] = shift[13:10] + 3;
shift = shift << 1;
end
new_units = shift[9:6];
new_tens = shift[13:10];
end

Resources