@@ -80,6 +80,15 @@ _strtoull:
8080
8181 private __strtoll_common
8282
83+ __strtoll_common.invalid_base:
84+ xor a, a
85+ ld c, a
86+ ; Setting C (base) to zero ensures that cp a, c will never set carry.
87+ ; forcing the function to return.
88+ push af
89+ ; sets BC:UDE:UHL to zero
90+ jr __strtoll_common.invalid_base_hijack
91+
8392__strtoll_common:
8493 ; output: BC:UDE:UHL
8594 ; NC = no overflow for strtoull
@@ -93,9 +102,8 @@ __strtoll_common:
93102
94103 ld bc, (ix + 15) ; base
95104 add hl, bc
96- jr c, .invalid_base
105+ jr c, __strtoll_common .invalid_base
97106 ; UBC is zero here
98- ld b, c ; store the base in B to allow for djnz hax
99107 ld hl, (ix + 9) ; nptr
100108;-------------------------------------------------------------------------------
101109; consume whitespace (inlinsed isspace)
@@ -122,7 +130,7 @@ __strtoll_common:
122130 ; A = 0, (HL) = start of number
123131;-------------------------------------------------------------------------------
124132; update the base if needed
125- or a, b ; base
133+ or a, c ; base
126134 jr z, .auto_base
127135 xor a, 16
128136 jr z, .hex_base
@@ -131,7 +139,7 @@ __strtoll_common:
131139.auto_base: ; test for 0* 0x* 0X* 0b* 0B*
132140.bin_base: ; test for 0x* 0X*
133141.hex_base: ; test for 0b* 0B*
134- inc b ; djnz hax
142+ inc c
135143 ld a, (hl)
136144 xor a, '0'
137145 jr nz, .maybe_decimal
@@ -143,34 +151,36 @@ __strtoll_common:
143151 xor a, 'B' xor 'X'
144152 jr z, .maybe_bin
145153 dec hl
146- djnz .other_base
147- ld b, 8 ; octal
154+ dec c
155+ jr nz, .other_base
156+ ld c, 8 ; octal
148157 jr .save_new_base
149158
150159.maybe_bin:
151- bit 4, b
160+ bit 4, c
152161 jr nz, .undo_inc ; hexadecimal
153162 ; base is 0 or 2
154163 inc hl
155- ld b , 2
164+ ld c , 2
156165 jr .save_new_base
157166
158167.maybe_hex:
159- bit 1, b
168+ bit 1, c
160169 jr nz, .undo_inc ; binary
161170 ; base is 0 or 16
162171 inc hl
163- ld b , 16
172+ ld c , 16
164173 jr .save_new_base
165174
166175.undo_inc:
167176 dec hl
168- ; dec b
177+ ; dec c
169178 ; jr .other_base
170179.maybe_decimal:
171180 ; set to decimal if base is not zero
172- djnz .other_base
173- ld b, 10 ; decimal
181+ dec c
182+ jr nz, .other_base
183+ ld c, 10 ; decimal
174184.save_new_base:
175185;-------------------------------------------------------------------------------
176186.other_base:
@@ -180,12 +190,10 @@ __strtoll_common:
180190.invalid_base_hijack:
181191 ; or a, a ; carry is cleared here
182192 sbc hl, hl
183- ex de, hl
184- sbc hl, hl
185- ld c, l
186193 ; A = first digit of the number
187- ; BC:UDE:UHL = 0
188- ; (ix - 1) = base
194+ ; HL = 0
195+ ; B = 0
196+ ; C = base
189197 ; (ix - 2) = (first-non-whitespace) XOR '-'
190198 ; 6, (ix - 3) = Z if result should be negative, NZ for positive
191199 ; 0, (ix - 3) = overflow bit
@@ -203,146 +211,133 @@ __strtoll_common:
203211 add a, 10
204212.check_digit:
205213 ; End the loop when the digit is out of range for the base
206- cp a, b
207- ld (ix - 1), b ; store base
208- ld b, l ; now BC:UDE:UHL is zero
214+ cp a, c
215+ push hl ; (ix - 6) = $000000
216+ push hl ; (ix - 9) = $000000
209217 jr c, .loop
210218;-------------------------------------------------------------------------------
211219; no digit found or invalid base
212220 ; set *endptr to nptr and return 0
213221 ld iy, (ix + 9) ; nptr
214222 jr .write_endptr
215- .invalid_base:
216- xor a, a
217- ld b, a
218- ; Setting B (base) to zero ensures that cp a, b will never set carry.
219- ; forcing the function to return.
220- push af
221- ; sets BC:UDE:UHL to zero
222- jr .invalid_base_hijack
223+
223224;-------------------------------------------------------------------------------
224225; CC per non-decimal digit:
225- ; minimum : 100F + 20R + 18W + 35
226- ; low average : 102F + 20R + 18W + 36
227- ; high average : 112F + 20R + 18W + 37 ; an over-estimate of the average CC
228- ; maximum : 127F + 20R + 18W + 40
229- ; overflow max : 133F + 24R + 22W + 42
226+ ; no overflow : 109F + 10R + 9W + 33
227+ ; overflow : 117F + 11R + 10W + 35
230228.check_decimal:
231- cp a, (ix - 1)
229+ cp a, c
232230 jr nc, .end_loop
233231.loop:
234- call __llmul_add_b_overflow
235- .next_digit:
236- ; IY = str, BC:UDE:UHL = accumulator, 0, (ix - 3) = overflow bit
237- inc iy
238- ; Convert a numerical digit
239- ld a, (iy)
240- sub a, 48
241- cp a, 10
242- jr c, .check_decimal
243- ; Convert an alphabetic digit, case-insensitive
244- sub a, 65 - 48
245- res 5, a
246- add a, 10
247- ; End the loop when the digit is out of range for the base
248- cp a, (ix - 1)
249- jr c, .loop
250- .end_loop:
251- ;-------------------------------------------------------------------------------
252- .write_endptr:
253- push hl
254- ld hl, (ix + 12) ; endptr
255- add hl, de
256- or a, a
257- sbc hl, de
258- jr z, .endptr_null
259- ld (hl), iy
260- .endptr_null:
261- pop hl
262- pop af ; overflow and sign flags
263- pop ix
264- ret
265-
266- ;-------------------------------------------------------------------------------
267-
268- private __llmul_add_b_overflow
269- __llmul_add_b_overflow:
270- ; BC:UDE:UHL = (BC:UDE:UHL * (ix - 1)) + A
232+ .__llmul_add_b_overflow:
233+ ; value = (value * C) + A
271234; bit 0, (ix - 3) is set if overflow has occured
272- .__llmulu_b_overflow:
273- ; inlined/modified __llmulu_b
274- ; CC no overflow : 69F + 16R + 15W + 33
275- ; CC overflow max : 73F + 17R + 16W + 34
276- push hl ; (ix - 9)
277- push de ; (ix - 12)
278- push bc ; (ix - 15)
279- ld b, (ix - 1)
280- ld c, e ; ld c, (ix - 12)
281- ld e, h ; ld e, (ix - 8)
282- ld h, b
235+ ; (ix - 6) --> HL
236+ ; (ix - 9) --> DE
237+ ; HL --> BC
238+ push hl ; (ix - 12)
239+ ld h, c
240+ ld l, (ix - 6) ; L
283241 mlt hl
284242
285243 ; (255 * 255) + 255 < 65535 so no 16bit carry can occur
286244 add a, l
287- ld (ix - 9 ), a ; L
288- ld d, b
289- ; ld e, (ix - 8 ) ; H
245+ ld (ix - 6 ), a ; L
246+ ld d, c
247+ ld e, (ix - 5 ) ; H
290248 mlt de
291249 ld l, h
292- ld h, 0
250+ ld h, b ; B is guaranteed to be zero if overflow has not occured
293251 adc hl, de ; handles carry from adding A
294252 xor a, a
295253
296- ld (ix - 8 ), l ; H
297- ld d, b
298- ld e, (ix - 7 ) ; UHL
254+ ld (ix - 5 ), l ; H
255+ ld d, c
256+ ld e, (ix - 4 ) ; UHL
299257 mlt de
300258 ld l, h
301259 ld h, a
302260 add hl, de
303- ld (ix - 7 ), l ; UHL
304- ld d, b
305- ld e, c ; ld e, (ix - 12) ; E
261+ ld (ix - 4 ), l ; UHL
262+ ld d, c
263+ ld e, (ix - 9) ; E
306264 mlt de
307265 ld l, h
308266 ld h, a
309267 add hl, de
310- ld (ix - 12 ), l ; E
311- ld d, b
312- ld e, (ix - 11 ) ; D
268+ ld (ix - 9 ), l ; E
269+ ld d, c
270+ ld e, (ix - 8 ) ; D
313271 mlt de
314272 ld l, h
315273 ld h, a
316274 add hl, de
317- ld (ix - 11 ), l ; D
318- ld d, b
319- ld e, (ix - 10 ) ; UDE
275+ ld (ix - 8 ), l ; D
276+ ld d, c
277+ ld e, (ix - 7 ) ; UDE
320278 mlt de
321279 ld l, h
322280 ld h, a
323281 add hl, de
324- ld (ix - 10 ), l ; UDE
282+ ld (ix - 7 ), l ; UDE
325283
326284 pop de
327285 ld l, h
328- ld c , d
329- ld d, b
286+ ld b , d
287+ ld d, c ; D = base
330288 mlt bc
331289 ld h, c
290+ ld c, d ; C = base
332291 mlt de
333292
334293 add.s hl, de
335- pop de
294+ sbc a, b ; set carry if B is non-zero or if there was carry previously
336295 jr c, .set_overflow_bit
337- sub a, b ; set carry if B is non-zero
338- ld b, h
296+ .next_digit:
297+ ; (ix - 6) --> HL
298+ ; (ix - 9) --> DE
299+ ; HL --> BC
300+ ; C = base
301+ ; IY = str
302+ ; 0, (ix - 3) = overflow bit
303+ inc iy
304+ ; Convert a numerical digit
305+ ld a, (iy)
306+ sub a, 48
307+ cp a, 10
308+ jr c, .check_decimal
309+ ; Convert an alphabetic digit, case-insensitive
310+ sub a, 65 - 48
311+ res 5, a
312+ add a, 10
313+ ; End the loop when the digit is out of range for the base
314+ cp a, c
315+ jr c, .loop
316+ .end_loop:
317+ ;-------------------------------------------------------------------------------
318+ .write_endptr:
339319 ld c, l
340- .set_overflow_bit:
320+ ld b, h
321+ ld hl, (ix + 12) ; endptr
322+ add hl, de
323+ or a, a
324+ sbc hl, de
325+ jr z, .endptr_null
326+ ld (hl), iy
327+ .endptr_null:
328+ pop de
341329 pop hl
342- ret nc
343- set 0, (ix - 3) ; set carry
330+ pop af ; overflow and sign flags
331+ pop ix
344332 ret
345333
334+ ;-------------------------------------------------------------------------------
335+ .set_overflow_bit:
336+ set 0, (ix - 3) ; set carry
337+ jr .next_digit
338+
339+ ;-------------------------------------------------------------------------------
340+
346341 extern _errno
347342 extern __llneg
348343 extern __llcmpzero
0 commit comments