Files
fail/simulators/ovp/armmModel/armmDebug.c

684 lines
18 KiB
C

/*
* Copyright (c) 2005-2011 Imperas Software Ltd., www.imperas.com
*
* YOUR ACCESS TO THE INFORMATION IN THIS MODEL IS CONDITIONAL
* UPON YOUR ACCEPTANCE THAT YOU WILL NOT USE OR PERMIT OTHERS
* TO USE THE INFORMATION FOR THE PURPOSES OF DETERMINING WHETHER
* IMPLEMENTATIONS OF THE ARM ARCHITECTURE INFRINGE ANY THIRD
* PARTY PATENTS.
*
* THE LICENSE BELOW EXTENDS ONLY TO USE OF THE SOFTWARE FOR
* MODELING PURPOSES AND SHALL NOT BE CONSTRUED AS GRANTING
* A LICENSE TO CREATE A HARDWARE IMPLEMENTATION OF THE
* FUNCTIONALITY OF THE SOFTWARE LICENSED HEREUNDER.
* YOU MAY USE THE SOFTWARE SUBJECT TO THE LICENSE TERMS BELOW
* PROVIDED THAT YOU ENSURE THAT THIS NOTICE IS REPLICATED UNMODIFIED
* AND IN ITS ENTIRETY IN ALL DISTRIBUTIONS OF THE SOFTWARE,
* MODIFIED OR UNMODIFIED, IN SOURCE CODE OR IN BINARY FORM.
*
* Licensed under an Imperas Modfied 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.ovpworld.org/licenses/OVP_MODIFIED_1.0_APACHE_OPEN_SOURCE_LICENSE_2.0.pdf
*
* 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.
*
*/
// Standard header files
#include "string.h"
#include "stdio.h"
// Imperas header files
#include "hostapi/impAlloc.h"
// VMI header files
#include "vmi/vmiAttrs.h"
#include "vmi/vmiDbg.h"
#include "vmi/vmiMessage.h"
#include "vmi/vmiOSLib.h"
#include "vmi/vmiRt.h"
// model header files
#include "armRegisters.h"
#include "armStructure.h"
#include "armUtils.h"
#include "armSys.h"
#include "armVFP.h"
//
// Prefix for messages from this module
//
#define CPU_PREFIX "ARM_DEBUG"
////////////////////////////////////////////////////////////////////////////////
// REGISTER GROUPS
////////////////////////////////////////////////////////////////////////////////
//
// This describes the register groups in the processor
//
typedef enum armRegGroupIdE {
ARM_RG_CORE, // Core group
ARM_RG_CONTROL, // control register group
ARM_RG_SYSTEM, // memory-mapped system register group
ARM_RG_FPR, // VFP register group
ARM_RG_LAST // KEEP LAST: for sizing
} armRegGroupId;
//
// This provides information about each group
//
static const vmiRegGroup groups[ARM_RG_LAST+1] = {
[ARM_RG_CORE] = {name: "Core" },
[ARM_RG_CONTROL] = {name: "Control"},
[ARM_RG_SYSTEM] = {name: "System" },
[ARM_RG_FPR] = {name: "VFP" },
};
//
// Macro to specify a the group for a register
//
#define ARM_GROUP(_G) &groups[ARM_RG_##_G]
////////////////////////////////////////////////////////////////////////////////
// MACROS FOR REGISTER ACCESS
////////////////////////////////////////////////////////////////////////////////
//
// Macro to specify a register that can be accessed using raw read/write
// callbacks
//
#define ARM_RAW_REG(_R, _G) \
VMI_REG_RAW_READ_CB, \
VMI_REG_RAW_WRITE_CB, \
(void *)ARM_CPU_OFFSET(_R), \
_G
//
// Core registers
//
#define ARM_CORE_REG(_I) ARM_RAW_REG(regs[_I], ARM_GROUP(CORE))
//
// Macro to specify the PC accessible for read/write
//
#define ARM_PC_RW readPC, writePC, 0, ARM_GROUP(CORE)
//
// Macro to specify access for the stack pointer register
//
#define ARM_SP_REG(_R) \
VMI_REG_RAW_READ_CB, \
writeSP, \
(void *)ARM_CPU_OFFSET(regs[_R]), \
ARM_GROUP(CORE)
//
// Macro to specify the control registers
//
#define ARM_CONTROL_RW(_ID) read##_ID, write##_ID, 0, ARM_GROUP(CONTROL)
//
// Some registers are hidden in gdb, but we allow access to them
//
#define ARM_GDB_HIDDEN_INDEX 99
#define IS_GDB_HIDDEN_REG(_I) ((_I)>=ARM_GDB_HIDDEN_INDEX)
//
// system registers do not have access
//
#define ARM_CP_INDEX 0x1000
#define IS_SCS_REG(_I) ((_I)>=ARM_CP_INDEX)
//
// VFP registers - must check for existence in the variant
//
#define ARM_FPSCR_INDEX 24
#define ARM_VFP0_INDEX 700
#define ARM_VFP15_INDEX 715
#define IS_VFP_REG(_I) ((_I)==ARM_FPSCR_INDEX || IS_VFP_DATA_REG(_I))
#define IS_VFP_DATA_REG(_I) (((_I)>=ARM_VFP0_INDEX) && ((_I)<=ARM_VFP15_INDEX))
#define ARM_VFP_INDEX(_I) ((_I)-ARM_VFP0_INDEX)
#define ARM_VFP_DATA_REG(_I) ARM_RAW_REG(vregs.d[_I], ARM_GROUP(FPR))
////////////////////////////////////////////////////////////////////////////////
// DEBUGGER REGISTER INTERFACE
////////////////////////////////////////////////////////////////////////////////
//
// Return current vmiRegInfoCP structure for the passed banked vmiRegInfoCP
//
vmiRegInfoCP getCurrentInfo(vmiRegInfoCP reg);
//
// Return system register id for vmiRegInfoCP
//
static armSCSRegId getSysId(vmiRegInfoCP reg) {
if(!IS_SCS_REG(reg->gdbIndex)) {
return SCS_ID(INVALID);
} else {
return (armSCSRegId)reg->userData;
}
}
//
// Write callback for sp
//
static VMI_REG_WRITE_FN(writeSP) {
armWriteSP((armP)processor, *(Uns32*)buffer);
return True;
}
//
// Read callback for pc
//
static VMI_REG_READ_FN(readPC) {
*(Uns32*)buffer = ((Uns32)vmirtGetPC(processor));
return True;
}
//
// Write callback for pc
//
static VMI_REG_WRITE_FN(writePC) {
Uns32 simPC = *(Uns32*)buffer;
vmirtSetPC(processor, simPC & ~1);
return True;
}
//
// Read callback for PSR
//
static VMI_REG_READ_FN(readPSR) {
*(Uns32*)buffer = armReadCPSR((armP)processor);
return True;
}
//
// Write callback for PSR
//
static VMI_REG_WRITE_FN(writePSR) {
armP arm = (armP)processor;
armWriteCPSR(arm, *(Uns32*)buffer, PSR_ALL);
return True;
}
//
// Read callback for FPSCR
//
static VMI_REG_READ_FN(readFPSCR) {
*(Uns32*)buffer = armReadFPSCR((armP)processor);
return True;
}
//
// Write callback for FPSCR
//
static VMI_REG_WRITE_FN(writeFPSCR) {
armP arm = (armP)processor;
armWriteFPSCR(arm, *(Uns32*)buffer, FPSCR_MASK);
return True;
}
//
// Read callback for CONTROL
//
static VMI_REG_READ_FN(readControl) {
*(Uns32*)buffer = armReadCONTROL((armP)processor);
return True;
}
//
// Write callback for CONTROL
//
static VMI_REG_WRITE_FN(writeControl) {
armP arm = (armP)processor;
armWriteCONTROL(arm, *(Uns32*)buffer);
return True;
}
//
// Read callback for PRIMASK
//
static VMI_REG_READ_FN(readPRIMASK) {
armP arm = (armP)processor;
*(Uns32*)buffer = arm->sregs.PRIMASK;
return True;
}
//
// Write callback for PRIMASK
//
static VMI_REG_WRITE_FN(writePRIMASK) {
armP arm = (armP)processor;
armWritePRIMASK(arm, *(Uns32*)buffer);
return True;
}
//
// Read callback for FAULTMASK
//
static VMI_REG_READ_FN(readFAULTMASK) {
armP arm = (armP)processor;
*(Uns32*)buffer = arm->sregs.FAULTMASK;
return True;
}
//
// Write callback for FAULTMASK
//
static VMI_REG_WRITE_FN(writeFAULTMASK) {
armP arm = (armP)processor;
armWriteFAULTMASK(arm, *(Uns32*)buffer);
return True;
}
//
// Read callback for FAULTMASK
//
static VMI_REG_READ_FN(readBASEPRI) {
armP arm = (armP)processor;
*(Uns32*)buffer = arm->sregs.BASEPRI;
return True;
}
//
// Write callback for BASEPRI
//
static VMI_REG_WRITE_FN(writeBASEPRI) {
armP arm = (armP)processor;
armWriteBASEPRI(arm, *(Uns32*)buffer);
return True;
}
//
// Read callback for banked register
//
static VMI_REG_READ_FN(readBank) {
armP arm = (armP)processor;
Bool trueUseSPProcess = USE_SP_PROCESS(arm);
Bool tempUseSPProcess = True;
armSwitchRegs(arm, trueUseSPProcess, tempUseSPProcess);
Bool result = vmiosRegRead(processor, getCurrentInfo(reg), buffer);
armSwitchRegs(arm, tempUseSPProcess, trueUseSPProcess);
return result;
}
//
// Write callback for banked register
//
static VMI_REG_WRITE_FN(writeBank) {
armP arm = (armP)processor;
Bool trueUseSPProcess = USE_SP_PROCESS(arm);
Bool tempUseSPProcess = True;
armSwitchRegs(arm, trueUseSPProcess, tempUseSPProcess);
Bool result = vmiosRegWrite(processor, getCurrentInfo(reg), buffer);
armSwitchRegs(arm, tempUseSPProcess, trueUseSPProcess);
return result;
}
//
// Read callback for system register
//
static VMI_REG_READ_FN(readSCS) {
armP arm = (armP)processor;
armSCSRegId id = getSysId(reg);
if(!armReadSysRegPriv(id, arm, (Uns32*)buffer)) {
return False;
} else if(id!=SCS_ID(CPUID)) {
return True;
} else {
union {Uns32 u32; SCS_REG_DECL(CPUID);} u = {*(Uns32*)buffer};
if(!u.u32) {
armArchitecture variant = arm->configInfo.arch;
u.CPUID.ARCHITECTURE = ARM_VARIANT_ARCH(variant);
*(Uns32*)buffer = u.u32;
}
return True;
}
}
//
// Write callback for system register
//
static VMI_REG_WRITE_FN(writeSCS) {
return armWriteSysRegPriv(getSysId(reg), (armP)processor, *(Uns32*)buffer);
}
//
// Static const array holding information about the registers in the cpu,
// used for debugger interaction
//
static const vmiRegInfo basicRegisters[] = {
// current mode registers (visible in gdb)
{"r0", 0, vmi_REG_NONE, 32, False, ARM_CORE_REG(0) },
{"r1", 1, vmi_REG_NONE, 32, False, ARM_CORE_REG(1) },
{"r2", 2, vmi_REG_NONE, 32, False, ARM_CORE_REG(2) },
{"r3", 3, vmi_REG_NONE, 32, False, ARM_CORE_REG(3) },
{"r4", 4, vmi_REG_NONE, 32, False, ARM_CORE_REG(4) },
{"r5", 5, vmi_REG_NONE, 32, False, ARM_CORE_REG(5) },
{"r6", 6, vmi_REG_NONE, 32, False, ARM_CORE_REG(6) },
{"r7", 7, vmi_REG_NONE, 32, False, ARM_CORE_REG(7) },
{"r8", 8, vmi_REG_NONE, 32, False, ARM_CORE_REG(8) },
{"r9", 9, vmi_REG_NONE, 32, False, ARM_CORE_REG(9) },
{"r10", 10, vmi_REG_NONE, 32, False, ARM_CORE_REG(10) },
{"r11", 11, vmi_REG_FP, 32, False, ARM_CORE_REG(11) },
{"r12", 12, vmi_REG_NONE, 32, False, ARM_CORE_REG(12) },
{"sp", 13, vmi_REG_SP, 32, False, ARM_SP_REG (13) },
{"lr", 14, vmi_REG_NONE, 32, False, ARM_CORE_REG(14) },
{"pc", 15, vmi_REG_PC, 32, False, ARM_PC_RW },
{"fps", 24, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(FPSCR) },
{"cpsr", 25, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(PSR) },
// control and SP_process (not visible in gdb)
{"control", 100, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(Control)},
{"primask", 101, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(PRIMASK)},
{"faultmask", 102, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(FAULTMASK)},
{"basepri", 103, vmi_REG_NONE, 32, False, ARM_CONTROL_RW(BASEPRI)},
{"sp_process", 113, vmi_REG_SP, 32, False, ARM_CONTROL_RW(Bank) },
// VFP registers - double word view only (not visible in gdb)
{"d0", 700, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(0) },
{"d1", 701, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(1) },
{"d2", 702, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(2) },
{"d3", 703, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(3) },
{"d4", 704, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(4) },
{"d5", 705, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(5) },
{"d6", 706, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(6) },
{"d7", 707, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(7) },
{"d8", 708, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(8) },
{"d9", 709, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(9) },
{"d10", 710, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(10)},
{"d11", 711, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(11)},
{"d12", 712, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(12)},
{"d13", 713, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(13)},
{"d14", 714, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(14)},
{"d15", 715, vmi_REG_NONE, 64, False, ARM_VFP_DATA_REG(15)},
{0},
};
//
// Return ARM register descriptions
//
static vmiRegInfoCP getRegisters(void) {
static vmiRegInfo *allRegisters;
if(!allRegisters) {
armSysRegDesc desc;
Uns32 basicNum = 0;
Uns32 sysNum = 0;
Uns32 i;
// count basic registers
while(basicRegisters[basicNum].name) {
basicNum++;
}
// count system registers
desc.name = 0;
while(armGetSysRegisterDesc(&desc)) {
sysNum++;
}
// allocate full register information, including terminating NULL entry
// TODO: This is never freed! Need to free description too
allRegisters = STYPE_CALLOC_N(vmiRegInfo, basicNum+sysNum+1);
// fill basic entries
for(i=0; i<basicNum; i++) {
allRegisters[i] = basicRegisters[i];
}
// fill system entries
for(desc.name=0, i=0; armGetSysRegisterDesc(&desc); i++) {
vmiRegInfo *reg = &allRegisters[basicNum+i];
// fill basic fields
reg->name = desc.name;
reg->usage = vmi_REG_NONE;
reg->bits = 32;
reg->readonly = False;
reg->readCB = readSCS;
reg->writeCB = writeSCS;
reg->userData = (void *)desc.id;
reg->group = ARM_GROUP(SYSTEM);
// synthesize a description
char descStr[64];
snprintf(descStr, 64, "Addr: 0x%08x Priv:%s User:%s", desc.address, desc.privRW, desc.userRW);
reg->description = strdup(descStr);
// use address as gdb pseudo-index
reg->gdbIndex = desc.address;
}
}
// return register set
return allRegisters;
}
//
// Return current vmiRegInfoCP structure for the passed banked vmiRegInfoCP
//
vmiRegInfoCP getCurrentInfo(vmiRegInfoCP reg) {
Uns32 index = reg->gdbIndex % 100;
vmiRegInfoCP info;
for(info=getRegisters(); info->name; info++) {
if(info->gdbIndex == index) {
return info;
}
}
return 0;
}
//
// Is the passed register supported on this processor?
//
static Bool isRegSupported(armP arm, vmiRegInfoCP reg, Bool gdbFrame) {
if(gdbFrame && IS_GDB_HIDDEN_REG(reg->gdbIndex)) {
// if this is a GDB frame request then registers that should be hidden
// from GDB should be ignored
return False;
} else if(IS_VFP_REG(reg->gdbIndex)) {
// VFP registers are supported if in variant
return FPU_PRESENT(arm);
} else if(IS_SCS_REG(reg->gdbIndex)) {
// system registers are supported only if the associated unit is present
return armGetSysRegSupported(getSysId(reg), arm);
}
// other registers are always supported
return True;
}
//
// Return next supported register on this processor
//
static vmiRegInfoCP getNextRegister(armP arm, vmiRegInfoCP reg, Bool gdbFrame) {
do {
if(!reg) {
reg = getRegisters();
} else if((reg+1)->name) {
reg = reg+1;
} else {
reg = 0;
}
} while(reg && !isRegSupported(arm, reg, gdbFrame));
return reg;
}
//
// Is the passed register group supported on this processor?
//
static Bool isGroupSupported(armP arm, vmiRegGroupCP group) {
vmiRegInfoCP info = 0;
while((info=getNextRegister(arm, info, False))) {
if(info->group == group) {
return True;
}
}
return False;
}
//
// Return next supported group on this processor
//
static vmiRegGroupCP getNextGroup(armP arm, vmiRegGroupCP group) {
do {
if(!group) {
group = groups;
} else if((group+1)->name) {
group = group+1;
} else {
group = 0;
}
} while(group && !isGroupSupported(arm, group));
return group;
}
//
// Register structure iterator
//
VMI_REG_INFO_FN(armRegInfo) {
return getNextRegister((armP)processor, prev, gdbFrame);
}
//
// Register group iterator
//
VMI_REG_GROUP_FN(armRegGroup) {
return getNextGroup((armP)processor, prev);
}
////////////////////////////////////////////////////////////////////////////////
// REGISTER DUMP INTERFACE
////////////////////////////////////////////////////////////////////////////////
//
// Dump processor registers
//
VMI_DEBUG_FN(armDumpRegisters) {
armP arm = (armP)processor;
Bool showHiddenRegs = arm->showHiddenRegs;
Uns32 nameWidth = showHiddenRegs ? 10 : 7;
vmiRegInfoCP info = 0;
while((info=getNextRegister(arm, info, False))) {
if(IS_SCS_REG(info->gdbIndex)) {
// ignore system registers
} else if(IS_VFP_DATA_REG(info->gdbIndex)) {
// print VFP regs if enabled
if(ARM_DUMP_SDFP_REG(arm)) {
const char *fmt = " %-*s 0x" FMT_640Nx "\n";
Uns64 value;
// read and print register value
vmiosRegRead(processor, info, &value);
vmiPrintf(fmt, nameWidth, info->name, value);
}
} else if(!IS_GDB_HIDDEN_REG(info->gdbIndex) || showHiddenRegs) {
const char *fmt;
Uns32 value;
// read register value
vmiosRegRead(processor, info, &value);
// select approriate format string
if((info->usage==vmi_REG_SP) || (info->usage==vmi_REG_PC)) {
fmt = " %-*s 0x%-8x 0x%x\n";
} else {
fmt = " %-*s 0x%-8x %u\n";
}
// print register using selected format
vmiPrintf(fmt, nameWidth, info->name, value, value);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// SCS PROGRAMMER'S VIEW
////////////////////////////////////////////////////////////////////////////////
//
// Add programmer's view of all system registers
//
void armAddSysRegistersView(armP arm, vmiViewObjectP processorObject) {
vmiRegInfoCP info = 0;
// create coprocessor 15 child object
vmiViewObjectP baseObject = vmirtAddViewObject(processorObject, "SCS", 0);
while((info=getNextRegister(arm, info, False))) {
if(IS_SCS_REG(info->gdbIndex)) {
const char *name = info->name;
armSCSRegId id = getSysId(info);
armAddSysRegisterView(id, arm, baseObject, name);
}
}
}