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 ++++- 3 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 atk16_asm/builtin_asm/std_term.atk16 (limited to 'atk16_asm') 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("@"): -- cgit v1.3