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