From 86b72b11d6abcc602a93aa480f27644cc0b34373 Mon Sep 17 00:00:00 2001 From: Jacques Comeaux Date: Wed, 29 May 2024 08:15:09 -0500 Subject: Use absolute branches for subroutine calls --- assembler/assemble.s | 156 ++++++++++++++++++++++--------------------------- assembler/instructions | 7 +-- assembler/octal.s | 116 +++++++++++++++--------------------- assembler/opcode.s | 43 ++++++-------- assembler/register.s | 73 +++++++++++------------ assembler/uart.s | 107 ++++++++++++++++----------------- 6 files changed, 228 insertions(+), 274 deletions(-) (limited to 'assembler') 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 -- cgit v1.2.3