En circuitos digitales y computación se conoce el concepto de unidad lógica-aritmética. Este es un tipo de circuito digital que nos permite realizar operaciones aritméticas y lógicas. Se conoce con el acrónimo ALU u es el componente fundamental de la CPU (Central Processing Unit). El corazón de la ALU se basa en un sumador completo, permitiendo hacer operaciones básicas como las de adición, sustracción, o hasta rodar un número específico.
El artículo no se centra en definir más a fondo qué es la ALU. Se ha tomado en cuenta que el lector ya sabe cómo funciona. En este apartado trataremos de diseñar una unidad lógica aritmética que haga las siguientes funciones en VHDL.
Para esto vamos a diseñar una tabla de funciones en donde se mostrará qué operación debe hacer y cuáles serán sus salidas.
Tabla de Funciones:
sel(2:0) |
Función |
Salida |
000 |
Transfiere a |
a |
001 |
Suma |
a+b |
010 |
Resta |
a-b |
011 |
Resta |
b-a |
100 |
Invierte |
not a |
101 |
And |
a and b |
110 |
Or |
a or b |
111 |
Xor |
a xor b |
Debido a que necesitamos hacer 8 funciones, tendremos un vector de selección para que la alu sepa qué función hacer dependiendo de esa combinación. En este caso utilizaremos una ALU de cuatro bits. Adicional a esto, agregaré dos salidas que nos ayudarán en un futuro a poder implementar esta ALU a un microcontrolador dedicado. Estas salidas se denominan banderas y son las siguientes:
cf: Se encargará de presentar un uno a la salida en binario cuando se de préstamo o acarreo, esto es muy importante cuando se hace la sustracción y suma. Los acarreos y los préstamos no tienen ningún sentido en las operaciones aritméticas.
zf: Se encargará de indicarnos cuándo en la salida se produce un cero, es decir: “0000” en binario, cuando esto acontece la salida zf se activa.
A continuación presento mi código VHDL:
1 |
</span></p> <p><span class="clase-nuevo">library IEEE;</span><br /><span class="clase-nuevo"> use IEEE.STD_LOGIC_1164.ALL;</span><br /><span class="clase-nuevo"> use IEEE.STD_LOGIC_unsigned.all;</span><br /> <br /><span class="clase-nuevo"> entity alu_clase911 is</span><br /><span class="clase-nuevo"> port (alusel: in std_logic_vector(2 downto 0);</span><br /><span class="clase-nuevo"> a,b: in std_logic_vector(3 downto 0);</span><br /><span class="clase-nuevo"> cf,zf: out std_logic;</span><br /><span class="clase-nuevo"> salida: out std_logic_vector(3 downto 0)</span><br /><span class="clase-nuevo"> );</span><br /><span class="clase-nuevo"> end alu_clase911;</span><br /> <br /><span class="clase-nuevo"> architecture alu_clas911_arch of alu_clase911 is</span><br /><span class="clase-nuevo"> begin</span><br /><span class="clase-nuevo"> process(a,b,alusel)</span><br /><span class="clase-nuevo"> variable coxsalida: std_logic_vector(4 downto 0); --Definimos una variable para manipular la salida de nuestra ALU</span><br /><span class="clase-nuevo"> variable cfv,zfv: std_logic; --Definimos dos variables para manejar el estado de los flags en el proceso</span><br /><span class="clase-nuevo"> variable yv: std_logic_vector(3 downto 0); --Definimos nuestra variable para manejar el valor de salida</span><br /><span class="clase-nuevo"> begin</span><br /><span class="clase-nuevo"> cf <= '0';</span><br /><span class="clase-nuevo"> coxsalida := "00000";</span><br /><span class="clase-nuevo"> zfv := '0';</span><br /><span class="clase-nuevo"> case alusel is </span><br /><span class="clase-nuevo"> when "000" => </span><br /><span class="clase-nuevo"> yv := a; --Transferimos a</span><br /><span class="clase-nuevo"> when "001" =></span><br /><span class="clase-nuevo"> coxsalida := ('0'&a)+('0'&b); --a+b</span><br /><span class="clase-nuevo"> yv := coxsalida(3 downto 0);</span><br /><span class="clase-nuevo"> cfv := coxsalida(4);</span><br /><span class="clase-nuevo"> cf <= cfv;</span><br /><span class="clase-nuevo"> when "010" => </span><br /><span class="clase-nuevo"> coxsalida := ('0'&a) -('0'&b); --a-b</span><br /><span class="clase-nuevo"> yv := coxsalida(3 downto 0);</span><br /><span class="clase-nuevo"> cfv := coxsalida(4);</span><br /><span class="clase-nuevo"> cf <= cfv;</span><br /><span class="clase-nuevo"> when "011" => </span><br /><span class="clase-nuevo"> coxsalida := ('0'&b)-('0'&a); --b-a</span><br /><span class="clase-nuevo"> yv := coxsalida(3 downto 0);</span><br /><span class="clase-nuevo"> cfv := coxsalida(4);</span><br /><span class="clase-nuevo"> cf <= cfv;</span><br /><span class="clase-nuevo"> when "100" =></span><br /><span class="clase-nuevo"> yv := not a; --NOT</span><br /><span class="clase-nuevo"> when "101" =></span><br /><span class="clase-nuevo"> yv := a and b; --AND</span><br /><span class="clase-nuevo"> when "110" =></span><br /><span class="clase-nuevo"> yv := a or b; --OR</span><br /><span class="clase-nuevo"> when "111" =></span><br /><span class="clase-nuevo"> yv := a xor b; --XOR</span><br /><span class="clase-nuevo"> when others =></span><br /><span class="clase-nuevo"> yv := a;</span><br /><span class="clase-nuevo"> end case;</span><br /><span class="clase-nuevo"> for i in 0 to 3 loop</span><br /><span class="clase-nuevo"> zfv := zfv or coxsalida(i); --En esta parte zfv = 0 si todos los coxsalida(i) = 0.</span><br /><span class="clase-nuevo"> end loop;</span><br /><span class="clase-nuevo"> salida <= yv;</span><br /><span class="clase-nuevo"> zf <= not zfv;</span><br /><span class="clase-nuevo"> end process;</span><br /><span class="clase-nuevo"> end alu_clas911_arch;</span></p> <p><span class="clase-nuevo"> |
Imagen: Wikipedia