Освоение инстанцирования модулей Verilog: лучшие практики иерархического дизайна
Как мы видели ранее, большие и сложные дизайны строятся интеграцией множества модулей иерархическим образом. Модули могут инстанцироваться внутри других модулей, а порты этих инстансов соединяются с другими сигналами внутри родительского модуля.
Эти соединения портов можно делать через упорядоченный список или по имени.
Соединение портов упорядоченным списком
Один метод — ordered list. Порты соединяются в определённом порядке, определяемом позицией порта в списке портов объявления модуля. Например, b в тестбенче соединяется с y дизайна просто потому, что оба на второй позиции в списке портов.
module mydesign ( input x, y, z, output o); endmodule
module tb_top;
wire [1:0] a; wire b, c;
mydesign d0 (a[0], b, a[1], c); // a[0]->x, b->y, a[1]->z, c->o
endmodule
Порядок портов в дизайн-модуле должен быть известен для правильного соединения.
Это неудобно: порядок может измениться при добавлении порта или при большом их количестве.
Соединение портов по имени
Лучший способ — явно связывать порты по их имени.
Точка . указывает, что имя порта после точки принадлежит дизайну. Имя сигнала, к которому подключается порт дизайна, даётся в скобках ( ).
module design_top;
wire [1:0] a; wire b, c;
mydesign d0 (
.x (a[0]), // порт "x" в mydesign соединяется с "a[0]" в design_top
.y (b), // порт "y" в mydesign соединяется с "b"
.z (a[1]),
.o (c)
);
endmodule
Рекомендуется писать каждое соединение порта на отдельной строке — тогда сообщения об ошибках компиляции корректно укажут номер строки с ошибкой. Это намного проще отлаживать, чем когда все в одной строке.
Так как соединения по именам, их порядок неважен. Множественные соединения одного порта инстанса недопустимы.
module design_top;
mydesign d0 (
.x (a[0]),
.z (a[1]), // z на второй позиции — OK благодаря явному соединению
.y (a[1]),
.x (b), // недопустимо — x уже подключён к a[0]
.o (c)
);
endmodule
Неподключённые / висячие порты (Unconnected/Floating Ports)
Порты, не подключённые к проводу в инстанцирующем модуле, будут иметь значение высокого импеданса (Z).
module design_top;
mydesign d0 (
// x — вход, не подключен, значит a[0] будет Z
.y (a[1]),
.z (a[1]),
.o () // o имеет значение в mydesign, но не подключён к "c" в design_top, c будет Z
);
endmodule
Пример
Возьмём пример сдвигового регистра и оставим некоторые порты неподключёнными.
module shift_reg ( input d, input clk, input rstn, output q);
wire [2:0] q_net;
dff u0 (.d(d), .clk(clk), .rstn(rstn), .q(q_net[0]));
dff u1 (.d(q_net[0]), .clk(clk), .rstn(rstn), .q()); // выход q висит
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q()); // выход q висит
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
На RTL-схеме после синтеза видно, что выходы инстансов u1 и u2 остались неподключёнными. Поскольку входы d инстансов u2 и u3 теперь соединены с сетями, ничем не управляемыми, они заземлены.
В симуляциях такие неподключённые порты обозначаются высоким импедансом ('hZ), обычно показываются на волнах как оранжевая вертикальная линия посередине.
Все объявления портов неявно имеют тип wire, поэтому направления порта достаточно. Однако output порты, которым нужно хранить значения, должны быть объявлены как reg и могут использоваться в процедурных блоках always и initial.
Порты типа input или inout не могут быть reg, потому что они управляются извне непрерывно и не должны хранить значения, а отражать изменения внешних сигналов максимально быстро. Соединять порты с разной векторной разрядностью допустимо, но преобладает тот, у которого меньшая разрядность, а остальные биты порта с большей шириной игнорируются.
// Case #1: Входы неявно wire
module des0_1 (input wire clk ...); // wire не обязателен
module des0_2 (input clk, ...); // по умолчанию clk — wire
// Case #2: Входы не могут быть reg
module des1 (input reg clk, ...); // Недопустимо: входы не могут быть reg
// Case #3: Разная ширина портов
module des2 (output [3:0] data, ...); // 4-битный вектор выход
module des3 (input [7:0] data, ...); // 8-битный вектор вход
module top ( ... );
wire [7:0] net;
des2 u0 ( .data(net) ... ); // Старшие 4 бита net не управляются
des3 u1 ( .data(net) ... );
endmodule
// Case #4: Выходы не могут соединяться с reg в родительском модуле
module top_0 ( ... );
reg [3:0] data_reg;
des2 ( .data(data) ...); // Недопустимо: выходной порт data подключён к reg сигналу data_reg
endmodule
Verilog
- Освоение Verilog: полное руководство по проектированию цифровых схем
- Освоение конкатенации в Verilog: практическое руководство
- Основы Verilog: краткий обзор
- Понимание назначений в Verilog: типы, синтаксис и лучшие практики
- Блокирующие и неблокирующие назначения в Verilog: ключевые различия
- Мастерство функций в Verilog для эффективного RTL дизайна
- Понимание задач (Tasks) в Verilog: отличия от функций, синтаксис и применение
- Иерархические ссылки в Verilog: область видимости и избежание коллизий имен
- Генератор тактового сигнала в Verilog: проектирование и реализация
- Мастерство математических функций Verilog для эффективного аппаратного дизайна