aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Comeaux <jacquesrcomeaux@protonmail.com>2024-05-29 08:15:09 -0500
committerJacques Comeaux <jacquesrcomeaux@protonmail.com>2024-05-29 08:15:09 -0500
commit86b72b11d6abcc602a93aa480f27644cc0b34373 (patch)
tree5c1c7875e9ae3cc72248d5e7dab9af083de98d6d
parente8bc3587cce27b25ba07469964828a327471e5ed (diff)
Use absolute branches for subroutine calls
-rw-r--r--assembler/assemble.s156
-rw-r--r--assembler/instructions7
-rw-r--r--assembler/octal.s116
-rw-r--r--assembler/opcode.s43
-rw-r--r--assembler/register.s73
-rw-r--r--assembler/uart.s107
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