//----------------------------------------------------------------
//	base10io.s
//
//	This file defines a pair of generally useful subroutines
//	for converting between numerical data and digit-strings. 
//	The 'eax2asc' procedure converts a number into a decimal
//	string, and the 'asc2eax' procedure converts a string of
//	decimal numerals into the numerical value it represents.
//	
//	     assemble using:  $ as base10io.s -o base10io.o
//
//	programmer: ALLAN CRUSE
//	written on: 27 FEB 2006
//----------------------------------------------------------------


	.section	.text
#-----------------------------------------------------------------
asc2eax:	
#
# This procedure converts a string of decimal digits found at ESI
# into its numerical value, which it returns in the EAX register.
# (If that value overflows this register, the carry-flag is set.)
#
	pushal				# preserve CPU registers

	# Note: the saved image of register EAX is at 28(%esp)

	movl	$10, %ebx		# setup multiplier in EBX
	movl	$0, 28(%esp)		# image of EAX is cleared
nxasc:	# quit -- unless the next character is a valid digit  
	cmpb	$'0', (%esi)		# does char preceed '0'?
	jb	retok			# yes, end of the digits
	cmpb	$'9', (%esi)		# does char follow '9'?
	ja	retok			# yes, end of the digits
	# OK, convert digit to its 32-bit numeric value in EAX 
	movb	(%esi), %al		# copy the digit into AL
	subb	$'0', %al		# convert digit to number
	andl	$0xFF, %eax		# extend byte to 32-bits
	# add this new number to ten times the prior total  
	xchg	%eax, 28(%esp)		# swap with prior total
	mull	%ebx			# prior total times ten
	addl	%eax, 28(%esp)		# is added to digit-value
	jc	finis			# overflow? exit with CF=1
	# point ESI to the next source-character 
	incl	%esi			# else advance array-index
	jmp	nxasc			# and check the next char

retok:	clc				# clear carry-flag for exit
finis:
	popal				# restore saved registers
	ret				# return control to caller
#-----------------------------------------------------------------



#-----------------------------------------------------------------
eax2asc:	
#
# This procedure converts the 32-bit value found in register EAX 
# into its representation as a string of decimal numerals at EDI.
#
	pushal				# precerve CPU registers

	movl	$10, %ebx		# setup our divisor in EBX	
	xorl	%ecx, %ecx		# use ECX as digit counter
nxdiv:	# loop to generate and push the division-by-ten remainders 
	xorl	%edx, %edx		# extend dividend to qword
	divl	%ebx			# perform division by ten
	pushl	%edx			# save remainder on stack 
	incl	%ecx			# increment digit-counter 
	orl	%eax, %eax		# was the quotient zero?
	jnz	nxdiv			# no, do another division
nxdgt:	# loop to pop and store the digits in reversed order
	popl	%edx			# recover saved remainder
	addb	$'0', %dl		# convert number to ascii 
	movb	%dl, (%edi)		# place numeral in buffer
	incl	%edi			# and advance buffer-index
	loop	nxdgt			# convert another remainder

	popal				# restore saved registers
	ret				# return control to caller 
#-----------------------------------------------------------------

	.global	eax2asc, asc2eax	# make procedures visible
	.end				# nothing more to assemble