;------------------------------------------------------------------------------
TITLE - Programma N° 33
;------------------------------------------------------------------------------
;----------------------------------------------------------
; Prova Assembler esame di Calcolatori Elettronici A - 26/01/2007
;----------------------------------------------------------
;NOME: prog33.asm
;AUTORE: Mattia Panciroli (157499)
;DESCRIZIONE: Programma N. 33
;
;
; Il programma deve:
; - accettare in ingresso un numero di quattro cifre
; - stampare tutti i numeri (di 4 cifre) diversi tra loro che è possibile
; formare con le cifre del primo numero
; - stampare i numeri in modo che compaiano in una sola schermata
; - stampare i numeri in ordine crescente
;**********************************************************
; Definizioni costanti
;**********************************************************
;----------- Gestione video -----------
PAGINA EQU 00h
;-------- Gestione bios video ---------
BIOS_VIDEO EQU 10h ; Interrupt gestione video
SET_VIDEO_MODE EQU 00h ; Impostazione modalita' video
MODO_TESTO EQU 03h ; Modaliita' 80 x 25 caratteri a colori
W_CHR_TTY EQU 0Eh ; Scrittura carattere
SET_CURSOR EQU 02h ; Posizione cursore
;--------- Gestione tastiera ----------
KEY_IO_SERVICE EQU 16h ; Interrupt gestione tastiera
R_KEY EQU 00h ; Legge un carattere
;----------- Interrupt DOS ------------
DOS EQU 21h ; Interrupt DOS
PRINT_STRING EQU 09h ; Stampa stringa
;--------- Costanti programma ---------
; Costanti realtive a tasti della tastiera e caratteri
TASTO_INVIO EQU 0Dh
BS EQU 08h
HT EQU 09h
CR EQU 0Dh
LF EQU 0Ah
;**********************************************************
; Definizioni variabili
;**********************************************************
DSEG SEGMENT PARA PUBLIC 'DATA'
;-------- Stringhe da stampare --------
; Stringhe di output del programma
PRESENTAZIONE_S DB HT,HT,'SEQUENZA ORDINATA DI NUMERI DECIMALI A 4 CIFRE',CR,LF,'$'
IMMISSIONE DB CR,LF,'Inserire quattro cifre decimali: $'
TERMINE DB CR,LF,CR,LF,'Ripetere? (s\n) $'
;-------- Variabili programma ---------
V DB 4 DUP(0) ; Vettore che memorizza le quattro cifre
E DW 0 ; Numero corrente
DSEG ENDS
;**********************************************************
; Definizione stack
;**********************************************************
STACKM SEGMENT PARA STACK 'STACK'
DB 64 DUP(' ')
STACKM ENDS
;**********************************************************
; Codice programma
;**********************************************************
ASSUME CS:CSEG, DS:DSEG, SS:STACKM
CSEG SEGMENT PARA PUBLIC 'CODE'
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;----------------------------------------------------------
;| Corpo pincipale programma |
;----------------------------------------------------------
MAIN PROC FAR
PUSH DS ; Istruzioni necessarie da lasciare in
MOV AX,00h ; questa posizione
PUSH AX
CALL INIZIALIZZAZIONE
CICLO_PRINCIPALE:
CALL PRESENTAZIONE ; Stampa etichetta programma
CALL LEGGI_DATI ; Legge il numero in ingresso
CALL STAMPA_SEQUENZA ; Stampa la sequenza ordinata di numeri
CALL TEST_FINALE ; Ripetere? (s/n)
JZ FINE
CALL SETTA_MOD_VIDEO ; Pulisce lo schermo
JMP CICLO_PRINCIPALE
FINE:
CALL SETTA_MOD_VIDEO ; Ripristina il video e pulisce lo schermo
RET
MAIN ENDP
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;----------------------------------------------------------
;| Procedure |
;----------------------------------------------------------
;----------------------------------------------------------
;------------- Procedura di inizializzazione --------------
;
; Registri utilizzati: AX, DS
;----------------------------------------------------------
INIZIALIZZAZIONE PROC NEAR
MOV AX,DSEG ; Inizializzazione segmento dati
MOV DS,AX
CALL SETTA_MOD_VIDEO
RET
INIZIALIZZAZIONE ENDP
;----------------------------------------------------------
;--------------- Procedura di presentazione ---------------
;
; Registri utilizzati: DX
;----------------------------------------------------------
PRESENTAZIONE PROC NEAR
MOV DX,offset PRESENTAZIONE_S
CALL STAMPA_STRINGA
RET
PRESENTAZIONE ENDP
;----------------------------------------------------------
;-------------- Procedura per leggere i dati --------------
;
; Ritorna: V inizializzato
; Registri utilizzati: AL, DX
;----------------------------------------------------------
LEGGI_DATI PROC NEAR
MOV DX,offset IMMISSIONE
CALL STAMPA_STRINGA
CALL LEGGI_CIFRA
MOV [V+0],AL
CALL LEGGI_CIFRA
MOV [V+1],AL
CALL LEGGI_CIFRA
MOV [V+2],AL
CALL LEGGI_CIFRA
MOV [V+3],AL
RET
LEGGI_DATI ENDP
;----------------------------------------------------------
;----------- Procedura per stampare la sequenza---------
;
; Parametri: V,E
; Registri utilizzati: AX,BX, CX, DX
;----------------------------------------------------------
STAMPA_SEQUENZA PROC NEAR
;---------------------------------
MOV DX,0400h ; Sposta il cursore in (4,0)
CALL SPOSTA_CURSORE
;---------------------------------
; Procedura di ordinamento del vettore V
XOR AX,AX
SU1:
MOV DI,AX
MOV CL,V[DI]
MOV BX,AX
INC BX
SU2:
MOV DI,BX
CMP CL,V[DI]
JNG GIU
MOV CH,V[DI]
MOV V[DI],CL
MOV DI,AX
MOV V[DI],CH
MOV CL,CH
GIU:
INC BX
CMP BX,4
JNE SU2
INC AX
CMP AX,3
JNE SU1
; Inizio algoritmo sequenza
MOV [E],-1 ; Inizializzo numero corrente
MOV CH,0
A1:
MOV CL,0
A2:
MOV DH,0
A3:
MOV DL,0
A4:
; Test di verifica che tutte le cifre siano tutte diverse
CMP CH,CL
JE NULLA
CMP CH,CL
JE NULLA
CMP CH,DH
JE NULLA
CMP CH,DL
JE NULLA
CMP CL,DH
JE NULLA
CMP CL,DL
JE NULLA
CMP DL,DH
JE NULLA
; Test di verifica che il numero corrente sia maggiore del precedente
CALL CONV_DEC
CMP [E],AX
JGE NULLA
MOV [E],AX
; Il numero formalmente corretto per la sequenza viene stampato
CALL STAMPA_NUMERO
NULLA:
INC DL
CMP DL,4
JNE A4
INC DH
CMP DH,4
JNE A3
INC CL
CMP CL,4
JNE A2
INC CH
CMP CH,4
JNE A1
RET
STAMPA_SEQUENZA ENDP
;----------------------------------------------------------
;----------- Procedura per convertire gli elementi del vettore in numero---------
;
; Parametri: V contiene le quattro cifre decimali
; Registri utilizzati: AX,BX, CX, DX
; Ritorna: AX numero convertito
;----------------------------------------------------------
CONV_DEC PROC NEAR
PUSH DX
XOR AX,AX
XOR BX,BX
MOV BL,CH ; Carico la prima cifra in AL
MOV DI,BX
MOV AL,V[DI]
MOV BX,10 ; Moltiplico la prima cifra x10
MUL BX
MOV BL,CL ; Carico la seconda cifra in BL
MOV DI,BX
XOR BH,BH
MOV BL,V[DI]
ADD AX,BX ; Sommo la seconda cifra alla prima moltiplicata x10
MOV BX,10 ; Moltiplico AX x10
MUL BX
POP DX
PUSH DX
MOV BL,DH ; Carico la terza cifra in BL
MOV DI,BX
XOR BH,BH
MOV BL,V[DI]
ADD AX,BX ; Sommo la terza cifra ad AX
MOV BX,10 ; Moltiplico AX x10
MUL BX
POP DX
PUSH DX
MOV BL,DL ; Carica la quarta cifra in BL
MOV DI,BX
XOR BH,BH
MOV BL,V[DI]
ADD AX,BX ; Sommo la quarta cifra ad AX
POP DX
RET
CONV_DEC ENDP
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;----------------------------------------------------------
;| Procedure di basso livello di interfaccia |
;----------------------------------------------------------
;----------------------------------------------------------
;--------- Procedura che setta la modalita' video ---------
;
; Registri utilizzati: AX, DX
;----------------------------------------------------------
SETTA_MOD_VIDEO PROC NEAR
MOV AH,SET_VIDEO_MODE ; Impostazione modalità video
MOV AL,MODO_TESTO ; e pulizia lo schermo
INT BIOS_VIDEO
MOV DX,0000h ; Sposta il cursore in (0,0)
CALL SPOSTA_CURSORE
RET
SETTA_MOD_VIDEO ENDP
;----------------------------------------------------------
;------- Procedura per stampare un numero da 0 a 9999 ------
;
; Paramentri: AX numero da stampare
; Registri utilizzati: AX, BL, CX
;----------------------------------------------------------
STAMPA_NUMERO PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
XOR DX,DX
MOV BX,10 ; Divido il numero x10
DIV BX ; Il resto sono le unità
PUSH DX ; Salvo nello stack
XOR DX,DX ; Ripeto l'operazione
DIV BX
PUSH DX
XOR DX,DX ; Ripeto l'operazione
DIV BX
PUSH DX
CALL STAMPA_CIFRA ; Stampa le migliaia
POP AX
CALL STAMPA_CIFRA ; Stampa le centinaia
POP AX
CALL STAMPA_CIFRA ; Stampa le decine
POP AX
CALL STAMPA_CIFRA ; Stampa le unità
MOV AL,' '
CALL STAMPA_CAR
POP DX
POP CX
POP BX
POP AX
RET
STAMPA_NUMERO ENDP
;----------------------------------------------------------
;-------- Procedura per leggere una cifra da 0 a 9 --------
;
; Ritorna: Zero_flag = 0 premuto invio
; Zero_flag = 1 letta cifra
; AL cifra letta
; Registri utilizzati: AH
;----------------------------------------------------------
LEGGI_CIFRA PROC NEAR
RILEGGI:
CALL LEGGI_TASTO_NE
CMP AL,'0' ; Controlla sia un cifra se no rilegge
JL RILEGGI
CMP AL,'9'
JG RILEGGI
MOV BL,AL ; Visualizza la cifra
CALL STAMPA_CAR
MOV AL,BL
SUB AL,'0'
XOR AH,AH ; Setta lo Zero_flag
RET
LEGGI_CIFRA ENDP
;----------------------------------------------------------
;-- Procedura per stampare una cifra da 0 a 9 con blank ---
;
; Parametri: BL = 0 blank
; BL <> 1 zero
; AL cifra
; Registri utilizzati:
;----------------------------------------------------------
STAMPA_CIFRA PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
ADD AL,'0' ; altrimenti stampo la cifra
CALL STAMPA_CAR
POP DX
POP CX
POP BX
POP AX
RET
STAMPA_SPAZIO:
MOV AL,' '
CALL STAMPA_CAR
RET
STAMPA_CIFRA ENDP
;----------------------------------------------------------
;---------- Procedura per vedere se teriminare -----------
;
; Ritorna: Zero_flag = 0 ripeti
; Zero_flag = 1 esci
; Registri utilizzati: AL, DX
;----------------------------------------------------------
TEST_FINALE PROC NEAR
MOV DX,offset TERMINE ; Stampa la richiesta
CALL STAMPA_STRINGA
CALL LETTURA_SN ; Leggere risposta
CMP AL,'n'
RET
TEST_FINALE ENDP
;----------------------------------------------------------
;------------- Procedura per stampare stringa -------------
;
; Paramentri: DS:DX indirizzo stringa
; Registri utilizzati: AH, DX
;----------------------------------------------------------
STAMPA_STRINGA PROC NEAR
MOV AH,PRINT_STRING
INT DOS
RET
STAMPA_STRINGA ENDP
;----------------------------------------------------------
;-- Procedura per leggere da tastiera i caratteri S o N ---
;
; Ritorna: AL codice ascii del tasto letto
; Registri utilizzati: AX
;----------------------------------------------------------
LETTURA_SN PROC NEAR
NUOVA_LETTURA:
CALL LEGGI_TASTO_NE
OR AL,00100000b ; Rende il carattere minuscolo
CMP AL,'n' ; Se il tasto è 'n'
JZ FINE_LETTURA ; termina la procedura
CMP AL,'s' ; Se il tasto non è 's'
JNZ NUOVA_LETTURA ; ripete la lettura
FINE_LETTURA:
RET
LETTURA_SN ENDP
;----------------------------------------------------------
;------- Procedura per leggere un tasto senza eco --------
;
; Ritorna: AL codice ascii del tasto letto
; Registri utilizzati: AX
;----------------------------------------------------------
LEGGI_TASTO_NE PROC NEAR
MOV AH,R_KEY ; Legge un carattere dal buffer
INT KEY_IO_SERVICE
RET
LEGGI_TASTO_NE ENDP
;----------------------------------------------------------
;---------- Procedura per stampare un carattere -----------
;
; Ritorna: AL carattere da stampare
; Registri utilizzati: AX
;----------------------------------------------------------
STAMPA_CAR PROC NEAR
MOV AH,W_CHR_TTY ; Scrive il carattere
INT BIOS_VIDEO
RET
STAMPA_CAR ENDP
;----------------------------------------------------------
;----------- Procedura per spostare il cursore ------------
;
; Ritorna: DH riga
; DL colonna
; Registri utilizzati: AX, BH
;----------------------------------------------------------
SPOSTA_CURSORE PROC NEAR
MOV BH,PAGINA
MOV AH,SET_CURSOR ; Sposta il cursore
INT BIOS_VIDEO
RET
SPOSTA_CURSORE ENDP
CSEG ENDS
END MAIN