Instanciações do módulo Verilog
Como vimos em um artigo anterior, projetos maiores e complexos são construídos integrando vários módulos de forma hierárquica. Os módulos podem ser instanciados dentro de outros módulos e portas dessas instâncias pode ser conectado com outros sinais dentro do módulo pai.
Essas conexões de porta podem ser feitas por meio de uma lista ordenada ou por nome.
Conexão de porta por lista ordenada
Um método de fazer a conexão entre as expressões de porta listadas em uma instanciação de módulo com os sinais dentro do módulo pai é pela lista ordenada .
meudesign é um
module
instanciado com o nome d0 em outro módulo chamado tb_top. As portas são conectadas em uma determinada ordem que é determinada pela posição daquela porta na lista de portas da declaração do módulo. Por exemplo, b no testbench está conectado a y do projeto simplesmente porque ambos estão na segunda posição na lista de portas.
module mydesign ( input x, y, z, // x is at position 1, y at 2, x at 3 and
output o); // o is at position 4
endmodule
module tb_top;
wire [1:0] a;
wire b, c;
mydesign d0 (a[0], b, a[1], c); // a[0] is at position 1 so it is automatically connected to x
// b is at position 2 so it is automatically connected to y
// a[1] is at position 3 so it is connected to z
// c is at position 4, and hence connection is with o
endmodule
A ordem das portas no módulo de projeto deve ser conhecida para uma conexão correta.
Isso é muito inconveniente porque a ordem pode mudar se uma nova porta for adicionada à lista ou quando o número de portas no design for muito grande.
Conexão de porta por nome
Uma maneira melhor de conectar portas é vinculando explicitamente as portas em ambos os lados usando o nome da porta .
O ponto
.
indica que o nome da porta após o ponto pertence ao design. O nome do sinal ao qual a porta de projeto deve ser conectada é fornecido entre parênteses ( )
.
module design_top;
wire [1:0] a;
wire b, c;
mydesign d0 ( .x (a[0]), // signal "x" in mydesign should be connected to "a[0]" in this module (design_top)
.y (b), // signal "y" in mydesign should be connected to "b" in this module (design_top)
.z (a[1]),
.o (c));
endmodule
Recomenda-se codificar cada conexão de porta em uma linha separada para que qualquer mensagem de erro de compilação aponte corretamente para o número da linha em que o erro ocorreu. Isso é muito mais fácil de depurar e resolver em comparação com não saber qual porta criou o erro se todas estivessem na mesma linha.
Como essas conexões são feitas pelo nome, a ordem em que aparecem é irrelevante. Conexões de porta de instância de módulo múltiplo não são permitidas.
module design_top;
mydesign d0 ( .x (a[0]),
.z (a[1]), // z at second position is okay because of explicit connection
.y (a[1]),
.x (b), // illegal - x is already connected to a[0]
.o (c));
endmodule
Portas desconectadas/flutuantes
As portas que não estão conectadas a nenhum fio no módulo de instanciação terão um valor de alta impedância.
module design_top;
mydesign d0 ( // x is an input and not connected, hence a[0] will be Z
.y (a[1]),
.z (a[1]),
.o ()); // o has valid value in mydesign but since
// it is not connected to "c" in design_top, c will be Z
endmodule
Exemplo
Vamos pegar o exemplo do registrador de deslocamento que vimos antes e deixar algumas portas desconectadas.
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()); // Output q is left floating
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q()); // Output q is left floating
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
Observe que as saídas das instâncias u1 e u2 são deixadas desconectadas no esquema RTL obtido após a síntese. Como a entrada d para as instâncias u2 e u3 agora estão conectadas a redes que não estão sendo acionadas por nada, ela é aterrada.
Nas simulações, essas portas desconectadas serão indicadas como alta impedância ('hZ) normalmente mostrada em formas de onda como uma linha laranja alinhada verticalmente no meio.
Todas as declarações de porta são declaradas implicitamente como
wire
e, portanto, a direção da porta é suficiente nesse caso. No entanto, output
portas que precisam armazenar valores devem ser declaradas como reg
tipo de dados e pode ser usado em um bloco procedural como always
e initial
só. Portas do tipo
input
ou inout
não pode ser declarado como reg
porque eles estão sendo acionados de fora continuamente e não devem armazenar valores, mas sim refletir as mudanças nos sinais externos o mais rápido possível. É perfeitamente legal conectar duas portas com tamanhos de vetor variados, mas aquela com tamanho de vetor menor prevalecerá e os bits restantes da outra porta com largura maior serão ignorados.
// Case #1 : Inputs are by default implicitly declared as type "wire"
module des0_1 (input wire clk ...); // wire need not be specified here
module des0_2 (input clk, ...); // By default clk is of type wire
// Case #2 : Inputs cannot be of type reg
module des1 (input reg clk, ...); // Illegal: inputs cannot be of type reg
// Case #3: Take two modules here with varying port widths
module des2 (output [3:0] data, ...); // A module declaration with 4-bit vector as output
module des3 (input [7:0] data, ...); // A module declaration with 8-bit vector as input
module top ( ... );
wire [7:0] net;
des2 u0 ( .data(net) ... ); // Upper 4-bits of net are undriven
des3 u1 ( .data(net) ... );
endmodule
// Case #4 : Outputs cannot be connected to reg in parent module
module top_0 ( ... );
reg [3:0] data_reg;
des2 ( .data(data) ...); // Illegal: data output port is connected to a reg type signal "data_reg"
endmodule
Verilog