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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
// Based on restoring division algorithm
// Algorithm source document: Lecture notes by S. Galal and D. Pham, Division algorithms and hardware implementations.
// Link to documentation http://www.seas.ucla.edu/~ingrid/ee213a/lectures/division_presentV2.pdf
// Also refer to description on Wikipedia: https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
// Note that the algorithm automatically yields the following results for special cases:
// z div 0 = MAX(type)
// 0 div 0 = MAX(type)
// 0 div n = 0
// Checks for z = 0; n = [0,1]; n = z and n > z could shortcut the algorithm for speed-ups
// but would add extra code
// Perhaps add the checks depending on optimization settings?
// z in Ra, n in Rb, 0 in Rp
function fpc_divmod_byte(n, z: byte): byte; assembler; nostackframe;
label
div1, div2, div3, finish;
asm
// Symbol Name Register(s)
// z (A) dividend R22
// n (B) divisor R24
// p (P) remainder R20
// i counter R18
clr R20 // clear remainder
ldi R18, 8 // iterate over 8 bits
div1:
lsl R22 // shift left A
rol R20 // shift left P with carry from A shift
sub R20, R24 // Subtract B from P, P <= P - B
brlo div2
ori R22, 1 // Set A[0] = 1
rjmp div3
div2: // negative branch, A[0] = 0 (default after shift), restore P
add R20, R24 // restore old value of P
div3:
dec R18
brne div1
finish:
mov R24, R22 // Move result from R22 to R24
end;
{$if defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}
function fpc_divmod_word(n, z: word): word; assembler; nostackframe;
label
div1, div2, div3, finish;
asm
// Symbol Name Register(s)
// z (A) dividend R23, R22
// n (B) divisor R25, R24
// p (P) remainder R21, R20
// i counter R18
clr R20 // clear remainder low
clr R21 // clear remainder hi
ldi R18, 16 // iterate over 16 bits
div1:
lsl R22 // shift left A_L
rol R23
rol R20 // shift left P with carry from A shift
rol R21
sub R20, R24 // Subtract B from P, P <= P - B
sbc R21, R25
brlo div2
ori R22, 1 // Set A[0] = 1
rjmp div3
div2: // negative branch, A[0] = 0 (default after shift), restore P
add R20, R24 // restore old value of P
adc R21, R25
div3:
dec R18
brne div1
finish:
mov R24, R22 // Move result from R22:R23 to R24:R25
mov R25, R23 // Move result from R22:R23 to R24:R25
end;
function fpc_divmod_dword(n, z: dword): dword; assembler; nostackframe;
label
div1, div2, div3, finish;
asm
end;
{$else defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}
// z in Ra, n in Rb, 0 in Rp
function fpc_divmod_word(n, z: word): word; assembler; nostackframe;
label
div1, div2, div3, finish;
asm
// Symbol Name Register(s)
// z (A) dividend R23, R22
// n (B) divisor R25, R24
// p (P) remainder R21, R20
// i counter R18
clr R20 // clear remainder low
clr R21 // clear remainder hi
ldi R18, 16 // iterate over 16 bits
div1:
lsl R22 // shift left A_L
rol R23
rol R20 // shift left P with carry from A shift
rol R21
sub R20, R24 // Subtract B from P, P <= P - B
sbc R21, R25
brlo div2
ori R22, 1 // Set A[0] = 1
rjmp div3
div2: // negative branch, A[0] = 0 (default after shift), restore P
add R20, R24 // restore old value of P
adc R21, R25
div3:
dec R18
brne div1
finish:
movw R24, R22 // Move result from R22:R23 to R24:R25
end;
// z in Ra, n in Rb, 0 in Rp
function fpc_divmod_dword(n, z: dword): dword; assembler; nostackframe;
label
div1, div2, div3, finish;
asm
// Symbol Name Register(s)
// z (A) dividend R21, R20, R19, R18
// n (B) divisor R25, R24, R23, R22
// p (P) remainder R17, R16, R15, R14 -> Returned in R25, R24, R23, R22
// i counter R26
push R17
push R16
push R15
push R14
clr R14 // clear remainder
clr R15 // clear remainder
clr R16
clr R17
ldi R26, 32 // iterate over 32 bits
div1:
lsl R18 // shift left A_L
rol R19
rol R20
rol R21
rol R14 // shift left P with carry from A shift
rol R15
rol R16
rol R17
sub R14, R22 // Subtract B from P, P <= P - B
sbc R15, R23
sbc R16, R24
sbc R17, R25
brlo div2
ori R18, 1 // Set A[0] = 1
rjmp div3
div2: // negative branch, A[0] = 0 (default after shift), restore P
add R14, R22 // restore old value of P
adc R15, R23
adc R16, R24
adc R17, R25
div3:
dec R26
brne div1
finish:
movw R22, R14 // Move remainder into reg that is not volatile
movw R24, R16
pop R14
pop R15
pop R16
pop R17
end;
{$endif defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}
|