|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
|
|
|
|
* *
|
|
|
|
* 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 "pic_register_view.h"
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqpushbutton.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqcombobox.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
|
|
|
|
#include "libgui/main_global.h"
|
|
|
|
#include "devices/gui/hex_word_editor.h"
|
|
|
|
#include "common/gui/misc_gui.h"
|
|
|
|
#include "devices/pic/base/pic.h"
|
|
|
|
#include "progs/base/generic_prog.h"
|
|
|
|
#include "progs/base/generic_debug.h"
|
|
|
|
#include "progs/base/prog_group.h"
|
|
|
|
#include "libgui/gui_debug_manager.h"
|
|
|
|
#include "coff/base/text_coff.h"
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Pic::BankWidget::BankWidget(uint i, TQWidget *parent)
|
|
|
|
: TQFrame(parent, "bank_widget"), _bindex(i), _bankCombo(0)
|
|
|
|
{
|
|
|
|
setFrameStyle(WinPanel | Sunken);
|
|
|
|
TQGridLayout *top = new TQGridLayout(this, 1, 1, 5, 0);
|
|
|
|
top->setColSpacing(1, 4);
|
|
|
|
TQFont f("courier", font().pointSize());
|
|
|
|
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
bool debugging = Main::programmerGroup().isDebugger();
|
|
|
|
uint row = 0;
|
|
|
|
if ( rdata.nbBanks!=1 ) {
|
|
|
|
if ( data.is18Family() ) {
|
|
|
|
if ( (i/2)==0 ) {
|
|
|
|
TQString title = ((i%2)==0 ? i18n("Access Bank (low)") : i18n("Access Bank (high)"));
|
|
|
|
TQLabel *label = new TQLabel(title, this);
|
|
|
|
label->tqsetAlignment(AlignCenter);
|
|
|
|
top->addMultiCellWidget(label, row,row, 0,6, AlignHCenter);
|
|
|
|
} else {
|
|
|
|
_bankCombo = new TQComboBox(this);
|
|
|
|
for (uint k=1; k<2*rdata.nbBanks-1; k++) {
|
|
|
|
_bankCombo->insertItem((k%2)==0 ? i18n("Bank %1 (low)").tqarg(k/2) : i18n("Bank %1 (high)").tqarg(k/2));
|
|
|
|
}
|
|
|
|
if ( _bindex==3 ) _bankCombo->setCurrentItem(1);
|
|
|
|
connect(_bankCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(bankChanged()));
|
|
|
|
top->addMultiCellWidget(_bankCombo, row,row, 0,6, AlignHCenter);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TQLabel *label = new TQLabel(i18n("Bank %1").tqarg(i), this);
|
|
|
|
label->tqsetAlignment(AlignCenter);
|
|
|
|
top->addMultiCellWidget(label, row,row, 0,6, AlignHCenter);
|
|
|
|
}
|
|
|
|
row++;
|
|
|
|
top->setRowSpacing(row, 5);
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
|
|
|
KIconLoader loader;
|
|
|
|
TQPixmap readIcon = loader.loadIcon("viewmag", KIcon::Small);
|
|
|
|
TQPixmap editIcon = loader.loadIcon("edit", KIcon::Small);
|
|
|
|
uint nb;
|
|
|
|
if ( !data.is18Family() ) nb = rdata.nbRegistersPerBank();
|
|
|
|
else nb = kMax(rdata.accessBankSplit, rdata.nbRegistersPerBank() - rdata.accessBankSplit);
|
|
|
|
_registers.resize(nb);
|
|
|
|
for (uint k=0; k<nb; k++) {
|
|
|
|
_registers[k].alabel = new TQLabel(this);
|
|
|
|
_registers[k].alabel->setFont(f);
|
|
|
|
top->addWidget(_registers[k].alabel, row, 0);
|
|
|
|
if (debugging) {
|
|
|
|
_registers[k].button = new PopupButton(this);
|
|
|
|
_registers[k].button->appendItem(i18n("Read"), readIcon, ReadId);
|
|
|
|
_registers[k].button->appendItem(i18n("Edit"), editIcon, EditId);
|
|
|
|
_registers[k].button->appendItem(i18n("Watch"), WatchId);
|
|
|
|
connect(_registers[k].button, TQT_SIGNAL(activated(int)), TQT_SLOT(buttonActivated(int)));
|
|
|
|
top->addWidget(_registers[k].button, row, 2);
|
|
|
|
_registers[k].edit = new Register::LineEdit(this);
|
|
|
|
connect(_registers[k].edit, TQT_SIGNAL(modified()), TQT_SLOT(write()));
|
|
|
|
_registers[k].edit->setFont(f);
|
|
|
|
top->addWidget(_registers[k].edit, row, 6);
|
|
|
|
} else {
|
|
|
|
_registers[k].label = new TQLabel(this);
|
|
|
|
top->addWidget(_registers[k].label, row, 2);
|
|
|
|
}
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debugging) {
|
|
|
|
top->setColSpacing(3, 5);
|
|
|
|
top->setColSpacing(5, 5);
|
|
|
|
}
|
|
|
|
top->setRowStretch(row, 1);
|
|
|
|
|
|
|
|
updateRegisterAddresses();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::BankWidget::bankChanged()
|
|
|
|
{
|
|
|
|
updateRegisterAddresses();
|
|
|
|
updateView();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint Pic::BankWidget::bank() const
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
if ( !data.is18Family() ) return _bindex;
|
|
|
|
if ( _bindex==0 ) return 0;
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
if ( _bindex==1 ) return rdata.nbBanks - 1;
|
|
|
|
return (_bankCombo->currentItem()+1)/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint Pic::BankWidget::nbRegisters() const
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
if ( !data.is18Family() ) return rdata.nbRegistersPerBank();
|
|
|
|
if ( _bindex==0 || (_bankCombo && _bankCombo->currentItem()==2*int(rdata.nbBanks)-3) ) return rdata.accessBankSplit;
|
|
|
|
if ( _bindex==1 || (_bankCombo && _bankCombo->currentItem()==0) ) return rdata.nbRegistersPerBank() - rdata.accessBankSplit;
|
|
|
|
return rdata.nbRegistersPerBank() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint Pic::BankWidget::indexOffset() const
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
uint offset = bank() * rdata.nbRegistersPerBank();
|
|
|
|
if ( !data.is18Family() ) return offset;
|
|
|
|
if ( _bindex==0 || (_bankCombo && (_bankCombo->currentItem()%2)==1) ) return offset;
|
|
|
|
if ( _bindex==1 || (_bankCombo && _bankCombo->currentItem()==0) ) return offset + rdata.accessBankSplit;
|
|
|
|
return offset + rdata.nbRegistersPerBank()/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::BankWidget::updateRegisterAddresses()
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
uint nbChars = rdata.nbCharsAddress();
|
|
|
|
uint nb = nbRegisters();
|
|
|
|
uint offset = indexOffset();
|
|
|
|
for (uint k=0; k<_registers.count(); k++) {
|
|
|
|
if ( k<nb ) {
|
|
|
|
_registers[k].alabel->show();
|
|
|
|
_registers[k].address = rdata.addressFromIndex(offset + k);
|
|
|
|
_registers[k].alabel->setText(toHexLabel(_registers[k].address, nbChars) + ":");
|
|
|
|
} else _registers[k].alabel->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::BankWidget::buttonActivated(int id)
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
for (uint i=0; i<_registers.count(); i++) {
|
|
|
|
if ( sender()!=_registers[i].button ) continue;
|
|
|
|
Register::TypeData rtd(_registers[i].address, rdata.nbChars());
|
|
|
|
switch (id) {
|
|
|
|
case ReadId: Debugger::manager->readRegister(rtd); break;
|
|
|
|
case EditId:
|
|
|
|
_registers[i].edit->selectAll();
|
|
|
|
_registers[i].edit->setFocus();
|
|
|
|
break;
|
|
|
|
case WatchId: {
|
|
|
|
bool isWatched = Register::list().isWatched(rtd);
|
|
|
|
Debugger::manager->setRegisterWatched(rtd, !isWatched);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::BankWidget::write()
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
for (uint i=0; i<_registers.count(); i++) {
|
|
|
|
if ( sender()!=_registers[i].edit ) continue;
|
|
|
|
Register::TypeData rtd(_registers[i].address, rdata.nbChars());
|
|
|
|
Debugger::manager->writeRegister(rtd, _registers[i].edit->value());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::BankWidget::updateView()
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
const Pic::RegistersData &rdata = data.registersData();
|
|
|
|
bool active = ( Main::programmerState()==Programmer::Halted );
|
|
|
|
const Coff::Object *coff = Debugger::manager->coff();
|
|
|
|
uint nb = nbRegisters();
|
|
|
|
for (uint i=0; i<_registers.count(); i++) {
|
|
|
|
uint address = _registers[i].address;
|
|
|
|
Device::RegisterProperties rp = rdata.properties(address);
|
|
|
|
TQString label = rdata.label(address);
|
|
|
|
Register::TypeData rtd(address, rdata.nbChars());
|
|
|
|
bool isWatched = Register::list().isWatched(rtd);
|
|
|
|
if (coff) {
|
|
|
|
TQString name = coff->variableName(address);
|
|
|
|
if ( !name.isEmpty() ) label = "<" + name + ">";
|
|
|
|
}
|
|
|
|
if (_registers[i].button) {
|
|
|
|
if ( i<nb ) {
|
|
|
|
_registers[i].button->show();
|
|
|
|
_registers[i].button->setText(label);
|
|
|
|
if (isWatched) {
|
|
|
|
TQFont f = _registers[i].button->font();
|
|
|
|
f.setBold(true);
|
|
|
|
_registers[i].button->setFont(f);
|
|
|
|
} else _registers[i].button->unsetFont();
|
|
|
|
_registers[i].button->popup()->setItemEnabled(ReadId, active && (rp & Device::Readable));
|
|
|
|
_registers[i].button->popup()->setItemEnabled(EditId, active);
|
|
|
|
_registers[i].button->popup()->changeItem(WatchId, isWatched ? i18n("Stop Watching") : i18n("Watch"));
|
|
|
|
_registers[i].button->popup()->setItemEnabled(WatchId, rp & Device::Readable);
|
|
|
|
} else _registers[i].button->hide();
|
|
|
|
}
|
|
|
|
if (_registers[i].label) {
|
|
|
|
if ( i<nb ) {
|
|
|
|
_registers[i].label->show();
|
|
|
|
_registers[i].label->setText(label);
|
|
|
|
} else _registers[i].label->hide();
|
|
|
|
}
|
|
|
|
if (_registers[i].edit) {
|
|
|
|
if ( i<nb ) {
|
|
|
|
_registers[i].edit->show();
|
|
|
|
_registers[i].edit->setEnabled(active);
|
|
|
|
BitValue value = Register::list().value(rtd);
|
|
|
|
if ( value!=Register::list().oldValue(rtd) ) _registers[i].edit->setColor(red);
|
|
|
|
else _registers[i].edit->unsetColor();
|
|
|
|
_registers[i].edit->setValue(NumberBase::Hex, value, rdata.nbChars());
|
|
|
|
} else _registers[i].edit->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Pic::RegisterView::RegisterView(TQWidget *parent)
|
|
|
|
: Register::View(parent, "pic_register_view"),
|
|
|
|
_readAllButton(0), _clearAllButton(0)
|
|
|
|
{
|
|
|
|
TQVBoxLayout *vbox = new TQVBoxLayout(this, 10, 10);
|
|
|
|
TQHBoxLayout *hbox = new TQHBoxLayout(vbox);
|
|
|
|
|
|
|
|
bool debugging = Main::programmerGroup().isDebugger();
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
uint nb = data.registersData().nbBanks;
|
|
|
|
if ( debugging && nb!=0 ) {
|
|
|
|
TQWidget *w = new TQWidget(this);
|
|
|
|
hbox->addWidget(w);
|
|
|
|
TQGridLayout *grid = new TQGridLayout(w, 1, 1, 0, 10);
|
|
|
|
_readAllButton = new TQPushButton(i18n("Read All"), w);
|
|
|
|
connect(_readAllButton, TQT_SIGNAL(clicked()), Debugger::manager, TQT_SLOT(readAllRegisters()));
|
|
|
|
grid->addWidget(_readAllButton, 0, 0);
|
|
|
|
_clearAllButton = new TQPushButton(i18n("Clear all watching"), w);
|
|
|
|
connect(_clearAllButton, TQT_SIGNAL(clicked()), TQT_SLOT(stopWatchAllRegisters()));
|
|
|
|
grid->addWidget(_clearAllButton, 0, 1);
|
|
|
|
grid->setColStretch(2, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQHBoxLayout *hbox2 = 0;
|
|
|
|
if ( nb==0 ) {
|
|
|
|
TQLabel *label = new TQLabel(i18n("Registers information not available."), this);
|
|
|
|
vbox->addWidget(label);
|
|
|
|
} else {
|
|
|
|
hbox = new TQHBoxLayout(vbox);
|
|
|
|
hbox2 = new TQHBoxLayout(hbox);
|
|
|
|
hbox->addStretch(1);
|
|
|
|
if ( data.is18Family() ) {
|
|
|
|
nb = 2;
|
|
|
|
for (uint k=1; k<data.registersData().nbBanks-1; k++) {
|
|
|
|
if ( !data.registersData().isBankUsed(k) ) continue;
|
|
|
|
nb += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_banks.resize(nb);
|
|
|
|
for (uint i=0; i<nb; i++) {
|
|
|
|
_banks[i] = new BankWidget(i, this);
|
|
|
|
_banks[i]->show();
|
|
|
|
hbox2->addWidget(_banks[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vbox->addStretch(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::RegisterView::updateView()
|
|
|
|
{
|
|
|
|
if (_readAllButton) _readAllButton->setEnabled(Main::programmerState()==Programmer::Halted);
|
|
|
|
for (uint i=0; i<_banks.count(); i++) if (_banks[i]) _banks[i]->updateView();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pic::RegisterView::stopWatchAllRegisters()
|
|
|
|
{
|
|
|
|
Debugger::manager->stopWatchAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
Pic::RegisterListViewItem::RegisterListViewItem(const Register::TypeData &data, KListViewItem *parent)
|
|
|
|
: Register::ListViewItem(data, parent)
|
|
|
|
{}
|
|
|
|
|
|
|
|
uint Pic::RegisterListViewItem::nbCharsAddress() const
|
|
|
|
{
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
return data.registersData().nbCharsAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Pic::RegisterListViewItem::label() const
|
|
|
|
{
|
|
|
|
if ( _data.type()!=Register::Regular ) return _data.name();
|
|
|
|
const Coff::Object *coff = Debugger::manager->coff();
|
|
|
|
if (coff) {
|
|
|
|
TQString name = coff->variableName(_data.address());
|
|
|
|
if ( !name.isEmpty() ) return "<" + name + ">";
|
|
|
|
}
|
|
|
|
const Pic::Data &data = static_cast<const Pic::Data &>(*Main::deviceData());
|
|
|
|
return data.registersData().label(_data.address());
|
|
|
|
}
|