Calcolatori Elettronici M Modulo 2 04 - Mapping di un progetto … - Mapping_di... · 4 Nel corso...
-
Upload
nguyenmien -
Category
Documents
-
view
221 -
download
0
Transcript of Calcolatori Elettronici M Modulo 2 04 - Mapping di un progetto … - Mapping_di... · 4 Nel corso...
1
Calcolatori Elettronici M Modulo 2
04 - Mapping di un progetto VHDL
su FPGA
In collaborazione con: Davide Nanni*, Andrea Bucaletti e Domenico Di Carlo
2
L’obiettivo di questa lezione è mostrare come sia possibile (e facile) sintetizzare del codice VHDL su una FPGA utilizzando (nel caso specifico):
• l’ambiente di sviluppo (ISE Xilinx)
• una development board (StarterKit Xilinx)
La development board utilizzata contiene una FPGA di classe Spartan 3E con le seguenti caratteristiche(**):
• Xilinx XC3S500E*
• 232 user-I/O pins
• 320-pin FBGA package
• oltre 10,000 logic cells
Sul sito del corso sono disponibili: il datasheet del dispositivo (XC3S500E), la user guide della development board e il codice utilizzato oggi (**) Sono disponibili per gli interessati anche dev board basate su Spartan 6
3
Mapping su FPGA: fasi di progettazione
Design Entry (VHDL)
Compilazione
Simulazione
NO
SI
Funzionamento previsto?
Mapping su FPGA
Oggi esamineremo questo aspetto in dettaglio !
(1)
(2)
(3)
(4)
4
Nel corso di questa presentazione verrà descritto il progetto VHDL che si intende sintetizzare sulla scheda. Il progetto consiste in un semplice contatore modulo 256 dotato dei seguenti comandi (SINCRONI): ENABLE : (en) RESET : (reset), prioritario rispetto ad ENABLE UP/DOWN* : (ud)
La sintesi del contatore sulla developmet board verrà mostrata in due differenti realizzazioni: - mostrando l’output del contatore su 8 LED
- mostrando l’output del contatore e i comandi su LCD
5
Contatore modulo 256: codice VHDL (1) e (2)
entity Counter is
port (
clk : in std_logic; -- clock
reset : in std_logic; -- reset
en : in std_logic; -- enable
ud : in std_logic; -- up/down*
o : out std_logic_vector(7 downto 0) -- output[255 … 0]
);
end Counter;
COUNTER X 256
EN
RES
U/D*
O[7..0] O[7..0] en reset
ud
clk
6
architecture Arch1_Counter of Counter is -- segnale utilizzato internamente per memorizzare lo stato signal o_buffer: std_logic_vector(7 downto 0) := (others => '0'); begin
sync: process(clk) begin
-- attende il fronte positivo del clock
if (clk = '1‘) and (clk'event) then if reset = '1' then -- reset prioritario sull'enable o_buffer <= (others => '0'); else if en = '1' then – enable asserito
if ud = '1' then -- up o_buffer <= o_buffer + 1;
else -- down o_buffer <= o_buffer - 1; end if; end if; end if; end if; end process;
o <= o_buffer; -- assegna lo stato all’uscita
end Arch1_Counter;
7
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity Counter_Test is end Counter_Test; architecture Test of Counter_Test is component Counter
port ( clk: in std_logic; -- clock reset: in std_logic; -- reset en: in std_logic; -- enable ud: in std_logic; -- up/down* o: out std_logic_vector(7 downto 0)); -- output end component; signal clk, reset, en, ud: std_logic := '0'; signal o: std_logic_vector(7 downto 0); begin uut: Counter port map (clk => clk, reset => reset, en => en, ud => ud, o => o); 1/2
Contatore modulo 256: testbench (3)
8
clk_process: process begin clk <= '0'; wait for 20 ns; clk <= '1'; wait for 20 ns; end process; stim_process: process begin reset <= '1'; wait for 95 ns; reset <= '0'; en <= '1'; ud <= '1'; wait for 310 ns; ud <= '0'; wait for 110 ns; ud <= '1'; wait for 1 us; en <= '0'; wait for 210 ns; end process; end Test; 2/2
9
Contatore modulo 256: simulazione (3)
Dopo aver scritto il testbench si analizza il risultato della simulazione verificando che il comportamento della rete sia quello desiderato (ripetendo eventualmente, se necessario, i passi (1), (2) e (3)). Una volta che è stato verificato (mediante simulazione) il corretto funzionamento è possibile effettuare (fase numero (4)) il mapping del progetto su FPGA...
10
Mapping su FPGA (4) Development board Spartan 3E Xilinx
USB (to host PC per configurazione)
LCD (2 righe)
LED (8x)
Clock 50 MHz
FPGA
Switch (4X)
11
Mapping dei segnali
Al fine di poter utilizzare nel codice VHDL i dispositivi presenti sulla scheda (clock, display leds, switches,etc) è necessario specificare un collegamento tra i segnali presenti sulla scheda e i segnali utilizzati dal nostro codice all’interno della FPGA. A tal proposito ogni segnale di input ed output del progetto vhdl (e.g. reset) può essere associato ad un pin fisico presente sulla scheda (e.g. K17). Per associare ad un segnale di I/O del proprio codice VHDL un segnale fisico presente sulla scheda è necessario fare una associazione (link) mediante una opportuna Sintassi definita nell’ambiente di sviluppo*. La lista completa di dei pin presenti sulla scheda è fornita dal manuale della development board*. Nella pagina successiva è mostrato quanto riportato nel manuale a proposito del clock a 50 MHz, dei tre Switch e dei led.
12
NET "clk_50mhz" LOC = "C9" | IOSTANDARD = LVCMOS33 ;
NET "switch<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ;
NET "switch<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
NET "switch<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ;
NET "LEDS<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "LEDS<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
Il manuale indica come il LEDS<0> sia connesso al pin «F12» della FPGA
13
Esempio: connettere all’ingresso di up/down(ud) del nostro contatore lo switch[1]: - A livello HARDWARE lo switch[1] è fisicamente saldato su un piedino denominato L14 infatti il manuale riporta:
NET " switch<1> " LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
Up/down ud in VHDL
- A livello software (VHDL) possiamo usare lo switch[1] dopo averlo mappato tramite l’ausilio del file UCF come un segnale VHDL qualsiasi.
Associazione segnali-pin
14
UCF User Constraint File
ENABLE en in VHDL
NET " en" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
-The UCF file is an ASCII file specifying constraints on the logical design
-These constraints affect how the logical design is implemented in the target device.
-Per associare il signal en allo switch<1> :
Aggiungendo il file UCF al progetto, in fase di implementazione il
compilatore associerà al segnale en il pin L14.
…from Xilinx help:
15
Andiamo ora a vedere in dettaglio come sia possibile sintetizzare il nostro contatore sulla development board Xilinx
COUNTER X 256
EN
RES
U/D*
O[7..0] O[7..0] en reset
ud
clk
Visualizzate sui led
16
Osservazione:
COUNTER X 256
EN
RES
U/D*
O[7..0] O[7..0] en reset
ud
clk
Se utilizzassimo direttamente il clk della scheda a 50Mhz il conteggio avverrebbe troppo
Velocemente e non lo potremmo apprezzare sui led!
Dobbiamo dividere il clk in ingresso Creiamo Clock_Divide
17
entity ClockDivide is port ( clk_in: in std_logic; -- clock da 20ns (50 MHz) clk_1: out std_logic; -- clock da 0.01 sec (circa) clk_2: out std_logic; -- clock da 0.17 sec (circa) clk_3: out std_logic -- clock da 0.67 sec (circa) );
end ClockDivide;
architecture Behavioral of ClockDivide is signal s_clk_1: std_logic := '0'; signal s_clk_2: std_logic := '0'; signal s_clk_3: std_logic := '0'; begin clk1_proc: process variable cont: integer := 1; begin wait until clk_in'event and clk_in = '1'; if (cont mod 2**19) = 0 then s_clk_1 <= not s_clk_1; end if; if (cont mod 2**22) = 0 then s_clk_2 <= not s_clk_2; end if; if (cont mod 2**25) = 0 then s_clk_3 <= not s_clk_3; end if; if (cont = 2**25) then cont := 1; else cont := cont + 1; end if; end process; clk_1 <= s_clk_1; clk_2 <= s_clk_2; clk_3 <= s_clk_3; end Behavioral;
Clock Divide
clk_in
clk_3
clk_2
clk_1
Clock Divide
18
Mettiamo insieme i due elementi:
COUNTER X 256
EN RESET
U/D*
O[7..0] Output_led En_input
Reset_input
Ud_input
clk_input
Clock Divide
Contatore_led
clk_in
clk_3
COMPONENT
19
entity contatore_led is port(
clk_input : in std_logic; -- clock reset_input : in std_logic; -- reset en_input : in std_logic; -- enable ud_input : in std_logic; -- up/down* output_led : out std_logic_vector(7 downto 0)
); end contatore_led;
architecture Archi of contatore_led is -- dichiarazione dei componenti component Counter is
port ( clk: in std_logic; -- clock reset: in std_logic; -- reset en: in std_logic; -- enable ud: in std_logic; -- up/down* o: out std_logic_vector(7 downto 0) );
end component;
DICHIARO COMPONENT
…definisco interfaccia
…tradotto in VHDL
20
component ClockDivide is port ( clk_in: in std_logic; -- clock da 20ns (50 MHz) clk_1: out std_logic; -- clock da 0.01 sec (circa) clk_2: out std_logic; -- clock da 0.17 sec (circa) clk_3: out std_logic -- clock da 0.67 sec (circa) );
end component; --segnali usati nella architettura signal signal_clk : std_logic; begin --component instantiations Counter_1 : Counter
port map ( clk => signal_clk, reset => reset_input, en => en_input, ud => ud_input, o => output_led );
ClockDivide_1 : ClockDivide
port map ( clk_in => clk_input, clk_1 => open, clk_2 => open, clk_3 => signal_clk );
end Archi;
DICHIARO COMPONENT
ISTANZIO COMPONENT
…lo connetto
21
ENTITY TestBench IS END TestBench; ARCHITECTURE behavior OF TestBench IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT contatore_led PORT( clk_input : IN std_logic; reset_input : IN std_logic; en_input : IN std_logic; ud_input : IN std_logic; output_led : OUT std_logic_vector(7 downto 0) ); END COMPONENT; --Inputs signal clk_input : std_logic := '0'; signal reset_input : std_logic := '0'; signal en_input : std_logic := '0'; signal ud_input : std_logic := '0'; --Outputs signal output_led : std_logic_vector(7 downto 0); -- Clock period definitions constant clk_input_period : time := 20 ns;
TestBench
Il testbench vede solo
contatore_led
22
-- Clock process definitions clk_input_process :process begin
clk_input <= '0'; wait for clk_input_period/2; clk_input <= '1'; wait for clk_input_period/2;
end process; -- Stimulus process stim_proc: process begin en_input<='0'; ud_input <= '1'; reset_input <= '1'; wait for 100 ns; reset_input <= '0'; wait for 100 ns; en_input<='1'; wait; end process; END;
TestBench 2
Stimoli ai pin di
ingresso
Output_led En_input
Reset_input
Ud_input
clk_input
Contatore_led
23
NET "clk_input" LOC = "C9" | IOSTANDARD = LVCMOS33 ; # switch<0> NET "en_input" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ; #switch<1> NET "ud_input" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ; #BTN_SOUTH NET "reset_input" LOC = "K17" | IOSTANDARD = LVTTL | PULLDOWN ; # The LED 8bit. NET "output_led<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ; NET "output_led<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW=SLOW | DRIVE=8 ;
Per mappare contatore_led sulla scheda dobbiamo aggiungere al progetto il file ucf:
24
La possibilità di costruire strutture modulari consente di utilizzare moduli senza preoccuparsi di come siano
realizzati al loro interno, basta conoscerne la funzionalità ai morsetti.
Grande Vantaggio!!
Possiamo unire diversi component insieme realizzando via via funzionalità più complesse.
Possiamo riutilizzare il codice già scritto
Modularità Riusabilità
25
Esempio:
COUNTER X 256
EN RESET
U/D*
O[7..0] LCD
DISPLAY
En_input
Reset_input
Ud_input
clk_input
Clock Divide
Contatore_display
clk_in
clk_3
LCD DRIVER
Controllo display
26
entity contatore_lcd is port(
clk_input : in std_logic; -- clock reset_input : in std_logic; -- reset en_input : in std_logic; -- enable ud_input : in std_logic; -- up/down* lcd_d : out std_logic_vector(3 downto 0); --comandi display lcd_e, lcd_rs, lcd_rw : out std_logic --comandi display );
end contatore_lcd;
architecture Archi of contatore_lcd is -- dichiarazione dei componenti component Counter is
port ( clk: in std_logic; -- clock reset: in std_logic; -- reset en: in std_logic; -- enable ud: in std_logic; -- up/down* o: out std_logic_vector(7 downto 0) );
end component;
DICHIARO COMPONENT
…definisco interfaccia
…tradotto in VHDL
COUNTER X 256
O[7..0]
27
component ClockDivide is port ( clk_in: in std_logic; -- clock da 20ns (50 MHz) clk_1: out std_logic; -- clock da 0.01 sec (circa) clk_2: out std_logic; -- clock da 0.17 sec (circa) clk_3: out std_logic -- clock da 0.67 sec (circa) );
end component; component LCDDriver is
port ( clk, we: in std_logic; -- clock e write enable address: in std_logic_vector(4 downto 0);-- indirizzo display: -- 0-15 prima riga -- 16-31 seconda riga data_in: in std_logic_vector(7 downto 0);-- codice ascii
-- del carattere da scrivere lcd_d: out std_logic_vector(3 downto 0); -- comandi del display lcd_e, lcd_rs, lcd_rw: out std_logic -- comandi del display );
end component;
DICHIARO COMPONENT
LCD DRIVER
DICHIARO COMPONENT
Clock Divide
clk_in
28
--definizione dei segnali signal signal_clk : std_logic; signal counterValue : std_logic_vector (7 downto 0); signal lcd_we :std_logic; signal lcd_address : std_logic_vector (4 downto 0); signal lcd_data_in : std_logic_vector (7 downto 0); --stato iniziale display signal lcd_data : std_logic_vector(0 to 255) :=ASCII_UMAIUSC & ASCII_SLASH & ASCII_DMAIUSC & ASCII_ASTERISCO & ASCII_DUEPUNTI
& ASCII_SPAZIO & ASCII_0 &ASCII_SPAZIO & ASCII_SPAZIO & ASCII_EMAIUSC & ASCII_N & ASCII_DUEPUNTI & ASCII_SPAZIO & ASCII_Q
& ASCII_SPAZIO & ASCII_SPAZIO & ASCII_VMAIUSC & ASCII_A & ASCII_L & ASCII_U & ASCII_E & ASCII_DUEPUNTI & ASCII_SPAZIO & ASCII_0 & ASCII_0 & ASCII_SPAZIO & ASCII_SPAZIO & ASCII_SPAZIO & ASCII_SPAZIO & ASCII_SPAZIO
& ASCII_SPAZIO & ASCII_SPAZIO;
29
begin -- component instantiations Counter_1 : Counter
port map ( clk => signal_clk, reset => reset_input, en => en_input, ud => ud_input, o => counterValue );
ClockMultiplier_1 : ClockMultiplier
port map ( clk_in => clk_input, clk_1 => open, clk_2 => open, clk_3 => signal_clk );
LCD_Driver_1 : LCDDRIVER
port map ( clk => clk_input, we => lcd_we, address => lcd_address, data_in => lcd_data_in, lcd_d => lcd_d, lcd_e => lcd_e, lcd_rs => lcd_rs, lcd_rw => lcd_rw );
ISTANZIO COMPONENT
…li connetto
…ma non ci preoccupiamo di come siano fatti
dentro ..li aggiungiamo al progetto come
black-box
30
--refresh display update : process
variable counter : integer :=0; variable line_address : std_logic_vector(4 downto 0) := (others =>'0'); begin wait until clk_input'event and clk_input = '1';
lcd_we <= '1'; lcd_address <= line_address; lcd_data_in <= lcd_data(counter*8 to counter*8+7); line_address := line_address+1; if counter = 31 then counter := 0; else counter := counter+1; end if;
end process; --aggiornamento display async : process (ud_input, en_input, counterValue) begin lcd_data(8*6 to 8*6+7)<=conv_bit(ud_input); lcd_data(8*13 to 8*13+7)<=conv_bit(en_input); lcd_data(8*23 to 8*23+15)<=conv_hex_string(counterValue); end process;
end Archi;
Controllo display
…basta conoscerne il funzionamento ai morsetti per
poterli controllare
31
NET "clk_input" LOC = "C9" | IOSTANDARD = LVCMOS33 ; NET "lcd_e" LOC = "M18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "lcd_rs" LOC = "L18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "lcd_rw" LOC = "L17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; # The LCD four-bit data interface is shared with the StrataFlash. NET "lcd_d<0>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "lcd_d<1>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "lcd_d<2>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "lcd_d<3>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; #switch<0> NET "en_input" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ; #switch<1> NET "ud_input" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ; #BTN_SOUTH NET "reset_input" LOC = "K17" | IOSTANDARD = LVTTL | PULLDOWN ;
Per mappare contatore_Display sulla scheda dobbiamo aggiungere al progetto il file ucf: