blob: 6544b3269302998cc5716cb2fb888bbd3bc44ee2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
@data mul_sign_mask ${2 ** 15}
@data mul_not_mask 0xFFFF
@label mul
; multiply a signed (a) and a signed (b)
; parameters RA = a
; RB = b
; return RG = a * b
stack_stash RA RB RC RD
ldi 0 RG ; initialize return value in RG to 0
ldi mul_sign_mask RD
ldr RD RD ; RD := 2 ** 16
and RA RD RC ; RC := 2 ** 16 if a is negative, 0 otherwise
and RB RD RD ; RD := 2 ** 16 if b is negative, 0 otherwise
xor RC RD RC ; RC := 2 ** 16 if exactly one of a or b is negative, 0 otherwise
ldi mul_not_mask RD
ldr RD RD ; RD := 0xFFFF
; RA := abs(a)
subi RA 0 RA
bri sign mul_a_negative
jpi mul_a_negative_done
@label mul_a_negative
xor RA RD RA ; RA := ~a
inc RA ; negate twos complement a
@label mul_a_negative_done
; RB := abs(b)
subi RB 0 RB
bri sign mul_b_negative
jpi mul_b_negative_done
@label mul_b_negative
xor RB RD RB ; RB := ~b
inc RB ; negate twos complement b
@label mul_b_negative_done
; the algorithms iterates b times, adding a to RG each time
; so b should be as small as possible
sub RB RA RD ; if a <= b, swap a and b
bri sign mul_loop
mov RA RD
mov RB RA
mov RD RB
@label mul_loop
; if b == 0, we are done
subi RB 0 RB
bri zero mul_done
; RG += RA
add RA RG RG
dec RB
jpi mul_loop
@label mul_done
; set the most significant bit to the precomputed sign
subi RC 0 RC
bri sign mul_negate_result
jpi mul_return
@label mul_negate_result
ldi mul_not_mask RD
ldr RD RD ; RD := 0xFFFF
xor RG RD RG
inc RG
@label mul_return
stack_restore RA RB RC RD
return
; Recursive impl of the factorial
; Calling convention is that arguments are in registers RA..RG (max 7 arguments since RH = SP)
; and the return value is in RG (note: overwriting arg in RG)
@label fact
; parameters RA = n
; return RG = factorial(n)
subi RA 0 RA
bri zero fact_basecase
@label fact_reccase
stack_stash RA RB
mov RA RB ; RB := n
subi RA 1 RA ; RA := n - 1
calli fact ; RG := fact(n - 1)
mov RG RA ; RA := fact(n - 1)
calli mul ; RG := n * fact(n - 1)
stack_restore RA RB
return
@label fact_basecase
ldi 1 RG
return
|