library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SimpleALU is
port(
-- inputs
S : in std_logic_vector (2 downto 0);
A : in std_logic_vector (2 downto 0);
B : in std_logic_vector (2 downto 0);
-- outputs
Q : out std_logic_vector (4 downto 0);
Z : out std_logic_vector (3 downto 0);
C : out std_logic;
O : out std_logic
);
-- types
type AdderResult is
record
q : std_logic;
c : std_logic;
end record AdderResult;
-- function prototypes
function Invert(x : std_logic_vector) return std_logic_vector;
function FullAdder(a,b,c : std_logic) return AdderResult;
function Add(x,y : std_logic_vector) return std_logic_vector;
function TwosCompliment(x : std_logic_vector) return std_logic_vector;
function Subtract(x,y : std_logic_vector) return std_logic_vector;
end SimpleALU;
architecture rtl of SimpleALU is
--================================================================================
--= Functions
--================================================================================
-- Invert
-- runs an xor operation on all bits of the vector
function Invert(x : std_logic_vector) return std_logic_vector is
variable mask : std_logic_vector(x'high downto 0) := (others => '1'); -- mask of all 1's of the length of the source
begin
return x xor mask; -- return the argument xor'd with the mask
end;
-- FullAdder
-- binary full adder with a,b and carry input; returns custom structure
-- returning result bit (q) and carry bit (c).
function FullAdder(a,b,c : std_logic) return AdderResult is
variable result : AdderResult;
begin
-- calculate the return bit value
result.q := a xor b xor c;
-- calculate if a carry has occured
result.c := (a and b) or (c and (a xor b));
return result;
end;
-- Add
-- adds two logic vectors together and returns a vector one larger than
-- the largest to hold the extra bit of data (carry)
function Add(x,y : std_logic_vector) return std_logic_vector is
variable temp : std_logic_vector(x'high+1 downto 0) := (others => '0');
variable ret : AdderResult;
variable c : std_logic := '0';
begin
-- make sure the input vectors are the same length
assert x'high = y'high report "input vectors must be of equal length (x:" & integer'image(x'high) & ", y:" & integer'image(y'high) & ")";
-- loop through each bit of the vectors and add them together with carry
for n in 0 to x'high loop
ret := FullAdder(x(n), y(n), c); -- add the two bits together with the previous carry
temp(n) := ret.q; -- store the resulting bit in temp (return var)
c := ret.c; -- store the new carry value for the next iteration
end loop;
temp(x'high+1) := c; -- store the last carry flag in the final bit of the result
return temp;
end;
-- TwosCompliment
function TwosCompliment(x : std_logic_vector) return std_logic_vector is
variable one : std_logic_vector(x'high downto 0) := (0 => '1', others => '0');
variable tmp : std_logic_vector(x'high downto 0);
begin
-- return (x inverted plus one)
tmp := Invert(x);
return Add(tmp, one)(x'high downto 0);
end;
-- Subtract
function Subtract(x,y : std_logic_vector) return std_logic_vector is
variable tmp : std_logic_vector(x'high+1 downto 0);
variable ret : std_logic_vector(x'high+1 downto 0);
begin
tmp := TwosCompliment('0' & y);
ret := Add('0' & x, tmp)(x'high+1 downto 0);
return ret;
end;
--================================================================================
--= Signals
--================================================================================
--================================================================================
--= Architecture Body
--================================================================================
signal temp : std_logic_vector(3 downto 0) := (others => '0');
signal tmp2 : AdderResult;
begin
--Q <= Add(A, B); --works
--Q <= '0' & TwosCompliment(A); -- works
Q <= Add('0' & A, TwosCompliment('0' & B))(3 downto 0); -- doesn't work
--Q <= Add('0' & A, '0' & B)(3 downto 0); -- doesn't work
end rtl;