2013-06-13 8 views
7

Sto cercando di implementare un partitore hardware a virgola mobile a 32 bit nell'hardware e mi chiedo se posso ottenere qualche suggerimento su alcuni compromessi tra diversi algoritmi?Dettagli di implementazione di Mobile Point Divider

La mia unità in virgola mobile supporterà attualmente la moltiplicazione e l'addizione/sottrazione, ma non ho intenzione di passare a un'architettura in virgola mobile a moltiplicazione multipla (FMA) poiché questa è una piattaforma incorporata in cui sto cercando di ridurre l'utilizzo dell'area .

+0

avete un vincolo su quanti cicli può richiedere? –

+0

L'implementazione deve essere conforme allo standard IEEE-754? Che tipo di hardware è questo, ASIC, FPGA, qualcos'altro? Hai consultato la letteratura pertinente, a partire dagli articoli di S. Oberman e P. Soderquist negli anni '90? – njuffa

+0

Non ho un vincolo sul conteggio del ciclo. Vorrei che l'area fosse bassa. Il mio addizionatore è 1 ciclo, il mio moltiplicatore è 1 ciclo. Questo è per un ASIC. Ho consultato alcune pubblicazioni, ma non ho ancora trovato nulla di buono, è per questo che lo sto chiedendo. – Veridian

risposta

1

C'era molto tempo fa, mi imbatto in questo pulito e facile da implementare l'algoritmo galleggiante/punto fisso Divison utilizzato in FPU militari di quel periodo di tempo:

  1. ingresso deve essere unsigned e spostato in modo x < y ed entrambi sono nella gamma < 0.5 ; 1 >

    non dimenticate di conservare la differenza di turni sh = shx - shy e dei segni originali

  2. trovare f (scorrendo) in modo y*f -> 1 .... dopo che x*f -> x/y che è il risultato della divisione

  3. spostamento del x*f indietro di sh e ripristinare risultato segno (sig=sigx*sigy)

    il x*f può essere calcolato facilmente come questo:

    z=1-y 
    (x*f)=(x/y)=x*(1+z)*(1+z^2)*(1+z^4)*(1+z^8)*(1+z^16)...(1+z^2n) 
    

    dove

    n = log2(num of fractional bits for fixed point, or mantisa bit size for floating point) 
    

Sto usando questo Divison nei miei bignum aritmetica, C++ realizzazione di alto livello Divison è come questo:

fixnum fixnum::operator/(const fixnum &x) // return = this/x 
    { 
    fixnum u,v,w; 
    int k=0,s; 
    s=sig*x.sig;    // compute result signum 
    u=this[0]; u.sig=+1; 
    v=x; v.sig=+1; 
    w.one(); 
    while (geq(v,w)) { v=v>>1; k++; } // shift input in range 
    w=w>>1; 
    while (geq(w,v)==1) { v=v<<1; k--; } 
    w.div(u,v);    // use divider block 
    w=w>>k;     // shift result back 
    w.sig=s;    // set signum 
    return w; 
    } 

questo è stato sviluppato nel tempo in cui conta ogni transistor ... quindi dovresti essere in grado di compattarlo con l'uso delle tue unità + e *. spero che sia d'aiuto....

[edit1:] qui è il mio galleggiante attuazione punto

void arbnum::div(const arbnum &x,const arbnum &y,int acc) 
    { 
    // O(log(N)*(sqr+mul+inc)) ~ O(1.5*log(N)*(N^2)) 
    // x<y = < 0.5 ; 1 > 
    // x*f -> x/y , y*f -> 1 
    int i,nz; 
    arbnum c,z,q; 
    c=x; 
    z.one(); z.sub(z,y); // z=1-y 
    q=z; 
    q.inci(); 
    c.mul(c,q);    // (x/y)'=x*(1+z) 
    c._normalize(); 
    nz=z.nfbits(); 
    if (acc<=0) acc=(nz+c.nfbits())<<1; 
    for (i=int_log2(acc);i>=0;i--) 
     { 
//  z.mul(z,z); 
     z.sqr(z); 
     nz<<=1; if (nz>acc) nz=acc; z._normalize(nz); 
     q=z; 
     q.inci(); 
     c.mul(c,q);   // (x/y)'=x*(1+z)*(1+z^2)*(1+z^4)*(1+z^8)*(1+z^16)... 
     if (i) c._normalize(acc+nz); 
     } 
    c._normalize(acc); 
    overflow(); 
    c.sig=sig; 
    *this=c; 
    } 

numeri sono:

DWORD *dat; int siz,exp,sig,bits; 

dat[siz]: mantisa MSW = dat[0]
exp: base 2 esponente di MSB di mantisa
sig: signum di mantisa
bits: bit utilizzati di mantisa per velocità fino someoperations
a.inci(): a++
a.zero: a=0
a.one: a=1
a.geq(x,y): confronta |x|,|y|, restituire 0 per |x|<|y|, 1 > 2 == a.add(x,y): a=x+y
a.sub(x,y): a=x-y
a.mul(x,y): a=x*y
a.sqr(x): a=x*x
a.nfbits(): ritorno num di bit frazionari utilizzati in numero (00000100.00011100b -> 6)
a._normalize(): normalizzare numero (MSB di mantissa = 1)
a.overflow(): se rileva che num è ?.111111111111111111111111111111111111111111111b allora round acc si desidera la precisione dei bit di mantissa (il mio arbnum ha un numero illimitato di bit di mantissa)

+0

Grazie per la risposta, ma davvero non riesco a capire il tuo codice. Hai scritto una divisione, ma stai usando il blocco del divisore lol? – Veridian

+0

il blocco del divisore è questo z = 1-y; (x * f) = (x/y) = x * (1 + z) * (1 + z^2) * (1 + z^4) * (1 + z^8) * (1 + z^16) ... (1 + z^2n) quindi per la divisione è necessario solo + e *, ...termini z^2n sono fatti facilmente in loop da z = z * z .... – Spektre

+0

oh e vedo ora la confusione nel blocco di divisione x, y sono le variabili u, v dalla routine di divisione principale – Spektre