VHDL: diseñando una unidad aritmético lógica

VHDL diseñando una ALU.

Aquí dejo otro code-kata en VHDL, esta vez de una ALU básica con 8 modos de funcionamiento: suma, resta, multiplicación, exponente a 2, complemento a 2, and, or y not. ALU son las siglas de Arithmetic Logic Unit. Se trata de un componente básico de los procesadores. Resumiendo, es un circuito que recibe unas entradas y saca unas señales de salida, destinado a hacer operaciones aritméticas o lógicas como pueden ser la suma, resta, multiplicación, and, or, etcétera.

En esta ALU tenemos 3 entradas: 2 de ellas son los números, y la tercera entrada es el modo de funcionamiento (la operación que queremos que haga). En las salidas le he puesto 3 salidas: 1 es el resultado básico para la mayoría de estas operaciones, 1 resultado de multiplicación que es un vector de bits más largo, y una salida de estado que aunque no se en éste código usa la idea es dar una señal de éxito 0 o de error 1.

El código de la ALU

Para esta ALU sólo hay 8 modos de funcionamiento, seleccionados con la entrada mode de 3 bits, el resultado funcionando ha quedado algo tal que así:

-- ALU -- -- 000 A + B -- 001 A - B -- 010 A * B -- 011 A^2 -- 100 -A -- 101 A and B -- 110 A or B -- 111 not A library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity alu is port ( status : out std_logic; result : out std_logic_vector (7 downto 0); resultMult : out std_logic_vector (15 downto 0); mode : in std_logic_vector (2 downto 0); a : in std_logic_vector (7 downto 0); b : in std_logic_vector (7 downto 0) ); end entity; architecture arch_alu of alu is begin -- Este process se ejecuta cada vez que cambian las señales -- a las que es sensible: mode, a y/o b. main_process: process (mode, a, b) begin if mode = "000" then result <= std_logic_vector(unsigned(a) + unsigned(b)); resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; elsif mode = "001" then result <= std_logic_vector(unsigned(a) - unsigned(b)); resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; elsif mode = "010" then result <= "UUUUUUUU"; resultMult <= std_logic_vector(signed(a) * signed(b)); status <= '0'; elsif mode = "011" then result <= "UUUUUUUU"; resultMult <= std_logic_vector(signed(a) * signed(a)); status <= '0'; elsif mode = "100" then result <= std_logic_vector(-signed(a)); resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; elsif mode = "101" then result <= a and b; resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; elsif mode = "110" then result <= a or b; resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; elsif mode = "111" then result <= not a; resultMult <= "UUUUUUUUUUUUUUUU"; status <= '0'; end if; end process; end architecture;

El código del banco de pruebas

Y el banco de pruebas, esta vez generando bucles para algunas de las posibles combinaciones de señales de entrada:

library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity alu_tb is end entity; architecture arch_alu_tb of alu_tb is component alu is port ( status : out std_logic; result : out std_logic_vector (7 downto 0); resultMult : out std_logic_vector (15 downto 0); mode : in std_logic_vector (2 downto 0); a : in std_logic_vector (7 downto 0); b : in std_logic_vector (7 downto 0) ); end component; signal testStatus : std_logic; signal testResult : std_logic_vector (7 downto 0); signal testResultMult : std_logic_vector (15 downto 0); signal testMode : std_logic_vector (2 downto 0); signal testA : std_logic_vector (7 downto 0); signal testB : std_logic_vector (7 downto 0); begin testing_unit: alu port map ( status => testStatus, result => testResult, resultMult => testResultMult, mode => testMode, a => testA, b => testB ); generate_signals : process begin report "Comienza la simulación."; -- Simulando números pequeños -- en los 8 modos disponibles for i in 0 to 2 loop for j in 0 to 2 loop for k in 0 to 7 loop report integer'image(i) & " " & integer'image(j) & " " & integer'image(k); testA <= std_logic_vector(to_unsigned(i, 8)); testB <= std_logic_vector(to_unsigned(j, 8)); testMode <= std_logic_vector(to_unsigned(k, 3)); wait for 10 ns; end loop; end loop; end loop; -- Simulando números grandes -- en los 8 modos disponibles for i in 253 to 255 loop for j in 253 to 255 loop for k in 0 to 7 loop report integer'image(i) & " " & integer'image(j) & " " & integer'image(k); testA <= std_logic_vector(to_unsigned(i, 8)); testB <= std_logic_vector(to_unsigned(j, 8)); testMode <= std_logic_vector(to_unsigned(k, 3)); wait for 10 ns; end loop; end loop; end loop; report "Finaliza la simulación."; wait; end process; end architecture;

Se simulan todos los modos de funcionamientos, pero los números de entradas van de los rangos 0 a 2 y 253 a 255 en decimal. Queda pendiente el hacer comprobaciones usando assert y report para que esté completo.. dejo esto para otro post.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *