/*

	Program to read the radius of a sphere, compute its volume, and print
	the volume of the sphere.
	

*/

.text
.global _start

_start:
	/* Prompt the user with a message "Enter radius ... : " using
	   the Linux sys call. */
	mov $4, %eax        /* The system call for write (sys_write) */
	mov $1, %ebx        /* File descriptor 1 - standard output */
	mov $prompt, %ecx   /* Put the address of prompt in ecx */
	mov $promptLen, %edx/* Place number of characters to display */
	int $0x80	    /* Call to the Linux OS */

	/* The next set of instructions implement the following while loop 

	   char c;
	   while ((c = getchar()) != '\n') {
	       radius = (radius * 10) + (c - '0') ;
	   }
	*/
readInput:
	movl $3, %eax        /* The system call for read (sys_read) */
	movl $0, %ebx        /* File descriptor 0 - standard input */
	movl $buf, %ecx      /* Put the character in a buffer */
	movl $1, %edx        /* Place number of characters to read in edx */
	int $0x80	     /* Call to the Linux OS */

	movb buf, %al
	cmpb $'\n', %al      /* Is the character '\n'? */
	je   computeVolume
	subb $'0', buf      /* Convert '0'..'9' to 0..9 */
	
	/* radius = (radius * 10) + (buf - '0') */
	movl $10, %eax
	xorl %edx, %edx
	mull radius        /* radius *= 10 */
	xorl %ebx, %ebx    /* ebx = (int) buf */
	movb buf, %bl
	addl %ebx, %eax    /* eax += buf */
	movl %eax, radius
	/* Read the next character */
	jmp readInput

computeVolume:
	/* Compute volume of sphere using the formula:

	   volume = 4 * 22 * radius * radius * radius / 7 / 3 
	*/
	movl $88, %eax     /* eax = (4 * 22) = 88 */
	xorl %edx, %edx   
	imull radius       /* radius cubed */
	imull radius
	imull radius		
	movl  $21, %ecx    /* Set ecx = 21 */
	xorl  %edx, %edx   /* Reset edx to zero for division */
	idivl %ecx         /* Divide by 21 */
        movl  %eax, volume /* Store result in volume. */

	/* Now to print the volume of the sphere. For this operation it is
	easiest to reverse the digits in volume and print the reversed integer
	on the console digit by digit.  */

	/* First reverse volume using this approach

	   int temp    = volume
	   int reverse = 0
	   int length  = 0
	   while (temp > 0) {
	       int digit = (temp % 10) ;
	       temp     /= 10	;
	       reverse   = (reverse * 10) + digit;
	       length++
	   }
	*/

	movl volume, %eax
	movl %eax, temp		/* temp = volume */
reverseLoop:	
	cmpl $0, temp
	je   printReverse
	movl temp, %eax        /* Do div and mod operations */
	xorl %edx, %edx
	idivl ten
	movl %edx, digit       /* digit = temp % 10 */
	movl %eax, temp        /* temp /= 10 */

        movl reverse, %eax     /* Do reverse *= 10 */
	xorl %edx, %edx
	imull ten
	addl digit, %eax
	movl %eax, reverse
	incl length            /* Track digits in number */
	jmp reverseLoop
	
printReverse:
	/* Here we print each digit of reversed number as follows:	
	
	   do {
	      char digit = (reverse % 10) + '0';
	      System.out.print(digit); 
	      reverse /= 10; 
	   } while (reverse > 0); 
	*/

	/* Display static message first */
	mov $4, %eax        /* The system call for write (sys_write) */
	mov $1, %ebx        /* File descriptor 1 - standard output */
	mov $msg, %ecx      /* Put the address of buf in ecx */
	mov $msgLen, %edx   /* Place number of characters to display */
	int $0x80	    /* Call to the Linux OS */
	
printLoop:
	movl reverse, %eax	
	xorl %edx, %edx
	idivl ten          /* now edx = reverse % 10 */
	movl %eax, reverse /* reverse /= 10 */
	addl $'0', %edx    /* convert 0..9 to '0'..'9' */
	movb %dl, buf      /* store character in buffer to display */

	/* Display character in buf on console */
	mov $4, %eax        /* The system call for write (sys_write) */
	mov $1, %ebx        /* File descriptor 1 - standard output */
	mov $buf, %ecx      /* Put the address of buf in ecx */
	mov $1, %edx        /* Place number of characters to display */
	int $0x80	    /* Call to the Linux OS */

	/* Check if we have more digits to print and do that */
	decl length         /* Dec also setz ZF */
	jg   printLoop

	/* Print trailing new line to finish display */
	mov $4, %eax        /* The system call for write (sys_write) */
	mov $1, %ebx        /* File descriptor 1 - standard output */
	mov $nl, %ecx       /* Put the address of buf in ecx */
	mov $1, %edx        /* Place number of characters to display */
	int $0x80	    /* Call to the Linux OS */
	
exit:	
	mov $1, %eax          /* The system call for exit (sys_exit) */
	mov $1, %ebx          /* Exit with return code of 0 (no error) */
	int $0x80

.data
radius:	.int 0
volume:	.int 0
temp:	.int 0
reverse:.int 0
digit:	.int 0
buf:	.int 0
ten:	.int 10
length:	.int 0
		
prompt:	.string "Enter radius of sphere: "
.equ promptLen, . - prompt

msg: .string "Volume of sphere: "
.equ msgLen, . - msg

nl:	.byte '\n'
