Esercizio Assembler

bibus12
Ciao a tutti come esercizio dovevo svolgere questa consegna in linguaggio c e assembly:


acquisire due numeri A e B compresi tra 0 e 64000 e calcolare la somma dei "2" presenti nei numeri compresi tra A e B.

quindi se scegliessi i numeri 2001 e 2003, la catena di numeri da prendere in considerazione sarebbe : 2001 , 2002 , 2003 (A e B compresi ). in questa catena il numero "2" ricorre 4 volte quindi la somma totale dei numeri "2" è 8.

In linguaggio c sono riuscita a svolgere l'esercizio e compila, ma in assembler ho molti problemi.
Secondo me dovrei creare un ciclo che comincia col numero A e finisce quando raggiunge il numero B compreso, all'interno dovrei impostare un altro ciclo che controlli il numero A (che sarà incrementato ogni volta dal primo ciclo) e incrementi di 1 un'altra variabile ogni volta che incontra un 2 . poi basterebbe moltiplicare questa variabile per 2 e stamparla

quello che ho scritto, escludendo la richiesta dei numeri è questo, ma non compila.. potreste aiutarmi???

MOV CX,0 ; lo uso come contatore dei "2"
LOOP1:
MOV AX,SI ; mette il numero da testare in AX
LOOP2:
XOR DX,DX ; il dividendo è in DX:AX (numero a 32 bit) DX è sempre ZERO
MOV BX,10 ; il divisore
DIV BX ; divide DX:AX per BX, quoziente in AX, resto in DX (il resto è la cifra decimale)
CMP DX,2 ; se il resto è '2' allora abbiamo la cifra '2' nel numero
JNE NOT_DUE
INC CX ; incremento il contatore dei 2
NOT_DUE:
CMP AX,0 ; se il quoziente è ZERO ho finito col numero attuale
JNE LOOP2
INC SI ; passa al prossimo numero
CMP SI,DI ; se SI è minore/uguale a DI continua
JBE LOOP1

Risposte
hamming_burst
Ciao,
forse ti complichi la vita.

Secondo me basta che fai:
- la differenza tra A e B: $C = |A-B|$ il valore assoluto non esiste mi pare in assembler, per evitarlo basta che espliciti che $A>B$
- $C$ lo dividi per 2, cioè uno schift logico a sinistra di una posizione (LSHL mi pare) ed avrai il numero che ti serve.

bibus12
il prof mi ha appena detto , sostanzialmente , che ho fatto un gran casino. l'algoritmo è testato su una piattaforma a 32 bit ma usando registri a 16 bit per i calcoli, e lui mi ha scritto che il programma deve andare sotto dosbox. quindi non riesco a capire che intende? che devo modificare? perdonate se le domande sono stupide ma abbiamo appena iniziato con assembler.

hamming_burst
ah scusa ho capito ora che devi fare, sorry in sto periodo capisco tutto il contrario di tutto :roll:

mostra il codice C così è più facile farti capire se ci son errori di interpretazione del tuo codice assembly. Il docente se sottolinea che utilizzerai dosbox vuol dire che sara assembly x86.

bibus12
Ahah nn c'è problema ! fai anche troppo ad aiutarmi! il codice che ho scritto in c è questo , a meno che io non abbia una forma di demenza precoce dovrebbe compilare.


#include
#define LIM_INF 0
#define LIM_SUP 64000
#define TARGET_DIGIT 2

int main(void) {
int A, B;
int contatore, curr;

//controllo dell'input
do { //ciclo che controlla se A < B
do { //ciclo che controlla se LIM_INF <= A <= LIM_SUP
printf("Inserisci estremo inferiore: ");
scanf("%d", &A);
} while (A < LIM_INF | A > LIM_SUP);

do { //ciclo che controlla se LIM_INF <= B <= LIM_SUP
printf("Inserisci estremo superiore: ");
scanf("%d", &B);
} while (B < LIM_INF || B > LIM_SUP);
} while (A > B);

for (contatore = 0; A <= B; A++)
//scompone il numero in cifre e cerca la cifra bersaglio (2 in questo caso)
for (curr = A; curr > 0; curr /= 10)
//ottengo cifra meno significativa e faccio quel che devo fare
if (curr % 10 == TARGET_DIGIT)
contatore++;

printf("Sono stati trovati %d cifre uguali a %d\n", contatore, TARGET_DIGIT);
printf("La somma delle %d occorrenze di %d e' %d\n", contatore, TARGET_DIGIT, TARGET_DIGIT * contatore);
return 0;
}

bibus12
addirittura per saltarci fuori con il codice in assembler, ho seguito in tutorial che mi spiegava come convertire il codice in c ed arrivare al codice macchina in assembler. sono venuti fuori dei nomi di variabili che sono un misto tra il cinese e l'aramaico. se il mio prof lo scoprisse sarei bandita a vita dal corso :S

bibus12
FORSE HO CAPITO DOVE HO SBAGLIATO
Per capire se un numero ha, al suo interno, uno o più 2, il modo più semplice è trattarlo come stringa e analizzare carattere per carattere.
Ad esempio, se A=19 e B=31 , si inizia da A e :
- il carattere 1 è uguale al carattere 2? NO
- il carattere 9 è uguale al carattere 2? NO
- fine numero... allora, lo converto in numero (da '19' a 19), lo incremento (da 19 a 20) e poi lo riconverto in stringa (da 20 a '20') e rinizio il ciclo
- il carattere 2 è uguale al carattere 2? SI, allora sommo 2 a una variabile contatore

quindi non è vero, come ho scritto nei commenti, che se un numero è divisibile per 2 il resto della divisione per 10 deve essere 2 (prendi numero=21 e lo vedi...). solo che ora non ho la più pallida idea di come scriverlo :(

hamming_burst
Ciao,
allora il programma di per se non è complicato.
Ma una questione da chiarire primea con "acquisire due numeri A e B" sicura che siano da linea di comando o da tastiera?

non è così immediato scrivere il codice assembly che fa tale operazione, c'è da abilitare lo standard input (operazioni di I/O) lo hai fatto nel tuo corso (attesa polling, DIN, ...) leggendo il tuo codice, sembra che sia semplicemente leggere da due rigistri due interi caricati da memoria, non introdotti da tastiera.

bibus12
purtroppo i numeri sono da introdurre da tastiera, l'ho appena chiesto al professore dato che mi è venuto il dubbio adesso. poi mi ha scritto di prendere in considerazione la seconda interpretazione del codice, e lasciare perdere la divisione per 10 come ho scritto nel codice.quindi sono da capo! :shock:

hamming_burst
Allora vediamo...
Facciamo a pezzi che è più semplice per me, e soprattutto per te, così comprendi cosa accade.

ti do le istruzioni di assembly Intel per lettura da tastiera semplice non ingrippiamoci in codici ed operandi complicati. Utilizziamo un'iterazione a polling su stdin. Ricorda che si lavora in Byte e non a parole.

TESTB   $3,  SIN
JNCB     READ

MOVB   Din, %al


questo è per un singolo byte, cioè una singola cifra.
Considera adesso che devi inserire un numero di massimo 5 cifre, ti servono 5 registri da 8 bit. Cioè un registro da 32 bit + una porzione di un secondo.
Dobbiamo perciò fare un LOOP di 5 iterazioni massime (per due cifre). Non sempre questo serve, possono esserci LOOP di 4,3,2,1 cifre. Per questo introduciamo un carattere ASCII che per noi vuol dire fine iterazione, cioè facciamo un LOOP di 6 iterazioni: 5 cifre massime + carattere speciale. Questo comporerà che ci possono essere $<5$ cifre + un carattere (immagina una stringa, qui invece è una array di registri).

Prova a pensare a come fare e che registri utilizzare, poi continuamo :-)

bibus12
per leggere e stampare una sola cifra io farei così :

DOSSEG
.MODEL SMALL .STACK 200H .DATA
CIFRA DB ? .CODE
BEGIN:
MOV AX,@DATA
MOV DS,AX ;stampa del prompt MOV DL,"?"
MOV AH,02H
INT 21H
;lettura della cifra MOV AH,01
INT 21H
SUB AL,30H
MOV CIFRA,AL ;ritorno a capo MOV DL,0AH MOV AH,02H
INT 21H
MOV DL,0DH MOV AH,02H
INT 21H
;stampa della cifra MOV DL,CIFRA ADD DL,30H
MOV AH,02H
INT 21H
MOV AX,4C00H INT 21H
END BEGIN

bibus12
ho provato a riscrivere il codice in modo da poter stampare a video un numero di 5 cifre.. spero di non avere scritto una cosa aberrante!


DOSSEG
.MODEL SMALL .STACK 200H .DATA
CIFRA DB ? .CODE
BEGIN:
MOV AX,@DATA
MOV DS,AX ;stampa del prompt MOV DL,"?"
MOV AH,02H
INT 21H
mov cx,5
accetta_cifra: MOV AH,01 ;lettura della cifra
INT 21H
SUB AL,30H
MOV CIFRA,AL ;ritorno a capo
MOV DL,0AH
MOV AH,02H
INT 21H
MOV DL,0DH
MOV AH,02H
INT 21H
MOV DL,CIFRA ;stampa della cifra
ADD DL,30H
MOV AH,02H
INT 21H
loop accetta_cifra
MOV AX,4C00H
INT 21H
END BEGIN

hamming_burst
ah devi utilizzare gli interrupt, ok.
Le istruzioni non le ho guardate tutte. Ma le operazioni che fai prima di ogni INT mi sembrano ok.
Forse per la tastiera non serve, ma se ricordo bene bisognerebbe abilitare il bit di interrupt (con STI). Ma guardando in rete sembra che non serva...

mi spiegheresti questo pezzo, che fa, penso inizializzi qualcosa...
DOSSEG
.MODEL SMALL .STACK 200H .DATA
CIFRA DB ? .CODE

bibus12
Questo pezzo ci è stato assegnato per iniziare la maggior parte dei programmi dal nostro professore. A lezione ci ha spiegato che un programma assembly che prevede l’uso di routine, assume la seguente struttura. cosa faccia nell'insieme questa struttura non lo so di preciso ma prendendo appunti in aula, il professore ha spiegato le diverse funzioni delle varie componenti generiche che ci ha detto a priori di utilizzare.
io in classe ho scritto che :


DOSSEG --> Ordina il segmento usando DOS standard, che è:

1) segmenti di "codice" (in ordine alfabetico)
2) segmenti di "dati" (in ordine alfabetico)
3) 'impilare' segmenti (di nuovo, in ordine alfabetico)


MODEL --> ha bisogno di essere utilizzato se si usano i segmenti semplificati.
In poche parole MODEL Seleziona il modello da utilizzare. Questo viene usato in modo che tale
codice può essere collegato con C, PASCAL, ADA, BASIC, ASSEMBLER oppure altri programmi, e
altre lingue con facilità.ci sono diversi tipi di model ( qui riporto solo la dfinizione che il prof ha dato del model small , presente nel codice )
SMALL: Code & Data hanno un segmento individuale, ma che deve essere meno di 64 KB ciascuno
Sia il codice che dati sono vicino.

STACK 200h -->

Dice al compilatore di creare una pila byte 200h al momento dell'esecuzione del
programma. MA la dimensione scelta per lo stack non cambia la dimensione
del file sul disco. se cambiando la 200h, per esempio,
metto 400h e poi ricompilo , Le dimensioni dei file sono comunque identiche.

tale costrutto potrebbe essere sostituito da :

: MyStack SEGMENT PARA PUBLIC STACK 'STACK'
: Db 200h dup (0)
: MyStack ENDS

MA, facendo in questo modo rende i vostri eseguibili vengono resi 512 byte più grandi.
se avessimo dovuto raddoppiare a 400h, l'eseguibile sarebbe stato altri 512 byte più grande.


DATI -->
segmento senza nome 'dati' e semplificato. Se si dovesse scrivere la dichiarazione di un
segmento di questo tipo in modo regolare, dovrei scrivere qualcosa del genere:

: MyData SEGMENT PARA PUBLIC 'DATA'
:
: ... ; qui metterò i miei dati
:
: MyData ENDS

'MyData' è il nome del segmento. "public" indica invece è appunto di tipo pubblico,
,e PARA è l'allineamento dell'inizio del segmento. 'DATA'
specifica il tipo di segmento. (PARA = si avvierà su di un indirizzo che è un multiplo
di 16 )


CODICE -->
Più o meno la stessa storia, ma questo riguarda il segmento di codice.
Potrebbe essere sostituito con:

- IN MODO MASM -
: 'CODE' mycode SEGMENT PARA PUBLIC
: ...
: Mycode ENDS

- IN MODO IDEAL -
: 'CODE' mycode SEGMENT PARA PUBLIC
: ...
: FINISCE mycode; la 'mycode' è opzionale in modalità IDEAL

hamming_burst
ok capito di cosa si tratta, grazie della spiegazione.
Utilizzi uno standard del mondo Microsoft, cosa che mi è un po' oscura nei dettagli. Conosco la stessa procedura però da legare al C e compilatore gcc (perciò flusso di lavoro di trasformazione del codice assembly in standard di chiamata C).

Per questa parte di inglobazione del codice, non so aiutarti, ma se il codice di input da tastiera è sempre quello che ti ha dato il docente utilizza quello senza tante modifiche, perciò passiamo direttamente a risolvere il problema dei $2$.
Oda fai così: riassumimi i registri dove sono contenuti le cifre dalla più dignificativa alla meno di A e B, non ho voglia di tradurlo (PS: utilizzi i tag CODE).

bibus12
non sono sparita :) sto cercando una illuminazione divina per fare questa parte del programma guardando vecchi temi svolti!

bibus12
eccomi! scusa per il ritardo ma oggi e ieri avevo due esami quindi ho dovuto abbandonare un attimo assembler!
ho mostrato il codice all'assistente del mio prof, e lui mi ha detto che la parte che gli ho mostrato ( quella del numero a 5 cifre da prendere in output) è giusta, ma lui la modificherebbe perché , mi ha detto , è unacosa che si può scrivere anche in sei righe -_-' per aiutarmi mi ha lasciato abusivamente un esercizio svolto da cui prendere spunto ( per la prima parte). secondo me però potrebbe essermi utile anche per abbozzare la seconda parte del testo (secondo la mia mente contorta)

;Definizione costanti
LUN_STRINGA 	EQU		05h
PAGINA			EQU		00h
HT  			EQU   	09h         ;tabulazione
LF  	 		EQU   	0Ah			;nuova linea
CR				EQU   	0Dh			;invio
;
BIOS_VIDEO		EQU		10H
SET_VIDEO_MODE 	EQU		00h 		;in AH
MODO_TESTO		EQU		03H			;in AL
;
SET_CURSOR		EQU		02h 		;in AH
W_CHR_TTY		EQU		0Eh  		;in AH
;
DOS				EQU		21H
CLEAR_BUFF      EQU     0CH
R_KEY_BUFF 		EQU		0AH
PRINT_STRING	EQU		09H
R_KEY_CHR_NE 	EQU		07h 



DSEG            SEGMENT PARA PUBLIC 'DATA'
TITOLO          DB    	'CORSO di CALCOLATORI ELETTRONICI$'
ISTRUZIONI      DB    	CR,LF,'Inserire due numeri compresi tra 0 e 64000, col primo minore del secondo$'
ISTRUZIONE1     DB    	CR,LF,'Inserire primo numero: $'
ISTRUZIONE2     DB    	CR,LF,'Inserire secondo numero: $'
TERMINE         DB    	CR,LF,LF,HT,'Un''altra iterazione? [S/N]$'
BUFFER          LABEL   BYTE
LUN_MAX         DB      LUN_STRINGA+01h
LETTI           DB      00h
STRINGA         DB      LUN_STRINGA+01h DUP (' '), '$'
NUM1            DW      00h
NUM2            DW      00h
DSEG            ENDS


STACKM          SEGMENT PARA STACK 'STACK'  ;Viene allocata una zona di
                DB      64 DUP('12345678')  ; memoria per lo Stack: in
STACKM          ENDS                        ; tutto 64*8 bytes.


                ASSUME CS:CSEG,DS:DSEG,SS:STACKM
CSEG            SEGMENT PARA PUBLIC 'CODE'


;---------------------------------------------------------------------;
;                   Corpo principale del programma                    ;
;---------------------------------------------------------------------;

MAIN              PROC  FAR
                  PUSH  DS              	;Istruzioni da lasciare SEMPRE
                  MOV   AX,00h          	; al principio dei programmi!
                  PUSH  AX              	;
                  CALL  INIZIALIZZAZIONE
CICLO_PRINCIPALE: CALL  PROMPT
				  CALL  LETTURA_DATI
				  CALL  ELABORAZIONE
                  CALL  TEST_FINALE
                  JNZ   CICLO_PRINCIPALE
                  RET                   	;Ritorno al Sistema Operativo
MAIN              ENDP

;---------------------------------------------------------------------;
;   Procedura per leggere un tasto e memorizzarlo in CODICE_TASTO     ;
;                                                                     ;
; PARAMETRI: il numero e' memorizzato in CODICE_TASTO                 ;
; REGISTRI UTILIZZATI: AX                                             ;
;---------------------------------------------------------------------;

LETTURA_DATI      PROC  NEAR
                  MOV   DX,OFFSET ISTRUZIONE1 ;Sceglie la stringa (DS:DX)
                  CALL  STAMPA_STRINGA  ; e la stampa.
                  MOV   AH,CLEAR_BUFF	;Servizio DOS 'Read Keyboard Char'
				  MOV   AL,R_KEY_BUFF
				  LEA   DX, BUFFER
                  INT   DOS             ;Memorizza il carattere alla loca-
				  
				  MOV   DL,LF
				  MOV   AH,02h
				  INT   DOS
	
	              MOV   [NUM1],00H
				  MOV   [NUM2],00H
				  XOR   AX,AX
				  XOR   BX,BX
				  XOR   CX,CX
				  XOR   DX,DX
				  
				  MOV 	SI, OFFSET STRINGA
NUMBER1:	      MOV   AX, [SI+BX]
				  XOR   AH,AH
				  CMP   AX,CR	  
			      JE    END1
				  SUB   AX,'0'
				  DEC   [LETTI]
				  MOV   CL,[LETTI]
MOL1:			  MOV   DX,10d  
				  CMP   CL,00h
				  JE    PASS1
				  MUL   DX
				  DEC   CL
				  JNZ   MOL1
PASS1:			  INC   BX
				  ADD   [NUM1],AX
				  XOR   AX, AX
				  JMP   NUMBER1
END1:	     	  

				  MOV   DL,LF
				  MOV   AH,02h
				  INT   DOS
				  


                  MOV   DX,OFFSET ISTRUZIONE2 ;Sceglie la stringa (DS:DX)
                  CALL  STAMPA_STRINGA  ; e la stampa.
                  MOV   AH,CLEAR_BUFF	;Servizio DOS 'Read Keyboard Char'
				  MOV   AL,R_KEY_BUFF
				  LEA   DX, BUFFER
                  INT   DOS             ;Memorizza il carattere alla loca-
				  
				  MOV   DL,LF
				  MOV   AH,02h
				  INT   DOS
	
				  XOR   AX,AX
				  XOR   BX,BX
				  XOR   CX,CX
				  XOR   DX,DX
				  
				  MOV 	SI, OFFSET STRINGA
NUMBER2:	      MOV   AX, [SI+BX]
				  XOR   AH,AH
				  CMP   AX,CR	  
			      JE    END2
				  SUB   AX,'0'
				  DEC   [LETTI]
				  MOV   CL,[LETTI]
MOL2:			  MOV   DX,10d  
				  CMP   CL,00h
				  JE    PASS2
				  MUL   DX
				  DEC   CL
				  JNZ   MOL2
PASS2:			  INC   BX
				  ADD   [NUM2],AX
				  XOR   AX, AX
				  JMP   NUMBER2
END2:	     	  

				  MOV   DL,LF
				  MOV   AH,02h
				  INT   DOS
				  

				  RET                   ;Ritorno alla procedura chiamante
LETTURA_DATI      ENDP


;---------------------------------------------------------------------;
;                   Procedura di inizializzazione                     ;
;                                                                     ;
; REGISTRI UTILIZZATI: AX, DX, DS                                     ;
;---------------------------------------------------------------------;

INIZIALIZZAZIONE  PROC  NEAR
                  MOV   AX,DSEG         	;Inizializzazione segmento dati
                  MOV   DS,AX           	; tramite il registro AX.

                  MOV   AH,SET_VIDEO_MODE  	;Servizio BIOS 'Set Video Mode':
                  MOV   AL,MODO_TESTO  		; modo testo 80 x 25, colori
                  INT   BIOS_VIDEO          ;

                  MOV   DX,0315h        	;Imposta riga (DH) e colonna (DL)
                  CALL  SPOSTA_CURSORE  	;Muove il cursore nella pos scelta

                  MOV   DX,OFFSET TITOLO 	;Sceglie la stringa (DS:DX)
                  CALL  STAMPA_STRINGA  	; e la stampa.

                  MOV   DX,0606h        	;Imposta riga (DH) e colonna (DL)
                  CALL  SPOSTA_CURSORE  	;Muove il cursore nella pos scelta
                  RET                   	;Ritorno alla procedura chiamante
INIZIALIZZAZIONE  ENDP


;---------------------------------------------------------------------;
;                   Procedura per l'elaborazione                      ;
;                                                                     ;
; REGISTRI UTILIZZATI: AX, DX, DS                                     ;
;---------------------------------------------------------------------;

ELABORAZIONE 	PROC NEAR
					
				XOR AX,AX
				XOR BX,BX
				XOR CX,CX
				XOR DX,DX
				
				MOV DX,[NUM1]					;inserisco in DX il numero inferiore
				MOV BX,[NUM2]					;inserisco in BX il numero superiore
				
				;MOV DX,0000000000000000b			;questi sono di prova
				;MOV BX,0000111100000110b
				
;attraverso dei confronti stabilisco qual'Ë il numero massimo di 1
;(siccome un numero composto da tutti e soli 1 nelle posizioni meno significative
;Ë sicuramente il numero pi˘ basso con quella quantit‡ di 1)
				
				MOV CX,1111111111111111b
				MOV AL,16d
				
PREPARAZIONE:	SHR CX,01h
				DEC AL
				CMP BX,CX
				JGE CAMBIA_CONF
				CMP AL,01d
				JNE PREPARAZIONE
				
;se necessario alzando il limite inferiore elimino tutti i numeri 
;che sicuramente hanno meno 1 del risultato trovato
				
CAMBIA_CONF:	CMP DX,CX
				JL CAMBIA_INF
				JMP PRE
CAMBIA_INF:		MOV DX,CX
				JMP PRE
				
;conto il numero di 1 di ogni dato e lo confronto con il precedente risultato
				
PRE:			MOV CH,AL
				JMP CONTA_BITS
				
PEZZA:			DEC CH
				MOV DX,[NUM1]
				
				
CONTA_BITS:		MOV CL,16d
				XOR AL,AL

CONTEGGIO:		ROR DX,01d
				ADC AL,00h
				DEC CL
				JNZ CONTEGGIO
				
				CMP AL,CH
				JE STAMPA_NUMERO
				
PREP_SUCCES:	ADD DX,01b
				CMP DX,BX
				JG FINE
				JMP CONTA_BITS
				
;se un numero ha il valore massimo di 1 allora lo stampo			
				
STAMPA_NUMERO:	MOV CL,16d
          
CICLO_BINARIO5:  XOR AL,AL           
                ROL DX,01h          
                ADC AL,AL           
                ADD AL,'0'
                MOV AH,0Eh
                INT 10h
                DEC CL              
                JNZ CICLO_BINARIO5
                
               	MOV AL,10d
                MOV AH,0Eh
                INT 10h
                MOV AL,13d
                MOV AH,0Eh
                INT 10h
                
				JMP PREP_SUCCES
				
				
FINE:			RET
					
					
ELABORAZIONE	ENDP


;---------------------------------------------------------------------;
;              Procedura per stampare il messaggio iniziale           ;
;                                                                     ;
; REGISTRI UTILIZZATI: DX, AH                                         ;
;---------------------------------------------------------------------;

PROMPT            PROC  NEAR
                  MOV   DX,OFFSET ISTRUZIONI ;Sceglie la stringa (DS:DX)
                  CALL  STAMPA_STRINGA  ; e la stampa.
                  RET                   ;Ritorno alla procedura chiamante
PROMPT            ENDP


;---------------------------------------------------------------------;
;       Procedura per determinare se occorre un'altra iterazione      ;
;                                                                     ;
; REGISTRI UTILIZZATI: AX, DX                                         ;
; CODICI DI RITORNO:                                                  ;
;               Zero flag = 0  -> un'altra iterazione                 ;
;               Zero flag = 1  -> esci dal programma                  ;
;---------------------------------------------------------------------;

TEST_FINALE       PROC  NEAR
                  MOV   DX,OFFSET TERMINE ;Sceglie la stringa (DS:DX)
                  CALL  STAMPA_STRINGA  ; e la stampa.
                  CALL  LETTURA_SN      ;Legge da tastiera senza echo.
                  CMP   AL,'n'          ;Modifica il FLAG 'Z'
                  RET                   ;Ritorno alla procedura chiamante
TEST_FINALE       ENDP


;*********************************************************************;
;*              Procedure di basso livello di interfaccia            *;
;*********************************************************************;




;---------------------------------------------------------------------;
;     Procedura per leggere da tastiera uno dei tasti 'S' o 'N'       ;
;     ritorna solo dopo aver letto almeno uno dei due tasti           ;
;                                                                     ;
; REGISTRI UTILIZZATI: AX                                             ;
; CODICI DI RITORNO: in AL il codice ASCII letto                      ;
;---------------------------------------------------------------------;

LETTURA_SN        PROC  NEAR
NUOVA_LETTURA:    MOV   AH,R_KEY_CHR_NE	;Servizio DOS 'Read Keyboard Char
                  INT   DOS             ; Without Echo'
                  OR    AL,00100000b    ;Converte in minuscolo
                  CMP   AL,'n'          ;Se il tasto premuto e' 'N' esce
                  JZ    FINE_LETTURA    ; dalla procedura
                  CMP   AL,'s'          ;Se non e' 'S', ne legge
                  JNZ   NUOVA_LETTURA   ; un altro
FINE_LETTURA:     RET                   ;Ritorno alla procedura chiamante
LETTURA_SN        ENDP


;---------------------------------------------------------------------;
;                   Procedura per spostare il cursore                 ;
;                                                                     ;
; PARAMETRI: le coordinate della posizione del cursore sono memoriz-  ;
;            zate nel registro DX: DH riga, DL colonna.               ;
; VARIABILI: il numero della pagina e` memorizzato in PAGINA          ;
; REGISTRI UTILIZZATI: AH, BH                                         ;
;---------------------------------------------------------------------;

SPOSTA_CURSORE    PROC  NEAR   
                  MOV   BH,PAGINA       ;Pagina video attiva.
                  MOV   AH,SET_CURSOR	;Servizio BIOS 'Set Cursor
                  INT   BIOS_VIDEO      ; Position'
                  RET                   ;Ritorno alla procedura chiamante
SPOSTA_CURSORE    ENDP


;---------------------------------------------------------------------;
;                  Procedura per stampare una stringa                 ;
;                                                                     ;
; PARAMETRI: l'indirizzo della stringa e` memorizzato in DS:DX        ;
; REGISTRI UTILIZZATI: AH, DX                                         ;
;---------------------------------------------------------------------;

STAMPA_STRINGA    PROC  NEAR 
                  MOV   AH,PRINT_STRING ;Servizio DOS 'Print String'; la
                  INT   DOS             ; stringa e' puntata da DS:DX.
                  RET                   ;Ritorno alla procedura chiamante
STAMPA_STRINGA    ENDP


CSEG              ENDS
                  END  MAIN


e scusa ancora se continuo a romperti le scatole!

hamming_burst
eeeehh è un po' lunghetto :D
ok quando ho tempo vediamo...

apatriarca
@ellosma: Usa il tag code per rendere più chiaro il codice che posti! Questa volta l'ho fatto io.. Prendi l'abitudine di commentare molto di più il tuo codice assembly (scrivendo in particolare la logica del programma invece che commenti sugli aspetti più tecnici).

bibus12
Nella mia mente contorta ho pensato di risolvere il conteggio dei "2" in questo modo, ma il professore ha detto che è un ragionamento molto contorto e che il problema è risolvibile molto più facilmente di così :?

 

CHECK2(B):

q = 0; // Inizio l'esame della cifra più significativa di B.

LOOP:

if (q >= k) j RETURN // Se ho letto tutte le cifre di B passo al prossimo numero.

if ((B % 10^(k - q)) / 10^(k - q - 1) == 2) count += 1; // Incremento il contatore se la cifra in esame è un 2.

q += 1; // Scorro alla cifra subito meno significativa.

j LOOP // Esamino la cifra subito meno significativa.

RETURN:

if (B == A - 1) j EXIT // Torno al main se ho finito di calcolare le ricorrenze di 2 in tutti i numeri tra B ed A estremi compresi.

count += CHECK2(B - 1) // Altrimenti sommo al contatore ottenuto per il numero corrente (già sommato ai contatori dei numeri superiori) il contatore del numero inferiore. 

EXIT: return count // Restituisco al main il contatore col risultato definitivo


Shulz1
"ellosma":
Nella mia mente contorta ho pensato di risolvere il conteggio dei "2" in questo modo, ma il professore ha detto che è un ragionamento molto contorto e che il problema è risolvibile molto più facilmente di così :?

 

CHECK2(B):

q = 0; // Inizio l'esame della cifra più significativa di B.

LOOP:

if (q >= k) j RETURN // Se ho letto tutte le cifre di B passo al prossimo numero.

if ((B % 10^(k - q)) / 10^(k - q - 1) == 2) count += 1; // Incremento il contatore se la cifra in esame è un 2.

q += 1; // Scorro alla cifra subito meno significativa.

j LOOP // Esamino la cifra subito meno significativa.

RETURN:

if (B == A - 1) j EXIT // Torno al main se ho finito di calcolare le ricorrenze di 2 in tutti i numeri tra B ed A estremi compresi.

count += CHECK2(B - 1) // Altrimenti sommo al contatore ottenuto per il numero corrente (già sommato ai contatori dei numeri superiori) il contatore del numero inferiore. 

EXIT: return count // Restituisco al main il contatore col risultato definitivo



Ciao, un possibile algoritmo che potresti usare è questo (Python):
def count(a, b=2):
    res = 0
    while a > 0:
        if a % 10 == b:
            res += 1
        a /= 10

    return res

if __name__ == '__main__':
    digit = 2
    up_lim = 2003
    down_lim = 2001

    values = range(down_lim, up_lim+1)
    result = sum(map(count,values))

    print result


Purtroppo sono un po' arrugginito per quanto riguarda l'assembly (e all'uni devo ancora farlo) :D
Comunque,in breve, l'algoritmo che utilizzo incrementa un contatore ogni qualvolta l'ultima cifra del numero è uguale a due.
Ovviamente alla fine di ogni 'giro' del ciclo il numero n viene diviso per 10, così che la cifra appena analizzata sparisca e si possa passare alla successiva.
Il tutto viene ripetuto finchè il risultato della divisione non diventa zero.

Spero di esserti stato di aiuto!

Ciao,
Shulz

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.