Numeri a 32bit - Assembly8086

di il
14 risposte

Numeri a 32bit - Assembly8086

Ciao a tutti!
Sono nuova della programmazione in Assembly e il secondo assegnamento di un programma che devo svolgere mi chiede di prendere dall'utente due numeri A e B compresi tra 0 e 64000 e di restituire in output il numero di 1 compresi nell'intervallo tra A e B...
Per essere più chiari, se l'utente mi inserisce 1 e 3 io devo stampare 4, ovvero nella sequenza 001 - 010 - 011 sono presenti 4 uno...

Il programma è ormai a buon punto, riesco a prendere i due numeri come char e convertirli in interi poi scorro tutto l'intervallo e analizzo ogni numero con divisioni successive per 2...se il resto è uno incremento BX che sto tenendo come contatore degli 1 incontrati...

E' qui che mi sorge il problema...nel range che mi viene dato posso incontrare troppi 1 per inserirli solo nel registro BX a 16bit e devo passare ad utilizzare numeri a 32bit...
Che non ho la più pallida idea di come trattare...indizi su come poter procedere?!
Dovrei praticamente unire due registri a 16bit e salvare in entrambi il mio risultato, nella funzione che utilizzo ho ancora libero il registro CX ma non ho idea di come fare a dirgli che se BX è completamente pieno di passare a incrementare CX e tenerli uniti...
Stavo pensando di fare un controllo e se BX raggiunge 65536 (2^16) di iniziare ad incrementare CX e sommare successivamente CX e BX ma mi sembra molto macchinosa la cosa...oltretutto la somma tra BX e CX sforerebbe nuovamente i 16bit e io mi troverei punto a capo...

Oltre a non sapere dove salvarlo, non so nemmeno poi come stamparlo ma direi di fare un passo per volta...

Scusate il papiro, è che ci sto sclerando da una settimana e vorrei riuscire a consegnare l'assegnamento lunedì

14 Risposte

  • Re: Numeri a 32bit - Assembly8086

    Va bene la prima parte (se superi 65535 incrementi il registro CX) ma non sommi nulla ...

    Alla fine i due registri conterranno la parte alta e la parte bassa del numero a 32 bit.
  • Re: Numeri a 32bit - Assembly8086

    Mmm...ma come è possibile?! Non riesco a capire...
    Io una volta che BX > 65535 lascerei stare BX e incrementerei solo CX ma se BX è la parte bassa e CX la alta la cosa non mi torna...BX conterebbe 16 bit a 1 e CX al primo incremento per dire contiene 15 bit a 0 e il più basso a 1 ma se io li unisco come parte alta e parte bassa ottengo un numero con 17 bit a 1 e non il successivo che dovrebbe invece avere si il 17esimo bit a 1 ma seguito da 16 zeri (il registro BX)
  • Re: Numeri a 32bit - Assembly8086

    Naturalmente devi azzerare BX ogni volta che incrementi CX ... è un normalissimo "riporto" ...

    Basta seguire queste semplici regole

    incrementa bx
    se bx == 0 allora incrementa cx
  • Re: Numeri a 32bit - Assembly8086

    Il fatto è che non ne ho mai usati e mi è un attimo complicato capire il meccanismo anche se si tratta di un normalissimo riporto...
    Se non ho capito male incrementando CX la prima volta azzero BX però i cicli successivi torno ad incrementare BX lasciando invariato CX giusto?!
    In questo modo effettivamente dovrei riuscire ad ottenere CX come parte alta e BX come parte bassa...guarderò meglio domani come implementarlo con le istruzioni corrette perchè al momento sto raggiungendo la fusione...

    Se il mio primo ragionamento è corretto ora arriverei ad avere quindi un numero salvato di fila in CX e BX e arrivo al problema della stampa di tale numero...
    Io ho una funzione per stampare un numero tramite sempre divisioni successive e utilizzando lo stack, quindi inserendo prima nello stack il resto delle divisioni per 10 e poi ritirarli fuori mano a mano che li stampavo a video...il fatto è che mettevo nel registro AX il valore di BX, e quindi effettuavo su questo il ciclo di divisioni per 10...
    Ora avendo anche il registro CX la stampa deve per forza cambiare...potrebbe essere corretto fare le divisioni prima su BX, mettendo i valori nello stack, e successivamente effettuare lo stesso procedimento su CX?! Poi essendo lo stack una LIFO con la POP se non ho commesso errori estraggo prima i "resti" dati da CX e poi quelli da BX in modo da stampare poi il numero dell'ordine corretto...

    Scusa nuovamente la rottura, ci sto ragionando su di getto al momento e volevo sapere se teoricamente sono sulla via corretta prima di procedere a scrivere codice...

    EDIT: ho visto ora le ultime due righe! Grazie mille! =D Ora è più chiara la cosa...io continuo a incrementare BX e quando aggiungo l' "uno di troppo" comincio a incrementare CX! Non ci ero proprio arrivata!
  • Re: Numeri a 32bit - Assembly8086

    Mari91 ha scritto:


    Se non ho capito male incrementando CX la prima volta azzero BX però i cicli successivi torno ad incrementare BX lasciando invariato CX giusto?!
    Giusto ... come ti dicevo, per ogni incremento devi eseguire

    incrementa bx
    se bx == 0 allora incrementa cx
    potrebbe essere corretto fare le divisioni prima su BX, mettendo i valori nello stack, e successivamente effettuare lo stesso procedimento su CX?!
    No ... devi fare la divisione per 10 di tutto il valore a 32 bit ... facci vedere il codice che utilizzi per questa fase ...

    A questo proposito la divisione (vedi http://css.csail.mit.edu/6.858/2011/readings/i386/DIV.htm ) può essere fatta usando DX:AX

    word DX:AX r/m16 AX DX

    La CPU considera già a 32 bit il gruppo DX:AX
  • Re: Numeri a 32bit - Assembly8086

    Ma come faccio ad inserire il valore che io ho nei registri CX e BX in DX:AX?!
    E poi io di solito chiamo DIV con: DIV numero per cui dividere
    E in questo modo mi divide quello che è presente in AX, mette ancora lì il risultato e in DX il resto...

    il codice che uso è fatto da due funzioni, queste:
    STAMPA_NUM1     PROC  NEAR
    		         
    				XOR DX,DX
    				XOR	CX,CX
    				MOV	AX,BX
    				XOR BX, BX
                    MOV BX, 10           ;imposta il divisore
    
    	MEMONUM1:   XOR  DX,DX             ;azzero DX
                    DIV  BX                ;divido per 10
                    PUSH DX				 ;salvo il resto
                    INC  CX                ;incremento il contatore cifre
                    CMP  AX, 0             ;devo ripetere?
                    JNZ MEMONUM1
    
                      
    	STAMPANUM1: POP DX                 ;riprende i numeri come LIFO
                    MOV AX, DX             ;metto in AX numero da stampare
                    CALL STAMPA_NUMERO     ;stampo
                    LOOP STAMPANUM1         ;ripeto
    
    				RET                    ;Ritorno alla procedura chiamante
    STAMPA_NUM1     ENDP
    
    STAMPA_NUMERO     PROC  NEAR
                      ADD   AL,'0'          ;La base da cui partire e' '0'
                      MOV   AH,W_CHR_TTY	;Servizio BIOS 'Write Char in TTY'
    				  
        			  INT   BIOS_VIDEO
                      RET                   ;Ritorno alla procedura chiamante
    STAMPA_NUMERO     ENDP
    Ovviamente qui come dicevo ho il mio numero di uno in BX (registro che non basta da solo) e lo copio in AX prima di cominciare le divisioni successive...
  • Re: Numeri a 32bit - Assembly8086

    Forse ci sono riuscita...modificare in questo modo la STAMPA_NUM1 mi fa stampare anche valori come 79000, 102mila e così...non ho ancora scoperto se abbia un limite anche questa o meno ma pare andare...

    Se hai voglia di buttarci un occhio che magari tu sei più esperto e vedi se c'è qualcosa che non va che a me sfugge mi fai un piacere altrimenti credo lo consegnerò così
    STAMPA_NUM1     PROC  NEAR
                   
    				MOV	DX,CX
    				MOV AX,BX
    				XOR BX, BX
    				XOR	CX,CX
                    MOV BX, 10           ;imposta il divisore
    
       MEMONUM1:   	
                    DIV  BX                ;divido per 10
                    PUSH DX             ;salvo il resto
    				XOR  DX,DX             ;azzero DX
                    INC  CX                ;incremento il contatore cifre
                    CMP  AX, 0             ;devo ripetere?
                    JNZ MEMONUM1
    
                     
       STAMPANUM1: 	POP DX                 ;riprende i numeri come LIFO
                    MOV AX, DX             ;metto in AX numero da stampare
                    CALL STAMPA_NUMERO     ;stampo
                    LOOP STAMPANUM1         ;ripeto
    
    				RET                    ;Ritorno alla procedura chiamante
    STAMPA_NUM1     ENDP
    EDIT: Come non detto...se inserisco i numeri 1 e 32750 mi da 245mila e qualcosa ma tra 1 e 32800 ancora sballa...temo sia il fatto che la divisione di DX:AX per 10 di numeri più grandi non ci stia in AX ma qui proprio non saprei come risolvere perchè la funzione DIV stessa che opera in quel modo e non posso dirgli di mettermi il risultato in più di un registro
  • Re: Numeri a 32bit - Assembly8086

    No, in quel codice ci sono degli errori ... ma prima di correggerli dimmi ... è possibile che il valore a 32 bit da dividere sia maggiore di 655359 (ovvero maggiore di 9FFFF) ?
  • Re: Numeri a 32bit - Assembly8086

    Se ho a disposizione 32bit posso avere 2^32 combinazioni no?! E sono di più di 655359...ma non capisco da dove venga questo valore
  • Re: Numeri a 32bit - Assembly8086

    Questo lo so ... ma ti chiedevo se ti bastasse un valore fino a 0009FFFF o dovessi gestire per forza valori fino a FFFFFFFF (ovvero poco più di 4 miliardi).

    Te lo chiedevo perché la DIV BX (se BX è 10) ti darà un errore di overflow se il valore di DX:AX è maggiore di 0009FFFF e quindi devi adottare del codice un po' più complesso per la divisione.
  • Re: Numeri a 32bit - Assembly8086

    Comunque ... lasciamo perdere quello che ti ho detto ed esaminiamo il caso generale ... questo codice penso che possa andare bene in tutti i casi ...
    
    STAMPA_NUM1     PROC NEAR
    
                    MOV DX,CX
                    MOV AX,BX
    
    ; Contatore cifre				
                    XOR SI,SI
    
    ; Divide    DX:AX / 00:0A
    ; Risultato DX:AX
    ; Resto     CX:BX
    
    LPDIV:
    				XOR CX,CX
    				MOV BX,10
    
    				CMP DX,BX
    				JB LB10
    				MOV CX,AX
    				MOV AX,DX
    				XOR DX,DX
    				DIV BX
    				XCHG AX,CX
    LB10:			
    				DIV BX
    				MOV BX,DX
    				MOV DX,CX
    
    				PUSH BX
    	
    				INC SI
    
    				CMP AX,0
    				JNZ LPDIV
    				CMP DX,0
    				JNZ LPDIV
    
    ; Visualizza numero da stack
    				
    				MOV CX,SI
    LPNUM:
    				POP AX
                    CALL STAMPA_NUMERO
    				LOOP LPNUM
    
                    RET
    STAMPA_NUM1     ENDP
    
    Fammi sapere se ti è servito ...
  • Re: Numeri a 32bit - Assembly8086

    Non capisco cosa faccia la parte di codice in LPDIV
    Cioè...che cosa fanno le singole righe ok ma non ne capisco lo scopo...perchè se la parte alta è minore di 10 non è necessario effettuare quella prima divisione per BX di cui non salvo nemmeno il resto

    Inoltre ho notato che il funzionamento della mia funzione e di questa in output danno lo stesso identico risultato

    Ah, e scusami ma non avevo proprio capito la domanda! Comunque, non lo so nemmeno io sinceramente...avrei probabilmente dovuto fare un codice anche in C per saperne la risposta visto che là non ho problemi di registri a 16bit da utilizzare in modo corretto...visto il fatto che se inserisco 1 e 32800 mi printa uno 0 direi che sono di più di quel numero che mi dicevi ma a questo punto credo lo consegnerò così e se non va bene mi farò spiegare cosa devo fare per sistemarlo direttamente...

    Grazie mille ancora!
  • Re: Numeri a 32bit - Assembly8086

    Mari91 ha scritto:


    Non capisco cosa faccia la parte di codice in LPDIV
    Per questo ti ho scritto quel commento

    ; Divide DX:AX / 00:0A
    ; Risultato DX:AX
    ; Resto CX:BX

    Serve a dividere un valore a 32 bit per 10 senza avere overflow di divisione e ottenendo anche il risultato e il resto a 32 bit. Ovviamente per il resto non ci sarà bisogno (perché sarà sempre compreso tra 0 e 9) e per questo utilizzi solamente la parte BX del resto.

    Il codice che hai scritto funziona fino a 655359 poi avrai un errore. Se va bene puoi usare il tuo codice.
  • Re: Numeri a 32bit - Assembly8086

    Aaahn, ho capito! Grazie mille! Nel programma metterò comunque la mia che visto che mi chiederà la spiegazione e sono più sicura su quel codice ma la tua la tengo comunque che in vista del terzo assegnamento tutto può tornare utile
    Grazie, grazie, grazie!!
Devi accedere o registrarti per scrivere nel forum
14 risposte