0% found this document useful (0 votes)
13 views11 pages

COS2621 Programs

The document provides a series of assembly language programs demonstrating how to display characters and strings, accept keyboard input, and convert numbers to strings. It includes examples of using procedures for simplifying code, as well as algorithms for finding prime numbers and calculating factorials. Key concepts such as indirect addressing, ASCII conversion, and the importance of string termination are emphasized throughout.

Uploaded by

Mega Byte
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views11 pages

COS2621 Programs

The document provides a series of assembly language programs demonstrating how to display characters and strings, accept keyboard input, and convert numbers to strings. It includes examples of using procedures for simplifying code, as well as algorithms for finding prime numbers and calculating factorials. Key concepts such as indirect addressing, ASCII conversion, and the importance of string termination are emphasized throughout.

Uploaded by

Mega Byte
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

http://wikistudent.

ws/Unisa
How to display output on the screen:
1. This program prints the character ‘a’:

org 0x100
bits 16
jmp main
message: db 'a' ; message is the address of char 'a'
main: mov bx, message ; move message (i.e. an address) to bx
mov dl,[ bx ] ; move contents of address pointed to
; by bx to dl. This is an example
; of register INDIRECT addressing
mov ah,02
int 21h
int 20h

Notes:
• mov ah,02 is used for displaying ONE character (in dl) only. If message
was ‘abc’, just ‘a’ would be displayed.
• To avoid indirect addressing, if you knew that the offset of message was
3, you could type mov dl,[103h] instead. It would be even simpler to type
mov dl,’a’ if you don’t need to give the character a label.
• Of AX, BX, CX, and DX, only BX can be used for indirect addressing.

2.This program prints a sentence:

org 0x100
bits 16
jmp main
message: db 'long string with no dollar/appostrophe characters!','$'
main: mov dx,message ; move the start address of message

mov ah,09
int 21h
int 20h

Notes:
• The string MUST end with ‘$’ - otherwise garbage follows in the output.
An optional 0ah, 0dh provide a line feed and carriage return.
• mov dx,message could be replaced with mov dx,103h because the offset of
message is 3.

Remember:
Character output - When ah contains 2, a character must be in dl.
String output - When ah contains 9, an address must be in dx.

3. This program uses INC to increment a character:

org 0x100
bits 16

mov dl,'q'
inc dl ; increment a VALUE

mov ah,02
int 21h ; displays 'r'
int 20h

4. This program uses INC to advance a start address by one:

org 0x100
bits 16
1
http://wikistudent.ws/Unisa

mov dx,message
inc dx ; increment an ADDRESS

mov ah,09
int 21h ; displays 'werty'
int 20h

message: db 'q','w','e','r','t','y','$' ; same as 'qwerty$'

Notes:
• message may appear after the program!

Accepting input from the keyboard and displaying it:


org 0x100
bits 16
jmp main

input: db 20 ; length of the buffer


db 0 ; no of bytes read (written here later)
resb 21 ; bytes reserved for input characters
prompt1: db 'Enter a word', 0ah, 0dh, '$'
prompt2: db 13,10,'Enter a character', 0ah, 0dh, '$'

main: mov dx,prompt1


mov ah,09
int 21h

mov dx,input
mov ah,0ah
int 21h ; a string has been read into dx;

mov dl,13 ; carriage return


mov ah,2
int 21h

mov dl,10 ; line feed


mov ah,2
int 21h

mov dx,input
inc dx ; skip over the length of the buffer
inc dx ; skip over the no of bytes read
mov bx,dx ; bx points to start of input characters
mov al,[input+1]; the length of the string
mov ah,0 ; (this fills up ax)
add bx,ax ; bx points one char past last char entered
mov al,'$'
mov [bx],al ; put a $ sign after the last character
mov ah,09
int 21h ; the string in dx is displayed on the screen

mov dx,prompt2
mov ah,09
int 21h

mov ah,01
int 21h ; a character has been read into al

mov dl,al ; the character is moved to dl for display


mov ah,02
int 21h

2
http://wikistudent.ws/Unisa
int 20h

Notes:
• When displaying the string that was read, you have to leave out the info
stored in the first two bytes, and add a $ sign to the end, with the help
of bx.

Simplifying the above program by using procedures:

org 0x100
bits 16
jmp main

input: db 20
db 0
resb 21

prompt1: db 'Enter a word', 0ah, 0dh, '$'


prompt2: db 13, 10, 'Enter a character', 0ah, 0dh, '$'

get_string: mov ah,0ah


int 21h
ret

display_string: mov ah,09


int 21h
ret

get_char: mov ah,01


int 21h;
ret

display_char: mov ah,02


int 21h
ret

main: mov dx,prompt1


call display_string ; prompt for a string

mov dx,input
call get_string ; read in the string

mov dl,13
call display_char

mov dl,10
call display_char

mov dx,input
inc dx
inc dx
mov bx,dx
mov al,[input+1]
mov ah,0
add bx,ax
mov al,'$'
mov [bx],al
call display_string ; display the string

mov dx,prompt2
call display_string ; prompt for a character

call get_char ; read in the character

mov dl,al
3
http://wikistudent.ws/Unisa
call display_char ; display the character

int 20h

Notes:
• When you want to display a character, you can use either single quotes
around the character, as in mov al,’2’, or a number which is the ASCII
equivalent, as in mov al,50 (which is also the character ‘2’). This won’t
work if you want to display a string that is in dx.

Useful table to memorise:


Input Output
char mov ah,01 (char is now mov ah,02 (char must first
pointed to by al) be pointed to by dl)
string mov ah,10 (string is now mov ah,09 (string must first
pointed to by dx) be pointed to by dx)

Converting numbers to strings:


These programs display numbers as strings on the screen. They need to be
converted to ASCII values because if you try printing a number (using mov
ah,02) you get the ASCII equivalent, not the actual number. Number characters
in ASCII start at position 48 (or 30h), so that’s the amount you need to add to
each digit. One digit is converted at a time, starting with the right-most one
and using modulo 10 to extract it. With each loop iteration the last digit is
added to the next-last position in the buffer. The buffer pointer must be
decremented each time for this to happen.

This version of the program uses a 16-bit divisor (pointed to by bx):


bits 16
org 0x100
jmp main

buffer: db ' ', '$' ; 5 spaces for max number of 65535 (FFFF)

main: mov di,buffer ; (di can be used for string operations)


add di,4 ; di now points to the last buffer position
mov bx,10 ; the numbers are going to be divided by 10
mov ax,65535 ; FFFF is the largest number you can use in ax

loop1: xor dx,dx ; clear dx (because idiv uses dx:ax here)


; not clearing dx gives a division overflow
idiv bx ; divide dx:ax by bx
; result in ax, remainder in dx
add dx,30h ; convert remainder to ASCII
mov [di],dl ; move the ASCII digit to the next last pos
cmp ax,0 ; test if there are more digits left
je finis
dec di ; point to a previous position
jmp loop1

finis: mov dx,buffer ; dx points to the beginning of the buffer


mov ah,09
int 21h

int 20h

This version of the program uses an 8-bit divisor (pointed to by bl):


bits 16
org 0x100
jmp main

buffer: db ' ', '$' ; 3 spaces for max number of 255 (FF)

4
http://wikistudent.ws/Unisa
main: mov di,buffer
add di,2
mov bl,10
mov al,255 ; FF is the largest number you can use in al

loop1: xor ah,ah ; clear ah (because idiv uses the entire ax)
; not clearing ah gives a division overflow
idiv bl ; divide ax by bl
; result in al, remainder in ah
add ah,30h
mov [di],ah
cmp al,0
je finis
dec di
jmp loop1

finis: mov dx,buffer


mov ah,09
int 21h

int 20h

Reading in a number as a string, converting it to a numeric value,


adding 5, and then converting it to a string for display:
org 0x100
bits 16
jmp main

inputbuffer: db 6;
db 0;
resb 6;

outputbuffer: db ' ','$' ; length of 5 chars

prompt: db 'Enter a number: ','$'

str_to_num: xor ax,ax ; ax will point to the number


xor bh,bh ; clear bh because bx is used later
mov cx,10
mov si,dx ; si points to the start address

next_char: mov bl,[si] ; move the first character to bl


cmp bl,'$' ; check if it is the last char
je finis
cmp bl,39h ; character '9'
jg error
cmp bl,30h ; character '0'
jl error
sub bl,30h ; convert to ASCII numeric value
imul cx ; dx:ax = ax * 10 (shift digits left)
add ax,bx ; add the character to ax
inc si ; point to the next character
jmp next_char

error: mov al,'E'

finis: ret

main: mov dx,prompt ; display prompt


mov ah,09
int 21h

mov dx,inputbuffer ; read in the number string

5
http://wikistudent.ws/Unisa
mov ah,10
int 21h

mov dl,13 ; carriage return


mov ah,2
int 21h

mov dl,10 ; line feed


mov ah,2
int 21h

mov dx,inputbuffer
inc dx
inc dx
mov bx,dx
mov al,[inputbuffer + 1]
mov ah,0
add bx,ax
mov al,'$'
mov [bx],al ; now the string with '$' is in dx

call str_to_num ; afterwards, the number is in ax


cmp al,69 ; test for error character 'E'
je display_error
add ax,5 ; add 5 before making it a string

mov di,outputbuffer
add di,4
xor bx,bx
mov bx,10

num_to_str: xor dx,dx


idiv bx ; divide dx:ax by bx
add dx,30h ; convert the remainder to ASCII
mov [di],dl
cmp ax,0
je display_str
dec di
jmp num_to_str

display_str: mov dx,outputbuffer


mov ah,09
int 21h

int 20h

display_error: mov dl,al


mov ah,02
int 21h

int 20h

Notes:
• You can’t read in or print numbers using their actual values - they are
always treated as ASCII strings.
• The largest number that can be displayed is 65535. Because 5 is added to
the input value, the largest number you can enter is 65530.

Using the sieve of Eratosthenes to find the first 1000 primes:


Algorithm: Initialise 1000 bytes to ‘1’ and use nested loops to replace bytes
in non-prime positions with ‘0’. The outer loop (i) runs from 2 to 32 (you only
need to iterate till the square root of 1000!) and the inner loop (j) goes from

6
http://wikistudent.ws/Unisa
i to 1000, in increments of i, replacing these multiples of i with ‘0’ (because
multiples of anything cannot be prime!).
The program prints the list of ‘1’s and ‘0’s. A ‘1’ indicates that the number
in that position (starting from position 1, not 0) is prime. If it is ‘0’, the
number in that position is not prime.

org 0x100
bits 16
jmp main

buffer: times 1000 db '1'


db '$'

start: mov ax,1 ; the outer-loop counter


mov cl,30h ; char '0' to wipe out non-primes

outer_loop: inc ax ; for loop from 2 to 32


cmp ax,32
jge print_primes ; quit after 31 iterations

mov bx,ax ; start from current outer index


inner_loop: add bx,ax ; check every jth number above j
cmp bx,1000 ; see if you've reached the end
jg outer_loop
mov [bx+buffer-1],cl ; turn multiples of j into '0'
jmp inner_loop

print_primes: mov dx,buffer


mov ah,09
int 21h

int 20h

main: jmp start

Finding the factorial of a number and displaying it:


bits 16
org 0x100
jmp main

buffer db ' $' ; 5 spaces reserved for output (FFFF = 65535)

number: dw 8 ; the largest number you can use (8! = 40320)


; equivalent to db 8,0 (little endian!)

main: mov di,buffer ; this will store the output string later
add di,4 ; point to the last space
mov ax,[number] ; the number, and product so far = in dx:ax
mov cx,ax ; used to multiply, with each loop iteration
dec cx ; because you start multiplying by n - 1

repeat: imul cx ; multiply ax by cx - product in dx:ax


loop repeat ; decrement cx and loop till cx = 0

mov bx,10 ; you're goint to extract 1 digit at a time


loop1: xor dx,dx ; clear dx to prevent a divide overflow error
div bx ; divide dx:ax by 10
; quotient in ax, remainder in dx
add dx,30h ; convert to string for display
mov [di],dl ; move the digit to the right-most space
dec di ; point to the next right-most space
cmp ax,0 ; more digits to divide?
je display
jmp loop1 ; else loop
7
http://wikistudent.ws/Unisa

display: mov dx,buffer ; modified buffer, thanks to di operations


mov ah,09
int 21h

int 20h

Setting the time on your computer clock:


bits 16
org 0x100
jmp main

main: mov ch,20 ; hours


mov cl,58 ; minutes
mov dh,1 ; seconds
mov dl,9 ; hundredths of a second

mov ah,2dh
int 21h
int 20h

Notes:
• You can shorten the program with mov cx,nn and mov dx,nn instead
• Remember: mov ch,10h and mov cl,23h is the same as mov cx,1023h!

Using the stack to reverse user input:


bits 16
org 0x100
jmp main

input_buffer: db 21
buffer_len: db 00
string: resb 21

array: times 20 db ' ' ; 20 spaces = max output length

cr_lf: db 13, 10, '$'

main: mov dx,input_buffer


mov ah,0ah
int 21h ; read in a string

mov dx,cr_lf
mov ah,9
int 21h ; move to the next line

mov si,string ; (the user input)


mov cl,[buffer_len]
xor ch,ch ; cx will be the loop counter
xor ah,ah ; ax will be pushed on the stack

loop1: mov al,[si] ; work with one char at a time


push ax
inc si ; point to the next char
loop loop1

unpack: mov di,array ; point to the start of the array


mov dx,di ; for display, later on
mov cl,[buffer_len] ; set the loop counter
xor ch,ch

loop2: pop ax
8
http://wikistudent.ws/Unisa
mov [di],al ; move one char at a time
inc di ; point to the next space
loop loop2

add di,[buffer_len] ; point to the end of the string


mov bx,'$'
mov di,bx ; place a $ at the end
mov ah,09
int 21h ; display the string in reverse

int 20h

Note: The stack is implicitly used when a procedure is called (with ‘call’).
The address of the instruction following the call is pushed onto the stack and
when the ‘ret’ instruction is executed in the subroutine, it’s popped off.
Remember: when you’re in a subroutine, the return address is always on top of
the stack!

Something to remember: Bytes are stored in reverse order in memory!

Comparing LEA with MOV:


org 0x100
bits 16
jmp main
buffer1: db 'Hello', 13, 10,'$'
buffer2: db 'Goodbye','$'

main: mov dx,buffer1


mov ah,09
int 21h

lea dx,[buffer2] ; loads the effective address of buffer2


mov ah,09
int 21h

int 20h

• mov dx,buffer and lea dx,[buffer] have the same effect, but these
different instructions may occupy a different number of bytes. You can
always insert ‘nop’ to fill in the gap.

Parameter passing:
There are three ways of passing parameters:
1. Store the parameters in a parameter block in memory
2. Store the parameters in registers before calling the subroutine
3. Push the parameters onto the stack

1. Using a parameter block in memory (calling by name):


The address of the block is stored in a register before the subroutine is
called.

In this program, the procedure that accepts a string from the keyboard makes
use of the ‘input_buffer’, by storing the length of the string entered, etc.
This buffer is passed as a parameter by the statement ‘mov dx,input_buffer’,
just before the procedure call.

org 0x100
bits 16
jmp main

; parameter block:
input_buffer: db 5 ; max 5 chars
9
http://wikistudent.ws/Unisa
db 0 ; length of string entered
resb 5 ; 5 bytes reserved as input buffer

; procedure: ; uses the parameter block in dx


accept_string: mov ah,0ah
int 21h
ret

main: mov dx,input_buffer ; mov parameter block in dx first!


call accept_string
int 20h

2. Passing parameters in registers (calling by value):


The calling program must simply store the parameters in the relevant registers
before calling the subroutine. On entering the subroutine, nothing needs to be
done in the prolog because the parameters are already in the required
registers. This mechanism is fast but can only be used when we have to pass a
few values that will fit into registers.

3. Passing parameters on the stack (calling by value):


The return address is pushed onto the top of the stack when the subroutine is
called, and popped off when the subroutine returns.

org 0x100
bits 16
jmp main

output_buffer: db ' $'

number_3: dw 3 ; dw, not db (because AX etc. = 2 bytes!)


number_7: dw 7
number_1: dw 1

return_second: ; the procedure returns the second parameter


prolog: pop ax ; store the RETURN ADDRESS temporarily
pop bx ; pop the three parameters
pop cx ; into bx, cx and dx
pop dx ; for local use

body: ; this is where you could have additional program statements

epilog: push cx ; cx points to the second parameter


push ax ; restore the RETURN ADDRESS
ret ; the 2nd parameter is returned on the stack

main: mov ax,[number_3] ; store three different numbers


mov bx,[number_7] ; which will be sent as parameters
mov cx,[number_1] ; on the stack to the procedure

start_up: push ax ; push the 3 numbers onto the stack


push bx ; the procedure will access them
push cx ; by popping them off

call return_second ; the return address is IMPLICITLY


; pushed on the stack!! so when
; you enter the procedure it is
; popped off FIRST

; the return address was implicitly popped off, so now:


clean_up: pop dx ; pop the return value off the stack into dx
add dl,30h ; convert to ascii string
mov di,output_buffer
mov [di],dl ; move the digit into the buffer
mov dx,output_buffer
mov ah,09h
10
http://wikistudent.ws/Unisa
int 21h ; prints 7
int 20h

11

You might also like