File indexing completed on 2025-02-02 12:45:50
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "config.h" 0012 #ifndef NO_GPSIM 0013 0014 #ifndef GPSIMPROCESSOR_H 0015 #define GPSIMPROCESSOR_H 0016 0017 #include "sourceline.h" 0018 0019 #include <QMap> 0020 // #include <q3valuevector.h> 0021 #include <QList> 0022 #include <QObject> 0023 #include <QVector> 0024 0025 class DebugLine; 0026 class GpsimProcessor; 0027 class MicroInfo; 0028 class pic_processor; // from gpsim 0029 class Register; 0030 class RegisterMemoryAccess; 0031 0032 typedef QMap<SourceLine, SourceLine> SourceLineMap; 0033 typedef QList<int> IntList; 0034 0035 class DebugLine : public SourceLine 0036 { 0037 public: 0038 DebugLine(); 0039 /// @param fileName a path to a file in the local filesystem 0040 DebugLine(const QString &fileName, int line); 0041 /** 0042 * Whether or not to break when we reach this line. 0043 */ 0044 bool isBreakpoint() const 0045 { 0046 return m_bIsBreakpoint; 0047 } 0048 /** 0049 * Set whether or not to break when we reach this line. 0050 */ 0051 void setBreakpoint(bool breakpoint) 0052 { 0053 m_bIsBreakpoint = breakpoint; 0054 } 0055 /** 0056 * Used for efficiency purposes by GpsimProcessor. Sets a flag. 0057 */ 0058 void markAsDeleted() 0059 { 0060 m_bMarkedAsDeleted = true; 0061 } 0062 /** 0063 * Used for efficiency purposes by GpsimProcessor. 0064 */ 0065 bool markedAsDeleted() const 0066 { 0067 return m_bMarkedAsDeleted; 0068 } 0069 0070 protected: 0071 bool m_bIsBreakpoint; 0072 bool m_bMarkedAsDeleted; 0073 0074 private: 0075 DebugLine(const DebugLine &dl); 0076 DebugLine &operator=(const DebugLine &dl); 0077 }; 0078 0079 /** 0080 @short Stores info from gpsim register, used to hide gpsim interface 0081 @author David Saxton 0082 */ 0083 class RegisterInfo : public QObject 0084 { 0085 Q_OBJECT 0086 public: 0087 RegisterInfo(Register *reg); 0088 0089 enum RegisterType { Invalid, Generic, File, SFR, Breakpoint }; 0090 0091 RegisterType type() const 0092 { 0093 return m_type; 0094 } 0095 QString name() const 0096 { 0097 return m_name; 0098 } 0099 unsigned value() const; 0100 static QString toString(RegisterType type); 0101 0102 /** 0103 * Checks to see if the value has changed; if so, emit new value. 0104 */ 0105 void update(); 0106 0107 signals: 0108 void valueChanged(unsigned newValue); 0109 0110 protected: 0111 QString m_name; 0112 RegisterType m_type; 0113 Register *m_pRegister; 0114 unsigned m_prevEmitValue; 0115 }; 0116 0117 /** 0118 @short Stores information about a set of registers, used to hide gpsim interface. 0119 @author David Saxton 0120 */ 0121 class RegisterSet 0122 { 0123 public: 0124 RegisterSet(pic_processor *picProcessor); 0125 ~RegisterSet(); 0126 0127 /** 0128 * Calls update for each RegisterInfo in this set. 0129 */ 0130 void update(); 0131 /** 0132 * Returns the number of registers. 0133 */ 0134 unsigned size() const 0135 { 0136 return m_registers.size(); 0137 } 0138 0139 RegisterInfo *fromAddress(unsigned address); 0140 RegisterInfo *fromName(const QString &name); 0141 0142 protected: 0143 typedef QMap<QString, RegisterInfo *> RegisterInfoMap; 0144 RegisterInfoMap m_nameToRegisterMap; 0145 QVector<RegisterInfo *> m_registers; 0146 }; 0147 0148 /** 0149 @author David Saxton 0150 */ 0151 class GpsimDebugger : public QObject 0152 { 0153 friend class GpsimProcessor; 0154 Q_OBJECT 0155 0156 public: 0157 enum Type { AsmDebugger = 0, HLLDebugger = 1 }; 0158 0159 GpsimDebugger(Type type, GpsimProcessor *gpsim); 0160 ~GpsimDebugger() override; 0161 0162 GpsimProcessor *gpsim() const 0163 { 0164 return m_pGpsim; 0165 } 0166 0167 /** 0168 * When an assembly file was generated by a high level language compiler 0169 * like SDCC, it will insert markers like ";#CSRC" that show which line 0170 * of source-code generated the given set of assembly instructions. This 0171 * matches up the assembly file lines with the associated source file 0172 * lines. 0173 * @param sourceFile the path to an assembly file in the local filesystem 0174 * @param assemblyFile the path to a source file in the local filesystem 0175 */ 0176 void associateLine(const QString &sourceFile, int sourceLine, const QString &assemblyFile, int assemblyLine); 0177 /** 0178 * Check to see if we've hit a breakpoint or similar; if so, this 0179 * function will stop the execution of the PIC program. 0180 */ 0181 void checkForBreak(); 0182 /** 0183 * Sets the breakpoints used for the given file to exactly those that 0184 * are contained in this list. Breakpoints for other files are not 0185 * affected. 0186 * @param path the location of the file (which gpsim must recognise). 0187 */ 0188 void setBreakpoints(const QString &path, const IntList &lines); 0189 /** 0190 * Sets / removes the breakpoint at the given line 0191 */ 0192 void setBreakpoint(const QString &path, int line, bool isBreakpoint); 0193 /** 0194 * Returns the current source line that gpsim is at. By default, this 0195 * will be the corresponding assembly line. That can be overwritten 0196 * using mapAddressBlockToLine. 0197 */ 0198 SourceLine currentLine(); 0199 /** 0200 * Returns a pointer to the debug info for the current line. 0201 */ 0202 DebugLine *currentDebugLine(); 0203 /** 0204 * @return the program address for the given line (or -1 if no such 0205 * line). 0206 */ 0207 int programAddress(const QString &path, int line); 0208 /** 0209 * Step into the next program line. 0210 */ 0211 void stepInto(); 0212 /** 0213 * Step over the next program instruction. If we are currently running, 0214 * this function will do nothing. Otherwise, it will record the current 0215 * stack level, step, and if the new stack level is <= the initial level 0216 * then return - otherwise, this processor will set a breakpoint for 0217 * stack levels <= initial, and go to running mode. 0218 */ 0219 void stepOver(); 0220 /** 0221 * Similar to stepOver, except we break when the stack level becomes < 0222 * the initial stack level (instead of <= initial). 0223 */ 0224 void stepOut(); 0225 0226 signals: 0227 /** 0228 * Emitted when a line is reached. By default, this is the line of the 0229 * input assembly file; however, the line associated with an address in 0230 * the PIC memory can be changed with mapAddressBlockToLine. 0231 */ 0232 void lineReached(const SourceLine &sourceLine); 0233 0234 protected slots: 0235 void gpsimRunningStatusChanged(bool isRunning); 0236 0237 protected: 0238 void initAddressToLineMap(); 0239 void stackStep(int dl); 0240 void emitLineReached(); 0241 0242 int m_stackLevelLowerBreak; // Set by step-over, for when the stack level decreases to the one given 0243 SourceLine m_previousAtLineEmit; // Used for working out whether we should emit a new line reached signal 0244 DebugLine **m_addressToLineMap; 0245 DebugLine *m_pBreakFromOldLine; 0246 GpsimProcessor *m_pGpsim; 0247 Type m_type; 0248 unsigned m_addressSize; 0249 SourceLineMap m_sourceLineMap; // assembly <--> High level language 0250 }; 0251 0252 /** 0253 @author David Saxton 0254 */ 0255 class GpsimProcessor : public QObject 0256 { 0257 friend class GpsimDebugger; 0258 Q_OBJECT 0259 0260 public: 0261 /** 0262 * Create a new gpsim processor. After calling this constructor, you 0263 * should always call codLoadStatus() to ensure that the cod file was 0264 * loaded successfully. 0265 */ 0266 GpsimProcessor(QString symbolFile, QObject *parent = nullptr); 0267 ~GpsimProcessor() override; 0268 0269 void setDebugMode(GpsimDebugger::Type mode) 0270 { 0271 m_debugMode = mode; 0272 } 0273 GpsimDebugger *currentDebugger() const 0274 { 0275 return m_pDebugger[m_debugMode]; 0276 } 0277 0278 enum CodLoadStatus { 0279 CodSuccess, 0280 CodFileNotFound, 0281 CodUnrecognizedProcessor, 0282 CodFileNameTooLong, 0283 CodLstNotFound, 0284 CodBadFile, 0285 CodFileUnreadable, 0286 CodFailure, 0287 CodUnknown // Should never be this, but just in case load_symbol_file returns something funny 0288 }; 0289 0290 enum InstructionType { LiteralOp, BitOp, RegisterOp, UnknownOp }; 0291 0292 /** 0293 * @return status of opening the COD file 0294 * @see displayCodLoadStatus 0295 */ 0296 CodLoadStatus codLoadStatus() const 0297 { 0298 return m_codLoadStatus; 0299 } 0300 /** 0301 * Popups a messagebox to the user according to the CodLoadStatus. Will 0302 * only popup a messagebox if the CodLoadStatus wasn't CodSuccess. 0303 */ 0304 void displayCodLoadStatus(); 0305 /** 0306 * Returns a list of source files for the currently running program. 0307 * Each entry is a path in the local filesystem. 0308 */ 0309 QStringList sourceFileList(); 0310 /** 0311 * Set whether or not to run gpsim. (i.e. whether or not the step 0312 * function should do anything when called with force=false). 0313 */ 0314 void setRunning(bool run); 0315 /** 0316 * Returns true if running (currently simulating), else gpsim is paused. 0317 */ 0318 bool isRunning() const 0319 { 0320 return m_bIsRunning; 0321 } 0322 /** 0323 * Execute the next program instruction. If we are not in a running 0324 * mode, then this function will do nothing. 0325 */ 0326 void executeNext(); 0327 /** 0328 * Reset all parts of the simulation. Gpsim will not run until 0329 * setRunning(true) is called. Breakpoints are not affected. 0330 */ 0331 void reset(); 0332 /** 0333 * Returns the microinfo describing this processor. 0334 */ 0335 MicroInfo *microInfo() const; 0336 0337 pic_processor *picProcessor() const 0338 { 0339 return m_pPicProcessor; 0340 } 0341 unsigned programMemorySize() const; 0342 RegisterSet *registerMemory() const 0343 { 0344 return m_pRegisterMemory; 0345 } 0346 /** 0347 * @return the instruction type at the given address. 0348 */ 0349 InstructionType instructionType(unsigned address); 0350 /** 0351 * @return the address of the operand's register at address if the 0352 * instruction at address is a register operation, and -1 otherwise. 0353 */ 0354 int operandRegister(unsigned address); 0355 /** 0356 * @return the literal if the instruction at address is a literal 0357 * operation, and -1 otherwise. 0358 */ 0359 int operandLiteral(unsigned address); 0360 0361 // BEGIN Convenience functions for PIC files 0362 enum ProgramFileValidity { DoesntExist, IncorrectType, Valid }; 0363 /** 0364 * @return information on the validity of the given program file (either 0365 * DoesntExist, IncorrectType, or Valid). 0366 * @see static QString generateSymbolFile 0367 */ 0368 static ProgramFileValidity isValidProgramFile(const QString &programFile); 0369 /** 0370 * Converts the file at programFile to a Symbol file for emulation, 0371 * and returns that symbol file's path 0372 * @param fileName The full url to the file 0373 * @param receiver The slot to connect the assembled signal to 0374 * @see static bool isValidProgramFile( const QString &programFile ) 0375 */ 0376 static QString generateSymbolFile(const QString &fileName, QObject *receiver, const char *successMember, const char *failMember = nullptr); 0377 /** 0378 *Compile microbe to output to the given filename 0379 */ 0380 static void compileMicrobe(const QString &filename, QObject *receiver, const char *successMember, const char *failMember = nullptr); 0381 // END convenience functions for PIC files 0382 0383 signals: 0384 /** 0385 * Emitted when the running status of gpsim changes. 0386 */ 0387 void runningStatusChanged(bool isRunning); 0388 0389 protected: 0390 /** 0391 * Calls emitLineReached for each debugger. 0392 */ 0393 void emitLineReached(); 0394 0395 pic_processor *m_pPicProcessor; 0396 CodLoadStatus m_codLoadStatus; 0397 const QString m_symbolFile; 0398 RegisterSet *m_pRegisterMemory; 0399 GpsimDebugger::Type m_debugMode; 0400 GpsimDebugger *m_pDebugger[2]; // Asm, HLL 0401 0402 /** 0403 * We are called effectively for each cycle of the cycle of the 0404 * processor. This value is used as some instructions (e.g. goto) take 0405 * two cycles to execute, and so we must ignore one cycle to ensure 0406 * realtime simulation. 0407 */ 0408 bool m_bCanExecuteNextCycle; 0409 0410 private: 0411 bool m_bIsRunning; 0412 }; 0413 0414 #endif 0415 0416 #endif // !NO_GPSIM