I am trying to make a 4-bit adder and test it. I decided to use wait to determine when the adder circuit is done by checking when my sum and carry_out are >= 0. The inputs for the circuit are given as command line arguments. I am constructing my 4-bit adder using my full adder which I was able test successfully using this method.
full_adder.v
//Behavioral Verilog
module full_adder (input a, input b, input cin, output s, output cout);
assign s = a ^ b ^ cin;
assign cout = (a && b) || (a && cin) || (b && cin);
endmodule
4_bit_adder.v
module four_bit_adder(input [0:3] x, input [0:3] y, input carry_in, output [0:3] sum, output carry_out);
full_adder add1(x[0], y[0], sum[0], carry_in, carry1);
full_adder add2(x[1], y[1], sum[1], carry1, carry2);
full_adder add3(x[2], y[2], sum[2], carry2, carry3);
full_adder add4(x[3], y[3], sum[3], carry3, carry_out);
endmodule
4_bit_adder_tester.v
module four_bit_adder_test;
reg [0:3]x;
reg [0:3]y;
reg carry_in;
wire sum;
wire carry_out;
four_bit_adder adder(x, y, carry_in, sum, carry_out);
initial begin
$display("Here");
if (!$value$plusargs("x=%d", x)) begin
$display("ERROR: please specify +x=<value> to start.");
$finish;
end
if (!$value$plusargs("y=%d", y)) begin
$display("ERROR: please specify +y=<value> to start.");
$finish;
end
if (!$value$plusargs("carry_in=%d", carry_in)) begin
$display("ERROR: please specify +carry_in=<value> to start.");
$finish;
end
wait(sum >= 0 && carry_out>= 0) $display("sum=%d, carry_out=%d", sum, carry_out);
$finish;
end
endmodule
The problem is that carry_out remains at x so the sum and carry_out variables never get printed. I tried printing out the value of carry_out, and I think the logic in my circuits should work. Is this a valid way of testing my Verilog code?
That not a recommended way of testing because you get no output if the data is incorrect.
A better way is checking if the output matches what you expect
$display("Expected %b + %b + %b = %b", x,y,carry_in, {x+y+carry_in});
#1 // let output propagate
if ( {carry_out,sum} == x + y + carry_in )
$display("passed sum=%b, carry_out=%b", sum, carry_out);
else
$display("failed sum=%b, carry_out=%b", sum, carry_out);
end
This gives you a better picture of what is going wrong. You sill see that the output is z which means you have not connected thing up properly.
Also, get rid of all warning messages.
You need to pay close attention to your simulator log files because there should be warning messages which will point out the problem in your code. For example, on EDA Playground, I see this warning:
Warning-[PCWM-W] Port connection width mismatch
testbench.sv, 21
"four_bit_adder adder(x, y, carry_in, sum, carry_out);"
The following 1-bit expression is connected to 4-bit port "sum" of module
"four_bit_adder", instance "adder".
Expression: sum
Instantiated module defined at: "testbench.sv", 8
The warning goes away when you change:
wire sum;
to:
wire [0:3] sum;
You can use wait, but you should account for the situation when the expression is never true. In this case, you could add a testbench timeout which ends the simulation cleanly after a reasonable amount of time. For example, add a second initial block in four_bit_adder_test:
initial begin
#50 $display("Error: timeout");
$finish;
end
I am trying to determine how to turn this code into a 4-bit adder/subtractor using a fulladder. Right now it is doing the adding but I don't know how to do the subtract part.
module Adder #(parameter N = 4)(
output wire [N-1:0] sum, // sum
output wire co, // carry
input wire [N-1:0] x,
input wire [N-1:0] y,
input wire is_sub;
);
wire [N:0] c;
assign c[0] = 1'b0;
assign co = c[N];
genvar i;
generate
for (i = 0; i < N; i=i+1)
begin : counter_gen_label
FA FAInst (
.s(sum[i]),
.co(c[i+1]),
.a(x[i]),
.b(y[i]),
.cin(c[i]),
.is_sub(is_sub)
);
end
endgenerate
endmodule
module FA(
output reg s,
output reg co,
input wire a,
input wire b,
input wire cin,
input wire is_sub
);
always #(*)
begin
s = a ^ b ^ cin;
co = (a & b) | (a & cin) | (b & cin);
end
endmodule
How would I go by doing the subtraction inside the FA module?
Thanks!
FA does not need to use is_sub input.
Replace c[0] = 1'b0; with c[0] = is_sub;, and .b(y[i]) with .b(y[i] ^ is_sub).
This is from x - y = x + y' + 1 where y' means inverted y.
I am trying to re-write the following pseudocode as the simplest if-else, but am struggling to understand the logic fully.
if (a <= b) then // Here, a <= b.
if (y > b) then P // Here, (a <= b) & (y > b).
else if (x < a) then P // Here, (a <= b) & !(y > b) & (x < a).
else if ((y >= a) & (x <= b)) then Q else R
My interpretations of the pseudocode so far are written in comments above.
I think that I have correctly understood the logic of the first three lines of pseudocode.
However, I am not sure how to interpret the logic of the fourth and last line of the pseudocode.
I would like help to understand the state(s) of the four variables at the fourth line, as well as how to re-write the pseudocode as the simplest if-else.
How to get to the last line:
a <= b has to be true
y > b has to be false
x < a has to be false
so the last line would be:
(a <= b) & !(y > b) & !(x < a) & (y >= a) & (x <= b)
this leads to the following results:
a <= b & a <= x & a <= y -> a has to be the smallest value
b >= a & b >= y & b >= x -> b has to be the greatest value
y <= b & y >= a -> y has to be in between of a and b
x >= a & x <= b -> x has to be in between of a and b
which leads to:
if((x >= a & x <= b) & (y >= a & y <= b))
(but this only works if you just want to get to the last line)
How does the following translates into hardware? If I have multiple same equation assigning it to a different register, how does it translate? Say I have
reg [31:0] A;
reg [31:0] B;
reg [31:0] C;
reg [31:0] D;
function [31:0] foo;
reg [31:0] x, y ,z;
// do something
endfunction
always#(posedge clk)
.
.
.
A <= (B <<< 50) + (C ^ D | A) + A;
B <= C + A + B;
C <= foo((B <<< 50) + (C ^ D | A) + A, C + A + B, C <<< 30)
.
.
.
Would I have two combination blocks (4 blocks total) of
(B <<< 50) + (C ^ D | A) + A
and
C + A + B
or would I only have one of each (2 blocks) wiring out the results into A, B, C, and foo? If the compiler makes two of those logic each, is there a way to ensure only one of each is made, and those two combinational logic wires to multiple registers?
As noted by #mcleod_ideafix, it will often depend on the compiler/synthesis tool. Some are better than others at seeing the repeated logic:
(B <<< 50) + (C ^ D | A) + A;
and
C + A + B;
What you should do is write your code to explicitly call these operations out as their own bus and then re-use that named bus inside the expressions. This will clearly show the synthesis tool that your non-blocking statements contain logic that already exists within the design. This will also make it easier to debug in simulation, since you can now easily drop temp1 and temp2 onto your waveform viewer. It is definitely longer, since it adds two lines of code. But it makes your code clearer, easier to understand, and it is more likely to provide the smaller area result that you want. Below is an example:
reg [31:0] A;
reg [31:0] B;
reg [31:0] C;
reg [31:0] D;
function [31:0] foo;
reg [31:0] x, y ,z;
// do something
endfunction
wire [31:0] temp1 = (B <<< 50) + (C ^ D | A) + A;
wire [31:0] temp2 = C + A + B;
always#(posedge clk)
.
.
.
A <= temp1;
B <= temp2;
C <= foo(temp1, temp2, C <<< 30)
.
.
.
I'm studying Verilog and here's my first ALU.
I can't understand why the output does not display in the tester block.
Sample outputs(scroll horizontally):
FAIL: a=00010010000101010011010100100100, b=11000000100010010101111010000001, op=101, z=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, expect=11010010100111010111111110100101
FAIL: a=10000100100001001101011000001001, b=10110001111100000101011001100011, op=101, z=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, expect=10110101111101001101011001101011
Why isn't z calculated?
ALU
module yAlu(z, ex, a, b, op);
input [31:0] a, b;
input [2:0] op;
output[31:0] z;
output ex;
wire [31:0] andRes, orRes, arithmRes, slt;
wire cout;
assign slt = 0; // not supported
assign ex = 0; // not supported
and myand[31:0] (andRes, a, b);
or myor[31:0](orRes, a, b);
//Instantiating yArith adder/subtractor from addSub.v
yArith addSub(arithmRes, cout, a, b, op[2]);
//Instantiating 4-to-1 32-bit multiplexor from 4to1Mux.v
yMux4to1 multiplexor(z, andRes, orRes, arithmRes, slt, op[1:0]);
endmodule
MULTIPLEXORS:
// 1-bit 2 to 1 selector
module yMux1(z, a, b, c);
output z;
input a, b, c;
wire notC, upper, lower;
not my_not(notC, c);
and upperAnd(upper, a, notC);
and lowerAnd(lower, c, b);
or my_or(z, upper, lower);
endmodule
//--------------------------------------------
// n-bit 2 to 1 selector
module yMux(z, a, b, c);
parameter SIZE = 2;
output [SIZE-1:0] z;
input [SIZE-1:0] a, b;
input c;
yMux1 mine[SIZE-1:0] (z, a, b, c);
endmodule
//--------------------------------------------
// n-bit 4-to-1 multiplexor
module yMux4to1(z, a0, a1, a2, a3, c);
parameter SIZE = 32;
output [SIZE-1:0] z;
input [SIZE-1:0] a0, a1, a2, a3;
input [1:0] c;
wire [SIZE-1:0] zLo, zHi;
yMux #(.SIZE(32)) lo(zLo, a0, a1, c[0]);
yMux #(.SIZE(32)) hi(zLo, a2, a3, c[0]);
yMux #(.SIZE(32)) final(zLo, zLo, zHi, c[1]);
// c in array is important (see LabL4.v page)
endmodule
//----------------------------------------------
ADDER/SUBTRACTOR BLOCK:
// A simple 1-bit full adder
module yAdder1(z, cout, a, b, cin);
output z, cout;
input a, b, cin;
xor left_xor(tmp, a, b);
xor right_xor(z, cin, tmp);
and left_and(outL, a, b);
and right_and(outR, tmp, cin);
or my_or(cout, outR, outL);
endmodule
//----------------------------------------------
// 32-bit adder with 1 bit carry
module yAdder(z, cout, a, b, cin);
output [31:0] z;
output cout;
input [31:0] a, b;
input cin;
wire [31:0] in, out;
yAdder1 adder[31:0](z, out, a, b, in);
assign in[0] = cin;
assign in[1] = out[0];
assign in[2] = out[1];
assign in[3] = out[2];
assign in[4] = out[3];
assign in[5] = out[4];
assign in[6] = out[5];
assign in[7] = out[6];
assign in[8] = out[7];
assign in[9] = out[8];
assign in[10] = out[9];
assign in[11] = out[10];
assign in[12] = out[11];
assign in[13] = out[12];
assign in[14] = out[13];
assign in[15] = out[14];
assign in[16] = out[15];
assign in[17] = out[16];
assign in[18] = out[17];
assign in[19] = out[18];
assign in[20] = out[19];
assign in[21] = out[20];
assign in[22] = out[21];
assign in[23] = out[22];
assign in[24] = out[23];
assign in[25] = out[24];
assign in[26] = out[25];
assign in[27] = out[26];
assign in[28] = out[27];
assign in[29] = out[28];
assign in[30] = out[29];
assign in[31] = out[30];
assign cout = out[31];
endmodule
//----------------------------------------------
// Arithmetic module. Adds if ctrl = 0, subtracts if ctrl = 1
module yArith(z, cout, a, b, ctrl);
output [31:0] z;
output cout;
input [31:0] a, b;
input ctrl;
wire [31:0] notB, tmp;
wire cin;
assign notB = ~b;
assign cin = ctrl;
yMux #(.SIZE(32)) mux(tmp, b, notB, ctrl);
yAdder adderSubtractor(z, cout, a, tmp, cin);
endmodule
//----------------------------------------------
TESTER:
module labL;
reg [31:0] a, b;
reg [31:0] expect;
reg [2:0] op;
wire ex;
wire[31:0] z;
reg ok, flag;
yAlu mine(z, ex, a, b, op);
initial
begin
repeat(10)
begin
a = $random;
b = $random;
op = 3'b101;
//flag = $value$plusargs("op=%d", op);
#10;
// ERROR CASE
if (op === 3'b011)
$display("Error!");
else if (op === 3'b111)
$display("Error!");
// ARITHM CASE
else if(op === 3'b010)
expect = a + b;
else if(op === 3'b110)
expect = a + ~b + 1;
// AND CASE
else if(op === 3'b000)
expect = a & b;
else if (op === 3'b100)
expect = a & b;
// OR CASE
else if (op === 3'b001)
expect = a | b;
else if (op === 3'b101)
expect = a | b;
// DONE WITH CASES;
#5;
if (expect === z)
$display("PASS: a=%b, b=%b, op=%b, z=%b", a, b, op, z, ex);
else
$display("FAIL: a=%b, b=%b, op=%b, z=%b, expect=%b", a, b, op, z, expect);
end
$finish;
end
endmodule
Your yMux4to1 does not drive the z output, so that's why you see 'zzz' as the output.
This means undriven/high-impedance.
You should be able to use a waveform viewer/simulator to trace your outputs (much better than using print statements).
You are getting a high-impedance signal out on Z. This means that your output Z is not driven. You should step through your design in simulation and put traces on your control signals and Z. Your IDE should support this. You most likely do not have the design wired up correctly so it's important to check your datapath and make sure all inputs/outputs are properly connected.