|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by David Saxton *
|
|
|
|
* david@bluehaze.org *
|
|
|
|
* *
|
|
|
|
* This program 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 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#ifndef NO_GPSIM
|
|
|
|
|
|
|
|
#ifndef GPSIMPROCESSOR_H
|
|
|
|
#define GPSIMPROCESSOR_H
|
|
|
|
|
|
|
|
#include "sourceline.h"
|
|
|
|
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqvaluevector.h>
|
|
|
|
#include <tqobject.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
|
|
|
|
class DebugLine;
|
|
|
|
class GpsimProcessor;
|
|
|
|
class MicroInfo;
|
|
|
|
class pic_processor; // from gpsim
|
|
|
|
class Register;
|
|
|
|
class RegisterMemoryAccess;
|
|
|
|
|
|
|
|
typedef TQMap<SourceLine, SourceLine> SourceLineMap;
|
|
|
|
typedef TQMap<int, TQString> TQStringMap;
|
|
|
|
typedef TQValueList<int> IntList;
|
|
|
|
|
|
|
|
|
|
|
|
class DebugLine : public SourceLine
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DebugLine();
|
|
|
|
DebugLine( const TQString & fileName, int line );
|
|
|
|
/**
|
|
|
|
* Whether or not to break when we reach this line.
|
|
|
|
*/
|
|
|
|
bool isBreakpoint() const { return m_bIsBreakpoint; }
|
|
|
|
/**
|
|
|
|
* Set whether or not to break when we reach this line.
|
|
|
|
*/
|
|
|
|
void setBreakpoint( bool breakpoint ) { m_bIsBreakpoint = breakpoint; }
|
|
|
|
/**
|
|
|
|
* Used for efficiency purposes by GpsimProcessor. Sets a flag.
|
|
|
|
*/
|
|
|
|
void markAsDeleted() { m_bMarkedAsDeleted = true; }
|
|
|
|
/**
|
|
|
|
* Used for efficiency purposes by GpsimProcessor.
|
|
|
|
*/
|
|
|
|
bool markedAsDeleted() const { return m_bMarkedAsDeleted; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool m_bIsBreakpoint;
|
|
|
|
bool m_bMarkedAsDeleted;
|
|
|
|
|
|
|
|
private:
|
|
|
|
DebugLine( const DebugLine & dl );
|
|
|
|
DebugLine & operator = ( const DebugLine & dl );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@short Stores info from gpsim register, used to hide gpsim interface
|
|
|
|
@author David Saxton
|
|
|
|
*/
|
|
|
|
class RegisterInfo : public TQObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
RegisterInfo( Register * reg );
|
|
|
|
|
|
|
|
enum RegisterType
|
|
|
|
{
|
|
|
|
Invalid,
|
|
|
|
Generic,
|
|
|
|
File,
|
|
|
|
SFR,
|
|
|
|
Breakpoint
|
|
|
|
};
|
|
|
|
|
|
|
|
RegisterType type() const { return m_type; }
|
|
|
|
TQString name() const { return m_name; }
|
|
|
|
unsigned value() const;
|
|
|
|
static TQString toString( RegisterType type );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks to see if the value has changed; if so, emit new value.
|
|
|
|
*/
|
|
|
|
void update();
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void valueChanged( unsigned newValue );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
TQString m_name;
|
|
|
|
RegisterType m_type;
|
|
|
|
Register * m_pRegister;
|
|
|
|
unsigned m_prevEmitValue;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@short Stores information about a set of registers, used to hide gpsim interface.
|
|
|
|
@author David Saxton
|
|
|
|
*/
|
|
|
|
class RegisterSet
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RegisterSet( pic_processor * picProcessor );
|
|
|
|
~RegisterSet();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls update for each RegisterInfo in this set.
|
|
|
|
*/
|
|
|
|
void update();
|
|
|
|
/**
|
|
|
|
* Returns the number of registers.
|
|
|
|
*/
|
|
|
|
unsigned size() const { return m_registers.size(); }
|
|
|
|
|
|
|
|
RegisterInfo * fromAddress( unsigned address );
|
|
|
|
RegisterInfo * fromName( const TQString & name );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
typedef TQMap< TQString, RegisterInfo * > RegisterInfoMap;
|
|
|
|
RegisterInfoMap m_nameToRegisterMap;
|
|
|
|
TQValueVector< RegisterInfo * > m_registers;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@author David Saxton
|
|
|
|
*/
|
|
|
|
class GpsimDebugger : public TQObject
|
|
|
|
{
|
|
|
|
friend class GpsimProcessor;
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum Type
|
|
|
|
{
|
|
|
|
AsmDebugger = 0,
|
|
|
|
HLLDebugger = 1
|
|
|
|
};
|
|
|
|
|
|
|
|
GpsimDebugger( Type type, GpsimProcessor * gpsim );
|
|
|
|
~GpsimDebugger();
|
|
|
|
|
|
|
|
GpsimProcessor * gpsim() const { return m_pGpsim; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When an assembly file was generated by a high level language compiler
|
|
|
|
* like SDCC, it will insert markers like ";#CSRC" that show which line
|
|
|
|
* of source-code generated the given set of assembly instructions. This
|
|
|
|
* matches up the assembly file lines with the associated source file
|
|
|
|
* lines.
|
|
|
|
*/
|
|
|
|
void associateLine( const TQString & sourceFile, int sourceLine, const TQString & assemblyFile, int assemblyLine );
|
|
|
|
/**
|
|
|
|
* Check to see if we've hit a breakpoint or similar; if so, this
|
|
|
|
* function will stop the execution of the PIC program.
|
|
|
|
*/
|
|
|
|
void checkForBreak();
|
|
|
|
/**
|
|
|
|
* Sets the breakpoints used for the given file to exactly those that
|
|
|
|
* are contained in this list. Breakpoints for other files are not
|
|
|
|
* affected.
|
|
|
|
* @param path the location of the file (which gpsim must recognise).
|
|
|
|
*/
|
|
|
|
void setBreakpoints( const TQString & path, const IntList & lines );
|
|
|
|
/**
|
|
|
|
* Sets / removes the breakpoint at the given line
|
|
|
|
*/
|
|
|
|
void setBreakpoint( const TQString & path, int line, bool isBreakpoint );
|
|
|
|
/**
|
|
|
|
* Returns the current source line that gpsim is at. By default, this
|
|
|
|
* will be the corresponding assembly line. That can be overwritten
|
|
|
|
* using mapAddressBlockToLine.
|
|
|
|
*/
|
|
|
|
SourceLine currentLine();
|
|
|
|
/**
|
|
|
|
* Returns a pointer to the debug info for the current line.
|
|
|
|
*/
|
|
|
|
DebugLine * currentDebugLine();
|
|
|
|
/**
|
|
|
|
* @return the program address for the given line (or -1 if no such
|
|
|
|
* line).
|
|
|
|
*/
|
|
|
|
int programAddress( const TQString & path, int line );
|
|
|
|
/**
|
|
|
|
* Step into the next program line.
|
|
|
|
*/
|
|
|
|
void stepInto();
|
|
|
|
/**
|
|
|
|
* Step over the next program instruction. If we are currently running,
|
|
|
|
* this function will do nothing. Otherwise, it will record the current
|
|
|
|
* stack level, step, and if the new stack level is <= the initial level
|
|
|
|
* then return - otherwise, this processor will set a breakpoint for
|
|
|
|
* stack levels <= initial, and go to running mode.
|
|
|
|
*/
|
|
|
|
void stepOver();
|
|
|
|
/**
|
|
|
|
* Similar to stepOver, except we break when the stack level becomes <
|
|
|
|
* the initial stack level (instead of <= initial).
|
|
|
|
*/
|
|
|
|
void stepOut();
|
|
|
|
|
|
|
|
signals:
|
|
|
|
/**
|
|
|
|
* Emitted when a line is reached. By default, this is the line of the
|
|
|
|
* input assembly file; however, the line associated with an address in
|
|
|
|
* the PIC memory can be changed with mapAddressBlockToLine.
|
|
|
|
*/
|
|
|
|
void lineReached( const SourceLine & sourceLine );
|
|
|
|
|
|
|
|
protected slots:
|
|
|
|
void gpsimRunningStatusChanged( bool isRunning );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void initAddressToLineMap();
|
|
|
|
void stackStep( int dl );
|
|
|
|
void emitLineReached();
|
|
|
|
|
|
|
|
int m_stackLevelLowerBreak; // Set by step-over, for when the stack level decreases to the one given
|
|
|
|
SourceLine m_previousAtLineEmit; // Used for working out whether we should emit a new line reached signal
|
|
|
|
DebugLine ** m_addressToLineMap;
|
|
|
|
DebugLine * m_pBreakFromOldLine;
|
|
|
|
GpsimProcessor * m_pGpsim;
|
|
|
|
Type m_type;
|
|
|
|
unsigned m_addressSize;
|
|
|
|
SourceLineMap m_sourceLineMap; // assembly <--> High level language
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@author David Saxton
|
|
|
|
*/
|
|
|
|
class GpsimProcessor : public TQObject
|
|
|
|
{
|
|
|
|
friend class GpsimDebugger;
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Create a new gpsim processor. After calling this constructor, you
|
|
|
|
* should always call codLoadStatus() to ensure that the cod file was
|
|
|
|
* loaded successfully.
|
|
|
|
*/
|
|
|
|
GpsimProcessor( TQString symbolFile, TQObject *parent = 0 );
|
|
|
|
~GpsimProcessor();
|
|
|
|
|
|
|
|
void setDebugMode( GpsimDebugger::Type mode ) { m_debugMode = mode; }
|
|
|
|
GpsimDebugger * currentDebugger() const { return m_pDebugger[m_debugMode]; }
|
|
|
|
|
|
|
|
enum CodLoadStatus
|
|
|
|
{
|
|
|
|
CodSuccess,
|
|
|
|
CodFileNotFound,
|
|
|
|
CodUnrecognizedProcessor,
|
|
|
|
CodFileNameTooLong,
|
|
|
|
CodLstNotFound,
|
|
|
|
CodBadFile,
|
|
|
|
CodFileUnreadable,
|
|
|
|
CodFailure,
|
|
|
|
CodUnknown // Should never be this, but just in case load_symbol_file returns something funny
|
|
|
|
};
|
|
|
|
|
|
|
|
enum InstructionType
|
|
|
|
{
|
|
|
|
LiteralOp,
|
|
|
|
BitOp,
|
|
|
|
RegisterOp,
|
|
|
|
UnknownOp,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return status of opening the COD file
|
|
|
|
* @see displayCodLoadStatus
|
|
|
|
*/
|
|
|
|
CodLoadStatus codLoadStatus() const { return m_codLoadStatus; }
|
|
|
|
/**
|
|
|
|
* Popups a messagebox to the user according to the CodLoadStatus. Will
|
|
|
|
* only popup a messagebox if the CodLoadStatus wasn't CodSuccess.
|
|
|
|
*/
|
|
|
|
void displayCodLoadStatus();
|
|
|
|
/**
|
|
|
|
* Returns a list of source files for the currently running program.
|
|
|
|
*/
|
|
|
|
TQStringList sourceFileList();
|
|
|
|
/**
|
|
|
|
* Set whether or not to run gpsim. (i.e. whether or not the step
|
|
|
|
* function should do anything when called with force=false).
|
|
|
|
*/
|
|
|
|
void setRunning( bool run );
|
|
|
|
/**
|
|
|
|
* Returns true if running (currently simulating), else gpsim is paused.
|
|
|
|
*/
|
|
|
|
bool isRunning() const { return m_bIsRunning; }
|
|
|
|
/**
|
|
|
|
* Execute the next program instruction. If we are not in a running
|
|
|
|
* mode, then this function will do nothing.
|
|
|
|
*/
|
|
|
|
void executeNext();
|
|
|
|
/**
|
|
|
|
* Reset all parts of the simulation. Gpsim will not run until
|
|
|
|
* setRunning(true) is called. Breakpoints are not affected.
|
|
|
|
*/
|
|
|
|
void reset();
|
|
|
|
/**
|
|
|
|
* Returns the microinfo describing this processor.
|
|
|
|
*/
|
|
|
|
MicroInfo * microInfo() const;
|
|
|
|
|
|
|
|
pic_processor * picProcessor() const { return m_pPicProcessor; }
|
|
|
|
unsigned programMemorySize() const;
|
|
|
|
RegisterSet * registerMemory() const { return m_pRegisterMemory; }
|
|
|
|
/**
|
|
|
|
* @return the instruction type at the given address.
|
|
|
|
*/
|
|
|
|
InstructionType instructionType( unsigned address );
|
|
|
|
/**
|
|
|
|
* @return the address of the operand's register at address if the
|
|
|
|
* instruction at address is a register operation, and -1 otherwise.
|
|
|
|
*/
|
|
|
|
int operandRegister( unsigned address );
|
|
|
|
/**
|
|
|
|
* @return the literal if the instruction at address is a literal
|
|
|
|
* operation, and -1 otherwise.
|
|
|
|
*/
|
|
|
|
int operandLiteral( unsigned address );
|
|
|
|
|
|
|
|
//BEGIN Convenience functions for PIC files
|
|
|
|
enum ProgramFileValidity { DoesntExist, IncorrectType, Valid };
|
|
|
|
/**
|
|
|
|
* @return information on the validity of the given program file (either
|
|
|
|
* DoesntExist, IncorrectType, or Valid).
|
|
|
|
* @see static TQString generateSymbolFile
|
|
|
|
*/
|
|
|
|
static ProgramFileValidity isValidProgramFile( const TQString & programFile );
|
|
|
|
/**
|
|
|
|
* Converts the file at programFile to a Symbol file for emulation,
|
|
|
|
* and returns that symbol file's path
|
|
|
|
* @param programFile The full url to the file
|
|
|
|
* @param assembled The slot to connect the assembled signal to
|
|
|
|
* @see static bool isValidProgramFile( const TQString &programFile )
|
|
|
|
*/
|
|
|
|
static TQString generateSymbolFile( const TQString &fileName, TQObject *receiver, const char *successMember, const char * failMember = 0l );
|
|
|
|
/**
|
|
|
|
*Compile microbe to output to the given filename
|
|
|
|
*/
|
|
|
|
static void compileMicrobe( const TQString &filename, TQObject *receiver, const char * successMember, const char * failMember = 0l );
|
|
|
|
//END convenience functions for PIC files
|
|
|
|
|
|
|
|
signals:
|
|
|
|
/**
|
|
|
|
* Emitted when the running status of gpsim changes.
|
|
|
|
*/
|
|
|
|
void runningStatusChanged( bool isRunning );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/**
|
|
|
|
* Calls emitLineReached for each debugger.
|
|
|
|
*/
|
|
|
|
void emitLineReached();
|
|
|
|
|
|
|
|
pic_processor * m_pPicProcessor;
|
|
|
|
CodLoadStatus m_codLoadStatus;
|
|
|
|
const TQString m_symbolFile;
|
|
|
|
RegisterSet * m_pRegisterMemory;
|
|
|
|
GpsimDebugger::Type m_debugMode;
|
|
|
|
GpsimDebugger * m_pDebugger[2]; // Asm, HLL
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We are called effectively for each cycle of the cycle of the
|
|
|
|
* processor. This value is used as some instructions (e.g. goto) take
|
|
|
|
* two cycles to execute, and so we must ignore one cycle to ensure
|
|
|
|
* realtime simulation.
|
|
|
|
*/
|
|
|
|
bool m_bCanExecuteNextCycle;
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool m_bIsRunning;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // !NO_GPSIM
|