From 3589b9be557fddc859405b937c3ed84342d66852 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Mon, 15 Apr 2024 23:16:41 +0300 Subject: Work on monitor, add std_term --- atk16_asm/asm_pass0.py | 47 +++++++++++++----- atk16_asm/builtin_asm/std_term.atk16 | 46 ++++++++++++++++++ atk16_asm/parser.py | 6 ++- resources/asm/monitor.atk16 | 85 +++++---------------------------- resources/asm/monitor_bak.atk16 | 92 ++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 86 deletions(-) create mode 100644 atk16_asm/builtin_asm/std_term.atk16 create mode 100644 resources/asm/monitor_bak.atk16 diff --git a/atk16_asm/asm_pass0.py b/atk16_asm/asm_pass0.py index 270dc7a..bda16a4 100644 --- a/atk16_asm/asm_pass0.py +++ b/atk16_asm/asm_pass0.py @@ -15,14 +15,14 @@ class Result0Line: class Result0: lines: list[Result0Line] -InsertAtDataSegment = Callable[[str, str, str, int], None] +InsertAtDataSegment = Callable[[str, list[str], str, int], None] def pass_0(lines: list[str], file_name: str, insert_at_data_segment: InsertAtDataSegment | None = None) -> Result0: file_name = file_name if file_name.endswith(".atk16") else file_name + ".atk16" result_lines: list[Result0Line] = [] if not insert_at_data_segment: - def _insert_at_data_segment(label: str, value: str, context_file_name: str, context_line_num: int): + def _insert_at_data_segment(label: str, values: list[str], context_file_name: str, context_line_num: int): data_segment_index = None for idx, result_line in enumerate(result_lines): if result_line.line == "%%data_segment": @@ -32,19 +32,43 @@ def pass_0(lines: list[str], file_name: str, insert_at_data_segment: InsertAtDat if data_segment_index is None: raise Exception(f"Error: @data before @data_segment in {context_file_name}:{context_line_num}") - # Inverted order because of insert semantics - result_lines.insert(data_segment_index + 1, Result0Line( - src_file=context_file_name, - line_num=context_line_num, - line=f"${{{value}}}" - )) - result_lines.insert(data_segment_index + 1, Result0Line( src_file=context_file_name, line_num=context_line_num, line=f"@label {label}" )) + offset = 2 + for value in values: + if value[0] == "\"" and value[-1] == "\"": + string_chars = value[1:-1] + string_chars = string_chars.replace("\\n", "\n") + string_chars = string_chars.replace("\\r", "\r") + string_chars = string_chars.replace("\\t", "\t") + + length = len(string_chars) + result_lines.insert(data_segment_index + offset, Result0Line( + src_file=context_file_name, + line_num=context_line_num, + line=f" {length}" + )) + offset += 1 + + for char in string_chars: + result_lines.insert(data_segment_index + offset, Result0Line( + src_file=context_file_name, + line_num=context_line_num, + line=f" {ord(char)}" + )) + offset += 1 + else: + result_lines.insert(data_segment_index + offset, Result0Line( + src_file=context_file_name, + line_num=context_line_num, + line=f" ${{{value}}}" + )) + offset += 1 + insert_at_data_segment = _insert_at_data_segment for (line_num, line) in enumerate(lines): @@ -65,12 +89,11 @@ def pass_0(lines: list[str], file_name: str, insert_at_data_segment: InsertAtDat )) case "@data": - if len(args) != 2: + if len(args) < 2: raise Exception(f"Error: @data missing arguments in {file_name}:{line_num}") name = args[0] - data = args[1] - + data = args[1:] insert_at_data_segment(name, data, file_name, line_num) case "@include": diff --git a/atk16_asm/builtin_asm/std_term.atk16 b/atk16_asm/builtin_asm/std_term.atk16 new file mode 100644 index 0000000..b0c9f4f --- /dev/null +++ b/atk16_asm/builtin_asm/std_term.atk16 @@ -0,0 +1,46 @@ +@label log_term_char + ; send a character to the terminal + ; parameters: RA = character code + ; return: none + + ; RG is allowed to be clobbered by the calling convention + ldi vt_term_pp_addr RG ; RG := terminal address pointer + ldr RG RG ; RG := terminal address + + str RA RG ; write 'A' to terminal + return + + + +@label log_term_string + ; send a string to the terminal + ; parameters: RA = address of string allocation + ; return: none + + ; strings are encoded as a length word followed by the string data + ; RG is allowed to be clobbered by the calling convention + ldi vt_term_pp_addr RG ; RG := terminal address pointer + ldr RG RG ; RG := terminal address + + stack_stash RA RB RC RD + + ldr RA RB ; RB := string length + ldi 0 RC ; RC := 0 + +@label log_term_string_loop + sub RB RC RD ; RD := remaining length + bri zero log_term_string_done + + add RC RA RD ; RD := pointer to next character - 1 + addi RD 1 RD ; RD := pointer to next character + + ldr RD RD ; RD := next character + + str RD RG ; write character to terminal + inc RC ; increment pointer + + jpi log_term_string_loop + +@label log_term_string_done + stack_restore RA RB RC RD + return diff --git a/atk16_asm/parser.py b/atk16_asm/parser.py index 4823450..3394c2e 100644 --- a/atk16_asm/parser.py +++ b/atk16_asm/parser.py @@ -117,7 +117,11 @@ def parse(tokens: list[str]) -> list[Term]: elif term.startswith("${") and term.endswith("}"): return Expr(term[2:-1]) elif term.startswith("\"") and term.endswith("\""): - return StringLiteral(term[1:-1]) + string_chars = term[1:-1] + string_chars = string_chars.replace("\\n", "\n") + string_chars = string_chars.replace("\\r", "\r") + string_chars = string_chars.replace("\\t", "\t") + return StringLiteral(string_chars) elif term.startswith("&"): return LabelRef(term[1:]) elif term.startswith("@"): diff --git a/resources/asm/monitor.atk16 b/resources/asm/monitor.atk16 index 778aa01..95f017c 100644 --- a/resources/asm/monitor.atk16 +++ b/resources/asm/monitor.atk16 @@ -1,10 +1,11 @@ -@use ext_string_io:* - @include %bootstrap @include %std_mem +@include %std_term @data text_buffer_size 2048 +@data hello_string "foobar baz\n" + @label main ; use memset to clear the text buffer ldi vt_text_mem RA ; RA := text buffer address pointer @@ -14,79 +15,17 @@ 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 +; @data test_char ${ord('A')} +; ldi test_char RA ; RA := 'A' pointer +; ldr RA RA ; RA := 'A' +; calli log_term_char - 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 + ldi hello_string RA ; RA := hello string pointer + calli log_term_string -@data row_index_line_end 39 - ldi row_index_line_end RD - ldr RD RD ; RD := 39 + ; loop forever - 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 +@label loop + jpi loop diff --git a/resources/asm/monitor_bak.atk16 b/resources/asm/monitor_bak.atk16 new file mode 100644 index 0000000..778aa01 --- /dev/null +++ b/resources/asm/monitor_bak.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