Altifigence Academy

54 / 63 · Concetto

Moltiplicatore unsigned shift-add multiciclo

Accumulare prodotti parziali in W clock verificando accettazione, fine, ultimo accumulo, larghezza e invariante.

Prerequisiti: logica sequenziale, assegnazioni non bloccantiNonblocking Assegnazione RTL sequenziale con <=. Valuta il membro destro e pianifica l’aggiornamento, permettendo ai registri dello stesso fronte di usare lo stato precedente. Approfondisci, contatori, shift e sommatori.

Riutilizzare un sommatore su più clock

La moltiplicazione unsignedUnsigned Interpretazione dei bit come intero non negativo. Il campo a n bit è 0–2^n−1 e può differire dalla lettura signed degli stessi bit. Approfondisci a W bit somma i prodotti parziali scelti dai bit di B.

AB=∑i=0W−1bi(A2i)A B=\sum_{i=0}^{W-1} b_i(A2^i)

Sommarli tutti insieme richiede molta logica. Qui riutilizziamo un sommatore W volte, con un compromesso fra area e throughput. Un ciclo RTL da solo non genera una struttura multiciclo: servono registriRegistro Memorizza uno stato di più bit. I registri sincroni del corso acquisiscono gli ingressi specificati al fronte di clock. Approfondisci per lo stato intermedio e una condizione di fine.

Accumulatore P e moltiplicando spostato M hanno 2W bit; il moltiplicatore Q, spostato a destra, ne ha W. All'inizio P=0, M=zero-extend(A), Q=B. Ogni clock di lavoro aggiunge M a P se Q[0]=1, poi sposta M a sinistra e Q a destra di uno.

Pk+1=Pk+Qk[0]Mk,Mk+1=2Mk,Qk+1=⌊Qk/2⌋P_{k+1}=P_k+Q_k[0]M_k,\quad M_{k+1}=2M_k,\quad Q_{k+1}=\lfloor Q_k/2\rfloor

Dopo W passi Q=0 e P è il prodotto completo. Bastano 2W bit: (2W−1)2<22W(2^W-1)^2<2^{2W} e le somme parziali unsigned non superano il prodotto finale.

Con A=13, B=11, W=4, i bit bassi di Q sono 1,1,0,1. P segue 0→13→39→39→143; M usato è 13→26→52→104. Anche al terzo passo, Q[0]=0, shift e contatore devono avanzare.

Ogni colonna mostra lo stato dopo acquisizione o lavoro. La prima inizializza; le quattro successive calcolano. Al terzo passo resta fermo solo P, mentre M e Q scorrono.

Calcolare 13×11 con quattro accumulazioni
Mostra i dati della forma d’onda
Dati della forma d’onda: ogni carattere è un intervallo; il punto mantiene lo stato precedente; p è un ciclo di clock.
SegnaleForma d’ondaValori del bus
edge23452capture → work1 → work2 → work3 → work4
P after234.50 → 13 → 39 → 143
M after2345213 → 26 → 52 → 104 → 208
Q after2345211 → 5 → 2 → 1 → 0
done after0...1

Definire prima accettazione e completamento

La richiesta viene accettata al fronte di salitaFronte di salita Passaggio del clock da 0 a 1, distinto dall’intero intervallo di livello CLK=1. Approfondisci con start=1 in idle. A t0 si salvano solo gli ingressi. Da t1 a tW si eseguono W passi; subito dopo tW product e done sono validi. Fra accettazione e fine passano W periodi, mentre contando anche il fronte iniziale compaiono W+1 fronti.

Con busy=1 start è ignorato. Anche il fronte finale non accetta una nuova richiesta, perché busy prima del fronte vale 1. La prima accettazione seguente è tW+1: distanza minima W+1 periodi. Tenendo start=1 si riparte al prossimo fronte idle. Il chiamante normalmente fornisce un impulso allineato all'accettazione.

SystemVerilog
module mul_iter #(parameter int W = 8) (
  input  logic clk, rst, start,
  input  logic [W-1:0] a, b,
  output logic busy, done,
  output logic [2*W-1:0] product
);
  localparam int CW = (W <= 1) ? 1 : $clog2(W);
  localparam logic [CW-1:0] LAST = CW'(W-1);
  logic [CW-1:0] step;
  logic [2*W-1:0] acc, m, next_acc;
  logic [W-1:0] q;

  assign next_acc = acc + (q[0] ? m : {2*W{1'b0}});

  always_ff @(posedge clk) begin
    if (rst) begin
      busy <= 1'b0;
      done <= 1'b0;
      product <= '0;
      acc <= '0;
      m <= '0;
      q <= '0;
      step <= '0;
    end else begin
      done <= 1'b0;
      if (!busy) begin
        if (start) begin
          busy <= 1'b1;
          acc <= '0;
          m <= {{W{1'b0}}, a};
          q <= b;
          step <= '0;
        end
      end else begin
        acc <= next_acc;
        m <= m << 1;
        q <= q >> 1;
        if (step == LAST) begin
          product <= next_acc;
          busy <= 1'b0;
          done <= 1'b1;
        end else begin
          step <= step + 1'b1;
        end
      end
    end
  end
endmodule

Si assume W≥1; CW è almeno 1 per evitare un contatore a zero bit con W=1. Reset sincrono active-high prevale sull'operazione. Cambiare a, b esterni dopo la richiesta non influisce su m, q salvati. product cambia solo al reset o al termine. done è un impulso di un ciclo, non un valid mantenuto fino al consumo.

L'ultima assegnazione è product<=next_acc, non product<=acc. Nonblocking legge i valori precedenti: usare acc perderebbe l'ultimo prodotto parziale. Analogamente next_acc usa Q[0] corrente anche scrivendo prima lo shift di q nel codice.

Invariante e scelte reali

Dopo k passi vale:

Pk+MkQk=ABP_k+M_kQ_k=A B

Separando Q in parte pari e bit basso si verifica che la relazione resta vera al passo successivo. A k=W, Q=0, dunque P=AB. L'invarianteInvariante Condizione sempre vera in ogni esecuzione ammessa. Una FIFO profonda quattro contiene, per esempio, sempre da zero a quattro elementi. Approfondisci spiega l'ordine di accumulo e shift meglio di poche forme d'onda.

Il cammino critico di un passo include sommatore a 2W bit e selezione d'ingresso. Eliminare * non garantisce area o velocità migliori. Confrontate DSP dedicati FPGA, sintesi e throughputThroughput Numero di operazioni accettate o completate per unità di tempo. Una pipeline può aumentarlo senza ridurre la latenza del singolo lavoro. Approfondisci richiesto. Non sono implementati early-exit, signed e backpressure del risultato. Il consumatore non deve perdere done.

Testate 0,1, massimo e B con solo il MSB acceso, oltre a start e cambi d'ingresso durante busy e annullamento tramite reset. Il solo MSB di B rivela particolarmente bene l'ultima accumulazione mancante.

Prova tu

W=4, A=9, B=10 sono accettati a t0. Calcolate acc, q, done dopo t1–t4 e la prima accettazione successiva. Cosa produce product<=acc finale?

Leggi la spiegazione

Inizialmente acc=0, m=9, q=1010. t1: bit basso 0, acc=0, q=0101, done=0. t2: aggiunge M=18, acc=18, q=0010, done=0. t3: bit basso 0, acc=18, q=0001, done=0. t4: aggiunge M=72, acc=90, q=0000, done=1, busy=0, product=90. Prima di t4 busy è ancora 1, quindi la prima richiesta successiva è t5. product<=acc legge il vecchio 18 e perde l’ultimo prodotto parziale 72.

La scelta vale per questo browser. Puoi modificarla in qualsiasi momento dal piè di pagina.