#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
# any of the things in {} can trigger the action for these
# the letters in square brackets are bound to the bits after the arrow.
# The [] brackets are like an OR-triggering function.

# For encoding, we spell out the order of the legacy prefixes and rex
# prefixes. On decode, the sequential semantics were used to zero out
# the effects of rex prefixes but that doesn't work for encode. So we
# have to make a different table for encoding.


SEQUENCE ISA_ENCODE
   ISA_BINDINGS
   ISA_EMIT

# These bind the operand deciders that control the encoding
SEQUENCE ISA_BINDINGS
   FIXUP_EOSZ_ENC_BIND()
   FIXUP_EASZ_ENC_BIND()
   ASZ_NONTERM_BIND()  
   INSTRUCTIONS_BIND()    
   OSZ_NONTERM_ENC_BIND()   # OSZ must be after the instructions so that DF64 is bound (and before any prefixes obviously)
   PREFIX_ENC_BIND() 
   REX_PREFIX_ENC_BIND() 

# These emit the bits and bytes that make up the encoding
SEQUENCE ISA_EMIT
   PREFIX_ENC_EMIT() 
   REX_PREFIX_ENC_EMIT() 
   INSTRUCTIONS_EMIT()  # THIS TAKES CARE OF MODRM/SIB/DISP/IMM


FIXUP_EOSZ_ENC()::
mode16 EOSZ=0 -> EOSZ=1
mode32 EOSZ=0 -> EOSZ=2
mode64 EOSZ=0 -> EOSZ=2
otherwise -> nothing

FIXUP_EASZ_ENC()::
mode16 EASZ=0 -> EASZ=1
mode32 EASZ=0 -> EASZ=2
mode64 EASZ=0 -> EASZ=3
otherwise -> nothing

FIXUP_SMODE_ENC()::
mode64 SMODE=0 -> SMODE=2
mode64 SMODE=1 -> error
otherwise -> nothing

# FIXME: make ICLASS a possible field?
# Remove the segment override if any supplied, from an LEA
REMOVE_SEGMENT()::
AGEN=0  -> nothing
AGEN=1  -> REMOVE_SEGMENT_AGEN1()

REMOVE_SEGMENT_AGEN1()::
SEG0=@      -> nothing
SEG0=SEGe() -> error


# need to emit a segment override if the segment is not the default segment for the operation.
# These are only meant for use with the things that do not use MODRM (like xlat, A0-A3 MOVs, and the string ops).
# (MODRM encoding handles this stuff much better).
OVERRIDE_SEG0()::
SEG0=@            -> SEG_OVD=0
SEG0=XED_REG_DS   -> SEG_OVD=0
SEG0=XED_REG_CS   -> SEG_OVD=1 
SEG0=XED_REG_ES   -> SEG_OVD=3 
SEG0=XED_REG_FS   -> SEG_OVD=4
SEG0=XED_REG_GS   -> SEG_OVD=5
SEG0=XED_REG_SS   -> SEG_OVD=6

OVERRIDE_SEG1()::
SEG1=@           -> SEG_OVD=0 
SEG1=XED_REG_DS  -> SEG_OVD=0 
SEG1=XED_REG_CS  -> SEG_OVD=1 
SEG1=XED_REG_ES  -> SEG_OVD=3 
SEG1=XED_REG_FS  -> SEG_OVD=4
SEG1=XED_REG_GS  -> SEG_OVD=5
SEG1=XED_REG_SS  -> SEG_OVD=6



REX_PREFIX_ENC()::
#### REX2 ####
# NOREX2=1 : Illegal REX2 prefix
# REX2=1   : opcode refining prefix (REX2 is required)
#
# Set the REX2 operand to skip a later escape byte emit
# MAP must be in [0,1]. This check is executed as part of the encoder input checks set
# so we don't need to double check it here
mode64  NOREX=0 NOREX2=0 REX2=1  REXR4[u] REXX4[y] REXB4[z] MAP[m] REXW[w] REXR[r] REXX[x] REXB[b] -> 0xd5 muyz_wrxb
mode64  NOREX=0 NOREX2=0         REXR4[u]=1 REXX4[y] REXB4[z] MAP[m] REXW[w] REXB[b] REXX[x] REXR[r] -> 0xd5 muyz_wrxb REX2=1
mode64  NOREX=0 NOREX2=0         REXR4[u] REXX4[y]=1 REXB4[z] MAP[m] REXW[w] REXB[b] REXX[x] REXR[r] -> 0xd5 muyz_wrxb REX2=1
mode64  NOREX=0 NOREX2=0         REXR4[u] REXX4[y] REXB4[z]=1 MAP[m] REXW[w] REXB[b] REXX[x] REXR[r] -> 0xd5 muyz_wrxb REX2=1
mode64  NOREX2=1  REX2=1      -> error
mode64  NOREX2=1  REXB4=1     -> error
mode64  NOREX2=1  REXX4=1     -> error
mode64  NOREX2=1  REXR4=1     -> error

#### REX ####
mode64  REX2=0 NOREX=0  NEEDREX=1 REXR4=0 REXX4=0 REXB4=0 REXW[w] REXB[b] REXX[x] REXR[r]  -> 0b0100 wrxb
mode64  REX2=0 NOREX=0  REX=1     REXR4=0 REXX4=0 REXB4=0 REXW[w] REXB[b] REXX[x] REXR[r]  -> 0b0100 wrxb
mode64  REX2=0 NOREX=0            REXR4=0 REXX4=0 REXB4=0 REXW[w]=1 REXB[b] REXX[x] REXR[r] -> 0b0100 wrxb
mode64  REX2=0 NOREX=0            REXR4=0 REXX4=0 REXB4=0 REXW[w] REXB[b]=1 REXX[x] REXR[r] -> 0b0100 wrxb
mode64  REX2=0 NOREX=0            REXR4=0 REXX4=0 REXB4=0 REXW[w] REXB[b] REXX[x]=1 REXR[r] -> 0b0100 wrxb
mode64  REX2=0 NOREX=0            REXR4=0 REXX4=0 REXB4=0 REXW[w] REXB[b] REXX[x] REXR[r]=1 -> 0b0100 wrxb
mode64  NOREX=1  NEEDREX=1  -> error
mode64  NOREX=1  REX=1      -> error
mode64  NOREX=1  REXW=1     -> error
mode64  NOREX=1  REXB=1     -> error
mode64  NOREX=1  REXX=1     -> error
mode64  NOREX=1  REXR=1     -> error

#### No REX/2 (All modes) ####
HAS_EGPR=0 NEEDREX=0 REX=0 REX2=0 REXR4=0 REXX4=0 REXB4=0 REXW=0 REXB=0 REXX=0 REXR=0 -> nothing
# or die...
otherwise                                                        -> error

# This checks that we didn't try to use a byte register that requires
# we do not have a rex with something else that requires we have a REX
# prefix.

# FIXME: need to allow repeated prefixes

# FIXME: optionally allow for prefix order to be specified (from decode)

PREFIX_ENC()::
# create an "OR" of REFINING=2 and REP=2
VV0 REP=2 -> 0xf2 no_return
VV0 REP=3 -> 0xf3 no_return
#
VV0 66_prefix              -> 0x66 no_return
67_prefix                  -> 0x67 no_return
lock_prefix                -> 0xf0 no_return
fs_prefix                  -> 0x64 no_return
gs_prefix                  -> 0x65 no_return
####################################################
mode64 HINT=3              -> 0x2e no_return
mode64 HINT=4              -> 0x3e no_return
mode64 HINT=5              -> 0x3e no_return # CET NO-TRACK
#####################################################
not64 cs_prefix            -> 0x2e no_return
not64 HINT=3               -> 0x2e no_return
not64 ds_prefix            -> 0x3e no_return
not64 HINT=4               -> 0x3e no_return
not64 HINT=5               -> 0x3e no_return # CET NO-TRACK
not64 es_prefix            -> 0x26 no_return
not64 ss_prefix            -> 0x36 no_return
otherwise                  -> nothing


##########################################################################
#
#
# This is the encode version. It just sets DF64 for later use by the
# OSZ_NONTERM_ENC() nonterminal. 
#
DF64()::
mode16 -> nothing
mode32 -> nothing
mode64 -> DF64=1 ### EOSZ=3 -- removed EOSZ=3 because it broke encoding pop 16b dx in 64b mode.

#
# If an instruction pattern sets W to zero or 1, we make sure it also
# sets SKIP_OSZ=1 so that we do not do any overwrite of that value for
# the EOSZ computation.
#
OSZ_NONTERM_ENC()::
VEXVALID=0 mode16 EOSZ=1        -> nothing
VEXVALID=0 mode16 EOSZ=2 DF32=1 -> nothing

# We don't use SKIP_OSZ=1 with the MOV_CR instructions but this is
#  here for completeness.
#VEXVALID=0 mode16 EOSZ=2 DF32=0 SKIP_OSZ=1       -> nothing
#VEXVALID=0 mode16 EOSZ=2 DF32=0 SKIP_OSZ=0       -> 66_prefix
VEXVALID=0 mode16 EOSZ=2 DF32=0      -> 66_prefix

#VEXVALID=0 mode32 EOSZ=1 SKIP_OSZ=1  -> nothing
#VEXVALID=0 mode32 EOSZ=1 SKIP_OSZ=0  -> 66_prefix
VEXVALID=0 mode32 EOSZ=1  -> 66_prefix

VEXVALID=0 mode32 EOSZ=2        -> nothing

#VEXVALID=0 mode64 EOSZ=1 SKIP_OSZ=1   -> nothing
#VEXVALID=0 mode64 EOSZ=1 SKIP_OSZ=0   -> 66_prefix
VEXVALID=0 mode64 EOSZ=1  -> 66_prefix

VEXVALID=0 mode64 EOSZ=2 DF64=1 -> error
VEXVALID=0 mode64 EOSZ=2 DF64=0 -> nothing 
VEXVALID=0 mode64 EOSZ=3 DF64=1 -> nothing

#VEXVALID=0 mode64 EOSZ=3 DF64=0 SKIP_OSZ=1 -> nothing
#VEXVALID=0 mode64 EOSZ=3 DF64=0 SKIP_OSZ=0 -> REXW=1
VEXVALID=0 mode64 EOSZ=3 DF64=0 -> REXW=1

otherwise -> nothing

# The REFINING66() decode version is required for when we have a 66
# prefix that should not change the EOSZ. The REFINING66() decode
# nonterminal restores that EOSZ.
#
# This one, the REFINING66() encode version is required for
# compatibility, but it doesn't do anything. The EOSZ is an input to
# the endoder.
#
# Turn off the REP prefix in case we are switching forms.
REFINING66()::
otherwise -> nothing # norep works too
IGNORE66()::
otherwise -> nothing 

# Same for IMMUNE66() used for sttni/cmpxchg8B/cmpxchg16b. We do not want to emit a 66 prefix in 32b mode
IMMUNE66()::
mode16        -> EOSZ=2 DF32=1
otherwise     -> nothing


IMMUNE66_LOOP64()::
otherwise -> nothing

IMMUNE_REXW()::
otherwise -> nothing

CR_WIDTH()::
mode16 -> DF32=1 EOSZ=2
mode32 -> nothing
mode64 -> DF64=1 EOSZ=3

FORCE64()::
otherwise -> DF64=1 EOSZ=3


# the prefix encoder does all the required work.
BRANCH_HINT()::
otherwise  -> nothing
# the prefix encoder does all the required work.
CET_NO_TRACK()::
otherwise  -> nothing

# end of xed-prefixes-encode.txt
##########################################################################
