Tohle je vzor pro soubory *.com, kerý už na 64bitovejch operačních systémech nespustíte. Kromě práce se souborama a práce s myší se to dá využít při tvorbě zavaděče systému (boot loader).
[org 100h]
[bits 16]
jmp MAIN
; Locate the cursor
; IN: dl = x, dh = y
curto:
xor bh,bh
mov ah,2
int 10h
ret
; Write colored characters without moving the cursor
; IN: al = char, bl = color, cx = count
putchar:
xor bh,bh
mov ah,9
int 10h
ret
; Write a character and move the cursor
; IN: al = char
wrchar:
xor bh,bh
mov ah,0Eh
int 10h
ret
; Write a null-terminated string
; IN: ds:si -> stringz
writez:
l_writez1:
lodsb
or al,al
jz l_writez9
xor bh,bh
mov ah,0Eh
int 10h
jmp l_writez1
l_writez9:
ret
; Write a number
; IN: ax = number, cx = system (10,2,16)
write_num:
sub sp,32
; Number to string
mov bx,sp
cmp cx,1
ja l_write_num_1
mov cx,10 ; 0 or 1 would fail
l_write_num_1:
xor dx,dx
div cx
cmp dl,10
jnb l_write_num_2
add dl,'0'
jmp short l_write_num_3
l_write_num_2:
add dl,55
l_write_num_3:
mov [ss:bx],dl
inc bx
or ax,ax
jnz l_write_num_1
; Write it
mov cx,bx
sub cx,sp
l_write_num_5:
dec bx
mov al,[ss:bx]
push bx
xor bh,bh
mov ah,0Eh
int 10h
pop bx
loop l_write_num_5
add sp,32
ret
; Save the current screen to memory (text mode only)
; IN: es:di -> variable of size 4006 bytes
save_scr:
; Save video mode
push es
mov ax,40h
mov es,ax
mov al,[es:49h]
xor ah,ah
pop es
stosw
; Save cursor position and settings
mov ah,3
xor bh,bh
int 10h
mov ax,dx
stosw
mov ax,cx
stosw
; Save screen content
push ds
mov ax,0B800h
mov ds,ax
xor si,si
mov cx,2000 ; 80x25
rep movsw
pop ds
ret
; Restore screen (text mode only)
; IN: ds:si -> variable of size 4006 bytes (stored by save_scr)
restore_scr:
; Restore video mode
mov ax,40h
mov es,ax
mov cl,[es:49h]
mov al,[si]
cmp al,cl
jz l_restore_scr_1
xor ah,ah
int 10h
l_restore_scr_1:
; Restore screen content
mov ax,0B800h
mov es,ax
xor di,di
push si
add si,6
mov cx,2000
rep movsw
pop si
; Restore cursor position
mov dx,[si+2]
mov ah,2
xor bh,bh
int 10h
; Restore cursor settings
mov cx,[si+4]
mov ah,1
xor bh,bh
int 10h
ret
; Wait for key and read it
; OUT: al = ASCII code, ah = scan code
inkey:
mov ah,0
int 16h
ret
; Check if there is any key in the keyboard buffer
; OUT: jnz <=> key pressed, jz <=> no key
iskey:
mov ah,1
int 16h
ret
; Read a sector using BIOS
; IN: dl = drive, dh = side, ch = track, cl = sector, es:bx -> buffer
; OUT: al = 0 || error code
; bits 6-7 of sector mean bits 8-9 of track
; drive: 0=A:, 1=B:, 80h=C:(hda), 81h=hdb
; buffer: 512 bytes
; error code: 3=disk is write-protected, 4=sector not found,
; 6=disk was changed, 16=CRC error, 128=timeout
read_sector_BIOS:
mov ah,02h
mov al,1
int 13h
jnc l_read_sector_8
mov al,ah
jmp short l_read_sector_9
l_read_sector_8:
xor ax,ax
l_read_sector_9:
ret
; Write a sector using BIOS
; IN: dl = drive, dh = side, ch = track, cl = sector, es:bx -> buffer
; OUT: al = 0 || error code
write_sector_BIOS:
mov ah,03h
mov al,1
int 13h
jnc l_write_sector_8
mov al,ah
jmp short l_write_sector_9
l_write_sector_8:
xor ax,ax
l_write_sector_9:
ret
; Read data directly from hard disk
; IN: dx = drive & head 0..31, cx = cylinder 0..65535,
; ax = sect 0..63, es:di -> buffer (512 bytes)
; OUT: ax = 0 || error code
read_sect_hd:
push ax
mov bx,dx
mov dx,1F6h ; Drive and head port
mov al,bl
out dx,al
mov dx,1F4h ; Cylinder low port
mov al,cl
out dx,al
mov dx,1F5h ; Cylinder high port
mov al,ch
out dx,al
mov dx,1F2h ; Sector count port
mov al,1
out dx,al
pop ax
mov dx,1F3h ; Sector number port
out dx,al
mov dx,1F7h ; Command port
mov al,20h ; Read with retry
out dx,al
l_read_sect_hd_5:
in al,dx
test al,128 ; Busy
jnz l_read_sect_hd_5
test al,1 ; Error
jnz l_disk_error
mov cx,512/2
mov dx,1F0h ; Data port
rep insw
xor ax,ax ; Return with errorcode 0
ret
l_disk_error:
mov dx,1F1h
in al,dx ; Errorcode
mov ah,1
ret
; Write data directly to hard disk
; IN: dx = drive & head 0..31, cx = cylinder 0..65535,
; ax = sect 0..63, ds:si -> buffer (512 bytes)
; OUT: ax = 0 || error code
write_sect_hd:
push ax
mov bx,dx
mov dx,1F6h ; Drive and head port
mov al,bl
out dx,al
mov dx,1F4h ; Cylinder low port
mov al,cl
out dx,al
mov dx,1F5h ; Cylinder high port
mov al,ch
out dx,al
mov dx,1F2h ; Sector count port
mov al,1
out dx,al
pop ax
mov dx,1F3h ; Sector number port
out dx,al
mov dx,1F7h ; Command port
mov al,30h ; Write with retry
out dx,al
l_write_sect_hd_5:
in al,dx
test al,128 ; Busy
jnz l_write_sect_hd_5
test al,1 ; Error
jnz l_disk_error
mov cx,512/2
mov dx,1F0h ; Data port
rep outsw
xor ax,ax ; Return with errorcode 0
ret
; Open a file for reading
; IN: ds:dx -> filenamez
; OUT: ax = filehandle || 65535 (error), jz <=> error
dosfopen:
xor cx,cx
mov ax,3D02h
int 21h
jnc ldosfopen8
mov ax,65535
ldosfopen8:
cmp ax,65535
ret
; Close a file
; IN: bx = filehandle
dosfclose:
mov ah,3Eh
int 21h
ret
; Read a block from file
; IN: ds:dx -> buffer, cx = maxsize, bx = filehandle
; OUT: ax = sizeread || 0 (error), jz <=> error
dosfread:
mov ah,3Fh
int 21h
jnc ldosfread8
xor ax,ax
ldosfread8:
or ax,ax
ret
; Open a file for writing
; IN: ds:dx -> filenamez
; OUT: ax = filehandle || 65535 (error), jz <=> error
dosfcreate:
xor cx,cx
mov ah,3Ch
int 21h
jnc ldosfcreate8
mov ax,65535
ldosfcreate8:
cmp ax,65535
ret
; Write a block to file
; IN: ds:dx -> buffer, cx = count of bytes to write, bx = filehandle
; OUT: ax = sizewrite, jz <=> error
; if cx = 0, truncates file at the current position
dosfwrite:
mov ah,40h
int 21h
jnc ldosfwrite8
xor ax,ax
ldosfwrite8:
or ax,ax
ret
; Set position in file
; IN: cx(hw):dx(lw) = file offset, bx = filehandle
; OUT: ax = 0 || error code
dosfseek:
mov ax,4200h
int 21h
jc ldosfseek8
xor ax,ax
ldosfseek8:
or ax,ax
ret
; Get position in file
; IN: bx = filehandle
; OUT: dx:ax = position
dosfpos:
xor cx,cx
xor dx,dx
mov ax,4201h
int 21h
jnc ldosfpos8
xor ax,ax
xor dx,dx
ldosfpos8:
ret
; Go to end of file
; IN: bx = filehandle
; OUT: dx:ax = file size
dosfeof:
xor cx,cx
xor dx,dx
mov ax,4202h
int 21h
jnc ldosfeof8
xor ax,ax
xor dx,dx
ldosfeof8:
ret
; Read all file < 64 KiB
; IN: ds:dx -> filenamez, es:di -> buffer, cx = maxsize
; OUT: ax = sizeread || 0 (error)
readfile:
push es
push di
push cx
call dosfopen
mov bx,ax
pop cx
pop dx
pop ds
push bx
call dosfread
pop bx
push ax
call dosfclose
pop ax
ret
; Find the first file that matches the mask
; IN: es:di -> filerec, ds:dx -> maskz
; OUT: al = 0 || error
; filerec = { byte[21] system, byte attributes, word time, word date,
; dword size, byte[13] namez }
find_first:
; Set DTA keeping ds,dx
push ds
push dx
push es
pop ds
mov dx,di
mov ah,1Ah
int 21h
pop dx
pop ds
; Find first
mov cx,3Fh ; Attribute mask
mov ah,4Eh
int 21h
jc l_find_first_9
xor ax,ax
l_find_first_9:
ret
; Find the next file
; IN: es:di -> filerec
; OUT: al = 0 || error
find_next:
; Set DTA keeping ds,dx
push ds
push dx
push es
pop ds
mov dx,di
mov ah,1Ah
int 21h
pop dx
pop ds
; Find next
mov ah,4Fh
int 21h
jc l_find_next_9
xor ax,ax
l_find_next_9:
ret
; Initialize graphic mode 320x200x256
graph_mode_MCGA:
mov ax,13h
int 10h
ret
; Return text mode 80x25x16
text_mode:
mov ax,3
int 10h
ret
; Set the red, green, blue components of the color
; IN: bl = color number, ch = green(0..63), cl = blue(0..63), dh = red(0..63)
set_RGB:
mov ah, dh
mov dx, 3C8h
mov al, bl
out dx, al
inc dx
mov al, ah ; red
out dx, al
mov al, ch ; green
out dx, al
mov al, cl ; blue
out dx, al
ret
; Draw a pixel on the screen
; IN: cx = x, dx = y, bl = color
put_pixel_MCGA:
mov ax,dx
mov dx,320
mul dx
add ax,cx
mov di,ax ; di = y * 320 + x
mov dx,0A000h
mov es,dx
mov al,bl
mov [es:di],al
ret
; Get the color of a pixel on the screen
; IN: cx = x, dx = y
; OUT: al = color
get_pixel_MCGA:
mov ax,dx
mov dx,320
mul dx
add ax,cx
mov di,ax ; di = y * 320 + x
mov dx,0A000h
mov es,dx
mov al,[es:di]
ret
; Initialize graphic mode 640x480x16
graph_mode_VGA:
mov ax,12h
int 10h
call set_write_mode_2
ret
; Set write mode 2
; Needs to be called again after task switch or mouse move
set_write_mode_2:
mov dx,3CEh
mov al,5
out dx,al
inc dx
mov al,2
out dx,al
ret
; Set pixel mask
; IN: ah = mask
set_mask:
mov dx,3CEh
mov al,8
out dx,al
inc dx
mov al,ah
out dx,al
ret
; Draw a pixel on the screen
; IN: cx = x, dx = y, bl = color
put_pixel_VGA:
mov si,cx
mov ax,640/8
mul dx
mov dx,cx
mov cl,3
shr dx,cl
add ax,dx
mov di,ax ; di = (640/8) * y + (x/8)
mov cx,si
and cl,7
mov ah,128
shr ah,cl
call set_mask ; mask( 128 shr (x mod 8) )
mov ax,0A000h
mov es,ax
mov al,[es:di] ; Load to latche
mov [es:di],bl ; Merge with latche by mask
ret
; Get the color of a pixel on the screen
; IN: cx = x, dx = y
; OUT: al = color
get_pixel_VGA:
mov si,cx
mov ax,640/8
mul dx
mov dx,cx
mov cl,3
shr dx,cl
add ax,dx
mov di,ax ; di = (640/8) * y + (x/8)
mov cx,si
and cl,7
mov ch,128
shr ch,cl
xor cl,7
mov ax,0A000h
mov es,ax
mov dx,3CEh
mov ax,304h
xor bl,bl
l_get_pixel_VGA_5:
out dx,ax
mov bh,[es:di]
and bh,ch
shr bh,cl
shl bl,1
or bl,bh
dec ah
jnl l_get_pixel_VGA_5
mov al,bl
ret
; Reset mouse controller and put mouse to the middle of the screen
mreset:
mov ax,0
int 33h
ret
; Show mouse cursor
mshow:
mov ax,1
int 33h
ret
; Hide mouse cursor
mhide:
mov ax,2
int 33h
ret
; Get mouse position
; OUT: cx = x, dx = y, bx = buttons
mget:
mov ax,3
int 33h
ret
; Set mouse position
; IN: cx = x, dx = y
msetpos:
mov ax,4
int 33h
ret
; Set mouse window
; IN: cx = x1, dx = x2, si = y1, di = y2
msetwin:
mov ax,7
int 33h
mov cx,si
mov dx,di
mov ax,8
int 33h
ret
; Set mouse sensitivity
; IN: cx = x, dx = y
msensit:
mov ax,0Fh
int 33h
ret
; Set mouse cursor
; IN: es:dx -> mousecursor
; mousecursor = 32 x word (2 squares 16x16 bits)
; bit combinations:
; first ? second ?: black
; first ? second ?: white
; first ? second ?: none
; first ? second ?: invert
mcursor:
mov bl,0 ; shift x
mov cl,0 ; shift y
mov ax,09h
int 33h
ret
stringz_hello_world: db "Hello world!\0"
MAIN:
push ds
push cs
pop ds
mov si, offset stringz_hello_world
call writez
pop ds
call inkey
END:
mov ax,4C00h
int 21h