typedef ap_int<20> DATA_T;
typedef ap_uint<2> OP_T;
DATA_T ale(DATA_T x, DATA_T y, OP_T op);
#endif
```
### Izdelava projekta
Ob izdelavi novega projekta v Vitis HLS vključimo datoteko s funkcijo (ale.cpp), zaglavno datoteko (ale.h) in
v okence *Top Function* vnesemo ime funkcije. V naslednjem koraku lahko dodamo glavni program (ale_test.cpp) s
funkcijo main() za simulacijo. V zadnjem koraku izdelave novega projekta določimo periodo ure in ciljno vezje FPGA.
![](./hls/newHLS.png)
Delovni koraki so v orodju Vitis HLS dosegljivi v glavnem meniju, navigacijskem oknu (Flow Navigator) ali
na ikonah v orodni vrstici. Koraki vključujejo:
- simulacijo v jeziku C, kjer prevedemo in izvedemo simulacijski program skupaj s funkcijo oz. modelom vezja,
- sintezo vezja iz funkcije v jeziku C,
- povezano simulacijo, kjer izvedemo simulacijski program skupa s simulacijo sintetizirane funkcije in
- implementacijo s tehnološkimi koraki za vezja FPGA.
![](./hls/HLSmenu.png)
### Sinteza
Sintezo vezja izvedemo s klikom na **Run C Synthesis**. Določiti moramo periodo ure v nanosekundah in ciljno tehnologijo,
kjer izberemo FPGA ali razvojno ploščo (gumb Boards). Cilj sinteze je avtomatska izdelava sinhronega vezja, ki izvaja
v funkciji opisane operacije in deluje v izbrani tehnologiji s frekvenco nastavljene ure.
![](./hls/Csynth.png)
Sintetizator naredi vezje z gradniki ciljne tehnologije in razdeli zahtevnejše operacije na več ciklov ure.
Vezje sestavljajo namenske enote (npr. množilniki v blokih DSP), kombinacijska logika (LUT), pomnilniki (BRAM)
in flip-flopi (FF). Rezultat sinteze je model vezja z ocenjeno porabo tehnoloških gradnikov in časovno metriko:
- *latenca* je število ciklov za izračun izhodnih vrednosti (en klic funkcije)
- *interval* II (iniciacijski interval) je število ciklov do naslednje ponovitve funkcije
Vsi rezultati sinteze se shranijo v podmapo s privzetim imenom *solution1*.
Poročilo sinteze podaja zmogljivost vezja, oceno porabe gradnikov, opis priključkov in povezav operacij z gradniki.
Grafični pregledovalnik *Schedule Viewer* prikazuje podrobnejšo časovno razdelitev operacij, ki jih izvaja funkcija.
Vezje *ale* ima latenco 1 cikel, interval 2 cikla in zasede 1 DSP ter 5 flip-flopov. V prvem ciklu ure prebere in dekodira operacijo, v drugem pa jo izvede.
![](./hls/aleSchedule.png)
Če zmanjšamo periodo ure na 5 ns, se po ponovni sintezi število urnih ciklov izvedbe funkcije poveča za 3 zaradi množenja velikih števil,
ki je časovno zahtevnejša operacija. V grafičnem pregledovalniku razberemo, da se izbrana operacije prebere v ciklu 0, v 1. ciklu se
prebereta operanda in izračuna vsota, izračun produkta pa traja do 3. cikla. V zadnjem ciklu ure se določi izhodna vrednost.
![](./hls/aleSchedule2.png)
Časovni potek delovanja vezja je odvisen od vmesnika in zahtevanih lastnosti.
Na rezultat sinteze vplivamo z dodatnimi navodili v obliki direktiv. Če naprimer želimo obdelavo vhodnih podatkov v vsakem,
ki se spremenijo v vsakem ciklu ure, sintetiziramo vezje v cevovodni izvedbi (pipeline). Takšno vezje bo običajno porabilo
več logičnih in pomnilnih gradnikov.
Direktive lahko vnašamo neposredno v opis funkcije ali pa s pomočjo grafičnega urejevalnika.
V zavihku *Directive* dodamo z desnim klikom na glavno funkcijo *ale()* direktivo PIPELINE.
Po sintezi vezja se inteval zmanjša na 1 cikel za ceno večje površine vezja (več uporabljenih FF in LUT).
![](./hls/directive.png)
### Simulacija
Delovanje funkcije z visokonivojskim modelom vezja preizkusimo s simulacijo v programskem jeziku, kjer pripravimo
simulacijski program (Testbench). Simulacijski program vsebuje glavno funkcijo main() v kateri nastavlja vhodne
parametre, kliče funkcijo in prikazuje, shranjuje ali celo avtomatsko preverja rezultate. Zaznano napako lahko
javimo tako, da glavna funkcija vrne vrednost različno od 0.
```C
#include "ale.h"
using namespace std;
int main()
{
DATA_T x, y, z;
OP_T op;
cout << "Test Bench " << endl;
x=8; y=7; op=2; z=ale(x,y,op);
cout << x << "," << y << ", op:" << op << " z = " << z << endl;
return 0;
}
```
Za demonstracijo naredimo preprost testni program v katerem pokličemo funkcijo in izpišemo rezultate.
Pri op=2 bo rezultat izpis:
Test Bench
8,7, op:2 z = 56
V praksi bo program bolj zapleten in bo naredil veliko klicev funkcije z različnimi parametri.
Poleg simulacije v programskem jeziku je po sintezi na voljo povezana simulacija (Cosimulation),
kjer se simulacijski program poveže s simulatorjem sintetiziranega vezja.
Če želimo opazovati časovni potek signalov (waveform) moramo ob zagonu izbrati shranjevanje poteka signalov,
npr. priključkov vezja (v okencu *Dump Trace* izberemo: *port*).
![](./hls/aleSim.png)
Shranjen potek signalov lahko opazujemo v simulatorju vezij, ki je del orodja **Vivado**.
Odpremo ga z novo ikono *Wave Viewer*, ki se prikaže v orodni vrstici po uspešno opravljeni povezani simulaciji.
Na simulaciji opazujemo signale vmesnika: *ap_start*, *ap_idle*, *ap_ready* in *ap_done*.
Logična 1 na *ap_start* sproži začetek izvajanja funkcije, *ap_done* pa signalizira zaključek, ko lahko preberemo
rezultat.