1 /*************************************************************************** 2 * Copyright (C) 2005 by David Saxton * 3 * david@bluehaze.org * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 ***************************************************************************/ 10 11 #include "config.h" 12 #ifndef NO_GPSIM 13 14 #ifndef GPSIMPROCESSOR_H 15 #define GPSIMPROCESSOR_H 16 17 #include "sourceline.h" 18 19 #include <QMap> 20 // #include <q3valuevector.h> 21 #include <QObject> 22 #include <QList> 23 #include <QVector> 24 25 class DebugLine; 26 class GpsimProcessor; 27 class MicroInfo; 28 class pic_processor; // from gpsim 29 class Register; 30 class RegisterMemoryAccess; 31 32 typedef QMap<SourceLine, SourceLine> SourceLineMap; 33 typedef QList<int> IntList; 34 35 36 class DebugLine : public SourceLine 37 { 38 public: 39 DebugLine(); 40 /// @param fileName a path to a file in the local filesystem 41 DebugLine( const QString & fileName, int line ); 42 /** 43 * Whether or not to break when we reach this line. 44 */ isBreakpoint()45 bool isBreakpoint() const { return m_bIsBreakpoint; } 46 /** 47 * Set whether or not to break when we reach this line. 48 */ setBreakpoint(bool breakpoint)49 void setBreakpoint( bool breakpoint ) { m_bIsBreakpoint = breakpoint; } 50 /** 51 * Used for efficiency purposes by GpsimProcessor. Sets a flag. 52 */ markAsDeleted()53 void markAsDeleted() { m_bMarkedAsDeleted = true; } 54 /** 55 * Used for efficiency purposes by GpsimProcessor. 56 */ markedAsDeleted()57 bool markedAsDeleted() const { return m_bMarkedAsDeleted; } 58 59 protected: 60 bool m_bIsBreakpoint; 61 bool m_bMarkedAsDeleted; 62 63 private: 64 DebugLine( const DebugLine & dl ); 65 DebugLine & operator = ( const DebugLine & dl ); 66 }; 67 68 69 /** 70 @short Stores info from gpsim register, used to hide gpsim interface 71 @author David Saxton 72 */ 73 class RegisterInfo : public QObject 74 { 75 Q_OBJECT 76 public: 77 RegisterInfo( Register * reg ); 78 79 enum RegisterType 80 { 81 Invalid, 82 Generic, 83 File, 84 SFR, 85 Breakpoint 86 }; 87 type()88 RegisterType type() const { return m_type; } name()89 QString name() const { return m_name; } 90 unsigned value() const; 91 static QString toString( RegisterType type ); 92 93 /** 94 * Checks to see if the value has changed; if so, emit new value. 95 */ 96 void update(); 97 98 signals: 99 void valueChanged( unsigned newValue ); 100 101 protected: 102 QString m_name; 103 RegisterType m_type; 104 Register * m_pRegister; 105 unsigned m_prevEmitValue; 106 }; 107 108 109 /** 110 @short Stores information about a set of registers, used to hide gpsim interface. 111 @author David Saxton 112 */ 113 class RegisterSet 114 { 115 public: 116 RegisterSet( pic_processor * picProcessor ); 117 ~RegisterSet(); 118 119 /** 120 * Calls update for each RegisterInfo in this set. 121 */ 122 void update(); 123 /** 124 * Returns the number of registers. 125 */ size()126 unsigned size() const { return m_registers.size(); } 127 128 RegisterInfo * fromAddress( unsigned address ); 129 RegisterInfo * fromName( const QString & name ); 130 131 protected: 132 typedef QMap< QString, RegisterInfo * > RegisterInfoMap; 133 RegisterInfoMap m_nameToRegisterMap; 134 QVector< RegisterInfo * > m_registers; 135 }; 136 137 138 /** 139 @author David Saxton 140 */ 141 class GpsimDebugger : public QObject 142 { 143 friend class GpsimProcessor; 144 Q_OBJECT 145 146 public: 147 enum Type 148 { 149 AsmDebugger = 0, 150 HLLDebugger = 1 151 }; 152 153 GpsimDebugger( Type type, GpsimProcessor * gpsim ); 154 ~GpsimDebugger() override; 155 gpsim()156 GpsimProcessor * gpsim() const { return m_pGpsim; } 157 158 /** 159 * When an assembly file was generated by a high level language compiler 160 * like SDCC, it will insert markers like ";#CSRC" that show which line 161 * of source-code generated the given set of assembly instructions. This 162 * matches up the assembly file lines with the associated source file 163 * lines. 164 * @param sourceFile the path to an assembly file in the local filesystem 165 * @param assemblyFile the path to a source file in the local filesystem 166 */ 167 void associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine ); 168 /** 169 * Check to see if we've hit a breakpoint or similar; if so, this 170 * function will stop the execution of the PIC program. 171 */ 172 void checkForBreak(); 173 /** 174 * Sets the breakpoints used for the given file to exactly those that 175 * are contained in this list. Breakpoints for other files are not 176 * affected. 177 * @param path the location of the file (which gpsim must recognise). 178 */ 179 void setBreakpoints( const QString & path, const IntList & lines ); 180 /** 181 * Sets / removes the breakpoint at the given line 182 */ 183 void setBreakpoint( const QString & path, int line, bool isBreakpoint ); 184 /** 185 * Returns the current source line that gpsim is at. By default, this 186 * will be the corresponding assembly line. That can be overwritten 187 * using mapAddressBlockToLine. 188 */ 189 SourceLine currentLine(); 190 /** 191 * Returns a pointer to the debug info for the current line. 192 */ 193 DebugLine * currentDebugLine(); 194 /** 195 * @return the program address for the given line (or -1 if no such 196 * line). 197 */ 198 int programAddress( const QString & path, int line ); 199 /** 200 * Step into the next program line. 201 */ 202 void stepInto(); 203 /** 204 * Step over the next program instruction. If we are currently running, 205 * this function will do nothing. Otherwise, it will record the current 206 * stack level, step, and if the new stack level is <= the initial level 207 * then return - otherwise, this processor will set a breakpoint for 208 * stack levels <= initial, and go to running mode. 209 */ 210 void stepOver(); 211 /** 212 * Similar to stepOver, except we break when the stack level becomes < 213 * the initial stack level (instead of <= initial). 214 */ 215 void stepOut(); 216 217 signals: 218 /** 219 * Emitted when a line is reached. By default, this is the line of the 220 * input assembly file; however, the line associated with an address in 221 * the PIC memory can be changed with mapAddressBlockToLine. 222 */ 223 void lineReached( const SourceLine & sourceLine ); 224 225 protected slots: 226 void gpsimRunningStatusChanged( bool isRunning ); 227 228 protected: 229 void initAddressToLineMap(); 230 void stackStep( int dl ); 231 void emitLineReached(); 232 233 int m_stackLevelLowerBreak; // Set by step-over, for when the stack level decreases to the one given 234 SourceLine m_previousAtLineEmit; // Used for working out whether we should emit a new line reached signal 235 DebugLine ** m_addressToLineMap; 236 DebugLine * m_pBreakFromOldLine; 237 GpsimProcessor * m_pGpsim; 238 Type m_type; 239 unsigned m_addressSize; 240 SourceLineMap m_sourceLineMap; // assembly <--> High level language 241 }; 242 243 244 /** 245 @author David Saxton 246 */ 247 class GpsimProcessor : public QObject 248 { 249 friend class GpsimDebugger; 250 Q_OBJECT 251 252 public: 253 /** 254 * Create a new gpsim processor. After calling this constructor, you 255 * should always call codLoadStatus() to ensure that the cod file was 256 * loaded successfully. 257 */ 258 GpsimProcessor( QString symbolFile, QObject *parent = nullptr ); 259 ~GpsimProcessor() override; 260 setDebugMode(GpsimDebugger::Type mode)261 void setDebugMode( GpsimDebugger::Type mode ) { m_debugMode = mode; } currentDebugger()262 GpsimDebugger * currentDebugger() const { return m_pDebugger[m_debugMode]; } 263 264 enum CodLoadStatus 265 { 266 CodSuccess, 267 CodFileNotFound, 268 CodUnrecognizedProcessor, 269 CodFileNameTooLong, 270 CodLstNotFound, 271 CodBadFile, 272 CodFileUnreadable, 273 CodFailure, 274 CodUnknown // Should never be this, but just in case load_symbol_file returns something funny 275 }; 276 277 enum InstructionType 278 { 279 LiteralOp, 280 BitOp, 281 RegisterOp, 282 UnknownOp 283 }; 284 285 /** 286 * @return status of opening the COD file 287 * @see displayCodLoadStatus 288 */ codLoadStatus()289 CodLoadStatus codLoadStatus() const { return m_codLoadStatus; } 290 /** 291 * Popups a messagebox to the user according to the CodLoadStatus. Will 292 * only popup a messagebox if the CodLoadStatus wasn't CodSuccess. 293 */ 294 void displayCodLoadStatus(); 295 /** 296 * Returns a list of source files for the currently running program. 297 * Each entry is a path in the local filesystem. 298 */ 299 QStringList sourceFileList(); 300 /** 301 * Set whether or not to run gpsim. (i.e. whether or not the step 302 * function should do anything when called with force=false). 303 */ 304 void setRunning( bool run ); 305 /** 306 * Returns true if running (currently simulating), else gpsim is paused. 307 */ isRunning()308 bool isRunning() const { return m_bIsRunning; } 309 /** 310 * Execute the next program instruction. If we are not in a running 311 * mode, then this function will do nothing. 312 */ 313 void executeNext(); 314 /** 315 * Reset all parts of the simulation. Gpsim will not run until 316 * setRunning(true) is called. Breakpoints are not affected. 317 */ 318 void reset(); 319 /** 320 * Returns the microinfo describing this processor. 321 */ 322 MicroInfo * microInfo() const; 323 picProcessor()324 pic_processor * picProcessor() const { return m_pPicProcessor; } 325 unsigned programMemorySize() const; registerMemory()326 RegisterSet * registerMemory() const { return m_pRegisterMemory; } 327 /** 328 * @return the instruction type at the given address. 329 */ 330 InstructionType instructionType( unsigned address ); 331 /** 332 * @return the address of the operand's register at address if the 333 * instruction at address is a register operation, and -1 otherwise. 334 */ 335 int operandRegister( unsigned address ); 336 /** 337 * @return the literal if the instruction at address is a literal 338 * operation, and -1 otherwise. 339 */ 340 int operandLiteral( unsigned address ); 341 342 //BEGIN Convenience functions for PIC files 343 enum ProgramFileValidity { DoesntExist, IncorrectType, Valid }; 344 /** 345 * @return information on the validity of the given program file (either 346 * DoesntExist, IncorrectType, or Valid). 347 * @see static QString generateSymbolFile 348 */ 349 static ProgramFileValidity isValidProgramFile( const QString & programFile ); 350 /** 351 * Converts the file at programFile to a Symbol file for emulation, 352 * and returns that symbol file's path 353 * @param fileName The full url to the file 354 * @param receiver The slot to connect the assembled signal to 355 * @see static bool isValidProgramFile( const QString &programFile ) 356 */ 357 static QString generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember = nullptr ); 358 /** 359 *Compile microbe to output to the given filename 360 */ 361 static void compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember = nullptr ); 362 //END convenience functions for PIC files 363 364 signals: 365 /** 366 * Emitted when the running status of gpsim changes. 367 */ 368 void runningStatusChanged( bool isRunning ); 369 370 protected: 371 /** 372 * Calls emitLineReached for each debugger. 373 */ 374 void emitLineReached(); 375 376 pic_processor * m_pPicProcessor; 377 CodLoadStatus m_codLoadStatus; 378 const QString m_symbolFile; 379 RegisterSet * m_pRegisterMemory; 380 GpsimDebugger::Type m_debugMode; 381 GpsimDebugger * m_pDebugger[2]; // Asm, HLL 382 383 /** 384 * We are called effectively for each cycle of the cycle of the 385 * processor. This value is used as some instructions (e.g. goto) take 386 * two cycles to execute, and so we must ignore one cycle to ensure 387 * realtime simulation. 388 */ 389 bool m_bCanExecuteNextCycle; 390 391 private: 392 bool m_bIsRunning; 393 }; 394 395 #endif 396 397 #endif // !NO_GPSIM 398