AFON // радиотехник affonya@mail.ru
← Проекты на VHDL

Проект 25. Арифметико-логическое устройство

АЛУ выполняет восемь операций над двумя числами и выставляет флаги нуля, переноса и знака. Это вычислительное ядро любого процессора.

Задача

Выполнить одну из восьми операций над парой чисел и выдать флаги.

Тип схемы: Комбинационная схема с выбором операции.
Модуль: alu. Среда: Quartus, Vivado, ISE или свободный GHDL для моделирования. Теорию по языку смотрите в статье VHDL — язык описания аппаратуры, по самим микросхемам — на странице ПЛИС.

Алгоритм

  1. Объявить результат на разряд шире операндов — старший разряд станет переносом.
  2. Оператором case выбрать операцию по коду.
  3. Взять младшие разряды результата как выходное значение.
  4. Сформировать флаги: ноль, перенос и знак.

Код на VHDL

Код проверен компилятором GHDL: проходит анализ и элаборацию без ошибок и предупреждений. Скачать: v25.vhd

--=====================================================
-- Проект 25. Арифметико-логическое устройство
-- Восемь операций над двумя числами с флагами
-- нуля, переноса и знака.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity alu is
    generic (
        WIDTH : integer := 8
    );
    port (
        a, b   : in  std_logic_vector(WIDTH-1 downto 0);
        op     : in  std_logic_vector(2 downto 0);      -- код операции
        result : out std_logic_vector(WIDTH-1 downto 0);
        zero   : out std_logic;
        carry  : out std_logic;
        neg    : out std_logic
    );
end entity alu;

architecture rtl of alu is
    signal res_ext : unsigned(WIDTH downto 0);          -- на разряд шире для переноса
    signal res     : unsigned(WIDTH-1 downto 0);
begin
    process (a, b, op)
    begin
        case op is
            when "000" => res_ext <= ('0' & unsigned(a)) + ('0' & unsigned(b));  -- сложение
            when "001" => res_ext <= ('0' & unsigned(a)) - ('0' & unsigned(b));  -- вычитание
            when "010" => res_ext <= '0' & (unsigned(a) and unsigned(b));
            when "011" => res_ext <= '0' & (unsigned(a) or  unsigned(b));
            when "100" => res_ext <= '0' & (unsigned(a) xor unsigned(b));
            when "101" => res_ext <= '0' & (not unsigned(a));
            when "110" => res_ext <= '0' & (unsigned(a(WIDTH-2 downto 0)) & '0'); -- сдвиг влево
            when others=> res_ext <= '0' & ('0' & unsigned(a(WIDTH-1 downto 1))); -- сдвиг вправо
        end case;
    end process;

    res    <= res_ext(WIDTH-1 downto 0);
    result <= std_logic_vector(res);
    carry  <= res_ext(WIDTH);
    zero   <= '1' when res = 0 else '0';
    neg    <= res(WIDTH-1);
end architecture rtl;

Пояснения

  • Расширение операндов нулём перед сложением — стандартный приём получения переноса: он оказывается в дополнительном старшем разряде.
  • Флаг знака — это просто старший бит результата при трактовке числа как знакового.
  • Все ветви case присваивают результат, поэтому защёлки не возникают — типичная ошибка при неполном описании.

Что дальше

Следующие проекты — в разделе проекты на VHDL. Сравнить подход с языком Verilog можно в статье Verilog, а разобраться в устройстве самих кристаллов — в статье ПЛИС: FPGA и CPLD.