oldos/funcs.asm

847 lines
15 KiB
NASM
Raw Permalink Normal View History

; Clear the screen and set cursor position to (0, 0)
clear:
push ax
mov ax, 03h
int 10h
mov ax, 200h
xor dx, dx
int 10h
pop ax
ret
; Detect display. Video mode 0 if no display,
; 1 if monochrome display, 2 if colour display
detect_video:
push ax
mov ax, 30h
and ax, DETECTED_HARDWARE
cmp ax, 20h
mov [VIDEO_MODE], 2
cmp ax, 30h
mov [VIDEO_MODE], 1
pop ax
ret
; Print terminated string
;
; DS:SI - Pointer on string
print_string:
pusha
mov cx, 1
mov bh, 0Fh
print_string.print:
lodsb
cmp al, 0
je print_string.finish
call print_symbol
jmp print_string.print
print_string.finish:
popa
ret
; Split user input on 4 parts by space
split_str_4_space:
push ax
push bx
push cx
push dx
push si
reset_buf cmd.userinput_com, ARGUMENT_BUFFER_SIZE
reset_buf cmd.userinput_arg1, ARGUMENT_BUFFER_SIZE
reset_buf cmd.userinput_arg2, ARGUMENT_BUFFER_SIZE
reset_buf cmd.userinput_arg3, ARGUMENT_BUFFER_SIZE
mov bx, cmd.userinput_com
mov si, cmd.userinput_buf
split_str_4_space.lp:
mov al, [si]
mov [bx], al
inc bx
inc si
cmp byte [si], ' '
je split_str_4_space.change_part
cmp byte [si], 0
je split_str_4_space.rtt
jmp split_str_4_space.lp
split_str_4_space.rtt:
pop si
pop dx
pop cx
pop bx
pop ax
mov byte [split_str_4_space.part], 1
ret
split_str_4_space.change_part:
cmp byte [split_str_4_space.part], 1
je split_str_4_space.change_part.part1
cmp byte [split_str_4_space.part], 2
je split_str_4_space.change_part.part2
cmp byte [split_str_4_space.part], 3
je split_str_4_space.change_part.part3
cmp byte [split_str_4_space.part], 4
je split_str_4_space.change_part.part4
split_str_4_space.part db 1
split_str_4_space.change_part.part1:
inc [split_str_4_space.part]
mov bx, cmd.userinput_arg1
inc si
jmp split_str_4_space.lp
split_str_4_space.change_part.part2:
inc [split_str_4_space.part]
mov bx, cmd.userinput_arg2
inc si
jmp split_str_4_space.lp
split_str_4_space.change_part.part3:
inc [split_str_4_space.part]
mov bx, cmd.userinput_arg3
inc si
jmp split_str_4_space.lp
split_str_4_space.change_part.part4:
jmp split_str_4_space.rtt
; Print symbol
;
; AL - symbol
print_symbol:
pusha
xor bx, bx
mov cx, 1
mov ah, 0Eh
int 10h
popa
ret
; Reset buffer
; DS:SI - buffer
; CX - Length
reset_buffer:
push si
push cx
reset_buffer.lp:
mov byte [ds:si], 0
inc si
dec cx
cmp cx, 0
jne reset_buffer.lp
reset_buffer.nd:
pop cx
pop si
ret
; Input string
;
; DS:SI - Pointer on buffer
; CX - Buffer length
; ---
; AX - Last pressed key
input_string:
push bx
mov bx, 0
input_string.reset_buffer:
push si
push cx
input_string.reset_buffer.lp:
mov byte [ds:si], 0
inc si
dec cx
cmp cx, 0
jne input_string.reset_buffer.lp
input_string.reset_buffer.nd:
pop cx
pop si
input_string.processing:
xor ah, ah
int 16h
cmp al, 0Dh
je input_string.ent
cmp al, 08h
je input_string.backspace
cmp al, 03h
je input_string.ctrlc
call print_symbol
mov [ds:si+bx], al
inc bx
cmp bx, cx
je input_string.ent
jmp input_string.processing
input_string.backspace:
cmp bx, 0
je input_string.processing
mov ah, 0Eh
int 10h
mov al, ' '
int 10h
mov al, 08h
int 10h
dec bx
mov byte [ds:si+bx], 0
jmp input_string.processing
input_string.ent:
pop bx
xor ah, ah
print ln
ret
input_string.ctrlc:
jmp input_string.ent
; Compare strings
;
; DS:SI - Pointer on first string
; DS:BX - Pointer on second string
; ---
; Carry flag - 1 if strings are not equal
compare_strings:
push ax
push bx
push si
compare_strings.comp:
lodsb
cmp [bx], al
jne compare_strings.not_equal
cmp al, 0
je compare_strings.equal
inc bx
jmp compare_strings.comp
compare_strings.equal:
clc
jmp compare_strings.return
compare_strings.not_equal:
stc
jmp compare_strings.return
compare_strings.return:
pop si
pop bx
pop ax
ret
; Copies string
;
; DS:SI - Pointer on memory from where copy
; DS:BX - Pointer on memory where copy
copy_string:
push si
push bx
push ax
copy_string.lp:
lodsb
cmp al, 0
je copy_string.ed
mov byte [bx], al
inc bx
jmp copy_string.lp
copy_string.ed:
pop ax
pop bx
pop si
ret
; Calculate len of string
;
; DS:SI - Pointer on string
; ---
; AX - Len of string
calculate_string_len:
push si
xor ax, ax
push ax
calculate_string_len.lp:
lodsb
cmp al, 0
je calculate_string_len.ed
pop ax
inc ax
push ax
jmp calculate_string_len.lp
calculate_string_len.ed:
pop ax
pop si
ret
; ------------------------------------------------------------------
; os_print_digit -- Displays contents of AX as a single digit
; Works up to base 37, ie digits 0-Z
; IN: AX = "digit" to format and print
os_print_digit:
pusha
cmp ax, 9 ; There is a break in ASCII table between 9 and A
jle .digit_format
add ax, 'A'-'9'-1 ; Correct for the skipped punctuation
.digit_format:
add ax, "0" ; 0 will display as '0', etc.
mov ah, 0Eh ; May modify other registers
int 10h
popa
ret
; ------------------------------------------------------------------
; os_print_1hex -- Displays low nibble of AL in hex format
; IN: AL = number to format and print
os_print_1hex:
pusha
and ax, 0Fh ; Mask off data to display
call os_print_digit
popa
ret
; Print AL in hex
;
; AL - Number to print
os_print_2hex:
pusha
push ax ; Output high nibble
shr ax, 4
call os_print_1hex
pop ax ; Output low nibble
call os_print_1hex
popa
ret
; Print AX in hex
;
; AX - Number to print
print_hex:
pusha
push ax ; Output high byte
mov al, ah
call os_print_2hex
pop ax ; Output low byte
call os_print_2hex
popa
ret
; Print values of registers to screen
;
; AX, BX, CX, DX, SI, DI, ES, DS, SS, FLAGS - Registers to print
print_registers:
pushf
push ss
push ds
push es
push di
push si
push dx
push cx
push bx
print print_registers.axd
call print_hex
print print_registers.h
pop ax
print print_registers.bxd
call print_hex
print print_registers.h, ln
pop ax
print print_registers.cxd
call print_hex
print print_registers.h
pop ax
print print_registers.dxd
call print_hex
print print_registers.h, ln
pop ax
print print_registers.sid
call print_hex
print print_registers.h
pop ax
print print_registers.did
call print_hex
print print_registers.h, ln
pop ax
print print_registers.esd
call print_hex
print print_registers.h
pop ax
print print_registers.dsd
call print_hex
print print_registers.h, ln
pop ax
print print_registers.ssd
call print_hex
print print_registers.h
pop ax
print print_registers.fd
call print_hex
print print_registers.h, ln
ret
; ------------------------------------------------------------------
; os_string_to_int -- Convert decimal string to integer value
; IN: SI = string location (max 5 chars, up to '65536')
; OUT: AX = number
string_to_int:
pusha
mov ax, si ; First, get length of string
call os_string_length
add si, ax ; Work from rightmost char in string
dec si
mov cx, ax ; Use string length as counter
mov bx, 0 ; BX will be the final number
mov ax, 0
; As we move left in the string, each char is a bigger multiple. The
; right-most character is a multiple of 1, then next (a char to the
; left) a multiple of 10, then 100, then 1,000, and the final (and
; leftmost char) in a five-char number would be a multiple of 10,000
mov word [.multiplier], 1 ; Start with multiples of 1
.loop:
mov ax, 0
mov byte al, [si] ; Get character
sub al, 48 ; Convert from ASCII to real number
mul word [.multiplier] ; Multiply by our multiplier
add bx, ax ; Add it to BX
push ax ; Multiply our multiplier by 10 for next char
mov word ax, [.multiplier]
mov dx, 10
mul dx
mov word [.multiplier], ax
pop ax
dec cx ; Any more chars?
cmp cx, 0
je .finish
dec si ; Move back a char in the string
jmp .loop
.finish:
mov word [.tmp], bx
popa
mov word ax, [.tmp]
ret
.multiplier dw 0
.tmp dw 0
os_string_length:
pusha
mov bx, ax ; Move location of string to BX
mov cx, 0 ; Counter
.more:
cmp byte [bx], 0 ; Zero (end of string) yet?
je .done
inc bx ; If not, keep adding
inc cx
jmp .more
.done:
mov word [.tmp_counter], cx ; Store count before restoring other registers
popa
mov ax, [.tmp_counter] ; Put count back into AX before returning
ret
.tmp_counter dw 0
; Convert unsigned int to string
;
; AX - Num to convert
; SI - Where save string
; ---
; SI - Pointer to string with converted num
int_to_string:
push cx
push bx
push di
push ax
mov cx, 0
mov bx, 10 ; Set BX 10, for division and mod
mov di, si ; Get our pointer ready
int_to_string.push:
mov dx, 0
div bx ; Remainder in DX, quotient in AX
inc cx ; Increase pop loop counter
push dx ; Push remainder, so as to reverse order when popping
test ax, ax ; Is quotient zero?
jnz int_to_string.push ; If not, loop again
int_to_string.pop:
pop dx ; Pop off values in reverse order, and add 48 to make them digits
add dl, '0' ; And save them in the string, increasing the pointer each time
mov [di], dl
inc di
dec cx
jnz int_to_string.pop
mov byte [di], 0 ; Zero-terminate string
mov si, di
pop ax
pop di
pop bx
pop cx
ret
; Find file on disk from filename
; BX - filename
; ---
; SI - filename position in table
; CF - 1 if file not exist
find_file:
push bx
push ax
push cx
mov cx, TABLE_SIZE
mov si, filetable
add si, 4
mov [find_file.fn_offset], bx
find_file.lp:
mov bx, [find_file.fn_offset]
call compare_strings
jnc find_file.found
dec cx
cmp cx, 0
je find_fileret
mov bx, 12
; len si
xor ax, ax
sub bx, ax
xchg ax, bx
add si, ax
add si, 4
; mov al, [si]
; cmp al, 0
je find_fileret
jmp find_file.lp
find_file.found:
sub si, 4
pop cx
pop ax
pop bx
clc
ret
find_fileret:
xor si, si
pop cx
pop ax
pop bx
stc
ret
find_file.fn_offset dw 0
; Remove file
; BX - filename
; ---
; CF - 1 if file not exist
remove_file:
push ax
push si
push bx
call find_file
jc remove_file.rtt
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
add si, 2
mov dword [si], 0
pop bx
pop si
pop ax
ret
remove_file.rtt:
pop bx
pop si
pop ax
ret
; Append file to FS table
; AL - Cylinder
; AH - Head
; BL - sector
; BH - Size
; SI - Pointer on name (Max 11 chars)
append_file:
pusha
mov [append_file.cylinder], al
mov [append_file.head], ah
mov [append_file.sector], bl
mov [append_file.size], bh
mov word [append_file.name_os], si
mov cx, TABLE_SIZE
mov si, filetable+4
append_file.lp:
cmp byte [si], 0
je append_file.write
add si, 16
dec cx
cmp cx, 0
je append_file.cannot
jmp append_file.lp
append_file.nd:
popa
ret
append_file.write:
sub si, 4
mov al, [append_file.cylinder]
mov ah, [append_file.head]
mov bl, [append_file.sector]
mov bh, [append_file.size]
mov byte [si], al
mov byte [si+1], ah
mov byte [si+2], bl
mov byte [si+3], bh
add si, 4
mov bx, si
mov si, word [append_file.name_os]
call copy_string
clc
call write_table
jmp append_file.nd
append_file.cannot:
stc
jmp append_file.nd
append_file.cylinder db 0
append_file.head db 0
append_file.sector db 0
append_file.size db 0
append_file.name_os dw 0
; Rename file in FS table
; SI - Filename
; BX - To what filename change
rename_file:
pusha
mov word [rename_file.fst], si
mov word [rename_file.snd], bx
mov bx, si
call find_file
jc rename_file.notfound
add si, 4
push si
reset_buf si, 12
pop si
mov bx, si
mov si, word [rename_file.snd]
call copy_string
rename_file.notfound:
popa
ret
rename_file.fst dw 0
rename_file.snd dw 0
; Read file and load to memory
; SI - File in FS table
; BX - Where load
load_file:
pusha
mov ah, 02h
mov al, [si+3]
mov dl, [BOOT_DRIVE]
mov ch, [si]
mov dh, [si+1]
mov cl, [si+2]
int 13h
popa
ret
; loadoffset dw 0
; Write file and load to memory
; SI - File in FS table
; CX - Where
save_file:
pusha
popa
ret
; Read FS table from disk
read_table:
pusha
mov ah, 02h
mov al, 2
mov dl, [BOOT_DRIVE]
mov ch, 0
mov dh, 0
mov cl, 3
mov bx, filetable
int 13h
popa
ret
; Write FS table to disk
write_table:
pusha
mov ah, 03h
mov al, 2
mov dl, [BOOT_DRIVE]
mov ch, 0
mov dh, 0
mov cl, 3
mov bx, filetable
int 13h
popa
ret
wait_key:
mov ah, 11h
int 16h
jnz wait_key.key_pressed
hlt
jmp wait_key
wait_key.key_pressed:
mov ah, 10h
int 16h
ret
; Copy memory from A to B
; SI - A
; BX - B
; CX - Number of bytes to copy
copy_memory:
pusha
copy_memory.lp:
cmp cx, 0
je copy_memory.nd
lodsb
mov [bx], al
inc bx
dec cx
jmp copy_memory.lp
copy_memory.nd:
popa
ret
; Get cursor position
; ---
; DL - X
; DH - Y
get_cursor_pos:
push ax
push cx
push bx
mov ah, 03h
xor bx, bx
int 10h
pop bx
pop cx
pop ax
ret
; Set cursor position
; DL - X
; DH - Y
set_cursor_pos:
push ax
push bx
mov ah, 02h
xor bx, bx
int 10h
pop bx
pop ax
ret
; Print values of registers and halt cpu
dbg_halt_cpu:
call print_registers
call halt_cpu
; Shows goodbye message and stops the CPU
halt_cpu:
print ln, goodbye
cli
hlt