Hex1 assembler optimization to reduce size and number of clock cycles

required to process input
This commit is contained in:
Jeremiah Orians 2017-12-17 21:29:35 -05:00
parent 0ad7d92437
commit 0805284391
No known key found for this signature in database
GPG Key ID: 7457821534D2ACCD
6 changed files with 207 additions and 513 deletions

View File

@ -21,6 +21,7 @@ Added program to search for unusual characters that are not human detectable
** Changed ** Changed
Expanded stage0 web IDE to include the PC and instruction counter Expanded stage0 web IDE to include the PC and instruction counter
Performance tuned hex1 to reduce both size and instruction count
** Fixed ** Fixed
Fixed behavior of R@ thanks to reepca Fixed behavior of R@ thanks to reepca
@ -31,6 +32,7 @@ Fixed output of large negative numbers in hex
** Removed ** Removed
Removed stage1_assembler-0's need for Memory and reduced size of program while at it 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
* 0.0.9 - 2017-08-17 * 0.0.9 - 2017-08-17
** Added ** Added

View File

@ -93,7 +93,7 @@ So we are going to limit ourselves to single character labels and pointers (:a a
To build our improved hex assembler: To build our improved hex assembler:
./bin/vm --rom roms/stage1_assembler-0 --tape_01 stage1/stage1_assembler-1.hex0 --tape_02 roms/stage1_assembler-1 ./bin/vm --rom roms/stage1_assembler-0 --tape_01 stage1/stage1_assembler-1.hex0 --tape_02 roms/stage1_assembler-1
roms/stage1_assembler-1 should have the sha256sum of e4f0ed6e78ae79bb5e4a4fbde36f085dd0469cd6ae036dce5953b3d1c89801ce roms/stage1_assembler-1 should have the sha256sum of e59338381ca3ab01a14fa0fc85d0fa1c6e4d59a06ac2d9d75668d878ab469769
* Step 4 get even long label support * Step 4 get even long label support
Now that we have labels and pointers, I want the ability to have labels like :main_function and :stack_start and be able to reference the absolute address of things in my code like $stack_start and complex objects that have 32bit pointers like &foo_bar. Now that we have labels and pointers, I want the ability to have labels like :main_function and :stack_start and be able to reference the absolute address of things in my code like $stack_start and complex objects that have 32bit pointers like &foo_bar.

View File

@ -1,7 +1,7 @@
## Copyright (C) 2016 Jeremiah Orians ## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0. ## 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 ## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or ## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version. ## (at your option) any later version.
@ -14,14 +14,11 @@
## You should have received a copy of the GNU General Public License ## You should have received a copy of the GNU General Public License
## along with stage0. If not, see <http://www.gnu.org/licenses/>. ## along with stage0. If not, see <http://www.gnu.org/licenses/>.
# start #:start 0
2D2801e8 # LOADUI R8 @table ; Where we are putting our address pointers 2D2B019C # LOADUI R11 $table ; Where we are putting our address pointers
2D2900ff # LOADUI R9 0xFF ; Byte mask 0D00003C # TRUE R12 ; Our toggle
2D2A000f # LOADUI R10 0x0F ; nybble mask 0D00002D # FALSE R13 ; Our PC counter
2D2B0001 # LOADUI R11 1 ; Our toggle 2D2E0040 # LOADUI R14 $getLables_2 ; our first iterator
0D00002C # FALSE R12 ; Our PC counter
2D2D0600 # LOADUI R13 0x600 ; Where we are starting our Stack
# ;; We will be using R14 for our condition codes
# ;; We will be using R15 for holding our processed nybbles # ;; We will be using R15 for holding our processed nybbles
# ;; Prep TAPE_01 # ;; Prep TAPE_01
@ -32,211 +29,194 @@
2D201101 # LOADUI R0 0x1101 2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE 42100001 # FOPEN_WRITE
# ;; Function for collecting the address of all labels
# getLables
2D211100 # LOADUI R1 0x1100 ; Read from tape_01 2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF # ;; Function for collecting the address of all labels
A0100000 # CMPSKIPI.GE R0 0 #:getLables 24
3C00005c # JUMP @stage2 42100100 # FGETC ; Read a Char
2CC00048 # JUMP.NP R0 @stage2 ; Check for EOF
# ;; Check for Label # ;; Check for Label
A030003a # CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label A030003A # CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label
2D0D0040 # CALLI R13 @storeLabel 3C000030 # JUMP @storeLabel
# ;; Check for pointer to label # ;; Check for pointer to label
1FE00040 # CMPUI R14 R0 64 ; If the Char is @ the next char is the pointer to a label A0300040 # CMPSKIPI.NE R0 64 ; If the Char is @ the next char is the pointer to a label
2C6E0014 # JUMP.NE R14 @.L0 3C00001C # JUMP @ignorePointer
# ;; Ignore the pointer for now
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
0FCC0002 # ADDUI R12 R12 2 ; The pointer will end up taking 2 bytes
3C00ffd4 # JUMP @getLables
# .L0
# ;; Otherwise attempt to process # ;; Otherwise attempt to process
2D0D00fc # CALLI R13 @hex ; Convert it 3C0000DC # JUMP @hex ; Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00ffc8 # JUMP @getLables ; Move onto Next char
# ;; Determine if we got a full byte #:getLables_2 40
2C9B000c # JUMP.Z R11 @.L1 ; Jump if toggled 2CC0FFE4 # JUMP.NP R0 @getLables ; Don't record, nonhex values
090006CC # NOT R12 R12 ; Flip the toggle
2C9CFFDC # JUMP.Z R12 @getLables ; First half doesn't need anything
# ;; Deal with case of first half of byte
0D00002B # FALSE R11 ; Flip the toggle
3C00ffbc # JUMP @getLables
# .L1
# ;; Deal with case of second half of byte # ;; Deal with case of second half of byte
0D00003B # TRUE R11 ; Flip the toggle 0FDD0001 # ADDUI R13 R13 1 ; increment PC now that we have a full byte
0FCC0001 # ADDUI R12 R12 1 ; increment PC now that we have a full byte 3C00FFD4 # JUMP @getLables
3C00ffb0 # JUMP @getLables
#:ignorePointer 54
# ;; Ignore the pointer for now
42100100 # FGETC ; Read a Char
0FDD0002 # ADDUI R13 R13 2 ; The pointer will end up taking 2 bytes
3C00FFC8 # JUMP @getLables
# ;; Function for storing the address of the label # ;; Function for storing the address of the label
# storeLabel #:storeLabel 60
# ;; Get the char of the Label # ;; Get the char of the Label
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char 42100100 # FGETC ; Read a Char
# ;; We require 4 bytes to store the pointer values # ;; We require 2 bytes to store the pointer values
2D500002 # SL0I R0 2 ; Thus we multiply our label by 4 2D500001 # SL0I R0 1 ; Thus we multiply our label by 2
# ;; Store the current Program counter # ;; Store the current Program counter
05048C80 # STOREX R12 R8 R0 0504ADB0 # STOREX16 R13 R11 R0
# ;; Label is safely stored, return # ;; Label is safely stored, return
0D01001D # RET R13 3C00FFB8 # JUMP @getLables
# ;; Main Functionality
# stage2 # ;; Now that we have all of the label addresses,
# ;; We can process input to produce our output
#:stage2 70
# ;; We first need to rewind tape_01 to perform our second pass # ;; We first need to rewind tape_01 to perform our second pass
2D201100 # LOADUI R0 0x1100 2D201100 # LOADUI R0 0x1100
42100003 # REWIND 42100003 # REWIND
# ;; Reset our toggle and counter, just in case # ;; Reset our toggle and counter
2D2B0001 # LOADUI R11 1 ; Our toggle 2D291101 # LOADUI R9 0x1101 ; Where to write the combined byte
0D00002C # FALSE R12 ; Our PC counter 0D00003C # TRUE R12 ; Our toggle
0D00002D # FALSE R13 ; Our PC counter
2D2E00A4 # LOADUI R14 $loop_hex ; The hex return target
# loop #:loop 88
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char 42100100 # FGETC ; Read a Char
2CC000FC # JUMP.NP R0 @finish ; Check for EOF
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
3C000128 # JUMP @finish
# ;; Check for Label # ;; Check for Label
1FE0003a # CMPUI R14 R0 58 ; Make sure we jump over the label A030003A # CMPSKIPI.NE R0 58 ; Make sure we jump over the label
2C6E0010 # JUMP.NE R14 @.L97 3C000044 # JUMP @ignoreLabel
# ;; Consume next char
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
3C00ffe0 # JUMP @loop
# .L97
# ;; Check for Pointer # ;; Check for Pointer
1FE00040 # CMPUI R14 R0 64 ; If it is a pointer Deal with it A0300040 # CMPSKIPI.NE R0 64 ; If it is a pointer Deal with it
2C6E000c # JUMP.NE R14 @.L98 ; Otherwise attempt to process it 3C000044 # JUMP @storePointer
2D0D004c # CALLI R13 @storePointer
3C00ffd0 # JUMP @loop
# .L98
# ;; Process Char # ;; Process Char
2D210000 # LOADUI R1 0 ; Write to Char to TTY 3C000078 # JUMP @hex ; Convert it
42100200 # FPUTC ; Print the Char
2D0D0078 # CALLI R13 @hex ; Convert it #:loop_hex a4
12E00000 # CMPI R14 R0 0 ; Check if it is hex 2CC0FFE4 # JUMP.NP R0 @loop ; Don't use nonhex chars
2C8Effbc # JUMP.L R14 @loop ; Don't use nonhex chars 090006CC # NOT R12 R12 ; Flip the toggle
2C9B0010 # JUMP.Z R11 @.L99 ; Jump if toggled 2CAC000C # JUMP.NZ R12 @loop_second_nybble ; Jump if toggled
# ;; Process first byte of pair # ;; Process first byte of pair
05020F0A # AND R15 R0 R10 ; Store First nibble B0F0000F # ANDI R15 R0 0xF ; Store First nibble
0D00002B # FALSE R11 ; Flip the toggle 3C00FFD4 # JUMP @loop
3C00ffac # JUMP @loop
# .L99 #:loop_second_nybble b8
2D5F0004 # SL0I R15 4 ; Shift our first nibble 2D5F0004 # SL0I R15 4 ; Shift our first nibble
0502000A # AND R0 R0 R10 ; Mask out top B000000F # ANDI R0 R0 0xF ; Mask out top
0500000F # ADD R0 R0 R15 ; Combine nibbles 0500000F # ADD R0 R0 R15 ; Combine nibbles
0D00003B # TRUE R11 ; Flip the toggle 09000319 # SWAP R1 R9 ; Set to write to tape_2
2D211101 # LOADUI R1 0x1101 ; Write the combined byte
42100200 # FPUTC ; To TAPE_02 42100200 # FPUTC ; To TAPE_02
0FCC0001 # ADDUI R12 R12 1 ; increment PC now that we have a full byte 09000319 # SWAP R1 R9 ; Restore from tape_1
3C00ff8c # JUMP @loop ; Try to get more bytes 0FDD0001 # ADDUI R13 R13 1 ; increment PC now that we have a full byte
3C00FFB4 # JUMP @loop ; Try to get more bytes
# storePointer #:ignoreLabel d8
# ;; Consume next char
42100100 # FGETC ; Read a Char
3C00FFAC # JUMP @loop
#:storePointer e0
# ;; Correct the PC to reflect the size of the pointer # ;; Correct the PC to reflect the size of the pointer
0FCC0002 # ADDUI R12 R12 2 ; Exactly 2 bytes 0FDD0002 # ADDUI R13 R13 2 ; Exactly 2 bytes
# ;; Get the char of the Label # ;; Get the char of the Label
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char 42100100 # FGETC ; Read a Char
# ;; Since we stored a full pointer taking up 4 bytes # ;; Since we stored a short pointer taking up 2 bytes
2D500002 # SL0I R0 2 ; Thus we multiply our label by 4 to get where it is stored 2D500001 # SL0I R0 1 ; Thus we multiply our label by 2 to get where it is stored
05038280 # LOADX R2 R8 R0 ; Load the address of the label 0503C3B0 # LOADXU16 R3 R11 R0 ; Load the address of the label
# ;; We now have to calculate the distance and store the 2 bytes # ;; We now have to calculate the distance and store the 2 bytes
0500222C # SUB R2 R2 R12 ; First determine the difference between the current PC and the stored PC of the label 0500233D # SUB R3 R3 R13 ; First determine the difference between the current PC and the stored PC of the label
0F220004 # ADDUI R2 R2 4 ; Adjust for relative positioning 0F330004 # ADDUI R3 R3 4 ; Adjust for relative positioning
# ;; Store Upper byte # ;; Store Upper byte
09000402 # COPY R0 R2 B003FF00 # ANDI R0 R3 0xFF00 ; Mask out everything but top byte
2D400008 # SARI R0 8 ; Drop the bottom 8 bits 2D400008 # SARI R0 8 ; Drop the bottom 8 bits
05020009 # AND R0 R0 R9 ; Mask out everything but bottom bits 09000319 # SWAP R1 R9 ; Write the byte
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02 42100200 # FPUTC ; To TAPE_02
# ;; Store Lower byte # ;; Store Lower byte
05020029 # AND R0 R2 R9 ; Drop everything but the bottom 8 bits B00300FF # ANDI R0 R3 0xFF ; Preserve bottom half for later
42100200 # FPUTC ; Write the byte to TAPE_02 42100200 # FPUTC ; Write the byte to TAPE_02
0D01001D # RET R13 09000319 # SWAP R1 R9 ; Restore Read
3C00FF74 # JUMP @loop
# hex # ;; Hex function
# ;; Returns hex value of ascii char
# ;; Or -1 if not a hex char
#:hex 118
# ;; Deal with line comments starting with # # ;; Deal with line comments starting with #
1FE00023 # CMPUI R14 R0 35 A0300023 # CMPSKIPI.NE R0 35
2C5E0060 # JUMP.E R14 @ascii_comment 3C000058 # JUMP @ascii_comment
# ;; Deal with line comments starting with ; # ;; Deal with line comments starting with ;
1FE0003b # CMPUI R14 R0 59 A030003B # CMPSKIPI.NE R0 59
2C5E0058 # JUMP.E R14 @ascii_comment 3C000050 # JUMP @ascii_comment
# ;; Deal with all ascii less than '0' # ;; Deal with all ascii less than '0'
1FE00030 # CMPUI R14 R0 48 A0100030 # CMPSKIPI.GE R0 48
2C8E0048 # JUMP.L R14 @ascii_other 3C000054 # JUMP @ascii_other
# ;; Deal with '0'-'9' # ;; Deal with '0'-'9'
1FE00039 # CMPUI R14 R0 57 A0000039 # CMPSKIPI.G R0 57
2C7E0028 # JUMP.LE R14 @ascii_num 3C000028 # JUMP @ascii_num
# ;; Deal with all ascii less than 'A' # ;; Deal with all ascii less than 'A'
1FE00041 # CMPUI R14 R0 65 A0100041 # CMPSKIPI.GE R0 65
2C8E0038 # JUMP.L R14 @ascii_other 3C000044 # JUMP @ascii_other
# ;; Deal with 'A'-'F' # ;; Deal with 'A'-'F'
1FE00046 # CMPUI R14 R0 70 A0000046 # CMPSKIPI.G R0 70
2C7E0028 # JUMP.LE R14 @ascii_high 3C000028 # JUMP @ascii_high
# ;; Deal with all ascii less than 'a' # ;; Deal with all ascii less than 'a'
1FE00061 # CMPUI R14 R0 97 A0100061 # CMPSKIPI.GE R0 97
2C8E0028 # JUMP.L R14 @ascii_other 3C000034 # JUMP @ascii_other
# ;; Deal with 'a'-'f' # ;; Deal with 'a'-'f'
1FE00066 # CMPUI R14 R0 102 A0000066 # CMPSKIPI.G R0 102
2C7E0010 # JUMP.LE R14 @ascii_low 3C000010 # JUMP @ascii_low
# ;; Ignore the rest # ;; Ignore the rest
3C00001c # JUMP @ascii_other 3C000028 # JUMP @ascii_other
# ascii_num #:ascii_num 15c
11000030 # SUBUI R0 R0 48 11000030 # SUBUI R0 R0 48
0D01001D # RET R13 0D01000E # JSR_COROUTINE R14
# ascii_low #:ascii_low 164
11000057 # SUBUI R0 R0 87 11000057 # SUBUI R0 R0 87
0D01001D # RET R13 0D01000E # JSR_COROUTINE R14
# ascii_high #:ascii_high 16c
11000037 # SUBUI R0 R0 55 11000037 # SUBUI R0 R0 55
0D01001D # RET R13 0D01000E # JSR_COROUTINE R14
# ascii_other #:ascii_comment 174
0D000030 # TRUE R0
0D01001D # RET R13
# ascii_comment
2D211100 # LOADUI R1 0x1100 ; Read from TAPE_01
42100100 # FGETC ; Read another char 42100100 # FGETC ; Read another char
1FE0000a # CMPUI R14 R0 10 ; Stop at the end of line A020000A # CMPSKIPI.E R0 10 ; Stop at the end of line
2D210000 # LOADUI R1 0 ; Write to TTY 3C00FFF8 # JUMP @ascii_comment ; Otherwise keep looping
42100200 # FPUTC ; The char we just read
2C6Effec # JUMP.NE R14 @ascii_comment ; Otherwise keep looping
3C00ffe0 # JUMP @ascii_other
# finish #:ascii_other 180
0D000030 # TRUE R0
0D01000E # JSR_COROUTINE R14
#:finish 188
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01 2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE 42100002 # FCLOSE
2D201101 # LOADUI R0 0x1101 ; Close TAPE_02 2D201101 # LOADUI R0 0x1101 ; Close TAPE_02
@ -244,4 +224,4 @@ A0100000 # CMPSKIPI.GE R0 0
FFFFFFFF # HALT FFFFFFFF # HALT
# ;; Where all of our pointers will be stored for our locations # ;; Where all of our pointers will be stored for our locations
# table #:table 19c

View File

@ -1,265 +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
2D28 @z # LOADUI R8 @table ; Where we are putting our address pointers
2D2900ff # LOADUI R9 0xFF ; Byte mask
2D2A000f # LOADUI R10 0x0F ; nybble mask
2D2B0001 # LOADUI R11 1 ; Our toggle
0D00002C # FALSE R12 ; Our PC counter
2D2D0600 # LOADUI R13 0x600 ; Where we are starting our Stack
# ;; We will be using R14 for our condition codes
# ;; We will be using R15 for holding our processed nybbles
# ;; Prep TAPE_01
2D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
# ;; Prep TAPE_02
2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
# ;; Function for collecting the address of all labels
# getLables
:a
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
3C00 @e # JUMP @stage2
# ;; Check for Label
A030003a # CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label
2D0D @d # CALLI R13 @storeLabel
# ;; Check for pointer to label
1FE00040 # CMPUI R14 R0 64 ; If the Char is @ the next char is the pointer to a label
2C6E @b # JUMP.NE R14 @.L0
# ;; Ignore the pointer for now
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
0FCC0002 # ADDUI R12 R12 2 ; The pointer will end up taking 2 bytes
3C00 @a # JUMP @getLables
# .L0
:b
# ;; Otherwise attempt to process
2D0D @k # CALLI R13 @hex ; Convert it
A0100000 # CMPSKIPI.GE R0 0 ; Don't record, nonhex values
3C00 @a # JUMP @getLables ; Move onto Next char
# ;; Determine if we got a full byte
2C9B @c # JUMP.Z R11 @.L1 ; Jump if toggled
# ;; Deal with case of first half of byte
0D00002B # FALSE R11 ; Flip the toggle
3C00 @a # JUMP @getLables
# .L1
:c
# ;; Deal with case of second half of byte
0D00003B # TRUE R11 ; Flip the toggle
0FCC0001 # ADDUI R12 R12 1 ; increment PC now that we have a full byte
3C00 @a # JUMP @getLables
# ;; Function for storing the address of the label
# storeLabel
:d
# ;; Get the char of the Label
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; We require 4 bytes to store the pointer values
2D500002 # SL0I R0 2 ; Thus we multiply our label by 4
# ;; Store the current Program counter
05048C80 # STOREX R12 R8 R0
# ;; Label is safely stored, return
0D01001D # RET R13
# ;; Main Functionality
# stage2
:e
# ;; We first need to rewind tape_01 to perform our second pass
2D201100 # LOADUI R0 0x1100
42100003 # REWIND
# ;; Reset our toggle and counter, just in case
2D2B0001 # LOADUI R11 1 ; Our toggle
0D00002C # FALSE R12 ; Our PC counter
# loop
:f
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Check for EOF
A0100000 # CMPSKIPI.GE R0 0
3C00 @q # JUMP @finish
# ;; Check for Label
1FE0003a # CMPUI R14 R0 58 ; Make sure we jump over the label
2C6E @g # JUMP.NE R14 @.L97
# ;; Consume next char
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
3C00 @f # JUMP @loop
# .L97
:g
# ;; Check for Pointer
1FE00040 # CMPUI R14 R0 64 ; If it is a pointer Deal with it
2C6E @h # JUMP.NE R14 @.L98 ; Otherwise attempt to process it
2D0D @j # CALLI R13 @storePointer
3C00 @f # JUMP @loop
# .L98
:h
# ;; Process Char
2D210000 # LOADUI R1 0 ; Write to Char to TTY
42100200 # FPUTC ; Print the Char
2D0D @k # CALLI R13 @hex ; Convert it
12E00000 # CMPI R14 R0 0 ; Check if it is hex
2C8E @f # JUMP.L R14 @loop ; Don't use nonhex chars
2C9B @i # JUMP.Z R11 @.L99 ; Jump if toggled
# ;; Process first byte of pair
05020F0A # AND R15 R0 R10 ; Store First nibble
0D00002B # FALSE R11 ; Flip the toggle
3C00 @f # JUMP @loop
# .L99
:i
2D5F0004 # SL0I R15 4 ; Shift our first nibble
0502000A # AND R0 R0 R10 ; Mask out top
0500000F # ADD R0 R0 R15 ; Combine nibbles
0D00003B # TRUE R11 ; Flip the toggle
2D211101 # LOADUI R1 0x1101 ; Write the combined byte
42100200 # FPUTC ; To TAPE_02
0FCC0001 # ADDUI R12 R12 1 ; increment PC now that we have a full byte
3C00 @f # JUMP @loop ; Try to get more bytes
# storePointer
:j
# ;; Correct the PC to reflect the size of the pointer
0FCC0002 # ADDUI R12 R12 2 ; Exactly 2 bytes
# ;; Get the char of the Label
2D211100 # LOADUI R1 0x1100 ; Read from tape_01
42100100 # FGETC ; Read a Char
# ;; Since we stored a full pointer taking up 4 bytes
2D500002 # SL0I R0 2 ; Thus we multiply our label by 4 to get where it is stored
05038280 # LOADX R2 R8 R0 ; Load the address of the label
# ;; We now have to calculate the distance and store the 2 bytes
0500222C # SUB R2 R2 R12 ; First determine the difference between the current PC and the stored PC of the label
0F220004 # ADDUI R2 R2 4 ; Adjust for relative positioning
# ;; Store Upper byte
09000402 # COPY R0 R2
2D400008 # SARI R0 8 ; Drop the bottom 8 bits
05020009 # AND R0 R0 R9 ; Mask out everything but bottom bits
2D211101 # LOADUI R1 0x1101 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Store Lower byte
05020029 # AND R0 R2 R9 ; Drop everything but the bottom 8 bits
42100200 # FPUTC ; Write the byte to TAPE_02
0D01001D # RET R13
# hex
:k
# ;; Deal with line comments starting with #
1FE00023 # CMPUI R14 R0 35
2C5E @p # JUMP.E R14 @ascii_comment
# ;; Deal with line comments starting with ;
1FE0003b # CMPUI R14 R0 59
2C5E @p # JUMP.E R14 @ascii_comment
# ;; Deal with all ascii less than '0'
1FE00030 # CMPUI R14 R0 48
2C8E @o # JUMP.L R14 @ascii_other
# ;; Deal with '0'-'9'
1FE00039 # CMPUI R14 R0 57
2C7E @l # JUMP.LE R14 @ascii_num
# ;; Deal with all ascii less than 'A'
1FE00041 # CMPUI R14 R0 65
2C8E @o # JUMP.L R14 @ascii_other
# ;; Deal with 'A'-'F'
1FE00046 # CMPUI R14 R0 70
2C7E @n # JUMP.LE R14 @ascii_high
# ;; Deal with all ascii less than 'a'
1FE00061 # CMPUI R14 R0 97
2C8E @o # JUMP.L R14 @ascii_other
# ;; Deal with 'a'-'f'
1FE00066 # CMPUI R14 R0 102
2C7E @m # JUMP.LE R14 @ascii_low
# ;; Ignore the rest
3C00 @o # JUMP @ascii_other
# ascii_num
:l
11000030 # SUBUI R0 R0 48
0D01001D # RET R13
# ascii_low
:m
11000057 # SUBUI R0 R0 87
0D01001D # RET R13
# ascii_high
:n
11000037 # SUBUI R0 R0 55
0D01001D # RET R13
# ascii_other
:o
0D000030 # TRUE R0
0D01001D # RET R13
# ascii_comment
:p
2D211100 # LOADUI R1 0x1100 ; Read from TAPE_01
42100100 # FGETC ; Read another char
1FE0000a # CMPUI R14 R0 10 ; Stop at the end of line
2D210000 # LOADUI R1 0 ; Write to TTY
42100200 # FPUTC ; The char we just read
2C6E @p # JUMP.NE R14 @ascii_comment ; Otherwise keep looping
3C00 @o # JUMP @ascii_other
# finish
:q
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
2D201101 # LOADUI R0 0x1101 ; Close TAPE_02
42100002 # FCLOSE
FFFFFFFF # HALT
# ;; Where all of our pointers will be stored for our locations
# table
:z

View File

@ -15,13 +15,10 @@
; along with stage0. If not, see <http://www.gnu.org/licenses/>. ; along with stage0. If not, see <http://www.gnu.org/licenses/>.
:start :start
LOADUI R8 @table ; Where we are putting our address pointers LOADUI R11 $table ; Where we are putting our address pointers
LOADUI R9 0xFF ; Byte mask TRUE R12 ; Our toggle
LOADUI R10 0x0F ; nybble mask FALSE R13 ; Our PC counter
LOADUI R11 1 ; Our toggle LOADUI R14 $getLables_2 ; our first iterator
FALSE R12 ; Our PC counter
LOADUI R13 0x600 ; Where we are starting our Stack
;; We will be using R14 for our condition codes
;; We will be using R15 for holding our processed nybbles ;; We will be using R15 for holding our processed nybbles
;; Prep TAPE_01 ;; Prep TAPE_01
@ -32,150 +29,135 @@
LOADUI R0 0x1101 LOADUI R0 0x1101
FOPEN_WRITE FOPEN_WRITE
LOADUI R1 0x1100 ; Read from tape_01
;; Function for collecting the address of all labels ;; Function for collecting the address of all labels
:getLables :getLables
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char FGETC ; Read a Char
;; Check for EOF ;; Check for EOF
CMPSKIPI.GE R0 0 JUMP.NP R0 @stage2
JUMP @stage2
;; Check for Label ;; Check for Label
CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label
CALLI R13 @storeLabel JUMP @storeLabel
;; Check for pointer to label ;; Check for pointer to label
CMPUI R14 R0 64 ; If the Char is @ the next char is the pointer to a label CMPSKIPI.NE R0 64 ; If the Char is @ the next char is the pointer to a label
JUMP.NE R14 @.L0 JUMP @ignorePointer
;; Ignore the pointer for now
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char
ADDUI R12 R12 2 ; The pointer will end up taking 2 bytes
JUMP @getLables
:.L0
;; Otherwise attempt to process ;; Otherwise attempt to process
CALLI R13 @hex ; Convert it JUMP @hex ; Convert it
CMPSKIPI.GE R0 0 ; Don't record, nonhex values :getLables_2
JUMP @getLables ; Move onto Next char JUMP.NP R0 @getLables ; Don't record, nonhex values
NOT R12 R12 ; Flip the toggle
JUMP.Z R12 @getLables ; First half doesn't need anything
;; Determine if we got a full byte ;; Deal with case of second half of byte
JUMP.Z R11 @.L1 ; Jump if toggled ADDUI R13 R13 1 ; increment PC now that we have a full byte
;; Deal with case of first half of byte
FALSE R11 ; Flip the toggle
JUMP @getLables JUMP @getLables
:.L1 :ignorePointer
;; Deal with case of second half of byte ;; Ignore the pointer for now
TRUE R11 ; Flip the toggle FGETC ; Read a Char
ADDUI R12 R12 1 ; increment PC now that we have a full byte ADDUI R13 R13 2 ; The pointer will end up taking 2 bytes
JUMP @getLables JUMP @getLables
;; Function for storing the address of the label ;; Function for storing the address of the label
:storeLabel :storeLabel
;; Get the char of the Label ;; Get the char of the Label
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char FGETC ; Read a Char
;; We require 4 bytes to store the pointer values ;; We require 2 bytes to store the pointer values
SL0I R0 2 ; Thus we multiply our label by 4 SL0I R0 1 ; Thus we multiply our label by 2
;; Store the current Program counter ;; Store the current Program counter
STOREX R12 R8 R0 STOREX16 R13 R11 R0
;; Label is safely stored, return ;; Label is safely stored, return
RET R13 JUMP @getLables
;; Main Functionality
;; Now that we have all of the label addresses,
;; We can process input to produce our output
:stage2 :stage2
;; We first need to rewind tape_01 to perform our second pass ;; We first need to rewind tape_01 to perform our second pass
LOADUI R0 0x1100 LOADUI R0 0x1100
REWIND REWIND
;; Reset our toggle and counter, just in case ;; Reset our toggle and counter
LOADUI R11 1 ; Our toggle LOADUI R9 0x1101 ; Where to write the combined byte
FALSE R12 ; Our PC counter TRUE R12 ; Our toggle
FALSE R13 ; Our PC counter
LOADUI R14 $loop_hex ; The hex return target
:loop :loop
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char FGETC ; Read a Char
;; Check for EOF ;; Check for EOF
CMPSKIPI.GE R0 0 JUMP.NP R0 @finish
JUMP @finish
;; Check for Label ;; Check for Label
CMPUI R14 R0 58 ; Make sure we jump over the label CMPSKIPI.NE R0 58 ; Make sure we jump over the label
JUMP.NE R14 @.L97 JUMP @ignoreLabel
;; Consume next char
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char
JUMP @loop
:.L97
;; Check for Pointer ;; Check for Pointer
CMPUI R14 R0 64 ; If it is a pointer Deal with it CMPSKIPI.NE R0 64 ; If it is a pointer Deal with it
JUMP.NE R14 @.L98 ; Otherwise attempt to process it JUMP @storePointer
CALLI R13 @storePointer
JUMP @loop
:.L98
;; Process Char ;; Process Char
LOADUI R1 0 ; Write to Char to TTY JUMP @hex ; Convert it
FPUTC ; Print the Char
CALLI R13 @hex ; Convert it :loop_hex
CMPI R14 R0 0 ; Check if it is hex JUMP.NP R0 @loop ; Don't use nonhex chars
JUMP.L R14 @loop ; Don't use nonhex chars NOT R12 R12 ; Flip the toggle
JUMP.Z R11 @.L99 ; Jump if toggled JUMP.NZ R12 @loop_second_nybble ; Jump if toggled
;; Process first byte of pair ;; Process first byte of pair
AND R15 R0 R10 ; Store First nibble ANDI R15 R0 0xF ; Store First nibble
FALSE R11 ; Flip the toggle
JUMP @loop JUMP @loop
:.L99 :loop_second_nybble
SL0I R15 4 ; Shift our first nibble SL0I R15 4 ; Shift our first nibble
AND R0 R0 R10 ; Mask out top ANDI R0 R0 0xF ; Mask out top
ADD R0 R0 R15 ; Combine nibbles ADD R0 R0 R15 ; Combine nibbles
TRUE R11 ; Flip the toggle SWAP R1 R9 ; Set to write to tape_2
LOADUI R1 0x1101 ; Write the combined byte
FPUTC ; To TAPE_02 FPUTC ; To TAPE_02
ADDUI R12 R12 1 ; increment PC now that we have a full byte SWAP R1 R9 ; Restore from tape_1
ADDUI R13 R13 1 ; increment PC now that we have a full byte
JUMP @loop ; Try to get more bytes JUMP @loop ; Try to get more bytes
:ignoreLabel
;; Consume next char
FGETC ; Read a Char
JUMP @loop
:storePointer :storePointer
;; Correct the PC to reflect the size of the pointer ;; Correct the PC to reflect the size of the pointer
ADDUI R12 R12 2 ; Exactly 2 bytes ADDUI R13 R13 2 ; Exactly 2 bytes
;; Get the char of the Label ;; Get the char of the Label
LOADUI R1 0x1100 ; Read from tape_01
FGETC ; Read a Char FGETC ; Read a Char
;; Since we stored a full pointer taking up 4 bytes ;; Since we stored a short pointer taking up 2 bytes
SL0I R0 2 ; Thus we multiply our label by 4 to get where it is stored SL0I R0 1 ; Thus we multiply our label by 2 to get where it is stored
LOADX R2 R8 R0 ; Load the address of the label LOADXU16 R3 R11 R0 ; Load the address of the label
;; We now have to calculate the distance and store the 2 bytes ;; We now have to calculate the distance and store the 2 bytes
SUB R2 R2 R12 ; First determine the difference between the current PC and the stored PC of the label SUB R3 R3 R13 ; First determine the difference between the current PC and the stored PC of the label
ADDUI R2 R2 4 ; Adjust for relative positioning ADDUI R3 R3 4 ; Adjust for relative positioning
;; Store Upper byte ;; Store Upper byte
COPY R0 R2 ANDI R0 R3 0xFF00 ; Mask out everything but top byte
SARI R0 8 ; Drop the bottom 8 bits SARI R0 8 ; Drop the bottom 8 bits
AND R0 R0 R9 ; Mask out everything but bottom bits SWAP R1 R9 ; Write the byte
LOADUI R1 0x1101 ; Write the byte
FPUTC ; To TAPE_02 FPUTC ; To TAPE_02
;; Store Lower byte ;; Store Lower byte
AND R0 R2 R9 ; Drop everything but the bottom 8 bits ANDI R0 R3 0xFF ; Preserve bottom half for later
FPUTC ; Write the byte to TAPE_02 FPUTC ; Write the byte to TAPE_02
RET R13 SWAP R1 R9 ; Restore Read
JUMP @loop
;; Hex function ;; Hex function
@ -183,52 +165,48 @@
;; Or -1 if not a hex char ;; Or -1 if not a hex char
:hex :hex
;; Deal with line comments starting with # ;; Deal with line comments starting with #
CMPUI R14 R0 35 CMPSKIPI.NE R0 35
JUMP.E R14 @ascii_comment JUMP @ascii_comment
;; Deal with line comments starting with ; ;; Deal with line comments starting with ;
CMPUI R14 R0 59 CMPSKIPI.NE R0 59
JUMP.E R14 @ascii_comment JUMP @ascii_comment
;; Deal with all ascii less than '0' ;; Deal with all ascii less than '0'
CMPUI R14 R0 48 CMPSKIPI.GE R0 48
JUMP.L R14 @ascii_other JUMP @ascii_other
;; Deal with '0'-'9' ;; Deal with '0'-'9'
CMPUI R14 R0 57 CMPSKIPI.G R0 57
JUMP.LE R14 @ascii_num JUMP @ascii_num
;; Deal with all ascii less than 'A' ;; Deal with all ascii less than 'A'
CMPUI R14 R0 65 CMPSKIPI.GE R0 65
JUMP.L R14 @ascii_other JUMP @ascii_other
;; Deal with 'A'-'F' ;; Deal with 'A'-'F'
CMPUI R14 R0 70 CMPSKIPI.G R0 70
JUMP.LE R14 @ascii_high JUMP @ascii_high
;; Deal with all ascii less than 'a' ;; Deal with all ascii less than 'a'
CMPUI R14 R0 97 CMPSKIPI.GE R0 97
JUMP.L R14 @ascii_other JUMP @ascii_other
;; Deal with 'a'-'f' ;; Deal with 'a'-'f'
CMPUI R14 R0 102 CMPSKIPI.G R0 102
JUMP.LE R14 @ascii_low JUMP @ascii_low
;; Ignore the rest ;; Ignore the rest
JUMP @ascii_other JUMP @ascii_other
:ascii_num :ascii_num
SUBUI R0 R0 48 SUBUI R0 R0 48
RET R13 JSR_COROUTINE R14
:ascii_low :ascii_low
SUBUI R0 R0 87 SUBUI R0 R0 87
RET R13 JSR_COROUTINE R14
:ascii_high :ascii_high
SUBUI R0 R0 55 SUBUI R0 R0 55
RET R13 JSR_COROUTINE R14
:ascii_comment
FGETC ; Read another char
CMPSKIPI.E R0 10 ; Stop at the end of line
JUMP @ascii_comment ; Otherwise keep looping
:ascii_other :ascii_other
TRUE R0 TRUE R0
RET R13 JSR_COROUTINE R14
:ascii_comment
LOADUI R1 0x1100 ; Read from TAPE_01
FGETC ; Read another char
CMPUI R14 R0 10 ; Stop at the end of line
LOADUI R1 0 ; Write to TTY
FPUTC ; The char we just read
JUMP.NE R14 @ascii_comment ; Otherwise keep looping
JUMP @ascii_other
:finish :finish
LOADUI R0 0x1100 ; Close TAPE_01 LOADUI R0 0x1100 ; Close TAPE_01
@ -237,6 +215,5 @@
FCLOSE FCLOSE
HALT HALT
;; Where all of our pointers will be stored for our locations ;; Where all of our pointers will be stored for our locations
:table :table

View File

@ -6,5 +6,5 @@ b3a910f18c6bc0ef4aa7a53cb3f0216a9f143319da67ed2a02210fe88b1e1131 roms/forth
24a4d74eb2eb7a82e68335643855658b27b5a6c3b13db473539f3e08d6f26ceb roms/SET 24a4d74eb2eb7a82e68335643855658b27b5a6c3b13db473539f3e08d6f26ceb roms/SET
0a427b14020354d1c785f5f900677e0059fce8f8d4456e9c19e5528cb17101eb roms/stage0_monitor 0a427b14020354d1c785f5f900677e0059fce8f8d4456e9c19e5528cb17101eb roms/stage0_monitor
85e5c06ac07f2b97d01dfb5454f5a698b3ec6c21fe53bf3fa57b386aac7b9601 roms/stage1_assembler-0 85e5c06ac07f2b97d01dfb5454f5a698b3ec6c21fe53bf3fa57b386aac7b9601 roms/stage1_assembler-0
e4f0ed6e78ae79bb5e4a4fbde36f085dd0469cd6ae036dce5953b3d1c89801ce roms/stage1_assembler-1 e59338381ca3ab01a14fa0fc85d0fa1c6e4d59a06ac2d9d75668d878ab469769 roms/stage1_assembler-1
61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99 roms/stage1_assembler-2 61c1b0f2f628847d9491bd678ac7a23231527cc36493b321612f191674ff3c99 roms/stage1_assembler-2