Skip to content

Instantly share code, notes, and snippets.

@markjenkins
Last active February 29, 2020 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markjenkins/202d7e0c5328ccfd567f16b2d405e9bf to your computer and use it in GitHub Desktop.
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
; 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
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
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
@markjenkins
Copy link
Author

markjenkins commented Feb 29, 2020

This is the audit process for M0-macro-compact.hex2 documented here

../knightpies/get_instructions_in_M1.py High_level_prototypes/defs stage1/M0-macro-compact.s > M0-macro-compact_instructions_used
awk "{print \"sed -i -e s/\" \$1 \"/\" \$2 \"/ M0-macro-compact.hex2.audit\"}" < M0-macro-compact_instructions_used >  M0-macro-compact.hex2.audit.sh
cp stage1/M0-macro-compact.hex2 M0-macro-compact.hex2.audit
sh M0-macro-compact.hex2.audit.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment