Add shell task and terminal application

This commit is contained in:
Ry 2022-10-14 16:53:41 -07:00
parent 75eb29613b
commit 3cd4341986
15 changed files with 1054 additions and 0 deletions

View File

@ -19,6 +19,9 @@ echo "assembling launcher"
echo "assembling barclock" echo "assembling barclock"
../fox32asm/target/release/fox32asm barclock/main.asm base_image/barclock.fxf ../fox32asm/target/release/fox32asm barclock/main.asm base_image/barclock.fxf
echo "assembling terminal"
../fox32asm/target/release/fox32asm terminal/main.asm base_image/terminal.fxf
echo "creating wallpapr.raw" echo "creating wallpapr.raw"
../tools/gfx2inc/target/release/gfx2inc 640 480 launcher/wallpaper.png launcher/wallpaper.inc ../tools/gfx2inc/target/release/gfx2inc 640 480 launcher/wallpaper.png launcher/wallpaper.inc
../fox32asm/target/release/fox32asm launcher/wallpaper.inc base_image/wallpapr.raw ../fox32asm/target/release/fox32asm launcher/wallpaper.inc base_image/wallpapr.raw

View File

@ -35,3 +35,6 @@ seek: jmp [0x00000D14]
tell: jmp [0x00000D18] tell: jmp [0x00000D18]
read: jmp [0x00000D1C] read: jmp [0x00000D1C]
write: jmp [0x00000D20] write: jmp [0x00000D20]
; shell jump table
new_shell_task: jmp [0x00000E10]

View File

@ -55,6 +55,10 @@ jump_table:
data.32 read data.32 read
data.32 write data.32 write
; shell jump table
org.pad 0x00000E10
data.32 new_shell_task
; initialization code ; initialization code
entry: entry:
mov rsp, SYSTEM_STACK mov rsp, SYSTEM_STACK
@ -253,6 +257,7 @@ get_os_version:
#include "allocator.asm" #include "allocator.asm"
#include "fxf/fxf.asm" #include "fxf/fxf.asm"
#include "shell/shell.asm"
#include "task.asm" #include "task.asm"
#include "window/window.asm" #include "window/window.asm"
#include "vfs.asm" #include "vfs.asm"

View File

@ -0,0 +1,53 @@
; command parser
shell_parse_command:
mov r0, shell_text_buf_bottom
; dir
mov r1, shell_dir_command_string
call compare_string
ifz jmp shell_dir_command
; disk
mov r1, shell_disk_command_string
call compare_string
ifz jmp shell_disk_command
; diskrm
mov r1, shell_diskrm_command_string
call compare_string
ifz jmp shell_diskrm_command
; exit
mov r1, shell_exit_command_string
call compare_string
ifz jmp shell_exit_command
; help
mov r1, shell_help_command_string
call compare_string
ifz jmp shell_help_command
; type
mov r1, shell_type_command_string
call compare_string
ifz jmp shell_type_command
; attempt to run a FXF binary
call launch_fxf
; invalid command
mov r0, shell_invalid_command_string
call print_str_to_terminal
ret
shell_invalid_command_string: data.str "invalid command or FXF binary" data.8 10 data.8 0
; all commands
#include "shell/commands/dir.asm"
#include "shell/commands/disk.asm"
#include "shell/commands/diskrm.asm"
#include "shell/commands/exit.asm"
#include "shell/commands/help.asm"
#include "shell/commands/type.asm"

View File

@ -0,0 +1,37 @@
; dir command
shell_dir_command_string: data.str "dir" data.8 0
shell_dir_command:
mov r0, shell_dir_command_list_buffer
movz.8 r1, [shell_current_disk]
call ryfs_get_file_list
mov r31, r0
mov r3, 0
shell_dir_command_loop:
; copy one file name from the list buffer to the file buffer
mov r0, shell_dir_command_list_buffer
add r0, r3
mov r1, shell_dir_command_file_buffer
mov r2, 11
call copy_memory_bytes
add r1, 11
mov.8 [r1], 0
; then print the file name to the terminal
mov r0, shell_dir_command_file_buffer
call print_str_to_terminal
; new line
mov r0, 10
call print_character_to_terminal
; point to next file name in the buffer
add r3, 11
loop shell_dir_command_loop
ret
shell_dir_command_list_buffer: data.fill 0, 341
shell_dir_command_file_buffer: data.fill 0, 12

View File

@ -0,0 +1,39 @@
; disk command
shell_disk_command_string: data.str "disk" data.8 0
shell_disk_command:
call shell_parse_arguments
mov r1, 10
call string_to_int
; r0: disk ID
; check if it's in range
cmp r0, 3
ifgt jmp shell_disk_command_out_of_range
; OR it with the IO port to get the current insert state of a disk
; if no disk is inserted then prompt the user to insert a disk
or r0, 0x80001000
in r1, r0
cmp r1, 0
ifz jmp shell_disk_command_insert_disk
; set the current disk ID
mov.8 [shell_current_disk], r0
ret
shell_disk_command_out_of_range:
mov r0, shell_disk_command_out_of_range_string
call print_str_to_terminal
ret
shell_disk_command_insert_disk:
out r0, 0
ret
shell_disk_command_out_of_range_string: data.str "invalid disk ID" data.8 10 data.8 0

View File

@ -0,0 +1,30 @@
; eject command
shell_diskrm_command_string: data.str "diskrm" data.8 0
shell_diskrm_command:
call shell_parse_arguments
mov r1, 10
call string_to_int
; r0: disk ID
; check if it's in range
cmp r0, 3
ifgt jmp shell_diskrm_command_out_of_range
; OR it with the IO port to remove a disk
or r0, 0x80005000
; remove disk
out r0, 0
ret
shell_diskrm_command_out_of_range:
mov r0, shell_diskrm_command_out_of_range_string
call print_str_to_terminal
ret
shell_diskrm_command_out_of_range_string: data.str "invalid disk ID" data.8 10 data.8 0

View File

@ -0,0 +1,6 @@
; exit command
shell_exit_command_string: data.str "exit" data.8 0
shell_exit_command:
call end_current_task

View File

@ -0,0 +1,27 @@
; help command
shell_help_command_string: data.str "help" data.8 0
shell_help_command:
mov r0, shell_help_text
call print_str_to_terminal
ret
shell_help_text:
data.str "fox32os shell" data.8 10
data.8 10
data.str "(in descriptions, $n is argument n)" data.8 10
data.str "command | description" data.8 10
data.str "------- | -----------" data.8 10
data.str "dir | show contents of selected disk" data.8 10
data.str "disk | select disk $0" data.8 10
data.str "diskrm | remove disk $0" data.8 10
data.str "exit | exit the shell" data.8 10
data.str "help | show this help text" data.8 10
data.str "type | print file $0 of type $1" data.8 10
data.8 10
data.str "type the name of an FXF binary to launch" data.8 10
data.str "it as a new task; the shell will suspend" data.8 10
data.str "until the launched task ends" data.8 10
data.8 0

View File

@ -0,0 +1,90 @@
; type command
shell_type_command_string: data.str "type" data.8 0
; FIXME: check string length before blindly copying
shell_type_command:
call shell_parse_arguments
; r0: file name
; r1: file extension
; copy empty file name
push r1
push r0
mov r0, shell_type_command_file_empty
mov r1, shell_type_command_file
mov r2, 11
call copy_memory_bytes
; copy file name
pop r0
mov r1, shell_type_command_file
call custom_copy_string
; copy file extension
pop r0
mov r1, shell_type_command_file
add r1, 8
call custom_copy_string
add r1, 3
mov.8 [r1], 0
; open the file
mov r0, shell_type_command_file
movz.8 r1, [shell_current_disk]
mov r2, shell_type_command_file_struct
call open
cmp r0, 0
ifz jmp shell_type_command_file_not_found
mov r0, shell_type_command_file_struct
call ryfs_get_size
mov r31, r0
shell_type_command_loop:
mov r0, 1
mov r1, shell_type_command_file_struct
mov r2, shell_type_command_file_character_buffer
call read
movz.8 r0, [shell_type_command_file_character_buffer]
call print_character_to_terminal
loop shell_type_command_loop
mov r0, 10
call print_character_to_terminal
ret
shell_type_command_file_not_found:
mov r0, shell_type_command_file_not_found_string
call print_str_to_terminal
mov r0, shell_type_command_file
call print_str_to_terminal
mov r0, 10
call print_character_to_terminal
ret
custom_copy_string:
push r0
push r1
push r2
custom_copy_string_loop:
mov.8 r2, [r0]
mov.8 [r1], r2
inc r0
inc r1
cmp.8 [r0], 0
ifnz jmp custom_copy_string_loop
pop r2
pop r1
pop r0
ret
shell_type_command_file: data.fill 0, 12
shell_type_command_file_empty: data.str " "
shell_type_command_file_struct: data.32 0 data.32 0
shell_type_command_file_character_buffer: data.8 0
shell_type_command_file_not_found_string: data.str "file not found: " data.8 0

107
kernel/shell/launch.asm Normal file
View File

@ -0,0 +1,107 @@
; FXF launcher helper routines
; launch an FXF binary from a shell entry
; inputs:
; r0-r3: shell arguments
; outputs:
; none, does not return if task started successfully
; returns if FXF file not found
launch_fxf:
; clear the first 8 characters of the launch_fxf_name buffer
push r0
mov r0, launch_fxf_spaces
mov r1, launch_fxf_name
mov r2, 8
call copy_memory_bytes
pop r0
; copy the name into the launch_fxf_name buffer
mov r1, launch_fxf_name
mov r31, 8
launch_fxf_name_loop:
mov.8 [r1], [r0]
inc r0
inc r1
cmp.8 [r0], 0
ifz jmp launch_fxf_name_loop_done
loop launch_fxf_name_loop
launch_fxf_name_loop_done:
; open the file
mov r0, launch_fxf_name
movz.8 r1, [shell_current_disk]
mov r2, launch_fxf_struct
call ryfs_open
cmp r0, 0
ifz ret
; allocate memory for the binary
mov r0, launch_fxf_struct
call ryfs_get_size
call allocate_memory
cmp r0, 0
ifz jmp allocate_error
mov [launch_fxf_binary_ptr], r0
; read the file into memory
mov r0, launch_fxf_struct
mov r1, [launch_fxf_binary_ptr]
call ryfs_read_whole_file
; allocate a 64KiB stack
mov r0, 65536
call allocate_memory
cmp r0, 0
ifz jmp allocate_error
mov [launch_fxf_stack_ptr], r0
; push the argument pointers and terminal stream struct pointer to the task's stack
call shell_parse_arguments
mov r4, rsp
mov rsp, [launch_fxf_stack_ptr]
add rsp, 65536 ; point to the end of the stack (stack grows down!!)
push r3
push r2
push r1
push r0
push [shell_terminal_stream_struct_ptr]
sub rsp, 65516
mov [launch_fxf_stack_ptr], rsp
mov rsp, r4
; relocate the binary
mov r0, [launch_fxf_binary_ptr]
call parse_fxf_binary
; create a new task
mov r1, r0
call get_unused_task_id
mov.8 [launch_fxf_task_id], r0
mov r2, [launch_fxf_stack_ptr]
add r2, 65516 ; point to the end of the stack (stack grows down!!)
mov r3, [launch_fxf_binary_ptr]
mov r4, [launch_fxf_stack_ptr]
call new_task
; fall-through to launch_fxf_yield_loop
; loop until the launched task ends
launch_fxf_yield_loop:
movz.8 r0, [launch_fxf_task_id]
call is_task_id_used
ifz jmp shell_task_return
call yield_task
rjmp launch_fxf_yield_loop
allocate_error:
mov r0, out_of_memory_string
call print_str_to_terminal
ret
launch_fxf_name: data.str " fxf"
launch_fxf_spaces: data.str " "
launch_fxf_struct: data.32 0 data.32 0
launch_fxf_task_id: data.8 0
launch_fxf_binary_ptr: data.32 0
launch_fxf_stack_ptr: data.32 0
out_of_memory_string: data.str "failed to allocate for new task!" data.8 10 data.8 0

309
kernel/shell/shell.asm Normal file
View File

@ -0,0 +1,309 @@
; shell routines
const CURSOR: 138
; create a new shell task
; inputs:
; r0: task ID
; r1: pointer to stream struct
; outputs:
; none
new_shell_task:
push r0
push r1
push r2
push r3
push r4
push r10
; allocate a 64KiB stack and push the pointer to the stream struct to it
push r0
push r1
mov r0, 65536
call allocate_memory
add r0, 65532
pop r1
mov [r0], r1
mov r10, r0
pop r0
; then start the task
mov r1, shell_task ; initial instruction pointer
mov r2, r10 ; initial stack pointer
mov r3, 0 ; pointer to task code block to free when task ends
; (zero since we don't want to free any code blocks when the task ends)
mov r4, r10 ; pointer to task stack block to free when task ends
sub r4, 65536 ; point to the start of the stack block that we allocated above
call new_task
pop r10
pop r4
pop r3
pop r2
pop r1
pop r0
ret
; print a character to the terminal
; inputs:
; r0: ASCII character
; outputs:
; none
print_character_to_terminal:
push r1
push r2
mov.8 [shell_char_buffer], r0
mov r1, [shell_terminal_stream_struct_ptr]
mov r2, shell_char_buffer
call write
pop r2
pop r1
ret
; print a string to the terminal
; inputs:
; r0: pointer to null-terminated string
; outputs:
; none
print_str_to_terminal:
push r0
push r2
mov r1, [shell_terminal_stream_struct_ptr]
mov r2, r0
print_str_to_terminal_loop:
call write
inc r2
cmp.8 [r2], 0x00
ifnz jmp print_str_to_terminal_loop
pop r2
pop r0
ret
shell_task:
pop [shell_terminal_stream_struct_ptr]
shell_task_return:
call shell_clear_buffer
call shell_print_prompt
shell_task_loop:
mov r1, [shell_terminal_stream_struct_ptr]
mov r2, shell_char_buffer
call read
movz.8 r0, [shell_char_buffer]
cmp.8 r0, 0
ifnz call shell_task_parse_key
call yield_task
rjmp shell_task_loop
shell_task_parse_key:
; first, check if enter, delete, or backspace was pressed
cmp.8 r0, 0x1C ; enter
ifz jmp shell_key_down_enter
cmp.8 r0, 0x6F ; delete
ifz jmp shell_key_down_backspace
cmp.8 r0, 0x0E ; backspace
ifz jmp shell_key_down_backspace
; then, overwrite the cursor
mov r1, r0
mov r0, 8 ; backspace character
call print_character_to_terminal
mov r0, r1
; then, add it to the text buffer and print it to the screen
call scancode_to_ascii
call print_character_to_terminal
call shell_push_character
; finally, print the cursor
mov r0, CURSOR
call print_character_to_terminal
ret
shell_key_down_enter:
; clear the cursor from the screen
mov r0, 8 ; backspace character
call print_character_to_terminal
mov r0, ' ' ; space character
call print_character_to_terminal
mov r0, 8 ; backspace character
call print_character_to_terminal
mov r0, 10 ; line feed
call print_character_to_terminal
mov r0, 0
call shell_push_character
call shell_parse_line
call shell_clear_buffer
call shell_print_prompt
ret
shell_key_down_backspace:
; check if we are already at the start of the prompt
mov r1, [shell_text_buf_ptr]
cmp r1, shell_text_buf_bottom
iflteq ret
; delete the last character from the screen, draw the cursor, and pop the last character from the buffer
mov r0, 8 ; backspace character
call print_character_to_terminal
mov r0, ' ' ; space character
call print_character_to_terminal
mov r0, 8 ; backspace character
call print_character_to_terminal
call print_character_to_terminal
mov r0, CURSOR ; cursor
call print_character_to_terminal
call shell_delete_character
ret
shell_print_prompt:
movz.8 r0, [shell_current_disk]
add r0, '0'
call print_character_to_terminal
mov r0, shell_prompt
call print_str_to_terminal
ret
shell_parse_line:
; if the line is empty, just return
cmp.8 [shell_text_buf_bottom], 0
ifz ret
; separate the command from the arguments
; store the pointer to the arguments
mov r0, shell_text_buf_bottom
mov r1, ' '
call shell_tokenize
mov [shell_args_ptr], r0
call shell_parse_command
ret
; return tokens separated by the specified character
; returns the next token in the list
; inputs:
; r0: pointer to null-terminated string
; r1: separator character
; outputs:
; r0: pointer to next token or zero if none
shell_tokenize:
cmp.8 [r0], r1
ifz jmp shell_tokenize_found_token
cmp.8 [r0], 0
ifz mov r0, 0
ifz ret
inc r0
jmp shell_tokenize
shell_tokenize_found_token:
mov.8 [r0], 0
inc r0
ret
; parse up to 4 arguments into individual strings
; for example, "this is a test" will be converted to
; r0: pointer to "this" data.8 0
; r1: pointer to "is" data.8 0
; r2: pointer to "a" data.8 0
; r3: pointer to "test" data.8 0
; inputs:
; none
; outputs:
; r0: pointer to 1st null-terminated argument, or zero if none
; r1: pointer to 2nd null-terminated argument, or zero if none
; r2: pointer to 3rd null-terminated argument, or zero if none
; r3: pointer to 4th null-terminated argument, or zero if none
shell_parse_arguments:
push r31
mov r0, [shell_args_ptr]
mov r1, ' '
mov r31, 3
push r0
shell_parse_arguments_loop:
call shell_tokenize
push r0
loop shell_parse_arguments_loop
pop r3
pop r2
pop r1
pop r0
pop r31
ret
; push a character to the text buffer
; inputs:
; r0: character
; outputs:
; none
shell_push_character:
push r1
mov r1, [shell_text_buf_ptr]
cmp r1, shell_text_buf_top
ifgteq jmp shell_push_character_end
mov.8 [r1], r0
inc [shell_text_buf_ptr]
shell_push_character_end:
pop r1
ret
; pop a character from the text buffer and zero it
; inputs:
; none
; outputs:
; r0: character
shell_delete_character:
push r1
mov r1, [shell_text_buf_ptr]
cmp r1, shell_text_buf_bottom
iflteq jmp shell_delete_character_end
dec [shell_text_buf_ptr]
movz.8 r0, [r1]
mov.8 [r1], 0
shell_delete_character_end:
pop r1
ret
; mark the text buffer as empty
; inputs:
; none
; outputs:
; none
shell_clear_buffer:
push r0
; set the text buffer poinrer to the start of the text buffer
mov [shell_text_buf_ptr], shell_text_buf_bottom
; set the first character as null
mov r0, [shell_text_buf_ptr]
mov.8 [r0], 0
pop r0
ret
shell_text_buf_bottom: data.fill 0, 32
shell_text_buf_top:
shell_text_buf_ptr: data.32 0 ; pointer to the current input character
shell_args_ptr: data.32 0 ; pointer to the beginning of the command arguments
shell_current_disk: data.8 0
shell_prompt: data.str "> " data.8 CURSOR data.8 0
shell_terminal_stream_struct_ptr: data.32 0
shell_char_buffer: data.32 0
#include "shell/commands/commands.asm"
#include "shell/launch.asm"

104
terminal/main.asm Normal file
View File

@ -0,0 +1,104 @@
; terminal
mov r0, window_struct
mov r1, window_title
mov r2, 320
mov r3, 400
mov r4, 32
mov r5, 32
call new_window
call get_unused_task_id
mov.8 [shell_task_id], r0
mov r1, stream_struct
call new_shell_task
event_loop:
mov r0, window_struct
call get_next_window_event
cmp r0, EVENT_TYPE_MOUSE_CLICK
ifz jmp mouse_down
cmp r0, EVENT_TYPE_KEY_DOWN
ifz jmp key_down
cmp r0, EVENT_TYPE_KEY_UP
ifz jmp key_up
event_loop_end:
movz.8 r0, [shell_task_id]
call is_task_id_used
ifz jmp close_window
call yield_task
mov.8 [read_buffer], 0
rjmp event_loop
mouse_down:
; check if we are attempting to drag or close the window
cmp r2, 16
iflteq jmp drag_window
jmp event_loop_end
key_down:
mov r0, r1
cmp.8 r0, KEY_LSHIFT
ifz push event_loop_end
ifz jmp shift_pressed
cmp.8 r0, KEY_RSHIFT
ifz push event_loop_end
ifz jmp shift_pressed
cmp.8 r0, KEY_CAPS
ifz push event_loop_end
ifz jmp caps_pressed
mov.8 [read_buffer], r0
jmp event_loop_end
key_up:
mov r0, r1
cmp.8 r0, KEY_LSHIFT
ifz push event_loop_end
ifz jmp shift_released
cmp.8 r0, KEY_RSHIFT
ifz push event_loop_end
ifz jmp shift_released
jmp event_loop_end
drag_window:
cmp r1, 8
iflteq jmp event_loop_end
mov r0, window_struct
call start_dragging_window
jmp event_loop_end
close_window:
mov r0, window_struct
call destroy_window
call end_current_task
jmp event_loop_end
window_title: data.str "Terminal" data.8 0
window_struct: data.fill 0, 32
shell_task_id: data.8 0
stream_struct:
data.8 0x00
data.16 0x00
data.32 0x00
data.8 0x01
data.32 stream_get_input
data.32 stream_write_to_terminal
#include "stream.asm"
#include "text.asm"
; include system defs
#include "../../fox32rom/fox32rom.def"
#include "../fox32os.def"

14
terminal/stream.asm Normal file
View File

@ -0,0 +1,14 @@
; stream IO routines
; write a character to the terminal
; inputs:
; r0: pointer to ASCII character
stream_write_to_terminal:
mov r0, [r0]
jmp print_character_to_terminal
stream_get_input:
mov r0, [read_buffer]
ret
read_buffer: data.32 0

227
terminal/text.asm Normal file
View File

@ -0,0 +1,227 @@
; text rendering routines
const TERMINAL_X_SIZE: 40
const TERMINAL_Y_SIZE: 25
const TEXT_COLOR: 0xFFFFFFFF
const BACKGROUND_COLOR: 0xFF000000
; print a single character to the terminal
; inputs:
; r0: ASCII character
; outputs:
; none
print_character_to_terminal:
push r0
push r1
push r2
cmp.8 r0, 0 ; null
ifz jmp print_character_to_terminal_end
cmp.8 r0, 8 ; backspace
ifz jmp print_character_to_terminal_bs
cmp.8 r0, 10 ; line feed
ifz jmp print_character_to_terminal_lf
cmp.8 r0, 13 ; carriage return
ifz jmp print_character_to_terminal_cr
; check if we are at the end of this line
cmp.8 [terminal_x], TERMINAL_X_SIZE
; if so, increment to the next line
ifgteq mov.8 [terminal_x], 0
ifgteq inc.8 [terminal_y]
; check if we need to scroll the display
cmp.8 [terminal_y], TERMINAL_Y_SIZE
ifgteq call scroll_terminal
; calculate coords for character...
movz.8 r1, [terminal_x]
movz.8 r2, [terminal_y]
mul r2, TERMINAL_X_SIZE
add r1, r2
add r1, terminal_text_buf
; ...and print!!
mov.8 [r1], r0
inc.8 [terminal_x]
jmp print_character_to_terminal_end
print_character_to_terminal_cr:
; return to the beginning of the line
mov.8 [terminal_x], 0
jmp print_character_to_terminal_end
print_character_to_terminal_lf:
; return to the beginning of the line and increment the line
mov.8 [terminal_x], 0
inc.8 [terminal_y]
; scroll the display if needed
cmp.8 [terminal_y], TERMINAL_Y_SIZE
ifgteq call scroll_terminal
jmp print_character_to_terminal_end
print_character_to_terminal_bs:
; go back one character
cmp.8 [terminal_x], 0
ifnz dec.8 [terminal_x]
print_character_to_terminal_end:
call redraw_terminal_line
pop r2
pop r1
pop r0
ret
; scroll the terminal
; inputs:
; none
; outputs:
; none
scroll_terminal:
push r0
push r1
push r2
push r31
; source
mov r0, terminal_text_buf
add r0, TERMINAL_X_SIZE
; destination
mov r1, terminal_text_buf
; size
mov r2, TERMINAL_X_SIZE
mul r2, 24
div r2, 4
call copy_memory_words
mov.8 [terminal_x], 0
mov.8 [terminal_y], 24
; clear the last line
mov r0, terminal_text_buf
add r0, 960 ; 40 * 24
mov r31, TERMINAL_X_SIZE
scroll_terminal_clear_loop:
mov.8 [r0], 0
inc r0
loop scroll_terminal_clear_loop
; redraw the screen
call redraw_terminal
pop r31
pop r2
pop r1
pop r0
ret
; redraw the whole terminal
; inputs:
; none
; outputs:
; none
redraw_terminal:
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r31
mov r0, window_struct
call get_window_overlay_number
mov r5, r0
mov r0, terminal_text_buf
mov r1, 0
mov r2, 16
mov r3, TEXT_COLOR
mov r4, BACKGROUND_COLOR
mov r31, TERMINAL_Y_SIZE
redraw_terminal_loop_y:
push r31
mov r1, 0
mov r31, TERMINAL_X_SIZE
redraw_terminal_loop_x:
push r0
movz.8 r0, [r0]
call draw_font_tile_to_overlay
movz.8 r0, 8
add r1, r0
pop r0
inc r0
loop redraw_terminal_loop_x
pop r31
movz.8 r6, 16
add r2, r6
loop redraw_terminal_loop_y
pop r31
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret
; redraw only the current line
; inputs:
; none
; outputs:
; none
redraw_terminal_line:
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r31
mov r0, window_struct
call get_window_overlay_number
mov r5, r0
movz.8 r0, [terminal_y]
mul r0, TERMINAL_X_SIZE
add r0, terminal_text_buf
movz.8 r1, [terminal_y]
mov r2, 16
mul r2, r1
add r2, 16
mov r1, 0
mov r3, TEXT_COLOR
mov r4, BACKGROUND_COLOR
mov r1, 0
mov r31, TERMINAL_X_SIZE
redraw_terminal_line_loop_x:
push r0
movz.8 r0, [r0]
call draw_font_tile_to_overlay
movz.8 r0, 8
add r1, r0
pop r0
inc r0
loop redraw_terminal_line_loop_x
pop r31
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret
terminal_x: data.8 0
terminal_y: data.8 0
terminal_text_buf: data.fill 0, 1000 ; 40x25 = 1000 bytes