
'==================
' Oxygen Assembler
' Charles E V Pegge
'==================


function stackpointadj(string*s, int*i) as string
=================================================
'sp
int a,u,v
string wr
do
  wr=yword(s,i)
  ascii_to_float strptr wr
  fistp dword u
  v+=u
  a=i
  do
    skipspace(s,a)
    if ascn=0
      exit do
    endif
    if ise(ascn)
      endline(s,a)  'ignoring comments
    else
      exit do
    endif
  loop
  wr=yword(s,a)
  if wr="|sp"
    i=a
  else
    exit do
  endif
loop
i+=len(cr)
if v
  return "add "+qesp+cm+str(v)+cr
endif
end function


'=======================
' IDENTIFY x86 REGISTERS
'=======================


'DETECT XMMX OR MMX REGISTER

function xmmxid(string*w, int*ds) as int
========================================
  '
  'XMM MM MMX
  '
  int a=asc(w),b=1,e=len(w)
  ds=0 : rexi=0 : function=-1
  if (a<97)or(e>5)or(e<3)
    exit function
  endif
  if a=0x78
    ds=1 : b++
  endif
  if (asc(w,b)<>0x6d)or(asc(w,b+1)<>0x6d)
    exit function
  endif
  a=asc(w,e)-48
  if (a>=0)and(a<10)
    if asc(w,e-1)=49
      a=10
    endif
    if (a>=0)and(a<16)
      if a>=8
        rexi=1
      endif
      function=a
    endif

  endif
  '
end function

function regid(string*wr, int*l) as int
=======================================
  int a,b,e,v=-1
  string s
  l=0 : a=lookupm(wr) : rexi=0
  if a
    if drc(a).a=-10
      s=mrcso(a,1)
      b=valchahex(s,3)
      e=valchahex(s,1)
      if b=9
        if cpuw=8
          rexi=1
        else 'DOWGRADE TO 32BITS
          if e=8
            e=4
          endif
          mid(wr,1)="e"
        endif
        b=1
      endif
      if b=1
        l=e : v=valchahex(s,2)
      endif
      if l=15
        l=16
      endif
    endif
  endif
  function=v
end function


'DETECT CONTROL,DEBUG AND SEGMENT REGISTERS
'
function sregid(string*w, int*ds) as int
========================================
  '
  int a,b,rg
  string s
  ds=0 : rg=-1 : rexi=0
  a=lookupm(w)
  if a=0
    goto xsreg
  endif
  if drc(a).a<>-10
    goto xsreg
  endif
  s=mrcso(a,1)
  b=valchahex(s,3) : if b>4
    rg=valchahex(s,2) : ds=b+124
  endif
  xsreg:
  function=rg
  '
end function


'RANGE LIMITS
double bx16=65536
double bxm15=-32768
double bx32=4.0*0x40000000
double bxm31=-2.0*0x40000000

'
'          ###
'         ## ##
'        ##   ##
'       ##     ##
'      ##       ##
'     #############
'    ##           ##
'   ##             ##
'  ##               ##

'data "popad  ` 61`"    '32bit only
'data "pushad ` 60`"    '32bit only
'data "rdmsr  ` 0f 32`" 'read from model specific register
'data "rdpmc  ` 0f 33`" 'read performance monitoring counter
'data "rdtsc  ` 0f 31`" 'read timestamp counter

' cpu no operands
' fpu no operands
' other cpu

' FORMAT:
'-------------------------------------
' flt pn `prefix codes` dm c ima im ic
'=====================================
' flt=0 general instruction
' flt=1 fpu instruction
' flt=2 mmx instruction
' flt=3 xmm instruction
' flt=4 general instruction without di and ws additions
'
' pn=0  undefined
' pn=1  single operand
' pn=2  2 operands
' pn=3  2 operands - the first must be a register
' pn=4  2 operands - the first is an r/m, the second must be a register
' pn=5  2 operands -  the first must be a register
' pn=6  2 operands - the first must be a mem, not a register
' pn=7  1 operand  - must be a mem
' pn=8  undefined
' pn=9  undefined
' pn=10 3 operands - the third must be an 8 bit value eg some xmmx instructions
' pn=11 3 operands - the third must be an 8 bit value or the cl register eg: shld shrd
' pn=12 1 2 or 3 operands - specific to imul
' pn=13 1 or 2 operand bit shift shl ror etc
' pn=14 first reg is general purpose, second reg is xmmx, rg and rm octals are then swapped thus: md-rm-rg (PMOVMSKB)
' pn=15 r/m.xmm,imm8  (pextrb pextrw pextrd pextrq)

'---------------------------------

function lookupc(string*wd) as int
'=================================
'FOR ASSM LIST
int v,i,q
sys p=strptr(wd)
hashmac(p,i)
v=i and 511
do
  q=v*opdw
  if opd(q)=i ' match#
    if wd=opn(v)
      exit do ' confirm perfect match
    endif
  endif
  q=v*opdw+1
  v=opd(q)
  if v=-1
    exit do
  endif
loop
return v
end function


string opcode_data="

' already directly decoded using instr(..)

db
dw
dd
dq

ret
in
out
outs
outsb
outsw
outsd
enter
leave

call
jmp
jz
jnz
jl
jge
jle
jg
jb
jae
jbe
ja
jo
js
jpe
jpo
jc
je
jnge
jnl
jng
jnle
jnae
jnc
jnb
jna
jnbe
jno
jns
jnc
jne

fild
fist
fiadd
fisub
fimul
fidiv
fisubr
fidivr
fistp
fimulp
fidivp
fidivrp
ficom
ficomp

fstp
faddp
fsubp
fsubrp
fmulp
fdivp
fdivrp
fcomip
fucomip
fcomp

fst
fld
fadd
fsub
fmul
fdiv
fsubr
fdivr
fcomi
fucomi
fcom
fldt
fstpt

fxch
fbld
fbstp
ffree
fldcw
fldenv
fstcw
fstenv
fstsw
fucom
fucomp
frstor
fsave
fnsave
fnstcw
fnstenv
fnstsw
fisttp

fcmovb
fcmove
fcmovbe
fcmovu
fcmovnb
fcmovne
fcmovnbe
fcmovnu

mov
inc
dec
push
pop
add
sub
mul
div
cmp
and
or
xor
test
xchg
movsx
movzx

neg
not
adc
sbb
imul
idiv
bound
arpl
bsf
bsr

rcl
rcr
rol
ror
sal
sar
shl
shr
shld
shrd

jcxz
jecxz
loopz
loope
loopnz
loopne
loop

rep
repne
repnz
repe
repz

ins
lods
movs
outs
cmps
stos
scas

cmovz
cmovnz
cmovl
cmovge
cmovle
cmovg
cmovb
cmovae
cmovbe
cmova
cmovo
cmovno
cmovs
cmovns
cmovpe
cmovpo
cmovc
cmovnc
cmove
cmovne

setz
setnz
setl
setge
setle
setg
setb
setae
setbe
seta
seto
setno
sets
setns
setpe
setpo
setc
setnc
sete
setne

padd
padds
paddus
pcmpeq
pcmpgt
psll
psra
psrl
psub
psubs
psubus
punpckhb
punpckhw
punpckhd
punpcklb
punpcklw
punpckld

emms
movd
movq
packssdw
packsswb
packuswb
padd padds
paddus
pand
pandn

pcmpeq
pcmpgt
pmaddwd
pmulhw
pmullw
por psll
psra psrl
psub psubs
psubus
punpckhb
punpckhw
punpckhd
punpcklb
punpcklw
punpckld
pmulhuw
pxor


' cpu no operands

cbw    ` 98`
cdqe   ` 49 98`
cwde   ` 98`
cwd    ` 99`
cdq    ` 99`
cdqo   ` 49 99`
clc    ` f8`
cld    ` fc`
cli    ` fa`
clts   ` 0f 06`
cmc    ` f5`
cpuid  ` 0f a2`
daa    ` 27`
das    ` 2f`
into   ` ce`
invd   ` 0f 08`
iret   ` cf`
nop    ` 90`
lahf   ` 9f`
popa   ` 61`
popad  ` 61`
popf   ` 9d`
pushf  ` 9c`
popfd  ` 9d`
pushfd ` 9c`
pusha  ` 60`
pushad ` 60`
rdmsr  ` 0f 32`
rdpmc  ` 0f 33`
rdtsc  ` 0f 31`
rsm    ` 0f aa`
sahf   ` 9e`
sec    ` f9`
stc    ` f9`
std    ` fd`
sti    ` fb`
wait   ` 9b`
wbinvd ` 0f 09`
wrmsr  ` 0f 30`
xlat   ` d7`
lock   ` f0`
leave  ` c9`
halt   ` f4`
aaa    ` 37`
aad    ` d5 0a`
aam    ` d4 0a`
hlt    ` f4`
aas    ` 3f`

sysenter ` 0f 34`
sysexit  ` 0f 35`
ud2      ` 0f 0b`

' fpu no operands

fabs    ` d9 e1`
fchs    ` d9 e0`
fldz    ` d9 ee`
fld1    ` d9 e8`
fldpi   ` d9 eb`
fsqrt   ` d9 fa`
fsin    ` d9 fe`
fcos    ` d9 ff`
fsincos ` d9 fb`
fptan   ` d9 f2`
fpatan  ` d9 f3`

fclex   ` 9b db e2`
fnclex  ` db e2`
fdecstp ` d9 f6`
fincstp ` d9 f7`
fnop    ` d9 d0`
fprem   ` d9 f8`
fprem1  ` d9 f5`
frndint ` d9 fc`
fscale  ` d9 fd`
fstsw   ` df e0`
ftst    ` d9 e4`
fucompp ` da e9`
fxam    ` d9 e5`
fxtract ` d9 f4`
finit   ` 9b db e3`
fninit   ` db e3`

fcompp  ` de d9`
f2xm1   ` d9 f0`
fldl2e  ` d9 ea`
fldl2t  ` d9 e9`
fldlg2  ` d9 ec`
fldln2  ` d9 ed`
fyl2x   ` d9 f1`
fyl2xp1 ` d9 f9`
fwait   ` 9b`

' other cpu

bt    0 4 ` 0f` a3 0 8 ba 4
btc   0 4 ` 0f` bb 0 8 ba 7
btr   0 4 ` 0f` b3 0 8 ba 6
bts   0 4 ` 0f` ab 0 8 ba 5
xadd  0 4 ` 0f` c0 0

sgdt  4 7 ` 0f` 01 0
sidt  4 7 ` 0f` 01 1
sldt  4 1 ` 0f` 00 0
smsw  4 1 ` 0f` 01 4
str   4 1 ` 0f` 00 1
verr  4 1 ` 0f` 00 4
verw  4 1 ` 0f` 00 5
cmpxchg   04 04 ` 0f` b0 0
cmpxchg8b 04 07 ` 0f` c7 1

movsxd 4 3 63 0
 
lds  4 3 c5 0
lea  4 3 8d 0
les  4 3 c4 0
lar  4 3 ` 0f` 02 0
lfs  4 3 ` 0f` b4 0
lgdt 4 7 ` 0f` 01 2
lgs  4 7 ` 0f` b5 0
lsl  4 3 ` 0f` 03 0
lss  4 3 ` 0f` b2 0
ltr  4 1 ` 0f` 00 3
lidt 4 7 ` 0f` 01 3
lldt 4 1 ` 0f` 00 2
ldt  4 1 ` 0f` 00 2
ldtr 4 1 ` 0f` 00 2
lmsw 4 1 ` 0f` 01 6

'---
'sse
'===

addps     3 3 ` 0f` 58
addss     3 3 ` f3 0f` 58
andnps    3 3 ` 0f` 55
andps     3 3 ` 0f` 54
cmpps     3 a ` 0f` - - 8 c2 0
cmpss     3 a ` f3 0f` - - 8 c2 0
comiss    3 3 ` 0f` 2f
cvtpi2ps  3 3 ` 0f` 2a
cvtps2pi  3 3 ` 0f` 2d
cvtsi2ss  3 3 ` f3 0f` 2a
cvtss2si  3 3 ` f3 0f` 2d
cvttps2pi 3 3 ` 0f` 2c
cvttss2si 3 3 ` f3 0f` 2c

divps     3 3 ` 0f` 5e
divss     3 3 ` f3 0f` 5e
fxrstor   3 7 ` 0f` ae 1
fxsave    3 7 ` 0f` ae 0
ldmxcsr   3 7 ` 0f` ae 12

maxps    3 3 ` 0f` 5f
maxss    3 3 ` f3 0f` 5f
minps    3 3 ` 0f` 5d
minss    3 3 ` f3 0f` 5d
movaps   3 2 ` 0f` 28
movhlps  3 3 ` 0f` 12
movlhps  3 3 ` 0f` 16
movhps   3 2 ` 0f` 16
movlps   3 2 ` 0f` 12
movmskps 3 3 ` 0f` 50
movss    3 2 ` f3 0f` 10
movups   3 2 ` 0f` 10
mulps    3 3 ` 0f` 59
mulss    3 3 ` f3 0f` 59
maskmovq 3 3 ` 0f` f7
movntps  3 6 ` 0f` 2b
movntq   3 6 ` 0f` e7

orps     3 3 ` 0f` 56
rcpps    3 3 ` 0f` 53
rcpss    3 3 ` f3 0f` 53
rsqrtps  3 3 ` 0f` 52
rsqrtss  3 3 ` f3 0f` 52
shufps   3 a ` 0f` - - 8 c6
sqrtps   3 3 ` 0f` 51
sqrtss   3 3 ` f3 0f` 51
stmxcsr  3 7 ` 0f` ae 3
subps    3 3 ` 0f` 5c
subss    3 3 ` f3 0f` 5c
sfence   ` 0f ae f8`
ucomiss  3 3 ` 0f` 2e
unpckhps 3 3 ` 0f` 15
unpcklps 3 3 ` 0f` 14
xorps    3 3 ` 0f` 57

pavgb    3 3 ` 0f` e0
pavgw    3 3 ` 0f` e3
pextrw   3 f ` 0f` c5 - 8 c5
pinsrw   3 a ` 0f` - - 8 c4
pmaxsw   3 3 ` 0f` ee
pmaxub   3 3 ` 0f` de
pminsw   3 3 ` 0f` ea
pminub   3 3 ` 0f` da
pmovmskb 3 e ` 0f` d7
psadbw   3 3 ` 0f` f6
pshufw   3 a ` 0f` - - 8 70

'sse2 extended: double precision

addpd      3 3 ` 66 0f` 58
addsd      3 3 ` f2 0f` 58
andnpd     3 3 ` 66 0f` 55
andpd      3 3 ` 66 0f` 54
cmppd      3 a ` 66 0f` - - 8 c2 0
cmpsd      3 a ` f2 0f` - - 8 c2 0
comisd     3 3 ` 66 0f` 2f

cvtpi2pd   3 3 ` 66 0f` 2a
cvtpd2pi   3 3 ` 66 0f` 2d
cvtsi2sd   3 3 ` f2 0f` 2a
cvtsd2si   3 3 ` f2 0f` 2d
cvttpd2pi  3 3 ` 66 0f` 2c
cvttsd2si  3 3 ` f2 0f` 2c

divpd      3 3 ` 66 0f` 5e
divsd      3 3 ` f2 0f` 5e
maxpd      3 3 ` 66 0f` 5f
maxsd      3 3 ` f2 0f` 5f
minpd      3 3 ` 66 0f` 5d
minsd      3 3 ` f2 0f` 5d

movapd     3 2 ` 66 0f` 28
movhlpd    3 3 ` 66 0f` 12
movlhpd    3 3 ` 66 0f` 16
movhpd     3 2 ` 66 0f` 16
movlpd     3 2 ` 66 0f` 12
movmskpd   3 3 ` 66 0f` 50
movsd      3 2 ` f2 0f` 10
movupd     3 2 ` 66 0f` 10
mulpd      3 3 ` 66 0f` 59
mulsd      3 3 ` f2 0f` 59

maskmovdqu 3 3 ` 66 0f` f7
movntpd    3 6 ` 66 0f` 2b

orpd       3 3 ` 66 0f` 56
shufpd     3 a ` 66 0f` - - 8 c6
sqrtpd     3 3 ` 66 0f` 51
sqrtsd     3 3 ` f2 0f` 51
subpd      3 3 ` 66 0f` 5c
subsd      3 3 ` f2 0f` 5c
ucomisd    3 3 ` 66 0f` 2e
unpckhpd   3 3 ` 66 0f` 15
unpcklpd   3 3 ` 66 0f` 14
xorpd      3 3 ` 66 0f` 57

'----
'sse3
'====

addsubpd  3 4 ` 66 0f` d0
addsubps  3 4 ` f2 0f` d0
haddpd    3 4 ` 66 0f` 7c
haddps    3 4 ` f2 0f` 7c
hsubpd    3 4 ` 66 0f` 70
hsubps    3 4 ` f2 0f` 7d
lddqu     3 4 ` f2 0f` f0
movddup   3 4 ` f2 0f` 12
movshdup  3 4 ` f3 0f` 16
movsldup  3 4 ` f3 0f` 12
mwait 03  ` 0f 01 c9`

'----
'sse4
'sse4.1
'====

blendpd   3 a ` 66 0f 3a` 0d - 8 0d
blendps   3 a ` 66 0f 3a` 0c - 8 0c
blendvpd  3 4 ` 66 0f 38` 15
blendvps  3 4 ` 66 0f 38` 14
dppd      3 a ` 66 0f 3a` 41 - 8 41
dpps      3 a ` 66 0f 3a` 40 - 8 40
extractps 3 a ` 66 0f 3a` 17 - 8 17
insertps  3 a ` 66 0f 3a` 21 - 8 21
movntdqa  3 4 ` 66 0f 38` 2a
mpsadbw   3 a ` 66 0f 3a` 42 - 8 42
packusdw  3 4 ` 66 0f 38` 2b
pblendvb  3 4 ` 66 0f 38` 10
pblendw   3 a ` 66 0f 3a` 0e - 8 0e
'pcmpeqq   3 4 ` 66 0f 38` 29

pextrb     3 f ` 66 0f 3a` 14 - 8 14
pextrd     3 f ` 66 0f 3a` 16 - 8 16
' pextrw     3 f ` 66 0f 3a` 15 - 8 15
phminposuw 3 4 ` 66 0f 38` 41
pinsrb     3 a ` 66 0f 3a` 20 - 8 20
pinsrd     3 a ` 66 0f 3a` 22 - 8 22
pinsrq     3 a ` 66 0f 3a` 22 - 8 22

pmaxsb     3 4 ` 66 0f 38` 3c
pmaxsd     3 4 ` 66 0f 38` 3d
pmaxud     3 4 ` 66 0f 38` 3f
pmaxuw     3 4 ` 66 0f 38` 3e

pminsb     3 4 ` 66 0f 38` 38
pminsd     3 4 ` 66 0f 38` 39
pminud     3 4 ` 66 0f 38` 3b
pminuw     3 4 ` 66 0f 38` 3a

pmovsxbd   3 4 ` 66 0f 38` 21
pmovsxbq   3 4 ` 66 0f 38` 22
pmovsxbw   3 4 ` 66 0f 38` 20
pmovsxwd   3 4 ` 66 0f 38` 23
pmovsxwq   3 4 ` 66 0f 38` 24
pmovsxdq   3 4 ` 66 0f 38` 25

pmovzxbd   3 4 ` 66 0f 38` 31
pmovzxbq   3 4 ` 66 0f 38` 32
pmovzxbw   3 4 ` 66 0f 38` 30
pmovzxwd   3 4 ` 66 0f 38` 33
pmovzxwq   3 4 ` 66 0f 38` 34
pmovzxdq   3 4 ` 66 0f 38` 35
pmuldq     3 4 ` 66 0f 38` 38
pmulld     3 4 ` 66 0f 38` 40
ptest      3 4 ` 66 0f 38` 17

roundpd    3 a ` 66 0f 3a` 09 - 8 09
roundps    3 a ` 66 0f 3a` 08 - 8 08
roundsd    3 a ` 66 0f 3a` 0b - 8 0b
roundss    3 a ` 66 0f 3a` 0a - 8 0a

'SSE4.2
'https://software.intel.com/sites/default/files/m/8/b/8/D9156103.pdf

crc32      4 3 ` f2 0f 38` f0 0

pcmpestri   3 a ` 66 0f 3a` 61 - 8 61 '??..
pcmpestrm   3 a ` 66 0f 3a` 60 - 8 60
pcmpistri   3 a ` 66 0f 3a` 63 - 8 63
pcmpistrm   3 a ` 66 0f 3a` 62 - 8 62

pcmpgtq     3 4 ` 66 0f 38` 37

'SSE4.2 included

popcnt     4 3 ` f3 0f` b8 0
lzcnt      4 3 ` f3 0f` bd 0

'-----
'3dnow
'=====

pi2fw    2 3 `0f ` 0f + 0c
pi2fd    2 3 `0f ` 0f + 0d
pf2iw    2 3 `0f ` 0f + 1c
pf2id    2 3 `0f ` 0f + 1d
pfnacc   2 3 `0f ` 0f + 8a
pfpnacc  2 3 `0f ` 0f + 8e
pfcmpge  2 3 `0f ` 0f + 90
pfmin    2 3 `0f ` 0f + 94
pfrcp    2 3 `0f ` 0f + 96
pfrsqrt  2 3 `0f ` 0f + 97
pfsub    2 3 `0f ` 0f + 9a
pfadd    2 3 `0f ` 0f + 9e
pfcmpgt  2 3 `0f ` 0f + a0

pfmax    2 3 `0f ` 0f + a4
pfrcpit1 2 3 `0f ` 0f + a6
pfrsqit1 2 3 `0f ` 0f + a7
pfsubr   2 3 `0f ` 0f + aa
pfacc    2 3 `0f ` 0f + ae
pfcmpeq  2 3 `0f ` 0f + b0
pfmul    2 3 `0f ` 0f + b4
pfrcpit2 2 3 `0f ` 0f + b6
pmulhrw  2 3 `0f ` 0f + b7
pswapd   2 3 `0f ` 0f + bb
pavgusb  2 3 `0f ` 0f + bf

'cache management

prefetcht0  4 1 ` 0f` 18 08
prefetcht1  4 1 ` 0f` 18 10
prefetcht2  4 1 ` 0f` 18 18
prefetchnta 4 1 ` 0f` 18 00

!end!
"


procedure loadops()
===================
int a,h,i,j,k,v,f,n,q
int t,u,uu,tal
sys p
string s,d,wd
ope=0
n=512
init4 @opd,9000,-1
h=1
do
  s=readdata(opcode_data,h)
  if lenw=0
    exit do
  endif
  i=1o
  wd=aword(s,i)
  a=ascw
  p=strptr(wd)
  hashmac(p,v)
  ope=v and 511
  u++
  if opn(ope)
     uu++
     t=0
     do
       q=ope*opdw+1
       if opd(q)=-1
         opd(q)=n : ope=n : n++ : exit do
       endif
       t++
       if t>tal
         tal=t
       endif
       ope=opd(q)
     loop
     if n>999
       ers="Too many instruction definitions" : ert=9 : ope=0
       exit procedure
     endif
   endif
   opn(ope)=wd
   q=ope*opdw
   opd(q)=v ' 32 bit hash code
   '
   'print ope, wd, hex(v)
   ' ops prefix codes
   ' opd flags and opcodes
   '
   ' k=0 32bit hash code
   ' k=1 lk link index
   '
   ' k=2 flt
   ' k=3 pn
   ' k=4 dm
   ' k=5 c
   ' k=6 ima
   ' k=7 im
   ' k=8 ic
   ' k=9 dn
   k=1
   do
     k++
     if k>9
       exit do
     endif
     if ascn<=13
       exit do
     endif
     wd=aword(s,i)
     a=ascw
     if a<=13
       exit do
     endif
     if isq(a)
       k-- : ops(ope)=mid(wd,2,len(wd)-2) : continue do
     endif
     if a=43
       wd=aword(s,i) : k=9 : a=ascw '3dnow postfix code
     endif
     if a=45
       continue do ' leave default -1
     endif
     if isc(a)
       exit do ' comment
     endif
     q=ope*opdw+k
     opd(q)=val("0x"+wd)
   loop
loop
' coincidence check
'------------------
'i=-1
'do
'  i++
'  if i>=n
'    exit do
'  endif
'  q=i*opdw+1
'  j=opd(q)
'  if j=-1
'    continue do ' not links
'  endif
'  do
'    if opd(i*opdw)=opd(j*opdw)
'      ert=9 : ers="!! instruction hash not unique: "+opn(i)+" "+opn(j*opdw)+" "+hex(opd(j*opdw))
'      'messagebox 0,ers,"Coincidence check",0
'      exit procedure 
'    endif
'    j=opd(j*opdw+1) ' next in chain
'    if j=-1
'      exit do
'  endif
'  loop
'loop
'------------------
''print "Extra ",n-512
' messagebox 0, str(tal)+" "+str(u)+" "+str(uu),"Maxlinks",0
' ert=9 : ers="error test"
end procedure


'LOAD ASSEMBLy CODE TABLES
'=========================
if ope=0
  loadops() ' loads assembler once when required
  if ert
    ope=0
  endif
endif


function jword(string*s, int*st,*i,*lw) as string
=================================================
' eg:
'    jmp long repeat
'    jmp repeat
'    call label
  int a
  string wd
  double v
  i=st
  wd=aword(s,i)
  '
  lw=1 'long by default
  '
  if wd="long"
    lw=1 : wd=aword(s,i)
  endif
  if wd="short"
    lw=0 : wd=aword(s,i)
    if wd="fwd"
      lw=2
      wd=aword(s,i)
    endif
  endif
  if wd="fwd"
    lw=3
    wd=aword(s,i)
  endif
  'if wd="#"
  '  wd+=aword(s,i)
  'endif
  wordeval(s,swd,i) : v=dv
  if nan=0
    ' immediate
    if lw=1
      wd=hexl(dv) : goto xitj
    endif
    if lw=0
      wd=hexb(v) : goto xitj
    endif
  endif
  if wd="exit"
    wd="x"
    a=ascn
    if (a>48)and(a<58)
      lw=1 : wd+=aword(s,i)
      goto xitj ' multi exit
    endif
    if lw
      wd+="l"
    endif
    goto xitj
  endif
  if wd="repeat" 
    wd="r"
    if lw 
      wd+="l"
    endif
    goto xitj
  endif
  if lw=0
    wd="g "+wd : goto xitj
  endif
  if lw=1
    wd="gl "+wd : goto xitj
  endif
  if lw=2
    wd="gs "+wd : goto xitj
  endif
  if lw=3
    wd="gf "+wd : goto xitj
  endif
xitj:
  lw and=1
  return " "+wd
  '
end function



function condi(string*wr, int*i) as int
=======================================
  int m, v, b, e
  if asc(wr,i)=0x6e
    i++ 'skip n
    b=1 'opposite flag
  endif
  v=-1
  e=len(wr)
  if (e>i+2)or(e<i)
    return -1
  endif
  m=asc(wr,i)*256+asc(wr,i+1)
  select m
    case 0x7a00 : v=04 ' jz   je
    case 0x6c00 : v=12 ' jl        jnge
    case 0x6765 : v=13 ' jge       jnl
    case 0x6c65 : v=14 ' jle       jng
    case 0x6700 : v=15 ' jg        jnle
    case 0x6200 : v=02 ' jb    jc  jnae
    case 0x6165 : v=03 ' jae   jnc jnb
    case 0x6265 : v=06 ' jbe       jna
    case 0x6100 : v=07 ' ja        jnbe
    case 0x6f00 : v=00 ' jo
    case 0x7300 : v=08 ' js
    case 0x7065 : v=10 ' jpe
    case 0x706f : v=11 ' jpo
    case 0x6300 : v=02 ' jc    jb
    case 0x6500 : v=04 ' je    jz
   '------------------------------
   'case 0x6e7a : v=05 ' jnz   jne
   'case 0x6e6f : v=01 ' jno
   'case 0x6e73 : v=09 ' jns
   'case 0x6e63 : v=03 ' jnc   jae
   'case 0x6e65 : v=05 ' jne   jnz
  end select
  return v xor b
end function


function rexcode(int*v, w) as int
=================================
  int rex
  if v>=8
    v-=8
    rex or=1 'registers 8..15
  endif
  if w=8
    rex or=8         '64 bit reg
  endif
  return rex
end function


procedure pfx66(string*s, int*i)
================================
  if instr(s," 66")=0
    s=" 66"+s : i+=3
  endif
end procedure


function SegOverride(string*wd) as int
'=====================================
  int k
  if wd="cs"
    k=0x2e
  elseif wd="ss"
    k=0x36
  elseif wd="ds"
    k=0x3e
  elseif wd="es"
    k=0x26
  elseif wd="fs"
    k=0x64
  elseif wd="gs"
    k=0x65
  endif
  return k
end function



function streg(string*wd,*s, int*i) as int
==========================================
  int v
  '
  'ST0..ST7  ST0(0)..ST(7)
  '-----------------------
  '
  if lenw=3
    v=asc(wd,3)
    if (v>=48)and(v<=57)
      wd=left(wd,2) : v-=48
    endif
  elseif wd="st"
    if ascn=40
      i++  ' ignore (
      v=val(aword(s,i))
      if ascn=41
        i++ ' ignore )
      endif
    endif
  endif
  '
  if wd<>"st"
    ers="Expecting st(..)" : ert=16
  endif
  if (v<0)or(v>7)
    ers="Expecting range 0..7 " : ert=16
  endif
  return v
end function



function Assemble(string*s) as string
=====================================
'
' s    preprocessor source
' t    assembler output
' i    source index
' j    output index
' m    general match index
' n    general purpose
' q    calc index for opd
' v    general purpose
' w    general purpose
' a    ascii code
' b    general purpose
' c    encoding (in rg position)
' d    general purpose
' wd   word
' wr   word
' wt   word
' co   code
' nn   operand length (like wk)
' sb   shortform byte code
' l    general purpose length
' pm   main prefix code
' rex  rex prefix code or null
' dm   main instruction code
' qm   address mode code
' dn   3dnow postfix
' md   mod component
' rg   reg component
' rm   rm component
' di   direction component
' im   immediate encoding
' ic   immediate encoding (in rg postion)
' pn   operand encoding constraint flag
' sg   sign flag
' ws   word size encoding
' wk   register size as bytes (also specialised regs 129 130 131)
' wk1  first operand size (from wk)
' se   sign extension encoding/flag
' axdi eax direct shortform encoding
' axim eax immediate shortform encoding
' ima  supports immediate operand flag
' lw   length of operand bytes in relative jumps / calls
' flt  instruction  class : gpu/fpu/mmx/simd/other
' bs   fpu mem operand encoding
' pp   fpu stack operand encoding
' cp   fpu stack operand encoding
' ppf  fpu pop flag
' et   fpu extended number encoding (for 10 byte number formats)
' qt   fpu operand size flag 
' itf  fpu integer instruction
' ads  address offset string
' dss  data code string
' re   register identifier (mem)
' sc   sib scal 
' id   sib index
' ptf  pointer flag
' rtf  return instruction flag
' rmf  
' rsf  bitscan instruction flag
' dv   double precision number (set by wordeval)
' rgm  reg rm encoding
' gg   mmx granularity encoding
' pfx  prefic codes as string
' flot foating point literal flag
' ncm  no comment
' rip  RIP addressing (relative to instruction pointer)
' w1   general purpose string

' ersl errors list
' flos float encoding string
' flot float flag
' n3   secondop size (for rex)

'SIGNALS:

' flt=0 genereal instruction
' flt=1 fpu instruction
' flt=2 mmx instruction
' flt=3 xmmx instruction
' flt=4 general instruction without di and ws additions
' pn=0  undefined
' pn=1  single operand
' pn=2  2 operands
' pn=3  2 operands - the first must be a register
' pn=4  2 operands - the first is an r/m, the second must be a register
' pn=5  2 operands -  the first must be a register
' pn=6  2 operands - the first must be a mem, not a register
' pn=7  1 operand  - must be a mem
' pn=8  undefined
' pn=9  undefined
' pn=10 3 operands - the third must be an 8 bit value eg some xmmx instructions
' pn=11 3 operands - the third must be an 8 bit value or the cl register eg: shld shrd
' pn=12 1 2 or 3 operands - specific to imul
' pn=13 1 or 2 operand bit shift shl ror etc
' pn=14 first reg is general purpose, second reg is xmmx, rg and rm octals are swapped thus: md-rm-rg (PMOVMSKB)
' pn=15 r/m.xmm,imm8  (pextrb pextrw pextrd pextrq)

  int i,j,k,m,n,v,w,a,b,c,d
  string wd,wr,wp,wt,co,pfx
  int nn,sb,l,le
  int pm,rex,dm,qm,dn,lp
  int md,rg,rm,er,di,im,pn,sg,ws,wk,wk1,se
  int axim,axdi
  int ima,ic,lw
  int flt,bs,pp,cp,ppf,et,qt,itf
  int re,ds,sc,id,ptf,rtf,rmf,rsf,rgm,gg,flot,ncm,rip,fwd,n3

  string ads,dss,ersl,t,w1,flos,fnmks

  byte bb at strptr(s)-1


  le=len(s) : a=le+1000
  t=space(a)

  i=1
  j=1
  lct=1
  ert=0
  ers=""
  'pm=-1
  dm=-1
  qm=-1
  dn=-1
  lp=0
  wct=0

  '============
  do 'MAIN LOOP
  '============

  co=""
  pm=-1
  im=0
  di=0
  flt=0
  rsf=0
  pn=0
  flot=0
  rex=0
  rip=0
  fwd=0
  n3=0
  '
  'skip crlfs etc at beginning of line
  '
  do
    a=bb(i)
    select a
    case 0  : goto term
    case 10 : lct++
    case 9  : a=32
    case 58 : a=13
    case 33 to 255 : exit do
    end select
    i++
  loop
  '
  bgl=i
  '
  'CONSOLIDATED STACK POINTER ADJUSTMENT
  '=====================================
  '
  if a=hasa
    if mid(s,i+1,3)="sp "
      i+=4
      wr=stackpointadj(s,i)
      inserts(s,wr,i) : @bb=strptr(s)-1
      continue do
    endif
  endif
  '
  wr=aword(s,i)
  a=ascw
  '
  select a
  '
  '
  'VIEW MARKERS
  '============
  '
  case 35

  if wr="#view"
    vwb=j
  endif
  if wr="#endv"
    vwe=j+7
  endif
  continue do
  '
  '
  case 0x6f
  '
  if wr="o2"
    co=" "+captureblock(s,i,"")+cr
    goto addcode2
  endif
  '
  case 40
  '
  co=" "+wr : goto addcode
  '
  case 41
  '
  co=" "+wr : goto addcode
  '
  'LABELS
  '
  case 46
  '
  i=swd
  wr=aword(s,i)
  co=wr
  wr=""
  goto addcode1
  '
  case 0x65
  '
  if wr="exit"
    a=ascn
    if (a>48)and(a<58)
      co=" e9 x"+aword(s,i) : goto addcode
    endif
    co=" e9 xl" : goto addcode
  endif
  '
  case 0x72
  '
  if wr="repeat"
    co=" e9 rl" : goto addcode
  endif
  '
  case 39,59
  '
  'COMMENTS
  '========
  '
  if isc(a) ' ' ; comment
    if ascn=95
      swd+=2 : endline(s,i) : w1=mid(s,swd,i-swd) '_n
      if asc(w1)=34
        fnmks=w1
      else
        lnmks=w1
      endif
      co=mid(s,swd-2,i-swd+4)
      goto addcode2
    endif
    i=bgl : goto flush
  endif
  '
  end select
  '
  '
  md=0
  rg=0
  rm=0
  er=0
  sg=0
  ima=0
  ic=0
  sb=0
  d=len(wr)
  '
  '
  '=============
  'PASS THROUGHS
  '=============
  '
  'boundary spaces for instr searching
  wd=" "+wr+" "
  '
  m=0
  if a=0x64
    m=instr(" db dw dd dq ",wd) ' commas are optional
  endif
  if m>0
    do
      skiplspace(s,i)
      a=ascn
      if ise(a)
        goto addcode
      endif
      wordeval(s,i,i) : v=dv
      select m
      case 1  : co+=hexb(v)
      case 4  : co+=hexw(v)
      case 7  : co+=hexl(dv)
      case 10 : co+=" hq"+hex(dv) 'itr limited size
      end select
      do
        skiplspace(s,i)
        a=ascn
        if ise(a)
          goto addcode
        elseif (a=44)or(a<38)
          i++ : continue do
        else
          exit do
        endif
      loop
    loop
  endif
  '
  '
  'SPECIAL CASES
  '=============
  '
  m=instr(" ret in out outs outsb outsw outsd enter leave ",wd)
          '01  05 08  12   17    23    29    35    41    57
  if m>0
    if m=01
      rtf=1 : k=0
      a=ascl(s,i)
      if a=0x66
        wd=aword(s,i)
        if wd="far"
          k=8 : a=bb(i)
        endif
      endif
      if isx(a)=0
        wd=aword(s,i)
        wordeval(s,swd,i)
        if ert
          goto exita
        endif
        v=dv
        if v>0
          co=hexb(0xc2+k)+hexw(v) : goto addcode
        endif
      endif
      co=hexb(0xc3+k) : goto addcode
    endif
    '
    if m=05
      'IN al or eax, nn or dx 
      dm=0xe4' IN Input From Port  fixed port e4w : port number ' variable port ecw
      a=ascl(s,i)
      wd=aword(s,i)
      if wd="eax"
        dm++
      endif
      wd=aword(s,i) ' swallow comma
      wd=aword(s,i)
      ' no macro
      if wd="dx"
        dm+=8 : co=hexb(dm) : goto addcode
      endif
      wordeval(s,swd,i)
      if ert
        goto exita
      endif
      v=dv : co=hexb(dm)+hexb(v) : goto addcode
      goto addcode
    endif
    '
    if m=08
      ' OUT  nn or dx, eax or al 
      dm=0xe6 ' OUT to Port  fixed port e6w : port number ' variable port eew
      wd=aword(s,i)
      if wd="dx"
        dm+=8
        wd=aword(s,i) ' comma
        wd=aword(s,i)
        if wd="eax"
          dm++
        endif
        co=hexb(dm) : goto addcode
      endif
      '
      wordeval(s,swd,i)
      if ert
        goto exita
      endif
      wd=aword(s,i)
      wd=aword(s,i)
      if wd="eax"
        dm++
      endif
      v=dv : co=hexb(dm)+hexb(v) : goto addcode
    endif
    '
    if m=12
      co=" 6E" : goto addcode  ' OUTS  string Output to DX Port
    endif
    '
    if m=17
      co=" 6E" : goto addcode  ' OUTS  string Output to DX Port
    endif
    '
    if (m=23)or(m=29)
      co=" 6F" : goto addcode
    endif
    '
    if m=35  ' ENTER
      wordeval(s,i,i) : v=dv
      wd=aword(s,i) ' skip comma 
      wordeval(s,i,i)
      co=" C8"+hexw(v)+hexb(dv) : goto addcode
    endif
    '
    if m=41 ' LEAVE
      co=" C9" : goto addcode
    endif
    '
  endif 'special cases


  b=ascl(s,i)




  if m=77
    m=01
  endif

  'INSTRUCTIONS WITHOUT OPERANDS
  '=============================

  ' cbw   - convert byte to word
  ' cdq   - Convert Doubleword to Qword
  ' clc   - Clear Carry Flag
  ' cld   - clear direction flag
  ' cli   - Clear Direction Flag
  ' clts  - Clear Task-Switched Flag in CR0
  ' cmc   - Complement Carry Flag
  ' cpuid - CPU Identification
  ' cwd   - Convert Word to Doubleword
  ' cwde  - Convert Word to Doubleword
  ' daa   - Decimal Adjust AL after Addition 
  ' das   - Decimal Adjust AL after Subtraction 
  ' into  - Interrupt 4 on Overflow 
  ' invd - Invalidate Cache 
  ' iret / retd  Interrupt Return
  ' nop   - no operation
  ' lahf   - Load Status Flags into AH Register
  '
  ' popa / popad    Pop All General Registers
  ' popf / popfd    Pop Stack into FLAGS or EFLAGS Register
  ' pusha / pushad  Push All General Registers
  ' pushf / pushd   Push Flags Register onto the Stack
  ' rdmsr   Read from Model-Specific Register
  ' rdpmc   Read Performance Monitoring Counters
  ' rdtsc   Read Time-Stamp Counter 
  ' rsm     Resume from System Management Mode
  ' UD2  Undefined instruction 0000 FFFF : 0000 1011
  '
  ' sahf   - Store AH into Flags 
  ' sec     Set Carry Flag
  ' std     Set Direction Flag 
  ' sti     Set Interrupt Flag
  ' wait    Wait
  ' wbinvd  Writeback and Invalidate Data Cache
  ' wrmsr   Write to Model-Specific Register
  ' xlat    Table Look-up Translation            '
  ' stc     Set carry flag          '
  '
  ' LOCK  Assert LOCK# Signal Prefix 1111 0000
  ' LEAVE  High Level Procedure Exit 1100 1001
  ' HLT  Halt 1111 0100
  ' AAA  ASCII Adjust after Addition 0011 0111
  ' AAD  ASCII Adjust AX before Division 
  ' AAM  ASCII Adjust AX after Multiply 
  ' AAS  ASCII Adjust AL after Subtraction 
  ' SYSENTER
  ' SYSEXIT
  ' UD2 Undefined instruction


  'RELATIVE IMMEDIATE JUMPS AND CALLS
  '==================================

  m=0
  if (a=0x63)or(a=0x6a)
    m=instr( _
    " call jmp jz jnz jl jge jle jg jb jae jbe ja jo js jpe jpo jc je jnge jnl jng jnle jnae jnc jnb jna jnbe jno jns jnc jne ",wd)
    '01   06  10 13  
    'todo jc jnc
  endif
  if m=0
    goto Group_F
  endif
  '
  pn=1 : ws=0 : ima=0 : k=0
  wd=aword(s,i)
  '
  if m=1
    'call
    dm=0xff : bs=0xe8 : c=2 : lw=1
    if wd="far"
      c=3 : bs=0x9a : k=1 : wd=aword(s,i)
    endif
    goto jumpmode
  endif
  '
  if m<>6
    goto nucjumps
  endif
  '
  'jmp
  dm=0xff : bs=0xe9 : c=4 : lw=0
  if wd="far"
    c=5 : bs=0xea : k=1 : wd=aword(s,i)
  endif
  '
  jumpmode:
  '--------
  '
  if wd="["
    i=swd : goto mos
  endif
  v=regid(wd,wk)
  if v<0
    v=sregid(wd,wk)
  endif
  if v>=0
    i=swd : goto mos
  endif
  wordeval(s,swd,i)
  if nan=0
    ' immediate
    co=hexb(bs)+hexl(dv)
    if k=1
      ' far direct absolute
      i++ : wordeval(s,i,i) 'skip colon
      co+=hexw(dv)
    endif
    goto addcode
  endif
  wd=jword(s,swd,i,lw) ' long short
  if lw=0
    co=" EB"+wd : goto addcode ' short relative jump
  endif
  co=hexb(bs)+wd
  goto addcode ' long relative jump

  nucjumps: 'end of ucjumps
  =========
  '
  '
  'Conditional jumps
  '-----------------
  '
  v=regid(wd,nn)
  if (v>=0)or(wd="[")
    ers="must be a label" : ert=13 : goto exita
  endif
  '
  v=condi(wr,2)
  '
  if v>=0
    lw=0 : wd=jword(s,swd,i,lw)
    if lw
      co=" 0F"+hexb(0x80+v)+wd : goto addcode
    endif
    co=hexb(0x70+v)+wd : goto addcode
  endif
  '
  axdi=-1
  '
  '
  '=======
  Group_F:
  '=======
  '
  if a<>0x66
    goto Group_M
  endif
  '
  qt=4 : itf=0
  '
  if wr="fild"
    itf=5 ' 64 bit possible
  endif
  if wr="fistp"
    itf=7 ' 64 bit possible
  endif
    'FI INTEGER
    if instr(" fild fist fiadd fisub fimul fidiv fisubr fidivr fistp fimulp fidivp fidivrp ficom ficomp ",wd)
      qt=2 : wr="f"+mid(wr,3)
      endif
      ppf=0 : pp=0 'POP
      if instr(" fstp faddp fsubp fsubrp fmulp fdivp fdivrp fcomip fucomip fcomp"," "+wr)
        if right(wr,1)="p"
          ppf=1
          wr=left(wr,len(wr)-1)
        endif
      endif
      wd=" "+wr+" "
      m=instr(" fst fld fadd fsub fmul fdiv fsubr fdivr fcomi fucomi fcom fldt fstpt ",wd)
              '01  05  09   14   19   24   29    35    41    47     54
      if m>0 
        flt=1 : pn=1 : et=-1 : d=0
        if m=01
          if (ppf>0)and(qt=4)
            et=7  ' FST  Store Real
          endif
          dm=0xd9 : bs=0xdd : c=2 : d=-2 : pp=0xdd : cp=3
          if ppf>0
            ppf=0 : c++ ' fstp fistp
          endif
          goto fcode
        endif
        '
        if m=05
          if qt=4
            et=5
          endif
          dm=0xd9 : bs=0xd9 : c=0 : d=-3 : goto fcode ' FLD  Load Real
        endif
        '
        select m
        '-------
        case 09 : dm=0xd8 : bs=0xd8 : c=0 : pp=0xde : cp=0 : goto fcode  ' FADD   Add
        case 14 : dm=0xd8 : bs=0xd8 : c=4 : pp=0xde : cp=5 : goto fcode  ' FSUBP  Subtract and Pop 
        case 19 : dm=0xd8 : bs=0xd8 : c=1 : pp=0xde : cp=1 : goto fcode  ' FMUL   Multiply 
        case 24 : dm=0xd8 : bs=0xd8 : c=6 : pp=0xde : cp=7 : goto fcode  ' FDIV   Divide 
        case 29 : dm=0xd8 : bs=0xd8 : c=5 : pp=0xde : cp=4 : goto fcode  ' FSUBR  Reverse Subtract 
        case 35 : dm=0xd8 : bs=0xd8 : c=7 : pp=0xde : cp=6 : goto fcode  ' FDIVR  Reverse Divide 
        case 41 : dm=-1   : bs=0xdb : c=6 : pp=0xdf : cp=6 : goto fcode  ' FCOMI  Compare Real and Set EFLAGS db : c-r=6 st?
        case 47 : dm=-1   : bs=0xdb : c=5 : pp=0xdf : cp=5 : goto fcode  ' FUCOMI Compare Real unordered and Set EFLAGS db : c-r=6 st?
        case 54 : dm=0xd8 : bs=0xd8 : c=2 : pp=0xd8 : cp=3 : goto fcode  ' FCOM   Compare Real
        end select
        if wr="fldt"
          qt=4 : v=-1 : dm=0xd9 : et=5 : wd="eword" : goto memoperand
        endif
        if wr="fstpt"
          qt=4 : v=-1 : dm=0xd9 : et=7 : wd="eword" : goto memoperand
        endif
        'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
      endif
      '
      m=instr(" fxch fbld fbstp ffree fldcw fldenv fstcw fstenv fstsw fucom fucomp frstor fsave fnsave fnstcw fnstenv fnstsw fisttp ",wd)
              '01   06   11    17    23    29     36    42     49    55    61     68     75    81     88     95      103    110    117
      if m>0
        flt=1 : pn=1 : et=-1 : d=0
        select m
        '-------
        case 01  : dm=-1   : bs=0xd9 : c=1 :                  goto fcode  ' FXCH    Exchange st0 and st? d9 : c 1 st? 
        case 06  : dm=0xdf : bs=-1   : c=4 : et=0 :           goto fcode  ' FBLD    Load Binary Coded Decimal df : md-4-rm
        case 11  : dm=0xdf : bs=-1   : c=6 : et=0 :           goto fcode  ' FBSTP   Store Binary Coded Decimal and Pop df : md-6-rm
        case 17  : dm=-1   : bs=0xdd : c=0 :                  goto fcode  ' FFREE   Free st? Register dd : c 0 st? 
        case 23  : dm=0xd9 : bs=-1   : c=5 : qt=1 :           goto fcode  ' FLDCW   Load Control Word d9 : md-5-rm
        case 29  : dm=0xd9 : bs=-1   : c=4 : qt=1 :           goto fcode  ' FLDENV  Load FPU Environment d9 : md-4-rm
        case 36  : dm=0xd9 : bs=-1   : c=7 : qt=1 : pm=0x9b : goto fcode  ' FSTCW   Store Control Word d9 : md-7-rm
        case 42  : dm=0xd9 : bs=-1   : c=6 : qt=1 : pm=0x9b : goto fcode  ' FSTENV  Store FPU Environment d9 : md-6-rm
        case 49  : dm=0xdd : bs=-1   : c=7 : qt=1 : pm=0x9b : goto feax   ' FSTSW   Store Status Word into Memory dd : md-7-rm ' ax: df e0
        case 55  : dm=-1   : bs=0xdd : c=4 :                  goto fcode  ' FUCOM   Unordered Compare Real dd : e 0 st?
        case 61  : dm=-1   : bs=0xdd : c=5 :                  goto fcode  ' FUCOMP  Unordered Compare Real and Pop dd : e 1 st? 
        case 68  : dm=0xdd : bs=-1   : c=4 : qt=1 :           goto fcode  ' FRSTOR  Restore FPU state into Memory dd : md-4-rm ' ax: df e0
        case 75  : dm=0xdd : bs=-1   : c=6 : qt=1 : pm=0x9b : goto fcode  ' FSAVE   Store FPU state into Memory dd : md-4-rm ' ax: df e0
        case 81  : dm=0xdd : bs=-1   : c=6 : qt=1 :           goto fcode  ' FNSAVE  Store FPU state into Memory dd : md-4-rm ' ax: df e0
        case 88  : dm=0xd9 : bs=-1   : c=7 : qt=1 :           goto fcode  ' FNSTCW  Store Control Word d9 : md-7-rm
        case 95  : dm=0xd9 : bs=-1   : c=6 : qt=1 :           goto fcode  ' FNSTENV Store FPU Environment d9 : md-6-rm
        case 103 : dm=0xdd : bs=-1   : c=7 : qt=1 :           goto feax   ' FNSTSW  Store Status Word into Memory dd : md-1-rm 'df/db/dd
        case 110 :                     c=1 : qt=5 :           goto mos   ' FISTTP   Store integer with truncation ?? : md-7-rm ' ax : df e0 SSE3
        end select
        'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
  '
  '====
  feax:
  '====

        wd=aword(s,i)
        v=regid(wd,wk)
        if v=0
          if pm>=0
            co=hexb(pm)
          endif
          co+=" DF E0" : goto addcode
        endif
        i=swd : goto fcode
      endif
      '
      if left(wr,5)="fcmov"
        wp=" "+mid(wr,6)+" "
        m=instr(" b e be u nb ne nbe nu ",wp)' FCMOVcc  Conditional Move on EFLAG
        '1 3 5  8 10 13 16  20
        if m>0
          dm=-1 : d=0
          bs=0xda
          select m
          '-------
          case 01 : c=0 : goto fcode  ' fcmovb   -  move if below (B) da : c-0-st?
          case 03 : c=1 : goto fcode  ' fcmove   -  move if equal (E) da : c-1-st?
          case 05 : c=2 : goto fcode  ' fcmovbe  -  move if below or equal (BE) da : c-2-st?
          case 08 : c=3 : goto fcode  ' fcmovu   -  move if unordered (U) da : c-3-st?
          end select
          bs=0xdb  ' fcmov
          select m
          '-------
          case 10 : c=0 : goto fcode  ' fcmovnb  -  move if not below (NB) db : c-0-st?
          case 13 : c=1 : goto fcode  ' fcmovne  -  move if not equal (NE) db : c-1-st?
          case 16 : c=2 : goto fcode  ' fcmovnbe -  move if not below or equal (NBE) db : c-2-st?
          case 20 : c=3 : goto fcode  ' fcmovnu  -  move if not unordered (NU) db : c-3-st?
          end select
          'ers="Internal error : Misaligned "+wd : ert=19 : goto exita
        endif
      endif
      ' 
      if m=0
        goto Group_F1 ' fixed instructions
      endif
      '
      '
      '=====
      fcode:
      '=====
      '
      v=-1
      '
      'POPPING eg: fstp
      '
      if ppf
        dm=pp : c=cp
      endif
      '
      a=ascn
      '
      if isx(a)
        if ppf=0
          dm=bs
        endif
        co=hexb(dm)+hexb(0xc0+c*8+1) : goto addcode ' implicit operands
      endif
      '
      wd=aword(s,i)
      '
      if ascw=91
        goto memoperand
      endif
      '
      a=idword(" word dword qword eword single double extended ",wd)
      '
      if a
        if dm<0
          ers="Stack operands only st(0..7) " : ert=16 : goto exita
        endif
        goto memoperand
      endif
      '
      if bs<0
        ers="memory operands only [..] " : ert=16 : goto exita
      endif
      '
      if ppf=0
        dm=bs
      endif
      '
      v=streg(wd,s,i)
      if ert
        goto exita
      endif
      '
      if qt=2
        ers="FPU Integers use memory pointers, not stack regs" : ert=16 : goto exita
      endif
      '
      w=0 : skiplspace(s,i)
      '
      if ascn=44
        '
        w=v : v=-1 : i++ : wd=aword(s,i)
        '
        v=streg(wd,s,i)
        if ert
          goto exita
        endif
        '
        if v>w ' attempt storing from st(1).. to st(0)
          if d=-2
            ers="source must be st(0) dest st(0..7)" : ert=16 : goto exita
          endif
        endif
      endif
      '
      if (w>0)and(v>0)
        ers="one operand must be st(0)" : ert=16 : goto exita
      endif
      '
      if w>v
        if d=-3
          ers="Destination must be st(0) " : ert=16 : goto exita
        endif
        dm=dm or 4
        if c>1
          c=c or 1 ' swap source,dest
        endif
        qm=0xc0+c*8+w
      else
        qm=0xc0+c*8+v
      endif
      '
      co=hexb(dm)+hexb(qm) 
      goto addcode
      '
    '========
    Group_F1: 'FPU - no operands
    '========

    ' FABS     Absolute Value d9 : e1
    ' FCHS     Change Sign d9 : e0
    ' FLDZ     Load +0.0 into st0 d9 : ee
    ' FLD1     Load +1.0 into st0 d9 : e8
    ' FLDPI    Load p into st0 d9 : eb
    ' FSQRT    Square Root d9 : fa
    ' FSIN     Sine d9 : fe
    ' FCOS     Cosine of st0 d9 : ff
    ' FSINCOS  Sine and Cosine d9 : fb
    ' FPTAN    Partial Tangent d9 : f2
    ' FPATAN   Partial Arctangent d9 : f3

    ' FCLEX    Clear Exceptions db : e2
    ' FDECSTP  Decrement Stack-Top Pointer d9 : f6
    ' FINCSTP  Increment Stack Pointer d9 : f7
    ' FINIT    Initialize Floating-Point Unit db e3
    ' FNOP     No Operation d9 : d0
    ' FPREM    Partial Remainder d9 : f8
    ' FPREM1   Partial Remainder (IEEE) d9 : f5
    ' FRNDINT  Round to Integer d9 : fc
    ' FSCALE   Scale d9 : fd
    ' FSTSW    Store Status Word (to ax)
    ' FTST  Test d9 : e4
    ' FUCOMPP  Unordered Compare Real and Pop Twice da : e9
    ' FXAM     Examine d9 : e5
    ' FXTRACT  Extract Exponent and Significand d9 : f 4

    ' FCOMPP   Compare Real and Pop Twice de : c-3-1
    ' F2XM1    Compute 2ST(0)  1 d9 : f0
    ' FLDL2E   Load log2(e) into st0 d9 : ea
    ' FLDL2T   Load log2(10) into st0 d9 : e9
    ' FLDLG2   Load log10(2) into st0 d9 : ec
    ' FLDLN2   Load loge(2) into st0 d9 : ed
    ' FYL2X    st1  log2(ST(0)) d9 : f1
    ' FYL2XP1  st1  log2(ST(0) + 1.0) d9 : f9
    ' FWAIT
    '


  '=======
  Group_M:
  '=======



  'CPU INSTRUCTIONS WITH OPERANDS


  'GENERAL ARITHMETIC AND LOGIC


  m=instr(" mov inc dec push pop add sub mul div cmp and or xor test xchg movsx movzx ",wd)
          '01  05  09  13   18  22  26  30  34  38  42  46 49  53   58   63    69    75
  if m
    '
    select m
    '-------
    case 01 : pn=2 : dm=0x88 : im=0xc6 : ic=0 : ima=2 : axim=0xb0 : goto mos  ' mov
    case 05 : pn=1 : dm=0xfe : im=0    : c=0  : ima=0 :             goto mos  ' inc    ' sb=0x40 not 64 bit mode
    case 09 : pn=1 : dm=0xfe : im=0    : c=1  : ima=0 :             goto mos  ' dec    ' sb=0x48 not 64 bit mode
    case 13 : pn=1 : dm=0xff : im=0x68 : c=6  : ima=1 : sb=0x50 : ic=0 : goto mos ' push
    case 18 : pn=1 : dm=0x8f : im=0    : c=0  : ima=0 : sb=0x58   : goto mos  ' pop
    case 22 : pn=2 : dm=0x00 : im=0x80 : ic=0 : ima=1 :             goto mos  ' add
    case 26 : pn=2 : dm=0x28 : im=0x80 : ic=5 : ima=1 :             goto mos  ' sub
    case 38 : pn=2 : dm=0x38 : im=0x80 : ic=7 : ima=1 :             goto mos  ' cmp
    case 30 : pn=1 : dm=-1   : im=0    : c=4  : ima=1 : axdi=0xf6 : goto mos  ' mul
    case 34 : pn=1 : dm=-1   : im=0    : c=6  : ima=1 : axdi=0xf6 : goto mos  ' div
    case 42 : pn=2 : dm=0x20 : im=0x80 : ic=4 : ima=1 :             goto mos  ' and
    case 46 : pn=2 : dm=0x08 : im=0x80 : ic=1 : ima=1 :             goto mos  ' or
    case 49 : pn=2 : dm=0x30 : im=0x80 : ic=6 : ima=1 :             goto mos  ' xor
    case 53 : pn=2 : dm=0x84 : im=0xf6 : ic=0 : ima=2 :             goto mos  ' test (no di)
    case 58 : pn=2 : dm=0x86 : im=0    :        ima=0 : axdi=0x90 : goto mos  ' XCHG (no di) Exchange Register/Memory with mrm and AL/AX/EAX Register 90+reg
    case 63 : pn=3 : dm=0xbe : im=0    :        ima=0 : pm=0x0f   : goto mos  ' MOVSX Move with Sign-Extend
    case 69 : pn=3 : dm=0xb6 : im=0    :        ima=0 : pm=0x0f   : goto mos  ' MOVZX Move with Zero-Extend
    end select
    'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
  endif
  '
  m=instr(" neg not adc sbb imul idiv bound arpl bsf bsr ",wd)
          '01  05  09  13  17   22   27    33   38  42  46
  if m
    select m
    '-------
    case 01 : pn=1 : dm=0xf6 :             c=3              ' neg
    case 05 : pn=1 : dm=0xf6 :             c=2              ' not
    case 09 : pn=2 : dm=0x10 : im=0x80   : ic=2 : ima=1     ' adc
    case 13 : pn=2 : dm=0x18 : im=0x80   : ic=3 : ima=1     ' sbc
    case 17 : pn=12: dm=0xaf : im=0x69   : c=5  : axdi=0xf6 : ic=0x0 : ima=1 ' imul **** extra formats
    case 22 : pn=1 : dm=-1   : axdi=0xf6 : c=7  : ima=0     ' idiv
    case 27 : pn=3 : dm=0x62                                ' BOUND  Check Array Against Bounds
    case 33 : pn=4 : dm=0x63                                ' ARPL  Adjust RPL Field of Selector '+ws
    case 38 : pn=3 : dm=0xbc : pm=0x0f : rsf=4              ' BSF  Bit Scan Forward
    case 42 : pn=3 : dm=0xbd : pm=0x0f : rsf=4              ' BSR  Bit Scan Reverse
    end select
    'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
    goto mos
  endif
  '
  ' also extended modes 0f af mrm  mem imm to reg = 69 6b mrm dat
  '
  'BIT SHIFTING
  '============

  m=instr(" rcl rcr rol ror sal sar shl shr shld shrd ",wd)
          '01  05  09  13  17  21  25  29  33   38   43
  if m
    pn=13 : dm=0xd0 : im=0xc0 : ima=8
    if m=25
      m=17
    endif
    '
    select m
    '-------
    case 01 : c=2 : ic=2   ' RCL  Rotate thru Carry Left df by cl 8bit imm
    case 05 : c=3 : ic=3   ' RCR  Rotate thru Carry Right df by cl 8bit imm
    case 09 : c=0 : ic=0   ' ROL  Rotate Left  8bit imm
    case 13 : c=1 : ic=1   ' ROR  Rotate Right 8bit imm
    case 17 : c=4 : ic=4   ' SAL  Shift Left   8bit imm
    case 21 : c=7 : ic=7   ' SAR  Shift Right  8bit imm
    case 29 : c=5 : ic=5   ' SHR  Shift Right  8bit imm
    case 33 : c=0 : ic=0 : pn=11 : pm=0x0f : dm=0xa5 : im=0xa4   ' SHLD  Double Precision Shift Left
    case 38 : c=0 : ic=0 : pn=11 : pm=0x0f : dm=0xad : im=0xac : ' SHRD  Double Precision Shift Right
    end select
    'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
    goto mos
  endif

  'ITERATIVES
  '==========
  '
  m=instr(" jcxz jecxz loopz loope loopnz loopne loop ",wd)
          '01   06    12    18    24     31     38   43
  if m
    pn=0 : c=0 : rmf=3
    select m
    case 01 : dm=0xe3  ' JCXZ   ' Jump on CX/ECX Zero Address-size prefix differentiates JCXZ and JECXZ 1110 0011 : 8-bit displacement
    case 06 : dm=0xe3  ' JECXZ  ' Jump on CX/ECX Zero Address-size prefix differentiates JCXZ and JECXZ 1110 0011 : 8-bit displacement
    case 12 : dm=0xe1  ' LOOPZ  ' Loop Count while Zero/Equal 1110 0001 : 8-bit displacement
    case 18 : dm=0xe1  ' LOOPE  ' Loop Count while Zero/Equal 1110 0001 : 8-bit displacement
    case 24 : dm=0xe0  ' LOOPNZ ' Loop Count while not Zero/Equal 1110 0000 : 8-bit displacement
    case 31 : dm=0xe0  ' LOOPNE ' Loop Count while not Zero/Equal 1110 0000 : 8-bit displacement
    case 38 : dm=0xe2  ' LOOP   ' Loop Count 1110 0010 : 8-bit displacement
    end select
    'ers="Internal error: Misaligned "+wd : ert=19 : goto exita
    if ascl(s,i)=0x6c
      if wd="long"
        ers="Short jump only " : ert=15 : goto exita
      endif
    endif
    '
    if ascl(s,i)>0x40
      wd=aword(s,i)
      if wd="exit"
        wd="x"
      elseif wd="repeat"
        wd="r"
      else
        wd="g "+wd
      endif
    else
      wd="r"
    endif
    '
    co=hexb(dm)+" "+wd : goto addcode
    '
  endif

  v=instr(" rep repne repnz repe repz",wd)
          '01  05    11    17   22
  wp=wr    
  if v
    select v
    case 1  to 11 : pfx=" f3" : lp=3
    case 17 to 22 : pfx=" f2" : lp=3
    end select
    wp=aword(s,i) ' rep something
  endif
  l=len(wp) : b=asc(wp,l)
  ' b d m q signifying operand size
  if (b=0x62)or(b=0x64)or(b=0x77)or(b=0x71)
    l-- : wp=left(wp,l)
  endif
  if asc(wp,l)<>0x73
    goto nost
  endif
  if wd=" movsd "
    goto nost
  endif
  ws=1
  if b=0x62
    ws=0
  endif
  m=instr(" ins lods movs outs cmps stos scas  "," "+wp+" ")
          '01  05   10   15   20   25   30   35
  if m
    '
    select m
    case 01 : dm=0x6c  ' REP INS   Input String     f3 : 6cw
    case 05 : dm=0xac  ' REP LODS  Load String      f3 : acw
    case 10 : dm=0xa4  ' REP MOVS  Move String      f3 : a4w
    case 15 : dm=0x6e  ' REP OUTS  Output String    f3 : 6ew
    case 20 : dm=0xa6  ' REP CMPS  Compare String   f3 : a6w
    case 25 : dm=0xaa  ' REP STOS  Store String     f3 : aaw
    case 30 : dm=0xae  ' REP SCAS  Scan String      f3 : aew
    case else
    ers="expecting ins lods movs outs stos scas etc " : ert=15 : goto exita
    end select
    dm+=ws
    if b=0x74
      dm++                   'lodsd etc
    endif
    if b=0x77
      pfx=" 66"+pfx : lp+=3  'lodsw etc
    endif
    if b=0x71
      pfx+=" 48"    : lp+=3  'lodsq etc
    endif
    co=hexb(dm)
    goto addcode
  endif
  '
  '====
  nost:
  '====
  '
  if wr="int"
    wd=aword(s,i)
    v=val(wd)
    if v=3
      co=" CC" : goto addcode      ' INT 3
    endif
    co=" CD"+hexb(v) : goto addcode ' INT imm8
  endif




  'ima 1 8 or 16 bit data
  '    8 8  bit data only


  ' BT   Bit Test 
  ' BTC  Bit Test and Complement
  ' BTR  Bit Test and Reset
  ' BTS  Bit Test and Set
  ' XADD  Exchange and Add 0f c0w mrm
  '
  ' SGDT  Store Global Descriptor Table Register 0f:01:m0m
  ' SIDT  Store Interrupt Descriptor Table Register of:01:m1m
  ' SLDT  Store Local Descriptor Table Register mrm
  ' SMSW  Store Machine Status Word mxm
  ' STR   Store Task Register mxm
  ' VERR  Verify a Segment for Reading m4m
  ' VERW  Verify a Segment for Writing m5m
  ' CMPXCHG  Compare and Exchange
  ' CMPXCHG8B  Compare and Exchange 8 Bytes
  '
  '
  ' LDS   Load Pointer to DS
  ' LEA   Load Effective Address
  ' LES   Load Pointer to ES
  ' LAR   Load Access Rights Byte
  ' LFS   Load Pointer to FS
  ' LGDT  Load Global Descriptor Table Register
  ' LIDT  Load Global Descriptor Table Register
  ' LGS   Load Pointer to GS mrm
  ' LSL   Load Segment Limit
  ' LSS   Load Pointer to SS
  ' LTR   Load Task Register
  ' LLDT  Load Local Descriptor Table Register
  ' LMSW  Load Machine Status Word
 

  'MOV conditional
  '===============
  '
  if left(wr,4)="cmov"
    if asc(wr,5)>96
      v=condi(wr,5)
      if v>=0
        pn=2 : pm=0x0f : dm=0x40 : flt=4
        dm+=v
        goto mos
      endif
    endif
  endif
  '
  'm=instr(" cmovz cmovnz cmovl cmovge cmovle cmovg cmovb cmovae cmovbe cmova cmovo cmovno cmovs cmovns cmovpe cmovpo cmovc cmovnc cmove cmovne ",wd)
  'if m>0
  '  'cmovcc Byte Set on Condition '  register 0f:40+tttn : m0m
  '  '8 bit regs
  '  pn=2 : pm=0x0f : dm=0x40 : flt=4
  '  v=condi(wr,5)
  '  if v<0
  '    ers="Internal error: Misaligned "+wd : ert=19 : goto exita
  '  endif
  '  dm+=v
  '  goto mos
  'endif

  'SET conditional
  '===============
  '  
  if left(wr,3)="set"
    if asc(wr,4)>96
      v=condi(wr,4)
      if v>=0
        pn=1 : pm=0x0f : dm=0x90+v : c=0
        goto mos
      endif
    endif
  endif
  '
  'm=instr(" setz setnz setl setge setle setg setb setae setbe seta seto setno sets setns setpe setpo setc setnc sete setne ",wd)
  'if m>0
  '  'SETcc Byte Set on Condition '  register 0f:90+tttn : m0m
  '  '8 bit regs
  '  pn=1 : pm=0x0f : dm=0x90
  '  v=condi(wr,4)
  '  c=0
  '  'if v<0
  '  '  ers="Internal error: Misaligned "+wd : ert=19 : goto exita
  '  'endif
  '  dm+=v
  '  goto mos
  'endif



  'Prefix Bytes
  '
  'address size 0110 0111        '
  'LOCK 1111 0000                '
  'operand size 0110 0110        ' word
  '
  'CS segment override 0010 1110 ' seg CS
  'DS segment override 0011 1110 ' seg ds
  'ES segment override 0010 0110 ' seg es
  'FS segment override 0110 0100 ' seg fs
  'GS segment override 0110 0101 ' seg gs
  'SS segment override           '



  '=============
  'MMX ENCODINGS
  '=============
  '
  '
  if asc(wr)=0x70
    gg=0
    v=len(wr)
    wp=left(wr,v-1)
    m=instr(" padd padds paddus pcmpeq pcmpgt psll psra psrl psub psubs psubus punpckhb punpckhw punpckhd punpcklb punpcklw punpckld "," "+wp)
    if m>0
      a=asc(wr,v)
      k=-1
      select a
      case 0x62 : k=0 ' b
      case 0x77 : k=1 ' w
      case 0x64 : k=2 ' d
      case 0x71 : k=3 ' q ' psllq
      end select
      if k>=0
        gg=k
        wr=left(wr,v-1)
        wd=" "+wr+" "
      endif
    endif
  endif
  '
  '
  if d>3
    m=instr(" emms movd movq packssdw packsswb packuswb padd padds paddus pand pandn ",wd)
  '         '01   06   11   16       25       34       43   48    54     61   66    72
  endif
  if m>0
    pn=3
    pm=0x0f
    im=-1
    ' d=0 1 2 3
    ' qm= md-mmx-rm
    ' di +0x10 to mem
    ' immediate opts
    select m
    '-------
    case 01 : dm=0x77      ' EMMS      - Empty MMX state 
    case 06 : dm=0x6e : pn=2 ' MOVD      - Move doubleword:  mem to mx 0f:6e: mem from mx 0f:7e
    case 11 : dm=0x6f : pn=2 ' MOVQ      - Move quadword: mem to mx 0f:6f: mem from mx 0f:7f
    case 16 : dm=0x6b        ' PACKSSDW1 - Pack dword to word data (signed with saturation) memory to mx 0f:6b
    case 25 : dm=0x63        ' PACKSSWB1 - Pack word to byte data (signed with saturation):   memory to mx 0f:63
    case 34 : dm=0x67      ' PACKUSWB1 - Pack word to byte data (unsigned with saturation):   memory to mx 0f:67
    case 43 : dm=0xfc      ' PADD      - Add with wrap-around:   memory to mx 0f: fc+gg
    case 48 : dm=0xec      ' PADDS     - Add signed with saturation: memory to mx 0f: ec+gg
    case 54 : dm=0xdc      ' PADDUS    - Add unsigned with saturation: memory to mx 0f: dc+gg
    case 61 : dm=0xdb      ' PAND      - Bitwise And:   memory to mx 0f:db
    case 66 : dm=0xdf      ' PANDN     - Bitwise AndNot: mmxreg2 to mmxreg1 0f:bf:c-mx1-mx2:   memory to mx 0f:df
    end select
    'ers="Internal error: Misaligned MMX list1"+wd:ert=19: goto exita
    v=dm : dm+=gg : gg=0
    if v=0x77
      co=" 0F"+hexb(dm) : goto addcode ' check for junk
    endif
    flt=2 : goto mos
  endif
  '
  '
  m=instr(" pcmpeq pcmpgt pmaddwd pmulhw pmullw por psll psra psrl psub psubs psubus punpckhb punpckhw punpckhd punpcklb punpcklw punpckld pmulhuw pxor ",wd)
          '01     08     15      23     30     37  41   46   51   56   61    67     74       83      92        101     110       119      128     136  141
  if m>0
    pn=3
    pm=0x0f
    im=-1
    ' qm= md-mmx-rm
    select m
    '-------
    case 01  : dm=0x74              ' PCMPEQ  - Packed compare for equality: mx with memory 0f:74+gg
    case 08  : dm=0x64              ' PCMPGT  - Packed compare greater (signed):   mx with memory 0f:64+gg
    case 15  : dm=0xf5              ' PMADDWD - Packed multiply add: memory to mx 0f:f5
    case 23  : dm=0xe5              ' PMULHW  - Packed multiplication: memory to mx 0f:e5
    case 30  : dm=0xd5              ' PMULLW  - Packed multiplication: memory to mx 0f:d5
    case 37  : dm=0xeb              ' POR     - Bitwise Or:   memory to mx 0f:eb
    case 136 : dm=0xef              ' PXOR    - Bitwise Or:   memory to mx 0f:ef
    case 41  : dm=0xf0 : im=0x70 : ic=6 ' PSLL2   - Packed shift left logical: mx by memory 0f:f0+gg:md-mx-rm:  mx by immediate 0f:70+gg: c-6-mx: imm8 data
    case 46  : dm=0xe0 : im=0x70 : ic=4 ' PSRA2   - Packed shift right arithmetic: mx by memory 0f:e0+gg:md-mx-rm:  mx by immediate 0f:70+gg: c-4-mx: imm8 data
    case 51  : dm=0xd0 : im=0x70 : ic=2 ' PSRL2   - Packed shift right logical: mx by memory 0f:d0+gg:md-mx-rm :   mx by immediate 0f:70+gg: c-2-mx: imm8 data
    case 56  : dm=0xf8              ' PSUB    - Subtract with wraparound: memory from mx 0f:f8+gg
    case 61  : dm=0xe8              ' PSUBS   - Subtract signed with saturation: memory from mx 0f:e8+gg:md-mx-rm
    case 67  : dm=0xd8              ' PSUBUS  - Subtract unsigned with saturation: memory from mx 0f:d8+gg
    case 74  : dm=0x67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 83  : dm=0x67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 92  : dm=0x67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 101 : dm=0x5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 110 : dm=0x5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 119 : dm=0x5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 128 : dm=0xe4                     ' PMULHUW     - Packed Multiply High Unsigned : mm to mm 0f:e4:c-mm1-mm2 : mem to mm 0f:e4:md-mm-rm
    end select
    'ers="Internal error: Misaligned MMX list2"+wd : ert=19 : goto exita
    if im>=0
      im+=gg : ima=8 ' + 8bit data
    endif
    flt=2 : dm+=gg : gg=0 : goto mos
  endif
  '
  '
  'BSWAP
  '-----
  '
  if wr="bswap"
    wd=aword(s,i)
    v=regid(wd,wk)
    if (v>=0)and(wk=4)
      co=" 0F"+hexb(0xc8+v) : goto addcode
    endif
    ers="Expecting 16/32 bit rigister" : ert=16 : goto exita
  endif


'=======================================================================================================
' OPERAND PROCESSING
'=======================================================================================================


  '=====
  other:
  '=====

  'ops prefix codes
  'opd flags and opcodes
  wd=ltrim(rtrim(wd))
  v=lookupc(wr)
  if v<0
    ert=9 : ers="Unidentified instruction: "+wr : goto exita
  endif
  pfx=ops(v)
  lp=len(pfx)
  int q=v*opdw
  sys k=@opd(q)+8 'offset
  '
  'assume row major order (1st term>2nd term)
  '
  mov rdx,k
  mov eax,[rdx]
  mov flt,eax
  mov eax,[rdx+04]
  mov pn,eax
  mov eax,[rdx+08]
  mov dm,eax
  mov eax,[rdx+12]
  mov c, eax
  mov eax,[rdx+16]
  mov ima,eax
  mov eax,[rdx+20]
  mov im,eax
  mov eax,[edx+24]
  mov ic,eax
  mov eax,[rdx+28]
  mov dn,eax
  '
  if ima<1
    ima=0
  endif
  if (dm<0)and(ima<1)and(dn<0)
    goto addcode ' no operands expected
  endif
  ' otherwise procede to mos
        '
  '===
  mos:
  '===
  '
  do
    a=bb(i)
    if ise(a)
      if pn=1
        ers="missing operand" : ert=31 : goto exita
      endif
      ers="missing operands" : ert=31 : goto exita
    endif
    '
    wd=aword(s,i)
    '
    if wd="rip"
      rip=1     : continue do 'IP-RELATIVE ADDRESSING (64 BIT MODE ONLY)
    endif
    if wd="float"
      flot=1  : flos=" ns" :  continue do 'FLOATING POINT SINGLE
    endif
    if wd="double"
      flot=2 : flos=" nd" : continue do 'FLOATING POINT DOUBLE
    endif
    if wd="fwd"
      fwd=1     : continue do 'LOOK FORWARD ONLY
    endif
    exit do
  loop

  if ascn=38
    k=SegOverride(wd)
    if k
      pfx=hexb(k)+pfx
      lp+=3 : i++
      wd=aword(s,i)
    endif
  endif
  '
  a=ascn

  v=regid(wd,wk)

  if v>=0
    if wk=2
      if flt>0
        ers="Can't use 16 bit register here" : ert=12 : goto exita
      endif
      pfx66(pfx,lp)
      endif
      if flt=2
        ers="Can't use gp register with this mmx instruction" : ert=3 : goto exita
      endif
      if (flt=3)and(pn<>15)
        if (dm<>0x50)and(im<>0xc5)and(im<>0xc4)and(dm<>0xd7)
          ers="Can't use gp register with this simd instruction" : ert=3 : goto exita
        endif
      endif
    endif
    if v<0
      if pn=14
        ers="Expecting a general reg followed by mm? " : ert=11 : goto exita
    endif
    if flt>1 
      v=xmmxid(wd,wk)
    endif
    if (flt=0)and(v<0)and(lp=0)
      v=sregid(wd,wk) ' with di
      if dm=0x88 ' mov
        if wk=129
          flt=0 : dm=0x20 : pm=0x0f ' to cr
        endif
        if wk=130
          flt=0 : dm=0x21 : pm=0x0f ' to dr
        endif
        if wk=131
          flt=0 : dm=0x8c :         ' to segreg
        endif
      endif
      if sb=0x50 ' push
        if wk=131
          select v
          '-------
          case 3 : co=" 1e"   : goto addcode ' ds
          case 1 : co=" 0e"   : goto addcode ' cs
          case 0 : co=" 06"   : goto addcode ' es
          case 2 : co=" 16"   : goto addcode ' ss
          case 4 : co=" 0F A0": goto addcode ' fs
          case 5 : co=" 0F A8": goto addcode ' gs
          end select
        endif
      endif
      if sb=0x58 ' pop
        if wk=131
          select v
          '-------
          case 3 : co=" 1f"   : goto addcode ' ds
          case 0 : co=" 07"   : goto addcode ' es
          case 2 : co=" 17"   : goto addcode ' ss
          case 4 : co=" 0F A1": goto addcode ' fs
          case 5 : co=" 0F A9": goto addcode ' gs
          end select
        endif
      endif
    endif
  endif




  '========================
  'ACCUMULATOR - MEM to EAX
  '========================
  '
  if (axdi>=0)and(flt=0)
    if dm=-1
      dm=axdi : goto memoperand ' mul div idiv: imm
    endif
    if pn=12
      a=ascn
      if a<>44 ' single operand
        dm=axdi : pn=1 'mul imul
      else
        pm=0x0f : dm=0xaf : im=0x69 'imul
      endif
    endif
  endif



  '===================================
  memoperand: 'MEMORY AS FIRST OPERAND
  '===================================
  '
  if v<0
    'catch later
    if pn=5
      ers="Expecting a register" : ert=31 : goto exita
    endif
    ptf=0
    m=i
    wk=cpuw ' set as default: 4 for 32 bit mode, 8 for 64 bit mode
    a=0
    '
    if flt=1
      '
      '=========
      'FPU TYPES
      '=========
      '
      ptf=dic(" word 2, dword 4, qword 8, eword A, single 4, double 8, ext A, extended A, ",wd)
      select ptf
      case 2
        select qt
        case 1 : a=2
        case 2 : a=2 : dm+=6
        case 4 : ers="'word' not supported for float types" : ert=16 : goto exita
        case 5 : a=2 : dm=0xdf ' fisttp
        end select
      case 4
        a=4
        select qt
        case 2 : dm+=2 ' f integer
        case 5 : dm=0xdb ' fisttp
        end select
      case 8
        select qt
        case 4 : a=8 : dm+=4
        case 5 : a=8 : dm=0xdd ' fisttp
        case 2
          if itf=0
            ers=wd+" not supported here" : ert=16 : goto exita
          endif
          a=8 : dm+=6 : c=itf
        end select
      case 10
        if (et<0)or(qt=2)
          ers=wd+" not compatible here" : ert=16 : goto exita
        endif
        a=10
        if et>0
          dm+=2 : c=et ' otherwise bbld or fbstp
        endif
      end select
      '
      if (a=0)and(et<>0)and(qt<>1)
        ers="Expect FPU type: word,dword,qword,eword " : ert=16 : goto exita
      endif
      '
    elseif flt=0
      '
      '=========
      'CPU TYPES
      '=========
      '
      a=dic(" qword 8, dword 4, word 2, byte 1, ",wd)
      if a
        ptf=1
      endif
      if a=8
        rex or=8 'qword operand
      endif
      '
    elseif flt>1
      '
      '==========
      'SIMD TYPES
      '==========
      '
      if idword(" word dword qword eword ",wd) 
        ers="SIMD instructions have implicit operand sizes" : ert=31 : goto exita
      endif
      '
    endif
    '
    '======================
    'VALIDATED OPERAND TYPE
    '======================
    '
    if a
      wr=aword(s,m)
      if wr="ptr"
        i=m
      elseif wr="pointer"
        i=m
      endif
      wk=a
      wd=aword(s,i)
      if (pn<6)and(ascw<>91)
        v=regid(wd,k)
        if v>=0
          if (wk>1)and(pn>2)
            dm++
          endif
          if pm>-1
            goto op1reg 'movsx movzx
          endif
          if k<>a
            ers="wrong size for this register: "+wd : ert=31 : goto exita
          endif
          goto op1reg
        endif
      endif
    endif
    wk1=wk
    rg=c
    '
    '===============================
    'MEMORY OPERAND AS FIRST OPERAND
    '===============================

    if wd="["
      if pn=3
        select flt
        case 2 : ers="Expecting mmx1..7 register first" : ert=31 : goto exita
        case 3 : ers="Expecting xmm1..7 register first" : ert=31 : goto exita
        ers="Expecting register first" : ert=31 : goto exita
        end select
      endif
      if wk=2
        if flt=0
          pfx66(pfx,lp)
        endif
      endif
      di=0 : goto nextop
    endif
    '
    if flt=1
      ers="Expecting '[..]'" : ert=16 : goto exita
    endif
    select pn
    case 6 : ers="Expecting memory operand first [...],reg" : ert=31 : goto exita
    case 7 : ers="Expecting memory operand [...]" : ert=31 : goto exita
    end select
  endif
    '
    '
    '
    '==========================
    'IMMEDIATE AS FIRST OPERAND
    '==========================
    '
    if v<0
      if pn=3
        ers="Expecting register first " : ert=31 : goto exita
      endif
    endif
    '
    if (v<0)and(ima>0)
      if pn>1
       ers="Expecting  a register or [mem operand]" : ert=31 : goto exita
      endif
      wordeval(s,swd,i)
      if nan
        ers="Unidentified "+wd : ert=10 : goto exita
      endif
      v=dv
      if flot
        se=0 : co=flos+str(dv)
      else
        if (v<-128)or(v>127)
          se=0 : co=hexl(dv)
        else
          se=2 : co=hexb(v)
        endif
      endif
      '
      'PUSH
      '
      if im=0x68
        'immed push
        if wk=2
          w1=" 66" : co=hexw(v) : se=0
        else
          w1=""
        endif
        co=w1+hexb(im+se)+co : goto addcode
      else
        ers="This operand cannot be used in this position" : ert=10 : goto exita
      endif
    endif



    '=========================
    'REGISTER AS FIRST OPERAND
    '=========================



    '======
    op1reg:
    '======

    if v>=0
      if rexi
        rex=rexcode(v,wk)
      endif
      rg=v
      if sb>0
        if wk=2 '16bit data prefix
          w1=" 66"
        else
          w1=""
        endif
        if wk>=2
          co=w1+hexb(sb+rg) : goto addcode
        endif
        if (sb=0x50)or(sb=0x58)
          ers="byte push/pop not possible " : ert=11 : goto exita
        endif
      endif
      '
      if pn=1
        '
        'INC DEC
        '-------
        '
        if (wk>=1)and(wk<=8)
          if (wk>1)and(flt=0)
            dm or = 1
          endif
          if pm>=0
            co=hexb(pm)
          endif
          md=0xc0
          qm=md+c*8+rg
          co+=hexb(dm)+hexb(qm)
          goto addcode
        endif
        if co=""
          ers="Wrong operand size "+wd : ert=11 : goto exita
        endif
      endif
      '
      a=ascn
      '
      if a<>44
        if pn=13 'implicit  ,1 shift
          ws=0
          if wk>1
            ws=1
          endif
          co=hexb(dm+ws)+hexb(0xc0+c*8+rg)
          goto addcode
        endif
        ers= "Expecting comma and operand" : ert=10 : goto exita
      endif
      '
      i++ ' skip comma
      '
      wk1=wk
      if (flt=0)and(pn<3)
        if (dm<0x84)or(dm>0x87)
          di=2 'EXCLUDE 'TEST' AND 'EXCHANGE'
        endif
      endif
      '
      wd=aword(s,i)
      '
      if ascn=38
        k=SegOverride(wd)
        if k
          pfx=hexb(k)+pfx
          lp=3 : i++
          wd=aword(s,i)
        endif
      endif
      '
      a=ascn
      '
      if wd="["
        if wk>128
          wk=1 ' segregs etc
        endif
        select pn
        case 4
          ers="Second operand must be a register" : ert=15 : goto exita
        case 11 
          ers="operand 2 must be a register,operand 3 is cl or 8 bit value "
          ert=15 : goto exita
        end select
        goto nextop
      endif




      '==========================
      'REGISTER AS SECOND OPERAND
      '==========================

      rm=regid(wd,wk)

      if rm<0
        '
        'CHECK FOR OTHER KINDS OF REGISTERS
        '----------------------------------
        '
        if flt>1
          rm=xmmxid(wd,wk)
        endif
        if pn=14
          '
          'MOVMSKB
          '
          if rm>=0
            if rm>7
              rex or=4
            endif
            co=hexb(dm)+hexb(0xc0+rm*8+rg) : goto addcode ' swapped rm and rg positions
          endif
          ers="Expecting general reg then mm? " : ert=11 : goto exita
        endif
        '
        if pn=15
          'pextr
          if ascn<>44
            ers="Expecting 8 bit value as third operand" : ert=10 : goto exita
          endif
          i++ : wd=aword(s,i) : v=val(wd)
          if v>255
            ers="Expecting 8 bit value" : ert=10 : goto exita
          endif
          dm=im : co=hexb(0xc0+rm*8+rg)+hexb(v) : goto encode ' swapped rm and rg positions
        endif
      endif

      if (rm<0)and(dm=0x88)and(lp=0)
        rm=sregid(wd,wk)
        if rm>=0
          if wk1>=128
            ers="Expecting general purpose reg or mem [..]" : ert=16 : goto exita
          endif
          v=sregid(wd,wk) ' with di
          select wk
          case 129 : dm=0x20 : pm=0x0f ' from cr
          case 130 : dm=0x21 : pm=0x0f ' from  dr
          case 131 : dm=0x8c :         ' from segreg
          end select
          di=0
          swap rg,rm
        endif
      endif
      '
      '=============================
      'IF SECOND REGISTER IDENTIFIED
      '=============================
      '
      if rm>=0
        '
        if rexi
          a=rex
          if (a and 1)
            a+=3 'SHIFT B BIT TO R BIT
          endif
          rex=rexcode(rm,wk) or a
        endif
        '
        if pn=3
          if wk=2
            if pm>-1
              if (dm=0xb6)or(dm=0xbe)
                dm++ 'MOVZX MOVSX ... AX
              endif
            endif
          endif
        endif

        if (wk>128)or(wk1>128)
          wk=1 : wk1=1
        endif
        if (wk1<>wk)and(pn=2) 
          if flt=0
            if wk1=8 and wk=4
            else
              ers="Register size mismatch" : ert=31 : goto exita
            endif
          endif
        endif
        if (wk1<>4)and(wk1<>8)and(wk<>2)
          wk=1 '??
        endif
        if (rsf<>0)and(wk<>0)and(rsf<>wk)
          select rsf
          case 4 : ers="Not expecting 8 bit register" : ert=31 : goto exita
          case 1 : ers="Expecting 8 bit register" : ert=31 : goto exita
          end select
        endif
        '
        ' data register direct
        '
        if pn=13
          '
          if (rm<>1)and(wk<>1)
            ers="Expecting cl register or shift 1..64 " : ert=15
            goto exita
          endif
          di=2
          rm=rg : rg=c
         if wk1>1
           dm or= 1
         endif
         'itr AH BH CH DH not accessible in 64 bit mode eg: shr ??
        endif
        '
        '
        '=================================
        'CHECK FOR THIRD IMMEDIATE OPERAND
        '=================================
        '
        if (pn=10)or(pn=11)or(pn=12)or(pn=15)
          a=ascn
          if a<>44
            if pn=12
              co=hexb(0xc0+rg*8+rm)+co
              goto encode '2 operand form
            endif
            ers="Expecting third operand" : ert=16 : goto exita
          endif
          if pn=11
            swap rg,rm 'shld shrd
          endif
          i++
          wd=aword(s,i) : a=ascw
          wordeval(s,swd,i) : v=dv
          di=0 : wk=0
          '
          'number
          '
          if nan=0 
            dm=im
            if pn<>12
              co=hexb(v)
            else 'pn=12
              pm=-1
              if (v>=128)or(v<-128)
                dm=0x69
                if wk1=2
                  co=hexw(v)
                else
                  co=hexl(dv)
                endif
              else
                dm=0x6b : co=hexb(v)
              endif
            endif
          endif
          if nan
            if pn=10
              ers="Expecting an 8 bit value as third operand" : ert=16 : goto exita
            elseif wd<>"cl"
              ers="Expecting cl register " : ert=16 : goto exita
            endif
          endif
        endif 'THIRD OPERAND
        '
        md=0xc0
        dm+=di
        if (pn=4)and(wk>1)
          dm++
        endif
        qm=md+rg*8+rm
        co=hexb(qm)+co
        goto encode
      endif



      '===========================
      'IMMEDIATE AS SECOND OPERAND
      '===========================

      '======
      regimm:
      '======


      a=ascw
      if v<0
        if ima<1
          if(a>44)and(a<58)and(a<>47)
            ers="Not expecting a number here" : ert=31 : goto exita
          endif
        endif
      endif
      if ima>0

        if wk1=8
          rexi=1 : rex or=8
        endif

        ws=0 : se=0
        if a=35 '#'
          'load immediate address
          co=" "+wd
          '
          if wk1<4
            ers="#symbols only valid with 32+ bit regs" : ert=11 : goto exita
          endif 
          di=0 : dm=im : wk=wk1
          co=hexb(0xc0+ic*8+rg)+co
          goto encode
        endif
        '
        wordeval(s,swd,i)
        if ert
          goto exita
        endif
        '
        if nan
          if (a<>46)and(a<>45)and(a<>48)
            if wk1<4
              ers="label offsets only valid with 32 or 64 bit regs" : ert=11 : goto exita
            endif
            wk=wk1
            dm=im : co=hexb(0xc0+ic*8+rg)+" ga "+wd : goto encode
          endif
        endif
        '
        v=dv
        ws=0
        if (v<-128)or(v>255)
          ws=1 'REQUIRES LONG
        endif
        '
        if ws=0
          co=hexb(v)
        else
          co=hexl(dv)
        endif
        '
        '
        'REQUIRES BYTE
        '
        if (wk1=1)or(ima=8)
          if ws=1
            ers="Value out of range "+str(v) : ert=12
            goto exita
          endif
        endif
        '
        if (wk1>1)and(pn<3)
          ws=1 : se=2         'ASSUME BYTE
          if (v<-128)or(v>127)
            se=0              'REQUIRES LONG
          endif
          if ima=2
            se=0              'FORCE LONG
          endif
          '
          if flot=0
            if se=2
              co=hexb(v) 
            else
              if wk1=2
                co=hexw(v)
              elseif wk1>=4
                co=hexl(dv)
              endif
            endif
          else 'flot>0
            if wk>=4
              se=0 : co=flos+str(dv)
            else
              ers="float will not fit into register" : ert=12 : goto exita
            endif
          endif
        endif 'wk1>1 and pn<3
        if wk1=2
          if (dv>=bx16)or(dv<bxm15)
            ers="Value out of range for 16 bit number" : ert=10 : goto exita
          endif
        endif
        if flot=0
          if (wk1>=4)
            if (dv>=bx32)'or(dv<bxm31)
              if wk1=8
                dm=-1
                qm=0xb8+rg
                co=hexb(qm)+encodenum(s,i)
                goto addcode
              endif
              'ers="Value out of range for 32 bit number" : ert=10 : goto exita
            endif
          endif
        endif
        if pn=13 'shifts
          if (v<0)or(v>64)
            ers=" bit-shift value out of range 1..32/64 " : ert=14 : goto exita
          endif
          dm=im
          se=0
          if wk1>1
            ws=1
          endif
        endif
        md=0xc0
        if pn=12 'imul
          if im=0x69
            pm=-1
            dm=im+se
            qm=md+rg*8+rg
          else
            ers="immediate value not supported" : ert=15 : goto exita
          endif
        else 'pn<>12
          dm=im+se+ws
          qm=md+ic*8+rg
        endif
        co=hexb(qm)+co
        di=0
        wk=0
        goto encode
      endif
      if ascn<>91
        '
        'IF RIP THEN ASSUME TO BE LABEL
        '
        if rip
          if fwd
            w1=" gf "
          else
            w1=" gl "
          endif
          if (rex and 1)
            rex+=3
          endif
          co=hexb(rg*8+5)+w1+wd : goto encode
        endif
        '
        ers="Can't identify next operand ' " : ert=11 : goto exita
        '
      endif
      goto nextop
    endif ' end of reg as first operand







  '=================================
  'MEMORY AS FIRST OR SECOND OPERAND
  '=================================






  '======
  nextop:
  '======



  if (rex and 1)
    rex+=3 'SHIFT B BIT TO R BIT
  endif

  '-------------------
  ' [ebx+ecx*4+20],adx
  '-------------------


  if pn=14
    ers="Expecting reg,mmx not memory" : ert=11 : goto exita
  endif


  if wd="["

    ads="" : dss="" : se=0 : id=-1 : sc=-1 : bs=-1 : md=0


    '----------------------
    dreg1: ' FIRST REGISTER
    '======================

    wd=aword(s,i) : a=ascw
    if a=93
      ers="Empty [] " : ert=12 : goto exita
    endif
    '
    rm=regid(wd,nn)
    if rm<0
      rm=xmmxid(wd,nn)
        if rm<0
          rm=sregid(wd,nn)
        endif
        if rm>=0
          ers="mem operands require eax..edi registers" : ert=13 : goto exita
        endif
        '
        goto doffs 'OFFSET ONLY
        '
    endif
    '
    if nn=1
      ers="Need 32 bit register": ert=12 : goto exita
    endif
    '
    wd=aword(s,i)

    'REGISTER, INDEX OR OFFSET?
    '
    select ascw
    case 42   : id=rm : goto dscale 'THIS IS AN INDEX BUT NO BASE YET
    case 93   : goto dendbrak       'END OF OPERAND, SINGLE REG ONLY, MAY NOT REQUIRE SIB
    case 45   :
    case else : wd=aword(s,i)       'DROP THRU FOR REGISTER OR OFFSET
    end select


    '----------------------------------------------
    dreg2: 'OFFSET OR SECOND REGISTER REQUIRING SIB
    '==============================================

    re=regid(wd,nn)
    '
    if re<0
      re=xmmxid(wd,nn)
      if re<0
        re=sregid(wd,nn)
      endif
      if re>=0
        ers="mem operands require eax..edi registers" : ert=13
        goto exita
      endif
      '
      goto doffs 'ASSUME ITS AN OFFSET
      '
    endif
    '
    bs=rm 'FIRST REGISTER TO SIB BASE
    id=re 'SECOND REGISTER TO SIB INDEX

    '
    '======
    dreg2a:
    '======
    '
    if nn=1
      ers="Need 32bit register" : ert=12 : goto exita
    endif
    '
    wd=aword(s,i)
    select ascw
    case 42   : goto dscale               'MAY BE SCALED
    case 45   : goto doffs                'ITS AN OFFSET
    case 43   : wd=aword(s,i) : goto doffs 'ITS AN OFFSET
    case 93   : goto dendbrak             'END OF OPERAND
    case else : ers="Syntax error in memory operand" : ert=16 : goto exita
    end select



    '===========================================
    dscale: ' SCALE FOR FIRST OR SECOND REGISTER
    '===========================================


    '
    'CHECK IF SCALE ALREADY DEFINED
    '
    if sc>1
      ers="Only one register may be scaled" : ert=15 : goto exita
    endif
    '
    wd=aword(s,i)
    sc=val(wd) ' literal scale
    wd=aword(s,i)
    select ascw
    case 45
      goto doffs 'OFFSET FOLLOWS
    case 43
      wd=aword(s,i) : a=regid(wd,nn)
      if a>=0
        id=rm : bs=a : goto dreg2a 'SECOND REGISTER (SIB BASE) FOLLOWS SCALE
      endif
      goto doffs 'OFFSET FOLLOWS
    case else 
      goto dendbrak 'OTHERWISE NO OFFSET
    end select


    '==============
    doffs: ' OFFSET
    '==============

    wordeval(s,swd,i) : v=dv
    'i=swd : v=metaval(s,i,wd) ...
    'if nan
    '  ers="Expecting an offset value" : ert=12
    'endif
    if ert
      goto exita
    endif
    if (v>=-128)and(v<128)and(rm>=0)
      md=0x40 : ads=hexb(v)
    else
    'endif
    'if (v<-128)or(v>127)
      md=0x80 : ads=hexl(dv)
    endif
    wd=aword(s,i) ' expecting ']'


    '===============================
    dendbrak: 'END OF MEMORY OPERAND
    '===============================

    if ascw<>93
      ert=12: ers="Expecting  ']' " 
      goto exita
    endif
    if ascn<>44
      if pn=13
        if wk1>1
          dm or=1
        endif
      endif
      goto dexit ' dm the same. assume ,1 for single bit shift
    endif
    i++
    wd=aword(s,i)
    if (pn=1)or(di>0)
      ers="comma found, surplus operand" : ert=12
      goto exita
    endif



    '==============================
    secondop: ' A REGISTER OR VALUE
    '==============================

    v=regid(wd,wk) : n3=wk

    if v<0
      if flt>1 
        v=xmmxid(wd,wk)
        if v>=0
          ' reverse direction
          if (pn<>4)and(pn<>6)
            if flt=2
              dm+=16
            endif
            if flt=3
              dm++
            endif
          endif
          '
          if pn=15
            'pextr
            rg=v
            if ascn<>44
              ers="Expecting 8 bit value as third operand" : ert=10
              goto exita
            endif
            i++ : wd=aword(s,i) : wordeval(s,swd,i) : v=dv
            if (v>255)or(nan=1)
              ers="Expecting 8 bit value" : ert=10
              goto exita
            endif
            dm=im : dss=hexb(v) : goto dexit
          endif
        endif
      endif
      '
      if v<0
        if (pn=4)and(ima<1)
          ers="Second operand must be a register" : ert=15
          goto exita
        endif
        if pn=11
          ers="Operand 2 must be a register, Op 3 is either cl or 8 bit value" : ert=15
          goto exita
        endif
      endif
      ' 
      if (pn=10)or(pn=12)or(pn=15)
        'third operand
        wordeval(s,swd,i) : v=dv
        if ert
          goto exita
        endif
        ws=0 : wk=0
        if nan=0
          if pn=12
            pm=-1
            if (v>=128)or(v<-128)
              dm=0x69 : dss=hexl(dv)
            else
              dm=0x6b : dss=hexb(v)
            endif
            goto dexit
          endif
          dm=im : dss=hexb(v) : goto dexit
        endif
        ers="Expecting an 8 bit value as third operand" : ert=16 : goto exita
      endif
      '
      if (v<0)and(flt=0)and(dm=0x88)and(lp=0)
        v=sregid(wd,wk)
        if v>=0
          if wk=131
            dm=0x8c : wk=1 : wk1=1 ' from segreg
          endif
          if (wk=129)or(wk=130)
            ers="These registers move to general purpose  regs only" : ert=16
            goto exita
          endif
        endif
      endif
    endif
    '
    if v>=0
      '
      if (v>=8)and(v<=15)
        a=rexcode(v,wk)
        if (a and 1)
          a+=3 'SHIFT B BIT TO R BIT
        endif
        rex or=a
      endif
      '
      if wk=2
        pfx66(pfx,lp)
        if flt>1
          ers="Cant use a 16 bit register here":ert=12
          goto exita
        endif
      endif
      'allow this
      'if ptf
      '  if ima<>8
      '    ers=" word size is determined by register " : ert=13 : goto exita
      '  endif
      'endif
      if pn=13
        if (v<>1)and(wk<>1)
          ers="Expecting cl register or shift 1..64 " : ert=15
          goto exita
        endif
        wk=wk1
        if wk>1
          dm++
        endif
        di=2
        rg=c
        goto dexit
      endif
      rg=v
      wk1=wk
      '
      if (pn=10)or(pn=11)
        a=ascn
        if a<>44
          ers="Expecting third operand" : ert=16
          goto exita
        endif
        i++
        wd=aword(s,i) : a=ascw
        wordeval(s,swd,i) : v=dv
        ws=0 : wk=0
        if nan=0
          dm=im : dss=hexb(v) : goto dexit
        elseif pn=11
          if wd<>"cl"
            ers="Expecting cl register (or 8 bit shift value)" : ert=16
            goto exita
          endif
        endif
        goto dexit
      endif
      '
      if (pn=4)and(wk>1)
        dm++
      endif
      goto dexit
    endif

    '=======
    immedop:
    '=======

    if ima<1
      ers="Must be a register " : ert=12 : goto exita
    endif

    if wk1=8
      rexi=1 : rex or=8
    endif

    a=ascw

    if a=35
      dss=" "+wd
      if wk1<4
        ers="#symbols only valid with 32+ bit operands" : ert=11 : goto exita
      endif
      ws=1 : dm=im+ws : rg=ic : goto dexit
    endif

    wordeval(s,swd,i) : if ert
      goto exita
    endif
    v=dv

    if nan
      if wk1<4
        ers="label offsets only valid with 32+ bit operands" : ert=11 : goto exita
      endif
      rg=ic : ws=1 : dm=im+ws : dss=" ga "+wd
      goto dexit
    endif

    ws=0:se=0
    if (wk1=1)or(ima=8)
      if (ws=1)or(a=35)
        ers="Value out of range " : ert=12 : goto exita
      endif
      co=hexb(v)
    endif

    if wk1=2
      if (dv>=bx16)or(dv<bxm15)
        ers="Value out of range for 16 bit number" : ert=10 : goto exita
      endif
    endif
    '
    if wk1=4
      if flot=0
        if (dv>=bx32)or(dv<bxm31)
          ers="Value out of range for 32 bit number" : ert=10 : goto exita
        endif
      endif
    endif

    rg=ic
    '
    if (wk1>1)and(pn<3)
      ws=1 : se=2 ' assume byte sign extended
      if (v<-128)or(v>127)
        se=0 ' long
      endif
      if ima=2
        se=0
      endif
      if se=2
        co=hexb(v) 'byte
      elseif se=0
        if wk1=2
          co=hexw(v)
        elseif wk1>=4
          if flot=0
            co=hexl(dv)
          else
            co=flos+str(dv)
          endif
        endif
      endif
    endif
    '
    if (wk1=8)and(cpuw=4)
      ers="Invalid ptr size: qword" : ert=13 : goto exita
    endif
    '
    if wk1=10
      ers="Invalid ptr size: eword" : ert=13 : goto exita
    endif

    if pn=13
      if (v<0)or(v>64)
        ers=" bit-shift value out of range 1..32/64 " : ert=14 : goto exita
      endif
      ws=0
      if wk1>1
        ws=1
      endif
      dss=hexb(v) : dm=im+ws : goto dexit
    endif

    ' assume immediate value
    dss=co
    dm=im+ws+se
    '
    '=====
    dexit:
    '=====
    '
    'CHECK FOR FURTHER OPERANDS
    '--------------------------
    '
    a=ascn
    if a=44
      ers="Too many operands for this instruction" : ert=10 : goto exita
    endif
    '
    '
    'DIRECTION OF ASSIGNMENT OTHER THAN 'TEST' AND 'XCHG'
    '----------------------------------------------------
    '
    if (di=2)and(flt=0)
      if (dm<0x84)or(dm>0x87)
        dm+=2 'is a first op with a reg source
      endif
    endif
    '
    '
    'CHECK IF A SIB IS REQUIRED:
    '---------------------------
    '
    if (bs>=0)or(id>=0)
      rm=-2 'SIGNAL EXPLICIT SIB ENCODING TO FOLLOW
    endif
    '
    w1="" 'POTENTIAL SIB BYTE
    '
    '
    'RM IS ESP AND THEREFORE REQUIRES SIB ENCODING
    '---------------------------------------------
    '
    if rm=4
      bs=4 : rm=-2 'MAKE USE OF SIB BASE (AND NULL THE INDEX REG)
    endif

    '
    'NON SIB EBP MUST HAVE AN OFFSET
    '-------------------------------
    '
    if rm=05
      if md=0
        md=0x40 : ads=" 00"
      endif
      goto nsib
    endif
    '
    '
    'OFFSET ONLY: (64BIT MODE COMPATIBLE)
    '------------------------------------
    '
    if (md>0)and(rm=-1)
      '
      'RIP OR ABSOLUTE ADDRESSING
      '
      if rip
        '
        '64 BIT CPU MODE ONLY
        '
        ert=144 : ers="RIP Addressing inappropriate here." : goto exita
        '
      else 'NON RIP ADDRESSES
        '
        'MAKE USE OF SIB FOR OFFSET-ONLY ADDRESSING
        '
        'THIS IS COMPATIBLE WITH BOTH 32 AND 64 BIT MODE
        '
        md=0 : rm=4 : w1=hexb(0x25) : goto nsib
        '
      endif
    endif
    '
    '
    'SIB ENCODING PROCEDURE
    '======================
    '
    if rm=-2
      '
      if (bs>=0)or(id>=0)
        '
        'ESP IN THE INDEX FIELD MUST BE MOVED
        '------------------------------------
        '
        if id=4
          if sc>1
            ers="Cant have scaled ESP/RSP/R12 " : ert=12 : goto exita
          elseif (bs<>4)and(sc<=1)
            swap id,bs 'IF THE SCALE IS 1 THEN BASE AND INDEX CAN BE SWAPPED
          else 
            ers="Cant have ESP as both index and base in SIB" : ert=13 : goto exita
          endif
        endif
      endif
      '
      '
      'SIB BASE EBP MUST HAVE AN OFFSET
      '--------------------------------
      '
      if bs=5
        if id=5
          ers="Cant have EBP as both index and base in SIB" : ert=13 : goto exita
        elseif ((id<0)or(sc<=1))and(md=0)
          swap bs,id 'EBP CAN BE SWAPPED INTO THE INDEX FIELD
        elseif md=0
          md=0x40 : ads=" 00" 'ADD A NULL OFFSET
        endif
      endif
      '
      'NO SIB INDEX REG SPECIFIED
      '--------------------------
      ' 
      if id<0
        id=4 'CODING FOR NO INDEX
      endif
      '
      '
      'INDEX  BUT NO BASE
      '------------------
      '
      'MUST HAVE 32 BIT DISPLACEMENT
      '
      if bs<0
        if md=0
          ads=" 00 00 00 00"  'MUST SPECIFY DISPLACEMENT
        endif
        if md=0x40
          ads+=" 00 00 00" 'MUST BE 32 BIT DISPLACEMENT
        endif
        md=0 : bs=5                      'CODING FOR NO BASE BUT 32 DISPLACEMENT
      endif
      '
      '
      'SCALE ENCODING
      '---------------
      '
      select sc
      case -1     : sc=0
      case 1      : sc=0
      case 2      : sc=0x40
      case 4      : sc=0x80
      case 8      : sc=0xc0
      case else   : ers="Invalid scale (1 2 4 8): "+str(sc) : ert=12 : goto exita
      end select
      '
      '
      'COMPOSE REX FOR SIB REGISTERS
      '-----------------------------
      '
      if id>=8
        id-=8 : rex or=2 'EXTENDED INDEX REG
      endif
      if bs>=8
        bs-=8 : rex or=1 'EXTENDED BASE REG
      endif
      '
      'COMPOSE SIB
      '-----------
      '
      
      rm=4 : w1=hexb(sc+id*8+bs)
      '
    endif
    '
    '=====================
    nsib: 'COMPOSE OPCODES
    '=====================
    '
    if rm>=8
      rm-=8 : rex or=1 'EXTENDED RM REG
    endif
    if n3=8
      rex or=8
    endif
    co=hexb(md+rg*8+rm)+w1+ads+dss
    goto encode
    '
  endif   ' ....]

  '---------------
  'end of operands
  '---------------


  '======
  encode:
  '======

  if (flt=0)and(pn<3)and(wk>1)
    dm=dm or 1 ' word size ' alt pn<5
  endif
  if (co="")and(lp=0)
    ers="Unidentified Operand or none" : ert=12 : goto exita
  endif
  '
  co=hexb(dm)+co
  '
  if pm>=0
    co=hexb(pm)+co : pm=-1
  endif
  if dn>=0
    co+=hexb(dn) : dn=-1 '3dnow postfix
  endif


  '=======
  addcode:
  '=======
  '
  if rex
    rex or=0x40
    a=asc(pfx,2)
    if a>=0x36 'prefix code 6n or above
      pfx=left(pfx,3)+hexb(rex)+mid(pfx,4)
    else
      pfx=hexb(rex)+pfx
    endif
    rex=0
    lp+=3
  endif
  '
  if lp
    co=pfx+co
    pfx="" : lp=0
  endif
  '
  '
  ' now check for uninterpreted stuff
  '
  if not co
    if pn>0
      ers="Unresolved operand type "+wd : ert=15 : goto exita
    endif
  endif

  '=====
  flush:
  '=====

  '------------------------
  'CODE VERIFICATION SYSTEM
  '------------------------
  '
  ' correct opcodes are contained in the comment using prefix !? 
  ' eg : ; !? b0 2a
  '
  skiplspace(s,i)
  select ascn
  case 0 to 13
    goto nverifyop
  case 58
    i++ : skiplspace(s,i) : goto nverifyop
  case 39
  case 59
  case else
    co+=aword(s,i) 'supporting op labels
    'j-=len(co)
    'ers="Junk after instruction: "+mid(s,bgl,i-bgl)+cr'+">>"+co
    'ert=200 : goto exita
  end select
  m=0 : b=len(co)+1 : k=0 : c=i : i++
  do
    select bb(i)
    case 0 to 13
      exit do
    case 33 '!'
      if m=1
        i++ : a=bb(i)
        if a=63
          m=2 : b=1 : i++ : continue do
        endif
      endif
      endline(s,i) : exit do
    case 34 to 255
      if m=2
        'compare code with commented code
        wd=aword(s,i)
        v=val("0x"+wd)
        wd=aword(co,b)
        if val("0x"+wd)=v
          continue do
        endif
        k=1 : endline(s,i) : exit do 'DISAGREE k
      endif
    end select
    i++
  loop
  if (k=1)or(b<=len(co))
    co+=" ;!! "
  endif
  '
  nverifyop:
  


  '======================
  'ADDITIONS TO CODE LINE
  '======================

  '========
  addcode1: 'ADD CODE LINE DIRECT
  '========

  if vew=0
    wr=cr ' EXCLUDE COMMENTS
  endif
  '
  'APPEND COMMENTS
  '---------------
  '
  if vew>0
    '
    'APPEND CLIPPED COMMENTS
    '-----------------------
    '
    a=i-bgl
    if a>64
      a=64 ' clip src comment
    endif
    if ncm
      a=0 ' NO COMMENT
    endif
    '
    'PAD ASSEMBLY CODE TO 32 CHARS
    '-----------------------------
    '
    wr=space(32-len(co))+chr(ct1)+"  "+mid(s,bgl,a)+cr ' append source as comment

    'BLANK OUT TABS,CR,LF ETC INSIDE COMMENT
    '---------------------------------------
    v=0
    m=len(wr)-2
    do
      v++
      if v>m
        exit do
      endif
      a=asc(wr,v)
      if a=9
        a=32 ' tab ignore
      endif
      if a<32
        mid(wr,v)=" "
      endif
    loop
    ncm=0
  endif
  '
  'ADJUST SIZE OF BUFFER IF NECESSARY
  '----------------------------------
  '
  co+=wr
  '
  '========
  addcode2:
  '========
  a=len(t)
  b=len(co)
  if j+b>a
    t+=space(b+0x10000)
  endif
  '
  'APPEND LINE OF CODE
  '-------------------
  '
  mid(t,j)=co : j+=b ' add code

  '=====
  exita:
  '=====
    
  '
  'CHECK FOR ERROR MESSAGES
  '------------------------
  '
  if ert>0
    '
    '
    'CAPTURE REST OF CURRENT LINE
    '----------------------------
    '
    v=i : endline(s,i)
    '
    'COMPLETE ERROR MESSAGE
    '----------------------
    '
    ers="ASSEMBLER:"+cr+
    " ERROR:"+htb+mid(s,bgl,i-bgl)+"!!  "+ers+cr
    if lnmks
      ers+="COL:"+htb+"1"+cr
      ers+="LINE:"+htb+lnmks+cr
    endif
    if fnmks
      ers+="FILE:"+htb+fnmks+cr
    endif

    ersl+=ers+cr 'BUILD ERRORS LIST
    '
    'DECIDE MODAL BEHAVIOUR
    '----------------------
    '
    if vew<2
      i=k 
      exit do ' STOP ASSEMBLY NOW
    endif
    if vew>=2
      mid(t,j)=ers
      j+=len(ers) ' ADD ERROR MESSAGE AS COMMENT THEN CONTINUE
    endif
    '
    'CHECK BUFFER SPACE
    '------------------
    '
    a=len(t) : b=len(ers)
    if j+b>a
      t+=space(b+4000)
    endif
    '
    'ADD ERROR MESSAGE
    '-----------------
    '
    mid(t,j)=ers : j+=b



    '==============================
    'CLEARDOWN FOR NEXT INSTRUCTION
    '==============================
    '

    ert=0 : ers=""
    pm=-1 : dm=-1 : qm=-1 : dn=-1 : lp=0 : pfx=""
    endif


  loop ' main loop
  '
  '======
  'FINISH
  '======

  term:

  ers=ersl : ersl=""


  'if (ert=0)and(rtf=0)
  '  ers="Missing ret" : ert=20
  'endif
  '
  t=left(t,j-1)
  '
  if vew>0
    if vwb
      if vwe=0
        vwe=j
      endif
      t=mid(t,vwb,vwe-vwb)
    endif
  endif
  '
  if ert=0
    if not t
      ers="Empty" : ert=10
    endif
  endif
  '
  if ert>0
    if vew=0
      t="c3"
    endif
  endif


  '===========
  'DIAGNOSTICS
  '===========
  '
  'putfile("t.txt","ASSEMBLED:"+cr+t)

  return t
  '
end function


