diff --git a/CHANGELOG.org b/CHANGELOG.org index 7978211..e027981 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -1,11 +1,13 @@ * Unreleased ** Added + Created xeh tool in C for more cross platform debugging ++ Created M0 in hex2 ** Changed + Renamed xeh1 files to match current naming standard ** Fixed ++ Fixed leading char bug in M0 ** Removed diff --git a/stage1/M0-macro.hex2 b/stage1/M0-macro.hex2 new file mode 100644 index 0000000..1404580 --- /dev/null +++ b/stage1/M0-macro.hex2 @@ -0,0 +1,741 @@ +:start +# ;; We will be using R13 for storage of Head +# ;; We will be using R14 for our condition codes +2D2F $stack # LOADUI R15 $stack ; Put stack at end of progra +# ;; Main program +# ;; Reads contents of Tape_01 and applies all Definitions +# ;; Writes results to Tape_02 +# ;; Accepts no arguments and HALTS when done +:main +# ;; Prep TAPE_01 +2D201100 # LOADUI R0 0x1100 +42100000 # FOPEN_READ +0D00002D # FALSE R13 ; Head is NULL +09000510 # MOVE R1 R0 ; Read Tape_01 +0D00002E # FALSE R14 ; We haven't yet reached EOF + +:main_0 +2D0F @Tokenize_Line # CALLI R15 @Tokenize_Line ; Call Tokenize_Line +2C9E @main_0 # JUMP.Z R14 @main_0 ; Until we reach EOF + +# ;; Done reading File +2D201100 # LOADUI R0 0x1100 ; Close TAPE_01 +42100002 # FCLOSE +0900040D # COPY R0 R13 ; Prepare for function +2D0F @Identify_Macros # CALLI R15 @Identify_Macros ; Tag all nodes that are macros +2D0F @Line_Macro # CALLI R15 @Line_Macro ; Apply macros down nodes +2D0F @Process_String # CALLI R15 @Process_String ; Convert string values to Hex16 +2D0F @Eval_Immediates # CALLI R15 @Eval_Immediates ; Convert numbers to hex +2D0F @Preserve_Other # CALLI R15 @Preserve_Other ; Ensure labels/Pointers aren't lost + +# ;; Prep TAPE_02 +2D201101 # LOADUI R0 0x1101 +42100001 # FOPEN_WRITE +2D0F @Print_Hex # CALLI R15 @Print_Hex ; Write Nodes to Tape_02 + +# ;; Done writing File +2D201101 # LOADUI R0 0x1101 ; Close TAPE_01 +42100002 # FCLOSE +FFFFFFFF # HALT ; We are Done + + +# ;; Primative malloc function +# ;; Recieves number of bytes to allocate in R0 +# ;; Returns pointer to block of that size in R0 +# ;; Returns to whatever called it +:malloc +# ;; Preserve registers +0902001F # PUSHR R1 R15 +# ;; Get current malloc pointer +2E01 @malloc_pointer # LOADR R1 @malloc_pointer +# ;; Deal with special case +A0310000 # CMPSKIP.NE R1 0 ; If Zero set to our start of heap space +2D214000 # LOADUI R1 0x4000 +# ;; update malloc pointer +09000301 # SWAP R0 R1 +05000101 # ADD R1 R0 R1 +2F01 @malloc_pointer # STORER R1 @malloc_pointer +# ;; Done +# ;; Restore registers +0902801F # POPR R1 R15 +0D01001F # RET R15 +# ;; Our static value for malloc pointer +:malloc_pointer +00000000 # NOP + + +# ;; Tokenize_Line function +# ;; Recieves pointer to Head in R0 and desired input in R1 +# ;; Alters R14 when EOF Reached +# ;; Returns to whatever called it +:Tokenize_Line +# ;; Preserve registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +0900044D # COPY R4 R13 ; Get Head pointer out of the way +:Tokenize_Line_0 +42100100 # FGETC ; Get a Char +# ;; Deal with lines comments starting with # +A0300023 # CMPSKIP.NE R0 35 +3C00 @Purge_Line_Comment # JUMP @Purge_Line_Comment +# ;; Deal with Line comments starting with ; +A030003b # CMPSKIP.NE R0 59 +3C00 @Purge_Line_Comment # JUMP @Purge_Line_Comment +# ;; Deal with Tab +A0300009 # CMPSKIP.NE R0 9 +3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again +# ;; Deal with New line +A030000a # CMPSKIP.NE R0 10 +3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again +# ;; Deal with space characters +A0300020 # CMPSKIP.NE R0 32 +3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again +# ;; Flag if reached EOF +A0100000 # CMPSKIP.GE R0 0 +0D00003E # TRUE R14 +# ;; Stop if EOF +A0100000 # CMPSKIP.GE R0 0 +3C00 @Tokenize_Line_Done # JUMP @Tokenize_Line_Done +# ;; Allocate a new Node +09000520 # MOVE R2 R0 ; Get Char out the way +2D200010 # LOADUI R0 16 ; Allocate 16 Bytes +2D0F @malloc # CALLI R15 @malloc ; Get address of new Node +09000320 # SWAP R2 R0 ; Store Pointer in R2 +# ;; Deal with Strings wrapped in "" +A0300022 # CMPSKIP.NE R0 34 +3C00 @Store_String # JUMP @Store_String +# ;; Deal with Strings wrapped in ' +A0300027 # CMPSKIP.NE R0 39 +3C00 @Store_String # JUMP @Store_String +# ;; Everything else is an atom store it +2D0F @Store_Atom # CALLI R15 @Store_Atom +:Tokenize_Line_Done +09000512 # MOVE R1 R2 ; Put Node pointer we are working on into R1 +0900040D # COPY R0 R13 ; Get current HEAD +2D0F @Add_Token # CALLI R15 @Add_Token ; Append new token to Head +# ;; Restore registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +# ;; Return since we are done +0D01001F # RET R15 + + +# ;; Purge_Line_Comment Function +# ;; Recieves char in R0 and desired input in R1 +# ;; Modifies R0 +# ;; Returns to Tokenize_Line as if the entire line +# ;; Comment never existed +:Purge_Line_Comment +42100100 # FGETC ; Get another Char +A020000a # CMPSKIP.E R0 10 ; Stop When LF is reached +3C00 @Purge_Line_Comment # JUMP @Purge_Line_Comment ; Otherwise keep looping +3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Return as if this never happened + + +# ;; Store_String function +# ;; Recieves Char in R0, desired input in R1 +# ;; And node pointer in R2 +# ;; Modifies node Text to point to string and sets +# ;; Type to string. +:Store_String +# ;; Preserve registers +0902004F # PUSHR R4 R15 +0902005F # PUSHR R5 R15 +0902006F # PUSHR R6 R15 +# ;; Initialize +09000560 # MOVE R6 R0 ; Get R0 out of the way +2D0F @malloc # CALLI R15 @malloc ; Get where space is free +09000540 # MOVE R4 R0 ; Put pointer someplace safe +0D000025 # FALSE R5 ; Start at index 0 +09000406 # COPY R0 R6 ; Copy Char back into R0 +# ;; Primary Loop +:Store_String_0 +05049045 # STOREX8 R0 R4 R5 ; Store the Byte +42100100 # FGETC ; Get next Byte +0F550001 # ADDUI R5 R5 1 ; Prep for next loop +C306 @Store_String_0 # CMPJUMP.NE R0 R6 @Store_String_0 ; Loop if matching not found +# ;; Clean up +23420008 # STORE32 R4 R2 8 ; Set Text pointer +0F050004 # ADDUI R0 R5 4 ; Correct Malloc +2D0F @malloc # CALLI R15 @malloc ; To the amount of space used +2D200002 # LOADUI R0 2 ; Using type string +23020004 # STORE32 R0 R2 4 ; Set node type +# ;; Restore Registers +0902806F # POPR R6 R15 +0902805F # POPR R5 R15 +0902804F # POPR R4 R15 +3C00 @Tokenize_Line_Done # JUMP @Tokenize_Line_Done + + +# ;; Store_Atom function +# ;; Recieves Char in R0, desired input in R1 +# ;; And node pointer in R2 +# ;; Modifies node Text to point to string +:Store_Atom +# ;; Preserve registers +0902004F # PUSHR R4 R15 +0902005F # PUSHR R5 R15 +# ;; Initialize +09000550 # MOVE R5 R0 ; Get R0 out of the way +2D0F @malloc # CALLI R15 @malloc ; Get where space is free +09000540 # MOVE R4 R0 ; Put pointer someplace safe +09000505 # MOVE R0 R5 ; Copy Char back and Set index to 0 +# ;; Primary Loop +:Store_Atom_0 +05049045 # STOREX8 R0 R4 R5 ; Store the Byte +42100100 # FGETC ; Get next Byte +0F550001 # ADDUI R5 R5 1 ; Prep for next loop +A0300009 # CMPSKIP.NE R0 9 ; If char is Tab +3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done +A030000a # CMPSKIP.NE R0 10 ; If char is LF +3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done +A0300020 # CMPSKIP.NE R0 32 ; If char is Space +3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done +# ;; Otherwise loop +3C00 @Store_Atom_0 # JUMP @Store_Atom_0 +:Store_Atom_Done +# ;; Cleanup +23420008 # STORE32 R4 R2 8 ; Set Text pointer +0F050001 # ADDUI R0 R5 1 ; Correct Malloc +2D0F @malloc # CALLI R15 @malloc ; To the amount of space used +# ;; Restore Registers +0902805F # POPR R5 R15 +0902804F # POPR R4 R15 +0D01001F # RET R15 + + +# ;; Add_Token Function +# ;; Recieves pointers in R0 R1 +# ;; Alters R13 if R) is NULL +# ;; Appends nodes together +# ;; Returns to whatever called it +:Add_Token +# ;; Preserve Registers +0902002F # PUSHR R2 R15 +0902001F # PUSHR R1 R15 +0902000F # PUSHR R0 R15 +# ;; Handle if Head is NULL +2CA0 @Add_Token_0 # JUMP.NZ R0 @Add_Token_0 +090004D1 # COPY R13 R1 ; Fix head +0902800F # POPR R0 R15 ; Clean up register +0902001F # PUSHR R1 R15 ; And act like we passed the reverse +3C00 @Add_Token_2 # JUMP @Add_Token_2 +:Add_Token_0 +# ;; Handle if Head->next is NULL +18200000 # LOAD32 R2 R0 0 +2CA2 @Add_Token_1 # JUMP.NZ R2 @Add_Token_1 +# ;; Set head->next = p +23100000 # STORE32 R1 R0 0 +3C00 @Add_Token_2 # JUMP @Add_Token_2 +:Add_Token_1 +# ;; Handle case of Head->next not being NULL +18000000 # LOAD32 R0 R0 0 ; Move to next node +18200000 # LOAD32 R2 R0 0 ; Get node->next +A0220000 # CMPSKIP.E R2 0 ; If it is not null +3C00 @Add_Token_1 # JUMP @Add_Token_1 ; Move to the next node and try again +3C00 @Add_Token_0 # JUMP @Add_Token_0 ; Else simply act as if we got this node +# ; in the first place +:Add_Token_2 +# ;; Restore registers +0902800F # POPR R0 R15 +0902801F # POPR R1 R15 +0902802F # POPR R2 R15 +0D01001F # RET R15 + + +# ;; strcmp function +# ;; Recieves pointers to null terminated strings +# ;; In R0 and R1 +# ;; Returns if they are equal in R0 +# ;; Returns to whatever called it +:strcmp +# ;; Preserve registers +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Setup registers +09000520 # MOVE R2 R0 ; Put R0 in a safe place +09000531 # MOVE R3 R1 ; Put R1 in a safe place +2D240000 # LOADUI R4 0 ; Starting at index 0 +:cmpbyte +0503A024 # LOADXU8 R0 R2 R4 ; Get a byte of our first string +0503A134 # LOADXU8 R1 R3 R4 ; Get a byte of our second string +0F440001 # ADDUI R4 R4 1 ; Prep for next loop +05004101 # CMP R1 R0 R1 ; Compare the bytes +A0200000 # CMPSKIP.E R0 0 ; Stop if byte is NULL +2C51 @cmpbyte # JUMP.E R1 @cmpbyte ; Loop if bytes are equal +# ;; Done +09000501 # MOVE R0 R1 ; Prepare for return +# ;; Restore registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0D01001F # RET R15 + + +# ;; Identify_Macros Function +# ;; Recieves a pointer to a node in R0 +# ;; If the text stored in its Text segment matches +# ;; DEFINE, flag it and Collapse it down to a single Node +# ;; Loop until all nodes are checked +# ;; Return to whatever called it +:Identify_Macros +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +# ;; Main Loop +:Identify_Macros_0 +09000520 # MOVE R2 R0 +18120008 # LOAD32 R1 R2 8 ; Get Pointer to Text +2D20 $Identify_Macros_string # LOADUI R0 $Identify_Macros_string +2D0F @strcmp # CALLI R15 @strcmp +09000512 # MOVE R1 R2 +2C60 @Identify_Macros_1 # JUMP.NE R0 @Identify_Macros_1 +# ;; It is a definition +# ;; Set p->Type = macro +2D200001 # LOADUI R0 1 ; The Enum value for macro +23010004 # STORE32 R0 R1 4 ; Set node type +# ;; Set p->Text = p->Next->Text +18210000 # LOAD32 R2 R1 0 ; Get Next +18020008 # LOAD32 R0 R2 8 ; Get Next->Text +23010008 # STORE32 R0 R1 8 ; Set Text = Next->Text +# ;; Set p->Expression = p->next->next->Text +18220000 # LOAD32 R2 R2 0 ; Get Next->Next +18020008 # LOAD32 R0 R2 8 ; Get Next->Next->Text +18320004 # LOAD32 R3 R2 4 ; Get Next->Next->type +A0330002 # CMPSKIP.NE R3 2 ; If node is a string +0F000001 # ADDUI R0 R0 1 ; Skip first char +2301000c # STORE32 R0 R1 12 ; Set Expression = Next->Next->Text +# ;; Set p->Next = p->Next->Next->Next +18020000 # LOAD32 R0 R2 0 ; Get Next->Next->Next +23010000 # STORE32 R0 R1 0 ; Set Next = Next->Next->Next +:Identify_Macros_1 +18010000 # LOAD32 R0 R1 0 ; Get node->next +A0300000 # CMPSKIP.NE R0 0 ; If node->next is NULL +3C00 @Identify_Macros_Done # JUMP @Identify_Macros_Done ; Be done +# ;; Otherwise keep looping +3C00 @Identify_Macros_0 # JUMP @Identify_Macros_0 +:Identify_Macros_Done +# ;; Restore registers +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 +:Identify_Macros_string +444546494E450000 # "DEFINE" + + +# ;; Line_Macro Function +# ;; Recieves a node pointer in R0 +# ;; Causes macros to be applied +# ;; Returns to whatever called it +:Line_Macro +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +# ;; Main loop +:Line_Macro_0 +18300004 # LOAD32 R3 R0 4 ; Load Node type +1820000c # LOAD32 R2 R0 12 ; Load Expression pointer +18100008 # LOAD32 R1 R0 8 ; Load Text pointer +18000000 # LOAD32 R0 R0 0 ; Load Next pointer +A0330001 # CMPSKIP.NE R3 1 ; If a macro +2D0F @setExpression # CALLI R15 @setExpression ; Apply to other nodes +A0200000 # CMPSKIP.E R0 0 ; If Next is Null +3C00 @Line_Macro_0 # JUMP @Line_Macro_0 ; Don't loop +# ;; Clean up +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; setExpression Function +# ;; Recieves a node pointer in R0 +# ;; A string pointer to compare against in R1 +# ;; A string pointer for replacement in R2 +# ;; Doesn't modify any registers +# ;; Returns to whatever called it +:setExpression +# ;; Preserve registers +0902000F # PUSHR R0 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +0902005F # PUSHR R5 R15 +# ;; Initialize +09000541 # MOVE R4 R1 ; Put Macro Text in a safe place +09000450 # COPY R5 R0 ; Use R5 for Node pointer +:setExpression_0 +18350004 # LOAD32 R3 R5 4 ; Load type into R3 +A0330001 # CMPSKIP.NE R3 1 ; Check if Macro +3C00 @setExpression_1 # JUMP @setExpression_1 ; Move to next if Macro +18050008 # LOAD32 R0 R5 8 ; Load Text pointer into R0 for Comparision +09000414 # COPY R1 R4 ; Put Macro Text for comparision +2D0F @strcmp # CALLI R15 @strcmp ; compare Text and Macro Text +2C60 @setExpression_1 # JUMP.NE R0 @setExpression_1 ; Move to next if not Match +2325000c # STORE32 R2 R5 12 ; Set node->Expression = Exp +:setExpression_1 +18550000 # LOAD32 R5 R5 0 ; Load Next +2CA5 @setExpression_0 # JUMP.NZ R5 @setExpression_0 ; Loop if next isn't NULL +:setExpression_Done +# ;; Restore registers +0902805F # POPR R5 R15 +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; Process_String Function +# ;; Recieves a Node in R0 +# ;; Doesn't modify registers +# ;; Returns back to whatever called it +:Process_String +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +:Process_String_0 +# ;; Get node type +18100004 # LOAD32 R1 R0 4 ; Load Type +A0210002 # CMPSKIP.E R1 2 ; If not a string +3C00 @Process_String_Done # JUMP @Process_String_Done ; Just go to next +# ;; Its a string +18100008 # LOAD32 R1 R0 8 ; Get Text pointer +14210000 # LOAD8 R2 R1 0 ; Get first char of Text +# ;; Deal with ' +A0220027 # CMPSKIP.E R2 39 ; If char is not ' +3C00 @Process_String_1 # JUMP @Process_String_1 ; Move to next label +# ;; Simply use Hex strings as is +0F110001 # ADDUI R1 R1 1 ; Move Text pointer by 1 +2310000c # STORE32 R1 R0 12 ; Set expression to Text + 1 +3C00 @Process_String_Done # JUMP @Process_String_Done ; And move on +:Process_String_1 +# ;; Deal with "" +2D0F @Hexify_String # CALLI R15 @Hexify_String +:Process_String_Done +18000000 # LOAD32 R0 R0 0 ; Load Next +A0200000 # CMPSKIP.E R0 0 ; If Next isn't NULL +3C00 @Process_String_0 # JUMP @Process_String_0 ; Recurse down list +# ;; Restore registers +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; Hexify_String Function +# ;; Recieves a node pointer in R0 +# ;; Converts Quoted text to Hex values +# ;; Pads values up to multiple of 4 bytes +# ;; Doesn't modify registers +# ;; Returns to whatever called it +:Hexify_String +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +09000520 # MOVE R2 R0 ; Move R0 out of the way +2D0F @malloc # CALLI R15 @malloc ; Get address of new Node +09000510 # MOVE R1 R0 ; Prep For Hex32 +2312000c # STORE32 R1 R2 12 ; Set node expression pointer +18220008 # LOAD32 R2 R2 8 ; Load Text pointer into R2 +0F220001 # ADDUI R2 R2 1 ; SKip leading "" +0D000024 # FALSE R4 ; Set counter for malloc to Zero +# ;; Main Loop +:Hexify_String_0 +18020000 # LOAD32 R0 R2 0 ; Load 4 bytes into R0 from Text +B03000ff # ANDI R3 R0 0xFF ; Preserve byte to check for NULL +2D0F @hex32 # CALLI R15 @hex32 ; Convert to hex and store in Expression +0F220004 # ADDUI R2 R2 4 ; Pointer Text pointer to next 4 bytes +0F440008 # ADDUI R4 R4 8 ; Increment storage space required +A0230000 # CMPSKIP.E R3 0 ; If byte was NULL +3C00 @Hexify_String_0 # JUMP @Hexify_String_0 +# ;; Done +0F040001 # ADDUI R0 R4 1 ; Lead space for NULL terminator +2D0F @malloc # CALLI R15 @malloc ; Correct malloc value +# ;; Restore Registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; hex32 functionality +# ;; Accepts 32bit value in R0 +# ;; Require R1 to be a pointer to place to store hex16 +# ;; WILL ALTER R1 ! +# ;; Returns to whatever called it +:hex32 +0902000F # PUSHR R0 R15 +2D600010 # SR0I R0 16 ; Do high word first +2D0F @hex16 # CALLI R15 @hex16 +0902800F # POPR R0 R15 +:hex16 +0902000F # PUSHR R0 R15 +2D600008 # SR0I R0 8 ; Do high byte first +2D0F @hex8 # CALLI R15 @hex8 +0902800F # POPR R0 R15 +:hex8 +0902000F # PUSHR R0 R15 +2D600004 # SR0I R0 4 ; Do high nybble first +2D0F @hex4 # CALLI R15 @hex4 +0902800F # POPR R0 R15 +:hex4 +B000000f # ANDI R0 R0 0x000F ; isolate nybble +0F000030 # ADDUI R0 R0 48 ; convert to ascii +A0400039 # CMPSKIP.LE R0 57 ; If nybble was greater than '9' +0F000007 # ADDUI R0 R0 7 ; Shift it into 'A' range of ascii +21010000 # STORE8 R0 R1 0 ; Store Hex Char +0F110001 # ADDUI R1 R1 1 ; Increment address pointer +0D01001F # RET R15 ; Get next nybble or return if done + + +# ;; Eval_Immediates function +# ;; Recieves a node in R0 +# ;; Converts number into Hex +# ;; And write into Memory and fix pointer +:Eval_Immediates +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +0902005F # PUSHR R5 R15 +0902006F # PUSHR R6 R15 +# ;; Initialize +0900040D # COPY R0 R13 ; Start with Head +0D000025 # FALSE R5 ; Zero for checking return of numerate_string +# ;; Process Text +:Eval_Immediates_0 +09000460 # COPY R6 R0 ; Safely preserve pointer to node +18400000 # LOAD32 R4 R0 0 ; Load Node->Next +18300004 # LOAD32 R3 R0 4 ; Load Node type +1820000c # LOAD32 R2 R0 12 ; Load Expression pointer +18100008 # LOAD32 R1 R0 8 ; Load Text pointer +2CA2 @Eval_Immediates_1 # JUMP.NZ R2 @Eval_Immediates_1 ; Don't do anything if Expression is set +2CA3 @Eval_Immediates_1 # JUMP.NZ R3 @Eval_Immediates_1 ; Don't do anything if Typed +09000401 # COPY R0 R1 ; Put Text pointer into R0 +2D0F @numerate_string # CALLI R15 @numerate_string ; Convert to number in R0 +14110000 # LOAD8 R1 R1 0 ; Get first char of Text +A0210030 # CMPSKIP.E R1 48 ; Skip next comparision if '0' +C205 @Eval_Immediates_1 # CMPJUMP.E R0 R5 @Eval_Immediates_1 ; Don't do anything if string isn't a number +09000510 # MOVE R1 R0 ; Preserve number +2D200005 # LOADUI R0 5 ; Allocate enough space for 4 hex and a null +2D0F @malloc # CALLI R15 @malloc ; Obtain the pointer the newly allocated Expression +2006000c # STORE R0 R6 12 ; Preserve pointer to expression +09000301 # SWAP R0 R1 ; Fix order for call to hex16 +2D0F @hex16 # CALLI R15 @hex16 ; Shove our number into expression +# ;; Handle looping +:Eval_Immediates_1 +C245 @Eval_Immediates_2 # CMPJUMP.E R4 R5 @Eval_Immediates_2 ; If null be done +09000504 # MOVE R0 R4 ; Prepare for next loop +3C00 @Eval_Immediates_0 # JUMP @Eval_Immediates_0 ; And loop +# ;; Clean up +:Eval_Immediates_2 +# ;; Restore Registers +0902806F # POPR R6 R15 +0902805F # POPR R5 R15 +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; numerate_string function +# ;; Recieves 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 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +09000510 # MOVE R1 R0 ; Get Text pointer out of the way +0D000022 # FALSE R2 ; Set Negative flag to false +0D000023 # FALSE R3 ; Set current count to Zero +14010001 # LOAD8 R0 R1 1 ; Get second byte +A0300078 # CMPSKIP.NE R0 120 ; If the second byte is x +3C00 @numerate_string_hex # JUMP @numerate_string_hex ; treat string like hex +# ;; Deal with Decimal input +2D24000a # LOADUI R4 10 ; Multiply by 10 +14010000 # LOAD8 R0 R1 0 ; Get a byte +A030002d # CMPSKIP.NE R0 45 ; If - toggle flag +0D000032 # TRUE R2 ; So that we know to negate +A0220000 # CMPSKIP.E R2 0 ; If toggled +0F110001 # ADDUI R1 R1 1 ; Move to next +:numerate_string_dec +14010000 # LOAD8 R0 R1 0 ; Get a byte +A0300000 # CMPSKIP.NE R0 0 ; If NULL +3C00 @numerate_string_done # JUMP @numerate_string_done ; Be done +05006334 # MUL R3 R3 R4 ; Shift counter by 10 +10000030 # SUBI R0 R0 48 ; Convert ascii to number +A0100000 # CMPSKIP.GE R0 0 ; If less than a number +3C00 @numerate_string_done # JUMP @numerate_string_done ; Terminate NOW +A050000a # CMPSKIP.L R0 10 ; If more than a number +3C00 @numerate_string_done # JUMP @numerate_string_done ; Terminate NOW +05001330 # ADDU R3 R3 R0 ; Don't add to the count +0F110001 # ADDUI R1 R1 1 ; Move onto next byte +3C00 @numerate_string_dec # JUMP @numerate_string_dec +# ;; Deal with Hex input +:numerate_string_hex +14010000 # LOAD8 R0 R1 0 ; Get a byte +A0200030 # CMPSKIP.E R0 48 ; All hex strings start with 0x +3C00 @numerate_string_done # JUMP @numerate_string_done ; Be done if not a match +0F110002 # ADDUI R1 R1 2 ; Move to after leading 0x +:numerate_string_hex_0 +14010000 # LOAD8 R0 R1 0 ; Get a byte +A0300000 # CMPSKIP.NE R0 0 ; If NULL +3C00 @numerate_string_done # JUMP @numerate_string_done ; Be done +2D530004 # SL0I R3 4 ; Shift counter by 16 +10000030 # SUBI R0 R0 48 ; Convert ascii number to number +A050000a # CMPSKIP.L R0 10 ; If A-F +10000007 # SUBI R0 R0 7 ; Shove into Range +A0500010 # CMPSKIP.L R0 16 ; If a-f +10000020 # SUBI R0 R0 32 ; Shove into Range +05001330 # ADDU R3 R3 R0 ; Add to the count +0F110001 # ADDUI R1 R1 1 ; Get next Hex +3C00 @numerate_string_hex_0 # JUMP @numerate_string_hex_0 +# ;; Clean up +:numerate_string_done +A0220000 # CMPSKIP.E R2 0 ; If Negate flag has been set +09000033 # NEG R3 R3 ; Make the number negative +09000503 # MOVE R0 R3 ; Put number in R0 +# ;; Restore Registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0D01001F # RET R15 + + +# ;; Preserve_Other function +# ;; Sets Expression pointer to Text pointer value +# ;; For all unset nodes +:Preserve_Other +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +0900040D # COPY R0 R13 ; Start with HEAD +# ;; Process Node +:Preserve_Other_0 +18400000 # LOAD32 R4 R0 0 ; Load Node->Next +18300004 # LOAD32 R3 R0 4 ; Load Node type +1820000c # LOAD32 R2 R0 12 ; Load Expression pointer +18100008 # LOAD32 R1 R0 8 ; Load Text pointer +2CA2 @Preserve_Other_1 # JUMP.NZ R2 @Preserve_Other_1 ; Don't do anything if Expression is set +2CA3 @Preserve_Other_1 # JUMP.NZ R3 @Preserve_Other_1 ; Don't do anything if Typed +2310000c # STORE32 R1 R0 12 ; Set Expression pointer to Text pointer +# ;; Loop through nodes +:Preserve_Other_1 +09000504 # MOVE R0 R4 ; Prepare for next loop +2CA0 @Preserve_Other_0 # JUMP.NZ R0 @Preserve_Other_0 +# ;; Clean up +:Preserve_Other_Done +# ;; Restore Registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; Print_Hex Function +# ;; Print all of the expressions +# ;; Starting with HEAD +:Print_Hex +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +0900040D # COPY R0 R13 ; Start with HEAD +:Print_Hex_0 +18200000 # LOAD32 R2 R0 0 ; Load Node->Next +18100004 # LOAD32 R1 R0 4 ; Load Node type +1800000c # LOAD32 R0 R0 12 ; Load Expression pointer +10110001 # SUBI R1 R1 1 ; Check for Macros +2C91 @Print_Hex_1 # JUMP.Z R1 @Print_Hex_1 ; Don't print Macros +2D211101 # LOADUI R1 0x1101 ; Write to Tape_02 +2D0F @Print_Line # CALLI R15 @Print_Line ; Print the Expression +# ;; Loop down the nodes +:Print_Hex_1 +09000502 # MOVE R0 R2 ; Prepare for next loop +2CA0 @Print_Hex_0 # JUMP.NZ R0 @Print_Hex_0 ; Keep looping if not NULL +# ;; Clean up +:Print_Hex_Done +# ;; Restore Registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + + +# ;; Print_Line Function +# ;; Receives a pointer to a string in R0 +# ;; And an interface in R1 +# ;; Writes all Chars in string +# ;; Then writes a New line character to interface +:Print_Line +# ;; Preserve Registers +0902000F # PUSHR R0 R15 +0902001F # PUSHR R1 R15 +0902002F # PUSHR R2 R15 +0902003F # PUSHR R3 R15 +0902004F # PUSHR R4 R15 +# ;; Initialize +09000530 # MOVE R3 R0 ; Get Pointer safely out of the way +0D000024 # FALSE R4 ; Start index at 0 +:Print_Line_0 +0503A034 # LOADXU8 R0 R3 R4 ; Get our first byte +A0300000 # CMPSKIP.NE R0 0 ; If the loaded byte is NULL +3C00 @Print_Line_Done # JUMP @Print_Line_Done ; Be done +42100200 # FPUTC ; Otherwise print +0F440001 # ADDUI R4 R4 1 ; Increment for next loop +3C00 @Print_Line_0 # JUMP @Print_Line_0 ; And Loop +# ;; Clean up +:Print_Line_Done +2D20000a # LOADUI R0 10 ; Put in Newline char +42100200 # FPUTC ; Write it out +# ;; Restore Registers +0902804F # POPR R4 R15 +0902803F # POPR R3 R15 +0902802F # POPR R2 R15 +0902801F # POPR R1 R15 +0902800F # POPR R0 R15 +0D01001F # RET R15 + +# ;; Where we are putting the start of our stack +:stack