From c563ce3ddc2fd35a7d4a00dc38c7c485a6b8118f Mon Sep 17 00:00:00 2001 From: Dmitry Petukhov Date: Sat, 12 Oct 2019 12:31:34 +0500 Subject: [PATCH] reduce stage0_monitor size by 6 bytes (toggle default zero, use mux) The toggle can have default state of zero, and then non-zero means second nybble is processed. That allows to skip initialization of toggle, and save 4 bytes. But then we cannot create value 1 with 4-byte instruction. But we can get something out of this situation: we can initialize R11 to 0x1101, and R15 to 0xF, and then we can get 0x1100 with MUX: MUX R0 R15 R11 R8 ; 0x1100 = ((0x1101 & ~0xF) | (0 | 0xF)) And we will also have value 0xF in R15. 0xF is used twice as immediate thus we save another 4 bytes by using non-immediate instructions two times We save 6 bytes overall. (We lose 2 bytes because we use immediate load to R15) --- bootstrapping Steps.org | 2 +- stage0/stage0_monitor.hex0 | 98 ++++++++++++++++++++------------------ stage0/stage0_monitor.s | 66 +++++++++++++------------ test/SHA256SUMS | 2 +- 4 files changed, 89 insertions(+), 79 deletions(-) diff --git a/bootstrapping Steps.org b/bootstrapping Steps.org index 05b6446..095602f 100644 --- a/bootstrapping Steps.org +++ b/bootstrapping Steps.org @@ -37,7 +37,7 @@ gcc Linux\ Bootstrap/hex.c -o bin/hex Then we can use it to make our bootstrap binary: ./bin/hex < stage0/stage0_monitor.hex0 > roms/stage0_monitor -Which should have the sha256sum of c9d397b195c6ba2bb4b19428d8b21e7737a32e5275f3027270d8925aec878042 +Which should have the sha256sum of a551568d72804a2de6f6f94fcb507452e9d672c7638beb170dde84a9bf7fb82a * Step 2 create a hex assembler Now that we have a Hex monitor, we are now capable of either creating a text file (no ability to correct mistakes along the way) or any arbitrary hex program we want. diff --git a/stage0/stage0_monitor.hex0 b/stage0/stage0_monitor.hex0 index d680dc4..eff1b65 100644 --- a/stage0/stage0_monitor.hex0 +++ b/stage0/stage0_monitor.hex0 @@ -14,83 +14,89 @@ ## You should have received a copy of the GNU General Public License ## along with stage0. If not, see . +# ;; R14 will be storing our condition +# ;; +# ;; R13 will be a stack pointer. It will be zero +# ;; on the start, and the stack grows up. +# ;; This means that when stack is used, the +# ;; first instructions of this program will be +# ;; overwritten. But because this is initialization +# ;; code, it is already not used at the time. +# ;; And the stack usage is fixed - there is only one CALL +# ;; instruction in this file +# ;; +# ;; R2 Is our holder. +# ;; It holds the first nybble of the byte till the second iteration +# ;; +# ;; R12 Is our toggle. It is initialized to zero on start. +# ;; When non-zero, it means that we are processing the second nybble +# ;; +# ;; R8 will hold zero. It is initialized to zero on start. + # :start ; offset = 0 -0D00003C # TRUE R12 ; Our toggle, set to -1 (0xFFFFFFFF) - # ;; Prepare often-used values that will be held in registers -090001AC # ABS R10 R12 ; Set R10 to 1 -E0002D2B1100 # LOADUI R11 0x1100 ; R11 will hold 0x1100 - # - # ;; R14 will be storing our condition - # ;; - # ;; R13 will be a stack pointer. It will be zero - # ;; on the start, and the stack grows up. - # ;; This means that when stack is used, the - # ;; first instructions of this program will be - # ;; overwritten. But because this is initialization - # ;; code, it is already not used at the time. - # ;; And the stack usage is fixed - there is only one CALL - # ;; instruction in this file - # ;; - # ;; R15 Is our holder. It is initialized to zero on start. +E0002D2F000f # LOADUI R15 0xF ; Set R15 to 0xF +E0002D2B1101 # LOADUI R11 0x1101 ; R11 will hold 0x1101 # ;; Prep TAPE_01 -0900040B # COPY R0 R11 ; 0x1100 +01100FB8 # MUX R0 R15 R11 R8 ; 0x1100 = ((0x1101 & ~0xF) | (0 | 0xF)) 42100001 # FOPEN_WRITE # ;; Prep TAPE_02 -050210BA # OR R0 R11 R10 ; 0x1101 +0900040B # COPY R0 R11 ; 0x1101 42100001 # FOPEN_WRITE -# :loop ; offset = 1e +# :loop ; offset = 1c 0D000021 # FALSE R1 ; Read from tty 42100100 # FGETC ; Read a Char E000A030000d # CMPSKIPI.NE R0 13 ; Replace all CR E0002D20000a # LOADUI R0 10 ; WIth LF -42100200 # FPUTC ; Display the Char to User +42100200 # FPUTC + +# ; Display the Char to User # ;; Check for Ctrl-D E000A0300004 # CMPSKIPI.NE R0 4 -3C000108 # JUMP @finish +3C000104 # JUMP @finish # ;; Check for EOF -E0002CC00102 # JUMP.NP R0 @finish +E0002CC000fe # JUMP.NP R0 @finish # ;; Write out unprocessed byte -050211BA # OR R1 R11 R10 ; Write to TAPE_02 +0900041B # COPY R1 R11 ; Write to TAPE_02 42100200 # FPUTC ; Print the Char # ;; Convert byte to nybble -E0002D0D003a # CALLI R13 @hex ; Convert it +E0002D0D0036 # CALLI R13 @hex ; Convert it # ;; Get another byte if nonhex E0002CC0ffc4 # JUMP.NP R0 @loop ; Don't use nonhex chars # ;; Deal with the case of second nybble -E0002C9C000e # JUMP.Z R12 @second_nybble ; Jump if toggled +E0002CAC000c # JUMP.NZ R12 @second_nybble ; Jump if toggled # ;; Process first byte of pair -E100B0F0000f # ANDI R15 R0 0x0F ; Store First nibble -0D00002C # FALSE R12 ; Flip the toggle -3C00ffb0 # JUMP @loop +0502020F # AND R2 R0 R15 ; Store First nibble +0D00003C # TRUE R12 ; Flip the toggle +3C00ffb2 # JUMP @loop # ;; Combined second nybble in pair with first -# :second_nybble ; offset = 6e -E0002D5F0004 # SL0I R15 4 ; Shift our first nibble -E100B000000f # ANDI R0 R0 0x0F ; Mask out top -0500000F # ADD R0 R0 R15 ; Combine nibbles +# :second_nybble ; offset = 6a +E0002D520004 # SL0I R2 4 ; Shift our first nibble +0502000F # AND R0 R0 R15 ; Mask out top +05000002 # ADD R0 R0 R2 ; Combine nibbles # ;; Writeout and prepare for next cycle -0D00003C # TRUE R12 ; Flip the toggle +0D00002C # FALSE R12 ; Flip the toggle # ; Write the combined byte -0900041B # COPY R1 R11 ; To TAPE_01 +01101FB8 # MUX R1 R15 R11 R8 ; To TAPE_01 42100200 # FPUTC -3C00ff90 # JUMP @loop ; Try to get more bytes +3C00ff94 # JUMP @loop ; Try to get more bytes -# :hex ; offset = 8e +# :hex ; offset = 88 # ;; Deal with line comments starting with # E1001FE00023 # CMPUI R14 R0 35 @@ -127,37 +133,37 @@ E0002C7E000e # JUMP.LE R14 @ascii_low # ;; Ignore the rest 3C00001e # JUMP @ascii_other -# :ascii_num ; offset = f2 +# :ascii_num ; offset = ec E10011000030 # SUBUI R0 R0 48 0D01001D # RET R13 -# :ascii_low ; offset = fc +# :ascii_low ; offset = f6 E10011000057 # SUBUI R0 R0 87 0D01001D # RET R13 -# :ascii_high ; offset = 106 +# :ascii_high ; offset = 100 E10011000037 # SUBUI R0 R0 55 0D01001D # RET R13 -# :ascii_other ; offset = 110 +# :ascii_other ; offset = 10a 0D000030 # TRUE R0 0D01001D # RET R13 -# :ascii_comment ; offset = 118 +# :ascii_comment ; offset = 112 0D000021 # FALSE R1 ; Read from tty 42100100 # FGETC ; Read another char E000A030000d # CMPSKIPI.NE R0 13 ; Replace all CR E0002D20000a # LOADUI R0 10 ; WIth LF 42100200 # FPUTC ; Let the user see it E1001FE0000a # CMPUI R14 R0 10 ; Stop at the end of line -050211BA # OR R1 R11 R10 ; Write to TAPE_02 +0900041B # COPY R1 R11 ; Write to TAPE_02 42100200 # FPUTC ; The char we just read E0002C6Effd4 # JUMP.NE R14 @ascii_comment ; Otherwise keep looping 3C00ffc8 # JUMP @ascii_other -# :finish ; offset = 148 -0900040B # COPY R0 R11 ; Close TAPE_01 +# :finish ; offset = 142 +01100FB8 # MUX R0 R15 R11 R8 ; Close TAPE_01 42100002 # FCLOSE -050210BA # OR R0 R11 R10 ; Close TAPE_02 +0900040B # COPY R0 R11 ; Close TAPE_02 42100002 # FCLOSE FFFFFFFF # HALT diff --git a/stage0/stage0_monitor.s b/stage0/stage0_monitor.s index f69bb09..41debfc 100644 --- a/stage0/stage0_monitor.s +++ b/stage0/stage0_monitor.s @@ -14,32 +14,36 @@ ; You should have received a copy of the GNU General Public License ; along with stage0. If not, see . +;; R14 will be storing our condition +;; +;; R13 will be a stack pointer. It will be zero +;; on the start, and the stack grows up. +;; This means that when stack is used, the +;; first instructions of this program will be +;; overwritten. But because this is initialization +;; code, it is already not used at the time. +;; And the stack usage is fixed - there is only one CALL +;; instruction in this file +;; +;; R2 Is our holder. +;; It holds the first nybble of the byte till the second iteration +;; +;; R12 Is our toggle. It is initialized to zero on start. +;; When non-zero, it means that we are processing the second nybble +;; +;; R8 will hold zero. It is initialized to zero on start. + :start - TRUE R12 ; Our toggle, set to -1 (0xFFFFFFFF) - ;; Prepare often-used values that will be held in registers - ABS R10 R12 ; Set R10 to 1 - LOADUI R11 0x1100 ; R11 will hold 0x1100 - - ;; R14 will be storing our condition - ;; - ;; R13 will be a stack pointer. It will be zero - ;; on the start, and the stack grows up. - ;; This means that when stack is used, the - ;; first instructions of this program will be - ;; overwritten. But because this is initialization - ;; code, it is already not used at the time. - ;; And the stack usage is fixed - there is only one CALL - ;; instruction in this file - ;; - ;; R15 Is our holder. It is initialized to zero on start. + LOADUI R15 0xF ; Set R15 to 0xF + LOADUI R11 0x1101 ; R11 will hold 0x1101 ;; Prep TAPE_01 - COPY R0 R11 ; 0x1100 + MUX R0 R15 R11 R8 ; 0x1100 = ((0x1101 & ~0xF) | (0 | 0xF)) FOPEN_WRITE ;; Prep TAPE_02 - OR R0 R11 R10 ; 0x1101 + COPY R0 R11 ; 0x1101 FOPEN_WRITE :loop @@ -59,7 +63,7 @@ JUMP.NP R0 @finish ;; Write out unprocessed byte - OR R1 R11 R10 ; Write to TAPE_02 + COPY R1 R11 ; Write to TAPE_02 FPUTC ; Print the Char ;; Convert byte to nybble @@ -69,23 +73,23 @@ JUMP.NP R0 @loop ; Don't use nonhex chars ;; Deal with the case of second nybble - JUMP.Z R12 @second_nybble ; Jump if toggled + JUMP.NZ R12 @second_nybble ; Jump if toggled ;; Process first byte of pair - ANDI R15 R0 0x0F ; Store First nibble - FALSE R12 ; Flip the toggle + AND R2 R0 R15 ; Store First nibble + TRUE R12 ; Flip the toggle JUMP @loop ;; Combined second nybble in pair with first :second_nybble - SL0I R15 4 ; Shift our first nibble - ANDI R0 R0 0x0F ; Mask out top - ADD R0 R0 R15 ; Combine nibbles + SL0I R2 4 ; Shift our first nibble + AND R0 R0 R15 ; Mask out top + ADD R0 R0 R2 ; Combine nibbles ;; Writeout and prepare for next cycle - TRUE R12 ; Flip the toggle + FALSE R12 ; Flip the toggle ; Write the combined byte - COPY R1 R11 ; To TAPE_01 + MUX R1 R15 R11 R8 ; To TAPE_01 FPUTC JUMP @loop ; Try to get more bytes @@ -136,14 +140,14 @@ LOADUI R0 10 ; WIth LF FPUTC ; Let the user see it CMPUI R14 R0 10 ; Stop at the end of line - OR R1 R11 R10 ; Write to TAPE_02 + COPY R1 R11 ; Write to TAPE_02 FPUTC ; The char we just read JUMP.NE R14 @ascii_comment ; Otherwise keep looping JUMP @ascii_other :finish - COPY R0 R11 ; Close TAPE_01 + MUX R0 R15 R11 R8 ; Close TAPE_01 FCLOSE - OR R0 R11 R10 ; Close TAPE_02 + COPY R0 R11 ; Close TAPE_02 FCLOSE HALT diff --git a/test/SHA256SUMS b/test/SHA256SUMS index 8de36b8..9887970 100644 --- a/test/SHA256SUMS +++ b/test/SHA256SUMS @@ -5,7 +5,7 @@ f4bbf9e9c4828170d0c153ac265382dc705643f95efd2a029243326d426be5a4 roms/forth 2b80849180d5fb3757bcca2471b6337808e5b5ca80b18d93fa82ddef0435b84b roms/lisp 3020b194ead31ae19ba66fc35ed95465514373f6005896350d1608c9efabbdca roms/M0 059d38e34275029f2de5f600f08fe01bd13cd173f7da58e3fbec7114074beff2 roms/SET -c9d397b195c6ba2bb4b19428d8b21e7737a32e5275f3027270d8925aec878042 roms/stage0_monitor +a551568d72804a2de6f6f94fcb507452e9d672c7638beb170dde84a9bf7fb82a roms/stage0_monitor 13b45134a88c1c6db349cb40f82269cee9edfce71ac644dc0e137bad053bf5ce roms/stage1_assembler-0 156f555fce5b02f52445652b1ed0b443295706cdfbe23c5a021bd4efc77179bb roms/stage1_assembler-1 2c02c50958f489a660a4915d2a9e207a0c61f411d42628bdaf4dcf6bf7149a9d roms/stage1_assembler-2