/*
Copyright (C) 1998 T. Scott Dattalo
This file is part of gpsim.
gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gpsim; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <iostream>
#include <iomanip>
#include "cmd_gpsim.h"
#include "cmd_manager.h"
#include "../config.h"
#include "pic-processor.h"
#include "breakpoints.h"
#include "14bit-processors.h"
#include "xref.h"
#include "icd.h"
extern "C"{
#include "lxt_write.h"
}
#define PCPU ((Processor *)cpu)
extern guint64 simulation_start_cycle;
// Global declaration of THE breakpoint object
// create an instance of inline get_trace() method by taking its address
Breakpoints &(*dummy_bp)() = get_bp;
Breakpoints bp;
//------------------------------------------------------------------------
// find_free - search the array that holds the break points for a free slot
//
int Breakpoints::find_free()
{
for(int i=0; i<MAX_BREAKPOINTS; i++) {
if(break_status[i].type == BREAK_CLEAR) {
if (i + 1 > m_iMaxAllocated)
m_iMaxAllocated = i + 1;
return i;
}
}
cout << "*** out of breakpoints\n";
return(MAX_BREAKPOINTS);
}
//------------------------------------------------------------------------
// set_breakpoint - Set a breakpoint of a specific type.
//
int Breakpoints::set_breakpoint(BREAKPOINT_TYPES break_type,
Processor *cpu,
unsigned int arg1,
unsigned arg2,
TriggerObject *f1)
{
Register *fr;
breakpoint_number = find_free();
if(breakpoint_number >= MAX_BREAKPOINTS)
return breakpoint_number;
BreakStatus &bs = break_status[breakpoint_number];
bs.type = break_type;
bs.cpu = cpu;
bs.arg1 = arg1;
bs.arg2 = arg2;
bs.bpo = f1;
switch (break_type)
{
case BREAK_ON_INVALID_FR:
fr = cpu->registers[arg1];
return(breakpoint_number);
break;
case BREAK_ON_CYCLE:
{
guint64 cyc = arg2;
cyc = (cyc<<32) | arg1;
// The cycle counter does its own break points.
if(get_cycles().set_break(cyc, f1, breakpoint_number)) {
if(cpu != NULL) {
cpu->NotifyBreakpointSet(bs, f1);
}
return(breakpoint_number);
}
else
bs.type = BREAK_CLEAR;
}
break;
case BREAK_ON_STK_OVERFLOW:
if ((cpu->GetCapabilities() & Processor::eBREAKONSTACKOVER)
== Processor::eBREAKONSTACKOVER) {
// pic_processor should not be referenced here
// Should have a GetStack() virtual function in Processor class.
// Of course then the Stack class needs to be a virtual class.
if(((pic_processor *)(cpu))->stack->set_break_on_overflow(1))
return (breakpoint_number);
}
else {
// Need to add console object
printf("Stack breaks not available on a %s processor\n", cpu->name().c_str());
}
bs.type = BREAK_CLEAR;
break;
case BREAK_ON_STK_UNDERFLOW:
if ((cpu->GetCapabilities() & Processor::eBREAKONSTACKUNDER)
== Processor::eBREAKONSTACKUNDER) {
// pic_processor should not be referenced here
// Should have a GetStack() virtual function in Processor class.
// Of course then the Stack class needs to be a virtual class.
if(((pic_processor *)(cpu))->stack->set_break_on_underflow(1))
return (breakpoint_number);
}
else {
// Need to add console object
printf("Stack breaks not available on a %s processor\n", cpu->name().c_str());
}
bs.type = BREAK_CLEAR;
break;
case BREAK_ON_WDT_TIMEOUT:
if ((cpu->GetCapabilities() & Processor::eBREAKONWATCHDOGTIMER)
== Processor::eBREAKONWATCHDOGTIMER) {
// pic_processor should not be referenced here
// Should have a GetStack() virtual function in Processor class.
// Of course then the Stack class needs to be a virtual class.
((_14bit_processor *)cpu)->wdt.set_breakpoint(BREAK_ON_WDT_TIMEOUT | breakpoint_number);
return(breakpoint_number);
}
else {
// Need to add console object
printf("Watch dog timer breaks not available on a %s processor\n", cpu->name().c_str());
}
default: // Not a valid type
bs.type = BREAK_CLEAR;
break;
}
return(MAX_BREAKPOINTS);
}
//------------------------------------------------------------------------
//BreakTraceType *m_brt=0;
int Breakpoints::set_breakpoint(TriggerObject *bpo, Expression *pExpr)
{
int bpn = find_free();
if(bpn >= MAX_BREAKPOINTS || !bpo->set_break()) {
delete bpo;
return MAX_BREAKPOINTS;
}
BreakStatus &bs = break_status[bpn];
bs.bpo = bpo;
bs.type = BREAK_MASK; // place holder for now...
bpo->bpn = bpn;
bpo->set_Expression(pExpr);
if(get_active_cpu() != NULL)
get_active_cpu()->NotifyBreakpointSet(bs, bpo);
return bpn;
}
//------------------------------------------------------------------------
static BreakpointRegister_Value::BRV_Ops MapComparisonOperatorToBreakOperator(ComparisonOperator *pCompareOp)
{
if (pCompareOp)
switch(pCompareOp->isa()) {
case ComparisonOperator::eOpEq:
return BreakpointRegister_Value::eBREquals;
case ComparisonOperator::eOpGe:
return BreakpointRegister_Value::eBRGreaterThenEquals;
case ComparisonOperator::eOpGt:
return BreakpointRegister_Value::eBRGreaterThen;
case ComparisonOperator::eOpLe:
return BreakpointRegister_Value::eBRLessThenEquals;
case ComparisonOperator::eOpLt:
return BreakpointRegister_Value::eBRLessThen;
case ComparisonOperator::eOpNe:
return BreakpointRegister_Value::eBRNotEquals;
}
return BreakpointRegister_Value::eBRInvalid;
}
//------------------------------------------------------------------------
//
int Breakpoints::set_break(gpsimObject::ObjectBreakTypes bt, gpsimObject::ObjectActionTypes at,
Register *pReg,
Expression *pExpr)
{
int iValue = -1;
int iMask = -1;
bool bCompiledExpression = false;
BreakpointRegister_Value::BRV_Ops op = BreakpointRegister_Value::eBRInvalid;
Processor *pCpu = (pReg && pReg->get_cpu()) ? pReg->get_cpu() : get_active_cpu();
Register *pRegInExpr = 0;
if (pExpr) {
/* attempt to compile expressions of these types:
*
*
* ComparisonOperator
* / \
* OpAnd LiteralInteger
* / \
* register_symbol LiteralInteger
*
* --- OR ---
*
* ComparisonOperator
* / \
* register_symbol LiteralInteger
*
* --- OR ---
*
* OpAnd (not implemented)
* / \
* register_symbol LiteralInteger
*
*/
ComparisonOperator *pCompareExpr = dynamic_cast<ComparisonOperator *>(pExpr);
op = MapComparisonOperatorToBreakOperator(pCompareExpr);
if (op != BreakpointRegister_Value::eBRInvalid) {
OpAnd* pLeftOp = dynamic_cast<OpAnd*>(pCompareExpr->getLeft());
LiteralSymbol *pLeftSymbol = pLeftOp ?
dynamic_cast<LiteralSymbol*>(pLeftOp->getLeft()) :
dynamic_cast<LiteralSymbol*>(pCompareExpr->getLeft());
register_symbol *pRegSym = pLeftSymbol ?
dynamic_cast<register_symbol*>(pLeftSymbol->GetSymbol()) : 0;
pRegInExpr = pRegSym ? pRegSym->getReg() : 0;
if (!pRegInExpr) {
// Legacy code... try to cast the left most integer into a register.
LiteralInteger *pLeftRegAsInteger = pLeftOp ?
dynamic_cast<LiteralInteger*>(pLeftOp->getLeft()) :
dynamic_cast<LiteralInteger*>(pCompareExpr->getLeft());
Integer *pRegAddress = pLeftRegAsInteger ?
dynamic_cast<Integer*>(pLeftRegAsInteger->evaluate()) : 0;
pRegInExpr = (pRegAddress && pCpu) ? &pCpu->rma[(int)pRegAddress->getVal()] : 0;
delete pRegAddress;
}
LiteralInteger* pRightSymbol = pLeftOp ?
dynamic_cast<LiteralInteger*>(pLeftOp->getRight()) : 0;
Integer *pMask = pRightSymbol ?
dynamic_cast<Integer*>(pRightSymbol->evaluate()) : 0;
iMask = pCpu ? pCpu->register_mask() : iMask;
gint64 i64=0;
if (pMask) {
pMask->get(i64);
iMask = (int)i64;
}
LiteralInteger* pRightValue = dynamic_cast<LiteralInteger*>(pCompareExpr->getRight());
Integer *pValue = pRightValue ?
dynamic_cast<Integer*>(pRightValue->evaluate()) : 0;
// Now check if this parsing was successful
if (pReg == pRegInExpr && pValue) {
bCompiledExpression = true;
pValue->get(i64);
iValue = (int)i64;
}
delete pMask;
delete pValue;
}
}
// If there was no register passed in as an input and we failed to compile
// the expression (and hence unable to extract a register from the expression)
// then don't set a break.
pReg = pReg ? pReg : pRegInExpr;
if (!pReg)
return -1;
if (bt == gpsimObject::eBreakWrite) {
if (bCompiledExpression) {
delete pExpr;
return (at == gpsimObject::eActionLog) ?
set_breakpoint(new Log_Register_Write_value(pCpu, pReg->address, 0,iValue,op,iMask))
:
set_breakpoint(new Break_register_write_value(pCpu, pReg->address, 0,iValue,op,iMask));
} else
return (at == gpsimObject::eActionLog) ?
set_breakpoint(new Log_Register_Write(pCpu, pReg->address,0), pExpr)
:
set_breakpoint(new Break_register_write(pCpu, pReg->address,0), pExpr);
} else if (bt == gpsimObject::eBreakRead) {
if (bCompiledExpression) {
delete pExpr;
return (at == gpsimObject::eActionLog) ?
set_breakpoint(new Log_Register_Read_value(pCpu, pReg->address, 0,iValue,op,iMask))
:
set_breakpoint(new Break_register_read_value(pCpu, pReg->address, 0,iValue,op,iMask));
} else
return (at == gpsimObject::eActionLog) ?
set_breakpoint(new Log_Register_Read(pCpu, pReg->address,0), pExpr)
:
set_breakpoint(new Break_register_read(pCpu, pReg->address,0), pExpr);
}
return -1;
}
bool Breakpoints::set_expression(unsigned int bpn, Expression *pExpr)
{
if(bpn < MAX_BREAKPOINTS) {
BreakStatus &bs = break_status[bpn];
if(bs.bpo) {
bs.bpo->set_Expression(pExpr);
return true;
}
}
return false;
}
int Breakpoints::set_execution_break(Processor *cpu,
unsigned int address,
Expression *pExpr)
{
Breakpoint_Instruction *bpi = new Breakpoint_Instruction(cpu,address,0);
return bp.set_breakpoint(bpi,pExpr);
}
int Breakpoints::set_notify_break(Processor *cpu,
unsigned int address,
TriggerObject *f1 = 0)
{
GetTraceLog().enable_logging();
Notify_Instruction *ni = new Notify_Instruction(cpu,address,0,f1);
return bp.set_breakpoint(ni);
}
int Breakpoints::set_profile_start_break(Processor *cpu,
unsigned int address,
TriggerObject *f1)
{
Profile_Start_Instruction *psi = new Profile_Start_Instruction(cpu,address,0,f1);
return bp.set_breakpoint(psi);
}
int Breakpoints::set_profile_stop_break(Processor *cpu,
unsigned int address,
TriggerObject *f1)
{
Profile_Stop_Instruction *psi = new Profile_Stop_Instruction(cpu,address,0,f1);
return bp.set_breakpoint(psi);
}
int Breakpoints::set_read_break(Processor *cpu, unsigned int register_number)
{
Break_register_read *brr = new Break_register_read(cpu,register_number,0);
return bp.set_breakpoint(brr);
}
int Breakpoints::set_write_break(Processor *cpu, unsigned int register_number)
{
Break_register_write *brw = new Break_register_write(cpu,register_number,0);
return bp.set_breakpoint(brw);
}
int Breakpoints::set_read_value_break(Processor *cpu,
unsigned int register_number,
unsigned int value,
unsigned int mask)
{
return set_read_value_break(cpu, register_number,
BreakpointRegister_Value::eBREquals, value, mask);
}
int Breakpoints::set_read_value_break(Processor *cpu,
unsigned int register_number,
unsigned int op,
unsigned int value,
unsigned int mask)
{
Break_register_read_value *brrv = new Break_register_read_value(cpu,
register_number,
0,
value,
op,
mask);
return bp.set_breakpoint(brrv);
}
int Breakpoints::set_write_value_break(Processor *cpu,
unsigned int register_number,
unsigned int value,
unsigned int mask)
{
return set_write_value_break(cpu, register_number,
BreakpointRegister_Value::eBREquals, value, mask);
}
int Breakpoints::set_write_value_break(Processor *cpu,
unsigned int register_number,
unsigned int op,
unsigned int value,
unsigned int mask)
{
Break_register_write_value *brwv = new Break_register_write_value(cpu,
register_number,
0,
value,
op,
mask);
return bp.set_breakpoint(brwv);
}
int Breakpoints::set_cycle_break(Processor *cpu,
guint64 future_cycle,
TriggerObject *f1)
{
return(set_breakpoint (Breakpoints::BREAK_ON_CYCLE,
cpu,
(unsigned int)(future_cycle & 0xffffffff),
(unsigned int)(future_cycle>>32),
f1));
}
int Breakpoints::set_stk_overflow_break(Processor *cpu)
{
return(set_breakpoint (Breakpoints::BREAK_ON_STK_OVERFLOW, cpu, 0, 0));
}
int Breakpoints::set_stk_underflow_break(Processor *cpu)
{
return(set_breakpoint (Breakpoints::BREAK_ON_STK_UNDERFLOW, cpu, 0, 0));
}
int Breakpoints::set_wdt_break(Processor *cpu)
{
if ((cpu->GetCapabilities() & Processor::eBREAKONWATCHDOGTIMER)
== Processor::eBREAKONWATCHDOGTIMER) {
// Set a wdt break only if one is not already set.
if(!cpu14->wdt.hasBreak())
return(set_breakpoint (Breakpoints::BREAK_ON_WDT_TIMEOUT, cpu, 0, 0));
}
else {
// Need to add console object
printf("Watch dog timer breaks not available on a %s processor\n", cpu->name().c_str());
}
return MAX_BREAKPOINTS;
}
int Breakpoints::set_notify_read(Processor *cpu,
unsigned int register_number)
{
GetTraceLog().enable_logging();
Log_Register_Read *lrr = new Log_Register_Read(cpu,register_number,0);
return bp.set_breakpoint(lrr);
}
int Breakpoints::set_notify_write(Processor *cpu,
unsigned int register_number)
{
GetTraceLog().enable_logging();
Log_Register_Write *lrw = new Log_Register_Write(cpu,register_number,0);
return bp.set_breakpoint(lrw);
}
int Breakpoints::set_notify_read_value(Processor *cpu,
unsigned int register_number,
unsigned int value,
unsigned int mask)
{
GetTraceLog().enable_logging();
Log_Register_Read_value *lrrv = new Log_Register_Read_value(cpu,
register_number,
0,
value,
mask);
return bp.set_breakpoint(lrrv);
}
int Breakpoints::set_notify_write_value(Processor *cpu,
unsigned int register_number,
unsigned int value,
unsigned int mask)
{
GetTraceLog().enable_logging();
Log_Register_Write_value *lrwv = new Log_Register_Write_value(cpu,
register_number,
0,
value,
mask);
return bp.set_breakpoint(lrwv);
}
int Breakpoints::check_cycle_break(unsigned int bpn)
{
cout << "cycle break: 0x" << hex << cycles.value << dec << " = " << cycles.value << endl;
halt();
if( bpn < MAX_BREAKPOINTS)
{
if (break_status[bpn].bpo)
break_status[bpn].bpo->callback();
//trace.breakpoint( (Breakpoints::BREAK_ON_CYCLE>>8) );
//trace.raw(m_brt->type() | bpn);
clear(bpn);
}
return(1);
}
bool Breakpoints::dump(TriggerObject *pTO)
{
if (!pTO)
return false;
pTO->print();
return true;
}
bool Breakpoints::dump1(unsigned int bp_num, int dump_type)
{
if(!bIsValid(bp_num)) {
printf("Break point number: %d is out of range\n",bp_num);
return false;
}
BreakStatus &bs = break_status[bp_num];
if(bs.bpo) {
switch(dump_type) {
case BREAK_ON_EXECUTION:
if(dynamic_cast<RegisterAssertion*>(bs.bpo) != 0) {
// for 'break e' we skip RegisterAssertions
// and dump user execution breaks.
return false;
}
break;
case BREAK_ON_REG_WRITE:
if(dynamic_cast<Break_register_write *>(bs.bpo) != 0 ||
dynamic_cast<Break_register_write_value*>(bs.bpo) != 0) {
// for 'break w' we dump register write classes
break;
}
return false;
case BREAK_ON_REG_READ:
if(dynamic_cast<Break_register_read *>(bs.bpo) != 0 ||
dynamic_cast<Break_register_read_value*>(bs.bpo) != 0) {
// for 'break r' we dump register read classes
break;
}
default:
break;
}
return dump(bs.bpo);
} else {
BREAKPOINT_TYPES break_type = break_status[bp_num].type;
switch (break_type) {
case BREAK_ON_CYCLE:
{
const char * pFormat = "%d: cycle 0x%" PRINTF_INT64_MODIFIER "x = %" PRINTF_INT64_MODIFIER "d\n";
guint64 cyc = bs.arg2;
cyc = (cyc <<32) | bs.arg1;
GetUserInterface().DisplayMessage(pFormat, bp_num, cyc, cyc);
}
break;
case BREAK_ON_STK_UNDERFLOW:
case BREAK_ON_STK_OVERFLOW:
cout << hex << setw(0) << bp_num << ": " << bs.cpu->name() << " ";
cout << "stack " << ((break_type == BREAK_ON_STK_OVERFLOW)?"ov":"und") << "er flow\n";
break;
case BREAK_ON_WDT_TIMEOUT:
cout << hex << setw(0) << bp_num << ": " << bs.cpu->name() << " ";
cout << "wdt time out\n";
break;
default:
return false;
break;
}
}
return true;
}
void Breakpoints::dump(int dump_type)
{
bool have_breakpoints = 0;
if(dump_type != BREAK_ON_CYCLE) {
for(int i = 0; i<m_iMaxAllocated; i++)
{
if(dump1(i, dump_type))
have_breakpoints = 1;
}
}
if(dump_type == BREAK_DUMP_ALL ||
dump_type == BREAK_ON_CYCLE) {
cout << "Internal Cycle counter break points" << endl;
get_cycles().dump_breakpoints();
have_breakpoints = 1;
cout << endl;
}
if(!have_breakpoints)
cout << "No user breakpoints are set" << endl;
}
instruction *Breakpoints::find_previous(Processor *cpu,
unsigned int address,
instruction *_this)
{
Breakpoint_Instruction *p;
p = (Breakpoint_Instruction*) cpu->pma->getFromAddress(address);
if(!_this || p==_this)
return 0;
while(p->getReplaced()!=_this)
{
p=(Breakpoint_Instruction*)p->getReplaced();
}
return p;
}
void Breakpoints::clear(unsigned int b)
{
if (!bIsValid(b))
return;
BreakStatus &bs = break_status[b]; //
if(bs.bpo) {
bs.bpo->clear();
bs.type = BREAK_CLEAR;
get_active_cpu()->NotifyBreakpointCleared(bs, bs.bpo);
//delete bs.bpo; // FIXME - why does this delete cause a segv?
bs.bpo = 0;
return;
}
switch (bs.type) {
case BREAK_ON_CYCLE:
bs.type = BREAK_CLEAR;
//cout << "Cleared cycle breakpoint number " << b << '\n';
break;
case BREAK_ON_STK_OVERFLOW:
bs.type = BREAK_CLEAR;
if ((bs.cpu->GetCapabilities() & Processor::eSTACK)
== Processor::eSTACK) {
if(((pic_processor *)(bs.cpu))->stack->set_break_on_overflow(0))
cout << "Cleared stack overflow break point.\n";
else
cout << "Stack overflow break point is already cleared.\n";
}
break;
case BREAK_ON_STK_UNDERFLOW:
bs.type = BREAK_CLEAR;
if ((bs.cpu->GetCapabilities() & Processor::eSTACK)
== Processor::eSTACK) {
if(((pic_processor *)(bs.cpu))->stack->set_break_on_underflow(0))
cout << "Cleared stack underflow break point.\n";
else
cout << "Stack underflow break point is already cleared.\n";
}
break;
case BREAK_ON_WDT_TIMEOUT:
bs.type = BREAK_CLEAR;
if ((bs.cpu->GetCapabilities() & Processor::eBREAKONWATCHDOGTIMER)
== Processor::eBREAKONWATCHDOGTIMER) {
cout << "Cleared wdt timeout breakpoint number " << b << '\n';
((_14bit_processor *)bs.cpu)->wdt.set_breakpoint(0);
}
break;
default:
bs.type = BREAK_CLEAR;
break;
}
get_active_cpu()->NotifyBreakpointCleared(bs, NULL);
}
bool Breakpoints::bIsValid(unsigned int b)
{
return b < MAX_BREAKPOINTS;
}
bool Breakpoints::bIsClear(unsigned int b)
{
return bIsValid(b) && break_status[b].type == BREAK_CLEAR;
}
void Breakpoints::set_message(unsigned int b,string &m)
{
if (bIsValid(b) && break_status[b].type != BREAK_CLEAR && break_status[b].bpo)
break_status[b].bpo->new_message(m);
}
//
// dump_traced
// Called by the trace class to display a breakpoint that is in the
// trace buffer.
void Breakpoints::dump_traced(unsigned int b)
{
BREAKPOINT_TYPES break_type = (BREAKPOINT_TYPES) ((b & 0xff0000) << 8);
switch (break_type)
{
case BREAK_ON_EXECUTION:
cout << "execution at "<< hex << setw(4) << setfill('0') << (b & 0xffff) << '\n';
break;
case BREAK_ON_REG_WRITE:
cout << "reg write: " << hex << setw(2) << setfill('0') << (b & 0xff) << '\n';
break;
case BREAK_ON_REG_WRITE_VALUE:
cout << "wrote " << hex << setw(2) << setfill('0') << ((b & 0xff00)>>8) <<
" to register " << hex << setw(2) << setfill('0') << (b & 0xff) << '\n';
break;
case BREAK_ON_REG_READ:
cout << "reg write: " << hex << setw(2) << setfill('0') << (b & 0xff) << '\n';
break;
case BREAK_ON_REG_READ_VALUE:
cout << "read " << hex << setw(2) << setfill('0') << ((b & 0xff00)>>8) <<
" from register " << hex << setw(2) << setfill('0') << (b & 0xff) << '\n';
break;
case BREAK_ON_CYCLE:
cout << "cycle " << '\n';
break;
case BREAK_ON_WDT_TIMEOUT:
cout << "wdt time out\n";
break;
default:
cout << "unknown\n";
}
}
// Clear all break points that are set for a specific processor
// This only be called when a processor is being removed and not when a user
// wants to clear the break points. Otherwise, internal break points like
// invalid register accesses will get cleared.
void Breakpoints::clear_all(Processor *c)
{
for(int i=0; i<MAX_BREAKPOINTS; i++)
{
if(break_status[i].type != BREAK_CLEAR)
clear(i);
}
}
void Breakpoints::clear_all_set_by_user(Processor *c)
{
for(int i=0; i<MAX_BREAKPOINTS; i++)
{
if((c == break_status[i].cpu) && (break_status[i].type != BREAK_ON_INVALID_FR))
clear(i);
}
}
//--------------------------------------------------
// Clear all of the break points that are set on a register
//
// FIXME -- this tacitly assumes "register memory". Thus it's
// not possible to use this function on EEPROM or module registers.
void Breakpoints::clear_all_register(Processor *c,unsigned int address)
{
if(!c || address<0 || address > c->register_memory_size())
return;
while(c->registers[address]->isa()==Register::BP_REGISTER) {
BreakpointRegister *nr = dynamic_cast<BreakpointRegister *>(c->registers[address]);
if(!nr)
return;
bp.clear(nr->bpn & ~Breakpoints::BREAK_MASK);
}
}
void Breakpoints::halt()
{
if(get_use_icd()) {
icd_halt();
return;
}
global_break |= GLOBAL_STOP_RUNNING;
if(m_bExitOnBreak) {
// Let the UI or client code choose how and
// when to exit.
GetUserInterface().NotifyExitOnBreak(0);
}
}
Breakpoints::Breakpoints()
{
m_iMaxAllocated = 0;
breakpoint_number = 0;
m_bExitOnBreak = false;
for(int i=0; i<MAX_BREAKPOINTS; i++)
break_status[i].type = BREAK_CLEAR;
}
//----------------------------------------------------------------------------
bool Breakpoint_Instruction::eval_Expression()
{
if (bHasExpression())
return !TriggerObject::eval_Expression();
return true;
}
void Breakpoint_Instruction::execute()
{
if( (cpu->simulation_mode == eSM_RUNNING) &&
(simulation_start_cycle != get_cycles().value) &&
eval_Expression()) {
invokeAction();
} else
m_replaced->execute();
}
Breakpoint_Instruction::Breakpoint_Instruction(Processor *new_cpu,
unsigned int new_address,
unsigned int bp)
: TriggerObject(0)
{
cpu = new_cpu;
address = new_address;
opcode = 0xffffffff;
bpn = bp;
m_replaced = new_cpu->pma->getFromAddress(address);
set_action(new SimpleTriggerAction(this));
}
Processor* Breakpoint_Instruction::get_cpu()
{
return dynamic_cast<Processor *>(cpu);
}
//-------------------------------------------------------------------
bool Breakpoint_Instruction::set_break()
{
if(get_use_icd())
bp.clear_all(get_cpu());
unsigned int uIndex = get_cpu()->map_pm_address2index(address);
if(uIndex < get_cpu()->program_memory_size()) {
m_replaced = get_cpu()->pma->getFromIndex(uIndex);
get_cpu()->pma->putToIndex(uIndex, this);
if(get_use_icd())
icd_set_break(address);
return true;
}
return false;
}
void Breakpoint_Instruction::print()
{
// Output example
// 42: p17c756 Execution at 0x0123
const char * pLabel = get_symbol_table().
findProgramAddressLabel(address);
const char * pFormat = *pLabel == 0 ? "%d: %s %s at %s0x%x\n"
: "%d: %s %s at %s(0x%x)\n";
GetUserInterface().DisplayMessage(pFormat,
bpn, cpu->name().c_str(), bpName(), pLabel, address);
TriggerObject::print();
}
int Breakpoint_Instruction::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (!pBuf || !pTrace)
return 0;
int m;
if (bHasExpression()) {
char buf[256];
printExpression(buf, sizeof(buf));
m = snprintf(pBuf, szBuf,
" assertion at 0x%04x, expr:%s",address,buf);
} else
m = snprintf(pBuf, szBuf,
" execution at 0x%04x",address);
return m>0 ? m : 0;
}
void Breakpoint_Instruction::clear()
{
if(get_use_icd())
icd_clear_break();
get_cpu()->pma->clear_break_at_address(address, this);
get_cpu()->pma->getFromAddress(address)->update();
}
//------------------------------------------------------------------------
void Notify_Instruction::execute()
{
if(callback)
callback->callback();
m_replaced->execute();
}
Notify_Instruction::Notify_Instruction(Processor *cpu,
unsigned int address,
unsigned int bp,
TriggerObject *cb) :
Breakpoint_Instruction(cpu, address,bp)
{
callback=cb;
}
//------------------------------------------------------------------------
Profile_Start_Instruction::Profile_Start_Instruction(Processor *cpu,
unsigned int address,
unsigned int bp,
TriggerObject *cb) :
Notify_Instruction(cpu, address, bp, cb)
{
}
Profile_Stop_Instruction::Profile_Stop_Instruction(Processor *cpu,
unsigned int address,
unsigned int bp,
TriggerObject *cb) :
Notify_Instruction(cpu, address, bp, cb)
{
}
//------------------------------------------------------------------------------
RegisterAssertion::RegisterAssertion(Processor *cpu,
unsigned int address,
unsigned int bp,
unsigned int _regAddress,
unsigned int _regMask,
unsigned int _regValue,
bool _bPostAssertion) :
Breakpoint_Instruction(cpu, address,bp),
regAddress(_regAddress),
regMask(_regMask),
regValue(_regValue),
bPostAssertion(_bPostAssertion),
m_pfnIsAssertionBreak(IsAssertionEqualsBreakCondition) {
}
RegisterAssertion::RegisterAssertion(Processor *cpu,
unsigned int address,
unsigned int bp,
unsigned int _regAddress,
unsigned int _regMask,
unsigned int _operator,
unsigned int _regValue,
bool _bPostAssertion) :
Breakpoint_Instruction(cpu, address,bp),
regAddress(_regAddress),
regMask(_regMask),
regValue(_regValue),
bPostAssertion(_bPostAssertion)
{
switch(_operator) {
case eRAEquals:
m_pfnIsAssertionBreak = IsAssertionEqualsBreakCondition;
break;
case eRANotEquals:
m_pfnIsAssertionBreak = IsAssertionNotEqualsBreakCondition;
break;
case eRAGreaterThen:
m_pfnIsAssertionBreak = IsAssertionGreaterThenBreakCondition;
break;
case eRALessThen:
m_pfnIsAssertionBreak = IsAssertionLessThenBreakCondition;
break;
case eRAGreaterThenEquals:
m_pfnIsAssertionBreak = IsAssertionGreaterThenEqualsBreakCondition;
break;
case eRALessThenEquals:
m_pfnIsAssertionBreak = IsAssertionLessThenEqualsBreakCondition;
break;
default:
assert(false);
break;
}
}
bool RegisterAssertion::IsAssertionEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) != uRegTestValue;
}
bool RegisterAssertion::IsAssertionNotEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) == uRegTestValue;
}
bool RegisterAssertion::IsAssertionGreaterThenBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) <= uRegTestValue;
}
bool RegisterAssertion::IsAssertionLessThenBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) >= uRegTestValue;
}
bool RegisterAssertion::IsAssertionGreaterThenEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) < uRegTestValue;
}
bool RegisterAssertion::IsAssertionLessThenEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) > uRegTestValue;
}
//------------------------------------------------------------------------------
void RegisterAssertion::execute()
{
// For "post" assertions, the instruction is simulated first
// and then the register assertion is checked.
if(bPostAssertion && m_replaced)
m_replaced->execute();
// If the assertion is true, and the "phase" of the instruction is
// '0' then halt the simulation. Note, the reason for checking "phase"
// is to ensure the assertion applies to the the proper cycle of a
// multi-cycle instruction. For example, an assertion applied to a
// a "GOTO" instruction should only get checked before the instruction
// executes if it's a pre-assertion or after it completes if it's a
// post assertion.
unsigned int curRegValue = PCPU->rma[regAddress].get_value();
if( m_pfnIsAssertionBreak(curRegValue, regMask, regValue) &&
(PCPU->pc->get_phase() == 0) )
{
cout << "Caught Register assertion ";
cout << "while excuting at address " << address << endl;
cout << "register 0x"
<< hex
<< regAddress
<< " = 0x"
<< curRegValue << endl;
cout << "0x" << PCPU->rma[regAddress].get_value()
<< " & 0x" << regMask
<< " != 0x" << regValue << endl;
cout << " regAddress =0x" << regAddress
<< " regMask = 0x" << regMask
<< " regValue = 0x" << regValue << endl;
PCPU->Debug();
if( (PCPU->simulation_mode == eSM_RUNNING) &&
(simulation_start_cycle != get_cycles().value)) {
eval_Expression();
invokeAction();
trace.raw(m_brt->type(1) | curRegValue );
return;
}
}
// If this is not a post assertion, then the instruction executes after
// the instruction simulates.
if(!bPostAssertion && m_replaced)
m_replaced->execute();
}
//------------------------------------------------------------------------------
void RegisterAssertion::print()
{
Breakpoint_Instruction::print();
Register & pReg = PCPU->rma[regAddress];
string & sName = pReg.name();
const char * pFormat = sName.empty()
? " break when register %s0x%x ANDed with 0x%x equals 0x%x\n"
: " break when register %s(0x%x) ANDed with 0x%x equals 0x%x\n" ;
GetUserInterface().DisplayMessage(pFormat,
sName.c_str(), regAddress, regMask, regValue);
TriggerObject::print();
}
int RegisterAssertion::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (!pBuf || pTrace)
return 0;
unsigned int valueWritten = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf, szBuf,
" Register Assertion PC=0x%04x, reg[0x%x]==0x%x != 0x%x",
address,regAddress,valueWritten,regValue);
return m>0 ? m : 0;
}
//------------------------------------------------------------------------------
BreakpointRegister::BreakpointRegister()
: TriggerObject(0)
{
}
BreakpointRegister::BreakpointRegister(Processor *_cpu,
TriggerAction *pTA,
Register *pRepl)
: TriggerObject(pTA)
{
setReplaced(pRepl);
}
BreakpointRegister::BreakpointRegister(Processor *_cpu, TriggerAction *ta,
int _repl, int bp)
: TriggerObject(ta)
{
bpn = bp;
replace(_cpu,_repl);
address = _repl;
}
BreakpointRegister::BreakpointRegister(Processor *_cpu, int _repl, int bp)
: TriggerObject(0)
{
bpn = bp;
replace(_cpu,_repl);
address = _repl;
}
void BreakpointRegister::replace(Processor *_cpu, unsigned int reg)
{
if (_cpu) {
cpu = _cpu;
_cpu->rma.insertRegister(reg,this);
}
update();
}
unsigned int BreakpointRegister::clear(unsigned int bp_num)
{
clear();
return 1;
}
/// BreakpointRegister::clear() will delete itself from the
/// chain of BreakpointRegister objects.
/// All derived classes that override this function need to
/// call this function of this base class.
// Note: There should be a RegisterChain class and this code
// should exist in the RegisterChain class. get_cpu()->registers
// would then be an array of RegisterChains.
void BreakpointRegister::clear()
{
// FIXME, we don't know if this breakpoint register is actually associated
// with the active cpu or not. It looks like we need a way for either the
// registers to know in which array they're stored OR the Module class needs
// to provide a 'removeRegister()' method.
if (get_cpu()) {
get_cpu()->rma.removeRegister(address,this);
get_cpu()->registers[address]->update();
}
}
bool BreakpointRegister::set_break()
{
return true;
}
void BreakpointRegister::print()
{
Register * pReg = get_symbol_table().findRegister(address);
if (pReg)
GetUserInterface().DisplayMessage("%d: %s %s: %s(0x%x)\n",
bpn, cpu->name().c_str(),
bpName(), pReg->name().c_str(),
address);
else
GetUserInterface().DisplayMessage("%d: %s: reg(0x%x)\n",
bpn, bpName(),
address);
TriggerObject::print();
}
int BreakpointRegister::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (!pBuf || pTrace)
return 0;
int m = snprintf(pBuf, szBuf,
" Breakpoint register ");
return m>0 ? m : 0;
}
string &BreakpointRegister::name() const
{
return m_replaced ? m_replaced->name() : gpsimValue::name();
};
void BreakpointRegister::put_value(unsigned int new_value)
{
getReplaced()->put_value(new_value);
}
void BreakpointRegister::put(unsigned int new_value)
{
getReplaced()->put(new_value);
}
void BreakpointRegister::putRV(RegisterValue rv)
{
getReplaced()->putRV(rv);
}
unsigned int BreakpointRegister::get_value()
{
return(getReplaced()->get_value());
}
RegisterValue BreakpointRegister::getRV()
{
return getReplaced()->getRV();
}
RegisterValue BreakpointRegister::getRVN()
{
return getReplaced()->getRVN();
}
unsigned int BreakpointRegister::get()
{
return(getReplaced()->get());
}
Register *BreakpointRegister::getReg()
{
return getReplaced() ? getReplaced()->getReg() : this;
}
void BreakpointRegister::setbit(unsigned int bit_number, bool new_value)
{
getReplaced()->setbit(bit_number, new_value);
}
bool BreakpointRegister::get_bit(unsigned int bit_number)
{
return(getReplaced()->get_bit(bit_number));
}
double BreakpointRegister::get_bit_voltage(unsigned int bit_number)
{
return(getReplaced()->get_bit_voltage(bit_number));
}
bool BreakpointRegister::hasBreak()
{
return true;
}
void BreakpointRegister::update()
{
if(getReplaced())
getReplaced()->update();
}
void BreakpointRegister::add_xref(void *an_xref)
{
if(getReplaced())
getReplaced()->add_xref(an_xref);
}
void BreakpointRegister::remove_xref(void *an_xref)
{
if(getReplaced())
getReplaced()->remove_xref(an_xref);
}
//------------------------------------------------------------------------
//-------------------------------------------------------------------
BreakpointRegister_Value::BreakpointRegister_Value(
Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int bm ) :
BreakpointRegister(_cpu,_repl,bp )
{
m_uDefRegMask = _cpu->register_mask();
break_value = bv;
break_mask = bm;
m_pfnIsBreak = IsEqualsBreakCondition;
m_sOperator = "==";
int regMask = (0x100 << (_cpu->register_size()-1)) - 1;
if(break_mask == 0)
break_mask = regMask;
}
BreakpointRegister_Value::BreakpointRegister_Value(
Processor *_cpu,
TriggerAction * pTA,
int _repl,
int bp,
unsigned int bv,
unsigned int bm ) :
BreakpointRegister(_cpu,pTA,_repl,bp )
{
m_uDefRegMask = _cpu->register_mask();
break_value = bv;
break_mask = bm;
m_pfnIsBreak = IsEqualsBreakCondition;
m_sOperator = "==";
int regMask = (0x100 << (_cpu->register_size()-1)) - 1;
if(break_mask == 0)
break_mask = regMask;
}
BreakpointRegister_Value::BreakpointRegister_Value(
Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int _operator,
unsigned int bm ) :
BreakpointRegister(_cpu,_repl,bp )
{
m_uDefRegMask = _cpu->register_mask();
break_value = bv;
break_mask = bm;
switch(_operator) {
case eBREquals:
m_pfnIsBreak = IsEqualsBreakCondition;
m_sOperator = "==";
break;
case eBRNotEquals:
m_pfnIsBreak = IsNotEqualsBreakCondition;
m_sOperator = "!=";
break;
case eBRGreaterThen:
m_pfnIsBreak = IsGreaterThenBreakCondition;
m_sOperator = ">";
break;
case eBRLessThen:
m_pfnIsBreak = IsLessThenBreakCondition;
m_sOperator = "<";
break;
case eBRGreaterThenEquals:
m_pfnIsBreak = IsGreaterThenEqualsBreakCondition;
m_sOperator = ">=";
break;
case eBRLessThenEquals:
m_pfnIsBreak = IsLessThenEqualsBreakCondition;
m_sOperator = "<=";
break;
default:
assert(false);
break;
}
int regMask = (0x100 << (_cpu->register_size()-1)) - 1;
if(break_mask == 0)
break_mask = regMask;
}
bool BreakpointRegister_Value::IsEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) == uRegTestValue;
}
bool BreakpointRegister_Value::IsNotEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) != uRegTestValue;
}
bool BreakpointRegister_Value::IsGreaterThenBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) > uRegTestValue;
}
bool BreakpointRegister_Value::IsLessThenBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) < uRegTestValue;
}
bool BreakpointRegister_Value::IsGreaterThenEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) >= uRegTestValue;
}
bool BreakpointRegister_Value::IsLessThenEqualsBreakCondition(unsigned int uRegValue,
unsigned int uRegMask, unsigned int uRegTestValue) {
return (uRegValue & uRegMask) <= uRegTestValue;
}
void BreakpointRegister_Value::invokeAction() // remove this....
{
TriggerObject::invokeAction();
}
/// BreakpointRegister_Value::print() - base class function
/// would be unusual to not be over ridden.
void BreakpointRegister_Value::print()
{
Register *pReg = getReg();
string & sName = pReg->name();
const char * pFormat = sName.empty()
? "%d: %s %s: break when register %s0x%x ANDed with 0x%x %s 0x%x\n"
: "%d: %s %s: break when register %s(0x%x) ANDed with 0x%x %s 0x%x\n" ;
GetUserInterface().DisplayMessage(pFormat,
bpn,cpu->name().c_str(), bpName(),
sName.c_str(), pReg->address, break_mask,
m_sOperator.c_str(),break_value);
TriggerObject::print();
}
int BreakpointRegister_Value::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (pBuf && pTrace) {
unsigned int valueRead = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf,szBuf," read 0x%x from reg 0x%x", valueRead, address);
return m>0 ? m : 0;
}
return 0;
}
//-------------------------------------------------------------------
//
Break_register_write_value::Break_register_write_value(Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int bm ) :
BreakpointRegister_Value(_cpu, _repl, bp, bv, eBREquals, bm )
{
set_action(this);
}
Break_register_write_value::Break_register_write_value(Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int _operator,
unsigned int bm ) :
BreakpointRegister_Value(_cpu, _repl, bp, bv, _operator, bm )
{
set_action(this);
}
void Break_register_write_value::action()
{
trace.raw(m_brt->type(1) | (getReplaced()->get_value() & 0xffffff));
if(verbosity && verbosity->getVal()) {
GetUserInterface().DisplayMessage(IDS_HIT_BREAK,bpn);
string sFormattedRegAddress;
sFormattedRegAddress = GetUserInterface().FormatRegisterAddress(getReg());
if(break_mask != m_uDefRegMask) {
sFormattedRegAddress += " & ";
sFormattedRegAddress += GetUserInterface().FormatLabeledValue("",
break_mask);
}
GetUserInterface().DisplayMessage(IDS_BREAK_WRITING_REG_OP_VALUE,
sFormattedRegAddress.c_str(),
m_sOperator.c_str(),
break_value);
}
bp.halt();
}
//========================================================================
//
void Break_register_read::action()
{
trace.raw(m_brt->type(1) | (getReplaced()->get_value() & 0xffffff));
if(verbosity && verbosity->getVal()) {
GetUserInterface().DisplayMessage(IDS_HIT_BREAK,bpn);
string sFormattedRegAddress;
sFormattedRegAddress = GetUserInterface().FormatRegisterAddress(getReg());
GetUserInterface().DisplayMessage(IDS_BREAK_READING_REG,
sFormattedRegAddress.c_str());
}
bp.halt();
}
void Break_register_read::invokeAction()
{
if(eval_Expression())
TriggerObject::invokeAction();
}
unsigned int Break_register_read::get()
{
unsigned int v = getReplaced()->get();
invokeAction();
return v;
}
RegisterValue Break_register_read::getRV()
{
RegisterValue rv = getReplaced()->getRV();
invokeAction();
return rv;
}
RegisterValue Break_register_read::getRVN()
{
RegisterValue rv = getReplaced()->getRVN();
invokeAction();
return rv;
}
bool Break_register_read::get_bit(unsigned int bit_number)
{
invokeAction();
return(getReplaced()->get_bit(bit_number));
}
double Break_register_read::get_bit_voltage(unsigned int bit_number)
{
return getReplaced()->get_bit_voltage(bit_number);
}
int Break_register_read::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (pBuf && pTrace) {
unsigned int valueRead = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf,szBuf," read 0x%x from reg 0x%x", valueRead, address);
return m>0 ? m : 0;
}
return 0;
}
//========================================================================
//
void Break_register_write::action()
{
//trace.breakpoint( (Breakpoints::BREAK_ON_REG_WRITE>>8) | (getReplaced()->address) );
trace.raw(m_brt->type(1) | (getReplaced()->get_value() & 0xffffff));
if(verbosity && verbosity->getVal()) {
GetUserInterface().DisplayMessage(IDS_HIT_BREAK,bpn);
string sFormattedRegAddress;
sFormattedRegAddress = GetUserInterface().FormatRegisterAddress(
address, 0);
GetUserInterface().DisplayMessage(IDS_BREAK_WRITING_REG,
sFormattedRegAddress.c_str());
}
bp.halt();
}
void Break_register_write::invokeAction()
{
if(eval_Expression())
TriggerObject::invokeAction();
}
void Break_register_write::put(unsigned int new_value)
{
getReplaced()->put(new_value);
invokeAction();
}
void Break_register_write::putRV(RegisterValue rv)
{
getReplaced()->putRV(rv);
invokeAction();
}
void Break_register_write::setbit(unsigned int bit_number, bool new_value)
{
getReplaced()->setbit(bit_number,new_value);
invokeAction();
}
int Break_register_write::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (pBuf && pTrace) {
unsigned int valueRead = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf,szBuf," wrote 0x%x to reg 0x%x", valueRead, address);
return m>0 ? m : 0;
}
return 0;
}
//========================================================================
Break_register_read_value::Break_register_read_value(Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int bm ) :
BreakpointRegister_Value(_cpu, _repl, bp, bv, eBREquals, bm )
{
set_action(this);
}
Break_register_read_value::Break_register_read_value(Processor *_cpu,
int _repl,
int bp,
unsigned int bv,
unsigned int _operator,
unsigned int bm ) :
BreakpointRegister_Value(_cpu, _repl, bp, bv, _operator, bm ) {
set_action(this);
}
void Break_register_read_value::action()
{
trace.raw(m_brt->type(1) | (getReplaced()->get_value() & 0xffffff));
if(verbosity && verbosity->getVal()) {
GetUserInterface().DisplayMessage(IDS_HIT_BREAK,bpn);
string sFormattedRegAddress;
sFormattedRegAddress = GetUserInterface().FormatRegisterAddress(getReg());
if(break_mask != m_uDefRegMask) {
sFormattedRegAddress += " & ";
sFormattedRegAddress += GetUserInterface().FormatLabeledValue("",
break_mask);
}
GetUserInterface().DisplayMessage(IDS_BREAK_READING_REG_OP_VALUE,
sFormattedRegAddress.c_str(),
m_sOperator.c_str(),
break_value);
}
bp.halt();
}
unsigned int Break_register_read_value::get()
{
unsigned int v = getReplaced()->get();
if(m_pfnIsBreak(v, break_mask, break_value))
invokeAction();
return v;
}
RegisterValue Break_register_read_value::getRV()
{
RegisterValue v = getReplaced()->getRV();
if(m_pfnIsBreak(v.data, break_mask, break_value))
invokeAction();
return(v);
}
RegisterValue Break_register_read_value::getRVN()
{
RegisterValue v = getReplaced()->getRVN();
if(m_pfnIsBreak(v.data, break_mask, break_value))
invokeAction();
return(v);
}
bool Break_register_read_value::get_bit(unsigned int bit_number)
{
unsigned int v = getReplaced()->get();
unsigned int mask = 1<<(bit_number & 7);
if( (break_mask & mask) && (v & mask) == (break_value&mask))
invokeAction();
return getReplaced()->get_bit(bit_number);
}
double Break_register_read_value::get_bit_voltage(unsigned int bit_number)
{
return getReplaced()->get_bit_voltage(bit_number);
}
int Break_register_read_value::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (pBuf && pTrace) {
unsigned int valueRead = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf,szBuf," read 0x%x from reg 0x%x", valueRead, address);
return m>0 ? m : 0;
}
return 0;
}
//========================================================================
void Break_register_write_value::put(unsigned int new_value)
{
getReplaced()->put(new_value);
if(m_pfnIsBreak(new_value, break_mask, break_value))
invokeAction();
}
void Break_register_write_value::putRV(RegisterValue rv)
{
getReplaced()->putRV(rv);
if(m_pfnIsBreak(rv.data, break_mask, break_value))
invokeAction();
}
void Break_register_write_value::setbit(unsigned int bit_number, bool new_bit)
{
int val_mask = 1 << bit_number;
int new_value = ((int)new_bit) << bit_number;
getReplaced()->setbit(bit_number,new_value ? true : false);
if( (val_mask & break_mask) &&
( ( (getReplaced()->value.get() & ~val_mask) // clear the old bit
| new_value) // set the new bit
& break_mask) == break_value)
invokeAction();
}
int Break_register_write_value::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
if (pBuf && pTrace) {
unsigned int valueRead = pTrace->get(tbi+1) & 0xffff;
int m = snprintf(pBuf,szBuf," wrote 0x%x to reg 0x%x", valueRead, address);
return m>0 ? m : 0;
}
return 0;
}
//========================================================================
//------------------------------------------------------------------------
// CommandAssertion
//
// Associates a gpsim command with an instruction. I.e. when the simulated
// instruction is executed, the gpsim command will execute first and then
// the instruction is simulated.
CommandAssertion::CommandAssertion(Processor *new_cpu,
unsigned int instAddress,
unsigned int bp,
const char *_command,
bool _bPostAssertion)
: Breakpoint_Instruction(new_cpu, instAddress, bp), bPostAssertion(_bPostAssertion)
{
int len = (int)strlen(_command);
command = (char *)malloc(len+3);
strcpy(command,_command);
command[len] = '\n';
command[len+1] = 0;
command[len+2] = 0;
}
void CommandAssertion::execute()
{
if(bPostAssertion && getReplaced())
getReplaced()->execute();
//printf("execute command: %s -- post = %s\n",command,(bPostAssertion?"true":"false"));
ICommandHandler *pCli = CCommandManager::GetManager().find("gpsimCLI");
if(pCli) {
pCli->Execute(command, 0);
}
if(!bPostAssertion && getReplaced())
getReplaced()->execute();
}
//------------------------------------------------------------------------------
void CommandAssertion::print()
{
Breakpoint_Instruction::print();
cout << " execute command " << command << endl;
}
int CommandAssertion::printTraced(Trace *pTrace, unsigned int tbi,
char *pBuf, int szBuf)
{
return 0;
}
//============================================================================
void Log_Register_Write::action()
{
GetTraceLog().register_write(getReg(),
get_cycles().value);
}
void Log_Register_Write_value::action()
{
GetTraceLog().register_write_value(getReg(),
get_cycles().value);
}
void Log_Register_Read::action()
{
GetTraceLog().register_read(getReg(),
get_cycles().value);
}
void Log_Register_Read_value::action()
{
GetTraceLog().register_read(getReg(),
get_cycles().value);
}
syntax highlighted by Code2HTML, v. 0.9.1