Começando com Verilog 2 - Instanciação de Módulos
Published: 2023-09-30 18:06:43

#Opa, eae?

Curti muito a repercussão do último post e em especial muito obrigado a [He4rt Developers](https://twitter.com/He4rtDevs), essa comunidade que participo faz uns 3 anos e que é sensacional, não deixe de entrar.

Porém, acredito que ainda tem mais algumas coisas a serem abordadas para que você comece bem com Verilog e principalmente tenha todo o conhecimento para gabaritar o [HDLbits](https://hdlbits.01xz.net/wiki/Main_Page).

Bom, como o título já diz, esta é a parte dois do post “Começando com Verilog” então caso você não tenha lido a primeira parte, cola aqui nesse link primeiro:

[https://dev.to/marlonhenq/comecando-com-verilog-13n0](https://dev.to/marlonhenq/comecando-com-verilog-13n0)


#Aumentando a complexidade ou subindo a abstração com a instanciação de módulos

Uma das principais coisas que acabei não dizendo no último post é que módulos podem instanciar outros módulos.

Os que possuem olhares muito atentos podem até ter percebido isso quando falei sobre Verilog Estrutural “O Verilog Estrutural cria sua lógica chamando portas como módulos.”, porém irei explicar mais detalhadamente agora.

Uma forma muito comum de se fazer um multiplexador em Verilog é usando o operador ternário:

```verilog
module top_module(
    input a, b, sel,
    output out
    );


    assign out = sel ? b:a;
endmodule
```

>Obs: Olha ai uma nova forma de declarar os inputs e outputs, no post passado eu repetia sempre a palavra input e output para cada entrada/saida, mas caso elas sejam iguais (isto é, possuem a mesma quantidade de bits) você pode apenas colocar virgulas (como sempre Verilog possui várias formas de fazer a mesma coisa).

Caso você não saiba o que é um multiplexador, ele nada mais é que um permutador de entradas. No caso os inputs “a” e “b” são as entradas do nosso multiplexador, a “sel” é a nossa porta seletora, caso “sel” receba 0 o que vem por “a” é direcionado a saída “out”, caso “sel” receba 1 o que vem de “b” será direcionado a “out”.

Ele pode ser descrito pela tabela:

| A | B | Sel | Out |
|---|---|-----|-----|
| 0 | 0 | 0   | 0   |
| 0 | 0 | 1   | 0   |
| 0 | 1 | 0   | 0   |
| 0 | 1 | 1   | 1   |
| 1 | 0 | 0   | 1   |
| 1 | 0 | 1   | 0   |
| 1 | 1 | 0   | 1   |
| 1 | 1 | 1   | 1   |

Aí está a representação do último código com “a” recebendo 1 (representado pelo verde), “b” recebendo 0 (vermelho) e “sel” recebendo 0, assim o valor de “a” é direcionado a “out”:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bmhp1835e46tzrz7gon.png)

Mudando a entrada de “sel” para 1, temos o que vem por “b” indo para “out”:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ormeponc8skjd4w6syu.png)


Mas e se agora quisermos um multiplexador de 4 entradas?

Obviamente, vamos ter que aumentar nossas entradas para agora “a”, “b”, “c” e “d” nossa seleção “sel” também deve aumentar para 2 bits.

E um código que poderia resolver isso seria:

```verilog
module top_module( 
    input a, b, c, d,
    input [1:0] sel,
    output out ); 
	
    assign out  = sel[1] ? (sel[0] ? d : c) : (sel[0] ? b : a);
endmodule
```

A representação deste código é:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oez109wbphjrful98noa.png)

De fato funciona, mas a legibilidade de ternários encadeados não é muito boa, e se quisermos então um multiplexador de 8 entradas? Ai sim, temos um grande problema, e uma forma mais elegante de fazer isso é instanciar módulos por outros módulos.

Para instanciar módulos dentro de outros módulos em Verilog a sintaxe é “nome_do_modulo nome_da_instanciação (entrada1, entrada2,… saida1…);”.

Vamos lá, tendo o multiplexador de 2 entradas podemos fazer um multiplexador de 4 entradas instanciando o de 2 entradas três vezes, segue o código:

```verilog
module mux2( //multiplexador de 2 entradas já apresentado
    input a, b, sel,
    output out ); 
	
    assign out  = sel ? b:a;
endmodule

module mux4(//multiplexador de 4 entradas
    input a, b, c, d, 
    input [1:0] sel,
    output out ); 

    wire fio1, fio2;

    mux2 multiplexador1 (a, b, sel[0], fio1);
    mux2 multiplexador2 (c, d, sel[0], fio2);

    mux2 multiplexadorFinal (fio1, fio2, sel[1], out);

endmodule
```


Representação gráfica do modulo mux4:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y65pmva5ojplpwib8hc4.png)

Outra forma de instanciar módulos (mais verbosa, porém que prefiro) é a de repetir o nome das portas do módulo que está sendo instanciado dessa forma:

```verilog
module mux4(
    input a, b, c, d, 
    input [1:0] sel,
    output out ); 

    wire fio1, fio2;

    mux2 multiplexador1 (.a(a), .b(b), .sel(sel[0]), .out(fio1));
    mux2 multiplexador2 (.a(c), .b(d), .sel(sel[0]), .out(fio2));

    mux2 multiplexadorFinal (.a(fio1), .b(fio2), .sel(sel[1]), .out(out));

endmodule
```

Assim, além de ficar mais claro como está sendo o roteamento, não é necessário utilizar a ordem das entradas e saídas do módulo original, é inclusive possível suprimir algumas destas (caso não for necessário para algum tipo de instanciação).


#Aumentando muito a complexidade com a instanciação de N módulos via Generate For

Outro circuito muito comum é o de somador binário, ele basicamente tem 3 entradas, os dois dígitos que ira receber, e a entrada de “vai um” (cin), de saídas temos a saída da soma, além de uma saída de “vai um” (cout), para um próximo somador.

Um código para um somador binário de um único dígito é:

```verilog
module adder(
    input a,b,
    input cin,
    output cout,
	output sum );
	
    assign sum  = (a ^ b ^ cin);
    assign cout = ((a & b) | (b & cin) | (cin & a));
endmodule
```

O somador binário de um bit é graficamente representado assim:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp1628hd3blo1o1zs62p.png)

Um somador de 2 bits a partir da instanciação do somador simples pode ser:

```verilog
module adder2(
    input [1:0] a, b,
    input cin,
    output cout,
    output [1:0] sum );

    adder ad1 (a[0], b[0], cin, coutIntern, sum[0]);
    adder ad2 (a[1], b[1], coutIntern, cout, sum[1]);

endmodule
```

>Obs: Olha ai também uma forma nova de se declarar um wire! O fio “coutIntern” foi declarado de forma implícita, já que ele apenas é citado já sendo usado pelos módulos mesmo não sendo declarado formalmente com “wire coutIntern;” anteriormente.
Contudo, fique atento, apenas wires de um único bit podem ser declarados dessa forma.

E graficamente o somador de 2 bits fica assim:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9vgwjenpgivrzd9uo1q.png)

E se agora quisermos um somador de 100 bits? Acho que seria muito trabalho repetir essas linhas 100 vezes, né?
E é mesmo, mas temos uma forma mais elegante de fazer isso, o Generate For.

O Generate nada mais é que um bloco onde se pode executar alguns comandos que após realizarem suas condições uma (ou mais) instância(s) de módulo(s) pode(m) ser(em) incorporada(s) (ou não) ao circuito.

Dentro do Generate pode se utilizar “ifs”, “cases” e (os mais utilizados) os “fors” que realizarão loops os quais cada interação pode instanciar módulos.

Falando pode parecer difícil, então vamos direto para o código que é bastante autoexplicativo:

```verilog
module adder100( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    
    genvar i;
    
    adder ad0(a[0], b[0], cin, cout[0], sum[0]);
	
     generate
     	for (i = 1; i < 100; i = i + 1) begin
        		adder ad (a[i], b[i], cout[i-1], cout[i], sum[i]);
    	end
     endgenerate
    

endmodule
```

Após a criação do nosso módulo “adder100” e a declaração das nossas entradas e saídas, temos a criação de uma variável de geração “genvar” com o nome de “i”. 

Após isso, o primeiro módulo de adder é instanciado (ad0), já que este precisa receber o valor de “cin” ele acaba por ficar fora do nosso loop de geração.
Porém, agora todos os nossos demais 99 módulos irão interagir com vetores, ou seja, podem ser gerados por um loop de geração.

Assim, vem o nosso for com declaração muito próxima de C, onde a cada interação é instanciado um módulo adder de um bit.

>Obs: A utilização do for pode dar a entender a ideia de linguagens de programação de que cada interação é adicionado um módulo ao longo do tempo, mas isso é apenas uma automação para que não seja necessário escrever 100 linhas quase iguais de código.
No final, o que teremos é 100 módulos rodando ao mesmo tempo, como se fossem 100 CIs de adição binária em uma mesma placa. Blz?

E que fique a dica, essa é a resposta para o exercício [Adder100i](https://hdlbits.01xz.net/wiki/Adder100i) do HDLBits!

A visualização para esse circuito graficamente é:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgkwdu1pjhv6p7tq80t9.png)

Éhh… Bom, esse circuito é grande de mais para se visualizar e testar graficamente pelo DigitalJS. Em uma tela cheia o máximo que conseguimos ver é 15 instancias (de 100) e meu notebook sofreu para gerar essa simulação.

O que faremos para testar esse tipo de circuito, então?

**Testes!** Mais especificamente neste caso chamamos de “TestBench”, porém irei deixar isso para o próximo post!


#Isso é tudo!

Como sempre, obrigado por ter lido este post até aqui!

Demais dúvidas, comentários e sugestões podem ser enviados aqui embaixo (para o pessoal do DevTo) ou lá no meu Twitter [@marlonhenq](https://twitter.com/MarlonHenq).

Flw!