Задача
Выполнить арифметическую операцию над двумя цифрами и показать результат.
Тип схемы: Комбинационная схема с внутренней функцией преобразования.
Модуль: simple_calc. Среда: Quartus, Vivado, ISE или свободный GHDL для моделирования.
Теорию по языку смотрите в статье VHDL — язык описания аппаратуры,
по самим микросхемам — на странице ПЛИС.
Алгоритм
- Принять два операнда 0…9 и код операции.
- Оператором case выполнить сложение, вычитание, умножение или защититься от вычитания с отрицательным результатом.
- Ограничить результат двумя разрядами и выставить признак переполнения при выходе за пределы.
- Функцией преобразовать оба разряда результата в коды сегментов.
Код на 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.