Updated hex2 to improve performance and reduce size

This commit is contained in:
Jeremiah Orians 2017-12-24 17:17:37 -05:00
parent 21239523bd
commit deac93c6f2
No known key found for this signature in database
GPG Key ID: 7457821534D2ACCD
8 changed files with 345 additions and 1490 deletions

View File

@ -23,6 +23,7 @@ Added program to search for unusual characters that are not human detectable
Expanded stage0 web IDE to include the PC and instruction counter
Performance tuned hex1 to reduce both size and instruction count
Performance tuned hex0 to reduce both size and instruction count
Performance tuned hex2 to reduce both size and isntruction count
** Fixed
Fixed behavior of R@ thanks to reepca
@ -35,6 +36,8 @@ Updated checksums to reflect changed made in performance tuning
** Removed
Removed stage1_assembler-0's need for Memory and reduced size of program while at it
Removed stage1_assembler-1's hex1 implementation as it ended up being useless in bootstrapping
Removed stage1_assembler-2's hex0 and hex2 implementation as it ended up being useless in bootstrapping
Removed Checksums.org as it didn't really end up as useful at this time.
* 0.0.9 - 2017-08-17
** Added

View File

@ -1,50 +0,0 @@
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you an 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/>.
* x86
** stage0
| Filename | compiled binary sha256sum | compiled binary sha1sum | compiled binary md5sum |
|--------------------+------------------------------------------------------------------+------------------------------------------+----------------------------------|
| stage0_monitor.hex | 045ef96e1c8fb011cba89f268f823c06b21f91270fb9afb0af42a1ac8c3ee44b | b26c72762d2f77d8634cb532d581c1e76adceb3f | 9e29544f0220636437741cb5092cc411 |
** stage1
| Filename | compiled binary sha256sum | compiled binary sha1sum | compiled binary md5sum |
|-------------------+------------------------------------------------------------------+------------------------------------------+----------------------------------|
| stage1_loader.hex | 047a40efd79a2e1ce06124b9973c0db840cbb39b618dd4cc77036b0ddd54d0d5 | 0f5a2e0ff85cd7bca251e02a44bb5cca6453007a | e095a7a28c7e50c89b0c3edb0d4d97ae |
* Knight
** stage0
| Filename | compiled binary sha256sum | compiled binary sha1sum | compiled binary md5sum |
|---------------------+------------------------------------------------------------------+------------------------------------------+----------------------------------|
| stage0_monitor.hex0 | 0a427b14020354d1c785f5f900677e0059fce8f8d4456e9c19e5528cb17101eb | 1365da633f268f551424c621535bd94cfc6bf85b | f0890d7a69ed38f1fc5aa79d6f35c095 |
** stage1
| Filename | compiled binary sha256sum | compiled binary sha1sum | compiled binary md5sum |
|-------------------------+------------------------------------------------------------------+------------------------------------------+----------------------------------|
| stage1_assembler-0.hex0 | f8289dfa9dd92e8a1a48f9a624d5d19e4f312b91bc3d1e0796474b46157ec47a | 10b1490182ba3122cd80b1afe9ca11dfa71f2ce4 | a6e0f5348dbb9b049c65b467cf6033e4 |
| stage1_assembler-1.hex0 | e4f0ed6e78ae79bb5e4a4fbde36f085dd0469cd6ae036dce5953b3d1c89801ce | 358a22c6996808ef44a9596ce714970837b53379 | 5c26294c7c59b250fd00d5c3559e68d8 |
| stage1_assembler-1.hex1 | e4f0ed6e78ae79bb5e4a4fbde36f085dd0469cd6ae036dce5953b3d1c89801ce | 358a22c6996808ef44a9596ce714970837b53379 | 5c26294c7c59b250fd00d5c3559e68d8 |
| stage1_assembler-2.hex1 | 61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99 | 5d43563ee2297cea95a2117817c5e68b8a9c60d6 | c608fbb896b9931b90e86fe32996ccd8 |
| stage1_assembler-2.hex2 | 61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99 | 5d43563ee2297cea95a2117817c5e68b8a9c60d6 | c608fbb896b9931b90e86fe32996ccd8 |
| Filename | Compiled by | Number of instructions Executed |
| stage1_assembler-0.hex0 | stage1_assembler-0 | 28430 |
| stage1_assembler-1.hex0 | stage1_assembler-0 | 62292 |
| stage1_assembler-1.hex0 | stage1_assembler-1 | 125636 |
| stage1_assembler-1.hex1 | stage1_assembler-1 | 122210 |
| stage1_assembler-2.hex0 | stage1_assembler-0 | 144173 |
| stage1_assembler-2.hex1 | stage1_assembler-1 | 283432 |
| stage1_assembler-2.hex2 | stage1_assembler-2 | 278186 |

View File

@ -104,7 +104,7 @@ To build our last and greatest Hex assembler:
./bin/vm --rom roms/stage1_assembler-1 --tape_01 stage1/stage1_assembler-2.hex1 --tape_02 roms/stage1_assembler-2
Now tape_02 contains the last hex assembler we will need
roms/stage1_assembler-2 should have the sha256sum of 61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99
roms/stage1_assembler-2 should have the sha256sum of 7b02babee42a3c05b001fb44fb0917383d8f185e2817d57ad2349a4b36dfa4ed
* Step 5 Lets get us a line macro assembler
I don't know about you but at this point, I don't wanna convert another instruction into HEX by hand, so to save myself the pain we are going to write the most often ignored but important development in computer programming. The LINE MACRO ASSEMBLER.

View File

@ -1,512 +0,0 @@
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you an 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
2D2D040c # LOADUI R13 @table ; Where we are putting our table
# ;; We will be using R14 for our condition codes
2D2F7fff # LOADUI R15 0x7FFF ; We will be using R15 for our stack
# ;; Main program functionality
# ;; Reads in Tape_01 and writes out results onto Tape_02
# ;; Accepts no arguments and HALTS when done
# :main
# ;; Prep TAPE_01
2D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
# ;; Intialize environment
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
# ;; Perform first pass
2D0F0040 # CALLI R15 @first_pass
# ;; We need to rewind tape_01 to perform our second pass
2D201100 # LOADUI R0 0x1100
42100003 # REWIND
# ;; Reintialize environment
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
2D2900ff # LOADUI R9 0xFF ; Byte mask
2D28000f # LOADUI R8 0x0F ; nybble mask
# ;; Prep TAPE_02
2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
2D0F006c # CALLI R15 @second_pass
# ;; Close up as we are done
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
2D201101 # LOADUI R0 0x1101 ; Close TAPE_02
42100002 # FCLOSE
FFFFFFFF # HALT
# ;; First pass function
# ;; Reads Tape_01 and creates our label table
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
# :first_pass
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label (:)
A030003a # CMPSKIPI.NE R0 58
3C0000ac # JUMP @storeLabel
# ;; Check for and deal with pointers to labels
# ;; Starting with (@)
A0300040 # CMPSKIPI.NE R0 64
3C000298 # JUMP @ThrowAwayPointer
# ;; Then dealing with ($)
A0300024 # CMPSKIPI.NE R0 36
3C000290 # JUMP @ThrowAwayPointer
# ;; Now check for absolute addresses (&)
A0300026 # CMPSKIPI.NE R0 38
3C000294 # JUMP @ThrowAwayAddress
# ;; Otherwise attempt to process
2D0F02c8 # CALLI R15 @hex ; Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00ffc8 # JUMP @first_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A000c # JUMP.Z R10 @first_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
0D00002A # FALSE R10 ; Flip the toggle
3C00ffbc # JUMP @first_pass
# :first_pass_0
# ;; Deal with case of second half of byte
0D00003A # TRUE R10 ; Flip the toggle
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00ffb0 # JUMP @first_pass
# ;; Second pass function
# ;; Reads from Tape_01 and uses the values in the table
# ;; To write desired contents onto Tape_02
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
# :second_pass
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label
A030003a # CMPSKIPI.NE R0 58
3C000264 # JUMP @ThrowAwayLabel
# ;; Check for and deal with Pointers to labels
A0300040 # CMPSKIPI.NE R0 64 ; @ for relative
3C000078 # JUMP @StoreRelativePointer
A0300024 # CMPSKIPI.NE R0 36 ; $ for absolute
3C000098 # JUMP @StoreAbsolutePointer
A0300026 # CMPSKIPI.NE R0 38 ; & for address
3C0000b0 # JUMP @StoreAbsoluteAddress
# ;; Process everything else
2D0F0274 # CALLI R15 @hex ; Attempt to Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00ffc8 # JUMP @second_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A0010 # JUMP.Z R10 @second_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
05020C08 # AND R12 R0 R8 ; Store our first nibble
0D00002A # FALSE R10 ; Flip the toggle
3C00ffb8 # JUMP @second_pass
# :second_pass_0
# ;; Deal with case of second half of byte
2D5C0004 # SL0I R12 4 ; Shift our first nybble
05020008 # AND R0 R0 R8 ; Mask out top
0500000C # ADD R0 R0 R12 ; Combine nybbles
0D00003A # TRUE R10 ; Flip the toggle
2D211101 # LOADUI R1 0x1101 ; Write the combined byte
42100200 # FPUTC ; To TAPE_02
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00ff98 # JUMP @second_pass
# ;; Store Label function
# ;; Writes out the token and the current PC value
# ;; Its static variable for storing the next index to be used
# ;; Will overwrite R0
# ;; Returns to first pass when done
# :storeLabel
2E000024 # LOADR R0 @current_index ; Get address of first open index
A0300000 # CMPSKIPI.NE R0 0 ; If zero intialize from R13
0900040D # COPY R0 R13
# ;; Store the PC of the label
23B00000 # STORE32 R11 R0 0
# ;; Store the name of the Label
0F000004 # ADDUI R0 R0 4 ; Increment the offset of the index
2D0F0098 # CALLI R15 @writeout_token
# ;; Update our index
0F00003c # ADDUI R0 R0 60 ; Hopefully our tokens are less than 60 bytes long
2F000008 # STORER R0 @current_index
# ;; And be done
3C00ff20 # JUMP @first_pass
# ;; Where we are storing the location of the next free table entry
# :current_index
00000000 # NOP
# ;; StoreRelativepointer function
# ;; Deals with the special case of relative pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the offset
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
# :StoreRelativePointer
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D2003cc # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F00c8 # CALLI R15 @Clear_string ; Clear it
2D0F0078 # CALLI R15 @writeout_token ; Write it
2D0F0100 # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
0500200B # SUB R0 R0 R11 ; Determine the difference
0F000004 # ADDUI R0 R0 4 ; Adjust for relative positioning
2D0F0170 # CALLI R15 @ProcessImmediate ; Write out the value
3C00ff48 # JUMP @second_pass
# ;; StoreAbsolutepointer function
# ;; Deals with the special case of absolute pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the absolute address of match
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
# :StoreAbsolutePointer
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D2003cc # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F00a0 # CALLI R15 @Clear_string ; Clear it
2D0F0050 # CALLI R15 @writeout_token ; Write it
2D0F00d8 # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
2D0F0150 # CALLI R15 @ProcessImmediate ; Write out the value
3C00ff28 # JUMP @second_pass
# ;; StoreAbsoluteAddress function
# ;; Deal with the special case of absolute Addresses
# ;; Clear Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the full absolute address [32 bit machine]
# ;; Modifies R0 R11
# ;; Jumpbacs back into Pass2
# :StoreAbsoluteAddress
# ;; COrrect the PC to reflect the size of the address
0FBB0004 # ADDUI R11 R11 4 ; 4 Bytes on 32bit machines
2D2003cc # LOADUI R0 $Temp ; Set where we ant to shove our string
2D0F0080 # CALLI R15 @Clear_string ; Clear it
2D0F0030 # CALLI R15 @writeout_token ; Write it
2D0F00b8 # CALLI R15 @Match_string ; Find the Match
090200EF # PUSHR R14 R15 ; Get a temp storage place
18E0fffc # LOAD32 R14 R0 -4 ; Get the value we care about
0900040E # COPY R0 R14 ; We need to print the top 2 bytes first
2D400010 # SARI R0 16 ; Drop bottom 16 bits
2D0F0124 # CALLI R15 @ProcessImmediate ; Write out top 2 bytes
2D20ffff # LOADUI R0 0xFFFF ; Provide mask to keep bottom 2 bytes
0502000E # AND R0 R0 R14 ; Drop top 16 bits
090280EF # POPR R14 R15 ; Restore R14
2D0F0114 # CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
3C00feec # JUMP @second_pass
# ;; Writeout Token Function
# ;; Writes the Token [minus first char] to the address
# ;; It recieves in R0 until it reaches a delimiter
# ;; All register values are preserved
# ;; Returns to whatever called it
# :writeout_token
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize
09000520 # MOVE R2 R0 ; Set R2 as our index
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
# ;; Our core loop
# :writeout_token_0
42100100 # FGETC ; Get another byte
# ;; Deal with termination cases
A0300020 # CMPSKIPI.NE R0 32 ; Finished if space
3C000020 # JUMP @writeout_token_done
A0300009 # CMPSKIPI.NE R0 9 ; Finished if tab
3C000018 # JUMP @writeout_token_done
A030000a # CMPSKIPI.NE R0 10 ; Finished if newline
3C000010 # JUMP @writeout_token_done
# ;; Deal with valid input
21020000 # STORE8 R0 R2 0 ; Write out the byte
0F220001 # ADDUI R2 R2 1 ; Increment
3C00ffdc # JUMP @writeout_token_0 ; Keep looping
# ;; Clean up now that we are done
# :writeout_token_done
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; And be done
0D01001F # RET R15
# ;; Clear string function
# ;; Clears string pointed at by the value of R0
# ;; Until a null character is reached
# ;; Doesn't alter any registers
# ;; Returns to the function that calls it
# :Clear_string
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
# ;; Setup registers
09000510 # MOVE R1 R0
2D220000 # LOADUI R2 0
2D230000 # LOADUI R3 0
# :clear_byte
0503A012 # LOADXU8 R0 R1 R2 ; Get the byte
05049312 # STOREX8 R3 R1 R2 ; Overwrite with a Zero
0F220001 # ADDUI R2 R2 1 ; Prep for next loop
2CA0fff4 # JUMP.NZ R0 @clear_byte ; Stop if byte is NULL
# ;; Done
# ;; Restore registers
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Match string function
# ;; Walks down table until match is found
# ;; Then returns address of matching string in R0
# ;; Returns to whatever called it
# :Match_string
# ;; Preserve registers
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize for Loop
2D2103cc # LOADUI R1 $Temp ; We always compare against Temp
2D22040c # LOADUI R2 $table ; Begin at start of table
0F220004 # ADDUI R2 R2 4 ; Where the string is located
# ;; Loop until we find a match
# :Match_string_0
09000402 # COPY R0 R2 ; Set R0 to our current string
2D0F0024 # CALLI R15 @strcmp
2C500010 # JUMP.E R0 @Match_string_1 ; It is a match!
# ;; Prepare for next loop
2D2103cc # LOADUI R1 $Temp ; That function clears R1
0F220040 # ADDUI R2 R2 64 ; Each Index is 64 bytes
3C00ffec # JUMP @Match_string_0 ; Keep looping
# :Match_string_1
# ;; Store the correct answer
09000502 # MOVE R0 R2
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0D01001F # RET R15
# ;; Our simple string compare function
# ;; Recieves two pointers in R0 and R1
# ;; Returns the difference between the strings in R0
# ;; Clears R1
# ;; 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
09000531 # MOVE R3 R1
2D240000 # LOADUI R4 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 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
2C51ffec # 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
# ;; Processimmediate Function
# ;; Recieves an integer value in R0
# ;; Writes out the values to Tape_02
# ;; Doesn't modify registers
# ;; Returns to whatever called it
# :ProcessImmediate
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Break up Immediate
05020209 # AND R2 R0 R9 ; Put lower byte in R2
2D400008 # SARI R0 8 ; Drop Bottom byte from R0
05020009 # AND R0 R0 R9 ; Maskout everything outside of top byte
# ;; Write out Top Byte
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Write out bottom Byte
09000502 # MOVE R0 R2 ; Put Lower byte in R0
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; Be Done
0D01001F # RET R15
# ;; ThrowAwaypointer function
# ;; Handle the special case of a generic problem
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, only jump to it
# :ThrowAwayPointer
0FBB0002 # ADDUI R11 R11 2 ; Pointers always take up 2 bytes
2D0F001c # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00fd44 # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwayAddress function
# ;; Handle the case of a 32bit absolute address storage
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, conly jump to it
# :ThrowAwayAddress
0FBB0004 # ADDUI R11 R11 4 ; Addresses on 32bit systems take up 4 bytes
2D0F0010 # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00fd38 # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwaylabel function
# ;; Handle the special case of a generic problem
# ;; for Pass2, Will update R11 and modify R0
# ;; Will return to the start of second_pass
# ;; Never call this function, only jump to it
# :ThrowAwayLabel
2D0F0008 # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00fd84 # JUMP @second_pass
# ;; Throw away token function
# ;; Deals with the general case of not wanting
# ;; The rest of the characters in a token
# ;; This Will alter the values of R0 R1
# ;; Returns back to whatever called it
# :throwAwayToken
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Stop looping if space
A0300020 # CMPSKIPI.NE R0 32
0D01001F # RET R15
# ;; Stop looping if tab
A0300009 # CMPSKIPI.NE R0 9
0D01001F # RET R15
# ;; Stop looping if newline
A030000a # CMPSKIPI.NE R0 10
0D01001F # RET R15
# ;; Otherwise keep looping
3C00ffe0 # JUMP @throwAwayToken
# ;; Hex function
# ;; This function is serving three purposes:
# ;; Identifying hex characters
# ;; Purging line comments
# ;; Returning the converted value of a hex character
# ;; This function will alter the values of R0 R14
# ;; Returns back to whatever called it
# :hex
# ;; Deal with line comments starting with #
1FE00023 # CMPUI R14 R0 35
2C5E0060 # JUMP.E R14 @ascii_comment
# ;; Deal with line comments starting with ;
1FE0003b # CMPUI R14 R0 59
2C5E0058 # JUMP.E R14 @ascii_comment
# ;; Deal with all ascii less than '0'
1FE00030 # CMPUI R14 R0 48
2C8E0048 # JUMP.L R14 @ascii_other
# ;; Deal with '0'-'9'
1FE00039 # CMPUI R14 R0 57
2C7E0028 # JUMP.LE R14 @ascii_num
# ;; Deal with all ascii less than 'A'
1FE00041 # CMPUI R14 R0 65
2C8E0038 # JUMP.L R14 @ascii_other
# ;; Deal with 'A'-'F'
1FE00046 # CMPUI R14 R0 70
2C7E0028 # JUMP.LE R14 @ascii_high
# ;; Deal with all ascii less than 'a'
1FE00061 # CMPUI R14 R0 97
2C8E0028 # JUMP.L R14 @ascii_other
# ;; Deal with 'a'-'f'
1FE00066 # CMPUI R14 R0 102
2C7E0010 # JUMP.LE R14 @ascii_low
# ;; Ignore the rest
3C00001c # JUMP @ascii_other
# :ascii_num
11000030 # SUBUI R0 R0 48
0D01001F # RET R15
# :ascii_low
11000057 # SUBUI R0 R0 87
0D01001F # RET R15
# :ascii_high
11000037 # SUBUI R0 R0 55
0D01001F # RET R15
# :ascii_other
0D000030 # TRUE R0
0D01001F # RET R15
# :ascii_comment
2D211100 # LOADUI R1 0x1100 ; Read from TAPE_01
42100100 # FGETC ; Read another char
1FE0000a # CMPUI R14 R0 10 ; Stop at the end of line
2C6Efff4 # JUMP.NE R14 @ascii_comment ; Otherwise keep looping
3C00ffe8 # JUMP @ascii_other
# ;; Where we are storing our Temp
# :Temp
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
# ;; Where we will putting our Table
# :table

View File

@ -1,7 +1,7 @@
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you an redistribute it and/or modify
## 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.
@ -14,40 +14,65 @@
## You should have received a copy of the GNU General Public License
## along with stage0. If not, see <http://www.gnu.org/licenses/>.
# :start
:0
2D2D @1 # LOADUI R13 @table ; Where we are putting our table
# ;; We will be using R14 for our condition codes
2D2F7fff # LOADUI R15 0x7FFF ; We will be using R15 for our stack
;; Node format:
;; PREV->pointer (register size)
;; Address (register size)
;; NULL terminated string (strln + 1)
# :start 0
:0
# ;; R1 is reserved for reading/writing bytes (don't touch)
# ;; We will be using R8 for our malloc pointer
# ;; We will be using R9 for our header size in bytes
# ;; We will be using R10 for our toggle
# ;; We will be using R11 for our PC counter
# ;; We will be using R12 for holding our nybble
# ;; We will be using R13 for our register size in bytes
# ;; We will be using R14 for our head-node
2D2F @1 # LOADUI R15 $stack ; We will be using R15 for our stack
# ;; Main program functionality
# ;; Reads in Tape_01 and writes out results onto Tape_02
# ;; Accepts no arguments and HALTS when done
# :main
:3
# :main 4
:2
# ;; Initialize header info
0D000010 # READSCID R0 ; Get process capabilities
B010000f # ANDI R1 R0 0xF ; We only care about size nybble
2D200001 # LOADUI R0 1 ; Assume we are 8bit
05032D01 # SL0 R13 R0 R1 ; Let size nybble correct answer
0900049D # COPY R9 R13 ; Prepare Header size
2D590001 # SL0I R9 1 ; Double to make proper size
# ;; Prep TAPE_01
2D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
# ;; Intialize environment
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
0D00002A # FALSE R10 ; Our toggle
2D280500 # LOADUI R8 0x500 ; Where we want our heap to start
# ;; Perform first pass
2D0F @2 # CALLI R15 @first_pass
2D0F @3 # CALLI R15 @first_pass
# ;; We need to rewind tape_01 to perform our second pass
2D201100 # LOADUI R0 0x1100
42100003 # REWIND
# ;; Reintialize environment
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
2D2900ff # LOADUI R9 0xFF ; Byte mask
2D28000f # LOADUI R8 0x0F ; nybble mask
0D00002A # FALSE R10 ; Our toggle
# ;; Prep TAPE_02
2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
2D0F @4 # CALLI R15 @second_pass
# ;; Close up as we are done
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
@ -60,41 +85,42 @@ FFFFFFFF # HALT
# ;; Reads Tape_01 and creates our label table
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
# :first_pass
:2
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
# :first_pass 70
:3
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label (:)
A030003a # CMPSKIPI.NE R0 58
3C00 @5 # JUMP @storeLabel
# ;; Check for and deal with pointers to labels
# ;; Starting with (@)
A0300040 # CMPSKIPI.NE R0 64
3C00 @6 # JUMP @ThrowAwayPointer
# ;; Then dealing with ($)
A0300024 # CMPSKIPI.NE R0 36
3C00 @6 # JUMP @ThrowAwayPointer
# ;; Now check for absolute addresses (&)
A0300026 # CMPSKIPI.NE R0 38
3C00 @v # JUMP @ThrowAwayAddress
3C00 @7 # JUMP @ThrowAwayAddress
# ;; Otherwise attempt to process
2D0F @7 # CALLI R15 @hex ; Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00 @2 # JUMP @first_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A @8 # JUMP.Z R10 @first_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
0D00002A # FALSE R10 ; Flip the toggle
3C00 @2 # JUMP @first_pass
# :first_pass_0
:8
2D0F @8 # CALLI R15 @hex ; Convert it
2CC0 @3 # JUMP.NP R0 @first_pass ; Don't record, nonhex values
# ;; Flip the toggle
090006AA # NOT R10 R10
2C9A @3 # JUMP.Z R10 @first_pass ; Jump if toggled
# ;; Deal with case of second half of byte
0D00003A # TRUE R10 ; Flip the toggle
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00 @2 # JUMP @first_pass
3C00 @3 # JUMP @first_pass
# ;; Second pass function
@ -102,42 +128,48 @@ A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
# ;; To write desired contents onto Tape_02
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
#:second_pass
# :second_pass b4
:4
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label
A030003a # CMPSKIPI.NE R0 58
3C00 @9 # JUMP @ThrowAwayLabel
# ;; Check for and deal with Pointers to labels
A0300040 # CMPSKIPI.NE R0 64 ; @ for relative
3C00 @a # JUMP @StoreRelativePointer
A0300024 # CMPSKIPI.NE R0 36 ; $ for absolute
3C00 @b # JUMP @StoreAbsolutePointer
A0300026 # CMPSKIPI.NE R0 38 ; & for address
3C00 @w # JUMP @StoreAbsoluteAddress
3C00 @c # JUMP @StoreAbsoluteAddress
# ;; Process everything else
2D0F @7 # CALLI R15 @hex ; Attempt to Convert it
2D0F @8 # CALLI R15 @hex ; Attempt to Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00 @4 # JUMP @second_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A @c # JUMP.Z R10 @second_pass_0 ; Jump if toggled
090006AA # NOT R10 R10
2C9A @d # JUMP.Z R10 @second_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
05020C08 # AND R12 R0 R8 ; Store our first nibble
0D00002A # FALSE R10 ; Flip the toggle
B0C0000f # ANDI R12 R0 0x0F ; Store our first nibble
3C00 @4 # JUMP @second_pass
# :second_pass_0
:c
# :second_pass_0 fc
:d
# ;; Deal with case of second half of byte
2D5C0004 # SL0I R12 4 ; Shift our first nybble
05020008 # AND R0 R0 R8 ; Mask out top
B000000f # ANDI R0 R0 0x0F ; Mask out top
0500000C # ADD R0 R0 R12 ; Combine nybbles
0D00003A # TRUE R10 ; Flip the toggle
2D211101 # LOADUI R1 0x1101 ; Write the combined byte
42100200 # FPUTC ; To TAPE_02
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00 @4 # JUMP @second_pass
@ -147,197 +179,161 @@ A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
# ;; Its static variable for storing the next index to be used
# ;; Will overwrite R0
# ;; Returns to first pass when done
#:storeLabel
# :storeLabel 11c
:5
2E00 @d # LOADR R0 @current_index ; Get address of first open index
A0300000 # CMPSKIPI.NE R0 0 ; If zero intialize from R13
0900040D # COPY R0 R13
# ;; Store the PC of the label
23B00000 # STORE32 R11 R0 0
09000408 # COPY R0 R8 ; get current malloc
05000889 # ADD R8 R8 R9 ; update malloc
# ;; Add node info
05048B0D # STOREX R11 R0 R13 ; Store the PC of the label
20E00000 # STORE R14 R0 0 ; Store the Previous Head
090005E0 # MOVE R14 R0 ; Update Head
# ;; Store the name of the Label
0F000004 # ADDUI R0 R0 4 ; Increment the offset of the index
2D0F @e # CALLI R15 @writeout_token
# ;; Update our index
0F00003c # ADDUI R0 R0 60 ; Hopefully our tokens are less than 60 bytes long
2F00 @d # STORER R0 @current_index
# ;; And be done
3C00 @2 # JUMP @first_pass
# ;; Where we are storing the location of the next free table entry
# :current_index
:d
00000000 # NOP
3C00 @3 # JUMP @first_pass
# ;; StoreRelativepointer function
# ;; Deals with the special case of relative pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Stores string
# ;; Finds match in Table
# ;; Writes out the offset
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
# :StoreRelativePointer
# :StoreRelativePointer 138
:a
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D2003cc # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F @f # CALLI R15 @Clear_string ; Clear it
2D0F @e # CALLI R15 @writeout_token ; Write it
2D0F @g # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
2D0F @o # CALLI R15 @Match_string ; Find the Match
0500200B # SUB R0 R0 R11 ; Determine the difference
0F000004 # ADDUI R0 R0 4 ; Adjust for relative positioning
2D0F @h # CALLI R15 @ProcessImmediate ; Write out the value
2D0F @p # CALLI R15 @ProcessImmediate ; Write out the value
3C00 @4 # JUMP @second_pass
# ;; StoreAbsolutepointer function
# ;; Deals with the special case of absolute pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Stores string
# ;; Finds match in Table
# ;; Writes out the absolute address of match
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
# :StoreAbsolutePointer
# :StoreAbsolutePointer 150
:b
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D2003cc # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F @f # CALLI R15 @Clear_string ; Clear it
2D0F @e # CALLI R15 @writeout_token ; Write it
2D0F @g # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
2D0F @h # CALLI R15 @ProcessImmediate ; Write out the value
2D0F @o # CALLI R15 @Match_string ; Find the Match
2D0F @p # CALLI R15 @ProcessImmediate ; Write out the value
3C00 @4 # JUMP @second_pass
# ;; StoreAbsoluteAddress function
# ;; Deal with the special case of absolute Addresses
# ;; Clear Temp
# ;; Stores string in Temp
# ;; Stores string
# ;; Finds match in Table
# ;; Writes out the full absolute address [32 bit machine]
# ;; Modifies R0 R11
# ;; Jumpbacs back into Pass2
# :StoreAbsoluteAddress
# :StoreAbsoluteAddress 160
:c
# ;; COrrect the PC to reflect the size of the address
:w
0FBB0004 # ADDUI R11 R11 4 ; 4 Bytes on 32bit machines
2D2003cc # LOADUI R0 $Temp ; Set where we ant to shove our string
2D0F @f # CALLI R15 @Clear_string ; Clear it
2D0F @e # CALLI R15 @writeout_token ; Write it
2D0F @g # CALLI R15 @Match_string ; Find the Match
090200EF # PUSHR R14 R15 ; Get a temp storage place
18E0fffc # LOAD32 R14 R0 -4 ; Get the value we care about
0900040E # COPY R0 R14 ; We need to print the top 2 bytes first
2D0F @o # CALLI R15 @Match_string ; Find the Match
B020ffff # ANDI R2 R0 0xFFFF ; Save bottom half for next function
2D400010 # SARI R0 16 ; Drop bottom 16 bits
2D0F @h # CALLI R15 @ProcessImmediate ; Write out top 2 bytes
2D20ffff # LOADUI R0 0xFFFF ; Provide mask to keep bottom 2 bytes
0502000E # AND R0 R0 R14 ; Drop top 16 bits
090280EF # POPR R14 R15 ; Restore R14
2D0F @h # CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
2D0F @p # CALLI R15 @ProcessImmediate ; Write out top 2 bytes
09000502 # MOVE R0 R2 ; Use the saved 16bits
2D0F @p # CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
3C00 @4 # JUMP @second_pass
# ;; Writeout Token Function
# ;; Writes the Token [minus first char] to the address
# ;; It recieves in R0 until it reaches a delimiter
# ;; All register values are preserved
# ;; Returns to whatever called it
# :writeout_token
# ;; given by malloc and updates malloc pointer
# ;; Returns starting address of string
# :writeout_token 180
:e
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize
09000520 # MOVE R2 R0 ; Set R2 as our index
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
09000428 # COPY R2 R8 ; Get current malloc pointer
# ;; Our core loop
# :writeout_token_0
:j
# :writeout_token_0 18c
:r
42100100 # FGETC ; Get another byte
# ;; Deal with termination cases
A0300020 # CMPSKIPI.NE R0 32 ; Finished if space
3C00 @i # JUMP @writeout_token_done
3C00 @q # JUMP @writeout_token_done
A0300009 # CMPSKIPI.NE R0 9 ; Finished if tab
3C00 @i # JUMP @writeout_token_done
3C00 @q # JUMP @writeout_token_done
A030000a # CMPSKIPI.NE R0 10 ; Finished if newline
3C00 @i # JUMP @writeout_token_done
3C00 @q # JUMP @writeout_token_done
A030ffff # CMPSKIPI.NE R0 -1 ; Finished if EOF
3C00 @q # JUMP @writeout_token_done
# ;; Deal with valid input
21020000 # STORE8 R0 R2 0 ; Write out the byte
0F220001 # ADDUI R2 R2 1 ; Increment
3C00 @j # JUMP @writeout_token_0 ; Keep looping
21080000 # STORE8 R0 R8 0 ; Write out the byte
0F880001 # ADDUI R8 R8 1 ; Increment
3C00 @r # JUMP @writeout_token_0 ; Keep looping
# ;; Clean up now that we are done
# :writeout_token_done
:i
# :writeout_token_done 1bc
:q
# ;; Fix malloc
0F880001 # ADDUI R8 R8 1
# ;; Prepare for return
09000502 # MOVE R0 R2
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; And be done
0D01001F # RET R15
# ;; Clear string function
# ;; Clears string pointed at by the value of R0
# ;; Until a null character is reached
# ;; Doesn't alter any registers
# ;; Returns to the function that calls it
# :Clear_string
:f
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
# ;; Setup registers
09000510 # MOVE R1 R0
2D220000 # LOADUI R2 0
2D230000 # LOADUI R3 0
# :clear_byte
:k
0503A012 # LOADXU8 R0 R1 R2 ; Get the byte
05049312 # STOREX8 R3 R1 R2 ; Overwrite with a Zero
0F220001 # ADDUI R2 R2 1 ; Prep for next loop
2CA0 @k # JUMP.NZ R0 @clear_byte ; Stop if byte is NULL
# ;; Done
# ;; Restore registers
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Match string function
# ;; Walks down table until match is found
# ;; Then returns address of matching string in R0
# ;; Walks down list until match is found or returns -1
# ;; Reads a token
# ;; Then returns address of match in R0
# ;; Returns to whatever called it
# :Match_string
:g
# :Match_string 1d0
:o
# ;; Preserve registers
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize for Loop
2D2103cc # LOADUI R1 $Temp ; We always compare against Temp
2D22040c # LOADUI R2 $table ; Begin at start of table
0F220004 # ADDUI R2 R2 4 ; Where the string is located
2D0F @e # CALLI R15 @writeout_token ; Get our desired string
09000510 # MOVE R1 R0 ; Position our desired string
0900042E # COPY R2 R14 ; Begin at our head node
# ;; Loop until we find a match
# :Match_string_0
:n
09000402 # COPY R0 R2 ; Set R0 to our current string
2D0F @l # CALLI R15 @strcmp
2C50 @m # JUMP.E R0 @Match_string_1 ; It is a match!
# :Match_string_0 1e4
:h
05000029 # ADD R0 R2 R9 ; Where the string is located
2D0F @f # CALLI R15 @strcmp
2C50 @g # JUMP.E R0 @Match_string_1 ; It is a match!
# ;; Prepare for next loop
2D2103cc # LOADUI R1 $Temp ; That function clears R1
0F220040 # ADDUI R2 R2 64 ; Each Index is 64 bytes
3C00 @n # JUMP @Match_string_0 ; Keep looping
# :Match_string_1
:m
13220000 # LOAD R2 R2 0 ; Move to next node
2CA2 @h # JUMP.NZ R2 @Match_string_0 ; Keep looping
0D000032 # TRUE R2 ; Set result to -1 if not found
# :Match_string_1 1fc
:g
# ;; Store the correct answer
09000502 # MOVE R0 R2
A022ffff # CMPSKIPI.E R2 -1 ; Otherwise get the value
0503802D # LOADX R0 R2 R13 ; Get the value we care about
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
@ -347,32 +343,37 @@ A030000a # CMPSKIPI.NE R0 10 ; Finished if newline
# ;; Our simple string compare function
# ;; Recieves two pointers in R0 and R1
# ;; Returns the difference between the strings in R0
# ;; Clears R1
# ;; Returns to whatever called it
# :strcmp
:l
# :strcmp 210
:f
# ;; Preserve registers
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Setup registers
09000520 # MOVE R2 R0
09000531 # MOVE R3 R1
2D240000 # LOADUI R4 0
# :cmpbyte
:o
# :cmpbyte 22c
:i
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 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
2C51 @o # JUMP.E R1 @cmpbyte ; Loop if bytes are equal
2C51 @i # 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
0902801F # POPR R1 R15
0D01001F # RET R15
@ -381,27 +382,31 @@ A0200000 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
# ;; Writes out the values to Tape_02
# ;; Doesn't modify registers
# ;; Returns to whatever called it
# :ProcessImmediate
:h
# :ProcessImmediate 25c
:p
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Break up Immediate
05020209 # AND R2 R0 R9 ; Put lower byte in R2
B02000ff # ANDI R2 R0 0xFF ; Put lower byte in R2
2D400008 # SARI R0 8 ; Drop Bottom byte from R0
05020009 # AND R0 R0 R9 ; Maskout everything outside of top byte
B00000ff # ANDI R0 R0 0xFF ; Maskout everything outside of top byte
# ;; Write out Top Byte
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Write out bottom Byte
09000502 # MOVE R0 R2 ; Put Lower byte in R0
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; Be Done
0D01001F # RET R15
@ -411,11 +416,11 @@ A0200000 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, only jump to it
# :ThrowAwayPointer
# :ThrowAwayPointer 294
:6
0FBB0002 # ADDUI R11 R11 2 ; Pointers always take up 2 bytes
2D0F @p # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @2 # JUMP @first_pass ; Then return to the proper place
2D0F @j # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @3 # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwayAddress function
@ -423,11 +428,11 @@ A0200000 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, conly jump to it
# :ThrowAwayAddress
:v
# :ThrowAwayAddress 2a0
:7
0FBB0004 # ADDUI R11 R11 4 ; Addresses on 32bit systems take up 4 bytes
2D0F @p # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @2 # JUMP @first_pass ; Then return to the proper place
2D0F @j # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @3 # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwaylabel function
@ -435,31 +440,39 @@ A0200000 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
# ;; for Pass2, Will update R11 and modify R0
# ;; Will return to the start of second_pass
# ;; Never call this function, only jump to it
# :ThrowAwayLabel
# :ThrowAwayLabel 2ac
:9
2D0F @p # CALLI R15 @throwAwayToken ; Get rid of rest of token
2D0F @j # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @4 # JUMP @second_pass
# ;; Throw away token function
# ;; Deals with the general case of not wanting
# ;; The rest of the characters in a token
# ;; This Will alter the values of R0 R1
# ;; Returns back to whatever called it
# :throwAwayToken
:p
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
# :throwAwayToken 2b4
:j
42100100 # FGETC ; Read a Char
# ;; Stop looping if space
A0300020 # CMPSKIPI.NE R0 32
0D01001F # RET R15
# ;; Stop looping if tab
A0300009 # CMPSKIPI.NE R0 9
0D01001F # RET R15
# ;; Stop looping if newline
A030000a # CMPSKIPI.NE R0 10
0D01001F # RET R15
# ;; Stop looping if EOF
A030ffff # CMPSKIPI.NE R0 -1
0D01001F # RET R15
# ;; Otherwise keep looping
3C00 @p # JUMP @throwAwayToken
3C00 @j # JUMP @throwAwayToken
# ;; Hex function
@ -467,82 +480,60 @@ A030000a # CMPSKIPI.NE R0 10
# ;; Identifying hex characters
# ;; Purging line comments
# ;; Returning the converted value of a hex character
# ;; This function will alter the values of R0 R14
# ;; This function will alter the values of R0
# ;; Returns back to whatever called it
# :hex
:7
# :hex 2dc
:8
# ;; Deal with line comments starting with #
1FE00023 # CMPUI R14 R0 35
2C5E @q # JUMP.E R14 @ascii_comment
A0300023 # CMPSKIPI.NE R0 35
3C00 @k # JUMP @ascii_comment
# ;; Deal with line comments starting with ;
1FE0003b # CMPUI R14 R0 59
2C5E @q # JUMP.E R14 @ascii_comment
A030003b # CMPSKIPI.NE R0 59
3C00 @k # JUMP @ascii_comment
# ;; Deal with all ascii less than '0'
1FE00030 # CMPUI R14 R0 48
2C8E @r # JUMP.L R14 @ascii_other
A0100030 # CMPSKIPI.GE R0 48
3C00 @l # JUMP @ascii_other
# ;; Deal with '0'-'9'
1FE00039 # CMPUI R14 R0 57
2C7E @s # JUMP.LE R14 @ascii_num
A0000039 # CMPSKIPI.G R0 57
3C00 @m # JUMP @ascii_num
# ;; Deal with all ascii less than 'A'
1FE00041 # CMPUI R14 R0 65
2C8E @r # JUMP.L R14 @ascii_other
A0100041 # CMPSKIPI.GE R0 65
3C00 @l # JUMP @ascii_other
# ;; Unset high bit to set everything into uppercase
B00000df # ANDI R0 R0 0xDF
# ;; Deal with 'A'-'F'
1FE00046 # CMPUI R14 R0 70
2C7E @t # JUMP.LE R14 @ascii_high
# ;; Deal with all ascii less than 'a'
1FE00061 # CMPUI R14 R0 97
2C8E @r # JUMP.L R14 @ascii_other
# ;; Deal with 'a'-'f'
1FE00066 # CMPUI R14 R0 102
2C7E @u # JUMP.LE R14 @ascii_low
A0000046 # CMPSKIPI.G R0 70
3C00 @n # JUMP @ascii_high
# ;; Ignore the rest
3C00 @r # JUMP @ascii_other
# :ascii_num
:s
3C00 @l # JUMP @ascii_other
# :ascii_num 314
:m
11000030 # SUBUI R0 R0 48
0D01001F # RET R15
# :ascii_low
:u
11000057 # SUBUI R0 R0 87
0D01001F # RET R15
# :ascii_high
:t
# :ascii_high 31c
:n
11000037 # SUBUI R0 R0 55
0D01001F # RET R15
# :ascii_other
:r
# :ascii_comment 324
:k
42100100 # FGETC ; Read another char
2CC0 @l # JUMP.NP R0 @ascii_other ; Stop with EOF
A020000a # CMPSKIPI.E R0 10 ; Stop at the end of line
3C00 @k # JUMP @ascii_comment ; Otherwise keep looping
# :ascii_other 334
:l
0D000030 # TRUE R0
0D01001F # RET R15
# :ascii_comment
:q
2D211100 # LOADUI R1 0x1100 ; Read from TAPE_01
42100100 # FGETC ; Read another char
1FE0000a # CMPUI R14 R0 10 ; Stop at the end of line
2C6E @q # JUMP.NE R14 @ascii_comment ; Otherwise keep looping
3C00 @r # JUMP @ascii_other
# ;; Where we will putting our stack
# ;; Where we are storing our Temp
# :Temp
:z
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
# ;; Where we will putting our Table
# :table
# :stack 33c
:1

View File

@ -1,513 +0,0 @@
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you an 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
2D2D @table # LOADUI R13 @table ; Where we are putting our table
# ;; We will be using R14 for our condition codes
2D2F7fff # LOADUI R15 0x7FFF ; We will be using R15 for our stack
# ;; Main program functionality
# ;; Reads in Tape_01 and writes out results onto Tape_02
# ;; Accepts no arguments and HALTS when done
:main
# ;; Prep TAPE_01
2D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
# ;; Intialize environment
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
# ;; Perform first pass
2D0F @first_pass # CALLI R15 @first_pass
# ;; We need to rewind tape_01 to perform our second pass
2D201100 # LOADUI R0 0x1100
42100003 # REWIND
# ;; Reintialize environment
0D00002C # FALSE R12 ; Set holder to zero
0D00002B # FALSE R11 ; Set PC counter to zero
2D2A0001 # LOADUI R10 1 ; Our toggle
2D2900ff # LOADUI R9 0xFF ; Byte mask
2D28000f # LOADUI R8 0x0F ; nybble mask
# ;; Prep TAPE_02
2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
2D0F @second_pass # CALLI R15 @second_pass
# ;; Close up as we are done
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
2D201101 # LOADUI R0 0x1101 ; Close TAPE_02
42100002 # FCLOSE
FFFFFFFF # HALT
# ;; First pass function
# ;; Reads Tape_01 and creates our label table
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
:first_pass
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label (:)
A030003a # CMPSKIPI.NE R0 58
3C00 @storeLabel # JUMP @storeLabel
# ;; Check for and deal with pointers to labels
# ;; Starting with (@)
A0300040 # CMPSKIPI.NE R0 64
3C00 @ThrowAwayPointer # JUMP @ThrowAwayPointer
# ;; Then dealing with ($)
A0300024 # CMPSKIPI.NE R0 36
3C00 @ThrowAwayPointer # JUMP @ThrowAwayPointer
# ;; Now check for absolute addresses (&)
A0300026 # CMPSKIPI.NE R0 38
3C00 @ThrowAwayAddress # JUMP @ThrowAwayAddress
# ;; Otherwise attempt to process
2D0F @hex # CALLI R15 @hex ; Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00 @first_pass # JUMP @first_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A @first_pass_0 # JUMP.Z R10 @first_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
0D00002A # FALSE R10 ; Flip the toggle
3C00 @first_pass # JUMP @first_pass
:first_pass_0
# ;; Deal with case of second half of byte
0D00003A # TRUE R10 ; Flip the toggle
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00 @first_pass # JUMP @first_pass
# ;; Second pass function
# ;; Reads from Tape_01 and uses the values in the table
# ;; To write desired contents onto Tape_02
# ;; Will Overwrite R0 R10 R11
# ;; Returns to Main function when done
:second_pass
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
0D01001F # RET R15
# ;; Check for and deal with label
A030003a # CMPSKIPI.NE R0 58
3C00 @ThrowAwayLabel # JUMP @ThrowAwayLabel
# ;; Check for and deal with Pointers to labels
A0300040 # CMPSKIPI.NE R0 64 ; @ for relative
3C00 @StoreRelativePointer # JUMP @StoreRelativePointer
A0300024 # CMPSKIPI.NE R0 36 ; $ for absolute
3C00 @StoreAbsolutePointer # JUMP @StoreAbsolutePointer
A0300026 # CMPSKIPI.NE R0 38 ; & for address
3C00 @StoreAbsoluteAddress # JUMP @StoreAbsoluteAddress
# ;; Process everything else
2D0F @hex # CALLI R15 @hex ; Attempt to Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00 @second_pass # JUMP @second_pass ; Move onto Next char
# ;; Determine if we got a full byte
2C9A @second_pass_0 # JUMP.Z R10 @second_pass_0 ; Jump if toggled
# ;; Deal with case of first half of byte
05020C08 # AND R12 R0 R8 ; Store our first nibble
0D00002A # FALSE R10 ; Flip the toggle
3C00 @second_pass # JUMP @second_pass
:second_pass_0
# ;; Deal with case of second half of byte
2D5C0004 # SL0I R12 4 ; Shift our first nybble
05020008 # AND R0 R0 R8 ; Mask out top
0500000C # ADD R0 R0 R12 ; Combine nybbles
0D00003A # TRUE R10 ; Flip the toggle
2D211101 # LOADUI R1 0x1101 ; Write the combined byte
42100200 # FPUTC ; To TAPE_02
0FBB0001 # ADDUI R11 R11 1 ; increment PC now that that we have a full byte
3C00 @second_pass # JUMP @second_pass
# ;; Store Label function
# ;; Writes out the token and the current PC value
# ;; Its static variable for storing the next index to be used
# ;; Will overwrite R0
# ;; Returns to first pass when done
:storeLabel
2E00 @current_index # LOADR R0 @current_index ; Get address of first open index
A0300000 # CMPSKIPI.NE R0 0 ; If zero intialize from R13
0900040D # COPY R0 R13
# ;; Store the PC of the label
23B00000 # STORE32 R11 R0 0
# ;; Store the name of the Label
0F000004 # ADDUI R0 R0 4 ; Increment the offset of the index
2D0F @writeout_token # CALLI R15 @writeout_token
# ;; Update our index
0F00003c # ADDUI R0 R0 60 ; Hopefully our tokens are less than 60 bytes long
2F00 @current_index # STORER R0 @current_index
# ;; And be done
3C00 @first_pass # JUMP @first_pass
# ;; Where we are storing the location of the next free table entry
:current_index
00000000 # NOP
# ;; StoreRelativepointer function
# ;; Deals with the special case of relative pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the offset
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
:StoreRelativePointer
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D20 $Temp # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F @Clear_string # CALLI R15 @Clear_string ; Clear it
2D0F @writeout_token # CALLI R15 @writeout_token ; Write it
2D0F @Match_string # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
0500200B # SUB R0 R0 R11 ; Determine the difference
0F000004 # ADDUI R0 R0 4 ; Adjust for relative positioning
2D0F @ProcessImmediate # CALLI R15 @ProcessImmediate ; Write out the value
3C00 @second_pass # JUMP @second_pass
# ;; StoreAbsolutepointer function
# ;; Deals with the special case of absolute pointers
# ;; Clears Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the absolute address of match
# ;; Modifies R0 R11
# ;; Jumps back into Pass2
:StoreAbsolutePointer
# ;; Correct the PC to reflect the size of the pointer
0FBB0002 # ADDUI R11 R11 2 ; Exactly 2 bytes
2D20 $Temp # LOADUI R0 $Temp ; Set where we want to shove our string
2D0F @Clear_string # CALLI R15 @Clear_string ; Clear it
2D0F @writeout_token # CALLI R15 @writeout_token ; Write it
2D0F @Match_string # CALLI R15 @Match_string ; Find the Match
1800fffc # LOAD32 R0 R0 -4 ; Get the value we care about
2D0F @ProcessImmediate # CALLI R15 @ProcessImmediate ; Write out the value
3C00 @second_pass # JUMP @second_pass
# ;; StoreAbsoluteAddress function
# ;; Deal with the special case of absolute Addresses
# ;; Clear Temp
# ;; Stores string in Temp
# ;; Finds match in Table
# ;; Writes out the full absolute address [32 bit machine]
# ;; Modifies R0 R11
# ;; Jumpbacs back into Pass2
:StoreAbsoluteAddress
# ;; COrrect the PC to reflect the size of the address
0FBB0004 # ADDUI R11 R11 4 ; 4 Bytes on 32bit machines
2D20 $Temp # LOADUI R0 $Temp ; Set where we ant to shove our string
2D0F @Clear_string # CALLI R15 @Clear_string ; Clear it
2D0F @writeout_token # CALLI R15 @writeout_token ; Write it
2D0F @Match_string # CALLI R15 @Match_string ; Find the Match
090200EF # PUSHR R14 R15 ; Get a temp storage place
18E0fffc # LOAD32 R14 R0 -4 ; Get the value we care about
0900040E # COPY R0 R14 ; We need to print the top 2 bytes first
2D400010 # SARI R0 16 ; Drop bottom 16 bits
2D0F @ProcessImmediate # CALLI R15 @ProcessImmediate ; Write out top 2 bytes
2D20ffff # LOADUI R0 0xFFFF ; Provide mask to keep bottom 2 bytes
0502000E # AND R0 R0 R14 ; Drop top 16 bits
090280EF # POPR R14 R15 ; Restore R14
2D0F @ProcessImmediate # CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
3C00 @second_pass # JUMP @second_pass
# ;; Writeout Token Function
# ;; Writes the Token [minus first char] to the address
# ;; It recieves in R0 until it reaches a delimiter
# ;; All register values are preserved
# ;; Returns to whatever called it
:writeout_token
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize
09000520 # MOVE R2 R0 ; Set R2 as our index
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
# ;; Our core loop
:writeout_token_0
42100100 # FGETC ; Get another byte
# ;; Deal with termination cases
A0300020 # CMPSKIPI.NE R0 32 ; Finished if space
3C00 @writeout_token_done # JUMP @writeout_token_done
A0300009 # CMPSKIPI.NE R0 9 ; Finished if tab
3C00 @writeout_token_done # JUMP @writeout_token_done
A030000a # CMPSKIPI.NE R0 10 ; Finished if newline
3C00 @writeout_token_done # JUMP @writeout_token_done
# ;; Deal with valid input
21020000 # STORE8 R0 R2 0 ; Write out the byte
0F220001 # ADDUI R2 R2 1 ; Increment
3C00 @writeout_token_0 # JUMP @writeout_token_0 ; Keep looping
# ;; Clean up now that we are done
:writeout_token_done
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; And be done
0D01001F # RET R15
# ;; Clear string function
# ;; Clears string pointed at by the value of R0
# ;; Until a null character is reached
# ;; Doesn't alter any registers
# ;; Returns to the function that calls it
:Clear_string
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
# ;; Setup registers
09000510 # MOVE R1 R0
2D220000 # LOADUI R2 0
2D230000 # LOADUI R3 0
:clear_byte
0503A012 # LOADXU8 R0 R1 R2 ; Get the byte
05049312 # STOREX8 R3 R1 R2 ; Overwrite with a Zero
0F220001 # ADDUI R2 R2 1 ; Prep for next loop
2CA0 @clear_byte # JUMP.NZ R0 @clear_byte ; Stop if byte is NULL
# ;; Done
# ;; Restore registers
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Match string function
# ;; Walks down table until match is found
# ;; Then returns address of matching string in R0
# ;; Returns to whatever called it
:Match_string
# ;; Preserve registers
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Initialize for Loop
2D21 $Temp # LOADUI R1 $Temp ; We always compare against Temp
2D22 $table # LOADUI R2 $table ; Begin at start of table
0F220004 # ADDUI R2 R2 4 ; Where the string is located
# ;; Loop until we find a match
:Match_string_0
09000402 # COPY R0 R2 ; Set R0 to our current string
2D0F @strcmp # CALLI R15 @strcmp
2C50 @Match_string_1 # JUMP.E R0 @Match_string_1 ; It is a match!
# ;; Prepare for next loop
2D21 $Temp # LOADUI R1 $Temp ; That function clears R1
0F220040 # ADDUI R2 R2 64 ; Each Index is 64 bytes
3C00 @Match_string_0 # JUMP @Match_string_0 ; Keep looping
:Match_string_1
# ;; Store the correct answer
09000502 # MOVE R0 R2
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0D01001F # RET R15
# ;; Our simple string compare function
# ;; Recieves two pointers in R0 and R1
# ;; Returns the difference between the strings in R0
# ;; Clears R1
# ;; 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
09000531 # MOVE R3 R1
2D240000 # LOADUI R4 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 # CMPSKIPI.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
# ;; Processimmediate Function
# ;; Recieves an integer value in R0
# ;; Writes out the values to Tape_02
# ;; Doesn't modify registers
# ;; Returns to whatever called it
:ProcessImmediate
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
# ;; Break up Immediate
05020209 # AND R2 R0 R9 ; Put lower byte in R2
2D400008 # SARI R0 8 ; Drop Bottom byte from R0
05020009 # AND R0 R0 R9 ; Maskout everything outside of top byte
# ;; Write out Top Byte
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Write out bottom Byte
09000502 # MOVE R0 R2 ; Put Lower byte in R0
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; Be Done
0D01001F # RET R15
# ;; ThrowAwaypointer function
# ;; Handle the special case of a generic problem
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, only jump to it
:ThrowAwayPointer
0FBB0002 # ADDUI R11 R11 2 ; Pointers always take up 2 bytes
2D0F @throwAwayToken # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @first_pass # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwayAddress function
# ;; Handle the case of a 32bit absolute address storage
# ;; for Pass1, Will update R11 and modify R0
# ;; Will return to the start of first_pass
# ;; Never call this function, conly jump to it
:ThrowAwayAddress
0FBB0004 # ADDUI R11 R11 4 ; Addresses on 32bit systems take up 4 bytes
2D0F @throwAwayToken # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @first_pass # JUMP @first_pass ; Then return to the proper place
# ;; ThrowAwaylabel function
# ;; Handle the special case of a generic problem
# ;; for Pass2, Will update R11 and modify R0
# ;; Will return to the start of second_pass
# ;; Never call this function, only jump to it
:ThrowAwayLabel
2D0F @throwAwayToken # CALLI R15 @throwAwayToken ; Get rid of rest of token
3C00 @second_pass # JUMP @second_pass
# ;; Throw away token function
# ;; Deals with the general case of not wanting
# ;; The rest of the characters in a token
# ;; This Will alter the values of R0 R1
# ;; Returns back to whatever called it
:throwAwayToken
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Stop looping if space
A0300020 # CMPSKIPI.NE R0 32
0D01001F # RET R15
# ;; Stop looping if tab
A0300009 # CMPSKIPI.NE R0 9
0D01001F # RET R15
# ;; Stop looping if newline
A030000a # CMPSKIPI.NE R0 10
0D01001F # RET R15
# ;; Otherwise keep looping
3C00 @throwAwayToken # JUMP @throwAwayToken
# ;; Hex function
# ;; This function is serving three purposes:
# ;; Identifying hex characters
# ;; Purging line comments
# ;; Returning the converted value of a hex character
# ;; This function will alter the values of R0 R14
# ;; Returns back to whatever called it
:hex
# ;; Deal with line comments starting with #
1FE00023 # CMPUI R14 R0 35
2C5E @ascii_comment # JUMP.E R14 @ascii_comment
# ;; Deal with line comments starting with ;
1FE0003b # CMPUI R14 R0 59
2C5E @ascii_comment # JUMP.E R14 @ascii_comment
# ;; Deal with all ascii less than '0'
1FE00030 # CMPUI R14 R0 48
2C8E @ascii_other # JUMP.L R14 @ascii_other
# ;; Deal with '0'-'9'
1FE00039 # CMPUI R14 R0 57
2C7E @ascii_num # JUMP.LE R14 @ascii_num
# ;; Deal with all ascii less than 'A'
1FE00041 # CMPUI R14 R0 65
2C8E @ascii_other # JUMP.L R14 @ascii_other
# ;; Deal with 'A'-'F'
1FE00046 # CMPUI R14 R0 70
2C7E @ascii_high # JUMP.LE R14 @ascii_high
# ;; Deal with all ascii less than 'a'
1FE00061 # CMPUI R14 R0 97
2C8E @ascii_other # JUMP.L R14 @ascii_other
# ;; Deal with 'a'-'f'
1FE00066 # CMPUI R14 R0 102
2C7E @ascii_low # JUMP.LE R14 @ascii_low
# ;; Ignore the rest
3C00 @ascii_other # JUMP @ascii_other
:ascii_num
11000030 # SUBUI R0 R0 48
0D01001F # RET R15
:ascii_low
11000057 # SUBUI R0 R0 87
0D01001F # RET R15
:ascii_high
11000037 # SUBUI R0 R0 55
0D01001F # RET R15
:ascii_other
0D000030 # TRUE R0
0D01001F # RET R15
:ascii_comment
2D211100 # LOADUI R1 0x1100 ; Read from TAPE_01
42100100 # FGETC ; Read another char
1FE0000a # CMPUI R14 R0 10 ; Stop at the end of line
2C6E @ascii_comment # JUMP.NE R14 @ascii_comment ; Otherwise keep looping
3C00 @ascii_other # JUMP @ascii_other
# ;; Where we are storing our Temp
:Temp
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
00000000 # NOP
# ;; Where we will putting our Table
:table

View File

@ -14,24 +14,45 @@
; You should have received a copy of the GNU General Public License
; along with stage0. If not, see <http://www.gnu.org/licenses/>.
;; Node format:
;; PREV->pointer (register size)
;; Address (register size)
;; NULL terminated string (strln + 1)
:start
LOADUI R13 @table ; Where we are putting our table
;; We will be using R14 for our condition codes
LOADUI R15 0x7FFF ; We will be using R15 for our stack
;; R1 is reserved for reading/writing bytes (don't touch)
;; We will be using R8 for our malloc pointer
;; We will be using R9 for our header size in bytes
;; We will be using R10 for our toggle
;; We will be using R11 for our PC counter
;; We will be using R12 for holding our nybble
;; We will be using R13 for our register size in bytes
;; We will be using R14 for our head-node
LOADUI R15 $stack ; We will be using R15 for our stack
;; Main program functionality
;; Reads in Tape_01 and writes out results onto Tape_02
;; Accepts no arguments and HALTS when done
:main
;; Initialize header info
READSCID R0 ; Get process capabilities
ANDI R1 R0 0xF ; We only care about size nybble
LOADUI R0 1 ; Assume we are 8bit
SL0 R13 R0 R1 ; Let size nybble correct answer
COPY R9 R13 ; Prepare Header size
SL0I R9 1 ; Double to make proper size
;; Prep TAPE_01
LOADUI R0 0x1100
FOPEN_READ
;; Intialize environment
LOADUI R1 0x1100 ; Read from tape_01
FALSE R12 ; Set holder to zero
FALSE R11 ; Set PC counter to zero
LOADUI R10 1 ; Our toggle
FALSE R10 ; Our toggle
LOADUI R8 0x500 ; Where we want our heap to start
;; Perform first pass
CALLI R15 @first_pass
@ -43,9 +64,7 @@
;; Reintialize environment
FALSE R12 ; Set holder to zero
FALSE R11 ; Set PC counter to zero
LOADUI R10 1 ; Our toggle
LOADUI R9 0xFF ; Byte mask
LOADUI R8 0x0F ; nybble mask
FALSE R10 ; Our toggle
;; Prep TAPE_02
LOADUI R0 0x1101
@ -66,7 +85,6 @@
;; Will Overwrite R0 R10 R11
;; Returns to Main function when done
:first_pass
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char
;; Check for EOF
@ -92,19 +110,13 @@
;; Otherwise attempt to process
CALLI R15 @hex ; Convert it
CMPSKIPI.GE R0 0 ; Don't record, nonhex values
JUMP @first_pass ; Move onto Next char
JUMP.NP R0 @first_pass ; Don't record, nonhex values
;; Determine if we got a full byte
JUMP.Z R10 @first_pass_0 ; Jump if toggled
;; Flip the toggle
NOT R10 R10
JUMP.Z R10 @first_pass ; Jump if toggled
;; Deal with case of first half of byte
FALSE R10 ; Flip the toggle
JUMP @first_pass
:first_pass_0
;; Deal with case of second half of byte
TRUE R10 ; Flip the toggle
ADDUI R11 R11 1 ; increment PC now that that we have a full byte
JUMP @first_pass
@ -115,7 +127,6 @@
;; Will Overwrite R0 R10 R11
;; Returns to Main function when done
:second_pass
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char
;; Check for EOF
@ -142,21 +153,21 @@
JUMP @second_pass ; Move onto Next char
;; Determine if we got a full byte
NOT R10 R10
JUMP.Z R10 @second_pass_0 ; Jump if toggled
;; Deal with case of first half of byte
AND R12 R0 R8 ; Store our first nibble
FALSE R10 ; Flip the toggle
ANDI R12 R0 0x0F ; Store our first nibble
JUMP @second_pass
:second_pass_0
;; Deal with case of second half of byte
SL0I R12 4 ; Shift our first nybble
AND R0 R0 R8 ; Mask out top
ANDI R0 R0 0x0F ; Mask out top
ADD R0 R0 R12 ; Combine nybbles
TRUE R10 ; Flip the toggle
LOADUI R1 0x1101 ; Write the combined byte
FPUTC ; To TAPE_02
LOADUI R1 0x1100 ; Read from tape_01
ADDUI R11 R11 1 ; increment PC now that that we have a full byte
JUMP @second_pass
@ -167,32 +178,24 @@
;; Will overwrite R0
;; Returns to first pass when done
:storeLabel
LOADR R0 @current_index ; Get address of first open index
CMPSKIPI.NE R0 0 ; If zero intialize from R13
COPY R0 R13
COPY R0 R8 ; get current malloc
ADD R8 R8 R9 ; update malloc
;; Store the PC of the label
STORE32 R11 R0 0
;; Add node info
STOREX R11 R0 R13 ; Store the PC of the label
STORE R14 R0 0 ; Store the Previous Head
MOVE R14 R0 ; Update Head
;; Store the name of the Label
ADDUI R0 R0 4 ; Increment the offset of the index
CALLI R15 @writeout_token
;; Update our index
ADDUI R0 R0 60 ; Hopefully our tokens are less than 60 bytes long
STORER R0 @current_index
;; And be done
JUMP @first_pass
;; Where we are storing the location of the next free table entry
:current_index
NOP
;; StoreRelativepointer function
;; Deals with the special case of relative pointers
;; Clears Temp
;; Stores string in Temp
;; Stores string
;; Finds match in Table
;; Writes out the offset
;; Modifies R0 R11
@ -200,11 +203,7 @@
:StoreRelativePointer
;; Correct the PC to reflect the size of the pointer
ADDUI R11 R11 2 ; Exactly 2 bytes
LOADUI R0 $Temp ; Set where we want to shove our string
CALLI R15 @Clear_string ; Clear it
CALLI R15 @writeout_token ; Write it
CALLI R15 @Match_string ; Find the Match
LOAD32 R0 R0 -4 ; Get the value we care about
SUB R0 R0 R11 ; Determine the difference
ADDUI R0 R0 4 ; Adjust for relative positioning
CALLI R15 @ProcessImmediate ; Write out the value
@ -213,8 +212,7 @@
;; StoreAbsolutepointer function
;; Deals with the special case of absolute pointers
;; Clears Temp
;; Stores string in Temp
;; Stores string
;; Finds match in Table
;; Writes out the absolute address of match
;; Modifies R0 R11
@ -222,19 +220,14 @@
:StoreAbsolutePointer
;; Correct the PC to reflect the size of the pointer
ADDUI R11 R11 2 ; Exactly 2 bytes
LOADUI R0 $Temp ; Set where we want to shove our string
CALLI R15 @Clear_string ; Clear it
CALLI R15 @writeout_token ; Write it
CALLI R15 @Match_string ; Find the Match
LOAD32 R0 R0 -4 ; Get the value we care about
CALLI R15 @ProcessImmediate ; Write out the value
JUMP @second_pass
;; StoreAbsoluteAddress function
;; Deal with the special case of absolute Addresses
;; Clear Temp
;; Stores string in Temp
;; Stores string
;; Finds match in Table
;; Writes out the full absolute address [32 bit machine]
;; Modifies R0 R11
@ -242,36 +235,26 @@
:StoreAbsoluteAddress
;; COrrect the PC to reflect the size of the address
ADDUI R11 R11 4 ; 4 Bytes on 32bit machines
LOADUI R0 $Temp ; Set where we ant to shove our string
CALLI R15 @Clear_string ; Clear it
CALLI R15 @writeout_token ; Write it
CALLI R15 @Match_string ; Find the Match
PUSHR R14 R15 ; Get a temp storage place
LOAD32 R14 R0 -4 ; Get the value we care about
COPY R0 R14 ; We need to print the top 2 bytes first
ANDI R2 R0 0xFFFF ; Save bottom half for next function
SARI R0 16 ; Drop bottom 16 bits
CALLI R15 @ProcessImmediate ; Write out top 2 bytes
LOADUI R0 0xFFFF ; Provide mask to keep bottom 2 bytes
AND R0 R0 R14 ; Drop top 16 bits
POPR R14 R15 ; Restore R14
MOVE R0 R2 ; Use the saved 16bits
CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
JUMP @second_pass
;; Writeout Token Function
;; Writes the Token [minus first char] to the address
;; It recieves in R0 until it reaches a delimiter
;; All register values are preserved
;; Returns to whatever called it
;; given by malloc and updates malloc pointer
;; Returns starting address of string
:writeout_token
;; Preserve registers
PUSHR R0 R15
PUSHR R1 R15
PUSHR R2 R15
;; Initialize
MOVE R2 R0 ; Set R2 as our index
LOADUI R1 0x1100 ; Read from tape_01
COPY R2 R8 ; Get current malloc pointer
;; Our core loop
:writeout_token_0
@ -284,54 +267,31 @@
JUMP @writeout_token_done
CMPSKIPI.NE R0 10 ; Finished if newline
JUMP @writeout_token_done
CMPSKIPI.NE R0 -1 ; Finished if EOF
JUMP @writeout_token_done
;; Deal with valid input
STORE8 R0 R2 0 ; Write out the byte
ADDUI R2 R2 1 ; Increment
STORE8 R0 R8 0 ; Write out the byte
ADDUI R8 R8 1 ; Increment
JUMP @writeout_token_0 ; Keep looping
;; Clean up now that we are done
:writeout_token_done
;; Fix malloc
ADDUI R8 R8 1
;; Prepare for return
MOVE R0 R2
;; Restore registers
POPR R2 R15
POPR R1 R15
POPR R0 R15
;; And be done
RET R15
;; Clear string function
;; Clears string pointed at by the value of R0
;; Until a null character is reached
;; Doesn't alter any registers
;; Returns to the function that calls it
:Clear_string
;; Preserve registers
PUSHR R0 R15
PUSHR R1 R15
PUSHR R2 R15
PUSHR R3 R15
;; Setup registers
MOVE R1 R0
LOADUI R2 0
LOADUI R3 0
:clear_byte
LOADXU8 R0 R1 R2 ; Get the byte
STOREX8 R3 R1 R2 ; Overwrite with a Zero
ADDUI R2 R2 1 ; Prep for next loop
JUMP.NZ R0 @clear_byte ; Stop if byte is NULL
;; Done
;; Restore registers
POPR R3 R15
POPR R2 R15
POPR R1 R15
POPR R0 R15
RET R15
;; Match string function
;; Walks down table until match is found
;; Then returns address of matching string in R0
;; Walks down list until match is found or returns -1
;; Reads a token
;; Then returns address of match in R0
;; Returns to whatever called it
:Match_string
;; Preserve registers
@ -339,23 +299,24 @@
PUSHR R2 R15
;; Initialize for Loop
LOADUI R1 $Temp ; We always compare against Temp
LOADUI R2 $table ; Begin at start of table
ADDUI R2 R2 4 ; Where the string is located
CALLI R15 @writeout_token ; Get our desired string
MOVE R1 R0 ; Position our desired string
COPY R2 R14 ; Begin at our head node
;; Loop until we find a match
:Match_string_0
COPY R0 R2 ; Set R0 to our current string
ADD R0 R2 R9 ; Where the string is located
CALLI R15 @strcmp
JUMP.E R0 @Match_string_1 ; It is a match!
;; Prepare for next loop
LOADUI R1 $Temp ; That function clears R1
ADDUI R2 R2 64 ; Each Index is 64 bytes
JUMP @Match_string_0 ; Keep looping
LOAD R2 R2 0 ; Move to next node
JUMP.NZ R2 @Match_string_0 ; Keep looping
TRUE R2 ; Set result to -1 if not found
:Match_string_1
;; Store the correct answer
MOVE R0 R2
CMPSKIPI.E R2 -1 ; Otherwise get the value
LOADX R0 R2 R13 ; Get the value we care about
;; Restore registers
POPR R2 R15
POPR R1 R15
@ -365,10 +326,10 @@
;; Our simple string compare function
;; Recieves two pointers in R0 and R1
;; Returns the difference between the strings in R0
;; Clears R1
;; Returns to whatever called it
:strcmp
;; Preserve registers
PUSHR R1 R15
PUSHR R2 R15
PUSHR R3 R15
PUSHR R4 R15
@ -377,18 +338,19 @@
MOVE R3 R1
LOADUI R4 0
:cmpbyte
LOADXU8 R0 R2 R4 ; Get a byte of our first string
LOADXU8 R1 R3 R4 ; Get a byte of our second string
ADDUI R4 R4 1 ; Prep for next loop
CMP R1 R0 R1 ; Compare the bytes
CMPSKIPI.E R0 0 ; Stop if byte is NULL
JUMP.E R1 @cmpbyte ; Loop if bytes are equal
LOADXU8 R0 R2 R4 ; Get a byte of our first string
LOADXU8 R1 R3 R4 ; Get a byte of our second string
ADDUI R4 R4 1 ; Prep for next loop
CMP R1 R0 R1 ; Compare the bytes
CMPSKIPI.E R0 0 ; Stop if byte is NULL
JUMP.E R1 @cmpbyte ; Loop if bytes are equal
;; Done
MOVE R0 R1 ; Prepare for return
MOVE R0 R1 ; Prepare for return
;; Restore registers
POPR R4 R15
POPR R3 R15
POPR R2 R15
POPR R1 R15
RET R15
@ -403,16 +365,15 @@
PUSHR R1 R15
PUSHR R2 R15
;; Break up Immediate
AND R2 R0 R9 ; Put lower byte in R2
SARI R0 8 ; Drop Bottom byte from R0
AND R0 R0 R9 ; Maskout everything outside of top byte
ANDI R2 R0 0xFF ; Put lower byte in R2
SARI R0 8 ; Drop Bottom byte from R0
ANDI R0 R0 0xFF ; Maskout everything outside of top byte
;; Write out Top Byte
LOADUI R1 0x1101 ; Write the byte
FPUTC ; To TAPE_02
;; Write out bottom Byte
MOVE R0 R2 ; Put Lower byte in R0
LOADUI R1 0x1101 ; Write the byte
FPUTC ; To TAPE_02
;; Restore registers
@ -460,7 +421,6 @@
;; This Will alter the values of R0 R1
;; Returns back to whatever called it
:throwAwayToken
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char
;; Stop looping if space
@ -475,6 +435,10 @@
CMPSKIPI.NE R0 10
RET R15
;; Stop looping if EOF
CMPSKIPI.NE R0 -1
RET R15
;; Otherwise keep looping
JUMP @throwAwayToken
@ -484,75 +448,47 @@
;; Identifying hex characters
;; Purging line comments
;; Returning the converted value of a hex character
;; This function will alter the values of R0 R14
;; This function will alter the values of R0
;; Returns back to whatever called it
:hex
;; Deal with line comments starting with #
CMPUI R14 R0 35
JUMP.E R14 @ascii_comment
CMPSKIPI.NE R0 35
JUMP @ascii_comment
;; Deal with line comments starting with ;
CMPUI R14 R0 59
JUMP.E R14 @ascii_comment
CMPSKIPI.NE R0 59
JUMP @ascii_comment
;; Deal with all ascii less than '0'
CMPUI R14 R0 48
JUMP.L R14 @ascii_other
CMPSKIPI.GE R0 48
JUMP @ascii_other
;; Deal with '0'-'9'
CMPUI R14 R0 57
JUMP.LE R14 @ascii_num
CMPSKIPI.G R0 57
JUMP @ascii_num
;; Deal with all ascii less than 'A'
CMPUI R14 R0 65
JUMP.L R14 @ascii_other
CMPSKIPI.GE R0 65
JUMP @ascii_other
;; Unset high bit to set everything into uppercase
ANDI R0 R0 0xDF
;; Deal with 'A'-'F'
CMPUI R14 R0 70
JUMP.LE R14 @ascii_high
;; Deal with all ascii less than 'a'
CMPUI R14 R0 97
JUMP.L R14 @ascii_other
;; Deal with 'a'-'f'
CMPUI R14 R0 102
JUMP.LE R14 @ascii_low
CMPSKIPI.G R0 70
JUMP @ascii_high
;; Ignore the rest
JUMP @ascii_other
:ascii_num
SUBUI R0 R0 48
RET R15
:ascii_low
SUBUI R0 R0 87
RET R15
:ascii_high
SUBUI R0 R0 55
RET R15
:ascii_comment
FGETC ; Read another char
JUMP.NP R0 @ascii_other ; Stop with EOF
CMPSKIPI.E R0 10 ; Stop at the end of line
JUMP @ascii_comment ; Otherwise keep looping
:ascii_other
TRUE R0
RET R15
:ascii_comment
LOADUI R1 0x1100 ; Read from TAPE_01
FGETC ; Read another char
CMPUI R14 R0 10 ; Stop at the end of line
JUMP.NE R14 @ascii_comment ; Otherwise keep looping
JUMP @ascii_other
;; Where we are storing our Temp
:Temp
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
;; Where we will putting our Table
:table
;; Where we will putting our stack
:stack

View File

@ -7,4 +7,4 @@ b3a910f18c6bc0ef4aa7a53cb3f0216a9f143319da67ed2a02210fe88b1e1131 roms/forth
0a427b14020354d1c785f5f900677e0059fce8f8d4456e9c19e5528cb17101eb roms/stage0_monitor
3ea7fed1429400c1d6fc5b85180c4114755dfb1e6b88d69e7ecc465a40523bc8 roms/stage1_assembler-0
b6aabcc3418a0a28f4ed32ace43b20103d9d21dffae03e7936cb14fa0e044013 roms/stage1_assembler-1
61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99 roms/stage1_assembler-2
7b02babee42a3c05b001fb44fb0917383d8f185e2817d57ad2349a4b36dfa4ed roms/stage1_assembler-2