;    GRDB - debugger for dos with 32-bit extensions
;    Copyright (C) 1997-2006  David Lindauer
;
;    This program is free software; you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation; either version 2 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program; if not, write to the Free Software
;    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
;
;    (for GNU General public license see file COPYING)
;
;    you may contact the author at:  mailto::camille@bluegrass.net
; 
;    or by snail mail at:
;
;    David Lindauer
;    850 Washburn Ave.  Apt #99
;    Louisville, KY 40222
;
;
; ASMOPS.ASM
;
; Function: Assembler operand parsers
;
	;MASM MODE
	.386
	.MODEL use32 SMALL

include asm.asi
include asm.ase
include opcodes.asi
include opcodes.ase
include opcom.ase
include prints.ase 
include input.ase
include mtrap.ase
include	dispatch.ase
include operands.ase

	PUBLIC	aop0,  aop1,  aop2,  aop3,  aop4,  aop5,  aop6,  aop7
        PUBLIC  aop8,  aop9,  aop10, aop11, aop12, aop13, aop14, aop15
	PUBLIC	aop16, aop17, aop18, aop19, aop20, aop21, aop22, aop23
	PUBLIC	aop24, aop25, aop26, aop27, aop28, aop29, aop30, aop31
	PUBLIC	aop32, aop33, aop34, aop35, aop36, aop37, aop38, aop39
	PUBLIC	aop40, aop41, aop42, aop43, aop44, aop45, aop46, aop47
	PUBLIC	aop48, aop49, aop50, aop51, aop52, aop53, aop54, aop55
        PUBLIC  aop56, aop57, aop58, aop59, aop60, aop61, aop62, aop63
        PUBLIC  aop64, aop65, aop66, aop67, aop68, aop69, aop70

	.data
base16c	dw	0ff03h,0ff05h,0ff07h,0ff06h,0705h,0605h, 0703h,0603h
	dw	0ffffh,0ffffh,0ffffh,0ffffh,0507h,0506h, 0307h,0306h

	.code

;Check if arg1.asize is 4 or less.  If greater, return error to caller's
;caller by mucking with the stack.

intsize PROC
	cmp	[arg1.asize],DWORDSIZE	;maybe this means the first argument
	ja	rtnDirectlyToDispatcherWithCY	;can't exceed dword size
	ret
intsize	ENDP

;See if the mode field for this structure references a memory operand
;and return error to caller's caller if not

chkmem	PROC
	cmp	[ebx+asmop.mode],AM_MEM		;this is 3
	jne	rtnDirectlyToDispatcherWithCY	;bomb if not memory operand
	ret
chkmem	ENDP

;See if the mode field for this structure references an immediate operand
;and return error to caller's caller if not

chkimm	PROC
	cmp	[ebx+asmop.mode],AM_IMM		;check if immediate
	jne	rtnDirectlyToDispatcherWithCY	;if not, bomb
	ret
chkimm	ENDP

;See if the mode field for this structure references a segment
;and return error to caller's caller if not

chkseg	PROC
	cmp	[ebx+asmop.mode],AM_SEG
	jne	rtnDirectlyToDispatcherWithCY
	ret
chkseg	ENDP

;This is a little more complicated. Let's hypothesize that chkregw is 
;shorthand for checking a 16-bit register type opcode. In this case,maybe the
;opcode must contain more than a single byte.  So before we check if it
;is a register-type opcode, we must make sure it has extra byte(s). So
;we stop here first, and if the length makes us happy, then we check mode
;  Next guess - if this is a byte argument, we bomb since a word register
;requires a word operand.

chkregw	PROC
	cmp	[ebx+asmop.asize],BYTESIZE	;is this a byte opcode
	je	rtnDirectlyToDispatcherWithCY	;if so, bomb
	jmp	chkreg			;else check mode for register type
chkregw	ENDP

;Possibly this is used for in and out, where DX is the only register
;allowed?

chkdx	PROC
	cmp	[ebx+asmop.asize],WORDSIZE	;if not a word register
	jne	rtnDirectlyToDispatcherWithCY	;then bomb
	cmp	[ebx+asmop.areg1],isEDX		;else see if DX register
	jne	rtnDirectlyToDispatcherWithCY	;if not, bomb
	jmp	chkreg
chkdx	ENDP

;Not sure about the AX part of this, since all that is being checked is
;a size of byte

chkaxw	PROC
	cmp	[ebx+asmop.asize],BYTESIZE	;if a byte register
	je	rtnDirectlyToDispatcherWithCY	;then bomb
chkaxw	ENDP

;This IS a check for AX (actually, 0 is EAX)

chkax	PROC
	cmp	[ebx+asmop.areg1],0	    	;if not EAX (maybe AX or AL)
	jne	rtnDirectlyToDispatcherWithCY	;then bomb
chkax	ENDP

;Check for a register?  As opposed to ??

chkreg	PROC
	cmp	[ebx+asmop.mode],AM_REG		;is this flag set?
	jne	rtnDirectlyToDispatcherWithCY	;if not, bomb
	ret
chkreg	ENDP

;Check for a mmx register?  As opposed to ??

chkmmx  PROC
        cmp     [ebx+asmop.mode],AM_MMX          ;is this flag set?
	jne	rtnDirectlyToDispatcherWithCY	;if not, bomb
	ret
chkmmx  ENDP

;We bomb if arg3.mode isn't none, and if it is, we still bomb if arg2.mode
;is none.  So arg3 is required to have a 'mode', whatever that is, I guess

noarg3	PROC
	cmp	[arg3.mode],AM_NONE
	jne	rtnDirectlyToDispatcherWithCY
	cmp	[arg2.mode],AM_NONE
	je	rtnDirectlyToDispatcherWithCY
	ret
noarg3	ENDP

;Same as above, except it applies to arg2

noarg2	PROC
	cmp	[arg2.mode],AM_NONE
	jne	rtnDirectlyToDispatcherWithCY
	cmp	[arg1.mode],AM_NONE
	je	rtnDirectlyToDispatcherWithCY
	ret
noarg2	ENDP

;Whoa, lets see here.  If arg1.mode, whatever that is, is NOT 0, we jnz to
;rtnDirectlyToDispatcherWithCY. Since this routine was called, the return 
;address is on the stack. Which means rtnDirectlyToDispatcherWithCY strips 
;off the return address, and returns to the caller's caller. 

noarg1	PROC
	cmp	[arg1.mode],AM_NONE
	jne	rtnDirectlyToDispatcherWithCY
	ret
noarg1	ENDP
;
; pops the ret address from the aop caller
; and goes directly back to the parser with a mismatch error
;
rtnDirectlyToDispatcherWithCY	PROC
	pop	eax
	stc
	ret
rtnDirectlyToDispatcherWithCY	ENDP


;see if size of this opcode is 1. If not, we are returning NZ and AL=1. I
;assume that 1 is important, since without the OR line, we would also be
;returning NZ if the size was not 1. In fact, several callers immediately
;do a stosb, so at the very least we are ensuring an odd number???
;  Next guess: AL will eventually be used as part of the stored, assembled
;byte.  So apparently the purpose of this routine is to set bit 0 of the
;untimate assembled value if this is NOT a byte operand.

sizeb0	PROC
	cmp	[ebx+asmop.asize],BYTESIZE
	je	szb0x
	or	al,1
szb0x:
	ret
sizeb0	ENDP

;In which case, the purpose of this routine is to set bit 3 of AL if the
;operand is NOT a byte operand.

sizeb3	PROC
	cmp	[ebx+asmop.asize],BYTESIZE
	je	szb3x
	or	al,8
szb3x:
	ret
sizeb3	ENDP
;
; main RM handler
;
; within this routine, CX = pointer to mod/RM byte and DX = flag for
; <e>bp based indexing
;
; all MOD/RM fields are set up assuming no offset and updated 
; later...
;
asmfrm	PROC
	cmp	[ebx+asmop.mode],AM_FPREG ; check for register direct mode
	jne	asmrm2
	or	al,0c0h			; modrm = 0c0+al+regval
	or	al,[ebx+asmop.areg1]
	stosb
	ret
	
asmfrm	ENDP

asmrmmmx PROC
        cmp     [ebx+asmop.mode],AM_MMX
        jne     asmrm
        shl     al,3
        or      al,0c0h
        or      al,[ebx + asmop.areg1]
        stosb
        ret
asmrmmmx ENDP


asmrm	PROC
	shl	al,3			; shift reg val into place
asmrm	ENDP


asmrm2	PROC
;
; registers are the same in both 16 & 32-bit
;
	cmp	[ebx+asmop.mode],AM_REG	; 1check for register direct mode
	jne	rmnreg
	or	al,0c0h			; modrm = 0c0+al+regval
	or	al,[ebx+asmop.areg1]
	stosb
	ret
rmnreg:
	cmp	[ebx+asmop.msize],DWORDMODE	; see which style of addressing
	je	asmrm32
;
; 16-bit MEM handler
;
	cmp	[ebx+asmop.mode],AM_MEM	; 16 bit, check for mem
	jne	rm16nmem
	or	al,6			; MODRM = 6+al
	stosb
	jmp	rmwoffs
rm16nmem:
	cmp	[ebx+asmop.mode],AM_BASED ; check for 16 bit based
	jne	rtnDirectlyToDispatcherWithCY
;
; 16-bit base handler, restricted combos and no scaling
;
	push	eax			; yes, get the reg vals
	sub	eax,eax
	mov	al,[ebx+asmop.areg1]
	mov	ah,[ebx+asmop.areg2]
	mov	edx,eax
	push	edi			; scan for a match and to get index
	mov	edi,offset base16c
	mov	ecx,16
	repne	scasw
	pop	edi
	pop	eax
	jnz	rtnDirectlyToDispatcherWithCY	; scan failed, exit
	bt	ecx,3
	jc	rm16nswap
	xchg	dl,dh
rm16nswap:
	and	cl,7
	or	al,cl
	mov	ecx,edi			; cx points at modrm byte
	stosb
	jmp	rmanyoffs		; check for offs
;
; 32-bit modes start here
;
asmrm32:
	cmp	[ebx+asmop.mode],AM_MEM	; 32 bit, check for mem
	jne	rm32nmem
;
; generic mem handler
;
	or	al,5			; MODRM = 5+al
	stosb
	jmp	rmwoffs
rm32nmem:
	cmp	[ebx+asmop.mode],AM_BASED 	; check for based
	jne	rtnDirectlyToDispatcherWithCY	; not legal if not
	cmp	[ebx+asmop.areg2],0FFh	; else see if second reg defined
	je	rm32bbonly
	cmp	[ebx+asmop.areg1],0FFh	; else see if first reg defined
	je	rm32bionly
;
; both a base AND an index
;
; the parser should have checked that ESP is not the scond arg
; and that we don't have two EBP args
;
	cmp	[ebx+asmop.areg1],isEBP	; check for BP based
	je	rm32bbsebp
	or	al,4			; flag MOD for SIB
	mov	ecx,edi
	stosb
	bsf	ax,[ebx+asmop.ascale]	; calculate SIB byte
	shl	ax,3
	or	al,[ebx +asmop.areg2]
	shl	ax,3
	or	al,[ebx+asmop.areg1]
	stosb
	sub	edx,edx
	jmp	rmanyoffs
;
; base and index, base is ebp
rm32bbsebp:
	or	al,4
	mov	ecx,edi
	stosb
	bsf	ax,[ebx+asmop.ascale]	; calculate SIB byte
	shl	eax,3
	or	al,[ebx+asmop.areg2]
	shl	eax,3
	or	eax,5			; bp based
	stosb
	mov	edx,0ff05h
	jmp	rmanyoffs
;
; index only
rm32bionly:
	or	al,4 			; select SIB byte
	stosb
	bsf	ax,word ptr [ebx+asmop.ascale] ; calculate scale factor
	shl	eax,3			; shift over
	or	ax,word ptr [ebx+asmop.areg2] ; add in index
	shl	eax,3			; shift over
	or	eax,5			; base = 5, that is none since mod = 0
	stosb
	mov	eax,[ebx+asmop.addrx]	; always 32-bit ofs in this mode
	stosd
	ret
;
; only a base reg
;
rm32bbonly:
	; shouldn't get here if no regs
	cmp	[ebx+asmop.areg1],isESP	; only one reg, check for ESP
	je	rm32besp
	cmp	[ebx+asmop.areg1],isEBP	; only one reg, check for EBP
	je	rm32bebp
	or	al,[ebx+asmop.areg1]	; no, normal MODRM byte with no SIB
	mov	ecx,edi
	stosb
	mov	dh,0FFh			; pretend 16 bit
	mov	dl,al
	and	dl,7
	jmp	rmanyoffs
;
; based ESP, no index
;
rm32besp:
	or	al,4    		; select SIB byte (sib needed
	mov	cx,di			; for indexing off ESP)
	stosb
	mov	al,24h			; sib byte for [esp] mode
	stosb
	sub	edx,edx
	jmp	rmanyoffs
;
; based ebp, no index
;
rm32bebp:
	or	al,5
	mov	ecx,edi			; so we can adjust mod later
	stosb
	mov	edx,0ff05h		; MUST have offset, this is BP base reg
	jmp	rmanyoffs
;
; now the auto offset routine.
; if (E)BP, we ALWAYS have an offset	
; otherwise we see if the offset is zero before encoding anything
	
asmrm2	ENDP
rmanyoffs PROC
	mov	eax,[ebx+asmop.addrx]	; get offs
	cmp	dx,0ff05h		; BP reg ALWAYS has offs
	je	rmaomho

	or	eax,eax 		; else no offs if offs = 0
	jz	rmaook
;
; if we get here we have an offset, fix the RM field and embed the
; offset
;
rmaomho:
	add	byte ptr [ecx],40h	; else set MOD field = 1
	and	eax,NOT 7FH		; else see if fits in a byte
	jz	rmboffs
	cmp	eax,NOT 7fh
	je	rmboffs    		; yep, go do it
	add	byte ptr [ecx],40h	; else MOD field = 2
	jmp	rmwoffs			; and go do it

rmboffs:
	mov	eax,[ebx+asmop.addrx]	; get offs
	stosb      			; store a byte offs
rmaook:
	clc
	ret
rmanyoffs	ENDP
rmszoffs	PROC
	mov	eax,[ebx+asmop.addrx]
	cmp	[ebx+asmop.msize],WORDMODE
	jae	rmwoffs
	stosb
	clc
	ret
rmszoffs	ENDP
rmwoffs	PROC
	mov	eax,[ebx+asmop.addrx]	; check size
	cmp 	[ebx+asmop.msize],WORDMODE
	ja	rmdwoffs
	stosw				; word offs
	clc
	ret
rmdwoffs:
;	test	[Disassemble32Bit],1
;	jz	rtnDirectlyToDispatcherWithCY
	stosd				; dword offs
	clc
	ret
rmwoffs	ENDP
rmszimm	PROC
	mov	eax,[ebx+asmop.addrx]	; check size
	cmp	[ebx+asmop.asize],WORDSIZE
	jae	rmszimmw
	stosb
	clc
	ret
rmszimmw:
	jne	rmszimmd
	stosw
	ret
rmszimmd:
	cmp	[ebx+asmop.asize],DWORDSIZE
	jne	rtnDirectlyToDispatcherWithCY
;	test	[Disassemble32Bit],1
;	jz	rtnDirectlyToDispatcherWithCY
	stosd
	ret
rmszimm	ENDP

shiftopsize PROC
        cmp     [arg1.asize],DWORDSIZE
        jz      sozdword
        cmp     [arg1.asize],WORDSIZE
        jnz     sozret
        or      [PrefixBitmapWord],AS_OPSIZESET
sozret:
        ret
sozdword:
        or      [PrefixBitmapWord],AS_OPSIZE
        ret
shiftopsize ENDP
;
; no operands. In this case, the opcode length is 1, so we go through this
;	weird locution to rep mov a single byte out of the structure and
;	into [di], wherever that points. Apparently it points into an opcode
;	buffer somewhere. If the opcode length is greater than one, what
;	happens?
;
aop0	PROC
	call	noarg1			;see if arg1.mode=0, whatever that means
	push	esi			;only return here if it IS 0
	movzx	ecx,[esi+opcode.oclength]	;so get the length of the opcode
	lea	esi,[esi+opcode.compare]	;find the opcode in the structure
	rep	movsb			;copy from structure to buffer
	pop	esi			;restore pointer to structure
	clc				;say no problem
	ret
aop0	ENDP
;
; word reg, bits 0-2 of opcode = reg num
;
aop1	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkregw
	mov	al,byte ptr [esi+opcode.compare]
	or	al,[arg1.areg1]
	stosb
	clc
	ret
aop1	ENDP
;
; word acc,reg... reg = bits 0-2 of opcode
;
aop2	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkaxw
	mov	ebx,offset arg2
	call	chkregw
	mov	al,byte ptr [esi+opcode.compare]
	or	al,[arg2.areg1]
	stosb
	ret
aop2	ENDP
;
; one arg, seg goes in b3-4 of opcode
;
aop3	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkseg
	mov	ah,byte ptr [esi+opcode.compare]
	mov	al,[arg1.areg1]
	cmp	ah,8
	jae	aop3ext
	cmp	al,4
	jae	aop3errx
aop3c:
	shl	al,3
	or	al,ah
	stosb
	ret
aop3ext:
	sub	al,4
	jnc	aop3c
aop3errx:
	stc
	ret
	
aop3	ENDP
;
; either combo of a reg & rm... bit 1 of opcode set if reg is dest
; bit 0 set if size = word
;
aop4	PROC
	call	noarg3
	call	intsize
	sub	al,al
	mov	ebx,offset arg1
	call	sizeb0
 	cmp	[arg1.mode],AM_REG
	jne	aop4rs
	or	al,2
	mov	ebx,offset arg2
	mov	ah,[arg1.areg1]
	jmp	aop4j

aop4rs:
 	cmp	[arg2.mode],AM_REG
	jne	aop4err
	mov	ebx,offset arg1
	mov	ah,[arg2.areg1]
aop4j:
	or	al,byte ptr [esi+opcode.compare]
	stosb
	mov	al,ah
	call	asmrm
	ret
aop4err:
	stc
	ret
aop4	ENDP
;
; use only rm, bit 0 = size (exception : jmp/call)
;
aop5	PROC
	call	noarg2
	call	intsize
        test    [farptr],1
        jnz     aop5err
	mov	ebx,offset arg1
	mov	ax,[esi+opcode.compare]
	test	al,1
	jz	aop5cansize
        cmp     [ebx+asmop.asize],DWORDSIZE
        je      aop5unsized
	cmp	[ebx+asmop.asize],WORDSIZE
	je	aop5unsized
	cmp	[ebx+asmop.asize],NOSIZE
	je	aop5unsized
aop5err:
	stc
	ret
aop5cansize:
	call	sizeb0
aop5unsized:
	stosb
	xchg	al,ah
	and	al,38h
	mov	ebx,offset arg1
	call	asmrm2
	ret
aop5	ENDP
;
; rm,count or rm,cl (shifts) bit 0 = size
; bit 1 set if size = 1, bit 4 set if size = cl, otherwise follow rm with
; a count byte
;
aop6	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	mov	ax,[esi+opcode.compare]
	call	sizeb0
	cmp	[arg2.mode],AM_REG
	je	aop6cl
	cmp	[arg2.mode],AM_IMM
	je	aop6imm
aop6b:
	stc
	ret
aop6cl:
	cmp	[arg2.asize],BYTESIZE
	jne	aop6b
	cmp	[arg2.areg1],isECX
	jne	aop6b
	or	al,12h
	stosb
        call    shiftopsize
	jmp	aop6rm
aop6imm:
	cmp	[arg2.addrx],1
	je	aop6shift1
	stosb
	xchg	al,ah
	call	asmrm2
	mov	al,byte ptr [arg2.addrx]
	stosb
	ret
aop6shift1:
	or	al,10h
	stosb
aop6rm:
	xchg	al,ah
	call	asmrm2
	ret
aop6	ENDP
;
; unordered version of aop4.  (any combo of reg and RM)
; This is XCHG instructions,
; this is unordered, so, it doesn't
; need to know which comes first
;
; bit 0 = size
;
aop7	PROC
	call	noarg3
	call	intsize
	sub	al,al
	mov	ebx,offset arg1
	call	sizeb0
 	cmp	[arg1.mode],AM_REG
	jne	aop7rs
	mov	ebx,offset arg2
	mov	ah,[arg1.areg1]
	jmp	aop7j

aop7rs:
 	cmp	[arg2.mode],AM_REG
	jne	aop7err
	mov	ebx,offset arg1
	mov	ah,[arg2.areg1]
aop7j:
	or	al,byte ptr [esi+opcode.compare]
	stosb
	mov	al,ah
	call	asmrm
	ret
aop7err:
	stc
	ret
aop7	ENDP
;
; word regrm, reg = dest.
;
aop8	PROC
        call    noarg3
        call    intsize
	cmp	[arg1.asize],BYTESIZE
        je      aop8errx
	mov	ebx,offset arg1
        call    chkregw
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	mov	al,[ebx+asmop.areg1]
	mov	ebx,offset arg2
        call    asmrm
        clc
	ret
aop8errx:
        stc
        ret
aop8	ENDP
;
; interrupts (imm byte)
;
aop9	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	cmp	byte ptr [arg1.addrx],3
	je	aop9i3
        cmp     byte ptr [arg1.addrx],1
        je      aop9i1
	mov	al,byte ptr [esi+opcode.compare]
	or	al,1
	stosb
	mov	al,byte ptr [ebx+asmop.addrx]
	stosb
	clc
	ret
aop9i3:
	mov	al,0cch
	stosb
	ret
aop9i1:
        mov     al,0f1h
        stosb
        ret
aop9	ENDP
;
; short relative branches
;
aop10	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	eax,[lastofs]
	sub	eax,[ebx+asmop.addrx]
	neg	eax
	sub	eax,2
	cmp	eax,-128
	jl	aop10errx
	cmp	eax,127
	jle	aop10ok
aop10errx:
	stc
	ret
aop10ok:
	push	eax
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	pop	eax
	stosb
	clc
	ret
aop10	ENDP
;
; RM, IMMEDIATE
; bit 0 = size
;
aop11	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkimm
	mov	ebx,offset arg1
	mov	ax,[esi+opcode.compare]
	call	sizeb0
	stosb
	xchg	al,ah
	call	asmrm2
	mov	ebx,offset arg2
	call	rmszimm
	ret
aop11	ENDP
;
; ACC,immediate
; bit 0 = size
;
aop12	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkax
	mov	ebx,offset arg2
	call	chkimm
	mov	al,byte ptr [esi+opcode.compare]
	call	sizeb0
	stosb
	call	rmszimm
	ret
aop12	ENDP
;
; mem,acc
; bit 0 = size
;
aop13	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkax
	mov	ebx,offset arg1
	call	chkmem
	mov	al,byte ptr [esi+opcode.compare]
	call	sizeb0
	stosb
	call	rmszoffs
	ret
aop13	ENDP
;
; sign-extended RM/IMM
; b1 = 0, treat as normal RM/IMM (aop11)
; else b01=11 means sign-extend byte to word
;
aop14	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkimm
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop11
	mov	eax,[ebx +asmop.addrx]
	cmp	eax,-128
	jl	aop11
	cmp	eax,127
	jge	aop11
;
; get here for signed extension
;
	mov	ebx,offset arg1
	mov	ax,[esi+opcode.compare]
	or	al,3
	stosb
	xchg	al,ah
	call	asmrm2
	mov	al,byte ptr [arg2.addrx]
	stosb
	ret
aop14	ENDP
;
; acc,imm
; b3 of opcode = size
; 
aop15	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
        call    chkreg
	mov	al,byte ptr [esi+opcode.compare]
        or      al,[ebx+asmop.areg1] 
	call	sizeb3
	stosb
	mov	ebx,offset arg2
	call	chkimm
	call	rmszimm
	ret
aop15	ENDP
;
; seg,regrm or regrm,seg
; b1 set if seg is dest
;
aop16	PROC
	call	noarg3
        call    intsize
	mov	ebx,offset arg1
	cmp	[ebx+asmop.mode],AM_SEG
	jne	aop16seg2
	mov	al,byte ptr [esi+opcode.compare]
	or	al,2
	mov	ah,[ebx+asmop.areg1]
	mov	ebx,offset arg2
	cmp	[ebx+asmop.mode],AM_REG		;is this flag set?
        jnz     aop16nw1
        cmp     [ebx + asmop.asize],DWORDSIZE     ; auto prefixing on
        jne     aop16nw1                ; ins & outs is disabled
        or      [PrefixBitmapWord],AS_OPSIZE
aop16nw1:
	jmp	aop16rm
aop16seg2:
	mov	ebx,offset arg2
	call	chkseg
	mov	al,byte ptr [esi+opcode.compare]
	mov	ah,[ebx+asmop.areg1]
	mov	ebx,offset arg1
	cmp	[ebx+asmop.mode],AM_REG		;is this flag set?
        jnz     aop16nw2
        cmp     [ebx + asmop.asize],DWORDSIZE     ; auto prefixing on
        jne     aop16nw2                ; ins & outs is disabled
        or      [PrefixBitmapWord],AS_OPSIZE
aop16nw2:
aop16rm:
	stosb
	xchg	al,ah
	call	asmrm
	ret
aop16	ENDP
;
; returns which pop the stack
;
aop17	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	mov	ax,word ptr [ebx+asmop.addrx]
	stosw
	clc
	ret
aop17	ENDP
;
; far branch or call
;
aop18	PROC
	call	noarg2
	call	intsize
	cmp	[arg1.mode],AM_SEGOFFS
	jne	aop18bad
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	mov	eax,dword ptr [arg1.addrx2]
;        test    [optass32],255
;        jnz     fbcw
;	stosw
;        jmp     fbcjoin
;fbcw:
        stosd
fbcjoin:
	mov	ax,word ptr [arg1.addrx]
	stosw
	clc
	ret
aop18bad:
	stc
	ret
aop18	ENDP
;
; ESC instruction
; imm,rm... imm is six bits and fills the low three bits of the
; opcode and the reg field
;
aop19	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	al,byte ptr [ebx+asmop.addrx]
	shr	al,3
	and	al,7
	or	al,byte ptr [esi+opcode.compare]
	stosb
	mov	al,byte ptr [ebx+asmop.addrx]
	and	al,7
	mov	ebx,offset arg2
	call	asmrm
	ret
aop19	ENDP
;
; long relative branch
;  (the parser fills in the 0f starter)
;
aop20	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	eax,[lastofs]
	sub	eax,[ebx+asmop.addrx]
	neg	eax
	sub	eax,3
;        test    [optass32],255
;        jz      lrbnot32
        sub     eax,2
;lrbnot32:
	cmp	byte ptr [esi+opcode.compare],0e0h
	jae	aop20got
	dec	eax
aop20got:
	jmp aop20ok
;        test    [optass32],255
;        jnz     aop20ok
;        test    eax,0ffff0000h
;        jz      aop20ok
;        cmp     eax,0ffff0000h
;        jnc     aop20ok
aop20errx:
	stc
	ret
aop20ok:
	push	eax
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	pop	eax
;        test    [optass32],255
;        jnz     lrbw
;	stosw
;        jmp     lrbjoin
lrbw:
        stosd
lrbjoin:
	clc
	ret
aop20	ENDP
;
;	acc,dx (in instructions)
;	bit 0 = size
;
aop21	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkdx
	mov	ebx,offset arg1
	call	chkax
	mov	al,byte ptr [esi+opcode.compare]
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop21nw
	or	al,1
aop21nw:
	cmp	[ebx +asmop.asize],DWORDSIZE	; auto prefixing on
	jne	aop21nw2		; ins & outs is disabled
        or      [PrefixBitmapWord],AS_OPSIZE
aop21nw2:
	stosb
	clc
	ret
aop21	ENDP
;
; dx,acc (out_)
; bit 0 = size
;
aop22	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkdx
	mov	ebx,offset arg2
	call	chkax
	mov	al,byte ptr [esi+opcode.compare]
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop22nw
	or	al,1
aop22nw:
	cmp	[ebx +asmop.asize],DWORDSIZE	; auto prefixing on
	jne	aop22nw2		; ins & outs is disabled
        or      [PrefixBitmapWord],AS_OPSIZE
aop22nw2:
	stosb
	clc
	ret
aop22	ENDP
;
; port,acc or acc,port
; b0 =size, b1 = 1 if port is dest
;
aop23	PROC
	call	noarg3
	call	intsize
	test	byte ptr [esi+opcode.compare],2
	jz	aop23in
	mov	ebx,offset arg2
	call	chkax
	mov	ebx,offset arg1
	call	chkimm
	jmp	aop23j
aop23in:
	mov	ebx,offset arg1
	call	chkax
	mov	ebx,offset arg2
	call	chkimm
aop23j:
	mov	al,byte ptr [esi+opcode.compare]
	cmp	[ebx +asmop.asize],WORDSIZE
	jb	aop23b
       	or	al,1
aop23b:
	clc
	stosb
	mov	al,byte ptr [ebx +asmop.addrx]
	stosb
	ret
aop23	ENDP
;
; acc,mem
; bit 0 = size
;
aop24	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkax
	mov	ebx,offset arg2
	call	chkmem
	mov	al,byte ptr [esi+opcode.compare]
	call	sizeb0
	stosb
	call	rmszoffs
	ret
aop24	ENDP
;
; immediate byte or word
; this is push imm, bit 1 set for byte
; we were about due for a departure from the standard...
; anyway the op is sign-extended if it is byte size
;
aop25	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	al,byte ptr [esi+opcode.compare]
	mov	ebx,[ebx+asmop.addrx]
;        test    [optass32],255
;        jnz     aop25bsft
;        test    ebx,0ffff0000h
;        jnz     aop25w
;        cmp     bx,-128
;        jl      aop25w
;        cmp     bx,127
;        jg      aop25w
;        jmp     aop25bs
;aop25bsft:
	cmp	ebx,-128
	jl	aop25w
	cmp	ebx,127
	jg	aop25w
;
; byte size
;
aop25bs:
	or	al,2
	stosb
	mov	al,bl
	stosb
	ret
aop25w:
	stosb
        test   [PrefixBitmapWord],AS_OPSIZETEST
        jnz     aop25dw
;        test    [optass32],255
;        jnz     aop25dw
;        cmp     ebx,0ffffh
;        ja      aop25dw
;	mov	ax,bx
;	stosw
;	clc
;	ret
aop25dw:
	or	[PrefixBitmapWord],AS_OPSIZE
	mov	eax,ebx
	stosd
	clc
	ret
aop25	ENDP
;
; enter command, we have a word then a byte
;
aop26	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
	mov	[ebx+asmop.asize],WORDSIZE
	mov	ebx,offset arg2
	call	chkimm
	mov	[ebx+asmop.asize],BYTESIZE
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	mov	ax,word ptr [arg1.addrx]
	stosw
	mov	al,byte ptr [arg2.addrx]
	stosb
	ret
aop26	ENDP
;
; stringu/w/d, pushaw,pushfw, etc
; explicit byte sizing handled elsewhere (aop0)
;
aop27	PROC
	call	noarg1
	call	intsize
	mov	al,byte ptr [esi+opcode.compare]
	cmp	[lastbyte],'w'
	je	aop27w
	cmp	[lastbyte],'d'
	je	aop27dw
;
; get here if no size specced.
	mov	al,byte ptr [esi+opcode.compare]
	and	al,NOT 1
	cmp	al,60h		; default for push/pop is word
        je      aop27w2
	cmp	al,9ch
        je      aop27w2
	stosb		; else default is byte
	clc
	ret
aop27dw:
	or	[PrefixBitmapWord],AS_OPSIZE	; come here if specified dword
aop27w:
        or      [PrefixBitmapWord],AS_OPSIZESET
aop27w2:
	mov	al,byte ptr [esi+opcode.compare] ; or here if specified word
	stosb
	clc
	ret
aop27	ENDP
;
; rm,reg (test instruction)
; bit 0 = size
; 
aop28	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkreg
	mov	al,byte ptr [esi+opcode.compare]
	call	sizeb0
	stosb
	mov	al,[arg2.areg1]
	mov	ebx,offset arg1
	call	asmrm
	ret
aop28	ENDP
;
; rm, size don't care
;
aop29	PROC
	call	noarg2
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm2
	ret
aop29	ENDP
;
; RM, shift
; bit 0 & 1 of opcode set if uses CL
; bit 0 & 4 set if uses uses 1
; else nothing set
;
aop30	PROC
	call	noarg3
	call	intsize
	mov	ax,word ptr [esi+opcode.compare]
	and	al,0ech	; get rid of extraneous bits
	mov	ebx,offset arg2
	cmp	[ebx+asmop.areg1],isEBX
	je	aop30cl
	call	chkimm
	cmp	[ebx+asmop.addrx],1
	jne	aop30xx
	or	al,11h
	stosb
	xchg	al,ah
	call	asmrm2
	ret
aop30xx:
	or	al,3
	stosb
	xchg	al,ah
	call	asmrm2
	mov	al,byte ptr [arg2.addrx]
	stosb
	ret
aop30cl:
	cmp	[ebx+asmop.asize],BYTESIZE
	jne	aop30bad
	cmp	[ebx+asmop.mode],AM_REG
	jne	aop30bad
	stosb
        call    shiftopsize
	xchg	al,ah
	call	asmrm2
	ret

aop30bad:
	stc
	ret
aop30	ENDP
;
; reg,rm,imm or reg,imm (imul)
; bit 1 = set if immed = signed byte
;
aop31	PROC
	cmp	[arg3.mode],AM_NONE
	jne	aop31three
	mov	ebx,offset arg1
	call	chkreg
	mov	al,byte ptr [esi+opcode.compare]
	mov	ebx,offset arg2
	call	chkimm
	call	aop31sb
	stosb
	push	eax
	mov	al,[arg1.areg1]
	mov	ah,al
	shl	al,3
	or	al,ah
	or	al,0c0h
	stosb
	jmp	aop31sz
aop31three:
	mov	ebx,offset arg1
	call	chkreg
	mov	al,byte ptr [esi+opcode.compare]
	mov	ebx,offset arg3
	call	chkimm
	call	aop31sb
	stosb
	push	eax
	push	ebx
	mov	al,[arg1.areg1]
	mov	ebx,offset arg2
	call	asmrm
	pop	ebx
aop31sz:
	pop	eax
	test	al,2
	mov	eax,dword ptr [ebx +asmop.addrx]
	jnz	aop31sb1
	test	[PrefixBitmapWord],AS_OPSIZE
	jz	aop31szw
	stosd
	clc
	ret
aop31szw:
	stosw
	clc
	ret
aop31sb1:
	stosb
	clc
	ret
aop31sb	PROC
	mov	ecx,[ebx+asmop.addrx]
	test	ecx,NOT 7fh
	jnz	aop31sbx
	cmp	ecx,-80h
	jl	aop31sbx
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop31sbx
	or	al,2
aop31sbx:
	ret
aop31sb	ENDP

aop31	ENDP
;
; move to/from a special register
; bit 1 = set if spc reg is the dest
; bit 0 & 2 define the special reg
;
aop32	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	mov	ecx,offset arg2
	mov	ax,[esi+opcode.compare]
	cmp	[arg1.asize],DWORDSIZE
	jne	aop32bad
	cmp	[arg1.mode],AM_REG
	je	aop32crsource
	or	al,2
	xchg	ebx,ecx
aop32crsource:       		
	sub	dl,dl
	cmp	[ecx+asmop.mode],AM_CR
	je	aop32c
	mov	dl,1
	cmp	[ecx+asmop.mode],AM_DR
	je	aop32c
	mov	dl,4
	cmp	[ecx+asmop.mode],AM_TR
	jne	aop32bad
aop32c:
	or	al,dl
	stosb
	
	call	chkreg
	mov	al,[ecx+asmop.areg1]
	shl	al,3
	or	al,[ebx +asmop.areg1]
	or	al,ah		; actually is a MOD/RM which is restricted
				; to regs
	stosb
;        test    [optass32],255
;        jnz     aop32d
;	and	[PrefixBitmapWord],NOT AS_OPSIZE	; don't need opsize for this
;					; and there will be no clash
;					; if we got this far
;        or      [PrefixBitmapWord],AS_OPSIZESET        ; don't need opsize for this
;	ret
;aop32d:
        or      [PrefixBitmapWord],AS_OPSIZE        ; don't need opsize for this
        ret
aop32bad:
	stc
	ret
aop32	ENDP
;
; rm,reg,count (shld/shrd)
; bit 0 = set if using CL for count
;
;
aop33	PROC
	mov	ebx,offset arg2
	call	chkreg
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop33bad
	mov	ah,[ebx+asmop.areg1]
	mov	al,byte ptr [esi+opcode.compare]
	mov	ebx,offset arg3
	cmp	[ebx+asmop.areg1],isECX
	je	aop33cl
	call	chkimm
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm
	mov	al,byte ptr [arg3.addrx]
	stosb
	ret
aop33cl:
	cmp	[ebx+asmop.mode],AM_REG
	jne	aop33bad
	or	al,1h
	stosb
        call    shiftopsize
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm
	ret

aop33bad:
	stc
	ret
aop33	ENDP
;
; push & pop rm
;
aop34	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	cmp	[ebx+asmop.asize],BYTESIZE
	je	aop34bad
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	call	asmrm2
	ret
aop34bad:
	stc
	ret
aop34	ENDP
;
; floating R/M
; bit two of opcode set if size is qword
; bit 3 of mod/rm set if last ch = 'p'
;
aop35	PROC
        
     	call	noarg2
	mov	ax,[esi+opcode.compare]
	and	ax,010d8h
	cmp	[arg1.mode],AM_FPREG
	je	aop35fin
	cmp	[arg1.asize],QWORDSIZE
	jne	aop35fin
	or	al,4
aop35fin:
	cmp	[lastbyte],'p'
	jne	aop35fin2
	or	ah,8
aop35fin2:
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmfrm
	ret
aop35	ENDP
;
; fmathp
; sti),st(0) or nothing
;
aop36	PROC
	cmp	[arg3.mode],AM_NONE
	jne	aop36errx
	mov	eax,100h
	cmp	[arg2.mode],AM_NONE
	jne	aop362arg
        cmp     [arg1.mode],AM_FPREG
        jnz     aop36errx
        mov     ah,[arg1.areg1]
	jmp	aop36fin
aop362arg:
	cmp	[arg1.mode],AM_FPREG
	jne	aop36errx
	cmp	[arg2.mode],AM_FPREG
	jne	aop36errx
	cmp	[arg2.areg1],isEAX
	jne	aop36errx
	mov	ah,[arg1.areg1]
aop36fin:
	or	ax,[esi+opcode.compare]
	stosw
	ret
aop36errx:
	stc
	ret
aop36	ENDP
;
; fmath
; st(i),st(0) ; st(0), st(i), mem
; bit two of opcode set for i dest or qword mem
; bit 3 of mod/rm gets flipped if reg & al &6 & bit 5 of mod/rm set
; 
;
aop37	PROC
	cmp	[arg3.mode],AM_NONE
	jne	aop37errx
	mov	ax,[esi+opcode.compare]
	and	al,NOT 4
	cmp	[arg2.mode], AM_NONE
	je	aop37mem
	cmp	[arg1.mode],AM_FPREG
	jne	aop37mem
	cmp	[arg2.mode],AM_FPREG
	jne	aop37errx
	mov	bl,[arg2.areg1]
	mov	bh,[arg1.areg1]
	cmp	bh,0
	je	aop37isrc
	cmp	bl,0
	jne	aop37errx
	xchg	bl,bh
	or	al,4
aop37isrc:
	test	al,6
	jz	aop371
	test	ah,20h
	jz	aop371
	xor	ah,8
aop371:
	or	ah,bl
	or	ah,0c0h
	stosw
	ret
aop37mem:
        cmp     [arg1.mode],AM_FPREG
        jne     aop37memr
        mov     ah,[arg1.areg1]
        or      ah,0c0h
        mov     al,4
        or      ax,[esi+opcode.compare]
        stosw
        ret
aop37memr:
        cmp     [arg2.mode],AM_NONE
	jne	aop37errx
	cmp	[arg1.asize],QWORDSIZE
	jne	aop37memnq
	or	al,4
aop37memnq:
	stosb
	xchg	al,ah
	mov	ebx,offset [arg1]
	call	asmfrm
	ret
aop37errx:
	stc
	ret
aop37	ENDP
;
; far RM
;
aop38	PROC
	call	noarg2
        test    [farptr],1
        jz      aop38errx
	cmp	[arg1.mode],AM_REG
	je	aop38errx
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm2
	ret
aop38errx:
	stc
	ret
aop38	ENDP
;
; word regrm with reg  source
; bug: lets arpl [ebx],eax through
;
aop39	PROC
	cmp	[arg2.asize],BYTESIZE
	jne	aop40
	stc
	ret
aop39	ENDP
;
; regrm with reg source
; bit 0 = size
aop40	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkreg
	mov	al,byte ptr [esi+opcode.compare]
	call	sizeb0
	stosb
	mov	al,[arg2.areg1]
	mov	ebx,offset arg1
	call	asmrm
	ret
aop40	ENDP
;
; rm,immediate
;
aop41	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg2
	call	chkimm
	cmp	[arg1.asize],BYTESIZE
	je	aop41errx
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm2
	mov	al,byte ptr [arg2.addrx]
	stosb
	ret
aop41errx:
	stc
	ret
aop41	ENDP
;
; regrm with reg dest & forced strictness (MOVZX & MOVSX)
; bit 0 of opcode set if size is word
;
aop42	PROC
	call	noarg3
	call	intsize
	mov	ebx,offset arg1
	call	chkreg
	cmp	[arg1.asize],BYTESIZE
	je	aop42errx
	cmp	[arg2.asize],NOSIZE
	je	aop42errx
	mov	ebx,offset arg2
	mov	ax,[esi+opcode.compare]
	call	sizeb0
	stosb
        mov     al,[arg1.areg1]
        shl     al,3
        or      al,ah
	call	asmrm2
	cmp	[arg1.asize],DWORDSIZE	; another func for which
					; auto extend to dword doesn't work
	jne	aop42x
	or	[PrefixBitmapWord],AS_OPSIZE
aop42x:
        or      [PrefixBitmapWord],AS_OPSIZESET
	ret
aop42errx:
	stc
	ret
aop42	ENDP
;
; not needed in assembler, same as no args
; 
aop43	PROC
;        test    [optass32],255
;        jz      aop43off
        or      [PrefixBitmapWord],AS_OPSIZESET
;aop43off:
	jmp	aop0
aop43	ENDP
;
; unused
;
aop44	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkreg
	cmp	[ebx+asmop.asize],DWORDSIZE
	jne	aop44errx
	or	[PrefixBitmapWord],AS_OPSIZE
	mov	al,byte ptr [esi+opcode.compare]
	or	al,[ebx+asmop.areg1]
	stosb
	ret
aop44errx:
	stc
	ret
aop44	ENDP
;
; any regrm with reg source
; same as aop40
;
aop45	PROC
	jmp	aop40
aop45	ENDP
;
; rm , size don't care, but no regs
;
aop46	PROC
	cmp	[arg1.mode],AM_FPREG
	je	aop46err
	cmp	[arg1.mode],AM_REG
	jne	aop29
aop46err:
	stc
	ret
aop46	ENDP
;
; ax reg only
;
aop47	PROC
	call	noarg2
	mov	ebx,offset arg1
	call	chkaxw
	mov	ax,[esi+opcode.compare]
	stosw
	clc
	ret
aop47	ENDP
;
; bswap, 32-bit reg to bits 0-3 of opcode
;
aop48	PROC
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkreg
	cmp	[ebx+asmop.asize],DWORDSIZE
	jne	aop48errx
	or	[PrefixBitmapWord],AS_OPSIZE
	mov	al,byte ptr [esi+opcode.compare]
	or	al,[ebx+asmop.areg1]
	stosb
	ret
aop48errx:
	stc
	ret
aop48	ENDP
;
; fst
; same as next but no tbyte
;
aop49	PROC
	cmp	[arg1.asize],TBYTESIZE
	jb	aop50
	stc
	ret
aop49	ENDP
;
; fld/fstp
; freg
; dword,qword,tybe
; bit 1 of opcode set for tbyte
; bit 2 of opcode set for qword or store
; bit 5 of modrm set if tbyte
; bit 3 of modrm gets cleared if not tbyte && bit 4 set
;
aop50	PROC
	call	noarg2
	mov	ax,[esi+opcode.compare]
	AND	ax,NOT 0e006h
	cmp	[arg1.mode],AM_FPREG
	je	aop50reg
	cmp	[arg1.asize],DWORDSIZE
	jb	aop50errx
aop502:
	cmp	[arg1.asize],TBYTESIZE
	jne	aop503
	or	ax,2802h
	jmp	aop505

aop503:
	
	cmp	[arg1.asize],QWORDSIZE
	jne	aop504
	or	al,4
aop504:
	test	ah,10h
	jnz	aop505
	and	ah,NOT 8
aop505:
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmfrm
	ret
aop50reg:
	test	ah,10h
	jnz	aop506
	and	ah,NOT 8
	jmp	aop507
aop506:
	or	al,4
aop507:
	or	ah,0c0h
	or	ah,[arg1.areg1]
	stosw
	ret
aop50errx:
	stc
	ret
aop50	ENDP
;
;
; fbld/fbstp
; tbyte ptr mem
;
aop51	PROC
	call	noarg2
	cmp	[arg1.mode],AM_FPREG
	je	aop51errx
	cmp	[arg1.asize],NOSIZE
	je	aop51c
	cmp	[arg1.asize],TBYTESIZE
	jne	aop51errx
aop51c:
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmfrm
	ret
aop51errx:
	stc
	ret
aop51	ENDP
;
; fild/fistp
; word,dword,qword mem
; bit 2 of opcode set if word or qword
; bit 3 of modrm gets cleared if not qword & bit 4 is set
; bit 5 or modrm set if qword
;
aop52	PROC
	call	noarg2
	mov	ax,[esi+opcode.compare]
	and	ax,NOT 2004h
	cmp	[arg1.mode],AM_FPREG
	je	aop52errx
	cmp	[arg1.asize],DWORDSIZE
	je	aop522
       	or	al,4
aop522:
	cmp	[arg1.asize],QWORDSIZE
	ja	aop52errx
	jne	aop523
	or	ah,20h
	jmp	aop524
aop523:
	test	ah,10h
	jnz	aop524
	and	ah, NOT 8
aop524:	
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmfrm
	ret
aop52errx:
	stc
	ret
aop52	ENDP
;
; fist
; same as above but no qword mode
;
aop53	PROC
	cmp	[arg1.asize],QWORDSIZE
	jb	aop52
	stc
	ret
aop53	ENDP
;
; freg
; reg put in mod/rm byte
;
aop54	PROC
	call	noarg2
	cmp	[arg1.mode],AM_FPREG
	jne	aop54errx
	mov	ax,[esi+opcode.compare]
	or	ah,[arg1.areg1]
	stosw
	ret
aop54errx:
	stc
	ret
aop54	ENDP
;
; same as above, deault to reg 1 if no args
aop55	PROC
	cmp	[arg3.mode],AM_NONE
	jne	aop55errx
	cmp	[arg2.mode],AM_NONE
	jne	aop55errx
	call	noarg2
	mov	ax,[esi+opcode.compare]
	cmp	[arg1.mode],AM_FPREG
	jne	aop55chknone
	or	ah,[arg1.areg1]
	stosw
	ret
aop55chknone:
	cmp	[arg1.mode],AM_NONE
	jne  	aop55errx
	or	ah,1
	stosw
	ret	
aop55errx:
	stc
	ret
aop55	ENDP
;
; fimath
; word or dword arg
; bit two gets set if word
;
aop56	PROC
	call	noarg2
	call	intsize
	cmp	[arg1.asize],BYTESIZE
	je	aop56errx
	cmp	[arg1.mode],AM_FPREG
	je	aop56errx
	mov	ax,[esi+opcode.compare]
	cmp	[arg1.asize],WORDSIZE
	jne	aop56c
	or	al,4
aop56c:
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmfrm
	ret
aop56errx:
	ret

aop56	ENDP

;
; addrsize prefix on one-byte
;
aop57	PROC
;        test    [optass32],255
;        jnz     aop57off
;	or	[PrefixBitmapWord],AS_ADDRSIZE
;	jmp	aop0
;aop57off:
        and     [PrefixBitmapWord],NOT AS_ADDRSIZE
        or      [PrefixBitmapWord],AS_ADDRSIZESET 
        jmp     aop0
aop57	ENDP
;
; opsize prefix on one-byte
;
aop58	PROC
;        test    [optass32],255
;        jnz     aop58off
;	or	[PrefixBitmapWord],AS_OPSIZE
;aop58off:
	jmp	aop0
aop58	ENDP
;
; MMX standard
;              
aop59   proc
	call	noarg3
	call	intsize
        mov     ebx,offset arg1
        call    chkmmx
	mov	al,byte ptr [esi+opcode.compare]
	stosb
        mov     al,[arg1.areg1]
        mov     ebx,offset arg2
        call    asmrmmmx
	ret
aop59   endp
;
; MMX MOVD LD
;
aop60   proc
	call	noarg3
	call	intsize
        mov     ebx,offset arg1
        call    chkmmx
	mov	al,byte ptr [esi+opcode.compare]
        and     [PrefixBitmapWord],NOT AS_OPSIZE
	stosb
        mov     al,[arg1.areg1]
        mov     ebx,offset arg2
	call	asmrm
	ret
aop60   endp
;
; MMX MOVD ST
;
aop61   proc
	call	noarg3
	call	intsize
        mov     ebx,offset arg2
        call    chkmmx
        and     [PrefixBitmapWord],NOT AS_OPSIZE
	mov	al,byte ptr [esi+opcode.compare]
	stosb
        mov     al,[arg2.areg1]
        mov     ebx,offset arg1
	call	asmrm
	ret
aop61   endp
;
; MMX MOVQ LD
;
aop62   proc
	call	noarg3
	call	intsize
        mov     ebx,offset arg1
        call    chkmmx
	mov	al,byte ptr [esi+opcode.compare]
	stosb
        mov     al,[arg1.areg1]
        mov     ebx,offset arg2
        call    asmrmmmx
	ret
aop62   endp
;
; MMX MOVQ ST
;
aop63   proc
	call	noarg3
	call	intsize
        mov     ebx,offset arg2
        call    chkmmx
	mov	al,byte ptr [esi+opcode.compare]
	stosb
        mov     al,[arg2.areg1]
        mov     ebx,offset arg1
        call    asmrmmmx
	ret
aop63   endp
;         
; MMX SHIFT
;
aop64   proc
	call	noarg3
        mov     ebx,offset arg2
        call    chkimm
        mov     ebx,offset arg1
        call    chkmmx
        mov     ax,word ptr [esi+opcode.compare]
        or      ah,0c0h
        or      ah,[ebx+asmop.areg1]
        stosw
        mov     al,byte ptr [arg2.addrx]
        stosb
	ret
aop64   endp

;
; loop
;
aop65   proc
	call	noarg2
	call	intsize
	mov	ebx,offset arg1
	call	chkimm
        sub     edx,edx
        mov     al,[lastbyte]
        cmp     al,'d'
        jz      aop65dw
        cmp     al,'w'
        jz      aop65w
        mov     ax,word ptr [EnteredMnemonic]
        cmp     ax,"je"
        jz      aop65dw
        jmp     aop65okc
aop65w:
        or      [PrefixBitmapWord],AS_ADDRSIZESET
        jmp     short aop65join
aop65dw:
        or      [PrefixBitmapWord],AS_ADDRSIZE
        inc     edx
aop65join:
;        test    [optass32],255
;        jz      aop65okc
        neg     edx
        inc     edx
aop65okc:
	mov	eax,[lastofs]
	sub	eax,[ebx+asmop.addrx]
	neg	eax
        sub     eax,2
        sub     eax,edx
aop65lrbnot32:
        cmp     eax,-128
        jl      aop65as32
        cmp     eax,128
        jle     aop65ok
aop65as32:
        stc
        ret
aop65ok:
	push	eax
	mov	al,byte ptr [esi+opcode.compare]
	stosb
	pop	eax
        test    [PrefixBitmapWord],AS_OPSIZETEST
        jnz     aop65lrbw
        stosb
        jmp     aop65lrbjoin
aop65lrbw:
        stosd
aop65lrbjoin:
	clc
	ret
aop65   endp
;
; CWD
;
aop66   PROC
        call    noarg1
;        test    [optass32],255
;        jz      aop66off
        or      [PrefixBitmapWord],AS_OPSIZESET
aop66off:
        jmp     aop0
aop66   ENDP
;
; AAM
;
aop67   PROC
	cmp	[arg2.mode],AM_NONE
        stc
        jne     aop67err
        mov     bl,0ah
        cmp     [arg1.mode],AM_NONE
        je      aop67fin
        mov     ebx,offset arg1
        call    chkimm
        mov     bl,byte ptr [arg1.addrx]
aop67fin:
        mov     al,byte ptr [esi + opcode.compare]
        stosb
        mov     al,bl
        stosb
        clc
aop67err:
        ret
aop67   ENDP
;
; xlat
;
aop68   PROC
        cmp     [arg1.mode],AM_NONE
        jz      aop68to0
        call    noarg2        
        cmp     [arg1.areg1],3
        jnz     aop68err
        cmp     [arg1.areg2],0FFh   ; else see if second reg defined
        jnz     aop68err
        cmp     [arg1.mode],AM_BASED
        jnz     aop68err
        or      [PrefixBitmapWord],AS_ADDRSIZESET
        mov     al,byte ptr [esi + opcode.compare]
        stosb
        ret
aop68err:
        stc
        ret
aop68to0:
        jmp     aop0
aop68   ENDP
;
; sets
;
aop69 PROC          
        call    noarg2
        cmp     [arg1.asize],BYTESIZE  ;maybe this means the first argument
        ja      aop69err   ;can't exceed dword size
        jmp     aop29
aop69err:
        stc
        ret
aop69 ENDP
aop70 PROC
	call	noarg2
        cmp     [arg1.asize],FWORDSIZE
        jz      aop70dw
        cmp     [arg1.asize],PBYTESIZE
        jnz     aop70join
aop70w:
        or      [PrefixBitmapWord],AS_OPSIZESET
        jmp     short aop70join
aop70dw:
        or      [PrefixBitmapWord],AS_OPSIZE
aop70join:
	mov	ax,[esi+opcode.compare]
	stosb
	xchg	al,ah
	mov	ebx,offset arg1
	call	asmrm2
	ret
aop70 ENDP
        end