/*==============================================================================
 * FILE:       decoder.m
 * OVERVIEW:   This file contains the high level decoding functionality, for
 *              example matching logues, calls, branches, etc. Ordinary
 *              instructions are processed in decoder_low.m
 *
 * Copyright (C) 1998-2001, The University of Queensland, BT group
 *============================================================================*/ 
/*
 * $Revision: 1.3 $
 * 19 Jan 98 - Cristina
 *  Automatically generated by NJMC from 386-core.spec 
 *      (a scaled-down version of pentium-core.spec, NJMC v0.5*).
 *  Added code which I had previously added to scanner.m.pentium: 
 *      function signature for decode_instr(), global definitions 
 *      for asmprintf and asmprintfd, and fetch routines.
 *  Changed "reloc" variable name for "relocd" as NJMC v0.5* 
 *      has a problem with using the same name as relocatable names 
 *      Message: This can't happen: Bug in toolkit---can't use 
 *      relocatable name in matching statement (was `rethink projection')
 *      Similar change for "d" -> "dd" and "a" -> "ad"
 *  Separated instructions-only into one matching statement.  NJMC 
 *      generated several matching statements, one after the other
 *      without having self-contained matching statements.  
 *      I believe all the instructions were matched *twice*; about
 *      2000 lines were deleted.
 *  Several instructions rely on "index" which is not a field; 
 *      commented these out at present.   They have to do w/addr modes.
 *  After 35+ minutes running, NJMC v0.5* gives this error:
 *      Run-time error 301
 *      File expwalk.nw; Line 266
 *      evaluation stack overflow
 * 20 Jan 98 - Cristina
 *  Replaced all _ for . in names of patterns to be matched in order to 
 *      use the NJMC ML version (toolkitml).  Generates C file in few mins.
 *  Added matching statements for effective address and memory.  Removed
 *      generated dis_Eaddr() and dis_Mem() as they rely on other
 *      data structures, and replaced them for display routines w/same name. 
 *  Changed asmprintf to be fprintf, and asmprintfd to stdout, as the
 *      way the generated code is structured, it displays to asmprintfd 
 *      directly each subpart of the instruction; it can't buffer it!
 *  Added dis_unsigned_r32() which returns a string rather than prints it
 *      to asmprintfd.  This eliminates the large overhead of calls to print.
 *  Renamed get2Bytes() and get4Bytes() to getWord() and getDword() as these
 *      names are generated by toolkitml without regard to what is in 
 *      386dis.spec.
 *  The generated code references function asmprintreloc() which has the 
 *      following prototype in mclib.h:
 *          extern void (*asmprintreloc)(RAddr reloc); 
 *      I've replaced such calls for:
 *          asmprintf (asmprintfd, "%d (0x%x)", relocd, relocd);
 *  Renamed endPC to deltaPC as toolkitml returns in this variable the
 *      number of bytes parsed rather than the address for the next PC 
 *      (as per with NJMC v0.5*).
 * 22 Jan 98 - Cristina 
 *  Added LEA and lfp constructors to the matching statement as these were 
 *      missing from the original 386 & Pentium specs.  lfp matches to the 
 *      following: LDS, LES, LFS, LGS or LSS -- added one constructor for each.
 *  Changed Mem for Eaddr for construction CALL.Ev. 
 *  Added LEAVE constructor.
 *  Added dis_rel() function to display labelled names or offsets for 
 *      relocatable addresses (relocd).
 *  Placed NOP constructor first to XCHGeAXod as the former takes priority. 
 *  Replaced code for dis_signed_reg() to print the register as a 32-bit 
 *      register.  This assumption may not be right in all cases though.
 * 23 Jan 98 - Cristina
 *  Replaced "dis_signed_reg(i32)" for "dis_unsigned_i32(i32)".
 *  Replaced "dis_signed_reg(CS)" for "dis_unsigned_i16(CS)"; similar
 *      for IP.
 *
 * 29 Jan 98 - Mike
 *  Manually modified the cs:ip versions of call and jmp. The effect is
 *  to swap CS and IP (in both parameter and use), to prevent confusion.
 *  Changed dis_unsigned_i16 and i32 to display in hex for large
 *  values
 * 20 Oct 98 - Mike: Lower case register names
 * 21 Oct 88 - Mike: Changed from disassembler to rtl generator
 * 05 Nov 98 - Mike: Added Base, Base8, Base32 etc addressing modes
 * 11 Dec 98 - Mike: Added several FIXXX instructions; fixed MOVid and MOViw
 * 28 Jan 99 - Mike: Changed CMPS to not use address size overrides (av)
 * 03 Mar 99 - Doug
 *  - put everything into the NJMCDecoder class and added decodeInterface
 * 17 May 99 - Mike: mods for NJMCDecoder class, etc etc. Catch up with sparc
 * 11 Aug 99 - Mike: Added size arg to dis_Eaddr (for movsx etc)
 * 17 Aug 99 - Mike: Fixed register jumps and calls (was invalid instr)
 * 19 Apr 00 - Mike: Added isFunctionPrologue()
 * 28 Sep 00 - Mike: Added fp_names[] (names for float registers)
 * 08 Mar 01 - Mike: Added frameless_pro and frameless_epi logues
 * 13 Mar 01 - Mike: Added noPrologue boolean, so that once a prologue is
 *          matched, further "prologues" are treated as ordinary instructions.
 *          Needed for thirds.1 test
 * 30 Mar 01 - Mike: frameless callee prologue and epilogue can save and restore
 *          registers now
 * 09 Apr 01 - Mike: Added frameless_pro to isFuncPrologue()
 * 13 Aug 01 - Mike: There were still two "match [numBytes]" in there!
 * 06 Sep 01 - Mike: parameters are lists now (ere vectors); fixed unused "name"
 * 19 Oct 01 - Mike: Unconditional jumps to other procs handled now
*/

#include "global.h"
#include "decoder.h"
#include "prog.h"
#include "ss.h"
#include "rtl.h"
#include "proc.h"
#include "csr.h"
#include "386.pat.h"

/*==============================================================================
 * These arrays used to map register numbers to their names. These
 * must be the same names as used in the corresponding SSL file.
 *============================================================================*/

char *r32_names[] = {
    "%eax",
    "%ecx",
    "%edx",
    "%ebx",
    "%esp",
    "%ebp",
    "%esi",
    "%edi",
};
  
char *sr16_names[] = { 
    "??sr16=0?!", 
    "%cs", 
    "%ss", 
    "%ds", 
    "%es", 
    "%fs", 
    "%gs", 
    "??sr16=7?!", 
};
  

char *r8_names[] = {
    "%al",
    "%cl",
    "%dl",
    "%bl",
    "%ah",
    "%ch",
    "%dh",
    "%bh"
};
  

char *r16_names[] = { 
    "%ax", 
    "%cx", 
    "%dx", 
    "%bx", 
    "%sp", 
    "%bp", 
    "%si", 
    "%di"
};

char *fp_names[] = {
    "%st",
    "%st1",
    "%st2",
    "%st3",
    "%st4",
    "%st5",
    "%st6",
    "%st7"
};

/*==============================================================================
 * This array decodes scale field values in an index memory expression
 * to the scale factor they represent.
 *============================================================================*/
int scale[] = {1, 2, 4, 8};

/**********************************
 * NJMCDecoder methods.
 **********************************/   

/*==============================================================================
 * FUNCTION:       unused
 * OVERVIEW:       A dummy function to suppress "unused local variable" messages
 * PARAMETERS:     x: integer variable to be "used"
 * RETURNS:        Nothing
 *============================================================================*/
void unused(int x)
{}

/*==============================================================================
 * FUNCTION:        handleMemcpy
 * OVERVIEW:        Handle the memcpy pattern
 * PARAMETERS:      len - the length of the move
 *                  pc - native address of this instruction
 *                  decodeResult - result of the decode
 *                  numBytes - number of bytes this instruction
 *                  logue - pointer to the Logue for this pattern
 * RETURNS:         <nothing>, but reference parameter result updated
 *============================================================================*/
void handleMemcpy(int len, ADDRESS pc, DecodeResult& result, int numBytes,
    Logue* logue)
{
    /* The pattern:
     *  cld
     *  mov ecx, 3
     *  rep movsl
     *
     * which translates to
     *  memcpy(r[31], r[30], len);
     */
    
    HLCall* newCall = new HLCall(pc, 32, NULL);
    result.rtl = newCall;
    result.numBytes = numBytes;
    newCall->setPrologue(logue);

    // Set the name of the call
    newCall->setDestName("memcpy");
    // Need to force the parameter to the call to strlen, since we force
    // the name
    list<SemStr>* params = new list<SemStr>;
    SemStr* r31 = new SemStr;
    *r31 << idRegOf << idIntConst << 31;
    params->push_back(*r31);
    SemStr* r30 = new SemStr;
    *r30 << idRegOf << idIntConst << 30;
    params->push_back(*r30);
    SemStr* lenParam = new SemStr;
    *lenParam << idIntConst << len;
    params->push_back(*lenParam);
    newCall->setParams(*params);
    delete r31; delete r30; delete lenParam;

    SHOW_ASM("pat_memcpy " << len)
}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::decodeInstruction
 * OVERVIEW:       Decodes a machine instruction and returns an RTL instance. In
 *                 most cases a single instruction is decoded. However, if a
 *                 higher level construct that may consist of multiple
 *                 instructions is matched, then there may be a need to return
 *                 more than one RTL. The caller_prologue2 is an example of such
 *                 a construct which encloses an abritary instruction that must
 *                 be decoded into its own RTL.
 * PARAMETERS:     pc - the native address of the pc
 *                 delta - the difference between the above address and the
 *                   host address of the pc (i.e. the address that the pc is at
 *                   in the loaded object file)
 *                 RTLDict - the dictionary of RTL templates used to instantiate
 *                   the RTL for the instruction being decoded
 *                 proc - the enclosing procedure
 * RETURNS:        a DecodeResult structure containing all the information
 *                   gathered during decoding
 *============================================================================*/
DecodeResult& NJMCDecoder::decodeInstruction (ADDRESS pc, int delta,
    UserProc* proc /*= NULL*/)
{
    static DecodeResult result;
    ADDRESS hostPC = pc + delta;

    // Clear the result structure;
    result.reset();

    // The actual list of instantiated RTs
    list<RT*>* RTs = NULL;

    // Try matching a logue first
    int addr,regs,locals, stackSize, len;
    ADDRESS saveHostPC = hostPC;
    Logue* logue;
    bool noPrologue = true;     // True if no prologue matched yet
    if (proc != NULL)
        noPrologue = (proc->getPrologue() == NULL);

    if ((logue = InstructionPatterns::std_call(csr, hostPC, addr)) != NULL) {
        /*
         * Direct call
         */
        HLCall* newCall = new HLCall(pc, 0, RTs);
        result.rtl = newCall;
        result.numBytes = hostPC - saveHostPC;

        // Set the destination expression
        newCall->setDest(addr - delta);
        newCall->setPrologue(logue);

        SHOW_ASM("std_call " << hex << addr)

    }
    else if ((logue = InstructionPatterns::pat_strlen(csr, hostPC)) != NULL) {
        /*
         * The pattern:
         *  xorl   %eax,%eax
         *  cld    
         *  movl   $0xffffffff,%ecx
         *  repnz scasb %al,(%edi)
         * which translates to:
         *  r[24] := strlen(r[31]); ! %eax, %edi
         *  r[25] := -2 -r[24];     ! %ecs, %eax
         *  r[24] := 0;             ! %eax
         * We handle this by making it a HLCall with a null destination, but
         *  with a named destination (using setDestName), and two RTs for
         * negating r[25] and clearing %eax, in a postCallRtlist
         */

        // A list of RTs for the post call semantics
        list<RT*>* PCRTs = new list<RT*>;
        // First, the semantics for %ecx := -2 - %eax
        SemStr* left = new SemStr;
        left->push(idRegOf); left->push(idIntConst); left->push(25);
        SemStr* right = new SemStr;
        right->push(idMinus); right->push(idIntConst); right->push(-2);
        right->push(idRegOf); right->push(idIntConst); right->push(24);
        RTAssgn* rta = new RTAssgn(left, right, 32);
        PCRTs->push_back(rta);
 
        // Next, the semantics for %eax := 0
        SemStr* left2 = new SemStr;
        left2->push(idRegOf); left2->push(idIntConst); left2->push(24);
        SemStr* right2 = new SemStr;
        right2->push(idIntConst); right2->push(0);
        rta = new RTAssgn(left2, right2, 32);
        PCRTs->push_back(rta);

        HLCall* newCall = new HLCall(pc, 32, RTs);
        result.rtl = newCall;
        result.numBytes = hostPC - saveHostPC;
        newCall->setPrologue(logue);

        // Set the name of the call
        newCall->setDestName("strlen");
        // Set the post call semantics
        newCall->setPostCallRtlist(PCRTs);
        // Need to force the parameter to the call to strlen, since we force
        // the name
        list<SemStr>* params = new list<SemStr>;
        SemStr r31;
        r31 << idRegOf << idIntConst << 31;
        params->push_back(r31);
        newCall->setParams(*params);

        SHOW_ASM("pat_strlen ")

    }
    else if ((logue = InstructionPatterns::pat_memcpy_11(csr, hostPC, len))
      != NULL) {
        handleMemcpy(len*4+3, pc, result, hostPC - saveHostPC, logue);
    }  
    else if ((logue = InstructionPatterns::pat_memcpy_10(csr, hostPC, len))
      != NULL) {
        handleMemcpy(len*4+2, pc, result, hostPC - saveHostPC, logue);
    }  
    else if ((logue = InstructionPatterns::pat_memcpy_01(csr, hostPC, len))
      != NULL) {
        handleMemcpy(len*4+1, pc, result, hostPC - saveHostPC, logue);
    }  
    else if ((logue = InstructionPatterns::pat_memcpy_00(csr, hostPC, len))
      != NULL) {
        handleMemcpy(len*4+0, pc, result, hostPC - saveHostPC, logue);
    }  

    // Test for the callee prologues. Note that we only want to do this if
    // there isn't already a callee prologue for this procedure. For example
    // many Pentium programs have a subtract from stack pointer instruction
    // which matches a callee prologue; any time after the first prologue
    // is recorded, we don't want to match this (because the semantics of
    // logues is suppressed). Hence the "noPrologue &&" in the below

    else if (noPrologue && (logue = InstructionPatterns::struct_ptr(csr, hostPC,
      locals, regs)) != NULL) {
        /*
         * Callee that return a struct and immediately pops the
         * struct pointer off the stack into %eax
         */
        if (proc != NULL) {

            // Record the prologue of this callee
            assert(logue->getType() == Logue::CALLEE_PROLOGUE);
            proc->setPrologue((CalleePrologue*)logue);
        }
        result.rtl = new RTL(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("struct_ptr "<<locals<<" "<<regs)

    }
    else if (noPrologue && (logue = InstructionPatterns::std_entry(csr, hostPC,
      locals, regs)) != NULL) {
        /*
         * Callee that returns a scalar (or void) value or
         * returns a struct but doesn't use the previous prologue 
         */
        if (proc != NULL) {

            // Record the prologue of this callee
            assert(logue->getType() == Logue::CALLEE_PROLOGUE);
            proc->setPrologue((CalleePrologue*)logue);
        }
        result.rtl = new RTL(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("std_entry " << locals << " " << regs)

    }
    else if (noPrologue && (logue = InstructionPatterns::frameless_pro(csr,
      hostPC, locals, regs)) != NULL) {
        /*
         * Callee that has no frame
         */
        if (proc != NULL) {

            // Record the prologue of this callee
            assert(logue->getType() == Logue::CALLEE_PROLOGUE);
            proc->setPrologue((CalleePrologue*)logue);
        }
        result.rtl = new RTL(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("frameless_pro " << locals << " " << regs)

    }
    else if ((logue = InstructionPatterns::std_ret(csr, hostPC)) != NULL) {
        /*
         * A return that restores any preserved registers.
         */
        if (proc!= NULL) {

            // Record the epilogue of this callee
            assert(logue->getType() == Logue::CALLEE_EPILOGUE);
            proc->setEpilogue((CalleeEpilogue*)logue);
        }

        result.rtl = new HLReturn(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("std_ret")
    }
    else if ((logue = InstructionPatterns::frameless_epi(csr, hostPC,
      stackSize)) != NULL) {
        /*
         * Epilogue for frameless procedures
         * Note: match before clear_stack
         */
        if (proc!= NULL) {

            // Record the epilogue of this callee
            assert(logue->getType() == Logue::CALLEE_EPILOGUE);
            proc->setEpilogue((CalleeEpilogue*)logue);
        }

        result.rtl = new HLReturn(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("frameless_epi " << stackSize)

    }
#if 0
    else if ((logue = InstructionPatterns::simple_ret(csr, hostPC)) != NULL) {
        /*
         * Catch all for bare returns
         */
        if (proc!= NULL) {

            // Record the epilogue of this callee
            assert(logue->getType() == Logue::CALLEE_EPILOGUE);
            proc->setEpilogue((CalleeEpilogue*)logue);
        }

        result.rtl = new HLReturn(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
        SHOW_ASM("simple_ret")

    }
#endif
    else if ((logue = InstructionPatterns::clear_stack(csr,
        hostPC, stackSize)) != NULL)
    {
        /*
         * Remove params from stack
         */
        RTs = instantiate(pc, "clear_stack", dis_Num(stackSize));

        result.rtl = new RTL(pc, RTs);
        result.numBytes = hostPC - saveHostPC;
    }
    else {

        ADDRESS nextPC;
        match [nextPC] hostPC to
        
        | CALL.Evod(Eaddr) =>
            /*
             * Register call
             */
            // Mike: there should probably be a HLNwayCall class for this!
            HLCall* newCall = new HLCall(pc, 0, RTs);
            // Record the fact that this is a computed call
            newCall->setIsComputed();
            // Set the destination expression
            newCall->setDest(DIS_EADDR32);
            result.rtl = newCall;
            // Only one instruction, so size of result is size of this decode
            result.numBytes = nextPC - hostPC;
    
        | JMP.Evod(Eaddr) =>
            /*
             * Register jump
             */
            HLNwayJump* newJump = new HLNwayJump(pc, RTs);
            // Record the fact that this is a computed call
            newJump->setIsComputed();
            // Set the destination expression
            newJump->setDest(DIS_EADDR32);
            result.rtl = newJump;
            // Only one instruction, so size of result is size of this decode
            result.numBytes = nextPC - hostPC;
        
        /*
         * Unconditional branches
         */
        | JMP.Jvod(relocd) [name] =>
            unused((int) name);
            unconditionalJump(name, 5, relocd, proc, delta, pc, RTs, result);
        | JMP.Jvow(relocd) [name] =>
            unused((int) name);
            unconditionalJump(name, 3, relocd, proc, delta, pc, RTs, result);
        | JMP.Jb(relocd) [name] =>
            unused((int) name);
            unconditionalJump(name, 2, relocd, proc, delta, pc, RTs, result);
    
        /*
         * Conditional branches, 8 bit offset: 7X XX
         */
        | Jb.NLE(relocd) =>
            COND_JUMP("Jb.NLE", 2, relocd, HLJCOND_JSG)
        | Jb.LE(relocd) =>
            COND_JUMP("Jb.LE", 2, relocd, HLJCOND_JSLE)
        | Jb.NL(relocd) =>
            COND_JUMP("Jb.NL", 2, relocd, HLJCOND_JSGE)
        | Jb.L(relocd) =>
            COND_JUMP("Jb.L", 2, relocd, HLJCOND_JSL)
        | Jb.NP(relocd) =>
            COND_JUMP("Jb.NP", 2, relocd, (JCOND_TYPE)0)
        | Jb.P(relocd) =>
            COND_JUMP("Jb.P", 2, relocd, HLJCOND_JPAR)
        | Jb.NS(relocd) =>
            COND_JUMP("Jb.NS", 2, relocd, HLJCOND_JPOS)
        | Jb.S(relocd) =>
            COND_JUMP("Jb.S", 2, relocd, HLJCOND_JMI)
        | Jb.NBE(relocd) =>
            COND_JUMP("Jb.NBE", 2, relocd, HLJCOND_JUG)
        | Jb.BE(relocd) =>
            COND_JUMP("Jb.BE", 2, relocd, HLJCOND_JULE)
        | Jb.NZ(relocd) =>
            COND_JUMP("Jb.NZ", 2, relocd, HLJCOND_JNE)
        | Jb.Z(relocd) =>
            COND_JUMP("Jb.Z", 2, relocd, HLJCOND_JE)
        | Jb.NB(relocd) =>
            COND_JUMP("Jb.NB", 2, relocd, HLJCOND_JUGE)
        | Jb.B(relocd) =>
            COND_JUMP("Jb.B", 2, relocd, HLJCOND_JUL)
        | Jb.NO(relocd) =>
            COND_JUMP("Jb.NO", 2, relocd, (JCOND_TYPE)0)
        | Jb.O(relocd) =>
            COND_JUMP("Jb.O", 2, relocd, (JCOND_TYPE)0)
    
        /*
         * Conditional branches, 16 bit offset: 66 0F 8X XX XX
         */
        | Jv.NLEow(relocd) =>
            COND_JUMP("Jv.NLEow", 4, relocd, HLJCOND_JSG)
        | Jv.LEow(relocd) =>
            COND_JUMP("Jv.LEow", 4, relocd, HLJCOND_JSLE)
        | Jv.NLow(relocd) =>
            COND_JUMP("Jv.NLow", 4, relocd, HLJCOND_JSGE)
        | Jv.Low(relocd) =>
            COND_JUMP("Jv.Low", 4, relocd, HLJCOND_JSL)
        | Jv.NPow(relocd) =>
            COND_JUMP("Jv.NPow", 4, relocd, (JCOND_TYPE)0)
        | Jv.Pow(relocd) =>
            COND_JUMP("Jv.Pow", 4, relocd, HLJCOND_JPAR)
        | Jv.NSow(relocd) =>
            COND_JUMP("Jv.NSow", 4, relocd, HLJCOND_JPOS)
        | Jv.Sow(relocd) =>
            COND_JUMP("Jv.Sow", 4, relocd, HLJCOND_JMI)
        | Jv.NBEow(relocd) =>
            COND_JUMP("Jv.NBEow", 4, relocd, HLJCOND_JUG)
        | Jv.BEow(relocd) =>
            COND_JUMP("Jv.BEow", 4, relocd, HLJCOND_JULE)
        | Jv.NZow(relocd) =>
            COND_JUMP("Jv.NZow", 4, relocd, HLJCOND_JNE)
        | Jv.Zow(relocd) =>
            COND_JUMP("Jv.Zow", 4, relocd, HLJCOND_JE)
        | Jv.NBow(relocd) =>
            COND_JUMP("Jv.NBow", 4, relocd, HLJCOND_JUGE)
        | Jv.Bow(relocd) =>
            COND_JUMP("Jv.Bow", 4, relocd, HLJCOND_JUL)
        | Jv.NOow(relocd) =>
            COND_JUMP("Jv.NOow", 4, relocd, (JCOND_TYPE)0)
        | Jv.Oow(relocd) =>
            COND_JUMP("Jv.Oow", 4, relocd, (JCOND_TYPE)0)
    
        /*
         * Conditional branches, 32 bit offset: 0F 8X XX XX XX XX
         */
        | Jv.NLEod(relocd) =>
            COND_JUMP("Jv.NLEod", 6, relocd, HLJCOND_JSG)
        | Jv.LEod(relocd) =>
            COND_JUMP("Jv.LEod", 6, relocd, HLJCOND_JSLE)
        | Jv.NLod(relocd) =>
            COND_JUMP("Jv.NLod", 6, relocd, HLJCOND_JSGE)
        | Jv.Lod(relocd) =>
            COND_JUMP("Jv.Lod", 6, relocd, HLJCOND_JSL)
        | Jv.NPod(relocd) =>
            COND_JUMP("Jv.NPod", 6, relocd, (JCOND_TYPE)0)
        | Jv.Pod(relocd) =>
            COND_JUMP("Jv.Pod", 6, relocd, HLJCOND_JPAR)
        | Jv.NSod(relocd) =>
            COND_JUMP("Jv.NSod", 6, relocd, HLJCOND_JPOS)
        | Jv.Sod(relocd) =>
            COND_JUMP("Jv.Sod", 6, relocd, HLJCOND_JMI)
        | Jv.NBEod(relocd) =>
            COND_JUMP("Jv.NBEod", 6, relocd, HLJCOND_JUG)
        | Jv.BEod(relocd) =>
            COND_JUMP("Jv.BEod", 6, relocd, HLJCOND_JULE)
        | Jv.NZod(relocd) =>
            COND_JUMP("Jv.NZod", 6, relocd, HLJCOND_JNE)
        | Jv.Zod(relocd) =>
            COND_JUMP("Jv.Zod", 6, relocd, HLJCOND_JE)
        | Jv.NBod(relocd) =>
            COND_JUMP("Jv.NBod", 6, relocd, HLJCOND_JUGE)
        | Jv.Bod(relocd) =>
            COND_JUMP("Jv.Bod", 6, relocd, HLJCOND_JUL)
        | Jv.NOod(relocd) =>
            COND_JUMP("Jv.NOod", 6, relocd, (JCOND_TYPE)0)
        | Jv.Ood(relocd) =>
            COND_JUMP("Jv.Ood", 6, relocd, (JCOND_TYPE)0)
    
        | SETb.NLE(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JSG)
        | SETb.LE(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JSLE)
        | SETb.NL(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JSGE)
        | SETb.L(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JSL)
        //| SETb.NP(Eaddr) [name] =>
        //  RTs = instantiate(pc, name, DIS_EADDR8);
        //  SETS(name, DIS_EADDR8, HLJCOND_JSG)
        //| SETb.P(Eaddr) [name] =>
        //  RTs = instantiate(pc, name, DIS_EADDR8);
        //  SETS(name, DIS_EADDR8, HLJCOND_JSG)
        | SETb.NS(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JPOS)
        | SETb.S(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JMI)
        | SETb.NBE(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JUG)
        | SETb.BE(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JULE)
        | SETb.NZ(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JNE)
        | SETb.Z(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JE)
        | SETb.NB(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JUGE)
        | SETb.B(Eaddr) [name] =>
            RTs = instantiate(pc, name, DIS_EADDR8);
            SETS(name, DIS_EADDR8, HLJCOND_JUL)
        //| SETb.NO(Eaddr) [name] =>
        //  RTs = instantiate(pc, name, DIS_EADDR8);
        //  SETS(name, DIS_EADDR8, HLJCOND_JSG)
        //| SETb.O(Eaddr) [name] =>
        //  RTs = instantiate(pc, name, DIS_EADDR8);
        //  SETS(name, DIS_EADDR8, HLJCOND_JSG)
    
    else
            result.rtl = new RTL(pc,
                decodeLowLevelInstruction(hostPC, pc, result));
        endmatch
    }
    return result;
}

/*==============================================================================
 * These are machine specific functions used to decode instruction
 * operands into SemStrs.
 *============================================================================*/

/*==============================================================================
 * FUNCTION:        dis_Mem
 * OVERVIEW:        Converts a dynamic address to a SemStr expression.
 *                  E.g. [1000] --> m[, 1000
 * PARAMETERS:      pc - the address of the Eaddr part of the instr
 *                  expr - the expression that will be built
 * RETURNS:         the SemStr representation of the given Eaddr
 *============================================================================*/
SemStr* NJMCDecoder::dis_Mem(ADDRESS pc)
{
    SemStr* expr = new SemStr();

    match pc to 
    | Abs32 (a) =>
            // [a]
            expr->push(idMemOf);
            expr->push(idIntConst);
            expr->push(a);
    | Disp32 (d, base) => 
            // m[ r[ reg] + d]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);       // Always 32 bit register
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
    | Disp8 (d, r32) => 
            // m[ r[ r32] + d]
            SemStr* baseSS = dis_Reg(r32_names[r32]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
    | Index (base, index, ss) =>
            // m[ r[base] + r[index] * ss]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            SemStr* indexSS = dis_Reg(r32_names[index]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idMult);
            expr->push(idRegOf);
            expr->pushSS(indexSS);
            expr->push(idIntConst);
            expr->push(scale[ss]);
            delete baseSS;
            delete indexSS;
    | Base (base) =>
            // m[ r[base] ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            expr->push(idMemOf);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            delete baseSS;
    | Index32 (d, base, index, ss) =>
            // m[ r[ base ] + r[ index ] * ss + d ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            SemStr* indexSS = dis_Reg(r32_names[index]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idMult);
            expr->push(idRegOf);
            expr->pushSS(indexSS);
            expr->push(idIntConst);
            expr->push(scale[ss]);
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
            delete indexSS;
    | Base32 (d, base) =>
            // m[ r[ base] + d ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
    | Index8 (d, base, index, ss) =>
            // m[ r[ base ] + r[ index ] * ss + d ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            SemStr* indexSS = dis_Reg(r32_names[index]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idMult);
            expr->push(idRegOf);
            expr->pushSS(indexSS);
            expr->push(idIntConst);
            expr->push(scale[ss]);
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
            delete indexSS;
    | Base8 (d, base) =>
            // m[ r[ base] + d ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            expr->push(idIntConst);
            expr->push(d);
            delete baseSS;
    | Indir (base) => 
            // m[ r[reg] ]
            SemStr* baseSS = dis_Reg(r32_names[base]);
            expr->push(idMemOf);
            expr->push(idRegOf);
            expr->pushSS(baseSS);
            delete baseSS;
    | ShortIndex (d, index, ss) =>
            // m[ r[index] * ss + d ]
            SemStr* indexSS = dis_Reg(r32_names[index]);
            expr->push(idMemOf);
            expr->push(idPlus);
            expr->push(idMult);
            expr->push(idRegOf);
            expr->pushSS(indexSS);
            expr->push(idIntConst);
            expr->push(scale[ss]);
            expr->push(idIntConst);
            expr->push(d);
    | IndirMem (d) =>
            // [d] (Same as Abs32 using SIB)
            expr->push(idMemOf);
            expr->push(idIntConst);
            expr->push(d);
    endmatch
    return expr;
}

/*==============================================================================
 * FUNCTION:        dis_Eaddr
 * OVERVIEW:        Converts a dynamic address to a SemStr expression.
 *                  E.g. %ecx --> regOf, 25
 * CALLED FROM:     Macros DIS_EADDR32, DIS_EADDR16 and DIS_EADDR8 (see
 *                    HEADERS/decoder.h)
 * PARAMETERS:      pc - the instruction stream address of the dynamic
 *                    address
 *                  size - size of the operand (important if a register)
 * RETURNS:         the SemStr representation of the given Eaddr
 *============================================================================*/
SemStr* NJMCDecoder::dis_Eaddr(ADDRESS pc, int size)
{
    match pc to
    | E (mem) =>
        return dis_Mem (mem);
    | Reg (reg) =>
        SemStr* str;
        switch(size) {
            case 32: str = dis_Reg(r32_names[reg]); break;
            case 16: str = dis_Reg(r16_names[reg]); break;
            case  8: str = dis_Reg( r8_names[reg]); break;
        }
        str->prep(idRegOf);
        return str;
    endmatch
}

/*==============================================================================
 * FUNCTION:      isFuncPrologue()
 * OVERVIEW:      Check to see if the instructions at the given offset match
 *                  any callee prologue, i.e. does it look like this offset
 *                  is a pointer to a function?
 * PARAMETERS:    hostPC - pointer to the code in question (native address)
 * RETURNS:       True if a match found
 *============================================================================*/
bool isFuncPrologue(ADDRESS hostPC)
{
    int locals, regs;
    if ((InstructionPatterns::frameless_pro(prog.csrSrc, hostPC, locals, regs))
        != NULL)
            return true;
    if ((InstructionPatterns::struct_ptr(prog.csrSrc, hostPC, locals, regs))
        != NULL)
            return true;
    if ((InstructionPatterns::std_entry(prog.csrSrc, hostPC, locals, regs))
        != NULL)
            return true;

    return false;
}


/**********************************
 * These are the fetch routines.
 **********************************/   

/*==============================================================================
 * FUNCTION:        getWord
 * OVERVIEW:        Returns the word starting at the given address.
 * PARAMETERS:      lc - address at which to decode the double
 * RETURNS:         the decoded double
 *============================================================================*/
Byte getByte (unsigned lc)
/* getByte - returns next byte from image pointed to by lc.  */
{
    return *(Byte *)lc;
}

/*==============================================================================
 * FUNCTION:        getWord
 * OVERVIEW:        Returns the word starting at the given address.
 * PARAMETERS:      lc - address at which to decode the double
 * RETURNS:         the decoded double
 *============================================================================*/
SWord getWord (unsigned lc)
/* get2Bytes - returns next 2-Byte from image pointed to by lc.  */
{
    return (SWord)(*(Byte *)lc + (*(Byte *)(lc+1) << 8));
}

/*==============================================================================
 * FUNCTION:        getDword
 * OVERVIEW:        Returns the double starting at the given address.
 * PARAMETERS:      lc - address at which to decode the double
 * RETURNS:         the decoded double
 *============================================================================*/
DWord getDword (unsigned lc)
/* get4Bytes - returns the next 4-Byte word from image pointed to by lc. */
{
    return (DWord)(*(Byte *)lc + (*(Byte *)(lc+1) << 8) +
        (*(Byte *)(lc+2) << 16) + (*(Byte *)(lc+3) << 24));
}



