/*************************************************************************** * 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 #include #include #include class DebugLine; class GpsimProcessor; class MicroInfo; class pic_processor; // from gpsim class Register; class RegisterMemoryAccess; typedef TQMap SourceLineMap; typedef TQMap TQStringMap; typedef TQValueList 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