685 lines
17 KiB
C
685 lines
17 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
regs.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file provides disassembly ( alpha )
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Miche Baker-Harvey (v-michbh) 1-May-1993 (ported from ntsd)
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include <windows.h>
|
|||
|
#include <stddef.h>
|
|||
|
#include <string.h>
|
|||
|
#include <stdio.h>
|
|||
|
|
|||
|
#include <alphaops.h>
|
|||
|
#include "disasm.h"
|
|||
|
#include "regs.h"
|
|||
|
#include "optable.h"
|
|||
|
|
|||
|
#include "drwatson.h"
|
|||
|
#include "proto.h"
|
|||
|
|
|||
|
void BlankFill(ULONG);
|
|||
|
void OutputHex(ULONG, ULONG, BOOLEAN);
|
|||
|
|
|||
|
void OutputEffectiveAddress(PDEBUGPACKET, ULONG);
|
|||
|
void OutputString(char *);
|
|||
|
void OutputReg(ULONG);
|
|||
|
void OutputFReg(ULONG);
|
|||
|
void GetNextOffset(PDEBUGPACKET, PULONG, BOOLEAN);
|
|||
|
ULONG GetIntRegNumber(ULONG);
|
|||
|
|
|||
|
|
|||
|
ALPHA_INSTRUCTION disinstr;
|
|||
|
|
|||
|
extern PUCHAR pszReg[];
|
|||
|
|
|||
|
BOOLEAN disasm(PDEBUGPACKET, PDWORD, PUCHAR, BOOLEAN);
|
|||
|
|
|||
|
|
|||
|
static char *pBufStart;
|
|||
|
static char *pBuf;
|
|||
|
|
|||
|
|
|||
|
#define OPRNDCOL 27 // Column for first operand
|
|||
|
#define EACOL 40 // column for effective address
|
|||
|
#define FPTYPECOL 40 // .. for the type of FP instruction
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
disasm (PDEBUGPACKET dp, PDWORD poffset, PUCHAR bufptr, BOOLEAN fEAout)
|
|||
|
{
|
|||
|
static initialized = 0;
|
|||
|
ULONG opcode;
|
|||
|
ULONG Ea; // Effective Address
|
|||
|
POPTBLENTRY pEntry;
|
|||
|
|
|||
|
if (!initialized) {
|
|||
|
opTableInit();
|
|||
|
initialized = 1;
|
|||
|
}
|
|||
|
pBufStart = pBuf = bufptr; // Initialize pointers to buffer that
|
|||
|
// will receive the disassembly text
|
|||
|
OutputHex(*poffset, 8, FALSE);// Output Hex address of instruction
|
|||
|
*pBuf++ = ':';
|
|||
|
*pBuf++ = ' ';
|
|||
|
|
|||
|
if (!DoMemoryRead( dp,
|
|||
|
(LPVOID)*poffset,
|
|||
|
(LPVOID)&disinstr.Long,
|
|||
|
sizeof(DWORD),
|
|||
|
NULL
|
|||
|
)) {
|
|||
|
OutputString("???????? ????");
|
|||
|
*pBuf = '\0';
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
OutputHex(disinstr.Long, 8, FALSE); // Output instruction in Hex
|
|||
|
*pBuf++ = ' ';
|
|||
|
|
|||
|
opcode = disinstr.Memory.Opcode; // Select disassembly procedure from
|
|||
|
|
|||
|
pEntry = findOpCodeEntry(opcode); // Get non-func entry for this code
|
|||
|
if (pEntry == (POPTBLENTRY)-1) {
|
|||
|
OutputString("??????? ????");
|
|||
|
*pBuf = '\0';
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
switch (pEntry->iType) {
|
|||
|
case ALPHA_UNKNOWN:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_MEMORY:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.Memory.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputHex(disinstr.Memory.MemDisp, (WIDTH_MEM_DISP + 3)/4, TRUE );
|
|||
|
*pBuf++ = '(';
|
|||
|
OutputReg(disinstr.Memory.Rb);
|
|||
|
*pBuf++ = ')';
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_FP_MEMORY:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputFReg(disinstr.Memory.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputHex(disinstr.Memory.MemDisp, (WIDTH_MEM_DISP + 3)/4, TRUE );
|
|||
|
*pBuf++ = '(';
|
|||
|
OutputReg(disinstr.Memory.Rb);
|
|||
|
*pBuf++ = ')';
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_MEMSPC:
|
|||
|
OutputString(findFuncName(pEntry, disinstr.Memory.MemDisp & BITS_MEM_DISP));
|
|||
|
//
|
|||
|
// Some memory special instructions have an operand
|
|||
|
//
|
|||
|
|
|||
|
switch (disinstr.Memory.MemDisp & BITS_MEM_DISP) {
|
|||
|
case FETCH_FUNC:
|
|||
|
case FETCH_M_FUNC:
|
|||
|
// one operand, in Rb
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
*pBuf++ = '0';
|
|||
|
*pBuf++ = '(';
|
|||
|
OutputReg(disinstr.Memory.Rb);
|
|||
|
*pBuf++ = ')';
|
|||
|
break;
|
|||
|
|
|||
|
case RS_FUNC:
|
|||
|
case RC_FUNC:
|
|||
|
case RPCC_FUNC:
|
|||
|
// one operand, in Ra
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.Memory.Ra);
|
|||
|
break;
|
|||
|
|
|||
|
case MB_FUNC:
|
|||
|
case WMB_FUNC:
|
|||
|
case MB2_FUNC:
|
|||
|
case MB3_FUNC:
|
|||
|
case TRAPB_FUNC:
|
|||
|
case EXCB_FUNC:
|
|||
|
// no operands
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
printf("we shouldn't get here \n");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case ALPHA_JUMP:
|
|||
|
OutputString(findFuncName(pEntry, disinstr.Jump.Function));
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.Jump.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
*pBuf++ = '(';
|
|||
|
OutputReg(disinstr.Jump.Rb);
|
|||
|
*pBuf++ = ')';
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputHex(disinstr.Jump.Hint, (WIDTH_HINT + 3)/4, TRUE);
|
|||
|
|
|||
|
Ea = (ULONG) GetRegValue(dp, GetIntRegNumber(disinstr.Jump.Rb)) & (~3);
|
|||
|
OutputEffectiveAddress(dp, Ea);
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_BRANCH:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.Branch.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
|
|||
|
//
|
|||
|
// The next line might be a call to GetNextOffset, but
|
|||
|
// GetNextOffset assumes that it should work from REGFIR.
|
|||
|
//
|
|||
|
|
|||
|
Ea = *poffset +
|
|||
|
sizeof(DWORD) +
|
|||
|
(disinstr.Branch.BranchDisp << 2);
|
|||
|
OutputHex(Ea, 8, FALSE);
|
|||
|
OutputEffectiveAddress(dp, Ea);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_FP_BRANCH:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputFReg(disinstr.Branch.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
|
|||
|
//
|
|||
|
// The next line might be a call to GetNextOffset, but
|
|||
|
// GetNextOffset assumes that it should work from REGFIR.
|
|||
|
//
|
|||
|
|
|||
|
Ea = *poffset +
|
|||
|
sizeof(DWORD) +
|
|||
|
(disinstr.Branch.BranchDisp << 2);
|
|||
|
OutputHex(Ea, 8, FALSE);
|
|||
|
OutputEffectiveAddress(dp, Ea);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_OPERATE:
|
|||
|
OutputString(findFuncName(pEntry, disinstr.OpReg.Function));
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.OpReg.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
if (disinstr.OpReg.RbvType) {
|
|||
|
*pBuf++ = '#';
|
|||
|
OutputHex(disinstr.OpLit.Literal, (WIDTH_LIT + 3)/4, TRUE);
|
|||
|
} else
|
|||
|
OutputReg(disinstr.OpReg.Rb);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputReg(disinstr.OpReg.Rc);
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_FP_OPERATE:
|
|||
|
|
|||
|
{
|
|||
|
ULONG Function;
|
|||
|
ULONG Flags;
|
|||
|
|
|||
|
Flags = disinstr.FpOp.Function & MSK_FP_FLAGS;
|
|||
|
Function = disinstr.FpOp.Function & MSK_FP_OP;
|
|||
|
|
|||
|
// if (fVerboseOutput) {
|
|||
|
// dprintf("In FP_OPERATE: Flags %08x Function %08x\n",
|
|||
|
// Flags, Function);
|
|||
|
// dprintf("opcode %d \n", opcode);
|
|||
|
// }
|
|||
|
|
|||
|
//
|
|||
|
// CVTST and CVTST/S are different: they look like
|
|||
|
// CVTTS with some flags set
|
|||
|
//
|
|||
|
if (Function == CVTTS_FUNC) {
|
|||
|
if (disinstr.FpOp.Function == CVTST_S_FUNC) {
|
|||
|
Function = CVTST_S_FUNC;
|
|||
|
Flags = NONE_FLAGS;
|
|||
|
}
|
|||
|
if (disinstr.FpOp.Function == CVTST_FUNC) {
|
|||
|
Function = CVTST_FUNC;
|
|||
|
Flags = NONE_FLAGS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
OutputString(findFuncName(pEntry, Function));
|
|||
|
|
|||
|
//
|
|||
|
// Append the opcode qualifier, if any, to the opcode name.
|
|||
|
//
|
|||
|
|
|||
|
if ( (opcode == IEEEFP_OP) || (opcode == VAXFP_OP)
|
|||
|
|| (Function == CVTQL_FUNC) ) {
|
|||
|
OutputString(findFlagName(Flags, Function));
|
|||
|
}
|
|||
|
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
//
|
|||
|
// If this is a convert instruction, only Rb and Rc are used
|
|||
|
//
|
|||
|
if (strncmp("cvt", findFuncName(pEntry, Function), 3) != 0) {
|
|||
|
OutputFReg(disinstr.FpOp.Fa);
|
|||
|
*pBuf++ = ',';
|
|||
|
}
|
|||
|
OutputFReg(disinstr.FpOp.Fb);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputFReg(disinstr.FpOp.Fc);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case ALPHA_FP_CONVERT:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputFReg(disinstr.FpOp.Fa);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputFReg(disinstr.FpOp.Fb);
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_CALLPAL:
|
|||
|
OutputString(findFuncName(pEntry, disinstr.Pal.Function));
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_EV4_PR:
|
|||
|
if ((disinstr.Long & MSK_EV4_PR) == 0)
|
|||
|
OutputString("NOP");
|
|||
|
else {
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.EV4_PR.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
if(disinstr.EV4_PR.Ra != disinstr.EV4_PR.Rb) {
|
|||
|
OutputReg(disinstr.EV4_PR.Rb);
|
|||
|
*pBuf++ = ',';
|
|||
|
};
|
|||
|
OutputString(findFuncName(pEntry, (disinstr.Long & MSK_EV4_PR)));
|
|||
|
};
|
|||
|
break;
|
|||
|
case ALPHA_EV4_MEM:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
BlankFill(OPRNDCOL);
|
|||
|
OutputReg(disinstr.EV4_MEM.Ra);
|
|||
|
*pBuf++ = ',';
|
|||
|
OutputReg(disinstr.EV4_MEM.Rb);
|
|||
|
break;
|
|||
|
case ALPHA_EV4_REI:
|
|||
|
OutputString(pEntry->pszAlphaName);
|
|||
|
break;
|
|||
|
default:
|
|||
|
OutputString("Invalid type");
|
|||
|
break;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
*poffset += sizeof(ULONG);
|
|||
|
*pBuf = '\0';
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
/* BlankFill - blank-fill buffer
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* To fill the buffer at *pBuf with blanks until
|
|||
|
* position count is reached.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* None.
|
|||
|
*
|
|||
|
***********************************************************************/
|
|||
|
|
|||
|
void BlankFill(ULONG count)
|
|||
|
{
|
|||
|
do
|
|||
|
*pBuf++ = ' ';
|
|||
|
while (pBuf < pBufStart + count);
|
|||
|
}
|
|||
|
|
|||
|
/* OutputHex - output hex value
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Output the value in outvalue into the buffer
|
|||
|
* pointed by *pBuf. The value may be signed
|
|||
|
* or unsigned depending on the value fSigned.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* outvalue - value to output
|
|||
|
* length - length in digits
|
|||
|
* fSigned - TRUE if signed else FALSE
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* None.
|
|||
|
*
|
|||
|
***********************************************************************/
|
|||
|
|
|||
|
UCHAR HexDigit[16] = {
|
|||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|||
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|||
|
};
|
|||
|
|
|||
|
void OutputHex (ULONG outvalue, ULONG length, BOOLEAN fSigned)
|
|||
|
{
|
|||
|
UCHAR digit[8];
|
|||
|
LONG index = 0;
|
|||
|
|
|||
|
if (fSigned && (LONG)outvalue < 0) {
|
|||
|
*pBuf++ = '-';
|
|||
|
outvalue = - (LONG)outvalue;
|
|||
|
}
|
|||
|
do {
|
|||
|
digit[index++] = HexDigit[outvalue & 0xf];
|
|||
|
outvalue >>= 4;
|
|||
|
}
|
|||
|
|
|||
|
while ((fSigned && outvalue) || (!fSigned && index < (LONG)length))
|
|||
|
;
|
|||
|
while (--index >= 0)
|
|||
|
*pBuf++ = digit[index];
|
|||
|
}
|
|||
|
|
|||
|
/* OutputString - output string
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Copy the string into the buffer pointed by pBuf.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* *pStr - pointer to string
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* None.
|
|||
|
*
|
|||
|
***********************************************************************/
|
|||
|
|
|||
|
void OutputString (char *pStr)
|
|||
|
{
|
|||
|
while (*pStr)
|
|||
|
*pBuf++ = *pStr++;
|
|||
|
}
|
|||
|
|
|||
|
void OutputReg (ULONG regnum)
|
|||
|
{
|
|||
|
OutputString(pszReg[GetIntRegNumber(regnum)]);
|
|||
|
}
|
|||
|
|
|||
|
void OutputFReg (ULONG regnum)
|
|||
|
{
|
|||
|
*pBuf++ = 'f';
|
|||
|
if (regnum > 9)
|
|||
|
*pBuf++ = (UCHAR)('0' + regnum / 10);
|
|||
|
*pBuf++ = (UCHAR)('0' + regnum % 10);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*** OutputEffectiveAddress - Print EA symbolically
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Given the effective address (for a branch, jump or
|
|||
|
* memory instruction, print it symbolically, if
|
|||
|
* symbols are available.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* offset - computed by the caller as
|
|||
|
* for jumps, the value in Rb
|
|||
|
* for branches, func(PC, displacement)
|
|||
|
* for memory, func(PC, displacement)
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* None
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
void OutputEffectiveAddress(PDEBUGPACKET dp, ULONG offset)
|
|||
|
{
|
|||
|
ULONG displacement;
|
|||
|
PUCHAR pszTemp;
|
|||
|
UCHAR ch;
|
|||
|
|
|||
|
|
|||
|
BlankFill(EACOL);
|
|||
|
|
|||
|
if (SymGetSymFromAddr( dp->hProcess, offset, &displacement, sym )) {
|
|||
|
pszTemp = sym->Name;
|
|||
|
while (ch = *pszTemp++)
|
|||
|
*pBuf++ = ch;
|
|||
|
if (displacement) {
|
|||
|
*pBuf++ = '+';
|
|||
|
OutputHex(displacement, 8, TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
OutputHex(offset, 8, FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*** GetNextOffset - compute offset for trace or step
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* From a limited disassembly of the instruction pointed
|
|||
|
* by the FIR register, compute the offset of the next
|
|||
|
* instruction for either a trace or step operation.
|
|||
|
*
|
|||
|
* trace -> the next instruction to execute
|
|||
|
* step -> the instruction in the next memory location or the
|
|||
|
* next instruction executed due to a branch (step over
|
|||
|
* subroutine calls).
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* result - where to put the next offset
|
|||
|
* fStep - TRUE for step offset; FALSE for trace offset
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* step or trace offset if input is TRUE or FALSE, respectively
|
|||
|
* in result
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
/*
|
|||
|
void
|
|||
|
GetNextOffset (PDEBUGPACKET dp, PULONG result, BOOLEAN fStep)
|
|||
|
{
|
|||
|
ULONG rv;
|
|||
|
ULONG opcode;
|
|||
|
ULONG firaddr;
|
|||
|
ULONG updatedpc;
|
|||
|
ULONG branchTarget;
|
|||
|
DWORD fir;
|
|||
|
|
|||
|
// Canonical form to shorten tests; Abs is absolute value
|
|||
|
|
|||
|
LONG Can, Abs;
|
|||
|
|
|||
|
CONVERTED_DOUBLE Rav;
|
|||
|
CONVERTED_DOUBLE Fav;
|
|||
|
CONVERTED_DOUBLE Rbv;
|
|||
|
|
|||
|
//
|
|||
|
// Get current address
|
|||
|
//
|
|||
|
|
|||
|
firaddr = (ULONG) GetRegValue(dp, REGFIR);
|
|||
|
|
|||
|
//
|
|||
|
// relative addressing updates PC first
|
|||
|
// Assume next sequential instruction is next offset
|
|||
|
//
|
|||
|
|
|||
|
updatedpc = firaddr + sizeof(ULONG);
|
|||
|
rv = updatedpc;
|
|||
|
|
|||
|
DoMemoryRead( dp,
|
|||
|
(LPVOID)firaddr,
|
|||
|
(LPVOID)&disinstr.Long,
|
|||
|
sizeof(ULONG),
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
opcode = disinstr.Memory.Opcode;
|
|||
|
|
|||
|
switch(findOpCodeEntry(opcode)->iType) {
|
|||
|
|
|||
|
case ALPHA_JUMP:
|
|||
|
|
|||
|
switch(disinstr.Jump.Function) {
|
|||
|
|
|||
|
case JSR_FUNC:
|
|||
|
case JSR_CO_FUNC:
|
|||
|
|
|||
|
if (fStep) {
|
|||
|
|
|||
|
//
|
|||
|
// Step over the subroutine call;
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// fall through
|
|||
|
//
|
|||
|
|
|||
|
case JMP_FUNC:
|
|||
|
case RET_FUNC:
|
|||
|
|
|||
|
GetQuadRegValue(dp, GetIntRegNumber(disinstr.Jump.Rb), &Rbv);
|
|||
|
rv = (Rbv.li.LowPart & (~3));
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ALPHA_BRANCH:
|
|||
|
|
|||
|
branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
|
|||
|
|
|||
|
GetQuadRegValue(dp, GetIntRegNumber(disinstr.Branch.Ra), &Rav.li);
|
|||
|
|
|||
|
//
|
|||
|
// set up a canonical value for computing the branch test
|
|||
|
// - works with ALPHA, MIPS and 386 hosts
|
|||
|
//
|
|||
|
|
|||
|
Can = Rav.li.LowPart & 1;
|
|||
|
|
|||
|
if ((LONG)Rav.li.HighPart < 0) {
|
|||
|
Can |= 0x80000000;
|
|||
|
}
|
|||
|
|
|||
|
if ((Rav.li.LowPart & 0xfffffffe) || (Rav.li.HighPart & 0x7fffffff)) {
|
|||
|
Can |= 2;
|
|||
|
}
|
|||
|
|
|||
|
// if (fVerboseOutput) {
|
|||
|
// dprintf("Rav High %08lx Low %08lx Canonical %08lx\n",
|
|||
|
// Rav.li.HighPart, Rav.li.LowPart, Can);
|
|||
|
// dprintf("returnvalue %08lx branchTarget %08lx\n",
|
|||
|
// rv, branchTarget);
|
|||
|
// }
|
|||
|
|
|||
|
switch(opcode) {
|
|||
|
case BR_OP: rv = branchTarget; break;
|
|||
|
case BSR_OP: if (!fStep) rv = branchTarget; break;
|
|||
|
case BEQ_OP: if (Can == 0) rv = branchTarget; break;
|
|||
|
case BLT_OP: if (Can < 0) rv = branchTarget; break;
|
|||
|
case BLE_OP: if (Can <= 0) rv = branchTarget; break;
|
|||
|
case BNE_OP: if (Can != 0) rv = branchTarget; break;
|
|||
|
case BGE_OP: if (Can >= 0) rv = branchTarget; break;
|
|||
|
case BGT_OP: if (Can > 0) rv = branchTarget; break;
|
|||
|
case BLBC_OP: if ((Can & 0x1) == 0) rv = branchTarget; break;
|
|||
|
case BLBS_OP: if ((Can & 0x1) == 1) rv = branchTarget; break;
|
|||
|
};
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case ALPHA_FP_BRANCH:
|
|||
|
|
|||
|
branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
|
|||
|
|
|||
|
GetFloatingPointRegValue(dp, disinstr.Branch.Ra, &Fav);
|
|||
|
|
|||
|
//
|
|||
|
// Set up a canonical value for computing the branch test
|
|||
|
//
|
|||
|
|
|||
|
Can = Fav.li.HighPart & 0x80000000;
|
|||
|
|
|||
|
//
|
|||
|
// The absolute value is needed -0 and non-zero computation
|
|||
|
//
|
|||
|
|
|||
|
Abs = Fav.li.LowPart || (Fav.li.HighPart & 0x7fffffff);
|
|||
|
|
|||
|
if (Can && (Abs == 0x0)) {
|
|||
|
|
|||
|
//
|
|||
|
// negative 0 should be considered as zero
|
|||
|
//
|
|||
|
|
|||
|
Can = 0x0;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Can |= Abs;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// if (fVerboseOutput) {
|
|||
|
// dprintf("Fav High %08lx Low %08lx Canonical %08lx Absolute %08lx\n",
|
|||
|
// Fav.li.HighPart, Fav.li.LowPart, Can, Abs);
|
|||
|
// dprintf("returnvalue %08lx branchTarget %08lx\n",
|
|||
|
// rv, branchTarget);
|
|||
|
// }
|
|||
|
|
|||
|
switch(opcode) {
|
|||
|
case FBEQ_OP: if (Can == 0) rv = branchTarget; break;
|
|||
|
case FBLT_OP: if (Can < 0) rv = branchTarget; break;
|
|||
|
case FBNE_OP: if (Can != 0) rv = branchTarget; break;
|
|||
|
case FBLE_OP: if (Can <= 0) rv = branchTarget; break;
|
|||
|
case FBGE_OP: if (Can >= 0) rv = branchTarget; break;
|
|||
|
case FBGT_OP: if (Can > 0) rv = branchTarget; break;
|
|||
|
};
|
|||
|
|
|||
|
break;
|
|||
|
};
|
|||
|
|
|||
|
// if (fVerboseOutput) {
|
|||
|
// dprintf("GetNextOffset returning %08lx\n", rv);
|
|||
|
// }
|
|||
|
|
|||
|
*result = rv;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
*/
|