aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_projects
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-04-26 15:40:14 +0300
committerJan Tuomi <jan@jantuomi.fi>2024-04-26 15:40:14 +0300
commit7ca56c1a730fcecd0fe3af5e6b652fa09514a18b (patch)
treee2ef6a4d28fa26adf11e00d138ef21b8316497f6 /atk16_projects
parent2b18b320e97260f1d27143a37fe14953cf62e56d (diff)
Refactor project structure, add README and LICENSE
Diffstat (limited to 'atk16_projects')
-rw-r--r--atk16_projects/monitor/Makefile16
-rw-r--r--atk16_projects/monitor/monitor.atk16176
-rw-r--r--atk16_projects/monitor/monitor_macros.py45
-rw-r--r--atk16_projects/monitor_proto/Makefile16
-rw-r--r--atk16_projects/monitor_proto/ext_string_io.py55
-rw-r--r--atk16_projects/monitor_proto/monitor_proto.atk1692
6 files changed, 400 insertions, 0 deletions
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