/*************************************************************************** * Copyright (C) 2005-2007 Nicolas Hadacek * * * * This program 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 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "icd2_debug_specific.h" #include "devices/pic/base/pic_register.h" #include "icd2_data.h" //---------------------------------------------------------------------------- Address Icd2::P16FDebuggerSpecific::addressWREG() const { return FAMILY_DATA[family(device()->name())].wreg; } Address Icd2::P16FDebuggerSpecific::addressRegister(Address address) const { TQString name = device()->registersData().sfrNames[address]; if ( name=="FSR" ) return FAMILY_DATA[family(device()->name())].fsr; if ( name=="STATUS" ) return FAMILY_DATA[family(device()->name())].status; return address; } bool Icd2::P16FDebuggerSpecific::reset() { if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; return init(true); } bool Icd2::P16FDebuggerSpecific::setBreakpoint(Address address) { if ( !address.isValid() ) address = 0x1FFF; // outside memory range BitValue value = address.toUInt() | 0x8000; // read-only INBUG bit return hardware()->writeRegister(0x18E, value, 2); } bool Icd2::P16FDebuggerSpecific::readBreakpoint(BitValue &value) { if ( !hardware()->readRegister(0x18E, value, 2) ) return false; value = value.maskWith(0x1FFF); return true; } bool Icd2::P16FDebuggerSpecific::beginInit(Device::Array *saved) { if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; double vdd; if ( !hardware()->readVoltage(Pic::TargetVdd, vdd) ) return false; log(Log::DebugLevel::Normal, TQString(" Target Vdd: %1 V").arg(vdd)); if (saved) { saved->resize(1); if ( !hardware()->readMemory(Pic::MemoryRangeType::Code, 0, *saved, 0) ) return false; // save first instruction if ( (*saved)[0]!=device()->nopInstruction() ) log(Log::LineType::Warning, i18n(" According to ICD2 manual, instruction at address 0x0 should be \"nop\".")); } return true; } bool Icd2::P16FDebuggerSpecific::endInit(BitValue expectedPC) { if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; if ( !base().waitForTargetMode(Pic::TargetStopped) ) return false; BitValue value; if ( !readBreakpoint(value) ) return false; if ( value==expectedPC+1 ) { // #### happen for some custom icd2 or sometimes when we had to force a halt (?) expectedPC = expectedPC+1; //log(Log::LineType::Information, i18n("Detected custom ICD2")); } if ( value!=expectedPC ) { log(Log::LineType::Error, i18n(" PC is not at address %1 (%2)").arg(toHexLabel(expectedPC, 4)).arg(toHexLabel(value, 4))); return false; } if ( !setBreakpoint(0x0000) ) return false; if ( !base().update() ) return false; if ( base().pc()!=expectedPC ) { log(Log::LineType::Error, i18n(" PC is not at address %1 (%2)").arg(toHexLabel(expectedPC, 4)).arg(toHexLabel(base().pc(), 4))); return false; } return true; } bool Icd2::P16F872DebuggerSpecific::init(bool) { Device::Array saved; if ( !beginInit(&saved) ) return false; // this seems to be needed if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; Pic::TargetMode mode; if ( !programmer().getTargetMode(mode) ) return false; if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; if ( !hardware()->setWriteMode(Pic::EraseWriteMode) ) return false; log(Log::DebugLevel::Normal, " Write \"goto 0x0\" at reset vector and run target."); Device::Array data = device()->gotoInstruction(0x0000, false); // loop at reset vector if ( !hardware()->writeMemory(Pic::MemoryRangeType::Code, 0, data) ) return false; if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; // run device if ( !base().waitForTargetMode(Pic::TargetRunning) ) return false; log(Log::DebugLevel::Normal, " Try to halt target."); if ( !hardware()->haltRun() ) return false; if ( !base().waitForTargetMode(Pic::TargetStopped) ) return false; if ( !programmer().readDebugExecutiveVersion() ) return false; log(Log::DebugLevel::Normal, " Set breakpoint at reset vector."); if ( !setBreakpoint(0x0000) ) return false; if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; if ( !base().waitForTargetMode(Pic::TargetInProgramming) ) return false; log(Log::DebugLevel::Normal, " Restore instruction at reset vector and run target."); if ( !hardware()->writeMemory(Pic::MemoryRangeType::Code, 0, saved) ) return false; // restore instruction if ( !hardware()->setWriteMode(Pic::WriteOnlyMode) ) return false; return endInit(0x0001); } bool Icd2::P16F87XDebuggerSpecific::init(bool) { Device::Array saved; if ( !beginInit(&saved) ) return false; if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; if ( !hardware()->setWriteMode(Pic::EraseWriteMode) ) return false; log(Log::DebugLevel::Normal, " Write \"goto 0x0\" at reset vector and run target."); Device::Array data = device()->gotoInstruction(0x0000, false); // loop at reset vector if ( !hardware()->writeMemory(Pic::MemoryRangeType::Code, 0, data) ) return false; if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; // run device Pic::TargetMode mode; if ( !programmer().getTargetMode(mode) ) return false; if ( mode==Pic::TargetRunning && !hardware()->haltRun() ) return false; if ( !base().waitForTargetMode(Pic::TargetStopped) ) return false; if ( !programmer().readDebugExecutiveVersion() ) return false; log(Log::DebugLevel::Normal, " Set breakpoint at reset vector."); if ( !setBreakpoint(0x0000) ) return false; if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; if ( !base().waitForTargetMode(Pic::TargetInProgramming) ) return false; log(Log::DebugLevel::Normal, " Restore instruction at reset vector and run target."); if ( !hardware()->writeMemory(Pic::MemoryRangeType::Code, 0, saved) ) return false; // restore instruction if ( !hardware()->setWriteMode(Pic::WriteOnlyMode) ) return false; return endInit(0x0001); } bool Icd2::P16F7X7DebuggerSpecific::init(bool last) { Device::Array saved; if ( !beginInit(last ? &saved : 0) ) return false; log(Log::DebugLevel::Normal, " Run target."); if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; if ( !base().waitForTargetMode(Pic::TargetStopped) ) return false; if ( !programmer().readDebugExecutiveVersion() ) return false; BitValue value; if ( !readBreakpoint(value) ) return false; BitValue expectedPC = (last ? 0x0001 : 0x0000); if ( value==expectedPC+1 ) { expectedPC = expectedPC+1; log(Log::DebugLevel::Normal, "Probably detected custom ICD2"); } if ( value!=expectedPC ) log(Log::DebugLevel::Normal, i18n(" PC is not at address %1 (%2)").arg(toHexLabel(expectedPC, 4)).arg(toHexLabel(value, 4))); if ( !setBreakpoint(0x0000) ) return false; if ( !base().update() ) return false; // #### not sure if there is a better way to get initial values (we are stopped here...) Register::list().setValue(base().pcTypeData(), value); Register::list().setValue(base().registerTypeData("STATUS"), 0x0); Register::list().setValue(deviceSpecific()->wregTypeData(), 0x0); return true; } //---------------------------------------------------------------------------- Icd2::P18FDebuggerSpecific::P18FDebuggerSpecific(::Debugger::Base &base) : DebuggerSpecific(base) { const Pic::RegistersData &rdata = device()->registersData(); // find last used bank (but not #15) _reservedBank = rdata.nbBanks - 1; // #14 for (uint i=1; i0; _reservedBank--) if ( !rdata.bankHasSfrs(_reservedBank) ) break; // also take care of USB RAM if ( (device()->architecture()==Pic::Architecture::P18F || device()->architecture()==Pic::Architecture::P18J) && device()->hasFeature(Pic::Feature::USB) ) { if ( _reservedBank==7 ) _reservedBank = 3; // 18F2455 family: 4 USB RAM banks // 18F87J50 family ? } } Address Icd2::P18FDebuggerSpecific::addressWREG()const { return reservedRegisterOffset() | 0x0FF; } Address Icd2::P18FDebuggerSpecific::addressRegister(Address address) const { TQString name = device()->registersData().sfrNames[address]; if ( name=="PCLATU" ) return reservedRegisterOffset() | 0x0F4; if ( name=="PCLATH" ) return reservedRegisterOffset() | 0x0F5; if ( name=="FSR0H" ) return reservedRegisterOffset() | 0x0FB; if ( name=="FSR0L" ) return reservedRegisterOffset() | 0x0FC; if ( name=="BSR" ) return reservedRegisterOffset() | 0x0FD; if ( name=="STATUS" ) return reservedRegisterOffset() | 0x0FE; return address; } bool Icd2::P18FDebuggerSpecific::setBreakpoint(Address address) { BitValue value = (address.isValid() ? address.toUInt() << 15 : 0x0FFFFF00); // ?? return hardware()->writeRegister(0xFB6, value, 4); } bool Icd2::P18FDebuggerSpecific::readBreakpoint(BitValue &value) { if ( !hardware()->readRegister(0xFB6, value, 4) ) return false; value >>= 15; return true; } bool Icd2::P18FDebuggerSpecific::reset() { if ( !hardware()->writeRegister(0xFB5, 0x00, 1) ) return false; // #### ?? if ( !hardware()->writeRegister(0xFB5, 0x01, 1) ) return false; // #### ?? if ( !hardware()->command("2D", 0) ) return false; // reset if ( !hardware()->writeRegister(0xFB5, 0x00, 1) ) return false; // #### ?? if ( !base().update() ) return false; BitValue expectedPC = 0x0000; if ( base().pc()==0x0001) { expectedPC = 0x0001; log(Log::LineType::Information, i18n("Detected custom ICD2")); } if ( base().pc()!=expectedPC ) { log(Log::LineType::Error, i18n(" PC is not at address %1 (%2)").arg(toHexLabel(expectedPC, 4)).arg(toHexLabel(base().pc(), 4))); return false; } return true; } bool Icd2::P18FDebuggerSpecific::init(bool) { if ( !hardware()->setTargetReset(Pic::ResetReleased) ) return false; if ( !base().waitForTargetMode(Pic::TargetStopped) ) return false; return reset(); }