File indexing completed on 2024-04-21 05:43:34

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 #include "asmparser.h"
0015 #include "debugmanager.h"
0016 #include "flowcodedocument.h"
0017 #include "gpsimprocessor.h"
0018 #include "language.h"
0019 #include "languagemanager.h"
0020 #include "microlibrary.h"
0021 #include "processchain.h"
0022 #include "simulator.h"
0023 
0024 #include <cassert>
0025 
0026 #include <KLocalizedString>
0027 #include <KMessageBox>
0028 
0029 #include <QDir>
0030 #include <QFile>
0031 #include <QTemporaryFile>
0032 #include <QTextStream>
0033 #include <QTimer>
0034 
0035 #include <ktechlab_debug.h>
0036 
0037 // gpsim has problems with dependent include headers
0038 // clang-format off
0039 #include "gpsim/cod.h"
0040 #include "gpsim/interface.h"
0041 #include "gpsim/gpsim_classes.h"
0042 #include "gpsim/pic-processor.h"
0043 #include "gpsim/registers.h"
0044 #include "gpsim/14bit-registers.h"
0045 #include "gpsim/sim_context.h"
0046 #include "gpsim/symbol.h"
0047 // clang-format on
0048 
0049 bool bDoneGpsimInit = false;
0050 bool bUseGUI = true;
0051 // extern "C" void initialize_gpsim();
0052 // void initialize_gpsim(void);
0053 extern void initialize_commands();
0054 extern void initialize_readline();
0055 extern void gui_main(void);
0056 extern void cli_main();
0057 void gpsim_version()
0058 {
0059 }
0060 void quit_gui()
0061 {
0062 }
0063 
0064 // BEGIN class GpsimProcessor
0065 /**
0066 Work around a bug in gpsim: the directory in a filename is recorded twice, e.g.
0067 "/home/david/afile.asm" is recorded as "/home/david//home/david/afile.asm". This
0068 function will remove the duplicated directory path (by searching for a "//").
0069 */
0070 QString sanitizeGpsimFile(QString file)
0071 {
0072     int pos = file.indexOf("//");
0073     if (pos != -1) {
0074         file.remove(0, pos + 1);
0075     }
0076     return file;
0077 }
0078 
0079 GpsimProcessor::GpsimProcessor(QString symbolFile, QObject *parent)
0080     : QObject(parent)
0081     , m_symbolFile(symbolFile)
0082 {
0083     if (!bDoneGpsimInit) {
0084         initialize_gpsim_core();
0085         initialization_is_complete();
0086 
0087         bDoneGpsimInit = true;
0088     }
0089 
0090     m_bCanExecuteNextCycle = true;
0091     m_bIsRunning = false;
0092     m_pPicProcessor = nullptr;
0093     m_codLoadStatus = CodUnknown;
0094     m_pRegisterMemory = nullptr;
0095     m_debugMode = GpsimDebugger::AsmDebugger;
0096     m_pDebugger[0] = m_pDebugger[1] = nullptr;
0097 
0098     Processor *tempProcessor = nullptr;
0099     const QByteArray fileName = QFile::encodeName(symbolFile);
0100 
0101     qCDebug(KTL_LOG) << "GPSIM_0_21_11+ GpsimProcessor " << symbolFile;
0102     FILE *pFile = fopen(fileName.constData(), "r");
0103     if (!pFile)
0104         m_codLoadStatus = CodFileUnreadable;
0105     else
0106         m_codLoadStatus = (ProgramFileTypeList::GetList().LoadProgramFile(&tempProcessor, fileName.constData(), pFile)) ? CodSuccess : CodFailure;
0107     qCDebug(KTL_LOG) << " m_codLoadStatus=" << m_codLoadStatus;
0108 
0109     m_pPicProcessor = dynamic_cast<pic_processor *>(tempProcessor);
0110 
0111     if (codLoadStatus() == CodSuccess) {
0112         m_pRegisterMemory = new RegisterSet(m_pPicProcessor);
0113         m_pDebugger[0] = new GpsimDebugger(GpsimDebugger::AsmDebugger, this);
0114         m_pDebugger[1] = new GpsimDebugger(GpsimDebugger::HLLDebugger, this);
0115         Simulator::self()->attachGpsimProcessor(this);
0116         DebugManager::self()->registerGpsim(this);
0117     }
0118 }
0119 
0120 GpsimProcessor::~GpsimProcessor()
0121 {
0122     if (!Simulator::isDestroyedSim()) {
0123         Simulator::self()->detachGpsimProcessor(this);
0124     }
0125     delete m_pRegisterMemory;
0126 
0127     if (m_pDebugger[0])
0128         m_pDebugger[0]->deleteLater();
0129     if (m_pDebugger[1])
0130         m_pDebugger[1]->deleteLater();
0131 }
0132 
0133 void GpsimProcessor::displayCodLoadStatus()
0134 {
0135     switch (m_codLoadStatus) {
0136     case CodSuccess:
0137         break;
0138     case CodFileNotFound:
0139         KMessageBox::error(nullptr, i18n("The cod file \"%1\" was not found.", m_symbolFile), i18n("File Not Found"));
0140         break;
0141     case CodUnrecognizedProcessor:
0142         KMessageBox::error(nullptr, i18n("The processor for cod file \"%1\" is unrecognized.", m_symbolFile), i18n("Unrecognized Processor"));
0143         break;
0144     case CodFileNameTooLong:
0145         KMessageBox::error(nullptr, i18n("The file name \"%1\" is too long.", m_symbolFile), i18n("Filename Too Long"));
0146         break;
0147     case CodLstNotFound:
0148         KMessageBox::error(nullptr, i18n("The lst file associated with the cod file \"%1\" was not found.", m_symbolFile), i18n("LST File Not Found"));
0149         break;
0150     case CodBadFile:
0151         KMessageBox::error(nullptr, i18n("The cod file \"%1\" is bad.", m_symbolFile), i18n("Bad File"));
0152         break;
0153     case CodFileUnreadable:
0154         KMessageBox::error(nullptr, i18n("The cod file \"%1\" could not be read from.", m_symbolFile), i18n("Unreadable File"));
0155         break;
0156     case CodFailure:
0157     case CodUnknown:
0158         KMessageBox::error(nullptr, i18n("An error occurred with the cod file \"%1\".", m_symbolFile), i18n("Error"));
0159         break;
0160     }
0161 }
0162 
0163 unsigned GpsimProcessor::programMemorySize() const
0164 {
0165     return m_pPicProcessor->program_memory_size();
0166 }
0167 
0168 QStringList GpsimProcessor::sourceFileList()
0169 {
0170     QStringList files;
0171 
0172     int max = m_pPicProcessor->files.nsrc_files();
0173 
0174     for (int i = 0; i < max; ++i) {
0175         if (!m_pPicProcessor->files[i])
0176             continue;
0177 
0178         files << sanitizeGpsimFile(m_pPicProcessor->files[i]->name().c_str());
0179     }
0180 
0181     return files;
0182 }
0183 
0184 void GpsimProcessor::emitLineReached()
0185 {
0186     m_pDebugger[0]->emitLineReached();
0187     m_pDebugger[1]->emitLineReached();
0188 }
0189 
0190 void GpsimProcessor::setRunning(bool run)
0191 {
0192     if (m_bIsRunning == run)
0193         return;
0194 
0195     m_bIsRunning = run;
0196     emit runningStatusChanged(run);
0197 }
0198 
0199 void GpsimProcessor::executeNext()
0200 {
0201     if (!m_bIsRunning)
0202         return;
0203 
0204     if (!m_bCanExecuteNextCycle) {
0205         m_bCanExecuteNextCycle = true;
0206         return;
0207     }
0208 
0209     unsigned long long beforeExecuteCount = get_cycles().get();
0210 
0211     if (get_bp().have_interrupt()) {
0212         m_pPicProcessor->interrupt();
0213     } else {
0214         m_pPicProcessor->step_one(false); // Don't know what the false is for; gpsim ignores its value anyway
0215 
0216         // Some instructions take more than one cycle to execute, so ignore next cycle if this was the case
0217         if ((get_cycles().get() - beforeExecuteCount) > 1)
0218             m_bCanExecuteNextCycle = false;
0219     }
0220 
0221     currentDebugger()->checkForBreak();
0222 
0223     // Let's also update the values of RegisterInfo every 25 milliseconds
0224     if ((beforeExecuteCount % 10000) == 0)
0225         registerMemory()->update();
0226 }
0227 
0228 void GpsimProcessor::reset()
0229 {
0230     bool wasRunning = isRunning();
0231     m_pPicProcessor->reset(SIM_RESET);
0232     setRunning(false);
0233     if (!wasRunning) {
0234         // If we weren't running before, then the next signal won't have been emitted
0235         emitLineReached();
0236     }
0237 }
0238 
0239 MicroInfo *GpsimProcessor::microInfo() const
0240 {
0241     if (!m_pPicProcessor) {
0242         qCWarning(KTL_LOG) << " m_pPicProcessor == nullptr";
0243         return nullptr;
0244     }
0245 
0246     return MicroLibrary::self()->microInfoWithID(m_pPicProcessor->name().c_str());
0247 }
0248 
0249 int GpsimProcessor::operandRegister(unsigned address)
0250 {
0251     instruction *ins = m_pPicProcessor->program_memory[address];
0252     if (Register_op *reg = dynamic_cast<Register_op *>(ins))
0253         return reg->register_address;
0254     return -1;
0255 }
0256 
0257 int GpsimProcessor::operandLiteral(unsigned address)
0258 {
0259     instruction *ins = m_pPicProcessor->program_memory[address];
0260     if (Literal_op *lit = dynamic_cast<Literal_op *>(ins))
0261         return lit->L;
0262     return -1;
0263 }
0264 
0265 GpsimProcessor::ProgramFileValidity GpsimProcessor::isValidProgramFile(const QString &programFile)
0266 {
0267     if (!QFile::exists(programFile))
0268         return DoesntExist;
0269 
0270     QString extension = programFile.right(programFile.length() - programFile.lastIndexOf('.') - 1).toLower();
0271 
0272     if (extension == "flowcode" || extension == "asm" || extension == "cod" || extension == "basic" || extension == "microbe" || extension == "c")
0273         return Valid;
0274 
0275     if (extension == "hex" && QFile::exists(QString(programFile).replace(".hex", ".cod")))
0276         return Valid;
0277 
0278     return IncorrectType;
0279 }
0280 
0281 QString GpsimProcessor::generateSymbolFile(const QString &fileName, QObject *receiver, const char *successMember, const char *failMember)
0282 {
0283     qCDebug(KTL_LOG) << "fileName=" << fileName;
0284     if (isValidProgramFile(fileName) != GpsimProcessor::Valid) {
0285         qCDebug(KTL_LOG) << "not valid program file";
0286         return QString();
0287     }
0288 
0289     QString extension = fileName.right(fileName.length() - fileName.lastIndexOf('.') - 1).toLower();
0290 
0291     if (extension == "cod") {
0292         QTimer::singleShot(0, receiver, successMember);
0293         return fileName;
0294     }
0295     if (extension == "hex") {
0296         QTimer::singleShot(0, receiver, successMember);
0297         // We've already checked for the existance of the ".cod" file in GpsimProcessor::isValidProgramFile
0298         return QString(fileName).replace(".hex", ".cod");
0299     }
0300 
0301     else if (extension == "basic" || extension == "microbe") {
0302         compileMicrobe(fileName, receiver, successMember, failMember);
0303         return QString(fileName).replace("." + extension, ".cod");
0304     } else if (extension == "flowcode") {
0305         QTemporaryFile tmpFile(QDir::tempPath() + QLatin1String("/ktechlab_XXXXXX.hex"));
0306         if (!tmpFile.open()) {
0307             qCWarning(KTL_LOG) << " failed to open " << tmpFile.fileName() << " error " << tmpFile.errorString();
0308             return QString();
0309         }
0310         const QString hexFile = tmpFile.fileName();
0311         ProcessOptions o;
0312         o.b_addToProject = false;
0313         o.setTargetFile(hexFile);
0314         o.setInputFiles(QStringList(fileName));
0315         o.setMethod(ProcessOptions::Method::Forget);
0316         o.setProcessPath(ProcessOptions::ProcessPath::FlowCode_Program);
0317 
0318         ProcessChain *pc = LanguageManager::self()->compile(o);
0319         if (receiver) {
0320             if (successMember)
0321                 connect(pc, SIGNAL(successful()), receiver, successMember);
0322             if (failMember)
0323                 connect(pc, SIGNAL(failed()), receiver, failMember);
0324         }
0325 
0326         return QString(hexFile).replace(".hex", ".cod");
0327     } else if (extension == "asm") {
0328         ProcessOptions o;
0329         o.b_addToProject = false;
0330         o.setTargetFile(QString(fileName).replace(".asm", ".hex"));
0331         o.setInputFiles(QStringList(fileName));
0332         o.setMethod(ProcessOptions::Method::Forget);
0333         o.setProcessPath(ProcessOptions::ProcessPath::path(ProcessOptions::guessMediaType(fileName), ProcessOptions::ProcessPath::Program));
0334 
0335         ProcessChain *pc = LanguageManager::self()->compile(o);
0336         if (receiver) {
0337             if (successMember)
0338                 connect(pc, SIGNAL(successful()), receiver, successMember);
0339             if (failMember)
0340                 connect(pc, SIGNAL(failed()), receiver, failMember);
0341         }
0342 
0343         return QString(fileName).replace(".asm", ".cod");
0344     } else if (extension == "c") {
0345         ProcessOptions o;
0346         o.b_addToProject = false;
0347         o.setTargetFile(QString(fileName).replace(".c", ".hex"));
0348         o.setInputFiles(QStringList(fileName));
0349         o.setMethod(ProcessOptions::Method::Forget);
0350         o.setProcessPath(ProcessOptions::ProcessPath::C_Program);
0351 
0352         ProcessChain *pc = LanguageManager::self()->compile(o);
0353         if (receiver) {
0354             if (successMember)
0355                 connect(pc, SIGNAL(successful()), receiver, successMember);
0356             if (failMember)
0357                 connect(pc, SIGNAL(failed()), receiver, failMember);
0358         }
0359 
0360         return QString(fileName).replace(".c", ".cod");
0361     }
0362 
0363     if (failMember)
0364         QTimer::singleShot(0, receiver, failMember);
0365     return QString();
0366 }
0367 
0368 void GpsimProcessor::compileMicrobe(const QString &filename, QObject *receiver, const char *successMember, const char *failMember)
0369 {
0370     ProcessOptions o;
0371     o.b_addToProject = false;
0372     o.setTargetFile(QString(filename).replace(".microbe", ".hex"));
0373     o.setInputFiles(QStringList(filename));
0374     o.setMethod(ProcessOptions::Method::Forget);
0375     o.setProcessPath(ProcessOptions::ProcessPath::Microbe_Program);
0376     ProcessChain *pc = LanguageManager::self()->compile(o);
0377     if (receiver) {
0378         if (successMember)
0379             connect(pc, SIGNAL(successful()), receiver, successMember);
0380         if (failMember)
0381             connect(pc, SIGNAL(failed()), receiver, failMember);
0382     }
0383 }
0384 // END class GpsimProcessor
0385 
0386 // BEGIN class GpsimDebugger
0387 GpsimDebugger::GpsimDebugger(Type type, GpsimProcessor *gpsim)
0388     : QObject()
0389 {
0390     m_pGpsim = gpsim;
0391     m_type = type;
0392     m_pBreakFromOldLine = nullptr;
0393     m_addressToLineMap = nullptr;
0394     m_stackLevelLowerBreak = -1;
0395     m_addressSize = 0;
0396 
0397     connect(m_pGpsim, &GpsimProcessor::runningStatusChanged, this, &GpsimDebugger::gpsimRunningStatusChanged);
0398 
0399     if (type == HLLDebugger) {
0400         const QStringList sourceFileList = m_pGpsim->sourceFileList();
0401         QStringList::const_iterator sflEnd = sourceFileList.end();
0402         for (QStringList::const_iterator it = sourceFileList.begin(); it != sflEnd; ++it) {
0403             AsmParser p(*it);
0404             p.parse(this);
0405         }
0406     }
0407 
0408     initAddressToLineMap();
0409 }
0410 
0411 GpsimDebugger::~GpsimDebugger()
0412 {
0413     QList<DebugLine *> debugLinesToDelete;
0414 
0415     for (unsigned i = 0; i < m_addressSize; ++i) {
0416         DebugLine *dl = m_addressToLineMap[i];
0417         if (!dl || dl->markedAsDeleted())
0418             continue;
0419 
0420         dl->markAsDeleted();
0421         debugLinesToDelete += dl;
0422     }
0423 
0424     qDeleteAll(debugLinesToDelete);
0425 
0426     delete[] m_addressToLineMap;
0427 }
0428 
0429 void GpsimDebugger::gpsimRunningStatusChanged(bool isRunning)
0430 {
0431     if (!isRunning) {
0432         m_stackLevelLowerBreak = -1;
0433         m_pBreakFromOldLine = nullptr;
0434         emitLineReached();
0435     }
0436 }
0437 
0438 void GpsimDebugger::associateLine(const QString &sourceFile, int sourceLine, const QString &assemblyFile, int assemblyLine)
0439 {
0440     if (assemblyLine < 0 || sourceLine < 0) {
0441         qCWarning(KTL_LOG) << "Invalid lines: assemblyLine=" << assemblyLine << " sourceLine=" << sourceLine;
0442         return;
0443     }
0444 
0445     SourceLine hllSource = SourceLine(sourceFile, sourceLine);
0446     SourceLine asmSource = SourceLine(assemblyFile, assemblyLine);
0447 
0448     if (m_sourceLineMap.contains(asmSource)) {
0449         qCWarning(KTL_LOG) << "Already have an association for assembly (\"" << assemblyFile << "\"," << assemblyLine << ")";
0450         return;
0451     }
0452 
0453     m_sourceLineMap[asmSource] = hllSource;
0454 }
0455 
0456 void GpsimDebugger::initAddressToLineMap()
0457 {
0458     m_addressSize = m_pGpsim->programMemorySize();
0459 
0460     delete[] m_addressToLineMap;
0461     m_addressToLineMap = new DebugLine *[m_addressSize];
0462     memset(m_addressToLineMap, 0, m_addressSize * sizeof(DebugLine *));
0463 
0464     if (m_type == AsmDebugger) {
0465         for (unsigned i = 0; i < m_addressSize; ++i) {
0466             int line = m_pGpsim->picProcessor()->pma->get_src_line(i) - 1;
0467             int fileID = m_pGpsim->picProcessor()->pma->get_file_id(i);
0468             FileContext *fileContext = m_pGpsim->picProcessor()->files[fileID];
0469 
0470             if (fileContext)
0471                 m_addressToLineMap[i] = new DebugLine(sanitizeGpsimFile(fileContext->name().c_str()), line);
0472         }
0473     } else {
0474         SourceLineMap::const_iterator slmEnd = m_sourceLineMap.end();
0475         for (SourceLineMap::const_iterator it = m_sourceLineMap.begin(); it != slmEnd; ++it) {
0476             SourceLineMap::const_iterator next = it;
0477             ++next;
0478 
0479             int asmToLine = ((next == slmEnd) || (next.key().fileName() != it.key().fileName())) ? -1 : next.key().line() - 1;
0480 
0481             QString asmFile = it.key().fileName();
0482             int asmFromLine = it.key().line();
0483             SourceLine sourceLine = it.value();
0484 
0485             std::string stdAsmFile(asmFile.toLatin1());
0486             int fileID = m_pGpsim->picProcessor()->files.Find(stdAsmFile);
0487             if (fileID == -1) {
0488                 qCWarning(KTL_LOG) << "Could not find FileContext (asmFile=\"" << asmFile << "\")";
0489                 continue;
0490             }
0491 
0492             if (asmToLine == -1)
0493                 asmToLine = m_pGpsim->picProcessor()->files[fileID]->max_line() - 2;
0494 
0495             if ((asmFromLine < 0) || (asmToLine < asmFromLine)) {
0496                 qCWarning(KTL_LOG) << "Invalid lines: asmFromLine=" << asmFromLine << " asmToLine=" << asmToLine;
0497                 continue;
0498             }
0499 
0500             DebugLine *debugLine = new DebugLine(sourceLine.fileName(), sourceLine.line());
0501             bool used = false;
0502 
0503             for (int i = asmFromLine; i <= asmToLine; ++i) {
0504                 int address = m_pGpsim->picProcessor()->pma->find_address_from_line(m_pGpsim->picProcessor()->files[fileID], i + 1);
0505                 if (address != -1) {
0506                     used = true;
0507                     m_addressToLineMap[address] = debugLine;
0508                 }
0509             }
0510 
0511             if (!used)
0512                 delete debugLine;
0513         }
0514     }
0515 }
0516 
0517 void GpsimDebugger::setBreakpoints(const QString &path, const IntList &lines)
0518 {
0519     for (unsigned i = 0; i < m_addressSize; i++) {
0520         DebugLine *dl = m_addressToLineMap[i];
0521         if (!dl || dl->fileName() != path)
0522             continue;
0523 
0524         dl->setBreakpoint(lines.contains(dl->line()));
0525     }
0526 }
0527 
0528 void GpsimDebugger::setBreakpoint(const QString &path, int line, bool isBreakpoint)
0529 {
0530     for (unsigned i = 0; i < m_addressSize; i++) {
0531         if (!m_addressToLineMap[i])
0532             continue;
0533 
0534         if ((m_addressToLineMap[i]->fileName() == path) && (line == m_addressToLineMap[i]->line()))
0535             m_addressToLineMap[i]->setBreakpoint(isBreakpoint);
0536     }
0537 }
0538 
0539 DebugLine *GpsimDebugger::currentDebugLine()
0540 {
0541     return m_addressToLineMap[m_pGpsim->picProcessor()->pc->get_value()];
0542 }
0543 
0544 SourceLine GpsimDebugger::currentLine()
0545 {
0546     DebugLine *dl = currentDebugLine();
0547     return dl ? *dl : SourceLine();
0548 }
0549 
0550 void GpsimDebugger::emitLineReached()
0551 {
0552     SourceLine currentAt = currentLine();
0553 
0554     if (currentAt == m_previousAtLineEmit)
0555         return;
0556 
0557     m_previousAtLineEmit = currentAt;
0558     m_pGpsim->registerMemory()->update();
0559     emit lineReached(currentAt);
0560 }
0561 
0562 void GpsimDebugger::checkForBreak()
0563 {
0564     DebugLine *currentLine = m_addressToLineMap[m_pGpsim->picProcessor()->pc->get_value()];
0565     int currentStackLevel = int(m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask);
0566 
0567     bool ontoNextLine = m_pBreakFromOldLine != currentLine;
0568     bool lineBreakpoint = currentLine ? currentLine->isBreakpoint() : false;
0569     bool stackBreakpoint = m_stackLevelLowerBreak >= currentStackLevel;
0570 
0571     if (ontoNextLine && (lineBreakpoint || stackBreakpoint))
0572         m_pGpsim->setRunning(false);
0573 }
0574 
0575 int GpsimDebugger::programAddress(const QString &path, int line)
0576 {
0577     for (unsigned i = 0; i < m_addressSize; ++i) {
0578         DebugLine *dl = m_addressToLineMap[i];
0579         if (!dl || (dl->line() != line) || (dl->fileName() != path))
0580             continue;
0581 
0582         return i;
0583     }
0584 
0585     return -1;
0586 }
0587 
0588 void GpsimDebugger::stepInto()
0589 {
0590     // I'm not aware of the stack being able to increase in size by more than
0591     // one at a time, so "1" should suffice here...but to be on the safe side,
0592     // make it a nice large number
0593     stackStep(1 << 16);
0594 }
0595 void GpsimDebugger::stepOver()
0596 {
0597     stackStep(0);
0598 }
0599 void GpsimDebugger::stepOut()
0600 {
0601     stackStep(-1);
0602 }
0603 void GpsimDebugger::stackStep(int dl)
0604 {
0605     if (m_pGpsim->isRunning())
0606         return;
0607 
0608     int initialStack = (m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask) + dl;
0609     DebugLine *initialLine = currentDebugLine();
0610 
0611     if (initialStack < 0)
0612         initialStack = 0;
0613 
0614     // Reset any previous stackStep, and step
0615     m_pBreakFromOldLine = nullptr;
0616     m_stackLevelLowerBreak = -1;
0617     m_pGpsim->picProcessor()->step_one(false);
0618 
0619     int currentStack = m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask;
0620     DebugLine *currentLine = currentDebugLine();
0621 
0622     if ((initialStack >= currentStack) && (initialLine != currentLine))
0623         emitLineReached();
0624 
0625     else {
0626         // Looks like we stepped into something or haven't gone onto the next
0627         // instruction, wait until we step back out....
0628         m_stackLevelLowerBreak = initialStack;
0629         m_pBreakFromOldLine = initialLine;
0630         m_pGpsim->setRunning(true);
0631     }
0632 }
0633 // END class Debugger
0634 
0635 // BEGIN class RegisterSet
0636 RegisterSet::RegisterSet(pic_processor *picProcessor)
0637 {
0638     unsigned numRegisters = picProcessor->rma.get_size();
0639     qCDebug(KTL_LOG) << "numRegisters=" << numRegisters;
0640     m_registers.resize(numRegisters /*, nullptr - 2018.06.02 - initialized below */);
0641     for (unsigned i = 0; i < numRegisters; ++i) {
0642         RegisterInfo *info = new RegisterInfo(&picProcessor->rma[i]);
0643         m_registers[i] = info;
0644         m_nameToRegisterMap[info->name()] = info;
0645         qCDebug(KTL_LOG) << " add register info " << info->name() << " at pos " << i << " addr " << info;
0646     }
0647     RegisterInfo *info = new RegisterInfo(picProcessor->Wreg); // is tihs correct for "W" member? TODO
0648     m_registers.append(info);
0649     m_nameToRegisterMap[info->name()] = info;
0650     qCDebug(KTL_LOG) << " add register info " << info->name() << " at end, addr " << info;
0651     qCDebug(KTL_LOG) << " registers.size " << m_registers.size() << " ; numRegisters " << numRegisters;
0652 }
0653 
0654 RegisterSet::~RegisterSet()
0655 {
0656     qDeleteAll(m_registers);
0657 }
0658 
0659 RegisterInfo *RegisterSet::fromAddress(unsigned address)
0660 {
0661     return (int(address) < m_registers.size()) ? m_registers[address] : nullptr;
0662 }
0663 
0664 RegisterInfo *RegisterSet::fromName(const QString &name)
0665 {
0666     // First try the name as case sensitive, then as case insensitive.
0667     if (m_nameToRegisterMap.contains(name))
0668         return m_nameToRegisterMap[name];
0669 
0670     QString nameLower = name.toLower();
0671 
0672     RegisterInfoMap::iterator end = m_nameToRegisterMap.end();
0673     for (RegisterInfoMap::iterator it = m_nameToRegisterMap.begin(); it != end; ++it) {
0674         if (it.key().toLower() == nameLower)
0675             return it.value();
0676     }
0677 
0678     return nullptr;
0679 }
0680 
0681 void RegisterSet::update()
0682 {
0683     for (int i = 0; i < m_registers.size(); ++i)
0684         m_registers[i]->update();
0685 }
0686 // END class RegisterSet
0687 
0688 // BEGIN class RegisterInfo
0689 RegisterInfo::RegisterInfo(Register *reg)
0690 {
0691     assert(reg);
0692     m_pRegister = reg;
0693     m_type = Invalid;
0694     m_prevEmitValue = 0;
0695 
0696     switch (m_pRegister->isa()) {
0697     case Register::GENERIC_REGISTER:
0698         m_type = Generic;
0699         break;
0700     case Register::FILE_REGISTER:
0701         m_type = File;
0702         break;
0703     case Register::SFR_REGISTER:
0704         m_type = SFR;
0705         break;
0706     case Register::BP_REGISTER:
0707         m_type = Breakpoint;
0708         break;
0709     case Register::INVALID_REGISTER:
0710         m_type = Invalid;
0711         break;
0712     }
0713 
0714     m_name = QString::fromLatin1(m_pRegister->baseName().c_str());
0715 }
0716 
0717 unsigned RegisterInfo::value() const
0718 {
0719     return m_pRegister->value.data;
0720 }
0721 
0722 void RegisterInfo::update()
0723 {
0724     unsigned newValue = value();
0725     if (newValue != m_prevEmitValue) {
0726         m_prevEmitValue = newValue;
0727         emit valueChanged(newValue);
0728     }
0729 }
0730 
0731 QString RegisterInfo::toString(RegisterType type)
0732 {
0733     switch (type) {
0734     case Generic:
0735         return i18n("Generic");
0736 
0737     case File:
0738         return i18n("File");
0739 
0740     case SFR:
0741         return i18n("SFR");
0742 
0743     case Breakpoint:
0744         return i18n("Breakpoint");
0745 
0746     case Invalid:
0747         return i18n("Invalid");
0748     }
0749 
0750     return i18n("Unknown");
0751 }
0752 // END class RegisterInfo
0753 
0754 // BEGIN class DebugLine
0755 DebugLine::DebugLine(const QString &fileName, int line)
0756     : SourceLine(fileName, line)
0757 {
0758     m_bIsBreakpoint = false;
0759     m_bMarkedAsDeleted = false;
0760 }
0761 
0762 DebugLine::DebugLine()
0763     : SourceLine()
0764 {
0765     m_bIsBreakpoint = false;
0766     m_bMarkedAsDeleted = false;
0767 }
0768 // END class DebugLine
0769 
0770 #include "moc_gpsimprocessor.cpp"
0771 
0772 #endif