From 8e34f343cb7eafcdbb345b46ea4474aa3c45468b Mon Sep 17 00:00:00 2001 From: Jeremiah Orians Date: Sun, 26 Jun 2016 20:18:19 -0400 Subject: [PATCH] Created a hex assembler that supports single character labels with both forward and backward references --- stage1/stage1_assembler-1a.hex | 231 +++++++++++++++++++++++++++++++++ stage1/stage1_assembler-1a.s | 220 +++++++++++++++++++++++++++++++ 2 files changed, 451 insertions(+) create mode 100644 stage1/stage1_assembler-1a.hex create mode 100644 stage1/stage1_assembler-1a.s diff --git a/stage1/stage1_assembler-1a.hex b/stage1/stage1_assembler-1a.hex new file mode 100644 index 0000000..0d89593 --- /dev/null +++ b/stage1/stage1_assembler-1a.hex @@ -0,0 +1,231 @@ +# start +2D2801e8 # 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 +2D211100 # LOADUI R1 0x1100 ; Read from tape_01 +42100100 # FGETC ; Read a Char + +# ;; Check for EOF +A0100000 # CMPSKIP.GE R0 0 +3C00005c # JUMP @stage2 + +# ;; Check for Label +A030003a # CMPSKIP.NE R0 58 ; If the Char is : the next char is the label +2D0D0040 # 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 +2C6E0014 # 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 +3C00ffd4 # JUMP @getLables + +# .L0 +# ;; Otherwise attempt to process +2D0D00fc # CALLI R13 @hex ; Convert it +A0100000 # CMPSKIP.GE R0 0 ; Don't record, nonhex values +3C00ffc8 # JUMP @getLables ; Move onto Next char + +# ;; Determine if we got a full byte +2C9B000c # JUMP.Z R11 @.L1 ; Jump if toggled + +# ;; 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 +0D00003B # TRUE R11 ; Flip the toggle +0FCC0001 # ADDUI R12 R12 1 ; increment PC now that we have a full byte +3C00ffb0 # JUMP @getLables + +# ;; Function for storing the address of the label +# storeLabel +# ;; 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 +# ;; 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 +2D211100 # LOADUI R1 0x1100 ; Read from tape_01 +42100100 # FGETC ; Read a Char + +# ;; Check for EOF +A0100000 # CMPSKIP.GE R0 0 +3C000128 # JUMP @finish + +# ;; Check for Label +1FE0003a # CMPUI R14 R0 58 ; Make sure we jump over the label +2C6E0010 # JUMP.NE R14 @.L97 + +# ;; Consume next char +2D211100 # LOADUI R1 0x1100 ; Read from tape_01 +42100100 # FGETC ; Read a Char +3C00ffe0 # JUMP @loop + +# .L97 +# ;; Check for Pointer +1FE00040 # CMPUI R14 R0 64 ; If it is a pointer Deal with it +2C6E000c # JUMP.NE R14 @.L98 ; Otherwise attempt to process it +2D0D004c # CALLI R13 @storePointer +3C00ffd0 # JUMP @loop + +# .L98 +# ;; Process Char +2D210000 # LOADUI R1 0 ; Write to Char to TTY +42100200 # FPUTC ; Print the Char +2D0D0078 # CALLI R13 @hex ; Convert it +12E00000 # CMPI R14 R0 0 ; Check if it is hex +2C8Effbc # JUMP.L R14 @loop ; Don't use nonhex chars +2C9B0010 # 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 +3C00ffac # JUMP @loop + +# .L99 +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 +3C00ff8c # JUMP @loop ; Try to get more bytes + +# storePointer +# ;; 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 +# ;; 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 +0D01001D # RET R13 + +# ascii_low +11000057 # SUBUI R0 R0 87 +0D01001D # RET R13 + +# ascii_high +11000037 # SUBUI R0 R0 55 +0D01001D # RET R13 + +# ascii_other +0D000030 # TRUE R0 +0D01001D # RET R13 + +# 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 +2D210000 # LOADUI R1 0 ; Write to TTY +42100200 # FPUTC ; The char we just read +2C6Effec # JUMP.NE R14 @ascii_comment ; Otherwise keep looping +3C00ffe0 # JUMP @ascii_other + +# finish +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 diff --git a/stage1/stage1_assembler-1a.s b/stage1/stage1_assembler-1a.s new file mode 100644 index 0000000..867a748 --- /dev/null +++ b/stage1/stage1_assembler-1a.s @@ -0,0 +1,220 @@ +start + LOADUI R8 @table ; Where we are putting our address pointers + LOADUI R9 0xFF ; Byte mask + LOADUI R10 0x0F ; nybble mask + LOADUI R11 1 ; Our toggle + 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 + + ;; Prep TAPE_01 + LOADUI R0 0x1100 + FOPEN_READ + + ;; Prep TAPE_02 + LOADUI R0 0x1101 + FOPEN_WRITE + +;; Function for collecting the address of all labels +getLables + LOADUI R1 0x1100 ; Read from tape_01 + FGETC ; Read a Char + + ;; Check for EOF + CMPSKIP.GE R0 0 + JUMP @stage2 + + ;; Check for Label + CMPSKIP.NE R0 58 ; If the Char is : the next char is the label + CALLI R13 @storeLabel + + ;; Check for pointer to label + CMPUI R14 R0 64 ; If the Char is @ the next char is the pointer to a label + JUMP.NE R14 @.L0 + + ;; 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 + CALLI R13 @hex ; Convert it + CMPSKIP.GE R0 0 ; Don't record, nonhex values + JUMP @getLables ; Move onto Next char + + ;; Determine if we got a full byte + JUMP.Z R11 @.L1 ; Jump if toggled + + ;; Deal with case of first half of byte + FALSE R11 ; Flip the toggle + JUMP @getLables + +.L1 + ;; Deal with case of second half of byte + TRUE R11 ; Flip the toggle + ADDUI R12 R12 1 ; increment PC now that we have a full byte + JUMP @getLables + +;; Function for storing the address of the label +storeLabel + ;; Get the char of the Label + LOADUI R1 0x1100 ; Read from tape_01 + FGETC ; Read a Char + + ;; We require 4 bytes to store the pointer values + SL0I R0 2 ; Thus we multiply our label by 4 + + ;; Store the current Program counter + STOREX R12 R8 R0 + + ;; Label is safely stored, return + RET R13 + +;; Main Functionality +stage2 + ;; We first need to rewind tape_01 to perform our second pass + LOADUI R0 0x1100 + REWIND + + ;; Reset our toggle and counter, just in case + LOADUI R11 1 ; Our toggle + FALSE R12 ; Our PC counter + +loop + LOADUI R1 0x1100 ; Read from tape_01 + FGETC ; Read a Char + + ;; Check for EOF + CMPSKIP.GE R0 0 + JUMP @finish + + ;; Check for Label + CMPUI R14 R0 58 ; Make sure we jump over the label + JUMP.NE R14 @.L97 + + ;; Consume next char + LOADUI R1 0x1100 ; Read from tape_01 + FGETC ; Read a Char + JUMP @loop + +.L97 + ;; Check for Pointer + CMPUI R14 R0 64 ; If it is a pointer Deal with it + JUMP.NE R14 @.L98 ; Otherwise attempt to process it + CALLI R13 @storePointer + JUMP @loop + +.L98 + ;; Process Char + LOADUI R1 0 ; Write to Char to TTY + FPUTC ; Print the Char + CALLI R13 @hex ; Convert it + CMPI R14 R0 0 ; Check if it is hex + JUMP.L R14 @loop ; Don't use nonhex chars + JUMP.Z R11 @.L99 ; Jump if toggled + + ;; Process first byte of pair + AND R15 R0 R10 ; Store First nibble + FALSE R11 ; Flip the toggle + JUMP @loop + +.L99 + SL0I R15 4 ; Shift our first nibble + AND R0 R0 R10 ; Mask out top + ADD R0 R0 R15 ; Combine nibbles + TRUE R11 ; Flip the toggle + LOADUI R1 0x1101 ; Write the combined byte + FPUTC ; To TAPE_02 + ADDUI R12 R12 1 ; increment PC now that we have a full byte + JUMP @loop ; Try to get more bytes + +storePointer + ;; Correct the PC to reflect the size of the pointer + ADDUI R12 R12 2 ; Exactly 2 bytes + + ;; Get the char of the Label + LOADUI R1 0x1100 ; Read from tape_01 + FGETC ; Read a Char + + ;; Since we stored a full pointer taking up 4 bytes + SL0I R0 2 ; Thus we multiply our label by 4 to get where it is stored + LOADX R2 R8 R0 ; Load the address of the label + + ;; 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 + ADDUI R2 R2 4 ; Adjust for relative positioning + + ;; Store Upper byte + COPY R0 R2 + SARI R0 8 ; Drop the bottom 8 bits + AND R0 R0 R9 ; Mask out everything but bottom bits + LOADUI R1 0x1101 ; Write the byte + FPUTC ; To TAPE_02 + + ;; Store Lower byte + AND R0 R2 R9 ; Drop everything but the bottom 8 bits + FPUTC ; Write the byte to TAPE_02 + RET R13 + +hex + ;; Deal with line comments starting with # + CMPUI R14 R0 35 + JUMP.E R14 @ascii_comment + ;; Deal with line comments starting with ; + CMPUI R14 R0 59 + JUMP.E R14 @ascii_comment + ;; Deal with all ascii less than '0' + CMPUI R14 R0 48 + JUMP.L R14 @ascii_other + ;; Deal with '0'-'9' + CMPUI R14 R0 57 + JUMP.LE R14 @ascii_num + ;; Deal with all ascii less than 'A' + CMPUI R14 R0 65 + JUMP.L R14 @ascii_other + ;; 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 + ;; Ignore the rest + JUMP @ascii_other + +ascii_num + SUBUI R0 R0 48 + RET R13 +ascii_low + SUBUI R0 R0 87 + RET R13 +ascii_high + SUBUI R0 R0 55 + RET R13 +ascii_other + TRUE R0 + RET R13 +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 + LOADUI R0 0x1100 ; Close TAPE_01 + FCLOSE + LOADUI R0 0x1101 ; Close TAPE_02 + FCLOSE + HALT + + ;; Where all of our pointers will be stored for our locations +table