So far in this course, we have been considering combinational logic circuits whose outputs are formed by combining individual input signals – the signals have been called A, B, C, etc., and we have considered them as unrelated signals arising from independent sources like switches or buttons. The logic functions acting on those inputs have been described using truth tables, logic equations, minterm equations, or written descriptions that define the outputs for every possible combination of inputs. These representation methods work well for simpler circuits that operate on independent inputs, but they are unwieldly for larger circuits that operate on groups of signals organized as busses.
Here, we consider combinational logic circuits that act on busses, rather than individual signals. Recall that busses are groups of related signals that are regarded as a single logical unit transporting a binary number, instead of a collection of independent signals. Even though we will regard the input signals as bits in a binary number, they are nevertheless logic signals, and we know how to design logic circuits that operate on logic signals. In this case, the circuits we will design combine input signals to produce output signals that are in accordance with the rules of addition, subtraction, and multiplication.
Before you begin, you should:
- Be confident in implementing combinational and seqential circuits in Vivado;
- Be confident in using the Xilinx simulator.
After you’re done, you should:
- Understand the operation of adders, multipliers, subtractors, and comparators;
- Be comfortable designing circuits using structural Verilog.
Circuits that operate on bus inputs are typically too large to represent using the methods developed so far. Consider for example a circuit that adds two 8-bit binary number inputs to produce an 8-bit binary number output. A truth table used to represent the behavioral requirements of this circuit would need (2 x 8), or 16 input columns to represent all 2^16 (= 65,536) possible input combinations, with the eight output columns showing the sum of the two 8-bit input numbers. Clearly, this truth table is far too large to produce in its entirety.
Not only is the truth table too large to produce, it’s also too large to implement using the methods we have developed so far. We need a new design method to tackle these larger circuits. The only practicable way to approach a design like this is to “divide and conquer”, and find smaller, simpler designs that can address part of the requirement, and then build up the overall solution based on the simpler components.
In the case of a circuit that operates on busses, one approach is to break up the overall design into a collection of smaller circuits that each operate on a pair of bits, and then to use as many of the bit-pair circuits as are needed to address the overall n-bit circuit. Of course, the goal is to design just one circuit that operate on any pair of bits, and then to replicate that exact same circuit n times. This is called the “bit slice” design method.
Adding binary numbers seems a different and more abstract problem than combining logic signals using simple logic gates. But really, arithmetic circuits are no different than the logic circuits we have been working with – they just have more inputs and more outputs. As the truth table above shows, a 16-input, 8-output combinational logic circuit can be defined, with the eight output logic functions forming the eight bits of a binary number that is the sum if the two inputs.
But there is a difference in context. With arithmetic circuits like an adder, there is a stronger association between the input 1’s and 0’s, and the abstraction to a logical binary number (instead of just individual signals). If you don’t focus on this abstraction, and just think of the inputs and outputs as signals, then the adder design is no different than any other combinational logic circuit design (apart from the larger truth table). The fact that we’re looking at signals as bits in binary numbers doesn’t change the design methods used to find an efficient circuit.
1. 4-bit CLA
Define a 4-bit CLA using structural Verilog (i.e., define a module for the bit-slice component and a module for the CPGN network, and then connect four bit-slice modules to the CPGN). Simulate your circuit to verify its function, and then program it into the Boolean board. Use eight slide switches to define the inputs, and display the output on two digits of a seven-segment display.
Create an 8-bit adder using the Verilog addition operator ("+"). Connect the adder’s inputs to two banks of eight slide switches. Connect the adder’s output to two digits of the seven-segment display. Since the inputs are 8-bit binary numbers, you should use a seven-segment controller than can generate hex digits as well as BCD digits.
reg [7:0] op1, op2; always @ (posedge(clk)) begin if (btn) op1 <= sw; if (btn) op2 <= sw; end
Configure the adder to be an adder/subtractor by including a circuit that can change one of the operand inputs into its negated two’s-compliment form (i.e., invert all the bits and add one). Use a pushbutton to select between addition and subtraction.
Drive two additional LEDs as well – one to indicate whether the output from adder/subtractor was negative, and the other to indicate if the result is inaccurate due to overflow or underflow. Verify your circuit’s function by applying several test cases.
Finally, modify the circuit by adding a binary-to-BCD conversion circuit so that it is easier to read the seven-segment display. You can find information on the bin2bcd circuit (including complete working code) in one of the background topic documents.
3. Behavioral Multiplier
Define an 8-bit multiplier using behavioral Verilog (use the “ * ” operator). Connect the multiplier inputs to two banks of eight slide switches as before. Connect the 16-bit result to the four digits of the seven-segment display using the bin2bcd converter. Check several test cases to make sure your multiplier is working correctly.
Define a 16-bit register and a 16-bit comparator in Verilog. Connect the output of your 8-bit multiplier to the 16-bit register and to one input of the comparator. Use a pushbutton to load the register. Use the comparator to compare an initial output of the multiplier (captured in the 16-bit register) to a subsequent output. Connect the LT, EQ, and GT comparator outputs to three LEDs, and verify your comparator’s function.