@@ -80,6 +80,15 @@ _strtoull:
8080
8181private __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
94103ld bc, (ix + 15) ; base
95104add 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
99107ld 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
126134jr z, .auto_base
127135xor a, 16
128136jr 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- incb ; djnz hax
142+ incc
135143ld a, (hl)
136144xor a, '0'
137145jr nz, .maybe_decimal
@@ -143,34 +151,36 @@ __strtoll_common:
143151xor a, 'B' xor 'X'
144152jr z, .maybe_bin
145153dec hl
146- djnz .other_base
147- ld b, 8 ; octal
154+ dec c
155+ jr nz, .other_base
156+ ld c, 8 ; octal
148157jr .save_new_base
149158
150159.maybe_bin:
151- bit 4, b
160+ bit 4, c
152161jr nz, .undo_inc ; hexadecimal
153162; base is 0 or 2
154163inc hl
155- ldb , 2
164+ ldc , 2
156165jr .save_new_base
157166
158167.maybe_hex:
159- bit 1, b
168+ bit 1, c
160169jr nz, .undo_inc ; binary
161170; base is 0 or 16
162171inc hl
163- ldb , 16
172+ ldc , 16
164173jr .save_new_base
165174
166175.undo_inc:
167176dec hl
168- ; decb
177+ ; decc
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
182192sbc 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:
203211add 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
209217jr c, .loop
210218;-------------------------------------------------------------------------------
211219; no digit found or invalid base
212220; set *endptr to nptr and return 0
213221ld iy, (ix + 9) ; nptr
214222jr .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
232230jr 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
283241mlt hl
284242
285243; (255 * 255) + 255 < 65535 so no 16bit carry can occur
286244add 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
290248mlt de
291249ld l, h
292- ld h, 0
250+ ld h, b ; B is guaranteed to be zero if overflow has not occured
293251adc hl, de ; handles carry from adding A
294252xor 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
299257mlt de
300258ld l, h
301259ld h, a
302260add 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
306264mlt de
307265ld l, h
308266ld h, a
309267add 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
313271mlt de
314272ld l, h
315273ld h, a
316274add 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
320278mlt de
321279ld l, h
322280ld h, a
323281add hl, de
324- ld (ix - 10 ), l ; UDE
282+ ld (ix - 7 ), l ; UDE
325283
326284pop de
327285ld l, h
328- ldc , d
329- ld d, b
286+ ldb , d
287+ ld d, c ; D = base
330288mlt bc
331289ld h, c
290+ ld c, d ; C = base
332291mlt de
333292
334293add.s hl, de
335- pop de
294+ sbc a, b ; set carry if B is non-zero or if there was carry previously
336295jr 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:
339319ld 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
341329pop hl
342- ret nc
343- set 0, (ix - 3) ; set carry
330+ pop af ; overflow and sign flags
331+ pop ix
344332ret
345333
334+ ;-------------------------------------------------------------------------------
335+ .set_overflow_bit:
336+ set 0, (ix - 3) ; set carry
337+ jr .next_digit
338+
339+ ;-------------------------------------------------------------------------------
340+
346341extern _errno
347342extern __llneg
348343extern __llcmpzero
0 commit comments