Você está na página 1de 8

Multiplicador de ponto flutuante IEEE-754

Shyam Shankar H R
EE15B127

16 de setembro de 2017

Declaração do problema
Pergunta nº: 18. Para implementar a multiplicação de ponto flutuante com o formato de precisão única IEEE.

Procedimento
1. Obtenção do sinal do produto.

2. Somando os expoentes e subtraindo-se o viés (=127).

3. Multiplicando a mantissa com MSB 1 concatenado.

4. Colocando o ponto binário no resultado e verificando o requisito de normalização.

5. Normalizando a mantissa e incrementando o expoente se necessário.

6. Arredondando a mantissa para 23 bits.

7. Verificação de transbordamento/transbordamento.

O código verilog escrito é quase inteiramente estrutural.

Implementação (Module-wise)
0.1 Identificação do bit de sinal
Para encontrar o bit de sinal do produto, basta XOR os bits de sinal do multiplicador e multiplicador. O bit de sinal 1 implica -ve e 0 implica
+ve.

Código Verilog:
módulo sign_bit( sinal de fio de saída, fio de entrada [31:0] ini, fio de entrada [31:0] in2 );
xor(sinal,ini[31],in2[31]); módulo final

0.2 Adicionando os expoentes e subtraindo o viés


Precisamos de um adder de 8 bits e um subtractor de 9 bits (para incluir o transporte de adição, no minuend). Aqui, eu fiz um módulo adder
completo e implementei o algoritmo ripple carry para torná-lo 8 bit adder. Aqui o adder de transporte de ondulação é suficiente, pois a
complexidade de tempo geral do código será determinada pela parte de multiplicação mantissa (24 bits x 24 bits).

1
Código Verilog:
Eu bit Full Adder módulo full_adder (soma do fio de saída, saída fio cout, fio de entrada ini, entrada fio in2, entrada fio cin);
tempi de arame;
temperatura do fio2;
temp do fio3;
xor(soma,ini,in2,cin);
e(tempi,ini,in2); e(temp2,ini,cin); e(temp3,in2,cin);
ou(cout, templ, temp2, temp3); módulo final

Módulo adder Ripple-carry de 8 bits ripple_8( fio de saída [7:0] soma, saída fio cout,
entrada Fio [7:0] ini, Fio [7:0] in2,
de Fio CIN
entrada
);
fio cl,c2,c3,c4,c5,c6,c7;
full_adder FAl(sum[0],cl,inl[0],in2[0],cin); full_adder FA2(sum[l],c2,inl[l],in2[l],cl); full_adder FA3(soma[2],c3,inl[2],in2[2],c2); full_adder
FA4(soma[3],c4,inl[3],in2[3] ,c3); full_adder FA5(soma[4],c5,inl[4],in2[4],c4); full_adder FA6(soma[5],c6,inl[5],in2[5],c5); full_adder
FA7(soma[6],c7,inl[6],in2[6],c6); full_adder FA8(soma[7],cout,inl[7],in2[7],c7); módulo final

Depois de somar os expoentes, precisamos subtrair o viés, que é 127. Utilizando o fato de que o subtrahend é sempre uma constante
(001111111), podemos fazer dois subtratores completos especializados (onde o subtrahend é fixado em 0 e em 1 respectivamente).

Subtractor completo com subtractor = Subtractor completo com subtrahend


1 =0
Esses circuitos lógicos são obtidos a partir de tabelas de verdade simples, não mostradas aqui.

Código Verilog:
Subtrator de bit I com subtrahend = 1 módulo full_subtractor_subl(
diff do fio de saída, //difference saída wire bout, //emprestado para fora do fio de entrada min, Minuend
Compartimento de Arame de Entrada pedir emprestado em

2
);
Aqui, o subtrahend é sempre 1. Podemos implementá-lo como: xnor (diff, min, bin);
ou (bout, "min, bin) ;
módulo final

Subtractor de bits I com subtrahend = 0 módulo full_subtractor_subO( diff de fio de saída, //difference output wire bout, //borrow out input wire
min, //minuend input wire bin //borrow in );
Aqui, o subtrahend é sempre O.We pode implementá-lo como: xor(diff,min,bin);
e(bout,~min,bin); módulo final

Finalmente, fazemos o subtrator de viés (subtrator de 9 bits) da seguinte maneira:

Código Verilog:
Subtrator de 9 bits
módulo subtractor_9(
fio de saída [8:0] diff,
fio de saída bout,
fio de entrada [8:0] min,
Compartimento de Arame de Entrada
);
fio bl, b2, b3, b4, b5, b6, b7, b8;
full_subtractor_subl subl(diff[0],bl,min[0],bin);
full_subtractor_subl sub2(diff[1],b2,min[l],bl);
full_subtractor_subl sub3(diff[2],b3,min[2],b2);
full_subtractor_subl sub4(diff[3],b4,min[3],b3);
full_subtractor_subl sub5(diff[4],b5,min[4],b4);
full_subtractor_subl sub6(diff[5],b6,min[5],b5);
full_subtractor_subl sub7(diff[6],b7,min[6],b6);
full_subtractor_subO sub8(diff[7],b8,min[7],b7); Duas subtrahends mais significativas são 0 em 001111111. full_subtractor_subO
sub9(diff[8],bout,min[8],b8);
módulo final

0.3 Multiplicando a mantissa usando o Carry Save Multiplier


Precisamos acrescentar o bit '1' à mantissa e multiplicar os números de 24 bits resultantes. Implementei uma rotina de multiplicação de carry
save para implementar isso. Na multiplicação carry save, o carry de cada nível de soma parcial do produto flui para o próximo nível
diagonalmente. É retratado na figura mostrada (retirada da 5ª ed., Carl Hamacher):

Primeiro criamos um módulo para a célula de bit único:

3
Código Verilog:
bloco de módulos(
fio de saída ppo, //saída parcial produto termo fio de saída fio, //saída realizar saída fio mout, //saída multiplicand termo fio de entrada min, //entrada
multiplicand termo fio de entrada ppi, //entrada produto parcial termo fio de entrada q, //entrada multiplicador termo fio de entrada cin //entrada carry
in );
temperatura do fio;
e(temp,min,q);
full_adder FA (ppo, cout, ppi, temp, cin);
ou(mout,min,l'bO);
módulo final

Em seguida, estendemos essa célula de bits para implementar uma linha de 23 dessas células de bit único:

Código Verilog:
linha do módulo(
fio de saída[23:0] ppo,
fio de saída[23:0] mout,
soma do fio de saída,
fio de entrada[23:0] min,
fio de entrada[23:0] ppi, fio de entrada q );
fio cl,c2,c3,c4,c5,c6,c7,c8,c9,clO;
fio cll, cl2, cl3, cl4, cl5, cl6, cl7, cl8, cl9, c20;
fio c21,c22,c23;
bloco bl (soma,cl,mout[0],min[0],ppi[0],q,l'bO);
Multiplicador de ponto flutuante IEEE-754 1
Declaração do problema 1
Procedimento 1
Implementação (Module-wise) 1
0.1 Identificação do bit de sinal 1
Código Verilog: 1
0.2 Adicionando os expoentes e subtraindo o viés 1
Código Verilog: 2
Código Verilog: 2
Código Verilog: 3
0.3 Multiplicando a mantissa usando o Carry Save Multiplier 3
Código Verilog: 4
Código Verilog: 4
Código Verilog: 5
0.4 Colocando o ponto binário e normalizando a mantissa 5
Código Verilog: 5
0.5 Módulo de verificação e controle de transbordamento/transbordamento para operação de outros módulos 6
Código Verilog: 6
Bancada de testes 6
Código Verilog: 6
Entradas e resultados de teste 7
Command promt output 8
Referências 8

4
bloco b24(ppo[22], ppo [23], mout[23], min[23], ppi [23], q, c23); módulo final

Finalmente, estendemos as linhas para formar as grades diagonais. As únicas entradas deste módulo são o multiplicador e o multiplicador e a
saída é o produto final. Temos 24 linhas que levam um bit cada do multiplicador. Este é o módulo de nível superior do multiplicador de
salvamento de transporte:

Código Verilog:
produto módulo(
fio de saída[47:0] soma,
fio de entrada[23:0] min,
Fio de entrada[23:0]Q
);
fio [23:0] tempi, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, templ0; diagonal m
fio [23:0] templl, templ2, templ3, templ4, templ5, templ6, templ7, templ8, templ9, temp20;
fio [23:0] temp21,temp22,temp23,temp24;
fio [23:0] ptempl, ptemp2, ptemp3, ptemp4, ptemp5, ptemp6, ptemp7, ptemp8, ptemp9, ptempl0;
vertical p
fio [23:0] ptempll, ptempl2, ptempl3, ptempl4, ptempl5, ptempl6, ptempl7, ptempl8, ptempl9, ptemp20;
fio [23:0] ptemp21,ptemp22,ptemp23;
linha rl (ptempl, tempi, sum[0] , min, 24'h000000, q[0]);
remar R2 (PTEMP2, temp2, soma[l], Tempi Ptempl, q[l]);
remar R3 (PTEMP3, temp3, soma[2], temp2, PTEMP2, Q[2]);
remar R4 (PTEMP4, temp4, soma[3], temp3, PTEMP3, Q[3]);
remar r5 (PTEMP5, temp5, soma[4], temp4, PTEMP4, Q[4]);
remar r6 (PTEMP6, temp6, soma[5], temp5, PTEMP5, Q[5]);
remar R7 (PTEMP7, temp7, soma[6], temp6, PTEMP6, Q[6]);
remar R8 (PTEMP8, temp8, soma[7], temp7, PTEMP7, Q[7]);
remar R9 (PTEMP9, temp9, soma[8], temp8, PTEMP8, Q[8]);
linha r10(ptemp10, templO, sum[9] , temp9, ptemp9, q[9]);
linha r11(ptemp11, templl, sum[10] , templO, ptemplO, q[10]);
linha rl2(ptempl2, templ2, sum[ll], templl, ptempll, q[ll]);
linha rl3(ptempl3, templ3, sum[12], templ2, ptempl2, q[12]);
linha rl4(ptempl4, templ4, sum[13], templ3, ptempl3, q[13]);
linha rl5(ptempl5, templ5, sum[14], templ4, ptempl4, q[14]);
linha rl6(ptempl6, templ6, sum[15], templ5, ptempl5, q[15]);
linha rl7(ptempl7, tempi?, sum[16], templ6, ptempl6, q[16]);
linha rl8(ptempl8, templ8, sum[17], templ7, ptempl7, q[17]);
linha rl9(ptempl9, templ9, sum[18], templ8, ptempl8, q[18]);
linha r20(ptemp20, temp20, sum[19], templ9, ptempl9, q[19]);
linha r21(ptemp21, temp21, sum[20], temp20, ptemp20, q[20]);
linha r22(ptemp22, temp22, sum[21], temp21, ptemp21, q[21]);
linha r23(ptemp23, temp23, sum[22], temp22, ptemp22, q[22]);
linha r24(soma[47:24], temp24, soma[23], temp23, ptemp23, q[23]);
módulo final

0.4 Colocando o ponto binário e normalizando a mantissa


Em um número de ponto flutuante IEEE-754 normalizado, haverá um 'l'bit à esquerda do ponto binário. Ao multiplicar a mantissa (23 bits à
esquerda do ponto binário), ingerimos o ponto binário. Assim, no resultado, os 46 bits inferiores ficam à esquerda do ponto binário, ou seja, o
ponto binário ocorre entre o 45º e o 46º bit (a partir do Oth bit no LSB). Depois de colocar o ponto binário, se houver apenas um '1' bit
restante, não há necessidade de normalização. Mas se houver MSB '1' ocorre um bit pai do ponto binário, precisamos normalizar a mantissa,
ou seja, deslocá-la para a direita por uma. Na matissa do produto final, são apenas 23 bits, então arredondamos nosso resultado para 23 bits
(truncamento simples). O bit 'I' à esquerda do ponto binário é descartado no produto mantissa. Aqui, fazemos um módulo "normalizar" para
realizar essas operações. Ele também gera um bit de sinalizador "norm_flag", para indicar que a normalização está feita e precisamos
incrementar o expoente em 1. Além disso, em vez de mudar para a direita e depois deixar cair os termos em excesso, nós apenas cortamos
os bits, ou seja, capturamos de [45:23] se não houver normalização e de [46:24] se houver normalização. Finalmente, um multiplexador é
usado para canalizar a mantissa apropriada (deslocada ou intacta) dependendo do "norm_flag".

Código Verilog:
módulo normalizar(
fio de saída[22:0] adj_mantissa, //mantissa ajustado (após extrair a peça necessária) fio de saída norm_flag, fio de entrada[47:0] prdt
); retorna norma =1 se a normalização precisar ser feita.
e(norm_flag,prdt[47],1'bl); sei = 1 se liderar um está em 47... precisa de normalização
se sei = 0, levando zero não em 47... sem necessidade de resultados de fio de normalização [1:0][22:0];

5
atribuir resultados[0] = prdt[45:23];
atribuir resultados[1] = prdt[46:24];
atribuir adj_mantissa = {resultados[norm_flag+0]};
módulo final

0.5 Módulo de verificação e controle de transbordamento/transbordamento para operação de outros


módulos
Neste módulo, obtemos diferentes fatias do resultado final, invocando os módulos necessários em ordem. O expoente final deve ficar entre 1
e 254. Ao encontrar expoente, se expl + exp2 - viés dá um empréstimo, significa um underflow. E se o expoente final (após a normalização)
for 255 ou maior, então há transbordamento. Aqui invocamos o módulo de normalização para verificar se o expoente precisa ser
incrementado ou não. O resultado final é formado em fatias e concatenado.

Código Verilog:
Módulo de controle para acionar e regular os módulos necessários em ordem de controle do módulo (fio de entrada[31:0] inpl, fio de entrada[31:0]
inp2, fio de saída[31:0] de saída, subfluxo de fio de saída, estouro de fio de saída);
sinal de arame;
fio [7:0] expl;
fio [7:0] exp2;
fio [7:0] exp_out;
fio [7:0] test_exp;
fio [22:0] manti;
fio [22:0] mant2;
fio [22:0] mant_out;
sign_bit sign_bitl(sinal,inpl,inp2);
fio [7:0]tempi;
manequim de arame; conectar portas de saída não utilizadas de transporte de fio aditivo;
fio [8:0] sub_temp;
ripple_8 ripl(tempi,carry,inpl[30:23],inp2[30:23],1'bO);
subtractor_9 subl(sub_temp,underflow,{carry,tempi},1'bO);
se houver um underflow =>
e(transbordamento,sub_temp[8],1'bl); se o expoente tiver mais de 8 bits: estouro //tomando produto de mantissa: fio [47:0] prdt;
produto pl(prdt,{1'bl,inpl[22:0]},{1'bl,inp2[22:0]});
norm_flag de fios;
fio [22:0] adj_mantissa;
normalizar norml(adj_mantissa,norm_flag,prdt);
ripple_8 ripple_norm(test_exp,dummy,sub_temp[7:0],{7'b0,norm_flag},l'b0);
atribuir [31] = sinal;
atribuir out[30:23] = test_exp;
atribuir out[22:0] = adj_mantissa;
módulo final

Bancada de testes
Implementamos o banco de testes de modo a dar quatro entradas de teste para o programa, e os resultados são mostrados abaixo.

Código Verilog:
«Estímulo do módulo Ins/lps em escala de tempo;

6
reg [31:0] ini;
reg [31:0] em2;
Fio [31:0] PRDCT;
transbordamento de fios;
subfluxo de fios;
fio [7:0] test_exp;
fio [22:0] mant;
arame normativo;
controle de controle1(
.inpl(ini), .inp2(in2), .out(prdct), .underflow(underflow), .overflow(transbordamento) );
início inicial
$dumpfile("multiplicar.vcd");
$dumpvars(0,estímulo);
ini = 32'b010000101101110101010010101001010;
em2 = 32'b0100001100100110011101011011010;
producti = 0 10001101 00011111111001111001010
#10
ini = 32'bll010110110110100101011101000110;
em2 = 32'b01001010101110100101110001110010010;
produto2 = 1 11000100 00111101111001001000001
#10
ini = 32'b0100010101010010010001111000101010;
em2 = 32'b01001001101001011010001110110001;
#10
ini = 32'bll001001110100101101100001110100;
em2 = 32'bll000011001110110011011010101010100;
#10
$finish; fim
início inicial
$monitor("Multiplicand = %32b. Multiplicador = %32b. Produto = %32b. Underflow = 7,1b, Overflow = %1b" ,ini,in2,prdct,underflow,overflow) ;
fim
módulo final

Entradas e resultados de teste


Julgamento Multiplicando Multiplicador Produto
nº.
1 01000010110111010110001010110010 01000011001001100111010110110110 01000110100011111111001111001010
2 11010110110110100101011101000110 01001010101110100101110001110010 11100010000111101111001001000001
3 01000101010100100100011110001010 01001001101001011010001110110001 01001111100010000000111010010000
4 11001001110100101101100001110100 11000011001110110011011010110100 01001101100110100011000100101010

+1,12462746 x 214.
No ensaio 2, multiplicador é -1,705788373 x 246 e multiplicador é +1,455946207 x 222. O produto é obtido corretamente como -
1,241768056 x 269.
As formas de onda obtidas para as observações acima, usando gtkwave, são mostradas abaixo:
No ensaio 1, multiplicador é +1,729574441 x 26 e multiplicador é +1,300467252 x 27. O produto é obtido corretamente como

7
Command promt output

Referências
[1] Hamacher Computer Organization 5ª ed.
[2] Projeto e Arquitetura de Sistemas de Computação, V.P Heuring.
[3] IEEE 754-2008, Padrão IEEE para Aritmética de Ponto Flutuante, 2008.
[4] Douglas J. Smith, VHDL & Verilog Compared & Contrasted Plus Modeled Exemplo Escrito em VHDL, Verilog e C
[5] http://www.ece.umd.edu/class/enee359a/verilog_tutorial.pdf

Você também pode gostar