Прости съвети за стил Verilog

Всъщност в езика Verilog, който популяризирам по всякакъв възможен начин, наистина има странни места, от които начинаещите програмисти получават „премахване на мозъка“. Често объркването е свързано с тел и reg - къде и кога могат или трябва да бъдат написани.
Всичко би било повече или по-малко ясно, ако reg винаги означаваше едно и също нещо. Например, ако reg в програма Verilog беше уникално съпоставена с тригер в схемата, тогава изучаването на езика би било по-лесно. Това е IMHO.
Уви, езикът Verilog HDL е "много гъвкав" и поради това не всичко е толкова просто. Понякога (и често) присвояването на стойност на reg регистъра не генерира тригер в схемата.
винаги @* c = a + b ;
В този пример резултатътc е комбинирана функция. В получената схема в FPGA няма да има задействащи регистри за съхранение, а само логика. Компилирайте такава конструкция в Quartus II и погледнете в Tools => Netlist Viewers => RTL Viewer:

Нотацията @* означава, че блокът се изпълнява винаги, както непрекъснато, така и безкрайно. Никъде не се съхраняват стойности. Когато входните сигнали се променят, отговорът на сигнала незабавно се променя.
Но какво да кажем за думата reg (регистър)? Изглежда сме свикнали с факта, че нещо се съхранява в регистри, както в регистрите на процесор или микроконтролер. И тук или се съхранява, или не се съхранява - не е ясно ..
Предлагам някои прости глупави правила, които значително ограничават самия език Verilog и неговите възможности, но правят програмния код по-разбираем, четим и по-съвместим с получената физическа верига на цифрово устройство. Това е моята интерпретация - много "пресечен" Verilog.
Майсторите на Verilog би било по-добре да не виждат това. Предвиждам полета на гнили ябълки в моята посока.
Правило 1. Никога не пишете разделнокомбинационни функции във винаги блокове.
Е, това е така, за да не мислите, че веригата ще има задействащ регистър за съхранениеc, в който ще бъде записан някакъв резултат; не е необходимо да пишете, както в горния пример. Вместо това напишете:
проводник c; присвояване на c = a + b;
В този случай получаваме само чисти проводници. Изходният сигнал се получава от входните сигнали чрез трансформирането им с логически комбинационни функции.
Комбинационните функции са всякакви прости И, ИЛИ, НЕ, изключителни или. Още суматори, изваждачи, сравнители, мултиплексори, декодери. Ето всички от тях в кабел и с помощта на присвояване и описание. Всяка комбинирана функция може лесно да бъде описана с помощта на wire и assign. Това е вместо съответната винаги @* конструкция.
Дори когато логиката е сложна и има условни изчисления, винаги можете да напишете нещо като мултиплексор:
проводник c; присвояване на c = a? (b+1) : (d
В този пример, в зависимост от стойността наa, се избира или първата(b+1), или втората(d изчислена стойност.
Дори с помощта на проводници можете и трябва да свържете модулите един към друг.
Правило 2. Опитайте се да опишете с reg регистри само онези променливи, които искате да бъдат реални тригери в получената схема.
Представете си, че това са точно онези клетки от паметта, които приемат стойност и то само по тактов сигнал.
reg[7:0]a; винаги @( posedge clk) a
Тук в резултат от този код ще бъдат получени осем тригерни регистъра, в които се записва нова стойност според тактовия сигнал @(posedge clk). Вярно е, че в този пример има и комбинирана функция - суматор, но изписването й отделно чрез wire и assign би било напълно скучно.
Повечетоосновното тук е, че присвояването на променлива от тип reg съответства на фиксиране, фиксиране на данни в тригери по ръба на часовника. Имаме предвид регистър-тригер (тригер) - тук описваме променливата с тип reg.
Ако такъв код бъде компилиран в Quartus II и прегледан в RTL Viewer, тогава директно ще видим клетките за съхранение под формата на правоъгълници със сини регистри:

Правило 3 В винаги блок с тактов сигнал от тип @(posedge clk), винаги използвайте присвоявания само от един тип "неблокиращо присвояване"
тест на модула ( входен проводник clk, входен проводник в, изходен reg in_edge );
винаги @( posedge clk) начало sr край
Регистърsr иin_edge се тактират на една и съща честота и данните се записват в тях едновременно. Разглеждаме RTL Viewer и виждаме точно регистрите, тактовани от общия часовник:

Отново. В блоковете always @( posedge clk) се опитвайте винаги да пишете само неблокиращи присвоявания, като по този начин указвате едновременното предаване на данни в реални тригери. Ако пишете или рег . Следващото състояние на машината се изчислява чрез комбинационни функции, които се опитваме да опишем с проводник и да присвоим . Машината преминава от едно състояние в друго, например на границата на тактовата честота.
Ако можете да следвате този стил и тези три прости правила за известно време, тогава може би ще можете мислено да си представите фрагмент от вашата верига, докато пишете програмния код.
Проверката на проект е лесна. Ако използвате Altera Quartus II, компилирайте проекта и вижте какво се случва като диаграма в RTL Viewer. Ако сте си представяли описаната схема почти по същия начин, както я показва Квартус, значи се движите в правилната посока.
със сигурностгорните правила и ограничения са доста шантави. В един момент това дори е лош съвет. Езикът Verilog ви позволява да пишете много неща и по много различни начини.
Струва ми се обаче, че този стил може да бъде полезен за начинаещи, изучаващи Verilog. Поне аз самият измислих този стил, когато започнах да уча езика Verilog HDL и дълго време нямах ясна представа как работи всичко.