Assembler in examples

Clearing of the screen

    We begin with this simple example. We want to clear the screen in text mode and we will use a direct acces to the screen. The screen begins at B800:0000h and has 80 columns and 25 rows (in basic text mode) each cell two bytes long. The first byte is the ASCII code of the character, the second is the character's color.

[BITS 16]
[ORG 0x0100]
[SECTION .text]

MOV AX,0B800H
;a hexadecimal number has to begin with a cipher so this won't be confound with a name of a label, so that's why we have to write it as 0B800h and not B800h
MOV ES,AX
;segment register ES can be filled with a number only using AX register
MOV CX,80*25
MOV AX,7*256+' '
;using color 7 (white) "clear" the screen with spaces
REP STOSW

MOV AX,4C00h
INT 21h

Printing numbers

    The next example will print a fixed chosen number in a fixed chosen number system (in range from 2 - binary - to 16 - hexadecimal). We'll use a DOS function for printing the number.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

MOV AX,12345
;chosen number in range from 0 to 65535
MOV BL,16
;the basis of chosen number system in range from 2 to 16

MOV DI,16
;we will print the number from the end - beginning with the lowest cipher

next:
DEC DI
;next cipher
XOR DX,DX
;DX<-0
DIV BX
;next cipher into DX
MOV SI,DX
MOV DL,[SI+ciphers]
;find out the right character for this cipher...
MOV [DI+prnt],DL
;...and print it
AND AX,AX
JNZ next
;continue until AX=0, i.e. until all ciphers are printed

MOV DX,text
;address of first text into DX
MOV AH,09h
;service number...
INT 21h
;...used for text output
MOV DX,prnt
ADD DX,DI
;we will print the number beginning with the first - most valuable (significant) cipher, so the very last printed cipher
MOV AH,09h
INT 21h

MOV AX,4C00h
INT 21h

[SECTION .data]
;this way is variable section defined

ciphers DB '0123456789ABCDEF'
;list of cipher characters
text DB 'Number = $'
;output text ending with $
prnt TIMES 16 DB 0
DB '$'
;maximum sixteen ciphers output number - using directive TIMES we can define a field of equal items much easier

Calculating of square root

    This program works with number from the input (from keyboard, in NASMIDE environmnet you have to enter the input using menu item parameters), in a word-range (from 0 to 65535). It is looking for the result using try-fail method. It tries to set particular bits of the searched result (beginning with the most significant) and then it computes a square of this number. If that square is greater than input number, the bit set has to be cleared.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

MOV DX,input
;get the first seven characters from the standard input,...
MOV CX,7
;...because two of them will mean ending of the input - pressing the ENTER key (0Dh, 0Ah),...
MOV BX,0
;...and write them into memory beginning at the "input" label
MOV AH,3Fh
INT 21h

SUB AX,2
;in AX is the input characters count but we have to subtract two to get rid of the ENTER
OR AX,AX
JZ exit
;exit if there is no input
MOV CX,AX
;characters count into CX
MOV DI,input
MOV BX,10
;we will convert decimal input into AX register
XOR AX,AX
XOR DH,DH
;clear AX and DH
mk_test:
MUL BX
;multiply the timely result with ten
MOV DL,[DI]
;read the next character
SUB DL,'0'
;change the ASCII character into a number from 0 to 9
INC DI
;get the pointer on the next character
CMP DL,0
JC exit
;if the number isn't in range from 0 to 9, exit
CMP DL,10
JNC exit
ADD AX,DX
;add the timely result and the new cipher
LOOP mk_test
;i.e. SUB CX,1 and JNZ mk_test - a simple loop
JMP continue

exit:
MOV AX,4C00h
INT 21h
;wrong input - exit

continue:
MOV CX,AX
;number we want to calculate square root from into CX register
MOV BL,10000000b
;beginning with the most significant bit
XOR BH,BH
;BH<-0
MOV DL,2

search:
ADD BH,BL
;try to add the examined bit
MOV AL,BH
MUL AL
;calculate a square from the searched result...
CMP CX,AX
;...and compare it with the input number
JNC ok
SUB BH,BL
;that was too much, subtract the bit
ok:
MOV AL,BL
;if everything is O.K. ...
XOR AH,AH
DIV DL
MOV BL,AL
;move BL onto the next bit - divide it with two and it will rotate right
OR AL,AL
JNZ search
;if we haven't tried all bits, continue

MOV AL,BH
MUL AL
SUB CX,AX
;calculate a square from the result and get the remainder
MOV AL,BH
XOR AH,AH

MOV BX,10
MOV DI,3

next1:
;print AX register - the result - using procedure like in printing numbers
DEC DI
XOR DX,DX
DIV BX
MOV SI,DX
MOV DL,[SI+ciphers]
MOV [DI+output1],DL
AND AX,AX
JNZ next1

MOV DX,text1
MOV AH,09h
INT 21h
MOV DX,output1
ADD DX,DI
MOV AH,09h
INT 21h

MOV DI,3
MOV AX,CX

next2:
;print CX register - remainder - likewise
DEC DI
XOR DX,DX
DIV BX
MOV SI,DX
MOV DL,[SI+ciphers]
MOV [DI+output2],DL
AND AX,AX
JNZ next2

MOV DX,text2
MOV AH,09h
INT 21h
MOV DX,output2
ADD DX,DI
MOV AH,09h
INT 21h

MOV AX,4C00h
INT 21h

[SECTION .data]

input TIMES 7 DB 0
;place for input from keyboard
ciphers DB '0123456789'
;characters and texts to print like in program printing numbers
text1 DB 'Square root = $'
output1 TIMES 3 DB 0
DB '$'
text2 DB ', remainder = $'
output2 TIMES 3 DB 0
DB '.$'

Screensaver

    The last program is something like a screensaver. It prints fourty "smiley" characters (character 01h ASCII) and moves them in various directions. If a smiley "falls out" the screen a new character is generated.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

begin:
MOV AX,0B800h
;clears the screen
MOV ES,AX
XOR DI,DI
MOV CX,80*25
MOV AX,7*256+' '
REP STOSW

MOV SI,39*2
;we will print from a two-byte table beginning from the 39th character to the zero character - together 40 characters
MOV AH,01h
INT 16h
JZ cycle
;find out if a key was pressed and when it was so, exit
XOR AH,AH
;but also get it out of the buffer
INT 16h
MOV AX,4C00h
INT 21h

cycle:
MOV CX,[SI+pos]
;find out if the particular character is valid (after launching the program none is valid)
OR CX,CX
JNZ output
;if it's O.K. print it, if not continue and generate a new one

CALL random
;random number into DX register, it calls procedure named "random", after returning it continues with the next instruction
MOV CX,DX
;and now we try to extract from the content of the DX register the direction of the new character (without using the most significant - unused bit the three most significant bits of the higher byte), its row (lower four bits of the higher byte), color (two most significant bits in the lower byte) and column (other six bits of the lower byte)
AND CX,0000111100111111b
;mask for the y and x coordinate of the character...
ADD CX,5*256+9
;...which were generated in range from 0 to 15 (adding 5 changed to range from 5 to 20) and in range from 0 to 63 (adding 9 changed to range from 9 to 72)
MOV [SI+pos],CX
;store new coordinates into table

AND DX,0111000011000000b
;mask for the direction and color of the generated character
MOV [SI+info],DX
;store new informations into table

output:
MOV DL,160
;print the character, in CX remained its coordinates
SUB CX,0101h
;a correction from ranges 1..80 and 1..25 into ranges 0..79 a 0..24
ADD CL,CL
;multiply the x coordinate with two - one character takes in the screen memory two bytes
MOV AL,CH
MUL DL
;and multiply the y coordinate with 80*2 because of the same reason
XOR CH,CH
ADD AX,CX
MOV DI,AX
;address of the character on the screen into DI
MOV BX,[SI+info]
;find out the direction and color of the character
MOV AL,BL
MOV BL,01000000b
XOR AH,AH
DIV BL
;the color is recorded in the two most significant bits of the lower byte - we have to move it to the lowest position in a byte...
ADD AL,00001100b
;...and add 12 so we get a light color - we get then light red, light magenta, yellow and white
MOV AH,AL
MOV AL,1
;character 01h - a smiley
STOSW
;and print it

MOV BL,00100000b/2
;so move the direction but only to the second lowest bit - we use a two-bytes table
MOV AL,BH
XOR AH,AH
DIV BL
MOV DI,AX
MOV CX,[SI+pos]
;timely character position into CX register
ADD CX,[DI+tab]
;and add it with the "speed" according to the table
OR CH,CH
;we have to find out if the character fell out the screen
JZ delete
CMP CH,26
JNC delete
OR CL,CL
JZ delete
CMP CL,81
JC leave
delete:
XOR CX,CX
;it fell out - delete it
leave:
MOV [SI+pos],CX
;store new position of the character
SUB SI,2
;go to the next character
JNC cycle
XOR AX,AX
;all characters printed - now we have to include a waiting loop so the characters don't flash before our eyes...
MOV ES,AX
;...without this it wouldn't be possible to recognize those characters on today's computers
MOV AL,[ES:046Ch]
wait:
CMP AL,[ES:046Ch]
JZ wait
;we'll wait for a change of the timer which is changed every 55 milliseconds, i.e. 18.2 times per second
JMP begin
;and again to the beginning

random:
;procedure for generating a random number
MOV BX,0
;last generated number
MOV DH,BL
;I don't know how this works, it's transcribed from book "Assembler and ZX Spectrum 2" and its authors transcribed it from another program...
MOV DL,253
;but it reliably generates each number in range from 0 to 65535
MOV AL,BH
SUB DX,BX
SBB AL,0
SBB DX,BX
SBB AL,0
MOV BL,AL
MOV BH,0
SBB DX,BX
JNC random1
INC DX
random1:
MOV [random+1],DX
;store the new random number...
RET
;...and return from the procedure

[SECTION .data]

tab DW 0FFFFh,0FF00h,0FF01h,00001h,00101h,00100h,001FFh,000FFh
;a table of "speeds" according to the direction, beginning with the up-left direction clockwise, the higher byte is the "speed" in y coordinate, the lower byte is the "speed" in x, using numbers -1 (=0FFh=255), i.e.. up/left, 0 and 1, i.e. down/right
pos TIMES 40 DW 0
;position of the characters before launching - everything is equal to zero so all characters are generated anew
info TIMES 40 DW 0
;characters' informations - direction and color