forked from len0rd/rockbox
regtools/qeditor: prepare support for register writing
Change-Id: Ifef36a3ddb1604db63ec974da2d6a77a5540ff42
This commit is contained in:
parent
3d07706c05
commit
a66a5af4db
4 changed files with 207 additions and 8 deletions
|
@ -1,6 +1,7 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,9 +100,38 @@ bool FileIoBackend::Reload()
|
||||||
else if(ok)
|
else if(ok)
|
||||||
m_map[key] = val;
|
m_map[key] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_readonly = !QFileInfo(file).isWritable();
|
||||||
|
m_dirty = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FileIoBackend::WriteRegister(const QString& name, soc_word_t value)
|
||||||
|
{
|
||||||
|
m_dirty = true;
|
||||||
|
m_map[name] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileIoBackend::Commit()
|
||||||
|
{
|
||||||
|
if(!m_dirty)
|
||||||
|
return true;
|
||||||
|
QFile file(m_filename);
|
||||||
|
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||||
|
return false;
|
||||||
|
QTextStream out(&file);
|
||||||
|
out << "HW = " << m_soc << "\n";
|
||||||
|
QMapIterator< QString, soc_word_t > it(m_map);
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
out << it.key() << " = " << it.value() << "\n";
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
return file.flush();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_HWSTUB
|
#ifdef HAVE_HWSTUB
|
||||||
/**
|
/**
|
||||||
* HWStubDevice
|
* HWStubDevice
|
||||||
|
@ -195,6 +225,14 @@ bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer)
|
||||||
return ret >= 0 && (size_t)ret == length;
|
return ret >= 0 && (size_t)ret == length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HWStubDevice::WriteMem(soc_addr_t addr, size_t length, void *buffer)
|
||||||
|
{
|
||||||
|
if(!m_hwdev)
|
||||||
|
return false;
|
||||||
|
int ret = hwstub_rw_mem(m_hwdev, 0, addr, buffer, length);
|
||||||
|
return ret >= 0 && (size_t)ret == length;
|
||||||
|
}
|
||||||
|
|
||||||
bool HWStubDevice::IsValid()
|
bool HWStubDevice::IsValid()
|
||||||
{
|
{
|
||||||
return m_valid;
|
return m_valid;
|
||||||
|
@ -243,6 +281,11 @@ bool HWStubIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value)
|
||||||
return m_dev->ReadMem(addr, sizeof(value), &value);
|
return m_dev->ReadMem(addr, sizeof(value), &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HWStubIoBackend:: WriteRegister(soc_addr_t addr, soc_word_t value)
|
||||||
|
{
|
||||||
|
return m_dev->WriteMem(addr, sizeof(value), &value);
|
||||||
|
}
|
||||||
|
|
||||||
bool HWStubIoBackend::Reload()
|
bool HWStubIoBackend::Reload()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -32,6 +32,17 @@ public:
|
||||||
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value) = 0;
|
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value) = 0;
|
||||||
/* reload content (if it makes sense) */
|
/* reload content (if it makes sense) */
|
||||||
virtual bool Reload() = 0;
|
virtual bool Reload() = 0;
|
||||||
|
/* check whether backend supports writing */
|
||||||
|
virtual bool IsReadOnly() = 0;
|
||||||
|
/* write a register by name or address
|
||||||
|
* NOTE: even on a read-only backend, a write is allowed be successful as long
|
||||||
|
* as commit fails */
|
||||||
|
virtual bool WriteRegister(const QString& name, soc_word_t value) = 0;
|
||||||
|
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value) = 0;
|
||||||
|
/* check whether backend contains uncommitted (ie cached) writes */
|
||||||
|
virtual bool IsDirty() = 0;
|
||||||
|
/* commit all writes */
|
||||||
|
virtual bool Commit() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DummyIoBackend : public IoBackend
|
class DummyIoBackend : public IoBackend
|
||||||
|
@ -47,8 +58,17 @@ public:
|
||||||
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
|
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
|
||||||
{ (void) addr; (void) value; return false; }
|
{ (void) addr; (void) value; return false; }
|
||||||
virtual bool Reload() { return false; }
|
virtual bool Reload() { return false; }
|
||||||
|
virtual bool IsReadOnly() { return true; }
|
||||||
|
virtual bool WriteRegister(const QString& name, soc_word_t value)
|
||||||
|
{ (void) name; (void) value; return false; }
|
||||||
|
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value)
|
||||||
|
{ (void) addr; (void) value; return false; }
|
||||||
|
virtual bool IsDirty() { return false; }
|
||||||
|
virtual bool Commit() { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** NOTE the File backend makes a difference between writes and commits:
|
||||||
|
* a write will *never* touch the underlying file unless it was committed. */
|
||||||
class FileIoBackend : public IoBackend
|
class FileIoBackend : public IoBackend
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -61,10 +81,18 @@ public:
|
||||||
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
|
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
|
||||||
{ (void) addr; (void) value; return false; }
|
{ (void) addr; (void) value; return false; }
|
||||||
virtual bool Reload();
|
virtual bool Reload();
|
||||||
|
virtual bool IsReadOnly() { return m_readonly; }
|
||||||
|
virtual bool WriteRegister(const QString& name, soc_word_t value);
|
||||||
|
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value)
|
||||||
|
{ (void) addr; (void) value; return false; }
|
||||||
|
virtual bool IsDirty() { return m_dirty; }
|
||||||
|
virtual bool Commit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_filename;
|
QString m_filename;
|
||||||
QString m_soc;
|
QString m_soc;
|
||||||
|
bool m_readonly;
|
||||||
|
bool m_dirty;
|
||||||
QMap< QString, soc_word_t > m_map;
|
QMap< QString, soc_word_t > m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,6 +113,7 @@ public:
|
||||||
inline struct hwstub_stmp_desc_t GetSTMPInfo() { return m_hwdev_stmp; }
|
inline struct hwstub_stmp_desc_t GetSTMPInfo() { return m_hwdev_stmp; }
|
||||||
/* Calls below require the device to be opened */
|
/* Calls below require the device to be opened */
|
||||||
bool ReadMem(soc_addr_t addr, size_t length, void *buffer);
|
bool ReadMem(soc_addr_t addr, size_t length, void *buffer);
|
||||||
|
bool WriteMem(soc_addr_t addr, size_t length, void *buffer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool Probe();
|
bool Probe();
|
||||||
|
@ -98,6 +127,7 @@ protected:
|
||||||
struct hwstub_stmp_desc_t m_hwdev_stmp;
|
struct hwstub_stmp_desc_t m_hwdev_stmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** NOTE the HWStub backend is never dirty: all writes are immediately committed */
|
||||||
class HWStubIoBackend : public IoBackend
|
class HWStubIoBackend : public IoBackend
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -111,6 +141,12 @@ public:
|
||||||
{ (void) name; (void) value; return false; }
|
{ (void) name; (void) value; return false; }
|
||||||
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value);
|
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value);
|
||||||
virtual bool Reload();
|
virtual bool Reload();
|
||||||
|
virtual bool IsReadOnly() { return false; }
|
||||||
|
virtual bool WriteRegister(const QString& name, soc_word_t value)
|
||||||
|
{ (void) name; (void) value; return false; }
|
||||||
|
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value);
|
||||||
|
virtual bool IsDirty() { return false; }
|
||||||
|
virtual bool Commit() { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_soc;
|
QString m_soc;
|
||||||
|
|
|
@ -17,17 +17,100 @@
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
#include "analyser.h"
|
#include "analyser.h"
|
||||||
|
|
||||||
RegTreeItem::RegTreeItem(const QString& string, int type)
|
SocFieldValidator::SocFieldValidator(QObject *parent)
|
||||||
:QTreeWidgetItem(QStringList(string), type)
|
:QValidator(parent)
|
||||||
|
{
|
||||||
|
m_field.first_bit = 0;
|
||||||
|
m_field.last_bit = 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
|
||||||
|
:QValidator(parent), m_field(field)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegTreeItem::SetPath(int dev_idx, int dev_addr_idx, int reg_idx, int reg_addr_idx)
|
void SocFieldValidator::fixup(QString& input) const
|
||||||
{
|
{
|
||||||
m_dev_idx = dev_idx;
|
input = input.trimmed();
|
||||||
m_dev_addr_idx = dev_addr_idx;
|
}
|
||||||
m_reg_idx = reg_idx;
|
|
||||||
m_reg_addr_idx = reg_addr_idx;
|
QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
|
||||||
|
{
|
||||||
|
(void) pos;
|
||||||
|
soc_word_t val;
|
||||||
|
State state = parse(input, val);
|
||||||
|
qDebug() << "validate(" << input << "): " << state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
|
||||||
|
{
|
||||||
|
// the empty string is all alwats intermediate
|
||||||
|
if(input.size() == 0)
|
||||||
|
return Intermediate;
|
||||||
|
// first check named values
|
||||||
|
State state = Invalid;
|
||||||
|
foreach(const soc_reg_field_value_t& value, m_field.value)
|
||||||
|
{
|
||||||
|
QString name = QString::fromLocal8Bit(value.name.c_str());
|
||||||
|
// cannot be a substring if too long or empty
|
||||||
|
if(input.size() > name.size())
|
||||||
|
continue;
|
||||||
|
// check equal string
|
||||||
|
if(input == name)
|
||||||
|
{
|
||||||
|
state = Acceptable;
|
||||||
|
val = value.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check substring
|
||||||
|
if(name.startsWith(input))
|
||||||
|
state = Intermediate;
|
||||||
|
}
|
||||||
|
// early return for exact match
|
||||||
|
if(state == Acceptable)
|
||||||
|
return state;
|
||||||
|
// do a few special cases for convenience
|
||||||
|
if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
|
||||||
|
input.compare("0b", Qt::CaseInsensitive) == 0)
|
||||||
|
return Intermediate;
|
||||||
|
// try by parsing
|
||||||
|
unsigned basis, pos;
|
||||||
|
if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
basis = 16;
|
||||||
|
pos = 2;
|
||||||
|
}
|
||||||
|
else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
basis = 2;
|
||||||
|
pos = 2;
|
||||||
|
}
|
||||||
|
else if(input.size() >= 2 && input.startsWith("0"))
|
||||||
|
{
|
||||||
|
basis = 8;
|
||||||
|
pos = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
basis = 10;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
unsigned long v = input.mid(pos).toULong(&ok, basis);
|
||||||
|
// if not ok, return result of name parsing
|
||||||
|
if(!ok)
|
||||||
|
return state;
|
||||||
|
// if ok, check if it fits in the number of bits
|
||||||
|
unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
|
||||||
|
unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
|
||||||
|
if(v <= max)
|
||||||
|
{
|
||||||
|
val = v;
|
||||||
|
return Acceptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegTab::RegTab(Backend *backend)
|
RegTab::RegTab(Backend *backend)
|
||||||
|
@ -167,6 +250,7 @@ void RegTab::OnDataSelChanged(int index)
|
||||||
OnDataSocActivated(m_io_backend->GetSocName());
|
OnDataSocActivated(m_io_backend->GetSocName());
|
||||||
}
|
}
|
||||||
Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
|
Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
|
||||||
|
SetReadOnlyIndicator();
|
||||||
}
|
}
|
||||||
#ifdef HAVE_HWSTUB
|
#ifdef HAVE_HWSTUB
|
||||||
else if(var == DataSelDevice)
|
else if(var == DataSelDevice)
|
||||||
|
@ -189,6 +273,10 @@ void RegTab::OnDataSelChanged(int index)
|
||||||
OnDataChanged();
|
OnDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegTab::SetReadOnlyIndicator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void RegTab::OnDataChanged()
|
void RegTab::OnDataChanged()
|
||||||
{
|
{
|
||||||
OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem());
|
OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem());
|
||||||
|
@ -230,6 +318,8 @@ void RegTab::DisplayRegister(const SocRegRef& ref)
|
||||||
{
|
{
|
||||||
delete m_right_content;
|
delete m_right_content;
|
||||||
|
|
||||||
|
bool read_only = m_io_backend->IsReadOnly();
|
||||||
|
|
||||||
QVBoxLayout *right_layout = new QVBoxLayout;
|
QVBoxLayout *right_layout = new QVBoxLayout;
|
||||||
|
|
||||||
const soc_dev_addr_t& dev_addr = ref.GetDevAddr();
|
const soc_dev_addr_t& dev_addr = ref.GetDevAddr();
|
||||||
|
@ -286,9 +376,11 @@ void RegTab::DisplayRegister(const SocRegRef& ref)
|
||||||
QLabel *raw_val_name = new QLabel;
|
QLabel *raw_val_name = new QLabel;
|
||||||
raw_val_name->setText("Raw value:");
|
raw_val_name->setText("Raw value:");
|
||||||
QLineEdit *raw_val_edit = new QLineEdit;
|
QLineEdit *raw_val_edit = new QLineEdit;
|
||||||
raw_val_edit->setReadOnly(true);
|
raw_val_edit->setReadOnly(read_only);
|
||||||
raw_val_edit->setText(QString().sprintf("0x%08x", value));
|
raw_val_edit->setText(QString().sprintf("0x%08x", value));
|
||||||
raw_val_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
raw_val_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||||
|
raw_val_edit->setValidator(new SocFieldValidator(raw_val_edit));
|
||||||
|
connect(raw_val_edit, SIGNAL(returnPressed()), this, SLOT(OnRawRegValueReturnPressed()));
|
||||||
raw_val_layout = new QHBoxLayout;
|
raw_val_layout = new QHBoxLayout;
|
||||||
raw_val_layout->addStretch();
|
raw_val_layout->addStretch();
|
||||||
raw_val_layout->addWidget(raw_val_name);
|
raw_val_layout->addWidget(raw_val_name);
|
||||||
|
@ -445,3 +537,12 @@ void RegTab::OnSocChanged(const QString& soc)
|
||||||
FillRegTree();
|
FillRegTree();
|
||||||
FillAnalyserList();
|
FillAnalyserList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegTab::OnRawRegValueReturnPressed()
|
||||||
|
{
|
||||||
|
QObject *obj = sender();
|
||||||
|
QLineEdit *edit = dynamic_cast< QLineEdit* >(obj);
|
||||||
|
const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator* >(edit->validator());
|
||||||
|
soc_word_t val;
|
||||||
|
QValidator::State state = validator->parse(edit->text(), val);
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <QValidator>
|
||||||
#include <soc_desc.hpp>
|
#include <soc_desc.hpp>
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
@ -52,6 +53,22 @@ private:
|
||||||
SocRegRef m_ref;
|
SocRegRef m_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SocFieldValidator : public QValidator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SocFieldValidator(QObject *parent = 0);
|
||||||
|
SocFieldValidator(const soc_reg_field_t& field, QObject *parent = 0);
|
||||||
|
|
||||||
|
virtual void fixup(QString& input) const;
|
||||||
|
virtual State validate(QString& input, int& pos) const;
|
||||||
|
/* validate and return the interpreted value */
|
||||||
|
State parse(const QString& input, soc_word_t& val) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
soc_reg_field_t m_field;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RegTab : public QSplitter
|
class RegTab : public QSplitter
|
||||||
|
@ -90,6 +107,7 @@ private slots:
|
||||||
void OnDevListChanged();
|
void OnDevListChanged();
|
||||||
void OnDevChanged(int index);
|
void OnDevChanged(int index);
|
||||||
#endif
|
#endif
|
||||||
|
void SetReadOnlyIndicator();
|
||||||
void OnSocChanged(const QString& text);
|
void OnSocChanged(const QString& text);
|
||||||
void OnSocListChanged();
|
void OnSocListChanged();
|
||||||
void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
|
void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
|
||||||
|
@ -99,6 +117,7 @@ private slots:
|
||||||
void OnDataSocActivated(const QString&);
|
void OnDataSocActivated(const QString&);
|
||||||
void OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous);
|
void OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous);
|
||||||
void OnAnalyserClicked(QListWidgetItem *clicked);
|
void OnAnalyserClicked(QListWidgetItem *clicked);
|
||||||
|
void OnRawRegValueReturnPressed();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* REGTAB_H */
|
#endif /* REGTAB_H */
|
Loading…
Add table
Add a link
Reference in a new issue