с использованием языков описания аппаратуры VHDL и Verilog

advertisement
Глава 6.
Примеры проектирования цифровых устройств
с использованием языков описания аппаратуры VHDL и Verilog.
6.1. Общие сведения
Языки описания аппаратуры VHDL и Verilog HDL представляют собой языки высокого
уровня (в отличие от AHDL и ABEL HDL) и предназначены для описания цифровых схем и их
элементов в первую очередь на поведенческом уровне.
Эти языки поддерживают различные уровни абстракции проекта, включая поддержку
особенностей архитектуры ПЛИС, под которую выполняется проект (architecture-specific design).
Использование языков описания аппаратуры высокого уровня позволяет проектировать
цифровые системы, обладающие высокой мобильностью, то есть возможностью переносимости
на другую элементную базу. Для создания законченного проекта необходимо только лишь
произвести компиляцию в соответствующей системе в элементную базу выбранного
производителя. Но в этом и основной недостаток языков высокого уровня – недостаточный учет
специфических архитектурных особенностей используемой элементной базы (specific target
technology). В этом разделе мы попытаемся рассмотреть некоторые примеры использования
языков описания аппаратуры для создания проектов различного уровня сложности.
При проведении синтеза логической структуры ПЛИС с использованием языков описания
аппаратуры (HDL synthesis-based design flow) различают четыре основных стадии
проектирования:
- Создание и функциональная верификация проекта;
- Реализация проекта в САПР ПЛИС;
- Программирование ПЛИС
- Верификация всей системы
При функциональной верификации проекта ввод описания проекта осуществляется на
регистровом уровне (RTL-level) в поведенческой области (behavioral). После ввода описания
проекта поведенческое (функциональное) моделирование (верификация) позволяют оценить
степень правильности функционирования алгоритма. После проведения функционального
моделирования, описание синтезируется в список цепей на вентильном уровне (gate-level) в
структурной области (structural). После осуществленимя синтеза можно выполнеть структурное
(временное и функциональное) моделирование устройства. В результате мы получаем список
цепей (как правило, в формате EDIF) для временной верификации проекта.
Рассмотрим применение языков описания аппаратуры высокого уровня (VHDL и Verilog
HDL) для описания различных цифровых устройств. Данные описания, если не указывается
особо, не ориентированы на какую-либо конкретную систему проектирования или семейство
ПЛИС и могут быть воплощены в различных базисах. Такой тип описаний получил название
независимого от технологии стиля описания устройств (Technology Independent Coding Styles).
Начнем рассмотрение способов описания независимых от технологии устройств с
последовательностных устройств (Sequential Devices). В англоязычной литературе приняты
термины защелка (latch) для устройств, тактируемых уровнем, и триггер (flip-flop) для устройств,
тактируемым фронтом тактового импульса.
6.2. Триггеры и регистры (Flip-Flops, Registers)
Для описания триггерных схем в VHDL используются операторы wait и if вместе с
процессом, использующим аттрибуты переднего или заднего фронтов синхроимпульса (см.
Главу 4).
Ниже приведены примеры создания описаний срабатывания по фронту:
(clk'event and clk='1') –аттрибут срабатывания по переднему фронту
(clk'event and clk='0') -- аттрибут срабатывания по заднему фронту
rising_edge(clock) –вызов функции по переднему фронту
falling_edge(clock) -- вызов функции по заднему фронту
В этих примерах иллюстрируется применение аттрибута переднего фронта (rising edge
'event attribute). Использование аттрибутов следует рекомендовать в тех случаях, когда система
проектирования не поддерживает вызов функции по событию. Однако , использование функций
позволяет избежать коллизий, связанных с переходом из неопределенного состояния, поскольку
функция определяет только переходы уровней (из 0 в 1 или из 1 в 0), не не переход из
неопределенного состояния в 1 или 0. Это становиться достаточно важным в случае
использования многозначных типов данных, например std_logic, который имеет 9 возможных
значений(U, X, 0, 1, Z, W, L, H, -). Далее рассмотрим основные типы триггеров.
Триггеры, тактируемые передним фронтом (Rising Edge Flip-Flop)
Ниже приводиться пример описания D триггера без цепей асинхронного сброса (reset) или
предустановки (preset). На Рис. 1 приведено схемное обозначение рассматриваемого триггера.
Рис.6.1
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff is
port (data, clk : in std_logic;
q :out std_logic);
end dff;
architecture behav of dff is
begin
process (clk) begin
if (clk'event and clk = '1') then
q <= data;
end if;
end process;
end behav;
Описание на Verilog
module dff (data, clk, q);
input data, clk;
output q;
reg q;
always @(posedge clk)
q = data;
endmodule
Триггеры, тактируемые передним фронтом с асинхронным сбросом
(Rising Edge Flip-Flop with Asynchronous Reset)
Обозначение устройства приведено на Рис.6.2
Рис.6.2.
Пример описания на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_async_rst is
port (data, clk, reset : in std_logic;
q :out std_logic);
end dff_async_rst;
architecture behav of dff_async_rst is
begin
process (clk, reset) begin
if (reset = '0') then
q <= '0';
elsif (clk'event and clk = '1') then
q <= data;
end if;
end process;
end behav;
Пример описания на Verilog
module dff_async_rst (data, clk, reset, q);
input data, clk, reset;
output q;
reg q;
always @(posedge clk or negedge reset)
if (~reset)
q = 1'b0;
else
q = data;
endmodule
Триггеры, тактируемые передним фронтом с асинхронной предустановкой
(Rising Edge Filp-Flop with Asynchronous Preset)
Обозначение устройства на схеме приведено на Рис.6.3
Рис.6.3
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_async_pre is
port (data, clk, preset : in std_logic;
q :out std_logic);
end dff_async_pre;
architecture behav of dff_async_pre is
begin
process (clk, preset) begin
if (preset = '0') then
q <= '1';
elsif (clk'event and clk = '1') then
q <= data;
end if;
end process;
end behav;
Описание на Verilog
module dff_async_pre (data, clk, preset, q);
input data, clk, preset;
output q;
reg q;
always @(posedge clk or negedge preset)
if (~preset)
q = 1'b1;
else
q = data;
endmodule
Триггеры, тактируемые передним фронтом с асинхронным сбросом и предустановкой
(Rising Edge Filp-Flop with Asynchronous Reset and Preset)
Обозначение на схеме приведено на Рис.6.4
Рис.6.4
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_async is
port (data, clk, reset, preset : in std_logic;
q :out std_logic);
end dff_async;
architecture behav of dff_async is
begin
process (clk, reset, preset) begin
if (reset = '0') then
q <= '0';
elsif (preset = '1') then
q <= '1';
elsif (clk'event and clk = '1') then
q <= data;
end if;
end process;
end behav;
Описание на Verilog
module dff_async (reset, preset, data, q, clk);
input clk;
input reset, preset, data;
output q;
reg q;
always @(posedge clk or negedge reset or posedge preset)
if (~reset)
q = 1'b0;
else if (preset)
q = 1'b1;
else q = data;
endmodule
Триггеры, тактируемые передним фронтом с синхронным сбросом
(Rising Edge Filp-Flop with Synchronous Reset)
Обозначение на схеме приведено на Рис.6.5
Рис.6.5.
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_sync_rst is
port (data, clk, reset : in std_logic;
q :out std_logic);
end dff_sync_rst;
architecture behav of dff_sync_rst is
begin
process (clk) begin
if (clk'event and clk = '1') then
if (reset = '0') then
q <= '0';
else q <= data;
end if;
end if;
end process;
end behav;
Описание на Verilog
module dff_sync_rst (data, clk, reset, q);
input data, clk, reset;
output q;
reg q;
always @(posedge clk)
if (~reset)
q = 1'b0;
else q = data;
endmodule
Триггеры, тактируемые передним фронтом с синхронной предустановкой
(Rising Edge Filp-Flop with Synchronous Preset)
Обозначение на схеме приведено на Рис.6.6
Рис.6.6
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_sync_pre is
port (data, clk, preset : in std_logic;
q :out std_logic);
end dff_sync_pre;
architecture behav of dff_sync_pre is
begin
process (clk) begin
if (clk'event and clk = '1') then
if (preset = '0') then
q <= '1';
else q <= data;
end if;
end if;
end process;
end behav;
Описание на Verilog
module dff_sync_pre (data, clk, preset, q);
input data, clk, preset;
output q;
reg q;
always @(posedge clk)
if (~preset)
q = 1'b1;
else q = data;
endmodule
Триггеры, тактируемые передним фронтом с асинхронным сбросом и разрешением
тактового сигнала (Rising Edge Filp-Flop with Asynchronous Reset and Clock Enable)
Пример схемного обозначения приведен на Рис.6.7
Рис.6. 7.
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity dff_ck_en is
port (data, clk, reset, en : in std_logic;
q :out std_logic);
end dff_ck_en;
architecture behav of dff_ck_en is
begin
process (clk, reset) begin
if (reset = '0') then
q <= '0';
elsif (clk'event and clk = '1') then
if (en = '1') then
q <= data;
end if;
end if;
end process;
end behav;
Описание на Verilog
module dff_ck_en (data, clk, reset, en, q);
input data, clk, reset, en;
output q;
reg q;
always @(posedge clk or negedge reset)
if (~reset)
q = 1'b0;
else if (en)
q = data;
endmodule
Далее рассмотрим защелки на основе D-триггеров (D-Latches)
Защелка с разрешением выхода (D-Latch with Data and Enable)
Обозначение на схеме приведено на Рис.6.8
Рис.6.8
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity d_latch is
port(enable, data: in std_logic;
y :out std_logic);
end d_latch;
architecture behave of d_latch is
begin
process (enable, data)
begin
if (enable = '1') then
y <= data;
end if;
end process;
end behave;
Описание на Verilog
module d_latch (enable, data, y);
input enable, data;
output y;
reg y;
always @(enable or data)
if (enable)
y = data;
endmodule
Защелка с входом данных с разрешением (D-Latch with Gated Asynchronous Data)
Пример обозначения приведен на Рис.6.9
Рис.6.9.
Пример на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity d_latch_e is
port (enable, gate, data : in std_logic;
q :out std_logic);
end d_latch_e;
architecture behave of d_latch_e is
begin
process (enable, gate, data) begin
if (enable = '1') then
q <= data and gate;
end if;
end process;
end behave;
Пример на Verilog
module d_latch_e(enable, gate, data, q);
input enable, gate, data;
output q;
reg q;
always @ (enable or data or gate)
if (enable)
q = (data & gate);
endmodule
Защелка с входом разрешения (D-Latch with Gated Enable) (Рис.6.10)
Рис.6.10
Пример на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity d_latch_en is
port (enable, gate, d: in std_logic;
q :out std_logic);
end d_latch_en;
architecture behave of d_latch_en is
begin
process (enable, gate, d) begin
if ((enable and gate) = '1') then
q <=d;
end if;
end process;
end behave;
Пример на Verilog
module d_latch_en(enable, gate, d, q);
input enable, gate, d;
output q;
reg q;
always @ (enable or d or gate)
if (enable & gate)
q =d;
endmodule
Защелка с асинхронным сбросом (D-Latch with Asynchronous Reset) (Рис.6.11)
Рис.6.11.
Пример описания на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity d_latch_rst is
port (enable, data, reset: in std_logic;
q :out std_logic);
end d_latch_rst;
architecture behav of d_latch_rst is
begin
process (enable, data, reset) begin
if (reset = '0') then
q <= '0';
elsif (enable = '1') then
q <= data;
end if;
end process;
end behav;
Пример описания на Verilog
module d_latch_rst (reset, enable, data, q);
input reset, enable, data;
output q;
reg q;
always @ (reset or enable or data)
if (~reset)
q = 1'b0;
else if (enable)
q = data;
endmodule
6.3. Построение устройств потоковой обработки данных (Datapath logic)
Как правило, устройства потоковой обработки данных представляют собой структурированные,
повторяющиеся функции. Рассмотрение таких устройств начнем с приоритетного шифратора.
Приоритетный шифратор (Рис.6.12) строиться с использованием оператора If-Then-Else
Рис.6.12
Пример описания шифратора на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity my_if is
port (c, d, e, f: in std_logic;
s :in std_logic_vector(1 downto 0);
pout : out std_logic);
end my_if;
architecture my_arc of my_if is
begin
myif_pro: process (s, c, d, e, f) begin
if s = “00” then
pout <= c;
elsif s = “01” then
pout <= d;
elsif s = “10” then
pout <= e;
else pout <= f;
end if;
end process myif_pro;
end my_arc;
Пример описания на Verilog
module IF_MUX (c, d, e, f, s, pout);
input c, d, e, f;
input [1:0]s;
output pout;
reg pout;
always @(c or d or e or f or s) begin
if (s == 2'b00)
pout = c;
else if (s ==2'b01)
pout = d;
else if (s ==2'b10)
pout = e;
else pout = f;
end
endmodule
Другим часто используемым устройством является мультиплексор (Multiplexors).
Как правило, для построения мультиплексора удобно использовать оператор Case. Оператор case
обеспечивает параллельную обработку. Оператор выбора case (case statement) используется для
выбора одного варианта из нескольких в зависимости от условий.
Средства синтеза с VHDL позволяют автоматически выполнить параллельную обработку без
приоритета, в то время, как средства синтеза с Verilog поддерживают приоритет в выполнении
оператора case и в ряде случаев необходимо ввести специфические инструкции в код и для того,
чтобы оператор выбора не имел приоритета.
Рис.6.13 Мультиплексор 4 в 1
Ниже приводятся примеры описания мультиплексора 4 в 1
Пример описания на VHDL
--4:1 Multiplexor
library IEEE;
use IEEE.std_logic_1164.all;
entity mux is
port (c, d, e, f : in std_logic;
s :in std_logic_vector(1 downto 0);
muxout : out std_logic);
end mux;
architecture my_mux of mux is
begin
mux1: process (s, c, d, e, f) begin
case s is
when “00” => muxout <= c;
when “01” => muxout <= d;
when “10” => muxout <= e;
when others => muxout <= f;
end case;
end process mux1;
end my_mux;
Пример описания на Verilog
//4:1 Multiplexor
module MUX (C, D, E, F, S, MUX_OUT);
input C, D, E, F;
input [1:0] S;
output MUX_OUT;
reg MUX_OUT;
always @(C or D or E or F or S)
begin
case (S)
2'b00 : MUX_OUT = C;
2'b01 : MUX_OUT = D;
2'b10 : MUX_OUT = E;
default : MUX_OUT = F;
endcase
end
endmodule
Для более сложного случая рассмотрим пример мультиплексора 12 в 1
Пример описания на VHDL
-- 12:1 mux
library ieee;
use ieee.std_logic_1164.all;
-- Entity declaration:
entity mux12_1 is
port
(
mux_sel: in std_logic_vector (3 downto 0);-- mux select
A: in std_logic;
B: in std_logic;
C: in std_logic;
D: in std_logic;
E: in std_logic;
F: in std_logic;
G: in std_logic;
H: in std_logic;
I: in std_logic;
J: in std_logic;
K: in std_logic;
M: in std_logic;
mux_out: out std_logic -- mux output
);
end mux12_1;
-- Architectural body:
architecture synth of mux12_1 is
begin
proc1: process (mux_sel, A, B, C, D, E, F, G, H, I, J, K, M)
begin
case mux_sel is
when "0000" => mux_out<= A;
when "0001" => mux_out <= B;
when "0010" => mux_out <= C;
when "0011” => mux_out <= D;
when "0100" => mux_out <= E;
when "0101" => mux_out <= F;
when "0110"
when "0111"
when "1000"
when "1001"
when "1010"
when "1011"
when others
end case;
end process
end synth;
=>
=>
=>
=>
=>
=>
=>
mux_out <= G;
mux_out <= H;
mux_out <= I;
mux_out <= J;
mux_out <= K;
mux_out <= M;
mux_out<= '0';
proc1;
Описание мультиплексора 12 в 1на Verilog
// 12:1 mux
module mux12_1(mux_out,
mux_sel,M,L,K,J,H,G,F,E,D,C,B,A
);
output mux_out;
input [3:0] mux_sel;
input M;
input L;
input K;
input J;
input H;
input G;
input F;
input E;
input D;
input C;
input B;
input A;
reg mux_out;
// create a 12:1 mux using a case statement
always @ ({mux_sel[3:0]} or M or L or K or J or H or G or F or
E or D or C or B or A)
begin: mux_blk
case ({mux_sel[3:0]}) // synthesis full_case parallel_case
4'b0000 : mux_out = A;
4'b0001 : mux_out = B;
4'b0010 : mux_out = C;
4'b0011 : mux_out = D;
4'b0100 : mux_out = E;
4'b0101 : mux_out = F;
4'b0110 : mux_out = G;
4'b0111 : mux_out = H;
4'b1000 : mux_out = J;
4'b1001 : mux_out = K;
4'b1010 : mux_out = L;
4'b1011 : mux_out = M;
4'b1100 : mux_out = 1'b0;
4'b1101 : mux_out = 1'b0;
4'b1110 : mux_out = 1'b0;
4'b1111 : mux_out = 1'b0;
endcase
end
endmodule
Кроме обычного опреатора выбора в языке описания аппараатуры Verilog используется оператор
выбора casex
Ниже приводится описание на Verilog мультиплексора 4 в 1
//8 bit 4:1 multiplexor with don't care X, 3:1 equivalent mux
module mux4 (a, b, c, sel, q);
input [7:0] a, b, c;
input [1:0] sel;
output [7:0] q;
reg [7:0] q;
always @ (sel or a or b or c)
casex (sel)
2'b00:q =a;
2'b01:q =b;
2'b1x:q =c;
default:q =c;
endcase
endmodule
Дешифратор, пожалуй, является самым распространенным комбинационным устройством. Ниже
приводиться пример дешифратора 3 в 8.
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity decode is
port ( Ain : in std_logic_vector (2 downto 0);
En: in std_logic;
Yout : out std_logic_vector (7 downto 0));
end decode;
architecture decode_arch of decode is
begin
process (Ain)
begin
if (En='0') then
Yout <= (others => '0');
else
case Ain is
when "000" => Yout <= "00000001";
when "001" => Yout <= "00000010";
when "010" => Yout <= "00000100";
when "011" => Yout <= "00001000";
when "100" => Yout <= "00010000";
when "101" => Yout <= "00100000";
when "110" => Yout <= "01000000";
when "111" => Yout <= "10000000";
when others => Yout <= "00000000";
end case;
end if;
end process;
end decode_arch;
Описание дешифратора на Verilog имеет вид
module decode (Ain, En, Yout);
input En;
input [2:0] Ain;
output [7:0] Yout;
reg [7:0] Yout;
always @ (En or Ain)
begin
if (!En)
Yout = 8'b0;
else
case (Ain)
3'b000 : Yout = 8'b00000001;
3'b001 : Yout = 8'b00000010;
3'b010 : Yout = 8'b00000100;
3'b011 : Yout = 8'b00001000;
3'b100 : Yout = 8'b00010000;
3'b101 : Yout = 8'b00100000;
3'b110 : Yout = 8'b01000000;
3'b111 : Yout = 8'b10000000;
default : Yout = 8'b00000000;
endcase
end
endmodule
6.4. Счетчики
Счетчики являются достаточно широко распространенными устройствами, их классификация и
принципы построения изложены в литературе [34-38]. Следует помнить, что большинство
программ синтеза не позволяют получить приемлимых результатов по быстродействию при
разрядности счетчика более 8 бит, в этом случае часто применяются специфические приемы
синтеза, зависящие от технологии, по которой выполнена ПЛИС.
Рассмотрим пример построения 8 разрядного счетчика, считающего в прямом направлении и
имеющего цепи разрешения счета и асинхронного сброса.
Пример описания на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity counter8 is
port (clk, en, rst : in std_logic;
count : out std_logic_vector (7 downto 0));
end counter8;
architecture behav of counter8 is
signal cnt: std_logic_vector (7 downto 0);
begin
process (clk, en, cnt, rst)
begin
if (rst = '0') then
cnt <= (others => '0');
elsif (clk'event and clk = '1') then
if (en = '1') then
cnt <= cnt + '1';
end if;
end process;
count <= cnt;
end behav;
Пример на Verilog
module count_en (en, clock, reset, out);
parameter Width = 8;
input clock, reset, en;
output [Width-1:0] out;
reg [Width-1:0] out;
always @(posedge clock or negedge reset)
if(!reset)
out = 8'b0;
else if(en)
out =out +1;
endmodule
Другой пример иллюстрирует построение 8 разрядного счетчика с загрузкой и асинхронным
сбросом (8-bit Up Counter with Load and Asynchronous Reset)
Пример на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity counter is
port (clk, reset, load: in std_logic;
data: in std_logic_vector (7 downto 0);
count: out std_logic_vector (7 downto 0));
end counter;
architecture behave of counter is
signal count_i : std_logic_vector (7 downto 0);
begin
process (clk, reset)
begin
if (reset = '0') then
count_i <= (others => '0');
elsif (clk'event and clk = '1') then
if load = '1' then
count_i <= data;
else
count_i <= count_i + '1';
end if;
end if;
end process;
count <= count_i;
end behave;
Описание на Verilog
module count_load (out, data, load, clk, reset);
parameter Width = 8;
input load, clk, reset;
input [Width-1:0] data;
output [Width-1:0] out;
reg [Width-1:0] out;
always @(posedge clk or negedge reset)
if(!reset)
out = 8'b0;
else if(load)
out = data;
else
out =out +1;
endmodule
Пример построения счетчика с предварительной загрузкой, входами разрешения и остановом
счета (8-bit Up Counter with Load, Count Enable, Terminal Count and Asynchronous Reset) приведен
ниже.
Описание на Verilog
module count_load (out, cout, data, load, clk, en, reset);
parameter Width = 8;
input load, clk, en, reset;
input [Width-1:0] data;
output cout; // carry out
output [Width-1:0] out;
reg [Width-1:0] out;
always @(posedge clk or negedge reset)
if(!reset)
out = 8'b0;
else if(load)
out = data;
else if(en)
out =out +1;
// cout=1 when all out bits equal 1
assign cout = &out;
endmodule
Следующий пример – счетчик с произвольным модулем счета и всеми остальными функциями –
сброс, загрузка и т.п. (N-bit Up Counter with Load, Count Enable, and Asynchronous Reset)
Пример на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity counter is
generic (width : integer := n);
port (data : in std_logic_vector (width-1 downto 0);
load, en, clk, rst : in std_logic;
q :out std_logic_vector (width-1 downto 0));
end counter;
architecture behave of counter is
signal count : std_logic_vector (width-1 downto 0);
begin
process(clk, rst)
begin
if rst = '1' then
count <= (others => '0');
elsif (clk'event and clk = '1') then
if load = '1' then
count <= data;
elsif en = '1' then
count <= count + 1;
end if;
end if;
end process;
q <= count;
end behave;
6.5. Арифметические устройства
Проектирование устройств обработки информации немыслимо без реализациии арифметических
опреаций – сложения, умножения, вычитания и деления. Ниже приводяться примеры
использования арифметических операторов при проектировании на языках описания аппаратуры
высокого уровня.
Пример выполнения арифметических операций приведен ниже.
Описание на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity arithmetic is
port (A, B: in std_logic_vector(3 downto 0);
Q1: out std_logic_vector(4 downto 0);
Q2, Q3: out std_logic_vector(3 downto 0);
Q4: out std_logic_vector(7 downto 0));
end arithmetic;
architecture behav of arithmetic is
begin
process (A, B)
begin
Q1 <= ('0' & A) + ('0' & B); --addition
Q2<=A -B;--subtraction
Q3<=A /B;--division
Q4<=A *B;--multiplication
end process;
end behav;
Конечно, такое описание не всегда (скорее никогда) не приводит к хорошим результатам. Ниже
мы еще вернемся к теме построения быстродействующих арифметических устройств. Здесь же
заметим, что если требуется выполнить умножени или деление на число, являющееся степенью
двойки, то арифметическая операция легко выполняется путем сдвига на необходимое число
разрядов вправо или влево.
Например выражение:
Q <= C/16 + C*4;
может быть представлено как
Q <= shr (C, “100”) + shl (C, “10”);
Или на VHDL
Q <= “0000”&C (8downto 4)+C (6downto 0) & ”00”;
Функции “shr” и “shl” находятся в пакете IEEE.std_logic_arith.all.
Пример арифметических операций в Verilog
module arithmetic (A, B, Q1, Q2, Q3, Q4);
input [3:0] A, B;
output [4:0] Q1;
output [3:0] Q2, Q3;
output [7:0] Q4;
reg [4:0] Q1;
reg [3:0] Q2, Q3;
reg [7:0] Q4;
always @(Aor B)
begin
Q1 =A +B;//addition
Q2 =A -B;//subtraction
Q3 =A /2;//division
Q4 =A *B;//multiplication
end
endmodule
Реализация регистров сдвига имеет вид
Q = {4b'0000 C[8:4]} + {C[6:0] 2b'00};
Опреаторы отношения сравнивают два операнда и выдают значение истинно или ложно (true or
false). Приведенные ниже примеры показывают применение операторов отношения.
Пример использования операторов отношения в VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
entity relational is
port (A,B :in std_logic_vector(3 downto 0);
Q1, Q2, Q3, Q4 : out std_logic);
end relational;
architecture behav of relational is
begin
process (A, B)
begin
--Q1<=A >B;--greater than
--Q2<=A <B;--less than
-- Q3 <= A >= B; -- greater than equal to
if (A <= B) then –- less than equal to
Q4 <= '1';
else
Q4 <= '0';
end if;
end process;
end behav;
Оераторы отношения в Verilog
module relational (A, B, Q1, Q2, Q3, Q4);
input [3:0] A, B;
output Q1, Q2, Q3, Q4;
reg Q1, Q2, Q3, Q4;
always @(Aor B)
begin
//Q1 =A >B;//greater than
//Q2 =A <B;//less than
//Q3 =A >=B;//greater than equal to
if (A <= B) //less than equal to
Q4 =1;
else
Q4 =0;
end
endmodule
Оператор эквивалентности (Equality Operator) используется для сравнения операндов. Пример
реализации оператора эквивалентности на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity equality is
port (
A: in STD_LOGIC_VECTOR (3 downto 0);
B: in STD_LOGIC_VECTOR (3 downto 0);
Q1: out STD_LOGIC;
Q2: out STD_LOGIC
);
end equality;
architecture equality_arch of equality is
begin
process (A, B)
begin
Q1<=A =B;--equality
if (A /= B) then -- inequality
Q2 <= '1';
else
Q2 <= '0';
end if;
end process;
end equality_arch;
Другой вариант описания на VHDL имеет вид
library IEEE;
use IEEE.std_logic_1164.all;
entity equality is
port (
A: in STD_LOGIC_VECTOR (3 downto 0);
B: in STD_LOGIC_VECTOR (3 downto 0);
Q1: out STD_LOGIC;
Q2: out STD_LOGIC
);
end equality;
architecture equality_arch of equality is
begin
Q1 <= '1' when A =Belse '0'; -- equality
Q2 <= '1' when A /=Belse '0'; -- inequality
end equality_arch;
Описание на Verilog
module equality (A, B, Q1, Q2);
input [3:0] A;
input [3:0] B;
output Q1;
output Q2;
reg Q1, Q2;
always @(A or B)
begin
Q1 =A ==B;//equality
if (A != B) //inequality
Q2 =1;
else
Q2 =0;
end
endmodule
Реализация сдвигателей (Shift operators) может быть полезна в различных схемах умножения –
деления, а также нормализации данных
Пример сдвигателя на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity shift is
port (data : in std_logic_vector(3 downto 0);
q1, q2 : out std_logic_vector(3 downto 0));
end shift;
architecture rtl of shift is
begin
process (data)
begin
q1 <= shl (data, "10"); -- logical shift left
q2 <= shr (data, "10"); --logical shift right
end process;
end rtl;
Другой вариант сдвигателя
library IEEE;
use IEEE.std_logic_1164.all;
entity shift is
port (data : in std_logic_vector(3 downto 0);
q1, q2 : out std_logic_vector(3 downto 0));
end shift;
architecture rtl of shift is
begin
process (data)
begin
q1 <= data(1 downto 0) & “10”; -- logical shift left
q2 <= “10” & data(3 downto 2); --logical shift right
end process;
end rtl;
Описание на Verilog
module shift (data, q1, q2);
input [3:0] data;
output [3:0] q1, q2;
parameter B =2;
reg [3:0] q1, q2;
always @ (data)
begin
q1 = data << B; // logical shift left
q2 = data >> B; //logical shift right
end
endmodule
6.6.Конечные автоматы (Finite State Machine)
Конечные автоматы (Finite State Machine) и средства их проектирования быле рассмотрены выше
(см. Главу.2). В ряде случаев автоматная модель (описание) устройства позволяют получить
быструю и эффективную реализацию последовательностного устройства. Как известно, обычно
рассматривают два типа автоматов – автомат Мили (Mealy) и Мура (Moore). Выход автомата
Мура является функцией только текущего состояния, в то время, как выход автомата Мили
функция как текущего состояния, так и начального внешнего воздействия. Обычно конечный
автомат состоит из трех основных частей:
Регистр текущего состояния (Sequential Current State Register). Этот регистр представляет
собой набор тактируемых D-триггеров синхронизируемых одним синхросигналом и
используется для хранения кода текущего состояния автомата. Очевидно, что для автомата с n
состояниями требуется log 2 (n) триггеров.
Логика переходов (Combinational Next State Logic). Как известно, конечный автомат может
находиться в каждый конкретный момент времени только в одном состоянии. Каждый тактовый
импульс вызывает переход автомата из одного состояния в другое. Правила перехода и
определяются комбинационной схемой, называемой логикой переходов. Следующее состояние
определяется как функция текущего состояния и входного воздействия.
Логика формирования выхода (Combinational Output Logic). Выход цифрового автомата
обычно определяется как функция текущего состояния и исходной установки (в случае автомата
Мили). Формирование выходного сигнала автомата определяется с помощью логики
формирования выхода.
На Рис. 6.14 и 6.15 приведены структуры автоматов Мура и Мили соответственно.
Рис.6.14. Автомат Мура
Рис.6.15. Автомат Мили
Для обеспечения стабильной и безотказной работы используется сброс автомата в начальное
состояние. Таким образом всегда обеспечивается инициализация автомата в заранее
предорпеделенном сотоянии при первом тактовом импульсе. В случае, если сброс не
предусмотрен, невозможно предсказать с какого начального состояния начнет
функционирование, что может привести к сбоям в работе всей системы. Особенно эта ситуация
актуальна при включении питания системы. Поэтому мы настоятельно рекоммендуем
использовать схемы сброса и начальной установки при проектировании устройств на ПЛИС.
Обычно применяют асинхронные схемы сброса, из-за того, что не требуется использовать
дешифратор неиспользуемых (избыточных) состояний, что упрощает логику переходов.
С другой стороны, из-за того, что ПЛИС, выполненные по архитектуре FPGA имеют достаточное
число регистров (триггеров), использование автоматных моделей позволяет получить достаточно
быстродействующую и, в то же время наглядную реализацию при приемлимых затратах
ресурсов.
Ниже рассмотрим пример проектирования автомата Мили.
Диаграмма переходов автомата приведена на Рис.6.16.
Рис.6.16. Диаграмма переходов автомата Мили.
Пример автомата Мили на VHDL
-- Автомат Мили с 5 состояниями
library ieee;
use ieee.std_logic_1164.all;
entity mealy is
port (clock, reset: in std_logic;
data_out: out std_logic;
data_in: in std_logic_vector (1 downto 0));
end mealy;
architecture behave of mealy is
type state_values is (st0, st1, st2, st3, st4);
signal pres_state, next_state: state_values;
begin
-- FSM register
statereg: process (clock, reset)
begin
if (reset = '0') then
pres_state <= st0;
elsif (clock'event and clock ='1') then
pres_state <= next_state;
end if;
end process statereg;
-- FSM combinational block
fsm: process (pres_state, data_in)
begin
case pres_state is
when st0 =>
case data_in is
when "00" => next_state <= st0;
when "01" => next_state <= st4;
when "10" => next_state <= st1;
when "11" => next_state <= st2;
when others => next_state <= (others <= ‘x’);
end case;
when st1 =>
case data_in is
when "00" => next_state <= st0;
when "10" => next_state <= st2;
when others => next_state <= st1;
end case;
when st2 =>
case data_in is
when "00" => next_state <= st1;
when "01" => next_state <= st1;
when "10" => next_state <= st3;
when "11" => next_state <= st3;
when others => next_state <= (others <= ‘x’);
end case;
when st3 =>
case data_in is
when "01" => next_state <= st4;
when "11" => next_state <= st4;
when others => next_state <= st3;
end case;
when st4 =>
case data_in is
when "11" => next_state <= st4;
when others => next_state <= st0;
end case;
when others => next_state <= st0;
end case;
end process fsm;
-- Mealy output definition using pres_state w/ data_in
outputs: process (pres_state, data_in)
begin
case pres_state is
when st0 =>
case data_in is
when "00" => data_out <= '0';
when others => data_out <= '1';
end case;
when st1 => data_out <= '0';
when st2 =>
case data_in is
when "00" => data_out <= '0';
when "01" => data_out <= '0';
when others => data_out <= '1';
end case;
when st3 => data_out <= '1';
when st4 =>
case data_in is
when "10" => data_out <= '1';
when "11" => data_out <= '1';
when others => data_out <= '0';
end case;
when others => data_out <= '0';
end case;
end process outputs;
end behave;
Описание автомата на Verilog имеет вид
// Example of a 5-state Mealy FSM
module mealy (data_in, data_out, reset, clock);
output data_out;
input [1:0] data_in;
input reset, clock;
reg data_out;
reg [2:0] pres_state, next_state;
parameter st0=3'd0, st1=3'd1, st2=3'd2, st3=3'd3, st4=3'd4;
// FSM register
always @(posedge clock or negedge reset)
begin: statereg
if(!reset)// asynchronous reset
pres_state = st0;
else
pres_state = next_state;
end // statereg
// FSM combinational block
always @(pres_state or data_in)
begin: fsm
case (pres_state)
st0: case(data_in)
2'b00: next_state=st0;
2'b01: next_state=st4;
2'b10: next_state=st1;
2'b11: next_state=st2;
endcase
st1: case(data_in)
2'b00: next_state=st0;
2'b10: next_state=st2;
default: next_state=st1;
endcase
st2: case(data_in)
2'b0x: next_state=st1;
2'b1x: next_state=st3;
endcase
st3: case(data_in)
2'bx1: next_state=st4;
default: next_state=st3;
endcase
st4: case(data_in)
2'b11: next_state=st4;
default: next_state=st0;
endcase
default: next_state=st0;
endcase
end // fsm
// Mealy output definition using pres_state w/ data_in
always @(data_in or pres_state)
begin: outputs
case(pres_state)
st0: case(data_in)
2'b00: data_out=1'b0;
default: data_out=1'b1;
endcase
st1: data_out=1'b0;
st2: case(data_in)
2'b0x: data_out=1'b0;
default: data_out=1'b1;
endcase
st3: data_out=1'b1;
st4: case(data_in)
2'b1x: data_out=1'b1;
default: data_out=1'b0;
endcase
default: data_out=1'b0;
endcase
end // outputs
endmodule
Пример автомата Мура (Moore Machine) с тем же графом переходов имеет вид.
Описание на VHDL
-- Example of a 5-state Moore FSM
library ieee;
use ieee.std_logic_1164.all;
entity moore is
port (clock, reset: in std_logic;
data_out: out std_logic;
data_in: in std_logic_vector (1 downto 0));
end moore;
architecture behave of moore is
type state_values is (st0, st1, st2, st3, st4);
signal pres_state, next_state: state_values;
begin
-- FSM register
statereg: process (clock, reset)
begin
if (reset = '0') then
pres_state <= st0;
elsif (clock ='1' and clock'event) then
pres_state <= next_state;
end if;
end process statereg;
-- FSM combinational block
fsm: process (pres_state, data_in)
begin
case pres_state is
when st0 =>
case data_in is
when "00" => next_state <= st0;
when "01" => next_state <= st4;
when "10" => next_state <= st1;
when "11" => next_state <= st2;
when others => next_state <= (others <= ‘x’);
end case;
when st1 =>
case data_in is
when "00" => next_state <= st0;
when "10" => next_state <= st2;
when others => next_state <= st1;
end case;
when st2 =>
case data_in is
when "00" => next_state <= st1;
when "01" => next_state <= st1;
when "10" => next_state <= st3;
when "11" => next_state <= st3;
when others => next_state <= (others <= ‘x’);
end case;
when st3 =>
case data_in is
when "01" => next_state <= st4;
when "11" => next_state <= st4;
when others => next_state <= st3;
end case;
when st4 =>
case data_in is
when "11" => next_state <= st4;
when others => next_state <= st0;
end case;
when others => next_state <= st0;
end case;
end process fsm;
-- Moore output definition using pres_state only
outputs: process (pres_state)
begin
case pres_state is
when st0 => data_out <= '1';
when st1 => data_out <= '0';
when st2 => data_out <= '1';
when st3 => data_out <= '0';
when st4 => data_out <= '1';
when others => data_out <= '0';
end case;
end process outputs;
end behave;
Описание автомата Мура на Verilog
// Example of a 5-state Moore FSM
module moore (data_in, data_out, reset, clock);
output data_out;
input [1:0] data_in;
input reset, clock;
reg data_out;
reg [2:0] pres_state, next_state;
parameter st0=3'd0, st1=3'd1, st2=3'd2, st3=3'd3, st4=3'd4;
//FSM register
always @(posedge clock or negedge reset)
begin: statereg
if(!reset)
pres_state = st0;
else
pres_state = next_state;
end // statereg
// FSM combinational block
always @(pres_state or data_in)
begin: fsm
case (pres_state)
st0: case(data_in)
2'b00: next_state=st0;
2'b01: next_state=st4;
2'b10: next_state=st1;
2'b11: next_state=st2;
endcase
st1: case(data_in)
2'b00: next_state=st0;
2'b10: next_state=st2;
default: next_state=st1;
endcase
st2: case(data_in)
2'b0x: next_state=st1;
2'b1x: next_state=st3;
endcase
st3: case(data_in)
2'bx1: next_state=st4;
default: next_state=st3;
endcase
st4: case(data_in)
2'b11: next_state=st4;
default: next_state=st0;
endcase
default: next_state=st0;
endcase
end // fsm
// Moore output definition using pres_state only
always @(pres_state)
begin: outputs
case(pres_state)
st0: data_out=1'b1;
st1: data_out=1'b0;
st2: data_out=1'b1;
st3: data_out=1'b0;
st4: data_out=1'b1;
default: data_out=1'b0;
endcase
end // outputs
endmodule // Moore
6.7. Элементы ввода – вывода
Без элементов ввода вывода невозможна организация полноценного обмена данных, организация
шин и т.п. Рассмотрим особенности описания на языках описания аппаратуры элементов ввода –
вывода (Input-Output Buffers).
Элемент с тремя состояниями (Tri-State Buffer) позволяет организовать подключение нескольких
устройств к общей шине. Обозначение такого элемента на схеме приведено на Рис.6.17
Рис.6.17. Элемент с тремя состояниями.
Пример описания на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity tristate is
port (e,a :in std_logic;
y :out std_logic);
end tristate;
architecture tri of tristate is
begin
process (e, a)
begin
if e = '1' then
y <=a;
else
y <= 'Z';
end if;
end process;
end tri;
Другой вариант описания элемента с тремя состояниями на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity tristate is
port (e,a :in std_logic;
y :out std_logic);
end tristate;
architecture tri of tristate is
begin
Y <=awhen (e = '1') else 'Z';
end tri;
На Verilog элемент с тремя состояниями описывается следующим образом
module TRISTATE (e, a, y);
input a, e;
output y;
reg y;
always @(e or a) begin
if (e)
y =a;
else
y = 1'bz;
end
endmodule
OR
module TRISTATE (e, a, y);
input a, e;
output y;
assign y =e ?a :1'bZ;
endmodule
Приведенные выше примеры показывают логику функционирования элемента с тремя
сростояниями. Примеры создания экземрляра компонента приведены ниже.
Экземпляр компонента на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity tristate is
port (e,a :in std_logic;
y :out std_logic);
end tristate;
architecture tri of tristate is
component TRIBUFF
port (D, E: in std_logic;
PAD: out std_logic);
end component;
begin
U1: TRIBUFF port map (D => a,
E =>e,
PAD => y);
end tri;
Экземпляр компонента на Verilog
module TRISTATE (e, a, y);
input a, e;
output y;
TRIBUFF U1 (.D(a),.E(e),.PAD(y));
endmodule
Двунаправленные элементы ввода-вывода (Bi-Directional Buffer)
Двунаправленный элемент ввода-вывода используется либо как элемент ввода, либо как
выходной буфер с возможностью перехода в третье состояние.
Ниже приводятся примеры создания описания двунаправленного буфера (Рис.618).
Рис.6.18.
Пример логики двунаправленного буфера на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity bidir is
port (y : inout std_logic;
e, a: in std_logic;
b :out std_logic);
end bidir;
architecture bi of bidir is
begin
process (e, a)
begin
case e is
when '1'=>y <=a;
when '0' => y <= 'Z';
when others => y <= 'X';
end case;
end process;
b <=y;
end bi;
Описание двунаправленного буфера на Verilog
module bidir (e, y, a, b);
input a, e;
inout y;
output b;
reg y_int;
wire y, b;
always @(a or e)
begin
if (e == 1'b1)
y_int <= a;
else
y_int <= 1'bz;
end
assign y = y_int;
assign b =y;
endmodule
Примеры создания экземпляров компонента на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity bidir is
port (y : inout std_logic;
e, a: in std_logic;
b :out std_logic);
end bidir;
architecture bi of bidir is
component BIBUF
port (D, E: in std_logic;
Y :out std_logic;
PAD: inout std_logic);
end component;
begin
U1: BIBUF port map (D => a,
E =>e,
Y =>b,
PAD => y);
end bi;
Описание экземпляра буфера на Verilog
module bidir (e, y, a, b);
input a, e;
inout y;
output b;
BIBUF U1 (.PAD(y),.D(a),.E(e),.Y(b) );
Endmodule
6.8.Параметризация
Как уже отмечалось выше, в последние годы наметилась тенденция к разработке и
использованию параметризованных модулей (ядер, макросов, мегафункций) при проектировании
устройств на ПЛИС с использованием языков описания аппаратуры. В языках описания
аппаратуры существуют специальные конструкции, позволяющие обеспечить полную
параметризацию проекта. Это так называемые родовые (параметризованные, настраиваемые)
типы данных (Generics) и параметры (Parameters). Мы будем использовать термин
настраиваемый тип. Насираиваемые типы данных и параметры используются обычно для
определения размерности компонента (например разрядность шин, коэффициентов и т.п.)
Конкретное значение параметров определяется при создании конкретного экземпляра
компонента. Рассмотрим пример использования параметризации на примере сумматора.
Описание параметризируемого сумматора на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity adder is
generic (WIDTH : integer := 8);
port (A, B: in UNSIGNED(WIDTH-1 downto 0);
CIN: in std_logic;
COUT: out std_logic;
Y: out UNSIGNED(WIDTH-1 downto 0));
end adder;
architecture rtl of adder is
begin
process (A,B,CIN)
variable TEMP_A,TEMP_B,TEMP_Y:UNSIGNED(A'length downto 0);
begin
TEMP_A := '0' & A;
TEMP_B := '0' & B;
TEMP_Y := TEMP_A + TEMP_B + CIN;
Y <= TEMP_Y (A'length-1 downto 0);
COUT <= TEMP_Y (A'length);
end process;
end rtl;
Параметр “Width” определяет разрядность данных. Пример конкретного экземпляра компонента
с 16 разрядными данными приведен ниже:
U1: adder generic map(16) port map (A_A, B_A, CIN_A, COUT_A, Y_A);
Описание сумматора на Verilog
module adder (cout, sum, a, b, cin);
parameter Size = 8;
output cout;
output [Size-1:0] sum;
input cin;
input [Size-1:0] a, b;
assign {cout, sum}=a +b +cin;
endmodule
Параметр “Size” определяет ширину сумматора. Реализация компонента 16 битного сумматора
приведена ниже:
adder #(16) adder16(cout_A, sun_A, a_A, b_A, cin_A)
6.9. Спрецифика проектирования устройств с учетом архитектурных особенностей
ПЛИС
В отличие от специализированных БИС (ASIC), ПЛИС выполненные по FPGA архитектуре
имеют модульную матричную структуру.
Каждая комбинационная ступень реализации сложной функции вносит свой вклад в суммарную
задержку распространения сигнала. В результате приходиться учитывать ограничения, связанные
с слишком длинными цепями распространения сигналов. Использование соответствующих
приемов описания устройств (coding style) позволяет улучшить временные характеристики
спроекированного устройства.
Рассмотрим способы снижения числа ступеней вычисления сложной функции (Reducing Logic
Levels) для уменьшения длины критических путей распространения сигнала (Critical Paths). Ниже
приводятся примеры оптимального проектирования таких устройств.
Пример 1. В данном примере сигнал “critical” (Рис.6.19) проходит через три ступени (logic levels).
Рис.6.19.
Пример написан на языке VHDL.
if ((( Crtical='0' and Obi='1' and Sar='1')
or CpuG='0') and CpuR='0') then
Des <= Adr;
elsif (((Crtical='0' and Obi='1' and Sar='1')
or CpuG='0') and CpuR='1') then
Des <= Bdr;
elsif (Sar='0' and..........
В результате сигнал “critical” является запаздывающим. Чтобы уменьшить число ступеней
используем конструкцию if-then-else statement. В результате сигнал “critical” проходит только
через одну ступень как показано на Рис.6.20
Рис.6.20
if (Critical='0') then
if (((Obi='1' and Sar='1')
or CpuG='0') and CpuR='0') then
Des <= Adr;
elsif (((Obi='1' and Sar='1')
or CpuG='0' and CpuR='1') then
Des <= Bdr;
end if;
end if;
Пример 2. В данном случае сигнал, обозначенный “critical” (Рис.6.21), проходит через две
ступени.
Рис.6.21.
if (clk'event and clk ='1') then
if (non_critical and critical) then
out1 <= in1
else
out1 <= in2
end if;
end if;
Для уменьшения числа ступений для сигнала “critical”, используем мультиплексирование
входных сигналов “in1” и “in2” используя для управления мультиплексором сигнал
“non_critical”. Выход мультиплексора затем мультиплексируется с входом “in2” при управлении
сигналом “critical”. В итоге сигнал “critical” проходит только через одну ступень задержки
(Рис.6.22)
Рис.6.22
Реализация на VHDL приведена ниже
signal out_temp : std_logic
if (non_critical)
out_temp <= in1;
else out_temp <= in2;
if (clk'event and clk ='1') then
if (critical) then
out1 <= out_temp;
else out1 <= in2;
end if;
end if;
end if;
6.10. Совместное использование ресурсов
Другим путем повышения эффективности описаний цифровых устройств является совместное
использование ресурсов (Resource Sharing). Совместное использование ресурсов позволяет
снизить число логических элементов для реализации операторов на языках описания аппаратуры.
Ниже приводяться два примера совместного использования ресурсов. Примеры написаны на
Пример 1. Реализация четырех сумматоров (счетчиков)
if (...(siz == 1)...)
count = count + 1;
else if (...((siz ==2)...)
count = count + 2;
else if (...(siz == 3)...)
count = count + 3;
else if (...(siz == 0)...)
count = count + 4;
Покажем, как можно избавиться от двух «лишних» счетчиков
if (...(siz == 0)...)
count = count + 4;
else if (...)
count = count + siz
Пример 2. В данном примере используется неполное совместное использование ресурсов для
реализации сумматоров (Рис.6.23).
Рис.6.23.
if (select)
sum<=A +B;
else
sum<=C +D;
Сумматоры занимают значительные ресурсы, для их уменьшения переписываем код с целью
ввести два мультиплексора и один сумматор, как показано ниже (Рис.6.24).
Рис.6. 24.
if (sel)
temp1 <= A;
temp2 <= B;
else
temp1 <= C;
temp2 <= D;
sum <= temp1 + temp2;
Следует помнить, что в данном примере сигнал выбора «sel» не является запаздывающим
сигналом
Еще одним способом организации совместного использования ресурсов является использование
операторов цикла
Арифметические операторы и мультиплексоры занимают значительные ресурсы. Если имеется
оператор внутри цикла, программа синтеза должна оценить все состояния. В следующем
примере на языке VHDL описываются четыре сумматора и один мультиплексор. Такая
реализация может быть рекомендована только, если сигнал выбора "req" – запаздывающий
сигнал (Рис.6.25).
Рис.6.25.
vsum := sum;
for i in 0 to 3 loop
if (req(i)='1') then
vsum <= vsum + offset(i);
end if;
end loop;
Если сигнал выбора “req” не является критическим, оператор может быть вынесен за пределы
цикла, что приведет к тому, что вместо четырех сумматоров будет использован один (Рис.6.26)
Рис.6.26
Пример описания приведен ниже
vsum := sum;
for i in 0 to 3 loop
if (req(i)='1') then
offset_1 <= offset(i);
end if;
end loop;
vsum <= vsum + offset_1;
Использование кодирования для сочетаемости (Coding for Combinability)
Использование кодирования для сочетаемости (Coding for Combinability) также позволяет
выкроить ресурсы ПЛИС.
Для ПЛИС некоторых архитектур возможно выполнение всей логики работы, как
комбинационной, так и последовательностной в пределах одного логического элемента (ячейки),
что значительно снижает задержки по критическим путям и экономит ресурсы.
Однако следует помнить, что такое объединение возможно только в том случае, если
комбинационная схема управляет только одним триггером. В приведенном примере описания на
VHDL элемент AND формирует управляющий сигнал для двух триггеров (Рис.6.27), что
препятствует введению элемента AND в последовательностный модуль
Рис.6.27
one :process (clk, a, b, c, en) begin
if (clk'event and clk ='1') then
if (en = '1') then
q2 <= a and b and c;
end if;
q1 <= a and b and c;
end if;
end process one;
Для того, чтобы объединить схему внутри одного элемента и убрать внешние цепи удобно
использовать дублирование логического элемента AND, уменьшая тем самым критические пути
распространения сигнала (Рис.6.28).
Рис.6.28.
part_one: process (clk, a, b, c, en) begin
if (clk'event and clk ='1') then
if (en = '1') then
q2 <= a and b and c;
end if;
end if;
end process part_one;
part_two: process (clk, a, b, c) begin
if (clk'event and clk ='1') then
q1 <= a and b and c;
end if;
end process part_two;
6.12. Дублирование регистра.
Задержка в цепи распространения сигнала возрастает с увеличением числа входов, нагруженных
на эту цепь. Такая ситуация еще может быть приемлема для цепей сброса, но для цепей
разрешения это недопустимо. Пример такой ситуации приведен ниже (Рис.6.29). В данном VHDL
примере коэффициент разветвления сигнала разрешения "Tri_en" равен 24.
Рис.6.29.
architecture load of four_load is
signal Tri_en std_logic;
begin
loadpro: process (Clk)
begin
if (clk'event and clk ='1') then
Tri_end <= Tri_en;
end if;
end process loadpro;
endpro : process (Tri_end, Data_in)
begin
if (Tri_end = '1') then
out <= Data_in;
else
out <= (others => 'Z');
end if;
end process endpro;
end load;
Число разветвлений (fanout) можно уменьшить вдвое, используя два регистра (Рис.6.30)
Рис.6.30
Ниже приведен пример реализации дублирования регистров на VHDL.
architecture loada of two_load is
signal Tri_en1, Tri_en2 : std_logic;
begin
loadpro: process (Clk)
begin
if (clk'event and clk ='1') then
Tri_en1 <= Tri_en;
Tri_en2 <= Tri_en;
end if;
end process loadpro;
process (Tri_en1, Data_in)
begin
if (Tri_en1 = '1') then
out(23:12) <= Data_in(23:12);
else
out(23:12) <= (others => 'Z');
end if;
end process;
process (Tri_en2, Data_in)
begin
if (Tri_en2 = '1') then
out(11:0) <= Data_in(11:0);
else
out(11:0) <= (others => 'Z');
end if;
end process;
Разделение проекта на части оптимальных размеров позволяет обеспечить оптимальное
использование ресурсов за счет их оптимизации при синтезе. Известно, что подавляющее
большинство программ синтеза достигают наиболее приемлимого результата при размере блока
порядка 2-5 тысяч эквивалентных вентилей.
Приведенный ниже пример показывает как можно сэкономить ресурсы путем замены
встроенного в модуль регистра(Рис.6.31) на выделенный регистр (рис 3.32)
Рис.6.31
process (clk, a, b) begin
if (clk'event and clk = '1') then
a1 <= a;
b1 <=b;
end if;
end process;
process (a1, b1)
begin c <=a1 +b1;
end process;
Рис.6.32
process (clk, a, b) begin
if (clk'event and clk = '1') then
c <=a +b;
end if;
end process;
6.13.Создание описаний с учетом особенностей архитектуры ПЛИС (Technology
Specific Coding Techniques).
Помимо способов создания описаний, независимых от используемой элементной базы и ее
архитектурных особенностей, в практике проектирования устройств на ПЛИС применяется так
называемое создание описаний с учетом особенностей архитектуры ПЛИС (Technology Specific
Coding Techniques).
Рассмотрим некоторые примеры проектирования цифровых устройств для использования с
учетом особенностей архитектуры FPGA ПЛИС.
Для реализации мультиплексоров как правило применяется конструкция case, что значительно
выгоднее с точки зрения быстродействия и затрат ресурсов, чем конструкция if-then-else.
Большинство производителей ПЛИС рекоммендуют использовать оператор case.
Как правило, при реализации на ПЛИС внутренняя шина с тремя состояниями эмулируется как
мультиплексор. Пример эмуляции шины в виде мультиплексора приведен на Рис.6.33
Рис.6.33
Пример эмуляции шины на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity tribus is
port (A, B, C, D : in std_logic_vector(7 downto 0);
E0, E1, E2, E3 : in std_logic;
Q :out std_logic_vector(7 downto 0));
end tribus;
architecture rtl of tribus is
begin
Q <=Awhen(E0 = '1') else "ZZZZZZZZ";
Q <=Bwhen(E1 = '1') else "ZZZZZZZZ";
Q <=Cwhen(E2 = '1') else "ZZZZZZZZ";
Q <=Dwhen(E3 = '1') else "ZZZZZZZZ";
end rtl;
Мультиплексор на VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity muxbus is
port (A, B, C, D : in std_logic_vector(7 downto 0);
E0, E1, E2, E3 : in std_logic;
Q :out std_logic_vector(7 downto 0));
end muxbus;
architecture rtl of muxbus is
signal E_int : std_logic_vector(1 downto 0);
begin
process (E0, E1, E2, E3)
variable E : std_logic_vector(3 downto 0);
begin
E :=E0 &E1 &E2 &E3;
case E is
when "0001" => E_int <= "00";
when "0010" => E_int <= "01";
when "0100" => E_int <= "10";
when "1000" => E_int <= "11";
when others => E_int <= "--";
end case;
end process;
process (E_int, A, B, C, D)
begin
case E_int is
when "00" => Q <= D;
when "01" => Q <= C;
when "10" => Q <= B;
when "11" => Q <= A;
when others =>Q <=(others => '-');
end case;
end process;
end rtl;
Эмуляция шины на Verilog
module tribus (A, B, C, D, E0, E1, E2, E3, Q);
input [7:0]A, B, C, D;
output [7:0]Q;
input E0, E1, E2, E3;
assign Q[7:0] = E0 ? A[7:0] : 8'bzzzzzzzz;
assign Q[7:0] = E1 ? B[7:0] : 8'bzzzzzzzz;
assign Q[7:0] = E2 ? C[7:0] : 8'bzzzzzzzz;
assign Q[7:0] = E3 ? D[7:0] : 8'bzzzzzzzz;
endmodule
Реализация мультиплексора на Verilog
module muxbus (A, B, C, D, E0, E1, E2, E3, Q);
input [7:0]A, B, C, D;
output [7:0]Q;
input E0, E1, E2, E3;
wire [3:0] select4;
reg [1:0] select2;
reg [7:0]Q;
assign select4 = {E0, E1, E2, E3};
always @ (select4)
begin
case(select4)
4'b0001 : select2 = 2'b00;
4'b0010 : select2 = 2'b01;
4'b0100 : select2 = 2'b10;
4'b1000 : select2 = 2'b11;
default : select2 = 2'bxx;
endcase
end
always @ (select2 or A or B or C or D)
begin
case(select2)
2'b00 :Q =D;
2'b01 :Q =C;
2'b10 :Q =B;
2'b11 :Q =A;
endcase
end
endmodule
Несколько примеров хотелось бы привести по реализации устройств памяти
Приведенный ниже пример иллюстрирует описание статической памяти (SRAM) на VHDL для
реализации на ПЛИС, не имеющих встроенных блоков памяти. В ряде случаев этот прием
позволяет не выходя за рамки одного устройствареализовать небольшой буфер. Пример
реализован на VHDL
-- *************************************************
-- Behavioral description of a single-port SRAM with:
-- Active High write enable (WE)
-- Rising clock edge (Clock)
-- *************************************************
library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity reg_sram is
generic (width : integer:=8;
depth : integer:=8;
addr : integer:=3);
port (Data : in std_logic_vector (width-1 downto 0);
Q :out std_logic_vector (width-1 downto 0);
Clock : in std_logic;
WE : in std_logic;
Address : in std_logic_vector (addr-1 downto 0));
end reg_sram;
architecture behav of reg_sram is
type MEM is array (0 to depth-1) of std_logic_vector(width-1
downto 0);
signal ramTmp : MEM;
begin
process (Clock)
begin
if (clock'event and clock='1') then
if (WE = '1') then
ramTmp (conv_integer (Address)) <= Data;
end if;
end if;
end process;
Q <= ramTmp(conv_integer(Address));
end behav;
Модель на Verilog имеет вид
`timescale 1 ns/100 ps
//########################################################
//# Behavioral single-port SRAM description :
//# Active High write enable (WE)
//# Rising clock edge (Clock)
//#######################################################
module reg_sram (Data, Q, Clock, WE, Address);
parameter width = 8;
parameter depth = 8;
parameter addr = 3;
input Clock, WE;
input [addr-1:0] Address;
input [width-1:0] Data;
output [width-1:0] Q;
wire [width-1:0] Q;
reg [width-1:0] mem_data [depth-1:0];
always @(posedge Clock)
if(WE)
mem_data[Address] = #1 Data;
assign Q = mem_data[Address];
endmodule
Следующий пример иллюстрирует создание модели двупортовой статической памяти (Dual-Port
SRAM). Описывается модуль 8 х 8 ячеек.
Описание на VHDL имеет вид
-- Behavioral description of dual-port SRAM with :
-- Active High write enable (WE)
-- Active High read enable (RE)
-- Rising clock edge (Clock)
library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity reg_dpram is
generic (width : integer:=8;
depth : integer:=8;
addr : integer:=3);
port (Data : in std_logic_vector (width-1 downto 0);
Q :out std_logic_vector (width-1 downto 0);
Clock : in std_logic;
WE : in std_logic;
RE : in std_logic;
WAddress: in std_logic_vector (addr-1 downto 0);
RAddress: in std_logic_vector (addr-1 downto 0));
end reg_dpram;
architecture behav of reg_dpram is
type MEM is array (0 to depth-1) of std_logic_vector(width-1
downto 0);
signal ramTmp : MEM;
begin
-- Write Functional Section
process (Clock)
begin
if (clock'event and clock='1') then
if (WE = '1') then
ramTmp (conv_integer (WAddress)) <= Data;
end if;
end if;
end process;
-- Read Functional Section
process (Clock)
begin
if (clock'event and clock='1') then
if (RE = '1') then
Q <= ramTmp(conv_integer (RAddress));
end if;
end if;
end process;
end behav;
Модель двупортовой памяти на Verilog
`timescale 1 ns/100 ps
//########################################################
//# Behavioral dual-port SRAM description :
//# Active High write enable (WE)
//# Active High read enable (RE)
//# Rising clock edge (Clock)
//#######################################################
module reg_dpram (Data, Q, Clock, WE, RE, WAddress, RAddress);
parameter width = 8;
parameter depth = 8;
parameter addr = 3;
input Clock, WE, RE;
input [addr-1:0] WAddress, RAddress;
input [width-1:0] Data;
output [width-1:0] Q;
reg [width-1:0] Q;
reg [width-1:0] mem_data [depth-1:0];
// ######################################################
// # Write Functional Section
// ######################################################
always @(posedge Clock)
begin
if(WE)
mem_data[WAddress] = #1 Data;
end
//####################################################
//# Read Functional Section
//####################################################
always @(posedge Clock)
begin
if(RE)
Q = #1 mem_data[RAddress];
end
endmodule
Download