513 lines
12 KiB
Text
513 lines
12 KiB
Text
.data
|
|
.align 2
|
|
.code 32
|
|
|
|
.section .rodata
|
|
.align 2
|
|
.code 32
|
|
|
|
overflow_msg: .ascii "Invalid number. Overflow.\n"
|
|
overflow_msglen = . - overflow_msg
|
|
bad_input_msg: .ascii "Invalid input. NaN.\n"
|
|
bad_input_msglen = . - bad_input_msg
|
|
range_err_msg: .ascii "Value out of range.\n"
|
|
range_err_msglen = . - range_err_msg
|
|
io_error_msg: .ascii "I/O error.\n"
|
|
io_error_msglen = . - range_err_msg
|
|
|
|
sys_exit = 1
|
|
sys_read = 3
|
|
sys_write = 4
|
|
max_rd_buf = 14
|
|
lf = 10
|
|
m10_9 = 0x3b9aca00
|
|
maxval = 1000
|
|
minval = -1000
|
|
|
|
.text
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ void main()
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type _start STT_FUNC
|
|
.global _start
|
|
_start:
|
|
stmfd sp!, {r4,r5,lr}
|
|
|
|
.read_lhs:
|
|
ldr r0, =max_rd_buf
|
|
bl readint
|
|
mov r4, r0
|
|
bl printint
|
|
mov r0, r4
|
|
bl range_check
|
|
|
|
.read_rhs:
|
|
ldr r0, =max_rd_buf
|
|
bl readint
|
|
mov r5, r0
|
|
bl printint
|
|
mov r0, r5
|
|
bl range_check
|
|
|
|
.sum_and_print:
|
|
adds r0, r4, r5
|
|
bvs overflow
|
|
bl printint
|
|
|
|
.main_exit:
|
|
mov r0, #0
|
|
bl exit
|
|
ldmfd sp!, {r4,r5,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ Read from stdin until we encounter a non-digit, or we have read bytes2rd digits.
|
|
@@ Ignore leading spaces.
|
|
@@ Return value to the caller converted to a signed int.
|
|
@@ We read positive values, but if we read a leading '-' sign, we convert the
|
|
@@ return value to two's complement.
|
|
@@ The argument is max number of bytes to read from stdin.
|
|
@@ int readint(int bytes2rd)
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type readint STT_FUNC
|
|
.global readint
|
|
readint:
|
|
stmfd sp!, {r4,r5,r6,r7,lr}
|
|
@@@@@@@@@@@@@@@
|
|
@@ r0 : #0 for stdin arg to read.
|
|
@@ r1 : ptr to current pos in local buffer.
|
|
@@ r2 : #1 to read one byte at a time.
|
|
@@ r3,r7 : tmp.
|
|
@@ r4 : number of bytes read.
|
|
@@ r5 : value of current byte.
|
|
@@ r6 : 0 while we are reading leading spaces.
|
|
@@@@@@@@@@@@@@@
|
|
sub sp, sp, r0
|
|
mov r1, sp
|
|
mov r3, #0
|
|
push {r3} @ sp,#4: local var @isnegative. return in r1. Default value is 0/false. Positive number.
|
|
push {r0} @ sp,#0: local var @maxbytes. const.
|
|
mov r2, #1
|
|
mov r4, #0
|
|
|
|
mov r6, #0
|
|
b .rd
|
|
@ we get here if r6 is 0.
|
|
@ if space, goto .rd.
|
|
@ else set r6 to 1 and goto .noleading.
|
|
.leadchk:
|
|
mov r0, r5
|
|
bl isspace
|
|
cmp r0, #1
|
|
beq .rd
|
|
|
|
.sign_chk:
|
|
mov r0, r5
|
|
push {r1}
|
|
bl issign
|
|
cmp r0, #1
|
|
streq r0, [sp,#8] @ sp,#4 + 4 for the pushed r1.
|
|
movhi r1, #0
|
|
strhi r1, [sp,#8] @ sp,#4 + 4 for the pushed r1.
|
|
pop {r1}
|
|
bhs .rd
|
|
|
|
mov r6, #1
|
|
b .noleading
|
|
|
|
.rd:
|
|
mov r0, #0
|
|
bl read
|
|
cmp r0, #1
|
|
bne .sum_digits_eof @ eof
|
|
mov r5, #0
|
|
ldrb r5, [r1]
|
|
cmp r6, #0
|
|
beq .leadchk
|
|
|
|
.noleading:
|
|
mov r0, r5
|
|
bl isdigit
|
|
cmp r0, #1
|
|
bne .sum_digits_nan @ r5 is non-digit
|
|
|
|
add r4, r4, #1
|
|
add r1, r1, #1
|
|
@ max chars to read is received in arg[0], stored in local var at sp.
|
|
@ Only 10 can be valid, so the default of 12 leaves space for separator.
|
|
ldr r3, [sp]
|
|
cmp r4, r3
|
|
beq .sum_digits_maxrd @ max bytes read.
|
|
b .rd
|
|
|
|
|
|
@@@@@@@@@@@@@@@
|
|
@ We have read r4 (0..arg[0](default 12)) digits when we get here. Go through them
|
|
@ and add/mul them together to calculate a number.
|
|
@ We multiply and add the digits in reverse order to simplify the multiplication.
|
|
@@@@@@@@@@@@@@@
|
|
@ r0: return value.
|
|
@ r1: local variable for read buffer.
|
|
@ r2: tmp for conversion.
|
|
@ r3,r6,r7: tmp
|
|
@ r4: number of chars we have read.
|
|
@ r5: multiplier 1,10,100.
|
|
@@@@@@@@@@@@@@@
|
|
.sum_digits_nan:
|
|
mov r0, r5
|
|
bl isspace
|
|
cmp r0, #1
|
|
bne bad_input
|
|
.sum_digits_maxrd:
|
|
.sum_digits_eof:
|
|
mov r0, #0
|
|
mov r5, #1
|
|
.count:
|
|
cmp r4, #0
|
|
beq .readint_ret
|
|
sub r4, r4, #1
|
|
sub r1, #1
|
|
ldrb r2, [r1]
|
|
sub r2, r2, #48
|
|
mov r3, r2
|
|
|
|
@ multiply r3 (char value of digit) with r5 (multiplier).
|
|
@ possible overflow.
|
|
@ MI means negative.
|
|
@ smulls multiples two signed 32 bit vals and returns a 64 bit result.
|
|
@ If we get anything in r7, the value has overflowed.
|
|
@ having r2[31] set is overflow too.
|
|
smulls r2, r7, r3, r5
|
|
cmp r7, #0
|
|
bne overflow
|
|
cmp r2, #0
|
|
bmi overflow
|
|
|
|
@@ possible overflow.
|
|
adds r0, r0, r2
|
|
bvs overflow
|
|
bmi overflow
|
|
|
|
@@ end of array check.
|
|
@@ check is needed here too, for large numbers, since 10 billion is not a valid 32 bit val.
|
|
cmp r4, #0
|
|
beq .readint_ret
|
|
|
|
@@ multiple multiplier by 10.
|
|
@@ possible overflow.
|
|
@@ too many digits is input. happens if input is more than 10 digits.
|
|
mov r3, #10
|
|
mov r6, r5
|
|
smulls r5, r7, r3, r6
|
|
cmp r7, #0
|
|
bne overflow
|
|
cmp r5, #0
|
|
bmi overflow
|
|
b .count
|
|
|
|
.readint_ret:
|
|
ldr r1, [sp,#4] @ read isnegative value.
|
|
cmp r1, #0
|
|
rsbne r0, r0, #0
|
|
pop {r2}
|
|
add sp, sp, #4
|
|
add sp, sp, r2
|
|
ldmfd sp!, {r4,r5,r6,r7,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ int isdigit(int)
|
|
@@ #48..#57 ascii range for '0'..'9'.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type isdigit STT_FUNC
|
|
.global isdigit
|
|
isdigit:
|
|
stmfd sp!, {r1,lr}
|
|
cmp r0, #48
|
|
blo .o_range
|
|
cmp r0, #57
|
|
bhi .o_range
|
|
mov r0, #1
|
|
ldmfd sp!, {r1,pc}
|
|
.o_range:
|
|
mov r0, #0
|
|
ldmfd sp!, {r1,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ int isspace(int)
|
|
@@ ascii space = 32, tab = 9, newline 10, cr = 13.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type isspace STT_FUNC
|
|
.global isspace
|
|
isspace:
|
|
stmfd sp!, {lr}
|
|
cmp r0, #32
|
|
cmpne r0, #9
|
|
cmpne r0, #10
|
|
cmpne r0, #13
|
|
beq .is_space
|
|
mov r0, #0
|
|
ldmfd sp!, {pc}
|
|
.is_space:
|
|
mov r0, #1
|
|
ldmfd sp!, {pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ Return value is 1 for '-' 2 for '+'.
|
|
@@ int isspace(int)
|
|
@@ '+' = 43 and '-' = 45.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type issign STT_FUNC
|
|
.global issign
|
|
issign:
|
|
stmfd sp!, {lr}
|
|
cmp r0, #43
|
|
beq .plus_sign
|
|
cmp r0, #45
|
|
beq .minus_sign
|
|
mov r0, #0
|
|
ldmfd sp!, {pc}
|
|
.plus_sign:
|
|
mov r0, #2
|
|
ldmfd sp!, {pc}
|
|
.minus_sign:
|
|
mov r0, #1
|
|
ldmfd sp!, {pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ ARGS:
|
|
@@ r0 : in out arg (current int value)
|
|
@@ r1 : in out arg (ptr to current pos in buffer)
|
|
@@ r2 : in arg (const increment. 1000_000_000, 100_000_000, 10_000_000, 1000_000, 100_000, 10_000, 1000, 100, 10, 1.)
|
|
@@
|
|
@@ r4 : tmp local. Outer scope must init to #10 and count down to #0.
|
|
@@ Special case is INTMAX. Must init to 5 if r4 >= 1000_000_000 (0x3b9aca00 = m10_9).
|
|
@@ r5: tmp
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type get_digit STT_FUNC
|
|
.global get_digit
|
|
get_digit:
|
|
stmfd sp!, {r2,r4,r5,lr}
|
|
ldr r5, =m10_9
|
|
cmp r2, r5
|
|
movlo r4, #10
|
|
movhs r4, #5
|
|
.get_digit_loop:
|
|
sub r4, #1
|
|
mul r5, r4, r2
|
|
cmp r0, r5
|
|
blo .get_digit_loop
|
|
sub r0, r5
|
|
add r4, r4, #48
|
|
strb r4, [r1], #1
|
|
ldmfd sp!, {r2,r4,r5,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ A quick way to divide (numbers evenly divisible by 10) by 10.
|
|
@@ Most ARM cpus don't have a divide instruction,
|
|
@@ so this will always work.
|
|
@@ A generic div function is long and not needed here.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.div_r2_10:
|
|
stmfd sp!, {r0,r1,r3,lr}
|
|
mov r0, #1
|
|
mov r1, #10
|
|
.find_x:
|
|
mul r3, r0, r1;
|
|
cmp r3, r2
|
|
movlo r0, r3
|
|
blo .find_x
|
|
mov r2, r0
|
|
ldmfd sp!, {r0,r1,r3,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.print_neg_sign:
|
|
stmfd sp!, {r0,r1,r2,lr}
|
|
@ 45 = '-'
|
|
mov r1, #45
|
|
push {r1}
|
|
mov r2, #1
|
|
@ r1 is ptr to our local variable (holding '-').
|
|
mov r1, sp
|
|
mov r0, #1
|
|
bl write
|
|
cmp r0, #0
|
|
blne io_error
|
|
pop {r1}
|
|
ldmfd sp!, {r0,r1,r2,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@ void printint(int val)
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type printint STT_FUNC
|
|
.global printint
|
|
printint:
|
|
stmfd sp!, {r4,r5,r6,lr}
|
|
mov r1, #1
|
|
ands r1, r1, r0, LSR #31
|
|
rsbne r0, r0, #0
|
|
blne .print_neg_sign
|
|
sub sp, sp, #20
|
|
mov r1, sp
|
|
mov r3, sp
|
|
|
|
ldr r2, =m10_9
|
|
.getc_loop:
|
|
bl get_digit
|
|
cmp r2, #1
|
|
beq .exit_getc_loop
|
|
bl .div_r2_10
|
|
b .getc_loop
|
|
.exit_getc_loop:
|
|
ldr r0, =lf
|
|
strb r0, [r1], #1
|
|
|
|
sub r2, r1, r3
|
|
mov r1, r3
|
|
mov r0, #1
|
|
bl write
|
|
cmp r0, #0
|
|
blne io_error
|
|
add sp, sp, #20
|
|
ldmfd sp!, {r4,r5,r6,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
range_check:
|
|
stmfd sp!, {r4,r5,lr}
|
|
ldr r4, =minval
|
|
ldr r5, =maxval
|
|
cmp r4, #0
|
|
cmpeq r5, #0
|
|
beq .skip_range_check
|
|
cmp r0, r4
|
|
bllt range_err
|
|
cmp r0, r5
|
|
blgt range_err
|
|
.skip_range_check:
|
|
ldmfd sp!, {r4,r5,pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ void range_err()
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
range_err:
|
|
stmfd sp!, {lr}
|
|
ldr r2, =range_err_msglen
|
|
ldr r1, =range_err_msg
|
|
mov r0, #2
|
|
bl write
|
|
mov r0, #-1
|
|
bl exit
|
|
ldmfd sp!, {pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ void overflow()
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
overflow:
|
|
stmfd sp!, {lr}
|
|
ldr r2, =overflow_msglen
|
|
ldr r1, =overflow_msg
|
|
mov r0, #2
|
|
bl write
|
|
mov r0, #-1
|
|
bl exit
|
|
ldmfd sp!, { pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ void bad_input()
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
bad_input:
|
|
stmfd sp!, {lr}
|
|
ldr r2, =bad_input_msglen
|
|
ldr r1, =bad_input_msg
|
|
mov r0, #2
|
|
bl write
|
|
mov r0, #-1
|
|
bl exit
|
|
ldmfd sp!, {pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ void io_error()
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
io_error:
|
|
stmfd sp!, {lr}
|
|
ldr r2, =io_error_msglen
|
|
ldr r1, =io_error_msg
|
|
mov r0, #2
|
|
bl write
|
|
mov r0, #-1
|
|
bl exit
|
|
ldmfd sp!, {pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ void exit(int)
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type _start STT_FUNC
|
|
.global exit
|
|
exit:
|
|
stmfd sp!, {r7, lr}
|
|
ldr r7, =sys_exit
|
|
svc #0
|
|
ldmfd sp!, {r7, pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ int write(int fd,char*buf,int len)
|
|
@ Return 0 if we successfully write all bytes. Otherwise return the error code.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type _start STT_FUNC
|
|
.global write
|
|
write:
|
|
stmfd sp!, {r4,r7, lr}
|
|
mov r4, r2
|
|
.wr_loop:
|
|
ldr r7, =sys_write
|
|
svc #0
|
|
@ If r0 is negative, it is more than r4 with LO (unsigned <).
|
|
cmp r0, r4
|
|
sublo r4, r0
|
|
blo .wr_loop
|
|
moveq r0, #0
|
|
ldmfd sp!, {r4,r7, pc}
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@ int read(int fd,char*buf,int len)
|
|
@ Return number of bytes successfully read. Ignore errors.
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
.align 2
|
|
.code 32
|
|
.type _start STT_FUNC
|
|
.global read
|
|
read:
|
|
stmfd sp!, {r7, lr}
|
|
ldr r7, =sys_read
|
|
svc #0
|
|
cmp r0, #0
|
|
movlt r0, #0
|
|
ldmfd sp!, {r7, pc}
|