-
Notifications
You must be signed in to change notification settings - Fork 43
/
Adder_Subtractor_Binary.v
145 lines (119 loc) · 5.15 KB
/
Adder_Subtractor_Binary.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//# Binary Integer Adder/Subtractor
// A signed binary integer adder/subtractor, with `carry_in`, `carry_out`,
// `overflow`, and all the intermediate `carries` into each bit position (see
// [Carry-In Calculator](./CarryIn_Binary.html) for their uses).
// Addition/subtraction is selected with `add_sub`: 0 for an add
// (`A+B+carry_in`), and 1 for a subtract (`A-B-carry_in`). This assignment
// conveniently matches the convention of sign bits. *Note that the `overflow`
// bit is only meaningful for signed numbers. For unsigned numbers, use
// `carry_out` instead.*
// On FPGAs, you are much better off letting the CAD tool infer the
// add/subtract circuitry from the `+` or `-` operator itself, rather than
// structurally describing it in Boolean logic, as the latter may not get
// mapped to the fast, dedicated ripple-carry hardware. Wrapping all this into
// a module hides the width adjustments necessary to get a warning-free
// synthesis of carry logic, and enables correct carry and overflow
// calculations.
// Because we handle the carry bits ourselves and do everything through an
// unsigned addition, we don't depend on the tricky Verilog behaviour where
// all terms of an expression must be declared signed else the expression is
// silently evaluated as unsigned!
`default_nettype none
module Adder_Subtractor_Binary
#(
parameter WORD_WIDTH = 0
)
(
input wire add_sub, // 0/1 -> A+B/A-B
input wire carry_in,
input wire [WORD_WIDTH-1:0] A,
input wire [WORD_WIDTH-1:0] B,
output reg [WORD_WIDTH-1:0] sum,
output reg carry_out,
output wire [WORD_WIDTH-1:0] carries,
output reg overflow
);
localparam ZERO = {WORD_WIDTH{1'b0}};
localparam ONE = {{WORD_WIDTH-1{1'b0}},1'b1};
initial begin
sum = ZERO;
carry_out = 1'b0;
overflow = 1'b0;
end
// Extend the `carry_in` to the extended word width, as both signed (0 or -1)
// and unsigned (0 or 1) words, so we don't have width mismatches nor rely on
// sign extension, which is full of pitfalls, and would trigger useless
// warnings in the CAD tools.
wire [WORD_WIDTH-1:0] carry_in_extended_unsigned;
wire [WORD_WIDTH-1:0] carry_in_extended_signed;
Width_Adjuster
#(
.WORD_WIDTH_IN (1),
.SIGNED (0),
.WORD_WIDTH_OUT (WORD_WIDTH)
)
extend_carry_in_unsigned
(
.original_input (carry_in),
.adjusted_output (carry_in_extended_unsigned)
);
Width_Adjuster
#(
.WORD_WIDTH_IN (1),
.SIGNED (1),
.WORD_WIDTH_OUT (WORD_WIDTH)
)
extend_carry_in_signed
(
.original_input (carry_in),
.adjusted_output (carry_in_extended_signed)
);
// Depending on the value of `add_sub`, generate the bit-negation of `B` and
// the necessary offset for `B`'s 2's-complement arithmetic negation, and
// select the correct `carry_in` value. We do this separately to have the
// negated `B` available later for the calculations of the `carries` and of
// the `overflow`.
reg [WORD_WIDTH-1:0] B_selected = ZERO;
reg [WORD_WIDTH-1:0] negation_offset = ZERO;
reg [WORD_WIDTH-1:0] carry_in_selected = ZERO;
always @(*) begin
B_selected = (add_sub == 1'b0) ? B : ~B;
negation_offset = (add_sub == 1'b0) ? ZERO : ONE;
carry_in_selected = (add_sub == 1'b0) ? carry_in_extended_unsigned : carry_in_extended_signed;
end
// And add as usual, with subtraction expressed as `A+((~B)+1)`, so as to
// generate the correct `carries` for each bit position.
// Since the left-hand side is one bit wider to hold `carry_out`, all other
// terms are implicitly extended to that width (see Verilog LRM, IEEE
// 1364-2001, Section 4.4, "Expression bit lengths"). However, since I avoid
// implicit width extension as a way to reduce warnings and prevent bugs,
// let's prepend a zero to all the unsigned right-hand terms to make all
// widths match and force a simple, unsigned addition.
// We could have done this more concisely by first widening all terms to
// `WORD_WIDTH+1`, then selecting addition/subtraction in one line, but we
// need the possibly negated `B` later for the `carries` and `overflow`
// calculation.
always @(*) begin
{carry_out, sum} = {1'b0, A} + {1'b0, B_selected} + {1'b0, negation_offset} + {1'b0, carry_in_selected};
end
// Finally, recover the carry *into* each bit from the selected addition
// terms. The first bit of `carries` is the same as `carry_in`. We must do
// this here rather than in the enclosing module, since if you are
// subtracting, the negated `B` term is not externally available.
CarryIn_Binary
#(
.WORD_WIDTH (WORD_WIDTH)
)
per_bit
(
.A (A),
.B (B_selected),
.sum (sum),
.carryin (carries)
);
// And compute the signed overflow, which happens when the carry into and out
// from the MSB do not agree.
always @(*) begin
overflow = (carries [WORD_WIDTH-1] != carry_out);
end
endmodule