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


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




opcode_data:



' cpu no operands

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

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

' fpu no operands

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

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

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

' other cpu



' FORMAT:
'-------------------------------------
' flt pn `prefix codes` b1 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)

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

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

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

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

'---
'sse
'===

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

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

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

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

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


'sse2 extended: double precision
'--------------------------------
data "addpd      3 3 ` 66 0f` 58"
data "addsd      3 3 ` f2 0f` 58"
data "andnpd     3 3 ` 66 0f` 55"
data "andpd      3 3 ` 66 0f` 54"
data "cmppd      3 a ` 66 0f` - - 8 c2 0"
data "cmpsd      3 a ` f2 0f` - - 8 c2 0"
data "comisd     3 3 ` 66 0f` 2f"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

data "crc32      4 3 ` f2 0f 38` f0 0"

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

data "pcmpgtq     3 4 ` 66 0f 38` 37"

'SSE4.2 included

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


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

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

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

' caxhe management

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

data "!end!"





'------------
sub loadops()
'============
dim as sys a,i,j,k,v,f,n
dim as sys t,u,uu,tal
dim as string s,wd
'f=freefile: err=0
'open mdl_path+"oxygenlib\o2asm.data" for input as f
'if err then ers="Problem accessing o2asm.data": ert=9: exit sub
restore opcode_data
ope=0
n=512
init4 @opd(0,0),9000,-1
do
  'if eof(f) then exit do
  'line input #f, s
  read s
  i=1
  wd=aword(s,i): a=ascw
  if a=33 then exit do '!end!'
  if isc(a) then continue do ' comment
  if wd="" then continue do
  'v=hashcode(wd)
  dim as byte ptr p=strptr(wd)
  asm
  mov edx,&h35db53bd
  mov ecx,[p]
  rhashcode4:
  mov al,[ecx]
  cmp al,0
  jz nhashcode4
  rol edx,1
  xor dl,al
  inc ecx
  jmp rhashcode4
  nhashcode4:
  mov [v],edx
  end asm
'
ope=v and 511
  'print wd,ope
  u+=1
  if len(opn(ope))>0 then
    'print "Chain: "+wd
     uu+=1
     t=0
     do
       'print "link",opn(ope)
       if opd(ope,1)=-1 then opd(ope,1)=n:ope=n:n+=1:exit do
       t+=1: if t>tal then tal=t
       ope=opd(ope,1)
     loop
     if n>999 then ers="Too many instruction definitions":ert=9:ope=0: exit sub
   end if
   opn(ope)=wd
   opd(ope,0)=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 b1
   ' k=5 c
   ' k=6 ima
   ' k=7 im
   ' k=8 ic
   ' k=9 dn
   k=1
   do
     k+=1: if k>9 then exit do
     wd=aword(s,i): a=ascw
     if a<=13 then exit do
     if isq(a) then k-=1:ops(ope)=mid(wd,2,len(wd)-2):continue do
     if a=43 then wd=aword(s,i):k=9:a=ascw '3dnow postfix code
     if a=45 then continue do ' leave default -1
     if isc(a) then exit do ' comment
     opd(ope,k)=wval("&h"+wd)
   loop
loop
' coincidence check
'------------------
'i=-1
'do
'  i+=1:if i>=n then exit do
'  j=opd(i,1): if j=-1 then continue do ' not links
'  do
'    if opd(i,0)=opd(j,0) then
'      ert=9:ers="!! instruction hash not unique: "+opn(i)+" "+opn(j)+" "+hexci(opd(j,0))
'      'messagebox 0,ers,"Coincidence check",0
'      exit sub 
'    end if
'    j=opd(j,1) ' next in chain
'    if j=-1 then exit do
'  loop
'loop
'------------------
''print "Extra ",n-512
' messagebox 0, str(tal)+" "+str(u)+" "+str(uu),"Maxlinks",0
' ert=9:ers="error test"
end sub





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



'--------------------------------------------------------
function condi(byref wr as string, byref i as sys) as sys
'========================================================
  dim as sys m, v, b, e
  if asc(wr,i)=&h6e then
    i+=1 'skip n
    b=1 'opposite flag
  end if
  v=-1
  e=len(wr)
  if (e>i+2)or(e<i) then return -1
  m=asc(wr,i)*256+asc(wr,i+1)
  select case m
    case &h7a00 : v=04 ' jz   je
    case &h6c00 : v=12 ' jl        jnge
    case &h6765 : v=13 ' jge       jnl
    case &h6c65 : v=14 ' jle       jng
    case &h6700 : v=15 ' jg        jnle
    case &h6200 : v=02 ' jb    jc  jnae
    case &h6165 : v=03 ' jae   jnc jnb
    case &h6265 : v=06 ' jbe       jna
    case &h6100 : v=07 ' ja        jnbe
    case &h6f00 : v=00 ' jo
    case &h7300 : v=08 ' js
    case &h7065 : v=10 ' jpe
    case &h706f : v=11 ' jpo
    case &h6300 : v=02 ' jc    jb
    case &h6500 : v=04 ' je    jz
   '------------------------------
   'case &h6e7a : v=05 ' jnz   jne
   'case &h6e6f : v=01 ' jno
   'case &h6e73 : v=09 ' jns
   'case &h6e63 : v=03 ' jnc   jae
   'case &h6e65 : v=05 ' jne   jnz
  end select
  function=v xor b
end function

'------------------------------------------------------
function rexcode(byref v as sys, byval w as sys) as sys
'======================================================
  dim as sys rex
  if v>=8 then
    v-=8
    rex or=1 'registers 8..15
  end if
  if w=8 then
    rex or=8         '64 bit reg
  end if
  return rex
end function


'----------------------------------------------
sub pfx66(byref pfx as string, byref lp as sys)
'==============================================
  if instr(pfx," 66")=0 then pfx=" 66"+pfx : lp+=3
end sub

'----------------------------------------------
function SegOverride(byref wd as string) as sys
'==============================================
  dim as sys k
  if wd="cs" then
    k=&h2e
  elseif wd="ss" then
    k=&h36
  elseif wd="ds" then
    k=&h3e
  elseif wd="es" then
    k=&h26
  elseif wd="fs" then
    k=&h64
  elseif wd="gs" then
    k=&h65
  end if
  function=k
end function


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



'---------------------------------------------
function Assemble(byref s as string) as string
'=============================================
'
' s    preprocessor source
' t    assembler output
' i    source index
' j    output index
' m    general match index
' n    general purpose
' 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
' b0   main prefix code
' rex  rex prefix code or null
' b1   main instruction code
' b2   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 wordval)
' 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 then swapped thus: md-rm-rg (PMOVMSKB)
' pn=15 r/m.xmm,imm8  (pextrb pextrw pextrd pextrq)

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

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


  'LOAD ASSEMBLy CODE TABLES
  '=========================

  if ope=0 then
    loadops() ' loads assembler once when required
    if ert>0 then ope=0: goto exita
  end if


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

  i=1
  j=1
  lct=1
  ert=0
  ers=""
  'b0=-1
  b1=-1
  b2=-1
  dn=-1
  lp=0

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

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

  if wr="#view" then vwb=j
  if wr="#endv" then vwe=j+7
  continue do
  '
  'case &h61
  '
  if wr="asm" then continue do ' ignore
  '
  'ALIGNMENT
  '=========
  '
  'if wr="align" then
  'co=" !"+aword(s,i): goto addcode
  'end if
  '
  case &h73
  '
  if wr="skip" then ' only occurs when vew=2 >> no oxygen
    capture(s,m,i,a): co=" ": goto addcode
  end if
  '
  case &h6f
  '
  if wr="o2" then
    co=captureblock(s,i,"")+cr
    goto addcode2
  end if
  '
  case 40
  '
  co=" "+wr: goto addcode
  '
  case 41
  '
  co=" "+wr: goto addcode
  '
  'LABELS
  '
  case 46
  '
  if i-swd=1 then
    wr="."+aword(s,i)
  end if
  lbw=wr
  co=wr
  wr=""
  goto addcode1
  '
  case &h65
  '
  if wr="exit" then
    a=ascn
    if (a>48)and(a<58) then co=" e9 x"+aword(s,i): goto addcode
    co=" e9 xl": goto addcode
  end if
  '
  case &h6e
  '
  if wr="namespace" then
    co=" k "
    if ise(ascn)=0 then co+=aword(s,i)
    goto addcode
  end if
  '
  case &h72
  '
  if wr="repeat" then co=" e9 rl": goto addcode
  '
  case 39 to 59
  '
  'COMMENTS
  '========
  '
  if isc(a) then ' ' ; comment
    if ascn=95 then swd+=2 : endline(s,i) : w1=mid(s,swd,i-swd) '_n
    if asc(w1)>&h40 then fnmks=w1 else lnmks=w1
    i=bgl: goto flush
  end if
  '
  end select
  '
  '
  md=0
  rg=0
  rm=0
  er=0
  sg=0
  ima=0
  ic=0
  sb=0
  d=len(wr)
  '
  '
  '=============
  'PASS THROUGHS
  '=============
  '
  wd=" "+wr+" "
  '
  m=0 : if a=&h64 then  m=instr(" db dw dd dq ",wd) ' commas are optional
  if m>0 then
    do
      skiplspace(s,i)
      a=ascn
      if ise(a) then goto addcode
      wordeval(s,i,i):v=dv
      select case 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) then
          goto addcode
        elseif (a=44)or(a<38) then
          i+=1 : continue do
        else
          exit do
        end if
      loop
    loop
  end if
  '
  '
  '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 then
    if m=01 then
      rtf=1:k=0
      a=ascl(s,i)
      if a=&h66 then wd=aword(s,i): if wd="far" then k=8:a=asc(s,i)
      if isx(a)=0 then
        wd=aword(s,i)
        wordeval(s,swd,i): if ert then goto exita
        v=dv: if v>0 then co=hexb(&hc2+k)+hexw(v): goto addcode
      end if
      co=hexb(&hc3+k): goto addcode
    end if
    '
    if m=05 then
      'IN al or eax, nn or dx 
      b1=&he4' IN Input From Port  fixed port e4w : port number ' variable port ecw
      a=ascl(s,i)
      wd=aword(s,i)
      if wd="eax" then b1+=1
      wd=aword(s,i) ' swallow comma
      wd=aword(s,i)
      ' no macro
      if wd="dx" then b1+=8:co=hexb(b1): goto addcode
      wordeval(s,swd,i): if ert then goto exita
      v=dv: co=hexb(b1)+hexb(v): goto addcode
      goto addcode
    end if
    '
    if m=08 then
      ' OUT  nn or dx, eax or al 
      b1=&he6 ' OUT to Port  fixed port e6w : port number ' variable port eew
      wd=aword(s,i)
      if wd="dx" then
        b1+=8
        wd=aword(s,i) ' comma
        wd=aword(s,i)
        if wd="eax" then b1+=1
        co=hexb(b1): goto addcode
      end if
      '
      wordeval(s,swd,i): if ert then goto exita
      wd=aword(s,i)
      wd=aword(s,i)
      if wd="eax" then b1+=1
      v=dv:co=hexb(b1)+hexb(v): goto addcode
    end if
    '
    if m=12 then
      co=" 6E": goto addcode  ' OUTS  string Output to DX Port
    end if
    '
    if m=17 then
      co=" 6E": goto addcode  ' OUTS  string Output to DX Port
    end if
    '
    if (m=23)or(m=29) then
      co=" 6F": goto addcode
    end if
    '
    if m=35  then ' 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
    end if
    '
    if m=41 then ' LEAVE
      co=" C9": goto addcode
    end if
    '
  end if 'special cases


  b=ascl(s,i)




  if m=77 then m=01

  '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=&h63)or(a=&h6a) then 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
  '
  if m=0 then goto Group_F
  '
  pn=1 : ws=0 : ima=0 : k=0
  wd=aword(s,i)
  '
  if m=1 then
    'call
    b1=&hff : bs=&he8 : c=2 : lw=1
    if wd="far" then
      c=3:bs=&h9a : k=1 : wd=aword(s,i)
    end if
    goto jumpmode
  end if
  '
  if m=6 then
    'jmp
    b1=&hff : bs=&he9 : c=4 : lw=0
    if wd="far" then
      c=5 : bs=&hea : k=1 : wd=aword(s,i)
    end if
    '
    jumpmode:
    '--------
    '
    if wd="[" then i=swd: goto mos
    v=regid(wd,wk)
    if v<0 then v=sregid(wd,wk)
    if v>=0 then i=swd: goto mos
    wordeval(s,swd,i)
    if nan=0 then
      ' immediate
      co=hexb(bs)+hexl(dv)
      if k=1 then
        ' far direct absolute
        i+=1:wordeval(s,i,i) 'skip colon
        co+=hexw(dv)
      end if
      goto addcode
    end if
    wd=jword(s,swd,i,lw) ' long short
    if lw=0 then co=" EB"+wd: goto addcode ' short relative jump
    co=hexb(bs)+wd
    goto addcode ' long relative jump
  end if
  '
  '
  'Conditional jumps
  '-----------------
  '
  v=regid(wd,nn)
  if (v>=0)or(wd="[") then ers="must be a label":ert=13: goto exita
  '
  v=condi(wr,2)
  '
  if v>=0 then
    lw=0:wd=jword(s,swd,i,lw)
    if lw then co=" 0F"+hexb(&h80+v)+wd: goto addcode
    co=hexb(&h70+v)+wd: goto addcode
  end if
  '
  axdi=-1
  '
  '
  '=======
  Group_F:
  '=======
  '
  if a<>&h66 then goto Group_M
  '
  qt=4 : itf=0
  '
  if wr="fild"  then itf=5 ' 64 bit possible
  if wr="fistp" then itf=7 ' 64 bit possible
    'FI INTEGER
    if instr(" fild fist fiadd fisub fimul fidiv fisubr fidivr fistp fimulp fidivp fidivrp ficom ficomp ",wd) then
      qt=2: wr="f"+mid(wr,3)
      end if
      ppf=0:pp=0 'POP
      if instr(" fstp faddp fsubp fsubrp fmulp fdivp fdivrp fcomip fucomip fcomp"," "+wr) then
        if right(wr,1)="p" then ppf=1: wr=left(wr,len(wr)-1)
      end if
      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 then 
        flt=1:pn=1:et=-1:d=0
        if m=01 then
          if (ppf>0)and(qt=4) then et=7  ' FST  Store Real
          b1=&hd9 : bs=&hdd : c=2 : d=-2 : pp=&hdd : cp=3
          if ppf>0 then ppf=0:c+=1 ' fstp fistp
          goto fcode
        end if
        '
        if m=05 then
          if qt=4 then et=5
          b1=&hd9 : bs=&hd9 : c=0 : d=-3 : goto fcode ' FLD  Load Real
        end if
        '
        select case m
        '------------
        case 09 : b1=&hd8 : bs=&hd8 : c=0 : pp=&hde : cp=0 : goto fcode  ' FADD   Add
        case 14 : b1=&hd8 : bs=&hd8 : c=4 : pp=&hde : cp=5 : goto fcode  ' FSUBP  Subtract and Pop 
        case 19 : b1=&hd8 : bs=&hd8 : c=1 : pp=&hde : cp=1 : goto fcode  ' FMUL   Multiply 
        case 24 : b1=&hd8 : bs=&hd8 : c=6 : pp=&hde : cp=7 : goto fcode  ' FDIV   Divide 
        case 29 : b1=&hd8 : bs=&hd8 : c=5 : pp=&hde : cp=4 : goto fcode  ' FSUBR  Reverse Subtract 
        case 35 : b1=&hd8 : bs=&hd8 : c=7 : pp=&hde : cp=6 : goto fcode  ' FDIVR  Reverse Divide 
        case 41 : b1=-1   : bs=&hdb : c=6 : pp=&hdf : cp=6 : goto fcode  ' FCOMI  Compare Real and Set EFLAGS db:c-r=6 st?
        case 47 : b1=-1   : bs=&hdb : c=5 : pp=&hdf : cp=5 : goto fcode  ' FUCOMI Compare Real unordered and Set EFLAGS db:c-r=6 st?
        case 54 : b1=&hd8 : bs=&hd8 : c=2 : pp=&hd8 : cp=3 : goto fcode  ' FCOM   Compare Real
        end select
        if wr="fldt"  then qt=4 : v=-1 : b1=&hd9 : et=5 : wd="eword" : goto memoperand
        if wr="fstpt" then qt=4 : v=-1 : b1=&hd9 : et=7 : wd="eword" : goto memoperand
        'ers="Internal error: Misaligned "+wd : ert=19: goto exita
      end if
      '
      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 then
        flt=1 : pn=1 : et=-1 : d=0
        select case m
        '------------
        case 01  : b1=-1   : bs=&hd9 : c=1 :                  goto fcode  ' FXCH    Exchange st0 and st? d9:c 1 st? 
        case 06  : b1=&hdf : bs=-1   : c=4 : et=0 :           goto fcode  ' FBLD    Load Binary Coded Decimal df:md-4-rm
        case 11  : b1=&hdf : bs=-1   : c=6 : et=0 :           goto fcode  ' FBSTP   Store Binary Coded Decimal and Pop df:md-6-rm
        case 17  : b1=-1   : bs=&hdd : c=0 :                  goto fcode  ' FFREE   Free st? Register dd:c 0 st? 
        case 23  : b1=&hd9 : bs=-1   : c=5 : qt=1 :           goto fcode  ' FLDCW   Load Control Word d9:md-5-rm
        case 29  : b1=&hd9 : bs=-1   : c=4 : qt=1 :           goto fcode  ' FLDENV  Load FPU Environment d9:md-4-rm
        case 36  : b1=&hd9 : bs=-1   : c=7 : qt=1 : b0=&h9b : goto fcode  ' FSTCW   Store Control Word d9:md-7-rm
        case 42  : b1=&hd9 : bs=-1   : c=6 : qt=1 : b0=&h9b : goto fcode  ' FSTENV  Store FPU Environment d9:md-6-rm
        case 49  : b1=&hdd : bs=-1   : c=7 : qt=1 : b0=&h9b : goto feax   ' FSTSW   Store Status Word into Memory dd:md-7-rm ' ax: df e0
        case 55  : b1=-1   : bs=&hdd : c=4 :                  goto fcode  ' FUCOM   Unordered Compare Real dd:e 0 st?
        case 61  : b1=-1   : bs=&hdd : c=5 :                  goto fcode  ' FUCOMP  Unordered Compare Real and Pop dd:e 1 st? 
        case 68  : b1=&hdd : bs=-1   : c=4 : qt=1 :           goto fcode  ' FRSTOR  Restore FPU state into Memory dd:md-4-rm ' ax: df e0
        case 75  : b1=&hdd : bs=-1   : c=6 : qt=1 : b0=&h9b : goto fcode  ' FSAVE   Store FPU state into Memory dd:md-4-rm ' ax: df e0
        case 81  : b1=&hdd : bs=-1   : c=6 : qt=1 :           goto fcode  ' FNSAVE  Store FPU state into Memory dd:md-4-rm ' ax: df e0
        case 88  : b1=&hd9 : bs=-1   : c=7 : qt=1 :           goto fcode  ' FNSTCW  Store Control Word d9:md-7-rm
        case 95  : b1=&hd9 : bs=-1   : c=6 : qt=1 :           goto fcode  ' FNSTENV Store FPU Environment d9:md-6-rm
        case 103 : b1=&hdd : 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 then
          if b0>=0 then co=hexb(b0)
          co+=" DF E0": goto addcode
        end if
        i=swd: goto fcode
      end if
      '
      if left(wr,5)="fcmov" then
        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 then
          b1=-1:d=0
          bs=&hda
          select case 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=&hdb  ' fcmov
          select case 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
        end if
      end if
      ' 
      if m=0 then goto Group_F1 ' fixed instructions
      '
      '
      '=====
      fcode:
      '=====
      '
      v=-1
      '
      'POPPING eg: fstp
      '
      if ppf then
        b1=pp : c=cp
      end if
      '
      a=ascn
      '
      if isx(a) then
        if ppf=0 then b1=bs
        co=hexb(b1)+hexb(&hc0+c*8+1): goto addcode ' implicit operands
      end if
      '
      wd=aword(s,i)
      '
      if ascw=91 then goto memoperand
      '
      a=instrword(" word dword qword eword single double extended ",wd)
      '
      if a then
        if b1<0 then ers="Stack operands only st(0..7) ":ert=16: goto exita
        goto memoperand
      end if
      '
      if bs<0 then ers="memory operands only [..] ":ert=16: goto exita
      '
      if ppf=0 then b1=bs
      '
      v=streg(wd,s,i) : if ert then goto exita
      '
      if qt=2 then ers="FPU Integers use memory pointers, not stack regs" : ert=16 : goto exita
      '
      w=0 : skiplspace(s,i)
      '
      if ascn=44 then
        '
        w=v : v=-1 : i+=1 : wd=aword(s,i)
        '
        v=streg(wd,s,i) : if ert then goto exita
        '
        if v>w then ' attempt storing from st(1).. to st(0)
          if d=-2 then ers="source must be st(0) dest st(0..7)":ert=16: goto exita
        end if
      end if
      '
      if (w>0)and(v>0) then ers="one operand must be st(0)":ert=16: goto exita
      '
      if (w>v) then
        if d=-3 then ers="Destination must be st(0) ":ert=16: goto exita
        b1=b1 or 4
        if c>1 then c=c or 1 ' swap source,dest
        b2=&hc0+c*8+w
      else
        b2=&hc0+c*8+v
      end if
      '
      co=hexb(b1)+hexb(b2) 
      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 then
    '
    select case m
    '------------
    case 01 : pn=2 : b1=&h88 : im=&hc6 : ic=0 : ima=2 : axim=&hb0 : goto mos  ' mov
    case 05 : pn=1 : b1=&hfe : im=0    : c=0  : ima=0 :             goto mos  ' inc    ' sb=&h40 not 64 bit mode
    case 09 : pn=1 : b1=&hfe : im=0    : c=1  : ima=0 :             goto mos  ' dec    ' sb=&h48 not 64 bit mode
    case 13 : pn=1 : b1=&hff : im=&h68 : c=6  : ima=1 : sb=&h50 : ic=0 : goto mos ' push
    case 18 : pn=1 : b1=&h8f : im=0    : c=0  : ima=0 : sb=&h58   : goto mos  ' pop
    case 22 : pn=2 : b1=&h00 : im=&h80 : ic=0 : ima=1 :             goto mos  ' add
    case 26 : pn=2 : b1=&h28 : im=&h80 : ic=5 : ima=1 :             goto mos  ' sub
    case 38 : pn=2 : b1=&h38 : im=&h80 : ic=7 : ima=1 :             goto mos  ' cmp
    case 30 : pn=1 : b1=-1   : im=0    : c=4  : ima=1 : axdi=&hf6 : goto mos  ' mul
    case 34 : pn=1 : b1=-1   : im=0    : c=6  : ima=1 : axdi=&hf6 : goto mos  ' div
    case 42 : pn=2 : b1=&h20 : im=&h80 : ic=4 : ima=1 :             goto mos  ' and
    case 46 : pn=2 : b1=&h08 : im=&h80 : ic=1 : ima=1 :             goto mos  ' or
    case 49 : pn=2 : b1=&h30 : im=&h80 : ic=6 : ima=1 :             goto mos  ' xor
    case 53 : pn=2 : b1=&h84 : im=&hf6 : ic=0 : ima=2 :             goto mos  ' test (no di)
    case 58 : pn=2 : b1=&h86 : im=0    :        ima=0 : axdi=&h90 : goto mos  ' XCHG (no di) Exchange Register/Memory with mrm and AL/AX/EAX Register 90+reg
    case 63 : pn=3 : b1=&hbe : im=0    :        ima=0 : b0=&h0f   : goto mos  ' MOVSX Move with Sign-Extend
    case 69 : pn=3 : b1=&hb6 : im=0    :        ima=0 : b0=&h0f   : goto mos  ' MOVZX Move with Zero-Extend
    end select
    'ers="Internal error: Misaligned "+wd:ert=19: goto exita
  end if
  '
  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 then
    select case m
    '------------
    case 01 : pn=1 : b1=&hf6 :             c=3              ' neg
    case 05 : pn=1 : b1=&hf6 :             c=2              ' not
    case 09 : pn=2 : b1=&h10 : im=&h80   : ic=2 : ima=1     ' adc
    case 13 : pn=2 : b1=&h18 : im=&h80   : ic=3 : ima=1     ' sbc
    case 17 : pn=12: b1=&haf : im=&h69   : c=5  : axdi=&hf6 : ic=&h0 : ima=1 ' imul **** extra formats
    case 22 : pn=1 : b1=-1   : axdi=&hf6 : c=7  : ima=0     ' idiv
    case 27 : pn=3 : b1=&h62                                ' BOUND  Check Array Against Bounds
    case 33 : pn=4 : b1=&h63                                ' ARPL  Adjust RPL Field of Selector '+ws
    case 38 : pn=3 : b1=&hbc : b0=&h0f : rsf=4              ' BSF  Bit Scan Forward
    case 42 : pn=3 : b1=&hbd : b0=&h0f : rsf=4              ' BSR  Bit Scan Reverse
    end select
    'ers="Internal error: Misaligned "+wd:ert=19: goto exita
    goto mos
  end if
  '
  ' 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 then
    pn=13 : b1=&hd0 : im=&hc0 : ima=8
    if m=25 then m=17
    '
    select case 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 : b0=&h0f : b1=&ha5 : im=&ha4   ' SHLD  Double Precision Shift Left
    case 38 : c=0 : ic=0 : pn=11 : b0=&h0f : b1=&had : im=&hac : ' SHRD  Double Precision Shift Right
    end select
    'ers="Internal error: Misaligned "+wd:ert=19: goto exita
    goto mos
  end if

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

  v=instr(" rep repne repnz repe repz",wd)
          '01  05    11    17   22
  wp=wr    
  if v then
    select case 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
  end if
  l=len(wp) : b=asc(wp,l)
  ' b d m q signifying operand size
  if (b=&h62)or(b=&h64)or(b=&h77)or(b=&h71) then l-=1 : wp=left(wp,l)
  if asc(wp,l)<>&h73 then goto nost
  if wd=" movsd " then goto nost
  ws=1
  if b=&h62 then ws=0
  m=instr(" ins lods movs outs cmps stos scas  "," "+wp+" ")
          '01  05   10   15   20   25   30   35
  if m then
    '
    select case m
    case 01 : b1=&h6c  ' REP INS   Input String     f3 : 6cw
    case 05 : b1=&hac  ' REP LODS  Load String      f3 : acw
    case 10 : b1=&ha4  ' REP MOVS  Move String      f3 : a4w
    case 15 : b1=&h6e  ' REP OUTS  Output String    f3 : 6ew
    case 20 : b1=&ha6  ' REP CMPS  Compare String   f3 : a6w
    case 25 : b1=&haa  ' REP STOS  Store String     f3 : aaw
    case 30 : b1=&hae  ' REP SCAS  Scan String      f3 : aew
    case else
    ers="expecting ins lods movs outs stos scas etc ":ert=15: goto exita
    end select
    b1+=ws
    if b=&h74 then b1+=1                  'lodsd etc
    if b=&h77 then pfx=" 66"+pfx : lp+=3  'lodsw etc
    if b=&h71 then pfx+=" 48"    : lp+=3  'lodsq etc
    co=hexb(b1)
    goto addcode
  end if
  '
  '====
  nost:
  '====
  '
  if wr="int" then
    wd=aword(s,i)
    v=wval(wd)
    if v=3 then co=" CC": goto addcode      ' INT 3
    co=" CD"+hexb(v): goto addcode ' INT imm8
  end if




  '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" then
    if asc(wr,5)>96 then
      v=condi(wr,5)
      if v>=0 then
        pn=2 : b0=&h0f : b1=&h40 : flt=4
        b1+=v
        goto mos
      end if
    end if
  end if
  '
  '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 then
  '  'cmovcc Byte Set on Condition '  register 0f:40+tttn : m0m
  '  '8 bit regs
  '  pn=2 : b0=&h0f : b1=&h40 : flt=4
  '  v=condi(wr,5)
  '  if v<0 then ers="Internal error: Misaligned "+wd:ert=19: goto exita
  '  b1+=v
  '  goto mos
  'end if

  'SET conditional
  '===============
  '  
  if left(wr,3)="set" then
    if asc(wr,4)>96 then
      v=condi(wr,4)
      if v>=0 then
        pn=1 : b0=&h0f : b1=&h90 : c=0
        b1+=v
        goto mos
      end if
    end if
  end if
  '
  '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 then
  '  'SETcc Byte Set on Condition '  register 0f:90+tttn : m0m
  '  '8 bit regs
  '  pn=1:b0=&h0f:b1=&h90
  '  v=condi(wr,4)
  '  c=0
  '  'if v<0 then ers="Internal error: Misaligned "+wd:ert=19: goto exita
  '  b1+=v
  '  goto mos
  'end if



  '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)=&h70 then
    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 then
      a=asc(wr,v)
      k=-1
      select case a
      case &h62 : k=0 ' b
      case &h77 : k=1 ' w
      case &h64 : k=2 ' d
      case &h71 : k=3 ' q ' psllq
      end select
      if k>=0 then
        gg=k
        wr=left(wr,v-1)
        wd=" "+wr+" "
      end if
    end if
  end if 
  '
  '
  if d>3 then 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
  if m>0 then
    pn=3
    b0=&h0f
    im=-1
    ' d=0 1 2 3
    ' b2= md-mmx-rm
    ' di +&h10 to mem
    ' immediate opts
    select case m
    '------------
    case 01 : b1=&h77      ' EMMS      - Empty MMX state 
    case 06 : b1=&h6e:pn=2 ' MOVD      - Move doubleword:  mem to mx 0f:6e: mem from mx 0f:7e
    case 11 : b1=&h6f:pn=2 ' MOVQ      - Move quadword: mem to mx 0f:6f: mem from mx 0f:7f
    case 16 : b1=&h6b      ' PACKSSDW1 - Pack dword to word data (signed with saturation) memory to mx 0f:6b
    case 25 : b1=&h63      ' PACKSSWB1 - Pack word to byte data (signed with saturation):   memory to mx 0f:63
    case 34 : b1=&h67      ' PACKUSWB1 - Pack word to byte data (unsigned with saturation):   memory to mx 0f:67
    case 43 : b1=&hfc      ' PADD      - Add with wrap-around:   memory to mx 0f: fc+gg
    case 48 : b1=&hec      ' PADDS     - Add signed with saturation: memory to mx 0f: ec+gg
    case 54 : b1=&hdc      ' PADDUS    - Add unsigned with saturation: memory to mx 0f: dc+gg
    case 61 : b1=&hdb      ' PAND      - Bitwise And:   memory to mx 0f:db
    case 66 : b1=&hdf      ' 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=b1:b1+=gg:gg=0
    if v=&h77 then co=" 0F"+hexb(b1): goto addcode ' check for junk
    flt=2: goto mos
  end if
  '
  '
  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 then
    pn=3
    b0=&h0f
    im=-1
    ' b2= md-mmx-rm
    select case m
    '------------
    case 01  : b1=&h74              ' PCMPEQ  - Packed compare for equality: mx with memory 0f:74+gg
    case 08  : b1=&h64              ' PCMPGT  - Packed compare greater (signed):   mx with memory 0f:64+gg
    case 15  : b1=&hf5              ' PMADDWD - Packed multiply add: memory to mx 0f:f5
    case 23  : b1=&he5              ' PMULHW  - Packed multiplication: memory to mx 0f:e5
    case 30  : b1=&hd5              ' PMULLW  - Packed multiplication: memory to mx 0f:d5
    case 37  : b1=&heb              ' POR     - Bitwise Or:   memory to mx 0f:eb
    case 136 : b1=&hef              ' PXOR    - Bitwise Or:   memory to mx 0f:ef
    case 41  : b1=&hf0:im=&h70: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  : b1=&he0:im=&h70: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  : b1=&hd0:im=&h70: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  : b1=&hf8              ' PSUB    - Subtract with wraparound: memory from mx 0f:f8+gg
    case 61  : b1=&he8              ' PSUBS   - Subtract signed with saturation: memory from mx 0f:e8+gg:md-mx-rm
    case 67  : b1=&hd8              ' PSUBUS  - Subtract unsigned with saturation: memory from mx 0f:d8+gg
    case 74  : b1=&h67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 83  : b1=&h67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 92  : b1=&h67              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 101 : b1=&h5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 110 : b1=&h5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 119 : b1=&h5F              ' PUNPCKH - Unpack high data to next larger type: memory to mx 0f:68+gg
    case 128 : b1=&he4                     ' 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 then im+=gg:ima=8 ' + 8bit data
    flt=2:b1+=gg:gg=0: goto mos
  end if
  '
  '
  'BSWAP
  '-----
  '
  if wr="bswap" then
    wd=aword(s,i)
    v=regid(wd,wk)
    if (v>=0)and(wk=4) then co=" 0F"+hexb(&hc8+v): goto addcode
    ers="Expecting 16/32 bit rigister":ert=16: goto exita
  end if


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


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

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

  a=ascn
  if a=58 then
    k=SegOverride(wd)
    if k then pfx=hexb(k)+pfx : lp+=3 : i+=1 : wd=aword(s,i)
  end if


  v=regid(wd,wk)


  if v>=0 then
    if wk=2 then
      if flt>0 then ers="Can't use 16 bit register here":ert=12: goto exita
        pfx66(pfx,lp)
      end if
      if flt=2 then ers="Can't use gp register with this mmx instruction":ert=3: goto exita
      if (flt=3)and(pn<>15) then
        if (b1<>&h50)and(im<>&hc5)and(im<>&hc4)and(b1<>&hd7) then
          ers="Can't use gp register with this simd instruction":ert=3: goto exita
        end if
      end if
    end if
    if v<0 then
      if pn=14 then
        ers="Expecting a general reg followed by mm? ":ert=11: goto exita
    end if
    if flt>1 then 
      v=xmmxid(wd,wk)
    end if
    if (flt=0)and(v<0)and(lp=0) then
      v=sregid(wd,wk) ' with di
      if b1=&h88 then ' mov
        if wk=129 then flt=0:b1=&h20: b0=&h0f ' to cr
        if wk=130 then flt=0:b1=&h21: b0=&h0f ' to dr
        if wk=131 then flt=0:b1=&h8c:         ' to segreg
      end if
      if sb=&h50 then ' push
        if wk=131 then
          select case 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
        end if
      end if
      if sb=&h58 then ' pop
        if wk=131 then
          select case 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
        end if
      end if
    end if
  end if




  '========================
  'ACCUMULATOR - MEM to EAX
  '========================
  '
  if (axdi>=0)and(flt=0) then
    if b1=-1 then
      b1=axdi : goto memoperand ' mul div idiv: imm
    end if
    if pn=12 then
      a=ascn
      if a<>44 then ' single operand
        b1=axdi : pn=1 'mul imul
      else
        b0=&h0f : b1=&haf : im=&h69 'imul
      end if                
    end if
  end if



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

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



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



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

    if v>=0 then
      if rexi then
        rex=rexcode(v,wk)
      end if
      rg=v
      if sb>0 then
        if wk=2 then w1=" 66" else w1="" '16bit data prefix
        if wk>=2 then co=w1+hexb(sb+rg) : goto addcode
        if (sb=&h50)or(sb=&h58) then
          ers="byte push/pop not possible ":ert=11: goto exita
        end if
      end if
      '
      if pn=1 then
        '
        'INC DEC
        '-------
        '
        if (wk>=1)and(wk<=8) then
          if (wk>1)and(flt=0) then b1 or = 1
          if b0>=0 then co=hexb(b0)
          md=&hc0
          b2=md+c*8+rg
          co+=hexb(b1)+hexb(b2)
          goto addcode
        end if
        if co="" then ers="Wrong operand size "+wd : ert=11 : goto exita
      end if
      '
      a=ascn
      '
      if a<>44 then
        if pn=13 then 'implicit  ,1 shift
          ws=0 : if wk>1 then ws=1
          co=hexb(b1+ws)+hexb(&hc0+c*8+rg)
          goto addcode
        end if
        ers= "Expecting comma and operand" : ert=10 : goto exita
      end if
      '
      i+=1 ' skip comma
      '
      wk1=wk
      if (flt=0)and(pn<3) then
        if (b1<&h84)or(b1>&h87) then di=2 'EXCLUDE 'TEST' AND 'EXCHANGE'
      end if
      '
      wd=aword(s,i)
      a=ascn
      '
      if a=58 then
        k=SegOverride(wd)
        if k then pfx=hexb(k)+pfx : lp=3 : i+=1 : wd=aword(s,i)
      end if
      if wd="[" then
        if wk>128 then wk=1 ' segregs etc
        select case 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
      end if




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

      rm=regid(wd,wk)

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

      if (rm<0)and(b1=&h88)and(lp=0) then
        rm=sregid(wd,wk)
        if rm>=0 then
          if wk1>=128 then
            ers="Expecting general purpose reg or mem [..]" : ert=16 : goto exita
          end if
          v=sregid(wd,wk) ' with di
          select case wk
          case 129 : b1=&h20: b0=&h0f ' from cr
          case 130 : b1=&h21: b0=&h0f ' from  dr
          case 131 : b1=&h8c:         ' from segreg
          end select
          di=0:swap rg,rm
        end if
      end if
      '
      '=============================
      'IF SECOND REGISTER IDENTIFIED
      '=============================
      '
      if rm>=0 then
        '
        if rexi then
          a=rex
          if (a and 1) then a+=3 'SHIFT B BIT TO R BIT
          rex=rexcode(rm,wk) or a
        end if
        '
        if pn=3 then
          if wk=2 then
            if b0>-1 then
              if (b1=&hb6)or(b1=&hbe) then b1+=1 'MOVZX MOVSX ... AX
            end if
          end if 
        end if

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



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

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


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

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

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







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






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






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

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


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


  if wd="[" then

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


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

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

    'REGISTER, INDEX OR OFFSET?
    '
    select case 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 then
      re=xmmxid(wd,nn)
      if re<0 then re=sregid(wd,nn)
      if re>=0  then ers="mem operands require eax..edi registers":ert=13: goto exita
      '
      goto doffs 'ASSUME ITS AN OFFSET
      '
    end if
    '
    bs=rm 'FIRST REGISTER TO SIB BASE
    id=re 'SECOND REGISTER TO SIB INDEX

    '
    '======
    dreg2a:
    '======
    '
    if nn=1 then ers="Need 32bit register": ert=12: goto exita
    '
    wd=aword(s,i)
    select case 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 then ers="Only one register may be scaled" : ert=15: goto exita
    '
    wd=aword(s,i)
    sc=wval(wd) ' literal scale
    wd=aword(s,i)
    select case ascw
    case 45
      goto doffs 'OFFSET FOLLOWS
    case 43
      wd=aword(s,i) : a=regid(wd,nn)
      if a>=0 then id=rm : bs=a : goto dreg2a: 'SECOND REGISTER (SIB BASE) FOLLOWS SCALE 
      goto doffs 'OFFSET FOLLOWS
    case else 
      goto dendbrak 'OTHERWISE NO OFFSET
    end select


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

    a=ascw
    select case a
    case 35
      ads=" "+wd : md=&h80 ' bound literal
    case else
      wordeval(s,swd,i) : v=dv
      'i=swd : v=metaval(s,i,wd) ...
      'if nan then ers="Expecting an offset value" : ert=12
      if ert then goto exita
      if (v>=-128)and(v<128) then md=&h40:ads=hexb(v)
      if (v<-128)or(v>127) then md=&h80: ads=hexl(dv)
    end select
    wd=aword(s,i) ' expecting ']'



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

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



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

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

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

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

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

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

    a=ascw

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

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

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

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

    if wk1=2 then
      if (dv>=2^16)or(dv<-2^15) then
        ers="Value out of range for 16 bit number":ert=10: goto exita
      end if
    end if
    '
    if wk1=4 then
      if flot=0 then
        if (dv>=2^32)or(dv<-2^31) then
          ers="Value out of range for 32 bit number":ert=10: goto exita
        end if
      end if
    end if

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

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

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

    '
    'NON SIB EBP MUST HAVE AN OFFSET
    '-------------------------------
    '
    if rm=05 then
      if md=0 then
        md=&h40 : ads=" 00"
      end if
      goto nsib
    end if
    '
    '
    'OFFSET ONLY: (64BIT MODE COMPATIBLE)
    '------------------------------------
    '
    if (md>0)and(rm=-1) then
      '
      'RIP OR ABSOLUTE ADDRESSING
      '
      if rip then
        '
        '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(&h25) : goto nsib
        '
      end if
    end if
    '
    '
    'SIB ENCODING PROCEDURE
    '======================
    '
    if rm=-2 then
      '
      if (bs>=0)or(id>=0) then
        '
        'ESP IN THE INDEX FIELD MUST BE MOVED
        '------------------------------------
        '
        if id=4 then
          if sc>1 then
            ers="Cant have scaled ESP/RSP/R12 ":ert=12: goto exita
          elseif (bs<>4)and(sc<=1) then
            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
          end if
        end if
      end if
      '
      '
      'SIB BASE EBP MUST HAVE AN OFFSET
      '--------------------------------
      '
      if bs=5 then
        if id=5 then
          ers="Cant have EBP as both index and base in SIB" : ert=13 : goto exita
        elseif ((id<0)or(sc<=1))and(md=0) then
          swap bs,id 'EBP CAN BE SWAPPED INTO THE INDEX FIELD
        elseif md=0 then
          md=&h40 : ads=" 00" 'ADD A NULL OFFSET
        end if
      end if
      '
      'NO SIB INDEX REG SPECIFIED
      '--------------------------
      ' 
      if id<0 then id=4 'CODING FOR NO INDEX
      '
      '
      'INDEX  BUT NO BASE
      '------------------
      '
      'MUST HAVE 32 BIT DISPLACEMENT
      '
      if bs<0 then
        if md=0 then ads=" 00 00 00 00"  'MUST SPECIFY DISPLACEMENT
        if md=&h40 then ads+=" 00 00 00" 'MUST BE 32 BIT DISPLACEMENT
        md=0 : bs=5                      'CODING FOR NO BASE BUT 32 DISPLACEMENT
      end if
      '
      '
      'SCALE ENCODING
      '---------------
      '
      select case sc
      case -1     : sc=0
      case 1      : sc=0
      case 2      : sc=&h40
      case 4      : sc=&h80
      case 8      : sc=&hc0
      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 then id-=8 : rex or=2 'EXTENDED INDEX REG
      if bs>=8 then bs-=8 : rex or=1 'EXTENDED BASE REG
      '
      'COMPOSE SIB
      '-----------
      '
      
      rm=4 : w1=hexb(sc+id*8+bs)
      '
    end if
    '
    '=====================
    nsib: 'COMPOSE OPCODES
    '=====================
    '
    if rm>=8 then rm-=8 : rex or=1 'EXTENDED RM REG
    if n3=8 then rex or=8
    co=hexb(md+rg*8+rm)+w1+ads+dss
    goto encode
    '
  end if   ' ....]

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


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

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


  '=======
  addcode:
  '=======
  if rex then
    '
    rex or=&h40
    a=asc(pfx,2)
    if a>=&h36 then
      pfx=left(pfx,3)+hexb(rex)+mid(pfx,4)
    else
      pfx=hexb(rex)+pfx
    end if
    rex=0
    lp+=3
    '
  end if
  '
  if lp then
    co=pfx+co : pfx="" : lp=0
  end if
  '
  '
  ' now check for uninterpreted stuff
  '
  if len(co)=0 then 
    if pn>0 then ers="Unresolved operand type "+wd:ert=15: goto exita
  end if

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

  '------------------------
  'CODE VERIFICATION SYSTEM
  '------------------------
  '
  ' correct opcodes are contained in the comment using prefix !? 
  ' eg : ; !? b0 2a
  '
  skiplspace(s,i)
  select case ascn
  case 0 to 13
    goto nverifyop
  case 58
    i+=1 : skiplspace(s,i) : goto nverifyop
  case 39
  case 59
  case else
    '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+=1
  do
    select case asc(s,i)
    case 0 to 13
      exit do
    case 33 '!'
      if m=1 then
        i+=1 : a=asc(s,i)
        if a=63 then
          m=2 : b=1 : i+=1 : continue do
        end if
      end if
      endline(s,i) : exit do
    case 34 to 255
      if m=2 then
        'compare code with commented code
        wd=aword(s,i)
        v=wval("&h"+wd)
        wd=aword(co,b)
        if wval("&h"+wd)=v then
          continue do
        end if
        k=1 : endline(s,i) : exit do 'DISAGREE k
      end if
    end select
    i+=1
  loop
  if (k=1)or(b<=len(co)) then
    co+=" ;!! "
  end if
  '
  nverifyop:
  


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

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

  if vew=0 then wr=cr ' EXCLUDE COMMENTS
  '
  'APPEND COMMENTS
  '---------------
  '
  if vew>0 then
    '
    'APPEND CLIPPED COMMENTS
    '-----------------------
    '
    a=i-bgl
    if a>64 then a=64 ' clip src comment
    if ncm then a=0 ' NO COMMENT
    '
    '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+=1:if v>m then exit do
      a=asc(wr,v)
      if a=9 then a=32 ' tab ignore
      if a<32 then mid(wr,v)=" "
    loop
    ncm=0
  end if
  '
  'ADJUST SIZE OF BUFFER IF NECESSARY
  '----------------------------------
  '
  co+=wr : a=len(t)
  '
  '
  '========
  addcode2:
  '========
  '
  b=len(co)
  if j+b>a then t+=space(b+4000)
  '
  'APPEND LINE OF CODE
  '-------------------
  '
  mid(t,j)=co: j+=b ' add code

  '=====
  exita:
  '=====
    
  '
  'CHECK FOR ERROR MESSAGES
  '------------------------
  '
  if ert>0 then
    '
    '
    'CAPTURE REST OF CURRENT LINE
    '----------------------------
    '
    v=i : endline(s,i)
    '
    'COMPLETE ERROR MESSAGE
    '----------------------
    '
    ers=                    " ; ASM ERR: "+htb+mid(s,bgl,i-bgl)+"!!  "+ers+cr
    if len(lbw)   then ers+=" ; AFTER:   "+htb+lbw+cr
    if len(lnmks) then ers+=" ; LINE:    "+htb+lnmks+cr
    if len(fnmks) then ers+=" ; FILE:    "+htb+fnmks+cr

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



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

    ert=0 : ers=""
    b0=-1 : b1=-1 : b2=-1 : dn=-1 : lp=0 : pfx=""
    end if


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

  term:

  ers=ersl : ersl=""


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


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


