; writebin.asm
name "writebin"
; version 0.02
; assembled by emu8086 -- must be compatible with major assemblers.
; writebin.com -- a tiny operating system loader.
; writebin [filename] [/k]
; this utility is be used from command prompt,
; it reads a specified file and writes it to floppy drive at
; cylinder: 0, head: 0, sector: 1 (boot sector).
; if there is /k parameter after the file name, then the
; file is written at cylinder: 0, head: 0, sector: 2.
; first sector of a floppy drive is reserved for boot sector.
; second and other sectors can be used to store any kind of data
; and code. kernel module of tiny operating system should be
; written to sector 2.
; this program works with drive A: only.
; for emulator drive A: is c:\emu8086\FLOPPY_0
; filename must be in 8.3 format,
; maximum 8 chars for the name and 3 chars after the dot.
; warning! if you run this program outside of the emulator
; it may corrupt existing data. use with caution.
; do not play with floppies that contain valuable data.
org 100h
jmp st
filename db 128 dup(0) ; full path up to 128 chars can be specified.
buffer db 512 dup (0)
buffer_size = $ - offset buffer
handle dw 0
kernel_flag db 0 ; if there is /k parameter, kernel_flag=1.
counter dw 0
sect db 1 ; sector number (1..18).
cyld db 0 ; cylinder number (0..79).
head db 0 ; head number (0..1).
drive db 0 ; drive number (0..3) ; A:=0, B:=1...
; init
st: mov ax, cs
mov ds, ax
mov es, ax
call clear_screen
; read cmd parameters
cp: xor cx, cx
mov cl, [80h]
jcxz np ; this instruction is assembled into OR CX, CX and two JMPs, tutorial 7 tells why.
mov si, 82h
mov di, offset filename
cld
rep movsb
mov [di-1], 0
; check for /k parameter:
cld
xor cx, cx
mov cl, [80h]
mov di, offset filename
mov al, '/'
repne scasb
jz fs
jmp boot
fs: cmp [di-2], ' '
jne nsp
mov [di-2], 0
nsp:mov [di-1], 0
or [di], 0010_0000b ; to lower case.
cmp [di], 'k'
jne wp
or kernel_flag, 1
mov sect, 2 ; start write at sector 2.
lea dx, s0
mov ah, 9
int 21h
jmp s0s
s0 db 0Dh,0Ah,"[/k] - start from sector: 2 " , 0Dh,0Ah, '$'
s0s:
jmp of
boot:
lea dx, s3
mov ah, 9
int 21h
jmp s3s
s3 db 0Dh,0Ah," boot record ", 1 , 0Dh,0Ah, '$'
s3s:
; open file
of: mov ah, 3dh
mov al, 0
mov dx, offset filename
int 21h
jc co
mov handle, ax
lea dx, m0
mov ah, 9
int 21h
jmp m0m
m0 db "opened: $"
m0m:
mov si, offset filename
call print_string
; read bytes from file
rd: mov ah, 3fh
mov bx, handle
mov cx, buffer_size
mov dx, offset buffer
int 21h
jc er
cmp ax, 0 ; no bytes left?
jz cf
; write bytes to disk
wr: mov ah, 03h
mov al, 1 ; write 1 sector (512 bytes).
mov cl, sect ; sector (1..18)
mov ch, cyld ; cylinder (0..79)
mov dh, head ; head (0..1)
mov dl, drive ; always 0 (A:)
mov bx, offset buffer
int 13h
jc er
inc counter
; set cursor at 2,5
mov ah, 2
mov dh, 5
mov bh, 0
int 10h
; show current progress:
lea dx, s1
mov ah, 9
int 21h
jmp s1s
s1 db 1Dh,0Ah,"writing: $"
s1s:
mov ax, counter
call print_num_uns
; sectors... cylinders... heads...
cmp kernel_flag, 1
jne cf
inc sect
cmp sect, 18
jbe rd ; ^
mov sect, 1
inc cyld
cmp cyld, 79
jbe rd ; ^
mov cyld, 0
inc head
cmp head, 1
jbe rd ; ^
; close file
cf: mov bx, handle
mov ah, 3eh
int 21h
jc er
jmp ex
co: lea dx, e0
mov ah, 9
int 21h
jmp e0e
e0 db " cannot open the file...",0Dh,0Ah,'$'
e0e:
jmp ex
np: lea dx, e1
mov ah, 9
int 21h
jmp e1e
e1 db " no parameters...",0Dh,0Ah
db "==============================================================================",0Dh,0Ah
db "this program was designed especially to test micro-operating system",0Dh,0Ah
db "if you are emulating in emu8086, click file->set command line parameters.",0Dh,0Ah
db "from command prompt type:", 0Dh,0Ah
db " writebin [filename] [/k]",0Dh,0Ah,
db "when /k parameter is specified file is written to second sector (kernel area).",0Dh,0Ah,
db "==============================================================================",0Dh,0Ah,'$'
e1e: jmp ex
er: lea dx, e2
mov ah, 9
int 21h
jmp e2e
e2 db " i/o error...",0Dh,0Ah,'$'
e2e:
jmp ex
wp: lea dx, e3
mov ah, 9
int 21h
jmp e3e
e3 db " wrong parameter. only [/k] is supported. use 8.3 short file names only.",0Dh,0Ah,'$'
e3e:
ex: lea dx, m1
mov ah, 9
int 21h
jmp m1m
m1 db 0Dh,0Ah," total sectors: $"
m1m:
mov ax, counter
call print_num_uns
lea dx, m2
mov ah, 9
int 21h
jmp m2m
m2 db 0Dh,0Ah, "thank your for using writebin! - emu8086.com - 2005 (c) freeware",0Dh,0Ah
db " press any key...",0Dh,0Ah, '$'
m2m:
; wait for any key...
mov ah, 0
int 16h
ret ; exit.
; 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
PUTC ENDM
; prints out an unsigned value of AX register.
; allowed values from 0 to 65535
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<bx then result of div will be zero:
cmp ax, bx
jb skip
calc:
mov cx, 0 ; set flag.
mov dx, 0
div bx ; ax = dx:ax / bx (dx=remainder).
; print last digit
; ah is always zero, so it's ignored
add al, 30h ; convert to ascii code.
putc al
mov ax, dx ; get remainder from last div.
skip:
; calculate bx=bx/10
push ax
mov dx, 0
mov ax, bx
div cs:ten ; ax = dx:ax / 10 (dx=remainder).
mov bx, ax
pop ax
jmp begin_print
print_zero:
putc '0'
end_print:
pop dx
pop cx
pop bx
pop ax
ret
ten dw 10 ; used as divider.
print_num_uns endp
; print null terminated string at ds:si
print_string proc near
push ax ; store registers...
push si ;
nxtch: mov al, [si]
cmp al, 0
jz printed
inc si
mov ah, 0eh ; teletype function.
int 10h
jmp nxtch
printed:
pop si ; re-store registers...
pop ax ;
ret
print_string endp
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, 07 ; 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
; some interrupt info:
; -----------------------------------------------------------
; INT 21h / AH= 3Dh - open existing file.
; entry: ;
; AL = access and sharing modes (if unsure set to zero).
; DS:DX -> ASCIZ filename.
; return:
; CF clear if successful, AX = file handle.
; CF set on error AX = error code.
; Note: file pointer is set to start of file.
; -----------------------------------------------------------
; INT 21h / AH= 3Fh - read from file.
; entry:
; BX = file handle.
; CX = number of bytes to read.
; DS:DX -> buffer for data.
; return:
; CF is clear if successful - AX = number of bytes actually read; 0 if at EOF (end of file) before call.
; CF is set on error AX = error code.
; note: data is read beginning at current file position, and the file position is updated after
; a successful read the returned AX may be smaller than the request in CX if a partial read occurred.
; -----------------------------------------------------------
; INT 21h / AH= 3Eh - close file.
; entry: BX = file handle
; return:
; CF clear if successful, AX destroyed.
; CF set on error, AX = error code (06h).
; -----------------------------------------------------------
; INT 13h / AH = 03h - write disk sectors.
; input:
; AL = number of sectors to read/write (must be nonzero)
; CL = sector number (1..18).
; CH = cylinder number (0..79).
; DH = head number (0..1).
; DL = drive number (0..3 , for the emulator it depends on quantity of FLOPPY_ files).
; ES:BX points to data buffer.
; return:
; CF set on error.
; CF clear if successful.
; AH = status (0 - if successful).
; AL = number of sectors transferred.
; Note: each sector has 512 bytes.
; -----------------------------------------------------------
; INT 10h / AH = 02h - set cursor position.
; input:
; DH = row.
; DL = column.
; BH = page number (0..7).
; -----------------------------------------------------------
; INT 21h / AH=09h - output of a string at DS:DX.
; string must be terminated by '$' character.
; -----------------------------------------------------------
; - Other Assembler Source Codes -
; - asm2html by emu8086 -