-
Notifications
You must be signed in to change notification settings - Fork 43
/
Bit_Reducer.v
171 lines (141 loc) · 6.23 KB
/
Bit_Reducer.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//# Boolean Bit Reducer
// This module generalizes the usual 2-input Boolean functions to their
// n-input reductions, which are interesting and useful:
// * Trivially calculate *any of these* (OR) or *all of these* (AND) conditions and their negations.
// * Calculate even/odd parity (XOR/XNOR)
// * Selectively invert some of the inputs and you can decode any intermediate condition you care to.
// Beginners can use this module to implement any combinational logic while
// knowing a minimum of Verilog (no always blocks, no blocking/non-blocking
// statements, only wires, etc...).
// Experts generally would not use this module. It's far simpler to [express
// the desired conditions directly](./verilog.html#boolean) in Verilog.
// However, there are a few reasons to use it:
// * It will keep your derived schematics clean of multiple random little gates, and generally preserve the schematic layout.
// * If there is a specific meaning to this reduction, you can name the module descriptively.
// * It will make clear which logic gets moved, in or out of that level of hierarchy, by optimization or retiming post-synthesis.
//## Differences with Verilog Reduction Operators
// The specification of reduction operators in Verilog (2001 or SystemVerilog)
// contains an error which does not perform a true reduction when the Boolean
// operator in the reduction contains an inversion (NOR, NAND, XNOR). Instead,
// the operator will perform a non-inverting reduction (e.g.: XOR), then
// invert the final result. For example, `A = ~^B;` (XNOR reduction) should
// perform the following:
// <pre>(((B[0] ~^ B[1]) ~^ B[2]) ~^ B[3) ... </pre>
// but instead performs the following, which is not always equivalent:
// <pre>~(B[0] ^ B[1] ^ B[2] ^ B[3 ...)</pre>
// To implement the correct logical behaviour, we do the reduction in a loop
// using the alternate implementation described in the [Word
// Reducer](./Word_Reducer.html) module. The differences were
// [spotted](https://twitter.com/wren6991/status/1259098465835106304) by Luke
// Wren ([@wren6991](https://twitter.com/wren6991)).
//## Errors, Verilog Strings, and Linter Warnings
// There's no clean way to stop the CAD tools if the `OPERATION` parameter is
// missing or incorrect. Here, the logic doesn't get generated, which will
// fail pretty fast...
// The `OPERATION` parameter also reveals how strings are implemented in
// Verilog: just a sequence of 8-bit bytes. Thus, if we give `OPERATION`
// a value of `"OR"` (16 bits), it must first get compared against `"AND"` (24
// bits) and `"NAND"` (32 bits). The Verilator linter throws a width mismatch
// warning at those first two comparisons, of course. Width warnings are
// important to spot bugs, so to keep them relevant we carefully disable width
// checks only during the parameter tests.
`default_nettype none
module Bit_Reducer
#(
parameter OPERATION = "",
parameter INPUT_COUNT = 0
)
(
input wire [INPUT_COUNT-1:0] bits_in,
output reg bit_out
);
initial begin
bit_out = 1'b0;
end
// First, initialize the partial reduction storage. Each partial reduction
// must be stored in its own storage, else we describe a broken combinational
// loop.
// To make the code clearer, `partial_reduction` is read and written in
// different `always` blocks, so the linter is confused and sees a potential
// combinational loop, which doesn't exist here because of the non-overlapping
// indices. So we disable that warning here.
// verilator lint_off UNOPTFLAT
reg [INPUT_COUNT-1:0] partial_reduction;
// verilator lint_on UNOPTFLAT
integer i;
initial begin
for(i=0; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = 1'b0;
end
end
// Then prime the partial reductions with the first input, and read out the
// result at the last partial reduction.
always @(*) begin
partial_reduction[0] = bits_in[0];
bit_out = partial_reduction[INPUT_COUNT-1];
end
// Finally, select the logic to instantiate based on the `OPERATION`
// parameter. Each partial reduction is the combination of the previous
// reduction and the current corresponding input bit.
generate
// verilator lint_off WIDTH
if (OPERATION == "AND") begin : gen_and
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = partial_reduction[i-1] & bits_in[i];
end
end
end
else
// verilator lint_off WIDTH
if (OPERATION == "NAND") begin : gen_nand
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = ~(partial_reduction[i-1] & bits_in[i]);
end
end
end
else
// verilator lint_off WIDTH
if (OPERATION == "OR") begin : gen_or
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = partial_reduction[i-1] | bits_in[i];
end
end
end
else
// verilator lint_off WIDTH
if (OPERATION == "NOR") begin : gen_nor
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = ~(partial_reduction[i-1] | bits_in[i]);
end
end
end
else
// verilator lint_off WIDTH
if (OPERATION == "XOR") begin : gen_xor
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = partial_reduction[i-1] ^ bits_in[i];
end
end
end
else
// verilator lint_off WIDTH
if (OPERATION == "XNOR") begin : gen_xnor
// verilator lint_on WIDTH
always @(*) begin
for(i=1; i < INPUT_COUNT; i=i+1) begin
partial_reduction[i] = ~(partial_reduction[i-1] ^ bits_in[i]);
end
end
end
endgenerate
endmodule