Macchine a stati, memorie e funzioni in VHDL
Macchine a stati in VHDL
Section titled “Macchine a stati in VHDL”Per realizzare una macchina a stati in VHDL, possiamo separare la parte sequenziale e quella combinatoria. In particolare, la prima sarà un registro a molti bit e la seconda verrà divisa in 2 parti, una per il calcolo dello stato futuro e l’altra per le uscite.

Derivatore
Section titled “Derivatore”Realizziamo il derivatore, nell’implementazione come macchina di Moore.
library ieee;use ieee.std_logic_1164.all;
entity derivatore is port ( s, clk, res : in std_logic; y : out std_logic; );end;
architecture behavioral of derivatore is -- Lo stato è un enum, in modo da non dover specificare subito la codifica. -- Non è sempre supportato dai sintetizzatori. Una soluzione più portatile -- sarebbe quella di usare costanti esplicite. type stato is (a, b, c, d); signal present_state, next_state : stato;begin -- Parte sequenziale del derivatore. seq: process (res, clk) is begin -- Segnale di reset asincrono. if res = '0' then -- a è lo stato iniziale. present_state <= a; elsif rising_edge(clk) then -- Al fronte del clock lo stato futuro diventa il presente. present_state <= next_state; end; end;
futuro: process (present_state, s) is begin -- Nei processi si usa case. case present_state is when a => if s = '0' then next_state <= a; else next_state <= b; end; when b => next_state <= c; when c => if s = '0' then next_state <= d; else next_state <= c; end; when d => next_state <= a;
-- Se ci fossero varianti rimanenti, si userebbe `when others =>`. end; end;
uscite: process (present_state) is begin y <= '0';
if present_state = b or present_state = d then y <= '1'; end; end;end;present_state viene sintetizzato come un insieme di flip-flop perché in alcuni
casi il processo combinatorio non gli assegna un valore.
Memorie
Section titled “Memorie”Quando si progetta un circuito si possono usare diversi tipi di memoria:
- ROM: read-only memory;
- RAM: random-access memory;
Normalmente la memoria non viene sintetizzata (verrebbe un circuito troppo grande). Si implementa manualmente o con specifici generatori automatici.
Può essere utile però esprimere delle memorie in VHDL per eseguire le simulazioni.
Una memoria ROM è semplicemente un array di valori indicizzato da un integer (indirizzo).
library ieee;use ieee.std_logic_1164.all;
entity ROM is port ( address : in integer range (0 to 15); data : out std_logic_vector(7 downto 0); );end;
architecture dataflow of ROM is type rom_array is array(0 to 15) of std_logic_vector(7 downto 0); constant rom : rom_array := ( "01010101", "10101010", -- ... "11111111", "00110011", );begin data <= rom(address) after 10ns;end;Con una ROM si può implementare una tabella della verità. Di conseguenza qualsiasi circuito combinatorio può essere implementato come una ROM.
Creiamo una RAM asincrona, con i seguenti segnali:
- bus dati di tipo
inout; cs: chip select, per segnalare che la memoria può usare il bus dati;oe: output enable, per abilitare la lettura dalla RAM;we: write enable, per abilitare la scrittura sulla RAM;
library ieee;use ieee.std_logic_1164.all;
entity RAM is port ( address : in integer range (0 to 15); data : inout std_logic_vector(7 downto 0); cs, oe, we : in std_logic; );end;
architecture behavioral of RAM isbegin process (address, cs, we, oe, data) is type ram_array is array(0 to 15) of std_logic_vector(7 downto 0); variable mem : ram_array; begin data <= (others => 'Z');
if cs = '0' then if oe = '0' then data <= mem(address); elsif we = '0' then mem(address) <= data; end; end; end;end;Bisogna fare attenzione a come viene pilotato l’ingresso dati, dato che esso sarà condiviso con altre periferiche.
Funzioni
Section titled “Funzioni”In VHDL una funzione è uno strumento che serve solo a modulare il codice.
I parametri sono solamente ingressi. È possibile ritornare un valore con la
parola chiave return.
Gli statement vengono eseguiti sequenzialmente, come in un processo. A differenza dei processi, viene eseguita solo quando viene chiamata, non quando cambia il valore dei parametri in ingresso.
library ieee;use ieee.std_logic_1164.all;
entity s is port ( p1, q1 : in std_logic_vector(7 downto 0); p2, q2 : in std_logic_vector(3 downto 0); y1 : out std_logic_vector(7 downto 0); y2 : out std_logic_vector(3 downto 0); );end;
architecture behavioral of s is function add(a, b : in std_logic_vector) return std_logic_vector is variable s : std_logic_vector(a'range); variable carry : std_logic; begin carry := '0'; for i in a'range loop s(i) := a(i) xor b(i) xor carry; carry := (a(i) and b(i)) or (carry and a(i)) or (carry and b(i)); end; return s; end;begin y1 <= add(p1, q1); y2 <= add(p2, q2);end;Procedure
Section titled “Procedure”Le procedure sono simili alle funzioni, ma possono ritornare più di un valore.
I parametri possono essere di tipo in, out o inout.
procedure somma( a, b : in std_logic_vector; y : out std_logic_vector; cout : out std_logic;) is variable carry : std_logic;begin carry := '0'; for i in a'range loop y(i) := a(i) xor b(i) xor carry; carry := (a(i) and b(i)) or (carry and a(i)) or (carry and b(i)); end; cout := carry;end;Uscite registrate
Section titled “Uscite registrate”Nelle macchine di Moore può essere utile fare in modo che le uscite del circuito corrispondano alle uscite di qualche flip-flop. In questo modo esse si aggiornano subito dopo il fronte del clock e non presentano glitch.
Per evitare ulteriori ritardi, è possibile calcolare il valore delle uscite a partire dallo stato futuro.
