Proces syntezy i symulacji przykładowego projektu
Spójrzmy teraz, w jaki sposób przeprowadzana jest synteza oraz symulacja przykładowego projektu, który będzie się składał z następujących plików:
- blink_top.v – główny moduł projektu, opisujący układ,
- blink.v – jeden z modułów projektu, implementujący przykładowy komponent,
- blink_tb.v – główny moduł, służący do symulacji tzw. test bench,
- icecore_pins.pcf – plik opisujący mapowanie modułu głównego do fizycznych wyprowadzeń układu FPGA.
Cykl projektowania możemy podzielić na dwa odrębne etapy (rysunek 2): symulacja, w wyniku której powstaje wynikowy plik, zawierający diagram przebiegów wyjściowych; synteza, tworząca w rezultacie plik bitstream, który może być wykorzystany do zaprogramowania pamięci konfigurującej układ FPGA.
Podczas symulacji wykorzystywany będzie plik blink_tb.v, stanowiący główny moduł symulacyjny, oraz plik blink.v, który stanowi jedyny moduł projektu. Plik blink_top.v, nie jest używany, ponieważ stanowi on moduł główny projektu, stosowany do syntezy. Do procesu symulacji wykorzystamy narzędzie „Icarus Verilog”, wywołując je z linii komend w następujący sposób:
iverilog -o blink.vvp blink_tb.v blink.v
vvp blink.vvp -lxt2
Pierwsza komenda dokonuje kompilacji plików źródłowych do kodu pośredniego, w wyniku której powstaje plik blink.vvp, stanowiący kod dla maszyny wirtualnej vvp. Druga komenda uruchamia maszynę wirtualną, która wykonuje plik blink.vvp, w efekcie czego, zgodnie z zawartością pliku blink_tb.v, powstaje plik zawierający diagramy, będące efektem symulacji. Tak powstały plik możemy otworzyć bezpośrednio w programie GTKWave, w efekcie czego ujrzymy przebiegi wewnątrz projektowanego układu (rysunek 3). W programie służącym do przeglądania przebiegów możemy wybrać interesujące nas sygnały i przeglądać je w całości lub oglądać ich fragmenty.
W procesie syntezy będziemy wykorzystywać pliki: blink_top.v, stanowiący główny moduł projektu blink.v oraz icecore_pins.pcf, opisujący mapowanie wejść i wyjść do fizycznych wyprowadzeń układu. Ponieważ mapowanie w komercyjnych środowiskach najczęściej realizowane jest w sposób graficzny, omówimy nieco szerzej zawartość tego pliku projektu, która wygląda w sposób następujący:
set_io clk 60
set_io led[0] 49 # B81/GBin5 L0 Blue led / S2 button
set_io led[1] 52 # B82/GBin4 L1 Green led / S1 button
set_io led[2] 55 # B91 L3 Yellow led
set_io led[3] 56 # B94 cs Red led
Deklaracja modułu głównego projektu wygląda tak:
module chip (
// 25MHz clock input
input clk,
// Led outputs
output [3:0] led
);
Poszczególne linie pliku mapującego zawierają zestaw komend set_io, nazwę sygnału w module głównym, a następnie numer fizycznego wyprowadzenia sygnału w układzie FPGA. Opcjonalnie możemy również dodać własny komentarz, posługując się znakiem #. Ponieważ w przykładowym projekcie wykorzystujemy obudowę TQFP, oznaczenia wyprowadzeń występują w postaci numerycznej.
Wróćmy teraz do głównego tematu, czyli syntezy, która realizowana jest w kilku krokach za pomocą następujących komend:
yosys -q -p "synth_ice40 -json blink.json" blink.v blink_top.v
nextpnr-ice40 --hx8k --package tq144:4k --json blink.json --asc blink.asc --pcf icecore_pins.pcf
icepack blink.asc blink.bin
W pierwszym poleceniu wywołujemy narzędzie yosys odpowiedzialne za wygenerowanie pliku netlisty. Jako pierwszy argument przekazywana jest opcja synth_ice40, pozwalająca na skorzystanie z modułów specyficznych dla rodziny układów iCE40. Następny argument json nakazuje wygenerowanie listy połączeń w formacie JSON. Jako kolejne argumenty przekazywane są nazwy wszystkich plików źródłowych, które biorą udział w syntezowaniu układu. Wynikiem działania polecenia jest plik o nazwie blink.json, zawierający listę połączeń.
Polecenie nextpnr-ice40 odpowiedzialne jest za mapowanie komponentów oraz trasowanie połączeń wewnątrz układu FPGA. Pierwszy argument zawiera typ układu, dla którego syntezowany jest projekt, natomiast drugi argument zawiera rodzaj obudowy wybranego układu. Jako argument json przekazujemy plik z listą połączeń, wygenerowany wcześniej za pomocą narzędzia yosys. Kolejny argument asc określa nazwę pliku wyjściowego, natomiast w ostatnim argumencie przekazujemy plik, zawierający mapowanie wyprowadzeń układu. Wynikiem działania polecenia jest powstanie listy połączeń w postaci tekstowej, specyficznej dla układu iCE40.
W ostatnim poleceniu wywołujemy program icepack, którego zadaniem jest przekształcenie listy połączeń z postaci tekstowej do wynikowego pliku bitstream. Jako pierwszy argument polecenie przyjmuje netlistę specyficzną dla układu, wygenerowaną za pomocą narzędzia nextpnr-ice40, natomiast drugi argument stanowi nazwa pliku wyjściowego, który będzie zawierał finalny plik z zawartością bitstream dla układu FPGA. Tak powstały plik możemy następnie wykorzystać do konfiguracji układu FPGA lub zaprogramowania układu pamięci, z której układ FPGA odczyta konfigurację.
Lucjan Bryndza, EP
lucjan.bryndza@boff.pl