PDA

View Full Version : [ASSEMBLY 8086] Programma somma


jyciap11
12-05-2013, 20:52
Ragazzi sto provando a fare una semplice somma con l'8086,però quando arrivo a stampare mi stampa una miriade di caratteri (cuori,frecce etc..) che non ci incastrano nulla.
Il codice è questo
.model small ;definisce il modello di memoria da utilizzare
.stack 200h ;dimensione massima del codice sorgente
.data ;definizione variabili e/o costanti
num1 db ?
ris db ?
.code
inizio:
mov ax,@data
mov ds,ax ;inizializzo il segmento
mov ah,1 ;funzione di lettura carattere
int 21h
mov bh,al
mov num1,bh
mov ah,1
int 21h
mov bh,al
add bh,num1
mov ris,bh
;
;a capo
mov AH,02h
mov DL,13
int 21h
mov AH,02h
mov DL,10
int 21h
;
mov ah,9 ;funzione di stampa della stringa
mov dx,offset ris
int 21H
jmp inizio

kwb
13-05-2013, 12:01
Hmm, non posso testare il tuo codice, e non mi ricordo bene l'8086.
Però sappi che le procedure DOS attivate attraverso l'istruzione INT 21H permettono di leggere o visualizzare esclusivamente caratteri ascii. Di conseguenza sta a te poi trasformare l'input in un vero numero.
Generalmente devi aggiungere/sottrarre ( ora non ricordo bene :fagiano: ) 48 ( il numero decimale che corrisponde allo 0 ascii ) perchè le somme stampate siano corrette.

jyciap11
13-05-2013, 14:07
un altra domanda,come faccio,tramite questo menù,ad andare a 4 procedure diverse?
Cioè io ero abituato a mettere il je (salta se è uguale) ma devo usare le procedure..e le procedure si richiamano solo con la call,quindi il controllo come lo faccio?

.code ;inizio codice sorgente
inizio:
mov ax,@data
mov ds,ax ;carica il segmento dati
;a capo
mov AH,02h
mov DL,13
int 21h
mov AH,02h
mov DL,10
int 21h
mov ah,9 ;funzione di stampa della stringa
mov dx,offset stringa ;visualizza la stringa
int 21h
mov dx,offset scelta1
int 21h
mov dx,offset scelta2
int 21h
mov dx,offset scelta3
int 21h
mov dx,offset scelta4
int 21h
mov ah,1 ;funzione di lettura carattere
int 21h

kwb
13-05-2013, 15:26
Metti il codice che vuoi far eseguire dentro una procedura.
Poi se la procedura deve essere richiamata solo in certe condizioni, le anteponi un'etichetta ( label ) così puoi con un salto condizionato, andare all'etichetta ( che come prima istruzione avrà una CALL procedura ):

CMP 0,CX
JE etichetta1
...
etichetta1: CALL procedura

jyciap11
13-05-2013, 15:45
Metti il codice che vuoi far eseguire dentro una procedura.
Poi se la procedura deve essere richiamata solo in certe condizioni, le anteponi un'etichetta ( label ) così puoi con un salto condizionato, andare all'etichetta ( che come prima istruzione avrà una CALL procedura ):

CMP 0,CX
JE etichetta1
...
etichetta1: CALL procedura


perfetto,pensavo fosse uno spreco di codice ma non è così.
Sono arrivato a questo punto,sto facendo la potenza,nel caso specifico un numero elevato alla prima (che quindi rimane uguale).

Stampa tutto correttamente,ma insieme mi stampa una marea di caratteri (come vi dicevo ieri sera).
Il pezzetto di codice che riguarda la variabile RIS (risultato) è questo:

stampa_ris:
;a capo
mov AH,02h
mov DL,13
int 21h
mov AH,02h
mov DL,10
int 21h
;
mov bl,n1
mov ris,bl
mov ah,9
mov dx,offset ris
int 21h
jmp inizio
end

però come ben sapete con l'offset si stampa le stringhe e non i numeri.
Come posso stampare ris?

kwb
13-05-2013, 18:07
Ma per stampare un numero o un singolo carattere ( ASCII ) ti basta fare uguale a come hai fatto per stampare il line-feed e il carriage-return...

Ti consiglio di leggerti un libro sull'Assembler 8086 perchè pare tu non abbia le idee chiare :D

jyciap11
13-05-2013, 19:49
Ma per stampare un numero o un singolo carattere ( ASCII ) ti basta fare uguale a come hai fatto per stampare il line-feed e il carriage-return...

Ti consiglio di leggerti un libro sull'Assembler 8086 perchè pare tu non abbia le idee chiare :D

mi riesce l'8086..ma non so stampare un risultato.

pabloski
13-05-2013, 20:34
mi riesce l'8086..ma non so stampare un risultato.

il motivo, come detto da kwb nella prima risposta, è che un valore zero in un registro non corrispondente al simbolo zero che vedi sullo schermo

lo zero sullo schermo ha valore 48, l'uno 49, ecc....

se vuoi stampare un numero ( ad una cifra ) devi sommargli 48

se i numeri sono a più cifre va ovviamente scisso il numero nelle sue cifre costituenti e ad ognuna va sommato 48 e poi inviato alla funzione di stampa

jyciap11
13-05-2013, 21:43
allora,comincio a capirci.
In questo caso N1 = 1 e N2 = 2
Mi stampa 3 quindi VA BENE !!!!
MOV AL, N1 ;carica N1 da RAM a registro AL
MOV BL, N2 ;carica N2 da RAM a registro BL
ADD AL, BL ;significa AL=AL+BL, il registro AL fa da accumulatore e contiene ora la somma
add al,48
MOV SOMMA, AL ;il risultato viene scritto in memoria nella variabile somma, copiato da registro AL
mov dl,somma
mov ah,2
int 21h


Se io avessi però 20 + 15?Come faccio a stampare 35 e non un carattere?

pabloski
13-05-2013, 21:54
Tramite divisioni successive per 10. Usa l'istruzione div e leggi, ad ogni divisione, il risultato in dx ( il resto ).

Ad esempio 15/10 = 1 con resto 5...1/10 = 0 con resto 1. Semplice!!

jyciap11
13-05-2013, 22:01
et voilà,siete dei geni ce l'ho fatta.
Una cosa però a me funziona SOLO se dichiaro in alto le variabili,cioè se dico db N1 3 e db N1 5 lui mi fa 3+5= 8 e va bene,però se io volessi inserire da tastiera n1 e n2 e faccio

mov n1,al
dichiarando dw n1 mi da errore,come posso fare per inserire il dato da tastiera in n1 senza errore?

kwb
14-05-2013, 11:13
La variabile ( che in realtà è un indirizzo di memoria... ) deve essere sempre dichiarata prima.
Mi pare che facendo:

variabile DW ?

Sia sufficiente.
Se poi vuoi mettere qualcosa in quella "variabile" puoi fare:

mov variabile,AL

Dove in AL c'è un dato caricato.

jyciap11
14-05-2013, 12:38
Ragazzi un altra domanda.
Ho fatto questo codice (è una procedura).
Se volessi "trasformarla" in MACRO come faccio per richiamarla?

input_potenza proc
;--------INPUT N1--------
mov n1, 0000h
mov ah,9 ;funzione di stampa della stringa
mov dx,offset mess_pot_1 ;visualizza la stringa
int 21h
mentre:
mov ah, 01h
int 21h
cmp al, 30h
jb continuo
cmp al, 39h
ja continuo
mov ah, 00h
sub al, 30h
mov cifra, ax
mov ax, n1
mov bx, 0ah
mul bx
add ax, cifra
mov n1,ax
jmp mentre
;--------INPUT N2---------
continuo:
mov n2, 0000h
mov ah,9 ;funzione di stampa della stringa
mov dx,offset mess_pot_2 ;visualizza la stringa
int 21h
mentre_2:
mov ah, 01h
int 21h
cmp al, 30h
jb fine
cmp al, 39h
ja fine
mov ah, 00h
sub al, 30h
mov cifra, ax
mov ax, n2
mov bx, 0ah
mul bx
add ax, cifra
mov n2,ax
jmp mentre_2
fine:
ret
endp

kwb
14-05-2013, 15:20
Una macro si crea nel seguente modo:

NomeMacro MACRO valore1, valore2, ..., valoreN
...
ENDM


Per chiamarla basta semplicemente scrivere il suo nome.

jyciap11
14-05-2013, 16:01
Ultima domanda.
Questo programma calcola una potenza,però con due cifre.
Qualcuno riesce a dirmi come fare per n cifre (esempio 9^9)

calcolo_potenza:
call input_potenza
call a_capo
mov ax,1
mov bx, n1
mov cx, n2
ciclo:
mul bx
loop ciclo
istr_finali:
mov ptz, ax
mov ah,0 ; azzero AH così AX è il risultato
mov bl,10 ; carico il divisore in BL
div bl ; divido AX per BL(10) ed ottengo AL=quoziente (le decine) AH=resto (le unità)
add al,30h ; le decine in ASCII
mov ris_ascii,al
add ah,30h ; le untià in ASCII
mov ris_ascii+1,ah
lea dx, ris
mov ah,09h
int 21h

kwb
14-05-2013, 18:49
Cioè tu vuoi calcolare la potenza n-esima di un numero i-esimo?
i^n?
Fa conto però che se così fosse, devi prevedere il caso in cui il risultato non sia memorizzabile in un singolo registro e attrezzarti per salvarlo in più registri.

jyciap11
14-05-2013, 18:54
Cioè tu vuoi calcolare la potenza n-esima di un numero i-esimo?
i^n?
Fa conto però che se così fosse, devi prevedere il caso in cui il risultato non sia memorizzabile in un singolo registro e attrezzarti per salvarlo in più registri.

si il programma deve fare quello.
Quindi fino a che il risultato è di due cifre funziona,ma dopo non funziona più

kwb
14-05-2013, 20:51
si il programma deve fare quello.
Quindi fino a che il risultato è di due cifre funziona,ma dopo non funziona più
Ora non ricordo bene, ma siccome i registri sono da 16bit, dovresti poter salvare numeri fino a (2^16)-1 = 65535. Tutto ciò è valido se i numeri sono solo interi positivi. :D
Secondo quanto ho detto ( ammesso sia corretto, ma ho ricontrollato sul libro che avevo usato per studiare il linguaggio e pare confermarlo ) non ci dovrebbero essere problemi fino a 65535. Inoltre, trattandosi di potenze, il numero è sempre positivo.

Tra l'altro, se usi delle variabili per salvare il risultato, assicurati che siano DW ( che mi pare sia il tipo di dato da 16 bit ) così da essere grandi quanto i registri.

jyciap11
14-05-2013, 21:05
Ora non ricordo bene, ma siccome i registri sono da 16bit, dovresti poter salvare numeri fino a (2^16)-1 = 65535. Tutto ciò è valido se i numeri sono solo interi positivi. :D
Secondo quanto ho detto ( ammesso sia corretto, ma ho ricontrollato sul libro che avevo usato per studiare il linguaggio e pare confermarlo ) non ci dovrebbero essere problemi fino a 65535. Inoltre, trattandosi di potenze, il numero è sempre positivo.

Tra l'altro, se usi delle variabili per salvare il risultato, assicurati che siano DW ( che mi pare sia il tipo di dato da 16 bit ) così da essere grandi quanto i registri.
questo,bene o male,ero riuscito a capirlo,non riesco a capire come gestire le divisioni in modo tale da fermarmi al momento giusto e trascrivere il risultato

pabloski
14-05-2013, 21:38
questo,bene o male,ero riuscito a capirlo,non riesco a capire come gestire le divisioni in modo tale da fermarmi al momento giusto e trascrivere il risultato

quando al contiene zero ( cioè il resto è zero ) ti fermi

jyciap11
14-05-2013, 22:13
quando al contiene zero ( cioè il resto è zero ) ti fermi

FATTO,non so come ringraziarvi.
Adesso ho un groooossssoo problema.
Il programma deve fare,attraverso le procedure e le macro (tramite un menù),la potenza,il calcolo di un fattoriale,e l'mcd.

Funziona tutto,ma sono troppe righe di codice (600 circa)...come posso fare a ridurlo?
Così il professore ha detto non lo legge nemmeno

esempio per la divisione con 3 cifre ho fatto così,devo arrivare a 9 sicchè mi si aggiungeranno minimo 100 righe di codice..non c'è un metodo più veloce?
mov dx,0
mov cx,100
div cx
add ax,30h
mov ris_ascii,ax
mov bx,dx ;salviamo il resto
mov ax,bx
mov dx,0
mov cx,10
div cx
add ax,30h
mov bx,dx
mov ris_ascii+1,ax
add bx,30h
mov ris_ascii+2,bx
lea dx, ris
mov ah,09h
int 21h
call a_capo
jmp inizio

kwb
14-05-2013, 22:31
FATTO,non so come ringraziarvi.
Adesso ho un groooossssoo problema.
Il programma deve fare,attraverso le procedure e le macro (tramite un menù),la potenza,il calcolo di un fattoriale,e l'mcd.

Funziona tutto,ma sono troppe righe di codice (600 circa)...come posso fare a ridurlo?
Così il professore ha detto non lo legge nemmeno
LOL

Si rende conto che è Assembly questo, si? :doh:

Devo dire che qua andiamo molto sul tecnico, e sapere come ottimizzare il programma credo che richieda un certo livello di conoscenza del linguaggio.

Quello che ti posso suggerire è: ricontrolla il tuo codice e guarda se ci sono delle parti ripetute, in tal caso riservagli una macro/procedura e richiamale all'occorrenza. Io ho spesso usato quest'espediente quando scrivevo in assembly per stampare rapidamente il linefeed e il carriage return ( o anche gli spazi ).

Per il resto, non so che dirti.. :boh:

jyciap11
14-05-2013, 22:43
LOL

Si rende conto che è Assembly questo, si? :doh:

Devo dire che qua andiamo molto sul tecnico, e sapere come ottimizzare il programma credo che richieda un certo livello di conoscenza del linguaggio.

Quello che ti posso suggerire è: ricontrolla il tuo codice e guarda se ci sono delle parti ripetute, in tal caso riservagli una macro/procedura e richiamale all'occorrenza. Io ho spesso usato quest'espediente quando scrivevo in assembly per stampare rapidamente il linefeed e il carriage return ( o anche gli spazi ).

Per il resto, non so che dirti.. :boh:
lo so,è una burla,lo scorso programma che feci (stampa un quadrato,triangolo,una linea e una cornice) mi rimproverò per 500 righe di codice... (senza macro ne procedure eh quindi..)

Vabè,tralasciando questo,vi faccio l'ultima domanda poi vi mollo.

Ho usato variabili DW,quindi vanno bene per numeri fino a 65536.
se faccio 9 alla 9 = 387 420 489 come faccio a spezzare il numero,metterlo in due variabili e riunirlo?

kwb
15-05-2013, 11:44
lo so,è una burla,lo scorso programma che feci (stampa un quadrato,triangolo,una linea e una cornice) mi rimproverò per 500 righe di codice... (senza macro ne procedure eh quindi..)

Vabè,tralasciando questo,vi faccio l'ultima domanda poi vi mollo.

Ho usato variabili DW,quindi vanno bene per numeri fino a 65536.
se faccio 9 alla 9 = 387 420 489 come faccio a spezzare il numero,metterlo in due variabili e riunirlo?

Fai prima a definire variabili doubleword, quadword,tenbyte.
Questo tipo di variabili permette di salvarci dentro fino a, rispettivamente, 4,8 e 10 Byte.
Nota che doubleword, quadword e tenbyte possono essere per salvare numeri e fino a 2 caratteri. Questo perchè gran parte delle istruzioni agiscono su un indirizzo di memoria di massimo 2 byte.
Questo tipo di dati si definisce così:

variabile DD ? ;Una doubleword
variabile DQ ? ;Una quadword
variabile DT ? ;Una tenbyte

Ci sono operazioni come ADC ( ADd with Carry ) e SBB ( SuBtrack with Borrow ) che permettono di fare operazioni su doubleword, quadword,tenbyte.
Tuttavia, nel caso volessi intraprendere questa strada, devi rivedere tutto il meccanismo di somme e sottrazioni perchè con così tanti bit la gestione è più complessa.
Ti riporto un esempio del mio libro per sommare due numeri rappresentati su 32 bit:

.MODEL small
.DATA

NUMA DD ?
NUMB DD ?
NUMC DD ?

.CODE
...
MOV AX, WORD PTR NUMA
ADD AX, WORD PTR NUMB ;Somma tra loro le 2 word meno significative

MOV WORD PTR NUMC, AX
MOV AX, WORD PTR NUMA+2
ADC AX, WORD PTR NUMB+2 ;Somma tra loro le 2 word più significative + l'eventuale
;carry della somma precedente
MOV WORD PTR NUMC+2, AX


Spero sia chiaro. :)

jyciap11
15-05-2013, 14:04
chiarissimo,mi metto all'opera e vi faccio sapere

jyciap11
15-05-2013, 21:55
Ragazzi mi sapete consigliare un'istruzione che chiuda il dos?
.exit non lo chiude ma esce dall'esecuzione del programma,a me serva che proprio chiuda il dos.

kwb
15-05-2013, 22:36
Io dico che non esiste...
Se DOS è un sistema operativo, chiuderlo significa arrestare il sistema. Che senso avrebbe?
Magari mi sbaglio eh, però boh, prova a guardare tra gli interrupt vari...

Ricorda però che quello che vedi stampato nella finestrella dal tuo codice non è altro che un po' di caratteri in un'astrazione di sistema operativo (MS-Dos )

EDIT: Io terminavo sempre i programmi con
.EXIT
END

Prova...

jyciap11
15-05-2013, 22:57
Io dico che non esiste...
Se DOS è un sistema operativo, chiuderlo significa arrestare il sistema. Che senso avrebbe?
Magari mi sbaglio eh, però boh, prova a guardare tra gli interrupt vari...

Ricorda però che quello che vedi stampato nella finestrella dal tuo codice non è altro che un po' di caratteri in un'astrazione di sistema operativo (MS-Dos )

EDIT: Io terminavo sempre i programmi con
.EXIT
END

Prova...

Il professore ci ha chiesto che quando viene premuto 4 dal menù la finestra si chiuda,quindi probabilmente esiste.

p.s. giocando con le procedure e le macro sono riuscito a ridurre il programma (che ricordo calcola potenza,fattoriale e mcd) a sole 200 righe di codice :ciapet: :ciapet:

p.p.s .exit non chiude la finestra ma termina il programma.

pabloski
16-05-2013, 11:06
quindi dev'essere il tuo programma a termine, non il dos

in questo caso basta richiamare la funzione 4C dell'interrupt 21

jyciap11
17-05-2013, 14:03
Ragazzi come faccio a controllare se c'è un overflow?
Cioè se io ho un registro dw e il risultato supera la dimensione massima di quel registro,come faccio per stampare un errore?

kwb
17-05-2013, 14:48
L'8086 dispone di una componente, chiamata registro di stato o Processor Status Word ( PSW ) che non è altro che un registro di 16 bit contente 9 flag.
I bit del registro vengono alterati al termine di ogni istruzione.
Tra questi c'è l'OF ( Overflow Flag ) che se viene impostato a 1 indica la presenza di un overflow. Puoi controllare quello...

jyciap11
19-05-2013, 09:04
Ragazzi ho un grosso problema,in questo codice la macron no funziona,o meglio quando vado a compilare il programma mi dice:

"Pass dependent costruction encountered : CLEAR_SCHERMO"

controllo proc
mov ah,1
int 21h
cmp al,49
je calcolo_potenza ; se 1 vai alla potenza
cmp al,50
je calcolo_fattoriale ; se 2 vai al fattoriale
cmp al,51
je calcolo_MCD ; se 3 vai all'MCD
clear_schermo
endp

clear_schermo MACRO
MOV AH,00h
MOV AL,03h
INT 10h
ENDM

pabloski
19-05-2013, 09:55
Ma è un warning? E che assembler stai usando?

jyciap11
19-05-2013, 11:04
Ma è un warning? E che assembler stai usando?

risolto,lo sapevate voi che bisogna mettere prima del modell small tutte le macro?