name "huge"
; this example shows how to add huge unpacked bcd numbers.
; this allows to over come the 16 bit and even 32 bit limitation.
; because 32 digit decimal value holds over 100 bits!
; with some effort the number of digits can be increased.
org 100h
; skip data:
jmp code
; the number of digits in numbers:
; it's important to reserve 0 as most significant digit, to avoid overflow.
; so if you need to operate with 250 digit values, you need to declare len = 251
len equ 32
; every decimal digit is stored in a separate byte.
; first number is: 423454612361234512344535179521
num1 db 0,0,4,2,3,4,5,4,6,1,2,3,6,1,2,3,4,5,1,2,3,4,4,5,3,5,1,7,9,5,2,1
; second number is: 712378847771981123513137882498
num2 db 0,0,7,1,2,3,7,8,8,4,7,7,7,1,9,8,1,1,2,3,5,1,3,1,3,7,8,8,2,4,9,8
; we will calculate this:
; sum = num1 + num2
; 423454612361234512344535179521 + 712378847771981123513137882498 =
; = 1135833460133215635857673062019
sum db len dup(0) ; declare array to keep the result.
; you may check the result on paper, or click Start , then Run, then type "calc" and hit enter key.
code: nop ; entry point (nop does nothing, it's nope).
; digit pointer:
mov bx,10
xor bx, bx
; setup the loop:
mov cx, len
mov bx, len-1 ; point to lest significant digit!
next_digit:
; add digits:
mov al, num1[bx]
adc al, num2[bx]
; this is a very useful instruction that
; adjusts the value of addition
; to be string compatible
aaa
; aaa stands for ascii add adjust.
; --- algorithm behind aaa ---
; if low nibble of al > 9 or af = 1 then:
; al = al + 6
; ah = ah + 1
; af = 1
; cf = 1
; else
; af = 0
; cf = 0
;
; in both cases: clear the high nibble of al.
; --- end of aaa logic ---
; store result:
mov sum[bx], al
; point to next digit:
dec bx
loop next_digit
; include carry in result (if any):
adc sum[bx], 0
; print out the result:
mov cx, len
; start printing from most significant digit:
mov bx, 0
print_d:
mov al, sum[bx]
; convert to ascii char:
;功能描述:在Teletype模式下显示字符
;入口参数:AH=0EH
;AL= 字符
;BH=页码
;BL=前景色(图形模式)
or al, 30h
mov ah, 0eh
int 10h
inc bx
loop print_d
; wait for any key press:
mov ah, 0
int 16h
ret ; stop
name "vga"
; this program draws a tiny rectangle in vga mode.
org 100h
jmp code
; dimensions of the rectangle:
; width: 10 pixels
; height: 5 pixels
w equ 100
h equ 50
; set video mode 13h - 320x200
code: mov ah, 0
mov al, 13h
int 10h
; draw upper line:
mov cx, 100+w ; column
mov dx, 20 ; row
mov al, 15 ; white
u1: mov ah, 0ch ; put pixel
int 10h
dec cx
cmp cx, 100
jae u1
; draw bottom line:
mov cx, 100+w ; column
mov dx, 20+h ; row
mov al, 15 ; white
u2: mov ah, 0ch ; put pixel
int 10h
dec cx
cmp cx, 100
ja u2
; draw left line:
mov cx, 100 ; column
mov dx, 20+h ; row
mov al, 15 ; white
u3: mov ah, 0ch ; put pixel
int 10h
dec dx
cmp dx, 20
ja u3
; draw right line:
mov cx, 100+w ; column
mov dx, 20+h ; row
mov al, 15 ; white
u4: mov ah, 0ch ; put pixel
int 10h
dec dx
cmp dx, 20
ja u4
; pause the screen for dos compatibility:
;wait for keypress
mov ah,00
int 16h
; return to text mode:
mov ah,00
mov al,03 ;text mode 3
int 10h
ret
name "hi-world"
; this example prints out "hello world!"
; by writing directly to video memory.
; in vga memory: first byte is ascii character, byte that follows is character attribute.
; if you change the second byte, you can change the color of
; the character even after it is printed.
; character attribute is 8 bit value,
; high 4 bits set background color and low 4 bits set foreground color.
; hex bin color
;
; 0 0000 black
; 1 0001 blue
; 2 0010 green
; 3 0011 cyan
; 4 0100 red
; 5 0101 magenta
; 6 0110 brown
; 7 0111 light gray
; 8 1000 dark gray
; 9 1001 light blue
; a 1010 light green
; b 1011 light cyan
; c 1100 light red
; d 1101 light magenta
; e 1110 yellow
; f 1111 white
org 100h
; set video mode
mov ax, 3 ; text mode 80x25, 16 colors, 8 pages (ah=0, al=3)
int 10h ; do it!
; cancel blinking and enable all 16 colors:
mov ax, 1003h
mov bx, 0
int 10h
; set segment register:
mov ax, 0b800h
mov ds, ax
; print "hello world"
; first byte is ascii code, second byte is color code.
mov [02h], 'H'
mov [04h], 'e'
mov [06h], 'l'
mov [08h], 'l'
mov [0ah], 'o'
mov [0ch], ','
mov [0eh], 'W'
mov [10h], 'o'
mov [12h], 'r'
mov [14h], 'l'
mov [16h], 'd'
mov [18h], '!'
; color all characters:
mov cx, 12 ; number of characters.
mov di, 03h ; start from byte after 'h'
c: mov [di], 11101100b ; light red(1100) on yellow(1110)
add di, 2 ; skip over next ascii code in vga memory.
loop c
; wait for any key press:
mov ah, 0
int 16h
ret
name "add-sub"
org 100h
mov al, 5 ; bin=00000101b
mov bl, 10 ; hex=0ah or bin=00001010b
; 5 + 10 = 15 (decimal) or hex=0fh or bin=00001111b
add bl, al
; 15 - 1 = 14 (decimal) or hex=0eh or bin=00001110b
sub bl, 1
; print result in binary:
mov cx, 8
print: mov ah, 2 ; print function.
mov dl, 'x'
test bl, 10000000b ; test first bit.
jz zero
mov dl, '1'
zero: int 21h
shl bl, 1
loop print
; print binary suffix:
mov dl, 'b'
int 21h
; wait for any key press:
mov ah, 0
int 16h
ret
name "calc-sum"
org 100h ; directive make tiny com file.
; calculate the sum of elements in vector,
; store result in m and print it in binary code.
; number of elements:
mov cx, 5
; al will store the sum:
mov al, 0
; bx is an index:
mov bx, 0
; sum elements:
next: add al, vector[bx]
; next byte:
inc bx
; loop until cx=0:
loop next
; store result in m:
mov m, al
; print result in binary:
mov bl, m
mov cx, 8
print: mov ah, 2 ; print function.
mov dl, '0'
test bl, 10000000b ; test first bit.
jz zero
mov dl, '1'
zero: int 21h
shl bl, 1
loop print
; print binary suffix:
mov dl, 'b'
int 21h
mov dl, 0ah ; new line.
int 21h
mov dl, 0dh ; carrige return.
int 21h
; print result in decimal:
mov al, m //打印m的值
call print_al
; wait for any key press:
mov ah, 0
int 16h
ret
; variables:
vector db 5, 4, 5, 2, 1
m db 0
print_al proc
cmp al, 0
jne print_al_r
push ax
mov al, '0'
mov ah, 0eh
int 10h
pop ax
ret
print_al_r:
pusha
mov ah, 0
cmp ax, 0
je pn_done
mov dl, 10
div dl
call print_al_r
mov al, ah
add al, 30h
mov ah, 0eh
int 10h
jmp pn_done
pn_done:
popa
ret
endp
name "flags"
org 100h
; this sample shows how cmp instruction sets the flags.
; usually cmp instruction is followed by any relative
; jump instruction such as: je, ja, jl, jae...
; it is recommended to click "flags" and "analyze"
; for better visual expirience before stepping through this code.
; (signed/unsigned)
; 4 is equal to 4
mov ah, 4
mov al, 4
cmp ah, al
nop
; (signed/unsigned)
; 4 is above and greater then 3
mov ah, 4
mov al, 3
cmp ah, al
nop
; -5 = 251 = 0fbh
; (signed)
; 1 is greater then -5
mov ah, 1
mov al, -5
cmp ah, al
nop
; (unsigned)
; 1 is below 251
mov ah, 1
mov al, 251
cmp ah, al
nop
; (signed)
; -3 is less then -2
mov ah, -3
mov al, -2
cmp ah, al
nop
; (signed)
; -2 is greater then -3
mov ah, -2
mov al, -3
cmp ah, al
nop
; (unsigned)
; 255 is above 1
mov ah, 255
mov al, 1
cmp ah, al
nop
; now a little game:
game: mov dx, offset msg1 //lea dx,msg1
mov ah, 9 ;打印字符串操作
int 21h
; read character in al:
mov ah, 1 ;读取数据失败??
int 21h
cmp al, '0'
jb stop
cmp al, '9'
ja stop
cmp al, '5'
jb below
ja above
mov dx, offset equal_5
jmp print
below: mov dx, offset below_5
jmp print
above: mov dx, offset above_5
print: mov ah, 9
int 21h
jmp game ; loop.
stop: ret ; stop
msg1 db "enter a number or any other character to exit: $"
equal_5 db " is five! (equal)", 0Dh,0Ah, "$"
below_5 db " is below five!" , 0Dh,0Ah, "$"
above_5 db " is above five!" , 0Dh,0Ah, "$"
name "add-2"
; this example calculates the sum of a vector with
; another vector and saves result in third vector.
; you can see the result if you click the "vars" button.
; set elements for vec1, vec2 and vec3 to 4 and show as "signed".
org 100h
jmp start
vec1 db 1, 2, 5, 6
vec2 db 3, 5, 6, 1
vec3 db ?, ?, ?, ?
start:
lea si, vec1
lea bx, vec2
lea di, vec3
mov cx, 4
sum:
mov al, [si]
add al, [bx]
mov [di], al
inc si
inc bx
inc di
loop sum
ret
实例:文件属性设置??
name "attrib"
; set and get file attributes...
; note 1: you need to manually create and copy "test.txt" to:
; c:\emu8086\vdrive\c before running this example.
; note 2: it may look like the file suddenly disappears unless
; you set the settings of file manager to show system and hidden files.
; note 3: file must exist for setting parameters. however reading
; parameters does not require the existance of a file and
; it is usually used to check if file exists or not.
org 100h
jmp start
filename db "d:\test.txt", 0
sOK db "ok! file found. attributes set: system, hidden & read-only. $"
sERR db "file does not exist. (expected i/o error)", 0dh, 0ah
db ' you need to manually create and copy "test.txt" to:', 0dh, 0ah
db ' "c:\emu8086\vdrive\c" before running this example.$ '
; when running in emulator, the real path of this file is:
; c:\emu8086\vdrive\c\test.txt
start:
xor cx, cx
; read attributes:
mov ah, 43h
mov al, 0
mov dx, offset filename
int 21h
jc error
; set new attributes:
mov ah, 43h
mov al, 1
mov cx, 7
mov dx, offset filename
int 21h
jc error
mov dx, offset sOK
mov ah, 9
int 21h
jmp wait_any_key
error:
mov dx, offset sERR
mov ah, 9
int 21h
wait_any_key:
mov ah, 0
int 16h
ret
实例:BCD_aaa 如果AL(3-0)大于9或辅助进位AF=1,则AH=AH+01H,AL=AL+06H,且置AF和CF为1;否则置AF和CF为零。AL(7-4)=0。
; this example shows the use of aaa instruction (ascii adjust after addition).
; it is used to add huge bcd numbers.
name "bcd_aaa"
org 100h
; first number '9':
mov ah, 09h
; second number '5':
mov al, 05h
; al = al + ah =
; = 09h + 05h = 0eh
add al, ah
; clear tens byte of bcd
; result:
xor ah, ah
; adjust result to bcd form,
; ah = 1, al = 4 -> '14'
aaa
; print the result:
; store contents of
; ax register:
mov dx, ax
; print first digit:
mov ah, 0eh
; convert to ascii:
or dh, 30h
mov al, dh ;34显示的是4
int 10h ;显示al的值
; print second digit:
; convert to ascii:
or dl, 30h
mov al, dl
int 10h
; wait for any key press:
mov ah, 0
int 16h
ret ; return control to operating system.
; this is an example of aas instruction,
; it is used to subtract huge bcd numbers (binary coded decimals).
name "bcd_aas"
org 100h
; make 5 - 8
; al = 0fdh (not in binary coded decimal form)
mov al, 05h
mov bl, 08h
sub al, bl
; convert to binary coded decimal,
; al = 7
; and 1 is borrowed from ah, like calculating 15 - 8:
aas
; convert to printable symbol:
or al, 30h
; print char in al using bios teletype function:
mov ah, 0eh
int 10h
; wait for any key press:
mov ah, 0
int 16h
ret ; return control to operating system.
; input8 bit binary number and print out decimal to screen.
; zeros and ones -> decimal value
ORG 100h
; macro
; this macro prints a char in AL and advances
; the current cursor position:
PUTC MACRO char
PUSH AX
MOV AL, char
MOV AH, 0Eh
INT 10h
POP AX
ENDM
.data
; null terminated input string:
DB "0"
s1 DB "00000000", 0
sum DW 0 ; result.
flag DB 0
.code
CALL print
DB 0dh, 0ah, "8 bit binary: ", 0
; get string:
MOV DX, 9 ; buffer size (1+ for zero terminator).
LEA DI, s1
CALL GET_STRING
; check that we really got 8 zeros and ones
MOV CX, 8
MOV SI, OFFSET s1
check_s:
CMP [SI], 0
JNE ok0
MOV flag, 1 ; terminated.
JMP convert
ok0:
CMP [SI], 'b'
JNE ok1
MOV flag, 1 ; terminated.
JMP convert
ok1:
; wrong digit? Not 1/0?
CMP [SI], 31h
JNA ok2
JMP error_not_valid
ok2:
INC SI
LOOP check_s
; start the conversion from string to value in SUM variable.
convert:
MOV BL, 1 ; multiplier.
MOV CX, SI
SUB CX, OFFSET s1
DEC SI
JCXZ stop_program
next_digit:
MOV AL, [SI] ; get digit.
SUB AL, 30h
MUL BL ; no change to AX.
ADD SUM, AX
SHL BL, 1
DEC SI ; go to previous digit.
LOOP next_digit
; done! converted number is in SUM.
; check if signed
TEST sum, 0000_0000_1000_0000b
JNZ print_signed_unsigned
print_unsigned:
CALL print
DB 0dh, 0ah, "decimal: ", 0
MOV AX, SUM
CALL PRINT_NUM_UNS
JMP stop_program
print_signed_unsigned:
CALL print
DB 0dh, 0ah, "unsigned decimal: ", 0
; print out unsigned:
MOV AX, SUM
CALL PRINT_NUM_UNS
CALL print
DB 0dh, 0ah, "signed decimal: ", 0
; print out singed:
MOV AX, SUM
CBW ; convert byte into word.
CALL PRINT_NUM
JMP stop_program
error_not_valid:
CALL print
DB 0dh, 0ah, "error: only zeros and ones are allowed!", 0
stop_program:
; wait for any key....
CALL print
DB 0dh, 0ah, "press any key...", 0
MOV AH, 0
INT 16h
RET
; procedures
; copied from c:\emu8086\emu8086.inc
GET_STRING PROC NEAR
PUSH AX
PUSH CX
PUSH DI
PUSH DX
MOV CX, 0 ; char counter.
CMP DX, 1 ; buffer too small?
JBE empty_buffer ;
DEC DX ; reserve space for last zero.
;============================
; loop to get and processes key presses:
wait_for_key:
MOV AH, 0 ; get pressed key.
INT 16h
CMP AL, 13 ; 'RETURN' pressed?
JZ exit
CMP AL, 8 ; 'BACKSPACE' pressed?
JNE add_to_buffer
JCXZ wait_for_key ; nothing to remove!
DEC CX
DEC DI
PUTC 8 ; backspace.
PUTC ' ' ; clear position.
PUTC 8 ; backspace again.
JMP wait_for_key
add_to_buffer:
CMP CX, DX ; buffer is full?
JAE wait_for_key ; if so wait for 'BACKSPACE' or 'RETURN'...
MOV [DI], AL
INC DI
INC CX
; print the key:
MOV AH, 0Eh
INT 10h
JMP wait_for_key
;============================
exit:
; terminate by null:
MOV [DI], 0
empty_buffer:
POP DX
POP DI
POP CX
POP AX
RET
GET_STRING ENDP
; copied from c:\emu8086\emu8086.inc
PRINT_NUM PROC NEAR
PUSH DX
PUSH AX
CMP AX, 0
JNZ not_zero
PUTC '0'
JMP printed_pn
not_zero:
; the check SIGN of AX,
; make absolute if it's negative:
CMP AX, 0
JNS positive
NEG AX
PUTC '-'
positive:
CALL PRINT_NUM_UNS
printed_pn:
POP AX
POP DX
RET
ENDP
; copied from c:\emu8086\emu8086.inc
PRINT_NUM_UNS PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; flag to prevent printing zeros before number:
MOV CX, 1
; (result of "/ 10000" is always less or equal to 9).
MOV BX, 10000 ; 2710h - divider.
; AX is zero?
CMP AX, 0
JZ print_zero
begin_print:
; check divider (if zero go to end_print):
CMP BX,0
JZ end_print
; avoid printing zeros before number:
CMP CX, 0
JE calc
; if AX
; output: com
org 100h
.data
msg db "Hello, World", 24h
.code
; mov ax, @data
;mov ds, ax
mov dx, offset msg ; lea dx, msg 和 mov dx, offset msg 基本上是等价的
mov ah, 9
int 21h
.exit
; procedures inside another procedure.
org 100h
mov ax, abc
mov abc_off, ax
mov abc_seg, cs
call far abc_off
call abc1
call abc2
ret
abc_off dw ?
abc_seg dw ?
abc proc far
mov ax, -1
jmp r
abc1 proc near
mov ax, 1
ret
endp
abc2 proc near
mov ax, 2
ret
endp
r:
retf
endp
; how to use cmpsb instruction to compare byte strings.
name "cmpsb"
org 100h
; set forward direction:
;清除方向标志,在字符串的比较,赋值,读取等一系列和rep连用的操作中,
;di或si是可以自动增减的而不需要人来加减它的值,cld即告诉程序si,di向前移动,std指令为设置方向,告诉程序si,di向后移动
cld
; load source into ds:si,
; load target into es:di:
; mov ax, cs ;CS是代码段寄存器,这个寄存器保存的是代码段的首地址
; mov ds, ax
; mov es, ax ??作用是什么??
lea si, str1
lea di, str2
; set counter to string length:
mov cx, size
; compare until equal:
; repe是一个串操作前缀,它重复串操作指令,每重复一次ECX的值就减一
;一直到CX为0或ZF为0时停止。
;cmpsb是字符串比较指令,把ESI指向的数据与EDI指向的数一个一个的进行比较。
;当repe cmpsb配合使用时就是字符串比较啦,当相同时继续比较,不同时不比较
repe cmpsb
jnz not_equal
; "yes" - equal!
mov al, 'y'
mov ah, 0eh
int 10h
jmp exit_here
not_equal:
; "no" - not equal!
mov al, 'n'
mov ah, 0eh
int 10h
exit_here:
; wait for any key press:
mov ah, 0
int 16h
ret
; strings must have equal lengths:
x1:
str1 db 'test string'
str2 db 'test string'
size = ($ - x1) / 2
org 100h
jmp a
; double word definition is supported:
mydouble dd 12345678h
; it is equal to:
mywords dw 5678h
dw 1234h
; and it is equal to:
mybytes db 78h
db 56h
db 34h
db 12h
; exactly 32 bits
binn dd 00010010001101000101011001111000b
; load double word to dx:ax
a: mov ax, binn
mov dx, [binn+2]
ret
实例:远程调用int 10h中断
name "callfar"
; examples shows how to call int 10h without using int instruction.
org 100h
; set es:bx to point to int 10h vector in interrupt vector table
mov bx, 0h
mov es, bx
mov bx, 40h
mov ah, 0eh ; set up int 10h params
mov al, '*'
pushf
call far es:[bx] ; do a far cal to int10h vector
; wait for any key....
mov ah, 0
int 16h
ret
; this example shows how to access virtual ports (0 to 65535).
; these ports are emulated in this file: c:\emu8086.io
; this technology allows to make external add-on devices
; for emu8086, such as led displays, robots, thermometers, stepper-motors, etc... etc...
; anyone can create an animated virtual device.
; c:\emu8086\devices\led_display.exe
#start=led_display.exe#
#make_bin#
name "led"
mov ax, 1234
out 199, ax
mov ax, -5678
out 199, ax
; Eternal loop to write
; values to port:
mov ax, 0
x1:
out 199, ax
inc ax
jmp x1
hlt
实例:嵌套循环
name "loops"
org 100h
mov bx, 0 ; total step counter
mov cx, 5
k1: add bx, 1
mov al, '1'
mov ah, 0eh
int 10h
push cx
mov cx, 5
k2: add bx, 1
mov al, '2'
mov ah, 0eh
int 10h
push cx
mov cx, 5
k3: add bx, 1
mov al, '3'
mov ah, 0eh
int 10h
loop k3 ; internal in internal loop.
pop cx
loop k2 ; internal loop.
pop cx
loop k1 ; external loop.
; wait any key...
mov ah, 1
int 21h
ret
实例:交通灯 虚拟端口
; controlling external device with 8086 microprocessor.
; realistic test for c:\emu8086\devices\Traffic_Lights.exe
#start=Traffic_Lights.exe#
name "traffic"
mov ax, all_red
out 4, ax
mov si, offset situation
next:
mov ax, [si]
out 4, ax
; wait 5 seconds (5 million microseconds)
mov cx, 4Ch ; 004C4B40h = 5,000,000
mov dx, 4B40h
mov ah, 86h
int 15h
add si, 2 ; next situation
cmp si, sit_end
jb next
mov si, offset situation
jmp next
; FEDC_BA98_7654_3210
situation dw 0000_0011_0000_1100b
s1 dw 0000_0110_1001_1010b
s2 dw 0000_1000_0110_0001b
s3 dw 0000_1000_0110_0001b
s4 dw 0000_0100_1101_0011b
sit_end = $
all_red equ 0000_0010_0100_1001b
实例:定时显示字符
; this sample shows the use of a timer function (int 15h / 86h)
; this code prints some chars with 1 second delay.
; note: Windows XP does not support this interrupt (always sets CF=1),
; to test this program in real environment write it to a floppy disk using
; compiled writebin.asm. after sucessfull compilation of both files,
; type this from command prompt: writebin timer.bin
; note: floppy disk boot record will be overwritten.
; the floppy will not be useable under windows/dos until
; you reformat it, data on floppy disk may be lost.
; use empty floppy disks only.
name "timer"
#make_boot#
org 7c00h
; set the segment registers
mov ax, cs
mov ds, ax
mov es, ax
call set_video_mode
call clear_screen ;清屏操作
next_char:
cmp count, 0
jz stop
; print char:
mov al, c1
mov ah, 0eh
int 10h ;输出字符设置
; next ascii char:
inc c1
dec count
; set 1 million microseconds interval (1 second) ;设置时间延迟
mov cx, 0fh
mov dx, 4240h
mov ah, 86h
int 15h
; stop any error:
jc stop
jmp next_char
stop:
; print message using bios int 10h/13h function
mov al, 1
mov bh, 0
mov bl, 0010_1111b
mov cx, msg_size
mov dl, 4
mov dh, 15
mov bp, offset msg
mov ah, 13h
int 10h
; wait for any key...
mov ah, 0
int 16h
int 19h ; reboot
count db 10
c1 db 'a'
msg db "remove floppy disk and press any key to reboot..."
msg_size = $ - msg
; set video mode and disable blinking (for compatibility).
set_video_mode proc
mov ah, 0
mov al, 3 ; text mode 80x25, 16 colors, 8 pages
int 10h
; blinking disabled for compatibility with dos,
; emulator and windows prompt do not blink anyway.
mov ax, 1003h
mov bx, 0 ; disable blinking.
int 10h
ret
set_video_mode endp
; clear the screen by scrolling entire screen window,
; and set cursor position on top.
; default attribute is changed to black on white.
clear_screen proc near
push ax ; store registers...
push ds ;
push bx ;
push cx ;
push di ;
mov ax, 40h
mov ds, ax ; for getting screen parameters.
mov ah, 06h ; scroll up function id.
mov al, 0 ; scroll all lines!
mov bh, 1111_0000b ; attribute for new lines.
mov ch, 0 ; upper row.
mov cl, 0 ; upper col.
mov di, 84h ; rows on screen -1,
mov dh, [di] ; lower row (byte).
mov di, 4ah ; columns on screen,
mov dl, [di]
dec dl ; lower col.
int 10h
; set cursor position to top
; of the screen:
mov bh, 0 ; current page.
mov dl, 0 ; col.
mov dh, 0 ; row.
mov ah, 02
int 10h
pop di ; re-store registers...
pop cx ;
pop bx ;
pop ds ;
pop ax ;
ret
clear_screen endp
; this is a program in 8086 assembly language that
; accepts a character string from the keyboard and
; stores it in the string array. the program then converts
; all the lower case characters of the string to upper case.
; if the string is empty (null), it doesn't do anything.
name "upper"
org 100h
jmp start
; first byte is buffer size,
; second byte will hold number
; of used bytes for string,
; all other bytes are for characters:
string db 20, 22 dup('?')
new_line db 0Dh,0Ah, '$' ; new line code.
start:
; int 21h / ah=0ah - input of a string to ds:dx,
; fist byte is buffer size, second byte is number
; of chars actually read. does not add '$' in the
; end of string. to print using int 21h / ah=09h
; you must set dollar sign at the end of it and
; start printing from address ds:dx + 2.
lea dx, string
mov ah, 0ah
int 21h
mov bx, dx
mov ah, 0
mov al, ds:[bx+1]
add bx, ax ; point to end of string.
mov byte ptr [bx+2], '$' ; put dollar to the end.
; int 21h / ah=09h - output of a string at ds:dx.
; string must be terminated by '$' sign.
lea dx, new_line
mov ah, 09h
int 21h
lea bx, string
mov ch, 0
mov cl, [bx+1] ; get string size.
jcxz null ; is string is empty?
add bx, 2 ; skip control chars.
upper_case:
; check if it's a lower case letter:
cmp byte ptr [bx], 'a'
jb ok
cmp byte ptr [bx], 'z'
ja ok
; convert to uppercase:
; upper case letter do not have
; third bit set, for example:
; 'a' : 01100001b
; 'a' : 01000001b
; upper case mask : 11011111b
; clear third bit:
and byte ptr [bx], 11011111b ;将小写变为大写
ok:
inc bx ; next char.
loop upper_case
; int 21h / ah=09h - output of a string at ds:dx.
; string must be terminated by '$' sign.
lea dx, string+2
mov ah, 09h
int 21h
; wait for any key press....
mov ah, 0
int 16h
null:
ret ; return to operating system.
; Count number of key presses. the result is in bx register.
;
; You must type into the emulator's screen,
; if it closes, press screen button to re-open it.
name "keycount"
org 100h
; print welcome message:
mov dx, offset msg
mov ah, 9
int 21h
xor bx, bx ; zero bx register.
wait: mov ah, 0 ; wait for any key....
int 16h
cmp al, 27 ; if key is 'esc' then exit.
je stop
mov ah, 0eh ; print it.
int 10h
inc bx ; increase bx on every key press.
jmp wait
; print result message:
stop: mov dx, offset msg2
mov ah, 9
int 21h
mov ax, bx
call print_al
;call print_ax
; wait for any key press:
mov ah, 0
int 16h
ret ; exit to operating system.
msg db "I'll count all your keypresses. press 'Esc' to stop...", 0Dh,0Ah, "$"
msg2 db 0Dh,0Ah, "recorded keypresses: $"
print_ax proc
cmp ax, 0
jne print_ax_r
push ax
mov al, '0'
mov ah, 0eh
int 10h
pop ax
ret
print_ax_r:
pusha
mov dx, 0
cmp ax, 0
je pn_done
mov bx, 10
div bx
call print_ax_r
mov ax, dx
add al, 30h
mov ah, 0eh
int 10h
jmp pn_done
pn_done:
popa
ret
endp
print_al proc ;以十进制方式输入
cmp al, 0
jne print_al_r
push ax
mov al, '0'
mov ah, 0eh
int 10h
pop ax
ret
print_al_r:
pusha
mov ah, 0
cmp ax, 0
je pn_done
mov dl, 10
div dl
call print_al_r
mov al, ah
add al, 30h
mov ah, 0eh
int 10h
jmp pn_done
pn_done:
popa
ret
endp
实例:体会stack的功能
; this sample shows how the stack works.
; click 'stack' button in emulator to see the contents of the stack.
; stack is important element in computer architecture.
; this code does nothing useful, except printing "Hi" in the end.
name "stack"
org 100h ; create tiny com file.
mov ax, 1234h
push ax
mov dx, 5678h
push dx
pop bx
pop cx
; function call pushes ip value of the next instruction:
call tfunc
mov ax, 7890h
push ax
pop bx
; interrupts are like funtions,
; but in addition they push code segment into the stack
mov ax, 3
int 10h ; set standart video mode.
; a typical use of stack is to set segment registers.
; set ds to video memory segment:
mov ax, 0b800h
push ax
pop ds
; print "hi":
mov [170h], 'H'
mov [172h], 'i'
; color attribute for 'h'
mov [171h], 11001110b
; color attribute for 'i'
mov [173h], 10011110b
; wait for any key press....
mov ah, 0
int 16h
; here we "pop" the ip value,
; and return control to the operating system:
ret
; the test procedure:
tfunc proc
xor bx, bx
xor cx, cx
; here we "pop" the ip value,
; and return control to the main program:
ret
endp