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

Проект 44. Простой калькулятор на 7-сегментном выводе

Два однозначных числа и код операции сразу дают результат на семисегментном индикаторе. Проект объединяет функцию, арифметику и дешифрацию сегментов в одном модуле.

Задача

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

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

Алгоритм

  1. Принять два операнда 0…9 и код операции.
  2. Оператором case выполнить сложение, вычитание, умножение или защититься от вычитания с отрицательным результатом.
  3. Ограничить результат двумя разрядами и выставить признак переполнения при выходе за пределы.
  4. Функцией преобразовать оба разряда результата в коды сегментов.

Код на VHDL

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

--=====================================================
-- Проект 44. Простой калькулятор на 7-сегментном выводе
-- Два однозначных числа и операция; результат
-- сразу подан на дешифратор индикатора.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity simple_calc is
    port (
        a, b    : in  std_logic_vector(3 downto 0);       -- операнды 0..9
        op      : in  std_logic_vector(1 downto 0);        -- 00 + 01 - 10 x
        seg_hi  : out std_logic_vector(6 downto 0);        -- старший разряд
        seg_lo  : out std_logic_vector(6 downto 0);        -- младший разряд
        overflow: out std_logic
    );
end entity simple_calc;

architecture rtl of simple_calc is
    function to_seg(d : integer) return std_logic_vector is
        type t is array (0 to 9) of std_logic_vector(6 downto 0);
        constant TAB : t := (
            "1000000","1111001","0100100","0110000","0011001",
            "0010010","0000010","1111000","0000000","0010000");
    begin
        return TAB(d);
    end function;

    signal res : integer range 0 to 99;
    signal ov  : std_logic;
begin
    process (a, b, op)
        variable ai, bi, r : integer;
    begin
        ai := to_integer(unsigned(a));
        bi := to_integer(unsigned(b));
        ov <= '0';
        case op is
            when "00" => r := ai + bi;
            when "01" =>
                if ai >= bi then r := ai - bi; else r := 0; ov <= '1'; end if;
            when "10" => r := ai * bi;
            when others => r := 0;
        end case;
        if r > 99 then
            r  := 99;
            ov <= '1';
        end if;
        res <= r;
    end process;

    seg_hi   <= to_seg(res / 10);
    seg_lo   <= to_seg(res mod 10);
    overflow <= ov;
end architecture rtl;

Пояснения

  • Функция to_seg вынесена отдельно и вызывается дважды — для десятков и для единиц результата, без дублирования таблицы.
  • Вычитание защищено проверкой: без неё отрицательный результат при типе integer без знака привёл бы к некорректному значению.
  • Модуль полностью комбинационный: результат появляется сразу вслед за изменением входов, без тактового сигнала.

Что дальше

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