ASCII Code
The ASCII is defined as 7-bit
meanwhile the extended version is 8-bit
.
We can add 0x30
to the numbers to represent their ASCII form (since the numbers themselves lie in range 30-39)
Display Memory Formation
We can send ASCII
codes to VGA
to print specific characters.
The screen has 80
rows and 25
columns.
Each character
needs 1 word
, first byte
being the character code and 2nd one being the attribute byte
.
Display Memory Base Address
The display video memory starts from B8000
Attribute Byte
This holds the foreground
and background
color for the character and is also called video attribute
.
- Blue component of foreground color
- Green component of foreground color
- Red component of foreground color
- Intensity component of foreground color
- Blue component of background color
- Green component of background color
- Red component of background color
- Blinking of foreground character
Display Examples
We can use DS
or ES
but to keep semantic separation, we use DS
for data and ES
for video.
Also, we cannot directly load an address into segment registers
.
Therefore, we use AX
as such:
mov ax, 0xb800
mov es, ax
mov word [es:0], 0x0741
the 41
indicates it is character A
and 07
is the attribute byte suggesting a white foreground (since all the RGB channels are ON).
mov word [es:160], 0x1230
This is displayed at the 2nd row, 1st column.
[org 0x0100]
mov ax, 0xb800 ; load video base in ax
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
nextchar:
mov word [es:di], 0x0720 ; clear next char on screen
add di, 2 ; move to next screen location
cmp di, 4000 ; has the whole screen cleared
jne nextchar ; if no clear next position
mov ax, 0x4c00 ; terminate program
int 0x21 ; interrupt to DOS
Hello World in Assembly
We can define the characters as such:
db 0x61, 0x62, 0x63
db 'a', 'b', 'c'
db 'abc'
[org 0x0100]
jmp start
message:
db 'hello world' ; string to be printed
length:
dw 11 ; length of the string
; subroutine to clear the screen
clrscr:
push es
push ax
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
nextloc:
mov word [es:di], 0x0720 ; clear next char on screen
add di, 2 ; move to next screen location
cmp di, 4000 ; has the whole screen cleared
jne nextloc ; if no, clear next position
pop di
pop ax
pop es
ret
; subroutine to print a string at top left of screen
; takes address of string and its length as parameters
printstr:
push bp
mov bp, sp
push es
push ax
push cx
push si
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
mov si, [bp+6] ; point si to string
mov cx, [bp+4] ; load length of string in cx
mov ah, 0x07 ; normal attribute fixed in al
nextchar:
mov al, [si] ; load next char of string
mov [es:di], ax ; show this char on screen
add di, 2 ; move to next screen location
add si, 1 ; move to next char in string
loop nextchar ; repeat the operation cx times
pop di
pop si
pop cx
pop ax
pop es
pop bp
ret 4
start:
call clrscr ; call the clrscr subroutine
mov ax, message
push ax ; push address of message
push word [length] ; push message length
call printstr ; call the printstr subroutine
mov ax, 0x4c00 ; terminate program
int 0x21 ; interrupt to DOS
Number Printing in Assembly
A problem is that the number 10
has its own ASCII
code.
You cannot add the codes of 1
and 0
.
Number Printing Algorithm
The algorithm is pretty simple: - Divide the number by base (10 in case of decimal) - The remainder is its right most digit - Convert the digit to its ASCII representation (Add 0x30 to the remainder in case of decimal) - Save this digit on stack - If the quotient is non-zero repeat the whole process to get the next digit, otherwise stop - Pop digits one by one and print on screen left to right
DIV Instruction
This is an integer
division instruction.
There are 2 forms of it.
1. The first form divides a 32-bit
number in DX:AX
by its 16-bit
operand and puts the remainder
in DX
and quotient
in AX
.
2. The second form divides a 16-bit
number in AX
by its 8-bit
operand and puts remainder
in AH
and quotient
in AL
.
If the quotient
exceeds the size of destination register then a type 0
interrupt is generated which is same for divide by zero
.
Number Printing Example
[org 0x0100]
jmp start
;;;;; COPY LINES 008-025 FROM EXAMPLE 6.2 (clrscr) ;;;;;
; subroutine to clear the screen
clrscr:
push es
push ax
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
nextloc:
mov word [es:di], 0x0720 ; clear next char on screen
add di, 2 ; move to next screen location
cmp di, 4000 ; has the whole screen cleared
jne nextloc ; if no, clear next position
pop di
pop ax
pop es
ret
; subroutine to print a number at top left of screen
; takes the number to be printed as its parameter
printnum:
push bp
mov bp, sp
push es
push ax
push bx
push cx
push dx
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov ax, [bp+4] ; load number in ax
mov bx, 10 ; use base 10 for division
mov cx, 0 ; initialize count of digits
nextdigit:
mov dx, 0 ; zero upper half of dividend
div bx ; divide by 10
add dl, 0x30 ; convert digit into ascii value
push dx ; save ascii value on stack
inc cx ; increment count of values
cmp ax, 0 ; is the quotient zero
jnz nextdigit ; if no, divide it again
mov di, 0 ; point di to top left column
nextpos:
pop dx ; remove a digit from the stack
mov dh, 0x07 ; use normal attribute
mov [es:di], dx ; print char on screen
add di, 2 ; move to next screen location
loop nextpos ; repeat for all digits on stack
pop di
pop dx
pop cx
pop bx
pop ax
pop es
pop bp
ret 2
start:
call clrscr ; call the clrscr subroutine
mov ax, 4529
push ax ; place number on stack
call printnum ; call the printnum subroutine
mov ax, 0x4c00 ; terminate program
int 0x21 ; interrupt to DOS
Screen Location Calculation
The 2
is there due to word
being used for a character
.
MUL Instruction
It is unsigned multiplication
.
If the operand is a byte
then it is multiplied by AL
and result is stored in AH
and AL
.
If it is a word
then it is multiplied by AX
and result is stored in DX
and AX
.
String Printing at Desired Location
[org 0x0100]
jmp start
message:
db 'hello world' ; string to be printed
length:
dw 11 ; length of the string
; subroutine to clear the screen
clrscr:
push es
push ax
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
nextloc:
mov word [es:di], 0x0720 ; clear next char on screen
add di, 2 ; move to next screen location
cmp di, 4000 ; has the whole screen cleared
jne nextloc ; if no, clear next position
pop di
pop ax
pop es
ret
; subroutine to print a string at desired screen location
; takes x position, y position, string attribute, address of string
; and its length as parameters
printstr:
push bp
mov bp, sp
push es
push ax
push cx
push si
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov al, 80 ; load al with columns per row
mul byte [bp+10] ; multiply with y position
add ax, [bp+12] ; add x position
shl ax, 1 ; turn into byte offset
mov di, ax ; point di to required location
mov si, [bp+6] ; point si to string
mov cx, [bp+4] ; load length of string in cx
mov ah, [bp+8] ; load attribute in ah
nextchar:
mov al, [si] ; load next char of string
mov [es:di], ax ; show this char on screen
add di, 2 ; move to next screen location
add si, 1 ; move to next char in string
loop nextchar ; repeat the operation cx times
pop di
pop si
pop cx
pop ax
pop es
pop bp
ret 10
start:
call clrscr ; call the clrscr subroutine
mov ax, 30
push ax ; push x position
mov ax, 20
push ax ; push y position
mov ax, 1 ; blue on black attribute
push ax ; push attribute
mov ax, message
push ax ; push address of message
push word [length] ; push message length
call printstr ; call the printstr subroutine
mov ax, 0x4c00 ; terminate program
int 0x21 ; interrupt to DOS