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.