TITLE accumain.asm: per esercitazione Calcolatori 30/11/2020 comment * Programma unico (main) per l'accumulazione in assembler 8086. Poi esteso alla versione chiamante e subroutine (accuproc.asm). data creazione: 29 novembre 2020 ultima revisione: 30 novembre 2020 * ;----------------------------------------------------------------- ; Definizione costanti CR EQU 13 ; carriage return LF EQU 10 ; line feed DOLLAR EQU '$' ;----------------------------------------------------------------- ; M A C R O ;----------------------------------------------------------------- display macro xxxx ; N.B. ogni stringa deve terminare con '$' push dx push ax mov dx,offset xxxx mov ah,9 int 21h pop ax pop dx endm ;----------------------------------------------------------------- ; PILA SEGMENT STACK 'STACK' ; definizione del segmento di stack DB 64 DUP('STACK') ; lo stack e' riempito con la stringa 'stack' ; per identificarlo meglio in fase di debug PILA ENDS ;----------------------------------------------------------------- ; DATI SEGMENT PUBLIC 'DATA' ; definizione del segmento dati CRLF db CR,LF,DOLLAR COMMA db ',',DOLLAR messaggio_v db "vettore da accumulare: ",DOLLAR messaggio_n db "numero di elementi (n): ",DOLLAR messaggio_i db "intruso: ",DOLLAR messaggio_s db "risultato (lettura per bytes): ",DOLLAR messaggio_w_even db "risultato (lettura per words, ipotesi n pari): ",DOLLAR messaggio_w db "risultato (lettura per words): ",DOLLAR vec_12_w label word vec_2 label byte vec_1 db 17,35,88,13,56,39,57,131 n_1 equ $-vec_1 ; = 8 ($ e' chiamato "location counter") db 223,107,67 n_2 equ $-vec_2 ; = 11 somma_1 dw ? ; = 436 somma_2 dw ? ; = 833 somma_1_w dw ? ; = 436 somma_2_w dw ? ; = 833 ; per conversione del risultato in ASCII e stampa a video max_strlen equ 16 stringa_ax db max_strlen dup (?),' $' alfabeto_numerazione db "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" DATI ENDS ;================================================================= CSEG1 SEGMENT PUBLIC 'CODE' MAIN proc far ASSUME CS:CSEG1,DS:DATI,SS:PILA,ES:NOTHING; MOV AX,SEG DATI MOV DS,AX ;****** DISPLAY e ACCUMULAZIONE del VETTORE vec_1 ***** ; stampa a video dati display crlf display messaggio_v ; elementi del vettore mov cx,n_1 mov si,offset vec_1 xor dh,dh display_loop_1: mov dl,[si] mov ax,dx call near ptr display_ax dec cx jz loop_end_1 display comma inc si jmp display_loop_1 loop_end_1: display crlf display messaggio_n ; dimensione del vettore mov ax,n_1 call near ptr display_ax ACCUMULA_1: ; lettura byte a byte xor ax,ax xor dh,dh ; superflua (messa gia' prima), ma si rimette qui per chiarezza mov cx,n_1 ; N.B. e' la terza volta che copiamo n_1 in un registro, e la seconda che copiamo offset vect_1 in si: mov si, offset vec_1 ; una soluzione alternativa e' salvare in stack (cfr. programma chiamante/subroutine) ciclo_accum_1: mov dl,[si] add ax,dx inc si dec cx jnz ciclo_accum_1 salva_1: mov somma_1,ax display crlf display messaggio_s ; risultato call near ptr display_ax display crlf ACCUMULA_1_w: ; lettura per words xor ax,ax xor bh,bh mov cx,n_1 mov si, offset vec_12_w ; = offset vec_1 = offest vec_2 ciclo_accum_1_w: mov dx,[si] mov bl,dh xor dh,dh add ax,bx add ax,dx add si,2 sub cx,2 ja ciclo_accum_1_w ; jump if above, ossia jump not below or equal (=jnbe) ; qui se l'ultima sub cx,2 ha dato cx == 0 o cx == -1. ; nel secondo caso si deve sottrarre il byte "intruso", ; che e' stato messo in bl (little-endian) jz salva_1_w display crlf display messaggio_w_even ; risultato supponendo cx == 0 call near ptr display_ax push ax ; si "parcheggia" ax nello stack per poterlo "sporcare" mov ax,bx display crlf display messaggio_i call near ptr display_ax ; stampa a video del byte "intruso" pop ax ; si ripristina il precedente valore di ax sub ax,bx ; si toglie dall'accumulatore il byte "intruso" salva_1_w: mov somma_1_w,ax display messaggio_w ; risultato call near ptr display_ax display crlf ;****** DISPLAY e ACCUMULAZIONE del VETTORE vec_2 ***** ; stampa a video dati display crlf display messaggio_v ; elementi del vettore mov cx,n_2 mov si,offset vec_2 xor dh,dh display_loop_2: mov dl,[si] mov ax,dx call near ptr display_ax dec cx jz loop_end_2 display comma inc si jmp display_loop_2 loop_end_2: display crlf display messaggio_n ; dimensione del vettore mov ax,n_2 call near ptr display_ax ACCUMULA_2: xor ax,ax xor dh,dh mov cx,n_2 mov si, offset vec_2 ciclo_accum_2: mov dl,[si] add ax,dx inc si dec cx jnz ciclo_accum_2 salva_2: mov somma_2,ax display crlf display messaggio_s ; risultato call near ptr display_ax ACCUMULA_2_w: ; lettura per words xor ax,ax xor bh,bh mov cx,n_2 mov si, offset vec_12_w ; = offset vec_1 = offest vec_2 ciclo_accum_2_w: mov dx,[si] mov bl,dh xor dh,dh add ax,bx add ax,dx add si,2 sub cx,2 ja ciclo_accum_2_w ; jump if above, ossia jump not below or equal (=jnbe) ; qui se l'ultima sub cx,2 ha dato cx == 0 o cx == -1. ; nel secondo caso devo sottrarre il byte "intruso", ; che e' stato messo in bl (little-endian) jz salva_2_w display crlf display messaggio_w_even ; risultato supponendo cx == 0 call near ptr display_ax push ax ; qui se cx == -1 (jl) mov ax,bx display crlf display messaggio_i call near ptr display_ax ; stampa a video del byte "intruso" pop ax sub ax,bx ; si toglie dall'accumulatore il byte "intruso" salva_2_w: mov somma_2_w,ax display crlf display messaggio_w ; risultato call near ptr display_ax display crlf ;*************************************************************** exit: MOV AH,4CH ; ritorno al DOS INT 21H main endp ; routine di conversione di un numero a 16 bit (il cui valore e' posto nello stack) ; nell'equivalente in una base prefissata, espresso in ASCII e posto ; in una stringa di N caratteri, il cui indirizzo e' anch'esso inserito nello stack ; prima della chiamata. Il valore di ritorno N rimpiazza il valore immesso nello stack ; dal chiamante, che indica la base in cui convertire il numero ; bin2bascii proc near push ax push bx push cx push dx push si push di push bp pushf mov bp,sp add bp,16 ; rimuove l'effetto dei push qui sopra mov ax,SS:[bp+6] ; numero da convertire (e' sepolto sotto 3 words) mov bx,[bp+2] mov cx,0 again: xor dx,dx div bx ; in DX il resto, in AX il quoziente di [DX:AX]/[BX] ; N.B. con or dx,0030h si renderebbe ASCII il contenuto di dx mov si,dx mov dl,alfabeto_numerazione[si] ; si prende il simbolo di numerazione dall'array apposito xor dh,dh push dx inc cx cmp ax,0 je save_result jmp again save_result: mov di,0 mov bx,[bp+4] ; offset della stringa destinazione cycle: pop dx mov [bx][di],dl inc di loop cycle mov [bp+2],di ; numero di caratteri nella stringa destinazione popf pop bp pop di pop si pop dx pop cx pop bx pop ax ret bin2bascii endp ; routine di conversione e stampa a video formattata ; di un numero intero non negativo posto nel registro AX ; display_ax proc near push ax push bx push ax mov ax,offset stringa_ax push ax mov ax,10 push ax call near ptr bin2bascii pop bx ; in bx il numero di caratteri della stringa add sp,4 mov stringa_ax[bx],'$' ; $ per poter stampare display stringa_ax pop bx pop ax ret display_ax endp cseg1 ends END MAIN ; il programma comincia all'indirizzo di MAIN