Najczęściej popełniane błędy w VHDL’u

Download Report

Transcript Najczęściej popełniane błędy w VHDL’u

Najczęściej popełniane błędy w
VHDL’u
Ernest Jamro
Kat. Elektroniki
AGH
Wzory poprawnej syntezy
• ActiveHDL: Menu/Tools/Language
Assistant: Synthesis Templates
• ISE Procject Navigator:
Menu/Edit/Language Templates:
VHDL / Synthesis Constructs / (Coding
Example)
Poprawna składnia przerzutnika
typu D
process (CLK, RESET)
begin
if RESET='1' then – reset asynchroniczny
DOUT <= '0';
elsif (CLK'event and CLK='1') then
DOUT <= DIN;
end if;
end process;
Najczęstsze błędy
process (CLK, RESET) – brak sygnału reset
begin
if RESET='1' then – reset asynchroniczny
DOUT <= '0';
elsif (CLK'event and CLK='1') then
DOUT <= DIN;
end if;
end process;
Przerzutnik D z Clock Enable (CE)
process (<clock>, <reset>)
begin
if <reset>=‘1' then
<output> <= '0';
elsif (<clock>'event and <clock>='1') then
if <clock_enable> = '1' then -- lub inna logika synchroniczna
<output> <= <input>;
end if;
end if;
end process;
Błędy: Przerzutnik z CE
process (<clock>, <reset>, <clock_enable>)
begin
if <reset>='0' then
<output> <= '0';
elsif (<clock>'event and <clock>='1‘ and <clock_enable> = '1' )
<output> <= <input>;
end if;
end process;
Błąd: Wymuszenie tego samego sygnału w
dwóch procesach
A0: process(...) begin
....
if ( ...)
a<= ‘0’;
end if;
end process;
A1: process(...) begin
....
if ( ...)
a<= ‘1’;
end if;
end process;
Przerzutnik typu Latch
process (GATE, DIN)
begin
if GATE='1' then --GATE active High
DOUT <= DIN;
end if;
end process;
Przerzutników Latch należy raczej unikać – z reguły powstają one
w wyniku błędu a nie zamierzonego projektowania
Multiplekser (lub inna logika kombinacyjna)
process (SEL, A, B, C)
begin
case SEL is
when "00" => MUX_OUT <= A;
when "01" => MUX_OUT <= B;
when "10" => MUX_OUT <= C;
when others => MUX_OUT <= 'X';
end case;
end process;
Multiplekser Błędy
process (SEL, A, B, C) – brak jednego z sygnałów wejściowych (latch)
begin
case SEL is
when "00" => MUX_OUT <= A;
when "01" => MUX_OUT <= B;
when "10" => MUX_OUT <= C;
when others => MUX_OUT <= 'X';
end case;
end process;
Process – magiczne słowo
Poza procesem nie można używać następujących składni:
If ... Then ... Elsif ... End if
For .... Loop
Uwaga: Wiele operacji (szczególnie logiki kombinacyjnej) można
umieścić poza procesem
Alternatywne rozwiązanie
Multiplekser
Mux_out<= A when sel = "00" else
B when sel = "01" else
C when sel = "10" else '-';
LUB
WITH sel SELECT
Mux_out <= A when "00",
B when "01",
C when "10"
'-' when others;
Umiejscawianie komponentów 1
entity FULL_ADDER
port
( a, b, cin: in std_logic;
s, cout: out std_logic);
end FULL_ADDER;
architecture arch of FULL_ADDER is
begin
s<= a xor b xor c;
cout<= a when a=b else cin;
end arch;
Umiejscawianie komponentów 2
entity MY_ADDER
generic (width: integer);
port ( a, b: in std_logic_vector(0 to width-1);
s: out std_logic_vector(0 to width-1);
end MY_ADDER;
architecture arch of MY_ADDER is
component FULL_ADDER -- deklaracja komponentu
port
( a, b, cin: in std_logic;
s, cout: out std_logic);
end component;
signal carry: std_logic_vector(0 to dwidth);
begin
Umiejscawianie komponentów 3
Ciąg dalszy z poprzedniej strony (rozwiązanie nieoptymalne)
Carry(0)<= ‘0’;
Gi: for i in 0 to width-1 generate – wielokrotne użycie elementu!
g: full_adder
port map (a=> a(i), b=> b(i), cin=> carry(i),
cout=> carry(i+1), s=> s(i));
end generate;
end arch;
Lepsze rozwiązanie (użyta dedykowana logika dodająca)
s<= a+ b;
Wartości domyślne, uaktualnienie modułów
Stary komponent
component and_gate port
( din1, din2: in std_logic;
dout: out std_logic);
end component;
Nowy komponent
component and_gate
generic (invert_output: integer:= 0); -- dodanie dodatkowego parametru
port
( din1, din2, din3: in std_logic:= ‘1’; -- wartość domyślna ‘1’
dout: out std_logic);
end component;
Użycie zmodyfikowanego komponentu
Stary kod używa nowego elementu z nowymi wartościami w formie
domyślnej
A: and_gate
port map (din1=> a, din2=> b, dout => y);
Równoważne i zalecane w nowym kodzie:
A: and_gate
generic map (invert_output=>0)
port map (din1=> a, din2=> b, din3=> ‘1’, dout => y);
Po co wartości domyślne
•Rozważany element jest elementem nadrzędnym podczas
symulacji lub implementacji
•Zgodność z poprzednimi wersjami tego samego elementu bez
konieczności zmiany całego starego kodu
Ustawianie wartości parametrów
Architecture arch of my_gate is
component and_gate
generic (invert_output: integer:= 1); -- nie zmieniamy wartości parametru tutaj
port
( din1, din2, din3: in std_logic:= ‘0’; -- nie zmieniamy wartości domyślnej tutaj
dout: out std_logic);
end component;
begin
a: and_gate -- użycie elementu
generic map (invert_output=> 1) -- umieszczamy wartość każdego parametru
port map (din1=> a, din2=> b, din3=> ‘0’); -- staramy się określić wartość każdego wejścia
End arch;
Dodawanie bibliotek
library ieee;
use ieee.std_logic_1164.all; -- użycie std_logic
use ieee.std_logic_unsigned.all; -- każda wartość std_logic_vector
jest traktowana jako integer bez znaku
use ieee.std_logic_signed.all; -- każda wartość std_logic_vector jest
traktowana jako integer ze znaku
Nie można równocześnie użyć obu bibliotek: std_logic_unsigned
oraz std_logic_signed. W tym wypadku należy użyć biblioteki:
use ieee.std_logic_arith.all;
oraz zamiast słowa kluczowego std_logic_vector należy użyć słów
unsigned lub signed (wada: konieczność używania konwersji
std_logic_vector  unsigned (lub signed))
Programowanie pod kątem sprzętu
Pamięć RAM 16x1 (distributed RAM)
type mem_type is array (0 to 15) od std_logic_vector(0 to 7)
signal mem: mem_type;
begin
process (<clock>)
begin
if (<clock>'event and <clock> = '1') then
if (<write_enable> = '1') then
mem(conv_integer(<address>)) <= <input_data>;
end if; end if;
end process;
<ram_output> <= mem(conv_integer(<address>));
Programowanie pod kątem sprzętu
Pamięć blokowa BRAM (dwuportowa)
PortA: process (<clockA>) begin
if (<clockA>'event and <clockA> = '1') then
if (<write_enableA> = '1') then
<ram_name>(conv_integer(<addressA>)) <= <input_dataA>;
end if;
<addressA_sig> <= <addressA>;
end if;
end process;
PortB: process (<clockB>) begin
if (<clockB>'event and <clockB> = '1') then
<addressB_sig> <= <addressB>;
end if;
end process;
<ram_outputA> <= <ram_name>(conv_integer(<addressA_sig>));
<ram_outputB> <= <ram_name>(conv_integer(<addressB_sig>));
Programowanie pod kątem sprzętu
Biblioteka: unisim a pamięć blokowa BRAM
entity RAMB16_S36_S36 is
generic (
INIT_00 : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000";
....
INIT_3F : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000"
);
port(
DOA : out STD_LOGIC_VECTOR (31 downto 0);
DOB
: out STD_LOGIC_VECTOR (31 downto 0);
DOPA : out STD_LOGIC_VECTOR (3 downto 0);
DOPB
: out STD_LOGIC_VECTOR (3 downto 0);
ADDRA : in STD_LOGIC_VECTOR (8 downto 0); ADDRB : in STD_LOGIC_VECTOR (8 downto 0);
CLKA : in STD_ULOGIC;
CLKB : in STD_ULOGIC;
DIA : in STD_LOGIC_VECTOR (31 downto 0);
DIB : in STD_LOGIC_VECTOR (31 downto 0);
DIPA : in STD_LOGIC_VECTOR (3 downto 0);
DIPB : in STD_LOGIC_VECTOR (3 downto 0);
ENA : in STD_ULOGIC;
ENB : in STD_ULOGIC;
SSRA : in STD_ULOGIC;
SSRB : in STD_ULOGIC;
WEA : in STD_ULOGIC; WEB
);
: in STD_ULOGIC
Programowanie pod kątem sprzętu
Biblioteka unisim: Pętla DLL (delay lock loop – działająca podobnie jak PLL)
entity CLKDLL is
port (
CLK0
: out std_ulogic := '0';
CLK180 : out std_ulogic := '0';
CLK270 : out std_ulogic := '0';
CLK2X : out std_ulogic := '0';
CLK90 : out std_ulogic := '0';
CLKDV : out std_ulogic := '0';
LOCKED : out std_ulogic := '0';
CLKFB : in std_ulogic := '0';
CLKIN : in std_ulogic := '0';
RST
: in std_ulogic := '0‘ )
Programowanie pod kątem sprzętu
library UNISIM;
use unisim.all; -- for global set reset signal
component ROC
port ( O : out std_ulogic := '1' );
end component
Każdy przerzutnik powinien być zerowany (ustawiany) asynchronicznie tym
sygnałem – jest to potrzebne zarówno do celów symulacyjnych jak i dla potrzeb
ustawiania (wartość ‘1’) po procesie konfiguracji.
Reset synchroniczny i asynchroniczny
•Reset asynchroniczny należy używać jako reset inicjalizujący
pracę układu FPGA po konfiguracji – jest on wspomagany
sprzętowo
•Reset synchroniczny (np. opb_rst) należy używać jako sygnał
zerujący w pozostałych przypadkach np. podczas zerowania
liczników, powtórnej inicjalizacji automatów, itd.
•Nie należy mieszać resetów synchronicznych i asynchronicznych
Poziomy logiczne
Standard std_logic zawiera wiele poziomów nie tylko ‘0’, ‘1’, co
może powodować inne zachowanie układu podczas symulacji
funkcjonalnej, po syntezie i w rzeczywistym układzie. Przykład:
if ce=‘1’ then
Q<= D;
end if;
Co się stanie jeżeli dana wejściowa ce jest typu: ‘H’, ‘X’, ‘Z’ itd
Operacje na wektorach przesunięcia
signal a, b: std_logic_vector(dwidth-1 downto 0); -- deklaracja wektorów, dwidth- szerokość wektora
Przesuniecie o jeden bit w lewo (pomnożenie przez 2):
a<= b(dwidth-2 downto 0) & ‘0’
Przesuwający o jeden bit w prawo (dzielenie liczb dodatnich przez 2):
a<= ‘0’ & ‘b(dwidth-1 downto 1) ;
Dzielenie liczb w kodzie uzupełnień do 2 przez 2:
a<= b(dwidth-1) & b(dwidth-1) & b(dwidth-2 downto 1); -- kopiowanie bitu znaku b(dwidth-1)
Przesunięcie o n-bitów w lewo (n- constant lub generic):
a(dwidth-1 downto n)<= b(dwidth-1-n downto 0);
a(n-1 downto 0)<= (others=>’0’);
Podzielenie przez 2n liczby w kodzie U2:
a(dwidth-1 downto dwidth-n-1)<= (others=> b(dwidth-1));
a(dwidth-2-n downto 0)<= b(dwidth-2 downto n);
Operacje logiczne na wektorach
signal c, a, b: std_logic_vector(dwidth-1 downto 0); -- deklaracja wektorów
c<= a and b;
Równoważne:
Gi: for i in 0 to dwidth-1 generate
c(i)<= a(i) and b(i);
end generate;
Operacje logiczne w ramach jednego wektora
Operacje logicze w ramach jednego wektora:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_MISC.all; -- dodatkowa biblioteka
signal a: std_logic_vector(dwidth-1 downto 0);
signal y: std_logic;
y<= OR_REDUCE(a);
Równoważne:
y<= a(0) or a(1) or a(2) or ..... or a(dwidth-1);
Równoważne:
Process(a)
variable b: std_logic;
begin
b:= ‘0’;
for i in 0 to dwidth-1 loop
b:= b or a(i);
end loop;
end process;