aboutsummaryrefslogtreecommitdiff
path: root/newasm
diff options
context:
space:
mode:
authorJacques Comeaux <jacquesrcomeaux@protonmail.com>2024-08-24 01:14:04 -0500
committerJacques Comeaux <jacquesrcomeaux@protonmail.com>2024-08-24 01:14:04 -0500
commitee01f1a7f1e10be78bcceb4f0f42aa352a6a588f (patch)
tree271e7034ee94e4447784db5b31bf8e332b30fbba /newasm
parent80d8f3ae48255f786bd4d52a1819ea0c339f6946 (diff)
Add parsers for basic instruction typesHEADmaster
Diffstat (limited to 'newasm')
-rw-r--r--newasm/Makefile28
-rw-r--r--newasm/errors.s30
-rw-r--r--newasm/imm.s27
-rw-r--r--newasm/main.s45
-rw-r--r--newasm/optable.s9
-rw-r--r--newasm/parsers/decimal.s4
-rw-r--r--newasm/parsers/immediate.s13
-rw-r--r--newasm/parsers/label.s5
-rw-r--r--newasm/parsers/register.s13
-rw-r--r--newasm/regimm.s37
-rw-r--r--newasm/regreg.s29
-rw-r--r--newasm/regregimm.s47
-rw-r--r--newasm/regregreg.s44
-rw-r--r--newasm/statement.s65
14 files changed, 309 insertions, 87 deletions
diff --git a/newasm/Makefile b/newasm/Makefile
index fd057fe..78a0828 100644
--- a/newasm/Makefile
+++ b/newasm/Makefile
@@ -2,40 +2,42 @@ PICO = /dev/disk/by-label/RPI-RP2
DEVICE = /dev/ttyUSB0
.PHONY: build
-build: parse.he
+build: assemble.he
-parse.he: parse.bin
- od -An -tx2 -v parse.bin | sed "s/^ //" | tr " " "\n" | tr [:lower:] [:upper:] | sed "s/^/0x/" > parse.he
+assemble.he: assemble.bin
+ od -An -tx2 -v assemble.bin | sed "s/^ //" | tr " " "\n" | tr [:lower:] [:upper:] | sed "s/^/0x/" > assemble.he
-parse.bin: parse.elf
- arm-none-eabi-objcopy -O binary parse.elf parse.bin
+assemble.bin: assemble.elf
+ arm-none-eabi-objcopy -O binary assemble.elf assemble.bin
objects = main.o uart.o data.o string.o input.o \
statement.o optable.o \
+ regreg.o regregimm.o regimm.o regregreg.o imm.o \
parsers/whitespace.o \
parsers/label.o \
parsers/symbol.o \
parsers/opcode.o \
parsers/register.o \
- parsers/decimal.o
+ parsers/decimal.o \
+ parsers/immediate.o
-parse.elf: pico_bin.ld $(objects)
- arm-none-eabi-ld -T pico_bin.ld -o parse.elf $(objects)
+assemble.elf: pico_bin.ld $(objects)
+ arm-none-eabi-ld -T pico_bin.ld -o assemble.elf $(objects)
$(objects): %.o: %.s
arm-none-eabi-as -o $@ $<
.PHONY: clean
clean:
- rm -f parse.elf parse.bin parse.he slowcat $(objects)
+ rm -f assemble.elf assemble.bin assemble.he slowcat $(objects)
.PHONY: dump
-dump: parse.bin
- @od -Ax -tx2 -v parse.bin
+dump: assemble.bin
+ @od -Ax -tx2 -v assemble.bin
.PHONY: serial
-serial: $(DEVICE) parse.he slowcat
- cat parse.he | tr "\n" "\r" | ./slowcat | picocom -b 115200 -q $(DEVICE)
+serial: $(DEVICE) assemble.he slowcat
+ cat assemble.he | tr "\n" "\r" | ./slowcat | picocom -b 115200 -q $(DEVICE)
@echo
echo -n "G" | picocom -b 115200 -q $(DEVICE)
@echo
diff --git a/newasm/errors.s b/newasm/errors.s
new file mode 100644
index 0000000..3822851
--- /dev/null
+++ b/newasm/errors.s
@@ -0,0 +1,30 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+// .type print_error, %function
+// .global print_error
+
+// 00 success
+// 01 expected an opcode (or unexpected character)
+// 02 expected label or opcode
+// 03 expected colon at end of label
+// 04 opcode not found
+
+// 05 expected digit
+
+// 06 expected register
+// 07 invalid general-purpose register number
+// 08 invalid register for this register position
+// 09 invalid register combo for this instruction
+
+// 0A immediate value too large
+
+// 0B extra input at end of statement
+
+ .align 4
+no_colon: .asciz "Error: Expected colon at end of label"
+ .align 4
+no_opcode: .asciz "Error: Expected an opcode"
+ .align 4
+not_found: .asciz "Error: Opcode not found"
diff --git a/newasm/imm.s b/newasm/imm.s
new file mode 100644
index 0000000..f6c7266
--- /dev/null
+++ b/newasm/imm.s
@@ -0,0 +1,27 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type imm, %function
+.global imm
+
+// R1 instruction under construction
+// R3 immediate width
+// R4 input buffer
+
+imm: PUSH {LR}
+ PUSH {R3}
+ BL immediate
+ POP {R3}
+ BNE exit
+ MOVS R0, 1
+ LSLS R0, R3
+ CMP R2, R0
+ BLO fine
+ MOVS R0, 0x0A // return code 0A (immediate value too large)
+ POP {PC}
+fine: ORRS R1, R2 // fill in imm
+ MOVS R0, 0 // return code 0 (success)
+exit: POP {PC}
+bad_reg: MOVS R0, 8 // return code 8 (invalid register for this register position)
+ POP {PC}
diff --git a/newasm/main.s b/newasm/main.s
index a27fec9..f1d3c0d 100644
--- a/newasm/main.s
+++ b/newasm/main.s
@@ -6,38 +6,31 @@
.global main, strbuf
main: LDR R5, =0x20002000
- BL uart_recv
-loop: BL prompt
- LDR R0, inpbuf
+ BL uart_recv // wait for keypress
+loop: BL prompt // display address and data
+ LDR R0, inpbuf // get a line of input
BL getline
- LDR R0, inpbuf
- BL putstrln
- LDR R4, inpbuf
- LDR R2, strbuf
- MOVS R0, 0
+ LDR R4, inpbuf // prepare input buffer
+ LDR R2, strbuf // prepare output buffer
+ MOVS R0, 0 // clear output buffer
STRB R0, [R2]
- BL statement
- BNE bad
-
-good: ADR R0, success
- PUSH {R1}
- BL putstrln
- MOVS R0, R4
- BL putstrln
- POP {R0}
+ BL statement // call statement parser
+ BNE bad // print message if failure
+ MOVS R0, R1 // show assembled instruction
BL send_hex
LDR R0, =crlf
BL putstr
- B loop
-
-bad: ADR R0, fail
- BL putstrln
- MOVS R0, R4
+ B loop // repeat
+bad: PUSH {R0}
+ ADR R0, fail
+ BL putstr
+ POP {R0}
+ BL send_hex
+ LDR R0, =crlf
+ BL putstr
+ MOVS R0, R4
BL putstrln
B loop
-never: BL uart_recv
- LDR R0, =0x20000001
- BX R0
prompt: PUSH {LR}
MOVS R0, R5
@@ -57,4 +50,4 @@ strbuf: .word 0x20001F80
.align 4
success: .asciz "The parser suceeded"
.align 4
-fail: .asciz "The parser failed"
+fail: .asciz "The parser failed: "
diff --git a/newasm/optable.s b/newasm/optable.s
index a063f02..fb80ab4 100644
--- a/newasm/optable.s
+++ b/newasm/optable.s
@@ -5,9 +5,6 @@
.type lookup, %function
.global lookup
-// 1 unexpected char
-// 2 unexpected end of input
-
// input:
// R0 input string (unboxed)
@@ -25,7 +22,7 @@ loop: CMP R5, R6 // if begin == end then range = 0
BEQ error
ADDS R2, R5, R6 // get sum
LSRS R2, 1 // divide by two
-no_jiggle:LSLS R3, R2, 3 // times 8 (index to offset)
+ LSLS R3, R2, 3 // times 8 (index to offset)
LDR R1, [R4, R3]// read opcode from optable
CMP R0, R1 // compare opcode to input
BLO lower // if lower
@@ -42,7 +39,7 @@ lower: MOVS R6, R2 // update end pointer
B loop
higher: ADDS R5, R2, 1 // update begin pointer
B loop
-error: MOVS R0, 1 // return code 1 (not found)
+error: MOVS R0, 4 // return code 4 (opcode not found)
POP {R4, R5, R6}
BX LR
@@ -53,5 +50,5 @@ op_table:
.ascii "ASPI"; .hword 0xB000; .byte 0x04, 0x07 // instr type 4, special code 7
.ascii "ASRI"; .hword 0x1000; .byte 0x01, 0x05 // instr type 1, special code 5 (imm width)
.ascii "ADCS"; .hword 0x4140; .byte 0x00, 0x00 // instr type 0, special code 0
- .ascii "ADDS"; .hword 0x1400; .byte 0x03, 0x00 // instr type 3, special code 0
+ .ascii "ADDS"; .hword 0x1800; .byte 0x03, 0x00 // instr type 3, special code 0
.ascii "BKPT"; .hword 0xBE00; .byte 0x04, 0x08 // instr type 4, special code 8
diff --git a/newasm/parsers/decimal.s b/newasm/parsers/decimal.s
index a1516d2..cc9dff4 100644
--- a/newasm/parsers/decimal.s
+++ b/newasm/parsers/decimal.s
@@ -5,8 +5,6 @@
.type decimal, %function
.global decimal
-// 1 not a digit
-
// R4 input stream
// R2 output value
@@ -35,5 +33,5 @@ loop: LDRB R0, [R4] // get another char
MULS R2, R3 // shift result by one decimal place
ADDS R2, R0 // accumulate into R2
B loop // keep getting digits
-bad: MOVS R0, #1 // return code 1 (not a digit)
+bad: MOVS R0, #5 // return code 5 (not a digit)
BX LR
diff --git a/newasm/parsers/immediate.s b/newasm/parsers/immediate.s
new file mode 100644
index 0000000..ac3e578
--- /dev/null
+++ b/newasm/parsers/immediate.s
@@ -0,0 +1,13 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type immediate, %function
+.global immediate
+
+// R4 input buffer
+// R2 output buffer
+
+immediate:PUSH {LR}
+ BL decimal
+ POP {PC}
diff --git a/newasm/parsers/label.s b/newasm/parsers/label.s
index 4770e6c..45d39e5 100644
--- a/newasm/parsers/label.s
+++ b/newasm/parsers/label.s
@@ -5,9 +5,6 @@
.type label, %function
.global label
-// 1 unexpected begin char
-// 2 doesn't end with colon
-
// R4 input buffer
// R2 output buffer
@@ -23,7 +20,7 @@ label: PUSH {LR}
LDRB R0, [R4] // get a char
CMP R0, ': // colon
BEQ 3f
- MOVS R0, #2 // return code 2 (expected colon)
+ MOVS R0, #3 // return code 3 (expected colon)
POP {PC}
3: ADDS R4, 1 // consume the colon
MOVS R0, #0 // return code 0 (success)
diff --git a/newasm/parsers/register.s b/newasm/parsers/register.s
index 48ebf7a..9334aa3 100644
--- a/newasm/parsers/register.s
+++ b/newasm/parsers/register.s
@@ -5,9 +5,6 @@
.type register, %function
.global register
-// 1 unexpected char
-// 2 invalid general-purpose register number
-
// R4 input buffer
// R2 output buffer
@@ -21,9 +18,12 @@ r_test: CMP R0, 'R
POP {PC} // error code already in R0
validate: CMP R2, #12 // general purpose registers 0-12
BLS success
- MOVS R0, #2 // invalid register number error code
+ MOVS R0, #7 // invalid register number error code
POP {PC}
-special: LDRH R0, [R4] // get two bytes from input stream
+special: LDRB R0, [R4] // get two bytes from input stream
+ LDRB R1, [R4, 1]
+ LSLS R1, 8
+ ORRS R0, R1
ADR R2, table // get address of table
MOVS R3, 0 // set table offset to 0
loop: LDRH R1, [R2, R3] // get two bytes from table at current offset
@@ -32,7 +32,7 @@ loop: LDRH R1, [R2, R3] // get two bytes from table at current offset
ADDS R3, 2 // increment table offset
CMP R3, 6 // compare offset to table size
BLO loop // loop until end of table
- MOVS R0, #1 // return code 1 (unexpected char)
+ MOVS R0, #6 // return code 6 (expected register)
POP {PC}
done: ADDS R4, 2 // consume two chars
LSRS R3, 1 // divide table offset by two to row
@@ -41,6 +41,7 @@ done: ADDS R4, 2 // consume two chars
success: MOVS R0, #0 // return code 0 (success)
POP {PC}
+ .align 4
table: .ascii "SP"
.ascii "LR"
.ascii "PC"
diff --git a/newasm/regimm.s b/newasm/regimm.s
new file mode 100644
index 0000000..3e294c8
--- /dev/null
+++ b/newasm/regimm.s
@@ -0,0 +1,37 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type regimm, %function
+.global regimm
+
+// R1 instruction under construction
+// R3 immediate width
+// R4 input buffer
+
+regimm: PUSH {LR}
+ PUSH {R3}
+ BL register // parse a register
+ POP {R3}
+ BNE exit // exit if failure
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ LSLS R2, 8 // shift by 8
+ ORRS R1, R2 // fill in Rdn
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+ PUSH {R3}
+ BL immediate
+ POP {R3}
+ BNE exit
+ MOVS R0, 1
+ LSLS R0, R3
+ CMP R2, R0
+ BLO fine
+ MOVS R0, 0x0A // returun code 0A (immediate value too large)
+ POP {PC}
+fine: ORRS R1, R2 // fill in imm
+ MOVS R0, 0 // return code 0 (success)
+exit: POP {PC}
+bad_reg: MOVS R0, 8 // return code 8 (invalid register for this register position)
+ POP {PC}
diff --git a/newasm/regreg.s b/newasm/regreg.s
new file mode 100644
index 0000000..6893dee
--- /dev/null
+++ b/newasm/regreg.s
@@ -0,0 +1,29 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type regreg, %function
+.global regreg
+
+// R1 instruction under construction
+// R2 output buffer
+// R4 input buffer
+
+regreg: PUSH {LR}
+ BL register // parse a register
+ BNE exit // exit if failure
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ ORRS R1, R2 // fill in Rdn
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+ BL register // parse a register
+ BNE exit
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ LSLS R2, 3 // shift by 3
+ ORRS R1, R2 // fill in Rm
+ MOVS R0, 0 // return code 0 (success)
+exit: POP {PC}
+bad_reg: MOVS R0, 8 // return code 8 (invalid register for this register position)
+ POP {PC}
diff --git a/newasm/regregimm.s b/newasm/regregimm.s
new file mode 100644
index 0000000..6c649e2
--- /dev/null
+++ b/newasm/regregimm.s
@@ -0,0 +1,47 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type regregimm, %function
+.global regregimm
+
+// R1 instruction under construction
+// R3 immediate width
+// R4 input buffer
+
+regregimm:PUSH {LR}
+ PUSH {R3}
+ BL register // parse a register
+ POP {R3}
+ BNE exit // exit if failure
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ ORRS R1, R2 // fill in Rd
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+ PUSH {R3}
+ BL register // parse a register
+ POP {R3}
+ BNE exit
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ LSLS R2, 3 // shift by 3
+ ORRS R1, R2 // fill in Rn
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+ PUSH {R3}
+ BL immediate
+ POP {R3}
+ BNE exit
+ MOVS R0, 1
+ LSLS R0, R3
+ CMP R2, R0
+ BLO fine
+ MOVS R0, 0x0A // returun code 0A (immediate value too large)
+ POP {PC}
+fine: LSLS R2, 6 // shift by 6
+ ORRS R1, R2 // fill in imm
+ MOVS R0, 0 // return code 0 (success)
+exit: POP {PC}
+bad_reg: MOVS R0, 8 // return code 8 (invalid register for this register position)
+ POP {PC}
diff --git a/newasm/regregreg.s b/newasm/regregreg.s
new file mode 100644
index 0000000..a8be6ee
--- /dev/null
+++ b/newasm/regregreg.s
@@ -0,0 +1,44 @@
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.type regregreg, %function
+.global regregreg
+
+// R1 instruction under construction
+// R2 output buffer
+// R4 input buffer
+
+regregreg:PUSH {LR}
+
+ // TODO loop it
+ BL register // parse a register
+ BNE exit // exit if failure
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ ORRS R1, R2 // fill in Rd
+
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+
+ BL register // parse a register
+ BNE exit
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ LSLS R2, 3 // shift by 3
+ ORRS R1, R2 // fill in Rn
+
+ BL whitespace // mandatory whitespace
+ BNE exit // exit if failure
+
+ BL register // parse a register
+ BNE exit
+ CMP R2, 7 // check that it's R0-R7
+ BHI bad_reg
+ LSLS R2, 6 // shift by 6
+ ORRS R1, R2 // fill in Rm
+
+ MOVS R0, 0 // return code 0 (success)
+exit: POP {PC}
+bad_reg: MOVS R0, 8 // return code 8 (invalid register for this register position)
+ POP {PC}
diff --git a/newasm/statement.s b/newasm/statement.s
index 4a199a6..436ae03 100644
--- a/newasm/statement.s
+++ b/newasm/statement.s
@@ -5,40 +5,47 @@
.type statement, %function
.global statement
-// 1 reported an error
-
// R4 input buffer
// R2 output buffer
statement:PUSH {LR}
- BL whitespace
- PUSH {R2}
+ MOVS R3, R2 // save output buffer
+ BL whitespace // skip leading whitespace
BL label
- POP {R2}
- CMP R0, #2 // check for error code 2 (no colon)
- BNE 1f
- ADR R0, no_colon
- B err_exit
+ CMP R0, 3 // only exit for code 3 (no colon at end of label)
+ BEQ exit
+ MOVS R1, R0
1: BL whitespace
- PUSH {R2}
- BL opcode
- POP {R2}
- BEQ 2f
- ADR R0, no_opcode
- B err_exit
-2: LDR R0, [R2]
+ MOVS R2, 0 // reset output buffer
+ STRB R2, [R3]
+ MOVS R2, R3
+ BL opcode // TODO opcodes longer than 4
+ ADD R0, R1
+ BNE exit
+2: MOVS R0, R3
+ PUSH {R3}
+ BL putstrln
+ POP {R3}
+ LDR R0, [R3]
BL lookup
- BEQ 3f
- ADR R0, not_found
- B err_exit
-3: POP {PC} // success code already in R0
-err_exit: BL putstrln
- MOVS R0, #1 // return code 1 (there was an error)
- POP {PC}
+ BNE exit
+ BL whitespace // TODO new return code for expected whitespace
+ BNE exit
+ ADR R0, parsers
+ LSLS R2, 2 // multiply by 4 to get byte offset
+ LDR R2, [R0, R2] // get address of parser
+ BLX R2
+ BNE exit
+ BL whitespace
+ LDRB R0, [R4] // get a byte from the input stream
+ TST R0, R0 // check if zero
+ BEQ exit // if it's zero then success
+ MOVS R0, 0x0B // return code 0B (extra input at end)
+exit: POP {PC}
- .align 4
-no_colon: .asciz "Error: Expected colon at end of label"
- .align 4
-no_opcode: .asciz "Error: Expected an opcode"
- .align 4
-not_found: .asciz "Error: Opcode not found"
+ .align 4
+parsers: .word regreg
+ .word regregimm
+ .word regimm
+ .word regregreg
+ .word imm