|
ALU pracuje na principu klasických procesorových ALU, kdy pro provedení operace je potřeba jednak kód vstupního operandu a dále jeden až tři vstupní proměnné.
Vstupy do ALU jsou zde max. dvě 8-mi bitová slova (A a B) a Carry (Cin). (Zdrojový kód lze snadno modifikovat pro ALU téměř libovolné šířky slova, pouhou změnou hodnoty proměnné N.)
TABULKA FUNKCÍ
KOMENTOVANÝ ZDROJOVÝ KÓD ALU - definice použitých knihoven a jejich podčástí. -- ALU library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; Definice entity ALU a vstupních (A, B - vstupní data, OP - operace, Cin - Carry in) a výstupních (Z - výstup, Cout - Carry out, OVF - overflow) signálů. N je pouze konstanta určující délku slova. entity ALU is generic ( N : in integer := 8); port ( A, B : in std_logic_vector(N-1 downto 0); OP : in std_logic_vector(3 downto 0); Cin : in std_logic; Cout, OVF : out std_logic; Z : out std_logic_vector(N-1 downto 0)); end ALU; Definice vlastní struktury (architektury) ALU. Subtype unsigned je dodefinován jako std_logic_vector, pouze pro přehlednost ve zdrojovém kódu. Následuje definice, zde jediného, jakoby paralelního procesu. Proměnné variable slouží pouze pro potřeby uchovávání vnitřních stavů VHDL, nejedná se tedy o signály, které se implementují na čip. architecture RTL of ALU is -- signal A, B : std_logic_vector(N-1 downto 0); subtype unsigned is std_logic_vector; begin proc : process (A, B, Cin, OP) variable temp1, temp2, result : unsigned(N downto 0); begin Z <= (Z'range => '0'); Cout <= '0'; OVF <= '0'; result := (result'range => '0'); temp1 := (temp1'range => '0'); temp2 := (temp2'range => '0'); -- zakladni operace -- logicke operace nebude carry ovlivnovat case OP is when "0000" => Z <= (Z'range => Cin); when "0001" => Z <= A and B; when "0010" => Z <= A or B; when "0011" => Z <= not A; when "0100" => Z <= not B; when "0101" => Z <= A xor B; when "0110" => Z <= A nand B; when "0111" => Z <= A nor B; when others => null; end case; Aritmetické operace byly zapsány s ohledem na minimalizaci množství implementovaných hradel na výsledném čipu. (Minimalizace je pouze mnou odhadovaná, syntéza čipu nebyla testována.) Operace byly rozděleny do čtyř skupin, kde první dvě jsou plnou implementací funkce odečítání (zde A-B+Cin a A-B-Cin), třetí skupina je sčítání A+X+Cin a čtvrtá je A+X-Cin. Možnosti takto rozdělit funkce bylo dosaženo vhodnou optimalizací volby operačních kódů instrukcí. Aritmetické přeplnění se indikuje tehdy, je-li výsledek součtu dvou záporných čísel číslo kladné, nebo je-li součet dvou kladných čísel záporný. V tom případě bude indikátor OVF=1. (Doplňkový kód) Odvození fce OVF. Cout je přetečení do N+1 bitu. -- ALU pouziva doplnkovy kod temp1 := '0' & unsigned(A); --plne operandy musi byt prvni if OP = "1000" then -- => Z <= A-B+Cin; temp2 := '0' & unsigned(B); result := temp1 - temp2 + Cin; -- OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) -- or ((temp1(N-1) and temp2(N-1)) and not(result(N-1)); OVF <= (temp1(N-1) xor temp2(N-1)) and (temp1(N-1) xor result(N-1)); Z <= result((N-1) downto 0); elsif OP = "1100" then -- => Z <= A-B-Cin; temp2 := '0' & unsigned(B); result := temp1 - temp2 - Cin; -- OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) -- or ((temp1(N-1) and temp2(N-1)) and not(result(N-1)); OVF <= (temp1(N-1) xor temp2(N-1)) and (temp1(N-1) xor result(N-1)); Z <= result((N-1) downto 0); elsif OP(3 downto 2) = "10" then -- + Cin case OP(1 downto 0) is -- scitani when "01" => -- Z <= A+B+Cin; temp2 := '0' & unsigned(B); when "10" => -- Z <= A+A+Cin; temp2 := '0' & unsigned(A); when "11" => -- Z <= A+Cin; temp2 := (temp2'range => '0'); when others => null; end case; result := temp1 + temp2 + Cin; -- OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) -- or ((temp1(N-1) and temp2(N-1)) and not(result(N-1)); OVF <= ((not (temp1(N-1) xor temp2(N-1))) and (temp1(N-1) xor result(N-1))); Z <= result((N-1) downto 0); elsif OP(3 downto 2) = "11" then -- -Cin case OP(1 downto 0) is when "01" => -- Z <= A+B-Cin; temp2 := '0' & unsigned(B); when "10" => -- Z <= A+A-Cin; temp2 := '0' & unsigned(A); when "11" => -- Z <= A-Cin; temp2 := (temp2'range => '0'); when others => null; end case; result := temp1 + temp2 - Cin; -- OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) -- or ((temp1(N-1) and temp2(N-1)) and not(result(N-1)); OVF <= ((not (temp1(N-1) xor temp2(N-1))) and (temp1(N-1) xor result(N-1))); Z <= result((N-1) downto 0); end if; Cout <= result(N); end process; end RTL; Velmi podstatná část kódu, sloužící pro testování správné funkce ALU. -- testovani ALU library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; entity TestALU_B is end TestALU_B; architecture BEH of TestALU_B is component ALU generic ( N : in integer := 8); port ( A, B : in std_logic_vector(N-1 downto 0); OP : in std_logic_vector(3 downto 0); Cin : in std_logic; Cout, OVF : out std_logic; Z : out std_logic_vector(N-1 downto 0) ); end component; constant PERIOD : time := 20 ns; constant N : integer := 8; signal A : std_logic_vector((N - 1) downto 0); signal B : std_logic_vector((N - 1) downto 0); signal S : std_logic_vector(3 downto 0); signal Cin : std_logic; signal Cout : std_logic; signal OVF : std_logic; signal Z : std_logic_vector((N - 1) downto 0); begin ALU0 : ALU generic map (N => N) port map (A => A, B => B, OP => S, Cin => Cin, Cout => Cout, OVF => OVF, Z => Z); process variable Aint : integer range 0 to 255 := 3; variable Bint : integer range 0 to 255 := 230; begin for i in 0 to 1 loop Aint := (Aint + 5) mod 255; Bint := (Bint + 53) mod 255; A <= to_stdlogicvector(Aint, N); B <= to_stdlogicvector(Bint, N); if (i = 0) then Cin <= '0'; for k in 0 to 15 loop S <= to_stdlogicvector(k, 4); wait for PERIOD; end loop; else Cin <= '1'; for k in 0 to 15 loop S <= to_stdlogicvector(k, 4); wait for PERIOD; end loop; end if; end loop; wait for 2 * PERIOD; end process; end BEH; Spuštění vlastního testu. Pokud byste měli ve zdrojovém kódu více struktur ALUX, které byste chtěli otestovat, dopíší se zde. library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; configuration BEH of TestALU_B is for BEH for ALU0 : ALU use entity work.ALU(RTL); end for; end for; end BEH; To je tedy celý, komentovaný zdrojový kód, jeho čistou podobu si můžete stáhnout na http://cs.felk.cvut.cz/~xpribyla/alu/. |