/*************************************************************************** * Copyright (C) 2006 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 "gpsim_debug.h" #include #include #include "devices/list/device_list.h" #include "devices/pic/base/pic_register.h" #include "coff/base/text_coff.h" #include "progs/manager/debug_manager.h" //---------------------------------------------------------------------------- GPSim::Debugger::Debugger(Programmer &programmer) : ::Debugger::PicBase(programmer), _nbBreakpoints(0) {} bool GPSim::Debugger::internalInit() { if ( !hardware()->execute("processor pic" + device()->name().lower(), true) ) return false; if ( _inputType==PURL::Cod ) return hardware()->execute("load s " + _filename, true); Q_ASSERT( _inputType==PURL::Hex ); return hardware()->execute("load h " + _filename, true); } bool GPSim::Debugger::internalRun() { return hardware()->execute("run", false); } bool GPSim::Debugger::hardHalt() { log(Log::LineType::Warning, i18n("Failed to halt target: kill process.")); _programmer.disconnectHardware(); return true; } bool GPSim::Debugger::softHalt(bool &success) { success = hardware()->signal(SIGINT, true); return true; } bool GPSim::Debugger::internalStep() { return hardware()->execute("step", true); } bool GPSim::Debugger::setBreakpoints(const TQValueList
&list) { for (uint i=0; i<_nbBreakpoints; i++) if ( !hardware()->execute("clear " + TQString::number(i), true) ) return false; for (uint i=0; iexecute("break e 0x" + toHex(list[i], nbChars(list[i].toUInt())), true) ) return false; _nbBreakpoints = list.count(); return true; } bool GPSim::Debugger::internalReset() { if ( _programmer.state()==::Programmer::Running && !halt() ) return false; return hardware()->execute("reset", true); } bool GPSim::Debugger::updateState() { if ( hardware()->isReady() ) _programmer.setState(::Programmer::Halted); else _programmer.setState(::Programmer::Running); return true; } bool GPSim::Debugger::findRegExp(const TQStringList &lines, const TQString &pattern, const TQString &label, TQString &value) const { TQRegExp rexp(pattern); uint i = 0; for (; iversion()<=VersionData(0, 21, 7) || hardware()->version()>=VersionData(0, 22, 0) ) return getRegister("W", value); TQStringList lines; if ( !hardware()->execute("dump s", true, &lines) ) return false; TQString w = (_coff->symbol("_WREG") ? "_WREG" : "W"); TQString s; if ( !findRegExp(lines, "^\\s*[0-9A-Fa-f]+\\s+(\\w+)\\s*=\\s*([0-9A-Fa-f]+)", w, s) ) { log(Log::LineType::Error, i18n("Error reading register \"%1\"").tqarg(w)); return false; } value = fromHex(s, 0); return true; } bool GPSim::Debugger::getRegister(const TQString &name, BitValue &value) { TQStringList lines; TQRegExp r; if ( hardware()->version()execute("x " + name, true, &lines) ) return false; r.setPattern("\\w+\\s*[][\\w]+\\s*=\\s*(?:0x|)([0-9A-Fa-f]+)(?:\\W.*|)"); } else { if ( !hardware()->execute(name, true, &lines) ) return false; r.setPattern("[^=]*=\\s*(?:0x|\\$)([0-9A-Fa-f]+)(?:\\W.*|)"); } uint i = 0; for (; iregistersData(); TQString name = toHex(address, rdata.nbCharsAddress()); if ( hardware()->version()registersData().sfrNames[data.address()]; if ( name=="WREG" ) return readWreg(value); if ( !name.isEmpty() ) return getRegister(name.lower(), value); return getRegister(data.address(), value); } bool GPSim::Debugger::setRegister(const TQString &name, BitValue value) { if ( hardware()->version()registersData(); TQString s = TQString("%1 = %2").tqarg(name).tqarg(toHexLabel(value, rdata.nbChars())); return hardware()->execute(s, true); } bool GPSim::Debugger::setRegister(Address address, BitValue value) { const Pic::RegistersData &rdata = device()->registersData(); TQString s = TQString("ramData[$%1]").tqarg(toHex(address, rdata.nbCharsAddress())); return setRegister(s, value); } bool GPSim::Debugger::writeRegister(const Register::TypeData &data, BitValue value) { if ( data.type()==Register::Special ) { if ( data.name()=="WREG" ) return writeWreg(value); if ( data.name()=="PC" ) { log(Log::LineType::Warning, i18n("Writing PC is not supported by gpsim")); return true; } Q_ASSERT(false); return false; } const Pic::RegistersData &rdata = device()->registersData(); TQString name = rdata.sfrNames[data.address()]; if ( !name.isEmpty() ) return setRegister(name.lower(), value); return setRegister(data.address(), value); } bool GPSim::Debugger::writeWreg(BitValue value) { return setRegister("W", value); } bool GPSim::Debugger::updatePorttqStatus(uint index, TQMap &bits) { for (uint i=0; iregistersData().hasPortBit(index, i) ) continue; TQString name = device()->registersData().portName(index).lower() + TQString::number(i); TQStringList lines; if ( !hardware()->execute("symbol " + name, true, &lines) ) return false; TQString pattern = "^(\\w+)=([^\\s])+\\s*", value; if ( !findRegExp(lines, pattern, "bitState", value) || value.length()!=1 ) { log(Log::LineType::Error, i18n("Error reading state of IO bit: %1").tqarg(name)); return false; } switch (value[0].latin1()) { case 'H': case '1': bits[i].state = Device::High; break; case 'L': case '0': bits[i].state = Device::Low; break; case 'W': bits[i].state = Device::WeakPullUp; break; case 'w': bits[i].state = Device::WeakPullDown; break; case 'Z': bits[i].state = Device::HighImpedance; break; case 'X': bits[i].state = Device::Unknown; break; default: bits[i].state = Device::Unknown; log(Log::LineType::Warning, i18n("Unknown state for IO bit: %1 (%2)").tqarg(name).tqarg(value)); break; } if ( !findRegExp(lines, pattern, "Driving", value) || value.length()!=1 ) { log(Log::LineType::Error, i18n("Error reading driving state of IO bit: %1").tqarg(name)); return false; } bits[i].driving = ( value[0]=='1' ); if (bits[i].driving) { if ( !findRegExp(lines, pattern, "drivingState", value) || value.length()!=1 ) { log(Log::LineType::Error, i18n("Error reading driving state of IO bit: %1").tqarg(name)); return false; } bits[i].drivingState = (value[0]=='0' ? Device::IoLow : Device::IoHigh); bits[i].drivenState = Device::IoUnknown; } else { if ( !findRegExp(lines, pattern, "drivenState", value) || value.length()!=1 ) { log(Log::LineType::Error, i18n("Error reading driven state of IO bit: %1").tqarg(name)); return false; } bits[i].drivenState = (value[0]=='0' ? Device::IoLow : Device::IoHigh); bits[i].drivingState = Device::IoUnknown; } } return true; } //---------------------------------------------------------------------------- TQString GPSim::Group::statusLabel() const { return i18n("GPSim (4MHz)"); // #### FIXME: add config } void GPSim::Group::initSupported() { ProcessManager manager(0); if ( !manager.start() ) return; VersionData version; if ( !manager.getVersion(version) ) return; bool oldGpsim = ( version(Device::lister().data(s)); if (data) { if ( data->architecture()==Pic::Architecture::P18F && oldGpsim ) continue; addDevice(data->name(), data, ::Group::Support::Tested); } } } Programmer::Hardware *GPSim::Group::createHardware(::Programmer::Base &base, const ::Programmer::HardwareDescription &) const { return new Hardware(base); } Programmer::DeviceSpecific *GPSim::Group::createDeviceSpecific(::Programmer::Base &base) const { return new DeviceSpecific(base); }