summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2014-02-09 02:16:43 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2014-02-10 23:14:26 +0100
commita66a5af4db8249b5b86a8126e0fe7a60a6f6338a (patch)
tree2b9507b56b72da61ffdf90ef44ec44a862fcd0c1 /utils
parent3d07706c05c46878533f55f26bbe02d7904efd75 (diff)
downloadrockbox-a66a5af4db8249b5b86a8126e0fe7a60a6f6338a.zip
rockbox-a66a5af4db8249b5b86a8126e0fe7a60a6f6338a.tar.gz
rockbox-a66a5af4db8249b5b86a8126e0fe7a60a6f6338a.tar.bz2
rockbox-a66a5af4db8249b5b86a8126e0fe7a60a6f6338a.tar.xz
regtools/qeditor: prepare support for register writing
Change-Id: Ifef36a3ddb1604db63ec974da2d6a77a5540ff42
Diffstat (limited to 'utils')
-rw-r--r--utils/regtools/qeditor/backend.cpp43
-rw-r--r--utils/regtools/qeditor/backend.h36
-rw-r--r--utils/regtools/qeditor/regtab.cpp117
-rw-r--r--utils/regtools/qeditor/regtab.h19
4 files changed, 207 insertions, 8 deletions
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp
index 75c504a..fa107ec 100644
--- a/utils/regtools/qeditor/backend.cpp
+++ b/utils/regtools/qeditor/backend.cpp
@@ -1,6 +1,7 @@
#include <QFile>
#include <QTextStream>
#include <QDebug>
+#include <QFileInfo>
#include "backend.h"
/**
@@ -99,9 +100,38 @@ bool FileIoBackend::Reload()
else if(ok)
m_map[key] = val;
}
+
+ m_readonly = !QFileInfo(file).isWritable();
+ m_dirty = false;
+ 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
/**
* HWStubDevice
@@ -195,6 +225,14 @@ bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer)
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()
{
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);
}
+bool HWStubIoBackend:: WriteRegister(soc_addr_t addr, soc_word_t value)
+{
+ return m_dev->WriteMem(addr, sizeof(value), &value);
+}
+
bool HWStubIoBackend::Reload()
{
return true;
diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h
index 879b88c..72a19b6 100644
--- a/utils/regtools/qeditor/backend.h
+++ b/utils/regtools/qeditor/backend.h
@@ -32,6 +32,17 @@ public:
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value) = 0;
/* reload content (if it makes sense) */
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
@@ -47,8 +58,17 @@ public:
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
{ (void) addr; (void) value; 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
{
Q_OBJECT
@@ -61,10 +81,18 @@ public:
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
{ (void) addr; (void) value; return false; }
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:
QString m_filename;
QString m_soc;
+ bool m_readonly;
+ bool m_dirty;
QMap< QString, soc_word_t > m_map;
};
@@ -85,6 +113,7 @@ public:
inline struct hwstub_stmp_desc_t GetSTMPInfo() { return m_hwdev_stmp; }
/* Calls below require the device to be opened */
bool ReadMem(soc_addr_t addr, size_t length, void *buffer);
+ bool WriteMem(soc_addr_t addr, size_t length, void *buffer);
protected:
bool Probe();
@@ -98,6 +127,7 @@ protected:
struct hwstub_stmp_desc_t m_hwdev_stmp;
};
+/** NOTE the HWStub backend is never dirty: all writes are immediately committed */
class HWStubIoBackend : public IoBackend
{
Q_OBJECT
@@ -111,6 +141,12 @@ public:
{ (void) name; (void) value; return false; }
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value);
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:
QString m_soc;
diff --git a/utils/regtools/qeditor/regtab.cpp b/utils/regtools/qeditor/regtab.cpp
index e4adecf..1e9846e 100644
--- a/utils/regtools/qeditor/regtab.cpp
+++ b/utils/regtools/qeditor/regtab.cpp
@@ -17,17 +17,100 @@
#include "backend.h"
#include "analyser.h"
-RegTreeItem::RegTreeItem(const QString& string, int type)
- :QTreeWidgetItem(QStringList(string), type)
+SocFieldValidator::SocFieldValidator(QObject *parent)
+ :QValidator(parent)
{
+ m_field.first_bit = 0;
+ m_field.last_bit = 31;
}
-void RegTreeItem::SetPath(int dev_idx, int dev_addr_idx, int reg_idx, int reg_addr_idx)
+SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
+ :QValidator(parent), m_field(field)
{
- m_dev_idx = dev_idx;
- m_dev_addr_idx = dev_addr_idx;
- m_reg_idx = reg_idx;
- m_reg_addr_idx = reg_addr_idx;
+}
+
+void SocFieldValidator::fixup(QString& input) const
+{
+ input = input.trimmed();
+}
+
+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)
@@ -167,6 +250,7 @@ void RegTab::OnDataSelChanged(int index)
OnDataSocActivated(m_io_backend->GetSocName());
}
Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
+ SetReadOnlyIndicator();
}
#ifdef HAVE_HWSTUB
else if(var == DataSelDevice)
@@ -189,6 +273,10 @@ void RegTab::OnDataSelChanged(int index)
OnDataChanged();
}
+void RegTab::SetReadOnlyIndicator()
+{
+}
+
void RegTab::OnDataChanged()
{
OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem());
@@ -230,6 +318,8 @@ void RegTab::DisplayRegister(const SocRegRef& ref)
{
delete m_right_content;
+ bool read_only = m_io_backend->IsReadOnly();
+
QVBoxLayout *right_layout = new QVBoxLayout;
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;
raw_val_name->setText("Raw value:");
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->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->addStretch();
raw_val_layout->addWidget(raw_val_name);
@@ -445,3 +537,12 @@ void RegTab::OnSocChanged(const QString& soc)
FillRegTree();
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);
+}
diff --git a/utils/regtools/qeditor/regtab.h b/utils/regtools/qeditor/regtab.h
index 107e4e3..72f00a3 100644
--- a/utils/regtools/qeditor/regtab.h
+++ b/utils/regtools/qeditor/regtab.h
@@ -11,6 +11,7 @@
#include <QPushButton>
#include <QLabel>
#include <QListWidget>
+#include <QValidator>
#include <soc_desc.hpp>
#include "backend.h"
#include "settings.h"
@@ -52,6 +53,22 @@ private:
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
@@ -90,6 +107,7 @@ private slots:
void OnDevListChanged();
void OnDevChanged(int index);
#endif
+ void SetReadOnlyIndicator();
void OnSocChanged(const QString& text);
void OnSocListChanged();
void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
@@ -99,6 +117,7 @@ private slots:
void OnDataSocActivated(const QString&);
void OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous);
void OnAnalyserClicked(QListWidgetItem *clicked);
+ void OnRawRegValueReturnPressed();
};
#endif /* REGTAB_H */ \ No newline at end of file