P I C   -   A P P U N T I    D I    U T I L I Z Z O

(avvertenze)

[Indice principale]


DIVISIONE BINARIA A 8 BIT (intera senza segno)

La divisione consiste nel determinare quante volte un numero (il divisore) e' contenuto in un altro (il dividendo), il risultato e' detto quoziente. Un modo semplice per effettuare una divisione e' contare quante volte si riesce a sottrarre il divisore dal dividendo senza ottenere un valore negativo. Per esempio nella divisione 80/7 il 7 si riesce a sottrarre per 11 volte, poi rimane un valore piu' piccolo di 7 detto resto (nel nostro caso 3). Tuttavia se il dividendo e' un numero molto grande e il divisore e' un numero molto piccolo (ad esempio 1), questa procedura e' estremamente poco efficiente in quanto puo' richiedere un numero elevatissimo di sottrazioni (infatti 255/1 richiederebbe ben 255 sottrazioni). Un algoritmo piu' efficiente e' invece quello di riprodurre a livello binario lo stesso tipo di procedimento che si mette in atto eseguendo una normale divisione decimale a mano su un foglio di carta. Questo consiste nell'allineare le cifre del divisore a sinistra sotto il dividendo, effettuare una sottrazione per vedere se il divisore e' maggiore del dividendo, segnarsi uno 0 nel caso in cui lo sia e un 1 nel caso in cui non lo sia, dopo di che shiftare il divisore a destra di una posizione e ripetere l'operazione. Gli 0 e gli 1 che si ottengono come risultato della sottrazione si aggiungono mano a mano sulla destra del quoziente facendolo scorrere verso sinistra. Dopo n+1 cicli (dove n e' il numero di spostamenti effettuati all'inizio per allineare il divisore a sinistra) nel quoziente si trova il risultato della divisione, e nel dividendo risulta presente il resto (0 se il divisore e' un sottomultiplo intero del dividendo). Con questo procedimento verranno eseguite al massimo n+1 sottrazioni, cioe' 8 nel caso peggiore. La subroutine seguente utilizza questo sistema, dapprima vi e' un ciclo di allineamento a sinistra del divisore (evidenziato in blu), seguito da quello delle n+1 sottrazioni. E' inutile ricordare che una divisione per zero e' un' operazione impossibile e va assolutamente evitata. Nel caso di divisore=0 si rimane infatti bloccati all'infinito nel loop di allineamento a sinistra in quanto il bit 7 di VL non diventara' mai 1.

;-----------------------------------------------------
; Divisione 8 bit intera senza segno
; Operazione: QL=DL/VL  DL=resto
; IN:  DL=dividendo  VL=divisore
; OUT: QL=quoziente  DL=resto
; CL = contatore di ciclo
;-----------------------------------------------------
DIV8        CLRF        QL          ;Azzera quoziente
            CLRF        CL          ;Azzera contatore di ciclo
DIV8_2     
INCF        CL,F        ;CL=CL+1
            BTFSC       VL,7        ;Se bit 7 di VL=0 skip
            GOTO        DIV8_3      ;altrimenti vai a DIV8_3
            BCF         STATUS,C    ;Azzera carry
            RLF         VL,F        ;Ruota divisore a sinistra
            GOTO        DIV8_2      ;Vai a DIV8_2
DIV8_3      MOVF        VL,W        ;W=divisore
            SUBWF       DL,W        ;W=dividendo-divisore
            RLF         QL,F        ;Ruota carry a destra nel quoziente
            BTFSC       QL,0        ;Se overflow skip
            MOVWF       DL          ;altrimenti dividendo=W
            BCF         STATUS,C    ;Azzera carry
            RRF         VL,F        ;Ruota divisore a destra
            DECFSZ      CL,F        ;Decrementa contat.ciclo, skip se 0
            GOTO        DIV8_3      ;altrimenti vai a DIV8_3
            RETURN                  ;Fine subroutine
;-----------------------------------------------------

divisione 8 bit senza segno


DIVISIONE BINARIA A 16 BIT (intera senza segno)

La divisione a 16 bit sfrutta lo stesso identico principio di quella a 8 bit. La difficolta' in piu' sta nel fatto che per ogni valore occorre usare una coppia di registri da 8 bit anziche' uno solo.  Queste coppie sono chiamate QH:QL per il quoziente, VH:VL per il divisore ecc... L'unico registro a 8 bit singolo che rimane e' il contatore di ciclo per le sottrazioni, infatti al massimo verranno eseguite 16 sottrazioni. La sottrazione a 16 bit (con regolazione corretta del flag C) e' stata spostata in un'apposita subroutine perche' piuttosto complessa. Con questo algoritmo la sottrazione tra dividendo e divisore altera il valore del dividendo, per questo motivo, nel caso in cui si verifichi un overflow (dividendo minore del divisore) e' successivamente necessario ripristinare il valore del dividendo risommandolo con il divisore, questa operazione e' detta restoring. Nella divisione a 8 bit non si effettua nessun restoring in quanto il valore effettivo del dividendo  non viene alterato dalla sottrazione, e il nuovo valore viene conservato in W e scritto nel dividendo solo in caso in cui non vi sia overflow.

;-----------------------------------------------------
; Divisione 16 bit intera senza segno
; Operazione: QH:QL=DH:DL/VH:VL  DH:DL=resto
; IN:  DH:DL=dividendo  VH:VL=divisore
; OUT: QH:QL=quoziente  DH:DL=resto
; CL = contatore di ciclo  FL = salvataggio flag
;-----------------------------------------------------
DIV16       CLRF        QH          ;Azzera quoziente
            CLRF        QL
            CLRF        CL          ;Azzera contatore di ciclo
DIV16_2    
INCF        CL,F        ;CL=CL+1
            BTFSC       VH,7        ;Se bit 7 di VH=0 skip
            GOTO        DIV16_3     ;altrimenti vai a DIV16_3
            BCF         STATUS,C    ;Azzera carry
            RLF         VL,F        ;Ruota divisore a sinistra
            RLF         VH,F
            GOTO        DIV16_2     ;Vai a DIV16_2
DIV16_3     CALL        SUB16       ;Chiama sottraz. DH:DL-VH:VL
            RLF         QL,F        ;Ruota carry a destra nel quoziente
            RLF         QH,F
            BTFSS       QL,0        ;Se non overflow skip
            CALL        RESTORING   ;altrimenti chiama somma DH:DL+VH:VL
            BCF         STATUS,C    ;Azzera carry
            RRF         VH,F        ;Ruota divisore a destra
            RRF         VL,F
            DECFSZ      CL,F        ;Decrementa contat.ciclo, skip se 0
            GOTO        DIV16_3     ;altrimenti vai a DIV16_3
            RETURN                  ;Fine subroutine
;-----------------------------------------------------
; DH:DL = DH:DL - VH:VL  (con regolazione corretta flag C)
; FL = salvataggio intermedio flag C
;-----------------------------------------------------
SUB16       BSF         FL,4        ;Imposta a 1 il bit 4 di FL
            MOVF        VL,W        ;W=parte bassa divisore
            SUBWF       DL,F        ;ao sottrae a parte bassa dividendo
            BTFSC       STATUS,C    ;Se overflow skip
            GOTO        SUB16_2     ;altrimenti vai a SUB16_2
            MOVLW       1
            SUBWF       DH,F        ;Sottrae 1 a parte alta dividendo
            SWAPF       STATUS,W    ;Salva i flag in FL
            MOVWF       FL
SUB16_2     MOVF        VH,W        ;W=parte alta divisore
            SUBWF       DH,F        ;la sottrae a parte alta dividendo
            BTFSS       FL,4        ;Controlla bit 4 di FL, se 1 skip
            BCF         STATUS,C    ;altrimenti resetta carry
            RETURN
;-----------------------------------------------------
; DH:DL = DH:DL + VH:VL  (senza regolazione flag C)
;-----------------------------------------------------
RESTORING   MOVF        VL,W        ;W=parte bassa divisore
            ADDWF       DL,F        ;la somma a parte bassa dividendo
            BTFSC       STATUS,C    ;Se non overflow skip
            INCF        DH,F        ;altrimenti incrementa parte alta dividendo
            MOVF        VH,W        ;W=parte alta divisore
            ADDWF       DH,F        ;la somma a parte alta dividendo
            RETURN
;-----------------------------------------------------




By Claudio Fin - Pagina creata nel febbraio 2004 - Ultimo aggiornamento 27-3-2004