Moltiplicazione Binaria

by

Chessa Salvatore




L'algoritmo usato nelle routine di moltiplicazione e' praticamente identico a quello a quello che noi umani abbiamo imparato nelle elementari.
Si scansiona il moltiplicatore partendo dalle unita' (cioe' da destra a sinistra) si moltiplica per il digit scansionato e lo si eleva per la posizione decimale. Si ottengono cosi' dei risultati parziali che al temine verranno sommati tra loro per fornire il risultato. Nei microprocessori analogamente, si scansiona il moltiplicatore partendo dal bit piu' basso, non si moltiplica perche' il valore e' al massimo 1 e quindi il risultato parziale e' il valore assunto dal moltiplicando ed infine si eleva il moltiplicando per la posizione binaria del bit. L'unica differenza e' che non ci sono risultati parziali dato che e' piu' comodo,piu' veloce e richiede meno passi di programma eseguire la somma immediata dei vari parziali. Questo e' il sorgente di una moltiplicazione con moltiplicando e moltiplicatore a 16 Bit. Il risultato e' a 32 Bit. Il processore e' del tipo 80x86 e seguenti. Ha la moltiplicazione tra le istruzioni ma non accetta operandi superiori a 16 bit. Pertanto se si vuole moltiplicare 100.000x100 ad esempio e' necessario preparare una routine ad hoc.



80x86
   
    MOV AX,100   ;  In AX i 16 Bit del moltiplicando 
    MOV BX,1000  ;  In BX i 16 Bit del moltiplicatore 
    MUL BX       ;  Esegui la moltiplicazione 

A questo punto troveremo il risultato in DX:AX Breve, semplice, conciso. Diverso e' il discorso quando si usano processori che non hanno la moltiplicazione tra le istruzioni. Di seguito vediamo una routine di moltiplicazione per Z80 questa volta pero' il moltiplicando accetta fino a 31 Bit cioe' fino ad oltre 2 miliardi mentre il moltiplicatore e' sempre da 16 Bit come sopra cioe' 65565.



Z80
 ; Moltiplicazione 16x32 bit con risultato a 32 bit
 ; Domanda:  Perche' fare una moltiplicazione a 32 bit
 ;           e magari bastava da 8 bit?
 ; Risposta: E se per caso salta fuori un numero superiore
 ;           a 255 che facciamo ? Un'altra routine !!

-----------------------------------------------------
DE = Contiene i 16 bit alti del moltiplicando HL = Contiene i 16 bit bassi del BC = Contiene i 16 bit del moltiplicatore --------------------------------------------- DE = Contiene i 16 bit alti del risultato HL = Contiene i 16 bit bassi del risultato
-----------------------------------------------------
; Questa moltiplicazione richiede per il moltiplicatore ; da caricare in BC un massimo di 16 bit cioe' 65535. ; Per il moltiplicando da caricare in DE:HL il massimo ; e' di 31 bit pari cioe a piu' di 2 miliardi. ; Sotto inizializzo i registri per eseguire la routine ORG 100H LD SP,1000H LD BC,1000 LD DE,0 LD HL,1000 CALL MUL32X16 JP 100H ; Qui' inizia la routine di moltiplicazione MUL32X16: ; Inizializzo la RAM e azzero il risultato CALL INIT ; Dopo aver copiato DE:HL in RAM copio BC in DE per ; poter utilizzare B come contatore di loop PUSH BC POP DE ; Inizializzo i puntatori IX e IY TP1: LD IX,MOLTIPLICANDO LD IY,RISULTATO ; Eseguo uno shift a destra del moltiplicatore ; contenuto in DE e se dal bit 0 esce un uno ; (che testo tramite il carry) sommo al risultato ; il contenuto del moltiplicando SRL D RR E JR NC, TP3 ; Nel carry c'e' uno e pertanto eseguo una somma ; sui 4 byte del risultato col moltiplicando AND A LD B,4 TP2: LD A,(IX+0) ADC A,(IY+0) LD (IY+0),A INC IX INC IY DJNZ TP2 ; Ad ogni ciclo controllo se il moltiplicatore ; e' a zero nel qual caso termina la routine ; dato che non c'e' piu' niente da moltiplicare TP3: LD A,D OR E JR Z, FINE ; Ad ogni ciclo viene raddoppiato il valore del ; moltiplicando eseguendo uno shift a sinistra ; dei 32 bit. Questo perche' il valore da sommare ; al risultato deve essere elevato per la posizione ; binaria del bit in uscita dal moliplicatore LD IX,MOLTIPLICANDO SLA (IX+0) RL (IX+1) RL (IX+2) RL (IX+3) JP TP1 ; Inizializzo la RAM con il valore del ; moltiplicando e azzero il risultato INIT: LD IX,MOLTIPLICANDO LD (IX+0),L LD (IX+1),H LD (IX+2),E LD (IX+3),D LD (IX+4),0 LD (IX+5),0 LD (IX+6),0 LD (IX+7),0 RET ; La routine e' terminata. Ora carico nei ; registri DE:HL il risultato finale FINE: LD IY,RISULTATO LD D,(IY+3) LD E,(IY+2) LD H,(IY+1) LD L,(IY+0) RET ; -------------- area dati ram ----------------- MOLTIPLICANDO: DB 0,0,0,0 RISULTATO: DB 0,0,0,0,0 LOGO: DB 'By Tore ... (c) Ottobre 1999 '



Quella che segue e' la routine per il microcontrollore ST62x10.
Questo microcontrollore della SGS ha un solo registro abilitato a svolgere operazioni logiche e aritmetiche ed e' l'accumulatore A che di conseguenza preleva dalla RAM o dai registri i dati, li elabora e li rimette da dove li ha presi. La routine e' analoga a quella per lo Z80. Sempre con 31 Bit di moltiplicando e 16 Bit di moltiplicatore. Ovviamente e' piu' lunga e complessa




ST6
; Sezione variabili (084H ..0BFH)

MUL_0      .DEF  084H       ; MSB del moltiplicando 
MUL_1      .DEF  085H       ;
MUL_2      .DEF  086H       ;
MUL_3      .DEF  087H       ; LSB del moltiplicando 


MULT_H     .DEF  088H       ; MSB del moltiplicatore 
MULT_L     .DEF  089H       ; LSB del moltiplicatore 


RES_0      .DEF  08AH       ; MSB del risultato 
RES_1      .DEF  08BH       ;
RES_2      .DEF  08CH       ;
RES_3      .DEF  08DH       ; LSB del risultato 

TABELLA    .DEF  08EH       ; tabella uso controllo bit 



;  Questa moltiplicazione richiede che il moltiplicando
;  ed il moltiplicatore siano posti in memoria.
;  Al ritorno dalla routine l'intero si trovera' nei 4 byte
;  del risultato.

; inizializzazione del sistema

RESET   LDI     WDOG,0FEH
        LDI     TSCR,0
        LDI     ADCR,0H
        LDI     IOR,00H
        RETI

; Inizializzazione delle variabili
; e azzeramento del risultato

        CALL    INIT
        NOP

; Questa e' la chiamata per la routine
; di moltiplicazione

        CALL    MUL32X16
        NOP
        JP      0880H

MUL32X16:

; azzero il risultato da precedenti operazioni

        CALL    CLEAR

; Per la moltiplicazione e' necessario addizionare
; il moltiplicando elevato per la posizione del bit
; del moltiplicatore al risultato. Pertanto sarebbe
; utile far scorrere i bit del moltiplicatore da
; sinistra verso destra e testarli nel carry oppure
; nel bit 0. Purtroppo per questo processore non e'
; disponibile uno shift da sinistra verso destra e
; quindi li faccio scorrere da destra verso sinistra
; li raccolgo nel carry e li deposito in una tabella
; creata in RAM per testarli successivamente.

        CALL    CREA_TABELLA

; Qui' punto alla tabella e ne testo il bit ivi contenuto.
; Se e' 1 sommo al risultato il moltiplicando, altrimenti
; raddoppio solo il valore del moltiplicando

        CLR     W
SW1:    LDI     X,TABELLA
        LD      A,W
        ADD     A,X
        LD      X,A
        LD      A,(X)
        CPI     A,0
        JRZ     SW2
        CALL    ADDIZIONA
        NOP
SW2:    CALL    RADDOPPIA
        INC     W
        LD      A,W
        CPI     A,15
        JRZ     SW3
        JP      SW1
SW3:    RET

; Questa parte di programma esegue una addizione
; su valori da 32 bit

ADDIZIONA:

        LD      A,RES_3
        ADD     A,MUL_3
        LD      RES_3,A
        LDI     A,0
        RLC     A
        ADD     A,RES_2
        ADD     A,MUL_2
        LD      RES_2,A
        LDI     A,0
        RLC     A
        ADD     A,RES_1
        ADD     A,MUL_1
        LD      RES_1,A
        LDI     A,0
        RLC     A
        ADD     A,RES_0
        ADD     A,MUL_0
        LD      RES_0,A
        RET

; Questa parte di programma esegue una rotazione
; da destra a sinistra su 32 bit che equivale
; a raddoppiare il valore del dato.

RADDOPPIA:

        LD      A,MUL_3
        SLA     A
        LD      MUL_3,A
        LD      A,MUL_2
        RLC     A
        LD      MUL_2,A
        LD      A,MUL_1
        RLC     A
        LD      MUL_1,A
        LD      A,MUL_0
        RLC     A
        LD      MUL_0,A
        RET

; Prima di iniziare la routine e' necessario
; azzerare il risultato da precedenti operazioni
; e la tabella del moltiplicatore

CLEAR:  LDI     Y,RES_0
        LDI     W,20
SW4:    CLR     A
        LD      (Y),A
        INC     Y
        DEC     W
        LD      A,W
        CPI     A,0
        JRNZ    SW4
        RET

; Creo una tabella con tutti i bit del moltiplicatore

CREA_TABELLA:

        LDI     A,TABELLA
        ADDI    A,15
        LD      X,A
        LDI     V,16
SW5:    LD      A,MULT_L
        SLA     A
        LD      MULT_L,A
        LD      A,MULT_H
        RLC     A
        LD      MULT_H,A
        JRNC    SW6
        INC     (X)
SW6:    DEC     X
        DEC     V
        LD      A,V
        CPI     A,0
        JRZ     SW7
        JP      SW5
SW7:    RET


; Questa parte serve ad inizializzare le variabili
; e non fa parte della routine

INIT:   LDI     Y,MUL_0
        LDI     A,0
        LD      (Y),A
        INC     Y
        LDI     A,0
        LD      (Y),A
        INC     Y
        LDI     A,027H
        LD      (Y),A
        INC     Y
        LDI     A,010H
        LD      (Y),A
        INC     Y
        LDI     A,027H
        LD      (Y),A
        INC     Y
        LDI     A,010H
        LD      (Y),A
        RET

Top  |  80x86  |  Z80  |  ST6  |  Home