In microprocessori dove la divisione e' parte delle istruzioni la cosa e molto semplice.
Il dividendo e' caricato in un registro (spesso specializzato), il divisore in un'altro
registro,il risultato ed il resto della divisione finiscono in altri registri ancora.
Il tutto risulta estremamente semplificato. 4 righe di programma e il gioco e' fatto.
Ad esempio per i processori della INTEL tipo 80x86 e sucessivi (compreso il PENTIUM)
questo e' il sorgente per una divisione con un dividendo da 32 bit ed un divisore a 16 Bit
80x86
MOV DX,10 ; In DX i 16 Bit alti
MOV AX,100 ; In AX i 16 Bit bassi
MOV BX,1000 ; In BX il divisore
DIV BX ; Esegui la divisione
Tutto qua. A questo punto troveremo il risultato in AX ed il resto in DX. Come potete vedere
e' breve, semplice, conciso. Diverso e' il discorso quando si usano processori che non hanno la
divisione tra le istruzioni. La faccenda si complica e il programma si allunga. Non dobbiamo mai
dimenticare che un processore e' in ultima analisi solo un grosso stupidone incapace di fare
alcunche' se non istruito con precisione. Di seguito vediamo una routine di divisione per Z80
sempre con dividendo da 32 Bit e divisore da 16 Bit esattamente come sopra.
Z80
DE = Contiene i 16 bit alti del dividendo
HL = Contiene i 16 bit bassi del dividendo
BC = Contiene i 16 bit del divisore
-----------------------------------------
DE = Contiene i 16 bit alti del risultato
HL = Contiene i 16 bit bassi del risultato
BC = Contiene il resto
; inizializzazione dei registri
LD DE,0AAAH ; byte alto del dividendo
LD HL,0AAAAH ; byte basso del dividendo
LD BC,0CH ; divisore
CALL DIVIDE ; esegui la divisione
JP 100H ; ritorna a capo
DIVIDE:
LD IX,DIVIDENDO ; punta ai 32 bit del dividendo
LD (IX+0),D ; carico (D) nel (MSB)
LD (IX+1),E ; proseguo con i byte decrescenti
LD (IX+2),H ; proseguo con i byte decrescent
LD (IX+3),L ; carico (L) nel (LSB)
LD H,B ; --------------------------
LD L,C ;
LD B,16 ; In questa parte determino di
LD D,16 ; quanti loop e' necessaria la
PK1: LD A,D ; divisione in base al valore
CP H ; del divisore in proporzione
JR NC, PK2 ; al dividendo.
JP START ;
PK2: LD E,B ; Sono necessari 2 diversi loop.
LD B,4 ; uno per la divisione ed uno
PK3: SLA L ; per estrarre il resto dalla
RL H ; coda del dividendo.
INC E ; aumentando il primo
DEC D ; deve diminuire il secondo
DJNZ PK3 ;
LD B,E ;
JP PK1 ; --------------------------
START:
CALL RESET_RISULTATO ; azzera i 4 byte del risultato
PK4: LD C,0 ; (C) e' usato come flag
CALL SHIFT_DIVIDENDO ; shift a sinistra del dividendo
CALL SHIFT_RISULTATO ; shift a sinistra del risultato
CALL COMP_SUB ; compara e sottrai se necessario
DJNZ PK4 ; -------------------------------
LD B,D ; carica in (B) il totale dei loop
LD D,(IY+0) ; carica in (D) il (MSB)
LD E,(IY+1) ; del risultato
LD H,(IY+2) ; e carica in (L) il (LSB)
LD L,(IY+3) ;
PK5: SLA (IX+1) ; eseguo uno shift a sinistra
RL (IX+0) ; sui 2 byte del resto
RL (IX+3) ; e li deposito momentaneamente
RL (IX+2) ; su 2 byte di appoggio
DJNZ PK5 ;
LD B,(IX+2) ; in (B) il byte alto del resto
LD C,(IX+3) ; in (C) il byte basso del resto
RET ; --------------------------------
SHIFT_DIVIDENDO:
LD IX,DIVIDENDO ; --------------------
SLA (IX+3) ; rotazione a sinistra dei
RL (IX+2) ; 4 byte del risultato con
RL (IX+1) ; riporto del carry nel
RL (IX+0) ; bit 0 del byte che segue
RL C ; Se c'e' carry e' posto in C
RET ; --------------------
SHIFT_RISULTATO:
LD IY,RISULTATO ; --------------------
SLA (IY+3) ; rotazione a sinistra dei
RL (IY+2) ; 4 byte del risultato con
RL (IY+1) ; riporto del carry nel
RL (IY+0) ; bit 0 del byte che segue
RET ; --------------------
RESET_RISULTATO:
LD IY,RISULTATO ; --------------------
LD (IY+0),0 ;
LD (IY+1),0 ; azzera i 4 byte
LD (IY+2),0 ; del risultato
LD (IY+3),0 ;
RET ; --------------------
COMP_SUB:
XOR A ; --------------------
OR C ;
JR NZ, PK7 ; confronto il byte
LD A,H ; alto del divisore
CP (IX+0) ; con il byte alto del dividendo
JR Z, PK6 ; se e' piu' grande ritorno
JR C, PK7 ; se e' uguale
RET ; --------------------
PK6: LD A,L ; confronto il byte
CP (IX+1) ; basso del divisore
JR Z, PK7 ; con il byte basso del dividendo
JR C, PK7 ; se e' piu' grande ritorno
RET ;
PK7: LD A,(IX+1) ; essendo il divisore piu'
SUB L ; piccolo del dividendo
LD (IX+1),A ; lo sottraggo e.....
LD A,(IX+0) ;
SBC H ;
LD (IX+0),A ;
LD A,(IY+3) ;--------------------------
ADD A,1 ;
LD (IY+3),A ;
LD A,(IY+2) ; incremento i 4 byte
ADC A,0 ; del risultato
LD (IY+2),A ;
LD A,(IY+1) ;
ADC A,0 ;
LD (IY+1),A ;
LD A,(IY+0) ;
ADC A,0 ;
LD (IY+0),A ;---------------------------
RET
; ------------------- AREA DATI IN RAM --------------
DIVIDENDO: DB 0,0,0,0
RISULTATO: DB 0,0,0,0
; ------------------------------------------------------
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.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.
ST6
Questa divisione richiede che il dividendo e il divisore siano posti in memoria. al ritorno
dalla divisione l'intero si trovera' su 4 byte nel risultato ed il resto su 2 byte si trovera'
al posto del divisore.
; sezione variabili (084H ..0BFH)
DVD_1 .DEF 084H ; 1 byte msb dividendo
DVD_2 .DEF 085H ; 2 byte
DVD_3 .DEF 086H ; 3 byte
DVD_4 .DEF 087H ; 4 byte lsb dividendo
DVS_1 .DEF 088H ; 1 byte msb divisore
DVS_2 .DEF 089H ; 2 byte lsb divisore
RESULT_1 .DEF 08AH ; 1 byte msb risultato
RESULT_2 .DEF 08BH ; 2 byte
RESULT_3 .DEF 08CH ; 3 byte
RESULT_4 .DEF 08DH ; 4 byte lsb risultato
FLAG .DEF 08EH ; variabile ad uso flag
;---------------------------------------------------
CALL DIVISIONE ; routine di divisione
JP 0880H ; ritorna da capo
DIVISIONE:
LDI V,16 ;-----------------------------
LDI Y,16 ;
SK1: LD A,DVD_1 ;
CP A,DVS_1 ;
JRNC SK2 ; In questa prima parte di programma
JP BEGIN ; adatto il numero dei loop in base
SK2: LDI W,4 ; alla proporzione tra dividendo e
SK3: INC V ; divisore. Il loop parte inizialmente
DEC Y ; da 16 e viene incrementato di 4 ogni
LD A,DVS_2 ; volta che non soddisfa la richiesta
SLA A ; E' necessario trovare il valore per
LD DVS_2,A ; 2 loop. Il primo (V) esegue lo shift
LD A,DVS_1 ; sul dividendo ed il risultato mentre
RLC A ; il secondo (Y) al termine della
LD DVS_1,A ; divisione esegue lo shift sul
DEC W ; dividendo per estrarre il resto
LD A,W ;
CPI A,0 ;
JRZ SK4 ;
JP SK3 ;
SK4: JP SK1 ;-----------------------------
BEGIN:
CALL CLEAN_RESULT ; azzera le variabili del risultato
SK5: RES 1,FLAG ; resetto il bit 1 dei flag
CALL SHIFT_DVD ; shift a sinistra del dividendo
CALL SHIFT_RST ; shift a sinistra del risultato
CALL COMP_SUB ; comparazione e sottrazione
DEC V ;
LD A,V ;
CPI A,0 ; ripeti fino a che (V)=0
JRNZ SK5 ;-----------------------------
SK6: LD A,DVD_2 ;-----------------------------
SLA A ;
LD DVD_2,A ;
LD A,DVD_1 ; Terminata la divisione, il resto
RLC A ; si trova nei due byte alti del
LD DVD_1,A ; dividendo. Lo estraggo tramite
LD A,DVS_2 ; shift e lo passo ai 2 byte del
RLC A ; divisore con un numero di loop
LD DVS_2,A ; caricato su (Y) determinato
LD A,DVS_1 ; dalla proporzione tra dividendo
RLC A ; e divisore
LD DVS_1,A ;
DEC Y ;
LD A,Y ;
CPI A,0 ;
JRZ SK7 ;
JP SK6 ;-----------------------------
SK7: RET
SHIFT_DVD:
LD A,DVD_4 ; ---------------------------
SLA A ;
LD DVD_4,A ;
LD A,DVD_3 ;
RLC A ; Eseguo lo shif a sinistra
LD DVD_3,A ; dei 4 byte del dividendo
LD A,DVD_2 ;
RLC A ;
LD DVD_2,A ; Se c'e ulteriore riporto
LD A,DVD_1 ; dal (MSB)
RLC A ; setto il bit 1 dei flag
LD DVD_1,A ;
JRNC SK8 ;
SET 1,FLAG ; ---------------------------
SK8: RET
SHIFT_RST:
LD A,RESULT_4 ; ---------------------------
SLA A ;
LD RESULT_4,A ; Eseguo lo shif a sinistra
LD A,RESULT_3 ; dei 4 byte del risultato
RLC A ;
LD RESULT_3,A ;
LD A,RESULT_2 ;
RLC A ;
LD RESULT_2,A ;
LD A,RESULT_1 ;
RLC A ;
LD RESULT_1,A ; ---------------------------
RET
COMP_SUB:
JRS 1,FLAG,SX2 ; Se e' alto il bit salta
LD A,DVS_1 ;
CP A,DVD_1 ; Confronto tra dividendo
JRZ SX1 ; e divisore
JRC SX2 ;
RET
SX1: LD A,DVS_2 ; finche' il divisore
CP A,DVD_2 ; e' maggiore,ritorna
JRZ SX2 ;
JRC SX2 ;
RET
SX2: LD A,DVD_2 ; ----------------------------
SUB A,DVS_2 ;
LD DVD_2,A ; Sottraggo il divisore
JRNC SX3 ; al dividendo
DEC DVD_1 ; e....
SX3: LD A,DVD_1 ;
SUB A,DVS_1 ;
LD DVD_1,A ; ----------------------------
LDI W,4 ; ----------------------------
LDI X,RESULT_4 ;
SX4: LD A,(X) ;
ADDI A,1 ;
LD (X),A ;
JRNC SX5 ;
DEC X ; Incremento il risultato
DEC W ;
LD A,W ;
CPI A,0 ;
JRNZ SX4 ; ----------------------------
SX5: RET
CLEAN_RESULT:
LDI W,4 ; ----------------------------
LDI X,RESULT_1 ;
SX6: CLR A ;
LD (X),A ; Azzera le variabili
INC X ; che conterranno
DEC W ; il risultato
LD A,W ;
CPI A,0 ;
JRNZ SX6 ; Azzera la variabile dei flag
CLR FLAG ; ----------------------------
RET
|