I decided to start playing around with Verilog this weekend. I am really new to this and don't entirely understand what I am doing. I copied this adder code out of a PDF tutorial. The issue is that the tutorial does not give any test code to run it with. I tried to write my own but the output I am getting is zzzz. I am thinking that maybe it is trying to produce the output before the addition function has finished executing.
module addbit(a, b, ci, sum, co);
input a, b, ci;
output sum, co;
wire a, b, ci, sum, co;
assign {co, sum} = a + b + ci;
endmodule
module adder(result, carry, r1, r2, ci);
input [3:0] r1;
input [3:0] r2;
input ci;
output [3:0] result;
output carry;
wire [3:0] r1;
wire [3:0] r2;
wire ci;
wire [3:0] result;
wire carry;
wire c1, c2, c3;
addbit u0(r1[0], r2[0], ci, result[0], c1);
addbit u1(r1[1], r2[1], c1, result[0], c2);
addbit u2(r1[2], r2[2], c2, result[0], c3);
addbit u3(r1[3], r2[3], c3, result[0], carry);
endmodule
module test();
wire [3:0] a = 4'b1000;
wire [3:0] b = 4'b0100;
wire [3:0] result;
wire carry = 0;
wire ocarry;
adder x(result, ocarry, a, b, carry);
initial begin
$display("%b", result);
end
endmodule
the output I am getting is zzzz
The reason why you are getting an output zzzz is from your adder circuit (see mcleod_ideafix's comment below).
You might want to change you're input type of a and b as reg type so you can assign them inside a procedural block and assign them with different values.
module test();
reg [3:0] a = 4'b1000;
reg [3:0] b = 4'b0100;
wire [3:0] result;
wire carry = 0;
wire ocarry;
adder x(result, ocarry, a, b, carry);
initial begin
$display("# %0dns a: %0d b: %0d result: %0d", $time, a, b, result);
#1ns;
a = 5;
b = 6;
$display("# %0dns a: %0d b: %0d result: %0d", $time, a, b, result);
end
endmodule
Using the RTL that you posted and the test bench I modified above, it will produce an output:
# 0ns a: 8 b: 4 result: X
# 1ns a: 5 b: 6 result: X
You're adder does not work as expected for an adder circuit.
To help you further, I created an adder circuit for you.
module adder(result, carry, r1, r2, ci);
input [3:0] r1;
input [3:0] r2;
input ci;
output [3:0] result;
output carry;
assign {carry, result} = r1 + r2 + ci;
endmodule
And a working test bench that initializes the input to 0 then loops 10 times. Inside the loop, we create a delay of 1ns and changes the input to a random value from 0 to 15.
module test();
reg [3:0] a;
reg [3:0] b;
wire [3:0] result;
wire carry = 0;
wire ocarry;
adder x(result, ocarry, a, b, carry);
initial begin
$monitor("#%0dns [a: %0d] + [b: %0d] = [result: %0d] [carry = %0d] [ocarry = %0d] ", $time, a, b, result, carry, ocarry);
end
initial begin
a = 0;
b = 0;
repeat (10) begin
#1ns;
a = $random % 'h10;
b = $random % 'h10;
end
end
endmodule
You can run this code in edaplayground and see the output.
For every change of a, b, result, carry, ocarry, this code is executed.
$monitor("#%0dns [a: %0d] + [b: %0d] = [result: %0d] [carry = %0d] [ocarry = %0d] ", $time, a, b, result, carry, ocarry);
Related
The output waveform shows no change in the sum, dif, burrow, and out. Even after increasing delay time, still the output shows no change. This should work like the mod adder like add 10 and 2 and with mod 3 give output zero.
CODE
module Mod_adder(a,b,p,out);
input [3:0] a;
input [3:0] b;
input [3:0] p;
output [3:0] out;
wire [3:0] sum;
wire cout;
wire burrow;
wire [3:0] dif;
ripple_carry_adder r1(a,b,sum,cout,1'b0);
ripple_carry_adder r2(sum,~p,dif,burrow,1'b1);
repeat_sum rs1(dif,burrow,sum);
outval o1(sum,burrow,out);
endmodule
module full_adder(in0, in1, cin, out, cout);
input in0, in1, cin;
output out, cout;
assign out = in0 ^ in1 ^ cin;
assign cout = ((in0 ^ in1) & cin) | (in0 & in1);
endmodule
module ripple_carry_adder(in0, in1, out, cout,cin);
input [3:0] in0;
input [3:0] in1;
output [3:0] out;
output cout;
input cin;
wire c1, c2, c3;
full_adder fa0(in0[0], in1[0], cin, out[0], c1);
full_adder fa1(in0[1], in1[1], c1, out[1], c2);
full_adder fa2(in0[2], in1[2], c2, out[2], c3);
full_adder fa3(in0[3], in1[3], c3, out[3], cout);
endmodule
module repeat_sum(dif,burrow,sum);
input [3:0] dif;
input burrow;
output [3:0] sum;
assign sum = (burrow == 1'b0) ? dif:sum;
endmodule
module outval(sum,burrow,out);
input [3:0] sum;
input burrow;
output [3:0] out;
assign out = (burrow == 1'b1) ? sum:out;
endmodule
TEST BENCH
` include "MOD_ADDER.V"
module Mod_adder_tb;
reg [3:0] a;
reg [3:0] b;
reg [3:0] p;
wire [3:0] out; // wires
// Instantiate the module to be tested
Mod_adder MA1(a,b,p,out);
initial begin // initial block
$dumpfile("Test_Full_Adder.vcd");
$dumpvars(1, MA1);
a=4'b1010;
b=4'b0100;
p=4'b0011;
#100;
end // end of initial block
endmodule
I see 2 major problems.
Your out testbench signal is unknown (X) because of driver contention. For example, the sum signal in Mod_adder has multiple drivers: from the r1 instance and from the rs1 instance. The out output of r1 and the sum output of rs1 are both driving the sum wire. You should not drive the same signal from 2 different module instances. You could rename one of the sum signals to something unique, like sum_rs1 and declare a new wire.
wire [3:0] sum, sum_rs1;
Also, you have combinational feed back loops. For example:
assign out = (burrow == 1'b1) ? sum:out;
The out signal should not be on both the LHS and RHS of a continuous assignment.
The output waveform shows no change in the sum, dif, burrow, and out. Even after increasing delay time, still the output shows no change. This should work like the mod adder like add 10 and 2 and with mod 3 give output zero.
CODE
module Mod_adder(a,b,p,out);
input [3:0] a;
input [3:0] b;
input [3:0] p;
output [3:0] out;
wire [3:0] sum;
wire cout;
wire burrow;
wire [3:0] dif;
ripple_carry_adder r1(a,b,sum,cout,1'b0);
ripple_carry_adder r2(sum,~p,dif,burrow,1'b1);
repeat_sum rs1(dif,burrow,sum);
outval o1(sum,burrow,out);
endmodule
module full_adder(in0, in1, cin, out, cout);
input in0, in1, cin;
output out, cout;
assign out = in0 ^ in1 ^ cin;
assign cout = ((in0 ^ in1) & cin) | (in0 & in1);
endmodule
module ripple_carry_adder(in0, in1, out, cout,cin);
input [3:0] in0;
input [3:0] in1;
output [3:0] out;
output cout;
input cin;
wire c1, c2, c3;
full_adder fa0(in0[0], in1[0], cin, out[0], c1);
full_adder fa1(in0[1], in1[1], c1, out[1], c2);
full_adder fa2(in0[2], in1[2], c2, out[2], c3);
full_adder fa3(in0[3], in1[3], c3, out[3], cout);
endmodule
module repeat_sum(dif,burrow,sum);
input [3:0] dif;
input burrow;
output [3:0] sum;
assign sum = (burrow == 1'b0) ? dif:sum;
endmodule
module outval(sum,burrow,out);
input [3:0] sum;
input burrow;
output [3:0] out;
assign out = (burrow == 1'b1) ? sum:out;
endmodule
TEST BENCH
` include "MOD_ADDER.V"
module Mod_adder_tb;
reg [3:0] a;
reg [3:0] b;
reg [3:0] p;
wire [3:0] out; // wires
// Instantiate the module to be tested
Mod_adder MA1(a,b,p,out);
initial begin // initial block
$dumpfile("Test_Full_Adder.vcd");
$dumpvars(1, MA1);
a=4'b1010;
b=4'b0100;
p=4'b0011;
#100;
end // end of initial block
endmodule
I see 2 major problems.
Your out testbench signal is unknown (X) because of driver contention. For example, the sum signal in Mod_adder has multiple drivers: from the r1 instance and from the rs1 instance. The out output of r1 and the sum output of rs1 are both driving the sum wire. You should not drive the same signal from 2 different module instances. You could rename one of the sum signals to something unique, like sum_rs1 and declare a new wire.
wire [3:0] sum, sum_rs1;
Also, you have combinational feed back loops. For example:
assign out = (burrow == 1'b1) ? sum:out;
The out signal should not be on both the LHS and RHS of a continuous assignment.
How can I check if my 4-bit adder is working properly. If it is then it should display "OK" or if it's not then "NOT". I wrote the code and the bench test which will calculate all possible 4-bit combinations, but i don't know whether the output values are correct and I want to check it. My test bench is already displaying overflow. Here is my code :
module ripple_carry_adder_subtractor(S, C, V, A, B, Op);
output [3:0] S; // The 4-bit sum/difference.
output C; // The 1-bit carry/borrow status.
output V; // The 1-bit overflow status.
input [3:0] A; // The 4-bit augend/minuend.
input [3:0] B; // The 4-bit addend/subtrahend.
input Op; // The operation: 0 => Add, 1=>Subtract.
wire C0; // The carry out bit of fa0, the carry in bit of fa1.
wire C1; // The carry out bit of fa1, the carry in bit of fa2.
wire C2; // The carry out bit of fa2, the carry in bit of fa3.
wire C3; // The carry out bit of fa2, used to generate final carry/borrrow.
wire B0; // The xor'd result of B[0] and Op
wire B1; // The xor'd result of B[1] and Op
wire B2; // The xor'd result of B[2] and Op
wire B3; // The xor'd result of B[3] and Op
xor(B0, B[0], Op);
xor(B1, B[1], Op);
xor(B2, B[2], Op);
xor(B3, B[3], Op);
xor(C, C3, Op); // Carry = C3 for addition, Carry = not(C3) for subtraction.
xor(V, C3, C2); // If the two most significant carry output bits differ, then we have an overflow.
full_adder fa0(S[0], C0, A[0], B0, Op); // Least significant bit.
full_adder fa1(S[1], C1, A[1], B1, C0);
full_adder fa2(S[2], C2, A[2], B2, C1);
full_adder fa3(S[3], C3, A[3], B3, C2); // Most significant bit.
endmodule // ripple_carry_adder_subtractor
module full_adder(S, Cout, A, B, Cin);
output S;
output Cout;
input A;
input B;
input Cin;
wire w1;
wire w2;
wire w3;
wire w4;
xor(w1, A, B);
xor(S, Cin, w1);
and(w2, A, B);
and(w3, A, Cin);
and(w4, B, Cin);
or(Cout, w2, w3, w4);
endmodule // full_adder
module tb_U2_add_sub;
reg [3:0] A;
reg [3:0] B;
wire [3:0] S;
reg Op;
wire V;
integer i, j;
ripple_carry_adder_subtractor U2AS(.A(A), .B(B), .S(S), .Op(Op), .V(V));
always #* if (V == 1) $display($time, " overflow");
initial begin
Op = 0; // Op = 0 ->adder; Op = 1 ->subtractor
for (i=0; i<16; i=i+1) begin
for (j=0; j<16; j=j+1) begin
A = i;
B = j;
#10;
end
end
end
endmodule
You can calculate expected values at testbench and compare them with calculated results from your module. If they are not same, you will now there is an error. In your case,
module tb_U2_add_sub;
reg [3:0] A;
reg [3:0] B;
wire [3:0] S;
reg Op;
wire V;
integer i, j;
ripple_carry_adder_subtractor U2AS(.A(A), .B(B), .S(S), .Op(Op), .V(V));
reg [3:0] S_exp; // expected S value
reg V_exp; // expected V value
initial begin
Op = 0; // Op = 0 ->adder; Op = 1 ->subtractor
for (i=0; i<16; i=i+1) begin
for (j=0; j<16; j=j+1) begin
A = i;
B = j;
// Calculate expected values
S_exp = i+j;
V_exp = (A[3]&B[3]&(~S_exp[3])) | ((~A[3])&(~B[3])&S_exp[3]);
#10;
// Compare expected values with calculated values
if ((S_exp[3:0] !== S) || (V_exp !== V)) begin
// if there is an error, display it and stop simulation
$display("Failed for A=%d,B=%d.\n",A,B);
$stop();
end
end
end
// if there is no error, you will see "Passed"
$display("Passed");
end
endmodule
I'm attempting to visualize some code from here. However, the wire values I'm trying to view (all the reqs and acks in SIMSYS) are displaying as 'x'.
I don't know enough about any HDLs to know what is going wrong, so I'd appreciate an explanation of what's going on. If it makes any difference, I'm running it with iverilog 10.2 on Ubuntu 19.04.
Here's the code in question:
// A Muller C-element
module MCEL (q, a, b);
input a, b;
output q;
wire reset;
wire p1 = !(a & q);
wire q1 = !(b & q);
wire r1 = !(a & b);
assign #13 q = !(p1 & q1 & r1);
endmodule
//Micropipeline stage (David Sutherland style).
module MPHSL(req_l, ack_l, req_r, ack_r, din,dout);
input req_l; output ack_l;
output req_r; input ack_r;
MCEL left(ack_l, req_l, !req_r);
MCEL right(req_r, ack_l, !ack_r);
// Data handling stage
input [7:0] din;
output [7:0] dout;
reg [7:0] dout1;
always #(posedge req_l) dout1 <= din;
assign dout = dout1;
endmodule
// Simulation wrapper
module SIMSYS();
wire req_1, ack_1;
wire req_2, ack_2;
wire req_3, ack_3;
wire req_4, ack_4;
reg tn;
initial begin tn = 0; #350 tn = 1; # 20 tn = 0; end
wire [7:0] d1,d2,d3,d4;
MPHSL s1(tn | req_4, ack_4, req_1, ack_1, (tn)? 8'hx5A: d4+1, d1);
MPHSL s2(req_1, ack_1, req_2, ack_2, d1, d2);
MPHSL s3(req_2, ack_2, req_3, ack_3, d2, d3);
MPHSL s4(req_3, ack_3, req_4, ack_4, d3, d4);
endmodule
The issue is that there are no initial values and no logic that resets any variables to a valid state, so the code is forever propagating X values. The first thing you need to do is change the MCEL module's q output to be a reg so you can assign it an initial value, then give it and MPHSL's dout1 reg their values. For example:
// A Muller C-element
module MCEL (q, a, b);
input a, b;
output reg q = 0;
wire reset;
wire p1 = !(a & q);
wire q1 = !(b & q);
wire r1 = !(a & b);
always #* #13 q = !(p1 & q1 & r1);
endmodule
//Micropipeline stage (David Sutherland style).
module MPHSL(req_l, ack_l, req_r, ack_r, din,dout);
input req_l; output ack_l;
output req_r; input ack_r;
MCEL left(ack_l, req_l, !req_r);
MCEL right(req_r, ack_l, !ack_r);
// Data handling stage
input [7:0] din;
output [7:0] dout;
reg [7:0] dout1 = 0;
always #(posedge req_l) dout1 <= din;
assign dout = dout1;
endmodule
// Simulation wrapper
module SIMSYS();
wire req_1, ack_1;
wire req_2, ack_2;
wire req_3, ack_3;
wire req_4, ack_4;
reg tn;
initial begin tn = 0; #350 tn = 1; # 20 tn = 0; end
wire [7:0] d1,d2,d3,d4;
MPHSL s1(tn | req_4, ack_4, req_1, ack_1, (tn)? 8'hx5A: d4+1, d1);
MPHSL s2(req_1, ack_1, req_2, ack_2, d1, d2);
MPHSL s3(req_2, ack_2, req_3, ack_3, d2, d3);
MPHSL s4(req_3, ack_3, req_4, ack_4, d3, d4);
endmodule
And the result:
I have two files named: summation.v and summationtest.v
Code for summation.v::
module summation(a, b, c);
input [3:0] a;
input [3:0] b;
output reg[7:0] c;
reg[3:0] anum;
reg[3:0] bnum;
always #(a) begin
anum <=a;
bnum <=b;
c = anum + bnum;
end
endmodule
The purpose of summation.v is to take two decimal input from summationtest.v, process the decimal values and send the result c back to the output (summationtest.v) again.
Code for summationtest.v:
module summationtest;
reg[3:0] a;
reg[3:0] b;
wire[7:0] c;
summation a1(a, b, c);
initial begin
a = 3;
b = 4;
$display("%d", c);
end
endmodule
When the program runs, no value of a and b passes from summationtest.v to summation.v; as a result, no value is assigned to c.
That is not the proper way to model combinational logic. You have an incomplete sensitivity list and you should not use nonblocking assignments (<=). You should use $monitor instead of display to view all signal changes.
Here is a much simpler way to code your adder:
module summation(a, b, c);
input [3:0] a;
input [3:0] b;
output [7:0] c;
assign c = a + b;
endmodule
module summationtest;
reg[3:0] a;
reg[3:0] b;
wire[7:0] c;
summation a1(a, b, c);
initial begin
$monitor("%d", c);
a = 3;
b = 4;
end
endmodule