1 /*
2    Copyright (C) 1998-2000 T. Scott Dattalo
3    Copyright (C) 2013      Roy R. Rankin
4 
5 This file is part of the libgpsim library of gpsim
6 
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11 
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, see
19 <http://www.gnu.org/licenses/lgpl-2.1.html>.
20 */
21 
22 #ifndef SRC_PIC_PROCESSORS_H_
23 #define SRC_PIC_PROCESSORS_H_
24 
25 #include <glib.h>
26 #include <stdio.h>
27 #include <iostream>
28 #include <string>
29 
30 #include "breakpoints.h"
31 #include "gpsim_classes.h"
32 #include "gpsim_object.h"
33 #include "processor.h"
34 #include "registers.h"
35 #include "tmr0.h"
36 
37 #include "pic-registers.h"
38 #include "14bit-registers.h"
39 #include "trigger.h"
40 #include "value.h"
41 
42 class ClockPhase;
43 class ConfigMemory;
44 class EEPROM;
45 class FSR;
46 class INDF;
47 class IOPIN;
48 class InterruptTraceType;
49 class PCHelper;
50 class PCL;
51 class PCLATH;
52 class PeripheralSignalSource;
53 class PicLatchRegister;
54 class PicPortRegister;
55 class PicTrisRegister;
56 class PinModule;
57 class PinMonitor;
58 class ResetTraceType;
59 class SignalControl;
60 class Stack;
61 class Status_register;
62 class WREG;
63 class instruction;
64 class pic_processor;
65 
66 enum PROCESSOR_TYPE
67 {
68     _PIC_PROCESSOR_,
69     _14BIT_PROCESSOR_,
70     _14BIT_E_PROCESSOR_, // 14bit enhanced processor
71     _12BIT_PROCESSOR_,
72     _PIC17_PROCESSOR_,
73     _PIC18_PROCESSOR_,
74     _P10F200_,
75     _P10F202_,
76     _P10F204_,
77     _P10F206_,
78     _P10F220_,
79     _P10F222_,
80     _P10F320_,
81     _P10LF320_,
82     _P10F322_,
83     _P10LF322_,
84     _P12C508_,
85     _P12C509_,
86     _P12F508_,
87     _P12F509_,
88     _P12F510_,
89     _P12F629_,
90     _P12F675_,
91     _P12F683_,
92     _P12F1822_,
93     _P12LF1822_,
94     _P12F1840_,
95     _P12LF1840_,
96     _P16C84_,
97     _P16CR83_,
98     _P16CR84_,
99     _P12CE518_,
100     _P12CE519_,
101     _P16F83_,
102     _P16F84_,
103     _P16C71_,
104     _P16C712_,
105     _P16C716_,
106     _P16C54_,
107     _P16C55_,
108     _P16C56_,
109     _P16C61_,
110     _P16C62_,
111     _P16C62A_,
112     _P16CR62_,
113     _P16F505_,
114     _P16F627_,
115     _P16F628_,
116     _P16F630_,
117     _P16F631_,
118     _P16F648_,
119     _P16F676_,
120     _P16F677_,
121     _P16F684_,
122     _P16F685_,
123     _P16F687_,
124     _P16F689_,
125     _P16F690_,
126     _P16C63_,
127     _P16C64_,
128     _P16C64A_,
129     _P16CR64_,
130     _P16C65_,
131     _P16C65A_,
132     _P16C72_,
133     _P16C73_,
134     _P16C74_,
135     _P16F73_,
136     _P16F74_,
137     _P16F716_,
138     _P16F87_,
139     _P16F88_,
140     _P16F818_,
141     _P16F819_,
142     _P16F871_,
143     _P16F873_,
144     _P16F873A_,
145     _P16F874_,
146     _P16F874A_,
147     _P16F876_,
148     _P16F876A_,
149     _P16F877_,
150     _P16F877A_,
151     _P16F882_,
152     _P16F883_,
153     _P16F884_,
154     _P16F886_,
155     _P16F887_,
156     _P16F913_,
157     _P16F914_,
158     _P16F916_,
159     _P16F917_,
160     _P16F1788_,
161     _P16F1503_,
162     _P16LF1503_,
163     _P16F1705_,
164     _P16LF1705_,
165     _P16F1709_,
166     _P16LF1709_,
167     _P16LF1788_,
168     _P16F1789_,
169     _P16F1823_,
170     _P16LF1823_,
171     _P16F1825_,
172     _P16LF1825_,
173     _P17C7xx_,
174     _P17C75x_,
175     _P17C752_,
176     _P17C756_,
177     _P17C756A_,
178     _P17C762_,
179     _P17C766_,
180     _P18Cxx2_,
181     _P18C2x2_,
182     _P18C242_,
183     _P18F242_,
184     _P18F248_,
185     _P18F258_,
186     _P18F448_,
187     _P18F458_,
188     _P18C252_,
189     _P18F252_,
190     _P18C442_,
191     _P18C452_,
192     _P18F442_,
193     _P18F452_,
194     _P18F1220_,
195     _P18F1320_,
196     _P18F14K22_,
197     _P18F2221_,
198     _P18F2321_,
199     _P18F2420_,
200     _P18F2455_,
201     _P18F2520_,
202     _P18F2525_,
203     _P18F2550_,
204     _P18F26K22_,
205     _P18F2620_,
206     _P18F4221_,
207     _P18F4321_,
208     _P18F4420_,
209     _P18F4455_,
210     _P18F4520_,
211     _P18F4550_,
212     _P18F4620_,
213     _P18F6520_,
214 };
215 
216 // Configuration modes.  DELETE THIS...
217 //  The configuration mode bits are the config word bits remapped.
218 //  The remapping removes processor dependent bit definitions.
219 class ConfigMode
220 {
221 public:
222 
223     enum
224     {
225         CM_FOSC0 = 1<<0,    // FOSC0 and  FOSC1 together define the PIC clock
226         CM_FOSC1 = 1<<1,    // All PICs todate have these two bits, but the
227         // ones with internal oscillators use them differently
228         CM_WDTE =  1<<2,    // Watch dog timer enable
229         CM_CP0 =   1<<3,    // Code Protection
230         CM_CP1 =   1<<4,
231         CM_PWRTE = 1<<5,    // Power on/Reset timer enable
232         CM_BODEN = 1<<6,    // Brown out detection enable
233         CM_CPD =   1<<7,
234         CM_MCLRE = 1<<8,    // MCLR enable
235 
236         CM_FOSC1x = 1<<31,   // Hack for internal oscillators
237     };
238 
239     int config_mode;
240     int valid_bits;
241 
ConfigMode()242     ConfigMode()
243     {
244         config_mode = 0xffff;
245         valid_bits = CM_FOSC0 | CM_FOSC1 | CM_WDTE;
246     }
247 
~ConfigMode()248     virtual ~ConfigMode()
249     {
250     }
251 
set_config_mode(int new_value)252     virtual void set_config_mode(int new_value) { config_mode = new_value & valid_bits;}
set_valid_bits(int new_value)253     virtual void set_valid_bits(int new_value) { valid_bits = new_value;}
set_fosc0()254     void set_fosc0() {config_mode |= CM_FOSC0;}
clear_fosc0()255     void clear_fosc0() {config_mode &= ~CM_FOSC0;}
get_fosc0()256     bool get_fosc0() {return (config_mode & CM_FOSC0);}
set_fosc1()257     void set_fosc1() {config_mode |= CM_FOSC1;}
clear_fosc1()258     void clear_fosc1() {config_mode &= ~CM_FOSC1;}
get_fosc1()259     bool get_fosc1() {return (0 != (config_mode & CM_FOSC1));}
get_fosc1x()260     bool get_fosc1x() {return (0 != (config_mode & CM_FOSC1x));}
set_fosc01(int v)261     void set_fosc01(int v)
262     {
263         config_mode = (config_mode & ~(CM_FOSC0 | CM_FOSC1)) |
264                       (v & (CM_FOSC0 | CM_FOSC1));
265     }
266 
set_cp0()267     void set_cp0()
268     {
269         config_mode |= CM_CP0;
270         valid_bits |= CM_CP0;
271     }
clear_cp0()272     void clear_cp0()
273     {
274         config_mode &= ~CM_CP0;
275         valid_bits |= CM_CP0;
276     }
get_cp0()277     bool get_cp0()  {return (0 != (config_mode & CM_CP0));}
set_cp1()278     void set_cp1()
279     {
280         config_mode |= CM_CP1;
281         valid_bits |= CM_CP1;
282     }
clear_cp1()283     void clear_cp1()
284     {
285         config_mode &= ~CM_CP1;
286         valid_bits |= CM_CP1;
287     }
get_cp1()288     bool get_cp1()  {return (0 != (config_mode & CM_CP1));}
289 
enable_wdt()290     void enable_wdt()  {config_mode |= CM_WDTE;}
disable_wdt()291     void disable_wdt() {config_mode &= ~CM_WDTE;}
set_wdte(bool b)292     void set_wdte(bool b) { config_mode = b ? (config_mode | CM_WDTE) : (config_mode & ~CM_WDTE); }
get_wdt()293     bool get_wdt()     {return (0 != (config_mode & CM_WDTE));}
294 
set_mclre(bool b)295     void set_mclre(bool b) { config_mode = b ? (config_mode | CM_MCLRE) : (config_mode & ~CM_MCLRE); }
get_mclre()296     bool get_mclre()     {return (0 != (config_mode & CM_MCLRE));}
297 
enable_pwrte()298     void enable_pwrte()
299     {
300         config_mode |= CM_PWRTE;
301         valid_bits |= CM_PWRTE;
302     }
disable_pwrte()303     void disable_pwrte()
304     {
305         config_mode &= ~CM_PWRTE;
306         valid_bits |= CM_PWRTE;
307     }
set_pwrte(bool b)308     void set_pwrte(bool b) { config_mode = b ? (config_mode | CM_PWRTE) : (config_mode & ~CM_PWRTE); }
get_pwrte()309     bool get_pwrte()      {return (0 != (config_mode & CM_PWRTE));}
is_valid_pwrte()310     bool is_valid_pwrte() {return (0 != (valid_bits & CM_PWRTE));}
311 
312     virtual void print();
313 
314 };
315 
316 
317 //---------------------------------------------------------
318 // Watch Dog Timer
319 //
320 
321 class WDT : public TriggerObject, public gpsimObject
322 {
323 public:
324     WDT(pic_processor *, double _timeout);
325 
326     void put(unsigned int new_value);
327     virtual void initialize(bool enable, bool _use_t0_prescale = true);
328     virtual void swdten(bool enable);
329     void set_timeout(double);
330     virtual void set_prescale(unsigned int);
331     virtual void set_postscale(unsigned int);
332     virtual void reset(RESET_TYPE r);
333     void clear();
334     virtual void callback();
335     virtual void update();
336     virtual void callback_print();
337     void set_breakpoint(unsigned int bpn);
hasBreak()338     bool hasBreak() { return breakpoint != 0;}
339 
340 protected:
341     pic_processor *cpu;           // The cpu to which this wdt belongs.
342 
343     unsigned int breakpoint = 0;
344     unsigned int prescale;
345     unsigned int postscale;
346     guint64 future_cycle = 0;
347 
348     double timeout;   // When no prescaler is assigned
349     bool   wdte = false;
350     bool   warned = false;
351     bool   cfgw_enable = false;  // Enabled from Configureation word
352     bool   use_t0_prescale = false;
353 
354 
355 };
356 
357 /*==================================================================
358  * FIXME - move these global references somewhere else
359  */
360 #include "cmd_gpsim.h"
361 extern guint64 gui_update_rate; // The rate (in simulation cycles) at which the gui is updated
362 
363 /*==================================================================
364  *
365  * Here are the base class declarations for the pic processors
366  */
367 
368 /*
369  * First, forward-declare a few class references
370  */
371 
372 enum IOPIN_TYPES
373 {
374     INPUT_ONLY,          // e.g. MCLR
375     BI_DIRECTIONAL,      // most iopins
376     BI_DIRECTIONAL_PU,   // same as bi_directional, but with pullup resistor. e.g. portb
377     OPEN_COLLECTOR       // bit4 in porta on the 18 pin midrange devices.
378 };
379 
380 /*
381  * Define a base class processor for the pic processor family
382  *
383  * All pic processors are derived from this class.
384  */
385 
386 class pic_processor : public Processor
387 {
388 public:
389 
390     unsigned int config_word = 0;      // as read from hex or cod file
391     ConfigMode   *config_modes;    // processor dependent configuration bits.
392 
393     unsigned int pll_factor = 0;       // 2^pll_factor is the speed boost the PLL adds
394     // to the instruction execution rate.
395 
396     WDT          wdt;
397 
398     INDF         *indf = nullptr;
399     FSR          *fsr = nullptr;
400     Stack        *stack = nullptr;
401 
402     Status_register *status = nullptr;
403     WREG	 *Wreg = nullptr;	// Used when W is a normal register
404     PCL          *pcl = nullptr;
405     PCLATH       *pclath = nullptr;
406     PCHelper     *m_PCHelper = nullptr;
407     TMR0         tmr0;
408     int          num_of_gprs = 0;
409 
410     EEPROM      *eeprom = nullptr;      // set to NULL for PIC's that don't have a data EEPROM
411 
412     bool LoadProgramFile(const char *pFilename,
413                          FILE *pFile,
414                          const char *pProcessorName
415                         );
416 
417     void add_sfr_register(Register *reg, unsigned int addr,
418                           RegisterValue por_value=RegisterValue(0,0),
419                           const char *new_name=nullptr,
420                           bool warn_dup = true);
421     void add_sfr_registerR(sfr_register *reg, unsigned int addr,
422                            RegisterValue por_value=RegisterValue(0,0),
423                            const char *new_name=nullptr,
424                            bool warn_dup = true);
425     void delete_sfr_register(Register *pReg);
426     void remove_sfr_register(Register *pReg);
427 
428     void init_program_memory(unsigned int memory_size);
429     void build_program_memory(int *memory, int minaddr, int maxaddr);
430 
431     virtual instruction * disasm ( unsigned int address,unsigned int inst)=0;
432     virtual void create_config_memory() = 0;
tris_instruction(unsigned int tris_register)433     virtual void tris_instruction(unsigned int tris_register) {return;}
434     virtual void create_symbols();
435     virtual void run(bool refresh=true);
436     virtual void finish();
437 
438     void sleep();
439     virtual void enter_sleep();
440     virtual void exit_sleep();
exit_wdt_sleep()441     virtual bool exit_wdt_sleep() { return true; } // WDT wakes sleep
swdten_active()442     virtual bool swdten_active() { return true; } // WDTCON can enable WDT
443     bool is_sleeping();
444     virtual void step(unsigned int steps,bool refresh=true);
445     virtual void step_over(bool refresh=true);
446     virtual void step_cycle();
447 
448     virtual void step_one(bool refresh=true)
449     {
450         (void)refresh;
451         if (pc->value < program_memory_size())
452         {
453             program_memory[pc->value]->execute();
454         }
455         else
456         {
457             std::cout << "Program counter not valid " << std::hex << pc->value << '\n';
458             get_bp().halt();
459         }
460     }
461 
462     // Take a snap shot of the internal state.
463     virtual void save_state();
464 
interrupt()465     virtual void interrupt() {}
466     //// TEMPORARY - consolidate the various bp.set_interrupt() calls to one function:
467     void BP_set_interrupt();
468     void pm_write();
469 
getConfigMemory()470     virtual ConfigMemory * getConfigMemory() { return m_configMemory;}
471     virtual bool set_config_word(unsigned int address, unsigned int cfg_word);
472     virtual unsigned int get_config_word(unsigned int address);
473     virtual int get_config_index(unsigned int address);
config_word_address()474     virtual unsigned int config_word_address() const {return 0x2007;}
create_ConfigMode()475     virtual ConfigMode *create_ConfigMode() { return new ConfigMode; }
476     virtual void reset(RESET_TYPE r);
477 
478     virtual void create();
479 
isa()480     virtual PROCESSOR_TYPE isa() {return _PIC_PROCESSOR_;}
base_isa()481     virtual PROCESSOR_TYPE base_isa() {return _PIC_PROCESSOR_;}
access_gprs()482     virtual unsigned int access_gprs() { return 0; }
bugs()483     virtual unsigned int bugs() { return 0; }    // default is no errata
484 
485     /* The program_counter class calls these two functions to get the upper bits of the PC
486      * for branching (e.g. goto) or modify PCL instructions (e.g. addwf pcl,f) */
487     virtual unsigned int get_pclath_branching_jump()=0;
488     virtual unsigned int get_pclath_branching_modpcl()=0;
489 
490     virtual void option_new_bits_6_7(unsigned int)=0;
put_option_reg(unsigned int)491     virtual void put_option_reg(unsigned int) {}
492 
493     virtual void set_eeprom(EEPROM *e);
get_eeprom()494     virtual EEPROM *get_eeprom() { return (eeprom); }
495     virtual void createMCLRPin(int pkgPinNumber);
496     virtual void assignMCLRPin(int pkgPinNumber);
497     virtual void unassignMCLRPin();
498     virtual void osc_mode(unsigned int );
set_config3h(gint64 x)499     virtual void set_config3h(gint64 x) {;}
string_config3h(gint64 x)500     virtual std::string string_config3h(gint64 x) {return "fix string_config3h";}
501 
502 
503     // Activity States reflect what the processor is currently doing
504     // (The breakpoint class formally implemented this functionality).
505     enum eProcessorActivityStates
506     {
507         ePAActive,      // Normal state
508         ePAIdle,        // Processor is held in reset
509         ePASleeping,    // Processor is sleeping
510         ePAInterrupt,   // do we need this?
511         ePAPMWrite      // Processor is busy performing a program memory write
512     };
513 
getActivityState()514     eProcessorActivityStates getActivityState() { return m_ActivityState; }
515 
516     pic_processor(const char *_name=nullptr, const char *desc=nullptr);
517     virtual ~pic_processor();
518 
set_osc_pin_Number(unsigned int i,unsigned int val,PinModule * pm)519     void set_osc_pin_Number(unsigned int i, unsigned int val, PinModule *pm)
520     {
521         if (i < 4)
522         {
523             osc_pin_Number[i] = val;
524             m_osc_Monitor[i] = pm;
525         }
526     }
get_osc_pin_Number(unsigned int i)527     unsigned char get_osc_pin_Number(unsigned int i)
528     {return (i<4)?osc_pin_Number[i]:253;}
get_osc_PinMonitor(unsigned int i)529     PinModule * get_osc_PinMonitor(unsigned int i)
530     { return (i<4)?m_osc_Monitor[i]:0; }
531 
532 
533     void set_clk_pin(unsigned int pkg_Pin_Number,
534                      PinModule *PinMod,
535                      const char * name,
536                      bool in,
537                      PicPortRegister *m_port = 0,
538                      PicTrisRegister *m_tris = 0,
539                      PicLatchRegister *m_lat = 0
540                     );
541     void clr_clk_pin(unsigned int pkg_Pin_Number, PinModule *PinMod,
542                      PicPortRegister *m_port = 0,
543                      PicTrisRegister *m_tris = 0,
544                      PicLatchRegister *m_lat = 0
545                     );
546 
set_int_osc(bool val)547     virtual void set_int_osc(bool val) { internal_osc = val;}
get_int_osc()548     virtual bool get_int_osc() { return internal_osc; }
set_pplx4_osc(bool val)549     virtual void set_pplx4_osc(bool val) { PPLx4 = val;}
get_pplx4_osc()550     virtual bool get_pplx4_osc() { return PPLx4; }
set_pps1way(bool val)551     virtual void set_pps1way(bool val) { pps1way = val;}
get_pps1way()552     virtual bool get_pps1way() { return pps1way; }
set_zcddis(bool val)553     virtual void set_zcddis(bool val) { zcddis = val;}
get_zcddis()554     virtual bool get_zcddis() { return zcddis; }
555 
556     virtual void Wput(unsigned int);
557     virtual unsigned int Wget();
558 
559 
560 
561 
562 protected:
563     ConfigMemory *m_configMemory = nullptr;
564     eProcessorActivityStates m_ActivityState = ePAActive;
565     ResetTraceType *m_pResetTT;
566     InterruptTraceType *m_pInterruptTT;
567     // Most midrange PIC's have a dedicated MCLR pin.
568     // For the ones that don't, m_MCLR will be null.
569     IOPIN *m_MCLR = nullptr;
570     IOPIN *m_MCLR_Save = nullptr;
571     int   m_MCLR_pin = 0;
572     PinMonitor *m_MCLRMonitor = nullptr;
573     std::string m_mclr_pin_name;
574     unsigned char osc_pin_Number[4];
575     PinModule *m_osc_Monitor[4];
576     bool internal_osc = false;	// internal RC oscilator enabled on Config Word
577     bool PPLx4 = false;		// 4x PPL enabled on Config Word
578     bool pps1way = false;	// PPS can be locked but not unlocked from Config Word
579     PeripheralSignalSource *clksource = nullptr;
580     bool zcddis = false;	// ZCD enable set by ZCDSEN bit of ZCDCON if true
581 
582     SignalControl *clkcontrol = nullptr;
583     guint64 sleep_time;
584     ClockPhase *save_pNextPhase = nullptr;
585     ClockPhase *save_CurrentPhase = nullptr;
586 };
587 
588 
589 #define cpu_pic ( (pic_processor *)cpu)
590 
591 
592 // Bit field of known silicon bugs
593 #define BUG_NONE        0
594 #define BUG_DAW         0x00000001
595 
596 
597 
598 
599 //------------------------------------------------------------------------
600 // Base Class for configuration memory
601 //
602 // The configuration memory is only a tiny portion of the overall processor
603 // program memory space (only 1-word on the mid range devices). So, explicit
604 // attributes are created for each memory configuration word. Since the meaning
605 // of configuration memory varies from processor to processor, it is up to
606 // each process to derive from this class.
607 
608 
609 class ConfigWord : public Integer
610 {
611 public:
612     ConfigWord(const char *_name, unsigned int default_val, const char *desc,
613                pic_processor *pCpu, unsigned int addr, bool EEw=true);
614     virtual void get(char *buffer, int buf_size);
615     virtual void get(gint64 &i);
ConfigWordAdd()616     unsigned int ConfigWordAdd() { return m_addr; }
isEEWritable()617     bool isEEWritable() { return EEWritable;}
618 
619 protected:
620     pic_processor *m_pCpu;
621     unsigned int m_addr;
622     bool EEWritable;
623 };
624 
625 class ConfigMemory
626 {
627 public:
628     ConfigMemory(pic_processor *pCpu, unsigned int nWords);
629     ~ConfigMemory();
630     int addConfigWord(unsigned int addr, ConfigWord *);
631     ConfigWord *getConfigWord(unsigned int addr);
getnConfigWords()632     int getnConfigWords() { return m_nConfigWords; }
633 
634 protected:
635     pic_processor *m_pCpu;
636     ConfigWord **m_ConfigWords;
637     unsigned int m_nConfigWords;
638 };
639 
640 /*
641 class ConfigMemory : public Integer
642 {
643 public:
644   ConfigMemory(const char *_name, unsigned int default_val, const char *desc,
645                pic_processor *pCpu, unsigned int addr);
646 protected:
647   pic_processor *m_pCpu;
648   unsigned int m_addr;
649 };
650 */
651 #endif
652