1 /*
2    Copyright (C) 1998-2003 T. Scott Dattalo
3 
4 This file is part of the libgpsim library of gpsim
5 
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10 
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, see
18 <http://www.gnu.org/licenses/lgpl-2.1.html>.
19 */
20 
21 /*
22   stuff that needs to be fixed:
23 
24   Register aliasing
25   The "invalid instruction" in program memory.
26 
27 */
28 
29 #include <stdio.h>
30 #ifdef _WIN32
31 #include "uxtime.h"
32 #endif
33 
34 #include <algorithm>
35 #include <cctype>
36 #include <iostream>
37 #include <iomanip>
38 #include <string>
39 #include <sstream>
40 #include <cstdio>
41 
42 #include "../config.h"
43 
44 
45 #include "gpsim_def.h"
46 #include <glib.h>
47 
48 #include "ValueCollections.h"
49 #include "gpsim_classes.h"
50 #include "gpsim_time.h"
51 #include "interface.h"
52 #include "modules.h"
53 #include "processor.h"
54 #include "pic-processor.h"
55 #include "trace.h"
56 #include "ui.h"
57 #include "xref.h"
58 
59 #include "attributes.h"
60 
61 #include "fopen-path.h"
62 #include "cmd_gpsim.h"
63 #include "sim_context.h"
64 
65 #include "clock_phase.h"
66 
67 #include "14bit-registers.h"
68 
69 #include <typeinfo>
70 
71 #define STR_HELPER(x) #x
72 #define STR(x) STR_HELPER(x)
73 
74 //#define DEBUG
75 #if defined(DEBUG)
76 #define Dprintf(arg) {printf("%s:%d-%s() ",__FILE__,__LINE__,__FUNCTION__); printf arg; }
77 #else
78 #define Dprintf(arg) {}
79 #endif
80 
81 //------------------------------------------------------------------------
82 // active_cpu  is a pointer to the pic processor that is currently 'active'.
83 // 'active' means that it's the one currently being simulated or the one
84 // currently being manipulated by the user (e.g. register dumps, break settings)
85 
86 Processor *active_cpu;
87 
88 // create instances of inline get_active_cpu() and set_active_cpu() methods
89 // by taking theirs address
90 Processor *(*dummy_get_active_cpu)(void) = get_active_cpu;
91 void (*dummy_set_active_cpu)(Processor *act_cpu) = set_active_cpu;
92 
93 static char pkg_version[] = PACKAGE_VERSION;
94 
95 class CPU_Freq : public Float {
96 public:
97   CPU_Freq(Processor * _cpu, double freq); //const char *_name, double newValue, const char *desc);
98 
99   virtual void set(double d);
100   void set_rc_freq(double d);
101   virtual void get(double &);
set_rc_active(bool _use_rc_freq)102   void set_rc_active(bool _use_rc_freq)
103   {
104     use_rc_freq = _use_rc_freq;
105   }
106 
107 private:
108   Processor * cpu;
109   double 	RCfreq;
110   bool		use_rc_freq;
111 };
112 
113 
CPU_Freq(Processor * _cpu,double freq)114 CPU_Freq::CPU_Freq(Processor * _cpu, double freq)
115   : Float("frequency", freq, " oscillator frequency."),
116     cpu(_cpu), RCfreq(0.0), use_rc_freq(false)
117 {
118 }
119 
120 
set_rc_freq(double d)121 void CPU_Freq::set_rc_freq(double d)
122 {
123   RCfreq = d;
124 }
125 
126 
get(double & d)127 void CPU_Freq::get(double &d)
128 {
129   if (use_rc_freq) {
130     d = RCfreq;
131 
132   } else {
133     double x;
134     Float::get(x);
135     d = x;
136   }
137 }
138 
139 
set(double d)140 void CPU_Freq::set(double d)
141 {
142   pic_processor *pCpu = dynamic_cast<pic_processor *>(cpu);
143   Float::set(d);
144 
145   if (cpu) {
146     cpu->update_cps();
147   }
148 
149   if (pCpu) {
150     pCpu->wdt.update();
151   }
152 }
153 
154 
CPU_Vdd(Processor * _cpu,double vdd)155 CPU_Vdd::CPU_Vdd(Processor * _cpu, double vdd)
156   : Float("Vdd", vdd, "Processor supply voltage"),
157     cpu(_cpu)
158 {
159 }
160 
161 
set(double d)162 void CPU_Vdd::set(double d)
163 {
164   Float::set(d);
165 
166   if (cpu) {
167     cpu->update_vdd();
168   }
169 }
170 
171 
172 //------------------------------------------------------------------------
173 //
174 // Processor - Constructor
175 //
176 
Processor(const char * _name,const char * _desc)177 Processor::Processor(const char *_name, const char *_desc)
178   : Module(_name, _desc),
179     pma(nullptr),
180     rma(this),
181     ema(this),
182     pc(nullptr),
183     bad_instruction(0, 0x3fff, 0),
184     mFrequency(nullptr)
185 {
186   registers = nullptr;
187   m_pConstructorObject = nullptr;
188   m_Capabilities = 0;
189   m_ProgramMemoryAllocationSize = 0;
190 
191   if (verbose) {
192     std::cout << "processor constructor\n";
193   }
194 
195   addSymbol(mFrequency = new CPU_Freq(this, 20e6));
196   set_ClockCycles_per_Instruction(4);
197   update_cps();
198   setWarnMode(true);
199   setSafeMode(true);
200   setUnknownMode(true);
201   setBreakOnReset(true);
202   // derived classes need to override these values
203   m_uPageMask    = 0x00;
204   m_uAddrMask    = 0xff;
205   readTT = nullptr;
206   writeTT = nullptr;
207   interface = new ProcessorInterface(this);
208   // let the processor version number simply be gpsim's version number.
209   version = &pkg_version[0];
210   get_trace().cycle_counter(get_cycles().get());
211   addSymbol(m_pWarnMode = new WarnModeAttribute(this));
212   addSymbol(m_pSafeMode = new SafeModeAttribute(this));
213   addSymbol(m_pUnknownMode = new UnknownModeAttribute(this));
214   addSymbol(m_pBreakOnReset = new BreakOnResetAttribute(this));
215   m_vdd = new CPU_Vdd(this, 5.0);
216   addSymbol(m_vdd);
217   m_pbBreakOnInvalidRegisterRead = new Boolean("BreakOnInvalidRegisterRead",
218       true, "Halt simulation when an invalid register is read from.");
219   addSymbol(m_pbBreakOnInvalidRegisterRead);
220   m_pbBreakOnInvalidRegisterWrite = new Boolean("BreakOnInvalidRegisterWrite",
221       true, "Halt simulation when an invalid register is written to.");
222   addSymbol(m_pbBreakOnInvalidRegisterWrite);
223   set_Vdd(5.0);
224 }
225 
226 
227 //-------------------------------------------------------------------
~Processor()228 Processor::~Processor()
229 {
230   deleteSymbol(m_pbBreakOnInvalidRegisterRead);
231   deleteSymbol(m_pbBreakOnInvalidRegisterWrite);
232   deleteSymbol(m_pWarnMode);
233   deleteSymbol(m_pSafeMode);
234   deleteSymbol(m_pUnknownMode);
235   deleteSymbol(m_pBreakOnReset);
236   deleteSymbol(mFrequency);
237   deleteSymbol(m_vdd);
238   delete interface;
239   delete_invalid_registers();
240   delete m_UiAccessOfRegisters;
241   delete []registers;
242   delete readTT;
243   delete writeTT;
244   destroyProgramMemoryAccess(pma);
245 
246   for (unsigned int i = 0; i < m_ProgramMemoryAllocationSize; i++) {
247     if (program_memory[i] != &bad_instruction) {
248       delete program_memory[i];
249     }
250   }
251 
252   delete []program_memory;
253 }
254 
255 
GetCapabilities()256 unsigned long Processor::GetCapabilities()
257 {
258   return m_Capabilities;
259 }
260 
261 
262 //-------------------------------------------------------------------
263 // Simulation modes:
setWarnMode(bool newWarnMode)264 void Processor::setWarnMode(bool newWarnMode)
265 {
266   bWarnMode = newWarnMode;
267 }
268 
269 
setSafeMode(bool newSafeMode)270 void Processor::setSafeMode(bool newSafeMode)
271 {
272   bSafeMode = newSafeMode;
273 }
274 
275 
setUnknownMode(bool newUnknownMode)276 void Processor::setUnknownMode(bool newUnknownMode)
277 {
278   bUnknownMode = newUnknownMode;
279 }
280 
281 
setBreakOnReset(bool newBreakOnReset)282 void Processor::setBreakOnReset(bool newBreakOnReset)
283 {
284   bBreakOnReset = newBreakOnReset;
285 }
286 
287 
288 //------------------------------------------------------------------------
289 // Attributes
290 
291 
set_RCfreq_active(bool state)292 void Processor::set_RCfreq_active(bool state)
293 {
294   if (mFrequency) {
295     mFrequency->set_rc_active(state);
296   }
297 
298   update_cps();
299 }
300 
301 
set_frequency(double f)302 void Processor::set_frequency(double f)
303 {
304   if (mFrequency) {
305     mFrequency->set(f);
306   }
307 
308   update_cps();
309 }
310 
311 
set_frequency_rc(double f)312 void Processor::set_frequency_rc(double f)
313 {
314   if (mFrequency) {
315     mFrequency->set_rc_freq(f);
316   }
317 
318   update_cps();
319 }
320 
321 
get_frequency()322 double Processor::get_frequency()
323 {
324   double d = 0.0;
325 
326   if (mFrequency) {
327     mFrequency->get(d);
328   }
329 
330   return d;
331 }
332 
333 
update_cps()334 void Processor::update_cps()
335 {
336   get_cycles().set_instruction_cps((guint64)(get_frequency() / clocks_per_inst));
337 }
338 
339 
get_OSCperiod()340 double  Processor::get_OSCperiod()
341 {
342   double f = get_frequency();
343 
344   if (f > 0.0) {
345     return 1.0 / f;
346 
347   } else {
348     return 0.0;
349   }
350 }
351 
352 
353 /*
354 void Processor::set(const char *cP,int len)
355 {
356 
357 }
358 
359 void Processor::get(char *cP, int len)
360 {
361   cP[0] = 0;
362 }
363 */
364 //-------------------------------------------------------------------
365 //
366 // init_register_memory (unsigned int memory_size)
367 //
368 // Allocate an array for holding register objects.
369 //
370 
init_register_memory(unsigned int memory_size)371 void Processor::init_register_memory(unsigned int memory_size)
372 {
373   if (verbose) {
374     std::cout << __FUNCTION__ << " memory size: " << memory_size << '\n';
375   }
376 
377   registers = new Register *[memory_size];
378   m_UiAccessOfRegisters = new RegisterCollection(this,
379       "ramData",
380       registers,
381       memory_size);
382   // For processors with banked memory, the register_bank corresponds to the
383   // active bank. Let this point to the beginning of the register array for
384   // now.
385   register_bank = registers;
386   rma.set_Registers(registers, memory_size);
387   // Make all of the file registers 'undefined' (each processor derived from this base
388   // class defines its own register mapping).
389   std::fill_n(registers, memory_size, nullptr);
390 }
391 
392 
393 //-------------------------------------------------------------------
394 //
395 //
396 // create_invalid_registers
397 //
398 //   The purpose of this function is to complete the initialization
399 // of the file register memory by placing an instance of an 'invalid
400 // file register' at each 'invalid' memory location. Most of PIC's
401 // do not use the entire address space available, so this routine
402 // fills the voids.
403 //
404 
create_invalid_registers()405 void Processor::create_invalid_registers()
406 {
407   unsigned int addr;
408 
409   if (verbose) {
410     std::cout << "Creating invalid registers " << register_memory_size() << '\n';
411   }
412 
413   // Now, initialize any undefined register as an 'invalid register'
414   // Note, each invalid register is given its own object. This enables
415   // the simulation code to efficiently capture any invalid register
416   // access. Furthermore, it's possible to set break points on
417   // individual invalid file registers. By default, gpsim halts whenever
418   // there is an invalid file register access.
419 
420   for (addr = 0; addr < register_memory_size(); addr += map_rm_index2address(1)) {
421     unsigned int index = map_rm_address2index(addr);
422 
423     if (!registers[index]) {
424       char nameBuff[100];
425       snprintf(nameBuff, sizeof(nameBuff), "INVREG_%X", addr);
426       registers[index] = new InvalidRegister(this, nameBuff);
427       registers[index]->setAddress(addr);
428     }
429   }
430 }
431 
432 
433 //-------------------------------------------------------------------
434 //
435 // Delete invalid registers
436 //
delete_invalid_registers()437 void Processor::delete_invalid_registers()
438 {
439   unsigned int i = 0;
440 
441   for (i = 0; i < rma.get_size(); i++) {
442     // cout << __FUNCTION__ << "  reg: 0x"<<hex << i << " ptr:" << registers[i] << endl;
443     InvalidRegister *pReg = dynamic_cast<InvalidRegister *>(registers[i]);
444 
445     if (pReg) {
446       delete registers[i];
447       registers[i] = nullptr;
448 
449     } else if (registers[i]) {
450       std::cout << __FUNCTION__ << "  reg: 0x" << std::hex << i << " ptr:" << registers[i];
451       std::cout << ' ' << registers[i]->name().substr(0, 10) << '\n';
452     }
453   }
454 }
455 
456 
457 //-------------------------------------------------------------------
458 //    add_file_registers
459 //
460 //  The purpose of this member function is to allocate memory for the
461 // general purpose registers.
462 //
463 
add_file_registers(unsigned int start_address,unsigned int end_address,unsigned int alias_offset)464 void Processor::add_file_registers(unsigned int start_address, unsigned int end_address, unsigned int alias_offset)
465 {
466   unsigned int j;
467   // Initialize the General Purpose Registers:
468   Dprintf((" from 0x%x to 0x%x alias 0x%x\n", start_address, end_address, alias_offset));
469   char str[100];
470 
471   for (j = start_address; j <= end_address; j++) {
472 #ifdef DEBUG
473 
474     if (j == 0x11) {
475       printf("Processor::add_file_registers j 0x%x\n", j);
476     }
477 
478 #endif
479 
480     if (registers[j] && (registers[j]->isa() == Register::INVALID_REGISTER)) {
481       delete registers[j];
482 
483     } else if (registers[j])
484       std::cout << __FUNCTION__ << " Already register " << registers[j]->name()
485                 << " at 0x" << std::hex << j << '\n';
486 
487     //The default register name is simply its address
488     snprintf(str, sizeof(str), "REG%03X", j);
489     registers[j] = new Register(this, str);
490 
491     if (alias_offset) {
492       registers[j + alias_offset] = registers[j];
493       registers[j]->alias_mask = alias_offset;
494 
495     } else {
496       registers[j]->alias_mask = 0;
497     }
498 
499     registers[j]->setAddress(j);
500     RegisterValue rv = getWriteTT(j);
501     registers[j]->set_write_trace(rv);
502     rv = getReadTT(j);
503     registers[j]->set_read_trace(rv);
504   }
505 }
506 
507 
508 //-------------------------------------------------------------------
509 //    delete_file_registers
510 //
511 //  The purpose of this member function is to delete file registers
512 //
513 
delete_file_registers(unsigned int start_address,unsigned int end_address,bool bRemoveWithoutDelete)514 void Processor::delete_file_registers(unsigned int start_address,
515                                       unsigned int end_address,
516                                       bool bRemoveWithoutDelete)
517 {
518 #define DFR_DEBUG 0
519 
520   if (DFR_DEBUG)
521     std::cout << __FUNCTION__
522               << "  start:" << std::hex << start_address
523               << "  end:" << std::hex << end_address
524               << '\n';
525 
526   //  FIXME - this function is bogus.
527   // The aliased registers do not need to be searched for - the alias mask
528   // can tell at what addresses a register is aliased.
529 #define SMALLEST_ALIAS_DISTANCE  32
530 #define ALIAS_MASK (SMALLEST_ALIAS_DISTANCE-1)
531   unsigned int i, j;
532 
533   if (start_address != end_address) {
534     Dprintf(("from 0x%x to 0x%x\n", start_address, end_address));
535   }
536 
537   for (j = start_address; j <= end_address; j++) {
538     if (registers[j]) {
539       Register *thisReg = registers[j];
540       Register *replaced = thisReg->getReplaced();
541 
542       if (thisReg->alias_mask) {
543         // This register appears in more than one place. Let's find all
544         // of its aliases.
545         for (i = j & ALIAS_MASK; i < rma.get_size(); i += SMALLEST_ALIAS_DISTANCE)
546           if (thisReg == registers[i]) {
547             if (DFR_DEBUG) {
548               std::cout << "   removing at address:" << std::hex << i << '\n';
549             }
550 
551             registers[i] = nullptr;
552           }
553       }
554 
555       if (DFR_DEBUG) {
556         std::cout << " deleting: " << std::hex << j << '\n';
557       }
558 
559       registers[j] = nullptr;
560 
561       if (!bRemoveWithoutDelete) {
562         delete replaced;
563         delete thisReg;
564       }
565 
566     } else {
567       printf("%s register 0x%x already deleted\n", __FUNCTION__, j);
568     }
569   }
570 }
571 
572 
573 //-------------------------------------------------------------------
574 //
575 //
576 //    alias_file_registers
577 //
578 //  The purpose of this member function is to alias the
579 // general purpose registers.
580 //
581 
alias_file_registers(unsigned int start_address,unsigned int end_address,unsigned int alias_offset)582 void Processor::alias_file_registers(unsigned int start_address, unsigned int end_address, unsigned int alias_offset)
583 {
584   unsigned int j;
585   // FIXME -- it'd probably make better sense to keep a list of register addresses at
586   // which a particular register appears.
587 #ifdef DEBUG
588 
589   if (start_address == 0x20) {
590     printf("DEBUG trace %x\n", start_address);
591   }
592 
593   if (start_address != end_address) {
594     Dprintf((" from 0x%x to 0x%x alias_offset 0x%x\n", start_address, end_address, alias_offset));
595   }
596 
597 #endif
598 
599   for (j = start_address; j <= end_address; j++) {
600     if (alias_offset && (j + alias_offset < rma.get_size())) {
601       if (registers[j + alias_offset]) {
602         if (registers[j + alias_offset] == registers[j]) {
603           printf("alias_file_register Duplicate alias %s from 0x%x to 0x%x \n", registers[j + alias_offset]->name().c_str(), j, j + alias_offset);
604 
605         } else {
606           delete registers[j + alias_offset];
607         }
608       }
609 
610       registers[j + alias_offset] = registers[j];
611 
612       if (registers[j]) {
613         registers[j]->alias_mask = alias_offset;
614       }
615     }
616   }
617 }
618 
619 
620 //-------------------------------------------------------------------
621 //
622 // init_program_memory(unsigned int memory_size)
623 //
624 // The purpose of this member function is to allocate memory for the
625 // pic's code space. The 'memory_size' parameter tells how much memory
626 // is to be allocated
627 //
628 //  The following is not correct for 18f2455 and 18f4455 processors
629 //  so test has been disabled (RRR)
630 //
631 //  AND it should be an integer of the form of 2^n.
632 // If the memory size is not of the form of 2^n, then this routine will
633 // round up to the next integer that is of the form 2^n.
634 //
635 //   Once the memory has been allocated, this routine will initialize
636 // it with the 'bad_instruction'. The bad_instruction is an instantiation
637 // of the instruction class that chokes gpsim if it is executed. Note that
638 // each processor owns its own 'bad_instruction' object.
639 
init_program_memory(unsigned int memory_size)640 void Processor::init_program_memory(unsigned int memory_size)
641 {
642   if (verbose) {
643     std::cout << "Initializing program memory: 0x" << memory_size << " words\n";
644   }
645 
646 #ifdef RRR
647 
648   if ((memory_size - 1) & memory_size) {
649     std:: cout << "*** WARNING *** memory_size should be of the form 2^N\n";
650     memory_size = (memory_size + ~memory_size) & MAX_PROGRAM_MEMORY;
651     std::cout << "gpsim is rounding up to memory_size = " << memory_size << '\n';
652   }
653 
654 #endif
655   // Initialize 'program_memory'. 'program_memory' is a pointer to an array of
656   // pointers of type 'instruction'. This is where the simulated instructions
657   // are stored.
658   program_memory = new instruction *[memory_size];
659   m_ProgramMemoryAllocationSize = memory_size;
660   bad_instruction.set_cpu(this);
661   std::fill_n(program_memory, memory_size, &bad_instruction);
662   pma = createProgramMemoryAccess(this);
663   pma->name();
664 }
665 
666 
createProgramMemoryAccess(Processor * processor)667 ProgramMemoryAccess * Processor::createProgramMemoryAccess(Processor *processor)
668 {
669   return new ProgramMemoryAccess(processor);
670 }
671 
672 
destroyProgramMemoryAccess(ProgramMemoryAccess * pma)673 void Processor::destroyProgramMemoryAccess(ProgramMemoryAccess *pma)
674 {
675   delete pma;
676 }
677 
678 
679 //-------------------------------------------------------------------
680 // init_program_memory(int address, int value)
681 //
682 // The purpose of this member fucntion is to instantiate an Instruction
683 // object in the program memory. If the opcode is invalid, then a 'bad_instruction'
684 // is inserted into the program memory instead. If the address is beyond
685 // the program memory address space, then it may be that the 'opcode' is
686 // is in fact a configuration word.
687 //
688 
init_program_memory(unsigned int address,unsigned int value)689 void Processor::init_program_memory(unsigned int address, unsigned int value)
690 {
691   unsigned int uIndex = map_pm_address2index(address);
692 
693   if (!program_memory) {
694     const char *buf = "ERROR: internal bug " __FILE__ ":" STR(__LINE__);
695     throw FatalError(buf);
696   }
697 
698   if (uIndex < program_memory_size()) {
699     if (program_memory[uIndex] != 0 && program_memory[uIndex]->isa() != instruction::INVALID_INSTRUCTION) {
700       // this should not happen
701       delete program_memory[uIndex];
702     }
703 
704     program_memory[uIndex] = disasm(address, value);
705 
706     if (program_memory[uIndex] == 0) {
707       program_memory[uIndex] = &bad_instruction;
708     }
709 
710     //program_memory[uIndex]->add_line_number_symbol();
711 
712   } else if (set_config_word(address, value)) {
713   } else {
714     set_out_of_range_pm(address, value);  // could be e2prom
715   }
716 }
717 
718 
719 //-------------------------------------------------------------------
720 //erase_program_memory(unsigned int address)
721 //
722 //	Checks if a program memory location contains an instruction
723 //	and deletes it if it does.
724 //
erase_program_memory(unsigned int address)725 void Processor::erase_program_memory(unsigned int address)
726 {
727   unsigned int uIndex = map_pm_address2index(address);
728 
729   if (!program_memory) {
730     const char *buf = "ERROR: internal bug " __FILE__ ":" STR(__LINE__);
731     throw FatalError(buf);
732   }
733 
734   if (uIndex < program_memory_size()) {
735     if (program_memory[uIndex] != 0 && program_memory[uIndex]->isa() != instruction::INVALID_INSTRUCTION) {
736       delete program_memory[uIndex];
737       program_memory[uIndex] = &bad_instruction;
738     }
739 
740   } else {
741     std::cout << "Erase Program memory\n";
742     std::cout << "Warning::Out of range address " << std::hex << address << '\n';
743     std::cout << "Max allowed address is 0x" << std::hex << (program_address_limit() - 1) << '\n';
744   }
745 }
746 
747 
init_program_memory_at_index(unsigned int uIndex,unsigned int value)748 void Processor::init_program_memory_at_index(unsigned int uIndex, unsigned int value)
749 {
750   init_program_memory(map_pm_index2address(uIndex), value);
751 }
752 
753 
init_program_memory_at_index(unsigned int uIndex,const unsigned char * bytes,int nBytes)754 void Processor::init_program_memory_at_index(unsigned int uIndex,
755     const unsigned char *bytes, int nBytes)
756 {
757   for (int i = 0; i < nBytes / 2; i++) {
758     init_program_memory_at_index(uIndex + i, (((unsigned int)bytes[2 * i + 1]) << 8)  | bytes[2 * i]);
759   }
760 }
761 
762 
763 //------------------------------------------------------------------
764 // Fetch the rom contents at a particular address.
get_program_memory_at_address(unsigned int address)765 unsigned int Processor::get_program_memory_at_address(unsigned int address)
766 {
767   unsigned int uIndex = map_pm_address2index(address);
768   return (uIndex < program_memory_size() && program_memory[uIndex])
769          ? program_memory[uIndex]->get_opcode()
770          : 0xffffffff;
771 }
772 
773 
774 //-------------------------------------------------------------------
775 // build_program_memory - given an array of opcodes this function
776 // will convert them into instructions and insert them into the
777 // simulated program memory.
778 //
779 
build_program_memory(unsigned int * memory,unsigned int minaddr,unsigned int maxaddr)780 void Processor::build_program_memory(unsigned int *memory,
781                                      unsigned int minaddr,
782                                      unsigned int maxaddr)
783 {
784   for (unsigned int i = minaddr; i <= maxaddr; i++)
785     if (memory[i] != 0xffffffff) {
786       init_program_memory(i, memory[i]);
787     }
788 }
789 
790 
791 //-------------------------------------------------------------------
792 /** @brief Write a word of data into memory outside flash
793  *
794  *  This method is called when loading data from the COD or HEX file
795  *  and the address is not in the program ROM or normal config space.
796  *  In this base class, there is no such memory. Real processors,
797  *  particularly those with EEPROM, will need to override this method.
798  *
799  *  @param  address Memory address to set. Byte address on 18F
800  *  @param  value   Word data to write in.
801  */
set_out_of_range_pm(unsigned int address,unsigned int value)802 void Processor::set_out_of_range_pm(unsigned int address, unsigned int value)
803 {
804   std::cout << "Warning::Out of range address " << address << " value " << value << '\n';
805   std::cout << "Max allowed address is 0x" << std::hex << (program_address_limit() - 1) << '\n';
806 }
807 
808 
809 //-------------------------------------------------------------------
810 //
811 // attach_src_line - This member function establishes the one-to-one link
812 // between instructions and the source code that create them.
813 
attach_src_line(unsigned int address,unsigned int file_id,unsigned int sline,unsigned int lst_line)814 void Processor::attach_src_line(unsigned int address,
815                                 unsigned int file_id,
816                                 unsigned int sline,
817                                 unsigned int lst_line)
818 {
819   unsigned int uIndex = map_pm_address2index(address);
820 
821   if (uIndex < program_memory_size()) {
822     program_memory[uIndex]->update_line_number(file_id, sline, lst_line, -1, -1);
823 
824   } else {
825     printf("%s:Address %03X out of range\n", __FUNCTION__, uIndex);
826   }
827 }
828 
829 
830 //-------------------------------------------------------------------
831 // read_src_files - this routine will open all of the source files
832 //   associated with the project and associate their line numbers
833 //   with the addresses of the opcodes they generated.
834 //
835 
read_src_files()836 void Processor::read_src_files()
837 {
838   int i;
839 
840   // Are there any src files ?
841   for (i = 0; i < files.nsrc_files(); i++) {
842     FileContext *fc = files[i];
843 
844     // did this src file generate any code?
845     if (fc && fc->max_line() > 0) {
846       // Create an array whose index corresponds to the
847       // line number of a source file line and whose data
848       // is the offset (in bytes) from the beginning of the
849       // file. (e.g. files[3].line_seek[20] references the
850       // 20th line of the third source file.)
851       fc->ReadSource();
852     }
853   }
854 
855   // Associate source files with the instructions they generated.
856   unsigned int addr;
857 
858   for (addr = 0; addr < program_memory_size(); addr++) {
859     if ((program_memory[addr]->isa() != instruction::INVALID_INSTRUCTION) &&
860         (program_memory[addr]->get_file_id() >= 0)) {
861       FileContext *fc = files[program_memory[addr]->get_file_id()];
862 
863       if (fc)
864         fc->put_address(program_memory[addr]->get_src_line(),
865                         map_pm_index2address(addr));
866     }
867   }
868 
869   // Associate the list file with
870   if (files.list_id() >= 0) {
871     // Parse the list file.
872     //printf("read_src_files List file:%d %d\n",files.list_id(),files.nsrc_files());
873     FileContext *fc = files[files.list_id()];
874 
875     if (!fc) {
876       return;
877     }
878 
879     fc->ReadSource();
880     fc->rewind();
881     char buf[256];
882     int line = 1;
883 
884     while (fc->gets(buf, sizeof(buf))) {
885       unsigned int address;
886       unsigned int opcode;
887 
888       if (sscanf(buf, "%x   %x", &address, &opcode) == 2) {
889         unsigned int uIndex = map_pm_address2index(address);
890 
891         if (uIndex < program_memory_size()) {
892           program_memory[uIndex]->update_line_number(-1, -1, line, -1, -1);
893           fc->put_address(line, address);
894         }
895       }
896 
897       line++;
898     }
899   }
900 }
901 
902 
903 //-------------------------------------------------------------------
904 //
905 // processor -- list
906 //
907 // Display the contents of either a source or list file
908 //
list(unsigned int file_id,unsigned int pc_val,int start_line,int end_line)909 void Processor::list(unsigned int file_id,
910                      unsigned int pc_val,
911                      int start_line,
912                      int end_line)
913 {
914   if (files.nsrc_files() == 0) {
915     return;
916   }
917 
918   if (pc_val > program_memory_size()) {
919     return;
920   }
921 
922   if (program_memory[pc_val]->isa() == instruction::INVALID_INSTRUCTION) {
923     std::cout << "There's no code at address 0x" << std::hex << pc_val << '\n';
924     return;
925   }
926 
927   unsigned int line, pc_line;
928 
929   if (file_id) {
930     file_id = files.list_id();
931     line = program_memory[pc_val]->get_lst_line();
932     pc_line = program_memory[pc->value]->get_lst_line();
933 
934   } else {
935     file_id = program_memory[pc_val]->get_file_id();
936     line = program_memory[pc_val]->get_src_line();
937     pc_line = program_memory[pc->value]->get_src_line();
938   }
939 
940   start_line += line;
941   end_line += line;
942   FileContext *fc = files[file_id];
943 
944   if (fc == nullptr) {
945     return;
946   }
947 
948   start_line = (start_line < 0) ? 0 : start_line;
949   end_line   = (end_line <= start_line) ? (start_line + 5) : end_line;
950   end_line   = (end_line > (int)fc->max_line()) ? fc->max_line() : end_line;
951   std::cout << " listing " << fc->name() << " Starting line " << start_line
952             << " Ending line " << end_line << '\n';
953 
954   if (end_line == start_line) {
955     return;
956   }
957 
958   for (unsigned int i = start_line; i <= (unsigned int)end_line; i++) {
959     char buf[256];
960     fc->ReadLine(i, buf, sizeof(buf));
961 
962     if (pc_line == i) {
963       std::cout << "==>";
964 
965     } else {
966       std::cout << "   ";
967     }
968 
969     std::cout << buf;
970   }
971 }
972 
973 
trim(char * pBuffer)974 static void trim(char * pBuffer)
975 {
976   size_t iPos = 0;
977   char * pChar = pBuffer;
978 
979   while (*pChar != 0 && ::isspace(*pChar)) {
980     pChar++;
981   }
982 
983   if (pBuffer != pChar) {
984     memmove(pBuffer, pChar, strlen(pBuffer) - iPos);
985   }
986 
987   iPos = strlen(pBuffer);
988   pChar = pBuffer + iPos - 1;
989 
990   while (pChar > pBuffer && ::isspace(*pChar)) {
991     *pChar = 0;
992     pChar--;
993   }
994 }
995 
996 
997 //-------------------------------------------------------------------
998 //
999 // disassemble - Disassemble the contents of program memory from
1000 // 'start_address' to 'end_address'. The instruction at the current
1001 // PC is marked with an arrow '==>'. If an instruction has a break
1002 // point set on it then it will be marked with a 'B'. The instruction
1003 // mnemonics come from the class declarations for each instruction.
1004 // However, it is possible to modify this on a per instruction basis.
1005 // In other words, each instruction in the program memory has it's
1006 // own instantiation. So a MOVWF at address 0x20 is different than
1007 // one at address 0x21. It is possible to change the mnemonic of
1008 // one without affecting the other. As of version 0.0.7 though, this
1009 // is not implemented.
1010 //
1011 
disassemble(signed int s,signed int e)1012 void Processor::disassemble(signed int s, signed int e)
1013 {
1014   instruction *inst;
1015   int use_src_to_disasm = 0;
1016 
1017   if (s > e) {
1018     return;
1019   }
1020 
1021   unsigned int start_PMindex = map_pm_address2index(s);
1022   unsigned int end_PMindex   = map_pm_address2index(e);
1023 
1024   if (start_PMindex >= program_memory_size()) {
1025     if (s < 0) {
1026       start_PMindex = 0;
1027 
1028     } else {
1029       return;
1030     }
1031   }
1032 
1033   if (end_PMindex  >= program_memory_size()) {
1034     if (e < 0) {
1035       return;
1036 
1037     } else {
1038       end_PMindex = program_memory_size() - 1;
1039     }
1040   }
1041 
1042   const int iConsoleWidth = 80;
1043   char str[iConsoleWidth];
1044   char str2[iConsoleWidth];
1045 
1046   if (!pc) {
1047     const char *buf = "ERROR: internal bug " __FILE__ ":" STR(__LINE__);
1048     throw FatalError(buf);
1049   }
1050 
1051   unsigned uPCAddress = pc->get_value();
1052   ISimConsole &Console = GetUserInterface().GetConsole();
1053   int iLastFileId = -1;
1054   FileContext *fc = nullptr;
1055 
1056   for (unsigned int PMindex = start_PMindex; PMindex <= end_PMindex; PMindex++) {
1057     unsigned int uAddress = map_pm_index2address(PMindex);
1058     str[0] = 0;
1059     const char *pszPC = (uPCAddress == uAddress) ? "==>" : "   ";
1060     inst = program_memory[PMindex];
1061     // If this is not a "base" instruction then it has been replaced
1062     // with something like a break point.
1063     char cBreak = ' ';
1064 
1065     if (!inst->isBase()) {
1066       cBreak = 'B';
1067       inst = pma->get_base_instruction(PMindex);
1068     }
1069 
1070     if (inst->get_file_id() != -1) {
1071       fc = files[inst->get_file_id()];
1072 
1073       if (iLastFileId != inst->get_file_id()) {
1074         Console.Printf("%s\n", fc->name().c_str());
1075       }
1076 
1077       iLastFileId = inst->get_file_id();
1078 
1079     } else {
1080       fc = 0;
1081     }
1082 
1083     //const char *pLabel = get_symbol_table().findProgramAddressLabel(uAddress);
1084     //if(*pLabel != 0)
1085     //  cout << pLabel << ":" << endl;
1086     AddressSymbol *pAddr = dynamic_cast<AddressSymbol *>(inst->getLineSymbol());
1087 
1088     if (pAddr) {
1089       std::cout << pAddr->name() << ":\n";
1090     }
1091 
1092     if (fc && files.nsrc_files() && use_src_to_disasm) {
1093       char buf[256];
1094       files.ReadLine(inst->get_file_id(),
1095                      inst->get_src_line() - 1,
1096                      buf,
1097                      sizeof(buf));
1098       std::cout << buf;
1099 
1100     }  else {
1101       if (fc != nullptr && inst->get_src_line() != -1) {
1102         if (fc->ReadLine(inst->get_src_line(), str2, iConsoleWidth - 33)
1103             != nullptr) {
1104           trim(str2);
1105 
1106         } else {
1107           str2[0] = 0;
1108         }
1109 
1110       } else {
1111         str2[0] = 0;
1112       }
1113 
1114       inst->name(str, sizeof(str));
1115       char *pAfterNumonic = strchr(str, '\t');
1116       int iNumonicWidth = pAfterNumonic ? pAfterNumonic - str : 5;
1117       int iOperandsWidth = 14;
1118       int iSrc = iOperandsWidth - (strlen(str) - iNumonicWidth - 1);
1119       //        Console.Printf("0.........1.........2.........3.........4.........5.........6.........7.........");
1120       //        Console.Printf("%d, strlen(str)=%d\n", iNumonicWidth, strlen(str));
1121       const char *pFormat = (opcode_size() <= 2) ?  "% 3s%c%04x  %04x  %s %*s%s\n" :  "% 3s%c%04x  %06x  %s %*s%s\n";
1122       Console.Printf(pFormat,
1123                      pszPC, cBreak, uAddress, inst->get_opcode(),
1124                      str, iSrc, "", str2);
1125     }
1126   }
1127 }
1128 
1129 
1130 //-------------------------------------------------------------------
save_state(FILE * fp)1131 void Processor::save_state(FILE *fp)
1132 {
1133   if (!fp) {
1134     return;
1135   }
1136 
1137   fprintf(fp, "PROCESSOR:%s\n", name().c_str());
1138 
1139   for (unsigned int i = 1; i < register_memory_size(); i++) {
1140     Register *reg = rma.get_register(i);
1141 
1142     if (reg && reg->isa() != Register::INVALID_REGISTER) {
1143       fprintf(fp, "R:%X:%s:(%X,%X)\n",
1144               reg->address,
1145               reg->name().c_str(),
1146               reg->value.get(),
1147               reg->value.geti());
1148     }
1149   }
1150 
1151   if (pc) {
1152     fprintf(fp, "P:0:PC:%X\n", pc->value);
1153   }
1154 }
1155 
1156 
1157 //-------------------------------------------------------------------
save_state()1158 void Processor::save_state()
1159 {
1160   for (unsigned int i = 0; i < register_memory_size(); i++) {
1161     Register *reg = rma.get_register(i);
1162 
1163     if (reg && reg->isa() != Register::INVALID_REGISTER) {
1164       reg->put_trace_state(reg->getRV_notrace());
1165     }
1166   }
1167 
1168   if (pc) {
1169     pc->put_trace_state(pc->value);
1170   }
1171 }
1172 
1173 
1174 //-------------------------------------------------------------------
load_state(FILE * fp)1175 void Processor::load_state(FILE *fp)
1176 {
1177   if (!fp) {
1178     return;
1179   }
1180 
1181   std::cout << "Not implemented\n";
1182 }
1183 
1184 
1185 /* If Vdd is changed, fix up the digital high low thresholds */
update_vdd()1186 void Processor::update_vdd()
1187 {
1188   for (int i = 1; i <= get_pin_count(); i++) {
1189     IOPIN *pin = get_pin(i);
1190 
1191     if (pin) {
1192       pin->set_digital_threshold(get_Vdd());
1193     }
1194   }
1195 }
1196 
1197 
1198 //-------------------------------------------------------------------
find_closest_address_to_line(int file_id,int src_line)1199 int ProgramMemoryAccess::find_closest_address_to_line(int file_id, int src_line)
1200 {
1201   int closest_address = -1;
1202 
1203   if ((!cpu) || (file_id == -1)) {
1204     return closest_address;
1205   }
1206 
1207   FileContext *fc = cpu->files[file_id];
1208 
1209   if (fc) {
1210     int offset = 0;
1211 
1212     while ((unsigned int)(src_line + offset) < fc->max_line()) {
1213       closest_address = fc->get_address(src_line + offset);
1214 
1215       if (closest_address >= 0) {
1216         return closest_address;
1217       }
1218 
1219       offset++;
1220     }
1221 
1222     offset = -1;
1223 
1224     while (src_line + offset >= 0) {
1225       closest_address = fc->get_address(src_line + offset);
1226 
1227       if (closest_address >= 0) {
1228         return closest_address;
1229       }
1230 
1231       offset--;
1232     }
1233   }
1234 
1235   return closest_address;
1236 }
1237 
1238 
1239 //-------------------------------------------------------------------
find_address_from_line(FileContext * fc,int src_line)1240 int ProgramMemoryAccess::find_address_from_line(FileContext *fc, int src_line)
1241 {
1242   return (cpu && fc) ? fc->get_address(src_line) : -1;
1243 }
1244 
1245 
1246 //--------------------------------------------------------------------------
1247 //
1248 // temporary - this could is going to get deleted as soon as file related
1249 // stuff gets put into its own object/class.
1250 
set_hll_mode(unsigned int new_hll_mode)1251 void ProgramMemoryAccess::set_hll_mode(unsigned int new_hll_mode)
1252 {
1253   switch (new_hll_mode) {
1254   case ASM_MODE:
1255     hll_mode = ASM_MODE;
1256     break;
1257 
1258   case HLL_MODE:
1259     hll_mode = HLL_MODE;
1260   }
1261 }
1262 
1263 
1264 //--------------------------------------------------------------------------
get_src_line(unsigned int address)1265 int ProgramMemoryAccess::get_src_line(unsigned int address)
1266 {
1267   unsigned int line = 0;
1268 
1269   if (!cpu || !cpu->IsAddressInRange(address)) {
1270     return INVALID_VALUE;
1271   }
1272 
1273   switch (get_hll_mode()) {
1274   case ASM_MODE:
1275     line = getFromAddress(address)->get_src_line();
1276     break;
1277 
1278   case HLL_MODE:
1279     line = getFromAddress(address)->get_hll_src_line();
1280     break;
1281   }
1282 
1283   return line;
1284 }
1285 
1286 
1287 //--------------------------------------------------------------------------
get_file_id(unsigned int address)1288 int ProgramMemoryAccess::get_file_id(unsigned int address)
1289 {
1290   if (!cpu) {
1291     return INVALID_VALUE;
1292   }
1293 
1294   switch (get_hll_mode()) {
1295   case ASM_MODE:
1296     return getFromAddress(address)->get_file_id();
1297     break;
1298 
1299   case HLL_MODE:
1300     return getFromAddress(address)->get_hll_file_id();
1301     break;
1302   }
1303 
1304   return INVALID_VALUE;
1305 }
1306 
1307 
1308 //-------------------------------------------------------------------
set_break_at_address(unsigned int address)1309 unsigned int ProgramMemoryAccess::set_break_at_address(unsigned int address)
1310 {
1311   if (hasValid_opcode_at_address(address)) {
1312     return bp.set_execution_break(cpu, address);
1313   }
1314 
1315   return INVALID_VALUE;
1316 }
1317 
1318 
1319 //-------------------------------------------------------------------
set_notify_at_address(unsigned int address,TriggerObject * cb)1320 unsigned int ProgramMemoryAccess::set_notify_at_address(unsigned int address, TriggerObject *cb)
1321 {
1322   if (hasValid_opcode_at_address(address)) {
1323     return bp.set_notify_break(cpu, address, cb);
1324   }
1325 
1326   return INVALID_VALUE;
1327 }
1328 
1329 
1330 //-------------------------------------------------------------------
set_profile_start_at_address(unsigned int address,TriggerObject * cb)1331 unsigned int ProgramMemoryAccess::set_profile_start_at_address(unsigned int address,
1332     TriggerObject *cb)
1333 {
1334   unsigned int pm_index = cpu->map_pm_address2index(address);
1335 
1336   if (pm_index < cpu->program_memory_size())
1337     if (cpu->program_memory[pm_index]->isa() != instruction::INVALID_INSTRUCTION) {
1338       return bp.set_profile_start_break(cpu, address, cb);
1339     }
1340 
1341   return INVALID_VALUE;
1342 }
1343 
1344 
1345 //-------------------------------------------------------------------
set_profile_stop_at_address(unsigned int address,TriggerObject * cb)1346 unsigned int ProgramMemoryAccess::set_profile_stop_at_address(unsigned int address,
1347     TriggerObject *cb)
1348 {
1349   if (hasValid_opcode_at_address(address)) {
1350     return bp.set_profile_stop_break(cpu, address, cb);
1351   }
1352 
1353   return INVALID_VALUE;
1354 }
1355 
1356 
1357 //-------------------------------------------------------------------
clear_break_at_address(unsigned int address,enum instruction::INSTRUCTION_TYPES type=instruction::BREAKPOINT_INSTRUCTION)1358 int ProgramMemoryAccess::clear_break_at_address(unsigned int address,
1359     enum instruction::INSTRUCTION_TYPES type =
1360       instruction::BREAKPOINT_INSTRUCTION)
1361 {
1362   unsigned int uIndex = cpu->map_pm_address2index(address);
1363 
1364   if (uIndex < cpu->program_memory_size())
1365   {
1366     instruction *instr = find_instruction(address, type);
1367 
1368     if (instr != 0) {
1369       int b = ((Breakpoint_Instruction *)instr)->bpn & BREAKPOINT_MASK;
1370       // this actually removes the object
1371       bp.clear(b);
1372       return 1;
1373     }
1374   }
1375 
1376   return 0;
1377 }
1378 
1379 
1380 //-------------------------------------------------------------------
clear_break_at_address(unsigned int address,instruction * pInstruction)1381 int ProgramMemoryAccess::clear_break_at_address(unsigned int address,
1382     instruction * pInstruction)
1383 {
1384   if (!cpu || !cpu->IsAddressInRange(address)) {
1385     return -1;
1386   }
1387 
1388   instruction **ppAddressLocation = &cpu->program_memory[cpu->map_pm_address2index(address)];
1389   Breakpoint_Instruction *br = dynamic_cast<Breakpoint_Instruction *>(*ppAddressLocation);
1390 
1391   if (br == pInstruction) {
1392     // at the head of the chain
1393     *ppAddressLocation = br->getReplaced();
1394     br->setReplaced(0);
1395 
1396   } else {
1397     Breakpoint_Instruction *pLast = br;
1398 
1399     // Find myself in the chain
1400     while (br != nullptr) {
1401       if (br == pInstruction) {
1402         // found -- remove from the chain
1403         pLast->setReplaced(br->getReplaced());
1404         br->setReplaced(0);
1405         return 1;
1406 
1407       } else {
1408         pLast = br;
1409         br = dynamic_cast<Breakpoint_Instruction *>(br->getReplaced());
1410       }
1411     }
1412   }
1413 
1414   return 0;
1415 }
1416 
1417 
1418 //-------------------------------------------------------------------
clear_notify_at_address(unsigned int address)1419 int ProgramMemoryAccess::clear_notify_at_address(unsigned int address)
1420 {
1421   return clear_break_at_address(address, instruction::NOTIFY_INSTRUCTION);
1422 }
1423 
1424 
1425 //-------------------------------------------------------------------
clear_profile_start_at_address(unsigned int address)1426 int ProgramMemoryAccess::clear_profile_start_at_address(unsigned int address)
1427 {
1428   return clear_break_at_address(address, instruction::PROFILE_START_INSTRUCTION);
1429 }
1430 
1431 
1432 //-------------------------------------------------------------------
clear_profile_stop_at_address(unsigned int address)1433 int ProgramMemoryAccess::clear_profile_stop_at_address(unsigned int address)
1434 {
1435   return clear_break_at_address(address, instruction::PROFILE_STOP_INSTRUCTION);
1436 }
1437 
1438 
1439 //-------------------------------------------------------------------
address_has_break(unsigned int address,enum instruction::INSTRUCTION_TYPES type)1440 int ProgramMemoryAccess::address_has_break(unsigned int address,
1441     enum instruction::INSTRUCTION_TYPES type)
1442 {
1443   if (find_instruction(address, type) != 0) {
1444     return 1;
1445   }
1446 
1447   return 0;
1448 }
1449 
1450 
1451 //-------------------------------------------------------------------
address_has_notify(unsigned int address)1452 int ProgramMemoryAccess::address_has_notify(unsigned int address)
1453 {
1454   return address_has_break(address, instruction::NOTIFY_INSTRUCTION);
1455 }
1456 
1457 
1458 //-------------------------------------------------------------------
address_has_profile_start(unsigned int address)1459 int ProgramMemoryAccess::address_has_profile_start(unsigned int address)
1460 {
1461   return address_has_break(address, instruction::PROFILE_START_INSTRUCTION);
1462 }
1463 
1464 
1465 //-------------------------------------------------------------------
address_has_profile_stop(unsigned int address)1466 int ProgramMemoryAccess::address_has_profile_stop(unsigned int address)
1467 {
1468   return address_has_break(address, instruction::PROFILE_STOP_INSTRUCTION);
1469 }
1470 
1471 
1472 //-------------------------------------------------------------------
toggle_break_at_address(unsigned int address)1473 void ProgramMemoryAccess::toggle_break_at_address(unsigned int address)
1474 {
1475   if (address_has_break(address)) {
1476     clear_break_at_address(address);
1477 
1478   } else {
1479     set_break_at_address(address);
1480   }
1481 }
1482 
1483 
1484 //-------------------------------------------------------------------
1485 
set_break_at_line(unsigned int file_id,unsigned int src_line)1486 void ProgramMemoryAccess::set_break_at_line(unsigned int file_id, unsigned int src_line)
1487 {
1488   int address;
1489 
1490   if ((address = find_closest_address_to_line(file_id, src_line)) >= 0) {
1491     set_break_at_address(address);
1492   }
1493 }
1494 
1495 
clear_break_at_line(unsigned int file_id,unsigned int src_line)1496 void ProgramMemoryAccess::clear_break_at_line(unsigned int file_id, unsigned int src_line)
1497 {
1498   int address;
1499 
1500   if ((address = find_closest_address_to_line(file_id, src_line)) >= 0) {
1501     clear_break_at_address(address);
1502   }
1503 }
1504 
1505 
toggle_break_at_line(unsigned int file_id,unsigned int src_line)1506 void ProgramMemoryAccess::toggle_break_at_line(unsigned int file_id, unsigned int src_line)
1507 {
1508   toggle_break_at_address(find_closest_address_to_line(file_id, src_line));
1509 }
1510 
1511 
1512 //-------------------------------------------------------------------
1513 //
construct()1514 Processor * Processor::construct()
1515 {
1516   std::cout << " Can't create a generic processor\n";
1517   return nullptr;
1518 }
1519 
1520 
1521 //-------------------------------------------------------------------
trace_dump(int,int amount)1522 void Processor::trace_dump(int /* type */, int amount)
1523 {
1524   trace.dump(amount, stdout);
1525 }
1526 
1527 //-------------------------------------------------------------------
1528 // Decode a single trace item
trace_dump1(int type,char * buffer,int bufsize)1529 int Processor::trace_dump1(int type, char *buffer, int bufsize)
1530 {
1531   snprintf(buffer, bufsize, "*** INVALID TRACE *** 0x%x", type);
1532   return 1;
1533 }
1534 
1535 
1536 //-------------------------------------------------------------------
1537 // getWriteTT
1538 //
1539 // For devices with more than 64k of registers (which are not supported
1540 // at the moment), we can enhance this function to return different Trace
1541 // type objects base on the upper address bits.
1542 
getWriteTT(unsigned int j)1543 RegisterValue Processor::getWriteTT(unsigned int j)
1544 {
1545   if (!writeTT) {
1546     writeTT = new RegisterWriteTraceType(this, 2);
1547     trace.allocateTraceType(writeTT);
1548   }
1549 
1550   // The upper 8-bits define the dynamically allocated trace type
1551   // The lower 8-bits will record the register value that is written.
1552   // The middle 16-bits are the register address
1553   unsigned int tt = (writeTT->type() & 0xff000000) | ((j & 0xffff) << 8);
1554   return RegisterValue(tt, tt + (1 << 24));
1555 }
1556 
1557 
getReadTT(unsigned int j)1558 RegisterValue Processor::getReadTT(unsigned int j)
1559 {
1560   if (!readTT) {
1561     readTT = new RegisterReadTraceType(this, 2);
1562     trace.allocateTraceType(readTT);
1563   }
1564 
1565   // The upper 8-bits define the dynamically allocated trace type
1566   // The lower 8-bits will record the register value that is written.
1567   // The middle 16-bits are the register address
1568   unsigned int tt = (readTT->type() & 0xff000000) | ((j & 0xffff) << 8);
1569   return RegisterValue(tt, tt + (1 << 24));
1570 }
1571 
1572 
1573 //-------------------------------------------------------------------
1574 //
1575 // step_over - In most cases, step_over will simulate just one instruction.
1576 // However, if the next instruction is a branching one (e.g. goto, call,
1577 // return, etc.) then a break point will be set after it and gpsim will
1578 // begin 'running'. This is useful for stepping over time-consuming calls.
1579 //
1580 
step_over(bool refresh)1581 void Processor::step_over(bool refresh)
1582 {
1583   step(1, refresh); // Try one step
1584 }
1585 
1586 
1587 //-------------------------------------------------------------------
1588 
run_to_address(unsigned int destination)1589 void Processor::run_to_address(unsigned int destination)
1590 {
1591   if (simulation_mode != eSM_STOPPED) {
1592     if (verbose) {
1593       std::cout << "Ignoring run-to-address request because simulation is not stopped\n";
1594     }
1595 
1596     return;
1597   }
1598 
1599   // Set a temporary break point
1600   unsigned int bp_num = bp.set_execution_break(this, destination);
1601   run();
1602   bp.clear(bp_num);
1603 }
1604 
1605 
1606 //-------------------------------------------------------------------
1607 //
1608 //
1609 //    create
1610 //
1611 //  The purpose of this member function is to 'create' a pic processor.
1612 // Since this is a base class member function, only those things that
1613 // are common to all pics are created.
1614 
create()1615 void Processor::create()
1616 {
1617   const char *buf = " a generic processor cannot be created " __FILE__ ":" STR(__LINE__);
1618   throw FatalError(buf);
1619 }
1620 
1621 
1622 //-------------------------------------------------------------------
dump_registers()1623 void Processor::dump_registers()
1624 {
1625   //  parse_string("dump");
1626 }
1627 
1628 
1629 //-------------------------------------------------------------------
Debug()1630 void Processor::Debug()
1631 {
1632   std::cout << " === Debug === \n";
1633 
1634   if (pc) {
1635     std::cout << "PC=0x" << std::hex << pc->value << '\n';
1636   }
1637 }
1638 
1639 
1640 //-------------------------------------------------------------------
find_instruction(unsigned int address,enum instruction::INSTRUCTION_TYPES type)1641 instruction *ProgramMemoryAccess::find_instruction(unsigned int address,
1642     enum instruction::INSTRUCTION_TYPES type)
1643 {
1644   unsigned int uIndex = cpu->map_pm_address2index(address);
1645 
1646   if (cpu->program_memory_size() <= uIndex) {
1647     return nullptr;
1648   }
1649 
1650   instruction *p = getFromIndex(uIndex);
1651 
1652   if (p->isa() == instruction::INVALID_INSTRUCTION) {
1653     return nullptr;
1654   }
1655 
1656   for (;;) {
1657     if (p->isa() == type) {
1658       return p;
1659     }
1660 
1661     switch (p->isa()) {
1662     case instruction::MULTIWORD_INSTRUCTION:
1663     case instruction::INVALID_INSTRUCTION:
1664     case instruction::NORMAL_INSTRUCTION:
1665       return nullptr;
1666 
1667     case instruction::BREAKPOINT_INSTRUCTION:
1668     case instruction::NOTIFY_INSTRUCTION:
1669     case instruction::PROFILE_START_INSTRUCTION:
1670     case instruction::PROFILE_STOP_INSTRUCTION:
1671     case instruction::ASSERTION_INSTRUCTION:
1672       p = ((Breakpoint_Instruction *)p)->getReplaced();
1673       break;
1674     }
1675   }
1676 
1677   return nullptr;
1678 }
1679 
1680 
1681 //-------------------------------------------------------------------
cycles_used(unsigned int address)1682 guint64 Processor::cycles_used(unsigned int address)
1683 {
1684   return program_memory[address]->getCyclesUsed();
1685 }
1686 
1687 
1688 //-------------------------------------------------------------------
MemoryAccess(Processor * new_cpu)1689 MemoryAccess::MemoryAccess(Processor *new_cpu)
1690 {
1691   cpu = new_cpu;
1692 }
1693 
1694 
~MemoryAccess()1695 MemoryAccess::~MemoryAccess()
1696 {
1697 }
1698 
1699 
get_cpu()1700 Processor *MemoryAccess::get_cpu()
1701 {
1702   return cpu;
1703 }
1704 
1705 
1706 //-------------------------------------------------------------------
1707 //-------------------------------------------------------------------
1708 // Program memory interface used by the command line
1709 class ProgramMemoryCollection : public IIndexedCollection {
1710 public:
1711   ProgramMemoryCollection(Processor *pProcessor,
1712                           const char *collection_name,
1713                           ProgramMemoryAccess *pPma);
1714   ~ProgramMemoryCollection();
1715 
1716   virtual unsigned int GetSize();
1717   virtual Value &GetAt(unsigned int uAddress, Value *pValue = nullptr);
1718   virtual void SetAt(unsigned int uAddress, Value *pValue);
1719   virtual void ConsolidateValues(int &iColumnWidth,
1720                                  std::vector<std::string> &aList,
1721                                  std::vector<std::string> &aValue);
1722   virtual unsigned int GetLowerBound();
1723   virtual unsigned int GetUpperBound();
1724   virtual bool bIsIndexInRange(unsigned int uIndex);
1725   virtual void get(char *return_str, int len);
1726 
1727 private:
1728   Processor *   m_pProcessor;
1729   ProgramMemoryAccess   *m_pPma;
1730   Integer       m_ReturnValue;
1731 };
1732 
1733 
ProgramMemoryCollection(Processor * pProcessor,const char * pC_collection_name,ProgramMemoryAccess * pPma)1734 ProgramMemoryCollection::ProgramMemoryCollection(Processor   *pProcessor,
1735     const char  *pC_collection_name,
1736     ProgramMemoryAccess *pPma) :
1737   IIndexedCollection(16), m_ReturnValue(0)
1738 {
1739   m_pProcessor = pProcessor;
1740   Value::new_name(pC_collection_name);
1741   m_pPma = pPma;
1742   pProcessor->addSymbol(this);
1743 }
1744 
1745 
~ProgramMemoryCollection()1746 ProgramMemoryCollection::~ProgramMemoryCollection()
1747 {
1748   if (m_pProcessor) {
1749     m_pProcessor->removeSymbol(this);
1750   }
1751 }
1752 
1753 
get(char * return_str,int len)1754 void ProgramMemoryCollection::get(char *return_str, int len)
1755 {
1756   if (return_str && len >= 1) {
1757     *return_str = '\0';
1758   }
1759 }
1760 
1761 
GetSize()1762 unsigned int ProgramMemoryCollection::GetSize()
1763 {
1764   return m_pProcessor->program_memory_size();
1765 }
1766 
1767 
GetAt(unsigned int uAddress,Value *)1768 Value &ProgramMemoryCollection::GetAt(unsigned int uAddress, Value *)
1769 {
1770   //m_pProcessor->map_pm_address2index
1771   m_ReturnValue.set((int)m_pPma->get_rom(uAddress));
1772   m_ReturnValue.setBitmask((1 << (m_pProcessor->opcode_size() * 8)) - 1);
1773   std::ostringstream sIndex;
1774   sIndex << Value::name() << "[" << std::hex << m_szPrefix << uAddress << "]" << '\000';
1775   m_ReturnValue.new_name(sIndex.str().c_str());
1776   return m_ReturnValue;
1777 }
1778 
1779 
SetAt(unsigned int uAddress,Value * pValue)1780 void ProgramMemoryCollection::SetAt(unsigned int uAddress, Value *pValue)
1781 {
1782   Integer *pInt = dynamic_cast<Integer*>(pValue);
1783 
1784   if (pInt == nullptr) {
1785     throw Error("rValue is not an Integer");
1786 
1787   } else {
1788     m_pPma->put_rom(uAddress, (unsigned int)(int)*pInt);
1789   }
1790 }
1791 
1792 
ConsolidateValues(int & iColumnWidth,std::vector<std::string> & aList,std::vector<std::string> & aValue)1793 void ProgramMemoryCollection::ConsolidateValues(int &iColumnWidth,
1794     std::vector<std::string> &aList,
1795     std::vector<std::string> &aValue)
1796 {
1797   unsigned int  uFirstAddress = 0;
1798   unsigned int  uAddress;
1799   //Register *    pReg = m_ppRegisters[0];
1800   //Integer       uLastValue(pReg->getRV_notrace().data);
1801   Integer uLastValue(m_pPma->get_opcode(0));
1802   uLastValue.setBitmask((1 << (m_pProcessor->opcode_size() * 8)) - 1);
1803   unsigned int uSize = GetSize();
1804 
1805   for (uAddress = 0; uAddress < uSize; uAddress++) {
1806     unsigned int ui_opcode = m_pPma->get_opcode(uAddress);
1807 
1808     if ((unsigned int)uLastValue != ui_opcode) {
1809       PushValue(uFirstAddress, uAddress,
1810                 &uLastValue, aList, aValue);
1811       iColumnWidth = std::max(iColumnWidth, (int)aList.back().size());
1812       uFirstAddress = uAddress;
1813       uLastValue = ui_opcode;
1814     }
1815   }
1816 
1817   uAddress--;
1818 
1819   // Record the last set of elements
1820   if (uFirstAddress <= uAddress) {
1821     PushValue(uFirstAddress, uAddress,
1822               &uLastValue, aList, aValue);
1823     iColumnWidth = std::max(iColumnWidth, (int)aList.back().size());
1824   }
1825 }
1826 
1827 
1828 //void RegisterCollection::SetAt(ExprList_t* pIndexers, Expression *pExpr) {
1829 //  throw Error("RegisterCollection::SetAt() not implemented");
1830 //}
1831 
GetLowerBound()1832 unsigned int ProgramMemoryCollection::GetLowerBound()
1833 {
1834   return 0;
1835 }
1836 
1837 
GetUpperBound()1838 unsigned int ProgramMemoryCollection::GetUpperBound()
1839 {
1840   return GetSize() - 1;
1841 }
1842 
1843 
bIsIndexInRange(unsigned int uAddress)1844 bool ProgramMemoryCollection::bIsIndexInRange(unsigned int uAddress)
1845 {
1846   return m_pPma->get_rom(uAddress) != 0xffffffff;
1847   // (uIndex >= GetLowerBound() &&  uIndex <= GetUpperBound()) ||
1848 }
1849 
1850 
1851 //-------------------------------------------------------------------
1852 //-------------------------------------------------------------------
1853 //
1854 // ProgramMemoryAccess
1855 //
1856 // The ProgramMemoryAccess class provides an interface to the processor's
1857 // program memory. On Pic processors, this is the memory where instructions
1858 // are stored.
1859 //
1860 
ProgramMemoryAccess(Processor * new_cpu)1861 ProgramMemoryAccess::ProgramMemoryAccess(Processor *new_cpu)
1862   : MemoryAccess(new_cpu), bpi(nullptr)
1863 {
1864   init(new_cpu);
1865   m_pRomCollection = new ProgramMemoryCollection(new_cpu,
1866       "romData",
1867       this);
1868 }
1869 
1870 
~ProgramMemoryAccess()1871 ProgramMemoryAccess::~ProgramMemoryAccess()
1872 {
1873   delete m_pRomCollection;
1874 }
1875 
1876 
init(Processor *)1877 void ProgramMemoryAccess::init(Processor * /* new_cpu */ )
1878 {
1879   _address = _opcode = _state = 0;
1880   hll_mode = ASM_MODE;
1881 
1882   // add the 'main' pma to the list pma context's. Processors may
1883   // choose to add multiple pma's to the context list. The gui
1884   // will build a source browser for each one of these. The purpose
1885   // is to provide more than one way of debugging the code. (e.g.
1886   // this is useful for debugging interrupt versus non-interrupt code).
1887 
1888   if (cpu) {
1889     cpu->pma_context.push_back(this);
1890   }
1891 }
1892 
1893 
1894 /*
1895 void ProgramMemoryAccess::name(string & new_name)
1896 {
1897   name_str = new_name;
1898 }
1899 */
putToAddress(unsigned int address,instruction * new_instruction)1900 void ProgramMemoryAccess::putToAddress(unsigned int address, instruction *new_instruction)
1901 {
1902   putToIndex(cpu->map_pm_address2index(address), new_instruction);
1903 }
1904 
1905 
putToIndex(unsigned int uIndex,instruction * new_instruction)1906 void ProgramMemoryAccess::putToIndex(unsigned int uIndex, instruction *new_instruction)
1907 {
1908   if (!new_instruction) {
1909     return;
1910   }
1911 
1912   cpu->program_memory[uIndex] = new_instruction;
1913   new_instruction->update();
1914 }
1915 
1916 
remove(unsigned int address,instruction * bp_instruction)1917 void ProgramMemoryAccess::remove(unsigned int address, instruction *bp_instruction)
1918 {
1919   if (!bp_instruction) {
1920     return;
1921   }
1922 
1923   instruction *instr = cpu->program_memory[cpu->map_pm_address2index(address)];
1924 
1925   if (typeid(Breakpoint_Instruction) == typeid(*instr) ||
1926       typeid(RegisterAssertion) == typeid(*instr)) {
1927     Breakpoint_Instruction* toRemove = (Breakpoint_Instruction*)bp_instruction;
1928     Breakpoint_Instruction *last = (Breakpoint_Instruction*)instr;
1929 
1930     if (toRemove == last) {
1931       cpu->program_memory[cpu->map_pm_address2index(address)] = last->getReplaced();
1932       return;
1933     }
1934 
1935     do {
1936       if (typeid(Breakpoint_Instruction) != typeid(*last->getReplaced()) &&
1937           typeid(RegisterAssertion) != typeid(*last->getReplaced()))
1938         // not found
1939       {
1940         return;
1941       }
1942 
1943       Breakpoint_Instruction *replaced = (Breakpoint_Instruction*)last->getReplaced();
1944 
1945       if (toRemove == replaced) {
1946         // remove from the chain
1947         last->setReplaced(replaced->getReplaced());
1948         return;
1949       }
1950 
1951       last = replaced;
1952     } while (typeid(Breakpoint_Instruction) != typeid(*last));
1953   }
1954 
1955   // if we get here the object was not in the list or was
1956   // not a Breakpoint_Instruction
1957   //  assert(typeid(*instr) != typeid(Breakpoint_Instruction));
1958 }
1959 
1960 
getFromAddress(unsigned int address)1961 instruction *ProgramMemoryAccess::getFromAddress(unsigned int address)
1962 {
1963   if (!cpu || !cpu->IsAddressInRange(address)) {
1964     return &cpu->bad_instruction;
1965   }
1966 
1967   unsigned int uIndex = cpu->map_pm_address2index(address);
1968   return getFromIndex(uIndex);
1969 }
1970 
1971 
getFromIndex(unsigned int uIndex)1972 instruction *ProgramMemoryAccess::getFromIndex(unsigned int uIndex)
1973 {
1974   if (uIndex < cpu->program_memory_size()) {
1975     return cpu->program_memory[uIndex];
1976 
1977   } else {
1978     return nullptr;
1979   }
1980 }
1981 
1982 
1983 // like get, but will ignore instruction break points
get_base_instruction(unsigned int uIndex)1984 instruction *ProgramMemoryAccess::get_base_instruction(unsigned int uIndex)
1985 {
1986   instruction *p = getFromIndex(uIndex);
1987 
1988   if (!p) {
1989     return nullptr;
1990   }
1991 
1992   for (;;) {
1993     switch (p->isa()) {
1994     case instruction::MULTIWORD_INSTRUCTION:
1995     case instruction::INVALID_INSTRUCTION:
1996     case instruction::NORMAL_INSTRUCTION:
1997       return p;
1998 
1999     case instruction::BREAKPOINT_INSTRUCTION:
2000     case instruction::NOTIFY_INSTRUCTION:
2001     case instruction::PROFILE_START_INSTRUCTION:
2002     case instruction::PROFILE_STOP_INSTRUCTION:
2003     case instruction::ASSERTION_INSTRUCTION:
2004       p = ((Breakpoint_Instruction *)p)->getReplaced();
2005       break;
2006     }
2007   }
2008 
2009   return nullptr;
2010 }
2011 
2012 
2013 //----------------------------------------
2014 // get_rom - return the rom contents from program memory
2015 //           If the address is normal program memory, then the opcode
2016 //           of the instruction at that address is returned.
2017 //           If the address is some other special memory (like configuration
2018 //           memory in a PIC) then that data is returned instead.
2019 
get_rom(unsigned int addr)2020 unsigned int ProgramMemoryAccess::get_rom(unsigned int addr)
2021 {
2022   return cpu->get_program_memory_at_address(addr);
2023 }
2024 
2025 
2026 //----------------------------------------
2027 // put_rom - write new data to the program memory.
2028 //           If the address is in normal program memory, then a new instruction
2029 //           will be generated (if possible). If the address is some other
2030 //           special memory (like configuration memory), then that area will
2031 //           be updated.
2032 //
put_rom(unsigned int addr,unsigned int value)2033 void ProgramMemoryAccess::put_rom(unsigned int addr, unsigned int value)
2034 {
2035   return cpu->init_program_memory(addr, value);
2036 }
2037 
2038 
2039 //----------------------------------------
2040 // get_opcode - return an opcode from program memory.
2041 //              If the address is out of range return 0.
2042 
get_opcode(unsigned int addr)2043 unsigned int ProgramMemoryAccess::get_opcode(unsigned int addr)
2044 {
2045   instruction * pInstr = getFromAddress(addr);
2046 
2047   if (pInstr) {
2048     return pInstr->get_opcode();
2049 
2050   } else {
2051     return 0;
2052   }
2053 }
2054 
2055 
2056 //----------------------------------------
2057 // get_opcode_name - return an opcode name from program memory.
2058 //                   If the address is out of range return 0;
2059 
get_opcode_name(unsigned int addr,char * buffer,unsigned int size)2060 char *ProgramMemoryAccess::get_opcode_name(unsigned int addr, char *buffer, unsigned int size)
2061 {
2062   unsigned int uIndex = cpu->map_pm_address2index(addr);
2063 
2064   if (uIndex < cpu->program_memory_size()) {
2065     return cpu->program_memory[uIndex]->name(buffer, size);
2066   }
2067 
2068   *buffer = 0;
2069   return nullptr;
2070 }
2071 
2072 
2073 //----------------------------------------
2074 // Get the current value of the program counter.
get_PC()2075 unsigned int ProgramMemoryAccess::get_PC()
2076 {
2077   if (cpu && cpu->pc) {
2078     return cpu->pc->get_value();
2079   }
2080 
2081   return 0;
2082 }
2083 
2084 
2085 //----------------------------------------
2086 // Get the current value of the program counter.
set_PC(unsigned int new_pc)2087 void ProgramMemoryAccess::set_PC(unsigned int new_pc)
2088 {
2089   if (cpu && cpu->pc) {
2090     return cpu->pc->put_value(new_pc);
2091   }
2092 }
2093 
2094 
GetProgramCounter()2095 Program_Counter *ProgramMemoryAccess::GetProgramCounter()
2096 {
2097   if (cpu) {
2098     return cpu->pc;
2099   }
2100 
2101   return nullptr;
2102 }
2103 
2104 
put_opcode_start(unsigned int addr,unsigned int new_opcode)2105 void ProgramMemoryAccess::put_opcode_start(unsigned int addr, unsigned int new_opcode)
2106 {
2107   unsigned int uIndex = cpu->map_pm_address2index(addr);
2108 
2109   if ((uIndex < cpu->program_memory_size()) && (_state == 0)) {
2110     _state = 1;
2111     _address = addr;
2112     _opcode = new_opcode;
2113     get_cycles().set_break_delta(40000, this);
2114     bp.set_pm_write();
2115   }
2116 }
2117 
2118 
put_opcode(unsigned int addr,unsigned int new_opcode)2119 void ProgramMemoryAccess::put_opcode(unsigned int addr, unsigned int new_opcode)
2120 {
2121   unsigned int uIndex = cpu->map_pm_address2index(addr);
2122 
2123   if (uIndex >= cpu->program_memory_size()) {
2124     return;
2125   }
2126 
2127   instruction *old_inst = get_base_instruction(uIndex);
2128   instruction *new_inst = cpu->disasm(addr, new_opcode);
2129 
2130   if (new_inst == nullptr) {
2131     puts("FIXME, in ProgramMemoryAccess::put_opcode");
2132     return;
2133   }
2134 
2135   if (!old_inst) {
2136     putToIndex(uIndex, new_inst);
2137     return;
2138   }
2139 
2140   if (old_inst->isa() == instruction::INVALID_INSTRUCTION) {
2141     putToIndex(uIndex, new_inst);
2142     return;
2143   }
2144 
2145   // Now we need to make sure that the instruction we are replacing is
2146   // not a multi-word instruction. The 12 and 14 bit cores don't have
2147   // multi-word instructions, but the 16 bit cores do. If we are replacing
2148   // the second word of a multiword instruction, then we only need to
2149   // 'uninitialize' it.
2150   // if there was a breakpoint set at addr, save a pointer to the breakpoint.
2151   Breakpoint_Instruction *b = bpi;
2152   instruction *prev = get_base_instruction(cpu->map_pm_address2index(addr - 1));
2153 
2154   if (prev) {
2155     prev->initialize(false);
2156   }
2157 
2158   new_inst->update_line_number(old_inst->get_file_id(),
2159                                old_inst->get_src_line(),
2160                                old_inst->get_lst_line(),
2161                                old_inst->get_hll_src_line(),
2162                                old_inst->get_hll_file_id());
2163 
2164   if (b) {
2165     b->setReplaced(new_inst);
2166 
2167   } else {
2168     cpu->program_memory[uIndex] = new_inst;
2169   }
2170 
2171   cpu->program_memory[uIndex]->setModified(true);
2172   cpu->program_memory[uIndex]->update();
2173   delete old_inst;
2174 }
2175 
2176 
2177 //--------------------------------------------------------------------------
2178 
assign_xref(unsigned int address,XrefObject * xref)2179 void  ProgramMemoryAccess::assign_xref(unsigned int address, XrefObject * xref)
2180 {
2181   instruction &q = *getFromAddress(address);
2182 
2183   if (q.isa() == instruction::INVALID_INSTRUCTION) {
2184     delete (int *)xref->data;
2185     delete xref;
2186     return;
2187   }
2188 
2189   q.add_xref(xref);
2190 }
2191 
2192 
2193 //--------------------------------------------------------------------------
step(unsigned int steps,bool refresh)2194 void ProgramMemoryAccess::step(unsigned int steps, bool refresh)
2195 {
2196   if (!cpu) {
2197     return;
2198   }
2199 
2200   switch (get_hll_mode()) {
2201   case ASM_MODE:
2202     cpu->step(steps, refresh);
2203     break;
2204 
2205   case HLL_MODE:
2206     unsigned int initial_pc = cpu->pc->get_value();
2207     int initial_line = cpu->pma->get_src_line(initial_pc);
2208     int initial_file = cpu->pma->get_file_id(initial_pc);
2209 
2210     while (1) {
2211       cpu->step(1, false);
2212       unsigned int current_pc = cpu->pc->get_value();
2213       int current_line = cpu->pma->get_src_line(current_pc);
2214       int current_file = cpu->pma->get_file_id(current_pc);
2215 
2216       if (current_line < 0 || current_file < 0) {
2217         continue;
2218       }
2219 
2220       if (current_pc == initial_pc ||
2221           current_line != initial_line ||
2222           current_file != initial_file) {
2223         if (refresh) {
2224           get_interface().simulation_has_stopped();
2225         }
2226 
2227         break;
2228       }
2229     }
2230 
2231     break;
2232   }
2233 }
2234 
2235 
2236 //--------------------------------------------------------------------------
step_over(bool refresh)2237 void ProgramMemoryAccess::step_over(bool refresh)
2238 {
2239   if (!cpu) {
2240     return;
2241   }
2242 
2243   switch (get_hll_mode()) {
2244   case ASM_MODE:
2245     cpu->step_over(refresh);
2246     break;
2247 
2248   case HLL_MODE:
2249     pic_processor *pic = dynamic_cast<pic_processor *>(cpu);
2250 
2251     if (!pic) {
2252       std::cout << "step-over is not supported for non-PIC processors\n";
2253       return;
2254     }
2255 
2256     unsigned int initial_pc = cpu->pc->get_value();
2257     int initial_line = cpu->pma->get_src_line(initial_pc);
2258     int initial_file = cpu->pma->get_file_id(initial_pc);
2259     unsigned int initial_stack_depth = pic->stack->pointer & pic->stack->stack_mask;
2260 
2261     while (1) {
2262       cpu->step(1, false);
2263 
2264       if (initial_stack_depth < (pic->stack->pointer & pic->stack->stack_mask)) {
2265         cpu->finish();
2266       }
2267 
2268       unsigned int current_pc = cpu->pc->get_value();
2269       int current_line = cpu->pma->get_src_line(current_pc);
2270       int current_file = cpu->pma->get_file_id(current_pc);
2271 
2272       if (current_line < 0 || current_file < 0) {
2273         continue;
2274       }
2275 
2276       if (current_pc == initial_pc ||
2277           current_line != initial_line ||
2278           current_file != initial_file) {
2279         if (refresh) {
2280           get_interface().simulation_has_stopped();
2281         }
2282 
2283         break;
2284       }
2285     }
2286 
2287     break;
2288   }
2289 }
2290 
2291 
2292 //--------------------------------------------------------------------------
run(bool refresh)2293 void ProgramMemoryAccess::run(bool refresh)
2294 {
2295   cpu->run(refresh);
2296 }
2297 
2298 
2299 //--------------------------------------------------------------------------
stop()2300 void ProgramMemoryAccess::stop()
2301 {
2302   bp.halt();
2303 }
2304 
2305 
2306 //--------------------------------------------------------------------------
finish()2307 void ProgramMemoryAccess::finish()
2308 {
2309   cpu->finish();
2310 }
2311 
2312 
2313 //--------------------------------------------------------------------------
2314 
hasValid_opcode_at_address(unsigned int address)2315 bool ProgramMemoryAccess::hasValid_opcode_at_address(unsigned int address)
2316 {
2317   if (getFromAddress(address)->isa() != instruction::INVALID_INSTRUCTION) {
2318     return true;
2319   }
2320 
2321   return false;
2322 }
2323 
2324 
hasValid_opcode_at_index(unsigned int uIndex)2325 bool ProgramMemoryAccess::hasValid_opcode_at_index(unsigned int uIndex)
2326 {
2327   if ((getFromIndex(uIndex))->isa() != instruction::INVALID_INSTRUCTION) {
2328     return true;
2329   }
2330 
2331   return false;
2332 }
2333 
2334 
2335 //--------------------------------------------------------------------------
2336 
isModified(unsigned int address)2337 bool ProgramMemoryAccess::isModified(unsigned int address)     // ***FIXME*** - address or index?
2338 {
2339   unsigned int uIndex = cpu->map_pm_address2index(address);
2340 
2341   if ((uIndex < cpu->program_memory_size()) &&
2342       cpu->program_memory[uIndex]->bIsModified()) {
2343     return true;
2344   }
2345 
2346   return false;
2347 }
2348 
2349 
2350 //========================================================================
2351 // Register Memory Access
2352 
RegisterMemoryAccess(Processor * new_cpu)2353 RegisterMemoryAccess::RegisterMemoryAccess(Processor *new_cpu) :
2354   MemoryAccess(new_cpu), initialized(false)
2355 {
2356   registers = nullptr;
2357   nRegisters = 0;
2358 }
2359 
2360 
~RegisterMemoryAccess()2361 RegisterMemoryAccess::~RegisterMemoryAccess()
2362 {
2363 }
2364 
2365 
2366 //--------------------------------------------------------------------------
2367 
get_register(unsigned int address)2368 Register *RegisterMemoryAccess::get_register(unsigned int address)
2369 {
2370   if (!cpu || !registers || nRegisters <= address) {
2371     return nullptr;
2372   }
2373 
2374   Register *reg = registers[address];
2375   // If there are breakpoints set on the register, then drill down
2376   // through them until we get to the real register.
2377   return reg ? reg->getReg() : nullptr;
2378 }
2379 
2380 
2381 //--------------------------------------------------------------------------
set_Registers(Register ** _registers,int _nRegisters)2382 void RegisterMemoryAccess::set_Registers(Register **_registers, int _nRegisters)
2383 {
2384   nRegisters = _nRegisters;
2385   registers = _registers;
2386 }
2387 
2388 
2389 //------------------------------------------------------------------------
2390 // insertRegister - Each register address may contain a linked list of registers.
2391 // The top most register is the one that is referenced whenever a processor
2392 // accesses the register memory. The primary purpose of the linked list is to
2393 // support register breakpoints. For example, a write breakpoint is implemented
2394 // with a breakpoint class derived from the register class. Setting a write
2395 // breakpoint involves creating the write breakpoint object and placing it
2396 // at the top of the register linked list. Then, when a processor attempts
2397 // to write to this register, the breakpoint object will capture this and
2398 // halt the simulation.
2399 
insertRegister(unsigned int address,Register * pReg)2400 bool RegisterMemoryAccess::insertRegister(unsigned int address, Register *pReg)
2401 {
2402   if (!cpu || !registers || nRegisters <= address || !pReg) {
2403     return false;
2404   }
2405 
2406   Register *ptop = registers[address];
2407   pReg->setReplaced(ptop);
2408   registers[address] = pReg;
2409   return true;
2410 }
2411 
2412 
2413 //------------------------------------------------------------------------
2414 // removeRegister - see comment on insertRegister. This method removes
2415 // a register object from the breakpoint linked list.
2416 
removeRegister(unsigned int address,Register * pReg)2417 bool RegisterMemoryAccess::removeRegister(unsigned int address, Register *pReg)
2418 {
2419   if (!cpu || !registers || nRegisters <= address || !pReg) {
2420     return false;
2421   }
2422 
2423   Register *ptop = registers[address];
2424 
2425   if (ptop == pReg  &&  pReg->getReplaced()) {
2426     registers[address] = pReg->getReplaced();
2427 
2428   } else
2429     while (ptop) {
2430       Register *pNext = ptop->getReplaced();
2431 
2432       if (pNext == pReg) {
2433         ptop->setReplaced(pNext->getReplaced());
2434         return true;
2435       }
2436 
2437       ptop = pNext;
2438     }
2439 
2440   return false;
2441 }
2442 
2443 
2444 //-------------------------------------------------------------------
hasBreak(unsigned int address)2445 bool RegisterMemoryAccess::hasBreak(unsigned int address)
2446 {
2447   if (!cpu || !registers || nRegisters <= address) {
2448     return false;
2449   }
2450 
2451   return registers[address]->isa() == Register::BP_REGISTER;
2452 }
2453 
2454 
2455 static InvalidRegister AnInvalidRegister(0, "AnInvalidRegister");
2456 
2457 //-------------------------------------------------------------------
operator [](unsigned int address)2458 Register &RegisterMemoryAccess::operator [](unsigned int address)
2459 {
2460   if (!registers || get_size() <= address) {
2461     return AnInvalidRegister;
2462   }
2463 
2464   return *registers[address];
2465 }
2466 
2467 
reset(RESET_TYPE r)2468 void RegisterMemoryAccess::reset(RESET_TYPE r)
2469 {
2470   for (unsigned int i = 0; i < nRegisters; i++) {
2471     // Do not reset aliased registers
2472     if (!(operator[](i).alias_mask && (operator[](i).alias_mask & i))) {
2473       operator[](i).reset(r);
2474     }
2475   }
2476 }
2477 
2478 
2479 //========================================================================
2480 // Processor Constructor
2481 
2482 ProcessorConstructorList *ProcessorConstructorList::processor_list;
2483 
GetList()2484 ProcessorConstructorList * ProcessorConstructorList::GetList()
2485 {
2486   return processor_list = ProcessorConstructor::GetList();
2487 }
2488 
2489 
ProcessorConstructor(tCpuContructor _cpu_constructor,const char * name1,const char * name2,const char * name3,const char * name4)2490 ProcessorConstructor::ProcessorConstructor(tCpuContructor _cpu_constructor,
2491     const char *name1,
2492     const char *name2,
2493     const char *name3,
2494     const char *name4)
2495 {
2496   cpu_constructor = _cpu_constructor;  // Pointer to the processor constructor
2497   names[0] = name1;                    // First name
2498   names[1] = name2;                    //  and three aliases...
2499   names[2] = name3;
2500   names[3] = name4;
2501   // Add the processor to the list of supported processors:
2502   GetList()->push_back(this);
2503 }
2504 
2505 
2506 //------------------------------------------------------------
ConstructProcessor(const char * opt_name)2507 Processor * ProcessorConstructor::ConstructProcessor(const char *opt_name)
2508 {
2509   // Instantiate a specific processor. If a name is provided, then that
2510   // will be used. Otherwise, the third name in the list of aliases for
2511   // this processor will be used instead. (Why 3rd?... Before optional
2512   // processor names were allowed, the default name matched what is now
2513   // the third alias; this maintains a backward compatibility).
2514   if (opt_name && *opt_name != '\0') {
2515     return cpu_constructor(opt_name);
2516   }
2517 
2518   return cpu_constructor(names[2]);
2519 }
2520 
2521 
2522 ProcessorConstructorList * ProcessorConstructor::processor_list;
2523 
GetList()2524 ProcessorConstructorList * ProcessorConstructor::GetList()
2525 {
2526   if (processor_list == nullptr) {
2527     processor_list = new ProcessorConstructorList();
2528   }
2529 
2530   return processor_list;
2531 }
2532 
2533 
2534 //------------------------------------------------------------
2535 // findByType -- search through the list of supported processors for
2536 //               the one matching 'name'.
2537 
2538 
findByType(const char * name)2539 ProcessorConstructor *ProcessorConstructorList::findByType(const char *name)
2540 {
2541   ProcessorConstructorList::iterator processor_iterator;
2542   ProcessorConstructorList *pl = ProcessorConstructor::GetList();
2543 
2544   for (processor_iterator = pl->begin();
2545        processor_iterator != pl->end();
2546        ++processor_iterator) {
2547     ProcessorConstructor *p = *processor_iterator;
2548 
2549     for (int j = 0; j < nProcessorNames; j++)
2550       if (p->names[j] && strcmp(name, p->names[j]) == 0) {
2551         return p;
2552       }
2553   }
2554 
2555   return nullptr;
2556 }
2557 
2558 
2559 //------------------------------------------------------------
2560 // dump() --  Print out a list of all of the processors
2561 //
2562 
DisplayString()2563 std::string ProcessorConstructorList::DisplayString()
2564 {
2565   std::ostringstream stream;
2566   std::list <ProcessorConstructor *>::iterator processor_iterator;
2567   const int nPerRow = 4;   // Number of names to print per row.
2568   int i, j, k, longest;
2569   ProcessorConstructorList *pl = ProcessorConstructor::GetList();
2570   ProcessorConstructor *p;
2571   // loop through all of the processors and find the
2572   // one with the longest name
2573   longest = 0;
2574 
2575   for (processor_iterator = pl->begin();
2576        processor_iterator != pl->end();
2577        ++processor_iterator) {
2578     p = *processor_iterator;
2579     k = strlen(p->names[1]);
2580 
2581     if (k > longest) {
2582       longest = k;
2583     }
2584   }
2585 
2586   // Print the name of each processor.
2587 
2588   for (processor_iterator = pl->begin();
2589        processor_iterator != pl->end();) {
2590     for (i = 0; i < nPerRow && processor_iterator != pl->end(); i++) {
2591       p = *processor_iterator++;
2592       stream << p->names[1];
2593 
2594       if (i < nPerRow - 1) {
2595         // if this is not the last processor in the column, then
2596         // pad a few spaces to align the columns.
2597         k = longest + 2 - strlen(p->names[1]);
2598 
2599         for (j = 0; j < k; j++) {
2600           stream << ' ';
2601         }
2602       }
2603     }
2604 
2605     stream << '\n';
2606   }
2607 
2608   stream << std::ends;
2609   return stream.str();
2610 }
2611 
2612 
2613 //------------------------------------------------------------------------
2614 
FileContext(std::string & new_name)2615 FileContext::FileContext(std::string &new_name)
2616   : name_str(new_name)
2617 {
2618 }
2619 
2620 
FileContext(const char * new_name)2621 FileContext::FileContext(const char *new_name)
2622 {
2623   if (new_name) {
2624     name_str = new_name;
2625   }
2626 }
2627 
2628 
~FileContext()2629 FileContext::~FileContext()
2630 {
2631 }
2632 
2633 
2634 //----------------------------------------
2635 // ReadSource
2636 //
2637 // This will open the file for this FileContext
2638 // and fill the line_seek vector with the file
2639 // positions corresponding to the start of every
2640 // source line in the file.
2641 //
2642 // e.g. lineseek[20] describes where the 20'th source
2643 // line is in the file.
2644 
ReadSource()2645 void FileContext::ReadSource()
2646 {
2647   if ((max_line() <= 0) || name_str.length() == 0) {
2648     return;
2649   }
2650 
2651   const char *str = name_str.c_str();
2652 
2653   // If the file is not open yet, then try to open it.
2654   if (!fptr) {
2655     fptr = fopen_path(str, "r");
2656   }
2657 
2658   // If the file still isn't open, then we have a problem
2659   // FIXME - should some corrective action be taken?
2660   if (!fptr) {
2661     std::cout << "Unable to open " << str << '\n';
2662     return;
2663   }
2664 
2665   line_seek.resize(max_line() + 1);
2666   pm_address.resize(max_line() + 1);
2667   std::rewind(fptr);
2668   char buf[256];
2669   line_seek[0] = 0;
2670 
2671   for (unsigned int j = 1; j <= max_line(); j++) {
2672     pm_address[j] = -1;
2673     line_seek[j] = ftell(fptr);
2674     char *s = fgets(buf, 256, fptr);
2675 
2676     if (s != buf) {
2677       break;
2678     }
2679   }
2680 }
2681 
2682 
2683 //----------------------------------------
2684 // ReadLine
2685 //
2686 // Read one line from a source file.
2687 
ReadLine(unsigned int line_number,char * buf,unsigned int nBytes)2688 char *FileContext::ReadLine(unsigned int line_number, char *buf, unsigned int nBytes)
2689 {
2690   if (buf && nBytes >= 1) {
2691     buf[0] = '\0';
2692   }
2693 
2694   if (!fptr) {
2695     return buf;
2696   }
2697 
2698   fseek(fptr,
2699         line_seek[line_number],
2700         SEEK_SET);
2701   return fgets(buf, nBytes, fptr);
2702 }
2703 
2704 
2705 //----------------------------------------
2706 //
gets(char * buf,unsigned int nBytes)2707 char *FileContext::gets(char *buf, unsigned int nBytes)
2708 {
2709   if (!fptr) {
2710     return nullptr;
2711   }
2712 
2713   return fgets(buf, nBytes, fptr);
2714 }
2715 
2716 
2717 //----------------------------------------
max_line()2718 unsigned int FileContext::max_line()
2719 {
2720   if (fptr && !m_uiMaxLine) {
2721     char buff[256];
2722     rewind();
2723     m_uiMaxLine = 0;
2724 
2725     while (fgets(buff, sizeof(buff), fptr)) {
2726       m_uiMaxLine++;
2727     }
2728   }
2729 
2730   return m_uiMaxLine;
2731 }
2732 
2733 
2734 //----------------------------------------
rewind()2735 void FileContext::rewind()
2736 {
2737   if (fptr) {
2738     fseek(fptr, 0, SEEK_SET);
2739   }
2740 }
2741 
2742 
2743 //----------------------------------------
open(const char * mode)2744 void FileContext::open(const char *mode)
2745 {
2746   if (!fptr) {
2747     fptr = fopen_path(name_str.c_str(), mode);
2748     max_line();
2749   }
2750 }
2751 
2752 
2753 //----------------------------------------
close()2754 void FileContext::close()
2755 {
2756   if (fptr) {
2757     fclose(fptr);
2758     fptr = nullptr;
2759   }
2760 }
2761 
2762 
2763 //----------------------------------------
get_address(unsigned int line_number)2764 int FileContext::get_address(unsigned int line_number)
2765 {
2766   if (line_number <= max_line() && pm_address.size() > line_number) {
2767     return pm_address[line_number];
2768   }
2769 
2770   return -1;
2771 }
2772 
2773 
2774 //----------------------------------------
put_address(unsigned int line_number,unsigned int address)2775 void FileContext::put_address(unsigned int line_number, unsigned int address)
2776 {
2777   if (line_number <= max_line()  && pm_address.size() > line_number && pm_address[line_number] < 0) {
2778     pm_address[line_number] = address;
2779   }
2780 }
2781 
2782 
2783 //------------------------------------------------------------------------
2784 
2785 
FileContextList()2786 FileContextList::FileContextList()
2787 {
2788   lastFile = 0;
2789   list_file_id = -1;  // assume that no list file is present.
2790 }
2791 
2792 
~FileContextList()2793 FileContextList::~FileContextList()
2794 {
2795   FileContextList::iterator it;
2796   FileContextList::iterator itEnd = end();
2797 
2798   for (it = begin(); it != itEnd; ++it) {
2799     it->close();
2800   }
2801 }
2802 
2803 
EndsWith(const std::string & sSubject,const std::string & sSubstring)2804 static bool EndsWith(const std::string &sSubject, const std::string &sSubstring)
2805 {
2806   if (sSubject.size() < sSubstring.size()) {
2807     return false;
2808 
2809   } else {
2810     std::string sSubjectEnding = sSubject.substr(sSubject.size() -
2811                                  sSubstring.size());
2812     return sSubjectEnding == sSubstring;
2813   }
2814 }
2815 
2816 
Find(std::string & fname)2817 int FileContextList::Find(std::string &fname)
2818 {
2819   if (lastFile) {
2820     for (int i = 0; i < lastFile; i++) {
2821       if (EndsWith((*this)[i]->name(), fname)) {
2822         return i;
2823       }
2824     }
2825   }
2826 
2827   return -1;
2828 }
2829 
2830 
2831 extern bool bHasAbsolutePath(std::string &fname);
2832 
Add(std::string & new_name,bool hll)2833 int FileContextList::Add(std::string &new_name, bool hll)
2834 {
2835   std::string sFull = bHasAbsolutePath(new_name) ? new_name : (sSourcePath + new_name);
2836   push_back(FileContext(sFull));
2837   back().setHLLId(hll);
2838   lastFile++;
2839 
2840   if (CSimulationContext::GetContext()->IsSourceEnabled()) {
2841     back().open("r");
2842 
2843     if (verbose)
2844       std::cout << "Added new file named: " << new_name
2845                 << "  id = " << lastFile << '\n';
2846   }
2847 
2848   return lastFile - 1;
2849 }
2850 
2851 
Add(const char * new_name,bool hll)2852 int FileContextList::Add(const char *new_name, bool hll)
2853 {
2854   std::string sNewName;
2855 
2856   if (new_name) {
2857     sNewName = new_name;
2858   }
2859 
2860   return Add(sNewName, hll);
2861 }
2862 
2863 
operator [](int file_id)2864 FileContext *FileContextList::operator [](int file_id)
2865 {
2866   if (file_id < 0 || file_id >= lastFile) {
2867     return nullptr;
2868   }
2869 
2870   return &this->_Myt::at(file_id);
2871 }
2872 
2873 
ReadLine(int file_id,int line_number,char * buf,int nBytes)2874 char *FileContextList::ReadLine(int file_id, int line_number, char *buf, int nBytes)
2875 {
2876   FileContext *fc = operator[](file_id);
2877 
2878   if (fc) {
2879     return fc->ReadLine(line_number, buf, nBytes);
2880   }
2881 
2882   buf[0] = '\0';
2883   return buf;
2884 }
2885 
2886 
2887 //----------------------------------------
2888 //
gets(int file_id,char * buf,int nBytes)2889 char *FileContextList::gets(int file_id, char *buf, int nBytes)
2890 {
2891   FileContext *fc = operator[](file_id);
2892 
2893   if (fc) {
2894     return fc->gets(buf, nBytes);
2895   }
2896 
2897   return nullptr;
2898 }
2899 
2900 
2901 //----------------------------------------
rewind(int file_id)2902 void FileContextList::rewind(int file_id)
2903 {
2904   FileContext *fc = operator[](file_id);
2905 
2906   if (fc) {
2907     fc->rewind();
2908   }
2909 }
2910 
2911 
2912 extern void EnsureTrailingFolderDelimiter(std::string &sPath);
2913 extern void SplitPathAndFile(std::string &sSource, std::string &sFolder, std::string &sFile);
2914 
2915 //----------------------------------------
SetSourcePath(const char * pPath)2916 void FileContextList::SetSourcePath(const char *pPath)
2917 {
2918   std::string sPath(pPath);
2919   std::string sFile;
2920   SplitPathAndFile(sPath, sSourcePath, sFile);
2921   EnsureTrailingFolderDelimiter(sSourcePath);
2922 }
2923 
2924 
2925 //----------------------------------------
2926 //
list_id(int new_list_id)2927 void FileContextList::list_id(int new_list_id)
2928 {
2929   FileContext *fc = operator[](list_file_id);
2930 
2931   if (fc) {
2932     fc->setListId(false);
2933   }
2934 
2935   list_file_id = new_list_id;
2936   fc = operator[](list_file_id);
2937 
2938   if (fc) {
2939     fc->setListId(true);
2940   }
2941 }
2942