Testbench of floating point adder in verilog - verilog

I want to write floating point double precision adder. in the test-bench of that, I have some problems.
*adder is a module which gets two 64bits number and give sum of them.
this is my test bench:
module testadder;
reg [63:0] a;
reg [63:0] b;
wire [63:0] sum;
reg[10:0] expa,expb,expsum;
reg signa,signb,signsum,one;
reg[51:0] fa,fb,fsum;
real ta,tb,fa2,fb2,sumcheck,fsum2,resultmodulesum;
integer i;
reg [10:0]h23;
adder nameofinstance(sum,a,b);
initial begin
for(i=0;i<1000;i=i+1)
begin
h23=1023;
one=1'b1;
a = {$random(),$random()};
b = {$random(),$random()};
#10;
expa=a[62:52]-h23;
expb=b[62:52]-h23;
fa=a[51:0];
fb=b[51:0];
signa=a[63];
signb=b[63];
fa2 = ( $bitstoreal(fa)/(2**52) )+ one ;
ta=(-1)**(signa)*fa2*(2**expa);
fb2 = ( $bitstoreal(fb)/(2**52) ) + one;
tb=(-1)**(signb)*fb2*(2**expb);
sumcheck=ta+tb;
fsum=sum[51:0];
signsum=sum[63];
fsum2 = ( $bitstoreal(fsum)/(2**52) ) +one;
expsum=$bitstoreal(sum[62:52])-1023;
resultmodulesum=(-1)**(signsum)*fsum2*(2**expsum);
if(sumcheck!=resultmodulesum)
$display("wrong");
end
end
endmodule
module adder(sum,a, b);
input [63:0] a;
input [63:0] b;
reg [63:0] fa,fb;
always #(a or b) begin
fa={1'b1,a[51:0],12'b0};
fb={1'b1,b[51:0],12'b0};
end
endmodule
when i add ( $bitstoreal(fa)/(2**52) ) with one , fa2 get 1 ! but when i don't add it , fa2 get real value of (fa/2^52).
so I change my code to something like that to avoid adding with one, but another problem appears!
my change for making ta,tb and resultmodulesum:
(example for fa)
fa2 = ( $bitstoreal(fa)/(2**52) ) ;
ta=(-1)**(signa)*(fa2*(2**expa)+(2**expa));
2.then i understand that ta always get to (-1)**(signa)*(2**expa);
it means that fa2*(2**expa) is 0 ! but i don't know why and what can I do to make it correct.
I think that even if I didn't change my fa2 and fa2 (with one added in it) give correct output, my ta might has a problem.
3.I have another problem in my module that it is really strange!
little part of adder code module comes after test-bench code.
it is that when i debug my code, 63th bit of fb is 0! any idea?

This is not a full answer but more than can be expressed in the comments.
For the model of the floating point double I would have expected to see something along the lines of:
reg [63:0] a;
reg [63:0] b;
//Built in real for verification of code
real result;
real a_real;
real b_real;
initial begin
a = {$random(),$random()};
b = {$random(),$random()};
#1ps;
a_real = $bitstoreal(a);
b_real = $bitstoreal(b);
result = a_real + b_real;
$display("a %64b", a);
$display("b %64b", b);
$display("a_real %f", a_real);
$display("b_real %g", b_real);
$display("result %f", result);
#1ps;
$finish;
end
For splitting the randomised doubles up in to parts I would have expected to see some thing like:
wire a_sign; // 1 bit
wire [10:0] a_exponent;//11 bit
wire [51:0] a_fraction;//52 bit
assign a_sign = a[63] ;
assign a_exponent = a[62:52];
assign a_fraction = a[51:0] ;
wire b_sign; // 1 bit
wire [10:0] b_exponent;//11 bit
wire [51:0] b_fraction;//52 bit
assign b_sign = b[63] ;
assign b_exponent = b[62:52];
assign b_fraction = b[51:0] ;

Related

Why is this counter assignment wrong?

I am learning Verilog using the HDLBits website, and I solved this problem (circuit counts the number of '1's in an input vector), but I want to understand why my previous tries were wrong.
correct answer
module top_module(
input [254:0] in,
output [7:0] out );
int i ;
reg [7:0] counter;
always #(*) begin
counter =0;
for (i=0;i<255;i++)begin
counter = (in[i]==1)? counter+1:counter;
end
out = counter ;
end
endmodule
1st wrong answer
module top_module(
input [254:0] in,
output [7:0] out );
int i ;
reg [7:0] counter;
always #(*) begin
counter =0;
for (i=0;i<255;i++)begin
counter = (in[i]==1)? counter+1:counter;
end
end
out = counter ;
endmodule
2nd wrong answer
module top_module(
input [254:0] in,
output [7:0] out );
int i ;
always #(*) begin
out=0;
for (i=0;i<255;i++)begin
out = (in[i]==1)? out+1:out;
end
end
endmodule
All 3 code samples have syntax errors. If the HDLBits website did not report errors, try the EDA Playground website simulators.
In your "correct" answer you need to change
output [7:0] out );
to:
output reg [7:0] out );
When you make an assignment to a signal inside an always block (a procedural assignment), you need to declare the signal as a reg.
In your "1st wrong answer", change:
out = counter ;
to:
assign out = counter ;
Continuous assignments (outside of always blocks) require the assign keyword.
In your "2nd wrong answer", use reg for out.

Absolute value module in Verilog returning only unknown values

I am trying to implement a simple 16-bit absolute value module; however, I am only getting unknown values as output.
Below is the code that I've written:
module refabs(b, a);
input wire [15:0] a;
output reg signed [15:0] b;
always #* begin
b = ((a < 0) ? -a : a);
end
endmodule
module testbench;
reg [15:0] a;
wire [15:0] b;
refabs abs(b, a);
initial begin
a = -30000;
begin
$display("refabs(%x) = %x", a, b);
end
end
endmodule
The output I get is:
refabs(8ad0) = xxxx
In your example, the initial block executes with 0 delay without giving the always #* a chance to execute.
Either change your $display to $strobe, or add a delay before the $display statement.

Fixed-point Signed Multiplication in Verilog

I am designing a signed verilog multiplier which I intend to use multiple times in another module.
My two inputs will be always s4.27 format. 1 bit signed, 4 bits of integer and 27 bits of fraction. My output has to be also in s4.27 format and I have to get the most accurate result out of it.
In C, the following not so perfect code snippet did the job.
int32_t mul(int32_t x, int32_t y)
{
int64_t mul = x;
mul *= y;
mul >>= 27;
return (int32_t) mul;
}
In verilog my simple version of code is given below,
`timescale 1ns/1ps
module fixed_multiplier (
i_a,
i_b,
o_p,
clk
);
input clk;
input signed [31:0] i_a;
input signed [31:0] i_b;
output signed [31:0] o_p;
wire signed [63:0] out;
assign out = i_a*i_b;
assign o_p = out;
endmodule
The above mentioned code has bugs that I know because I am not getting the desired results at all.
So my questions are,
(1) As this line "assign o_result = out;" seems crucial to me, how shall I do my assignments to my final output so that I get the correct and most accurate s4.27 format output? Please note, this output will be fed to an adder and the adder output will be again an input for the multiplier.
Above question being asked, I also tried with xor-ing of sign bits of both inputs and assigning [57:27] bits to final output. Did not suit me and resulted in overflow, while in C same inputs did not give any overflow error.
(2) With C I did not have any problem with fixed-point multiplication while in verilog I guess I am struggling as I am quite a newbie. Any suggestions what things to keep in mind while dealing with signed multiplication/addition?
Below is the testbench code,
`timescale 1ns / 1ps
module tb_mul;
// Inputs
reg clk;
reg [31:0] a;
reg [31:0] b;
// Outputs
wire [31:0] c;
fixed_multiplier mul_i (
.clk(clk),
.i_a(a),
.i_b(b),
.o_p(c)
);
initial begin
$dumpfile("test_mul.vcd");
$dumpvars(1);
$monitor ("a=%h,\tb=%h,\tc=%h",a,b,c);
a = 32'h10000000;
b = 32'h10000000;
$finish();
end
endmodule
Thank you in advance.
Your multiplier does not work like you think it does. Verilog will assume your multiplication will be unsigned, and will compute it as such. You might want to do something like the following:
wire [61:0] temp_out;
assign temp_out = i_multiplicand[30:0] * i_multiplier[30:0];
assign sign = i_multiplicand[31] ^ i_multiplier[31];
assign out = {sign, temp_out[57:37]};

variable width assignment from 2 wires in a new wire with bit masking [VERILOG]

I'm trying to implement in hardware (using Verilog) the function described by this pseudo code:
if A then
output [63:0] = b[63:56], c[X-1:0], b[Y-1:0]
else output [63:0] = c[X-1:0], b[Y-1:0]
A is a boolean value, while output, b and c are 64 bits long.
X and Y change at runtime so they can't be Verilog variables.
The value of X changes with A:
if A then
X = 56 - Y
else X = 63 - Y
while Y is read from a 6 bit register so it can be any number from 0 to 63.
So for both cases of A all 64 bits of output will be assigned.
I know bit masking and mux selection with A is required but it is a bit complex and I can't quite get a clear picture on how to implement this in Verilog.
The runtime dependent bit selection can be implemented with shift(<<), variable bit selection(a[k+:8]), a smartly designed for loop(a[i] = condition ? b:c) or a completely expressed case. And all of them should have similar synthesis result. Based on experience, the case implementation should have best area performance.
Here is an example (with testbench) for shift implementation:
`timescale 1ns/1ps
module example(
input A,
input [5:0] Y,
input [63:0] b, c,
output [63:0] result
);
reg [63:0] o_a, o_abar;
assign result = A ? o_a : o_abar;
wire [5:0] X = A ? (56-Y) : (63-Y);
reg [63:0] c1_tmp, b1_tmp, mask;
always#(*)begin
c1_tmp = (c << Y) & {8'd0, {56{1'b1}}};
mask = (({64{1'b1}}>>X) << Y) | ({64{1'b1}} >> (64-Y));
b1_tmp = mask & b;
o_a = c1_tmp | b1_tmp;
end
reg [63:0] c2_tmp, b2_tmp;
always#(*)begin
c2_tmp = c << Y;
b2_tmp = b & ({64{1'b1}} >> Y);
o_abar = c2_tmp | b2_tmp;
end
endmodule
module test;
reg A;
reg [5:0] Y;
reg [63:0] b, c;
wire [63:0] result;
example ex(.A(A), .Y(Y), .b(b), .c(c), .result(result));
initial begin
A = 1;
Y = 6;
c = -1;
b = 0;
#10
$display("%b", result);
$finish;
end
endmodule

Signal EXCEPTION_ACCESS_VIOLATION received xilinx

I'm trying to make an arithmetic logic unit in verilog and I received the following error when I tried to simulate in ISim Simulator (No errors reported at Behavioral Check Syntax):
ERROR:Simulator:754 - Signal EXCEPTION_ACCESS_VIOLATION received
Here is the code:
module alu(
input [3:0] right,
input [3:0] left,
input [2:0] sel,
input CarryIn,
output reg CarryOut,
output reg [3:0] out
);
function [3:0] add;
input [3:0] a;
input [3:0] b;
input CarryIn;
assign add = a + b + CarryIn;
endfunction
function [3:0] substract;
input [3:0] a;
input [3:0] b;
input CarryIn;
assign subtract = a - b + (~CarryIn);
endfunction
function [3:0] AND;
input [3:0] a;
input [3:0] b;
assign AND = {1'b0 , a & b};
endfunction
function [3:0] OR;
input [3:0] a;
input [3:0] b;
assign OR = {1'b0 , a | b};
endfunction
function [3:0] XOR;
input [3:0] a;
input [3:0] b;
assign XOR = {1'b0 , a ^ b};
endfunction
function [3:0] increment;
input [3:0] a;
assign increment = a + 1;
endfunction
function [3:0] left_shift;
input [3:0] a;
assign left_shift = a << 1;
endfunction
function [3:0] right_shift;
input [3:0] a;
assign right_shift = a >> 1;
endfunction
always # (left or right or sel) begin
case (sel)
0 : {CarryOut , out} = add(left,right,CarryIn);
1 : {CarryOut , out} = substract(left,right,CarryIn);
2 : {CarryOut , out} = AND(left,right);
3 : {CarryOut , out} = OR(left,right);
4 : {CarryOut , out} = XOR(left,right) ;
5 : {CarryOut , out} = increment(left);
6 : begin
CarryOut = left[3];
out = left_shift(left);
end
7 : begin
CarryOut = left[0];
out = right_shift(left);
end
default : {CarryOut , out} = {1'b0,left};
endcase
end
endmodule
Any ideas ?
Remove the keyword assign from all your functions. assign statements are for continuous assignments that should only be declared in a module; not a task, function, initial or always.
There is a typo too. A couple places you have "substract" and should be "subtract".
You are also missing CarryIn from your sensitivity list. If your sensitivity list is not complete it will infer complex latching logic. Better yet, switch to a IEEE 1364-2001 coding style and use always #(*) or always #* instead of always # (left or right or sel or CarryIn). They auto construct the sensitivity list for combinational logic.
One of the reasons for happening this is that the simulator does not understand a syntax.
I had run into similar problem in VIVADO for a silly mistake while writing a verilog syntax. For a concatenation in verilog, mistakenly i used ":" instead of ",". That caused the same problem. To find out exactly which module is causing the problem it is good to look at the tcl console message. The module causing the problem is simply after compiling which module this message shows.
This is silly but sometimes it may take a lot of time to figure out.

Resources