/vm.s
.section .text

.align 1
.global _err_halt
.type _err_halt, %function
_err_halt:
	push {lr}
	mov r0, #' '
	mov r4, r10
	add r4, #2
1:	bl _platform_putch
	sub r4, #1
	bne 1b
2:	mov r0, #'^'
	bl _platform_putch
	ldr r0, =_halted_str
	bl putstr
	ldr r1, =0xE000ED0C
	ldr r0, =0x05FA0004
	str r0, [r1]
	// should reset at this point
1:	b 1b

// print the null-terminated string pointed to by r0
.align 1
.global putstr
.type putstr, %function
putstr:
	push {lr}
	mov r4, r0
1:	ldrb r0, [r4]
	cmp r0, #0
	beq 2f
	bl _platform_putch
	add r4, #1
	b 1b
2:	pop {pc}

.align 2
.global Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
	ldr r0, =control_stack
	mov r9, r0
	bl setup_words
	bl _platform_serial_init

1:	ldr r0, =_prompt_str
	bl putstr
	bl read_input
	mov r0, #'\n'
	bl _platform_putch
	bl compile
	bl execute_scratchword
	mov r0, #'\n'
	bl _platform_putch
	b 1b

setup_words:
	push {lr}
	ldr r5, =environment
	add r1, r5, #4
	str r1, [r5]      // head (address where next word goes)
	mov r0, #0
	str r0, [r5, #4]  // next (offset to next word or 0 for end of list)
	// load ROM words
	ldr r4, =rom_word_list
1:	ldr r0, [r4]
	cmp r0, #0
	beq 2f
	push {r4}
	bl  add_rom_word
	pop {r4}
	add r4, #4
	b   1b
2:	pop {pc}

read_input:
	push {lr}
	ldr r4, =input_buffer
	mov r8, r4
	mov r5, #0         // r5 is position in buffer
	mov r10, r5
1:	bl _platform_getch
	cmp r0, #'\r'
	beq 2f
	cmp r0, #0x8   // backspace
	beq 3f
	cmp r0, #0x7F  // DEL
	beq 3f

	// a regular character
	cmp r5, #255
	beq 1b             // buffer is full, go back to start
	strb r0, [r4, r5]  // store char in buffer
	bl _platform_putch // print the character
	add r5, #1         // increment position counter
	b 1b               // go back to start

	// a newline
2:	sub r6, r4, #1     // back up to the input counter
	strb r5, [r6]      // write the number of characters
	pop {pc}           // return

	// a backspace
3:	cmp r5, #0
	beq 1b             // if we're already at zero characters, do nothing and continue
	sub r5, #1         // remove one char from the input buffer count
	mov r0, #0x08
	bl _platform_putch // backspace one character
	mov r0, #' '
	bl _platform_putch // print a space
	mov r0, #0x08
	bl _platform_putch // and backspace again
	b 1b               // back to the top

add_rom_word:
	ldr r5, =environment
	ldr r1, [r5]      // r1 is now the head address
	ldrh r2, [r0]     // get the number of bytes for the ROM word
	mov r4, #0        // counter value

1: 	ldr r3, [r0, r4]  // load
	str r3, [r1, r4]  // store
	add r4, #4
	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
.global get_next_word
.type get_next_word, %function
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.
.global search_environment
.type search_environment, %function
search_environment:
	push {r4, r5, r6, lr}
	ldr r6, =input_buffer
	mov r1, r10          // load input buffer position
	add r6, r1           // r6 is now a pointer into the input buffer
	ldr r4, =environment
	add r4, #4           // start at the beginning
1:	ldrh r0, [r4]        // load the offset to next word
	cmp r0, #0
	beq 5f               // if it's zero, we're done

	ldrb r3, [r4, #8]    // load the name length
	cmp r3, r11          // is it the same as the length we have in r11?
	beq 3f               // string lengths are the same; compare bytes
2:	add r4, r0           // else add to the word pointer
	b 1b                 // and try the next word

3:	ldrh r5, [r4, #2]    // load code length
	add r5, #10          // add header offset
	add r5, r4           // r5 is the beginning of the word name string
	mov r1, #0           // set up index
4:	ldrb r2, [r5, r1]    // load dict byte
	ldrb r3, [r6, r1]    // load input byte
	cmp r2, r3           // are they the same?
	bne 2b               // if not, go to the next dict word
	add r1, #1           // increment
	cmp r1, r11          // have we checked all the bytes in the word?
	bne 4b               // if not, check next byte

	// success!
	mov r0, r4
	pop {r4, r5, r6, pc}

	// the word was not found; set r0 to 0
5:	mov r0, #0
	pop {r4, r5, r6, pc}