-
-
Save markjenkins/202d7e0c5328ccfd567f16b2d405e9bf to your computer and use it in GitHub Desktop.
Process for auditing M0-macro-compact.hex by using sed as a primitive instruction disassembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Copyright (C) 2020 Jeremiah Orians | |
; This file is part of stage0. | |
; | |
; stage0 is free software: you can redistribute it and/or modify | |
; it under the terms of the GNU General Public License as published by | |
; the Free Software Foundation, either version 3 of the License, or | |
; (at your option) any later version. | |
; | |
; stage0 is distributed in the hope that it will be useful, | |
; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
; GNU General Public License for more details. | |
; | |
; You should have received a copy of the GNU General Public License | |
; along with stage0. If not, see <http://www.gnu.org/licenses/>. | |
:start | |
;; We will be using R12 for scratch | |
;; We will be using R13 for storage of tokens | |
LOADUI E 0800 # LOADUI R14 0x800 ; Our malloc pointer (Initialized) | |
LOADUI F $stack # LOADUI R15 $stack ; Put stack at end of program | |
;; Prep TAPE_01 | |
LOADUI 0 1100 # LOADUI R0 0x1100 | |
FOPEN_READ # FOPEN_READ | |
;; Prep TAPE_02 | |
LOADUI 0 1101 # LOADUI R0 0x1101 | |
FOPEN_WRITE # FOPEN_WRITE | |
;; Setup offset table | |
READSCID 0 # READSCID R0 ; Get process capabilities | |
ANDI 1 0 000f # ANDI R1 R0 0xF ; We only care about size nybble | |
LOADUI 0 0001 # LOADUI R0 1 ; Assume we are 8bit | |
SL0 0 0 1 # SL0 R0 R0 R1 ; Let size nybble correct answer | |
STORER16 0 @offset_Text # STORER16 R0 @offset_Text ; Set ->TEXT offset | |
ADDU 1 0 0 # ADDU R1 R0 R0 ; twice the size is the offset of the expression | |
STORER16 1 @offset_Expression # STORER16 R1 @offset_Expression ; Set ->EXPRESSION offset | |
ADDU 0 1 0 # ADDU R0 R1 R0 ; 3 times the size of the register is the size of the struct | |
STORER16 0 @offset_struct # STORER16 R0 @offset_struct ; Set offset_struct | |
;; Main program | |
;; Reads contents of Tape_01 and applies all Definitions | |
;; Writes results to Tape_02 | |
;; Accepts no arguments and HALTS when done | |
:main | |
COPY C E # COPY R12 R14 ; calloc scratch | |
CALLI F @collect_defines # CALLI R15 @collect_defines ; Get all the defines | |
;; We need to rewind tape_01 to perform our second pass | |
LOADUI 0 1100 # LOADUI R0 0x1100 | |
REWIND # REWIND | |
FALSE 0 # FALSE R0 ; Make sure not EOF | |
CALLI F @generate_output # CALLI R15 @generate_output ; Write the results to Tape_02 | |
LOADUI 0 1100 # LOADUI R0 0x1100 ; Close TAPE_01 | |
FCLOSE # FCLOSE | |
LOADUI 0 1101 # LOADUI R0 0x1101 ; Close TAPE_02 | |
FCLOSE # FCLOSE | |
HALT # HALT ; We are Done | |
;; match function | |
;; Receives a CHAR* in R0, CHAR* in R1 | |
;; Returns Bool in R0 indicating if strings match | |
:match | |
PUSHR 1 F # PUSHR R1 R15 ; Protect R1 | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 | |
PUSHR 3 F # PUSHR R3 R15 ; Protect R3 | |
PUSHR 4 F # PUSHR R4 R15 ; Protect R4 | |
MOVE 2 0 # MOVE R2 R0 ; Put First string in place | |
MOVE 3 1 # MOVE R3 R1 ; Put Second string in place | |
LOADUI 4 0000 # LOADUI R4 0 ; Set initial index of 0 | |
:match_cmpbyte | |
LOADXU8 0 2 4 # LOADXU8 R0 R2 R4 ; Get a byte of our first string | |
LOADXU8 1 3 4 # LOADXU8 R1 R3 R4 ; Get a byte of our second string | |
ADDUI 4 4 0001 # ADDUI R4 R4 1 ; Prep for next loop | |
CMPSKIP.NE 1 0 # CMPSKIP.NE R1 R0 ; Compare the bytes | |
JUMP.NZ 1 @match_cmpbyte # JUMP.NZ R1 @match_cmpbyte ; Loop if bytes are equal | |
;; Done | |
FALSE 2 # FALSE R2 ; Default answer | |
CMPSKIP.NE 0 1 # CMPSKIP.NE R0 R1 ; If ended loop with everything matching | |
TRUE 2 # TRUE R2 ; Set as TRUE | |
MOVE 0 2 # MOVE R0 R2 ; Prepare for return | |
POPR 4 F # POPR R4 R15 ; Restore R4 | |
POPR 3 F # POPR R3 R15 ; Restore R3 | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
POPR 1 F # POPR R1 R15 ; Restore R1 | |
RET F # RET R15 | |
;; in_set function | |
;; Receives a Char in R0, char* in R1 | |
;; Return result in R0 | |
:in_set | |
PUSHR 1 F # PUSHR R1 R15 ; Protect R1 | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 from changes | |
:in_set_reset | |
LOADU8 2 1 0000 # LOADU8 R2 R1 0 ; Get char from list | |
JUMP.Z 2 @in_set_fail # JUMP.Z R2 @in_set_fail ; Stop when 0 == s[0] | |
CMPJUMPI.E 0 2 @in_set_done # CMPJUMPI.E R0 R2 @in_set_done ; We found a match | |
ADDUI 1 1 0001 # ADDUI R1 R1 1 ; Increment to next char | |
JUMP.NZ 2 @in_set_reset # JUMP.NZ R2 @in_set_reset ; Iterate if not NULL | |
:in_set_fail | |
;; Looks like not found | |
FALSE 1 # FALSE R1 ; Return FALSE | |
:in_set_done | |
CMPSKIPI.E 1 0000 # CMPSKIPI.E R1 0 ; Provided not FALSE | |
TRUE 2 # TRUE R2 ; The result is true | |
MOVE 0 2 # MOVE R0 R2 ; Put result in correct place | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
POPR 1 F # POPR R1 R15 ; Restore R1 | |
RET F # RET R15 | |
;; file_print function | |
;; Receives pointer to string in R0 and FILE* in R1 | |
;; Returns nothing | |
:file_print | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 from Overwrite | |
MOVE 2 0 # MOVE R2 R0 ; Put string pointer into place | |
:file_print_read | |
LOAD8 0 2 0000 # LOAD8 R0 R2 0 ; Get a char | |
JUMP.Z 0 @file_print_done # JUMP.Z R0 @file_print_done ; If NULL be done | |
FPUTC # FPUTC ; Write the Char | |
ADDUI 2 2 0001 # ADDUI R2 R2 1 ; Point at next CHAR | |
JUMP @file_print_read # JUMP @file_print_read ; Loop again | |
:file_print_done | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
RET F # RET R15 | |
;; numerate_string function | |
;; Receives pointer To string in R0 | |
;; Returns number in R0 equal to value of string | |
;; Or Zero in the event of invalid string | |
:numerate_string | |
;; Preserve Registers | |
PUSHR 1 F # PUSHR R1 R15 | |
PUSHR 2 F # PUSHR R2 R15 | |
PUSHR 3 F # PUSHR R3 R15 | |
PUSHR 4 F # PUSHR R4 R15 | |
;; Initialize | |
MOVE 1 0 # MOVE R1 R0 ; Get Text pointer out of the way | |
FALSE 2 # FALSE R2 ; Set Negative flag to false | |
FALSE 3 # FALSE R3 ; Set current count to Zero | |
LOAD8 0 1 0001 # LOAD8 R0 R1 1 ; Get second byte | |
CMPSKIPI.NE 0 0078 # CMPSKIPI.NE R0 120 ; If the second byte is x | |
JUMP @numerate_string_hex # JUMP @numerate_string_hex ; treat string like hex | |
;; Deal with Decimal input | |
LOADUI 4 000a # LOADUI R4 10 ; Multiply by 10 | |
LOAD8 0 1 0000 # LOAD8 R0 R1 0 ; Get a byte | |
CMPSKIPI.NE 0 002d # CMPSKIPI.NE R0 45 ; If - toggle flag | |
TRUE 2 # TRUE R2 ; So that we know to negate | |
CMPSKIPI.E 2 0000 # CMPSKIPI.E R2 0 ; If toggled | |
ADDUI 1 1 0001 # ADDUI R1 R1 1 ; Move to next | |
:numerate_string_dec | |
LOAD8 0 1 0000 # LOAD8 R0 R1 0 ; Get a byte | |
CMPSKIPI.NE 0 0000 # CMPSKIPI.NE R0 0 ; If NULL | |
JUMP @numerate_string_done # JUMP @numerate_string_done ; Be done | |
MUL 3 3 4 # MUL R3 R3 R4 ; Shift counter by 10 | |
SUBI 0 0 0030 # SUBI R0 R0 48 ; Convert ascii to number | |
CMPSKIPI.GE 0 0000 # CMPSKIPI.GE R0 0 ; If less than a number | |
JUMP @numerate_string_done # JUMP @numerate_string_done ; Terminate NOW | |
CMPSKIPI.L 0 000a # CMPSKIPI.L R0 10 ; If more than a number | |
JUMP @numerate_string_done # JUMP @numerate_string_done ; Terminate NOW | |
ADDU 3 3 0 # ADDU R3 R3 R0 ; Don't add to the count | |
ADDUI 1 1 0001 # ADDUI R1 R1 1 ; Move onto next byte | |
JUMP @numerate_string_dec # JUMP @numerate_string_dec | |
;; Deal with Hex input | |
:numerate_string_hex | |
LOAD8 0 1 0000 # LOAD8 R0 R1 0 ; Get a byte | |
CMPSKIPI.E 0 0030 # CMPSKIPI.E R0 48 ; All hex strings start with 0x | |
JUMP @numerate_string_done # JUMP @numerate_string_done ; Be done if not a match | |
ADDUI 1 1 0002 # ADDUI R1 R1 2 ; Move to after leading 0x | |
:numerate_string_hex_0 | |
LOAD8 0 1 0000 # LOAD8 R0 R1 0 ; Get a byte | |
JUMP.Z 0 @numerate_string_done # JUMP.Z R0 @numerate_string_done ; If NULL Be done | |
SL0I 3 0004 # SL0I R3 4 ; Shift counter by 16 | |
SUBI 0 0 0030 # SUBI R0 R0 48 ; Convert ascii number to number | |
CMPSKIPI.L 0 000a # CMPSKIPI.L R0 10 ; If A-F | |
SUBI 0 0 0007 # SUBI R0 R0 7 ; Shove into Range | |
CMPSKIPI.L 0 0010 # CMPSKIPI.L R0 16 ; If a-f | |
SUBI 0 0 0020 # SUBI R0 R0 32 ; Shove into Range | |
ADDU 3 3 0 # ADDU R3 R3 R0 ; Add to the count | |
ADDUI 1 1 0001 # ADDUI R1 R1 1 ; Get next Hex | |
JUMP @numerate_string_hex_0 # JUMP @numerate_string_hex_0 | |
;; Clean up | |
:numerate_string_done | |
CMPSKIPI.E 2 0000 # CMPSKIPI.E R2 0 ; If Negate flag has been set | |
NEG 3 3 # NEG R3 R3 ; Make the number negative | |
MOVE 0 3 # MOVE R0 R3 ; Put number in R0 | |
;; Restore Registers | |
POPR 4 F # POPR R4 R15 | |
POPR 3 F # POPR R3 R15 | |
POPR 2 F # POPR R2 R15 | |
POPR 1 F # POPR R1 R15 | |
RET F # RET R15 | |
;; collect_defines function | |
;; Returns nothing | |
;; Recieves nothing | |
;; Simply reads one token at a time | |
;; Collecting the DEFINEs | |
;; Uses R0, R1 and R2 as temps | |
;; Updates R12 scratch, R13 tokens and R14 HEAP | |
:collect_defines | |
PUSHR 0 F # PUSHR R0 R15 ; Protect R0 | |
PUSHR 1 F # PUSHR R1 R15 ; Protect R1 | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 | |
:collect_defines_loop | |
CALLI F @read_token # CALLI R15 @read_token ; c = read_token(); | |
PUSHR 0 F # PUSHR R0 R15 ; Protect C | |
COPY 0 C # COPY R0 R12 ; Using scratch | |
LOADUI 1 $DEFINE_STRING # LOADUI R1 $DEFINE_STRING ; Using "DEFINE" | |
CALLI F @match # CALLI R15 @match ; See if they match | |
JUMP.NZ 0 @collect_defines_valid # JUMP.NZ R0 @collect_defines_valid ; Looks like we have a match | |
CALLI F @clear_scratch # CALLI R15 @clear_scratch ; Clear out the scratch buffer | |
POPR 0 F # POPR R0 R15 ; Restore C | |
JUMP.NP 0 @collect_defines_done # JUMP.NP R0 @collect_defines_done ; Hit EOF | |
JUMP @collect_defines_loop # JUMP @collect_defines_loop ; Otherwise keep looping | |
:collect_defines_valid | |
POPR 0 F # POPR R0 R15 ; Restore C | |
CALLI F @clear_scratch # CALLI R15 @clear_scratch ; Clear out the scratch buffer | |
LOADR16 0 @offset_struct # LOADR16 R0 @offset_struct ; Get the size of the struct | |
ADDU E E 0 # ADDU R14 R14 R0 ; Allocate struct | |
STORE D C 0000 # STORE R13 R12 0 ; N->NEXT = tokens | |
COPY D C # COPY R13 R12 ; tokens = N | |
COPY C E # COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char)); | |
CALLI F @read_token # CALLI R15 @read_token ; get the text of the define | |
LOADR16 0 @offset_Text # LOADR16 R0 @offset_Text ; Get ->TEXT offset | |
STOREX C D 0 # STOREX R12 R13 R0 ; N->TEXT = scratch | |
ADDUI E E 0001 # ADDUI R14 R14 1 ; Add some NULL padding | |
COPY C E # COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char)); length = 0; | |
CALLI F @read_token # CALLI R15 @read_token ; Get the expression of the define | |
PUSHR 0 F # PUSHR R0 R15 ; Protect C | |
LOADR16 0 @offset_Expression # LOADR16 R0 @offset_Expression ; Get ->EXPRESSION offset | |
STOREX C D 0 # STOREX R12 R13 R0 ; N->EXPRESSION = scratch | |
ADDUI E E 0001 # ADDUI R14 R14 1 ; Add some NULL padding | |
COPY C E # COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char)); length = 0; | |
POPR 0 F # POPR R0 R15 ; Restore C | |
JUMP.P 0 @collect_defines_loop # JUMP.P R0 @collect_defines_loop ; Keep looping if not NULL | |
:collect_defines_done | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
POPR 1 F # POPR R1 R15 ; Restore R1 | |
POPR 0 F # POPR R0 R15 ; Restore R0 | |
RET F # RET R15 | |
;; read_token function | |
;; Returns int C in R0 | |
;; Updates the contents of (R12) scratch and (R12-R14)length (via updating HEAP (R14)) | |
;; Uses R0, R1 and R2 as temps | |
:read_token | |
PUSHR 1 F # PUSHR R1 R15 ; Protect R1 | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 | |
LOADUI 1 1100 # LOADUI R1 0x1100 ; Using TAPE_01 | |
FGETC # FGETC ; Read a byte | |
JUMP.NP 0 @read_token_done # JUMP.NP R0 @read_token_done ; if EOF, just return EOF | |
CMPSKIPI.NE 0 000a # CMPSKIPI.NE R0 10 ; IF '\n' just return '\n' | |
JUMP @read_token_done # JUMP @read_token_done ; Be done | |
CMPSKIPI.NE 0 0009 # CMPSKIPI.NE R0 9 ; IF '\t' just return '\t' | |
JUMP @read_token_done # JUMP @read_token_done ; Be done | |
CMPSKIPI.NE 0 0020 # CMPSKIPI.NE R0 32 ; IF ' ' just return ' ' | |
JUMP @read_token_done # JUMP @read_token_done ; Be done | |
COPY 2 0 # COPY R2 R0 ; Protect C | |
LOADUI 1 $read_token_comments # LOADUI R1 $read_token_comments ; Using "#;" | |
CALLI F @in_set # CALLI R15 @in_set ; Check if in set | |
LOADUI 1 1100 # LOADUI R1 0x1100 ; Using TAPE_01 | |
JUMP.NZ 0 @delete_line_comment # JUMP.NZ R0 @delete_line_comment ; Then it is a line comment and needs to be purged | |
COPY 0 2 # COPY R0 R2 ; Put C into place for write | |
CMPSKIPI.NE 0 0022 # CMPSKIPI.NE R0 34 ; IF '"' | |
JUMP @read_string # JUMP @read_string ; Collect that string | |
CMPSKIPI.NE 0 0027 # CMPSKIPI.NE R0 39 ; IF "'" | |
JUMP @read_string # JUMP @read_string ; Collect that string | |
;; Deal with the fallthrough case of a single token | |
:read_token_loop | |
PUSH8 2 E # PUSH8 R2 R14 ; scratch[length] = c; length = length + 1; | |
LOADUI 1 1100 # LOADUI R1 0x1100 ; Using TAPE_01 | |
FGETC # FGETC ; Read a byte | |
COPY 2 0 # COPY R2 R0 ; Protect C | |
LOADUI 1 $read_token_whitespace # LOADUI R1 $read_token_whitespace ; Using " \t\n" | |
CALLI F @in_set # CALLI R15 @in_set ; IF in set | |
JUMP.Z 0 @read_token_loop # JUMP.Z R0 @read_token_loop ; Otherwise keep looping | |
MOVE 0 2 # MOVE R0 R2 ; Return our C | |
JUMP @read_token_done # JUMP @read_token_done ; else be done | |
;; Deal with line comment case | |
:delete_line_comment | |
FGETC # FGETC ; Read a byte | |
CMPSKIPI.NE 0 000a # CMPSKIPI.NE R0 10 ; IF '\n' | |
JUMP @read_token_done # JUMP @read_token_done ; Be done | |
JUMP @delete_line_comment # JUMP @delete_line_comment ; Otherwise keep looping | |
;; Deal with "RAW STRINGS" and 'HEX LITERALS' | |
;; R1 is already TAPE_01 and R2 is the terminator | |
:read_string | |
PUSH8 0 E # PUSH8 R0 R14 ; scratch[length] = c; length = length + 1; | |
FGETC # FGETC ; Read a byte | |
CMPJUMPI.NE 0 2 @read_string # CMPJUMPI.NE R0 R2 @read_string ; Keep looping if not terminator | |
:read_token_done | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
POPR 1 F # POPR R1 R15 ; Restore R1 | |
RET F # RET R15 | |
:read_token_comments | |
# "#;" | |
233b0000 | |
:read_token_whitespace | |
# " \t\n" | |
20090a00 | |
;; clear_scratch function | |
;; Recieves nothing | |
;; Returns nothing | |
;; Clears SCRATCH (R12) and LENGTH (R14-R12) by POPing off the HEAP (R14) | |
:clear_scratch | |
PUSHR 0 F # PUSHR R0 R15 ; Protect R0 | |
:clear_scratch_loop | |
CMPJUMPI.E C E @clear_scratch_done # CMPJUMPI.E R12 R14 @clear_scratch_done ; When LENGTH == 0 and SCRATCH is cleared | |
POP8 0 E # POP8 R0 R14 ; Clear the last byte of SCRATCH and decrement LENGTH | |
JUMP @clear_scratch_loop # JUMP @clear_scratch_loop ; Keep looping | |
:clear_scratch_done | |
POPR 0 F # POPR R0 R15 ; Restore R0 | |
RET F # RET R15 | |
;; generate_output function | |
;; Returns nothing | |
;; Recieves nothing | |
;; Simply reads one token at a time | |
;; Outputting if possible | |
;; Uses R0, R1 and R2 as temps | |
;; Manipulates SCRATCH (R12) and LENGTH (R14-R12) but should reset HEAP (R14) each loop | |
:generate_output | |
JUMP.NP 0 @generate_output_done # JUMP.NP R0 @generate_output_done ; Stop if we hit EOF | |
CALLI F @clear_scratch # CALLI R15 @clear_scratch ; Clear the scratch | |
CALLI F @read_token # CALLI R15 @read_token ; Get a token | |
CMPJUMPI.E C E @generate_output # CMPJUMPI.E R12 R14 @generate_output ; Go again if we read nothing | |
COPY 2 0 # COPY R2 R0 ; Protect C | |
LOAD8 0 C 0000 # LOAD8 R0 R12 0 ; SCRATCH[0] | |
LOADUI 1 $generate_output_hex # LOADUI R1 $generate_output_hex ; Using ":!@$%&" | |
CALLI F @in_set # CALLI R15 @in_set ; See if worth keeping | |
JUMP.Z 0 @generate_output_define # JUMP.Z R0 @generate_output_define | |
;; Deal with the case of labels and pointers | |
COPY 0 C # COPY R0 R12 ; Using scratch | |
LOADUI 1 1101 # LOADUI R1 0x1101 ; And TAPE_02 | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
LOADUI 0 000a # LOADUI R0 10 ; Using '\n' | |
FPUTC # FPUTC ; fputc('\n', TAPE_02); | |
MOVE 0 2 # MOVE R0 R2 ; Put C in correct spot for catching EOF | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_define | |
COPY 0 C # COPY R0 R12 ; Using SCRATCH | |
LOADUI 1 $DEFINE_STRING # LOADUI R1 $DEFINE_STRING ; Using "DEFINE" | |
CALLI F @match # CALLI R15 @match ; See if we have a match | |
JUMP.Z 0 @generate_output_string # JUMP.Z R0 @generate_output_string ; If not try a string | |
;; Deal with the case of DEFINE statement | |
CALLI F @clear_scratch # CALLI R15 @clear_scratch ; Clear out the scratch | |
CALLI F @read_token # CALLI R15 @read_token ; Get a token | |
CALLI F @clear_scratch # CALLI R15 @clear_scratch ; Clear out the scratch | |
CALLI F @read_token # CALLI R15 @read_token ; Get a token | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_string | |
LOAD8 0 C 0000 # LOAD8 R0 R12 0 ; SCRATCH[0] | |
CMPSKIPI.E 0 0022 # CMPSKIPI.E R0 34 ; If SCRATCH[0] == '"' | |
JUMP @generate_output_literal # JUMP @generate_output_literal ; Otherwise try next | |
;; Deal with the case of "RAW STRING" | |
LOADUI 1 1101 # LOADUI R1 0x1101 ; And TAPE_02 | |
CALLI F @hexify_string # CALLI R15 @hexify_string ; Write it | |
LOADUI 0 000a # LOADUI R0 10 ; Using '\n' | |
FPUTC # FPUTC ; Write it | |
MOVE 0 2 # MOVE R0 R2 ; Return C | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_literal | |
CMPSKIPI.E 0 0027 # CMPSKIPI.E R0 39 ; If SCRATCH[0] == '\'' | |
JUMP @generate_output_defined # JUMP @generate_output_defined ; Otherwise try next | |
;; Deal with the case of 'HEX LITERAL' | |
ADDUI 0 C 0001 # ADDUI R0 R12 1 ; Using SCRATCH + 1 | |
LOADUI 1 1101 # LOADUI R1 0x1101 ; And TAPE_02 | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
LOADUI 0 000a # LOADUI R0 10 ; Using '\n' | |
FPUTC # FPUTC ; Write it | |
MOVE 0 2 # MOVE R0 R2 ; Return C | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_defined | |
CALLI F @find_match # CALLI R15 @find_match ; Lets see if SCRATCH has a match | |
JUMP.Z 0 @generate_output_number # JUMP.Z R0 @generate_output_number ; Nope, try a NUMBER | |
;; Deal with case of a DEFINED token | |
LOADUI 1 1101 # LOADUI R1 0x1101 ; And TAPE_02 | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
LOADUI 0 000a # LOADUI R0 10 ; Using '\n' | |
FPUTC # FPUTC ; Write it | |
MOVE 0 2 # MOVE R0 R2 ; Return C | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_number | |
COPY 0 C # COPY R0 R12 ; Using SCRATCH | |
LOAD8 1 C 0000 # LOAD8 R1 R12 0 ; Get SCRATCH[0] | |
CALLI F @numerate_string # CALLI R15 @numerate_string ; See if it is a number | |
CMPSKIPI.E 1 0030 # CMPSKIPI.E R1 48 ; IF '0' == SCRATCH[0] | |
JUMP.Z 0 @generate_output_fail # JUMP.Z R0 @generate_output_fail ; We failed | |
;; Deal with the case of numbers | |
LOADUI 1 1101 # LOADUI R1 0x1101 ; And TAPE_02 | |
CALLI F @hex16 # CALLI R15 @hex16 ; Write it | |
LOADUI 0 000a # LOADUI R0 10 ; Using '\n' | |
FPUTC # FPUTC ; Write it | |
MOVE 0 2 # MOVE R0 R2 ; Return C | |
JUMP @generate_output # JUMP @generate_output ; Loop it | |
:generate_output_fail | |
FALSE 1 # FALSE R1 ; Write to STDOUT | |
LOADUI 0 $generate_output_message1 # LOADUI R0 $generate_output_message1 ; Put our header | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
MOVE 0 C # MOVE R0 R12 ; Using SCRATCH | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
LOADUI 0 $generate_output_message2 # LOADUI R0 $generate_output_message2 ; Put our header | |
CALLI F @file_print # CALLI R15 @file_print ; Print it | |
HALT # HALT ; FUCK | |
:generate_output_done | |
RET F # RET R15 | |
:generate_output_hex | |
# ":!@$%&" | |
3a21402425260000 | |
:generate_output_message1 | |
# "\nUnknown other: " | |
0a556e6b6e6f776e206f746865723a2000000000 | |
:generate_output_message2 | |
# "\nAborting to prevent problems\n" | |
0a41626f7274696e6720746f2070726576656e742070726f626c656d730a0000 | |
;; hexify_string function | |
;; Recieves FILE* in R1 | |
;; Writes SCRATCH (R12) | |
;; Uses R2 to check for hitting NULL and R3 for I | |
:hexify_string | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 | |
PUSHR 3 F # PUSHR R3 R15 ; Protect R3 | |
PUSHR C F # PUSHR R12 R15 ; Protect R12 | |
ADDUI C C 0001 # ADDUI R12 R12 1 ; Skip past the '"' | |
FALSE 3 # FALSE R3 ; I = 0 | |
:hexify_string_loop | |
LOADXU16 0 C 3 # LOADXU16 R0 R12 R3 ; Grab 2 bytes | |
ANDI 2 0 00ff # ANDI R2 R0 0xFF ; Preserve byte to check for NULL | |
CALLI F @hex16 # CALLI R15 @hex16 ; Convert to hex and print | |
ADDUI 3 3 0002 # ADDUI R3 R3 2 ; I = I + 2 | |
JUMP.NZ 2 @hexify_string_loop # JUMP.NZ R2 @hexify_string_loop | |
;; Deal with extra padding | |
:hexify_string_padding | |
FALSE 0 # FALSE R0 ; Writing ZERO | |
ANDI 3 3 0003 # ANDI R3 R3 0x3 ; (I & 0x3) | |
JUMP.Z 3 @hexify_string_done # JUMP.Z R3 @hexify_string_done ; IF (0 == (I & 0x3)) be done | |
CALLI F @hex8 # CALLI R15 @hex8 ; Write another NULL byte | |
ADDUI 3 3 0001 # ADDUI R3 R3 1 ; I = I + 1 | |
JUMP @hexify_string_padding # JUMP @hexify_string_padding ; Keep padding | |
:hexify_string_done | |
POPR C F # POPR R12 R15 ; Restore R12 | |
POPR 3 F # POPR R3 R15 ; Restore R3 | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
RET F # RET R15 | |
;; hex16 functionality | |
;; Accepts 16bit value in R0 | |
;; And FILE* output in R1 | |
;; Returns to whatever called it | |
:hex16 | |
PUSHR 0 F # PUSHR R0 R15 | |
SR0I 0 0008 # SR0I R0 8 ; Do high byte first | |
CALLI F @hex8 # CALLI R15 @hex8 | |
POPR 0 F # POPR R0 R15 | |
:hex8 | |
PUSHR 0 F # PUSHR R0 R15 | |
SR0I 0 0004 # SR0I R0 4 ; Do high nybble first | |
CALLI F @hex4 # CALLI R15 @hex4 | |
POPR 0 F # POPR R0 R15 | |
:hex4 | |
ANDI 0 0 000f # ANDI R0 R0 0xF ; isolate nybble | |
ADDUI 0 0 0030 # ADDUI R0 R0 48 ; convert to ascii | |
CMPSKIPI.LE 0 0039 # CMPSKIPI.LE R0 57 ; If nybble was greater than '9' | |
ADDUI 0 0 0007 # ADDUI R0 R0 7 ; Shift it into 'A' range of ascii | |
FPUTC # FPUTC ; Write HEX | |
RET F # RET R15 ; Get next nybble or return if done | |
;; find_match function | |
;; Recieves SCRATCH in R12 | |
;; And tokens in R13 | |
;; Returns NULL or EXPRESSION if match found | |
:find_match | |
PUSHR 1 F # PUSHR R1 R15 ; Protect R1 | |
PUSHR 2 F # PUSHR R2 R15 ; Protect R2 | |
COPY 2 D # COPY R2 R13 ; P = tokens | |
:find_match_loop | |
JUMP.Z 2 @find_match_done # JUMP.Z R2 @find_match_done ; Be done if not found | |
LOADR16 1 @offset_Text # LOADR16 R1 @offset_Text ; Get ->TEXT offset | |
LOADX 0 2 1 # LOADX R0 R2 R1 ; Using P->TEXT | |
COPY 1 C # COPY R1 R12 ; Using SCRATCH | |
CALLI F @match # CALLI R15 @match ; See if they match | |
JUMP.NZ 0 @find_match_success # JUMP.NZ R0 @find_match_success ; Found it | |
LOAD 2 2 0000 # LOAD R2 R2 0 ; P = P->NEXT | |
JUMP @find_match_loop # JUMP @find_match_loop ; Keep looping | |
;; Deal with match | |
:find_match_success | |
LOADR16 1 @offset_Expression # LOADR16 R1 @offset_Expression ; Using ->EXPRESSION offset | |
LOADX 2 2 1 # LOADX R2 R2 R1 ; Using P->EXPRESSION | |
:find_match_done | |
MOVE 0 2 # MOVE R0 R2 ; Put result in R0 | |
POPR 2 F # POPR R2 R15 ; Restore R2 | |
POPR 1 F # POPR R1 R15 ; Restore R1 | |
RET F # RET R15 | |
;; offset table | |
;; Values will be updated to reflect | |
;; register sizes greater than 8bits | |
;; if registers are larger than 8 bits | |
;; Padded with 2 extra NULLs to help the Disassembler | |
;; As 4byte alignment is generally assumed to simply | |
;; Work required to figure out strings | |
:offset_Text | |
0001 # 1 | |
:offset_Expression | |
0002 # 2 | |
:offset_struct | |
0003 # 3 | |
00 00 | |
:DEFINE_STRING | |
# "DEFINE" | |
444546494e450000 | |
; Where our stack will start | |
:stack |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sed -i -e s/FFFFFFFF/HALT/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100200/FPUTC/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100100/FGETC/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100003/REWIND/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100002/FCLOSE/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100001/FOPEN_WRITE/ M0-macro-compact.hex2.audit | |
sed -i -e s/42100000/FOPEN_READ/ M0-macro-compact.hex2.audit | |
sed -i -e s/E000A05/CMPSKIPI.L/ M0-macro-compact.hex2.audit | |
sed -i -e s/E000A04/CMPSKIPI.LE/ M0-macro-compact.hex2.audit | |
sed -i -e s/E000A03/CMPSKIPI.NE/ M0-macro-compact.hex2.audit | |
sed -i -e s/E000A02/CMPSKIPI.E/ M0-macro-compact.hex2.audit | |
sed -i -e s/E000A01/CMPSKIPI.GE/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002F2/STORER16/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002E3/LOADR16/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002D6/SR0I/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002D5/SL0I/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002D2/LOADUI/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002D0/CALLI/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002CC/JUMP.NP/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002CB/JUMP.P/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002CA/JUMP.NZ/ M0-macro-compact.hex2.audit | |
sed -i -e s/E0002C9/JUMP.Z/ M0-macro-compact.hex2.audit | |
sed -i -e s/0D01001/RET/ M0-macro-compact.hex2.audit | |
sed -i -e s/0D00003/TRUE/ M0-macro-compact.hex2.audit | |
sed -i -e s/0D00002/FALSE/ M0-macro-compact.hex2.audit | |
sed -i -e s/0D00001/READSCID/ M0-macro-compact.hex2.audit | |
sed -i -e s/E100C3/CMPJUMPI.NE/ M0-macro-compact.hex2.audit | |
sed -i -e s/E100C2/CMPJUMPI.E/ M0-macro-compact.hex2.audit | |
sed -i -e s/E100B0/ANDI/ M0-macro-compact.hex2.audit | |
sed -i -e s/E10020/STORE/ M0-macro-compact.hex2.audit | |
sed -i -e s/E10015/LOADU8/ M0-macro-compact.hex2.audit | |
sed -i -e s/E10014/LOAD8/ M0-macro-compact.hex2.audit | |
sed -i -e s/E10013/LOAD/ M0-macro-compact.hex2.audit | |
sed -i -e s/E10010/SUBI/ M0-macro-compact.hex2.audit | |
sed -i -e s/E1000F/ADDUI/ M0-macro-compact.hex2.audit | |
sed -i -e s/090303/CMPSKIP.NE/ M0-macro-compact.hex2.audit | |
sed -i -e s/090281/POP8/ M0-macro-compact.hex2.audit | |
sed -i -e s/090280/POPR/ M0-macro-compact.hex2.audit | |
sed -i -e s/090201/PUSH8/ M0-macro-compact.hex2.audit | |
sed -i -e s/090200/PUSHR/ M0-macro-compact.hex2.audit | |
sed -i -e s/090005/MOVE/ M0-macro-compact.hex2.audit | |
sed -i -e s/090004/COPY/ M0-macro-compact.hex2.audit | |
sed -i -e s/090000/NEG/ M0-macro-compact.hex2.audit | |
sed -i -e s/05048/STOREX/ M0-macro-compact.hex2.audit | |
sed -i -e s/0503C/LOADXU16/ M0-macro-compact.hex2.audit | |
sed -i -e s/0503A/LOADXU8/ M0-macro-compact.hex2.audit | |
sed -i -e s/05038/LOADX/ M0-macro-compact.hex2.audit | |
sed -i -e s/05032/SL0/ M0-macro-compact.hex2.audit | |
sed -i -e s/05006/MUL/ M0-macro-compact.hex2.audit | |
sed -i -e s/05001/ADDU/ M0-macro-compact.hex2.audit | |
sed -i -e s/3C00/JUMP/ M0-macro-compact.hex2.audit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FFFFFFFF HALT | |
42100200 FPUTC | |
42100100 FGETC | |
42100003 REWIND | |
42100002 FCLOSE | |
42100001 FOPEN_WRITE | |
42100000 FOPEN_READ | |
E000A05 CMPSKIPI.L | |
E000A04 CMPSKIPI.LE | |
E000A03 CMPSKIPI.NE | |
E000A02 CMPSKIPI.E | |
E000A01 CMPSKIPI.GE | |
E0002F2 STORER16 | |
E0002E3 LOADR16 | |
E0002D6 SR0I | |
E0002D5 SL0I | |
E0002D2 LOADUI | |
E0002D0 CALLI | |
E0002CC JUMP.NP | |
E0002CB JUMP.P | |
E0002CA JUMP.NZ | |
E0002C9 JUMP.Z | |
0D01001 RET | |
0D00003 TRUE | |
0D00002 FALSE | |
0D00001 READSCID | |
E100C3 CMPJUMPI.NE | |
E100C2 CMPJUMPI.E | |
E100B0 ANDI | |
E10020 STORE | |
E10015 LOADU8 | |
E10014 LOAD8 | |
E10013 LOAD | |
E10010 SUBI | |
E1000F ADDUI | |
090303 CMPSKIP.NE | |
090281 POP8 | |
090280 POPR | |
090201 PUSH8 | |
090200 PUSHR | |
090005 MOVE | |
090004 COPY | |
090000 NEG | |
05048 STOREX | |
0503C LOADXU16 | |
0503A LOADXU8 | |
05038 LOADX | |
05032 SL0 | |
05006 MUL | |
05001 ADDU | |
3C00 JUMP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is the audit process for M0-macro-compact.hex2 documented here