Оглавление
- Часть 1 Введение в Verilog
- 1.1. Introduction¶
- 4.2.2 Знаковые и беззнаковые числа в выражениях.
- Понятия моделирования и синтеза
- Пишем «демку» для LESO2 на Verilog
- Особенности языков описания архитектуры Verilog и VHDL
- 4.2.2 Знаковые и беззнаковые числа в выражениях.
- Procedural Continuous Assignment
- SystemVerilog logic, data types, and data objects
- Блок начальной инициализации
- Запись чисел в Verilog
- Программный языковой интерфейс (PLI)
- Continuous Assignment
- I’m confused… Just tell me how I should use SystemVerilog logic!
- Блокирующее присваивание
- Getting Used to the Waveform Window
- If-else
- Assigning and Copying Verilog Arrays
- 8.5. Read only memory (ROM)¶
- Example
- Пример определения вектора —
- Problems With Passing Multiple Control Signals Across Clock Domain Crossing (CDC)
Часть 1 Введение в Verilog
Verilog, Verilog HDL (англ. Verilog Hardware Description Language) — это язык описания аппаратуры, используемый для описания и моделирования электронных систем. Verilog HDL, не следует путать с VHDL (конкурирующий язык), наиболее часто используется в проектировании, верификации и реализации (например, в виде СБИС) аналоговых, цифровых и смешанных электронных систем на различных уровнях абстракции.
Разработчики Verilog сделали его синтаксис очень похожим на синтаксис языка C, что упрощает его освоение. Verilog имеет препроцессор, очень похожий на препроцессор языка C, и основные управляющие конструкции «if», «while» также подобны одноимённым конструкциям языка «C».
Следует отметить одну из самых важных отличительных особенностей программирования логики (Verilog, VHDL и т.д.) освоив которую, сразу же все возвращается на круги свои. Всё дело в том, что в ПЛИС все процессы выполняются одновременно! В то время как привычная и понятная нам процессорная техника работает иначе – последовательно. Уяснив эту важную отличительную особенность можно смело пытаться программировать.
Все плюсы и минусы СБИС ПЛИС освещаются в других разделах. Тут же хотелось бы продолжить уже конкретнее о языке описания аппаратуры Verilog.
Автор является приверженцем FPGA Xilinx, поэтому большинство примеров будет именно в пакете ISE 14.4, а времяночки из симулятора ModelSim 6.5b.
Теоретический материал был найден на просторах интернета, а так же в книгах с полки.
1.1. Introduction¶
In this tutorial, full adder is designed with the help of half adders. Here we will learn following methods to create/implement the digital designs using Altera-Quartus software,
- Digital design using ‘block schematics’,
- Digital design using ‘Verilog codes’,
- Manual pin assignment for implementation,
- Pin assignments using ‘.csv’ file,
- Loading the design on FPGA.
- Converting the ‘Verilog design’ to ‘Symbols’
- Converting the ‘Block schematic’ to ‘Verilog code’ and ‘Symbols’.
If you do not have the FPGA-board, then skip the last part i.e. ‘loading the design on FPGA’. Simulation of the designs using ‘Modelsim’ is discussed in .
4.2.2 Знаковые и беззнаковые числа в выражениях.
В Verilog, например, они бывают только цепными и регистровыми (последние могут запоминаться где-то).
Другие элементы VHDL и Verilog
В VHDL синтаксис позволяет описывать модель в разных стилях (структурное, потоковое, поведенческое описания), а также встраивать в описание фрагменты языков программирования высокого уровня (Си, Паскаль). Этим и достигается его большая универсальность и применяемость не только для описания архитектур вычислительных систем. Например, моделирование разных физических систем у него имеет поддержку в виде типов с физическими размерностями.
Verilog также поддерживает разные описания модели системы, но интерфейса с обычными языками программирования у него нет.
Заключение
Несмотря на похожие названия, Verilog HDL и VHDL — различные языки. Verilog — достаточно простой язык, сходный с языком программирования Си — как по синтаксису, так и по «идеологии». Малое количество служебных слов и простота основных конструкций упрощают изучение и позволяют использовать Verilog в целях обучения. Но в то же время это эффективный и специализированный язык. VHDL обладает большей универсальностью и может быть использован не только для описания моделей цифровых электронных схем, но и для других моделей. Однако из-за своих расширенных возможностей VHDL проигрывает в эффективности и простоте, то есть на описание одной и той же конструкции в Verilog потребуется в 3√4 раза меньше символов (ASCII), чем в VHDL.
Оба языка поддерживаются в качестве стандартов большим количеством программных продуктов, в том числе и open source, в области САПР. Имеются и компиляторы, и симуляторы для обоих языков, в том числе, например, и с первого языка на второй. Именно эти языки используются при проектировании (с помощью современных средств САПР ведущими производителями FPGA) не только самих СБИС, но и готовых модулей (ядер), мегафункций (megafunctions), предназначенных для решения достаточно сложных задач обработки сигналов.
Понятия моделирования и синтеза
Работу логического устройства, описанного с помощью языков HDL, можно проверить двумя способами: либо на персональном компьютере (моделирование), либо непосредственной реализацией в микросхеме (например – ПЛИС) (синтез). Процесс синтеза намного сложнее моделирования, поскольку предполагает, помимо компиляции кода, еще и синтез логической схемы (т.е. реализацию устройства с помощью доступных компонентов ПЛИС и трассировку проводников в выбранной микросхеме). Поэтому результат применения некоторых конструкций языка Verilog при моделировании и синтезе отличается! Не все операторы языка Verilog являются синтезируемыми!
Обычно для моделирования используются специальные тестовые программы – тестбенчи (testbench), которые предназначены для проверки программы описания модулей (их верификации). Обычно, для выполнения моделирования используется специализированное ПО, например – ModelSim.
Пишем «демку» для LESO2 на Verilog
Особенности языков описания архитектуры Verilog и VHDL
Вводные замечания
Языки VHDL и Verilog (Verilog HDL) относятся, в отличие от языка Argus, к языкам описания аппаратуры. Поэтому их нельзя напрямую сравнивать с Argus — они предназначены не для написания программ для FPGA и др. СБИС, а для проектирования логики самих этих устройств. Эти языки предназначены для моделирования электронных схем на уровнях вентильном, регистровых передач, корпусов микросхем. Поэтому эти языки можно назвать языками сквозного функционально-логического проектирования.
VHDL (Very high speed integrated circuits Hardware Description Language) был разработан в 1983 г. по заказу Пентагона с целью формального описания логических схем для всех этапов разработки электронных систем. Первый стандарт был утверждён в 1987 г., последний из известных — в 2002 г.
Verilog HDL был разработан фирмой Gateway Design Automaton как внутренний язык симуляции. Cadence приобрела Gateway в 1989 г. и открыла Verilog для общественного использования. В 1995 г. был определен стандарт языка — Verilog LRM (Language Reference Manual), IEEE1364-1995, а последний из известных — в 2001 г.
Первоначально VHDL предназначался для моделирования (что и объясняет его большую универсальность), но позднее из него было выделено синтезируемое подмножество. Написание алгоритмической модели на синтезируемом подмножестве гарантирует автоматический синтез по этой модели алгоритмической схемы. Аналогичная поддержка существует и для Verilog.
Основные составляющие языков VHDL и Verilog
Типы данных
В более простом языке Verilog поддерживаются только самые простые типы данных — целые (32-бит со знаком), действительные (с плавающей запятой), а также специфические типы «время» и «событие». В VHDL шире набор базовых типов, и, кроме этого, проектировщик может создавать свои типы данных, а в Verilog этого делать нельзя. Надо отметить, что программируются-то в этих языках как данные не элементы памяти, а сигналы.
4.2.2 Знаковые и беззнаковые числа в выражениях.
В Verilog, например, они бывают только цепными и регистровыми (последние могут запоминаться где-то).
Другие элементы VHDL и Verilog
В VHDL синтаксис позволяет описывать модель в разных стилях (структурное, потоковое, поведенческое описания), а также встраивать в описание фрагменты языков программирования высокого уровня (Си, Паскаль). Этим и достигается его большая универсальность и применяемость не только для описания архитектур вычислительных систем. Например, моделирование разных физических систем у него имеет поддержку в виде типов с физическими размерностями.
Verilog также поддерживает разные описания модели системы, но интерфейса с обычными языками программирования у него нет.
Заключение
Несмотря на похожие названия, Verilog HDL и VHDL — различные языки. Verilog — достаточно простой язык, сходный с языком программирования Си — как по синтаксису, так и по «идеологии». Малое количество служебных слов и простота основных конструкций упрощают изучение и позволяют использовать Verilog в целях обучения. Но в то же время это эффективный и специализированный язык. VHDL обладает большей универсальностью и может быть использован не только для описания моделей цифровых электронных схем, но и для других моделей. Однако из-за своих расширенных возможностей VHDL проигрывает в эффективности и простоте, то есть на описание одной и той же конструкции в Verilog потребуется в 3√4 раза меньше символов (ASCII), чем в VHDL.
Оба языка поддерживаются в качестве стандартов большим количеством программных продуктов, в том числе и open source, в области САПР. Имеются и компиляторы, и симуляторы для обоих языков, в том числе, например, и с первого языка на второй. Именно эти языки используются при проектировании (с помощью современных средств САПР ведущими производителями FPGA) не только самих СБИС, но и готовых модулей (ядер), мегафункций (megafunctions), предназначенных для решения достаточно сложных задач обработки сигналов.
Лаборатория Параллельных информационных технологий НИВЦ МГУ
Procedural Continuous Assignment
These are procedural statements that allow expressions to be continuously assigned to nets or variables and are of two types.
- …
- …
assign deassign
This will override all procedural assignments to a variable and is deactivated by using the same signal with . The value of the variable will remain same until the variable gets a new value through a procedural or procedural continuous assignment. The LHS of an statement cannot be a bit-select, part-select or an array reference but can be a variable or a concatenation of variables.
force release
These are similar to the statements but can also be applied to nets and variables. The LHS can be a bit-select of a net, part-select of a net, variable or a net but cannot be the reference to an array and bit/part select of a variable. The statment will override all other assignments made to the variable until it is released using the keyword.
SystemVerilog logic, data types, and data objects
SystemVerilog introduces a new 2-state data type—where only logic 0 and logic 1 are allowed, not X or Z—for testbench modeling. To distinguish the old Verilog 4-state behaviour, a new SystemVerilog logic data type is added to describe a generic 4-state data type.
What used to be data types in Verilog, like wire, reg, wand, are now called data objects in SystemVerilog. Wire, reg, wand (and almost all previous Verilog data types) are 4-state data objects. Bit, byte, shortint, int, longint are the new SystemVerilog 2-state data objects.
There are still the two main groups of data objects: nets and variables. All the Verilog data types (now data objects) that we are familiar with, since they are 4-state, should now properly also contain the SystemVerilog logic keyword.
wire my_wire; // implicitly means "wire logic my_wire" wire logic my_wire; // you can also declare it this way wire my_wire_bus; // implicitly means "wire logic my_wire_bus" wire logic my_wire_logic_bus; // you can also declare it this way reg my_reg_bus; // implicitly means "reg logic my_reg_bus" //reg logic my_reg_bus; // but if you declare it fully, VCS 2014.10 doesn't like it
There is a new way to declare variables, beginning with the keyword var. If the data type (2-state or 4-state) is not specified, then it is implicitly declared as logic. Below are some variable declaration examples. Although some don’t seem to be fully supported by tools.
// From the SV-2012 LRM Section 6.8 var byte my_byte; // byte is 2-state, so this is a variable // var v; // implicitly means "var logic v;", but VCS 2014.10 doesn't like this var logic v; // this is okay // var vw; // implicitly means "var logic vw;", but VCS 2014.10 doesn't like this var logic vw; // this is okay var enum bit {clear, error} status; // variable of enumerated type var reg r; // variable reg
Don’t worry too much about the var keyword. It was added for language preciseness (it’s what happens as a language evolves and language gurus strive to maintain backward-compatibility), and you’ll likely not see it in an RTL design.
Блок начальной инициализации
Начальная инициализация, как следует из названия, выполняется только один раз, при старте моделирования. Это полезно при написании тестов. Если у нас есть несколько блоков начальной инициализации, то все они выполнены в начале моделирования.
Пример
Verilog Code:
- initial begin
- clk = ;
- reset = ;
- req_0 = ;
- req_1 = ;
- end
В приведенном выше примере, в начале моделирования (т. е. при времени = 0), все переменные внутри блока begin / end установятся в ноль
Важно понимать, что на реально синтезируемую схему блок начальной инициализации влияния не оказывает
Просмотреть дискуссию.
-
Verilog за день часть 1.
-
Verilog за день часть 3.
Запись чисел в Verilog
Числа или иначе константы могут определяться в десятичном, шестнадцатеричном, восьмеричном или двоичном форматах. В языке Verilog предусмотрены две формы для записи чисел. Первая форма представляет собой простое десятичное число как последовательность цифр от 0 до 9 и опционально может предваряться символами плюса или минуса. Вторая форма представления чисел имеет следующий формат:
1 |
<size> <base_format> <number> |
Поле size содержит десятичные цифры и указывает разрядность константы в битах. Это поле опционально и может опускаться в случаях если разрядность константы заранее определена (Допустим производится присвоение константного значения переменной, разрядность которой задана при ее объявлении). Если разрядность не определена, то разрядность принимается по умолчанию равной 32 (32 в большинстве систем синтеза, в некоторых разрядность по умолчанию может отличаться).
Второе поле base_format содержит букву, определяющую формат представления числа (десятичный, двоичный …). Эта буква предваряется символом одиночной кавычки (‘). Формат представления определяется следующими буквами: d – десятичный; h – шестнадцатиричный; o – восьмеричный и b – двоичный. Допускается вводить эти буквы как прописными, так и строчными.
Последнее поле number содержит цифры допустимые для выбранного формата:
от 0 до 9 для десятичного формата;
от 0 до 7 для восьмеричного;
0 и 1 для двоичного;
от 0 до 9 и буквы a, b, c, d, e, f для шестнадцатеричного.
Буквенные обозначения могут вводится как строчными, так и прописными буквами.
Числа имеющие знаковое представление предваряются опциональными символами плюса и минуса перед полем size. Эти символы перед полем number недопустимы. Запись -8’h5A эквивалентна записи -(8’h5A), а запись 8’h-5A вызовет синтаксическую ошибку.
Помимо указанных цифр в поле numbers могут присутствовать буквы x, X, z, Z и символ (?) (В поле size они недопустимы). Буквы x и X обозначают неизвестное (неопределенное) состояние, т.е. состояние соответствующих битов неизвестно. Буквы z и Z обозначают состояние высокого импеданса – z-состояние или отсутствие источника (драйвера). Символ ? эквивалентен символу z и предназначен для лучшей читабельности кода в случаях когда это состояние безразлично (don’t-care).
Существует возможность сокращать запись числа: например 8’b1 будет эквивалентно записи 8’b11111111, но запись 8’b01 будет эквивалентна записи 8’b00000001. В силу того, что такие сокращенные записи могут мешать читабельности кода, употреблять их без особой надобноси не следует, пожалуй допустимыми можно считать записи 8’b0, 8’b1, 8’bx, можно записать и 16’hx – это эквивалентно 16’hxxxx. В остальных случаях лучше делать подробную запись числа.
Для улучшения читабельности допускаются еще два приема: допускается вставлять пробелы и символы табуляции между полями записи, например 8’hB6 можно записать как 8 ‘h B6. Вставлять пробелы внутри поля number не допускается, но можно вставлять символ подчеркивания (_), для разбиения числа на некоторые группы. Примеры 83465 можно записать как 83_465; 8’b01100111 можно записать как 8’b0110_0111. Символ подчеркивания в поле size или перед полем number недопустим.
Программный языковой интерфейс (PLI)
PLI предоставляет программисту механизм для передачи управления от Verilog программной функции, написанной на языке C. Это официально устарел по IEEE Std 1364-2005 в пользу более новой Процедурный интерфейс Verilog, который полностью заменяет PLI.
PLI (теперь VPI) позволяет Verilog взаимодействовать с другими программами, написанными на языке C, такими как испытательные жгуты, симуляторы набора команд из микроконтроллер, отладчики, и так далее. Например, он предоставляет функции C и которые используются для записи и чтения аргумента текущей задачи или функции Verilog соответственно.
Continuous Assignment
This is used to assign values onto scalar and vector nets and happens whenever there is a change in the RHS. It provides a way to model combinational logic without specifying an interconnection of gates and makes it easier to drive the net with logical expressions.
Whenever b or c changes its value, then the whole expression in RHS will be evaluated and a will be updated with the new value.
Net declaration assignment
This allows us to place a continuous assignment on the same statement that declares the net. Note that because a net can be declared only once, only one declaration assignment is possible for a net.
I’m confused… Just tell me how I should use SystemVerilog logic!
After all that technical specification gobbledygook, I have good news if you’re using SystemVerilog for RTL design. For everyday usage in RTL design, you can pretty much forget all of that!
The SystemVerilog logic keyword standalone will declare a variable, but the rules have been rewritten such that you can pretty much use a variable everywhere in RTL design. Hence, you see in my example code from other articles, I use SystemVerilog logic to declare variables and ports.
module my_systemverilog_module ( input logic clk, input logic rst_n, input logic data_in_valid, input logic data_in_bus, output logic data_out_valid, // driven by always_ff, it is a variable output logic data_out_bus, // driven by always_comb, it is a variable output logic data_out_err // also a variable, driven by continuous assignment (allowed in SV) ); assign data_out_err = 1'b1; // continuous assignment to a variable (allowed in SV) // always_comb data_out_err = 1'b0; // multiple drivers to variable not allowed, get compile time error always_comb data_out_bus = <data_out_bus logic expression>; always_ff @(posedge clk, negedge rst_n) if (!rst_n) data_out_valid <= 1'b0; else data_out_valid <= <data_out_valid logic expression>; endmodule
When you use SystemVerilog logic standalone this way, there is another advantage of improved checking for unintended multiple drivers. Multiple assignments, or mixing continuous and procedural (always block) assignments, to a SystemVerilog variable is an error, which means you will most likely see a compile time error. Mixing and multiple assignments is allowed for a net. So if you really want a multiply-driven net you will need to declare it a wire.
In Verilog it was legal to have an assignment to a module output port (declared as Verilog wire or Verilog reg) from outside the module, or to have an assignment inside the module to a net declared as an input port. Both of these are frequently unintended wiring mistakes, causing contention. With SystemVerilog, an output port declared as SystemVerilog logic variable prohibits multiple drivers, and an assignment to an input port declared as SystemVerilog logic variable is also illegal. So if you make this kind of wiring mistake, you will likely again get a compile time error.
SystemVerilog rule of thumb 1: if using SystemVerilog for RTL design, use SystemVerilog logic to declare:
- All point-to-point nets. If you specifically need a multi-driver net, then use one of the traditional net types like wire
- All variables (logic driven by always blocks)
- All input ports
- All output ports
If you follow this rule, you can pretty much forget about the differences between Verilog reg and Verilog wire! (well, most of the time)
Блокирующее присваивание
Блокирующее присваивание, заклеймленное некорыми как «медленное», в действительности во многих случаях синтезируется в совершенно ту же схему, что и неблокирующее. Так, например фрагменты:
Verilog Code:
- always @(posedge clk) begin
- x = x + 1;
- y = y + 1;
- end
и
Verilog Code:
- always @(posedge clk) begin
- x <= x + 1;
- y <= y + 1;
- end
дадут один и тот же результат. Оба выражения выполнятся одновременно, в обоих случаях «время выполнения» будет равно времени записи в соответствующий регистр значения на его входе. Пока выражения не зависят друг от друга, никакой разницы между блокирующими и неблокирующими присваиваниями нет.
В то же время, следующая запись являет собой что-то новое:
Verilog Code:
- always @(posedge clk) begin
- x = x + 1;
- y = x;
- end
Здесь x увеличится на 1, а y примет значение x + 1. Чтобы записать это выражение неблокирующими присваиваниями, потребовалась бы такая запись:
Verilog Code:
- always @(posedge clk) begin
- x <= x + 1;
- y <= x + 1;
- end
Цепочку блокирующих присваиваний можно рассматривать как одно большое выражение. Еще пример:
Verilog Code:
- y <= 3*((input_value >> 4) + center_offset
или
Verilog Code:
- y = input_value >> 4;
- y = y + center_offset;
- y = 3 * y;
Эти две записи эквивалентны. Но вторую запись нельзя понимать как последовательную цепочку вычислений. Это верно лишь в том смысле, что всё выражение действительно выстраивается в схему, в которой сначала отрезаются 4 младших разряда, результат и второй операнд идут на вход сумматора, а выход сумматора отдается умножителю на три. Так это представляется в электрической схеме и человек для удобства нарисует эту схему слева направо и читать он ее будет последовательно. Но в получившейся схеме все это выражение выполняется непрерывно, так же как и в предыдущей записи с неблокирующим присваиванием. Запись результата в регистр, как и следовало ожидать, происходит по фронту тактового импульса.
Заключительный пример, использующий оба вида присваиваний, заодно напоминающий о неродстве оператора for с одноименными операторами в алгоритмических языках программирования:
Verilog Code:
- // Эквивалентная запись:
- // history <= history; history <= history; history <= history; history <= current;
- always @(posedge clk) begin
- for (i = 1; i < 4; i = i + 1) historyi <= historyi-1;
- history <= current;
- end
- // Эквивалентная запись:
- // avg <= (history+history+history+history)/4;
- always @(posedge clk) begin
- sum = ;
- for (i = ; i < 4; i = i + 1) sum = sum + historyi;
- avg = sum4;
- end
Этот пример выдает скользящее среднее с запаздыванием на два такта.
Getting Used to the Waveform Window
Now that you have plotted your waveforms, you need to be familiarized with
the tools used to analyze them. One tool is the Waveform Calculator, but that
will be discussed in the next section. Some basic hotkeys and options that you
should be aware of are:
- z — Zoom in (after typing ‘z’, click the mouse to form the box that you
want to zoom in) - Z — Zoom out (after typing ‘Z’, click the mouse to form the box that you
want to zoom out) - ] — Fast zoom in
- [ — Fast zoom out
- F — Zoom to fit to the complete waveform
- Select Axes -> Options… — To turn the grid lines on/off and
change other axis properties. - a — Place crosshair marker A (for more information about placing crosshair
markers, click
) - b — Place crosshair marker B
If-else
If-else конструкция, проверяет условие, и решает будет или нет выполнена часть кода. Если условие верно, код выполнится. Иначе выполнится другая часть кода.
Verilog Code:
- // begin и end выполняют роль фигурных скобок в C/C++.
- if (enable == 1’b1) begin
- data = 10; // Десятичное присваивание
- address = 16’hDEAD; // Шестнадцатиричное присваивание
- wr_enable = 1’b1; // Двоичное присваивание
- end else begin
- data = 32’b0;
- wr_enable = 1’b0;
- address = address + 1;
- end
Можно использовать любой оператор для проверки состояния, так-же как в языке C. В случае необходимости, можно использовать вложенные if-else выражения; выражение без else так же является нормальным, но такое выражение может вызывать проблемы, при создании комбинаторной логики такое выражение может приводить к созданию защелки (впрочем не всегда).
Assigning and Copying Verilog Arrays
Verilog arrays can only be referenced one element at a time. Therefore, an array has to be copied a single element at a time. Array initialization has to happen a single element at a time. It is possible, however, to loop through array elements with a generate or similar loop construct. Elements of a memory must also be referenced one element at a time.
initial begin mema = 0; // Illegal syntax - Attempt to write to entire array arrayb = 0; // Illegal syntax - Attempt to write to elements ... arrayb = 0; // Illegal syntax - Attempt to write to multiple elements mema = 0; // Assigns 0 to the second element of mema arrayb = 0; // Assigns 0 to the bit referenced by indices end // Generate loop with arrays of wires generate genvar gi; for (gi=0; gi<8; gi=gi+1) begin : gen_array_transform my_example_16_bit_transform_module u_mod ( .in (y), .out (z) ); end endgenerate // For loop with arrays integer index; always @(posedge clk, negedge rst_n) begin if (!rst_n) begin // reset arrayb for (index=0; index<256; index=index+1) begin mema <= 8'h00; end end else begin // out of reset functional code end end
8.5. Read only memory (ROM)¶
ROMs are the devices which are used to store information permanently. In this section, ROM is implemented on FPGA to store the display-pattern for seven-segment device, which is explained in Section . Verilog files required for this example are listed below,
- ROM_sevenSegment.v
- ROM_sevenSegment_visualTest.v
8.5.1. ROM implementation using RAM (block ROM)
implements the ROM (Lines 27-47), which stores the seven-segment display pattern in it (Lines 30-45). Since the address width is 16 (Line 16), therefore total 16 values can be stored with different addresses (Lines 30-45). Further, 16 addresses can be represented by 4-bits, therefore ‘addr_bit’ is set to 4 at Line 17. Lastly, total 7 bits are required to represent the number in 7-segment-display, therefore ‘data_width’ is set to 7 at Line 18.
Listing 8.13 Seven segment display pattern stored in ROM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
//ROM_sevenSegment.v // created by : Meher Krishna Patel // date : 25-Dec-16 // Functionality: // seven-segment display format for Hexadecimal values (i.e. 0-F) are stored in ROM // ports: // addr : input port for getting address // data : ouput data at location 'addr' // addr_width : total number of elements to store (put exact number) // addr_bits : bits requires to store elements specified by addr_width // data_width : number of bits in each elements module ROM_sevenSegment #( parameter addr_width = 16, // store 16 elements addr_bits = 4, // required bits to store 16 elements data_width = 7 // each element has 7-bits ) ( input wire clk, input wire addr_bits-1 addr, output reg data_width-1 data // reg (not wire) ); always @* begin case(addr) 4'b0000 data = 7'b1000000; // 0 4'b0001 data = 7'b1111001; // 1 4'b0010 data = 7'b0100100; // 2 4'b0011 data = 7'b0110000; // 3 4'b0100 data = 7'b0011001; // 4 4'b0101 data = 7'b0010010; // 5 4'b0110 data = 7'b0000010; // 6 4'b0111 data = 7'b1111000; // 7 4'b1000 data = 7'b0000000; // 8 4'b1001 data = 7'b0010000; // 9 4'b1010 data = 7'b0001000; // a 4'b1011 data = 7'b0000011; // b 4'b1100 data = 7'b1000110; // c 4'b1101 data = 7'b0100001; // d 4'b1110 data = 7'b0000110; // e default data = 7'b0001110; // f endcase end endmodule |
Example
The design module shown below has a 2-bit select signal to route one of the three other 3-bit inputs to the output signal called out. A statement is used to assign the correct input to output based on the value of sel. Since sel is a 2-bit signal, it can have 22 combinations, 0 through 3. The default statement helps to set output to 0 if sel is 3.
Hardware Schematic
The rtl code is elaborated to get a hardware schematic that represents a 4 to 1 multiplexer.
See that output is zero when sel is 3 and corresponds to the assigned inputs for other values.
Simulation Log
ncsim> run a=0x4 b=0x1 c=0x1 sel=0b11 out=0x0 a=0x5 b=0x5 c=0x5 sel=0b10 out=0x5 a=0x1 b=0x5 c=0x6 sel=0b01 out=0x5 a=0x5 b=0x4 c=0x1 sel=0b10 out=0x1 a=0x5 b=0x2 c=0x5 sel=0b11 out=0x0 ncsim: *W,RNQUIE: Simulation is complete.
In a case statement, the comparison only succeeds when each bit of the expression matches one of the alternatives including 0, 1, x and z. In the example shown above, if any of the bits in sel is either x or z, the statement will be executed because none of the other alternatives matched. In such a case, output will be all zeros.
Simulation Log
ncsim> run a=0x4 b=0x1 c=0x1 sel=0bxx out=0x0 a=0x3 b=0x5 c=0x5 sel=0bzx out=0x0 a=0x5 b=0x2 c=0x1 sel=0bxx out=0x0 a=0x5 b=0x6 c=0x5 sel=0bzx out=0x0 a=0x5 b=0x4 c=0x1 sel=0bxz out=0x0 a=0x6 b=0x5 c=0x2 sel=0bxz out=0x0 a=0x5 b=0x7 c=0x2 sel=0bzx out=0x0 a=0x7 b=0x2 c=0x6 sel=0bzz out=0x0 a=0x0 b=0x5 c=0x4 sel=0bxx out=0x0 a=0x5 b=0x5 c=0x5 sel=0bxz out=0x0 ncsim: *W,RNQUIE: Simulation is complete.
If the case statement in design has x and z in the case item alternatives, the results would be quite different.
Simulation Log
ncsim> run a=0x4 b=0x1 c=0x1 sel=0bxx out=0x1 a=0x3 b=0x5 c=0x5 sel=0bzx out=0x5 a=0x5 b=0x2 c=0x1 sel=0bxx out=0x1 a=0x5 b=0x6 c=0x5 sel=0bzx out=0x6 a=0x5 b=0x4 c=0x1 sel=0bxz out=0x5 a=0x6 b=0x5 c=0x2 sel=0bxz out=0x6 a=0x5 b=0x7 c=0x2 sel=0bzx out=0x7 a=0x7 b=0x2 c=0x6 sel=0bzz out=0x0 a=0x0 b=0x5 c=0x4 sel=0bxx out=0x4 a=0x5 b=0x5 c=0x5 sel=0bxz out=0x5 ncsim: *W,RNQUIE: Simulation is complete.
Пример определения вектора —
inout address; //двунаправленный 8 битный порт «address»
Примечание: выражение , использует прямой порядок бит — самый младший бит находится справа, самый старший находится слева. Если бы мы написали , мы использовали бы обратный порядок бит и они увеличивались слева направо
Порядок бит — чисто произвольный способ решить, в каком порядке выстроятся ваши данные, в разных системах используется разный порядок слов, таким образом важно выбрать правильный порядок бит для совместимости с существующими системами. Как аналогия, представьте разные языки: (английский), в котором буквы написаны слева направо (прямой порядок) в других (арабский язык), написание букв справа налево (обратный порядок)
Знание того, как надо читать буквы, крайне важно для понимания слов, но направление букв было выбрано произвольно, много лет назад.
Problems With Passing Multiple Control Signals Across Clock Domain Crossing (CDC)
The fundamental problem with passing multiple bits is if they are synchronized individually, they cannot be guaranteed to arrive in the destination clock domain on the same clock edge. When the individual bits are launched from the source clock domain, they may be skewed relative to each other due to trace length, process variation, etc. Since in an asynchronous clock domain crossing (CDC) the destination clock can have every possible alignment relative to the source clock (and relative to the skewed data bits), the destination clock can (and will) sample at a time when not all the bits are at their stable final values. Therefore synchronizing individual bits of a multi-bit signal is not sufficient! Let’s look at several potential problems.
Two simultaneously required signals
The waveform below shows how data skew from the source clock domain can cause two signals to arrive in different clock cycles in the destination domain, if they are synchronized individually using two flip-flop synchronizers. Don’t do this!
Two sequenced signals
Individually synchronizing two signals that require precise sequencing across an asynchronous clock domain crossing (CDC) is a recipe for disaster. In fact a recent ASIC project at work had a problem like this that resulted in a chip that only booted 50% of the time, months of debug, and finally a respin (we make mistakes too).
The waveform below shows how two separate signals that are intended to arrive 1 cycle apart in the destination domain, can actually arrive either 1 or 2 cycles apart depending on data skew. It’s difficult to even analyze the frequency difference from the source to destination clock domain and come up with a potential sequence that may work… Just don’t do this. There are better ways!
Encoded control signals
There are many scenarios where you may want to pass a multi-bit signal across a clock domain crossing (CDC), such as an encoded signal. By now we understand the potential problem, right? Due to data skew, the different bits may take different number of cycles to synchronize, and we may not be able to read the same encoded value on the destination clock domain. You may get away with using a simple two flip-flop synchronizer if you know there will be sufficient time for the signal to settle before reading the synchronized value (like a relatively static encoded status signal). But it’s still not the best practice.