/*++

Copyright (c) 1993  Microsoft Corporation

Module Name:

    regs.c

Abstract:

    This file provides access to the machine's register set.

Author:

    Wesley Witt (wesw) 1-May-1993  (ported from ntsd)

Environment:

    User Mode

--*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "drwatson.h"
#include "proto.h"
#include "regs.h"

PUCHAR  UserRegs[10] = {0};


ULONG GetRegFlagValue (PDEBUGPACKET dp, ULONG regnum);
ULONG GetRegValue (PDEBUGPACKET dp, ULONG regnum);
ULONG GetRegName (void);
ULONG GetRegString (PUCHAR pszString);
void  GetRegPCValue (PDEBUGPACKET dp, PULONG Address);
PULONG GetRegFPValue (PDEBUGPACKET dp);
void OutputAllRegs(PDEBUGPACKET dp);
void OutputOneReg (PDEBUGPACKET dp, ULONG regnum);
PUCHAR RegNameFromIndex (ULONG index);




static ULONG   ProcessorType = 0;
ULONG   cbBrkptLength = 4;
ULONG   trapInstr = 0x0016000dL;  //  break 0x16 for brkpts
ULONG   ContextType = CONTEXT_CONTROL | CONTEXT_INTEGER;

//
// Define MIPS nonvolatile register test macros.
//

#define IS_FLOATING_SAVED(Register) ((SAVED_FLOATING_MASK >> Register) & 1L)
#define IS_INTEGER_SAVED(Register) ((SAVED_INTEGER_MASK >> Register) & 1L)

//
// Define MIPS instruction opcode values.
//

#define ADDIU_OP 0x9                    // add immediate unsigned integer register
#define ADDU_OP 0x21                    // add unsigned integer register
#define JUMP_RA 0x3e00008               // jump indirect return address register
#define LUI_OP 0xf                      // load upper immediate integer register
#define SD_OP 0x2f                      // store double integer register
#define SW_OP 0x2b                      // store word integer register
#define SDC1_OP 0x3d                    // store double floating register
#define SWC1_OP 0x39                    // store word floating register
#define SPEC_OP 0x0                     // special opcode - use function field
#define SUBU_OP 0x23                    // subtract unsigned integer register

//
// Define stack register and zero register numbers.
//

#define RA 0x1f                         // integer register 31
#define SP 0x1d                         // integer register 29
#define ZERO 0x0                        // integer register 0

//
// Define saved register masks.
//

#define SAVED_FLOATING_MASK 0xfff00000  // saved floating registers
#define SAVED_INTEGER_MASK 0xf3ffff02   // saved integer registers


UCHAR   szF0[]  = "f0";
UCHAR   szF1[]  = "f1";
UCHAR   szF2[]  = "f2";
UCHAR   szF3[]  = "f3";
UCHAR   szF4[]  = "f4";
UCHAR   szF5[]  = "f5";
UCHAR   szF6[]  = "f6";
UCHAR   szF7[]  = "f7";
UCHAR   szF8[]  = "f8";
UCHAR   szF9[]  = "f9";
UCHAR   szF10[] = "f10";
UCHAR   szF11[] = "f11";
UCHAR   szF12[] = "f12";
UCHAR   szF13[] = "f13";
UCHAR   szF14[] = "f14";
UCHAR   szF15[] = "f15";
UCHAR   szF16[] = "f16";
UCHAR   szF17[] = "f17";
UCHAR   szF18[] = "f18";
UCHAR   szF19[] = "f19";
UCHAR   szF20[] = "f20";
UCHAR   szF21[] = "f21";
UCHAR   szF22[] = "f22";
UCHAR   szF23[] = "f23";
UCHAR   szF24[] = "f24";
UCHAR   szF25[] = "f25";
UCHAR   szF26[] = "f26";
UCHAR   szF27[] = "f27";
UCHAR   szF28[] = "f28";
UCHAR   szF29[] = "f29";
UCHAR   szF30[] = "f30";
UCHAR   szF31[] = "f31";

UCHAR   szR0[]  = "zero";
UCHAR   szR1[]  = "at";
UCHAR   szR2[]  = "v0";
UCHAR   szR3[]  = "v1";
UCHAR   szR4[]  = "a0";
UCHAR   szR5[]  = "a1";
UCHAR   szR6[]  = "a2";
UCHAR   szR7[]  = "a3";
UCHAR   szR8[]  = "t0";
UCHAR   szR9[]  = "t1";
UCHAR   szR10[] = "t2";
UCHAR   szR11[] = "t3";
UCHAR   szR12[] = "t4";
UCHAR   szR13[] = "t5";
UCHAR   szR14[] = "t6";
UCHAR   szR15[] = "t7";
UCHAR   szR16[] = "s0";
UCHAR   szR17[] = "s1";
UCHAR   szR18[] = "s2";
UCHAR   szR19[] = "s3";
UCHAR   szR20[] = "s4";
UCHAR   szR21[] = "s5";
UCHAR   szR22[] = "s6";
UCHAR   szR23[] = "s7";
UCHAR   szR24[] = "t8";
UCHAR   szR25[] = "t9";
UCHAR   szR26[] = "k0";
UCHAR   szR27[] = "k1";
UCHAR   szR28[] = "gp";
UCHAR   szR29[] = "sp";
UCHAR   szR30[] = "s8";
UCHAR   szR31[] = "ra";

UCHAR   szLo[]  = "lo";
UCHAR   szHi[]  = "hi";
UCHAR   szFsr[] = "fsr";
UCHAR   szFir[] = "fir";
UCHAR   szPsr[] = "psr";

UCHAR   szFlagCu[] = "cu";
UCHAR   szFlagCu3[] = "cu3";
UCHAR   szFlagCu2[] = "cu2";
UCHAR   szFlagCu1[] = "cu1";
UCHAR   szFlagCu0[] = "cu0";
UCHAR   szFlagImsk[] = "imsk";
UCHAR   szFlagInt5[] = "int5";
UCHAR   szFlagInt4[] = "int4";
UCHAR   szFlagInt3[] = "int3";
UCHAR   szFlagInt2[] = "int2";
UCHAR   szFlagInt1[] = "int1";
UCHAR   szFlagInt0[] = "int0";
UCHAR   szFlagSw1[] = "sw1";
UCHAR   szFlagSw0[] = "sw0";
UCHAR   szFlagKuo[] = "kuo";
UCHAR   szFlagIeo[] = "ieo";
UCHAR   szFlagKup[] = "kup";
UCHAR   szFlagIep[] = "iep";
UCHAR   szFlagKuc[] = "kuc";
UCHAR   szFlagIec[] = "iec";
UCHAR   szFlagKsu[] = "ksu";
UCHAR   szFlagErl[] = "erl";
UCHAR   szFlagExl[] = "exl";
UCHAR   szFlagIe[]  = "ie";
UCHAR   szFlagFpc[] = "fpc";

char    szEaPReg[]   = "$ea";
char    szExpPReg[]  = "$exp";
char    szRaPReg[]   = "$ra";
char    szPPReg[]    = "$p";
char    szU0Preg[]   = "$u0";
char    szU1Preg[]   = "$u1";
char    szU2Preg[]   = "$u2";
char    szU3Preg[]   = "$u3";
char    szU4Preg[]   = "$u4";
char    szU5Preg[]   = "$u5";
char    szU6Preg[]   = "$u6";
char    szU7Preg[]   = "$u7";
char    szU8Preg[]   = "$u8";
char    szU9Preg[]   = "$u9";

PUCHAR  pszReg[] = {
    szF0,  szF1,  szF2,  szF3,  szF4,  szF5,  szF6,  szF7,
    szF8,  szF9,  szF10, szF11, szF12, szF13, szF14, szF15,
    szF16, szF17, szF18, szF19, szF20, szF21, szF22, szF23,
    szF24, szF25, szF26, szF27, szF28, szF29, szF30, szF31,

    szR0,  szR1,  szR2,  szR3,  szR4,  szR5,  szR6,  szR7,
    szR8,  szR9,  szR10, szR11, szR12, szR13, szR14, szR15,
    szR16, szR17, szR18, szR19, szR20, szR21, szR22, szR23,
    szR24, szR25, szR26, szR27, szR28, szR29, szR30, szR31,

    szLo,  szHi,  szFsr, szFir, szPsr,

    szFlagCu,   szFlagCu3,  szFlagCu2,  szFlagCu1,  szFlagCu0,
    szFlagImsk,
    szFlagInt5, szFlagInt4, szFlagInt3, szFlagInt2, szFlagInt1, szFlagInt0,
    szFlagSw1,  szFlagSw0,
    szFlagKuo,  szFlagIeo,                              //  R3000 flags
    szFlagKup,  szFlagIep,                              //  ...
    szFlagKuc,  szFlagIec,                              //  ...
    szFlagKsu,  szFlagErl,  szFlagExl,  szFlagIe,       //  R4000 flags

    szFlagFpc,                                          //  fl pt condition

    szEaPReg, szExpPReg, szRaPReg, szPPReg,             //  psuedo-registers
    szU0Preg, szU1Preg,  szU2Preg, szU3Preg, szU4Preg,
    szU5Preg, szU6Preg,  szU7Preg, szU8Preg, szU9Preg
    };

#define REGNAMESIZE     sizeof(pszReg) / sizeof(PUCHAR)

struct Reg {
        char    *psz;
        ULONG   value;
        };

struct SubReg {
        ULONG   regindex;
        ULONG   shift;
        ULONG   mask;
        };

struct SubReg subregname[] = {
    { REGPSR,   28,  0xf },             //  CU mask
    { REGPSR,   31,    1 },             //  CU3 flag
    { REGPSR,   30,    1 },             //  CU2 flag
    { REGPSR,   29,    1 },             //  CU1 flag
    { REGPSR,   28,    1 },             //  CU0 flag
    { REGPSR,   8,  0xff },             //  IMSK mask
    { REGPSR,   15,    1 },             //  INT5 - int 5 enable
    { REGPSR,   14,    1 },             //  INT4 - int 4 enable
    { REGPSR,   13,    1 },             //  INT3 - int 3 enable
    { REGPSR,   12,    1 },             //  INT2 - int 2 enable
    { REGPSR,   11,    1 },             //  INT1 - int 1 enable
    { REGPSR,   10,    1 },             //  INT0 - int 0 enable
    { REGPSR,   9,     1 },             //  SW1  - software int 1 enable
    { REGPSR,   8,     1 },             //  SW0  - software int 0 enable

    //  R3000-specific status bits

    { REGPSR,   5,     1 },             //  KUO
    { REGPSR,   4,     1 },             //  IEO
    { REGPSR,   3,     1 },             //  KUP
    { REGPSR,   2,     1 },             //  IEP
    { REGPSR,   1,     1 },             //  KUC
    { REGPSR,   0,     1 },             //  IEC

    //  R4000-specific status bits

    { REGPSR,   3,     2 },             //  KSU
    { REGPSR,   2,     1 },             //  ERL
    { REGPSR,   1,     1 },             //  EXL
    { REGPSR,   0,     1 },             //  IE

    { REGFSR,   23,    1 }              //  FPC - floating point condition
    };


/*** UserRegTest - test if index is a user-defined register
*
*   Purpose:
*       Test if register is user-defined for upper routines.
*
*   Input:
*       index - index of register
*
*   Returns:
*       TRUE if user-defined register, else FALSE
*
*************************************************************************/

BOOLEAN
UserRegTest (ULONG index)
{
    return (BOOLEAN)(index >= PREGU0 && index <= PREGU9);
}

/*** GetRegFlagValue - get register or flag value
*
*   Purpose:
*       Return the value of the specified register or flag.
*       This routine calls GetRegValue to get the register
*       value and shifts and masks appropriately to extract a
*       flag value.
*
*   Input:
*       regnum - register or flag specification
*
*   Returns:
*       Value of register or flag.

*************************************************************************/

ULONG
GetRegFlagValue (PDEBUGPACKET dp, ULONG regnum)
{
    ULONG value;

    if (regnum < FLAGBASE || regnum >= PREGBASE)
        value = GetRegValue(dp,regnum);
    else {
        regnum -= FLAGBASE;
        value = GetRegValue(dp,subregname[regnum].regindex);
        value = (value >> subregname[regnum].shift) & subregname[regnum].mask;
        }
    return value;
}

/*** GetRegValue - get register value
*
*   Purpose:
*       Returns the value of the register from the processor
*       context structure.
*
*   Input:
*       regnum - register specification
*
*   Returns:
*       value of the register from the context structure
*
*************************************************************************/

ULONG
GetRegValue (PDEBUGPACKET dp, ULONG regnum)
{
    return *(&dp->tctx->context.FltF0 + regnum);
}


ULONG
GetRegString (PUCHAR pszString)
{
    ULONG   count;

    for (count = 0; count < REGNAMESIZE; count++)
        if (!strcmp(pszString, pszReg[count]))
            return count;
    return (ULONG)-1;
}

void
GetRegPCValue (PDEBUGPACKET dp, PULONG Address)
{
    *Address = GetRegValue(dp,REGFIR);
    return;
}

PULONG
GetRegFPValue (PDEBUGPACKET dp)
{
    static ULONG addrFP;

    addrFP = GetRegValue(dp,REGGP);
    return &addrFP;
}

/*** OutputAllRegs - output all registers and present instruction
*
*   Purpose:
*       Function of "r" command.
*
*       To output the current register state of the processor.
*       All integer registers are output as well as processor status
*       registers.  Important flag fields are also output separately.
*       OutDisCurrent is called to output the current instruction(s).
*
*   Input:
*       None.
*
*   Output:
*       None.
*
*************************************************************************/

void
OutputAllRegs(PDEBUGPACKET dp)
{
    int     regindex;

    for (regindex = 1; regindex < 37; regindex++) {
        if (regindex == 34)
            lprintfs("          ");
        else {
            lprintfs("%s=%08lx", pszReg[regindex + REGBASE],
                               GetRegValue(dp,regindex + REGBASE));
            if (regindex % 6 == 0)
                lprintfs("\r\n");
            else
                lprintfs(" ");
            }
        }
    lprintfs("cu=%1lx%1lx%1lx%1lx intr(5:0)=%1lx%1lx%1lx%1lx%1lx%1lx ",
                GetRegFlagValue(dp,FLAGCU3),
                GetRegFlagValue(dp,FLAGCU2),
                GetRegFlagValue(dp,FLAGCU1),
                GetRegFlagValue(dp,FLAGCU0),
                GetRegFlagValue(dp,FLAGINT5),
                GetRegFlagValue(dp,FLAGINT4),
                GetRegFlagValue(dp,FLAGINT3),
                GetRegFlagValue(dp,FLAGINT2),
                GetRegFlagValue(dp,FLAGINT1),
                GetRegFlagValue(dp,FLAGINT0));
    lprintfs("sw(1:0)=%1lx%1lx ",
                GetRegFlagValue(dp,FLAGSW1),
                GetRegFlagValue(dp,FLAGSW0));
    if (ProcessorType == 0)
        lprintfs("kuo=%01lx ieo=%01lx kup=%01lx "
                "iep=%01lx kuc=%01lx iec=%01lx\r\n",
                GetRegFlagValue(dp,FLAGKUO),
                GetRegFlagValue(dp,FLAGIEO),
                GetRegFlagValue(dp,FLAGKUP),
                GetRegFlagValue(dp,FLAGIEP),
                GetRegFlagValue(dp,FLAGKUC),
                GetRegFlagValue(dp,FLAGIEC));
    else
        lprintfs("ksu=%01lx erl=%01lx exl=%01lx ie=%01lx\r\n",
                GetRegFlagValue(dp,FLAGKSU),
                GetRegFlagValue(dp,FLAGERL),
                GetRegFlagValue(dp,FLAGEXL),
                GetRegFlagValue(dp,FLAGIE));
    lprintfs("\r\n\r\n");
}

/*** OutputOneReg - output one register value
*
*   Purpose:
*       Function for the "r <regname>" command.
*
*       Output the value for the specified register or flag.
*
*   Input:
*       regnum - register or flag specification
*
*   Output:
*       None.
*
*************************************************************************/

void
OutputOneReg (PDEBUGPACKET dp, ULONG regnum)
{
    ULONG value;

    value = GetRegFlagValue(dp,regnum);
    if (regnum < FLAGBASE)
        lprintfs("%08lx\r\n", value);
    else
        lprintfs("%lx\r\n", value);
}

PUCHAR
RegNameFromIndex (ULONG index)
{
    return pszReg[index];
}
