;--------------------------------------------------;
; file jcond.asm                                   ; 
; programma di esempio per le istruzioni Jcond     ;
;--------------------------------------------------;
; nasm -f obj jcond.asm -l jcond.lst               ;
; tlink jcond.obj + exelib.obj                     ;
; (oppure link /map jcond.obj + exelib.obj)        ;
;--------------------------------------------------;                  

;########### direttive per l'assembler ############

CPU 386                             ; set di istruzioni a 32 bit
%include "exelib.inc"               ; inclusione libreria di I/O

;######### dichiarazione tipi e costanti ##########

%assign STACK_SIZE   0400h          ; 1024 byte per lo stack

;################ segmento dati ###################

SEGMENT     DATASEGM ALIGN=16 PUBLIC USE16 CLASS=DATA

;----- inizio definizione variabili statiche ------

vectWord    resw  20

strSign1    db    "e' positivo.", 0
strSign2    db    "e' negativo.", 0
strOverf    db    "e' in OVERFLOW!", 0

strCmp1     db    "e' maggiore di", 0
strCmp2     db    "e' minore di", 0
strCmp3     db    "e' uguale a", 0

stringaC    db    'Stringa alfanumerica da convertire in maiuscolo - [123]', 0
strBuffer   resb  128

;------- fine definizione variabili statiche ------

;############### segmento codice ##################

SEGMENT     CODESEGM ALIGN=16 PUBLIC USE16 CLASS=CODE

..start:                            ; entry point

   mov      ax, DATASEGM            ; trasferisce DATASEGM
   mov      ds, ax                  ; in DS attraverso AX

;------- inizio blocco principale istruzioni ------

   call     far set80x50            ; modo video 80 righe, 50 colonne
   call     far clearScreen         ; pulisce lo schermo
   
   push     ds                      ; copia DS
   pop      es                      ; in ES (per writeString)

; ATTENZIONE! Se si ha la necessita' di modificare ES, bisogna preservarne
; il vecchio contenuto; la procedura writeString presuppone, infatti, che
; ES contenga la componente Seg dell'indirizzo della stringa da visualizzare!

;  -------------------------------------------------------------------

;  Un blocco condizionale "IF - ELSE" permette di effettuare una
;  scelta basata sul risultato prodotto dalla valutazione di una
;  espressione booleana; la struttura generale del blocco
;  condizionale e' la seguente:

;  IF (espressione)
;     blocco istruzioni 1
;  ELSE
;     blocco istruzioni 2

;  Innanzi tutto viene valutata "espressione" e, se risulta TRUE, viene
;  eseguito il "blocco istruzioni 1", con conseguente uscita dall'intero
;  blocco condizionale; se "espressione" e' FALSE, viene eseguito il
;  "blocco istruzioni 2" associato all'ELSE.

;  I blocchi condizionali IF - ELSE possono essere anche innestati; cio'
;  significa che il "blocco istruzioni 1" e/o il "blocco istruzioni 2"
;  possono essere, a loro volta, degli ulteriori blocchi condizionali!

;  -------------------------------------------------------------------

;  Utilizziamo dei blocchi condizionali IF - ELSE innestati, per conoscere
;  il segno del risultato di una somma tra interi con segno a 16 bit in
;  complemento a 2; lo zero viene trattato come numero positivo. Il seguente
;  codice e' anche in grado di rilevare e segnalare un eventuale overflow;
;  inserendo in AX e BX una qualsiasi coppia lecita di numeri interi con
;  segno a 16 bit in complemento a 2, possiamo notare che il programma si
;  comporta sempre in modo corretto.
;  Si noti che il secondo blocco condizionale IF - ELSE, e' innestato
;  nella condizione ELSE del primo blocco condizionale.
;  In modalita' reale, le istruzioni Jcond non modificano nessun
;  campo del Flags Register, per cui possono essere utilizzate anche
;  in sequenza!

   mov      ax, -18421                 ; ax = primo addendo
   mov      bx, +11934                 ; bx = secondo addendo
   add      ax, bx                     ; ax = ax + bx
   jo       short overflow_label       ; IF (OF == 1)
   
no_overflow_label:                     ; ELSE
   js       short negative_label       ; IF (SF == 1)

positive_label:                        ; ELSE                     
   mov      di, strSign1               ; es:di punta a strSign1
   jmp      short output_label1        ; salta a output_label1

negative_label:                        ; il risultato e' negativo
   mov      di, strSign2               ; es:di punta a strSign2
   jmp      short output_label1        ; salta a output_label1

overflow_label:                        ; il risultato e' in overflow
   mov      di, strOverf               ; es:di punta a strOverf

output_label1:                         ; output dei risultati
   mov      dx, 0400h                  ; riga 4, colonna 0
   call     far writeSdec16            ; output somma (ax)

   mov      dx, 0407h                  ; riga 4, colonna 7
   call     far writeString            ; output stringa selezionata

;  Un blocco condizionale "IF - ELSE IF - ELSE" e' la generalizzazione
;  del blocco IF - ELSE, e permette quindi di effettuare un numero
;  arbitrario di scelte basate sul risultato prodotto dalla valutazione
;  di una espressione booleana; la struttura generale del blocco
;  condizionale e' la seguente:

;  IF (espressione 1)
;     blocco istruzioni 1
;  ELSE IF (espressione 2)
;     blocco istruzioni 2
;  ELSE IF (espressione 3)
;     blocco istruzioni 3
;  ELSE IF (espressione 4)
;     ..................
;  ELSE
;     blocco istruzioni n

;  In teoria, si puo' utilizzare un numero illimitato di condizioni
;  "ELSE IF".
;  Le varie "espressioni" vengono valutate in sequenza e, se una di esse
;  risulta TRUE, viene eseguito il relativo "blocco istruzioni", con
;  conseguente uscita dall'intero blocco condizionale; se nessuna delle
;  "espressioni" risulta TRUE, viene eseguito il "blocco istruzioni"
;  associato all'ultimo ELSE.

;  Come al solito, i blocchi condizionali possono essere anche innestati;
;  cio' significa che il "blocco istruzioni 1",  il "blocco istruzioni 2",
;  etc, possono essere, a loro volta, degli ulteriori blocchi condizionali!

;  -----------------------------------------------------------------------

;  Utilizziamo un blocco condizionale IF - ELSE IF - ELSE per conoscere il
;  risultato di una comparazione aritmetica tra due numeri interi senza
;  segno contenuti in AX e BX; inserendo in AX e BX qualsiasi coppia lecita
;  di numeri interi senza segno a 16 bit, possiamo notare che il programma
;  si comporta sempre in modo corretto.

   mov      ax, 16312               ; ax = 3FB8h
   mov      bx, 48173               ; bx = BC2Dh
   cmp      ax, bx                  ; compara ax con bx
   ja       short above_label       ; IF (ax maggiore di bx)
   jb       short below_label       ; ELSE IF (ax minore di bx)
   
equal_label1:                       ; ELSE
   mov      di, strCmp3             ; es:di punta a strCmp3
   jmp      short output_label2     ; salta a output_label2

above_label:                        ; ax e' maggiore di bx
   mov      di, strCmp1             ; es:di punta a strCmp1
   jmp      short output_label2     ; salta a output_label2

below_label:                        ; ax e' minore di bx
   mov      di, strCmp2             ; es:di punta a strCmp2

output_label2:                      ; output dei risultati
   mov      dx, 0600h               ; riga 6, colonna 0
   call     far writeUdec16         ; output ax = DEST

   mov      dx, 0606h               ; riga 6, colonna 6
   call     far writeString         ; output stringa selezionata

   mov      dx, 0615h               ; riga 6, colonna 21
   mov      ax, bx                  ; ax = bx = SRC
   call     far writeUdec16         ; output ax = SRC

;  Utilizziamo un blocco condizionale IF - ELSE IF - ELSE per conoscere il
;  risultato di una comparazione aritmetica tra due numeri interi con segno
;  a 16 bit in complemento a 2, contenuti in AX e BX; inserendo in AX e BX
;  qualsiasi coppia lecita di numeri interi con segno a 16 bit in complemento
;  a 2, possiamo notare che il programma si comporta sempre in modo corretto.

   mov      ax, +16312              ; ax = 3FB8h
   mov      bx, -17363              ; bx = BC2Dh
   cmp      ax, bx                  ; compara ax con bx
   jg       short greater_label     ; IF (ax maggiore di bx)
   jl       short less_label        ; ELSE IF (ax minore di bx)
   
equal_label2:                       ; ELSE
   mov      di, strCmp3             ; es:di punta a strCmp3
   jmp      short output_label3     ; salta a output_label3

greater_label:                      ; ax e' maggiore di bx
   mov      di, strCmp1             ; es:di punta a strCmp1
   jmp      short output_label3     ; salta a output_label3

less_label:                         ; ax e' minore di bx
   mov      di, strCmp2             ; es:di punta a strCmp2

output_label3:                      ; output dei risultati
   mov      dx, 0800h               ; riga 8, colonna 0
   call     far writeSdec16         ; output ax = DEST

   mov      dx, 0807h               ; riga 8, colonna 7
   call     far writeString         ; output stringa selezionata

   mov      dx, 0816h               ; riga 8, colonna 22
   mov      ax, bx                  ; ax = bx = SRC
   call     far writeSdec16         ; output ax = SRC

;  Si definisce iterazione (o ciclo, o loop), una tecnica che permette di
;  ripetere (iterare) per un certo numero di volte consecutive, uno stesso
;  blocco di istruzioni; le iterazioni vengono largamente utilizzate per
;  gestire vettori di qualsiasi natura.

;  Nel caso piu' semplice, il numero n di iterazioni da effettuare e'
;  noto in partenza; questa situazione puo' essere gestita facilmente con
;  un cosiddetto "ciclo FOR".
;  La struttura generale del ciclo FOR e' la seguente:

;  RIPETI PER (FOR) i che va da 0 a (n - 1)
;     blocco istruzioni

;  La variabile "i" viene definita "contatore", mentre "n" rappresenta il
;  numero di cicli da effettuare; nel caso piu' frequente, il contatore
;  "i" viene inizializzato con il valore 0, e viene incrementato di 1 ad
;  ogni ciclo finche' non raggiunge il valore "n" (condizione di uscita
;  dal ciclo).
;  Si puo' seguire anche un procedimento inverso che consiste
;  nell'inizializzare il contatore con il valore "n"; il contatore viene
;  poi decrementato di 1 ad ogni ciclo finche' non raggiunge il valore 0
;  (condizione di uscita dal ciclo).

;  Molto spesso, il numero di iterazioni da effettuare non e' noto a
;  priori; in questo caso si utilizzano i cicli DO - WHILE e WHILE - DO.

;  La struttura generale del ciclo DO - WHILE e' la seguente:

;  DO
;     blocco istruzioni
;  WHILE "espressione"

;  Innanzi tutto viene eseguito il "blocco istruzioni"; successivamente
;  viene valutata "espressione" e, se risulta TRUE, si ricomincia da
;  capo (si riesegue cioe', "blocco istruzioni"); questa situazione si
;  ripete finche' (while) "espressione" rimane TRUE.
;  Quando "espressione" diventa FALSE, il ciclo termina; ovviamente, se
;  "espressione" rimane sempre TRUE, il ciclo continua all'infinito
;  (loop infinito)!
;  Come si puo' notare, anche se "espressione" e' FALSE in partenza, il
;  ciclo DO - WHILE viene eseguito almeno una volta!

;  (Il ciclo DO - WHILE del C, equivale al ciclo REPEAT - UNTIL del
;  Pascal.)

;  La struttura generale del ciclo WHILE - DO e' la seguente:

;  WHILE (espressione)
;     blocco istruzioni
;  DO

;  Innanzi tutto viene valutata "espressione" e, se risulta TRUE, viene
;  eseguito il "blocco istruzioni"; questa situazione si ripete finche'
;  (while) "espressione" rimane TRUE.
;  Quando "espressione" diventa FALSE, il ciclo termina; ovviamente, se
;  "espressione" rimane sempre TRUE, il ciclo continua all'infinito
;  (loop infinito)!
;  Come si puo' notare, se "espressione" e' FALSE in partenza, il ciclo
;  WHILE - DO non viene mai eseguito!

;  --------------------------------------------------------------------

;  Utilizziamo un ciclo FOR per inizializzare e visualizzare un vettore
;  di 20 elementi di tipo intero senza segno a 16 bit; in questo caso, il
;  ciclo FOR e' quello piu' indicato in quanto conosciamo in partenza il
;  numero (20) di iterazioni da effettuare.
;  Gli elementi del vettore vengono inizializzati con il quadrato
;  del loro indice 0, 1, 2, 3, ...
;  Come contatore viene utilizzato CX (counter register).

%assign NUM_LOOPS 20                ; numero cicli

; inizializzazione del vettore

   xor      bx, bx                  ; bx = 0
   xor      si, si                  ; si = 0 (indice vettore)
   mov      cx, NUM_LOOPS           ; cx = numero cicli

initvector_loop:                    ; FOR cx che va da 20 a 0

   mov      ax, si                  ; ax = indice vettore
   mul      ax                      ; dx:ax = ax * ax
   mov      [vectWord+bx], ax       ; salva nel vettore

   inc      si                      ; incremento indice
   add      bx, 2                   ; prossima WORD di vectWord
   dec      cx                      ; decremento contatore
   jnz      short initvector_loop   ; controllo loop (CX == 0) ?

; output del vettore

   xor      bx, bx                  ; bx = 0
   xor      si, si                  ; si = 0 (indice vettore)
   mov      dx, 0A00h               ; riga, colonna iniziali
   mov      cx, NUM_LOOPS           ; cx = numero cicli

outputvector_loop:                  ; FOR cx che va da 20 a 0

   mov      ax, si                  ; ax = indice vettore
   call     far writeUdec8          ; output indice

   add      dl, 5                   ; colonna 5
   mov      ax, [vectWord+bx]       ; elemento da visualizzare
   call     far writeUdec16         ; output elemento

   xor      dl, dl                  ; colonna 0
   inc      dh                      ; incremento riga
   inc      si                      ; incremento indice
   add      bx, 2                   ; prossima WORD di vectWord
   dec      cx                      ; decremento contatore
   jnz      short outputvector_loop ; controllo loop (CX == 0) ?

;  Utilizziamo un ciclo WHILE - DO per convertire in maiuscolo una stringa C;
;  e' necessario utilizzare questo ciclo in quanto non conosciamo in anticipo
;  la lunghezza della stringa.
;  Il ciclo WHILE - DO e' preferibile al DO - WHILE in quanto la stringa
;  potrebbe anche avere una lunghezza nulla; in un caso del genere, il
;  "blocco istruzioni" non viene mai eseguito!
;  I codici ASCII delle lettere minuscole vanno da 97 a 122 (da 'a' a 'z'),
;  mentre i codici ASCII delle lettere maiuscole vanno da 65 a 90 (da 'A' a
;  'Z'); e' importante notare che in entrambi i casi, tali codici sono
;  consecutivi e contigui!
;  Data una lettera minuscola e la corrispondente lettera maiuscola, la
;  differenza tra i rispettivi codici ASCII e' 32; ad esempio:
;  'a' - 'A' = 32
;  Di conseguenza: 'A' = 'a' - 32.
;  Il nostro ciclo verifica innanzi tutto che un elemento della stringa sia
;  una lettera minuscola; solo in questo caso viene effettuata la conversione
;  in maiuscolo che consiste nel sottrarre 32 all'elemento stesso

   mov      di, stringaC            ; es:di punta a stringaC
   mov      dx, 2000h               ; riga 20h, colonna 00h
   call     far writeString         ; output stringa da convertire

strconvert_loop:                    ; WHILE ([ds:di] != 0)
   mov      al, [di]                ; al = codice ASCII da esaminare
   test     al, al                  ; (al == 0) ?
   jz       short exit_loop         ; if (al == 0) jump exit_loop
   cmp      al, 'a'                 ; confronta al con 'a'
   jb       short next_char         ; non e' una minuscola
   cmp      al, 'z'                 ; confronta al con 'z'
   ja       short next_char         ; non e' una minuscola

   sub      al, 32                  ; converte in maiuscolo
   mov      [di], al                ; salva in stringaC

next_char:
   inc      di                      ; prossimo elemento di stringaC
   jmp      short strconvert_loop   ; DO

exit_loop:

   mov      di, stringaC            ; es:di punta a stringaC
   mov      dx, 2200h               ; riga 22h, colonna 00h
   call     far writeString         ; output stringa convertita

;  Utilizziamo un ciclo DO - WHILE per copiare stringaC in strBuffer; e'
;  possibile utilizzare questo ciclo in quanto dobbiamo copiare in
;  strBuffer anche lo zero finale di stringaC (in sostanza, il ciclo deve
;  essere eseguito almeno una volta).
;  Naturalmente, strBuffer deve avere lo spazio sufficiente per contenere
;  stringaC; in caso contrario, invadiamo aree riservate della memoria!

   mov      di, stringaC            ; ds:di punta a stringaC
   mov      si, strBuffer           ; ds:si punta a strBuffer

strcopy_loop:                       ; DO
   mov      al, [di]                ; al = elemento da copiare
   mov      [si], al                ; copia in strBuffer

   inc      di                      ; prossimo elemento di stringaC
   inc      si                      ; prossimo elemento di strBuffer
   test     al, al                  ; (al == 0) ?
   jnz      short strcopy_loop      ; WHILE (al != 0)

   mov      di, strBuffer           ; es:di punta a strBuffer
   mov      dx, 2400h               ; riga 24h, colonna 00h
   call     far writeString         ; output strBuffer

;-------- fine blocco principale istruzioni -------
   
   mov      ah, 4ch                 ; servizio Terminate Program
   mov      al, 00h                 ; exit code = 0
   int      21h                     ; chiama i servizi DOS

;################# segmento stack #################

SEGMENT     STACKSEGM ALIGN=16 STACK USE16 CLASS=STACK

            resb     STACK_SIZE     ; 1024 byte per lo stack
            
;##################################################