Hace unos meses subimos en ejemplo de como hacer una ALU en VHDL y simularla utilizando EdaPlayground. Se me habia olvidado complemamente escribir el articulo correspondiente, asi que aqui lo teneis. En el hablaremos sobre que es una ALU y como crear una sencilla en VHDL y simularla.

¿Qué es una ALU?

Una ALU es una Unidad Aritmetico Logica. Suele ser el elemento central de un microprocesador y es la encargada de sumar, restar, a veces multiplicar y dividir y de las operaciones logicas como las AND, OR y NOT.

Una ALU tomas dos operandos y un codigo de operacion que le indica que debe de hacer con ellos y en su salida nos da el resultado de dicha operacion.

Una ALU de 8 bits en VHDL

En el video que hemos subido al canal, hemos creado una ALU de 8 bits capaz de hacer las siguientes operaciones:

  • Sumar. A+B
  • Restar: A-B
  • Operacion AND: A AND B
  • Operacion OR: A OR B

Estas operaciones son las mas sencillas que puede hacer una ALU ya que se pueden realizar en un solo ciclo de reloj. En caso de querer ampliar la ALU para realizar multiplicaciones o divisiones, la ALU tardaria mas de un ciclo de reloj en realizar dichas operaciones, lo cual cambiaria totalmente el diseño.

En ese caso deberiamos tener una entrada de validar el dato y un bit de salida que nos diga que lo que tenemos es el dato correcto. En general los multiplicadores son elementos complejos, (los divisores aun mas) y los bloques que realizan la multiplicacion son proporcionados directamente por los fabricantes de FPGA.

Nuestra ALU no va a tener flags, es decir no va a indicar en la salida condiciones de estado como un overflow o carry de salida. Recordad que cuando operamos con un numero finito de bits, por ejemplo 8, podemos sumar numeros hasta 9 bits. Si nos pasamos podemos tener acarreo, overflow o ambos. El overflow se dara cuando tenemos numeros representados en complemento a 2.

Sin mas os dejamos el video para que veais todo el proceso de diseño y la simulación.

Código de una ALU de 8 bits en VHDL

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity alu is
  port (
         a_i      : in std_logic_vector(7 downto 0);
         b_i      : in std_logic_vector(7 downto 0);
         opcode_i : in std_logic_vector(1 downto 0);
         d_o      : out std_logic_vector(7 downto 0)
  );
end entity;
architecture RTL of alu is
begin
  process(a_i,b_i,opcode_i)
  begin
    case opcode_i is
      when "00" =>
        d_o  <= std_logic_vector(unsigned(a_i) + unsigned(b_i));
      when "01" =>
        d_o  <= std_logic_vector(unsigned(a_i) - unsigned(b_i));
      when "10" =>
        d_o <= a_i and b_i;
      when others =>
        d_o <= a_i or b_i;
    end case;
  end process;
end architecture;
library IEEE;
use IEEE.std_logic_1164.all;

entity test is
end entity;

architecture tb of test is
component alu is
  port (
         a_i      : in std_logic_vector(7 downto 0);
         b_i      : in std_logic_vector(7 downto 0);
         opcode_i : in std_logic_vector(1 downto 0);
         d_o      : out std_logic_vector(7 downto 0)
  );
end component;

signal  a_s      : std_logic_vector(7 downto 0);
signal  b_s      : std_logic_vector(7 downto 0);
signal  opcode_s : std_logic_vector(1 downto 0);
signal  d_s      : std_logic_vector(7 downto 0);

begin
  UUT: alu port map(a_s, b_s, opcode_s, d_s);
  a_s <= "00010001", "01100101" after 5 ns;
  b_s <= "00100011", "00000010" after 5 ns, "00111001" after 20 ns;
  opcode_s <= "00", "01" after 5 ns;

end architecture;