With our shift register working nicely it is time to design the other parts of the serial adder. Both should be really easy.The gate structure of a full adder is well known but the derivation gives us a perfect test of the system so I will start with that. The full addder has to add three single bit inputs to generate a 2-bit output (since 1+1+1=3=0b11). The truth table is
C | B | A | Co | Q |
---|---|---|---|---|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
It is then straightforward to generate the logic equations
Q = A XOR B XOR C
Co = (A AND B) OR (A AND C) OR (B AND C)
which will allow us to write the simple Verilog behavioral description
module fadd(a, b, cin, q, cout); output q, cout; input a, b, cin; assign cout = (a & b) | (a & cin) | (b & cin); assign q = a ^ b ^ cin; endmodule // fadd |
This uses a different style of Verilog from our dataflow descriptions in the registers. Here we use assign to link outputs to logical products of inputs. Any change in an input will produce a corresponding change in the output.
I tested this by recreating the truth table thus.
Verilog | Output |
---|---|
module test; reg [2:0] in; wire q, cout; initial begin # 0 in = 0; # 5 in = 1; # 5 in = 2; # 5 in = 3; # 5 in = 4; # 5 in = 5; # 5 in = 6; # 5 in = 7; # 5 in = 0; end fadd f1(in[2], in[1], in[0], q, cout); initial $monitor("At time %t, in = %d, q = %d, cout=%d", $time, in, q, cout); endmodule // test |
At time 0, in = 0, q = 0, cout=0 At time 5, in = 1, q = 1, cout=0 At time 10, in = 2, q = 1, cout=0 At time 15, in = 3, q = 0, cout=1 At time 20, in = 4, q = 1, cout=0 At time 25, in = 5, q = 0, cout=1 At time 30, in = 6, q = 0, cout=1 At time 35, in = 7, q = 1, cout=1 At time 40, in = 0, q = 0, cout=0 |