Assembly Language Examples

Assembly Language Programming Examples
.James Zou.
10/24/2010

You must be crazy if you are ineresting in reading this kind of stuff here.

Example 1.  
.model small, c
.386
dseg    segment ‘data’
        copy_from       equ     0c000h                  ;copying from c000h segment
        copy_to         equ     8000h                   ;copying to 8000h segment
        n_data_tran     equ     0ffffh                  ;64k
        int_segment     equ     42h                     ;segment for INT 10 (i*4)
        int_offset      equ     40h                     ;offset for INT 10
dseg    ends
sseg    segment stack ‘stack’
        dw 100 dup(“s”)
        top_stack label word
sseg    ends

eseg    segment ‘data’
eseg    ends

cseg    segment ‘code’
        assume cs:cseg, ds:dseg, ss:sseg, es:eseg
start:
        mov     ax,dseg                         ;setup segment registers
        mov     ds,ax

        mov     ax,copy_from                    ;setup c000h segment register
        mov     ds,ax
        mov     ax,copy_to                      ;setup 8000h segment register
        mov     es,ax
        xor     si,si                           ;reset si…
        xor     di,di                           ;…and di

        mov     cx,n_data_tran                  ;set count, number of by to be copy
        rep     movsb

        ;modify INT 10 vector to point to the 8000 segment
        mov     ax,0000h                        ;init ax register for segment change
        mov     es,ax                           ;change the segment to point to the vector table
        mov     bx,int_segment                  ;get the interrupt type segment 8000h
        mov     ax,8000h                        ;address for the segment
        mov     es:[bx],ax                      ;INT 10 point to 8000h segment
.exit
end     start
Example 2.
.model small
 .stack 100h
 .386
 .data
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       Intialization                                                         ;
;                                                                             ;
;…………………………………………………………………..;
        input_request_msg       db ‘Enter CMOS register to read: 00h-8Fh’,0
        hit_any_key_msg         db ‘Hit any key to contiune’,0dh,0ah,'<ESC> to escape’
        nmi_msg                 db ‘NMI is ‘
        on_msg                  db ‘on ‘
        off_msg                 db ‘off ‘
;……………………………………………………………………

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       Control flow:                                                         ;
;       -cls                                                                  ;
;       -get data
;       -display NMI on or off depend on user input
;       -read CMOS location                                                              ;
;       -dipslay result                                                       ;
;       -repeat or exit                                                       ;
;…………………………………………………………………..;

.code
.startup

 control_loop:
        call    clear_scrn_25_x_80       ; clear the screen
        mov     cx, lengthof input_request_msg; set cx for string display
        mov     bp, offset input_request_msg; set pointer for string display
        xor     dx,dx                   ; set cusor position for screen display
        call    print_string_uc         ; display input request message
        call    get_byte_to_8F          ; get byte from user
        jnc     buffer_good             ; jump is user input good
        cmp     al, 27                  ; check for exc key
        je      exit_point              ; if esc pressed, exit program
        call    beep_char               ; any other error, beep and re-prompt
        jmp     control_loop            ; get new data
;…………………………………………………………………..
buffer_good:
        push    ax                      ; preserve input data
        inc     dh                      ; increment display line number
        mov     cx, lengthof nmi_msg    ; prep cx for display
        mov     bp, offset nmi_msg      ; prep pointer for display
        call    print_string_uc         ; print NMI message
        cmp     ah,’8’                  ; test for NMI on or off
        je      nmi_off                 ; skip print on msg
        mov     bp, offset on_msg       ; prep to print off msg
        mov     cx,03h                  ; set string print length
        jmp     nmi_on                  ; skip print on msg
nmi_off:
        mov     bp, offset off_msg      ; prep to print off msg
        mov     cx,04h                  ; set string print length
nmi_on:
        add     dl,07h                  ; set column position for disply
        call    print_string_uc         ; print on or off msg
        pop     ax                      ; restore input data

        call    ascii_byte_to_hex
        or      al,80h                  ; set msn to al
        out     70h,al                  ; send CMOS address
        in      al,71h                  ; read CMOS data into al
        call    hex_byte_to_ascii
        mov     cx,8
        rol     ax,cl                   ; put 1st char in al to be display
        call    print_char_ic           ; display 1st char
        rol     ax,cl                   ; put 2nd char in al to be display
        call    print_char_ic           ; display 2nd char
        inc     dh                      ; increment cursor line number
        inc     dh
        xor     dl, dl                  ; restet cursor to column 0
        mov     bp, offset hit_any_key_msg; prep to display msg
        mov     cx, lengthof hit_any_key_msg; prep to display msg
        call    print_string_uc         ; print ‘hit any key to continue’
        call    read_kbd_char           ; check for keypress
        cmp     al, 27                  ; check for esc key
        je      exit_point              ; exit if escape is pressed
        jmp     control_loop            ; return to begining

 exit_point:
 .exit

;…………………………………………………………………..;

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       clear_scrn_25_x_80                                                    ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06    ;
;                                                                             ;
;       input: nothing                                                        ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;

clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       position_cursor                                                       ;
;       this procedure uses DX and INT 10 function 02h to position the cursor ;
;       into a desired location on the screen.                                ;
;                                                                             ;
;       input:   dh=line (dec)                                                ;
;                dl=column (dec)                                              ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;

position_cursor proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 02h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
position_cursor endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       read_kbd_char                                                         ;
;       This procedure reads a single character from the keyboard             ;
;                                                                             ;
;       input:   nothing                                                      ;
;                                                                             ;
;       output: ah=scan code                                                  ;
;               al=ASCII code                                                 ;
;                                                                             ;
;       registers: AX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

read_kbd_char proc
        mov     ah,00h
        int     16h                     ; read char from keyboard
        ret
read_kbd_char endp
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       beep_char
;       print_char_0ah                                                        ;
;       print_char_0dh                                                        ;
;       print_char_ic                                                         ;
;       print_char                                                            ;
;       these procedures print a single cahracter to the screen.  _0ah and _odh;
;       and beep do not require any input.  _ic incrments the cursor position,;
;       while print_char does not.                                            ;
;                                                                             ;
;       input:          print_char_ic and print_char                          ;
;                       al=ascii of character to be written                   ;
;                                                                             ;
;       output:         nothing                                               ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

beep_char:
        push    ax                      ; save ax
        mov     ax,0e07h                ; ah=function number
                                        ; al=ascii for beep
        jmp     print_char_common

print_char_0ah:
        push    ax                      ; save ax
        mov     ax,0e0ah                ; ah=function number
                                        ; al=ascii for line feed
        jmp     print_char_common
print_char_0dh:
        push    ax                      ; save ax
        mov     ax,0e0dh                ; ah=function number
                                        ; al=ascii for carrage return
        jmp     print_char_common
print_char_ic:
        push    ax                      ; save ax   ***(ah=al)***
        mov     ah,0eh                  ; ah=function number
        jmp     print_char_common
print_char:
        push    ax                      ; save ax
        mov     ah,0ah                  ; ah=function number
print_char_common:
        push    bx                      ; save bx and cx
        push    cx
        mov     bx,01h                  ; indicate white on black
                                        ; text
        mov     cx,1                    ; indicate single execution
        int     10h
        pop     cx                      ; restore ax, bx, cx
        pop     bx
        pop     ax
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_0a0d                                                            ;
;       This function performs a carrage return and a line feed               ;
;                                                                             ;
;       input:          nothing                                               ;
;                                                                             ;
;       output:         nothing                                               ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

print_0a0d:
        call    print_char_0ah          ; display line feed char
        call    print_char_0dh          ; display carrage return char
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_number_in_range                                              ;
;       This procedure ensures that the provided ASCII char lies between      ;
;       zero and a range limit (decimal or hex) in ASCII.                     ;
;                                                                             ;
;       input:          ah= range limit  ‘0’-‘9’ or ‘A’-‘F’ (ascii)           ;
;                       al= char to check                                     ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_number_in_range:
        cmp     ah, ‘9’                         ; is range limit decimal?
        jbe     numeric_test                    ; test decimal range only
        and     ah, 11011111b                   ; convert to uppercase
        call    validate_hex_char               ; test hex range,
                                                ; carry=not in range
        jnc     number_in_range                 ; number good so ret
        mov     ah, ‘9’                         ; prime ah for numeric test
        clc
numeric_test:
        call    validate_numeric_char           ; test decimal range,
                                                ; carry=not in range
        jnc     number_in_range                 ; number good so return
        stc                                     ; number not in either range
                                                ; so set carry flag
number_in_range:
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_numeric_char                                                 ;
;       This procedure checks if a provided ascii number (al) is between zero ;
;       and a specified range limit (ah) in ASCII.                            ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘0’-‘9’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_numeric_char:
        clc
        cmp     al, ‘0’                         ; test al below zero
        jb      invalid_numeric                 ; if al is below 0 stc & exit
        cmp     al, ah
        jg      invalid_numeric                 ; if al is greater, stc & exit
        clc                                     ; clear carry; al is good!
        jmp     valid_numeric
invalid_numeric:
        stc                                     ; set carry; al is bad 😦
valid_numeric:
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_hex_char                                                     ;
;       This procedure checks if a provided ascii number (al) is between ‘A’  ;
;       and a specified range limit (ah) in ASCII.                            ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘A’-‘F’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_hex_char:
        clc
        push    ax
        and     al, 11011111b                   ; convert to uppercase
        cmp     al, ‘A’                         ; test al below ‘A’
        jb      invalid_hex                     ; if below ‘A’ stc & exit
        cmp     al, ah                          ; test al greater then ah
        jg      invalid_hex                     ; if al is greater, stc & exit
        clc                                     ; clear carry, al is good 🙂
        jmp     valid_hex
invalid_hex:
        stc                                     ; set carry, al is bad 😦
valid_hex:
        pop     ax
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       get_byte_to_8F                                              ;
;       This function reads two nibbles from the keyboard and ensures that    ;
;       each is a valid hex number in the range 00-8F.                        ;                                ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘A’-‘F’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = data good                                  ;
;                               ah= upper nibble                              ;
;                               al= lower nibble                              ;
;                       carry = data bad                                      ;
;                                                                             ;
;       registers:      ax, bx                                                ;
;                                                                             ;
;…………………………………………………………………..;

get_byte_to_8F:
        push    bx                      ; preserve bx
        clc                             ; clear carry flag to indicate no error
        call    read_kbd_char           ; get one ascii char from keyboard
        mov     ah,’8′                  ; set upper limit for range test
        call    validate_number_in_range; test 1st char is 0-8
        jc      abort_bad_char          ; quit if out of range
        call    print_char_ic           ; print valid char on screen
        mov     bh, al                  ; save char in bh
        call    read_kbd_char           ; get one ascii char from keyboard

        mov     ah,’F’                  ; set upper limit for range test
        call    validate_number_in_range; test 2nd char is 0-F
        jc      abort_bad_char          ; quit if out of range
        call    print_char_ic           ; print 2nd char
        mov     ah, bh                  ; load 1st char in ah
        jmp     all_data_good           ; quit with no carry
abort_bad_char:
        stc                             ; set carry for indicate error
all_data_good:
        pop     bx
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       ascii_byte_to_hex                                                     ;
;                                                                             ;
;       input:          ah=high ascii nibble                                  ;
;                       al=low ascii nibble                                   ;
;                                                                             ;
;       output:         ah=0                                                  ;
;                       al=hex byte                                           ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;       Note: MSN= Most Significant Nibble                                    ;               ;
;             LSN= Least Significant Nibble                                   ;                             ;
;…………………………………………………………………..;

ascii_byte_to_hex:
        push    cx                      ; preserve cx
        push    bx                      ; preserve bx
        push    ax                      ; preserve al (lsn)
        mov     al, ah                  ; mov high ascii nibble to al
        mov     ah,’9′                  ; load ah for ascii range check (0-9)

        call    validate_numeric_char   ; is msn numeric (0-9)?
        jc      msn_alpha               ; msn is aplha (a-f)
        and     al, 0fh                 ; translate ascii to numeric
        jmp     msn_rol                 ; skip alpha translation
msn_alpha:
        sub     al, 39                  ; translate ascii to alpha
        msn_rol:
        mov     cl, 4                   ;
        rol     al, cl                  ; shift msn left by 4 bits
        mov     bl, al                  ; preserve msn in bl
        pop     ax                      ; restore lsn
        mov     ah,’9′                  ; load ah for range check
        call    validate_numeric_char   ; is lsn numeric?
        jc      lsn_alpha               ; lsn is alpha
        and     al, 0fh                 ; translate ascii to numeric
        jmp     msn_lsn                 ; skip alpha translation
lsn_alpha:
        sub     al, 39                  ; translate ascii to alpha
msn_lsn:
        and     al,0fh                  ; keep the lsn in al
        or      al, bl                  ; drop msn into al
        xor     ah,ah                   ; clear ah
        pop     bx                      ; restore bx
        pop     cx                      ; restore cx
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       hex_byte_to_ascii                                                     ;
;       This procedure takes a hex byte in al, translates each nibble into    ;
;       ascii and stores the result in ax.                                    ;
;                                                                             ;
;       input:          al=hex byte data                                      ;
;                                                                             ;
;       output:         ah=upper ascii nibble  (upper case alpha)             ;
;                       al=lower ascii nibble  (upper case alpha)             ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;
hex_byte_to_ascii:
        push    cx                      ; preserve bx & cx
        push    bx
        push    ax                      ; preserve lower hex nibble
        and     al, 0f0h                ; mask off lower hex nibble
        mov     cx, 4
        ror     al, cl                  ; shift msn right 4 bits
        cmp     al,9                    ; is msn greater than 9?
        jg      mshexn_alpha            ; if so, translate aplha to ascii
        or      al,30h                  ; translate numeric to ascii
        jmp     get_lshexn              ; skip alpha translation
mshexn_alpha:
        add     al, 37h                 ; translate alpha to ascii (upper case)
get_lshexn:
        mov     bh, al                  ; save msn ascii in bh
        pop     ax                      ; restore lsn
        and     al,0fh                  ; mask off msn
        cmp     al,9                    ; is lsn greater than 9?
        jg      lshexn_alpha            ; if so, translate alpha to ascii
        or      al,30h                  ; translate numeric to ascii
        jmp     hex_to_ascii_done       ; skip alpha translation
lshexn_alpha:
        add     al, 37h                 ; translate alpha to ascii
hex_to_ascii_done:
        mov     ah, bh                  ; restore ms ascii nibble
        pop     bx
        pop     cx
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_hex_in_al                                                       ;
;       This routine takes a hex byte in al, translates it into ascii and     ;
;       and displays it to the screen.                                        ;
;                                                                             ;
;       input:          al= byte value in hex                                 ;
;                                                                             ;
;       output:         none                                                  ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;
print_hex_in_al:
        push    ax                      ; preserve ax
        call    hex_byte_to_ascii       ; convert hex byte to ascii
        push    ax                      ; preserve lower ascii nibble
        mov     al, ah                  ; move upper ascii nibble to al
        call    print_char_ic           ; display msn
        pop     ax                      ; retrieve lsn
        call    print_char_ic           ; display lsn
        pop     ax                      ; restore ax
        ret
end

.model small
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
dseg    segment ‘data’
        prompt_user     db      “Enter CMOS register to read. ==> “,’$’
        CMOS_address    db      2 dup (0)
        NMI_on          db      “NMI ENABLE ”
        NMI_off         db      “NMI DISABLE ”
        continue        db      “Hit any key to continue”
        exit_press      db      “OR Hit ESC key to exit”
dseg    ends

sseg    segment stack ‘stack’
        dw 100 dup(“s”)
        top_stack label word
sseg    ends

eseg    segment ‘data’
eseg    ends

;……………………………………………………………………..

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls                                                                    ;
;       -get data                                                               ;
;       -display NMI on or off depend on user input                             ;
;       -read CMOS location                                                     ;
;       -dipslay result                                                         ;
;       -repeat or exit                                                         ;
;…………………………………………………………………….;

cseg    segment ‘code’
        assume cs:cseg, ds:dseg, ss:sseg, es:eseg
start:
        mov     ax,dseg
        mov     ds,ax
restart:
        mov     ah,00h                  ;Set video mode
        mov     al,03h                  ;set to 640×200
        int     10h
        call    msg_enter_cmos          ;prompt user

        mov     bx,0h                   ;init array index
cmos_add:
        mov     ah,00h                  ;init input for read
        int     16h                     ;get input from keyboard
        mov     CMOS_address[bx],al     ;store user input
        cmp     al,1bh                  ;if user press ESC…
        jz      exit_prog               ;…exit the prog
        mov     ah,0eh                  ;init to display char
        int     10h                     ;display char in AL

        cmp     bx,0h                   ;check for 1st char input…
        jne     second_char             ;…if not then it a second char input
        cmp     al,30h                  ;if al is less then 0 then…
        jl      start                   ;…prompt user again…
        cmp     al,38h                  ;…else if al greater 8 then prompt user again…
        jg      start
        jmp     it_num                  ;go and get the 2nd input
second_char:
        cmp     al,30h                  ;if al is less then 0 then…
        jl      start                   ;…prompt user again…
        cmp     al,39h                  ;…else if al greater 9 then…
        jg      check_alp               ;…check if al is within a-f….
        jmp     it_num
check_alp:
        and     al,11011111b            ;convert to uppercase
        cmp     al,41h                  ;check to see if al is between a-f
        jl      start                   ;….
        cmp     al,46h                  ;if al is between a-f then done…
        jle     it_num
        jmp     start                   ;…else prompt the user again
it_num:
        mov     CMOS_address[bx],al     ;store user input

        inc     bx                      ;inc index
        cmp     bx,2h
        jnz     cmos_add                ;do until get all two numbers

        mov     dx,0100h                ;Set to display in the 2nd line
        call    new_line

        mov     bx,0h                   ;init the index
        mov     ah,CMOS_address[0]      ;get the first number
        cmp     ah,38h                  ;if the first number is greater or equal to 38 then…
        jge     off_nmi                 ;…turn NMI off else…
        jmp     on_nmi                  ;…turn NMI on

off_nmi:                                ;display disable NMI
        mov     ah,0eh                  ;init function
        mov     al,NMI_off[bx]          ;ASCII code of the char to be display
        int     10h                     ;display it
        inc     bx                      ;inc index to the next char in the string
        cmp     bx,11
        jnz     off_nmi                 ;until all of the NMI DISABLE words is display
        jmp     end_off_nmi

on_nmi:                                 ;display disable NMI
        mov     ah,0eh                  ;init function
        mov     al,NMI_on[bx]           ;ASCII code of the char to be display
        int     10h                     ;display it
        inc     bx                      ;inc index to the next char in the string
        cmp     bx,10
        jnz     on_nmi                  ;until all of the NMI ENABLE words is display

end_off_nmi:                            ;done with NMI ENABLE or NMI DISABLE
        mov     dx,0200h                ;set to display in the 3rd line
        call    new_line

        mov     al,CMOS_address[0]      ;get the first number
        call    hex_conversion          ;coverse ascii to hex number
        mov     bx,0h                   ;clear bx
        mov     bl,al                   ;copy the first number in hex
        push    bx                      ;store first number
        mov     al,CMOS_address[1]      ;get the 2nd number
        call    hex_conversion          ;converse ascii to hex number
        pop     bx                      ;restore first number
        mov     cx,4                    ;set positions for shifting
        shl     bl,cl                   ;shift bl 4 bits to the left
        or      al,bl                   ;combine the first and 2nd numbers
        out     70h,al                  ;read CMOS RAM, AL is the address
        in      al,71h                  ;read data from AL address, store infor in AL

        mov     bx,0h                   ;clear bx
        mov     bl,al                   ;copy data from al to bl
        push    bx                      ;store CMOS data
        and     al,0f0h                 ;take the 1st number
        mov     cx,4h                   ;set positions to shifted
        shr     al,cl                   ;shift AL

        call    ascii_conversion        ;converse hex to ascii
        mov     ah,0eh                  ;display the 1st number
        int     10h

        pop     bx                      ;restore CMOS data
        mov     al,bl                   ;copy it to AL
        and     al,0fh                  ;get the 2nd number
        call    ascii_conversion        ;converse hex to ascii
        mov     dx,0201h                ;move cursor one to the right
        call    new_line
        mov     ah,0eh                  ;display the 2st number
        int     10h

        mov     dx,0500h                ;move cursor one to the right
        call    new_line

        mov     bx,0h                   ;array index
cont:                                   ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,continue[bx]         ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,23                   ;repeat until the end of the string
        jnz     cont

        mov     dx,0600h                ;move cursor one to the right
        call    new_line

        mov     bx,0h                   ;array index
exit_p:                                 ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,exit_press[bx]       ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,22                   ;repeat until the end of the string
        jnz     exit_P

        mov     ah,00h                  ;init input for read
        int     16h                     ;get input from keyboard
        cmp     al,1bh                  ;if user press ESC…
        jz      exit_prog               ;…exit the prog

        jmp     start

exit_prog:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_conversion                                                          ;
;       This procedure takes the ascii in al, translates                        ;
;       the ascii into hex and stores the result in al.                         ;
;                                                                               ;
;       input: al = ascii data                                                    ;
;                                                                               ;
;       output: al = hex                                                      ;
;                                                                               ;
;       registers: aL                                                           ;
;                                                                               ;
;…………………………………………………………………….;
hex_conversion          proc    near
        cmp     al,39h                  ;if al is less or egual to 39h then…
        jle     sub_num                 ;…sub 30h to get the num else…
        jmp     sub_alp                 ;…sub 37h to get the alp
sub_num:
        sub     al,30h                  ;converse ascii number to hex
        jmp     hex_done
sub_alp:
        sub     al,37h                  ;converse ascii alp to hex
hex_done:
        ret
hex_conversion  endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       ascii_conversion                                                        ;
;       This procedure takes last hex in al, translates each                    ;
;       nibble into ascii and stores the result in al.                          ;
;                                                                               ;
;       input: al = hex data                                                    ;
;                                                                               ;
;       output: al = ascii                                                      ;
;                                                                               ;
;       registers: aL                                                           ;
;                                                                               ;
;…………………………………………………………………….;
ascii_conversion        proc    near
        cmp     al,9h                   ;if al is less or equal to 9 then…
        jle     add_num                 ;…add num else…
        jmp     add_alp                 ;…add alp
add_num:
        add     al,30h                  ;converse hex number to ascii
        jmp     done_conver
add_alp:
        add     al,37h                  ;converse hex alp to ascii
done_conver:
        ret
ascii_conversion        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line  (update cursor)                                               ;
;       This procedure position cursor.                                         ;
;                                                                               ;
;       input:  ah = function                                                   ;
;               dh = line number on screen                                      ;
;               dl = column number on screen                                    ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        mov     ah,02h                  ;init the function
        int     10h                     ;place the cursor
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       msg_enter_cmos                                                          ;
;       This procedure display msgs to ask user to enter the                    ;
;       cmos address.                                                           ;
;                                                                               ;
;       input:  none                                                                ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: ax, bx                                                       ;
;                                                                               ;
;…………………………………………………………………….;
msg_enter_cmos  proc    near
        mov     bx,0h                   ;array index
prompt:                                 ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,prompt_user[bx]      ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,33                   ;repeat until the end of the string
        jnz     prompt
        ret
msg_enter_cmos  endp
end     start

Example 3.
.model small
 .stack 100h
 .386
 .data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        msg_1                   db      ‘Standard CMOS:’
        msg_2                   db      ‘Extended Memory size from inside the CMOS checksum.’
        msg_3                   db      ‘Extended Memory size from outside the CMOS checksum.’
        msg_4                   db      ‘CMOS checksum: ‘
        msg_5                   db      ‘Interrupt Vector:’
        msg_6                   db      ‘Extended Memory size: ‘
        msg_7                   db      ‘Base Memory size: ‘
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -display msg_1                                                          ;
;       -display standard CMOS (all 128kb)                                      ;
;       -display msg_2                                                          ;
;       -read the extended memory size from inside the CMOS checksum            ;
;       -convert the hex numbers to dec numbers                                 ;
;       -display extended memory size from inside the CMOS checksum             ;
;       -display msg_3                                                          ;
;       -read the extended memory size from outside the CMOS checksum           ;
;       -convert the hex numbers to dec numbers                                 ;
;       -display extended memory size from outside the CMOS checksum            ;
;       -wait (prompt user)                                                     ;
;       -calculate the cmos, convert hex to dec, and display it                 ;
;       -use INT to get the extrended memory and display it                     ;
;       -use INT to get the base memory and display it                          ;
;…………………………………………………………………….;

.code
.startup

 control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msg_1              ; set cx for string display
        mov     bp, offset msg_1                ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line
        mov     cx,0h                           ; init counter
problem_1:
        mov     al,cl                           ; set cmos register number
        call    read_and_display                ; read cmos location and display it the screen
        push    cx                              ; store counter
        and     cl,0fh                          ; get the last nibble
        cmp     cl,0fh                          ; if register number not equal to Fh then …
        jne     cont                            ; …continue else…
        call    new_line                        ; …start from the next line
cont:
        pop     cx                              ; restore counter
        inc     cx                              ; inc counter
        cmp     cx,8fh                          ; if counter greater than 128kb then…
        jg      problem_2                       ; …do problem 2….
        jmp     problem_1                       ; …continue do problem 1
problem_2:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_2              ; set cx for string display
        mov     bp, offset msg_2                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     al,18h                          ; init to read extend memory (high byte)
        call    read_cmos_location              ; read the extend memory high byte
        mov     ah,al                           ; copy the high byte to ah
        mov     al,17h                          ; init to read extend memory (low byte)
        call    read_cmos_location              ; read the extend memory low byte
        call    hex_to_dec                      ; convert hex to dec and display it
problem_3:
        call    new_line                        ; start from the next line
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_3              ; set cx for string display
        mov     bp, offset msg_3                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     al,31h                          ; init to read extend memory (high byte)
        call    read_cmos_location              ; read the extend memory high byte
        mov     ah,al                           ; copy the high byte to ah
        mov     al,30h                          ; init to read extend memory (low byte)
        call    read_cmos_location              ; read the extend memory low byte
        call    hex_to_dec                      ; convert hex to dec and display it
        call    new_line                        ; start from the next line

problem_4:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_4              ; set cx for string display
        mov     bp, offset msg_4                ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     dx,0h                           ; clear register for checksum
        mov     cx,10h                          ; init counter
continue_4:
        mov     al,cl                           ; init cmos register number
        call    read_cmos_location              ; read cmos location
        mov     ah,0h                           ; clear ah register
        add     dx,ax                           ; checksum = checksum + ax
        inc     cx                              ; inc counter
        cmp     cx,2eh                          ; if counter not equal to 2eh (cmos register number) then…
        jne     continue_4                      ; …counter do the checksum

        mov     ax,dx                           ; set to al with hex nibble to convert to ascii
        call    hex_to_dec                      ; convert hex to dec and display it
        call    new_line                        ; start from the next line
        call    exit_or_continue                ; hold the display
problem_5:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_5              ; set cx for string display
        mov     bp, offset msg_5                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     dx,0h                           ; clear register
        mov     bx,0h                           ; init index
continue_5:
        push    ds                              ; store the segment
        mov     ds,dx                           ; set segment address to 0
        mov     al,ds:[bx]                      ; read 00:[bx] location
        pop     ds                              ; restore the segment
        call    hex_to_ascii                    ; convert to ascii
        call    display_hex                     ; display it
        push    bx                              ; store index
        and     bl,0fh                          ; get the last nibble
        cmp     bl,0fh                          ; if register number not equal to Fh then …
        jne     no_new_line_5                   ; …continue else…
        call    new_line                        ; …start from the next line
no_new_line_5:
        pop     bx                              ; restore index
        inc     bx                              ; inc index
        cmp     bx,02ffh                        ; if the offset is greater than 768b then…
        jg      problem_6                       ; …do problem 6 else…
        jmp     continue_5                      ; …continue reading the interrupt vector

problem_6:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_6              ; set cx for string display
        mov     bp, offset msg_6                ; set pointer for string display
        call    print_string_uc                 ; display input request message

continue_6:
        mov     ah, 88h                         ; get the extrended memory function
        int     15h                             ; get the size of extrended memory
        call    hex_to_dec                      ; convert hex to dec and display it

problem_7:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_7              ; set cx for string display
        mov     bp, offset msg_7                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        int     12h                             ; get the size of base memory
        call    hex_to_dec                      ; convert hex to dec and display it
exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_dec                                                              ;
;       the procedure convert hex to dec and display it on the screen           ;
;                                                                               ;
;       input: ax = hex numbers                                                 ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_dec      proc    near
        push    bx                      ; store register
        push    cx
        push    dx

        mov     bx,0h                   ; init the counter
        mov     dx,0h                   ; clear dx for remainder
        mov     cx,10                   ; set to be divided
next_div:
        div     cx                      ; ax/cx
        inc     bx                      ; inc counter
        push    dx                      ; store the remainder
        mov     dx,0h                   ; clear dx for the next remainder
        cmp     ax,0h                   ; stop dividing if the quotient is zero
        jne     next_div                ; else continue

do_pop:
        pop     dx                      ; restore the remainder
        mov     al,dl                   ; al take the remainder
        call    hex_to_ascii            ; convert the 2nd nibble into ascii
        mov     ah,0eh                  ; function code for display on the screen
        int     10h                     ; display it
        dec     bx                      ; dec the counter
        cmp     bx,0h                   ; if the counter reach zero then done restore…
        jne     do_pop                  ; …all remainder else continue getting the remainder

        pop    dx                       ; restore the register
        pop    cx
        pop    bx
        ret
hex_to_dec      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       exit_or_continue                                                        ;
;       the procedure prompt the user to press any to continue or               ;
;       press <esc> to exit the program                                         ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;

exit_or_continue        proc    near
        pusha
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof hit_any_key_msg    ; set cx for string display
        mov     bp, offset hit_any_key_msg      ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        call    read_kbd_char                   ; wait to user to press a button
        cmp     al, 27                          ; check for exc key
        je      exit_point                      ; if esc pressed, exit program
        popa
        ret
exit_or_continue        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       read_and_display                                                        ;
;       read_cmos_location (read cmos location)                                 ;
;       hex_to_ascii       (convert hex to ascii)                               ;
;       display_hex        (display ascii char to screen)                       ;
;                                                                               ;
;       input: al = cmos register number                                        ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
 read_and_display       proc    near
        call    read_cmos_location              ; read the cmos location
        call    hex_to_ascii                    ; convert hex into ascii code
        call    display_hex                     ; display to the screen
        ret
 read_and_display       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure will print two character to the screen.  One from ah     ;
;       another from al.                                                        ;
;                                                                               ;
;       input: ax = ascii of character to be written                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_hex     proc    near
        push    cx                      ; store register
        push    ax
        mov     cx,8h
        shr     ax,cl                   ; get the 1st nibble
        mov     ah,0eh                  ; function code for displaying char
        int     10h                     ; display the 1st nibble
        pop     ax                      ; restore data
        mov     ah, 0eh                 ; function code for displaying char
        int     10h                     ; display the 2nd nibble
        mov     ah,0eh                  ; function code for displaying char
        mov     al,20h                  ; display a space
        int     10h                     ; display it

        pop     cx                      ; restore register
        ret
display_hex     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                      ; store register
        push    cx
        push    ax
        mov     cx,4                    ; set for shifting
        shr     al,4                    ; get the 1st hex number
        cmp     al,9                    ; compare to see if it a number or alp
        jg      alp1                    ; if alp go to alp1 else…
        add     al,30h                  ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                  ; …convert to ascii
second_nibble:
        mov     bl,al                   ; store the 1st nibble
        pop     ax                      ; retore the hex numbers
        and     al,0fh                  ; get the 2nd hex number
        cmp     al,9                    ; compare to see if it a number or alp
        jg      alp2                    ; if alp go to alp2 else…
        add     al,30h                  ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                  ; …convert to ascii
done_nibble:
        mov     ah,bl                   ;
        pop     cx
        pop     bx
        ret
hex_to_ascii   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       read_cmos_location                                                      ;
;       this procedure uses al as an register number, then read the           ;
;       CMOS location and return the data in al register.                     ;
;                                                                               ;
;       input: al                                                               ;
;                                                                               ;
;       output: al                                                              ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
read_cmos_location      proc    near
        out     70h,al
        in      al,71h
        ret
read_cmos_location      endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                ;
;               bh = video page number                                       ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       read_kbd_char                                                         ;
;       This procedure reads a single character from the keyboard             ;
;                                                                             ;
;       input:   nothing                                                      ;
;                                                                             ;
;       output: ah=scan code                                                  ;
;               al=ASCII code                                                 ;
;                                                                             ;
;       registers: AX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

read_kbd_char   proc      near
        mov     ah,00h
        int     16h                     ; read char from keyboard
        ret
read_kbd_char   endp
end                                     ; end of file
Example 4.
We will read the PCI configuration space specification and develop an algorithm followed by an assembly language program to detect the number of PCI devices present in a system. A PCI device might be a multi function device as well. When a PCI device is detected, determine if the PCI device is a multi or a single function device. If it is a multi function device, determine how many functions present in that particular PCI device.

.model small
 .stack 100h
 .486p
 .data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        msgs_on_pci_bus         db      ‘On PCI Bus ‘
        msgs_device_present     db      ‘ device(s) present’
        msgs_device_no          db      ‘Device No. ‘
        msgs_has                db      ‘h has ‘
        msgs_function           db      ‘ function(s) ‘
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
        device_no               db      0
        function_no             db      0
        device_function         db      32 dup(0)
        div_ten                 db      10
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -Detect PCI device                                                      ;
;       -Determine if the PCI device has mult function or a single function     ;
;       -Determine how many functions present in a particular PCI device
;       -Display the inform has found for the Bus                               ;
;…………………………………………………………………….;
.code
.startup

zz control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msgs_on_pci_bus    ; set cx for string display
        mov     bp, offset msgs_on_pci_bus      ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message

        xor     bx, bx                          ; clear counter for Bus number
        mov     ah,0eh                          ; function to write to the screen
        mov     al, bl                          ; take the counter
        add     al, 30h                         ; convert the number into ascii number
        int     10h                             ; display it to the screen
        call    new_line                        ; down one line

        mov     eax, 80000000h                  ; Bus 0, PCI device 0, function 0, offset 0
search_next_bus:
        call    init_data                       ; init all the data to 0
        call    search_device                   ; search for the device
        call    display_device_function         ; display all of the device and function
                                                ; that has been found
        add     eax, 00010000h                  ; inc the configuration of the next Bus
        inc     bx                              ; inc the counter for Bus
        cmp     bl, 6                           ; if bus != 6 then
        jne     con_bus_search                  ; search the next bus
        jmp     exit_point                      ; else exit the program

con_bus_search:
        call    new_line                        ; down one line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_on_pci_bus    ; set cx for string display
        mov     bp, offset msgs_on_pci_bus      ; set pointer for string display
        call    print_string_uc                 ; display input request message

        push    eax                             ; save the PCI configuration
        mov     ah,0eh                          ; function to write to the screen
        mov     al, bl                          ; take the counter
        add     al, 30h                         ; convert the number into ascii number
        int     10h                             ; display the number to the screen
        call    new_line                        ; down one line

        pop     eax                             ; restore the PCI configuration
        jmp     search_next_bus

exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       init_data                                                               ;
;       the procedure init all of the data                                      ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
init_data       proc    near
        pusha                                   ; store all register
        mov     device_no, 0                    ; init device number
        mov     function_no, 0                  ; init device function
        xor     bx, bx                          ; clear index
init_data_continue:
        mov     device_function[bx], 0h         ; clear all of the data in the array
        inc     bx                              ; inc the index
        cmp     bx, 32                          ; if index != 32 then
        jne    init_data_continue               ; clear the next element in the array
        popa                                    ; restore all register
        ret
init_data       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       search_device                                                           ;
;       the procedure search for all of the PCI device                          ;
;                                                                               ;
;       input:  eax = pci configuration numbers                                 ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
search_device   proc    near
        pusha                                   ; store all register

        xor     bx, bx                          ; clear counter for device
detect_device:                                  ; search of number of device in Bus 0
        push    eax                             ; save pci configuration
        mov     dx, 0cf8h                       ; get the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; get the data port
        in      eax, dx                         ; Read from data port
        cmp     ax, 00h                         ; if read in data == 0 or ffffh
        je      no_device_found                 ;
        cmp     ax, 0ffffh                      ;
        je      no_device_found                 ; then not device is found

add_device_no:                                  ; found a device
        mov     al, device_no                   ; get the device number
        add     al, 1                           ; inc the device nubmer
        daa                                     ; convert the device number into dec
        mov     device_no, al                   ; save the device number
        pop     eax                             ; restore the PCI configuration
        call    search_function                 ; search for function
        mov     dl, function_no                 ; get the function number
        mov     device_function[bx], dl         ; save the function number into the device index
        push    eax                             ; save the PCI configuration
no_device_found:
        pop     eax                             ; restore the PCI configuration
        add     ah, 8h                          ; inc device, PCI configuration
        inc     bx                              ; inc the device index
        cmp     bx, 32                          ; if device != 32 then
        jne     detect_device                   ; continue detecting next device

        popa                                    ; restore all register
        ret
search_device   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_device_function                                                 ;
;       the procedure display all of the device numbers that has a function     ;
;       and number of functions                                                 ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_device_function         proc    near
        pusha

        mov     al, device_no                   ; get the device number
        call    hex_to_ascii                    ; convert the number into ascii number
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_device_present; set cx for string display
        mov     bp, offset msgs_device_present  ; set pointer for string display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line

        xor     bx, bx                          ; clear the index for device
display_next_device:
        mov     al, device_function[bx]         ; get the function number for precific device
        cmp     al, 0                           ; if function == 0
        je      counter_inc                     ; then check for the next device

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_device_no     ; set cx for string display
        mov     bp, offset msgs_device_no       ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     al, bl                          ; get the index for device
        call    hex_to_ascii                    ; convert it into ascii number
        mov     dl, al                          ; save the 2nd nibble
        mov     al, ah                          ; get the 1st nibble to be display
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        mov     al, dl                          ; get the 2nd nibble to be display
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_has           ; set cx for string display
        mov     bp, offset msgs_has             ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     al, device_function[bx]         ; get the function for a precific device
        call    hex_to_ascii                    ; convert it to ascii number
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_function      ; set cx for string display
        mov     bp, offset msgs_function        ; set pointer for string display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line
counter_inc:
        inc     bx                              ; inc the index for device
        cmp     bx, 32                          ; if the index device != 32
        jne     display_next_device             ; then continue to display else exit the loop
        popa                                    ; register all register
        ret
display_device_function         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       search_function                                                         ;
;       the procedure search the all of the function for the pci device         ;
;                                                                               ;
;       input:  eax = pci configuration number                                  ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
search_function         proc    near
        push    eax                             ; store all register
        push    bx
        push    cx
        push    dx

        push    eax                             ; save the pci configuration
        mov     function_no, 0h                 ; set the function number to 0
        add     al, 0ch                         ; set the pci configuration to point to
                                                ; read bist, header type, latency timer,
                                                ; and cache line size
        mov     dx, 0cf8h                       ; set the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; set the data port
        in      eax, dx                         ; Read from data port
        shr     eax, 23                         ; get the msb in the header type
        mov     bl, al                          ; save it in bl
        pop     eax                             ; restore the pci configuration
        cmp     bl, 1                           ; if bl == 1 then is a mult function
        je      mult_function_found
single_function_found:                          ; else is a single function
        mov     al, function_no                 ; get the function number
        add     al, 1                           ; inc function number
        daa                                     ; convert it to dec number
        mov     function_no, al                 ; save it
        jmp     done_function_search

mult_function_found:                            ; for mult function
        mov     cx, 7                           ; init the counter
search_next_function:
        push    eax                             ; save the pci configuration
        mov     dx, 0cf8h                       ; set up the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; set up the data port
        in      eax, dx                         ; Read from data port

        cmp     ax, 00h                         ; if the vendor id == 0 or ffffh
        je      no_function_found               ;
        cmp     ax, 0ffffh                      ;
        je      no_function_found               ; then there is no function
add_function_no:
        mov     al, function_no                 ; get the function number
        add     al, 1                           ; inc the function number
        daa                                     ; convert it to dec number
        mov     function_no, al                 ; save it
no_function_found:
        pop     eax                             ; restore the pci configuration
        add     ah, 1h                          ; inc the function for pci configuration
        loop    search_next_function

done_function_search:
        pop     dx                              ; restore all register
        pop     cx
        pop     bx
        pop     eax
        ret
search_function         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha                                   ; store all register
        mov     ah,0eh                          ; function to write to the screen
        mov     al,0dh                          ; carry return
        int     10h                             ; display it
        mov     ah,0eh                          ; function to write to the screen
        mov     al,0ah                          ; line feed
        int     10h                             ; display it
        popa                                    ; store all register
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ; get the 1st nibble
        pop     cx                              ; restore register
        pop     bx
        ret
hex_to_ascii   endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax, 0600h                       ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx, 700h                        ; bh=color attribute for new lines
        xor     cx, cx                          ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx, 184fh                       ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                              ; preserve ax & bx
        push    bx
        mov     ah, 03h                         ; function number for int10
        mov     bh, 00h                         ; video page number
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                              ; preserve ax & bx
        mov     ax, 1300h                       ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
print_string_common:                            ; portion of function common to both routines
        push    bx
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
end                                             ; end of file

        mov     consonant, 0                    ; set 1st letter for consonant to not
        mov     vowel, 0                        ; set 1st letter for consonant to not
        mov     space, 1                        ; set the spacing to yes
        jmp     write_next                      ; go write the char to file

check_space:
        cmp     space, 1                        ; check for the spacing between word
        jne     write_next                      ; if no spacing between word then write it to the file
        call    vowel_characters                ; else check for vowel in the 1st char
        jnc     check_space_con                 ; if not a vowel then check for consonant
        mov     consonant, 0                    ; set 1st letter for consonant to not
        mov     vowel, 1                        ; set 1st letter for vowel to yes
        mov     space, 0                        ; set the spacing to no
        jmp     write_next                      ; go write the char to file
check_space_con:
        call    consonant_characters            ; check for the consonant
        jnc     write_next                      ; if not a consonant then go write it to the file
        mov     dl, inbuff                      ; take the char
        mov     first_letter, dl                ; store it in file_letter
        mov     consonant, 1                    ; set 1st letter for consonant to yes
        mov     vowel, 0                        ; set 1st letter for vowel to not
        mov     space, 0                        ; set the spacing to yes
        jmp     next_char                       ; go get the the next char
write_next:
        call    write_character                 ; write to file_B
        jmp     next_char                       ; go read the next character

end_read_file:
        call    close_files                     ; close file_A and file_B

        mov     bx, 21h                         ; init the starting point
        mov     cx, 0h
to_screen:

        mov     al, array_alps[bx]              ; get the sum of the char
        cmp     al, 0
        je      cont

        mov     ah, 0eh                         ; function to write to the screen
        mov     al, bl                          ; al take the ascii to display the char
        int     10h
        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘=’                         ; display =
        int     10h
        mov     al, array_alps[bx]              ; get the sum of the char
        add     al, 30h                         ; convert it to ascii
        mov     ah,0eh                          ; function to write to the screen
        int     10h

        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘ ‘                         ; display a space
        int     10h
        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘ ‘                         ; display a space
        int     10h
        inc     cx                              ; init the display counter
        mov     ax, cx                          ; copy it
        and     ax, 0fh                         ; get the 2nd nibble
        cmp     ax, 05h                         ; if it equal to f then
        je      next_line                       ; print set the cursor to the next line
        jmp     cont                            ; else continue
next_line:
        call    new_line                        ; set cursor to the new line
        mov     cx, 0h                          ; reset the display counter
cont:
        inc     bx                              ; inc the ascii code
        cmp     bx, 07fh                        ; display until 7f
        jne     to_screen

exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       open_file                                                               ;
;       the procedure will open file_A and create a new file call file_B        ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
open_file       proc    near
        pusha
        mov     al, 02h                         ; open file_A for read
        lea     dx, file_A                      ;
        mov     ah, 3dh
        int     21h
        mov     handle_A, ax                    ; save the handle

        lea     dx, file_B                      ; delete file_B
        mov     ah, 41h
        int     21h

        mov     cx, 0020h                       ; attributes of a new file
        lea     dx, file_B                      ; create file_B
        mov     ah, 5bh
        int     21h
        mov     handle_B,ax                     ; save the handle
        popa
        ret
open_file       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_character                                                         ;
;       the procedure count the number of occurences of each character          ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
characters_counter      proc    near
        pusha
        mov     bx,0h                           ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff, use it as index
        mov     al, array_alps[bx]              ; get the contain
        inc     al                              ; inc the sum
        mov     array_alps[bx], al              ; write the sum back to memory
        popa
        ret
characters_counter      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_character                                                         ;
;       the procedure write a character in inbuff to file_B                     ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_character proc    near
        pusha                                   ; store register
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 1                           ; number of char
        lea     dx, inbuff                      ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa                                    ; retore the register
        ret
write_character endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_ay                                                                ;
;       the procedure write the 1st char in a word and the word ay to file_B    ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_ay     proc    near
        pusha
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 1                           ; number of char
        lea     dx, first_letter                ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h

        mov     bx, handle_B                    ; write to file_B
        mov     cx, 2                           ; number of char
        lea     dx, ay                          ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa
        ret
write_ay     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_way                                                               ;
;       the procedure write the word way to file_B                              ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_way     proc    near
        pusha                                   ; store register
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 3                           ; number of char
        lea     dx, way                         ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa                                    ; store register
        ret
write_way     endp

;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       init_data                                                               ;
;       the procedure init the data for an array of alps, number, and other     ;
;       consonant alps is set to 2 and vowel alps is set to 1 and all other     ;
;       is set to 0                                                             ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
init_data       proc    near
        pusha                                   ; store register
        mov     bx, 0                           ; init counter
        mov     ax, 0
init_all:                                       ; vowel = 1, consonant = 2, other = 0
        mov     con_vowel_other[bx], al         ; init everything to 0
        inc     bl                              ; inc counter
        inc     bl                              ; inc counter
        cmp     bl, 0feh
        jne     init_all

        mov     bl, ‘A’                         ; starting point
        mov     al, 2
init_consonant:
        mov     con_vowel_other[bx], al         ; init all consonants in uper case to 2
        inc     bl                              ; inc counter
        cmp     bl, ‘Z’
        jne     init_consonant

        mov     bl, ‘a’                         ; starting point
init_consonant_lower:
        mov     con_vowel_other[bx], al         ; init consonants in lower case to 2
        inc     bl                              ; inc counter
        cmp     bl, ‘z’
        jne     init_consonant_lower

init_vowel:
        mov     al, 1                           ; init all the vowel to 1
        mov     bl, ‘a’
        mov     con_vowel_other[bx], al
        mov     bl, ‘A’
        mov     con_vowel_other[bx], al
        mov     bl, ‘e’
        mov     con_vowel_other[bx], al
        mov     bl, ‘E’
        mov     con_vowel_other[bx], al
        mov     bl, ‘i’
        mov     con_vowel_other[bx], al
        mov     bl, ‘I’
        mov     con_vowel_other[bx], al
        mov     bl, ‘o’
        mov     con_vowel_other[bx], al
        mov     bl, ‘O’
        mov     con_vowel_other[bx], al
        mov     bl, ‘u’
        mov     con_vowel_other[bx], al
        mov     bl, ‘U’
        mov     con_vowel_other[bx], al
        popa                                    ; restore the register
        ret
init_data       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       consonant_characters                                                    ;
;       the procedure find if the character in inbuff is a consonant or not     ;
;       if the character is a consonant, the number counter of the character    ;
;       by one.                                                                 ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         carry flag = 0 if not a consonant                       ;
;                       carry flag = 1 if is a consonant                        ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
consonant_characters    proc    near
        pusha                                   ; store register
        mov     bx, 0h                          ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff
        and     bl, 11011111b                   ; convert to uppercase
        mov     al, con_vowel_other[bx]         ; vowel = 1, consonant = 2, other = 0
        cmp     al, 2                           ; 1 for vowel, check for consonant
        je      find_consonant                  ; if its a consonant
        jmp     not_consonant                   ; if its not a consonant
find_consonant:
        ;mov     bx,0h                           ; clear bx
        ;mov     bl, inbuff                      ; get the data from inbuff, use it as index
        ;mov     al, array_alps[bx]              ; get the contain
        ;inc     al                              ; inc the sum
        ;mov     array_alps[bx], al              ; write the sum back to memory
        stc                                     ; set carry flay
        jmp     done_consonant
not_consonant:
        clc                                     ; clear carry flag
done_consonant:
        popa                                    ; restore register
        ret
consonant_characters    endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       vowel_characters                                                        ;
;       the procedure find if the character in inbuff is a vowel or not         ;
;       if the character is a vowel, the number counter of the character        ;
;       by one.                                                                 ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         carry flag = 0 if not a vowel                           ;
;                       carry flag = 1 if is a vowel                            ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
vowel_characters proc    near
        pusha                                   ; store register
        mov     bx, 0h                          ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff
        and     bl, 11011111b                   ; convert it to uppercase
        mov     al, con_vowel_other[bx]         ; vowel = 1, consonant = 2, other = 0
        cmp     al, 1                           ; 1 for vowel, check for vowel
        je      find_vowel                      ; if its a vowel
        jmp     not_vowel                       ; if not a vowel
find_vowel:
        ;mov     bx,0h                           ; clear bx
        ;mov     bl, inbuff                      ; get the data from inbuff, use it as index
        ;mov     al, array_alps[bx]              ; get the contain
        ;inc     al                              ; inc the sum
        ;mov     array_alps[bx], al              ; write the sum back to memory
        stc                                     ; set carry flay
        jmp     done_vowel
not_vowel:
        clc                                     ; clear carry flag
done_vowel:
        popa                                    ; restore register
        ret
vowel_characters endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       close_files                                                             ;
;       the procedure will close the file_A and file_B                          ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
close_files     proc    near
        pusha                                   ; store the register
        mov     bx, handle_A                    ; close file_A
        mov     ah, 3eh                         ; function for closing
        int     21h

        mov     bx, handle_B                    ; close file_B
        mov     ah, 3eh                         ; function for closing
        int     21h
        popa                                    ; restore the register
        ret
close_files     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx = string length                                            ;
;               dh = line number                                              ;
;               dl = column number                                            ;
;               bp = offset to string buffer                                  ;
;               ds = segment for string buffer                                ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
end                                     ; end of file
Example 6.
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
; This Program is to fulfill the following:                                     ;
;       1. Clear the screen                                                     ;
;       2. Init the gdt table                                                   ;
;       3. Go into protected mode and write to memory and read back             ;
;       4. Switch back to real mode                                             ;
;       5. Compare the value read from protected mode with test pattern         ;
;       6. Display the memory location to the screen                            ;
;       7. Update the ES entry in the GDT                                       ;
;       8. Continue 3-7 until end of memory                                     ;
;…………………………………………………………………….;
.model small
.stack 100h
.386

gdt_table       struc
        limit           dw      0h
        lower_address   dw      0h
        upper_address   db      0h
        access_rights   db      0h
        zeros           dw      0h
gdt_table       ends

.data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
        msg_display             db      ‘Extended Memory Found at:’, 0dh, 0ah
        test_pattern_write      dw      5a5ah
        test_pattern_read       dw      5a5ah
        stack_segment           dw      ?
        stack_pointer           dw      ?
        counter                 db      0

        dummy_descriptor        gdt_table       <0h, 0, 0, 00h, 00h>
        gdt_descriptor          gdt_table       <40h, ?, ?, 93h, 00h>
        idt_descriptor          gdt_table       <0h, 0, 0, 00h, 00h>
        ds_descriptor           gdt_table       <0ffffh, ?, ?, 93h, 00h>
        es_descriptor           gdt_table       <0ffffh, 00h, 10h, 93h, 00h>
        ss_descriptor           gdt_table       <0ffffh, ?, ?, 93h, 00h>
        cs_descriptor           gdt_table       <0ffffh, ?, ?, 9bh, 00h>
        temp_cs_descriptor      gdt_table       <0h, 0, 0, 00h, 00h>
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -display extended memory found at: on to the screen                     ;
;       -calculate the physical address for gdt, ds, ss and cs descriptor       ;
;       -set the return address                                                 ;
;       -init soft shutdown                                                     ;
;       -save the ss segment                                                    ;
;       -switch to protected mode                                               ;
;       -write and read from memory                                             ;
;       -reset the CPU                                                          ;
;…………………………………………………………………….;
.code
.startup
control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msg_display        ; set cx for string display
        mov     bp, offset msg_display          ; set pointer for string display
        xor     dx, dx                          ; set cusor position for screen display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; down one line

        mov     ax, seg dummy_descriptor        ; get the gdt table address
        shl     ax, 4                           ; shift 4 bits to the left on the segment
        add     ax, offset dummy_descriptor     ; add the segment and offset address to
        mov     gdt_descriptor.lower_address, ax; physical address and store it to the lower address
        mov     ax, seg dummy_descriptor        ; get the segment addresss
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        adc     ax, 0h                          ; and add the carry if any
        mov     gdt_descriptor.upper_address, al; and store it in the ss descriptor uppper address

        push    ds                              ; push ds
        pop     ax                              ; get the ds segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     ds_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    ds                              ; push ds
        pop     ax                              ; get the ds segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     ds_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

        push    ss                              ; push ss
        pop     ax                              ; get the ss segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     ss_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    ss                              ; push ss
        pop     ax                              ; get the ss segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     ss_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

        push    cs                              ; push cs
        pop     ax                              ; get the cs segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     cs_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    cs                              ; push cs
        pop     ax                              ; get the cs segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     cs_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

next_address:
        mov     dx, 40h                         ; set the es segment to 40h
        mov     es, dx                          ;

        mov     es:[69h], seg return_address    ; take the segment of the return
        mov     es:[67h], offset return_address ; offset address after return to real mode

        mov     al, 8fh                         ; write 05h to cmos location 0fh
        out     70h, al                         ; for CPU shutdown
        mov     al, 05h                         ;
        out     71h, al                         ;

        pushf                                   ; save the flag register
        cli                                     ; clear interrupt flag
        mov     ah, 89h                         ; switch from real mode into pretected mode
        xor     bx, bx                          ; with offset to interrupt desciptor table
                                                ; to zero
        push    seg dummy_descriptor            ; setting up the address of descriptor table
        pop     es                              ; getting the segment address and
        mov     si, offset dummy_descriptor     ; the offset address

        push    ss                              ; push the ss segment to the stack
        pop     stack_segment                   ; pop ss segment into the stack_segment
        push    sp                              ; push the ss pointer to the stack
        pop     stack_pointer                   ; pop ss pointer into the stack_pointer
        int     15h                             ; switching mode

        xor     di, di                          ; clear di
        mov     ax, test_pattern_write          ; setup the test pattern
        mov     es:[di], ax                     ; write the test pattern to mem
        mov     ax, es:[di]                     ; and read back from the mem
        mov     test_pattern_read, ax           ; save the test pattern

        mov     al, 0feh                        ; resetting the CPU to return to real mode
        out     64h, al                         ;
return_address:
        xor     ax, ax                          ; write to programmable interrupt controller
        out     21h, ax                         ; to enable all of the operation
        mov     ax, @data                       ; reinit the data segment
        mov     ds, ax                          ;

        push    stack_segment                   ; push the stack_segment to stack
        pop     ss                              ; restore the ss segment
        push    stack_pointer                   ; push the stack_pointer to the stack
        pop     sp                              ; restore the ss pointer
        popf                                    ; restore all flag

        mov     ax, test_pattern_read           ; get the test pattern from mem
        cmp     test_pattern_write, ax          ; if write == read then continure
        jne     exit_point                      ; else exit the program

        inc     counter                         ; init the counter to set new line
        cmp     counter, 6h                     ; if the counter != 6 then
        jne     no_line                         ; continue display to the screen
        mov     counter, 1h                     ; else reset counter
        call    new_line                        ; and set new line
no_line:
        mov     ax, es_descriptor.zeros         ; get the es lower address
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen

        mov     al, es_descriptor.upper_address ; get the es lower address
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, 0h
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, 0h
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        call    display_test_pattern            ; display the memory location to the screen

        clc
        add     es_descriptor.upper_address, 1h ; inc the upper address
        jc      add_the_zeros                   ; if uppter addres > ffh then add_the_zeros
        jmp     no_add_zeros                    ; else do nothing
add_the_zeros:
        inc     es_descriptor.zeros             ; inc the zeros
no_add_zeros:
        mov     test_pattern_read, 0h           ; clear the test pattern read
        jmp     next_address                    ; continue test the mem

exit_point:
        xor     ax, ax                          ; write to programmable interrupt controller
        out     21h, ax                         ; to enable all of the operation
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure display the test pattern to the screen                   ;
;                                                                               ;
;       input: al = number to be display to the screen                          ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_test_pattern    proc    near
        push    bx                              ; store the register
        push    cx                              ;
        push    dx                              ;

        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it

        mov     ax, test_pattern_write          ;
        mov     dx, ax                          ; copy the test pattern
        mov     al, ah                          ; get the ah to be display first
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, dl                          ; setup the al
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen

        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it
        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it

        pop     dx                              ; restore teh register
        pop     cx                              ;
        pop     bx                              ;
        ret
display_test_pattern    endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure will print two character to the screen.  One from ah     ;
;       another from al.                                                        ;
;                                                                               ;
;       input: ax = ascii of character to be written                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_hex     proc    near
        push    cx                              ; store register
        push    ax
        mov     cx,8h
        shr     ax,cl                           ; get the 1st nibble
        mov     ah,0eh                          ; function code for displaying char
        int     10h                             ; display the 1st nibble
        pop     ax                              ; restore data
        mov     ah, 0eh                         ; function code for displaying char
        int     10h                             ; display the 2nd nibble

        pop     cx                              ; restore register
        ret
display_hex     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ;
        pop     cx                              ; restore the resgister
        pop     bx                              ;
        ret
hex_to_ascii   endp

;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax,0600h                        ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                         ; bh=color attribute for new lines
        xor     cx,cx                           ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                        ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen             7                              ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                              ; preserve ax & bx
        push    bx
        mov     ah, 03h                         ; function number for int10
        mov     bh, 00h                         ; video page number
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx = string length                                            ;
;               dh = line number                                              ;
;               dl = column number                                            ;
;               bp = offset to string buffer                                  ;
;               ds = segment for string buffer                                ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string_uc proc    near
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es                              ;
        int     10h                             ;
        pop     ax
        ret
print_string_uc endp
end                                             ; end of file
Example 7.

.model small
.stack 100h
.486p
descriptor      struct
        limit           dw      0h
        lower_address   dw      0h
        upper_address   db      0h
        access_rights   db      0h
        zeros           dw      0h
descriptor      ends
.data
        msgs_extend_memory      db      ‘Extended Memory found at: ‘
        current_position        dw      0h
        test_pattern_write      dw      5a5ah

        gdt_begin       label           word
        dummy           descriptor      <0,0,0,0,0>
        gdt_des         descriptor      <20h,?,?,93h,0>
        es_4gig_des     descriptor      <0ffffh,0,0,93h,8fh>
        es_64k_des      descriptor      <0ffffh,0,0,93h,0>

.code
.startup
start:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msgs_extend_memory ; set cx to get the string length
        mov     bp, offset msgs_extend_memory   ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message
        call    current_cursor_position         ; get the cursor position
        mov     current_position, dx            ; save it

        call    enable_gate_a20                 ; enable the a20 address line
        mov     dx, 10h                         ; for load a segment
        call    flat_and_real                   ; go into flat mode

        mov     esi, 100000h                    ; start point 1Mb
memory_testing:
        mov     dx, test_pattern_write          ; get the test pattern
        mov     es:[esi], dx                    ; write to memory location
        mov     dx, es:[esi]                    ; read test pattern
        cmp     dx, test_pattern_write          ; if read test pattern != write test pattern
        jne     done_mem_test                   ; then memory test is done else continue

        mov     dx, current_position            ; get the cursor position
        mov     ah, 02h                         ; function to set the cursor position
        int     10h                             ; set the cursor position
        call    time_delay                      ; delay time

        mov     eax, esi                        ; copy the memory location
        call    calculate_display_dec           ; display the memory location to the screen
        add     esi, 010000h                    ; inc memory location by 64k
        jmp     memory_testing

done_mem_test:
        call    disable_gate_a20                ; enable the a20 address line
        mov     dx, 18h                         ; loading a segment
        call    flat_and_real                   ; switch from flat to real mode
.exit
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  none                                                          ;
;                                                                             ;
;       output: dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int 10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       time_delay                                                              ;
;       this procedure will delay the time                                      ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
time_delay      proc    near
        pusha                                   ; store all register
        mov     cx, 0ffffh                      ; init the counter for delay
delay:
        nop                                     ; delay
        nop                                     ; delay
        loop    delay                           ; continue until cx = 0
        popa                                    ; restore all register
        ret
time_delay      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       calculate_display_dec                                                   ;
;       this procedure display the test pattern to the screen                   ;
;                                                                               ;
;       input:  eax = in hex to be convert to dec                               ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
calculate_display_dec   proc    near
        push    edx                             ; restore 32 bits register
        push    ecx
        push    ebx

        mov     cx, 0h                          ; init the counter
        mov     ebx, 10                         ; init the divider

next_dec:
        xor     edx, edx                        ; clear the remainder
        div     ebx                             ; eax / 10
        push    dx                              ; save the remainder
        inc     cx                              ; inc the counter
        cmp     eax, 0                          ; if eax != 0
        jne     next_dec                        ; then continue do the divide

        sub     cx, 3                           ; no to display the last 3 digit
next_display_dec:
        pop     dx                              ; restore the remainder
        mov     al, dl                          ; copy remainder into al for convertion
        call    hex_to_ascii                    ; convert hex number into ascii number
        mov     ah,0eh                          ; function code for displaying char
        int     10h                             ; display it
        dec     cx                              ; dec counter
        jnz     next_display_dec                ; continue if not cx != 0

        mov     ah,0eh                          ; function code for displaying char
        mov     al, ‘K’                         ; k on the screen
        int     10h                             ; display it
        mov     ah,0eh                          ; function code for displaying char
        mov     al, ‘b’                         ; b on the screen
        int     10h                             ; display it

        pop     dx                              ; restore 3 last remainders
        pop     dx                              ;
        pop     dx                              ;

        pop     ebx                             ; restore all register
        pop     ecx
        pop     edx
        ret
calculate_display_dec   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ;
        pop     cx                              ; restore the resgister
        pop     bx                              ;
        ret
hex_to_ascii   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       flat_and_real                                                           ;
;       this procedure uses dx as an input for loading a segment register       ;
;       (selector) ES.                                                          ;
;                                                                               ;
;       input:  dx = selector for es_4gig_des or es_64k_des                     ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
flat_and_real   proc    near
        pusha                                   ; store all register
                                                ; initialize the gdt descriptor
        mov     ax, ds                          ; get the ds address
        movzx   eax, ax                         ; make the bits 16-31 all zeros
        shl     eax, 4                          ; shift 4 bits to the left
        add     eax, offset gdt_begin           ; calculate the physical address
        mov     gdt_des.lower_address, ax       ; save the lower address
        shr     eax, 16                         ; calculate the upper address
        mov     gdt_des.upper_address, al       ; save the upper address

        mov     al, 80h                         ; disable NMI
        out     70h, al

        lgdt    ds:fword ptr gdt_begin+8        ; load the global descriptor table descriptor

        mov     eax, cr0                        ; get the cr0 register
        or      al, 1                           ; or to set the pe bit in cr0 register
        mov     cr0, eax                        ; set the pe bit in cr0 register
        jmp     $+2                             ; clear the prefetch queue

        mov     ax, dx                          ; dx = 16 for flat and 18 for real
        mov     es, ax

        mov     eax, cr0                        ; get the cr0 register
        and     al, 0feh                        ; and to clear the pe bit in cr0 register
        mov     cr0, eax                        ; clear pe bit in cr0 register
        jmp     $+2                             ; clear teh prefetch queue

        popa                                    ; restore all register
        ret
flat_and_real   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax,0600h                        ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                         ; bh=color attribute for new lines
        xor     cx,cx                           ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                        ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;…………………………………………………………………….;

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string_uc                                                       ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string_uc         proc    near
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
print_string_common:                            ; portion of function common to both routines
        push    bx
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
print_string_uc         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       enable / disable gate A20                                               ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
enable_gate_a20:
        push    ax                                      ; store ax register
        mov     ah, 0dfh                                ; command to enable a20 gate
        jmp     ed_1

disable_gate_a20:
        push    ax                                      ; store ax register
        mov     ah, 0ddh                                ; command to disable a20 gate
ed_1:
        mov     al, 0d1h                                ; command for write to output port
        out     64h, al                                 ;
ed_2:
        jcxz    $+2
        in      al, 64h                                 ; read status byte
        test    al, 2                                   ; check whether input buffer is full
        jnz     ed_2                                    ; some byte still in the input buffer
        mov     al, ah                                  ; pass data byte for controller command
        out     60h, al                                 ;
ed_3:
        in      al, 64h                                 ; read status byte
        test    al, 00000010b                           ; check whether input buffer is full
        jnz     ed_3                                    ; some byte still in the input buffer
        pop     ax                                      ; restore ax register
        ret

end                                                     ; end of program

Advertisements

About superjameszou

Hardware Design Engineer
This entry was posted in Assembly Language. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s