Vamos ver a partir deste post como funcionam os somadores. Um somador de N-bits consiste em um circuito que consegue somar duas entradas, cada uma delas com N-bits, e mais um sinal Carry de entrada e produz um resultado também com o mesmo tamanho, N-bits e um sinal Carry de Saída. Esse circuito somador é conhecido na literatura como Somador com Propagação do Carry, porque o sinal de Carry se propaga por todo o circuito do primeiro ao último bloco de hardware.
O símbolo de um somador pode ser representado como na figura abaixo.

Existem três implementações comuns de Somador com Propagação do Carry. São elas:
- Somador Ripple-Carry (Ripple-Carry Adder);
- Somador Carry Adder (Carry Lookahead Adder);
- Somador Prefixado (Prefix Adder).
Vamos abordar todos os somadores aqui no Embarcados. Neste post em específico estudaremos como funciona o Somador Ripple-Carry (Ripple-Carry Adder).
Somador Ripple-Carry
A forma mais simples, comum e intuitiva de criar um Somador é conectar vários somadores de 1-bit um após o outro, conectando o Carry de saída do anterior no Carry de entrada do atual e conectar o Carry de saída do atual no próximo bloco, totalizando uma cadeia de N blocos para um somador de N bits. Este então é o circuito do Ripple-Carry Adder. Ele é o somador mais modular que existe, já que podemos utilizar cada um dos somadores de 1-bit como módulos e escalarmos esse somador infinitamente. O problema dessa abordagem é que esse circuito é muito lento se compararmos com os demais somadores, conforme veremos quando forem apresentados os demais somadores. Abaixo está representado um somador de 4-bits.
Representação do Circuito Somador Ripple-Carry de 4-bits em termos de Somadores Completos de 1-bit
Represento nas imagens abaixo o mesmo circuito de Somador Ripple-Carry de 4-bits. Essa representação utiliza quatro blocos Somadores Completos de 1-bit. Os dois desenhos significam a mesma coisa, mas desenhei das duas maneiras porque pode-se encontrar as duas formas de representação.
Representação do Circuito Somador Ripple-Carry de 4-bits em Verilog
Para representar o circuito acima, escolhi a abordagem estrutural, onde codifico como se estivesse montando o esquemático do circuito. Criei um projeto em branco no Quartus (para ver como criar um projeto, veja este link) e utilizei o arquivo do meio somador e do somador completo de 1-bit mostrado no post anterior.
Arquivo meio_somador.v
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um meio somador // Thiago Lima - 19/11/2015 module meio_somador (S, C, A, B); output S, C; input A, B; assign S = A ^ B; assign C = A & B; endmodule
Arquivo SOMADOR.v
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um somador completo de 1bit // Thiago Lima - 19/11/2015 module SOMADOR (Soma, Cout, A, B, Cin); output Soma, Cout; input A, B, Cin; wire Carry_1, Carry_2, Soma_1; meio_somador U1 (Soma_1, Carry_1, A, B); meio_somador U2 (Soma, Carry_2, Cin, Soma_1); or U3 (Cout, Carry_1, Carry_2); endmodule
Então criei a estrutura do código em Verilog para o Somador Ripple-Carry. Como estou considerando um somador de 4-bits, considerei os sinais A, B e Soma como [3:0]. No primeiro bloco, eu apliquei o Carry de entrada Cin e assim por diante. Nos outros blocos somadores de 1-bit coloquei os sinais um a um até o quarto bloco.
Arquivo ripple_carry_adder.v
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um somador Ripple Carry de 4 bits // Thiago Lima - 19/11/2015 module ripple_carry_adder (Soma, Cout, A, B, Cin); output [3:0]Soma; output Cout; input [3:0]A; input [3:0]B; input Cin; wire C0, C1, C2; SOMADOR U0 (Soma[0], C0, A[0], B[0], Cin); SOMADOR U1 (Soma[1], C1, A[1], B[1], C0); SOMADOR U2 (Soma[2], C2, A[2], B[2], C1); SOMADOR U3 (Soma[3], Cout, A[3], B[3], C2); endmodule
Testbench para o Circuito Somador Ripple-Carry de 4-bits em Verilog
Para injetar valore e 0 a 15 em A e de zero a 15 em B, criei dois contadores, i e j. Os valores de i, injetei em A, os valores de j, injetei em B. Fiz dois testes que mostrariam uma mensagem de erro quando executasse o Testbench, uma testando o Carry e outra testando a soma. O testbench está abaixo.
Arquivo ripple_carry_adder_tb.v
//Testbench Somador Ripple Carry 4 bits
//by Thiago Lima
module ripple_carry_adder_tb;
wire [3:0] Soma_tb;
wire cout_tb;
reg [3:0] A_tb;
reg [3:0] B_tb;
reg Cin_tb;
integer i;
integer j;
ripple_carry_adder dut( Soma_tb, cout_tb, A_tb, B_tb, Cin_tb);
initial
begin
Cin_tb = 1'b0;
for (i = 0; i < 16; i = i + 1)
begin
A_tb = i; #1;
for (j = 0; j < 16; j = j + 1)
begin
B_tb = j; #1;
if ( Soma_tb !== (A_tb + B_tb) )
$display("Erro> %d+%d=%d, carry = %b", A_tb, B_tb, Soma_tb, cout_tb);
//else
// $display("%d %d", A_tb+B_tb, Soma_tb);
if ((A_tb + B_tb > 16 ) && (cout_tb === 0))
$display("Erro> Carry incorreto!!!");
end
end
end
endmodule
Forma de Onda resultante do teste
A forma de onda resultante foi de acordo com o esperado. O resultado no terminal também não apresentou nenhuma mensagem de erro.
Caso queira reproduzir o teste feito acima, faça Download do Projeto para o Quartus da Altera e aperte o play:
Representação do Circuito Somador Ripple-Carry de 32-bits em termos de Somadores Completos de 1-bit
Reproduzi o exemplo anterior para um somador de 32-bits na topologia Ripple-Carry. Ele funciona da mesma forma. Repare na figura abaixo para entender como funciona a expansão desse circuito.
Representação do Circuito Somador Ripple-Carry de 32-bits em Verilog
Arquivo meio_somador.v (igual ao exemplo anterior)
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um meio somador // Thiago Lima - 19/11/2015 module meio_somador (S, C, A, B); output S, C; input A, B; assign S = A ^ B; assign C = A & B; endmodule
Arquivo SOMADOR.v (igual ao exemplo anterior)
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um somador completo de 1bit // Thiago Lima - 19/11/2015 module SOMADOR (Soma, Cout, A, B, Cin); output Soma, Cout; input A, B, Cin; wire Carry_1, Carry_2, Soma_1; meio_somador U1 (Soma_1, Carry_1, A, B); meio_somador U2 (Soma, Carry_2, Cin, Soma_1); or U3 (Cout, Carry_1, Carry_2); endmodule
Foi codificado da mesma maneira que para 4-bits, mas dessa vez para um somador de 32 bits. Veja abaixo.
Arquivo ripple_carry_adder.v
// Embarcados - Use como quiser e de os creditos // Exemplo de Implementacao de um somador Ripple Carry de 32 bits // Thiago Lima - 19/11/2015 module ripple_carry_adder (Soma, Cout, A, B, Cin); output [31:0]Soma; output Cout; input [31:0]A; input [31:0]B; input Cin; wire C0, C1, C2, C3, C4, C5, C6, C7, C8, C9; wire C10, C11, C12, C13, C14, C15, C16, C17, C18, C19; wire C20, C21, C22, C23, C24, C25, C26, C27, C28, C29; wire C30; SOMADOR U0 (Soma[0], C0, A[0], B[0], Cin); SOMADOR U1 (Soma[1], C1, A[1], B[1], C0); SOMADOR U2 (Soma[2], C2, A[2], B[2], C1); SOMADOR U3 (Soma[3], C3, A[3], B[3], C2); SOMADOR U4 (Soma[4], C4, A[4], B[4], C3); SOMADOR U5 (Soma[5], C5, A[5], B[5], C4); SOMADOR U6 (Soma[6], C6, A[6], B[6], C5); SOMADOR U7 (Soma[7], C7, A[7], B[7], C6); SOMADOR U8 (Soma[8], C8, A[8], B[8], C7); SOMADOR U9 (Soma[9], C9, A[9], B[9], C8); SOMADOR U10(Soma[10], C10, A[10], B[10], C9); SOMADOR U11(Soma[11], C11, A[11], B[11], C10); SOMADOR U12(Soma[12], C12, A[12], B[12], C11); SOMADOR U13(Soma[13], C13, A[13], B[13], C12); SOMADOR U14(Soma[14], C14, A[14], B[14], C13); SOMADOR U15(Soma[15], C15, A[15], B[15], C14); SOMADOR U16(Soma[16], C16, A[16], B[16], C15); SOMADOR U17(Soma[17], C17, A[17], B[17], C16); SOMADOR U18(Soma[18], C18, A[18], B[18], C17); SOMADOR U19(Soma[19], C19, A[19], B[19], C18); SOMADOR U20(Soma[20], C20, A[20], B[20], C19); SOMADOR U21(Soma[21], C21, A[21], B[21], C20); SOMADOR U22(Soma[22], C22, A[22], B[22], C21); SOMADOR U23(Soma[23], C23, A[23], B[23], C22); SOMADOR U24(Soma[24], C24, A[24], B[24], C23); SOMADOR U25(Soma[25], C25, A[25], B[25], C24); SOMADOR U26(Soma[26], C26, A[26], B[26], C25); SOMADOR U27(Soma[27], C27, A[27], B[27], C26); SOMADOR U28(Soma[28], C28, A[28], B[28], C27); SOMADOR U29(Soma[29], C29, A[29], B[29], C28); SOMADOR U30(Soma[30], C30, A[30], B[30], C29); SOMADOR U31(Soma[31], COut, A[31], B[31], C30); endmodule
Testbench para o Circuito Somador Ripple-Carry de 32-bits em Verilog
Testei o código Verilog do Somador 32-bits utilizando o testbench altero do exemplo anterior e mostrado abaixo.
Arquivo ripple_carry_adder_tb.v
//Testbench Somador Ripple Carry 32 bits
//by Thiago Lima
module ripple_carry_adder_tb;
wire [31:0] Soma_tb;
wire cout_tb;
reg [31:0] A_tb;
reg [31:0] B_tb;
reg Cin_tb;
integer i;
integer j;
ripple_carry_adder dut( Soma_tb, cout_tb, A_tb, B_tb, Cin_tb);
initial
begin
Cin_tb = 1'b0;
for (i = 0; i < 32'hFFFFFFFF; i = i + 1)
begin
A_tb = i; #1;
for (j = 0; j < 32'hFFFFFFFF; j = j + 1)
begin
B_tb = j; #1;
if ( Soma_tb !== (A_tb + B_tb) )
$display("Erro> %d+%d=%d, carry = %b", A_tb, B_tb, Soma_tb, cout_tb);
//else
// $display("%d %d", A_tb+B_tb, Soma_tb);
if ((A_tb + B_tb > 16 ) && (cout_tb === 0))
$display("Erro> Carry incorreto!!!");
end
end
end
endmodule
Resultado do teste
Testei o circuito apenas parcialmente. Não rodei todo o teste por ele ser muito grande e ir além do escopo deste texto. Deixo no entanto disponível o projeto completo do Quartus. Caso queira reproduzir o teste completo ou mesmo só estudar o código, faça Download do Projeto para o Quartus da Altera e aperte o play:
É isso ai pessoal, espero que tenham gostado. Deixem seus comentários. É importante para guiar meus próximos passos.









