В данной статье мы рассмотрим примеры кода на языке Verilog с отчетами о компиляции и RTL. Всего мы представим 10 лучших примеров, начиная от простых операций с логическими элементами и заканчивая моделированием микропроцессоров и цифровых фильтров. Каждый пример сопровождается отчетом о его успешной компиляции, что позволяет убедиться в корректности представленного кода. Мы охватили широкий спектр тем для того, чтобы помочь разработчикам глубже понять синтаксис и семантику из документации Verilog, а также улучшить свои навыки в области моделирования электронных схем.
Пример 1. Двухпортовая Однотактовая Память RAM
Пример 1 — Объявления модуля памяти с использованием памяти ПЛИС c помощью Verilog(см. массивы и память). Этот модуль не использует регистры, а напрямую обращается к IP-блоку памяти. Здесь имеется в виду ресурс, заложенный в микрочип, отделенный от логических ячеек.
...
Копировать
module TWISE_PORTS_RAM(data, addr_we, addr_re, we, clk, q);
parameter BITS_DATA = 8; // кол-во битов в линии данныхparameter BITS_ADDR = 6; // кол-во битов в линии адресаinput [(BITS_DATA - 1): 0] data; // линия данныхinput [(BITS_ADDR - 1): 0] addr_we; // линия адреса для записиinput [(BITS_ADDR - 1): 0] addr_re; // линия адреса для чтенияinput we; // линия включения записиinput clk; // тактовый сигналoutputreg [(BITS_DATA - 1): 0] q; // линия выхода// регистр, использующий примитив FPGAreg [(BITS_DATA - 1): 0] ram [((2**BITS_ADDR) - 1): 0];
always @(posedge clk) begin// записьif (we)
ram[addr_we] <= data;
// чтение
q <= ram[addr_re];
endendmodule
При приходе восходящего фронта в тактовом сигнале clk и высоком сигнале записи write, происходит запись в память по адресу addr_we. При одинаковой ситуации тактовым сигналом происходит чтение с памяти по адресу addr_re. RTL модель показана на рисунке 1.
Пример 2 — Данный FIFO написан для заполнения слова буфера по битно. Модуль использует регистровую память на логических клетках. Вставьте экземпляр памяти из примера 1, чтоб использовать ресурсы(память) чипа. Объяснение по портам и параметрам не требуется, потому что код приведен с комментариями. Более подробно описано в статье про FIFO. Процедурный блок always «реагирует» на восходящий фронт тактового сигнала clk и асинхронного сигнала reset. Когда появляется восходящего фронта сигнала reset, сбрасывается все управляющие регистры FIFO и выставляется на логическую 1 сигнал пустоты буфера empty. Если буфер полон, выставляется сигнал full. Когда происходит переход тактового сигнала к логической 1, при высоком сигнале write_enable и не полном буфере осуществляется запись в буфер и увеличение счетчика и указателя. Если clk восходящий фронт, при высоком сигнале read_enable и при не полном буфере читаются данные из буфера, уменьшается счетчика и увеличивается указатель. Для заполнения буфера FIFO по другой величине битов, необходимо увеличить длину битов линии data_in, data_out на одинаковое кол-во и переделать счетчик и указателей write_pointer и read_pointer.
Пример 3 — Интегратор — это устройство или элемент, который выполняет функцию интегрирования. Данный интегратор реализован с выбором коэффициента дискретизации или без его наличия. Точечная нотация фиксированной точки равна 1.15. Именно, на такой нотации работает сигнальные процессоры. Код создавался и тестировался Quartus9.1, поэтому была необходимость прописывать умножение отдельным модулем. Иным образом программа искажала generate RTL(см generate).
RTL интегратора состоит из триггера, сумматора и умножителя и показан на рисунке 3.
"aligncenter size-full">
Рисунок 3 — RTL примера модуля интегратора.
Пример 4. Дифференциатор
Пример 4 — Дифференциатор — это устройство, которое позволяет получить производную сигнала. Дифференциатор представляет собой нерекурсивный фильтр 1 порядка с коэффициентом -1.
...
Копировать
module diff(data, clk, reset, out);
parameter DATA_WIDTH = 16; // Битовая длина линии данныхinputsigned [(DATA_WIDTH - 1): 0] data; // Линия данныхinput reset, clk; // асихронный сброс и тактовый сигналoutputsigned [(DATA_WIDTH - 1): 0] out; // линия выхода// z(-1) запоминает входной сигналreg [(DATA_WIDTH - 1): 0] z1 = 0;
// вычетание входных даных и предыдуших данныхassign out = data - z1;
always @(posedge clk, posedge reset) beginif (reset) begin
z1 <= 0;
endelsebegin
z1 <= data;
endendendmodule
RTL Дифференциатора состоит из триггера и разнатора и показан на рисунке 4.
"aligncenter size-full">
Рисунок 4 — RTL примера модуля дифференциатора.
Пример 5. Фазовый накопитель
Пример 5 — Фазовый накопитель — это БИХ-фильтр(рекурсивный фильтр) 1 порядка. Фазовый накопитель применяется во многих схема, но чаще его используется в схеме NCO генератора, управляемый числовой последовательность. Входной 16 битный сигнал складывается с предыдущим значением сумматора. Если значение сумматора выше заложенных битов, регистр запоминает лишь первые 16 бит(см. регистры).
Пример 6 — КИХ-фильтр 5 порядка(FIR) — нерекурсивный фильтр 5 порядка. КИХ-фильтры используют для фильтрации данных. С помощью КИХ-фильтров строят ФНЧ, ФВЧ, режекторный и полосовый фильтры. Данный код использует нотацию для фиксированной запятой 1.15.
Пример 7 — LUT — это таблица, которая выдает заранее определенные значения. LUT бывает 2-х типов: функциональная и хеш-таблица. В данном случае применяется функциональная LUT. Функциональная LUT — это комбинационная схема с определенным кол-во входов. Хорошим примером является LUT логической клетки семейства FPGA Cyclone. В примере используется директива `default_nettype, которая задает объявление по умолчанию не объявленных цепей.
RTL LUT 6-ти входная состоит из 2 конъюнкций, дизъюнкции и суммы по модуля 2 и показан на рисунке 7.
"aligncenter size-full">
Рисунок 7 — RTL примера модуля LUT 6-ти входная.
Пример 8. Полный N-битный сумматор
Пример 8 — Полный сумматор — это логический элемент, который суммирования числа с переносом и осуществляет перенос. N-битный сумматор — это сумматор с длинной линиями данных равной N. В этом примере шестнадцатибитный.
RTL Полного шестнадцатибитного сумматора состоит из 2-х примитивов сложения и показан на рисунке 8.
"aligncenter size-full">
Рисунок 8 — RTL примера модуля полного сумматора.
Пример 9. 16-входной мультиплексор
Пример 9 — Мультиплексор — это логический элемент, который осуществляет выборку сигналов из всех входных информационных сигналов через адресные управляющие входы.