.section .text
.align 2
.global _err_halt
_err_halt:
b _err_halt
.macro pstring str:req
.byte 2f - 1f
1:
.ascii "\str"
2:
.endm
.macro def_word name:req
.align 2
\name:
.short _\name\()_end - \name // total size
.short _\name - \name // offset to code start
.short _\name\()_code_end - _\name // code length (minus bx lr)
.short 1f - . - 2 // name length
.ascii "\name"
1:
.align 1
_\name:
.endm
.macro def_end name:req
_\name\()_code_end:
bx lr
.align 2
_\name\()_end:
.endm
def_word halt
b _halt
def_end halt
def_word push /* r0 onto stack */
push {r0}
def_end push
def_word pop /* r0 off of stack */
pop {r0}
def_end pop
def_word dup // ( a -- a a )
pop {r0}
push {r0}
push {r0}
def_end dup
def_word add // ( a b -- a + b)
pop {r0, r1}
add r0, r0, r1
push {r0}
def_end add
def_word rep
mov r0, pc
push {r0}
def_end rep
def_word jump
pop {pc}
def_end jump
.align 2
.global Reset_Handler
Reset_Handler:
/*
ldr r4, =program
ldr r5, =output
bl compiler
*/
bl setup_input
bl setup_words
ldr r0, =add
bl add_rom_word
ldr r0, =halt
bl add_rom_word
ldr r0, =rep
bl add_rom_word
ldr r0, =jump
bl add_rom_word
bl interpret_input
b _err_halt
setup_input:
/*
ldr r5, =input_counter
mov r0, str r0, [r5]
*/
ldr r0, =program
ldrb r1, [r0]
add r1, ldr r2, =input_counter
mov r3, 1: ldrb r4, [r0, r3]
strb r4, [r2, r3]
add r3, cmp r3, r1
bne 1b
bx lr
setup_words:
ldr r5, =output
add r1, r5, str r1, [r5] // head (address where next word goes)
mov r0, str r0, [r5, bx lr
add_rom_word:
ldr r5, =output
ldr r1, [r5] // r1 is now the head address
ldrh r2, [r0] // get the number of bytes for the ROM word
mov r4,
1: ldr r3, [r0, r4] // load
str r3, [r1, r4] // store
add r4, cmp r4, r2 // if we've copied all the bytes
bne 1b // loop
add r1, r2 // add to get the next head location
str r1, [r5] // store the new head
mov r2, #0
str r2, [r1] // And make sure the next word offset is end of list
bx lr
// r8 - in, input buffer address
// r10 - in/out, input buffer word position
// r11 - out, word length
get_next_word:
mov r4, r8 // r4 is the local input buffer address
ldr r5, =input_counter
ldrb r5, [r5] // r5 is the input buffer length
mov r0, r10 // r0 is word position
1:
ldrb r2, [r4, r0] // load char
cmp r2, #' ' // is it a space?
bne 2f // if so, continue
add r0, #1 // increment word position
cmp r0, r5
beq 4f // have we hit the input buffer length?
b 1b
2: mov r1, r0
3: ldrb r2, [r4, r1]
cmp r2, #' '
beq 4f // is it not a space?
add r1, #1
cmp r1, r5 // have we hit the input buffer length?
bne 3b // if not, continue
4: sub r1, r0 // word length is end - beginning
mov r11, r1
mov r10, r0
bx lr
// based on the input string starting at r10 and with length r11, set r0 to the
// beginning of the word's code or else set r0 to 0 if the word was not found.
search_dict:
ldr r4, =output
add r4, 1: ldrh r0, [r4] // load the offset to next word
beq 5f // if it's zero, we're done
mov r0, r4
add r0, ldrh r3, [r4, cmp r3, r11 // is it the same as the length we have in r11?
beq 3f // string lengths are the same; compare bytes
2: ldrh r0, [r4] // else load the offset to next word
add r4, r0 // add to the word pointer
b 1b // and try the next word
3: ldr r5, =input_buffer
ldr r6, =input_counter
ldrb r6, [r6]
mov r1, r10 // load input buffer position
add r5, r1 // r5 is now a pointer into the input buffer
mov r1, 4: ldrb r2, [r0, r1] // load dict byte
ldrb r3, [r5, r1] // load input byte
cmp r2, r3 // are they the same?
bne 2b // if not, go to the next dict word
add r1, cmp r1, r11 // have we checked all the bytes in the word?
bne 4b // if not, check next byte
// success!
ldrh r2, [r4, add r0, r4, r2 // add to word start
add r0, bx lr
// the word was not found; set r0 to 0
5: mov r0, bx lr
interpret_input:
mov r9, lr
ldr r0, =input_buffer
mov r8, r0
mov r0, mov r10, r0
1:
bl get_next_word
mov r4, r8
mov r0, r10
ldrb r2, [r4, r0] // get the first character
cmp r2, bne 2f
bl push_str
b 4f
2: cmp r2, bne 3f
bl push_lit
b 4f
3: bl search_dict // must be a word
beq 5f // word not found
blx r0 // branch to found word
4: mov r0, r10
mov r1, r11
add r0, r1 // move input pointer to next word
mov r10, r0
b 1b
5: bx r9
push_str:
mov r0, r10
add r0, mov r4, r8
1: ldrb r1, [r4, r0] // load character
push {r1} // push to stack
add r0, cmp r0, r11 // at the end?
bne 1b // repeat
bx lr
push_lit:
mov r0, r10 // input position
mov r1, r11 // input length
mov r4, r8 // input buffer
add r5, r0, r1 // calculate end position
add r3, r0, mov r7, 1: ldrb r2, [r4, r3] // load character
cmp r2, blt 4f // not in range
cmp r2, bgt 3f // not a digit, but possibly still a letter
// a digit
sub r2, b 5f
3: cmp r2, blt 4f // not in range
cmp r2, bgt 4f // not in range
// a letter a-f
sub r2, b 5f
// error parsing literal
4: push {lr}
bl _err_halt
5:
lsl r7, orr r7, r2 // or in the value
add r3, cmp r3, r5 // are we done?
bne 1b // continue
push {r7}
bx lr
.ltorg
.section .rodata
.align 2
program:
pstring "$0 rep $100 add jump halt"
.section .data
input_counter:
.skip 1
input_buffer:
.skip 255
output: