В моя скорошен проект за аудио обработка на Hackster.io създадох прост IP блок за синтез на високо ниво (HLS), към който могат да се добавят филтриране и ефекти. За да гарантирам, че това IP ядро ​​ще взаимодейства с I2S TX и RX IP ядрата от Xilinx, трябваше да създам AXI стрийминг интерфейси на HLS IP блока.

Правейки това ме накара да се замисля малко за това как изпълняваме интерфейс с помощта на Vivado HLS, така че в този блог ще обясня как контролираме какъв интерфейс използва нашия HLS IP блок.

Ще започнем от самото начало с прост HLS IP блок, който извършва просто събиране. За всички тези примери ще се насочим към Zedboard.

В HLS интерфейсите на синтезирания блок се дефинират от аргументите, които предаваме на нашата C/C++ функция заедно с всички върнати параметри. Посоката зависи от това как се използват във функцията; но ако използваме указатели или масиви, те могат да се използват като IO.

В допълнение към входовете и изходите ще бъде създаден и интерфейс ap_cntrl в синтезирания HLS IP блок. Този контролен интерфейс осигурява часовник, нулиране и ръкостискане, например, разрешаване на блока да бъде стартиран (ap_start), отчитане кога резултатът е готов (ap_done), кога блокът е готов да приеме нов вход (ap_ready) и ако блокът е неактивен (ap_idle).

Но дори поведението на интерфейса ap_cntrl зависи от нашата настройка на решението и самия код.

За първия пример ще използваме бавен часовник при 100 ns. Първият етап от процеса на HLS е планиране, когато инструментът HLS присвоява операции на тактови цикли. Ако периодът на часовника е достатъчно дълъг, тогава може дори да не се нуждае от регистри, което води до комбинаторен дизайн.

Поради това часовниковият период, дефиниран в настройките на решението, ще окаже влияние върху синтеза и взаимодействието. Много простият код по-долу, когато се синтезира с тактов период от 100 ns, ще доведе до комбинаторна реализация.

Като такива, няма нужда от сигнали за ръкостискане. Ако разгледате изхода VHDL или Verilog, ще видите, докато сигналите съществуват, те просто присвояват входовете и константите на изходите. Друга индикация, че синтезираният блок е комбинативен, е, че няма часовник или вход за нулиране.

Ако променим тактовия период на един от 5 ns, ще видим отчетеното увеличение на латентността, тъй като инструментът HLS вмъква етап на регистър. Това също се отразява в интерфейсите с часовника и нулирането, които вече присъстват, и поведението на сигналите за ръкостискане се актуализира, за да се приложи правилно необходимото ръкостискане.

Следователно този прост порт ap_cntrl ни дава възможност да работим с HLS IP блока в нашия дизайн и поради тази причина се нарича протокол на ниво блок.

Разбира се, за много приложения искаме да можем да свържем нашия HLS IP блок с проекти, които използват AXI или интерфейси на паметта.

Тук идват протоколите на ниво порт и за тях типът C конструкция, използвана за променливата, става важен. Протоколите на ниво порт ни позволяват да дефинираме за всеки порт на HLS блока конкретен интерфейсен протокол като AXI Lite, AXI, FIFO, BRAM и др.

Като актуализираме простия пример по-горе, за да използваме масиви, можем да модифицираме интерфейсите да използват интерфейси от типа FIFO. Ние дефинираме този тип интерфейс с помощта на прагмата:

#pragma HLS интерфейс ap_fifo depth = ‹depth› port =‹port›

За да дефинираме типа на интерфейса, можем или да ги въведем на ръка, както по-горе, или да използваме прозореца с директиви от дясната страна на прозореца на HLS.

Тъй като това е интерфейс на ниво порт, трябва да го дефинираме за всеки от интерфейсите в HLS блока.

Когато стартираме това през HLS, ще видим генерирания отчет за синтез, който дефинира внедрените интерфейси. Както можете да видите, FIFO интерфейсите са внедрени.

FIFO интерфейсите са интересни, когато искаме да предаваме поточно данни между HLS модули.

Често обаче искаме да внедрим интерфейси, които използват разновидност на AXI (s_axilite, axis, s_axi, m_axi). Можем да използваме същия подход за внедряване на AXIS и AXI главни и подчинени интерфейси.

Ако работим с хетерогенен SoC, като Zynq или Zynq MPSoC, може да искаме да използваме AXI lite за контрол на HLS IP блока, а не интерфейса на дискретния блок. Можем да направим това, като използваме прагмата по-долу:

#pragma s_axilite port=return bundle=cmd

Това ще създаде не само AXI lite интерфейс, който ни позволява да контролираме HLS IP ядрото, но и ще генерира софтуерните драйвери, необходими за работа с HLS IP ядрото в SDK.

Ако няма нужда да спираме и стартираме HLS IP ядрото, тогава можем да използваме прагмата:

#pragma HLS интерфейс ap_ctrl_none порт=връщане

Разбирането как можем да контролираме интерфейсите на нашите HLS IP блокове означава, че когато работим с HLS, можем да гарантираме, че нашият IP блок лесно се интегрира с останалата част от нашия дизайн, спестявайки време и усилия при създаването на блокове за преобразуване.

Вижте моите проекти за FPGA / SoC:Адам Тейлър в Hackster.io

Вземете кода:ATaylorCEngFIET (Адам Тейлър)

Достъп до архивите на MicroZed Chronicles с над 280 статии за Zynq / Zynq MpSoC, актуализирани всяка седмица в MicroZed Chronicles.