Programma in Assembly

Matteo34

Nuovo Utente
103
2
CPU
i5-10500 3.2Ghz
Dissipatore
Non specificato
Scheda Madre
Non specificata
HDD
M.2 251GB e M.2 500GB
RAM
16GB DDR4 2666mhz
GPU
Grafica Intel® UHD 630
Audio
Non specificata
Monitor
1920x1080 27"
PSU
Non specificato
Case
Non specificato
Periferiche
Nono specificato
Net
Eolo
OS
Ubuntu
Non so davvero come rendere questo programma più semplice.
Il programma deve effettuare la somma di due numeri presi in input, ma cioè che se uscito fuori è al limite del pauroso.
La mia prima idea è stata quella di creare due buffer entrambi di 5byte(il numero massimo di cifre rappresentabili con 16 bit in base 10) da riempire con i valori presi in input(un valore per ogni cifra), i quali verranno "tradotti" da ASCCI a numero "vero e proprio" all'interno degli stessi buffer, quindi mi sarei ritrovato con due buffer si interi dove ogni valore era la cifra di un numero, in questo modo mi sarei sommato i due buffer e avrei dovuto riconvertire tutti i valori in ASCII per ristamparli a schermo.
Ovviamente con vari controlli per evitare che non vengano inseriti lettere, con la stessa interruzione della lettura digitando il carattere 13(CL).
Ho iniziato a scrivere il programma am mi sembra davvero esagerato, e davvero necessario fare tutto ciò per sommare due numeri a 16bit, se l'avrei scritto su un architettura a 32bit averi dovuto creare un buffer di troppi byte

C'è un modo migliore di fare ciò?

Inviato da MI 8 tramite App ufficiale di Tom\'s Hardware Italia Forum
 

DispatchCode

Utente Attivo
1,012
616
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit
A 32bit cambiano un pò di cose. In primis l'interfaccia che utilizzi per leggere l'input, visto che gli OS moderni offrono una maggiore astrazione.

Gli step che devi seguire sono praticamente i seguenti:
  1. usi una variabile o un registro per contenere il numero
  2. usi un registro temporaneo per il singolo numero, inizializzato a 0 (esempio CX)
  3. leggi 1 carattere alla volta (da '0' a '9')
    1. per ogni carattere valido farai: CX * 10
    2. a questo punto sottrai '0' al carattere che hai letto in input (in AL)
    3. quindi alla fine CX = CX + AL
  4. se non è valido ed è Invio, ti fermi: questo è uno dei numeri letti
Sono un tantino arrugginito, specie con il 16bit che non tocco da anni, ma puoi guardare questo esempio (per vedere il risultato in DX, devi usare un debugger in quanto non lo printo a schermo):

Codice:
stack SEGMENT PARA STACK

         db    4096   dup(?)

stack ENDS

data SEGMENT PARA PUBLIC

        msg     db      "Number: ", '$'
        crlf    db      0Dh, 0Ah, '$'
        ten     db      0Ah
        
        num     dw      0

data ENDS

code SEGMENT PARA PUBLIC
        ASSUME cs: code, ds: data, ss: stack
_start:

    mov     ax, data
    mov     ds, ax

    mov     dx, offset msg
    mov     ah, 09h
    int     21h
    
    call    read_num
    
    add     num, cx
    
    mov     dx, offset crlf
    mov     ah, 09h
    int     21h
    
    mov     dx, offset msg
    mov     ah, 09h
    int     21h
    
    call    read_num
    
    add     num, cx
    mov     dx, num ; RISULTATO DELL'OPERAZIONE
    
    mov     ah, 00h
    mov     al, 4Ch
    int     21h
    
    ret


read_num    PROC     NEAR

    push    bp
    mov     bp, sp
    
    mov     cx, 0
    
_read:
    ; lettura numero
    mov     ah, 01h
    int     21h
    
    cmp     al, 0Dh ; Invio?
    je      _stop_input
    
    ; verifico se e' compreso tra 0 e 9
    cmp     al, '0'
    jb      _read
    cmp     al, '9'
    ja      _read
    
    ; preservo il valore di ax in quanto verrà usato come
    ; operando nella moltiplicazione * 10
    ; eg. se ax = 9 e cx=1, si verifica cx*=10 -> cx = 10
    push    ax
    mov     ax, cx
    mul     ten
    mov     cx, ax
    pop     ax
    
    ; dopo la trasformazione del valore di al in numero, lo si somma con cx
    sub     al, '0'
    mov     ah, 0h
    add     cx, ax
    ; quindi se cx = 10, ad esempio, la somma con ax (es. 9) darà come risultato 19
    
    jmp     _read
    
_stop_input:
        
    mov     sp, bp
    pop     bp
    ret
read_num    ENDP

code ENDS
END _start

Per stamparlo a schermo dovrai fare l'operazione inversa e stampare ogni singola cifra.
Puoi anche inserirlo in un buffer e stamparlo come stringa forse, ma non ricordo i vari "trick".

Sotto Windows funziona appunto diversamente, anche se non è comunque proprio semplicissimo (causa della WinAPI).
 

bigendian

Utente Attivo
349
169
OS
Linux forever, freedom
problema non e' la somma di due numeri, che, supponendo di avere i due numeri in bx e cx, si traduce in

Codice:
xor ax, ax
add ax, bx

add ax, cx

Ma c'e' certamente piu codice per leggere i numeri usando gli interrupt del bios.

Organizza il codice in 3 parti, con etichette o con routine ben ordinate se vuoi
- lettura valori,
- conversioni in numeri puri da ascii (sub 48)
Codice:
sub ax, 48
- somma
- conversione in ascii del risultato (add 48)
- stampa

Certo, codice assembly finale per fare una cavolata simile risulta magari un cnetinaio di righe,
ma e' quello che avviene a livello cpu.
 

Matteo34

Nuovo Utente
103
2
CPU
i5-10500 3.2Ghz
Dissipatore
Non specificato
Scheda Madre
Non specificata
HDD
M.2 251GB e M.2 500GB
RAM
16GB DDR4 2666mhz
GPU
Grafica Intel® UHD 630
Audio
Non specificata
Monitor
1920x1080 27"
PSU
Non specificato
Case
Non specificato
Periferiche
Nono specificato
Net
Eolo
OS
Ubuntu

DispatchCode

Utente Attivo
1,012
616
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit

Matteo34

Nuovo Utente
103
2
CPU
i5-10500 3.2Ghz
Dissipatore
Non specificato
Scheda Madre
Non specificata
HDD
M.2 251GB e M.2 500GB
RAM
16GB DDR4 2666mhz
GPU
Grafica Intel® UHD 630
Audio
Non specificata
Monitor
1920x1080 27"
PSU
Non specificato
Case
Non specificato
Periferiche
Nono specificato
Net
Eolo
OS
Ubuntu
Durante la stampa del risultato il programma si blocca
Codice:
mov    ax, bx ;bx contiene la somma
mov    cx, 10

output_add:
div  cx
cmp  ah, 0
je  stop
add  ah, 48
mov  dl, ah
mov  ah, 02h
int     21h
xor  ah, ah
jmp  output_add
                

stop: mov  ah, 04ch
          mov  al, 1
          int     21h
Per adesso il risultato viene stampato al contrario, ma per quale motivo si blocca, entra in ciclo infinito(a me non sembra) o c'è qualche problema?
Ah dovrebbe contenere il resto della divisione mentre Al il quoziente no?
 

DispatchCode

Utente Attivo
1,012
616
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit
Posta il codice completo.

Comunque la DIV la stai facendo su CX, quindi il risultato sarà in AX e il resto in DX. Se come divisore usi CL, allora il risultato è in AL e il resto in AH.

EDIT:
controlla sempre la doc per vedere le istruzioni che usi. Per evitare di guardare il manuale intel, ci sono siti tipo https://c9x.me/x86/html/file_module_x86_id_72.html
 

Matteo34

Nuovo Utente
103
2
CPU
i5-10500 3.2Ghz
Dissipatore
Non specificato
Scheda Madre
Non specificata
HDD
M.2 251GB e M.2 500GB
RAM
16GB DDR4 2666mhz
GPU
Grafica Intel® UHD 630
Audio
Non specificata
Monitor
1920x1080 27"
PSU
Non specificato
Case
Non specificato
Periferiche
Nono specificato
Net
Eolo
OS
Ubuntu
Posta il codice completo.

Comunque la DIV la stai facendo su CX, quindi il risultato sarà in AX e il resto in DX. Se come divisore usi CL, allora il risultato è in AL e il resto in AH.

EDIT:
controlla sempre la doc per vedere le istruzioni che usi. Per evitare di guardare il manuale intel, ci sono siti tipo https://c9x.me/x86/html/file_module_x86_id_72.html
Ho cambiato operandi ma si blocca ancora.
Ecco il codice completo:
Codice:
stack SEGMENT PARA STACK

        db      ?

stack ENDS

data SEGMENT PARA PUBLIC

        msg_1   db    "Primo numero:$"
        msg_2   db    "Secondo numero:$"
        msg_3   db     "Somma dei due numeri:$"

data ENDS

code SEGMENT PARA PUBLIC

        ASSUME ss: stack, ds: data, cs: code

_start:
       ;load the ds with data
       mov      ax, data
       mov      ds, ax

       mov      cx, 5

       ;output
       mov      ah, 09h
       mov      dx, OFFSET msg_1
       int      21h

       ;read the number and save it in bx
       read: mov   ah, 01h
             int   21h
             xor  ah, ah

             cmp   al, 13
             jne   continue

             ;output
             mov   ah, 09h
             mov   dx, OFFSET msg_2
             int   21h

             mov   cx, 5
             jmp   read2

             continue: cmp   al, 48
                       jb    stop

                       cmp   al, 57
                       ja    stop

                       sub   al, 48
                       add   bx, ax
                       mov   ax, 10
                       mul   bx
                       mov   bx, ax
                 
                       loop  read
                       mov   cx, 5

                       mov   ah, 02h
                       mov   dl, 13
                       int   21h
                       mov   dl, 10
                       int   21h

       ;output
       mov    ah, 09h
       mov    dx, OFFSET msg_2
       int    21h

       read2: mov   ah, 01h
              int   21h
              xor  ah, ah

              cmp   al, 13
              je    add_c

              cmp   al, 48
              jb    stop

              cmp   al, 57
              ja    stop

              sub   al, 48
              add   dx, ax
              mov   ax, 10
              mul   dx
              mov   dx, ax

              loop  read2

              mov   ah, 02h
              mov   dl, 10
              int   21h
              mov   dl, 13
              int   21h

       add_c: add  bx, dx
              jo   stop

       ;output
       mov    ah, 09h
       mov    dx, OFFSET msg_3
       int    21h

       mov    ax, bx
       mov    cx, 10

       output_add: div  cx
                   cmp  dx, 0
                   je   stop
                   add  dx, 48
                   mov  ah, 02h
                   int  21h
                   jmp  output_add

       stop: mov   ah, 04ch
             mov   al, 1
             int   21h

code ENDS
        END _start
 
Ultima modifica:

DispatchCode

Utente Attivo
1,012
616
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit
E' dovuto alla divisione nel momento in cui vai a stampare il risultato.

Assicurati sia corretto l'input, perchè secondo me ci sono errori in fase di lettura, a prima vista.

Codice:
                       sub   al, 48
                       add   bx, ax
                       mov   ax, 10
                       mul   bx
                       mov   bx, ax

inoltre qui: tu devi prima moltiplicare e poi sommare.
Così facendo se in input inserisci "12", ti ritrovi con "120".

Dai un occhio a come leggo l'input sopra.

EDIT:

Riporto l'errore.
E' dovuto alla divisione che viene fatta al termine (non ho provato il codice però).
Manca l'inizializzazione a 0 del registro DX, che viene usato come "parte alta" nella divisione (la coppia considerata è infatti DX:AX). Il risultato infatti non sta in 16bit, e quindi va in overflow.
 
Ultima modifica:

Entra

oppure Accedi utilizzando

Hot: Quale crypto per il futuro?

  • Bitcoin

    Voti: 83 46.1%
  • Ethereum

    Voti: 71 39.4%
  • Cardano

    Voti: 24 13.3%
  • Polkadot

    Voti: 8 4.4%
  • Monero

    Voti: 15 8.3%
  • XRP

    Voti: 15 8.3%
  • Uniswap

    Voti: 4 2.2%
  • Litecoin

    Voti: 13 7.2%
  • Stellar

    Voti: 12 6.7%
  • Altro (Specifica)

    Voti: 25 13.9%

Discussioni Simili