From 7ca56c1a730fcecd0fe3af5e6b652fa09514a18b Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 26 Apr 2024 15:40:14 +0300 Subject: Refactor project structure, add README and LICENSE --- atk16_projects/monitor/Makefile | 16 +++ atk16_projects/monitor/monitor.atk16 | 176 +++++++++++++++++++++++ atk16_projects/monitor/monitor_macros.py | 45 ++++++ atk16_projects/monitor_proto/Makefile | 16 +++ atk16_projects/monitor_proto/ext_string_io.py | 55 +++++++ atk16_projects/monitor_proto/monitor_proto.atk16 | 92 ++++++++++++ 6 files changed, 400 insertions(+) create mode 100644 atk16_projects/monitor/Makefile create mode 100644 atk16_projects/monitor/monitor.atk16 create mode 100644 atk16_projects/monitor/monitor_macros.py create mode 100644 atk16_projects/monitor_proto/Makefile create mode 100644 atk16_projects/monitor_proto/ext_string_io.py create mode 100644 atk16_projects/monitor_proto/monitor_proto.atk16 (limited to 'atk16_projects') diff --git a/atk16_projects/monitor/Makefile b/atk16_projects/monitor/Makefile new file mode 100644 index 0000000..ad8013b --- /dev/null +++ b/atk16_projects/monitor/Makefile @@ -0,0 +1,16 @@ +EMULATOR = atk16emu +ASSEMBLER = atk16c +PROJ = monitor + +out/$(PROJ).bin: $(PROJ).atk16 + $(ASSEMBLER) $< -o out/$(PROJ).bin + +### + +@PHONY: run +run: out/$(PROJ).bin + $(EMULATOR) $< + +@PHONY: debug +debug: out/$(PROJ).bin + $(EMULATOR) -d $< diff --git a/atk16_projects/monitor/monitor.atk16 b/atk16_projects/monitor/monitor.atk16 new file mode 100644 index 0000000..d3b8756 --- /dev/null +++ b/atk16_projects/monitor/monitor.atk16 @@ -0,0 +1,176 @@ +@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 64 + +; 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(64) + ldi input_buffer_size RA + calli bump_alloc + ldi input_buffer_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 wait_for_input_newline + ; wait for a newline character in the input buffer + ; parameters: none + ; returns: RG = key code + stack_stash RA RB + ldi 10 RB ; RB := newline character +@label wait_for_input_newline_loop + ldi input_cursor_p RA ; RA := data segment pointer + ldr RA RA ; RA := 0xE802 + ldr RA RA ; RA := &char + ldr RA RA ; RA := char + + sub RA RB RA ; if RA == newline, then stop waiting + bri zero wait_for_input_newline_done + + jpi wait_for_input_newline_loop +@label wait_for_input_newline_done + stack_restore RA RB + 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 diff --git a/atk16_projects/monitor/monitor_macros.py b/atk16_projects/monitor/monitor_macros.py new file mode 100644 index 0000000..b40be9e --- /dev/null +++ b/atk16_projects/monitor/monitor_macros.py @@ -0,0 +1,45 @@ +from atk16_asm.asm_ops import * + +expansions: dict[str, Callable[..., ExpandResult]] = {} +def register_macro(func): + expansions[func.__name__] = func + return func + +@register_macro +def m_newline(r1: str, r2: str) -> ExpandResult: + return [ + *expand_ldi("text_cursor_p", r1), + *expand_ldr(r1, r1), + *expand_ldr(r1, r2), + *expand_slri(r2, "6", r2), # cursor = cursor / 64 + *expand_addi(r2, "1", r2), # cursor = cursor + 1 + *expand_slli(r2, "6", r2), # cursor = cursor * 64 + *expand_str(r2, r1), + ] + +@register_macro +def m_put_char(char_r: str, r1: str, r2: str) -> ExpandResult: + return [ + *expand_ldi("text_cursor_p", r1), + *expand_ldr(r1, r1), + *expand_ldr(r1, r2), + *expand_str(char_r, r2), + *expand_addi(r2, "1", r2), + *expand_str(r2, r1), + ] + +def m_set_interrupt_state(r1: str, r2: str, value: int) -> ExpandResult: + return [ + *expand_ldi("vt_iset_addr", r1), + *expand_ldr(r1, r1), + *expand_ldi(value, r2), + *expand_str(r2, r1), + ] + +@register_macro +def m_set_critical(r1: str, r2: str) -> ExpandResult: + return m_set_interrupt_state(r1, r2, 1) + +@register_macro +def m_clear_critical(r1: str, r2: str) -> ExpandResult: + return m_set_interrupt_state(r1, r2, 0) diff --git a/atk16_projects/monitor_proto/Makefile b/atk16_projects/monitor_proto/Makefile new file mode 100644 index 0000000..0ef6d33 --- /dev/null +++ b/atk16_projects/monitor_proto/Makefile @@ -0,0 +1,16 @@ +EMULATOR = atk16emu +ASSEMBLER = atk16c +PROJ = monitor_proto + +out/$(PROJ).bin: $(PROJ).atk16 + $(ASSEMBLER) $< -o out/$(PROJ).bin + +### + +@PHONY: run +run: out/$(PROJ).bin + $(EMULATOR) $< + +@PHONY: debug +debug: out/$(PROJ).bin + $(EMULATOR) -d $< diff --git a/atk16_projects/monitor_proto/ext_string_io.py b/atk16_projects/monitor_proto/ext_string_io.py new file mode 100644 index 0000000..e00ac78 --- /dev/null +++ b/atk16_projects/monitor_proto/ext_string_io.py @@ -0,0 +1,55 @@ +from atk16_asm.asm_ops import * + +def to_char_code(c: str): + return ord(c) + +_counter = 0 +def get_unique_name(prefix: str): + global _counter + ret = f"{prefix}_{_counter}" + _counter += 1 + return ret + +def expand_put_char(cursor_reg: str, scratch_reg: str, c: str) -> ExpandResult: + c = c.strip("\"") + return [ + ["ldi", str(to_char_code(c)), scratch_reg], + ["str", scratch_reg, cursor_reg], + *expand_addi(cursor_reg, "1", cursor_reg), + ] + +def expand_put_string(cursor_reg: str, scratch_reg: str, *rest: str) -> ExpandResult: + string = " ".join(rest) + string = string.strip("\"") + result: ExpandResult = [] + for c in string: + result += expand_put_char(cursor_reg, scratch_reg, c) + + return result + +def expand_cursor_to_line(cursor_reg: str, line: int) -> ExpandResult: + lbl_data = get_unique_name("cursor_to_line_data") + lbl_jmpover = get_unique_name("cursor_to_line_jmpover") + line_width = 64 + return [ + ["jpi", lbl_jmpover], + ["@label", lbl_data], + [f"text_mem + {line} * {line_width}"], + ["@label", lbl_jmpover], + ["ldi", lbl_data, cursor_reg], + ["ldr", cursor_reg, cursor_reg], + ] + +def expand_new_line(cursor_reg: str) -> ExpandResult: + return [ + *expand_slri(cursor_reg, "6", cursor_reg), + *expand_addi(cursor_reg, "1", cursor_reg), + *expand_slli(cursor_reg, "6", cursor_reg), + ] + +expansions: OpExpansionDict = { + "put_char": expand_put_char, + "cursor_to_line": expand_cursor_to_line, + "put_string": expand_put_string, + "new_line": expand_new_line, +} diff --git a/atk16_projects/monitor_proto/monitor_proto.atk16 b/atk16_projects/monitor_proto/monitor_proto.atk16 new file mode 100644 index 0000000..778aa01 --- /dev/null +++ b/atk16_projects/monitor_proto/monitor_proto.atk16 @@ -0,0 +1,92 @@ +@use ext_string_io:* + +@include %bootstrap +@include %std_mem + +@data text_buffer_size 2048 + +@label main + ; use memset to clear the text buffer + 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 1024 + ldr RB RB ; RB := 1024 + ldi 0 RC ; RC := 0 + calli memset + + cursor_to_line RC 1 + put_string RC RB " »» ATK16 monitor v0.1 »»" + new_line RC + put_string RC RB " Run [help] for a list of commands" + new_line RC + new_line RC + put_string RC RB " > " + + set_graphics_mode gr_text_mode + +@label loop + jpi loop + +@data row_index_mask ${64 - 1} + +@label keyboard_isr + stack_stash RA RB RD RE + 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 + ldi vt_term_pp_addr RB ; RB := Terminal peripheral address pointer + ldr RB RB ; RB := Terminal peripheral address deref + + mov RA RD ; RD := character code + subi RD 5 RD ; if code == 10 (enter key), then run newline handler + subi RD 5 RD + bri zero keyboard_isr_newline + + mov RA RD ; if code == 8 (backspace key), then run backspace handler + subi RD 5 RD + subi RD 3 RD + + bri zero keyboard_isr_backspace + + ldi row_index_mask RE ; else code is not special; write it to text buffer + ldr RE RE ; if cursor is not at the end of the line + and RC RE RE + +@data row_index_line_end 39 + ldi row_index_line_end RD + ldr RD RD ; RD := 39 + + sub RE RD RD ; if row index == 39, then skip writing character + bri zero keyboard_isr_end + + str RA RC + addi RC 1 RC + jpi keyboard_isr_end + +@label keyboard_isr_newline + new_line RC + put_string RC RB " > " + jpi keyboard_isr_end + +@label keyboard_isr_backspace + ; check that RC is not at the beginning of the prompt + ldi row_index_mask RE + ldr RE RE + and RC RE RE ; RE := RC & 63, i.e. the position on the row + + subi RE 3 RE ; if RE == 3, then skip + bri zero keyboard_isr_end + + ; then move the cursor back one space and write a space to the screen + subi RC 1 RC + put_char RC RB " " + subi RC 1 RC + +@label keyboard_isr_end + stack_restore RA RB RD RE + rti + +@address vt_ISR0 +@begin_override + keyboard_isr +@end_override -- cgit v1.3