Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lek_Kratkie_svedenia_yazyka_Verilog.docx
Скачиваний:
82
Добавлен:
11.06.2015
Размер:
1.22 Mб
Скачать

Input x1, x2, x3, x4, x5, x6, x7;

output Y1, Y2, Y3;

assign Y1=X1 | X3 | X5 | X7;

assign Y2=X2 | X3 | X6 | X7;

assign Y3=X4 | X5 | X6 | X7;

endmodule

Аналогичная опишем четырехканальный мультиплексор, структурная формула которого в СДНФ имеет вид:

В соответствии со структурной формулой схема мультиплексора в блочном описании на языке Verilog имеет вид (исправить ошибку в схеме):

Опишем схему мультиплексора на языке Verilog

1-й способ:

module MULTIPLEXOR (A0, A1, D0, D1, D2, D3, Y);

Input a0, a1, d0, d1, d2, d3;

output Y;

assign Y=(D0 & !A1& !A0) | (D1 & !A1& A0) | (D2 & A1& !A0) | (D3 & A1 & A0);

endmodule

2-й способ (описание мультиплексора через wire):

module MULTIPLEXOR (input A0, input A1, input D0, input D1, input D2, input D3,

output Y);

wire S1, S2, S3, S4, S5, S6;

NOT my_1_not ( .OUT(S1), .IN1(A0));

NOT my_2_not ( .OUT(S2), .IN1(A1));

AND3 my_1_and ( .OUT(S3), .IN1(S1), .IN2(S2), .IN3(D0));

AND2 my_2_and ( .OUT(S4), .IN1(A0), .IN2(D1));

AND3 my_3_and ( .OUT(S5), .IN1(S1), .IN2(A1), .IN3(D2));

AND3 my_4_and ( .OUT(S6), .IN1(A0), .IN2(A1), .IN3(D3));

OR4 my_or ( .OUT(Y), .IN1(S3), .IN2(S4), .IN3(S5), .IN4(S6));

endmodule

Разработка модулей высокого уровня на ПЛИС на примере сумматора

Мы знаем про основные базовые логические элементы – и это тоже модули. Используем их в модуле более высокого уровня. Сделаем однобитный сумматор, а на его основе много битный сумматор (более высокого уровня).

Вначале рассмотрим синтез сумматора от постановки задачи до создания схемы однобитного сумматора.

Однобитный сумматор складывает два однобитных числа a и b. При выполнении сложения однобитных чисел может случиться «переполнение», то есть результат уже будет двух битным (1+1=2 или в двоичном виде 1’b1+1’b1=2’b10). Поэтому включим в сумматор выходной сигнал переноса c_out.

Дополнительный входной сигнал c_in служит для приема сигнала переноса от сумматоров младших разрядов (при построении много битных сумматоров).

Таблица истинности работы однобитного сумматора.

п/п

a

b

c_in

sum

c_out

Примечание

0

0

0

0

0

0

1

0

1

1

1

1

Перенос

2

1

0

0

1

0

3

1

1

1

0

1

Перенос

Примечание: С целью упрощения таблицы не все события в таблице перечислены для c_in, sum, c_out.

Структурные формулы работы однобитного сумматора с учетом минимизации учитывает все возможные события.

sum=(a^b) ^ c_in

c_out=((a^b) & c_in) ^ (a &b),

где символ «^» - сложение по модулю 2, символ «&» - логическая операция конъюнкция (and).

Схема согласно структурной формулы в графическом виде имеет вид:

Опишем эту схему на языке Verilog, устанавливая в теле модуля экземпляры других модулей.

Итак, модуль одно битного сумматора содержит 3 экземпляра модуля XOR и два экземпляра модуля AND2.

Порядок описания экземпляра модуля такой:

• название модуля, тип которого нам нужен (adder1) с указанием входов и выходов;

• описываем подключение сигналов: точка и затем имя сигнала модуля, затем в скобках имя проводника, который сюда подключен.

module adder1(input a, input b, input

c_in, output sum, output c_out);

wire s1,s2,s3;

XOR my_1_xor( .OUT (s1), .IN1 (a), .IN2 (b) );

AND2 my_1_and2( .OUT (s3), .IN1 (a), .IN2 (b) );

XOR my_2_xor( .OUT (sum), .IN1 (s1), .IN2 (c_in) );

AND2 my_2_and2( .OUT (s2), .IN1 (s1), .IN2 (c_in) );

XOR my_3_xor( .OUT (c_out), .IN1 (s2), .IN2 (s3) );

Endmodule

Опишем на языке Verilog однобитный сумматор на поведенческом уровне, то есть на основе структурных формул:

module adder1(input a, input b, input

c_in, output sum, output c_out);

assign sum = (a^b) ^ c_in;

assign c_out = ((a^b) & c_in) ^ (a&b);

endmodule

Следует помнить, что существуют разные методы описания и нужно уметь ими всеми пользоваться.

Итак, мы создали однобитный сумматор. На его основе можно создать n-битный сумматор. Рассмотрим, например, четырех битный сумматор (с

последовательным переносом).

Блочнe. схемe 4-х битного сумматора представим в виде:

Опишем эту схему на языке Verilog:

module adder4(output [3:0]sum, output c_out, input [3:0]a, input

[3:0]b );

wire c0, c1, c2;

adder1 my0_adder1( .sum (sum[0]) , .c_out (c0), .a (a[0]), .b

(b[0]), .c_in (1’b0) );

adder1 my1_adder1( .sum (sum[1]) , .c_out (c1), .a (a[1]), .b

(b[1]), .c_in (c0));

adder1 my2_adder1( .sum (sum[2]) , .c_out (c2), .a (a[2]), .b

(b[2]), .c_in (c1));

adder1 my3_adder1( .sum (sum[3]) , .c_out (c_out), .a (a[3]), .b

(b[3]), .c_in (c2) );

endmodule

Таким образом, мы реализовали четырехбитный сумматор. Мы получили его как модуль верхнего уровня adder4, состоящий из модулей adder1, которые, в свою очередь состоят из модулей примитивов AND2 и XOR.

Арифметические и логические функции

Мы уже знаем про модули, их входные и выходные сигналы и как они могут быть соединены друг с другом. Знаем, как можно сделать много битный сумматор. Нужно ли каждый раз, когда складываем два числа, делать такие сложные модули? Конечно нет! Поэтому познакомимся с основными арифметическими и логическими операторами языка Verilog.

С помощью комбинаторной логики посчитаем некоторые арифметические и логические функции.

Сложение и вычитание.

Пример модуля, который одновременно и складывает и вычитает два числа. Здесь входные операнды у нас 8-ми битные, а результат 9-ти битный. Verilog корректно сгенерирует бит переноса (carry bit) и поместит его в девятый бит выходного результата. С точки зрения Verilog входные операнды беззнаковые.

module simple_add_sub

(

operandA, operandB,

out_sum, out_dif

);

//два входных 8-ми битных операнда

input [7:0] operand A, operand B;

/*Выходы для арифметических операций имеют дополнительный 9-й бит

переполнения*/

output [8:0] out_sum, out_dif;

assign out_sum = operandA + operandB; //сложение

assign out_dif = operandA – operandB; //вычитание

endmodule

12

• Логический и арифметический сдвиг.

Рассмотрим пример модуля, который выполняет сдвиги. В нашем примере результат для сдвига влево16-ти битный. Если сдвигать влево или вправо слишком далеко, то результат получится просто ноль. Часто для сдвига используются только часть бит от второго операнда, для того, чтобы сэкономить логику.

module simple_shift

(

operandA, operandB,

out_shl, out_shr, out_sar

);

// два входных 8-ми битных операнда

input [7:0] operandA, operandB;

// Выходы для операций сдвига

output [15:0] out_shl;

output [7:0] out_shr;

output [7:0] out_sar;

//логический сдвиг влево

assign out_shl = operandA << operandB;

/* пример: на сколько сдвигать определяется 3-мя битами второго

операнда */

assign out_shr = operandA >> operandB[2:0];

//арифметический сдвиг вправо (сохранение знака числа)

assign out_sar = operandA >>> operandB[2:0];

endmodule

• Битовые логические операции

Битовые операции в Verilog выглядят так же, как и в языке C. Каждый бит результата вычисляется отдельно соответственно битам операндов. Пример:

module simple_bit_logic (

operandA, operandB,

out_bit_and, out_bit_or, out_bit_xor, out_bit_not);

//два входных 8-ми битных операнда

input [7:0] operandA, operandB;

//Выходы для битовых (bit-wise) логических операций

output [7:0] out_bit_and, out_bit_or, out_bit_xor, out_bit_not;

assign out_bit_and = operandA & operandB; //И

assign out_bit_or = operandA | operandB; //ИЛИ

assign out_bit_xor = operandA ^ operandB; //исключающее ИЛИ

assign out_bit_not = ~operandA; //НЕ

endmodule

Операции отношения

Следующие примеры иллюстрируют операторы отношения:

a < b a меньше чем b;

a > b a больше чем b;

a <= b a меньше или равно b;

a >= b a больше или равно b;

Все эти выражения возвращают лог.0 если приведенное отношение ложно (false) или лог.1 если отношение истинно (true). Если один из операндов имеет неопределенное значение, то и результат будет неопределен. Все операторы отношения имеют одинаковый приоритет и более низкий, чем приоритет арифметических операторов. Следующий пример иллюстрирует смысл этого правила:

a < size -1 // Эта конструкция идентична

a < (size -1) // этой, но

size – (1 < a) // эта конструкция отличается

size – 1 < a // от этой

Заметим, что в конструкции size – (1 < a) операция отношения вычисляется первой, а затем результат (0 или 1) вычитается из переменной size. В следующем же выражении сначала size уменьшается на 1, а затем результат сравнивается с а.

Операторы сравнения

Операторы сравнения имеют более низкий приоритет, чем операторы сравнения. В следующем примере иллюстрируются операторы сравнения.

a === b // a равно b, включая x

a !== b // a не равно b, включая x

a == b // a равно b, результат может быть неизвестен

a != b // a не равно b, результат может быть неизвестен

Все четыре оператора имеют одинаковый приоритет. Они сравнивают операнды бит в бит, и заполняют нулями в случае если операнды имеют различную разрядность. Так же как и операторы отношения они возвращают 0 если false и 1 если true. Если хотя бы один операнд содержит x, то операции == и != возвращают неопределенное значение. Операции === и !== сравнивают операнды с учетом x, поэтому всегда возвращают либо 0, либо 1.

Логические операции

Операторы логического И (&&) и логического ИЛИ (||) тесно связаны между собой. Результат логического сравнения может принимать значение «истинно» (true, 1) или «ложно» (false, 0), или если один из операндов имеет неопределенное значение, то и результат будет неопределен. Допустим, один из операндов имеет значение равное 10, а второй равен нулю. Результат логического И будет равен 0, так как второй операнд равен нулю. Результат логического ИЛИ, однако будет равен 1, так как первый операнд отличен от нуля. Verilog HDL воспринимает операнд равный 0 как «ложный», в то же время если операнд не равен нулю (не обязательно равен 1, например 10), то он воспринимается как «истинный». Именно это и произошло в приведенном примере: операция (true && false) привела к результату false, а операция (true || false) привела к результату true.

Операторы сдвига

К операторам сдвига относятся операторы <<, >>, <<< и >>>. Первые два оператора

выполняют простой сдвиг влево или вправо на количество позиций указанных

операндом в правой части выражения, два других выполняют циклический или иначе арифметический сдвиг. В следующем примере иллюстрируется механизм действия этих операторов.

Выражение Результат

8’b01001111 << 3 8’b01111000

8’b01001111 <<< 3 8’b01111010

8’b01001111 >> 3 8’b00001001

8’b01001111 >>> 3 8’b11101001

Условный оператор

Условный оператор имеет три операнда, разделенные двумя операторами в

следующем формате:

cond_expr ? true_expr : false_expr;

Если условие (cond_expr) вычисляется как «ложное» (false), то в качестве результата

будет использовано выражение false_expr. Если условие «истинно» (true), то будет

использовано выражение true_expr.

Операция объединения (конкатенация)

Операция конкатенации является одной из наиболее удобных и мощных операций в языке Verilog. Суть ее заключается в слиянии нескольких переменных в единое целое, единую переменную, с которой можно производить любые другие операции.

Необходимо отметить два момента: операция конкатенации обладает наивысшим приоритетом по сравнению с любой другой операцией вне символов конкатенации ({}), но операции заключенные внутри фигурных скобок имеют еще больший приоритет (Операции внутри фигурных скобок это недокументированное свойство языка, главное в этом случае, чтобы в результате внутренней операции результат получил определенную разрядность). Вторым моментом является тот факт, что операция конкатенации недопустима с вещественными числами. Синтаксис операции приведен ниже: {<expr_1>, <expr_2>, … <expr_n>};

Операция может содержать несколько повторяющихся элементов, для сокращения записи используется множитель, который указывает сколько раз повторяется данный элемент: {4{w}} эквивалентно {w, w, w, w}

Множитель может быть целой, неотрицатеьной константой или константным

выражением. Также в операции могут использоваться внутренние объединения: {{a, b, c}, {3{d, e}}} эквивалентно {a, b, c, d, e, d, e, d, e}

Результат операции слияния может использоваться в любом случае в качестве операндов или в качестве вектора (переменной) которой присваивается значение. Это широко используется для случаев, когда функция должна вернуть несколько значений.

С целью закрепления знаний языка описания аппаратуры, рассмотрим примеры описания ЦУ на языке Verilog.

Пример создания на САПР Quartus II цифрового устройства с использованием языка описания аппаратуры Verilog

Создадим на САПР Quartus II логический элемент 2И-НЕ с помощью языка описания аппаратуры Verilog. Для этого:

  • Выбрать в главном меню "File\New Project Wizard…" ("Файл\Мастер создания проекта…") (рис. 2.33).

Рис. 2.33

  • В появившемся окне "New Project Wizard: Directory, Name, Top-Level Entity [page 1 of 5] " (" Мастер создания проекта: Папка, Имя и Модуль верхнего уровня [страница 1 из 5]") щелкнуть по кнопке с тремя точками у верхнего поля ввода. В новом окне "Select Directory" ("Выбрать папку"), переместившись в желаемое место на диске, создать новую папку для вновь создаваемого проекта под именем, например, "ANDNOT2" и " зайти" в неё (папка необходима, поскольку проект содержит около пятидесяти файлов). После этого щелкнуть по кнопке "Отрыть" окна "Select Directory".

  • Возвратиться в окно "New Project Wizard: Directory, Name, Top-Level Entity [page 1 of 5] " и убедиться в том, что в верхнем поле ввода занесен полный маршрут к созданной папке, а именно, во втором поле – имя проекта, которое совпадает с именем папки, и в третьем (нижнем) поле – имя модуля верхнего уровня, совпадающего с именем папки. Щелкнуть по кнопке " Finish" ("Завершение") (рис. 2.34).

Рис. 2.34

  • Выбрать в главном меню "File\New…" ("Файл\Новый") (рис. 2.35).

Рис. 2.35

  • В появившемся окне " New" на закладке "Device Design File" ("Конструкторские файлы устройств") выбрать строку " Verilog HDL File " ("файл на универсальном языке описания аппаратуры Verilog ") (рис. 2.36). Щелкнуть по кнопке "ОК" в нижней части окна.

Рис. 2.36

  • На рабочем поле приложения появится окно созданного файла с именем в квадратных скобках ["Verilog.v"]. Его расширение ".v" означает, что это " Verilog HDL File ", т.е. файл с языком описания в Verilog (рис. 2.37).

Рис. 2.37

  • Описать схему 2И-НЕ в verilog HDL (рис. 2.38):

module ANDNOT2(output OUT, input IN1, input IN2);

assign OUT=~(IN1&IN2);

endmodule

Рис. 2.38

  • Выбрать в главном меню "File\Save As" ("Файл\Сохранить с Новым Именем ").

  • В появившемся окне "Сохранить как" будет предложено сохранить файл с именем проекта с расширением .v. Следует принять предложение и щелкнуть по кнопке "Сохранить".

  • Сделаем текущий файл главным файлом проекта, для этого выбираем в главном меню Project/Set As Top Level Entity (рис. 2.39).

Рис. 2.39

  • Выбрать в главном меню "Assignments\Devise…" ("Назначения\Микросхема…" ) (рис. 2.40).

Рис. 2.40

  • В открывшемся окне "Devise " в списке "Familiy" ("Семейство") выбрать для нашего примера семейство микросхем MAX3000A. В расположенном ниже списке "Available devices:" ("Доступные микросхемы:") выбрать микросхему, например, EPM3032ALC44-10. Далее нажать на кнопку “Device and Pin Options “ (“устройство и варианты контактов”) (рис. 2.41).

Рис. 2.41

  • В появившемся окне выбираем закладку “Unused Pins” (“неиспользованные контакты”) и в графе “Reserve all unused pins” (“Для всех неиспользованных контактов ”) выбрать “As input tri-started” (“В качестве входов с высоким входным сопротивлением”) (рис. 2.42). Это обозначает, что неиспользуемые входы будут входами с высоким входным сопротивлением. Это обезопасит микросхему и плату.

Рис. 2.42

  • Произвести компиляцию проекта, нажав на кнопку “Start Compilation”, находящейся на панели инструментов (рис. 2.43).

Рис. 2.43

  • После компиляции должно выскочить сообщение о её успешном завершении.

Распределение контактов входов и выходов ЦУ

  • При создании проекта входы и выходы на ПЛИСе задаются автоматически (программа автоматически определяет контакты и их назначение) и практически всегда находятся не там где нам нужно. Для принудительного назначения контактов входов и выходов необходимо в главном меню выбрать опцию “Assigments/Pins” (“Назначение/Контакты”) (рис. 2.44).

Рис. 2.44

  • В появившемся окне выбрать на схематичном изображении один из контактов, например, номер 27 (рис. 2.45), и присвоить ему вход IN1. Для этого необходимо 2 раза нажать левой кнопкой мыши на контакт 27, после чего появится окно “Pin Properties” (“Свойства контакта”).

Рис. 2.45

  • В окне “Pin Properties” (“Свойства контакта”) в списке “Node Name” выбираем интересующий нас вход IN1 и нажимаем “OK” (рис. 2.46).

Рис. 2.46

  • Аналогично присваиваем контакту №28 (Рис….) IN2 и контакту №6 OUT (рис. 2.47).

Рис. 2.47

  • Снова производим компиляцию проекта и убеждаемся в её правильном завершении.

Always-блоки, операторы if и case в Verilog

Процесс-блоки (always-блоки)

Блоки подобного типа здесь названы в силу того, что они реализуют некий процесс, который может повторятся многократно. В литературе их часто называют always-блоками по ключевому слову, определяющему такой блок.

Для описания поведенческого блока используется следующий синтаксис:

always @(<sensitivity_list>) <statements>

<sensitivity_list> – это список всех входных сигналов, к которым чувствителен блок. Это список входных сигналов, изменение которых влияет выходные сигналы этого блока. "Always" переводится как "всегда". Такую запись можно прочитать вот так: "Всегда выполнять выражения <statements> при изменении сигналов, описаных в списке чувствительности <sensitivity list>". Если указать список чувствительности неверно, то это не должно повлиять на синтез проекта, но может повлиять на его симуляцию. В списке чувствительности имена входных сигналов разделяются ключевым словом "or": always @(a or b or d) <statements>

Иногда гораздо проще и надежней включать в список чувствительности все сигналы. Это делается так: always @* <statements>

Тогда исправляя выражения в  <statements> вам не нужно задумываться об изменении списка чувствительности. При описании выражений внутри поведенческих блоков комбинаторной логики, с правой стороны от знака равенства, как и раньше, можно использовать типы сигналов wire или reg, а вот с левой стороны теперь используется только тип reg:

reg [3:0] c; always @(a or b or d) begin c = <выражение использующее входные сигналы a,b,d>; end

Синтаксис оператора if

Оператор ветвления if широко применяется для реализации элементов регистровой логики, таких как регистры данных, сдвига, счетчиков, цифровых автоматов и т.д. Синтаксис этого оператора очень похож на синтаксис в языке С. Общий вид оператора выглядит так:

if (<cond_expr1>)

[begin]

<statements>;

[end]

else if (<cond_expr2>)

[begin]

<statements>;

[end]

else

[begin]

<statements>;

[end]

Обязательной ветвью в этом операторе является ветвь после ключевого слова if. Ветви else if и else добавляются если они необходимы. Условные выражения cond_expr принимают значения true (результат cond_expr отличен от нуля) или false (результат равен нулю). Логика выполнения оператора следующая: если выполняется условие cond_expr1 (cond_expr1 != 0), то выполняется ветвь под оператором if, а остальные ветви пропускаются. Когда условие не выполняется (cond_expr1 == 0), осуществляется проверка условия cond_expr2. Ветвей else if в операторе может быть несколько. Если не выполняется предыдущее условие, то выполняется следующее. Когда не выполнилось ни одно из условий, управление передается ветви else (если она есть). Когда эта ветвь отсутствует, осуществляется выход из оператора. Ключевые слова begin end обозначают границы последовательных блоков. Если в ветви только одно выражение, эти ключевые слова можно опустить. Ветви if, else if и else иногда называют параллельными в том смысле, что всегда выполняется только одна из них. Операторы if могут быть вложенными – внутри одной ветви оператора вполне может быть размещен другой оператор if.

Синтаксис операторов case

Синтаксис оператора case выглядит так:

case (<cond_expr>)

<const_cond_1> : <statement>;

<const_cond_2> : <statement>;

* * *

<const_cond_n> : <statement>;

[default : <statement>;]

endcase

В этом операторе результат cond_expr по порядку сравнивается с константными условиями const_cond. В случае совпадения результата с одним из выражений, выполняется выражение statement соответствующее этому константному условию. Если не выполнилось ни одно из условий, то выполняется ветвь под ключевым словом default (если она есть – в противном случае не выполняется ни одно из выражений). Завершается оператор ключевым словом endcase.

34

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]