A representação de números inteiros com sinal em sistemas digitais utiliza o esquema de complemento de dois. Para uma palavra de N bits, o intervalo abrange de \(-2^{N-1}\) a \(2^{N-1}-1\). Este artigo detalha o projeto de um circuito multiplicador para operandos com sinal, empregando a linguagem de descrição de hardware Verilog.
Considerando dois números com sinal de N bits, A e B, podemos expressá-los algebricamente. Por exemplo, para N=4, A pode ser escrito como \(-a_3 \times 2^3 + A_3\), onde A_3 corresponde ao valor sem sinal dos bits menos significativos. A multiplicação A*B é então desenvolvida por expansão e simplificação, resultando em uma combinação de operações lógicas e deslocamentos.
O código Verilog a seguir apresenta uma implementação parametrizável do multiplicador. As variáveis, sinais e estrutura lógica foram modiifcados em relação a exemplos convencionais para proporcionar uma visão alternativa mantendo a funcionalidade.
`timescale 1ns/1ps
module mult_sinal
#(
parameter LARGURA_DADOS = 8
)
(
input [LARGURA_DADOS-1:0] operando_a,
input [LARGURA_DADOS-1:0] operando_b,
output [2*LARGURA_DADOS-1:0] produto
);
wire [LARGURA_DADOS-1:0] matriz_parciais [LARGURA_DADOS-1:0];
generate
genvar idx_i, idx_j;
for (idx_i = 0; idx_i < LARGURA_DADOS-1; idx_i = idx_i + 1) begin : linha_parcial
for (idx_j = 0; idx_j < LARGURA_DADOS-1; idx_j = idx_j + 1) begin : coluna_parcial
assign matriz_parciais[idx_i][idx_j] = operando_a[idx_i] & operando_b[idx_j];
end
end
for (idx_i = 0; idx_i < LARGURA_DADOS-1; idx_i = idx_i + 1) begin
assign matriz_parciais[idx_i][LARGURA_DADOS-1] = ~(operando_a[LARGURA_DADOS-1] & operando_b[idx_i]);
assign matriz_parciais[LARGURA_DADOS-1][idx_i] = ~(operando_a[idx_i] & operando_b[LARGURA_DADOS-1]);
end
assign matriz_parciais[LARGURA_DADOS-1][LARGURA_DADOS-1] = operando_a[LARGURA_DADOS-1] & operando_b[LARGURA_DADOS-1];
endgenerate
wire [2*LARGURA_DADOS-1:0] acumulador_somas [LARGURA_DADOS-1:0];
generate
genvar idx_k;
assign acumulador_somas[0] = {1'b1, matriz_parciais[0][LARGURA_DADOS-1], matriz_parciais[0][LARGURA_DADOS-2:0]};
for (idx_k = 1; idx_k < LARGURA_DADOS-1; idx_k = idx_k + 1) begin
assign acumulador_somas[idx_k] = {matriz_parciais[idx_k][LARGURA_DADOS-1], matriz_parciais[idx_k][LARGURA_DADOS-2:0]} << idx_k;
end
assign acumulador_somas[LARGURA_DADOS-1] = {1'b1, matriz_parciais[LARGURA_DADOS-1][LARGURA_DADOS-1], matriz_parciais[LARGURA_DADOS-1][LARGURA_DADOS-2:0]} << (LARGURA_DADOS-1);
endgenerate
assign produto = acumulador_somas[0] + acumulador_somas[1] + acumulador_somas[2] + acumulador_somas[3] + acumulador_somas[4] + acumulador_somas[5] + acumulador_somas[6] + acumulador_somas[7];
endmodule
Um banco de testes em Verilog é fornecido para validação funcional. A estrutura e nomenclatura foram adaptadas para demonstrar uma metodologia de verificação distinta.
`timescale 1ns/1ps
module banco_testes_mult;
localparam LARGURA = 8;
reg [LARGURA-1:0] estimulo_x, estimulo_y;
wire [2*LARGURA-1:0] resposta;
mult_sinal #(.LARGURA_DADOS(LARGURA)) inst_dut (
.operando_a(estimulo_x),
.operando_b(estimulo_y),
.produto(resposta)
);
initial begin
estimulo_x = 8'hFF;
estimulo_y = 8'hFF;
#40;
estimulo_x = 8'h01;
estimulo_y = 8'hFF;
#40;
integer contador_i, contador_j;
for (contador_i = 0; contador_i < 256; contador_i = contador_i + 1) begin
for (contador_j = 0; contador_j < 256; contador_j = contador_j + 1) begin
estimulo_x = contador_i;
estimulo_y = contador_j;
#20;
end
end
#100;
$stop;
end
endmodule
Os resultados das simulações confirmam que o multiplicador gera saídas corretas para múltiplos cenários de entrada, incluindo valores positivos, negativos e combinações limítrofes.