/* 
 * 387.S -- My 1989 DOS 387 asm benchmark revisited
 * Last modified: 2 February 2000
 * This code is Copyright (C)1989-2000 Nathan Laredo
 * May be freely distributed in unmodified form
 *
 * Special thanks to vbostrom at intel for p6
 * optimization hints
 *
 *  gcc -nostdlib 387.S -o 387
 */
#ifdef linux
#include <asm/unistd.h>
#define DoSysCall1	int $0x80
#define DoSysCall2	int $0x80
#define DoSysCall3	int $0x80
#else
#include <sys/syscall.h>
#define __NR_signal	SYS_signal
#define __NR_setitimer	SYS_setitimer
#define __NR_write	SYS_write
#define __NR_exit	SYS_exit
#define DoSysCall3	call BSDSysCall3
#define DoSysCall2	call BSDSysCall2
#define DoSysCall1	call BSDSysCall1
#undef  SysCallType	int $0x80
#define SysCallType	lcall $7,$0
#endif

.data

expired: .byte 1, 2, 3, 4
Output: .asciz "0000000000 "
Return: .asciz "\r"

Intro1: .asciz "387FLOPS v2.3  Last Revised 02 Feb 2000  (all values operations per second)\nFADD       FSUB       FMUL       FDIV       FSIN       FPTAN      FSINCOS\n" 

Message1: .asciz "\nAMD Opteron 246 @ 2GHz\n1910937080 2006808960 2006549480 0095542440 0021310060 0045446580 0042319780\nMobile Celeron 400 MHz:\n0519334460 0544740900 0271498800 0014680860 0006586220 0005580620 0004683380\n\nNathan Laredo (laredo@gnu.org)\n4380 Albany Dr Apt 32, San Jose CA 95129\n"

.text
	.align 4
#ifdef linux
.global _start
#endif
_start:
	/* print intro and header lines */
	movl  $Intro1,%ecx
	call  print
	/* trap signal 2 to do call exit routine below */
	movl  $2,%ebx
	movl  $doexit,%ecx
	movl  $__NR_signal,%eax
	DoSysCall2
	fld1
	fld1
	fld1
	fld1
	fld1
	fld1
back:	call  setup
	.align 4
doadd:  fadd  %st,%st(1)
	fadd  %st,%st(2)
	fadd  %st,%st(3)
	fadd  %st,%st(4)
	fadd  %st,%st(5)
	fadd  %st,%st(1)
	fadd  %st,%st(2)
	fadd  %st,%st(3)
	fadd  %st,%st(4)
	fadd  %st,%st(5)
	fadd  %st,%st(1)
	fadd  %st,%st(2)
	fadd  %st,%st(3)
	fadd  %st,%st(4)
	fadd  %st,%st(5)
	fadd  %st,%st(1)
	fadd  %st,%st(2)
	fadd  %st,%st(3)
	fadd  %st,%st(4)
	fadd  %st,%st(5)
	fadd  %st,%st(1)
	incl  %ecx
	cmpl  $0,expired
	je    doadd
	call  output
	call  setup
	.align 4
dosub:  fsub  %st,%st(1)
	fsub  %st,%st(2)
	fsub  %st,%st(3)
	fsub  %st,%st(4)
	fsub  %st,%st(5)
	fsub  %st,%st(1)
	fsub  %st,%st(2)
	fsub  %st,%st(3)
	fsub  %st,%st(4)
	fsub  %st,%st(5)
	fsub  %st,%st(1)
	fsub  %st,%st(2)
	fsub  %st,%st(3)
	fsub  %st,%st(4)
	fsub  %st,%st(5)
	fsub  %st,%st(1)
	fsub  %st,%st(2)
	fsub  %st,%st(3)
	fsub  %st,%st(4)
	fsub  %st,%st(5)
	incl  %ecx
	cmpl  $0,expired
	je    dosub
	call  output
	call  setup
	.align 4
domul:	fmul  %st,%st(1)
	fmul  %st,%st(2)
	fmul  %st,%st(3)
	fmul  %st,%st(4)
	fmul  %st,%st(5)
	fmul  %st,%st(1)
	fmul  %st,%st(2)
	fmul  %st,%st(3)
	fmul  %st,%st(4)
	fmul  %st,%st(5)
	fmul  %st,%st(1)
	fmul  %st,%st(2)
	fmul  %st,%st(3)
	fmul  %st,%st(4)
	fmul  %st,%st(5)
	fmul  %st,%st(1)
	fmul  %st,%st(2)
	fmul  %st,%st(3)
	fmul  %st,%st(4)
	fmul  %st,%st(5)
	incl  %ecx
	cmpl  $0,expired
	je    domul
	call  output
	call  setup
	.align 4
dodiv:	fdiv  %st,%st(1)
	fdiv  %st,%st(2)
	fdiv  %st,%st(3)
	fdiv  %st,%st(4)
	fdiv  %st,%st(5)
	fdiv  %st,%st(1)
	fdiv  %st,%st(2)
	fdiv  %st,%st(3)
	fdiv  %st,%st(4)
	fdiv  %st,%st(5)
	fdiv  %st,%st(1)
	fdiv  %st,%st(2)
	fdiv  %st,%st(3)
	fdiv  %st,%st(4)
	fdiv  %st,%st(5)
	fdiv  %st,%st(1)
	fdiv  %st,%st(2)
	fdiv  %st,%st(3)
	fdiv  %st,%st(4)
	fdiv  %st,%st(5)
	incl  %ecx
	cmpl  $0,expired
	je    dodiv
	call  output
	ffree %st(0)
	ffree %st(1)
	ffree %st(2)
	ffree %st(3)
	ffree %st(4)
	ffree %st(5)
	fldpi
	call  setup
	.align 4
dosin:	fsin 
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin 
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	fsin
	incl  %ecx
	cmpl  $0,expired
	je    dosin
	call  output
	call  setup
	.align 4
dotan:  fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	fptan
	incl  %ecx
	cmpl  $0,expired
	je    dotan
	call  output
	call  setup
	.align 4
dofsnc: fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	fsincos
	ffree %st(1)
	incl  %ecx
	cmpl  $0,expired
	je    dofsnc
	call  output
	movl  $Return,%ecx
	call  print
	ffree %st(7)
	ffree %st(6)
	ffree %st(5)
	ffree %st(4)
	ffree %st(3)
	ffree %st(2)
	ffree %st(1)
	ffree %st(0)
	fld1
	fld1
	fld1
	fld1
	fld1
	fld1
	jmp   back

	/* handle alarm: set expired flag, setup signal handler */
	.align 4
timeup:	incl  expired
	movl  $14,%ebx
	movl  $timeup,%ecx
	movl  $__NR_signal,%eax
	DoSysCall2
	ret

	/* setup an alarm to et expired flag in one second */
	/* clear iteration counter (%ecx) for benchmark */
	.align 4
setup:	call  timeup
	movl  $1,%ebx
	movl  $__NR_alarm,%eax
	DoSysCall2
	movl  $0,expired
	xorl  %ecx,%ecx
	ret

	/* convert counter %ecx to ascii -- multiply counter by 10 */
	.align 4
counttoascii:
	addl  %ecx,%ecx		/* multiply by 2 */
	movl  %ecx,%eax
	movl  $10,%ebx
	movl  $9,%ecx		/* we have 9 digits to convert */
div10:  xorl  %edx,%edx		/* clear remainder */
	divl  %ebx		/* eax/ebx, remainder in edx, quot eax */
	addb  $0x30,%dl		/* convert remainder to ascii and store */
	movb  %dl,Output-1(%ecx)	/* store ascii digit */
	loop  div10		/* keep going for all 9 digits */
	ret

	/* write the string pointed to by %ecx to stdout */
	.align 4
print:  movl %ecx,%edx
        xorl %ebx,%ebx
        decl %edx
print_count:
        incl %edx
        cmpb (%edx),%bl
        jnz  print_count
        subl %ecx,%edx
        movl $__NR_write,%eax
	DoSysCall3
        ret

	/* output counter contained in %ecx */
	.align 4
output:
	call  counttoascii
	movl  $Output,%ecx
	call  print
	ret

	/* exit program, printing reference comparison message */
doexit:	movl  $Message1,%ecx
	call  print
	xorl  %ebx,%ebx
	movl  $__NR_exit,%eax
	DoSysCall1	/* exit here and never return */
	int   $3	/* trap out if we get to here */

	/* wrapper for bsd syscalls */
BSDSysCall3:
	pushl  %edx
BSDSysCall2:
	pushl  %ecx
BSDSysCall1:
	pushl  %ebx
	pushl  %eax
	lcall  $7,$0
	ret
