An arithmetic logic unit (ALU) is a component that performs operations on (usually) two or more sets of inputs, and outputs results. The operation performed is designated by an
Our ALU will start simple, and we’ll add more operations over time. First, let’s build an add/sub unit. I already have an adder, which can be used to subtract by swapping some signals: In single-rail (standard) logic, to subtract instead of add, the second input to the adder is inverted and the carry bit is set – in NCL, we invert the input by swapping
The swapper operates as the following equations
output.0 = input.0*swap.0 + input.1*swap.1 output.1 = input.1*swap.0 + input.0*swap.1
These can be implemented with THxor0 gates:
output.0 = THxor0(input.0, swap.0, input.1, swap.1) output.1 = THxor0(input.1, swap.0, input.0, swap.1)
Our add/sub module will have these on every bit on input to the adder, with iC having the
swap signal fed directly into it.
Swap will be exposed in the component’s port as the add/subtract selector:
iA, blue is
iB, and red is
iC on the Adder. If
Control is asserted (
iB will be inverted and the carry in will be asserted as well, resulting in subtraction.
This module actually fulfills the interface of an ALU by itself, it has data inputs, and a opcode. When we add more operations, we’ll wrap it all up in a ALU block and add a MUX.
To implement this in VHDL, we need 1 Adder module and
use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.ncl.all; entity AddSub is generic(NumBits : integer := 4); port(iA : in ncl_pair_vector(0 to NumBits-1); iB : in ncl_pair_vector(0 to NumBits-1); Operation : in ncl_pair; oS : out ncl_pair_vector(0 to NumBits-1); oC : out ncl_pair); end AddSub; architecture structural of AddSub is -- iB into adder, potentially inverted from entity input signal adder_iB : ncl_pair_vector(0 to NumBits-1); begin plainAdder: Adder generic map(NumAdderBits => NumBits) port map(iC => Operation, iA => iA, iB => adder_iB, oS => oS, oC => oC); bits: for iBit in 0 to NumBits-1 generate inverter0: THxor0 -- DATA0, Potentially inverted port map(A => iB(iBit).DATA0, B => Operation.DATA0, C => iB(iBit).DATA1, D => Operation.DATA1, output => adder_iB(iBit).DATA0); inverter1: THxor0 -- DATA1, Potentially inverted port map(A => iB(iBit).DATA0, B => Operation.DATA1, C => iB(iBit).DATA1, D => Operation.DATA0, output => adder_iB(iBit).DATA1); end generate; end structural;
The 2-bit case above is a little small, but it runs quickly. I have tested the module up to 6 bits. To change the number of bits, change the number at the top of the test script. The first several cases (interpreted to decimal):
This test script does check the sum output, but it does not verify the carry out.