I'm sqauring a 16.16 fixed point binary number and then compare the result with an integer. The 16.16 number becomes a 64 Bit binary number after squaring.
I don't know exactly if my code is correct and every square of a 16.16 fixed point number is within range.
Also I cannot setup the right statement to represent the 32.32 fixed point result.
Pseudo code
reg [31:0] n; //the 32 Bit number we want to square
reg [63:0] res; //out result register after squaring n
integer i;
...
res = n * n; // squaring n
i = 1;
/* compare with some integer - bigger than i */
if( res[63:32] >= i && res[31:0] > 0)
begin ...do something ... end
/* compare with some integer - less/equal than i */
if( (res[63:32] < i && res[31:0] >= 0) || (res[63:32] <= i && res[31:0] == 0))
begin ...do something... end
...
In the testbench I'm trying to represent the result as a 32.32 fixed point binary number - but this representation won't give me the right float value when displaying:
res[63:32] + $bitstoreal({1'b0,15'b011111111111111,{fer3[31:0],{81{1'b0}} }) -1;
There is a similar question which discusses fixed point widths, ... multiply a 32 bit by 32 bit the answer would fit into 64bits. Your correct with 16.16 x 16.16 is 32.32.
verilog conversion to reals can be automatic, if done correctly, to scale a number for display n * 2**-16 does not work. n * 2.0**-16 Does because we used 2.0 the calculation is done using floating point instead of integer.
NB: 2**n is 2 to the power of n. 2^n in some languages but ^ is XOR in verilog.
A quick example of scaling for comparison using a real:
reg [31:0] n; //16.16
reg [63:0] n_sq; //32.32
real n_sq_real; // Floating Point
always #* begin
n_sq = n * n;
end
initial begin
#1ps;
n = { 16'd2, 16'b1000_0000_0000_0000}; //2.5
#1ns;
$display("n %f, n squared %f", (n * 2.0**-16), n_sq * 2.0**-32);
n_sq_real = n_sq * 2.0**-32 ;
$display("n_sq_real %f", n_sq_real);
end
Returns:
# n 2.500000, n squared 6.250000
# n_sq_real 6.250000
The example on EDA Playground.
If it is just for comparison to an integer you can just truncate your number by shifting out the fractional bits ie n_sq * 2.0**-32 becomes n_sq >> 32
Or you could scale the integer by the number of fractional bits.
n_sq >= i<<32 ;
At the end of the day fixed point numbers in verilog are just integers scaled by a power of 2 to thats some bits can represent fractional information.
Related
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
I am new to Verilog/System Verilog and I wanted to implement the square and cube a fractional number. Consider the following example
module test(
input wire [31:0] input,
output reg [63:0] output
);
reg [63:0] temp;
always # (*) begin
temp = input*input;
output <= temp*input;
end
endmodule
So, when my input is 32'h0_C7AE147 (0.78 in the hexadecimal number system using the 32 bits representation and assuming _ is the equivalent of . in Verilog) I expect an output of 32'h0_797C3D6 (0.4745 in decimal number system)
But I am getting an output of 64'hD546_4A9C_ED94_2917
Also, how to handle the increasing bit sizes in a multiplication?
When we multiply two N-bit wide operands, we get an output of width 2N-bits. When we multiply this 2N-bit wide number with a k bit wide number, we get a number of widths 2N+k-bit wide and this process goes on.
You mean you want to represent fractional number in 32-bit fixed point notation with 4-bit integer part + 28-bit fractional part? And why do you need 64 bits for output?
Anyway I think you need to shift the product to the right by 28 bits for each multiplication.
Try:
temp = input * input >> 28;
output <= temp * input >> 28;
If you need proper rounding, do it before each shifting.
`include "bcd.v"
module bcd_4(A,B,Cin,S,Cout);
input [15:0] A,B;
input Cin;
output [15:0] S;
output Cout;
wire w1,w2,w3;
bcd_adder U1(.A(A[3:0]),.B(B[3:0]),.Cin(Cin),.S(S[3:0]),.Cout(w1));
bcd_adder U2(.A(A[7:4]),.B(B[7:4]),.Cin(w1),.S(S[7:4]),.Cout(w2));
bcd_adder U3(.A(A[11:8]),.B(B[11:8]),.Cin(w2),.S(S[11:8]),.Cout(w3));
bcd_adder U4(.A(A[15:12]),.B(B[15:12]),.Cin(w3),.S(S[15:12]),.Cout(Cout));
endmodule
I have designed a 4-digit BCD adder using four 4-bit BCD adders. The inputs 'A' and 'B' are taking hexadecimal values. How can I write a testbench so that the input values should be decimal only? I have to check the following condition also:
if({Cout,S}==A+B+Cin) $display("pass");
else $stop;
The inputs of your adder do not take hexadecimal values. They are 16-bit inputs which represent 4 BCD digits of 4 bits each. The input for each digit can range from 0 to 15 in decimal, but since they are BCD any value greater than 9 would be invalid.
The inputs can be specified in any base (binary, octal, decimal or hexadecimal).
The following are all equivalent:
A <= 10;
A <= 4'd10;
A <= 4'hA;
A <= 4'b1010;
If you want to only generate valid BCD values inputs in your testbench, you should generate the entire 4-digit number as an integer and then convert each digit to the appropriate bits to drive your design.
For example, to drive every valid value for input A (0 to 9999) you could do the following:
integer a;
for (a = 0; a < 10000; a = a + 1) begin
// a is an integer
// A is a 16-bit, 4-digit BCD value
A[3:0] = a % 10; // digit 0, ones place
A[7:4] = (a / 10) % 10; // digit 1, tens place
A[11:8] = (a / 100) % 10; // digit 2, hundreds place
A[15:12] = (a / 1000) % 10; // digit 3, thousands place
end
For sampling the output, you would do the inverse - convert 4 4-bit BCD digits to an integer.
Here is a full, runnable example which includes code for sampling and verifying the output: http://www.edaplayground.com/x/2pT
I got it. I can write it using following function
function integer hexatodecimal;
input [16:0] a;
integer b;
begin
b=a[3:0]+a[7:4]*10+a[11:8]*100+a[15:12]*1000+a[16]*10000;
hexatodecimal=b;
end
endfunction
I can call this function to convert {Cout,S} into hexadecimal.
I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R;
assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R;
assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want.
Can anyone help me out?
Thank you
The SystemVerilog solution has a distribution method within randomize called dist. Weights are assigned by value_or_range := weight or value_or_range :/ distributed_weight. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of
1/3-1/3-1/3-2-5.
dist is used in randomization so it needs to be mare of a randomize() with (or a class constraint). randomize returns a success bit, therefore it should be in called within an assert, void'(), or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom works a little different to $random it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always # ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code:
randcase
60: R = 1;
40: R = 0;
endcase
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random uses produces numbers that are equally random whatever bits you take from it.
Basically I'm trying to code a synthesizable module in verilog which performs division between 2 numbers and rounds off the result . For example, if I'm doing 56/30 then resulting value is 1.86 and this value should be rounded off to 2 or if I'm doing 42/30 , the resulting value is 1.4 which should be rounded off to 1 . Can synthesizable code be written in verilog to achieve this?
The value of the answers LSB is determined by the input format. If you change the numerator input to Fixed point with at least 1 Fractional bit rather than integers, your output will have a bit representing 0.5 which you can use to control truncate (round down) or round up.
module test;
reg[4:0] a = 5'b0011_0; //3 with 1 Fractional bit
reg[4:0] b = 5'b00010; //2 no fractional bits
reg[9:0] c;
initial begin
c = a/b ; //LSB => 0.5
// c= 5'b01_1 => 1.5
#1 $display("C = %b", c);
end
endmodule
Verilog truncates the end of a number if <size> is smaller than the value returned. So if you divide 42/30, the value returned is 1.4. Simply define the <size> as 1, and the decimal will be truncated.
However, keep in mind that this solution truncates the decimal, and doesn't round it up. I'm not an expert at Verilog, but you could refer here to further solve your problem.