Введение в Verilog, Второй урок. Иерархия проекта.

Уроки Verilog

Мы уже знаем, что такое модуль.

В проекте, особенно сложном, бывает много модулей, соединенных между собой. Прежде всего, нужно заметить, что в проекте всегда есть один модуль самого верхнего уровня (top level). Он состоит из нескольких других модулей. Те в свою очередь могут содержать еще модули и так далее. Не обязательно, чтобы все модули были написаны на одном языке описания аппаратуры. Совсем наоборот. Довольно удобно и наглядно иметь модуль самого верхнего уровня выполненным в виде схемы, состоящей из модулей более низкого уровня. Эти модули могут быть написаны разными людьми, на разных языках (Verilog, VHDL, AHDL, и даже выполнены в виде схемы). На самом деле – это все дело вкуса и возможностей компилятора (синтезатора), а так же требований заказчика.

Поскольку у нас уроки Verilog, то будем все же рассматривать проект с точки зрения программирования на этом языке.

Итак, внутри тела любого модуля, можно объявлять экземпляры других модулей и потом соединять их друг с другом проводами.

Предположим у нас есть следующие примитивные модули:
Логические элементы И, И-НЕ
Слева  изображен двухвходовый логический элемент И. На его выходе единица, если на первом И на втором входе единица. Справа изображен двухвходовый логический элемент И-НЕ. На его выходе ноль, если на первом И втором входах единицы.

Обратите внимание, что на входе может быть не только логический ноль или единица, но и так же неопределенное значение x, или вход может быть подключен к двунаправленному сигналу (inout), находящемуся в высокоомном состоянии z. Эти значения так же указаны в таблице истинности для полноты картины.  

Эти логические модули можно было бы описать на языке Verilog следующим образом:


module AND2(output OUT, input IN1, input IN2);
assign OUT = IN1 & IN2;
endmodule  

module NAND2(output OUT, input IN1, input IN2);
assign OUT = ~(IN1 & IN2);
endmodule  


Однако, вот такие описания делать не нужно. Это базовые элементы (gates) и они наверняка должны быть в стандартных библиотеках синтезатора.

Вот еще пара важных логических элементов:
Логические элементы ИЛИ, ИЛИ-НЕ
Слева логический элемент ИЛИ. На выходе единица, если на первом ИЛИ втором входе единица. Справа – логический элемент ИЛИ-НЕ. На выходе ноль, если на первом ИЛИ втором входе – единица.

Следующие важные примитивы связаны с «отрицанием равнозначности»:
Логические элементы XOR, XNOR

Элемент слева (XOR) имеет на выходе ноль если на обоих входах одинаковое значение (либо оба входа ноль, либо оба входа единица). Элемент справа (XNOR) -  тоже самое, только с инверсией. На выходе единица, если либо оба входа ноль, лтбо оба входа единица.

Напоследок еще пара очень важных базовых элемента:
Логичекие элементы
Слева элемент НЕ. На его выходе значение противоположное входному значению. Если на входе единица, то на выходе ноль. И на оборот.

Справа - буфферный элемент, использующийся для двунаправленных сигналов (inout). Этот элемент «пропускает» через себя входной сигнал, только если на входе CTRL есть управляющая единица. Если на входе CTRL ноль, то элемент «отключается» от выходного провода переходя в высокоомное состояние. Такие элементы вообще-то используются только для выводов цифровых микросхем. Иными словами, использовать двунаправленные сигналы (inout) правильнее всего только в модуле самого верхнего уровня.

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

Посмотрите, как можно описать эту схему на языке Verilog, устанавливая в теле модуля экземпляры других модулей. Это описание на уровне элементов (gate-level modelling). Мы установим в наш модуль 3 экземпляра модуля XOR и два экземпляра модуля AND2.


module adder1(output sum, output c_out, input a, input b, input c_in);
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


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

Конечно, совсем не обязательо описывать наш модуль так, как описано выше. Честно говоря, мне гораздо приятней видеть вот такой код однобитного сумматора:


module adder1(output sum, output c_out, input a, input b, input c_in);
assign sum = (a^b) ^ c_in;
assign c_out = ((a^b) & c_in) ^ (a&b);
endmodule


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

Теперь у нас есть однобитный сумматор и мы можем сделать, например, четырехбитный (с последовательным переносом)!

Вот так:

adder4

На 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.

Вообще, даже примитивы типа AND могут быть описаны на языке Verilog в виде нескольких связанных MOS или CMOS переключателей. Это уже уровень транзисторов (switch level modeling). Мы этим заниматься сейчас не будем. Странно думать о транзисторах, если проект может использовать их тысячи и миллионы Smile

 

Добавить комментарий