#BEGIN_LEGAL
#
#Copyright (c) 2023 Intel Corporation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#  
#END_LEGAL
# Decoder ring
# @ = null = invalid register
# * = any valid register or value for this field
# nothing  = encode nothing in this case
# error = cannot encode 

SEQUENCE MODRM_BIND
  SIB_REQUIRED_ENCODE_BIND() 
  SIBSCALE_ENCODE_BIND()
  SIBINDEX_ENCODE_BIND() 
  SIBBASE_ENCODE_BIND() 
  MODRM_RM_ENCODE_BIND() 
  MODRM_MOD_ENCODE_BIND()  
  SEGMENT_DEFAULT_ENCODE_BIND()
  SEGMENT_ENCODE_BIND()
  SIB_NT_BIND()    # FIXME 2007-06-30
  DISP_NT_BIND()

SEQUENCE MODRM_EMIT
  #MODRM_NT_EMIT()  # FIXME: 2007-06-30 the instruction will emit this as part of the INSTRUCTIONS NT
  SIB_NT_EMIT() 
  DISP_NT_EMIT() 

SEGMENT_DEFAULT_ENCODE()::
BASE0=rIPa() -> nothing # no segment for RIP/EIP
BASE0=ArSP() -> default_ss # default to SS
BASE0=ArBP() -> default_ss # default to SS
BASE0=@      -> default_ds # default to DS -- baseless 
#
BASE0=ArAX() -> default_ds # everything else defaults to DS
BASE0=ArCX() -> default_ds
BASE0=ArDX() -> default_ds
BASE0=ArBX() -> default_ds
BASE0=ArSI() -> default_ds
BASE0=ArDI() -> default_ds
BASE0=Ar8()  -> default_ds
BASE0=Ar9()  -> default_ds
BASE0=Ar10() -> default_ds
BASE0=Ar11() -> default_ds
BASE0=Ar12() -> default_ds
BASE0=Ar13() -> default_ds
BASE0=Ar14() -> default_ds
BASE0=Ar15() -> default_ds
BASE0=Ar16() -> default_ds
BASE0=Ar17() -> default_ds
BASE0=Ar18() -> default_ds
BASE0=Ar19() -> default_ds
BASE0=Ar20() -> default_ds
BASE0=Ar21() -> default_ds
BASE0=Ar22() -> default_ds
BASE0=Ar23() -> default_ds
BASE0=Ar24() -> default_ds
BASE0=Ar25() -> default_ds
BASE0=Ar26() -> default_ds
BASE0=Ar27() -> default_ds
BASE0=Ar28() -> default_ds
BASE0=Ar29() -> default_ds
BASE0=Ar30() -> default_ds
BASE0=Ar31() -> default_ds

SEGMENT_ENCODE()::
default_ss SEG0=@          -> no_seg_prefix # was "nothing" 2007-0x08-0x14 # assume this is what the user wanted
default_ss SEG0=XED_REG_CS -> cs_prefix
default_ss SEG0=XED_REG_DS -> ds_prefix
default_ss SEG0=XED_REG_SS -> no_seg_prefix # was "nothing" 2007-0x08-0x14   # matches default
default_ss SEG0=XED_REG_ES -> es_prefix
default_ss SEG0=XED_REG_FS -> fs_prefix
default_ss SEG0=XED_REG_GS -> gs_prefix
#
default_ds SEG0=@          -> no_seg_prefix # was "nothing" 2007-0x08-0x14  # assume this is what the user wanted
default_ds SEG0=XED_REG_CS -> cs_prefix
default_ds SEG0=XED_REG_DS -> no_seg_prefix # was "nothing" 2007-0x08-0x14  # matches default
default_ds SEG0=XED_REG_SS -> ss_prefix
default_ds SEG0=XED_REG_ES -> es_prefix
default_ds SEG0=XED_REG_FS -> fs_prefix
default_ds SEG0=XED_REG_GS -> gs_prefix
otherwise                  -> no_seg_prefix # was "nothing" 2007-0x08-0x14


SIB_REQUIRED_ENCODE()::
eamode32 INDEX=GPR32e()  -> NEED_SIB=1 
eamode64 INDEX=GPR64e()  -> NEED_SIB=1 
#   base-less memop in 64b mode requires a SIB

eamode64 BASE0=@ DISP_WIDTH=32 ->  NEED_SIB=1
eamode32 mode64 BASE0=@ DISP_WIDTH=32 ->  NEED_SIB=1
eamode32 mode16 -> nothing
eamode32 mode32 -> nothing

#   Denote the need of a SIB byte if base is rSP, r12, r20 or 28
eanot16 BASE0=ArSP()  -> NEED_SIB=1
eanot16 BASE0=Ar12()  -> NEED_SIB=1
eanot16 BASE0=Ar20()  -> NEED_SIB=1
eanot16 BASE0=Ar28()  -> NEED_SIB=1

#  When the displacement is omitted, we supply one for these r13 and rBP.
#eanot16 BASE0=ArBP() DISP_WIDTH=0 -> NEED_SIB=1
#eanot16 BASE0=Ar13() DISP_WIDTH=0 -> NEED_SIB=1

otherwise -> nothing # FIXME: could set NEED_SIB=0

SIBBASE_ENCODE()::
NEED_SIB=0     -> nothing
NEED_SIB=1     -> SIBBASE_ENCODE_SIB1()

SIBBASE_ENCODE_SIB1()::
BASE0=ArAX()  -> SIBBASE=0 REXB=0 REXB4=0
BASE0=Ar8()   -> SIBBASE=0 REXB=1 REXB4=0
BASE0=Ar16()  -> SIBBASE=0 REXB=0 REXB4=1
BASE0=Ar24()  -> SIBBASE=0 REXB=1 REXB4=1
BASE0=ArCX()  -> SIBBASE=1 REXB=0 REXB4=0
BASE0=Ar9()   -> SIBBASE=1 REXB=1 REXB4=0
BASE0=Ar17()  -> SIBBASE=1 REXB=0 REXB4=1
BASE0=Ar25()  -> SIBBASE=1 REXB=1 REXB4=1
BASE0=ArDX()  -> SIBBASE=2 REXB=0 REXB4=0
BASE0=Ar10()  -> SIBBASE=2 REXB=1 REXB4=0
BASE0=Ar18()  -> SIBBASE=2 REXB=0 REXB4=1
BASE0=Ar26()  -> SIBBASE=2 REXB=1 REXB4=1
BASE0=ArBX()  -> SIBBASE=3 REXB=0 REXB4=0
BASE0=Ar11()  -> SIBBASE=3 REXB=1 REXB4=0
BASE0=Ar19()  -> SIBBASE=3 REXB=0 REXB4=1
BASE0=Ar27()  -> SIBBASE=3 REXB=1 REXB4=1
BASE0=ArSP()  -> SIBBASE=4 REXB=0 REXB4=0
BASE0=Ar12()  -> SIBBASE=4 REXB=1 REXB4=0
BASE0=Ar20()  -> SIBBASE=4 REXB=0 REXB4=1
BASE0=Ar28()  -> SIBBASE=4 REXB=1 REXB4=1

# The mod values are really gotten by the MOD rule, only requiring one
# addition.  
## BAD MODIFIES DISP! NEED_SIB=1 BASE0=@      DISP_WIDTH=8 -> SIBBASE=5 REXB=0 DISP_WIDTH=32 # MOD=0
BASE0=@      -> DISP_WIDTH_32() SIBBASE=5 REXB=0 # MOD=0
# The MOD rule handles the DISP arg modification for rBP and r13
BASE0=ArBP() -> DISP_WIDTH_0_8_32() SIBBASE=5 REXB=0 REXB4=0 # MOD=1 # ARG MODIFICATION LATER IN MOD RULE

# NEED_SIB=1 BASE0=@      DISP_WIDTH=32 -> SIBBASE=5 REXB=0 # MOD=0  redundant with the above
# The MOD rule handles the DISP arg modification for rBP and r13
BASE0=Ar13() -> DISP_WIDTH_0_8_32() SIBBASE=5 REXB=1 REXB4=0 # MOD=1 # ARG MODIFICATION LATER IN MOD RULE
BASE0=Ar21() -> DISP_WIDTH_0_8_32() SIBBASE=5 REXB=0 REXB4=1 # MOD=1 # ARG MODIFICATION LATER IN MOD RULE
BASE0=Ar29() -> DISP_WIDTH_0_8_32() SIBBASE=5 REXB=1 REXB4=1 # MOD=1 # ARG MODIFICATION LATER IN MOD RULE

BASE0=ArSI() -> SIBBASE=6 REXB=0 REXB4=0
BASE0=Ar14() -> SIBBASE=6 REXB=1 REXB4=0
BASE0=Ar22() -> SIBBASE=6 REXB=0 REXB4=1
BASE0=Ar30() -> SIBBASE=6 REXB=1 REXB4=1
BASE0=ArDI() -> SIBBASE=7 REXB=0 REXB4=0
BASE0=Ar15() -> SIBBASE=7 REXB=1 REXB4=0
BASE0=Ar23() -> SIBBASE=7 REXB=0 REXB4=1
BASE0=Ar31() -> SIBBASE=7 REXB=1 REXB4=1
otherwise    -> error             # BASE0 was some other register

SIBINDEX_ENCODE()::
NEED_SIB=0 -> nothing
NEED_SIB=1 -> SIBINDEX_ENCODE_SIB1()

SIBINDEX_ENCODE_SIB1()::    
INDEX=ArAX() -> SIBINDEX=0 REXX=0 REXX4=0
INDEX=Ar8()  -> SIBINDEX=0 REXX=1 REXX4=0
INDEX=Ar16() -> SIBINDEX=0 REXX=0 REXX4=1
INDEX=Ar24() -> SIBINDEX=0 REXX=1 REXX4=1
INDEX=ArCX() -> SIBINDEX=1 REXX=0 REXX4=0
INDEX=Ar9()  -> SIBINDEX=1 REXX=1 REXX4=0
INDEX=Ar17() -> SIBINDEX=1 REXX=0 REXX4=1
INDEX=Ar25() -> SIBINDEX=1 REXX=1 REXX4=1
INDEX=ArDX() -> SIBINDEX=2 REXX=0 REXX4=0
INDEX=Ar10() -> SIBINDEX=2 REXX=1 REXX4=0
INDEX=Ar18() -> SIBINDEX=2 REXX=0 REXX4=1
INDEX=Ar26() -> SIBINDEX=2 REXX=1 REXX4=1
INDEX=ArBX() -> SIBINDEX=3 REXX=0 REXX4=0
INDEX=Ar11() -> SIBINDEX=3 REXX=1 REXX4=0
INDEX=Ar19() -> SIBINDEX=3 REXX=0 REXX4=1
INDEX=Ar27() -> SIBINDEX=3 REXX=1 REXX4=1
INDEX=@      -> SIBINDEX=4 REXX=0 REXX4=0 # the "no index" option
INDEX=Ar12() -> SIBINDEX=4 REXX=1 REXX4=0
INDEX=Ar20() -> SIBINDEX=4 REXX=0 REXX4=1
INDEX=Ar28() -> SIBINDEX=4 REXX=1 REXX4=1
INDEX=ArBP() -> SIBINDEX=5 REXX=0 REXX4=0
INDEX=Ar13() -> SIBINDEX=5 REXX=1 REXX4=0
INDEX=Ar21() -> SIBINDEX=5 REXX=0 REXX4=1
INDEX=Ar29() -> SIBINDEX=5 REXX=1 REXX4=1
INDEX=ArSI() -> SIBINDEX=6 REXX=0 REXX4=0
INDEX=Ar14() -> SIBINDEX=6 REXX=1 REXX4=0
INDEX=Ar22() -> SIBINDEX=6 REXX=0 REXX4=1
INDEX=Ar30() -> SIBINDEX=6 REXX=1 REXX4=1
INDEX=ArDI() -> SIBINDEX=7 REXX=0 REXX4=0
INDEX=Ar15() -> SIBINDEX=7 REXX=1 REXX4=0
INDEX=Ar23() -> SIBINDEX=7 REXX=0 REXX4=1
INDEX=Ar31() -> SIBINDEX=7 REXX=1 REXX4=1
otherwise    -> error             # INDEX was some other register


SIBSCALE_ENCODE()::
NEED_SIB=0         -> nothing
NEED_SIB=1 SCALE=0 -> SIBSCALE=0 # this allows for default unset scales
NEED_SIB=1 SCALE=1 -> SIBSCALE=0
NEED_SIB=1 SCALE=2 -> SIBSCALE=1
NEED_SIB=1 SCALE=4 -> SIBSCALE=2
NEED_SIB=1 SCALE=8 -> SIBSCALE=3
otherwise    -> error             # SCALE was some other value

##############################################################################
MODRM_MOD_ENCODE()::
eamode16 DISP_WIDTH=0   -> MODRM_MOD_EA16_DISP0()
eamode16 DISP_WIDTH=8   -> MODRM_MOD_EA16_DISP8()
eamode16 DISP_WIDTH=16  -> MODRM_MOD_EA16_DISP16()
eamode16 DISP_WIDTH=32  -> ERROR()
eamode16 DISP_WIDTH=64  -> ERROR()

eamode32 DISP_WIDTH=0   -> MODRM_MOD_EA32_DISP0() 
eamode32 DISP_WIDTH=8   -> MODRM_MOD_EA32_DISP8() 
eamode32 DISP_WIDTH=16  -> ERROR()
eamode32 DISP_WIDTH=32  -> MODRM_MOD_EA32_DISP32()
eamode32 DISP_WIDTH=64  -> ERROR()

eamode64 DISP_WIDTH=0   -> MODRM_MOD_EA64_DISP0() 
eamode64 DISP_WIDTH=8   -> MODRM_MOD_EA64_DISP8() 
eamode64 DISP_WIDTH=16  -> ERROR()
eamode64 DISP_WIDTH=32  -> MODRM_MOD_EA64_DISP32()
eamode64 DISP_WIDTH=64  -> ERROR()
##############################################################################
#### EAMODE16  
##############################################################################
MODRM_MOD_EA16_DISP0()::
BASE0=XED_REG_BX INDEX=@  -> MOD=0
BASE0=XED_REG_SI INDEX=@  -> MOD=0
BASE0=XED_REG_DI INDEX=@  -> MOD=0
BASE0=XED_REG_BP INDEX=@  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION
BASE0=XED_REG_BP INDEX=XED_REG_SI -> MOD=0
BASE0=XED_REG_BP INDEX=XED_REG_DI -> MOD=0
BASE0=XED_REG_BX INDEX=XED_REG_SI -> MOD=0
BASE0=XED_REG_BX INDEX=XED_REG_DI -> MOD=0

MODRM_MOD_EA16_DISP8()::
BASE0=XED_REG_BX INDEX=@  -> MOD=1
BASE0=XED_REG_SI INDEX=@  -> MOD=1
BASE0=XED_REG_DI INDEX=@  -> MOD=1
BASE0=XED_REG_BP INDEX=@  -> MOD=1 
BASE0=XED_REG_BP INDEX=XED_REG_SI -> MOD=1
BASE0=XED_REG_BP INDEX=XED_REG_DI -> MOD=1
BASE0=XED_REG_BX INDEX=XED_REG_SI -> MOD=1
BASE0=XED_REG_BX INDEX=XED_REG_DI -> MOD=1

MODRM_MOD_EA16_DISP16()::
BASE0=@          INDEX=@   -> MOD=0
BASE0=XED_REG_BX INDEX=@  -> MOD=2
BASE0=XED_REG_SI INDEX=@  -> MOD=2
BASE0=XED_REG_DI INDEX=@  -> MOD=2
BASE0=XED_REG_BP INDEX=@  -> MOD=2 
BASE0=XED_REG_BP INDEX=XED_REG_SI -> MOD=2
BASE0=XED_REG_BP INDEX=XED_REG_DI -> MOD=2
BASE0=XED_REG_BX INDEX=XED_REG_SI -> MOD=2
BASE0=XED_REG_BX INDEX=XED_REG_DI -> MOD=2


##############################################################################
#### EAMODE32
##############################################################################
MODRM_MOD_EA32_DISP0()::
# Add a fake 1B displacement to rBP and r13 if they do not have one already.
BASE0=XED_REG_EBP  mode32  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION
BASE0=XED_REG_EBP  mode64  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION
BASE0=XED_REG_R13D mode64  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION
BASE0=XED_REG_R21D mode64  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION
BASE0=XED_REG_R29D mode64  -> MOD=1 DISP_WIDTH=8 DISP=0    # ARG MODIFICATION

# All these 32b and 64b base regs can handle no displacement
BASE0=XED_REG_EAX mode32       -> MOD=0 
BASE0=XED_REG_EBX mode32       -> MOD=0 
BASE0=XED_REG_ECX mode32       -> MOD=0 
BASE0=XED_REG_EDX mode32       -> MOD=0 
BASE0=XED_REG_ESI mode32       -> MOD=0 
BASE0=XED_REG_EDI mode32       -> MOD=0 
BASE0=XED_REG_ESP mode32       -> MOD=0 # our choice to use MOD=0 (w/sib)

BASE0=XED_REG_EAX mode64       -> MOD=0 
BASE0=XED_REG_EBX mode64       -> MOD=0 
BASE0=XED_REG_ECX mode64       -> MOD=0 
BASE0=XED_REG_EDX mode64       -> MOD=0 
BASE0=XED_REG_ESI mode64       -> MOD=0 
BASE0=XED_REG_EDI mode64       -> MOD=0 
BASE0=XED_REG_ESP mode64       -> MOD=0 # our choice to use MOD=0 (w/sib)

BASE0=XED_REG_R8D   mode64     -> MOD=0 
BASE0=XED_REG_R9D   mode64     -> MOD=0 
BASE0=XED_REG_R10D  mode64     -> MOD=0 
BASE0=XED_REG_R11D  mode64     -> MOD=0 
BASE0=XED_REG_R12D  mode64     -> MOD=0 # our choice to use MOD=0 (w/sib)
BASE0=XED_REG_R14D  mode64     -> MOD=0 
BASE0=XED_REG_R15D  mode64     -> MOD=0 

BASE0=XED_REG_R16D  mode64     -> MOD=0 
BASE0=XED_REG_R17D  mode64     -> MOD=0 
BASE0=XED_REG_R18D  mode64     -> MOD=0 
BASE0=XED_REG_R19D  mode64     -> MOD=0 
BASE0=XED_REG_R20D  mode64     -> MOD=0
BASE0=XED_REG_R22D  mode64     -> MOD=0 
BASE0=XED_REG_R23D  mode64     -> MOD=0 
BASE0=XED_REG_R24D  mode64     -> MOD=0 
BASE0=XED_REG_R25D  mode64     -> MOD=0 
BASE0=XED_REG_R26D  mode64     -> MOD=0 
BASE0=XED_REG_R27D  mode64     -> MOD=0
BASE0=XED_REG_R28D  mode64     -> MOD=0 
BASE0=XED_REG_R30D  mode64     -> MOD=0 
BASE0=XED_REG_R31D  mode64     -> MOD=0


MODRM_MOD_EA32_DISP8()::
otherwise                      -> MOD=1  # might use SIB

MODRM_MOD_EA32_DISP32()::
BASE0=@                    -> MOD=0 #no base (handles NEED_SIB=1 case)
BASE0=GPR32e()             -> MOD=2 #some base, not RIP, might use SIB
BASE0=rIPa() mode64        -> MOD=0

##############################################################################
#### EAMODE64
##############################################################################

MODRM_MOD_EA64_DISP0()::
BASE0=XED_REG_EIP       -> MOD=0 DISP_WIDTH=32 DISP=0    # base eip
BASE0=XED_REG_RIP       -> MOD=0 DISP_WIDTH=32 DISP=0    # base rip

BASE0=XED_REG_RBP       -> MOD=1 DISP_WIDTH=8 DISP=0     # ARG MODIFICATION
BASE0=XED_REG_R13       -> MOD=1 DISP_WIDTH=8 DISP=0     # ARG MODIFICATION
BASE0=XED_REG_R21       -> MOD=1 DISP_WIDTH=8 DISP=0     # ARG MODIFICATION
BASE0=XED_REG_R29       -> MOD=1 DISP_WIDTH=8 DISP=0     # ARG MODIFICATION
BASE0=XED_REG_RAX       -> MOD=0 
BASE0=XED_REG_RBX       -> MOD=0 
BASE0=XED_REG_RCX       -> MOD=0 
BASE0=XED_REG_RDX       -> MOD=0 
BASE0=XED_REG_RSI       -> MOD=0 
BASE0=XED_REG_RDI       -> MOD=0 
BASE0=XED_REG_RSP       -> MOD=0
BASE0=XED_REG_R8        -> MOD=0 
BASE0=XED_REG_R9        -> MOD=0 
BASE0=XED_REG_R10       -> MOD=0 
BASE0=XED_REG_R11       -> MOD=0 
BASE0=XED_REG_R12       -> MOD=0
BASE0=XED_REG_R14       -> MOD=0 
BASE0=XED_REG_R15       -> MOD=0 
BASE0=XED_REG_R16       -> MOD=0 
BASE0=XED_REG_R17       -> MOD=0 
BASE0=XED_REG_R18       -> MOD=0 
BASE0=XED_REG_R19       -> MOD=0 
BASE0=XED_REG_R20       -> MOD=0 
BASE0=XED_REG_R22       -> MOD=0
BASE0=XED_REG_R23       -> MOD=0 
BASE0=XED_REG_R24       -> MOD=0 
BASE0=XED_REG_R25       -> MOD=0 
BASE0=XED_REG_R26       -> MOD=0 
BASE0=XED_REG_R27       -> MOD=0
BASE0=XED_REG_R28       -> MOD=0 
BASE0=XED_REG_R30       -> MOD=0 
BASE0=XED_REG_R31       -> MOD=0 

MODRM_MOD_EA64_DISP8()::
BASE0=GPR64e()             -> MOD=1

MODRM_MOD_EA64_DISP32()::
BASE0=@              -> MOD=0 #no base, NEED_SIB=1 required (provided elsewhere)
BASE0=XED_REG_EIP    -> MOD=0 #base eip
BASE0=XED_REG_RIP    -> MOD=0 #base rip
BASE0=XED_REG_RAX    -> MOD=2 
BASE0=XED_REG_RBX    -> MOD=2 
BASE0=XED_REG_RCX    -> MOD=2 
BASE0=XED_REG_RDX    -> MOD=2 
BASE0=XED_REG_RSI    -> MOD=2 
BASE0=XED_REG_RDI    -> MOD=2 
BASE0=XED_REG_RSP    -> MOD=2 # NEED_SIB=1 required (and is provided elsewhere)
BASE0=XED_REG_RBP    -> MOD=2 
BASE0=XED_REG_R8     -> MOD=2 
BASE0=XED_REG_R9     -> MOD=2 
BASE0=XED_REG_R10    -> MOD=2 
BASE0=XED_REG_R11    -> MOD=2 
BASE0=XED_REG_R12    -> MOD=2 # NEED_SIB=1 required (and is provided elsewhere)
BASE0=XED_REG_R13    -> MOD=2 
BASE0=XED_REG_R14    -> MOD=2 
BASE0=XED_REG_R15    -> MOD=2 
BASE0=XED_REG_R16    -> MOD=2 
BASE0=XED_REG_R17    -> MOD=2 
BASE0=XED_REG_R18    -> MOD=2 
BASE0=XED_REG_R19    -> MOD=2 
BASE0=XED_REG_R20    -> MOD=2 # NEED_SIB=1 required (and is provided elsewhere)
BASE0=XED_REG_R21    -> MOD=2 
BASE0=XED_REG_R22    -> MOD=2 
BASE0=XED_REG_R23    -> MOD=2
BASE0=XED_REG_R24    -> MOD=2 
BASE0=XED_REG_R25    -> MOD=2 
BASE0=XED_REG_R26    -> MOD=2 
BASE0=XED_REG_R27    -> MOD=2 
BASE0=XED_REG_R28    -> MOD=2 # NEED_SIB=1 required (and is provided elsewhere)
BASE0=XED_REG_R29    -> MOD=2 
BASE0=XED_REG_R30    -> MOD=2 
BASE0=XED_REG_R31    -> MOD=2 
########################################################################################################


#If we didn't already encode the base in the SIB!
MODRM_RM_ENCODE()::

eamode16  NEED_SIB=0 -> MODRM_RM_ENCODE_EA16_SIB0()
eamode32  NEED_SIB=0 -> MODRM_RM_ENCODE_EA32_SIB0()
eamode64  NEED_SIB=0 -> MODRM_RM_ENCODE_EA64_SIB0()
eanot16   NEED_SIB=1 -> MODRM_RM_ENCODE_EANOT16_SIB1()

#############################################

MODRM_RM_ENCODE_EA16_SIB0()::
BASE0=XED_REG_BX INDEX=XED_REG_SI  -> RM=0
BASE0=XED_REG_BX INDEX=XED_REG_DI  -> RM=1
BASE0=XED_REG_BP INDEX=XED_REG_SI  -> RM=2
BASE0=XED_REG_BP INDEX=XED_REG_DI  -> RM=3
BASE0=XED_REG_SI INDEX=@           -> RM=4
BASE0=XED_REG_DI INDEX=@           -> RM=5
BASE0=@          INDEX=@           ->  DISP_WIDTH_16() RM=6


# for BP without an index, we add an imm8=0 when encoding the MOD
BASE0=XED_REG_BP INDEX=@           -> DISP_WIDTH_0_8_16() RM=6
BASE0=XED_REG_BX INDEX=@           -> RM=7

MODRM_RM_ENCODE_EA64_SIB0()::
BASE0=XED_REG_RAX -> RM=0 REXB=0 REXB4=0
BASE0=XED_REG_R8  -> RM=0 REXB=1 REXB4=0
BASE0=XED_REG_R16 -> RM=0 REXB=0 REXB4=1
BASE0=XED_REG_R24 -> RM=0 REXB=1 REXB4=1
BASE0=XED_REG_RCX -> RM=1 REXB=0 REXB4=0
BASE0=XED_REG_R9  -> RM=1 REXB=1 REXB4=0
BASE0=XED_REG_R17 -> RM=1 REXB=0 REXB4=1
BASE0=XED_REG_R25 -> RM=1 REXB=1 REXB4=1
BASE0=XED_REG_RDX -> RM=2 REXB=0 REXB4=0
BASE0=XED_REG_R10 -> RM=2 REXB=1 REXB4=0
BASE0=XED_REG_R18 -> RM=2 REXB=0 REXB4=1
BASE0=XED_REG_R26 -> RM=2 REXB=1 REXB4=1
BASE0=XED_REG_RBX -> RM=3 REXB=0 REXB4=0
BASE0=XED_REG_R11 -> RM=3 REXB=1 REXB4=0
BASE0=XED_REG_R19 -> RM=3 REXB=0 REXB4=1
BASE0=XED_REG_R27 -> RM=3 REXB=1 REXB4=1


BASE0=XED_REG_RSI -> RM=6 REXB=0 REXB4=0
BASE0=XED_REG_R14 -> RM=6 REXB=1 REXB4=0
BASE0=XED_REG_R22 -> RM=6 REXB=0 REXB4=1
BASE0=XED_REG_R30 -> RM=6 REXB=1 REXB4=1
BASE0=XED_REG_RDI -> RM=7 REXB=0 REXB4=0
BASE0=XED_REG_R15 -> RM=7 REXB=1 REXB4=0
BASE0=XED_REG_R23 -> RM=7 REXB=0 REXB4=1
BASE0=XED_REG_R31 -> RM=7 REXB=1 REXB4=1

# case RM=5 is tricky. The mode,base and disp width play a role
BASE0=@      -> DISP_WIDTH_32() RM=5 # not setting REXB FIXME?

# for rBP without a disp, we add a 1B disp so MOD will be 1
BASE0=XED_REG_RBP -> DISP_WIDTH_0_8_32() RM=5  REXB=0 REXB4=0


# When we do the MOD encoding, we fix the displacement at 4B.
BASE0=XED_REG_RIP -> RM=5 # not setting REXB FIXME?
BASE0=XED_REG_EIP -> RM=5 # not setting REXB FIXME?

# for r13 without a disp, we add a 1B disp so MOD will be 1
BASE0=XED_REG_R13 -> DISP_WIDTH_0_8_32() RM=5  REXB=1  REXB4=0
BASE0=XED_REG_R21 -> DISP_WIDTH_0_8_32() RM=5  REXB=0  REXB4=1
BASE0=XED_REG_R29 -> DISP_WIDTH_0_8_32() RM=5  REXB=1  REXB4=1

MODRM_RM_ENCODE_EA32_SIB0()::
BASE0=XED_REG_EAX   -> RM=0 REXB=0 REXB4=0
BASE0=XED_REG_R8D   -> RM=0 REXB=1 REXB4=0
BASE0=XED_REG_R16D  -> RM=0 REXB=0 REXB4=1
BASE0=XED_REG_R24D  -> RM=0 REXB=1 REXB4=1
BASE0=XED_REG_ECX   -> RM=1 REXB=0 REXB4=0
BASE0=XED_REG_R9D   -> RM=1 REXB=1 REXB4=0
BASE0=XED_REG_R17D  -> RM=1 REXB=0 REXB4=1
BASE0=XED_REG_R25D  -> RM=1 REXB=1 REXB4=1
BASE0=XED_REG_EDX   -> RM=2 REXB=0 REXB4=0
BASE0=XED_REG_R10D  -> RM=2 REXB=1 REXB4=0
BASE0=XED_REG_R18D  -> RM=2 REXB=0 REXB4=1
BASE0=XED_REG_R26D  -> RM=2 REXB=1 REXB4=1
BASE0=XED_REG_EBX   -> RM=3 REXB=0 REXB4=0
BASE0=XED_REG_R11D  -> RM=3 REXB=1 REXB4=0
BASE0=XED_REG_R19D  -> RM=3 REXB=0 REXB4=1
BASE0=XED_REG_R27D  -> RM=3 REXB=1 REXB4=1


BASE0=XED_REG_ESI   -> RM=6 REXB=0 REXB4=0
BASE0=XED_REG_R14D  -> RM=6 REXB=1 REXB4=0
BASE0=XED_REG_R22D  -> RM=6 REXB=0 REXB4=1
BASE0=XED_REG_R30D  -> RM=6 REXB=1 REXB4=1
BASE0=XED_REG_EDI   -> RM=7 REXB=0 REXB4=0
BASE0=XED_REG_R15D  -> RM=7 REXB=1 REXB4=0
BASE0=XED_REG_R23D  -> RM=7 REXB=0 REXB4=1
BASE0=XED_REG_R31D  -> RM=7 REXB=1 REXB4=1

# case RM=5 is tricky. The mode,base and disp width play a role
BASE0=@      -> DISP_WIDTH_32() RM=5 # not setting REXB FIXME?

# for rBP without a disp, we add a 1B disp so MOD will be 1
BASE0=XED_REG_EBP -> DISP_WIDTH_0_8_32() RM=5  REXB=0 REXB4=0

# for r13 without a disp, we add a 1B disp so MOD will be 1
BASE0=XED_REG_R13D -> DISP_WIDTH_0_8_32() RM=5  REXB=1  REXB4=0
BASE0=XED_REG_R21D -> DISP_WIDTH_0_8_32() RM=5  REXB=0  REXB4=1
BASE0=XED_REG_R29D -> DISP_WIDTH_0_8_32() RM=5  REXB=1  REXB4=1

BASE0=XED_REG_RIP mode64 -> RM=5
BASE0=XED_REG_EIP mode64 -> RM=5

MODRM_RM_ENCODE_EANOT16_SIB1()::
otherwise -> RM=4 # SIB will specify the REXB etc.

#############################################

          

# These are  good, seemingly:

# FIXME: these are semi-redundant with field bindings that I need for decode.
# I was thinking about using something like:
#    MODRM[mm,rrr,nnn] & SIB[ss,iii,bbb]
# coupled with:
#    MODRM = (MOD,2), (REG,3), (RM,3)
#    SIB = (SIBSCALE,2), (SIBINDEX,3), (SIBBASE,3)

#FIXME: don't require =*???
#FIXME: handle "nothing" option

## SIB_EMIT()::
## NEED_SIB=1 SIBBASE[bbb]=* SIBSCALE[ss]=* SIBINDEX[iii]=* -> ss_iii_bbb
## NEED_SIB=0                                               -> nothing
## 
## MODRM_EMIT()::
## MODRM=1 MOD[xx]=* REG[rrr]=* RM[mmm]=* -> xx_rrr_mmm
## MODRM=0                                -> nothing

# ... OR ...

SIB_NT()::
NEED_SIB=1 SIBBASE[bbb] SIBSCALE[ss] SIBINDEX[iii] -> ss_iii_bbb
NEED_SIB=0                                         -> nothing



# 2 bytes storage
DISP_NT()::
#DISP_WIDTH=0              -> nothing
DISP_WIDTH=8   DISP[d/8]   -> d/8
DISP_WIDTH=16  DISP[d/16]  -> d/16
DISP_WIDTH=32  DISP[d/32]  -> d/32
DISP_WIDTH=64  DISP[d/64]  -> d/64
otherwise                  -> nothing

ERROR()::
otherwise -> ERROR=XED_ERROR_GENERAL_ERROR

DISP_WIDTH_0()::
DISP_WIDTH=0 -> nothing

DISP_WIDTH_8():: 
DISP_WIDTH=8 -> nothing

DISP_WIDTH_16()::
DISP_WIDTH=16 -> nothing

DISP_WIDTH_32()::
DISP_WIDTH=32 -> nothing

DISP_WIDTH_0_8_16()::
DISP_WIDTH=0 -> nothing 
DISP_WIDTH=8 -> nothing
DISP_WIDTH=16 -> nothing


DISP_WIDTH_0_8_32()::
DISP_WIDTH=0 -> nothing 
DISP_WIDTH=8 -> nothing
DISP_WIDTH=32 -> nothing

