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