
if ~ defined i8087

	restore i8087	; this ensures that symbol cannot be forward-referenced
	i8087 = 1

	define x87 x87

	element st?

	repeat 8, i:0
		element st#i? : st? + i
	end repeat

	define x86.qword? :8
	define x86.tword? :10
	define x86.tbyte? :10

	iterate context, @dest,@src,@src2,@aux

		namespace context

			calminstruction x87.parse_operand#context operand

				local	i

				match	=st?(i), operand
				jyes	indexed_streg_operand

				call	x86.parse_operand#context, operand

				check	type = 'imm' & size = 0
				jno	done
				check	imm eq 1 elementof imm & 1 metadataof imm relativeto st?
				jyes	streg_operand
				check	imm relativeto st? & imm = st?
				jno	done

				compute type, 'streg'
				compute mod, 11b
				compute rm, 0

				exit

			    streg_operand:

				compute type, 'streg'
				compute mod, 11b
				compute rm, 1 metadataof imm - st?

				exit

			    indexed_streg_operand:

				compute size, 0
				compute type, 'streg'
				compute mod, 11b
				compute rm, +i

			    done:

			end calminstruction

		end namespace

	end iterate

	iterate <instr,opcode>, fwait,9Bh, wait,9Bh, fnop,<0D9h,0D0h>, \
				fchs,<0D9h,0E0h>, fabs,<0D9h,0E1h>, ftst,<0D9h,0E4h>, fxam,<0D9h,0E5h>, fld1,<0D9h,0E8h>, \
				fldl2t,<0D9h,0E9h>, fldl2e,<0D9h,0EAh>, fldpi,<0D9h,0EBh>, fldlg2,<0D9h,0ECh>, fldln2,<0D9h,0EDh>, fldz,<0D9h,0EEh>, \
				f2xm1,<0D9h,0F0h>, fyl2x,<0D9h,0F1h>, fptan,<0D9h,0F2h>, fpatan,<0D9h,0F3h>, fxtract,<0D9h,0F4h>, fdecstp,<0D9h,0F6h>, fincstp,<0D9h,0F7h>, fprem,<0D9h,0F8h>, \
				fyl2xp1,<0D9h,0F9h>, fsqrt,<0D9h,0FAh>, frndint,<0D9h,0FCh>, fscale,<0D9h,0FDh>, \
				fneni,<0DBh,0E0h>, fndisi,<0DBh,0E1h>, fnclex,<0DBh,0E2h>, fninit,<0DBh,0E3h>, \
				fcompp,<0DEh,0D9h>

		calminstruction instr?
			asm	db opcode
		end calminstruction

	end iterate

	iterate op,  eni, disi, clex, init
		calminstruction f#op?
			asm	fwait?
			asm	fn#op?
		end calminstruction
	end iterate

	iterate <instr,postbyte>, fadd,0, fmul,1, fsub,4, fsubr,5, fdiv,6, fdivr,7

		calminstruction instr? operand&
			local	dest, src
			match	dest=,src, operand
			jyes	st
			call	x87.parse_operand@dest, operand
			check	@dest.type = 'mem'
			jno	invalid_combination_of_operands
			check	@dest.size = 4
			jyes	mem_dword
			check	@dest.size = 8
			jyes	mem_qword
			check	@dest.size
			jno	unknown_size
			err	'invalid operand size'
			jump	mem_dword
		    unknown_size:
			err	'operand size not specified'
		    mem_dword:
			xcall	x86.store_instruction@dest, (0D8h),(postbyte)
			exit
		    mem_qword:
			xcall	x86.store_instruction@dest, (0DCh),(postbyte)
			exit
		    st:
			call	x87.parse_operand@dest, dest
			call	x87.parse_operand@src, src
			check	@dest.type = 'streg' & @src.type = 'streg'
			jno	invalid_combination_of_operands
			check	@dest.rm = 0
			jyes	st0_sti
			check	@src.rm = 0
			jyes	sti_st0
			jump	invalid_combination_of_operands
		    st0_sti:
			emit	1, 0D8h
			emit	1, 11b shl 6 + postbyte shl 3 + @src.rm
			exit
		    sti_st0:
			check	postbyte >= 4
			jyes	switched
			emit	1, 0DCh
			emit	1, 11b shl 6 + postbyte shl 3 + @dest.rm
			exit
		    switched:
			emit	1, 0DCh
			emit	1, 11b shl 6 + (postbyte xor 1) shl 3 + @dest.rm
			exit
		    invalid_combination_of_operands:
			err	'invalid combination of operands'
		end calminstruction

	end iterate

	iterate <instr,postbyte>, faddp,0, fmulp,1, fsubrp,4, fsubp,5, fdivrp,6, fdivp,7

		calminstruction instr? operand&
			local	dest, src
			match	, operand
			jyes	default
			match	dest=,src, operand
			jno	invalid_combination_of_operands
			call	x87.parse_operand@dest, dest
			call	x87.parse_operand@src, src
			check	@dest.type = 'streg' & @src.type = 'streg' & @src.rm = 0
			jyes	ok
		    invalid_combination_of_operands:
			err	'invalid combination of operands'
			exit
		    default:
			compute @dest.rm, 1
		    ok:
			emit	1, 0DEh
			emit	1, 11b shl 6 + postbyte shl 3 + @dest.rm
		end calminstruction

	end iterate

	iterate <instr,postbyte>, fcom,2, fcomp,3

		calminstruction instr? src:st1
			call	x87.parse_operand@src, src
			check	@src.type = 'streg'
			jyes	st
			check	@src.type = 'mem'
			jno	invalid_operand
			check	@src.size = 4
			jyes	mem_dword
			check	@src.size = 8
			jyes	mem_qword
			check	@src.size
			jno	unknown_size
			err	'invalid operand size'
			jump	mem_dword
		    unknown_size:
			err	'operand size not specified'
		    mem_dword: st:
			xcall	x86.store_instruction@src, (0D8h),(postbyte)
			exit
		    mem_qword:
			xcall	x86.store_instruction@src, (0DCh),(postbyte)
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	iterate <instr,postbyte>, fiadd,0, fimul,1, ficom,2, ficomp,3, fisub,4, fisubr,5, fidiv,6, fidivr,7

		calminstruction instr? src*
			call	x87.parse_operand@src, src
			check	@src.type = 'mem'
			jno	invalid_operand
			check	@src.size = 2
			jyes	mem_word
			check	@src.size = 4
			jyes	mem_dword
			check	@src.size
			jno	unknown_size
			err	'invalid operand size'
			jump	mem_word
		    unknown_size:
			err	'operand size not specified'
		    mem_word:
			xcall	x86.store_instruction@src, (0DEh),(postbyte)
			exit
		    mem_dword:
			xcall	x86.store_instruction@src, (0DAh),(postbyte)
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	calminstruction fld? src*
		call	x87.parse_operand@src, src
		check	@src.type = 'streg'
		jyes	st
		check	@src.type = 'mem'
		jno	invalid_operand
		check	@src.size = 4
		jyes	mem_dword
		check	@src.size = 8
		jyes	mem_qword
		check	@src.size = 10
		jyes	mem_tword
		check	@src.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_dword
	    unknown_size:
		err	'operand size not specified'
	    mem_dword: st:
		xcall	x86.store_instruction@src, (0D9h),(0)
		exit
	    mem_qword:
		xcall	x86.store_instruction@src, (0DDh),(0)
		exit
	    mem_tword:
		xcall	x86.store_instruction@src, (0DBh),(5)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fst? dest*
		call	x87.parse_operand@dest, dest
		check	@dest.type = 'streg'
		jyes	st
		check	@dest.type = 'mem'
		jno	invalid_operand
		check	@dest.size = 4
		jyes	mem_dword
		check	@dest.size = 8
		jyes	mem_qword
		check	@dest.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_dword
	    unknown_size:
		err	'operand size not specified'
	    mem_dword:
		xcall	x86.store_instruction@dest, (0D9h),(2)
		exit
	    mem_qword: st:
		xcall	x86.store_instruction@dest, (0DDh),(2)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fstp? dest*
		call	x87.parse_operand@dest, dest
		check	@dest.type = 'streg'
		jyes	st
		check	@dest.type = 'mem'
		jno	invalid_operand
		check	@dest.size = 4
		jyes	mem_dword
		check	@dest.size = 8
		jyes	mem_qword
		check	@dest.size = 10
		jyes	mem_tword
		check	@dest.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_dword
	    unknown_size:
		err	'operand size not specified'
	    mem_dword:
		xcall	x86.store_instruction@dest, (0D9h),(3)
		exit
	    mem_qword: st:
		xcall	x86.store_instruction@dest, (0DDh),(3)
		exit
	    mem_tword:
		xcall	x86.store_instruction@dest, (0DBh),(7)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fild? src*
		call	x87.parse_operand@src, src
		check	@src.type = 'mem'
		jno	invalid_operand
		check	@src.size = 2
		jyes	mem_word
		check	@src.size = 4
		jyes	mem_dword
		check	@src.size = 8
		jyes	mem_qword
		check	@src.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_word
	    unknown_size:
		err	'operand size not specified'
	    mem_word:
		xcall	x86.store_instruction@src, (0DFh),(0)
		exit
	    mem_dword:
		xcall	x86.store_instruction@src, (0DBh),(0)
		exit
	    mem_qword:
		xcall	x86.store_instruction@src, (0DFh),(5)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fist? dest*
		call	x87.parse_operand@dest, dest
		check	@dest.type = 'mem'
		jno	invalid_operand
		check	@dest.size = 2
		jyes	mem_word
		check	@dest.size = 4
		jyes	mem_dword
		check	@dest.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_word
	    unknown_size:
		err	'operand size not specified'
	    mem_word:
		xcall	x86.store_instruction@dest, (0DFh),(2)
		exit
	    mem_dword:
		xcall	x86.store_instruction@dest, (0DBh),(2)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fistp? dest*
		call	x87.parse_operand@dest, dest
		check	@dest.type = 'mem'
		jno	invalid_operand
		check	@dest.size = 2
		jyes	mem_word
		check	@dest.size = 4
		jyes	mem_dword
		check	@dest.size = 8
		jyes	mem_qword
		check	@dest.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_word
	    unknown_size:
		err	'operand size not specified'
	    mem_word:
		xcall	x86.store_instruction@dest, (0DFh),(3)
		exit
	    mem_dword:
		xcall	x86.store_instruction@dest, (0DBh),(3)
		exit
	    mem_qword:
		xcall	x86.store_instruction@dest, (0DFh),(7)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	calminstruction fisttp? dest*
		call	x87.parse_operand@dest, dest
		check	@dest.type = 'mem'
		jno	invalid_operand
		check	@dest.size = 2
		jyes	mem_word
		check	@dest.size = 4
		jyes	mem_dword
		check	@dest.size = 8
		jyes	mem_qword
		check	@dest.size
		jno	unknown_size
		err	'invalid operand size'
		jump	mem_word
	    unknown_size:
		err	'operand size not specified'
	    mem_word:
		xcall	x86.store_instruction@dest, (0DFh),(1)
		exit
	    mem_dword:
		xcall	x86.store_instruction@dest, (0DBh),(1)
		exit
	    mem_qword:
		xcall	x86.store_instruction@dest, (0DDh),(1)
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	iterate <instr,postbyte>, fbld,4, fbstp,6

		calminstruction instr? src*
			call	x87.parse_operand@src, src
			check	@src.type = 'mem'
			jno	invalid_operand
			check	@src.size and not 10
			jyes	invalid_operand_size
			xcall	x86.store_instruction@src, (0DFh),(postbyte)
			exit
		    invalid_operand_size:
			err	'invalid operand size'
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	calminstruction fxch? src:st1
		call	x87.parse_operand@src, src
		check	@src.type = 'streg'
		jno	invalid_operand
		emit	1, 0D9h
		emit	1, 11b shl 6 + 1 shl 3 + @src.rm
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	iterate <instr,basecode>, ffree,0DDh, ffreep,0DFh

		calminstruction instr? src*
			call	x87.parse_operand@src, src
			check	@src.type = 'streg'
			jno	invalid_operand
			emit	1, basecode
			emit	1, 11b shl 6 + @src.rm
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	calminstruction fnstsw? dest*
		call	x86.parse_operand@dest, dest
		check	@dest.size and not 2
		jyes	invalid_operand_size
		check	@dest.type = 'mem'
		jyes	mem
		check	@dest.type = 'reg' & @dest.rm = 0
		jno	invalid_operand
		emit	1, 0DFh
		emit	1, 0E0h
		exit
	    mem:
		xcall	x86.store_instruction@dest, (0DDh),(7)
		exit
	    invalid_operand_size:
		err	'invalid operand size'
		exit
	    invalid_operand:
		err	'invalid operand'
	end calminstruction

	iterate <instr,postbyte>, fldcw,5, fnstcw,7

		calminstruction instr? dest*
			call	x86.parse_operand@dest, dest
			check	@dest.size and not 2
			jyes	invalid_operand_size
			check	@dest.type = 'mem'
			jno	invalid_operand
			xcall	x86.store_instruction@dest, (0D9h),(postbyte)
			exit
		    invalid_operand_size:
			err	'invalid operand size'
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	iterate <instr,postbyte>, fldenv,4, fnstenv,6

		calminstruction instr? dest*
			call	x86.parse_operand@dest, dest
			check	@dest.size and not 14
			jyes	invalid_operand_size
			check	@dest.type = 'mem'
			jno	invalid_operand
			xcall	x86.store_instruction@dest, (0D9h),(postbyte)
			exit
		    invalid_operand_size:
			err	'invalid operand size'
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	iterate <instr,postbyte>, frstor,4, fnsave,6

		calminstruction instr? dest*
			call	x86.parse_operand@dest, dest
			check	@dest.size and not 94
			jyes	invalid_operand_size
			check	@dest.type = 'mem'
			jno	invalid_operand
			xcall	x86.store_instruction@dest, (0DDh),(postbyte)
			exit
		    invalid_operand_size:
			err	'invalid operand size'
			exit
		    invalid_operand:
			err	'invalid operand'
		end calminstruction

	end iterate

	iterate op,  stsw, stcw, stenv, save
		calminstruction f#op? dest*
			asm	fwait?
			asm	fn#op? dest
		end calminstruction
	end iterate

end if