Obsah

Jak na to v Assembleru

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

Práce s obrazovkou v textovym režimu

; 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

Čtení kláves

; 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

Práce s diskem

; 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

Práce se souborama

; 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

Grafickej režim

; 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

Práce s myší

; 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

Hlavní program

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