
define x86 x86

element x86.reg
element x86.r8	: x86.reg + 1
element x86.r16 : x86.reg + 2
element x86.r32 : x86.reg + 4

element al? : x86.r8 + 0
element cl? : x86.r8 + 1
element dl? : x86.r8 + 2
element bl? : x86.r8 + 3
element ah? : x86.r8 + 4
element ch? : x86.r8 + 5
element dh? : x86.r8 + 6
element bh? : x86.r8 + 7

element ax? : x86.r16 + 0
element cx? : x86.r16 + 1
element dx? : x86.r16 + 2
element bx? : x86.r16 + 3
element sp? : x86.r16 + 4
element bp? : x86.r16 + 5
element si? : x86.r16 + 6
element di? : x86.r16 + 7

element eax? : x86.r32 + 0
element ecx? : x86.r32 + 1
element edx? : x86.r32 + 2
element ebx? : x86.r32 + 3
element esp? : x86.r32 + 4
element ebp? : x86.r32 + 5
element esi? : x86.r32 + 6
element edi? : x86.r32 + 7

element x86.sreg

element es? : x86.sreg + 0
element cs? : x86.sreg + 1
element ss? : x86.sreg + 2
element ds? : x86.sreg + 3
element fs? : x86.sreg + 4
element gs? : x86.sreg + 5

element x86.creg

element x86.crx : x86.creg + 0
element x86.drx : x86.creg + 1
element x86.trx : x86.creg + 4

repeat 8, i:0
	element cr#i? : x86.crx + i
	element dr#i? : x86.drx + i
	element tr#i? : x86.trx + i
end repeat

define x86.byte? :1
define x86.word? :2
define x86.dword? :4
define x86.pword? :6
define x86.fword? :6
define x86.qword? :8

x86.mode = 16

macro use16?
	x86.mode = 16
end macro

macro use32?
	x86.mode = 32
end macro


calminstruction calminstruction?.initsym? var*, val&
	publish var, val
end calminstruction

calminstruction calminstruction?.asm? line&
	local	name, i
	initsym name, name.0
	match	name.i, name
	compute i, i+1
	arrange name, name.i
	publish name, line
	arrange line, =assemble name
	assemble line
end calminstruction

calminstruction calminstruction?.xcall? instruction*, arguments&
	arrange instruction, =call instruction
    convert:
	match	, arguments
	jyes	ready
	local	v
	match	v=,arguments, arguments, <>
	jyes	recognize
	arrange v, arguments
	arrange arguments,
    recognize:
	match	(v), v
	jyes	numeric
	match	<v>, v
	jyes	symbolic
    append:
	arrange instruction, instruction=,v
	jump	convert
    numeric:
	compute v, v
    symbolic:
	local proxy, base, i
	initsym base, proxy
	initsym i, 0
	compute i, i+1
	arrange proxy, base.i
	publish proxy, v
	arrange instruction, instruction=,proxy
	jump	convert
    ready:
	assemble instruction
end calminstruction


define @dest @dest
define @src @src
define @src2 @src2
define @aux @aux

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

	namespace context

		iterate name,	size, type, segment_prefix, prefix, opcode_prefix, \
				imm, unresolved, displacement, displacement_size, \
				address, address_registers, segment, offset, jump_type, \
				mode, mod, rm, \
				scale, index, base
			define name
		end iterate

		calminstruction x86.parse_operand#context operand

			local	i, pre, suf, sym

			compute segment_prefix, 0
			compute prefix, 0
			compute opcode_prefix, 0

			compute size, 0
			compute displacement_size, 0

			transform operand

			match	pre suf, operand
			jno	no_size_prefix
			transform pre, x86
			jno	no_size_prefix
			match	:size, pre
			jno	no_size_prefix
			arrange operand, suf
		      no_size_prefix:

			match	[address], operand
			jyes	memory_operand
			match	=ptr? address, operand
			jyes	memory_operand
			match	segment:offset, operand
			jyes	far_operand

		  immediate_operand:
			compute type, 'imm'
			compute imm, +operand

			compute unresolved, 0
			check	defined operand
			jyes	operand_resolved
			compute unresolved, 1
		      operand_resolved:

			check	imm eq 1 elementof imm
			jno	operand_ready
			check	1 metadataof (1 metadataof imm) relativeto x86.reg
			jyes	register_operand
			check	1 metadataof imm relativeto x86.sreg
			jyes	segment_register_operand

		      operand_ready:
			exit

		  register_operand:

			compute type, 'reg'
			compute mode, x86.mode
			compute mod, 11b
			compute rm, 1 metadataof imm - 1 elementof (1 metadataof imm)
			check	size & size <> 1 metadataof (1 metadataof imm) - x86.reg
			jyes	operand_sizes_do_not_match
			compute size, 1 metadataof (1 metadataof imm) - x86.reg

			exit

		  segment_register_operand:

			compute type, 'sreg'
			compute mode, x86.mode
			compute mod, 11b
			compute rm, 1 metadataof imm - x86.sreg
			check	size & size <> 2 & size <> 4
			jyes	invalid_operand_size

			exit

		  memory_operand:
			compute type, 'mem'

			match	segment:address, address
			jno	segment_prefix_ok
			check	segment eq 1 elementof segment & 1 metadataof segment relativeto x86.sreg
			jno	invalid_operand
			compute segment, 1 metadataof segment - x86.sreg
			check	segment >= 4
			jyes	segment_prefix_386
			compute segment_prefix, 26h + segment shl 3
			jump	segment_prefix_ok
		      segment_prefix_386:
			compute segment_prefix, 64h + segment-4
		      segment_prefix_ok:

			compute mode, 0

			match	pre suf, address
			jno	no_address_size_prefix
			transform pre, x86
			jno	no_address_size_prefix
			match	:pre, pre
			jno	no_address_size_prefix
			arrange address, suf
			check	pre = 2 | pre = 4 | pre = 8
			jno	invalid_address_size
			compute mode, pre shl 3
		      no_address_size_prefix:

			compute scale, 0
			compute index, 0
			compute base, 0

			check	size
			jyes	size_override
			compute size, sizeof address
		      size_override:

			compute address, address
			compute address_registers, 0
			compute i, 1
		      extract_registers:
			check	i > elementsof address
			jyes	registers_extracted
			check	i metadataof address relativeto x86.r16 | i metadataof address relativeto x86.r32
			jno	next_term
			compute address_registers, address_registers + i elementof address * i scaleof address
		      next_term:
			compute i, i+1
			jump	extract_registers
		      registers_extracted:
			compute displacement, address - address_registers

			check	mode
			jyes	verify_mode
			compute mode, x86.mode
			check	mode = 16 & displacement relativeto 0 & displacement >= 10000h & address_registers eq 0
			jno	mode_ok
			compute mode, 32
			jump	mode_ok
		      verify_mode:
			check	(mode = 16 & 1 metadataof address_registers relativeto x86.r32) | (mode = 32 & 1 metadataof address_registers relativeto x86.r16)
			jyes	invalid_address
		      mode_ok:

			check	address_registers eq 0
			jyes	direct_address
			check	1 metadataof address_registers relativeto x86.r32
			jyes	address_32bit
			check	1 metadataof address_registers relativeto x86.r16
			jyes	address_16bit
			jump	invalid_address

		    direct_address:
			compute mod, 0
			check	mode = 16
			jyes	direct_address_16bit
		      direct_address_32bit:
			compute rm, 5
			compute displacement_size, 4
			exit
		      direct_address_16bit:
			compute rm, 6
			compute displacement_size, 2
			exit

		    address_16bit:
			compute mode, 16

			check	address_registers relativeto bx+si
			jyes	rm_0
			check	address_registers relativeto bx+di
			jyes	rm_1
			check	address_registers relativeto bp+si
			jyes	rm_2
			check	address_registers relativeto bp+di
			jyes	rm_3
			check	address_registers relativeto si
			jyes	rm_4
			check	address_registers relativeto di
			jyes	rm_5
			check	address_registers relativeto bp
			jyes	rm_6
			check	address_registers relativeto bx
			jyes	rm_7
			jump	invalid_address

		      rm_0:
			compute rm, 0
			jump	rm_ok
		      rm_1:
			compute rm, 1
			jump	rm_ok
		      rm_2:
			compute rm, 2
			jump	rm_ok
		      rm_3:
			compute rm, 3
			jump	rm_ok
		      rm_4:
			compute rm, 4
			jump	rm_ok
		      rm_5:
			compute rm, 5
			jump	rm_ok
		      rm_6:
			compute rm, 6
			jump	rm_ok
		      rm_7:
			compute rm, 7
		      rm_ok:

			check	displacement relativeto 0
			jno	displacement_16bit
			check	displacement = 0 & rm <> 6
			jyes	displacement_empty
			check	displacement<80h & displacement>=-80h
			jyes	displacement_8bit
			check	displacement-10000h>=-80h & displacement<10000h
			jyes	displacement_8bit_wrap_16bit
		      displacement_16bit:
			compute displacement_size, 2
			compute mod, 2
			exit
		      displacement_empty:
			compute displacement_size, 0
			compute mod, 0
			exit
		      displacement_8bit_wrap_16bit:
			compute displacement, displacement-10000h
		      displacement_8bit:
			compute displacement_size, 1
			compute mod, 1
			exit

		    address_32bit:
			compute mode,32
			check	2 scaleof address_registers = 0
			jyes	one_register
			check	3 scaleof address_registers = 0 & 2 metadataof address_registers relativeto x86.r32
			jyes	two_registers
			jump	invalid_address

		      one_register:
			compute scale, 1 scaleof address_registers
			compute base, 1 metadataof address_registers - x86.r32
			check	scale = 1
			jyes	one_register_unscaled
			check	base <> 4 & (scale = 4 | scale = 8)
			jyes	one_register_scaled
			check	base <> 4 & (scale = 2 | scale = 3 | scale = 5 | scale = 9)
			jyes	one_register_split
			jump	invalid_address
		      one_register_unscaled:
			compute rm, base
			check	rm = 4
			jno	setup_displacement
			compute index, 4
			jump	setup_displacement
		      one_register_scaled:
			compute rm, 4
			compute index, base
			compute base, 5
			jump	index_only
		      one_register_split:
			compute rm, 4
			compute index, base
			compute scale, scale - 1
			jump	setup_displacement
		      two_registers:
			compute rm,4
			check	1 scaleof address_registers = 1
			jyes	base_first
			check	2 scaleof address_registers = 1
			jyes	base_second
			jump	invalid_address
		      base_first:
			compute base, 1 metadataof address_registers - x86.r32
			compute index, 2 metadataof address_registers - x86.r32
			compute scale, 2 scaleof address_registers
			jump	process_sib
		      base_second:
			compute base, 2 metadataof address_registers - x86.r32
			compute index, 1 metadataof address_registers - x86.r32
			compute scale, 1 scaleof address_registers
		      process_sib:
			check	index = 4
			jyes	forbidden_index
			check	segment_prefix = 36h & index = 5 & scale = 1
			jyes	switch_to_index
			check	segment_prefix = 3Eh & base = 5 & scale = 1
			jyes	switch_to_base
			check	scale and (scale-1) | scale > 8
			jyes	invalid_address
			jump	setup_displacement
		      forbidden_index:
			check	scale = 1
			jno	invalid_address
			compute index, base
			compute base, 4
			jump	setup_displacement
		      switch_to_index:
			compute index, base
			compute base, 5
			jump	setup_displacement
		      switch_to_base:
			compute base, index
			compute index, 5
			jump	setup_displacement

		      setup_displacement:
			check	displacement relativeto 0
			jno	displacement_32bit
			check	displacement = 0 & rm <> 5 & (rm <> 4 | base <> 5)
			jyes	displacement_empty
			check	displacement < 80h & displacement >= -80h
			jyes	displacement_8bit
			check	displacement-100000000h >= -80h & displacement < 100000000h
			jyes	displacement_8bit_wrap_32bit
			check	segment_prefix = 3Eh & base = 5 & index = 5 & scale = 1
			jno	displacement_32bit
			compute scale, 2
			jump	index_only
		      displacement_32bit:
			compute displacement_size, 4
			compute mod, 2
			exit
		      displacement_8bit_wrap_32bit:
			compute displacement, displacement-100000000h
			jump	displacement_8bit
		      index_only:
			compute displacement_size, 4
			compute mod, 0
			exit

		  far_operand:
			compute type, 'far'

			check	size & size <> 4 & size <> 6
			jyes	operand_sizes_do_not_match

			exit

		  invalid_operand:
			err	'invalid operand'
			exit
		  invalid_operand_size:
			err	'invalid operand size'
			exit
		  operand_sizes_do_not_match:
			err	'operand sizes do not match'
			exit
		  invalid_address:
			err	'invalid address'
			exit
		  invalid_address_size:
			err	'invalid address size'
			exit

		end calminstruction

		calminstruction x86.parse_jump_operand#context operand

			match	=far? operand, operand
			jyes	far_jump
			match	=near? operand, operand
			jyes	near_jump
			match	=short? operand, operand
			jyes	short_jump
			compute jump_type, ''
			jump	parse_operand
		    far_jump:
			compute jump_type, 'far'
			jump	parse_operand
		    near_jump:
			compute jump_type, 'near'
			jump	parse_operand
		    short_jump:
			compute jump_type, 'short'

		    parse_operand:

			call	x86.parse_operand#context, operand

			check	type = 'imm'
			jno	done

			check	size = 0
			jno	verify_target_address

			compute size, x86.mode shr 3

		    verify_target_address:

			check	imm relativeto 0
			jno	done
			check	imm < 0
			jyes	negative
			check	imm >= 1 shl (size*8)
			jno	done
		    out_of_range:
			err	'value out of range'
			exit
		    negative:
			check	imm < - 1 shl (size*8-1)
			jyes	out_of_range
			compute imm, imm and (1 shl (size*8) - 1)

		    done:

		end calminstruction

		calminstruction x86.select_operand_prefix#context size*

			check	(size = 2 & x86.mode = 32) | (size = 4 & x86.mode = 16)
			jno	no_prefix

			compute prefix, 66h

		    no_prefix:

			check	size <> 0 & size <> 2 & size <> 4
			jno	done

			err	'invalid operand size'

		    done:

		end calminstruction

		calminstruction x86.store_instruction#context opcode*,reg*,imm_size:0,immediate

			check	segment_prefix
			jno	segment_prefix_ok

			check	mode = 16 & ( rm = 2 | rm = 3 | ( mod > 0 & rm = 6 ) )
			jyes	ss_segment_default
			check	mode = 32 & ( ( mod > 0 & rm = 5 ) | ( rm = 4 & base = 4 ) | ( mod > 0 & rm = 4 & base = 5 ) )
			jyes	ss_segment_default

		    ds_segment_default:
			check	segment_prefix = 3Eh
			jyes	segment_prefix_ok
			jump	store_segment_prefix
		    ss_segment_default:
			check	segment_prefix = 36h
			jyes	segment_prefix_ok
		    store_segment_prefix:
			emit	1, segment_prefix
		    segment_prefix_ok:

			check	mod <> 11b & mode <> x86.mode
			jno	addressing_prefix_ok
			emit	1, 67h
		    addressing_prefix_ok:

			check	prefix
			jno	operand_prefix_ok
			emit	1, prefix
		    operand_prefix_ok:

			check	opcode_prefix
			jno	opcode_prefix_ok
			emit	1, opcode_prefix
		    opcode_prefix_ok:

			asm	db opcode
			emit	1, mod shl 6 + (reg and 111b) shl 3 + rm and 111b

			check	mod <> 11b & rm = 4 & mode = 32
			jno	sib_ok
			emit	1, (bsf scale) shl 6 + (index and 111b) shl 3 + base and 111b
		    sib_ok:

			check	displacement_size = 1
			jyes	displacement_8bit
			check	displacement_size = 2
			jyes	displacement_16bit
			check	displacement_size = 4
			jno	displacement_ok
		    displacement_32bit:
			asm	dd displacement
			jump	displacement_ok
		    displacement_16bit:
			asm	dw displacement
			jump	displacement_ok
		    displacement_8bit:
			emit	1, displacement
		    displacement_ok:

			check	imm_size = 1
			jyes	immediate_8bit
			check	imm_size = 2
			jyes	immediate_16bit
			check	imm_size = 4
			jno	immediate_ok
		    immediate_32bit:
			compute imm, +immediate
			asm	dd imm
			jump	immediate_ok
		    immediate_16bit:
			compute imm, +immediate
			asm	dw imm
			jump	immediate_ok
		    immediate_8bit:
			compute imm, +immediate
			emit	1, imm
			jump	immediate_ok
		    immediate_ok:

		end calminstruction

	end namespace

end iterate

calminstruction x86.store_operand_prefix size*

	check	(size = 2 & x86.mode = 32) | (size = 4 & x86.mode = 16)
	jno	no_prefix

	emit	1, 66h
	exit

    no_prefix:

	check	size <> 0 & size <> 2 & size <> 4
	jno	done

	err	'invalid operand size'

    done:

end calminstruction


iterate <instr,basecode>, add,0, or,8, adc,10h, sbb,18h, and,20h, sub,28h, xor,30h, cmp,38h

	calminstruction instr? dest*,src*

		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src

		local	opcode, rm, size

		compute opcode, basecode

		check	@dest.size = 0 & @src.size = 0
		jyes	operand_size_not_specified
		check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
		jyes	operand_sizes_do_not_match

		compute size, @dest.size or @src.size

	    main:

		check	@src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	reg_rm
		check	@src.type = 'mem' & @dest.type = 'reg'
		jyes	rm_reg
		check	@src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	rm_imm

		err	'invalid combination of operands'
		exit

	    operand_size_not_specified:
		err	'operand size not specified'
		compute size, 0
		jump	main

	    operand_sizes_do_not_match:
		err	'operand sizes do not match'
		compute size, 0
		jump	main

	    reg_rm:
		check	size > 1
		jno	reg_rm_store
		call	x86.select_operand_prefix@dest, size
		compute opcode, opcode + 1
	    reg_rm_store:
		call	x86.store_instruction@dest, opcode,@src.rm
		exit

	    rm_reg:
		compute opcode, opcode + 2
		check	size > 1
		jno	rm_reg_store
		call	x86.select_operand_prefix@src, size
		compute opcode, opcode + 1
	    rm_reg_store:
		call	x86.store_instruction@src, opcode,@dest.rm
		exit

	    rm_imm:
		check	size > 1
		jyes	rm_imm_word
		check	@dest.type = 'reg' & @dest.rm = 0
		jyes	al_imm

		compute opcode, opcode shr 3
		xcall	x86.store_instruction@dest, (80h),opcode,byte,@src.imm
		exit

	    al_imm:
		emit	1, opcode+4
		emit	1, @src.imm
		exit

	    rm_imm_word:

		call	x86.select_operand_prefix@dest, size

		check	@src.imm eqtype 0.0
		jno	rm_imm_optimize

		asm	virtual at 0
		asm	emit size: @src.imm
		asm	load @src.imm:size from 0
		asm	end virtual
		compute @src.imm, +@src.imm

	    rm_imm_optimize:
		check	@src.imm relativeto 0 & @src.imm<80h & @src.imm>=-80h
		jyes	rm_simm
		check	size = 2 & @src.imm relativeto 0 & @src.imm-10000h>=-80h & @src.imm<10000h
		jyes	rm_simm_wrap
		check	size = 4 & @src.imm relativeto 0 & @src.imm-100000000h>=-80h & @src.imm<100000000h
		jyes	rm_simm_wrap
		check	@dest.type = 'reg' & @dest.rm = 0
		jyes	ax_imm

		compute rm, opcode shr 3
		xcall	x86.store_instruction@dest, (81h),rm,size,@src.imm
		exit

	    ax_imm:
		check	@dest.prefix
		jno	ax_imm_prefix_ok
		emit	1, @dest.prefix
	      ax_imm_prefix_ok:
		emit	1, opcode+5
		check	size = 4
		jyes	imm32
		asm	dw @src.imm
		exit
	      imm32:
		asm	dd @src.imm
		exit

	    rm_simm_wrap:
		compute @src.imm, @src.imm - 1 shl (size shl 3)

	    rm_simm:
		compute rm, opcode shr 3
		xcall	x86.store_instruction@dest, (83h),rm,byte,@src.imm

	end calminstruction

end iterate

iterate <instr,postbyte>, not,2, neg,3, mul,4, div,6, idiv,7

	calminstruction instr? src*

		call	x86.parse_operand@src, src

		check	@src.size = 0
		jyes	operand_size_not_specified

	    main:
		check	@src.type = 'mem' | @src.type = 'reg'
		jno	invalid_operand
		check	@src.size > 1
		jyes	rm_word

		xcall	x86.store_instruction@src, (0F6h),(postbyte)
		exit

	    rm_word:
		call	x86.select_operand_prefix@src, @src.size
		xcall	x86.store_instruction@src, (0F7h),(postbyte)
		exit

	    operand_size_not_specified:
		err	'operand size not specified'
		jump	main

	    invalid_operand:
		err	'invalid operand'
		exit

	end calminstruction

end iterate

calminstruction mov? dest*,src*

	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src

	local	ext, rm, size

	check	@dest.size = 0 & @src.size = 0 & @dest.type <> 'sreg'
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match

	compute size, @dest.size or @src.size

    main:

	check	@src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
	jyes	mov_rm_reg
	check	@src.type = 'mem' & @dest.type = 'reg'
	jyes	mov_reg_mem
	check	@src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' )
	jyes	mov_rm_imm
	check	@src.type = 'reg' & @dest.type = 'imm'
	jyes	mov_creg_reg
	check	@src.type = 'sreg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
	jyes	mov_rm_sreg
	check	@dest.type = 'sreg' & @dest.rm <> 1 & ( @src.type = 'reg' | @src.type = 'mem' )
	jyes	mov_sreg_rm

    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit

    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	main

    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	main

    mov_rm_reg:
	check	@src.type = 'reg' & @dest.type = 'mem' & @src.rm = 0 & @dest.address_registers eq 0
	jyes	mov_dirmem_ax
	check	size > 1
	jno	mov_reg_rm_8bit
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (89h),@src.rm
	exit
      mov_reg_rm_8bit:
	xcall	x86.store_instruction@dest, (88h),@src.rm
	exit

    mov_reg_mem:
	check	@src.type = 'mem' & @dest.type = 'reg' & @dest.rm = 0 & @src.address_registers eq 0
	jyes	mov_ax_dirmem
	check	size > 1
	jno	mov_mem_reg_8bit
	call	x86.select_operand_prefix@src, size
	xcall	x86.store_instruction@src, (8Bh),@dest.rm
	exit
      mov_mem_reg_8bit:
	xcall	x86.store_instruction@src, (8Ah),@dest.rm
	exit

    mov_dirmem_ax:
	check	@dest.segment_prefix = 0 | @dest.segment_prefix = 3Eh
	jyes	dest_seg_ok
	emit	1, @dest.segment_prefix
      dest_seg_ok:
	check	@dest.mode = x86.mode
	jyes	dest_addr_size_ok
	emit	1, 67h
      dest_addr_size_ok:
	check	size > 1
	jno	mov_dirmem_al
	call	x86.store_operand_prefix, size
	emit	1, 0A3h
	jump	dest_displacement
      mov_dirmem_al:
	emit	1, 0A2h
      dest_displacement:
	check	@dest.mode = 16
	jyes	dest_displacement_16bit
	asm	dd @dest.address
	exit
      dest_displacement_16bit:
	asm	dw @dest.address
	exit

    mov_ax_dirmem:
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	src_seg_ok
	emit	1, @src.segment_prefix
      src_seg_ok:
	check	@src.mode = x86.mode
	jyes	src_addr_size_ok
	emit	1, 67h
      src_addr_size_ok:
	check	size > 1
	jno	mov_al_dirmem
	call	x86.store_operand_prefix, size
	emit	1, 0A1h
	jump	src_displacement
      mov_al_dirmem:
	emit	1, 0A0h
      src_displacement:
	check	@src.mode = 16
	jyes	src_displacement_16bit
	asm	dd @src.address
	exit
      src_displacement_16bit:
	asm	dw @src.address
	exit

    mov_rm_imm:
	check	@dest.type = 'mem'
	jyes	mov_mem_imm
	check	@dest.type = 'reg' & 1 metadataof (1 metadataof @src.imm) relativeto x86.creg & @src.imm relativeto 1 elementof @src.imm
	jyes	mov_reg_creg

    mov_reg_imm:
	check	size > 1
	jno	mov_reg_imm_8bit
	call	x86.store_operand_prefix, size
	emit	1, 0B8h + @dest.rm
	check	size = 2
	jyes	src_imm_16bit
	asm	dd @src.imm
	exit
      src_imm_16bit:
	asm	dw @src.imm
	exit
      mov_reg_imm_8bit:
	emit	1, 0B0h + @dest.rm
	emit	1, @src.imm
	exit

    mov_mem_imm:
	check	size > 1
	jno	mov_mem_imm_8bit
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (0C7h),(0),size,@src.imm
	exit
      mov_mem_imm_8bit:
	xcall	x86.store_instruction@dest, (0C6h),(0),byte,@src.imm
	exit

    mov_reg_creg:
	check	@dest.size = 4
	jno	invalid_operand_size
	compute ext, 20h + 1 metadataof (1 metadataof @src.imm) - x86.creg
	compute rm, 1 metadataof @src.imm - 1 elementof (1 metadataof @src.imm)
	xcall	x86.store_instruction@dest, <0Fh,ext>,rm
	exit

    mov_creg_reg:
	check	1 metadataof (1 metadataof @dest.imm) relativeto x86.creg & @dest.imm relativeto 1 elementof @dest.imm
	jno	invalid_combination_of_operands
	check	@src.size = 4
	jno	invalid_operand_size
	compute ext, 22h + 1 metadataof (1 metadataof @dest.imm) - x86.creg
	compute rm, 1 metadataof @dest.imm - 1 elementof (1 metadataof @dest.imm)
	xcall	x86.store_instruction@src, <0Fh,ext>,rm
	exit

    mov_rm_sreg:
	check	@dest.type = 'mem'
	jyes	mov_mem_sreg
      mov_reg_sreg:
	check	size > 1
	jno	invalid_operand_size
	call	x86.select_operand_prefix@dest, size
	jump	mov_rm_sreg_store
      mov_mem_sreg:
	check	size and not 2
	jyes	invalid_operand_size
      mov_rm_sreg_store:
	xcall	x86.store_instruction@dest, (8Ch),@src.rm
	exit

    mov_sreg_rm:
	check	size = 1
	jyes	invalid_operand_size
	xcall	x86.store_instruction@src, (8Eh),@dest.rm
	exit

    invalid_operand_size:
	err	'invalid operand size'
	exit

end calminstruction

calminstruction test? dest*,src*

	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src

	local	ext, rm, size

	check	@dest.size = 0 & @src.size = 0
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match

	compute size, @dest.size or @src.size

    main:

	check	@src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
	jyes	test_reg_rm
	check	@src.type = 'mem' & @dest.type = 'reg'
	jyes	test_mem_reg
	check	@src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' )
	jyes	test_rm_imm

    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit

    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	main

    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	main

    test_reg_rm:
	check	size > 1
	jno	test_reg_rm_8bit
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (85h),@src.rm
	exit
      test_reg_rm_8bit:
	xcall	x86.store_instruction@dest, (84h),@src.rm
	exit

    test_mem_reg:
	check	size > 1
	jno	test_mem_reg_8bit
	call	x86.select_operand_prefix@src, size
	xcall	x86.store_instruction@src, (85h),@dest.rm
	exit
      test_mem_reg_8bit:
	xcall	x86.store_instruction@src, (84h),@dest.rm
	exit

    test_rm_imm:
	check	size > 1
	jno	test_rm_imm_8bit
	check	@dest.type = 'reg' & @dest.rm = 0
	jyes	test_ax_imm
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (0F7h),(0),size,@src.imm
	exit

      test_ax_imm:
	call	x86.store_operand_prefix, size
	emit	1, 0A9h
	check	size = 2
	jyes	src_imm_16bit
	asm	dd @src.imm
	exit
      src_imm_16bit:
	asm	dw @src.imm
	exit

      test_rm_imm_8bit:
	check	@dest.type = 'reg' & @dest.rm = 0
	jyes	test_al_imm
	xcall	x86.store_instruction@dest, (0F6h),(0),byte,@src.imm
	exit
      test_al_imm:
	emit	1, 0A8h
	emit	1, @src.imm
	exit

end calminstruction

calminstruction xchg? dest*,src*

	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src

	local	ext, rm, size

	check	@dest.size = 0 & @src.size = 0
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match

	compute size, @dest.size or @src.size

    main:

	check	@src.type = 'reg' & @dest.type = 'reg'
	jyes	xchg_reg_reg
	check	@src.type = 'reg' & @dest.type = 'mem'
	jyes	xchg_reg_rm
	check	@src.type = 'mem' & @dest.type = 'reg'
	jyes	xchg_rm_reg

    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit

    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	main

    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	main

    xchg_reg_reg:
	check	@src.rm = 0 | @dest.rm = 0
	jno	xchg_rm_reg
	check	size > 1
	jno	xchg_rm_reg_8bit
	call	x86.store_operand_prefix, size
	emit	1, 90h + @src.rm + @dest.rm
	exit

    xchg_reg_rm:
	check	size > 1
	jno	xchg_reg_rm_8bit
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (87h),@src.rm
	exit
      xchg_reg_rm_8bit:
	xcall	x86.store_instruction@dest, (86h),@src.rm
	exit

    xchg_rm_reg:
	check	size > 1
	jno	xchg_rm_reg_8bit
	call	x86.select_operand_prefix@src, size
	xcall	x86.store_instruction@src, (87h),@dest.rm
	exit
      xchg_rm_reg_8bit:
	xcall	x86.store_instruction@src, (86h),@dest.rm
	exit

end calminstruction

iterate <instr,postbyte>, inc,00 ,dec,01

	calminstruction instr? dest*

		call	x86.parse_operand@dest, dest

		check	@dest.size
		jyes	main

		err	'operand size not specified'

	    main:
		check	@dest.type = 'reg'
		jyes	inc_reg
		check	@dest.type = 'mem'
		jyes	inc_rm

		err	'invalid operand'
		exit

	    inc_reg:
		check	@dest.size > 1
		jno	inc_rm_8bit
		call	x86.store_operand_prefix, @dest.size
		emit	1, 40h + @dest.rm + 0x#postbyte shl 3
		exit

	    inc_rm:
		check	@dest.size > 1
		jno	inc_rm_8bit
		call	x86.select_operand_prefix@dest, @dest.size
		xcall	x86.store_instruction@dest, (0FFh),(postbyte)
		exit
	      inc_rm_8bit:
		xcall	x86.store_instruction@dest, (0FEh),(postbyte)

	end calminstruction

end iterate

calminstruction imul? dest*,src&

	local	size

	call	x86.parse_operand@dest, dest

	match	, src
	jyes	imul_rm

	local	src1, src2

	match	src1 =, src2, src
	jyes	imul_second_source

	call	x86.parse_operand@src, src

	check	@dest.size = 0 & @src.size = 0
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match

	compute size, @dest.size or @src.size

	check	@dest.type = 'reg' & (@src.type = 'reg' | @src.type = 'mem')
	jyes	imul_reg_rm

	check	@src.type = 'imm' & @dest.type = 'reg'
	jno	invalid_combination_of_operands

	compute @aux.type, @src.type
	compute @aux.imm, @src.imm
	compute @src.type, @dest.type
	compute @src.mod, @dest.mod
	compute @src.rm, @dest.rm

	jump	main

    imul_second_source:
	call	x86.parse_operand@src, src1
	call	x86.parse_operand@aux, src2

	check	@dest.size = 0 & @src.size = 0 & @aux.size = 0
	jyes	operand_size_not_specified

	compute size, @dest.size or @src.size or @aux.size

	check	(@dest.size & @dest.size <> size) | (@src.size & @src.size <> size) | (@aux.size & @aux.size <> size)
	jyes	operand_sizes_do_not_match

	jump	main

    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	main

    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	main

    main:
	check	@aux.type = 'imm' & ( @src.type = 'mem' | @src.type = 'reg' ) & @dest.type = 'reg'
	jyes	imul_reg_rm_imm

    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit

    imul_rm:
	check	@dest.size
	jyes	imul_rm_size_ok
	err	'operand size not specified'
      imul_rm_size_ok:
	check	@dest.type = 'mem' | @dest.type = 'reg'
	jno	invalid_combination_of_operands
	check	@dest.size > 1
	jno	imul_rm_8bit
	call	x86.select_operand_prefix@dest, @dest.size
	xcall	x86.store_instruction@dest, (0F7h),(5)
	exit
      imul_rm_8bit:
	xcall	x86.store_instruction@dest, (0F6h),(5)
	exit

    imul_reg_rm:
	call	x86.select_operand_prefix@src, size
	xcall	x86.store_instruction@src, <0Fh,0AFh>,@dest.rm
	exit

    imul_reg_rm_imm:
	call	x86.select_operand_prefix@src, size
	check	@aux.imm eqtype 0.0
	jno	imul_reg_rm_imm_optimize
	asm	virtual at 0
	asm	emit size: @aux.imm
	asm	load @aux.imm:size from 0
	asm	end virtual
	compute @aux.imm, +@aux.imm
      imul_reg_rm_imm_optimize:
	check	@aux.imm relativeto 0 & @aux.imm < 80h & @aux.imm >= -80h
	jyes	imul_reg_rm_simm
	check	size = 2 & @aux.imm relativeto 0 & @aux.imm - 10000h >= -80h & @aux.imm < 10000h
	jyes	imul_reg_rm_simm_wrap
	check	size = 4 & @aux.imm relativeto 0 & @aux.imm - 100000000h >= -80h & @aux.imm < 100000000h
	jyes	imul_reg_rm_simm_wrap
	xcall	x86.store_instruction@src, (69h),@dest.rm,size,@aux.imm
	exit
      imul_reg_rm_simm_wrap:
	compute @aux.imm, @aux.imm - 1 shl (size shl 3)
      imul_reg_rm_simm:
	xcall	x86.store_instruction@src, (6Bh),@dest.rm,byte,@aux.imm
	exit

end calminstruction

calminstruction x86.push_instruction size:0,src*

	call	x86.parse_operand@src, src

	check	size <> 0 & @src.size and not size
	jyes	invalid_operand_size
	compute size, size or @src.size
	check	size = 0 | size = 2 | size = 4
	jyes	main

    invalid_operand_size:
	err	'invalid operand size'

    main:
	check	@src.type = 'mem'
	jyes	push_mem
	check	@src.type = 'reg'
	jyes	push_reg
	check	@src.type = 'sreg'
	jyes	push_sreg
	check	@src.type = 'imm'
	jyes	push_imm

	err	'invalid operand'
	exit

    push_mem:
	call	x86.select_operand_prefix@src, size
	xcall	x86.store_instruction@src, (0FFh),(110b)
	exit

    push_reg:
	call	x86.store_operand_prefix, size
	emit	1, 50h + @src.rm
	exit

    push_sreg:
	call	x86.store_operand_prefix, size
	check	@src.rm >= 4
	jyes	push_sreg_386
	emit	1, 6 + @src.rm shl 3
	exit
      push_sreg_386:
	emit	1, 0Fh
	emit	1, 0A0h + (@src.rm-4) shl 3
	exit

    push_imm:
	check	size
	jyes	push_imm_size_ok
	check	x86.mode = 16
	jyes	push_imm_16bit
	compute size, 4
	jump	push_imm_size_ok
      push_imm_16bit:
	compute size, 2
      push_imm_size_ok:

	call	x86.store_operand_prefix, size

	check	@src.imm eqtype 0.0
	jno	push_imm_optimize
	asm	virtual at 0
	asm	emit size: @src.imm
	asm	load @src.imm:size from 0
	asm	end virtual
	compute @src.imm, +@src.imm
      push_imm_optimize:
	check	@src.imm relativeto 0 & @src.imm < 80h & @src.imm >= -80h
	jyes	push_simm
	check	size = 2 & @src.imm relativeto 0 & @src.imm - 10000h >= -80h & @src.imm < 10000h
	jyes	push_simm_wrap
	check	size = 4 & @src.imm relativeto 0 & @src.imm - 100000000h >= -80h & @src.imm < 100000000h
	jyes	push_simm_wrap
	emit	1, 68h
	check	size = 2
	jyes	src_imm_16bit
	asm	dd @src.imm
	exit
      src_imm_16bit:
	asm	dw @src.imm
	exit
      push_simm_wrap:
	compute @src.imm, @src.imm - 1 shl (size shl 3)
      push_simm:
	emit	1, 6Ah
	emit	1, @src.imm
	exit

end calminstruction

calminstruction x86.pop_instruction size:0,dest*

	call	x86.parse_operand@dest, dest

	check	size <> 0 & @dest.size and not size
	jyes	invalid_operand_size
	compute size, size or @dest.size
	check	size = 0 | size = 2 | size = 4
	jyes	main

    invalid_operand_size:
	err	'invalid operand size'

    main:
	check	@dest.type = 'mem'
	jyes	pop_mem
	check	@dest.type = 'reg'
	jyes	pop_reg
	check	@dest.type = 'sreg'
	jyes	pop_sreg

    invalid_operand:
	err	'invalid operand'
	exit

    pop_mem:
	call	x86.select_operand_prefix@dest, size
	xcall	x86.store_instruction@dest, (8Fh),(0)
	exit

    pop_reg:
	call	x86.store_operand_prefix, size
	emit	1, 58h + @dest.rm
	exit

    pop_sreg:
	check	@dest.rm = 1
	jyes	invalid_operand
	call	x86.store_operand_prefix, size
	check	@dest.rm >= 4
	jyes	pop_sreg_386
	emit	1, 7 + @dest.rm shl 3
	exit
      pop_sreg_386:
	emit	1, 0Fh
	emit	1, 0A1h + (@dest.rm-4) shl 3
	exit

end calminstruction

iterate reg, ax,cx,dx,bx,sp,bp,si,di, eax,ecx,edx,ebx,esp,ebp,esi,edi, es,cs,ss,ds,fs,gs
	define x86.compact.reg? {reg}
end iterate

iterate <instr,handler,size>, push,push_instruction,0, pushw,push_instruction,2, pushd,push_instruction,4, \
			      pop,pop_instruction,0, popw,pop_instruction,2, popd,pop_instruction,4

	calminstruction instr? operand

		local	head, tail

		match	head tail, operand
		jno	plain
		transform head, x86.compact
		jno	plain
		match	{head}, head
		jno	plain
	    loop:
		xcall	x86.handler, (size),head
		match	head tail, tail
		jno	final
		transform head, x86.compact
		jno	error
		match	{head}, head
		jyes	loop
	    error:
		err	'only register operands allowed in compact syntax'
		exit
	    final:
		transform tail, x86.compact
		jno	error
		match	{operand}, tail
		jno	error
	    plain:
		xcall	x86.handler, (size),operand

	end calminstruction

end iterate

iterate <instr,opcode>, ret,0C2h, retn,0C2h, retf,0CAh

	calminstruction instr? operand
		match	, operand
		jyes	ret_short
		check	operand
		jno	ret_short
		emit	1, opcode
		asm	dw operand
		exit
	    ret_short:
		emit	1, opcode + 1
	end calminstruction

end iterate

iterate <instr,size,opcode>, retw,2,0C2h, retnw,2,0C2h, retd,4,0C2h, retnd,4,0C2h, retfw,2,0CAh, retfd,4,0CAh

	calminstruction instr? operand
		xcall	x86.store_operand_prefix, (size)
		match	, operand
		jyes	ret_short
		emit	1, opcode
		asm	dw operand
		exit
	    ret_short:
		emit	1, opcode + 1
	end calminstruction

end iterate

calminstruction lea? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@src.type = 'mem' & @dest.type = 'reg'
	jno	invalid_combination_of_operands
	call	x86.select_operand_prefix@src, @dest.size
	xcall	x86.store_instruction@src, (8Dh),@dest.rm
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
end calminstruction

iterate <instr,opcode>, les,0C4h, lds,0C5h, lss,<0Fh,0B2h>, lfs,<0Fh,0B4h>, lgs,<0Fh,0B5h>

	calminstruction instr? dest*,src*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		check	(@dest.size = 2 & (@src.size <> 0 & @src.size <> 4)) | (@dest.size = 4 & (@src.size <> 0 & @src.size <> 6))
		jyes	invalid_operand_size
		check	@src.type = 'mem' & @dest.type = 'reg'
		jno	invalid_combination_of_operands
		call	x86.select_operand_prefix@src, @dest.size
		xcall	x86.store_instruction@src, <opcode>,@dest.rm
		exit
	    invalid_operand_size:
		err	'invalid operand size'
		exit
	    invalid_combination_of_operands:
		err	'invalid combination of operands'
	end calminstruction

end iterate

iterate <instr,postbyte>, rol,0, ror,1, rcl,2, rcr,3, shl,4, sal, 4, shr,5, sar,7

	calminstruction instr? dest*,cnt*

		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, cnt

		check	@dest.size = 0
		jyes	operand_size_not_specified
		check	@src.size and not 1
		jyes	invalid_operand_size

	    main:
		check	@src.type = 'reg' & @src.size = 1 & @src.rm = 1 & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	shift_rm_cl
		check	@src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	shift_rm_imm

		err	'invalid combination of operands'
		exit

	    shift_rm_cl:
		check	@dest.size > 1
		jno	shift_r8_cl
		call	x86.select_operand_prefix@dest, @dest.size
		xcall	x86.store_instruction@dest, (0D3h),(postbyte)
		exit
	      shift_r8_cl:
		xcall	x86.store_instruction@dest, (0D2h),(postbyte)
		exit
	    shift_rm_imm:
		check	@dest.size > 1
		jno	shift_rm8_imm
		call	x86.select_operand_prefix@dest, @dest.size
		check	@src.imm = 1
		jyes	shift_rm_1
		xcall	x86.store_instruction@dest, (0C1h),(postbyte),byte,@src.imm
		exit
	      shift_rm_1:
		xcall	x86.store_instruction@dest, (0D1h),(postbyte)
		exit
	      shift_rm8_imm:
		check	@src.imm = 1
		jyes	shift_rm8_1
		xcall	x86.store_instruction@dest, (0C0h),(postbyte),byte,@src.imm
		exit
	      shift_rm8_1:
		xcall	x86.store_instruction@dest, (0D0h),(postbyte)
		exit

	    operand_size_not_specified:
		err	'operand size not specified'
		jump	main
	    invalid_operand_size:
		err	'invalid operand size'
		jump	main

	end calminstruction

end iterate

iterate <instr,ext>, shld,0A4h, shrd,0ACh

	calminstruction instr? dest*,src*,cnt*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		call	x86.parse_operand@aux, cnt
		check	@aux.size and not 1
		jyes	invalid_operand_size
		check	@dest.size and not @src.size
		jno	main
		err	'operand sizes do not match'
	    main:
		check	@aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1 & @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	shld_cl
		check	@aux.type = 'imm' & @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' )
		jyes	shld_imm
		err	'invalid combination of operands'
		exit
	    shld_cl:
		call	x86.select_operand_prefix@dest, @src.size
		xcall	x86.store_instruction@dest, <0Fh,ext+1>,@src.rm
		exit
	    shld_imm:
		call	x86.select_operand_prefix@dest, @src.size
		xcall	x86.store_instruction@dest, <0Fh,ext>,@src.rm,byte,@aux.imm
		exit
	    invalid_operand_size:
		err	'invalid operand size'
	end calminstruction

end iterate

iterate <instr,postbyte>, bt,4, bts,5, btr,6, btc,7

	calminstruction instr? dest*,src*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		check	@src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg')
		jyes	bt_rm_reg
		check	@src.type = 'imm' & (@dest.type = 'mem' | @dest.type = 'reg')
		jyes	bt_rm_imm
		err	'invalid combination of operands'
		exit
	    bt_rm_reg:
		local	opcode
		check	@dest.size and not @src.size
		jno	bt_rm_reg_ok
		err	'operand sizes do not match'
	      bt_rm_reg_ok:
		compute opcode, 0A3h+(postbyte-4) shl 3
		call	x86.select_operand_prefix@dest, @src.size
		xcall	x86.store_instruction@dest, <0Fh,opcode>,@src.rm
		exit
	    bt_rm_imm:
		check	@src.size and not 1
		jno	bt_rm_imm_ok
		err	'invalid operand size'
	      bt_rm_imm_ok:
		check	@dest.size
		jno	bt_rm_imm_prefix_ok
		call	x86.select_operand_prefix@dest, @dest.size
	      bt_rm_imm_prefix_ok:
		xcall	x86.store_instruction@dest, <0Fh,0BAh>,(postbyte),byte,@src.imm
	end calminstruction

end iterate

iterate <instr,ext>, bsf,0BCh, bsr,0BDh

	calminstruction instr? dest*,src*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		check	@dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg')
		jyes	bsf_reg_rm
		err	'invalid combination of operands'
		exit
	    bsf_reg_rm:
		check	@src.size and not @dest.size
		jno	bsf_reg_rm_ok
		err	'operand sizes do not match'
	      bsf_reg_rm_ok:
		call	x86.select_operand_prefix@src, @dest.size
		xcall	x86.store_instruction@src, <0Fh,ext>,@dest.rm
	end calminstruction

end iterate

iterate <instr,ext>, movzx,0B6h, movsx,0BEh

	calminstruction instr? dest*,src*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		check	@dest.size > @src.size
		jyes	size_ok
		err	'operand sizes do not match'
	    size_ok:
		check	@dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg')
		jyes	operands_ok
		err	'invalid combination of operands'
		exit
	    operands_ok:
		check	@src.size = 2
		jyes	movzx_word
		check	@src.size = 1 | (@src.size = 0 & @dest.size = 2)
		jyes	movzx_byte
		check	@src.size
		jyes	invalid_operand_size
		err	'operand size not specified'
	    movzx_word:
		call	x86.select_operand_prefix@src, @dest.size
		xcall	x86.store_instruction@src, <0Fh,ext+1>,@dest.rm
		exit
	    movzx_byte:
		call	x86.select_operand_prefix@src, @dest.size
		xcall	x86.store_instruction@src, <0Fh,ext>,@dest.rm
		exit
	    invalid_operand_size:
		err	'invalid operand size'
	end calminstruction

end iterate

iterate <cond,code>, o,0, no,1, c,2, b,2, nae,2, nc,3, nb,3, ae,3, z,4, e,4, nz,5, ne,5, na,6, be,6, a,7, nbe,7, \
		     s,8, ns,9, p,0Ah, pe,0Ah, np,0Bh, po,0Bh, l,0Ch, nge,0Ch, nl,0Dh, ge,0Dh, ng,0Eh, le,0Eh, g,0Fh, nle,0Fh

	calminstruction set#cond? dest*
		call	x86.parse_operand@dest, dest
		check	@dest.size > 1
		jno	size_ok
		err	'invalid operand size'
	    size_ok:
		check	@dest.type = 'reg' | @dest.type = 'mem'
		jyes	operand_ok
		err	'invalid operand'
		exit
	    operand_ok:
		xcall	x86.store_instruction@dest, <0Fh,90h+code>,(0)
	end calminstruction

end iterate

calminstruction call? dest*

	call	x86.parse_jump_operand@dest, dest

	check	@dest.type = 'imm'
	jyes	call_imm
	check	@dest.type = 'mem' | @dest.type = 'reg'
	jyes	call_rm
	check	@dest.type = 'far'
	jyes	call_direct_far

    invalid_operand:
	err	'invalid operand'
	exit

    call_direct_far:
	check	@dest.jump_type & @dest.jump_type <> 'far'
	jyes	invalid_operand
	check	@dest.size = 0
	jyes	prefix_ok
	local	size
	compute size, @dest.size - 2
	call	x86.store_operand_prefix, size
      prefix_ok:
	check	@dest.size and not 4 & @dest.size and not 6
	jyes	invalid_operand
	emit	1, 9Ah
	check	(@dest.size = 0 & x86.mode = 16) | @dest.size = 4
	jyes	far_dword
	asm	dd @dest.offset
	asm	dw @dest.segment
	exit
      far_dword:
	asm	dw @dest.offset,@dest.segment
	exit

    call_rm:
	check	@dest.size = 6
	jyes	call_rm_pword
	check	@dest.size = 4
	jyes	call_rm_dword
	check	@dest.size = 2
	jyes	call_rm_word
	check	@dest.size
	jyes	invalid_operand
	check	@dest.jump_type = 'far'
	jyes	call_rm_far
	check	@dest.jump_type = 'near'
	jyes	call_rm_near
	err	'operand size not specified'
	exit

      call_rm_pword:
	check	@dest.jump_type & @dest.jump_type <> 'far'
	jyes	invalid_operand
	xcall	x86.select_operand_prefix@dest, (4)
      call_rm_far:
	xcall	x86.store_instruction@dest, (0FFh),(11b)
	exit

      call_rm_dword:
	check	@dest.jump_type | @dest.type = 'reg'
	jno	call_rm_dword_auto
	check	@dest.jump_type = 'far'
	jyes	call_rm_dword_far
      call_rm_dword_near:
	xcall	x86.select_operand_prefix@dest, (4)
	jump	call_rm_near
      call_rm_dword_auto:
	check	x86.mode = 16
	jno	call_rm_dword_near
      call_rm_dword_far:
	xcall	x86.select_operand_prefix@dest, (2)
	jump	call_rm_far

      call_rm_word:
	check	@dest.jump_type & @dest.jump_type <> 'near'
	jyes	invalid_operand
	xcall	x86.select_operand_prefix@dest, (2)
      call_rm_near:
	xcall	x86.store_instruction@dest, (0FFh),(10b)
	exit

    call_imm:
	check	@dest.jump_type & @dest.jump_type <> 'near'
	jyes	invalid_operand
	check	@dest.size = 2
	jyes	call_imm_word
	check	@dest.size = 4
	jno	invalid_operand
	xcall	x86.store_operand_prefix, (4)
	emit	1, 0E8h
	compute @dest.imm, @dest.imm-($+4)
	asm	dd @dest.imm
	exit
      call_imm_word:
	xcall	x86.store_operand_prefix, (2)
	emit	1, 0E8h
	compute @dest.imm, @dest.imm-($+2)
	check	@dest.imm relativeto 0
	jno	store_word
	compute @dest.imm, @dest.imm and 0FFFFh
      store_word:
	asm	dw @dest.imm
	exit

end calminstruction

calminstruction jmp? dest*

	call	x86.parse_jump_operand@dest, dest

	check	@dest.type = 'imm'
	jyes	jmp_imm
	check	@dest.type = 'mem' | @dest.type = 'reg'
	jyes	jmp_rm
	check	@dest.type = 'far'
	jyes	jmp_direct_far

    invalid_operand:
	err	'invalid operand'
	exit

    jmp_direct_far:
	check	@dest.jump_type & @dest.jump_type <> 'far'
	jyes	invalid_operand
	check	@dest.size = 0
	jyes	prefix_ok
	local	size
	compute size, @dest.size - 2
	call	x86.store_operand_prefix, size
      prefix_ok:
	check	@dest.size and not 4 & @dest.size and not 6
	jyes	invalid_operand
	emit	1, 0EAh
	check	(@dest.size = 0 & x86.mode = 16) | @dest.size = 4
	jyes	far_dword
	asm	dd @dest.offset
	asm	dw @dest.segment
	exit
      far_dword:
	asm	dw @dest.offset,@dest.segment
	exit

    jmp_rm:
	check	@dest.size = 6
	jyes	jmp_rm_pword
	check	@dest.size = 4
	jyes	jmp_rm_dword
	check	@dest.size = 2
	jyes	jmp_rm_word
	check	@dest.size
	jyes	invalid_operand
	check	@dest.jump_type = 'far'
	jyes	jmp_rm_far
	check	@dest.jump_type = 'near'
	jyes	jmp_rm_near
	err	'operand size not specified'
	exit

      jmp_rm_pword:
	check	@dest.jump_type & @dest.jump_type <> 'far'
	jyes	invalid_operand
	xcall	x86.select_operand_prefix@dest, (4)
      jmp_rm_far:
	xcall	x86.store_instruction@dest, (0FFh),(101b)
	exit

      jmp_rm_dword:
	check	@dest.jump_type | @dest.type = 'reg'
	jno	jmp_rm_dword_auto
	check	@dest.jump_type = 'far'
	jyes	jmp_rm_dword_far
      jmp_rm_dword_near:
	xcall	x86.select_operand_prefix@dest, (4)
	jump	jmp_rm_near
      jmp_rm_dword_auto:
	check	x86.mode = 16
	jno	jmp_rm_dword_near
      jmp_rm_dword_far:
	xcall	x86.select_operand_prefix@dest, (2)
	jump	jmp_rm_far

      jmp_rm_word:
	check	@dest.jump_type & @dest.jump_type <> 'near'
	jyes	invalid_operand
	xcall	x86.select_operand_prefix@dest, (2)
      jmp_rm_near:
	xcall	x86.store_instruction@dest, (0FFh),(100b)
	exit

    jmp_imm:
	call	x86.store_operand_prefix, @dest.size
	check	@dest.jump_type = 'near'
	jyes	jmp_imm_near
	check	@dest.jump_type = 'short'
	jyes	jmp_imm_short_verify
	check	@dest.jump_type
	jyes	invalid_operand
	check	~ $ relativeto 0 & @dest.imm relativeto 0
	jno	jmp_optimize
	compute @dest.imm, @dest.imm + $ - 0 scaleof $
	err	'invalid address'
      jmp_optimize:
	check	@dest.unresolved
	jyes	jmp_imm_short
	check	@dest.imm relativeto $
	jno	jmp_imm_near
	check	(@dest.imm-($+2)) < 80h & (@dest.imm-($+2)) >= -80h
	jyes	jmp_imm_short
	check	(@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h
	jyes	jmp_imm_short
      jmp_imm_near:
	check	@dest.size = 2
	jyes	jmp_imm_word
	check	@dest.size = 4
	jno	invalid_operand
	emit	1, 0E9h
	compute @dest.imm, @dest.imm-($+4)
	asm	dd @dest.imm
	exit
      jmp_imm_word:
	emit	1, 0E9h
	compute @dest.imm, @dest.imm-($+2)
	check	@dest.imm relativeto 0
	jno	store_word
	compute @dest.imm, @dest.imm and 0FFFFh
      store_word:
	asm	dw @dest.imm
	exit
      jmp_imm_short_verify:
	check	(@dest.imm-($+2)) < 80h & (@dest.imm-($+2)) >= -80h
	jyes	jmp_imm_short
	check	(@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h
	jyes	jmp_imm_short
	emit	1, 0EBh
	emit	1
	jump	relative_jump_out_of_range
      jmp_imm_short:
	emit	1, 0EBh
	compute @dest.imm, (@dest.imm-($+1)) and 0FFh
	emit	1, @dest.imm
	exit
      relative_jump_out_of_range:
	err	'relative jump out of range'
	exit

end calminstruction

iterate <instr,opcode>, jo,70h, jno,71h, jc,72h, jb,72h, jnae,72h, jnc,73h, jnb,73h, jae,73h, jz,74h, je,74h, jnz,75h, jne,75h, jna,76h, jbe,76h, ja,77h, jnbe,77h, \
			js,78h, jns,79h, jp,7Ah, jpe,7Ah, jnp,7Bh, jpo,7Bh, jl,7Ch, jnge,7Ch, jnl,7Dh, jge,7Dh, jng,7Eh, jle,7Eh, jg,7Fh, jnle,7Fh

	calminstruction instr? dest*

		call	x86.parse_jump_operand@dest, dest

		check	@dest.type <> 'imm' | @dest.jump_type = 'far'
		jyes	invalid_operand

		call	x86.store_operand_prefix, @dest.size

		check	~ $ relativeto 0 & @dest.imm relativeto 0
		jno	optimize
		compute @dest.imm, @dest.imm + $ - 0 scaleof $
		err	'invalid address'
	    optimize:

		check	@dest.jump_type <> 'near' & ( @dest.unresolved | ( @dest.imm relativeto $ & @dest.imm-($+2) < 80h & @dest.imm-($+2) >= -80h ) )
		jyes	short
		check	@dest.jump_type <> 'near' & @dest.imm relativeto $ & ( (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h )
		jyes	short
		check	@dest.jump_type = 'short'
		jyes	relative_jump_out_of_range

		emit	1, 0Fh
		emit	1, 10h+opcode

		check	@dest.size = 2
		jyes	relative_word
		compute @dest.imm, @dest.imm-($+4)
		asm	dd @dest.imm
		exit
	      relative_word:
		compute @dest.imm, @dest.imm-($+2)
		check	@dest.imm relativeto 0
		jno	store_word
		compute @dest.imm, @dest.imm and 0FFFFh
	      store_word:
		asm	dw @dest.imm
		exit

	    short:
		compute @dest.imm, (@dest.imm-($+2)) and 0FFh
		emit	1, opcode
		emit	1, @dest.imm
		exit

	    relative_jump_out_of_range:
		emit	2
		err	'relative jump out of range'
		exit

	    invalid_operand:
		err	'invalid operand'
		exit

	end calminstruction
end iterate

iterate <instr,opcode,len>, loopnz,0E0h,0, loopne,0E0h,0, loopz,0E1h,0, loope,0E1h,0, loop,0E2h,0, \
			    loopnzw,0E0h,2, loopnew,0E0h,2, loopzw,0E1h,2, loopew,0E1h,2, loopw,0E2h,2, \
			    loopnzd,0E0h,4, loopned,0E0h,4, loopzd,0E1h,4, looped,0E1h,4, loopd,0E2h,4, \
			    jcxz,0E3h,2, jecxz,0E3h,4
	calminstruction instr? dest*

		call	x86.parse_jump_operand@dest, dest

		check	@dest.type = 'imm' & ( @dest.jump_type = 'short' | ~ @dest.jump_type )
		jno	invalid_operand

		check	len shl 3 and not x86.mode
		jno	address_prefix_ok
		emit	1, 67h
	    address_prefix_ok:
		check	@dest.size shl 3 <> x86.mode
		jno	operand_prefix_ok
		emit	1, 66h
	    operand_prefix_ok:

		emit	1, opcode

		check	@dest.imm-($+1) < 80h & @dest.imm-($+1) >= -80h
		jyes	relative_offset_ok
		check	(@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h
		jyes	relative_offset_ok
		emit	1
		err	'relative jump out of range'
		exit
	    relative_offset_ok:
		compute @dest.imm, (@dest.imm-($+1)) and 0FFh
		emit	1, @dest.imm
		exit

	    invalid_operand:
		err	'invalid operand'
		exit

	end calminstruction
end iterate

iterate <instr,opcode>, daa,27h, das,2Fh, aaa,37h, aas,3Fh, nop,90h, int3,0CCh, into,0CEh, int1,0F1h, iret,0CFh, salc,0D6h, \
			hlt,0F4h, cmc,0F5h, clc,0F8h, stc,0F9h, cli,0FAh, sti,0FBh, cld,0FCh, std,0FDh, \
			pusha,60h, popa,61h, pushf,9Ch, popf,9Dh, sahf,9Eh, lahf,9Fh, leave,0C9h, \
			insb,6Ch, outsb,6Eh, movsb,0A4h, cmpsb,0A6h, stosb,0AAh, lodsb,0ACh, scasb,0AEh, xlatb,0D7h, \
			clts,<0Fh,06h>, loadall,<0Fh,07h>

	match	byte1=,byte2, opcode
		calminstruction instr?
			emit	1, byte1
			emit	1, byte2
		end calminstruction
	else
		calminstruction instr?
			emit	1, opcode
		end calminstruction
	end match


end iterate

iterate <instr,opcode>, cbw,98h, cwd,99h, iretw,0CFh, pushaw,60h, popaw,61h, pushfw,9Ch, popfw,9Dh, \
			insw,6Dh, outsw,6Fh, movsw,0A5h, cmpsw,0A7h, stosw,0ABh, lodsw,0ADh, scasw,0AFh

	calminstruction instr?
		xcall	x86.store_operand_prefix, (2)
		emit	1, opcode
	end calminstruction

end iterate

iterate <instr,opcode>, cwde,98h, cdq,99h, iretd,0CFh, pushad,60h, popad,61h, pushfd,9Ch, popfd,9Ch, \
			insd,6Dh, outsd,6Fh, movsd,0A5h, cmpsd,0A7h, stosd,0ABh, lodsd,0ADh, scasd,0AFh

	calminstruction instr?
		xcall	x86.store_operand_prefix, (4)
		emit	1, opcode
	end calminstruction

end iterate

iterate <prefix,opcode>, lock,0F0h, repnz,0F2h, repne,0F2h, rep,0F3h, repz,0F3h, repe,0F3h

	calminstruction prefix? instr&
		emit	1, opcode
		assemble instr
	end calminstruction

end iterate

calminstruction int? number*
	emit	1, 0CDh
	emit	1, number
end calminstruction

calminstruction aam? number:10
	emit	1, 0D4h
	emit	1, number
end calminstruction

calminstruction aad? number:10
	emit	1, 0D5h
	emit	1, number
end calminstruction

if defined SSE2

	purge movsd?, cmpsd?

end if

calminstruction movs? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	local	size
	check	@dest.size = 0 & @src.size = 0
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match
	compute size, @dest.size or @src.size
    size_ok:
	check	@src.type = 'mem' & @src.mod = 0 & @dest.type = 'mem' & @dest.mod = 0 & ( (@src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode = 32 & @src.rm = 6 & @dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h )
	jno	invalid_combination_of_operands
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	segment_prefix_ok
	emit	1, @src.segment_prefix
    segment_prefix_ok:
	check	@dest.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	size > 1
	jyes	movs_word
	emit	1, 0A4h
	exit
    movs_word:
	call	x86.store_operand_prefix, size
	emit	1, 0A5h
	exit
    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	size_ok
    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	size_ok
    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit
end calminstruction

calminstruction cmps? src*,dest*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	local	size
	check	@dest.size = 0 & @src.size = 0
	jyes	operand_size_not_specified
	check	@dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size
	jyes	operand_sizes_do_not_match
	compute size, @dest.size or @src.size
    size_ok:
	check	@src.type = 'mem' & @src.mod = 0 & @dest.type = 'mem' & @dest.mod = 0 & ( (@src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode = 32 & @src.rm = 6 & @dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h )
	jno	invalid_combination_of_operands
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	segment_prefix_ok
	emit	1, @src.segment_prefix
    segment_prefix_ok:
	check	@dest.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	size > 1
	jyes	cmps_word
	emit	1, 0A6h
	exit
    cmps_word:
	call	x86.store_operand_prefix, size
	emit	1, 0A7h
	exit
    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	size_ok
    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	size_ok
    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit
end calminstruction

calminstruction stos? dest*
	call	x86.parse_operand@dest, dest
	check	@dest.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@dest.type = 'mem' & @dest.mod = 0 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h )
	jno	invalid_operand
	check	@dest.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	@dest.size > 1
	jyes	stos_word
	emit	1, 0AAh
	exit
    stos_word:
	call	x86.store_operand_prefix, @dest.size
	emit	1, 0ABh
	exit
    invalid_operand:
	err	'invalid operand'
	exit
end calminstruction

calminstruction lods? src*
	call	x86.parse_operand@src, src
	check	@src.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@src.type = 'mem' & @src.mod = 0 & ( (@src.mode = 16 & @src.rm = 4) | (@src.mode = 32 & @src.rm = 6) )
	jno	invalid_operand
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	segment_prefix_ok
	emit	1, @src.segment_prefix
    segment_prefix_ok:
	check	@src.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	@src.size > 1
	jyes	lods_word
	emit	1, 0ACh
	exit
    lods_word:
	call	x86.store_operand_prefix, @src.size
	emit	1, 0ADh
	exit
    invalid_operand:
	err	'invalid operand'
	exit
end calminstruction

calminstruction scas? dest*
	call	x86.parse_operand@dest, dest
	check	@dest.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@dest.type = 'mem' & @dest.mod = 0 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h )
	jno	invalid_operand
	check	@dest.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	@dest.size > 1
	jyes	scas_word
	emit	1, 0AEh
	exit
    scas_word:
	call	x86.store_operand_prefix, @dest.size
	emit	1, 0AFh
	exit
    invalid_operand:
	err	'invalid operand'
	exit
end calminstruction

calminstruction ins? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@dest.size
	jyes	size_ok
	err	'operand size not specified'
	compute size, 0
    size_ok:
	check	@src.type = 'reg' & @src.size = 2 & @src.rm = 2 & @dest.type = 'mem' & @dest.mod = 0 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h )
	jno	invalid_combination_of_operands
	check	@dest.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	@dest.size > 1
	jyes	ins_word
	emit	1, 6Ch
	exit
    ins_word:
	call	x86.store_operand_prefix, @dest.size
	emit	1, 6Dh
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit
end calminstruction

calminstruction outs? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@src.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@dest.type = 'reg' & @dest.size = 2 & @dest.rm = 2 & @src.type = 'mem' & @src.mod = 0 & ( (@src.mode = 16 & @src.rm = 4) | (@src.mode = 32 & @src.rm = 6) )
	jno	invalid_combination_of_operands
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	segment_prefix_ok
	emit	1, @src.segment_prefix
    segment_prefix_ok:
	check	@src.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	check	@src.size > 1
	jyes	outs_word
	emit	1, 6Eh
	exit
    outs_word:
	call	x86.store_operand_prefix, @src.size
	emit	1, 6Fh
	exit
    operand_size_not_specified:
	err	'operand size not specified'
	compute size, 0
	jump	size_ok
    operand_sizes_do_not_match:
	err	'operand sizes do not match'
	compute size, 0
	jump	size_ok
    invalid_combination_of_operands:
	err	'invalid combination of operands'
	exit
end calminstruction

calminstruction xlat? src*
	call	x86.parse_operand@src, src
	check	@src.size > 1
	jno	size_ok
	err	'invalid operand size'
    size_ok:
	check	@src.type = 'mem' & @src.mod = 0 & ( (@src.mode = 16 & @src.rm = 7) | (@src.mode = 32 & @src.rm = 3) )
	jno	invalid_operand
	check	@src.segment_prefix = 0 | @src.segment_prefix = 3Eh
	jyes	segment_prefix_ok
	emit	1, @src.segment_prefix
    segment_prefix_ok:
	check	@src.mode = x86.mode
	jyes	address_prefix_ok
	emit	1, 67h
    address_prefix_ok:
	emit	1, 0D7h
	exit
    invalid_operand:
	err	'invalid operand'
	exit
end calminstruction

calminstruction in? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@dest.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@src.type = 'reg' & @src.size = 2 & @src.rm = 2 & @dest.type = 'reg' & @dest.rm = 0
	jyes	in_ax_dx
	check	@src.type = 'imm' & @dest.type = 'reg' & @dest.rm = 0
	jyes	in_ax_imm
	err	'invalid combination of operands'
	exit
    in_ax_dx:
	check	@dest.size > 1
	jno	in_al_dx
	call	x86.store_operand_prefix, @dest.size
	emit	1, 0EDh
	exit
    in_al_dx:
	emit	1, 0ECh
	exit
    in_ax_imm:
	check	@dest.size > 1
	jno	in_al_imm
	call	x86.store_operand_prefix, @dest.size
	emit	1, 0E5h
	emit	1, @src.imm
	exit
    in_al_imm:
	emit	1, 0E4h
	emit	1, @src.imm
	exit
end calminstruction

calminstruction out? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@src.size
	jyes	size_ok
	err	'operand size not specified'
    size_ok:
	check	@dest.type = 'reg' & @dest.size = 2 & @dest.rm = 2 & @src.type = 'reg' & @src.rm = 0
	jyes	out_dx_ax
	check	@dest.type = 'imm' & @src.type = 'reg' & @src.rm = 0
	jyes	out_imm_ax
	err	'invalid combination of operands'
	exit
    out_dx_ax:
	check	@src.size > 1
	jno	out_dx_al
	call	x86.store_operand_prefix, @src.size
	emit	1, 0EFh
	exit
    out_dx_al:
	emit	1, 0EEh
	exit
    out_imm_ax:
	check	@src.size > 1
	jno	out_imm_al
	call	x86.store_operand_prefix, @src.size
	emit	1, 0E7h
	emit	1, @dest.imm
	exit
    out_imm_al:
	emit	1, 0E6h
	emit	1, @dest.imm
	exit
end calminstruction

calminstruction enter? alloc*,nesting*
	call	x86.parse_operand@src, alloc
	call	x86.parse_operand@aux, nesting
	check	(@src.size and not 2) | (@aux.size and not 1)
	jno	size_ok
	err	'invalid operand size'
    size_ok:
	check	@src.type = 'imm' & @aux.type = 'imm'
	jyes	operand_ok
	err	'invalid operand'
	exit
    operand_ok:
	emit	1, 0C8h
	asm	dw @src.imm
	emit	1, @aux.imm
end calminstruction

calminstruction bound? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@src.type = 'mem' & @dest.type = 'reg'
	jno	invalid_combination_of_operands
	check	@src.size and not @dest.size
	jno	size_ok
	err	'operand sizes do not match'
    size_ok:
	call	x86.select_operand_prefix@src, @dest.size
	xcall	x86.store_instruction@src, (62h),@dest.rm
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
end calminstruction

calminstruction arpl? dest*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	check	@src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg')
	jno	invalid_combination_of_operands
	check	@src.size = 2
	jno	invalid_operand_size
	check	@dest.size and not @src.size
	jno	size_ok
	err	'operand sizes do not match'
	jump	size_ok
    invalid_operand_size:
	err	'invalid operand size'
    size_ok:
	xcall	x86.store_instruction@dest, (63h),@src.rm
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
end calminstruction

iterate <instr,ext,postbyte>, lldt,0,2, ltr,0,3, verr,0,4, verw,0,5, lmsw,1,6

	calminstruction instr? dest*
		call	x86.parse_operand@dest, dest
		check	@dest.size and not 2
		jno	size_ok
		err	'invalid operand size'
	    size_ok:
		check	@dest.type = 'reg' | @dest.type = 'mem'
		jyes	operand_ok
		err	'invalid operand'
		exit
	    operand_ok:
		xcall	x86.store_instruction@dest, <0Fh,ext>,(postbyte)
	end calminstruction

end iterate

iterate <instr,ext,postbyte>, sldt,0,0, str,0,1, smsw,1,4

	calminstruction instr? dest*
		call	x86.parse_operand@dest, dest
		check	@dest.type = 'reg'
		jyes	select_operand_prefix
		check	@dest.size and not 2
		jno	size_ok
		err	'invalid operand size'
	    size_ok:
		check	@dest.type = 'mem'
		jyes	store_instruction
		err	'invalid combination of operands'
		exit
	    select_operand_prefix:
		call	x86.select_operand_prefix@dest, @dest.size
	    store_instruction:
		xcall	x86.store_instruction@dest, <0Fh,ext>,(postbyte)
	end calminstruction

end iterate

iterate <instr,postbyte>, lgdt,2, lidt,3, sgdt,0, sidt,1

	calminstruction instr? dest*
		call	x86.parse_operand@dest, dest
		check	@dest.type = 'mem'
		jyes	operand_ok
		err	'invalid operand'
		exit
	    operand_ok:
		check	@dest.size = 6
		jyes	o32
		check	@dest.size = 5
		jyes	o16
		check	@dest.size
		jno	store_instruction
		err	'invalid operand size'
		jump	store_instruction
	    o16:
		xcall	x86.select_operand_prefix@dest, (2)
		jump	store_instruction
	    o32:
		xcall	x86.select_operand_prefix@dest, (4)
	    store_instruction:
		xcall	x86.store_instruction@dest, <0Fh,1>,(postbyte)
	end calminstruction

end iterate

iterate <instr,ext>, lar,2, lsl,3

	calminstruction instr? dest*,src*
		call	x86.parse_operand@dest, dest
		call	x86.parse_operand@src, src
		check	@dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg')
		jno	invalid_combination_of_operands
		check	@src.size and not 2
		jno	size_ok
		err	'invalid operand size'
	    size_ok:
		call	x86.select_operand_prefix@src, @dest.size
		xcall	x86.store_instruction@src, <0Fh,ext>,@dest.rm
		exit
	    invalid_combination_of_operands:
		err	'invalid combination of operands'
	end calminstruction

end iterate

calminstruction xbts? dest*,src*,offs*,len*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	call	x86.parse_operand@src2, offs
	call	x86.parse_operand@aux, len
	check	@dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') & \
		@src2.type = 'reg' & @src2.rm = 0 & @aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1
	jno	invalid_combination_of_operands
	check	@src.size and not @dest.size | @src2.size <> @dest.size
	jyes	operand_sizes_no_not_match
	check	@dest.size > 1
	jyes	size_ok
	err	'invalid operand size'
	jump	size_ok
    operand_sizes_no_not_match:
	err	'operand sizes do not match'
    size_ok:
	call	x86.select_operand_prefix@src, @dest.size
	xcall	x86.store_instruction@src, <0Fh,0A6h>,@dest.rm
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
end calminstruction

calminstruction ibts? dest*,offs*,len*,src*
	call	x86.parse_operand@dest, dest
	call	x86.parse_operand@src, src
	call	x86.parse_operand@src2, offs
	call	x86.parse_operand@aux, len
	check	@src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg') & \
		@src2.type = 'reg' & @src2.rm = 0 & @aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1
	jno	invalid_combination_of_operands
	check	@dest.size and not @src.size | @src2.size <> @src.size
	jyes	operand_sizes_no_not_match
	check	@src.size > 1
	jyes	size_ok
	err	'invalid operand size'
	jump	size_ok
    operand_sizes_no_not_match:
	err	'operand sizes do not match'
    size_ok:
	call	x86.select_operand_prefix@dest, @src.size
	xcall	x86.store_instruction@dest, <0Fh,0A7h>,@src.rm
	exit
    invalid_combination_of_operands:
	err	'invalid combination of operands'
end calminstruction
