;------------------------------------------------------------; ; m68k ASM by Marco Benvegnu' www.benve.org Gen 2002 ; ;------------------------------------------------------------; ; ; ; Ecco alcuni algoritmi di divisione e moltiplicazione a ; ; precisione multipla per il Motorola M68000. ; ; ; ; NOTE: ; ; - MDIV16 divisione interi senza segno (divisore a 16 bit) ; ; Metodo tradizionale (semplice, veloce, espandibile) ; ; - MSDIV16 divisione interi con segno (metodo diretto) ; ; Questo e' molto interessante: in genere (v. MSDDIV) si ; ; effettua la divisione fra i valori assoluti e solo ; ; alla fine si tiene conto dei segni. ; ; Qui propongo una tecnica per valutare il segno ; ; direttamente all'interno del (potente) metodo ; ; tradizionale (MDIV16). ; ; - MSDDIV divisione interi con segno (divisore a 32 bit) ; ; - DDIV divisione interi senza segno (FIX) ; ; L'autore di DDIV e' Moro (unipd). ; ; - MDMUL moltiplicazione a 32 bit senza segno ; ; Metodo di scomposizione degli operandi in due parti ; ; da 16 bit (di interesse puramente accademico). ; ; ; ;------------------------------------------------------------; ;------------------------------------------------------------; ; NOME ; ; MDIV16 divisione interi senza segno (divisore di 16 bit) ; ; DESCRIZIONE ; ; Effettua la divisione tra interi senza segno, dividendo ; ; di 64 bit e divisore di 16 bit, fornendo quoziente di 64 ; ; bit e resto di 16 bit. Mai overflow. ; ; Estendibile a dividendo di dim. qualunque. ; ; INTERFACCIA ; ; A0 input puntatore dividendo ; ; A1 input puntatore quoziente ; ; QW[A0] input dividendo (64 bit) ; ; D1.W input divisore (16 bit) ; ; output resto (16 bit) ; ; QW[A1] output quoziente (64 bit) ; ; USA ; ; -- ; ;------------------------------------------------------------; MDIV16: MOVEM.L D0, -(SP) ; salva il registro CLR.L D0 MOVE.W (A0), D0 ; MSW DIVU.W D1, D0 MOVE.W D0, (A1) ; salva MSW quoziente MOVE.W 2(A0), D0 ; il precedente resto in D0.H DIVU.W D1, D0 MOVE.W D0, 2(A1) MOVE.W 4(A0), D0 ; il precedente resto in D0.H DIVU.W D1, D0 MOVE.W D0, 4(A1) MOVE.W 6(A0), D0 ; il precedente resto in D0.H DIVU.W D1, D0 MOVE.W D0, 6(A1) SWAP.W D0 ; sposta il resto in D0.W MOVE.W D0, D1 MOVEM.L (SP)+, D0 ; ripr. il registro RTS ;------------------------------------------------------------; ; NOME ; ; MSDIV16 divisione interi con segno (metodo diretto) ; ; DESCRIZIONE ; ; Effettua la divisione tra interi con segno, dividendo ; ; di 64 bit e divisore di 16 bit, fornendo quoziente di 64 ; ; bit e resto di 16 bit. Mai overflow (non segnalato se si ; ; calcola -2^63 / -1 ). ; ; Troncamento floor anche per risultati negativi! ; ; INTERFACCIA ; ; A0 input puntatore dividendo (64 bit) ; ; A1 input puntatore quoziente (64 bit) ; ; QW[A0] input dividendo (64 bit) ; ; D1.W input divisore (16 bit) ; ; output resto (16 bit) ; ; QW[A1] output quoziente (64 bit) ; ; USA ; ; -- ; ;------------------------------------------------------------; ; NOTA: nel simulatore di Shaban, DIVS puo' segnalare, ; erroneamente, N=1, Z=1; se lo usi, aggiungi le 3 istruzioni ; commentate (BEQ) MSDIV16: MOVEM.L D0, -(SP) ; salva il registro CLR.W D2 MOVE.W (A0), D0 ; MSW EXT.L D0 DIVS.W D1, D0 MOVE.W D0, (A1) ; salva MSW quoziente MOVE.W 2(A0), D0 ; il precedente resto in D0.H DIVS.W D1, D0 BPL MSD161 ;BEQ MSD161 SUBQ.W #1, (A1) ; riporto MSD161: MOVE.W D0, 2(A1) MOVE.W 4(A0), D0 ; il precedente resto in D0.H DIVS.W D1, D0 BPL MSD162 ;BEQ MSD162 SUBQ.W #1, 2(A1) ; riporto MSD162: MOVE.W D0, 4(A1) MOVE.W 6(A0), D0 ; il precedente resto in D0.H DIVS.W D1, D0 ; LSW, no riporto BPL MSD163 ;BEQ MSD163 SUBQ.W #1, 4(A1) ; riporto MSD163: MOVE.W D0, 6(A1) SWAP.W D0 ; sposta il resto in D0.L MOVE.W D0, D1 MOVEM.L (SP)+, D0 ; ripr. il registro RTS ;------------------------------------------------------------; ; NOME ; ; MSDDIV divisione interi con segno (FIX) ; ; DESCRIZIONE ; ; Effettua la divisione tra interi con segno, dividendo ; ; di 64 bit e divisore di 32 bit, fornendo quoziente e ; ; resto. ; ; INTERFACCIA ; ; D0 input dividendo (parte meno significativa) ; ; D1 input dividendo (parte piu` significativa) ; ; D2 input divisore ; ; D0 output resto ; ; D1 output quoziente ; ; C, X output = 1 se overflow ; ; USA ; ; Subr: DDIV ; ; ; ; TEST IT WITH C ; ; #include ; ; ; ; void main() ; ; { ; ; _int64 a=0x36543210efefefef; ; ; _int64 b=0x0000000074321234; ; ; _int64 c=a/b; ; ; unsigned int lo,hi; ; ; lo=c; ; ; hi=c>>32; ; ; printf("%x %x\n",hi,lo); ; ; } ; ;------------------------------------------------------------; SIGN EQU $80000000 CSIGNB EQU 30 MSDDIV: MOVEM.L D2-D4, -(SP) MOVE.L D1, D4 ASR.L #1, D4 ; copia il segno su b30 BPL SDV1 ; salta se dividendo positivo NEG.L D0 NEGX.L D1 SDV1: TST.L D2 BPL SDV2 ; salta divisore positivo EORI.L #SIGN, D4 ; sign(a)*sign(b) come segno NEG.L D2 ; divisore negativo SDV2: ;la seguente tecnica segnala erroneamente un overflow ;quando il quoziente raggiunge l'estremo negativo ;(parallelamente a quanto succede con DIVS.W) ;(ver. chiara: puo' essere ottimizzata (basta un CMP)) ;CMP.L D2, D1 ;BHS SDV5 ; overflow oltre la 32° cifra ;ASL.L #1, D0 ;ROXL.L #1, D1 ;CMP.L D2, D1 ;BHS SDV5 ; overflow sulla 32° cifra ;ROXR.L #1, D1 ; ripr. D1 e D0 ;ROXR.L #1, D0 ;(ver. ottimizzata) ASL.L #1, D0 ROXL.L #1, D1 BCS SDV5 ; overflow (il divisore e' <= 2^32) CMP.L D2, D1 BHS SDV5 ; overflow oltre la 31° cifra ROXR.L #1, D1 ; ripr. D1 e D0 ROXR.L #1, D0 BSR DDIV ; divisione ;BCS SDV5 ; salta se overflow (non serve +) BTST.L #CSIGNB, D4 ; resto stesso segno dividendo BEQ SDV3 ; salta se positivo NEG.L D0 SDV3: TST.L D4 BPL SDV4 ; salta se quoziente positivo NEG.L D1 ; quoziente < 0 SDV4: MOVE.W #00, CCR MOVEM.L (SP)+, D2-D4 ; ripr. registri RTS SDV5: MOVE.W #17, CCR ; overflow C, X=1 MOVEM.L (SP)+, D2-D4 ; ripr. registri (D0/D1 esclusi) RTS ;------------------------------------------------------------; ; NOME ; ; DDIV subroutine divisione interi senza segno (FIX) ; ; DESCRIZIONE ; ; Effettua la divisione tra interi senza segno, dividendo ; ; di 64 bit e divisore di 31 bit (o pari a 2^31), fornendo ; ; quoziente e resto. ; ; INTERFACCIA ; ; D0 input dividendo (parte meno significativa) ; ; D1 input dividendo (parte piu` significativa) ; ; D2 input divisore ; ; D0 output resto ; ; D1 output quoziente ; ; C, X output = 1 se overflow ; ; USA ; ; -- ; ;------------------------------------------------------------; DDIV: MOVEM.L D3, -(SP) ; salva il registro CMP.L D2, D1 ; (D1) >= (D2) ? BHS DDV1 ; si`, allora overflow MOVEQ.L #31, D3 ; contatore posto a 32-1 ASL.L #1, D0 ; shift rk parte meno sign. DDV4: ROXL.L #1, D1 ; shift rk parte piu` sign. CMP.L D2, D1 ; rk * 2 > 2^n * d? BLO DDV2 ; salta se q(k-1)=0 r(k-1)=r(k) SUB.L D2, D1 ; calcola r(k-1) MOVE.W #17, CCR ; set C, X=1 ovvero q(k-1)=1 BRA DDV3 DDV2: MOVE.W #00, CCR ; set C, X=0 ovvero q(k-1)=0 DDV3: ROXL.L #1, D0 ; shift r(k-1) parte meno sign. DBRA D3, DDV4 MOVE.W #00, CCR ; ris. in D1, C, X=0 BRA DDV5 DDV1: MOVE.W #17, CCR ; overflow C, X=1 DDV5: EXG.L D0, D1 ; D0 <-> D1 MOVEM.L (SP)+, D3 ; ripristina registro RTS ;------------------------------------------------------------; ; NOME ; ; MDMUL moltiplicazione 32 bit senza segno ; ; DESCRIZIONE ; ; Subroutine di moltiplicazione di due numeri di 32 bit ; ; senza segno. Metodo di scomposizione degli operandi in ; ; due parti da 16 bit. ; ; INTERFACCIA ; ; D0 input moltiplicando ; ; D1 input moltiplicatore ; ; D2 output prodotto (parte meno significativa) ; ; D3 output prodotto (parte piu` significativa) ; ; USA ; ; -- ; ;------------------------------------------------------------; MDMUL: MOVEM.L D5/D6, -(SP) MOVE.W D0, D2 MULU.W D1, D2 MOVE.L D0, D3 MOVE.L D1, D5 SWAP.W D3 SWAP.W D5 MULU.W D5, D3 MULU.W D0, D5 BSR DMUL1 MOVE.L D0, D5 SWAP D5 MULU.W D1, D5 BSR DMUL1 MOVEM.L (SP)+, D5/D6 RTS MDMUL1: MOVE.L D5, D6 CLR.W D6 SWAP.W D6 SWAP.W D5 CLR.W D5 ADD.L D5, D2 ADDX.L D6, D3 RTS