diff options
| author | Jacques Comeaux <jacquesrcomeaux@protonmail.com> | 2024-05-29 08:15:09 -0500 | 
|---|---|---|
| committer | Jacques Comeaux <jacquesrcomeaux@protonmail.com> | 2024-05-29 08:15:09 -0500 | 
| commit | 86b72b11d6abcc602a93aa480f27644cc0b34373 (patch) | |
| tree | 5c1c7875e9ae3cc72248d5e7dab9af083de98d6d | |
| parent | e8bc3587cce27b25ba07469964828a327471e5ed (diff) | |
Use absolute branches for subroutine calls
| -rw-r--r-- | assembler/assemble.s | 156 | ||||
| -rw-r--r-- | assembler/instructions | 7 | ||||
| -rw-r--r-- | assembler/octal.s | 116 | ||||
| -rw-r--r-- | assembler/opcode.s | 43 | ||||
| -rw-r--r-- | assembler/register.s | 73 | ||||
| -rw-r--r-- | assembler/uart.s | 107 | 
6 files changed, 228 insertions, 274 deletions
| diff --git a/assembler/assemble.s b/assembler/assemble.s index 6ef1436..04bfb6c 100644 --- a/assembler/assemble.s +++ b/assembler/assemble.s @@ -6,92 +6,78 @@  .global assemble  // TODO: +// - make subroutine addresses explicit  // - test each instruction  // - decide on additional push or pops -// - redo_line is problematic +// - add GO to get_char  // - PP and PL are broken (end char) -assemble: -  PUSH {LR} -  MOVS R6, 0 -  MOVS R0, '  -  MOV R8, R0 -  BL opcode -  MOV R0, R8 -  BL uart_send -  MOVS R7, R4 -main_loop: -  LSRS R0, R7, 8    // just peek -  BNE skip          // if more stuff then skip -  MOVS R0, '\r -  MOV R8, R0        //set end char to carriage return -skip: -  UXTB R0, R7       // store lsb in R0 -  LSRS R1, R0, 4    // upper nibble -  CMP R1, 0xC       // if 0xxxxxxx or 10xxxxxx -  BLO handle_opcode -  CMP R1, 0xE       // if 110xyyyy -  BLO handle_imm -handle_reg:         // if 111xyyyy -  MOVS R1, (1<<4)   // bit 4 mask -  ANDS R0, R1       // get bit 4 -  ADDS R0, 3        // add 3 to it (now 3 or 4) -  BL register       // result is put in R4 -  MOVS R0, 0x0F     // lower nibble mask -  ANDS R0, R7       // store shift amount in R0 -  LSLS R4, R0       // shift the result by the shift amount -  ORRS R6, R4       // OR the register code into the word under construction -  B done_stuff -handle_opcode: -  MOVS R2, 9        // shift amount for 7-bit opcode -  MOVS R1, (1<<7)   // bit 7 mask -  TST R0, R1        // check bit 7 -  BEQ fin           // if zero done -  BICS R0, R1       // clear bit 7 -  MOVS R2, 11       // shift amount for 5-bit opcode high -  MOVS R1, (1<<5)   // bit 5 mask -  TST R0, R1        // check bit 5 -  BEQ fin           // if zero done -  BICS R0, R1       // clear bit 5 -  MOVS R2, 6        // shift amount for 5-bit opcode low -fin: -  LSLS R0, R2 -  ORRS R6, R0 -  B here -handle_imm: -  MOVS R1, 0x0F  // lower nibble mask -  ANDS R0, R1    // store immediate width in R0 -  BL octal       // result is put in R4 -  LSLS R0, R7, 27 -  LSRS R0, 31 -  MOVS R2, 6 -  MULS R0, R2    // R0 has shift amount (0 or 6) -  LSLS R4, R0    // shift the result by the shift amount -  ORRS R6, R4    // OR the immediate into the word under construction -done_stuff: -  MOV R0, R8     // copy the end_char into R0 -  BL uart_send   // echo the space (or carriage return) -here: -  LSRS R7, 0x8   // get next parse instruction -  BNE main_loop  // if it's nonzero there are more things to parse -done: -  MOVS R0, '\n  // send newline -  BL uart_send -  POP {PC} - -.type get_char, %function -.global get_char - -// R8: end_char -get_char: -  PUSH {LR} -  BL uart_recv -  CMP R0, 025 // ^U (NAK) -  BEQ redo_line -  // CMP R0, 004 // ^D (EOT) -  // BEQ done_for_real -  CMP R0, R8 -  POP {PC} -redo_line: -  POP {R0} -  B done +assemble:   PUSH    {LR} +            LDR     R0, =uart_send +            LDR     R1, =get_char +            ADDS    R0, 1 +            ADDS    R1, 1 +            MOV     R9, R0 +            MOV     R10, R1 +            MOVS    R6, 0 +            MOVS    R0, '  +            MOV     R8, R0 +            LDR     R1, =opcode +            ADDS    R1, 1 +            BLX     R1 +            MOV     R0, R8 +            BLX     R9 +            MOVS    R7, R4 +main_loop:  LSRS    R0, R7, 8       // just peek +            BNE     skip            // if more stuff then skip +            MOVS    R0, '\r +            MOV     R8, R0          //set end char to carriage return +skip:       UXTB    R0, R7          // store lsb in R0 +            LSRS    R1, R0, 4       // upper nibble +            CMP     R1, 0xC         // if 0xxxxxxx or 10xxxxxx +            BLO     handle_op +            CMP     R1, 0xE         // if 110xyyyy +            BLO     handle_imm +handle_reg: MOVS    R1, (1<<4)      // bit 4 mask // if 111xyyyy +            ANDS    R0, R1          // get bit 4 +            ADDS    R0, 3           // add 3 to it (now 3 or 4) +            LDR     R1, =register +            ADDS    R1, 1 +            BLX     R1 +            MOVS    R0, 0x0F        // lower nibble mask +            ANDS    R0, R7          // store shift amount in R0 +            LSLS    R4, R0          // shift the result by the shift amount +            ORRS    R6, R4          // OR the register code into the word under construction +            B       done_stuff +handle_op:  MOVS    R2, 9           // shift amount for 7-bit opcode +            MOVS    R1, (1<<7)      // bit 7 mask +            TST     R0, R1          // check bit 7 +            BEQ     fin             // if zero done +            BICS    R0, R1          // clear bit 7 +            MOVS    R2, 11          // shift amount for 5-bit opcode high +            MOVS    R1, (1<<5)      // bit 5 mask +            TST     R0, R1          // check bit 5 +            BEQ     fin             // if zero done +            BICS    R0, R1          // clear bit 5 +            MOVS    R2, 6           // shift amount for 5-bit opcode low +fin:        LSLS    R0, R2 +            ORRS    R6, R0 +            B       here +handle_imm: MOVS    R1, 0x0F        // lower nibble mask +            ANDS    R0, R1          // store immediate width in R0 +            LDR     R1, =octal +            ADDS    R1, 1 +            BLX     R1              // result is put in R4 +            LSLS    R0, R7, 27 +            LSRS    R0, 31 +            MOVS    R2, 6 +            MULS    R0, R2          // R0 has shift amount (0 or 6) +            LSLS    R4, R0          // shift the result by the shift amount +            ORRS    R6, R4          // OR the immediate into the word under construction +done_stuff: MOV     R0, R8          // copy the end_char into R0 +            BLX     R9              // echo the space (or carriage return) +here:       LSRS    R7, 0x8         // get next parse instruction +            BNE     main_loop       // if it's nonzero there are more things to parse +done:       MOVS    R0, '\n         // send newline +            BLX     R9 +            POP     {PC} diff --git a/assembler/instructions b/assembler/instructions index a028eec..049b830 100644 --- a/assembler/instructions +++ b/assembler/instructions @@ -10,11 +10,8 @@ R5: second-level (octal or register) scratch  R6: word under construction  R7: parse instructions  R8: end_char -R8: -R9: -R10: -R11: -R12: +R9: uart_send +R10: get_char  Encoding diff --git a/assembler/octal.s b/assembler/octal.s index 18abebd..62e2b1e 100644 --- a/assembler/octal.s +++ b/assembler/octal.s @@ -5,71 +5,51 @@  .type octal, %function  .global octal -octal: -  PUSH {LR} -  MOVS R5, R0 - -  // Handle bit-width = 0 -  BNE 30f -10: -  BL get_char -  CMP R0, '0 -  BNE 10b -  BL uart_send -  MOVS R4, 0 -20: -  BL get_char -  BNE 20b -  POP {PC} -30: - -  // R4 will become '1 or '3 or '7 -  MOVS R0, 3 -  CMP R5, 3 -  BHS 40f -  MOVS R0, R5 -40: -  MOVS R4, 1 -  LSLS R4, R0 -  ADDS R4, ('0 - 1) - -  // Get first char -50: -  BL get_char -  CMP R0, '0 -  BLO 50b -  CMP R0, R4 -  BHI 50b -  BL uart_send -  SUBS R0, '0 -  MOVS R4, R0 - -  // Subtract 1, 2, or 3 from bit-width -  MOVS R1, 0 -60: -  ADDS R1, 1 -  LSRS R0, 1 -  BNE 60b -  SUBS R5, R1 - -  // Loop for remaining chars -70: -  CMP R5, 3 -  BLO 80f -  BL get_char -  BEQ 90f -  CMP R0, '0 -  BLO 70b -  CMP R0, '7 -  BHI 70b -  BL uart_send -  SUBS R0, '0 -  LSLS R4, 3 -  ADDS R4, R0 -  SUBS R5, 3 -  B 70b -80: -  BL get_char -  BNE 80b -90: -  POP {PC} +octal:  PUSH    {LR}            // 0c0000 0xB500  ; SAVE LINK REGISTER +        MOVS    R5, R0          // 0x0002 0x0005  ; SAVE BIT WIDTH +        BNE     30f             // 0x0004 0xD1    ; SKIP IF BIT WIDTH != 0 +10:     BLX     R10             // 0x0006 0x      ; GET CHAR +        CMP     R0, '0          // 0x000A 0x2830  ; COMPARE TO '0 CHAR +        BNE     10b             // 0x000C 0xD1    ; GET ANOTHER CHAR IF NOT '0 +        BLX     R9              // 0x000E 0x      ; OTHERWISE ECHO '0 CHAR +        MOVS    R4, 0           // 0x0012 0x2400  ; SET RESULT TO 0 +20:     BLX     R10             // 0x0014 0x      ; GET CHAR +        BNE     20b             // 0x0018 0xD1    ; LOOP IF NOT END CHAR +        POP     {PC}            // 0x001A 0xBD00  ; RETURN IF END CHAR +30:     MOVS    R0, 3           // 0x001C 0x2003  ; DEFAULT TO 3 +        CMP     R5, 3           // 0x001E 0x2D03  ; CHECK BIT WIDTH +        BHS     40f             // 0x0020 0xD2    ; IF BIT WIDTH >= 3 KEEP R0 == 3 +        MOVS    R0, R5          // 0x0022 0x0028  ; IF BIT WIDTH < 3 COPY TO R0 +40:     MOVS    R4, 1           // 0x0024 0x2401  ; 2^0 +        LSLS    R4, R0          // 0x0026 0x4084  ; 2^(MAX(BIT WIDTH, 3)) +        ADDS    R4, ('0 - 1)    // 0x0028 0x342F  ; '1 OR '3 or '7 +50:     BLX     R10             // 0x002A 0x      ; GET FIRST CHAR +        CMP     R0, '0          // 0x002E 0x2830  ; COMPARE WITH '0 +        BLO     50b             // 0x0030 0xD3    ; RETRY IF BELOW OCTAL RANGE +        CMP     R0, R4          // 0x0032 0x42A0  ; COMPARE WITH END CHAR +        BHI     50b             // 0x0034 0xD8    ; RETRY IF ABOVE RANGE +        BLX     R9              // 0x0036 0x      ; ECHO IF IN RANGE +        SUBS    R0, '0          // 0x003A 0x3830  ; GET VALUE FROM CHAR +        MOVS    R4, R0          // 0x003C 0x0004  ; STORE VALUE IN RESULT +        MOVS    R1, 0           // 0x003E 0x2100  ; BIT WIDTH FOR FIRST CHAR +60:     ADDS    R1, 1           // 0x0040 0x3101  ; INCREMENT FIRST CHAR WIDTH +        LSRS    R0, 1           // 0x0042 0x0840  ; SHIFT RIGHT ONE BIT +        BNE     60b             // 0x0044 0x      ; IF NONZERO STAY IN LOOP +        SUBS    R5, R1          // 0x0046 0x1A6D  ; SUBTRACT FIRST CHAR WIDTH FROM TOTAL +70:     CMP     R5, 3           // 0x0048 0x2D03  ; COMPARE BIT WIDTH TO 3 +        BLO     80f             // 0x004A 0xD3    ; EXIT LOOP IF LESS THAN 3 +        BLX     R10             // 0x004C 0x      ; GET ANOTHER CHAR +        BEQ     90f             // 0x0050 0xD0    ; IF END CHAR EXIT LOOP +        CMP     R0, '0          // 0x0052 0x2830  ; BOTTOM OF OCTAL RANGE +        BLO     70b             // 0x0054 0xD3    ; RETRY IF BELOW +        CMP     R0, '7          // 0x0056 0x2837  ; TOP OF OCTAL RANGE +        BHI     70b             // 0x0058 0xD8    ; RETRY IF ABOVE +        BLX     R9              // 0x005A 0x      ; ECHO IF IN RANGE +        SUBS    R0, '0          // 0x005E 0x3830  ; GET VALUE FROM CHAR +        LSLS    R4, 3           // 0x0060 0x00E4  ; SHIFT OLD VALUE BY ONE DIGIT +        ADDS    R4, R0          // 0x0062 0x1824  ; ACCUMULATE INTO VALUE +        SUBS    R5, 3           // 0x0064 0x3D03  ; DECREMENT BIT WIDTH BY 3 +        B       70b             // 0x0066 0xD0    ; LOOP FOR ANOTHER DIGIT +80:     BLX     R10             // 0x0068 0x      ; GET A CHAR +        BNE     80b             // 0x006C 0xD1    ; LOOP UNTIL END CHAR +90:     POP     {PC}            // 0x006E 0xBD00  ; RETURN diff --git a/assembler/opcode.s b/assembler/opcode.s index 18292ad..588d938 100644 --- a/assembler/opcode.s +++ b/assembler/opcode.s @@ -27,30 +27,25 @@  // R4: start of choices, final result (parse instruction)  // R5: choice pointer -opcode: -  PUSH {LR} -  ADR R4, start     // start at the start -get_match: -  BL get_char -  MOV R5, R4        // reset choice pointer -  B first_time      // don't increment pointer on first time -next_choice: -  ADDS R5, 8        // increment choice pointer -first_time: -  LDRB R1, [R5]     // load char -  TST R1, R1        // test if char is zero -  BEQ get_match     // if run out of options, get a new char -  CMP R0, R1        // check if input matches char -  BNE next_choice   // if not match try next option -  BL uart_send      // echo char send if match -  LDR R4, [R5, 4]   // load parse instruction or offset -  LDRB R1, [R5, 1]  // load parse instruction vs offset byte -  TST R1, R1        // check if zero -  BNE get_match     // non-zero means it's an address -get_end_char: -  BL get_char -  BNE get_end_char -  POP {PC}          // zero means it's a parse instruction +opcode: PUSH    {LR} +        ADR     R4, start     // start at the start +10:     BLX     R10 +        MOV     R5, R4        // reset choice pointer +        B       30f           // don't increment pointer on first time +20:     ADDS    R5, 8         // increment choice pointer +30:     LDRB    R1, [R5]      // load char +        TST     R1, R1        // test if char is zero +        BEQ     10b           // if run out of options, get a new char +        CMP     R0, R1        // check if input matches char +        BNE     20b           // if not match try next option +        BLX     R9            // echo char send if match +        LDR     R4, [R5, 4]   // load parse instruction or offset +        LDRB    R1, [R5, 1]   // load parse instruction vs offset byte +        TST     R1, R1        // check if zero +        BNE     10b           // non-zero means it's an address +40:     BLX     R10 +        BNE     40b +        POP     {PC}          // zero means it's a parse instruction  .align 4 diff --git a/assembler/register.s b/assembler/register.s index f8197fd..6728643 100644 --- a/assembler/register.s +++ b/assembler/register.s @@ -5,43 +5,36 @@  .type register, %function  .global register -register: -  PUSH {LR} -  MOV R4, R0 -  LSLS R4, 1 -  ADDS R4, ('0 + 1) -10: -  BL get_char -  CMP R0, 'R -  BNE 10b -  BL uart_send -20: -  BL get_char -  CMP R0, '0 -  BLO 20b -  CMP R0, R4 -  BHI 20b -  BL uart_send -  CMP R0, '1 -  BNE 30f -  CMP R4, '7 -  BEQ 30f -50: -  BL get_char -  BEQ 60f -  CMP R0, '0 -  BLO 50b -  CMP R0, '5 -  BHI 50b -  BL uart_send -  ADDS R0, 10 -30: -  SUBS R0, '0 -  MOV R4, R0 -40: -  BL get_char -  BNE 40b -  POP {PC} -60: -  MOVS R4, 1 -  POP {PC} +register: PUSH    {LR} +          MOV     R4, R0 +          LSLS    R4, 1 +          ADDS    R4, ('0 + 1) +10:       BLX     R10 +          CMP     R0, 'R +          BNE     10b +          BLX     R9 +20:       BLX     R10 +          CMP     R0, '0 +          BLO     20b +          CMP     R0, R4 +          BHI     20b +          BLX     R9 +          CMP     R0, '1 +          BNE     30f +          CMP     R4, '7 +          BEQ     30f +50:       BLX     R10 +          BEQ     60f +          CMP     R0, '0 +          BLO     50b +          CMP     R0, '5 +          BHI     50b +          BLX     R9 +          ADDS    R0, 10 +30:       SUBS    R0, '0 +          MOV     R4, R0 +40:       BLX     R10 +          BNE     40b +          POP     {PC} +60:       MOVS    R4, 1 +          POP     {PC} diff --git a/assembler/uart.s b/assembler/uart.s index b845c8b..8dd6a68 100644 --- a/assembler/uart.s +++ b/assembler/uart.s @@ -7,59 +7,62 @@  .equ UARTFR_OFST,     0x18  .type uart_send, %function -.global uart_send - -uart_send: -  ldr r1, =UART0_BASE -  movs r3, 0b1 << 5 // TX FIFO full -1: -  ldr r2, [r1, UARTFR_OFST] -  tst r2, r3 -  bne 1b -  strb r0, [r1, UARTDR_OFST] -  bx lr -  .type uart_recv, %function -.global uart_recv - -uart_recv: -  ldr r1, =UART0_BASE -  movs r3, 0b1 << 4 // RX FIFO empty -1: -  ldr r2, [r1, UARTFR_OFST] -  tst r2, r3 -  bne 1b -  ldrb r0, [r1, UARTDR_OFST] -  bx lr - +.type get_char, %function  .type send_hex, %function + +.global uart_send +.global uart_recv +.global get_char  .global send_hex -send_hex: -  push {lr} -  movs r4, r0 -  movs r0, '0 -  bl uart_send -  movs r0, 'x -  bl uart_send -  movs r5, 8 // eight nibbles in a word -0: -  movs r0, 28 // rotate left 4 -  rors r4, r0 -  movs r0, 0xF // lowest nibble mask -  ands r0, r4 -  cmp r0, 0x9 // number or letter? -  bhi 1f -  adds r0, '0 -  b 2f -1: -  adds r0, ('A - 0xA) -2: -  bl uart_send -  subs r5, 1 -  bne 0b -  movs r0, '\r -  bl uart_send -  movs r0, '\n -  bl uart_send -  pop {pc} +uart_send:  LDR     R1, =UART0_BASE         // 0x0000 0x4917 +            MOVS    R3, 0b1 << 5            // 0x0002 0x2320  ; TX FIFO FULL +1:          LDR     R2, [R1, UARTFR_OFST]   // 0x0004 0x670A +            TST     R2, R3                  // 0x0006 0x421A +            BNE     1b                      // 0x0008 0xD1FC +            STRB    R0, [R1, UARTDR_OFST]   // 0x000A 0x7008 +            BX      LR                      // 0x000C 0x4770 +uart_recv:  LDR     R1, =UART0_BASE         // 0x000E 0x4914 +            MOVS    R3, 0b1 << 4            // 0x0010 0x2310  ; RX FIFO EMPTY +1:          LDR     R2, [R1, UARTFR_OFST]   // 0x0012 0x670A +            TST     R2, R3                  // 0x0014 0x421A +            BNE     1b                      // 0x0016 0xF1FC +            LDRB    R0, [R1, UARTDR_OFST]   // 0x0018 0x7808 +            BX      LR                      // 0x001A 0x4770 +get_char:   PUSH    {LR}                    // 0x001C 0xB500 +            BL      uart_recv               // 0x001E 0xF7FF +                                            // 0x0020 0xFFF6 +            CMP     R0, R8                  // 0x0022 0x4540 +            POP     {PC}                    // 0x0024 0xBD00 +send_hex:   PUSH    {LR}                    // 0x0026 0xB500 +            MOVS    R4, R0                  // 0x0028 0x0004 +            MOVS    R0, '0                  // 0x002A 0x2030 +            BL      uart_send               // 0x002C 0xF7FF +                                            // 0x002E 0xFFE8 +            MOVS    R0, 'x                  // 0x0030 0x2078 +            BL      uart_send               // 0x0032 0xF7FF +                                            // 0x0034 0xFFE5 +            MOVS    R5, 8                   // 0x0036 0x2508 ; EIGHT NIBBLES IN A WORD +0:          MOVS    R0, 28                  // 0x0038 0x201C ; ROTATE LEFT 4 +            RORS    R4, R0                  // 0x003A 0x41C4 +            MOVS    R0, 0xF                 // 0x003C 0x200F ; LOWEST NIBBLE MASK +            ANDS    R0, R4                  // 0x003E 0x4020 +            CMP     R0, 0x9                 // 0x0040 0x0000 ; NUMBER OR LETTER? +            BHI     1f                      // 0x0042 0xD801 +            ADDS    R0, '0                  // 0x0044 0x3030 +            B       2f                      // 0x0046 0xE000 +1:          ADDS    R0, ('A - 0xA)          // 0x0048 0x3037 +2:          BL      uart_send               // 0x004A 0xF7FF +                                            // 0x004C 0xFFD9 +            SUBS    R5, 1                   // 0x004E 0x3D01 +            BNE     0b                      // 0x0050 0xD1F9 +            MOVS    R0, '\r                 // 0x0052 0x200D +            BL      uart_send               // 0x0054 0xF7FF +                                            // 0x0056 0xFFD4 +            MOVS    R0, '\n                 // 0x0058 0x200A +            BL      uart_send               // 0x005A 0xF7FF +                                            // 0x005C 0xFFD1 +            POP     {PC}                    // 0x005E 0xBD00 +                                            // 0x0060 0x4000 ; UART0_BASE +                                            // 0x0062 0x4003 | 
