@use monitor_macros:* @include %bootstrap @include %std_mem @include %std_term @include %std_bump_alloc ; Constants @data text_buffer_size 2048 @data input_buffer_size 36 ; 40 chars row - 2 padding - 2 for prompt ; Global variable pointers ; 0xE800 - 0xEFFF: sprite buffer space that is unused in this program @data text_cursor_p 0xE800 @data input_buffer_p 0xE801 @data input_cursor_p 0xE802 @data title_string " »» ATK16 monitor v0.1 »»" @data subtitle_string " Run [help] for a list of commands" @data prompt_string " > " @label main ; initialize heap allocator calli bump_reset ; initialize global variables ; BEGIN text_cursor_p = text_mem ldi text_cursor_p RA ldr RA RA ldi vt_text_mem RB ldr RB RB str RB RA ; END ; BEGIN input_buffer_p = alloc(input_buffer_size) ldi input_buffer_size RA calli bump_alloc ldi input_buffer_p RA ldr RA RA str RG RA ; END ; BEGIN input_cursor_p = input_buffer_p ldi input_cursor_p RA ldr RA RA str RG RA ; END ; use memset to clear the text buffer ; BEGIN memset(text_mem, 0, text_buffer_size) ldi vt_text_mem RA ; RA := text buffer address pointer ldr RA RA ; RA := text buffer address ldi text_buffer_size RB ; RB := pointer to text_buffer_size ldr RB RB ; RB := text_buffer_size ldi 0 RC ; RC := 0 calli memset ; END set_graphics_mode gr_text_mode m_newline RA RB ; BEGIN put_string(title_string) ldi title_string RA calli put_string ; END m_newline RA RB ; BEGIN put_string(subtitle_string) ldi subtitle_string RA calli put_string ; END m_newline RA RB m_newline RA RB ldi prompt_string RA calli put_string ; loop forever @label loop ; BEGIN critical section m_set_critical RA RB calli is_newline_pressed subi RG 1 RG ; if is_newline_pressed() == 1, then loop_newline_pressed bri zero loop_newline_pressed jpi loop_finally @label loop_newline_pressed ; TODO jpi loop_finally @label loop_finally m_clear_critical RA RB ; END critical section jpi loop ;;; Subroutines @label newline ; move cursor to the beginning of the next line ; parameters: none ; returns: none stack_stash RA RB m_newline RA RB stack_restore RA RB return @label put_char ; put a character at the current cursor position ; parameters: RA = character to put ; returns: none stack_stash RB RC m_put_char RA RB RC stack_restore RB RC return @label put_string ; put a string at the current cursor position ; parameters: RA = string_p ; returns: none stack_stash RA RB RC RD RE ldr RA RB ; RB := string length addi RA 1 RC ; RC := pointer to first character @label put_string_loop subi RB 0 RB ; exit if RB has been decremented to 0 bri zero put_string_done ; i.e. no more characters to put ldr RC RA ; RA := character to put m_put_char RA RD RE ; inline the put_char subroutine to avoid function call overhead inc RC subi RB 1 RB jpi put_string_loop @label put_string_done stack_restore RA RB RC RD RE return @label is_newline_pressed ; check if the last character in the input buffer is a newline ; parameters: none ; returns: RG = 1 if newline is pressed, 0 otherwise stack_stash RA RB ldi 10 RB ; RB := newline character ldi input_cursor_p RA ; RA := data segment pointer ldr RA RA ; RA := 0xE802 ldr RA RA ; RA := &char ldr RA RA ; RA := char ldi 1 RG ; RG := 1 sub RA RB RA ; if RA == newline, then return RG = 1 bri zero is_newline_pressed_done ldi 0 RG ; else return RG = 0 @label is_newline_pressed_done stack_restore RA RB return @data row_index_mask ${64 - 1} @label keyboard_isr stack_stash RA RB RC RD ldi vt_kb_pp_addr RA ; RA := Keyboard peripheral address pointer ldr RA RA ; RA := Keyboard peripheral address deref ldr RA RA ; RA := <16-bit keyboard character code> from MMIO register mov RA RB ; RB := character code subi RB 5 RB ; if code == 10 (enter key), then run newline handler subi RB 5 RB bri zero keyboard_isr_newline ldi text_cursor_p RC ldr RC RC ldr RC RC ; RC := text_cursor_p mov RA RB ; if code == 8 (backspace key), then run backspace handler subi RB 5 RB subi RB 3 RB bri zero keyboard_isr_backspace ldi row_index_mask RD ; else code is not special; write it to text buffer ldr RD RD ; if cursor is not at the end of the line and RC RD RD @data row_index_line_end 39 ldi row_index_line_end RB ldr RB RB ; RB := 39 sub RD RB RB ; if row index == 39, then skip writing character bri zero keyboard_isr_end m_put_char RA RB RC ; if row index < 39, then write character to text buffer jpi keyboard_isr_end @label keyboard_isr_newline m_newline RA RB ldi prompt_string RA calli put_string jpi keyboard_isr_end @label keyboard_isr_backspace ; check that RC is not at the beginning of the prompt ldi row_index_mask RD ldr RD RD and RC RD RD ; RD := RC & 63, i.e. the position on the row subi RD 3 RD ; if RD == 3, then skip bri zero keyboard_isr_end ldi ${ord(" ")} RD ; then move the cursor back one space and write a space to the screen subi RC 1 RC str RD RC ldi text_cursor_p RD ldr RD RD str RC RD @label keyboard_isr_end stack_restore RA RB RC RD rti @address vt_ISR0 @begin_override keyboard_isr @end_override