File indexing completed on 2024-06-16 08:27:18

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