//----------------------------------------------------------------
//	showpi.s
//
//	This program employs Pentium floating-point instructions
//	to exhibit the value of 'PI' to sixteen decimal-places.
//
//	   assemble using:  $ as showpi.s -o showpi.o
//	   and link using:  $ ld showpi.o -o showpi
//
//	programmer: ALLAN CRUSE
//	written on: 04 DEC 2003
//----------------------------------------------------------------
	
	# manifest constants
	.equ	sys_EXIT, 1
	.equ	sys_WRITE, 4
	.equ	STDOUT, 1


	.data
TenTo16: .quad	10000000000000000	# to shift decimal-point
pivalue: .tfloat 0			# holds a ten-byte value
message: .ascii	"\n\t\t\tPI = "		# text explaining output
numbuff: .ascii "                    "	# buffer holds numerals 
	 .ascii "\n\n"			# appends an extra line 
msgsize: .int	. - message		# length of the message


	.text
_start:
	# compute PI * 10**16 and store its integer part	

	finit				# initialize coprocessor
	fldpi				# load the value of 'PI'
	fildq	TenTo16			# load 10**16 multiplier
	fmulp	%st, %st(1)		# to shift decimal-point
	fbstp	pivalue			# store it as packed BCD
	fwait				# wait for NPX to finish

	# convert packed-decimal integer to an ascii string

	call	bcd2ascii		# routine for conversion

	# display a message that shows the value for 'PI'
	
	movl	$sys_WRITE, %eax	# service id-number
	movl	$STDOUT, %ebx		# device id-number
	leal	message, %ecx		# message address
	movl	msgsize, %edx		# message length
	int	$0x80			# enter the kernel

	# return control to the Linux shell

	movl	$sys_EXIT, %eax		# service id-number
	xorl	%ebx, %ebx		# program exit-code
	int	$0x80			# enter the kernel


#------------------------------------------------------------------
bcd2ascii:
#
# This procedure converts a packed-decimal stored as 'pivalue'
# to its representation as a string of decimal numerals with a
# decimal-point inserted just before the final sixteen digits.
# (The stack is used here to reverse the order of the digits.)
#
	leal	pivalue, %esi		# point ESI to BCD number
	leal	numbuff, %edi		# point EDI to out buffer
	cld				# use forward processing
	
	# loop to unpack digits and convert to ascii codes

	movl	$9, %ecx		# nine digit-pairs to unpack
nxunpk:
	lodsb				# fetch next packed-BCD byte
	xorb	%ah, %ah		# clear accumulator hi-byte
	rorw	$4, %ax			# rotate hi-nybble into AL
	rorb	$4, %ah			# rotate lo-nybble into AH
	addw	$0x3030, %ax		# convert nybbles to ascii
	pushl	%eax			# save numeral-pair on stack
	loop	nxunpk			# again for remaining bytes

	# loop to recover pairs and output in reverse order

	movl	$9, %ecx		# count of pairs to recover
nxpair:
	popl	%eax			# recover saved numeral-pair
	stosw				# move both to output buffer
	loop	nxpair			# again for remaining pairs

	# fixup output by inserting a decimal-point just ahead of
	# the final sixteen places in eighteen-character string

	movb	$'.', %al		# setup decimal-point in AL
	xchgb	%al, numbuff+1		# exchange AL with 2nd byte
	movb	%al, numbuff+0		# then put AL into 1st byte	
 
	ret				# back to calling procedure

#------------------------------------------------------------------

	.globl	_start			# make entry visible