	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
	@@@	ARM SUBLEQ for Linux			@@@
	@@@	Word size is 32 bits. The program is	@@@
	@@@	given 8 MB (2 Mwords) to run in.	@@@
	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.text
.global	_start
	@@@ Linux syscalls
.equ	exit,	1
.equ	read,	3
.equ	write,	4
.equ	open,	5
_start:	pop	{r6}		@ Retrieve amount of arguments
	cmp	r6,#2		@ There should be exactly 2 (incl program)
	ldrne	r1,=usage	@ Otherwise, print usage and stop
	bne 	die
	pop	{r0,r1}		@ Retrieve filename
	mov	r0,r1
	mov	r1,#0		@ Try to open the file in read mode
	mov	r2,#0
	mov	r7,#open
	swi	#0
	movs	r5,r0		@ File handle in R5
	ldrmi	r1,=efile	@ If the file can't be opened, error
	bmi	die
	ldr	r8,=prog	@ R8 = pointer into program
	mov	r6,#0		@ At the beginning, there is no data
rdnum:	bl	fchar		@ Skip past whitespace
	cmp	r0,#32
	bls 	rdnum
	mov	r9,#0		@ R9 = current number being read
	subs	r10,r0,#'-	@ R10 is zero if number is negative
	bleq	fchar		@ And get next character
1:	sub	r0,r0,#'0	@ Subtract ASCII 0
	cmp	r0,#9
	ldrhi	r1,=echar
	bhi	die		@ Invalid digit = error
	mov	r1,#10
	mla	r0,r9,r1,r0	@ Multiply accumulator by 10 and add digit
	mov	r9,r0 		
	bl	fchar		@ Get next character
	cmp 	r0,#32		@ If it isn't whitespace...
	bhi	1b		@ ...then it's the next digit
	tst	r10,r10		@ If the number should be negative,
	rsbeq	r9,r9,#0	@ ...then negate it
	str	r9,[r8],#4	@ Store the number
	b	rdnum		@ And get the next number.
setup:	ldr	r0,=prog	@ Zero out the rest of program memory
	sub	r0,r8,r0	@ Zero to 8-word (32-byte) boundary
	orr	r0,r0,#31	@ Find address of last byte within
	add	r0,r0,r8	@ current 31-byte block
	mov	r1,#0		@ R1 = zero to write
1:	str	r1,[r8],#4	@ Write zeroes,
	cmp	r0,r8		@ until boundary reached.
	blo	1b 
	mov	r0,#0		@ 8 words of zeroes in r0-r7
	umull	r2,r3,r0,r1	@ A trick to produce 2 zero words in one
	umull	r4,r5,r0,r1	@ go: 0*0 = 0, long multiplication 
	umull	r6,r7,r0,r1	@ results in 2 words.
	ldr	r9,=mem_end
2:	stmia	r8!,{r0-r7}	@ Write 8 zero words at a time
	cmp	r8,r9		@ Are we at mem_end yet?
	blo	2b		@ If not, keep going
	ldr	r8,=prog	@ R8 = IP, starts at beginning
	ldr	r6,=prog	@ R6 = base address for memory
	mov	r12,#0xFFFF	@ 0x1FFFFF = address mask
	movt	r12,#0x1F
instr:	ldmia	r8!,{r9-r11}	@ R9, R10, R11 = A, B, C
	cmp	r9,#-1		@ If A=-1, get character
	beq	rchar
	cmp	r10,#-1		@ Otherwise, if B=-1, write character
	beq	wchar
	and	r9,r9,r12	@ Keep addresses within 2 Mwords
	and	r10,r10,r12
	ldr	r0,[r6,r9,lsl #2]	@ Grab [A] and [B]
	ldr	r1,[r6,r10,lsl #2]
	subs	r1,r1,r0		@ Subtract
	str	r1,[r6,r10,lsl #2]	@ Store back in [B]
	cmpmi	r0,r0		@ Set zero flag if negative
	bne	instr		@ If result is positive, next instruction
	lsls	r8,r11,#2	@ Otherwise, C becomes the new IP
	add	r8,r8,r6
	bpl	instr		@ If result is positive, keep going
	mov	r0,#0		@ Otherwise, we exit
	mov	r7,#exit
	swi	#0
	@@@ 	Read character into [B]
rchar:	mov	r0,#0		@ STDIN
	and	r10,r10,r12	@ Address of B
	add	r10,r6,r10,lsl #2	@ Kept in R10 out of harm's way
	mov	r1,r10
	mov	r2,#1		@ Read one character
	mov	r7,#read
	swi	#0
	cmp	r0,#1		@ We should have received 1 byte
	movne	r1,#-1		@ If not, write -1
	ldreqb	r1,[r10]	@ Otherwise, blank out the top 3 bytes
	str	r1,[r10]
	b	instr
	@@@	Write character in [A]
wchar:	mov	r0,#1		@ STDIN
	and	r1,r9,r12	@ Address of [A]
	add	r1,r6,r1,lsl #2
	mov	r2,#1		@ Write one character
	mov	r7,#write
	swi	#0
	b	instr
	@@@	Read character from file into R0. Tries to read more
	@@@	if the buffer is empty (as given by R6). Buffer in R11.
fchar:	tst	r6,r6		@ Any bytes in the buffer?
	ldrneb	r0,[r11],#1	@ If so, return next character from buffer
	subne	r6,r6,#1
	bxne	lr
	mov	r12,lr		@ Save link register
	mov	r0,r5		@ If not, read from file into buffer
	ldr	r1,=fbuf
	mov	r2,#0x400000
	mov	r7,#read
	swi	#0
	movs	r6,r0		@ Amount of bytes in r6
	beq	setup		@ If no more bytes, start the program
	ldr	r11,=fbuf	@ Otherwise, R11 = start of buffer
	mov	lr,r12
	b	fchar
	@@@	Write a zero-terminated string, in [r1], to stdout.
print:	push	{lr}
	mov	r2,r1	
1:	ldrb	r0,[r2],#1	@ Get character and advance pointer
	tst	r0,r0		@ Zero yet?
	bne	1b		@ If not, keep scanning
	sub	r2,r2,r1	@ If so, calculate length
	mov	r0,#1		@ STDOUT
	mov	r7,#write	@ Write to STDOUT
	swi	#0
	pop	{pc}
	@@@	Print error message in [r1], then end.
die:	bl	print
	mov	r0,#255
	mov	r7,#exit
	swi	#0
usage:	.asciz	"Usage: subleq <filename>\n"
efile:	.asciz	"Cannot open file\n"
echar:	.asciz	"Invalid number in file\n"
	@@@ Memory
.bss
.align	4
prog:	.space	0x400000	@ Lower half of program memory
fbuf:	.space	0x400000	@ File buffer and top half of program memory
mem_end	=	.