Assembly VII

[Da questo momento i moduli seguiranno, revisionadolo e aggiungendo i commenti estesi, il progetto del testo Linguaggio Assembly per pc IBM di Peter Norton e John Socha per la costruzione di un programma per la visualizzazione e l'editor del contenuto dei settori dei dischi]

Output esadecimale

Quella che segue e' la prima procedura creata per il programma DSKPATCH proposto dal testo Linguaggio Assembly per pc IBM di Peter Norton e John Socha per la lettura e l'editing dei settori di un disco.
Il primo passo proposto dal testo prevede il perfezionamento della procedura di output dei caratteri esadecimali letti.

code_seg

 

segment ; nome del segmento di codice
assume cs:code_seg ; indicazione del nome del segmento di codice
  org 100h   ; inizio alla locazione di memoria 100
       
       
       
  public test_write_hex ; procedura di test per provare le procedure
    ; che seguono
       
test_write_hex proc near  
  mov dl, 3fh   ; numero di prova
  call write_hex   ; chiama la procedura write_hex
  int 20h  
test_write_hex endp    
       
       
     
  public write_hex   ; procedura di isolamento delle due cifre in DL:
      ; prima la cifra di sinistra poi quella di destra
   
write_hex proc near  
  mov dh, dl   ; muovi DL in DH per avere una copia di DL
      ; non trattata
  mov cx, 4   ; carica il contatore CX
  shr dl, cl ; slitta il contenuto di DL a destra per il valore
      ; decimale contenuto nel registro CL [0004]
      ; nel nostro caso -> 03h in modo da isolare la
      ; prima cifra esadecimale del numero 3fh in DL
  call write_hex_digit   ; richiama la procedura di controllo/conversione
      ; lettere/numeri
  mov dl, dh   ; muovi la copia di DL contenuta in DH in DL
  and dl, 0fh   ; azzera la prima cifra con la messa in and
      ; 00111111 and 00001111 = 00001111 ovvero 0Fh
      ; per isolare la seconda cifra
  call write_hex_digit   ; vai alla procedura di conversione lettere/numeri
ret   ; ritorna alla chiamata test_write_hex
      ; e fine [int 20h]
write_hex endp  
       
       
   
public write_hex_digit   ; procedura di controllo per cifre esadecimali da
    ; convertire in numeri [< Ah] o lettere [> Ah]
   
write_hex_digit proc near  
push dx   ; metti il contenuto di DX nello stack cosi' da
      ; salvare il contenuto originario di DL nel
      ; nostro caso 3Fh
cmp dl, 10   ; compara DL al decimale 10 che corrisponde
      ; all'esadecimale A per determinare se
      ; trasformarlo in lettera o numero
  jae hex_letter   ; se superiore o uguale trasforma in lettera
      ; saltando ad hex_letter
  add dl, "0"   ; altrimenti e' un numero, quindi addiziona "0" per
    ; trasformarlo in 3 decimale e...
  jmp short write_digit   ; vai alla chiamata di stampa write_digit per
  ; procedura di stampa write_char
hex_letter:     ; questa entrata e' per la trasformazione
      ; in lettera della cifra hex
add dl, "A" -10   ; addiziona cifra [> di A ] ad Ah e sottrai 10 dec
      ; nel nostro caso [F]: Fh + Ah = 19h. 19h e' pari a
      ; 25d [decimale] - 10d = 15d pari a Fh
write_digit:   ; questa entrata e' per l'invio alla
      ; procedura di stampa
  call write_char   ; vai a stampare cifra inviata
  pop dx   ; recupera il valore originario di DX e...
  ret   ; ritorna alla chiamata call write_hex_digit
write_hex_digit endp    
       
       
     
  public write_char   ; procedura di stampa
     
write_char proc near  
  mov ah, 2h    
  int 21h    
  ret   ; ritorna a call write_char
write_char endp    
code_seg ends    
  end test_write_hex  
   

Le tre procedure [esclusa quella test] si occupano di:
- write_hex si occupa di isolare le singole cifre esadecimali mediante un shr e un and;
- write_hex_digit
si occupa di controllare le cifre inviate da write_hex e convertile in numeri e lettere a seconda che siano > o < di Ah;
- write_char
si occupa di stampare una dopo l'altra le cifre inviate da write_hex_digit.
Le chiamate alle procedure funzionano in questo modo:
test_write_hex
chiama write_hex. Una volta isolata la prima cifra write_hex chiama write_hex_digit per il controllo. La procedura write_hex_digit per prima cosa salva nello stack DX che ci servira' integro al ritorno a write_hex per l'isolamento della seconda cifra. Cosi' facendo, write_hex_digit puo' utilizzare il registro DL per la somma di "0" e di "A" -10 senza perdere il numero hex di prova. Isolato il primo numero e convertito in lettera o in numero, write_hex_digit chiama write_char per la stampa del numero ottenuto dalla conversione. La procedura write_char torna a write_hex_digit, preleva il numero test originario dallo stack e torna a write_hex per l'isolamento della seconda cifra. Questa subira' lo stesso trattamento della prima ma quando infine write_hex_digit tornera' a write_hex il ret di quest'ultima procedura rimandera' a test_write_hex dove sotto la call troveremo l'int 20h per restituire i comandi a dos e il programma terminera'.

Output decimale

Ripartiamo dal programma appena visto per aggiungere una nuova procedura per la scrittura di un numero in notazione esadecimale. La nuova procedura deve essere inserita al di sotto della procedura di test.
Cambia la procedura di controllo che diventa test_decimal, viene introdotta la nuova procedura write_decimal al posto di test_write_hex
e viene eliminta a la procedura write_hex. Ora la procedura principale ha il nome di test_decimal quindi l'end diventa end
test_decimal.

code_seg

 

segment ; nome del segmento di codice
assume cs:code_seg ; indicazione del nome del segmento di codice
  org 100h   ; inizio alla locazione di memoria 100
       
       
       
  public test_decimal ; procedura di test per provare le procedure
    ; che seguono
       
test_decimal proc near  
  mov dx, 12345   ; numero di prova
  call write_decimal   ; chiama la procedura write_decimal
  int 20h  
test_decimal endp    
       
       
       
  public write_decimal    
       
       
write_decimal proc near  
mov ax, dx   ; copia di DX perche' l'istruzione div [dividi]
      ; opera sul registro AX
  mov si,10   ; muove nel registro SI il numero 10
  ; sfruttera' la correlazione div, AX, [SI], DX
      ; al posto di SI per la divisionepoteva usare altri
      ; registri d'uso generale non impegnati.
xor cx, cx   ; azzera il contenuto del registro CX per usarlo
      ; come contatore per i numeri inviati allo stack
non_zero:    
xor dx,dx   ; azzera il contenuto di DX per ricevere il resto
      ; della divisione
div si   ; divide il contenuto di AX per il numero
      ; contenuto nel registro SI
push dx   ; inserisci resto in DX nello stack
inc cx   ; incrementa di 1 il contatore CX per i loop finali
or ax,ax   ; verifica AX se il numero e' stato diviso
      ; completamente
jne non_zero   ; se diverso vai a non_zero per ripetere ulteriori
      ; divisioni, se uguale...
write_digit_loop:    
  pop dx   ; estrai un "numero resto" dallo stack e...
call write_hex_digit   ; vai alla procedura di controllo e poi stampalo
  loop write_digit_loop   ; esegui i loop per CX numero di volte
  ; decrementa il contatore CX e
      ; vai ad estrarre un nuovo "numero resto"
      ; all'istruzione pop dx del loop write_digit_loop
end_decimal:    
ret   ; torna a test_decimal e fine
write_decimal endp    
       
       
     
public write_hex_digit   ; procedura di controllo per cifre esadecimali da
    ; convertire in numeri [< Ah] o lettere [> Ah]
   
write_hex_digit proc near  
push dx   ; metti il contenuto di DX nello stack cosi' da
cmp dl, 10   ; compara DL al decimale 10 che corrisponde
      ; all'esadecimale A per determinare se
      ; trasformarlo in lettera o numero
  jae hex_letter   ; se superiore o uguale trasforma in lettera
      ; saltando ad hex_letter
  add dl, "0"   ; altrimenti e' un numero, quindi addiziona "0"
  jmp short write_digit   ; vai alla chiamata di stampa write_digit per
  ; procedura di stampa write_char
hex_letter:     ; questa entrata e' per la trasformazione
      ; in lettera della cifra hex
add dl, "A" -10   ; addiziona cifra [> di A ] ad Ah e sottrai 10 dec
write_digit:   ; questa entrata e' per l'invio alla
      ; procedura di stampa
  call write_char   ; vai a stampare cifra inviata
  pop dx   ; recupera il valore originario di DX e...
  ret   ; ritorna alla call write_decimal
write_hex_digit endp    
       
       
     
  public write_char   ; procedura di stampa
     
write_char proc near  
  mov ah, 2h    
  int 21h    
  ret   ; ritorna a call write_char
write_char endp    
code_seg ends    
  end test_decimal  
   

Puoi scaricare deci.zip, la versione asm del programma appena scritto.
Le istruzioni nuove utilizzate in questo programma sono:
- XOR, ovvero or esclusivo e' una operazione logica che funziona secondo questa regola:

A
B
risultato
0
0
0
0
1
1
1
0
1
1
1
0

il risultato e' vero solo se un solo bit e' vero, quindi un numero messo in xor con se stesso produce sempre bit non veri 00000000.
- Div, l'istruzione per dividere il cui funzionamento e' stato illustrato nei commenti al programma; in sintesi:
operando sorgente ad un byte AX/sorgente: AH = quoziente, AL = resto. Operando sorgente una parola [16 bit] AX/sorgente: AX = quoziente, DX = resto.
- OR e' un'operazione logica che funziona secondo questa regola:

A
B
risultato
0
0
0
0
1
1
1
0
1
1
1
1

il risultato e' vero se solo un bit e' 0 o se sono tutti e due veri. Un numero messo in or con se stesso restituisce lo stesso numero. Nel nostro caso se il numero e' stato completamente diviso 00000000 messo in relazione con se stesso 00000000 restituisce 00000000 e quindi sapremo che il numero e' stato completamente diviso.

modulo VIII
torna a modulo VI  
 
 

Assembly modulo VIl primi passi nella costruzione del programma DSKPATCH.