/* 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. */ #ifndef __BREAKPOINTS_H__ #define __BREAKPOINTS_H__ #include <iostream> #include <iomanip> #include <glib.h> #include <string> #include "trigger.h" #include "pic-instructions.h" #include "registers.h" #include "exports.h" #include "gpsim_object.h" // defines ObjectBreakTypes using namespace std; extern Integer *verbosity; // in ../src/init.cc class InvalidRegister; class TriggerGroup : public TriggerAction { public: protected: list<TriggerObject*> triggerList; virtual ~TriggerGroup(){} }; #define MAX_BREAKPOINTS 0x400 #define BREAKPOINT_MASK (MAX_BREAKPOINTS-1) class Breakpoint_Instruction : public AliasedInstruction , public TriggerObject { public: unsigned int address; virtual bool set_break(); virtual Processor* get_cpu(); virtual void print(); virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual void clear(); virtual char const * bpName() { return "Execution"; } Breakpoint_Instruction(Processor *new_cpu, unsigned int new_address, unsigned int bp); virtual enum INSTRUCTION_TYPES isa() {return BREAKPOINT_INSTRUCTION;}; virtual void execute(); virtual bool isBase() { return false;} virtual bool eval_Expression(); }; class Notify_Instruction : public Breakpoint_Instruction { TriggerObject *callback; public: Notify_Instruction(Processor *cpu, unsigned int address, unsigned int bp, TriggerObject *cb); virtual enum INSTRUCTION_TYPES isa() {return NOTIFY_INSTRUCTION;}; virtual void execute(); virtual char const * bpName() { return "Notify Execution"; } }; class Profile_Start_Instruction : public Notify_Instruction { public: Profile_Start_Instruction(Processor *cpu, unsigned int address, unsigned int bp, TriggerObject *cb); virtual enum INSTRUCTION_TYPES isa() {return PROFILE_START_INSTRUCTION;}; virtual char const * bpName() { return "Profile Start"; } }; class Profile_Stop_Instruction : public Notify_Instruction { public: Profile_Stop_Instruction(Processor *cpu, unsigned int address, unsigned int bp, TriggerObject *cb); virtual enum INSTRUCTION_TYPES isa() {return PROFILE_STOP_INSTRUCTION;}; virtual char const * bpName() { return "Profile Stop"; } }; // // Assertions // // Assertions are like breakpoints except that they're conditional. // For example, a user may wish to verify that the proper register // bank is selected while a variable is accessed. // class RegisterAssertion : public Breakpoint_Instruction { public: unsigned int regAddress; unsigned int regMask; unsigned int regValue; bool bPostAssertion; // True if assertion is checked after instruction simulates. typedef bool (*PFNISASSERTIONCONDITION)(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); PFNISASSERTIONCONDITION m_pfnIsAssertionBreak; enum { eRAEquals, eRANotEquals, eRAGreaterThen, eRALessThen, eRAGreaterThenEquals, eRALessThenEquals, }; static bool IsAssertionEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsAssertionNotEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsAssertionGreaterThenBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsAssertionLessThenBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsAssertionGreaterThenEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsAssertionLessThenEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); RegisterAssertion(Processor *new_cpu, unsigned int instAddress, unsigned int bp, unsigned int _regAddress, unsigned int _regMask, unsigned int _regValue, bool bPostAssertion=false ); RegisterAssertion(Processor *new_cpu, unsigned int instAddress, unsigned int bp, unsigned int _regAddress, unsigned int _regMask, unsigned int _operator, unsigned int _regValue, bool bPostAssertion=false ); virtual void execute(); virtual void print(); virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual char const * bpName() { return "Register Assertion"; } }; class Breakpoints; #if defined(IN_MODULE) && defined(_WIN32) // we are in a module: don't access the Breakpoints object directly! LIBGPSIM_EXPORT Breakpoints & get_bp(); #else // we are in gpsim: use of get_bp() is recommended, // even if the bp object can be accessed directly. extern Breakpoints bp; inline Breakpoints &get_bp() { return bp; } #endif class Breakpoints { public: enum BREAKPOINT_TYPES { BREAK_DUMP_ALL = 0, BREAK_CLEAR = 0, BREAK_ON_EXECUTION = 1<<24, BREAK_ON_REG_READ = 2<<24, BREAK_ON_REG_WRITE = 3<<24, BREAK_ON_REG_READ_VALUE = 4<<24, BREAK_ON_REG_WRITE_VALUE = 5<<24, BREAK_ON_INVALID_FR = 6<<24, BREAK_ON_CYCLE = 7<<24, BREAK_ON_WDT_TIMEOUT = 8<<24, BREAK_ON_STK_OVERFLOW = 9<<24, BREAK_ON_STK_UNDERFLOW = 10<<24, NOTIFY_ON_EXECUTION = 11<<24, PROFILE_START_NOTIFY_ON_EXECUTION = 12<<24, PROFILE_STOP_NOTIFY_ON_EXECUTION = 13<<24, NOTIFY_ON_REG_READ = 14<<24, NOTIFY_ON_REG_WRITE = 15<<24, NOTIFY_ON_REG_READ_VALUE = 16<<24, NOTIFY_ON_REG_WRITE_VALUE = 17<<24, BREAK_ON_ASSERTION = 18<<24, BREAK_MASK = 0xff<<24 }; #define GLOBAL_CLEAR 0 #define GLOBAL_STOP_RUNNING (1<<0) #define GLOBAL_INTERRUPT (1<<1) #define GLOBAL_SLEEP (1<<2) #define GLOBAL_PM_WRITE (1<<3) #define GLOBAL_SOCKET (1<<4) struct BreakStatus { BREAKPOINT_TYPES type; Processor *cpu; unsigned int arg1; unsigned int arg2; TriggerObject *bpo; } break_status[MAX_BREAKPOINTS]; int m_iMaxAllocated; class iterator { public: iterator(int index) : iIndex(index) { } int iIndex; iterator & operator++(int) { iIndex++; return *this; } BreakStatus * operator*() { return &get_bp().break_status[iIndex]; } bool operator!=(iterator &it) { return iIndex != it.iIndex; } }; iterator begin() { return iterator(0); } iterator end() { return iterator(m_iMaxAllocated); } BreakStatus *get(int index) { return (index>=0 && index<MAX_BREAKPOINTS) ? &break_status[index] : 0; } int global_break; bool m_bExitOnBreak; // enabled from command line option void EnableExitOnBreak(bool bExitOnBreak) { m_bExitOnBreak = bExitOnBreak; } int breakpoint_number,last_breakpoint; Breakpoints(); int set_breakpoint(BREAKPOINT_TYPES,Processor *, unsigned int, unsigned int, TriggerObject *f = 0); int set_breakpoint(TriggerObject *,Expression *pExpr=0); int set_execution_break(Processor *cpu, unsigned int address, Expression *pExpr=0); int set_notify_break(Processor *cpu, unsigned int address, TriggerObject *cb); int set_profile_start_break(Processor *cpu, unsigned int address, TriggerObject *f1 = 0); int set_profile_stop_break(Processor *cpu, unsigned int address, TriggerObject *f1 = 0); int set_read_break(Processor *cpu, unsigned int register_number); int set_write_break(Processor *cpu, unsigned int register_number); int set_read_value_break(Processor *cpu, unsigned int register_number, unsigned int value, unsigned int mask=0xff); int set_write_value_break(Processor *cpu, unsigned int register_number, unsigned int value, unsigned int mask=0xff); int set_read_value_break(Processor *cpu, unsigned int register_number, unsigned int op, unsigned int value, unsigned int mask=0xff); int set_write_value_break(Processor *cpu, unsigned int register_number, unsigned int op, unsigned int value, unsigned int mask=0xff); int set_break(gpsimObject::ObjectBreakTypes bt, gpsimObject::ObjectActionTypes at, Register *, Expression *pExpr=0); int set_cycle_break(Processor *cpu, guint64 cycle, TriggerObject *f = 0); int set_wdt_break(Processor *cpu); int set_stk_overflow_break(Processor *cpu); int set_stk_underflow_break(Processor *cpu); int check_cycle_break(unsigned int abp); int set_notify_read(Processor *cpu, unsigned int register_number); int set_notify_write(Processor *cpu, unsigned int register_number); int set_notify_read_value(Processor *cpu, unsigned int register_number, unsigned int value, unsigned int mask=0xff); int set_notify_write_value(Processor *cpu, unsigned int register_number, unsigned int value, unsigned int mask=0xff); bool set_expression(unsigned bp_number, Expression *pExpr); inline void clear_global() {global_break = GLOBAL_CLEAR;}; void halt(); inline bool have_halt() { return( (global_break & GLOBAL_STOP_RUNNING) != 0 ); } inline void clear_halt() { global_break &= ~GLOBAL_STOP_RUNNING; } inline bool have_interrupt() { return( (global_break & GLOBAL_INTERRUPT) != 0 ); } inline void clear_interrupt() { global_break &= ~GLOBAL_INTERRUPT; } inline void set_interrupt() { global_break |= GLOBAL_INTERRUPT; } inline bool have_sleep() { return( (global_break & GLOBAL_SLEEP) != 0 ); } inline void clear_sleep() { global_break &= ~GLOBAL_SLEEP; } inline void set_sleep() { global_break |= GLOBAL_SLEEP; } inline bool have_pm_write() { return( (global_break & GLOBAL_PM_WRITE) != 0 ); } inline void clear_pm_write() { global_break &= ~GLOBAL_PM_WRITE; } inline void set_pm_write() { global_break |= GLOBAL_PM_WRITE; } inline bool have_socket_break() { return( (global_break & GLOBAL_SOCKET) != 0); } inline void set_socket_break() { global_break |= GLOBAL_SOCKET; } inline void clear_socket_break() { global_break &= ~GLOBAL_SOCKET; } bool dump1(unsigned int bp_num, int dump_type = BREAK_DUMP_ALL); bool dump(TriggerObject *); void dump(int dump_type = BREAK_DUMP_ALL); void dump_traced(unsigned int b); void clear(unsigned int b); bool bIsValid(unsigned int b); bool bIsClear(unsigned int b); void set_message(unsigned int b,string &); void clear_all(Processor *c); void clear_all_set_by_user(Processor *c); void clear_all_register(Processor *c,unsigned int address=-1); void initialize_breakpoints(unsigned int memory_size); instruction *find_previous(Processor *cpu, unsigned int address, instruction *_this); int find_free(); }; // // BreakPointRegister // // This class serves as the base class for register break point and logging // classes. Register breakpoints are handled by replacing a register object // with one of the breakpoint objects. The simulated pic code has no idea that // breakpoints exist on a register. However, when the member functions of the // a register are accessed, the breakpoint member functions of the classes // described below are the ones actually invoked. Consequently, control of // the simulation can be manipulated. // class BreakpointRegister : public Register, public TriggerObject { public: BreakpointRegister(Processor *, TriggerAction *, Register *); BreakpointRegister(Processor *, int, int ); BreakpointRegister(Processor *, TriggerAction *, int, int ); virtual REGISTER_TYPES isa() {return BP_REGISTER;}; virtual string &name() const; virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual void putRV(RegisterValue rv); virtual unsigned int get_value(); virtual RegisterValue getRV(); virtual RegisterValue getRVN(); virtual unsigned int get(); virtual Register *getReg(); virtual void setbit(unsigned int bit_number, bool new_value); virtual bool get_bit(unsigned int bit_number); virtual double get_bit_voltage(unsigned int bit_number); virtual bool hasBreak(); virtual void update(); virtual void add_xref(void *an_xref); virtual void remove_xref(void *an_xref); void replace(Processor *_cpu, unsigned int reg); virtual bool set_break(); unsigned int clear(unsigned int bp_num); virtual void print(); virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual void clear(); protected: BreakpointRegister(); }; class BreakpointRegister_Value : public BreakpointRegister { public: unsigned int break_value, break_mask; unsigned int m_uDefRegMask; string m_sOperator; BreakpointRegister_Value() { break_value = 0; break_mask = 0; } BreakpointRegister_Value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int bm ); BreakpointRegister_Value(Processor *_cpu, TriggerAction *pTA, int _repl, int bp, unsigned int bv, unsigned int bm ); BreakpointRegister_Value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int _operator, unsigned int bm ); typedef bool (*PFNISBREAKCONDITION)(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); PFNISBREAKCONDITION m_pfnIsBreak; enum BRV_Ops { eBRInvalid, eBREquals, eBRNotEquals, eBRGreaterThen, eBRLessThen, eBRGreaterThenEquals, eBRLessThenEquals, }; static bool IsEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsNotEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsGreaterThenBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsLessThenBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsGreaterThenEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); static bool IsLessThenEqualsBreakCondition(unsigned int uRegValue, unsigned int uRegMask, unsigned int uRegTestValue); virtual void invokeAction(); virtual void print(); virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); }; class Break_register_read : public BreakpointRegister, TriggerAction { public: Break_register_read(Processor *_cpu, int _repl, int bp ): BreakpointRegister(_cpu, _repl,bp ) { set_action(this); } virtual unsigned int get(); virtual RegisterValue getRV(); virtual RegisterValue getRVN(); virtual bool get_bit(unsigned int bit_number); virtual double get_bit_voltage(unsigned int bit_number); virtual char const * bpName() { return "register read"; } virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual void invokeAction(); // TriggerAction overrides virtual void action(); }; class Break_register_write : public BreakpointRegister, TriggerAction { public: Break_register_write(Processor *_cpu, int _repl, int bp ): BreakpointRegister(_cpu,_repl,bp ) { set_action(this); } virtual void put(unsigned int new_value); virtual void putRV(RegisterValue rv); virtual void setbit(unsigned int bit_number, bool new_value); virtual char const * bpName() { return "register write"; } virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual void invokeAction(); // TriggerAction overrides virtual void action(); }; class Break_register_read_value : public BreakpointRegister_Value, TriggerAction { public: // Break_register_read_value(){ }; Break_register_read_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int bm ); Break_register_read_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int _operator, unsigned int bm ); virtual unsigned int get(); virtual RegisterValue getRV(); virtual RegisterValue getRVN(); virtual bool get_bit(unsigned int bit_number); virtual double get_bit_voltage(unsigned int bit_number); virtual char const * bpName() { return "register read value"; } virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); // TriggerAction overrides virtual void action(); }; class Break_register_write_value : public BreakpointRegister_Value, TriggerAction { public: Break_register_write_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int bm ); Break_register_write_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int _operator, unsigned int bm ); virtual void put(unsigned int new_value); virtual void putRV(RegisterValue rv); virtual void setbit(unsigned int bit_number, bool new_value); virtual char const * bpName() { return "register write value"; } virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); // TriggerAction overrides virtual void action(); }; class CommandAssertion : public Breakpoint_Instruction { public: bool bPostAssertion; // True if assertion is checked after instruction simulates. CommandAssertion(Processor *new_cpu, unsigned int instAddress, unsigned int bp, const char *_command, bool bPostAssertion ); virtual void execute(); virtual void print(); virtual int printTraced(Trace *pTrace, unsigned int tbi, char *pBuf, int szBuf); virtual char const * bpName() { return "Register Assertion"; } private: char *command; }; class Log_Register_Write : public Break_register_write { public: Log_Register_Write(Processor *_cpu, int _repl, int bp ): Break_register_write(_cpu,_repl,bp ) { }; //virtual void put(unsigned int new_value); //virtual void putRV(RegisterValue rv); //virtual void setbit(unsigned int bit_number, bool new_value); virtual char const * bpName() { return "log register write"; } virtual void action(); }; class Log_Register_Read : public Break_register_read { public: Log_Register_Read(Processor *_cpu, int _repl, int bp ): Break_register_read(_cpu,_repl,bp ) { }; virtual char const * bpName() { return "log register read"; } virtual void action(); }; class Log_Register_Read_value : public Break_register_read_value { public: Log_Register_Read_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int bm ) : Break_register_read_value(_cpu, _repl, bp, bv, bm ) { }; Log_Register_Read_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int _operator, unsigned int bm ) : Break_register_read_value(_cpu, _repl, bp, bv, _operator, bm ) { }; virtual char const * bpName() { return "log register read value"; } virtual void action(); }; class Log_Register_Write_value : public Break_register_write_value { public: Log_Register_Write_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int bm ) : Break_register_write_value(_cpu, _repl, bp, bv, bm ) { }; Log_Register_Write_value(Processor *_cpu, int _repl, int bp, unsigned int bv, unsigned int _operator, unsigned int bm ) : Break_register_write_value(_cpu, _repl, bp, bv, _operator,bm ) { }; virtual void action(); }; #ifdef HAVE_GUI class GuiCallBack: public TriggerObject { public: virtual void callback(); gpointer gui_callback_data; // Data to be passed back to the gui // A pointer to the gui call back function void (*gui_callback) (gpointer gui_callback_data); void set_break(int, void (*)(gpointer),gpointer ); GuiCallBack(); }; #endif // HAVE_GUI #endif // __BREAKPOINTS_H__