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 #include "asmparser.h"
15 #include "debugmanager.h"
16 #include "flowcodedocument.h"
17 #include "gpsimprocessor.h"
18 #include "language.h"
19 #include "languagemanager.h"
20 #include "microlibrary.h"
21 #include "processchain.h"
22 #include "simulator.h"
23
24 #include <cassert>
25
26 #include <KLocalizedString>
27 #include <KMessageBox>
28
29 #include <QDebug>
30 #include <QTemporaryFile>
31 #include <QDir>
32 #include <QFile>
33 #include <QTextStream>
34 #include <QTimer>
35
36 #include "gpsim/cod.h"
37 #include "gpsim/interface.h"
38 #include "gpsim/gpsim_classes.h"
39 #include "gpsim/pic-processor.h"
40 #include "gpsim/registers.h"
41 #include "gpsim/14bit-registers.h"
42 #include "gpsim/symbol.h"
43 #include "gpsim/sim_context.h"
44
45 bool bDoneGpsimInit = false;
46 bool bUseGUI = true;
47 // extern "C" void initialize_gpsim();
48 // void initialize_gpsim(void);
49 extern void initialize_commands();
50 extern void initialize_readline();
51 extern void gui_main(void);
52 extern void cli_main();
gpsim_version()53 void gpsim_version() {}
quit_gui()54 void quit_gui() {}
55
56
57 //BEGIN class GpsimProcessor
58 /**
59 Work around a bug in gpsim: the directory in a filename is recorded twice, e.g.
60 "/home/david/afile.asm" is recorded as "/home/david//home/david/afile.asm". This
61 function will remove the duplicated directory path (by searching for a "//").
62 */
sanitizeGpsimFile(QString file)63 QString sanitizeGpsimFile( QString file )
64 {
65 int pos = file.indexOf("//");
66 if ( pos != -1 )
67 {
68 file.remove( 0, pos + 1 );
69 }
70 return file;
71 }
72
73
GpsimProcessor(QString symbolFile,QObject * parent)74 GpsimProcessor::GpsimProcessor( QString symbolFile, QObject *parent )
75 : QObject(parent),
76 m_symbolFile(symbolFile)
77 {
78 if (!bDoneGpsimInit)
79 {
80 initialize_gpsim_core();
81 initialization_is_complete();
82
83 bDoneGpsimInit = true;
84 }
85
86 m_bCanExecuteNextCycle = true;
87 m_bIsRunning = false;
88 m_pPicProcessor = nullptr;
89 m_codLoadStatus = CodUnknown;
90 m_pRegisterMemory = nullptr;
91 m_debugMode = GpsimDebugger::AsmDebugger;
92 m_pDebugger[0] = m_pDebugger[1] = nullptr;
93
94 Processor * tempProcessor = nullptr;
95 const char * fileName = symbolFile.toAscii();
96
97 #ifdef GPSIM_0_21_4
98 qDebug() << "GPSIM_0_21_4 GpsimProcessor " << fileName;
99 switch ( (cod_errors)load_symbol_file( &tempProcessor, fileName ) )
100 {
101 case COD_SUCCESS:
102 m_codLoadStatus = CodSuccess;
103 break;
104 case COD_FILE_NOT_FOUND:
105 m_codLoadStatus = CodFileNotFound;
106 break;
107 case COD_UNRECOGNIZED_PROCESSOR:
108 m_codLoadStatus = CodUnrecognizedProcessor;
109 break;
110 case COD_FILE_NAME_TOO_LONG:
111 m_codLoadStatus = CodFileNameTooLong;
112 break;
113 case COD_LST_NOT_FOUND:
114 m_codLoadStatus = CodLstNotFound;
115 break;
116 case COD_BAD_FILE:
117 m_codLoadStatus = CodBadFile;
118 break;
119 default:
120 m_codLoadStatus = CodUnknown;
121 }
122 #else // GPSIM_0_21_11+
123 qDebug() << "GPSIM_0_21_11+ GpsimProcessor " << fileName;
124 FILE * pFile = fopen( fileName, "r" );
125 if ( !pFile )
126 m_codLoadStatus = CodFileUnreadable;
127 else
128 m_codLoadStatus = ( ProgramFileTypeList::GetList().LoadProgramFile( & tempProcessor, fileName, pFile ) ) ? CodSuccess : CodFailure;
129 #endif
130 qDebug() << " m_codLoadStatus=" << m_codLoadStatus;
131
132 m_pPicProcessor = dynamic_cast<pic_processor*>(tempProcessor);
133
134 if ( codLoadStatus() == CodSuccess )
135 {
136 m_pRegisterMemory = new RegisterSet( m_pPicProcessor );
137 m_pDebugger[0] = new GpsimDebugger( GpsimDebugger::AsmDebugger, this );
138 m_pDebugger[1] = new GpsimDebugger( GpsimDebugger::HLLDebugger, this );
139 Simulator::self()->attachGpsimProcessor(this);
140 DebugManager::self()->registerGpsim(this);
141 }
142 }
143
144
~GpsimProcessor()145 GpsimProcessor::~GpsimProcessor()
146 {
147 if (!Simulator::isDestroyedSim()) {
148 Simulator::self()->detachGpsimProcessor(this);
149 }
150 delete m_pRegisterMemory;
151
152 if ( m_pDebugger[0] )
153 m_pDebugger[0]->deleteLater();
154 if ( m_pDebugger[1] )
155 m_pDebugger[1]->deleteLater();
156 }
157
158
displayCodLoadStatus()159 void GpsimProcessor::displayCodLoadStatus( )
160 {
161 switch (m_codLoadStatus)
162 {
163 case CodSuccess:
164 break;
165 case CodFileNotFound:
166 KMessageBox::sorry( nullptr, i18n("The cod file \"%1\" was not found.", m_symbolFile), i18n("File Not Found") );
167 break;
168 case CodUnrecognizedProcessor:
169 KMessageBox::sorry( nullptr, i18n("The processor for cod file \"%1\" is unrecognized.", m_symbolFile), i18n("Unrecognized Processor") );
170 break;
171 case CodFileNameTooLong:
172 KMessageBox::sorry( nullptr, i18n("The file name \"%1\" is too long.", m_symbolFile), i18n("Filename Too Long") );
173 break;
174 case CodLstNotFound:
175 KMessageBox::sorry( nullptr, i18n("The lst file associated with the cod file \"%1\" was not found.", m_symbolFile), i18n("LST File Not Found") );
176 break;
177 case CodBadFile:
178 KMessageBox::sorry( nullptr, i18n("The cod file \"%1\" is bad.", m_symbolFile), i18n("Bad File") );
179 break;
180 case CodFileUnreadable:
181 KMessageBox::sorry( nullptr, i18n("The cod file \"%1\" could not be read from.", m_symbolFile), i18n("Unreadable File") );
182 break;
183 case CodFailure:
184 case CodUnknown:
185 KMessageBox::sorry( nullptr, i18n("An error occurred with the cod file \"%1\".", m_symbolFile), i18n("Error") );
186 break;
187 }
188 }
189
190
programMemorySize() const191 unsigned GpsimProcessor::programMemorySize() const
192 {
193 return m_pPicProcessor->program_memory_size();
194 }
195
196
sourceFileList()197 QStringList GpsimProcessor::sourceFileList()
198 {
199 QStringList files;
200
201 // Work around nasty bug in gpsim 0.21.4 where nsrc_files value might be used uninitiazed
202 int max = m_pPicProcessor->files.nsrc_files();
203 #ifdef GPSIM_0_21_4
204 if ( max > 10 )
205 max = 10;
206 #endif
207
208 for ( int i = 0; i < max; ++i )
209 {
210 if ( !m_pPicProcessor->files[i] )
211 continue;
212
213 files << sanitizeGpsimFile( m_pPicProcessor->files[i]->name().c_str() );
214 }
215
216 return files;
217 }
218
219
emitLineReached()220 void GpsimProcessor::emitLineReached()
221 {
222 m_pDebugger[0]->emitLineReached();
223 m_pDebugger[1]->emitLineReached();
224 }
225
226
setRunning(bool run)227 void GpsimProcessor::setRunning( bool run )
228 {
229 if ( m_bIsRunning == run )
230 return;
231
232 m_bIsRunning = run;
233 emit runningStatusChanged(run);
234 }
235
236
executeNext()237 void GpsimProcessor::executeNext()
238 {
239 if ( !m_bIsRunning )
240 return;
241
242 if ( !m_bCanExecuteNextCycle )
243 {
244 m_bCanExecuteNextCycle = true;
245 return;
246 }
247
248 unsigned long long beforeExecuteCount = get_cycles().get();
249
250 if(get_bp().have_interrupt())
251 {
252 m_pPicProcessor->interrupt();
253 }
254 else
255 {
256 m_pPicProcessor->step_one(false); // Don't know what the false is for; gpsim ignores its value anyway
257
258 // Some instructions take more than one cycle to execute, so ignore next cycle if this was the case
259 if ( (get_cycles().get() - beforeExecuteCount) > 1 )
260 m_bCanExecuteNextCycle = false;
261 }
262
263 currentDebugger()->checkForBreak();
264
265 // Let's also update the values of RegisterInfo every 25 milliseconds
266 if ( (beforeExecuteCount % 10000) == 0 )
267 registerMemory()->update();
268 }
269
270
reset()271 void GpsimProcessor::reset()
272 {
273 bool wasRunning = isRunning();
274 m_pPicProcessor->reset(SIM_RESET);
275 setRunning(false);
276 if (!wasRunning)
277 {
278 // If we weren't running before, then the next signal won't have been emitted
279 emitLineReached();
280 }
281 }
282
283
microInfo() const284 MicroInfo * GpsimProcessor::microInfo( ) const
285 {
286 if ( !m_pPicProcessor ){
287 qWarning() << Q_FUNC_INFO << " m_pPicProcessor == nullptr" << endl;
288 return nullptr;
289 }
290
291 return MicroLibrary::self()->microInfoWithID( m_pPicProcessor->name().c_str() );
292 }
293
294
operandRegister(unsigned address)295 int GpsimProcessor::operandRegister( unsigned address )
296 {
297 instruction * ins = m_pPicProcessor->program_memory[ address ];
298 if ( Register_op * reg = dynamic_cast<Register_op*>(ins) )
299 return reg->register_address;
300 return -1;
301 }
302
303
operandLiteral(unsigned address)304 int GpsimProcessor::operandLiteral( unsigned address )
305 {
306 instruction * ins = m_pPicProcessor->program_memory[ address ];
307 if ( Literal_op * lit = dynamic_cast<Literal_op*>(ins) )
308 return lit->L;
309 return -1;
310 }
311
312
isValidProgramFile(const QString & programFile)313 GpsimProcessor::ProgramFileValidity GpsimProcessor::isValidProgramFile( const QString & programFile )
314 {
315 if ( !QFile::exists(programFile) )
316 return DoesntExist;
317
318 QString extension = programFile.right( programFile.length() - programFile.lastIndexOf('.') - 1 ).toLower();
319
320 if ( extension == "flowcode" ||
321 extension == "asm" ||
322 extension == "cod" ||
323 extension == "basic" || extension == "microbe" ||
324 extension == "c" )
325 return Valid;
326
327 if ( extension == "hex" && QFile::exists( QString(programFile).replace(".hex",".cod") ) )
328 return Valid;
329
330 return IncorrectType;
331 }
332
333
generateSymbolFile(const QString & fileName,QObject * receiver,const char * successMember,const char * failMember)334 QString GpsimProcessor::generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember )
335 {
336 qDebug() << Q_FUNC_INFO << "fileName=" << fileName ;
337 if (isValidProgramFile(fileName) != GpsimProcessor::Valid) {
338 qDebug() << Q_FUNC_INFO << "not valid program file";
339 return QString::null;
340 }
341
342 QString extension = fileName.right( fileName.length() - fileName.lastIndexOf('.') - 1 ).toLower();
343
344 if ( extension == "cod" )
345 {
346 QTimer::singleShot( 0, receiver, successMember );
347 return fileName;
348 }
349 if ( extension == "hex" )
350 {
351 QTimer::singleShot( 0, receiver, successMember );
352 // We've already checked for the existance of the ".cod" file in GpsimProcessor::isValidProgramFile
353 return QString(fileName).replace(".hex",".cod");
354 }
355
356 else if ( extension == "basic" || extension == "microbe" )
357 {
358 compileMicrobe( fileName, receiver, successMember, failMember );
359 return QString(fileName).replace( "."+extension, ".cod" );
360 }
361 else if ( extension == "flowcode" )
362 {
363 QTemporaryFile tmpFile(QDir::tempPath() + QLatin1String("/ktechlab_XXXXXX.hex"));
364 if (!tmpFile.open()) {
365 qWarning() << " failed to open " << tmpFile.fileName() << " error " << tmpFile.errorString();
366 return QString::null;
367 }
368 const QString hexFile = tmpFile.fileName();
369 ProcessOptions o;
370 o.b_addToProject = false;
371 o.setTargetFile( hexFile );
372 o.setInputFiles( QStringList(fileName) );
373 o.setMethod( ProcessOptions::Method::Forget );
374 o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_Program );
375
376 ProcessChain * pc = LanguageManager::self()->compile(o);
377 if (receiver)
378 {
379 if (successMember)
380 connect( pc, SIGNAL(successful()), receiver, successMember );
381 if (failMember)
382 connect( pc, SIGNAL(failed()), receiver, failMember );
383 }
384
385 return QString(hexFile).replace( ".hex", ".cod" );
386 }
387 else if ( extension == "asm" )
388 {
389 ProcessOptions o;
390 o.b_addToProject = false;
391 o.setTargetFile( QString(fileName).replace(".asm",".hex"));
392 o.setInputFiles(QStringList(fileName));
393 o.setMethod( ProcessOptions::Method::Forget );
394 o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(fileName), ProcessOptions::ProcessPath::Program ) );
395
396 ProcessChain *pc = LanguageManager::self()->compile(o);
397 if (receiver)
398 {
399 if (successMember)
400 connect( pc, SIGNAL(successful()), receiver, successMember );
401 if (failMember)
402 connect( pc, SIGNAL(failed()), receiver, failMember );
403 }
404
405 return QString(fileName).replace(".asm",".cod");
406 }
407 else if ( extension == "c" )
408 {
409 ProcessOptions o;
410 o.b_addToProject = false;
411 o.setTargetFile( QString(fileName).replace(".c",".hex"));
412 o.setInputFiles(QStringList(fileName));
413 o.setMethod( ProcessOptions::Method::Forget );
414 o.setProcessPath( ProcessOptions::ProcessPath::C_Program );
415
416 ProcessChain *pc = LanguageManager::self()->compile(o);
417 if (receiver)
418 {
419 if (successMember)
420 connect( pc, SIGNAL(successful()), receiver, successMember );
421 if (failMember)
422 connect( pc, SIGNAL(failed()), receiver, failMember );
423 }
424
425 return QString(fileName).replace(".c",".cod");
426 }
427
428 if ( failMember )
429 QTimer::singleShot( 0, receiver, failMember );
430 return QString::null;
431 }
432
433
compileMicrobe(const QString & filename,QObject * receiver,const char * successMember,const char * failMember)434 void GpsimProcessor::compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember )
435 {
436 ProcessOptions o;
437 o.b_addToProject = false;
438 o.setTargetFile( QString(filename).replace(".microbe",".hex") );
439 o.setInputFiles(QStringList(filename));
440 o.setMethod( ProcessOptions::Method::Forget );
441 o.setProcessPath( ProcessOptions::ProcessPath::Microbe_Program );
442 ProcessChain * pc = LanguageManager::self()->compile(o);
443 if (receiver)
444 {
445 if (successMember)
446 connect( pc, SIGNAL(successful()), receiver, successMember );
447 if (failMember)
448 connect( pc, SIGNAL(failed()), receiver, failMember );
449 }
450 }
451 //END class GpsimProcessor
452
453
454
455 //BEGIN class GpsimDebugger
GpsimDebugger(Type type,GpsimProcessor * gpsim)456 GpsimDebugger::GpsimDebugger( Type type, GpsimProcessor * gpsim )
457 : QObject()
458 {
459 m_pGpsim = gpsim;
460 m_type = type;
461 m_pBreakFromOldLine = nullptr;
462 m_addressToLineMap = nullptr;
463 m_stackLevelLowerBreak = -1;
464 m_addressSize = 0;
465
466 connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(gpsimRunningStatusChanged(bool )) );
467
468 if ( type == HLLDebugger )
469 {
470 const QStringList sourceFileList = m_pGpsim->sourceFileList();
471 QStringList::const_iterator sflEnd = sourceFileList.end();
472 for ( QStringList::const_iterator it = sourceFileList.begin(); it != sflEnd; ++it )
473 {
474 AsmParser p(*it);
475 p.parse(this);
476 }
477 }
478
479 initAddressToLineMap();
480 }
481
482
~GpsimDebugger()483 GpsimDebugger::~GpsimDebugger()
484 {
485 QList<DebugLine*> debugLinesToDelete;
486
487 for ( unsigned i = 0; i < m_addressSize; ++i )
488 {
489 DebugLine * dl = m_addressToLineMap[i];
490 if ( !dl || dl->markedAsDeleted() )
491 continue;
492
493 dl->markAsDeleted();
494 debugLinesToDelete += dl;
495 }
496
497 const QList<DebugLine*>::iterator end = debugLinesToDelete.end();
498 for ( QList<DebugLine*>::iterator it = debugLinesToDelete.begin(); it != end; ++it )
499 delete *it;
500
501 delete [] m_addressToLineMap;
502 }
503
504
gpsimRunningStatusChanged(bool isRunning)505 void GpsimDebugger::gpsimRunningStatusChanged( bool isRunning )
506 {
507 if (!isRunning)
508 {
509 m_stackLevelLowerBreak = -1;
510 m_pBreakFromOldLine = nullptr;
511 emitLineReached();
512 }
513 }
514
515
associateLine(const QString & sourceFile,int sourceLine,const QString & assemblyFile,int assemblyLine)516 void GpsimDebugger::associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine )
517 {
518 if ( assemblyLine < 0 || sourceLine < 0 )
519 {
520 qWarning() << Q_FUNC_INFO << "Invalid lines: assemblyLine="<<assemblyLine<<" sourceLine="<<sourceLine<<endl;
521 return;
522 }
523
524 SourceLine hllSource = SourceLine( sourceFile, sourceLine );
525 SourceLine asmSource = SourceLine( assemblyFile, assemblyLine );
526
527 if ( m_sourceLineMap.contains(asmSource) )
528 {
529 qWarning() << Q_FUNC_INFO << "Already have an association for assembly (\""<<assemblyFile<<"\","<<assemblyLine<<")"<<endl;
530 return;
531 }
532
533 m_sourceLineMap[asmSource] = hllSource;
534 }
535
536
initAddressToLineMap()537 void GpsimDebugger::initAddressToLineMap()
538 {
539 m_addressSize = m_pGpsim->programMemorySize();
540
541 delete [] m_addressToLineMap;
542 m_addressToLineMap = new DebugLine*[m_addressSize];
543 memset( m_addressToLineMap, 0, m_addressSize * sizeof(DebugLine*) );
544
545 if ( m_type == AsmDebugger )
546 {
547 for ( unsigned i = 0; i < m_addressSize; ++i )
548 {
549 int line = m_pGpsim->picProcessor()->pma->get_src_line(i) - 1;
550 int fileID = m_pGpsim->picProcessor()->pma->get_file_id(i);
551 FileContext * fileContext = m_pGpsim->picProcessor()->files[fileID];
552
553 if (fileContext)
554 m_addressToLineMap[i] = new DebugLine( sanitizeGpsimFile( fileContext->name().c_str() ), line );
555 }
556 }
557 else
558 {
559 SourceLineMap::const_iterator slmEnd = m_sourceLineMap.end();
560 for ( SourceLineMap::const_iterator it = m_sourceLineMap.begin(); it != slmEnd; ++it )
561 {
562 SourceLineMap::const_iterator next = it;
563 ++next;
564
565 int asmToLine = ((next == slmEnd) || (next.key().fileName() != it.key().fileName())) ? -1 : next.key().line() - 1;
566
567 QString asmFile = it.key().fileName();
568 int asmFromLine = it.key().line();
569 SourceLine sourceLine = it.value();
570
571
572 std::string stdAsmFile( asmFile.toAscii() );
573 int fileID = m_pGpsim->picProcessor()->files.Find( stdAsmFile );
574 if ( fileID == -1 )
575 {
576 qWarning() << Q_FUNC_INFO << "Could not find FileContext (asmFile=\""<<asmFile<<"\")"<<endl;
577 continue;
578 }
579
580 if ( asmToLine == -1 )
581 asmToLine = m_pGpsim->picProcessor()->files[fileID]->max_line() - 2;
582
583 if ( (asmFromLine < 0) || (asmToLine < asmFromLine) )
584 {
585 qWarning() << Q_FUNC_INFO << "Invalid lines: asmFromLine="<<asmFromLine<<" asmToLine="<<asmToLine<<endl;
586 continue;
587 }
588
589 DebugLine * debugLine = new DebugLine( sourceLine.fileName(), sourceLine.line() );
590 bool used = false;
591
592 for ( int i = asmFromLine; i <= asmToLine; ++i )
593 {
594 #ifdef GPSIM_0_21_4
595 int address = m_pGpsim->picProcessor()->pma->find_address_from_line( fileID, i+1 );
596 #else // GPSIM_0_21_11
597 int address = m_pGpsim->picProcessor()->pma->find_address_from_line( m_pGpsim->picProcessor()->files[fileID], i+1 );
598 #endif
599 if ( address != -1 )
600 {
601 used = true;
602 m_addressToLineMap[address] = debugLine;
603 }
604 }
605
606 if (!used)
607 delete debugLine;
608 }
609 }
610 }
611
612
setBreakpoints(const QString & path,const IntList & lines)613 void GpsimDebugger::setBreakpoints( const QString & path, const IntList & lines )
614 {
615 for ( unsigned i = 0; i < m_addressSize; i++ )
616 {
617 DebugLine * dl = m_addressToLineMap[i];
618 if ( !dl || dl->fileName() != path )
619 continue;
620
621 dl->setBreakpoint( lines.contains( dl->line() ) );
622 }
623 }
624
625
setBreakpoint(const QString & path,int line,bool isBreakpoint)626 void GpsimDebugger::setBreakpoint( const QString & path, int line, bool isBreakpoint )
627 {
628 for ( unsigned i = 0; i < m_addressSize; i++ )
629 {
630 if ( !m_addressToLineMap[i] )
631 continue;
632
633 if ( (m_addressToLineMap[i]->fileName() == path) &&
634 ( line == m_addressToLineMap[i]->line() ) )
635 m_addressToLineMap[i]->setBreakpoint(isBreakpoint);
636 }
637 }
638
639
currentDebugLine()640 DebugLine * GpsimDebugger::currentDebugLine()
641 {
642 return m_addressToLineMap[ m_pGpsim->picProcessor()->pc->get_value() ];
643 }
644
645
currentLine()646 SourceLine GpsimDebugger::currentLine()
647 {
648 DebugLine * dl = currentDebugLine();
649 return dl ? *dl : SourceLine();
650 }
651
652
emitLineReached()653 void GpsimDebugger::emitLineReached()
654 {
655 SourceLine currentAt = currentLine();
656
657 if ( currentAt == m_previousAtLineEmit )
658 return;
659
660 m_previousAtLineEmit = currentAt;
661 m_pGpsim->registerMemory()->update();
662 emit lineReached(currentAt);
663 }
664
665
checkForBreak()666 void GpsimDebugger::checkForBreak()
667 {
668 DebugLine * currentLine = m_addressToLineMap[ m_pGpsim->picProcessor()->pc->get_value() ];
669 int currentStackLevel = int( m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask );
670
671 bool ontoNextLine = m_pBreakFromOldLine != currentLine;
672 bool lineBreakpoint = currentLine ? currentLine->isBreakpoint() : false;
673 bool stackBreakpoint = m_stackLevelLowerBreak >= currentStackLevel;
674
675 if ( ontoNextLine && (lineBreakpoint || stackBreakpoint) )
676 m_pGpsim->setRunning(false);
677 }
678
679
programAddress(const QString & path,int line)680 int GpsimDebugger::programAddress( const QString & path, int line )
681 {
682 for ( unsigned i = 0; i < m_addressSize; ++i )
683 {
684 DebugLine * dl = m_addressToLineMap[i];
685 if ( !dl || (dl->line() != line) || (dl->fileName() != path) )
686 continue;
687
688 return i;
689 }
690
691 return -1;
692 }
693
694
stepInto()695 void GpsimDebugger::stepInto()
696 {
697 // I'm not aware of the stack being able to increase in size by more than
698 // one at a time, so "1" should suffice here...but to be on the safe side,
699 // make it a nice large number
700 stackStep( 1 << 16 );
701 }
stepOver()702 void GpsimDebugger::stepOver()
703 {
704 stackStep(0);
705 }
stepOut()706 void GpsimDebugger::stepOut()
707 {
708 stackStep(-1);
709 }
stackStep(int dl)710 void GpsimDebugger::stackStep( int dl )
711 {
712 if ( m_pGpsim->isRunning() )
713 return;
714
715 int initialStack = (m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask) + dl;
716 DebugLine * initialLine = currentDebugLine();
717
718 if ( initialStack < 0 )
719 initialStack = 0;
720
721 // Reset any previous stackStep, and step
722 m_pBreakFromOldLine = nullptr;
723 m_stackLevelLowerBreak = -1;
724 m_pGpsim->picProcessor()->step_one(false);
725
726 int currentStack = m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask;
727 DebugLine * currentLine = currentDebugLine();
728
729 if ( (initialStack >= currentStack) && (initialLine != currentLine) )
730 emitLineReached();
731
732 else
733 {
734 // Looks like we stepped into something or haven't gone onto the next
735 // instruction, wait until we step back out....
736 m_stackLevelLowerBreak = initialStack;
737 m_pBreakFromOldLine = initialLine;
738 m_pGpsim->setRunning(true);
739 }
740 }
741 //END class Debugger
742
743
744
745 //BEGIN class RegisterSet
RegisterSet(pic_processor * picProcessor)746 RegisterSet::RegisterSet( pic_processor * picProcessor )
747 {
748 unsigned numRegisters = picProcessor->rma.get_size();
749 qDebug() << Q_FUNC_INFO << "numRegisters="<<numRegisters<<endl;
750 m_registers.resize( numRegisters /*, nullptr - 2018.06.02 - initialized below */ );
751 for ( unsigned i = 0; i < numRegisters; ++i )
752 {
753 RegisterInfo * info = new RegisterInfo( & picProcessor->rma[i] );
754 m_registers[i] = info;
755 m_nameToRegisterMap[ info->name() ] = info;
756 qDebug() << Q_FUNC_INFO << " add register info " << info->name() << " at pos " << i << " addr " << info;
757 }
758 #if defined(HAVE_GPSIM_0_26)
759 RegisterInfo * info = new RegisterInfo( picProcessor->Wreg ); // is tihs correct for "W" member? TODO
760 #else
761 RegisterInfo * info = new RegisterInfo( picProcessor->W );
762 #endif
763 m_registers.append( info );
764 m_nameToRegisterMap[ info->name() ] = info;
765 qDebug() << Q_FUNC_INFO << " add register info " << info->name() << " at end, addr " << info;
766 qDebug() << Q_FUNC_INFO << " registers.size " << m_registers.size() << " ; numRegisters " << numRegisters;
767 }
768
769
~RegisterSet()770 RegisterSet::~RegisterSet()
771 {
772 for ( unsigned i = 0; i < m_registers.size(); ++i )
773 delete m_registers[i];
774 }
775
776
fromAddress(unsigned address)777 RegisterInfo * RegisterSet::fromAddress( unsigned address )
778 {
779 return (address < m_registers.size()) ? m_registers[address] : nullptr;
780 }
781
782
fromName(const QString & name)783 RegisterInfo * RegisterSet::fromName( const QString & name )
784 {
785 // First try the name as case sensitive, then as case insensitive.
786 if ( m_nameToRegisterMap.contains( name ) )
787 return m_nameToRegisterMap[ name ];
788
789 QString nameLower = name.toLower();
790
791 RegisterInfoMap::iterator end = m_nameToRegisterMap.end();
792 for ( RegisterInfoMap::iterator it = m_nameToRegisterMap.begin(); it != end; ++ it )
793 {
794 if ( it.key().toLower() == nameLower )
795 return it.value();
796 }
797
798 return nullptr;
799 }
800
801
update()802 void RegisterSet::update()
803 {
804 for ( unsigned i = 0; i < m_registers.size(); ++i )
805 m_registers[i]->update();
806 }
807 //END class RegisterSet
808
809
810
811 //BEGIN class RegisterInfo
RegisterInfo(Register * reg)812 RegisterInfo::RegisterInfo( Register * reg )
813 {
814 assert(reg);
815 m_pRegister = reg;
816 m_type = Invalid;
817 m_prevEmitValue = 0;
818
819 switch ( m_pRegister->isa() )
820 {
821 case Register::GENERIC_REGISTER:
822 m_type = Generic;
823 break;
824 case Register::FILE_REGISTER:
825 m_type = File;
826 break;
827 case Register::SFR_REGISTER:
828 m_type = SFR;
829 break;
830 case Register::BP_REGISTER:
831 m_type = Breakpoint;
832 break;
833 case Register::INVALID_REGISTER:
834 m_type = Invalid;
835 break;
836 }
837
838 m_name = QString::fromLatin1(m_pRegister->baseName().c_str());
839 }
840
841
value() const842 unsigned RegisterInfo::value() const
843 {
844 return m_pRegister->value.data;
845 }
846
847
update()848 void RegisterInfo::update()
849 {
850 unsigned newValue = value();
851 if ( newValue != m_prevEmitValue )
852 {
853 m_prevEmitValue = newValue;
854 emit valueChanged(newValue);
855 }
856 }
857
858
toString(RegisterType type)859 QString RegisterInfo::toString( RegisterType type )
860 {
861 switch ( type )
862 {
863 case Generic:
864 return i18n("Generic");
865
866 case File:
867 return i18n("File");
868
869 case SFR:
870 return i18n("SFR");
871
872 case Breakpoint:
873 return i18n("Breakpoint");
874
875 case Invalid:
876 return i18n("Invalid");
877 }
878
879 return i18n("Unknown");
880 }
881 //END class RegisterInfo
882
883
884
885 //BEGIN class DebugLine
DebugLine(const QString & fileName,int line)886 DebugLine::DebugLine( const QString & fileName, int line )
887 : SourceLine( fileName, line )
888 {
889 m_bIsBreakpoint = false;
890 m_bMarkedAsDeleted = false;
891 }
892
893
DebugLine()894 DebugLine::DebugLine()
895 : SourceLine()
896 {
897 m_bIsBreakpoint = false;
898 m_bMarkedAsDeleted = false;
899 }
900 //END class DebugLine
901
902 #endif
903