/* Copyright (C) 2002 Ralf Forsberg This is based on the program icdprog 0.3 made by Geir Thomassen gpsim is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gpsim is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gpasm; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* FIXME - the design of this code needs to be revisited. Instead of making the icd a separate entity that "controls" a a processor, it makes MUCH more sense to derive the Icd class from the Processor class and let it effectively intercept and re-direct calls to the processor being debugged. This way, the gui and cli (and even external regression testing scripts) can treat the Icd just like it's another processor - no special circumstances are required. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../config.h" #include "pic-processor.h" #include "icd.h" #define BAUDRATE B57600 // Not all OSs support the O_SYNC open flag #ifndef O_SYNC #define O_SYNC 0 #endif static bool use_icd = false; static int bulk_flag = 0; extern Processor *active_cpu; static int icd_fd; /* file descriptor for serial port */ static int icd_sync(void); bool get_use_icd() { return use_icd; } /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// class icd_Register : public Register { public: Register *replaced; int is_stale; icd_Register(); virtual REGISTER_TYPES isa(void) {return replaced->isa();}; virtual string &name(void) { if(replaced) return replaced->name(); else return gpsimValue::name(); }; virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual unsigned int get_value(void); virtual unsigned int get(void); }; class icd_StatusReg : public Status_register { public: Status_register *replaced; int is_stale; icd_StatusReg(); virtual REGISTER_TYPES isa(void) {return replaced->isa();}; virtual string &name(void) { if(replaced) return replaced->name(); else return gpsimValue::name(); } virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual unsigned int get_value(void); virtual unsigned int get(void); }; class icd_WREG : public WREG { public: WREG *replaced; int is_stale; icd_WREG(); virtual REGISTER_TYPES isa(void) {return replaced->isa();}; virtual string &name(void) { if(replaced) return replaced->name(); else return gpsimValue::name(); } virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual unsigned int get_value(void); virtual unsigned int get(void); }; class icd_PCLATH : public PCLATH { public: PCLATH *replaced; int is_stale; icd_PCLATH(); virtual REGISTER_TYPES isa(void) {return replaced->isa();}; virtual string &name(void) { if(replaced) return replaced->name(); else return gpsimValue::name(); } virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual unsigned int get_value(void); virtual unsigned int get(void); }; class icd_FSR : public FSR { public: FSR *replaced; int is_stale; icd_FSR(); virtual REGISTER_TYPES isa(void) {return replaced->isa();}; virtual string &name(void) { if(replaced) return replaced->name(); else return gpsimValue::name(); } virtual void put_value(unsigned int new_value); virtual void put(unsigned int new_value); virtual unsigned int get_value(void); virtual unsigned int get(void); }; class icd_PC : public Program_Counter { public: Program_Counter *replaced; int is_stale; icd_PC(); virtual void put_value(unsigned int new_value); virtual unsigned int get_value(void); }; /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// static void udelay(unsigned usec) { /* wait for msec milliseconds or more ... */ struct timespec time; time.tv_sec = usec / 1000000; time.tv_nsec = ( usec % 1000000) * 1000; nanosleep(&time,0); } static void dtr_set() { int flag = TIOCM_DTR; if(icd_fd<0) return; if(ioctl(icd_fd, TIOCMBIS, &flag)) { perror("ioctl"); exit(-1); } } static void dtr_clear() { int flag = TIOCM_DTR; if(icd_fd<0) return; if(ioctl(icd_fd, TIOCMBIC, &flag)) { perror("ioctl"); exit(-1); } } static void rts_set() { int flag = TIOCM_RTS; if(icd_fd<0) return; if(ioctl(icd_fd, TIOCMBIS, &flag)) { perror("ioctl"); exit(-1); } } static void rts_clear() { int flag = TIOCM_RTS; if(icd_fd<0) return; if(ioctl(icd_fd, TIOCMBIC, &flag)) { perror("ioctl"); exit(-1); } } void icd_hw_reset() { if(icd_fd<0) return; rts_clear(); dtr_clear(); /* reset */ udelay(10000); dtr_set(); /* remove reset */ } static int icd_write(const char *s) { if(icd_fd<0) return -1; write(icd_fd,s, strlen(s)); /* Error checking ... */ return 1; } static int icd_read(unsigned char *p, int len) { int n_read; n_read=read(icd_fd,p,1); rts_clear(); udelay(1); rts_set(); if(n_read != 1) { cout << "Error in number of bytes read \n"; cout << "len="<1) return n_read+icd_read(p+1,len-1); return n_read; } #define MAX_CMD_LEN 100 static int icd_cmd(const char *cmd, ...) { char command[MAX_CMD_LEN]; unsigned char resp[3]; va_list ap; if(icd_fd<0) return -1; va_start(ap, cmd); (void) vsnprintf(command,MAX_CMD_LEN, cmd, ap); va_end(ap); icd_write(command); if(!icd_read(resp,2)) { icd_sync(); icd_write(command); if(!icd_read(resp,2)) { cout << "Command "<0) { tries--; if(icd_cmd("$$6307\r")==1) return 1; icd_write("$"); icd_read(buf,0x42); } puts("***************** DID NOT SYNC!"); return 0; } static int icd_baudrate_init() { int tries=3; char ch; if(icd_fd<0) return 0; while(tries) { write(icd_fd,"U",1); if(read(icd_fd,&ch,1) > 0) { rts_clear(); udelay(10); rts_set(); if(ch=='u') { return 1; } } tries--; } return 0; } char *icd_target(void) { static char return_string[256]; unsigned int dev_id, type,rev; if(icd_fd<0) return 0; dev_id=icd_cmd("$$7020\r"); type = (dev_id>>5) & 0x1FF; rev = type & 0x1F; if(dev_id == 0x3FFF) { sprintf(return_string,"no target"); } else { switch(type) { case 0x68: sprintf(return_string,"16F870 rev %d",rev); break; case 0x69: sprintf(return_string,"16F871 rev %d",rev); break; case 0x47: sprintf(return_string,"16F872 rev %d",rev); break; case 0x4B: sprintf(return_string,"16F873 rev %d",rev); break; case 0x49: sprintf(return_string,"16F874 rev %d",rev); break; case 0x4F: sprintf(return_string,"16F876 rev %d",rev); break; case 0x4D: sprintf(return_string,"16F877 rev %d",rev); break; default: sprintf(return_string,"Unknown, device id = %02X",dev_id); break; } } return return_string; } struct termios oldtio, newtio; void put_dumb_register(Register **frp, int address) { Register *fr = *frp; icd_Register *ir = new icd_Register; ir->set_cpu(fr->get_cpu()); *frp = ir; ir->replaced = fr; ir->address = address; } void put_dumb_status_register(Status_register **frp) { Status_register *fr = *frp; icd_StatusReg *ir = new icd_StatusReg; ir->set_cpu(fr->get_cpu()); *frp = ir; ir->replaced = fr; ir->address = fr->address; } void put_dumb_pc_register(Program_Counter **frp) { Program_Counter *fr = *frp; icd_PC *ir = new icd_PC; ir->set_cpu(fr->get_cpu()); ir->memory_size_mask = fr->memory_size_mask; *frp = ir; ir->replaced = fr; } void put_dumb_pclath_register(PCLATH **frp) { PCLATH *fr = *frp; icd_PCLATH *ir = new icd_PCLATH; ir->set_cpu(fr->get_cpu()); *frp = ir; ir->replaced = fr; } void put_dumb_w_register(WREG **frp) { WREG *fr = *frp; icd_WREG *ir = new icd_WREG; ir->set_cpu(fr->get_cpu()); *frp = ir; ir->replaced = fr; } void put_dumb_fsr_register(FSR **frp) { FSR *fr = *frp; icd_FSR *ir = new icd_FSR; ir->set_cpu(fr->get_cpu()); *frp = ir; ir->replaced = fr; } static void create_dumb_register_file(void) { pic_processor *cpu=dynamic_cast(active_cpu); if(!cpu) return; for(unsigned int i=0;iregister_memory_size();i++) { put_dumb_register(&cpu->registers[i], i); } put_dumb_status_register(&cpu->status); put_dumb_pc_register(&cpu->pc); put_dumb_pclath_register(&cpu->pclath); put_dumb_w_register(&cpu->W); put_dumb_fsr_register(&cpu->fsr); } int icd_connect(char *port) { pic_processor *pic=dynamic_cast(active_cpu); if(!pic) { cout << "You have to load the .cod file (or .hex and processor)" << endl; return 0; } if((icd_fd=open(port, O_NOCTTY | O_RDWR | O_SYNC)) == -1) { perror("Error opening device:"); return 0; } tcgetattr(icd_fd, &oldtio); memset(&newtio,0, sizeof(newtio)); newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 100; newtio.c_cc[VMIN] = 0; tcflush(icd_fd, TCIFLUSH); tcsetattr(icd_fd, TCSANOW, &newtio); icd_hw_reset(); rts_set(); if(!icd_baudrate_init()) { fprintf(stderr,"Can't initialize the ICD\n"); return 0; } create_dumb_register_file(); use_icd=true; icd_cmd("$$6300\r"); /* I really don't know what this is, but MPLAB does this. The program works ok without this though ..*/ // printf("ICD ver %s, target %s\n",icd_version(),icd_target()); // printf("Vdd %.2f, Vpp %.2f\n", icd_vdd(), icd_vpp()); if(icd_has_debug_module()) { if(verbose) cout << "Debug module present"<(active_cpu); if(!cpu) return; for(unsigned int i=0;iregister_memory_size();i++) { icd_Register *ir = dynamic_cast(cpu->registers[i]); assert(ir!=0); ir->is_stale=1; } icd_WREG *iw = dynamic_cast(cpu->W); assert(iw!=0); iw->is_stale=1; icd_PC *ipc = dynamic_cast(cpu->pc); assert(ipc!=0); ipc->is_stale=1; icd_PCLATH *ipclath = dynamic_cast(cpu->pclath); assert(ipclath!=0); ipclath->is_stale=1; icd_FSR *ifsr = dynamic_cast(cpu->fsr); assert(ifsr!=0); ifsr->is_stale=1; icd_StatusReg *isreg = dynamic_cast(cpu->status); assert(isreg!=0); isreg->is_stale=1; } int icd_reset(void) { if(icd_fd<0) return 0; cout << "Reset" << endl; icd_cmd("$$700A\r"); icd_cmd("$$701B\r"); make_stale(); pic_processor *pic=dynamic_cast(active_cpu); if(!pic) return 0; pic->pc->get_value(); gi.simulation_has_stopped(); return 1; } int icd_detected(void) { if(icd_fd<0) return 0; if(use_icd) return 1; return 0; } char *icd_version(void) { static char ret[256]; unsigned int ver1,ver2; if(icd_fd<0) return 0; ver1 = icd_cmd("$$7F00\r"); ver2 = icd_cmd("$$7021\r"); sprintf(ret, "%X.%02X.%02X", ver1>>8, ver1&0xFF, ver2); return ret; } float icd_vdd(void) { unsigned int vdd=0; if(icd_fd<0) return 0.0; vdd=icd_cmd("$$701C\r"); return ((double)vdd) / 40.0; } float icd_vpp(void) { unsigned int vpp=0; if(icd_fd<0) return 0.0; icd_cmd("$$7000\r"); // enable Vpp vpp=icd_cmd("$$701D\r") & 0xFF; // What the heck does the high byte contain ? icd_cmd("$$7001\r"); // disable Vpp return ((double)vpp) / 11.25; } int icd_step(void) { if(icd_fd<0) return 0; make_stale(); icd_cmd("$$700E\r"); return 1; } int icd_run(void) { if(icd_fd<0) return 0; make_stale(); if(icd_cmd("$$700F\r")!=1) { icd_sync(); if(icd_cmd("$$700F\r")!=1) cout << "fjsdk" << endl; } return 1; } int icd_stopped(void) { if(icd_fd<0) return 0; if(icd_cmd("$$701E\r")!=1) return 1; return 0; } int icd_halt(void) { if(icd_fd<0) return 0; make_stale(); icd_cmd("$$700D\r"); return 1; } int icd_set_break(int address) { if(icd_fd<0) return 0; cout << "Set breakpoint on address " << address << endl; icd_cmd("$$1F00\r"); if(icd_cmd("$$%04X\r",address)!=address) { puts("DEBUG: Set breakpoint failed?"); return 0; } return 1; } int icd_clear_break(void) { if(icd_fd<0) return 0; cout << "Clear breakpoints" << endl; icd_cmd("$$1F00\r"); return 1; } void icd_set_bulk(int flag) { bulk_flag=flag; } // Get the value of the specified file memory address /*int icd_read_file(int address) { unsigned char buf[8]; int offset = address - address%8; if(icd_fd<0) return 0; int value; cout << "this is deprecated" << endl; icd_cmd("$$%04X\r",0x7800+offset); icd_cmd("$$7C08\r"); icd_write("$$7D08\r"); icd_read(buf,8); value = buf[address%8]; pic_processor *pic=dynamic_cast(active_cpu); if(!pic) return; //if(gpsim_register_is_valid(1,REGISTER_RAM,address) && // !gpsim_register_is_alias(1,REGISTER_RAM,address)) { switch(address) { case 2: case 3: case 4: case 10: break; default: pic->registers[address]->put_value(value); cout << "Read file address " << address << "=" << value << endl; break; } } return 1; } int icd_write_file(int address, int data) { if(icd_fd<0) return 0; printf("Write file address 0x%04X with data 0x%02X\n",address,data); return 1; } int icd_read_eeprom(int address) { if(icd_fd<0) return 0; printf("Read eeprom address 0x%04X\n",address); return 1; } int write_eeprom(int address, int data) { if(icd_fd<0) return 0; printf("Write eeprom address 0x%04X with data 0x%02X\n",address,data); return 1; } int icd_get_state() { int pc=4, status, w, pclath, fsr; if(icd_fd<0) return 0; cout << "Get state" << endl; pc=icd_cmd("$$701F\r"); status=icd_cmd("$$7016\r")&0x00ff; w=icd_cmd("$$7017\r")&0x00ff; pclath=icd_cmd("$$7018\r")&0x00ff; fsr=icd_cmd("$$7019\r")&0x00ff; pic_processor *pic=dynamic_cast(active_cpu); if(!pic) return; pic->pc->put_value(pc); pic->status->put_value(status); pic->W->put_value(w); pic->pclath->put_value(pclath); pic->fsr->put_value(fsr); return 1; } */ // Get all of file memory /*int icd_get_file() { unsigned char buf[64]; if(icd_fd<0) return 0; cout << "Get file" << endl; pic_processor *pic=dynamic_cast(active_cpu); if(!pic) return; for(int i=0;iregister_memory_size()/0x40;i++) { if(icd_cmd("$$%04X\r",0x7A00+i)!=i) puts("EEEEEEEEEEEEEEEEEEEEE"); icd_write("$$7D40\r"); icd_read(buf,64); for(int j=0;j<64;j++) { if(gpsim_register_is_valid(1,REGISTER_RAM,i*0x40+j) && !gpsim_register_is_alias(1,REGISTER_RAM,i*0x40+j)) { switch(i*0x40+j) { case 2: case 3: case 4: case 10: break; default: pic->registers[i*0x40+j]->put_value(buf[j]); break; } } } // } return 1; } */ icd_Register::icd_Register() { replaced=0; value.put(0x42); is_stale=1; }; void icd_Register::put_value(unsigned int new_value) { } void icd_Register::put(unsigned int new_value) { } unsigned int icd_Register::get_value(void) { return(get()); } unsigned int icd_Register::get(void) { if(is_stale) { switch(address) { case 2: value.put(icd_cmd("$$701F\r")); cpu_pic->pcl->value.put(value.get() & 0xff); cpu_pic->pclath->value.put(value.get() >> 8); is_stale=0; break; case 3: value.put(icd_cmd("$$7016\r")&0x00ff); is_stale=0; replaced->update(); break; case 4: value.put(icd_cmd("$$7019\r")&0x00ff); is_stale=0; replaced->update(); break; case 10: value.put(icd_cmd("$$701F\r")); cpu_pic->pcl->value.put(value.get() & 0xff); cpu_pic->pclath->value.put(value.get() >> 8); is_stale=0; break; default: { if(bulk_flag==0) { unsigned char buf[8]; int offset = address - address%8; icd_cmd("$$%04X\r",0x7800+offset); icd_cmd("$$7C08\r"); icd_write("$$7D08\r"); icd_read(buf,8); for(int i=0;i<8;i++) { switch(offset+i) { case 2: case 3: case 4: case 10: break; default: icd_Register *ifr = static_cast(get_cpu()->registers[offset+i]); assert(ifr!=0); ifr->value.put(buf[i]); ifr->is_stale=0; break; } } for(int i=0;i<0x8;i++) { switch(offset+i) { case 2: case 3: case 4: case 10: break; default: icd_Register *ifr = static_cast(get_cpu()->registers[offset+i]); assert(ifr!=0); ifr->replaced->update(); break; } } } else { unsigned char buf[64]; int offset=address-address%0x40; assert(offset>=0); if(icd_cmd("$$%04X\r",0x7A00+offset/0x40)!=offset/0x40) puts("DDDDDDDDDDDDDDDDDDD"); icd_write("$$7D40\r"); int n_read = icd_read(buf,0x40); for(unsigned int i=0;i<0x40;i++) { switch(offset+i) { case 2: case 3: case 4: case 10: break; default: icd_Register *ifr = static_cast(get_cpu()->registers[offset+i]); assert(ifr!=0); ifr->value.put(buf[i]); ifr->is_stale=0; break; } } for(int i=0;i<0x40;i++) { switch(offset+i) { case 2: case 3: case 4: case 10: break; default: icd_Register *ifr = static_cast(get_cpu()->registers[offset+i]); assert(ifr!=0); ifr->replaced->update(); break; } } } } break; } } return(value.get()); } icd_WREG::icd_WREG() { replaced=0; value.put(0x42); is_stale=1; }; void icd_WREG::put_value(unsigned int new_value) { } void icd_WREG::put(unsigned int new_value) { } unsigned int icd_WREG::get_value(void) { return(get()); } unsigned int icd_WREG::get(void) { if(is_stale) { value.put(icd_cmd("$$7017\r")&0x00ff); is_stale=0; replaced->update(); } return(value.get()); } icd_StatusReg::icd_StatusReg() { replaced=0; value.put(0x42); is_stale=1; }; void icd_StatusReg::put_value(unsigned int new_value) { } void icd_StatusReg::put(unsigned int new_value) { } unsigned int icd_StatusReg::get_value(void) { if(icd_fd<0) return 0; return(get()); } unsigned int icd_StatusReg::get(void) { if(is_stale) { value.put(icd_cmd("$$7016\r")&0x00ff); is_stale=0; replaced->update(); } return(value.get()); } icd_FSR::icd_FSR() { replaced=0; value.put(0x42); is_stale=1; }; void icd_FSR::put(unsigned int new_value) { } void icd_FSR::put_value(unsigned int new_value) { } unsigned int icd_FSR::get(void) { return get_value(); } unsigned int icd_FSR::get_value(void) { if(icd_fd<0) return 0; if(is_stale) { value.put(icd_cmd("$$7019\r")&0x00ff); is_stale=0; replaced->update(); } return(value.get()); } icd_PCLATH::icd_PCLATH() { replaced=0; value.put(0x42); is_stale=1; }; void icd_PCLATH::put(unsigned int new_value) { } void icd_PCLATH::put_value(unsigned int new_value) { } unsigned int icd_PCLATH::get(void) { return get_value(); } unsigned int icd_PCLATH::get_value(void) { if(icd_fd<0) return 0; if(is_stale) { value.put((icd_cmd("$$701F\r")&0xff00)>>8); is_stale=0; replaced->update(); } return(value.get()); } icd_PC::icd_PC() { replaced=0; value=0x42; is_stale=1; }; void icd_PC::put_value(unsigned int new_value) { } unsigned int icd_PC::get_value(void) { if(icd_fd<0) return 0; if(is_stale) { value = icd_cmd("$$701F\r"); cpu_pic->pcl->value.put(value & 0xff); cpu_pic->pclath->value.put(value >> 8); is_stale=0; } return(value); }