summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-08-21 20:16:26 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-08-21 20:18:37 +0200
commitc323381f0b3ee68b0093442335e8e7cbb112858a (patch)
treeac27964bd0da6bc56f05ad965ce4de957ef22d59
parent902306378e38ce571f4595ae8dabb2acd2412faa (diff)
downloadrockbox-c323381.tar.gz
rockbox-c323381.tar.bz2
rockbox-c323381.zip
regtools: add graphical register explorer + analyser
This tool allows one to explore any register map. Register dumps (like produced by hwstub tools) can be loaded and decoded by the tool. Finally some analysers are provided for specific soc analysis like clock tree and emi on imx233 for example. Change-Id: Iaf81bd52d15f3e44ab4fe9bc039153fcf60cf92a
-rw-r--r--utils/regtools/qeditor/analyser.cpp44
-rw-r--r--utils/regtools/qeditor/analyser.h64
-rw-r--r--utils/regtools/qeditor/backend.cpp156
-rw-r--r--utils/regtools/qeditor/backend.h77
-rw-r--r--utils/regtools/qeditor/main.cpp30
-rw-r--r--utils/regtools/qeditor/mainwindow.cpp108
-rw-r--r--utils/regtools/qeditor/mainwindow.h44
-rw-r--r--utils/regtools/qeditor/qeditor.pro8
-rw-r--r--utils/regtools/qeditor/regtab.cpp392
-rw-r--r--utils/regtools/qeditor/regtab.h85
-rw-r--r--utils/regtools/qeditor/settings.cpp32
-rw-r--r--utils/regtools/qeditor/settings.h21
-rw-r--r--utils/regtools/qeditor/std_analysers.cpp636
-rw-r--r--utils/regtools/qeditor/std_analysers.h95
14 files changed, 1792 insertions, 0 deletions
diff --git a/utils/regtools/qeditor/analyser.cpp b/utils/regtools/qeditor/analyser.cpp
new file mode 100644
index 0000000000..1ab213872b
--- /dev/null
+++ b/utils/regtools/qeditor/analyser.cpp
@@ -0,0 +1,44 @@
+#include "analyser.h"
+
+Analyser::Analyser(const soc_t& soc, IoBackend *backend)
+ :m_soc(soc), m_io_backend(backend)
+{
+}
+
+Analyser::~Analyser()
+{
+}
+
+AnalyserFactory::AnalyserFactory(bool _register)
+{
+ if(_register)
+ RegisterAnalyser(this);
+}
+
+AnalyserFactory::~AnalyserFactory()
+{
+}
+
+QVector< AnalyserFactory * > AnalyserFactory::m_factories;
+
+QStringList AnalyserFactory::GetAnalysersForSoc(const QString& soc_name)
+{
+ QStringList list;
+ for(int i = 0; i < m_factories.size(); i++)
+ if(m_factories[i]->SupportSoc(soc_name))
+ list.append(m_factories[i]->GetName());
+ return list;
+}
+
+AnalyserFactory *AnalyserFactory::GetAnalyserByName(const QString& name)
+{
+ for(int i = 0; i < m_factories.size(); i++)
+ if(m_factories[i]->GetName() == name)
+ return m_factories[i];
+ return 0;
+}
+
+void AnalyserFactory::RegisterAnalyser(AnalyserFactory *factory)
+{
+ m_factories.append(factory);
+}
diff --git a/utils/regtools/qeditor/analyser.h b/utils/regtools/qeditor/analyser.h
new file mode 100644
index 0000000000..33094574c1
--- /dev/null
+++ b/utils/regtools/qeditor/analyser.h
@@ -0,0 +1,64 @@
+#ifndef _ANALYSER_H_
+#define _ANALYSER_H_
+
+#include <QObject>
+#include <QVector>
+#include <QString>
+#include "backend.h"
+
+class Analyser : public QObject
+{
+ Q_OBJECT
+public:
+ Analyser(const soc_t& soc, IoBackend *backend);
+ virtual ~Analyser();
+ virtual QWidget *GetWidget() = 0;
+
+protected:
+ soc_t m_soc;
+ IoBackend *m_io_backend;
+};
+
+class AnalyserFactory
+{
+public:
+ AnalyserFactory(bool _register);
+ virtual ~AnalyserFactory();
+
+ virtual QString GetName() = 0;
+ virtual bool SupportSoc(const QString& soc_name) = 0;
+ // return NULL of soc is not handled by the analyser
+ virtual Analyser *Create(const soc_t& soc, IoBackend *backend) = 0;
+private:
+ QString m_name;
+
+public:
+ static QStringList GetAnalysersForSoc(const QString& soc_name);
+ static AnalyserFactory *GetAnalyserByName(const QString& name);
+ static void RegisterAnalyser(AnalyserFactory *factory);
+
+private:
+ static QVector< AnalyserFactory * > m_factories;
+};
+
+template< typename T >
+class TmplAnalyserFactory : public AnalyserFactory
+{
+public:
+ TmplAnalyserFactory(bool _register, const QString& name) :AnalyserFactory(_register) { m_name = name; }
+ virtual ~TmplAnalyserFactory() {}
+
+ virtual QString GetName() { return m_name; }
+ virtual bool SupportSoc(const QString& soc_name) { return T::SupportSoc(soc_name); }
+ // return NULL of soc is not handled by the analyser
+ virtual T *Create(const soc_t& soc, IoBackend *backend)
+ {
+ if(!T::SupportSoc(soc.name.c_str()))
+ return 0;
+ return new T(soc, backend);
+ }
+private:
+ QString m_name;
+};
+
+#endif /* _ANALYSER_H_ */
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp
new file mode 100644
index 0000000000..e011965bd2
--- /dev/null
+++ b/utils/regtools/qeditor/backend.cpp
@@ -0,0 +1,156 @@
+#include <QFile>
+#include <QTextStream>
+#include <QDebug>
+#include "backend.h"
+
+Backend::Backend()
+{
+}
+
+QStringList Backend::GetSocNameList()
+{
+ QStringList sl;
+ for(size_t i = 0; i < m_socs.size(); i++)
+ sl.append(QString(m_socs[i].name.c_str()));
+ return sl;
+}
+
+bool Backend::GetSocByName(const QString& name, soc_t& s)
+{
+ for(size_t i = 0; i < m_socs.size(); i++)
+ if(m_socs[i].name == name.toStdString())
+ {
+ s = m_socs[i];
+ return true;
+ }
+ return false;
+}
+
+bool Backend::LoadSocDesc(const QString& filename)
+{
+ bool ret = soc_desc_parse_xml(filename.toStdString(), m_socs);
+ emit OnSocListChanged();
+ return ret;
+}
+
+IoBackend *Backend::CreateFileIoBackend(const QString& filename)
+{
+ return new FileIoBackend(filename);
+}
+
+IoBackend *Backend::CreateDummyIoBackend()
+{
+ return new DummyIoBackend();
+}
+
+IoBackend::IoBackend()
+{
+}
+
+FileIoBackend::FileIoBackend(const QString& filename)
+{
+ m_filename = filename;
+ Reload();
+}
+
+QString FileIoBackend::GetSocName()
+{
+ return m_soc;
+}
+
+bool FileIoBackend::ReadRegister(const QString& name, soc_word_t& value)
+{
+ if(m_map.find(name) == m_map.end())
+ return false;
+ value = m_map[name];
+ return true;
+}
+
+bool FileIoBackend::Reload()
+{
+ QFile file(m_filename);
+ if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return false;
+ m_map.clear();
+
+ QTextStream in(&file);
+ while(!in.atEnd())
+ {
+ QString line = in.readLine();
+ int idx = line.indexOf('=');
+ if(idx == -1)
+ continue;
+ QString key = line.left(idx).trimmed();
+ bool ok;
+ soc_word_t val = line.mid(idx + 1).trimmed().toULong(&ok, 0);
+ if(key == "HW")
+ m_soc = line.mid(idx + 1).trimmed();
+ else if(ok)
+ m_map[key] = val;
+ }
+ return true;
+}
+
+DummyIoBackend::DummyIoBackend()
+{
+}
+
+QString DummyIoBackend::GetSocName()
+{
+ return "";
+}
+
+bool DummyIoBackend::ReadRegister(const QString& name, soc_word_t& value)
+{
+ (void) name;
+ (void) value;
+ return false;
+}
+
+bool DummyIoBackend::Reload()
+{
+ return true;
+}
+
+BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc)
+ :m_io_backend(io_backend), m_soc(soc)
+{
+}
+
+bool BackendHelper::ReadRegister(const QString& dev, const QString& reg, soc_word_t& v)
+{
+ return m_io_backend->ReadRegister("HW." + dev + "." + reg, v);
+}
+
+bool BackendHelper::ReadRegisterField(const QString& dev, const QString& reg,
+ const QString& field, soc_word_t& v)
+{
+ soc_dev_t *sdev = 0;
+ for(size_t i = 0; i < m_soc.dev.size(); i++)
+ {
+ for(size_t j = 0; j < m_soc.dev[i].addr.size(); j++)
+ if(m_soc.dev[i].addr[j].name.c_str() == dev)
+ sdev = &m_soc.dev[i];
+ }
+ if(sdev == 0)
+ return false;
+ soc_reg_t *sreg = 0;
+ for(size_t i = 0; i < sdev->reg.size(); i++)
+ {
+ for(size_t j = 0; j < sdev->reg[i].addr.size(); j++)
+ if(sdev->reg[i].addr[j].name.c_str() == reg)
+ sreg = &sdev->reg[i];
+ }
+ if(sreg == 0)
+ return false;
+ soc_reg_field_t *sfield = 0;
+ for(size_t i = 0; i < sreg->field.size(); i++)
+ if(sreg->field[i].name.c_str() == field)
+ sfield = &sreg->field[i];
+ if(sfield == 0)
+ return false;
+ if(!ReadRegister(dev, reg, v))
+ return false;
+ v = (v & sfield->bitmask()) >> sfield->first_bit;
+ return true;
+} \ No newline at end of file
diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h
new file mode 100644
index 0000000000..536eb8cec5
--- /dev/null
+++ b/utils/regtools/qeditor/backend.h
@@ -0,0 +1,77 @@
+#ifndef __BACKEND_H__
+#define __BACKEND_H__
+
+#include <QObject>
+#include <QStringList>
+#include <QMap>
+#include "soc_desc.hpp"
+
+class IoBackend : public QObject
+{
+ Q_OBJECT
+public:
+ IoBackend();
+
+ virtual QString GetSocName() = 0;
+ virtual bool ReadRegister(const QString& name, soc_word_t& value) = 0;
+ virtual bool Reload() = 0;
+};
+
+class DummyIoBackend : public IoBackend
+{
+ Q_OBJECT
+public:
+ DummyIoBackend();
+
+ virtual QString GetSocName();
+ virtual bool ReadRegister(const QString& name, soc_word_t& value);
+ virtual bool Reload();
+};
+
+class FileIoBackend : public IoBackend
+{
+ Q_OBJECT
+public:
+ FileIoBackend(const QString& filename);
+
+ virtual QString GetSocName();
+ virtual bool ReadRegister(const QString& name, soc_word_t& value);
+ virtual bool Reload();
+
+protected:
+ QString m_filename;
+ QString m_soc;
+ QMap< QString, soc_word_t > m_map;
+};
+
+class Backend : public QObject
+{
+ Q_OBJECT
+public:
+ Backend();
+
+ QStringList GetSocNameList();
+ bool LoadSocDesc(const QString& filename);
+ bool GetSocByName(const QString& name, soc_t& s);
+ IoBackend *CreateDummyIoBackend();
+ IoBackend *CreateFileIoBackend(const QString& filename);
+
+signals:
+ void OnSocListChanged();
+private:
+ std::vector< soc_t > m_socs;
+};
+
+class BackendHelper
+{
+public:
+ BackendHelper(IoBackend *io_backend, const soc_t& soc);
+ bool ReadRegister(const QString& dev, const QString& reg, soc_word_t& v);
+ bool ReadRegisterField(const QString& dev, const QString& reg,
+ const QString& field, soc_word_t& v);
+private:
+ IoBackend *m_io_backend;
+ soc_t m_soc;
+};
+
+#endif /* __BACKEND_H__ */
diff --git a/utils/regtools/qeditor/main.cpp b/utils/regtools/qeditor/main.cpp
new file mode 100644
index 0000000000..cc3ea16066
--- /dev/null
+++ b/utils/regtools/qeditor/main.cpp
@@ -0,0 +1,30 @@
+#include <QApplication>
+#include <QDir>
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ Backend *backend = new Backend;
+ QDir dir(QCoreApplication::applicationDirPath());
+ dir.cdUp();
+ dir.cd("desc");
+ dir.setFilter(QDir::Files);
+ printf("%s\n", dir.absolutePath().toStdString().c_str());
+ QFileInfoList list = dir.entryInfoList();
+ for(int i = 0; i < list.size(); i++)
+ {
+ QFileInfo fileInfo = list.at(i);
+ if(fileInfo.fileName().right(4) != ".xml" || fileInfo.fileName().left(5) != "regs-")
+ continue;
+ backend->LoadSocDesc(fileInfo.absoluteFilePath());
+ }
+
+ QCoreApplication::setOrganizationName("Rockbox");
+ QCoreApplication::setApplicationName("Register Editor");
+ QCoreApplication::setOrganizationDomain("rockbox.com");
+ MainWindow win(backend);
+ win.show();
+ return app.exec();
+}
diff --git a/utils/regtools/qeditor/mainwindow.cpp b/utils/regtools/qeditor/mainwindow.cpp
new file mode 100644
index 0000000000..1e39dd1a83
--- /dev/null
+++ b/utils/regtools/qeditor/mainwindow.cpp
@@ -0,0 +1,108 @@
+#include <QWidget>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QFileDialog>
+#include <QAction>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QTabBar>
+#include <QCloseEvent>
+#include <QDebug>
+
+#include "mainwindow.h"
+#include "regtab.h"
+
+MyTabWidget::MyTabWidget()
+{
+ setMovable(true);
+ setTabsClosable(true);
+ connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(OnCloseTab(int)));
+}
+
+void MyTabWidget::OnCloseTab(int index)
+{
+ removeTab(index);
+}
+
+MainWindow::MainWindow(Backend *backend)
+ :m_backend(backend)
+{
+ QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("&Register Tab"), this);
+ QAction *load_desc_act = new QAction(QIcon::fromTheme("document-open"), tr("&Soc Description"), this);
+ QAction *quit_act = new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this);
+ QAction *about_act = new QAction(QIcon::fromTheme("help-about"), tr("&About"), this);
+
+ connect(new_regtab_act, SIGNAL(triggered()), this, SLOT(OnNewRegTab()));
+ connect(load_desc_act, SIGNAL(triggered()), this, SLOT(OnLoadDesc()));
+ connect(quit_act, SIGNAL(triggered()), this, SLOT(OnQuit()));
+ connect(about_act, SIGNAL(triggered()), this, SLOT(OnAbout()));
+
+ QMenu *file_menu = menuBar()->addMenu(tr("&File"));
+ QMenu *new_submenu = file_menu->addMenu(QIcon::fromTheme("document-new"), "&New");
+ QMenu *load_submenu = file_menu->addMenu(QIcon::fromTheme("document-open"), "&Load");
+ file_menu->addAction(quit_act);
+
+ new_submenu->addAction(new_regtab_act);
+
+ load_submenu->addAction(load_desc_act);
+
+ QMenu *about_menu = menuBar()->addMenu(tr("&About"));
+ about_menu->addAction(about_act);
+
+ m_tab = new MyTabWidget();
+
+ setCentralWidget(m_tab);
+
+ ReadSettings();
+}
+
+void MainWindow::ReadSettings()
+{
+ restoreGeometry(Settings::Get()->value("mainwindow/geometry").toByteArray());
+}
+
+void MainWindow::WriteSettings()
+{
+ Settings::Get()->setValue("mainwindow/geometry", saveGeometry());
+}
+
+void MainWindow::OnQuit()
+{
+ WriteSettings();
+}
+
+void MainWindow::OnAbout()
+{
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ WriteSettings();
+ event->accept();
+}
+
+void MainWindow::OnLoadDesc()
+{
+ QFileDialog *fd = new QFileDialog(this);
+ fd->setFilter("XML files (*.xml);;All files (*)");
+ fd->setFileMode(QFileDialog::ExistingFiles);
+ fd->setDirectory(Settings::Get()->value("mainwindow/loaddescdir", QDir::currentPath()).toString());
+ if(fd->exec())
+ {
+ QStringList filenames = fd->selectedFiles();
+ for(int i = 0; i < filenames.size(); i++)
+ if(!m_backend->LoadSocDesc(filenames[i]))
+ {
+ QMessageBox msg;
+ msg.setText(QString("Cannot load ") + filenames[i]);
+ msg.exec();
+ }
+ Settings::Get()->setValue("mainwindow/loaddescdir", fd->directory().absolutePath());
+ }
+}
+
+void MainWindow::OnNewRegTab()
+{
+ new RegTab(m_backend, m_tab);
+}
diff --git a/utils/regtools/qeditor/mainwindow.h b/utils/regtools/qeditor/mainwindow.h
new file mode 100644
index 0000000000..2897cde1ca
--- /dev/null
+++ b/utils/regtools/qeditor/mainwindow.h
@@ -0,0 +1,44 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QTabWidget>
+#include <QSettings>
+#include "backend.h"
+#include "settings.h"
+
+class MyTabWidget : public QTabWidget
+{
+ Q_OBJECT
+public:
+ MyTabWidget();
+
+private slots:
+ void OnCloseTab(int index);
+};
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(Backend *backend);
+ void center();
+ void ReadSettings();
+ void WriteSettings();
+
+private:
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void OnQuit();
+ void OnAbout();
+ void OnLoadDesc();
+ void OnNewRegTab();
+
+private:
+ QTabWidget *m_tab;
+ Backend *m_backend;
+};
+
+#endif
diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro
new file mode 100644
index 0000000000..4e25a48d89
--- /dev/null
+++ b/utils/regtools/qeditor/qeditor.pro
@@ -0,0 +1,8 @@
+QT += widgets
+
+HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h std_analysers.h
+SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp std_analysers.cpp settings.cpp
+LIBS += -L../lib/ -lsocdesc -lxml2
+INCLUDEPATH += ../lib/
+
+CONFIG += debug \ No newline at end of file
diff --git a/utils/regtools/qeditor/regtab.cpp b/utils/regtools/qeditor/regtab.cpp
new file mode 100644
index 0000000000..d535f6cdff
--- /dev/null
+++ b/utils/regtools/qeditor/regtab.cpp
@@ -0,0 +1,392 @@
+#include "regtab.h"
+
+#include <QSplitter>
+#include <QVBoxLayout>
+#include <QGroupBox>
+#include <QAbstractListModel>
+#include <QMessageBox>
+#include <QSizePolicy>
+#include <QHBoxLayout>
+#include <QStringBuilder>
+#include <QLabel>
+#include <QGridLayout>
+#include <QTableWidget>
+#include <QHeaderView>
+#include <QFileDialog>
+#include "backend.h"
+#include "analyser.h"
+
+RegTreeItem::RegTreeItem(const QString& string, int type)
+ :QTreeWidgetItem(QStringList(string), type)
+{
+}
+
+void RegTreeItem::SetPath(int dev_idx, int dev_addr_idx, int reg_idx, int reg_addr_idx)
+{
+ m_dev_idx = dev_idx;
+ m_dev_addr_idx = dev_addr_idx;
+ m_reg_idx = reg_idx;
+ m_reg_addr_idx = reg_addr_idx;
+}
+
+RegTab::RegTab(Backend *backend, QTabWidget *parent)
+ :m_backend(backend)
+{
+ m_splitter = new QSplitter();
+ QWidget *left = new QWidget;
+ m_splitter->addWidget(left);
+ QVBoxLayout *left_layout = new QVBoxLayout;
+ left->setLayout(left_layout);
+
+ QGroupBox *top_group = new QGroupBox("SOC selection");
+ QVBoxLayout *top_group_layout = new QVBoxLayout;
+ m_soc_selector = new QComboBox;
+ top_group_layout->addWidget(m_soc_selector);
+ top_group->setLayout(top_group_layout);
+
+ m_reg_tree = new QTreeWidget();
+ m_reg_tree->setColumnCount(1);
+ m_reg_tree->setHeaderLabel(QString("Name"));
+
+ m_analysers_list = new QListWidget;
+
+ m_type_selector = new QTabWidget;
+ m_type_selector->addTab(m_reg_tree, "Registers");
+ m_type_selector->addTab(m_analysers_list, "Analyzers");
+ m_type_selector->setTabPosition(QTabWidget::West);
+
+ left_layout->addWidget(top_group);
+ left_layout->addWidget(m_type_selector);
+
+ m_right_panel = new QVBoxLayout;
+ QGroupBox *data_sel_group = new QGroupBox("Data selection");
+ QHBoxLayout *data_sel_layout = new QHBoxLayout;
+ m_data_selector = new QComboBox;
+ m_data_selector->addItem(QIcon::fromTheme("face-sad"), "None", QVariant(DataSelNothing));
+ m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile));
+ m_data_sel_edit = new QLineEdit;
+ m_data_sel_edit->setReadOnly(true);
+ m_data_soc_label = new QLabel;
+ QPushButton *data_sel_reload = new QPushButton;
+ data_sel_reload->setIcon(QIcon::fromTheme("view-refresh"));
+ data_sel_layout->addWidget(m_data_selector);
+ data_sel_layout->addWidget(m_data_sel_edit);
+ data_sel_layout->addWidget(m_data_soc_label);
+ data_sel_layout->addWidget(data_sel_reload);
+ data_sel_group->setLayout(data_sel_layout);
+ m_data_soc_label->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
+
+ m_right_panel->addWidget(data_sel_group);
+ m_right_content = new QWidget;
+ QVBoxLayout *l = new QVBoxLayout;
+ l->addStretch();
+ m_right_content->setLayout(l);
+ m_right_panel->addWidget(m_right_content);
+ QWidget *w = new QWidget;
+ w->setLayout(m_right_panel);
+ m_splitter->addWidget(w);
+
+ m_io_backend = m_backend->CreateDummyIoBackend();
+
+ parent->addTab(m_splitter, "Register Tab");
+
+ connect(m_soc_selector, SIGNAL(currentIndexChanged(const QString&)),
+ this, SLOT(OnSocChanged(const QString&)));
+ connect(m_backend, SIGNAL(OnSocListChanged()), this, SLOT(OnSocListChanged()));
+ connect(m_reg_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(OnRegItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+ connect(m_reg_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
+ SLOT(OnRegItemClicked(QTreeWidgetItem *, int)));
+ connect(m_data_selector, SIGNAL(activated(int)),
+ this, SLOT(OnDataSelChanged(int)));
+ connect(m_data_soc_label, SIGNAL(linkActivated(const QString&)), this,
+ SLOT(OnDataSocActivated(const QString&)));
+ connect(m_analysers_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this, SLOT(OnAnalyserChanged(QListWidgetItem *, QListWidgetItem *)));
+ connect(m_analysers_list, SIGNAL(itemClicked(QListWidgetItem *)), this,
+ SLOT(OnAnalyserClicked(QListWidgetItem *)));
+
+ OnSocListChanged();
+ OnDataSelChanged(DataSelNothing);
+}
+
+void RegTab::SetDataSocName(const QString& socname)
+{
+ if(socname.size() != 0)
+ {
+ m_data_soc_label->setText("<a href=\"" + socname + "\">" + socname + "</a>");
+ m_data_soc_label->setTextFormat(Qt::RichText);
+ m_data_soc_label->show();
+ }
+ else
+ {
+ m_data_soc_label->setText("");
+ m_data_soc_label->hide();
+ }
+}
+
+void RegTab::OnDataSocActivated(const QString& str)
+{
+ int index = m_soc_selector->findText(str);
+ if(index != -1)
+ m_soc_selector->setCurrentIndex(index);
+}
+
+void RegTab::OnDataSelChanged(int index)
+{
+ if(index == -1)
+ return;
+ QVariant var = m_data_selector->itemData(index);
+ if(var == DataSelFile)
+ {
+ QFileDialog *fd = new QFileDialog(m_data_selector);
+ fd->setFilter("Textual files (*.txt);;All files (*)");
+ fd->setDirectory(Settings::Get()->value("regtab/loaddatadir", QDir::currentPath()).toString());
+ if(fd->exec())
+ {
+ QStringList filenames = fd->selectedFiles();
+ delete m_io_backend;
+ m_io_backend = m_backend->CreateFileIoBackend(filenames[0]);
+ m_data_sel_edit->setText(filenames[0]);
+ SetDataSocName(m_io_backend->GetSocName());
+ OnDataSocActivated(m_io_backend->GetSocName());
+ }
+ Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
+ }
+ else
+ {
+ delete m_io_backend;
+ m_io_backend = m_backend->CreateDummyIoBackend();
+ SetDataSocName("");
+ }
+ OnDataChanged();
+}
+
+void RegTab::OnDataChanged()
+{
+ OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem());
+}
+
+void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
+{
+ (void) previous;
+ OnRegItemClicked(current, 0);
+}
+
+void RegTab::OnRegItemClicked(QTreeWidgetItem *current, int col)
+{
+ (void) col;
+ if(current == 0)
+ return;
+ RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
+ if(item->type() != RegTreeRegType)
+ return;
+ soc_dev_t& dev = m_cur_soc.dev[item->GetDevIndex()];
+ soc_dev_addr_t& dev_addr = dev.addr[item->GetDevAddrIndex()];
+ soc_reg_t& reg = dev.reg[item->GetRegIndex()];
+ soc_reg_addr_t& reg_addr = reg.addr[item->GetRegAddrIndex()];
+
+ DisplayRegister(dev, dev_addr, reg, reg_addr);
+}
+
+void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ (void) previous;
+ OnAnalyserClicked(current);
+}
+
+void RegTab::OnAnalyserClicked(QListWidgetItem *current)
+{
+ if(current == 0)
+ return;
+ delete m_right_content;
+ AnalyserFactory *ana = AnalyserFactory::GetAnalyserByName(current->text());
+ m_right_content = ana->Create(m_cur_soc, m_io_backend)->GetWidget();
+ m_right_panel->addWidget(m_right_content);
+}
+
+void RegTab::DisplayRegister(soc_dev_t& dev, soc_dev_addr_t& dev_addr,
+ soc_reg_t& reg, soc_reg_addr_t& reg_addr)
+{
+ (void) dev;
+ delete m_right_content;
+
+ QVBoxLayout *right_layout = new QVBoxLayout;
+
+ QString reg_name;
+ reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
+ QStringList names;
+ QVector< soc_addr_t > addresses;
+ names.append(reg_name);
+ addresses.append(reg_addr.addr);
+ if(reg.flags & REG_HAS_SCT)
+ {
+ names.append(reg_name + "_SET");
+ names.append(reg_name + "_CLR");
+ names.append(reg_name + "_TOG");
+ addresses.append(reg_addr.addr + 4);
+ addresses.append(reg_addr.addr + 8);
+ addresses.append(reg_addr.addr + 12);
+ }
+
+ QString str;
+ str += "<table align=left>";
+ for(int i = 0; i < names.size(); i++)
+ str += "<tr><td><b>" + names[i] + "</b></td></tr>";
+ str += "</table>";
+ QLabel *label_names = new QLabel;
+ label_names->setTextFormat(Qt::RichText);
+ label_names->setText(str);
+
+ QString str_addr;
+ str_addr += "<table align=left>";
+ for(int i = 0; i < names.size(); i++)
+ str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
+ str_addr += "</table>";
+ QLabel *label_addr = new QLabel;
+ label_addr->setTextFormat(Qt::RichText);
+ label_addr->setText(str_addr);
+
+ QHBoxLayout *top_layout = new QHBoxLayout;
+ top_layout->addStretch();
+ top_layout->addWidget(label_names);
+ top_layout->addWidget(label_addr);
+ top_layout->addStretch();
+
+ soc_word_t value;
+ bool has_value = m_io_backend->ReadRegister(QString().sprintf("HW.%s.%s",
+ dev_addr.name.c_str(), reg_addr.name.c_str()), value);
+
+ QHBoxLayout *raw_val_layout = 0;
+ if(has_value)
+ {
+ 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->setText(QString().sprintf("0x%08x", value));
+ raw_val_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ raw_val_layout = new QHBoxLayout;
+ raw_val_layout->addStretch();
+ raw_val_layout->addWidget(raw_val_name);
+ raw_val_layout->addWidget(raw_val_edit);
+ raw_val_layout->addStretch();
+ }
+
+ QTableWidget *value_table = new QTableWidget;
+ value_table->setRowCount(reg.field.size());
+ value_table->setColumnCount(4);
+ for(size_t i = 0; i < reg.field.size(); i++)
+ {
+ QString bits_str;
+ if(reg.field[i].first_bit == reg.field[i].last_bit)
+ bits_str.sprintf("%d", reg.field[i].first_bit);
+ else
+ bits_str.sprintf("%d:%d", reg.field[i].last_bit, reg.field[i].first_bit);
+ QTableWidgetItem *item = new QTableWidgetItem(bits_str);
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ value_table->setItem(i, 0, item);
+ item = new QTableWidgetItem(QString(reg.field[i].name.c_str()));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ value_table->setItem(i, 1, item);
+ item = new QTableWidgetItem();
+ if(has_value)
+ {
+ const soc_reg_field_t& field = reg.field[i];
+ soc_word_t v = (value & field.bitmask()) >> field.first_bit;
+ QString value_name;
+ for(size_t j = 0; j < field.value.size(); j++)
+ if(v == field.value[j].value)
+ value_name = field.value[j].name.c_str();
+ const char *fmt = "%lu";
+ // heuristic
+ if((field.last_bit - field.first_bit + 1) > 16)
+ fmt = "0x%lx";
+ item->setText(QString().sprintf(fmt, (unsigned long)v));
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+
+ if(value_name.size() != 0)
+ {
+ QTableWidgetItem *t = new QTableWidgetItem(value_name);
+ t->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ t->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ value_table->setItem(i, 3, t);
+ }
+ }
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ value_table->setItem(i, 2, item);
+ }
+ value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
+ value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
+ value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
+ value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
+ value_table->verticalHeader()->setVisible(false);
+ value_table->resizeColumnsToContents();
+ value_table->horizontalHeader()->setStretchLastSection(true);
+ value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ right_layout->addLayout(top_layout);
+ if(raw_val_layout)
+ right_layout->addLayout(raw_val_layout);
+ //right_layout->addWidget(bits_label);
+ right_layout->addWidget(value_table);
+ //right_layout->addStretch();
+
+ m_right_content = new QGroupBox("Register Description");
+ m_right_content->setLayout(right_layout);
+ m_right_panel->addWidget(m_right_content);
+}
+
+void RegTab::OnSocListChanged()
+{
+ m_soc_selector->clear();
+ QStringList socs = m_backend->GetSocNameList();
+ for(int i = 0; i < socs.size(); i++)
+ m_soc_selector->addItem(socs[i]);
+}
+
+void RegTab::FillDevSubTree(RegTreeItem *item)
+{
+ soc_dev_t& sd = m_cur_soc.dev[item->GetDevIndex()];
+ for(size_t i = 0; i < sd.reg.size(); i++)
+ {
+ soc_reg_t& reg = sd.reg[i];
+ for(size_t j = 0; j < reg.addr.size(); j++)
+ {
+ RegTreeItem *reg_item = new RegTreeItem(reg.addr[j].name.c_str(), RegTreeRegType);
+ reg_item->SetPath(item->GetDevIndex(), item->GetDevAddrIndex(), i, j);
+ item->addChild(reg_item);
+ }
+ }
+}
+
+void RegTab::FillRegTree()
+{
+ for(size_t i = 0; i < m_cur_soc.dev.size(); i++)
+ {
+ soc_dev_t& sd = m_cur_soc.dev[i];
+ for(size_t j = 0; j < sd.addr.size(); j++)
+ {
+ RegTreeItem *dev_item = new RegTreeItem(sd.addr[j].name.c_str(), RegTreeDevType);
+ dev_item->SetPath(i, j);
+ FillDevSubTree(dev_item);
+ m_reg_tree->addTopLevelItem(dev_item);
+ }
+ }
+}
+
+void RegTab::FillAnalyserList()
+{
+ m_analysers_list->clear();
+ m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.name.c_str()));
+}
+
+void RegTab::OnSocChanged(const QString& soc)
+{
+ m_reg_tree->clear();
+ if(!m_backend->GetSocByName(soc, m_cur_soc))
+ return;
+ FillRegTree();
+ FillAnalyserList();
+}
diff --git a/utils/regtools/qeditor/regtab.h b/utils/regtools/qeditor/regtab.h
new file mode 100644
index 0000000000..7ec8c9009f
--- /dev/null
+++ b/utils/regtools/qeditor/regtab.h
@@ -0,0 +1,85 @@
+#ifndef REGTAB_H
+#define REGTAB_H
+
+#include <QComboBox>
+#include <QEvent>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QTabWidget>
+#include <QSplitter>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QLabel>
+#include <QListWidget>
+#include <soc_desc.hpp>
+#include "backend.h"
+#include "settings.h"
+
+enum
+{
+ RegTreeDevType = QTreeWidgetItem::UserType,
+ RegTreeRegType
+};
+
+enum
+{
+ DataSelNothing,
+ DataSelFile,
+};
+
+class RegTreeItem : public QTreeWidgetItem
+{
+public:
+ RegTreeItem(const QString& string, int type);
+
+ void SetPath(int dev_idx, int dev_addr_idx, int reg_idx = -1, int reg_addr_idx = -1);
+ int GetDevIndex() const { return m_dev_idx; }
+ int GetDevAddrIndex() const { return m_dev_addr_idx; }
+ int GetRegIndex() const { return m_reg_idx; }
+ int GetRegAddrIndex() const { return m_reg_addr_idx; }
+private:
+ int m_dev_idx, m_dev_addr_idx, m_reg_idx, m_reg_addr_idx;
+};
+
+class RegTab : public QObject
+{
+ Q_OBJECT
+public:
+ RegTab(Backend *backend, QTabWidget *parent);
+
+protected:
+ void FillDevSubTree(RegTreeItem *item);
+ void FillRegTree();
+ void FillAnalyserList();
+ void UpdateSocList();
+ void DisplayRegister(soc_dev_t& dev, soc_dev_addr_t& dev_addr,
+ soc_reg_t& reg, soc_reg_addr_t& reg_addr);
+ void SetDataSocName(const QString& socname);
+ QComboBox *m_soc_selector;
+ Backend *m_backend;
+ QTreeWidget *m_reg_tree;
+ soc_t m_cur_soc;
+ QVBoxLayout *m_right_panel;
+ QWidget *m_right_content;
+ QSplitter *m_splitter;
+ QLineEdit *m_data_sel_edit;
+ QLabel *m_data_soc_label;
+ QPushButton *m_data_sel_reload;
+ QComboBox *m_data_selector;
+ IoBackend *m_io_backend;
+ QTabWidget *m_type_selector;
+ QListWidget *m_analysers_list;
+
+private slots:
+ void OnSocChanged(const QString& text);
+ void OnSocListChanged();
+ void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
+ void OnRegItemClicked(QTreeWidgetItem *clicked, int col);
+ void OnDataSelChanged(int index);
+ void OnDataChanged();
+ void OnDataSocActivated(const QString&);
+ void OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void OnAnalyserClicked(QListWidgetItem *clicked);
+};
+
+#endif /* REGTAB_H */ \ No newline at end of file
diff --git a/utils/regtools/qeditor/settings.cpp b/utils/regtools/qeditor/settings.cpp
new file mode 100644
index 0000000000..d72a15f74f
--- /dev/null
+++ b/utils/regtools/qeditor/settings.cpp
@@ -0,0 +1,32 @@
+#include <QCoreApplication>
+#include <QDebug>
+#include "settings.h"
+
+Settings::Settings()
+{
+
+}
+
+Settings::~Settings()
+{
+ if(m_settings)
+ delete m_settings;
+}
+
+QSettings *Settings::GetSettings()
+{
+ if(!m_settings)
+ {
+ QDir dir(QCoreApplication::applicationDirPath());
+ QString filename = dir.filePath(QCoreApplication::organizationDomain() + ".ini");
+ m_settings = new QSettings(filename, QSettings::IniFormat);
+ }
+ return m_settings;
+}
+
+QSettings *Settings::Get()
+{
+ return g_settings.GetSettings();
+}
+
+Settings Settings::g_settings; \ No newline at end of file
diff --git a/utils/regtools/qeditor/settings.h b/utils/regtools/qeditor/settings.h
new file mode 100644
index 0000000000..0776ec3b89
--- /dev/null
+++ b/utils/regtools/qeditor/settings.h
@@ -0,0 +1,21 @@
+#ifndef _SETTINGS_H_
+#define _SETTINGS_H_
+
+#include <QSettings>
+#include <QString>
+#include <QDir>
+
+class Settings
+{
+public:
+ Settings();
+ ~Settings();
+
+ QSettings *GetSettings();
+ static QSettings *Get();
+private:
+ QSettings *m_settings;
+ static Settings g_settings;
+};
+
+#endif /* _SETTINGS_H_ */ \ No newline at end of file
diff --git a/utils/regtools/qeditor/std_analysers.cpp b/utils/regtools/qeditor/std_analysers.cpp
new file mode 100644
index 0000000000..49df671146
--- /dev/null
+++ b/utils/regtools/qeditor/std_analysers.cpp
@@ -0,0 +1,636 @@
+#include "std_analysers.h"
+
+/**
+ * Clock analyser
+ */
+
+ClockAnalyser::ClockAnalyser(const soc_t& soc, IoBackend *backend)
+ :Analyser(soc, backend)
+{
+ m_group = new QGroupBox("Clock Analyser");
+ QVBoxLayout *layout = new QVBoxLayout;
+ m_group->setLayout(layout);
+ m_tree_widget = new QTreeWidget;
+ layout->addWidget(m_tree_widget);
+
+ m_tree_widget->setColumnCount(2);
+ QStringList list;
+ list << "Name" << "Frequency";
+ m_tree_widget->setHeaderLabels(list);
+
+ FillTree();
+}
+
+ClockAnalyser::~ClockAnalyser()
+{
+}
+
+QWidget *ClockAnalyser::GetWidget()
+{
+ return m_group;
+}
+
+bool ClockAnalyser::SupportSoc(const QString& soc_name)
+{
+ return soc_name == "imx233";
+}
+
+QString ClockAnalyser::GetFreq(unsigned freq)
+{
+ if(freq >= 1000000)
+ {
+ if((freq % 1000000) == 0)
+ return QString().sprintf("%d MHz", freq / 1000000);
+ else
+ return QString().sprintf("%.3f MHz", freq / 1000000.0);
+ }
+ if(freq >= 1000)
+ {
+ if((freq % 1000) == 0)
+ return QString().sprintf("%d KHz", freq / 1000);
+ else
+ return QString().sprintf("%.3f KHz", freq / 1000.0);
+ }
+ return QString().sprintf("%d Hz", freq);
+}
+
+QTreeWidgetItem *ClockAnalyser::AddClock(QTreeWidgetItem *parent, const QString& name, int freq, int mul, int div)
+{
+ if(freq == FROM_PARENT)
+ {
+ int64_t f = GetClockFreq(parent);
+ f *= mul;
+ f /= div;
+ freq = f;
+ }
+ QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList() << name
+ << (freq == INVALID ? "<invalid>" : freq == 0 ? "<disabled>" : GetFreq(freq)));
+ item->setData(1, Qt::UserRole, freq);
+ if(freq == DISABLED || freq == INVALID || (parent && parent->isDisabled()))
+ item->setDisabled(true);
+ if(!parent)
+ m_tree_widget->addTopLevelItem(item);
+ return item;
+}
+
+int ClockAnalyser::GetClockFreq(QTreeWidgetItem *item)
+{
+ return item->data(1, Qt::UserRole).toInt();
+}
+
+void ClockAnalyser::FillTree()
+{
+ m_tree_widget->clear();
+ BackendHelper helper(m_io_backend, m_soc);
+ soc_word_t value, value2, value3;
+
+ QTreeWidgetItem *ring_osc = 0;
+ if(helper.ReadRegisterField("POWER", "MINPWR", "ENABLE_OSC", value))
+ ring_osc = AddClock(0, "ring_clk24m", value ? 24000000 : DISABLED);
+ else
+ ring_osc = AddClock(0, "ring_clk24m", INVALID);
+ QTreeWidgetItem *xtal_osc = 0;
+ if(helper.ReadRegisterField("POWER", "MINPWR", "PWD_XTAL24", value))
+ xtal_osc = AddClock(0, "xtal_clk24m", value ? DISABLED : 24000000);
+ else
+ xtal_osc = AddClock(0, "xtal_clk24m", INVALID);
+ QTreeWidgetItem *ref_xtal = 0;
+ if(helper.ReadRegisterField("POWER", "MINPWR", "SELECT_OSC", value))
+ ref_xtal = AddClock(value ? ring_osc : xtal_osc, "ref_xtal", FROM_PARENT);
+ else
+ ref_xtal = AddClock(0, "ref_xtal", INVALID);
+
+ QTreeWidgetItem *ref_pll = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "PLLCTRL0", "POWER", value))
+ ref_pll = AddClock(ref_xtal, "ref_pll", FROM_PARENT, 20);
+ else
+ ref_pll = AddClock(0, "ref_pll", INVALID);
+
+ QTreeWidgetItem *ref_io = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "FRAC", "CLKGATEIO", value) &&
+ helper.ReadRegisterField("CLKCTRL", "FRAC", "IOFRAC", value2))
+ ref_io = AddClock(ref_pll, "ref_io", value ? DISABLED : FROM_PARENT, 18, value2);
+ else
+ ref_io = AddClock(ref_pll, "ref_io", INVALID);
+
+ QTreeWidgetItem *ref_pix = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "FRAC", "CLKGATEPIX", value) &&
+ helper.ReadRegisterField("CLKCTRL", "FRAC", "PIXFRAC", value2))
+ ref_pix = AddClock(ref_pll, "ref_pix", value ? DISABLED : FROM_PARENT, 18, value2);
+ else
+ ref_pix = AddClock(ref_pll, "ref_pix", INVALID);
+
+ QTreeWidgetItem *ref_emi = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "FRAC", "CLKGATEEMI", value) &&
+ helper.ReadRegisterField("CLKCTRL", "FRAC", "EMIFRAC", value2))
+ ref_emi = AddClock(ref_pll, "ref_emi", value ? DISABLED : FROM_PARENT, 18, value2);
+ else
+ ref_emi = AddClock(ref_pll, "ref_emi", INVALID);
+
+ QTreeWidgetItem *ref_cpu = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "FRAC", "CLKGATECPU", value) &&
+ helper.ReadRegisterField("CLKCTRL", "FRAC", "CPUFRAC", value2))
+ ref_cpu = AddClock(ref_pll, "ref_cpu", value ? DISABLED : FROM_PARENT, 18, value2);
+ else
+ ref_cpu = AddClock(ref_pll, "ref_cpu", INVALID);
+
+ QTreeWidgetItem *clk_p = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_CPU", value))
+ {
+ if(!value)
+ {
+ if(helper.ReadRegisterField("CLKCTRL", "CPU", "DIV_CPU", value2))
+ clk_p = AddClock(ref_cpu, "clk_p", FROM_PARENT, 1, value2);
+ else
+ clk_p = AddClock(ref_cpu, "clk_p", INVALID);
+ }
+ else
+ {
+ if(helper.ReadRegisterField("CLKCTRL", "CPU", "DIV_XTAL_FRAC_EN", value) &&
+ helper.ReadRegisterField("CLKCTRL", "CPU", "DIV_XTAL", value2))
+ clk_p = AddClock(ref_xtal, "clk_p", FROM_PARENT, value ? 1024 : 1, value2);
+ else
+ clk_p = AddClock(ref_xtal, "clk_p", INVALID);
+ }
+ }
+ else
+ clk_p = AddClock(ref_xtal, "clk_p", INVALID);
+
+ QTreeWidgetItem *clk_h = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "HBUS", "DIV_FRAC_EN", value) &&
+ helper.ReadRegisterField("CLKCTRL", "HBUS", "DIV", value2))
+ clk_h = AddClock(clk_p, "clk_h", FROM_PARENT, value ? 32 : 1, value2);
+ else
+ clk_h = AddClock(clk_p, "clk_h", INVALID);
+
+ QTreeWidgetItem *clk_x = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "XBUS", "DIV", value))
+ clk_x = AddClock(ref_xtal, "clk_x", FROM_PARENT, 1, value);
+ else
+ clk_x = AddClock(ref_xtal, "clk_x", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "UART_CLK_GATE", value))
+ AddClock(ref_xtal, "clk_uart", value ? DISABLED : FROM_PARENT);
+ else
+ AddClock(ref_xtal, "clk_uart", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "FILT_CLK24M_GATE", value))
+ AddClock(ref_xtal, "clk_filt24m", value ? DISABLED : FROM_PARENT);
+ else
+ AddClock(ref_xtal, "clk_filt24m", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "PWM_CLK24M_GATE", value))
+ AddClock(ref_xtal, "clk_pwm24m", value ? DISABLED : FROM_PARENT);
+ else
+ AddClock(ref_xtal, "clk_pwm24m", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "DRI_CLK24M_GATE", value))
+ AddClock(ref_xtal, "clk_dri24m", value ? DISABLED : FROM_PARENT);
+ else
+ AddClock(ref_xtal, "clk_dri24m", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "DIGCTRL_CLK1M_GATE", value))
+ AddClock(ref_xtal, "clk_1m", value ? DISABLED : FROM_PARENT, 1, 24);
+ else
+ AddClock(ref_xtal, "clk_1m", INVALID);
+
+ QTreeWidgetItem *clk_32k = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "XTAL", "TIMROT_CLK32K_GATE", value))
+ clk_32k = AddClock(ref_xtal, "clk_32k", value ? DISABLED : FROM_PARENT, 1, 750);
+ else
+ clk_32k = AddClock(ref_xtal, "clk_32k", INVALID);
+
+ AddClock(clk_32k, "clk_adc", FROM_PARENT, 1, 16);
+
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_PIX", value) &&
+ helper.ReadRegisterField("CLKCTRL", "PIX", "DIV", value2))
+ AddClock(value ? ref_xtal : ref_pix, "clk_pix", FROM_PARENT, 1, value2);
+ else
+ AddClock(ref_xtal, "clk_p", INVALID);
+
+ QTreeWidgetItem *clk_ssp = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_SSP", value) &&
+ helper.ReadRegisterField("CLKCTRL", "SSP", "DIV", value2) &&
+ helper.ReadRegisterField("CLKCTRL", "SSP", "CLKGATE", value3))
+ clk_ssp = AddClock(value ? ref_xtal : ref_io, "clk_ssp", value3 ? DISABLED : FROM_PARENT, 1, value2);
+ else
+ clk_ssp = AddClock(ref_xtal, "clk_p", INVALID);
+
+ if(helper.ReadRegisterField("SSP1", "TIMING", "CLOCK_DIVIDE", value) &&
+ helper.ReadRegisterField("SSP1", "TIMING", "CLOCK_RATE", value2) &&
+ helper.ReadRegisterField("SSP1", "CTRL0", "CLKGATE", value3))
+ AddClock(clk_ssp, "clk_ssp1", value3 ? DISABLED : FROM_PARENT, 1, value * (1 + value2));
+ else
+ AddClock(clk_ssp, "clk_ssp1", INVALID);
+
+ if(helper.ReadRegisterField("SSP2", "TIMING", "CLOCK_DIVIDE", value) &&
+ helper.ReadRegisterField("SSP2", "TIMING", "CLOCK_RATE", value2) &&
+ helper.ReadRegisterField("SSP2", "CTRL0", "CLKGATE", value3))
+ AddClock(clk_ssp, "clk_ssp2", value3 ? DISABLED : FROM_PARENT, 1, value * (1 + value2));
+ else
+ AddClock(clk_ssp, "clk_ssp2", INVALID);
+
+ QTreeWidgetItem *clk_gpmi = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_GPMI", value) &&
+ helper.ReadRegisterField("CLKCTRL", "GPMI", "DIV", value2) &&
+ helper.ReadRegisterField("CLKCTRL", "GPMI", "CLKGATE", value3))
+ clk_gpmi = AddClock(value ? ref_xtal : ref_io, "clk_gpmi", value3 ? DISABLED : FROM_PARENT, 1, value2);
+ else
+ clk_gpmi = AddClock(ref_xtal, "clk_p", INVALID);
+
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_EMI", value))
+ {
+ if(!value)
+ {
+ if(helper.ReadRegisterField("CLKCTRL", "EMI", "DIV_EMI", value2) &&
+ helper.ReadRegisterField("CLKCTRL", "EMI", "CLKGATE", value3))
+ AddClock(ref_emi, "clk_emi", value3 ? DISABLED : FROM_PARENT, 1, value2);
+ else
+ AddClock(ref_emi, "clk_emi", INVALID);
+ }
+ else
+ {
+ if(helper.ReadRegisterField("CLKCTRL", "EMI", "DIV_XTAL", value2) &&
+ helper.ReadRegisterField("CLKCTRL", "EMI", "CLKGATE", value3))
+ AddClock(ref_xtal, "clk_emi", value3 ? DISABLED : FROM_PARENT, 1, value2);
+ else
+ AddClock(ref_xtal, "clk_emi", INVALID);
+ }
+ }
+ else
+ clk_p = AddClock(ref_xtal, "clk_emi", INVALID);
+
+ QTreeWidgetItem *ref_vid = AddClock(ref_pll, "clk_vid", FROM_PARENT);
+
+ if(helper.ReadRegisterField("CLKCTRL", "TV", "CLK_TV108M_GATE", value) &&
+ helper.ReadRegisterField("CLKCTRL", "TV", "CLK_TV_GATE", value2))
+ {
+ QTreeWidgetItem *clk_tv108m = AddClock(ref_vid, "clk_tv108m", value ? DISABLED : FROM_PARENT, 1, 4);
+ AddClock(clk_tv108m, "clk_tv54m", value2 ? DISABLED : FROM_PARENT, 1, 2);
+ AddClock(clk_tv108m, "clk_tv27m", value2 ? DISABLED : FROM_PARENT, 1, 4);
+ }
+
+ if(helper.ReadRegisterField("CLKCTRL", "PLLCTRL0", "EN_USB_CLKS", value))
+ AddClock(ref_pll, "utmi_clk480m", value ? FROM_PARENT : DISABLED);
+ else
+ AddClock(ref_pll, "utmi_clk480m", INVALID);
+
+ QTreeWidgetItem *xtal_clk32k = 0;
+ if(helper.ReadRegisterField("RTC", "PERSISTENT0", "XTAL32_FREQ", value) &&
+ helper.ReadRegisterField("RTC", "PERSISTENT0", "XTAL32KHZ_PWRUP", value2))
+ xtal_clk32k = AddClock(0, "xtal_clk32k", value2 == 0 ? DISABLED : value ? 32000 : 32768);
+ else
+ xtal_clk32k = AddClock(0, "xtal_clk32k", INVALID);
+
+ if(helper.ReadRegisterField("RTC", "PERSISTENT0", "CLOCKSOURCE", value))
+ AddClock(value ? xtal_clk32k : ref_xtal, "clk_rtc32k", FROM_PARENT, 1, value ? 1 : 768);
+ else
+ AddClock(ref_xtal, "clk_rtc32k", INVALID);
+
+ (void) clk_x;
+ (void) clk_gpmi;
+ (void) clk_h;
+
+ m_tree_widget->expandAll();
+ m_tree_widget->resizeColumnToContents(0);
+}
+
+static TmplAnalyserFactory< ClockAnalyser > g_clock_factory(true, "Clock Analyser");
+
+/**
+ * EMI analyser
+ */
+EmiAnalyser::EmiAnalyser(const soc_t& soc, IoBackend *backend)
+ :Analyser(soc, backend)
+{
+ m_group = new QGroupBox("EMI Analyser");
+ QVBoxLayout *layout = new QVBoxLayout;
+ m_group->setLayout(layout);
+ m_panel = new QToolBox;
+ m_display_selector = new QComboBox;
+ m_display_selector->addItem("Cycles", DisplayCycles);
+ m_display_selector->addItem("Raw Hexadecimal", DisplayRawHex);
+ m_display_selector->addItem("Time", DisplayTime);
+ QHBoxLayout *line_layout = new QHBoxLayout;
+ line_layout->addWidget(new QLabel("Display Mode:"));
+ line_layout->addWidget(m_display_selector);
+ m_emi_freq_label = new QLineEdit;
+ m_emi_freq_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ m_emi_freq_label->setReadOnly(true);
+ line_layout->addStretch();
+ line_layout->addWidget(new QLabel("Frequency:"));
+ line_layout->addWidget(m_emi_freq_label);
+ line_layout->addWidget(new QLabel("MHz"));
+ line_layout->addStretch();
+ layout->addLayout(line_layout);
+ layout->addWidget(m_panel);
+
+ connect(m_display_selector, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(OnChangeDisplayMode(int)));
+
+ FillTable();
+}
+
+EmiAnalyser::~EmiAnalyser()
+{
+}
+
+QWidget *EmiAnalyser::GetWidget()
+{
+ return m_group;
+}
+
+bool EmiAnalyser::SupportSoc(const QString& soc_name)
+{
+ return soc_name == "imx233";
+}
+
+void EmiAnalyser::OnChangeDisplayMode(int index)
+{
+ m_display_mode = (DisplayMode)m_display_selector->itemData(index).toInt();
+ int idx = m_panel->currentIndex();
+ FillTable();
+ m_panel->setCurrentIndex(idx);
+}
+
+void EmiAnalyser::NewGroup(const QString& name)
+{
+ QTableWidget *table = new QTableWidget;
+ table->setColumnCount(3);
+ table->setHorizontalHeaderItem(0, new QTableWidgetItem("Name"));
+ table->setHorizontalHeaderItem(1, new QTableWidgetItem("Value"));
+ table->setHorizontalHeaderItem(2, new QTableWidgetItem("Comment"));
+ table->verticalHeader()->setVisible(false);
+ table->horizontalHeader()->setStretchLastSection(true);
+ m_panel->addItem(table, name);
+}
+
+void EmiAnalyser::AddLine(const QString& name, int value, const QString& unit, const QString& comment)
+{
+ QTableWidget *table = dynamic_cast< QTableWidget* >(m_panel->widget(m_panel->count() - 1));
+ int row = table->rowCount();
+ table->setRowCount(row + 1);
+ table->setItem(row, 0, new QTableWidgetItem(name));
+ QString val;
+ if(value == INVALID)
+ val = "<invalid>";
+ else if(value == NONE)
+ val = unit;
+ else if(m_display_mode == DisplayRawHex && unit.size() == 0)
+ val = QString("0x%1").arg(value, 0, 16);
+ else
+ val = QString("%1%2").arg(value).arg(unit);
+ table->setItem(row, 1, new QTableWidgetItem(val));
+ table->item(row, 1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ table->setItem(row, 2, new QTableWidgetItem(comment));
+ table->resizeColumnToContents(0);
+ table->resizeColumnToContents(1);
+}
+
+void EmiAnalyser::AddCycleLine(const QString& name, unsigned raw_val, float val,
+ int digits, const QString& comment)
+{
+ if(m_display_mode == DisplayCycles)
+ {
+ QString str;
+ if(digits == 0)
+ str = QString("%1").arg((int)val);
+ else
+ str = QString("%1").arg(val, 0, 'f', digits);
+ str += " cycles";
+ AddLine(name, NONE, str, comment);
+ }
+ else if(m_display_mode == DisplayRawHex)
+ {
+ QString str = QString("0x%1").arg(raw_val, 0, 16);
+ AddLine(name, NONE, str, comment);
+ }
+ else if(m_display_mode == DisplayTime && m_emi_freq != 0)
+ {
+ float cycle_time_ns = 1000000000.0 / m_emi_freq;
+ val *= cycle_time_ns;
+ QString str;
+ if(val >= 1000)
+ str = QString::fromWCharArray(L"%1 ┬Ás").arg(val / 1000.0, 0, 'f', 2);
+ else
+ str = QString("%1 ns").arg(val, 0, 'f', 2);
+ AddLine(name, NONE, str, comment);
+ }
+ else
+ AddLine(name, raw_val, " cycles", comment);
+}
+
+void EmiAnalyser::FillTable()
+{
+ while(m_panel->count() > 0)
+ m_panel->removeItem(0);
+ BackendHelper helper(m_io_backend, m_soc);
+ soc_word_t value;
+
+ m_emi_freq = 0;
+ if(helper.ReadRegisterField("CLKCTRL", "CLKSEQ", "BYPASS_EMI", value))
+ {
+ bool ret;
+ if(value)
+ {
+ m_emi_freq = 24000000;
+ ret = helper.ReadRegisterField("CLKCTRL", "EMI", "DIV_XTAL", value);
+ }
+ else
+ {
+ m_emi_freq = 480000000;
+ if(helper.ReadRegisterField("CLKCTRL", "FRAC", "EMIFRAC", value))
+ m_emi_freq = 18 * (int64_t)m_emi_freq / value;
+ else
+ m_emi_freq = 0;
+ ret = helper.ReadRegisterField("CLKCTRL", "EMI", "DIV_EMI", value);
+ }
+ if(ret)
+ m_emi_freq /= value;
+ else
+ m_emi_freq = 0;
+ }
+
+ m_emi_freq_label->setText(QString().sprintf("%.3f", m_emi_freq / 1000000.0));
+
+ NewGroup("Control Parameters");
+ if(helper.ReadRegisterField("EMI", "CTRL", "PORT_PRIORITY_ORDER", value))
+ {
+ QStringList ports;
+ ports << "AXI0" << "AHB1" << "AHB2" << "AHB3";
+ QString order;
+ order += ports[value / 6];
+ ports.erase(ports.begin() + value / 6);
+ int ord[6][3] = { {0, 1, 2}, {2, 0, 1}, {1, 2, 0}, {2, 1, 0}, {1, 0, 2}, {0, 2, 1} };
+ for(int i = 0; i < 3; i++)
+ order += ", " + ports[ord[value][i]];
+ AddLine("Port Priority Order", value, "", order);
+ }
+
+ if(helper.ReadRegisterField("EMI", "CTRL", "MEM_WIDTH", value))
+ AddLine("Memory Width", value ? 16 : 8, "-bit");
+
+ if(helper.ReadRegisterField("DRAM", "CTL03", "AP", value))
+ AddLine("Auto Pre-Charge", NONE, value ? "Yes" : "No");
+
+ bool bypass_mode = false;
+ if(helper.ReadRegisterField("DRAM", "CTL04", "DLL_BYPASS_MODE", value))
+ {
+ bypass_mode = value == 1;
+ AddLine("DLL Bypass Mode", NONE, value ? "Yes" : "No");
+ }
+
+ if(helper.ReadRegisterField("DRAM", "CTL05", "EN_LOWPOWER_MODE", value))
+ AddLine("Low Power Mode", NONE, value ? "Enabled" : "Disabled");
+
+ if(helper.ReadRegisterField("DRAM", "CTL08", "SREFRESH", value))
+ AddLine("Self Refresh", NONE, value ? "Yes" : "No");
+
+ if(helper.ReadRegisterField("DRAM", "CTL08", "SDR_MODE", value))
+ AddLine("Mode", NONE, value ? "SDR" : "DDR");
+
+ if(helper.ReadRegisterField("DRAM", "CTL10", "ADDR_PINS", value))
+ AddLine("Address Pins", 13 - value, "");
+
+ if(helper.ReadRegisterField("DRAM", "CTL11", "ADDR_PINS", value))
+ AddLine("Column Size", 12 - value, "-bit");
+
+ if(helper.ReadRegisterField("DRAM", "CTL11", "ADDR_PINS", value))
+ AddLine("Encoded CAS", value, "Memory device dependent");
+
+ if(helper.ReadRegisterField("DRAM", "CTL14", "CS_MAP", value))
+ {
+ QString v;
+ for(int i = 0; i < 4; i++)
+ if(value & (1 << i))
+ {
+ if(v.size() != 0)
+ v += " ";
+ v += QString("%1").arg(i);
+ }
+ AddLine("Chip Select Pins", NONE, v, "");
+ }
+
+ if(helper.ReadRegisterField("DRAM", "CTL37", "TREF_ENABLE", value))
+ AddLine("Refresh Commands", NONE, value ? "Enabled" : "Disabled", "Issue self-refresh every TREF cycles");
+
+ NewGroup("Frequency Parameters");
+
+ if(helper.ReadRegisterField("DRAM", "CTL13", "CASLAT_LIN_GATE", value))
+ {
+ if(value >= 3 && value <= 10 && value != 9)
+ {
+ float v = (value / 2) + 0.5 * (value % 2);
+ AddCycleLine("CAS Gate", value, v, 1, "");
+ }
+ else
+ AddLine("CAS Gate", NONE, "Reserved", "Reserved value");
+ }
+ if(helper.ReadRegisterField("DRAM", "CTL13", "CASLAT_LIN", value))
+ {
+ if(value >= 3 && value <= 10 && value != 9)
+ {
+ float v = (value / 2) + 0.5 * (value % 2);
+ AddCycleLine("CAS Latency", value, v, 1, "");
+ }
+ else
+ AddLine("CAS Latency", NONE, "Reserved", "Reserved value");
+ }
+
+ if(helper.ReadRegisterField("DRAM", "CTL12", "TCKE", value))
+ AddCycleLine("tCKE", value, value, 0, "Minimum CKE pulse width");
+
+ if(helper.ReadRegisterField("DRAM", "CTL15", "TDAL", value))
+ AddCycleLine("tDAL", value, value, 0, "Auto pre-charge write recovery time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL31", "TDLL", value))
+ AddCycleLine("tDLL", value, value, 0, "DLL lock time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL10", "TEMRS", value))
+ AddCycleLine("tEMRS", value, value, 0, "Extended mode parameter set time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL34", "TINIT", value))
+ AddCycleLine("tINIT", value, value, 0, "Initialisation time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL16", "TMRD", value))
+ AddCycleLine("tMRD", value, value, 0, "Mode register set command time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL40", "TPDEX", value))
+ AddCycleLine("tPDEX", value, value, 0, "Power down exit time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL32", "TRAS_MAX", value))
+ AddCycleLine("tRAS Max", value, value, 0, "Maximum row activate time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL20", "TRAS_MIN", value))
+ AddCycleLine("tRAS Min", value, value, 0, "Minimum row activate time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL17", "TRC", value))
+ AddCycleLine("tRC", value, value, 0, "Activate to activate delay (same bank)");
+
+ if(helper.ReadRegisterField("DRAM", "CTL20", "TRCD_INT", value))
+ AddCycleLine("tRCD", value, value, 0, "RAS to CAS");
+
+ if(helper.ReadRegisterField("DRAM", "CTL26", "TREF", value))
+ AddCycleLine("tREF", value, value, 0, "Refresh to refresh time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL21", "TRFC", value))
+ AddCycleLine("tRFC", value, value, 0, "Refresh command time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL15", "TRP", value))
+ AddCycleLine("tRP", value, value, 0, "Pre-charge command time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL12", "TRRD", value))
+ AddCycleLine("tRRD", value, value, 0, "Activate to activate delay (different banks)");
+
+ if(helper.ReadRegisterField("DRAM", "CTL12", "TWR_INT", value))
+ AddCycleLine("tWR", value, value, 0, "Write recovery time");
+
+ if(helper.ReadRegisterField("DRAM", "CTL13", "TWTR", value))
+ AddCycleLine("tWTR", value, value, 0, "Write to read delay");
+
+ if(helper.ReadRegisterField("DRAM", "CTL32", "TXSNR", value))
+ AddCycleLine("tXSNR", value, value, 0, "");
+
+ if(helper.ReadRegisterField("DRAM", "CTL33", "TXSR", value))
+ AddCycleLine("tXSR", value, value, 0, "Self-refresh exit time");
+
+ NewGroup("DLL Parameters");
+
+ if(bypass_mode)
+ {
+ if(helper.ReadRegisterField("DRAM", "CTL19", "DLL_DQS_DELAY_0_BYPASS", value))
+ AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle (bypass mode)");
+
+ if(helper.ReadRegisterField("DRAM", "CTL19", "DLL_DQS_DELAY_1_BYPASS", value))
+ AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle (bypass mode)");
+
+ if(helper.ReadRegisterField("DRAM", "CTL19", "DQS_OUT_SHIFT_BYPASS", value))
+ AddLine("DQS Out Delay", value, "", "(bypass mode)");
+
+ if(helper.ReadRegisterField("DRAM", "CTL20", "WR_DQS_SHIFT_BYPASS", value))
+ AddLine("DQS Write Delay", value, "", "(bypass mode)");
+ }
+ else
+ {
+ if(helper.ReadRegisterField("DRAM", "CTL17", "DLL_START_POINT", value))
+ AddLine("DLL Start Point", value, "", "Initial delay count");
+
+ if(helper.ReadRegisterField("DRAM", "CTL17", "DLL_INCREMENT", value))
+ AddLine("DLL Increment", value, "", "Delay increment");
+
+ if(helper.ReadRegisterField("DRAM", "CTL18", "DLL_DQS_DELAY_0", value))
+ AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle");
+
+ if(helper.ReadRegisterField("DRAM", "CTL18", "DLL_DQS_DELAY_1", value))
+ AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle");
+
+ if(helper.ReadRegisterField("DRAM", "CTL19", "DQS_OUT_SHIFT", value))
+ AddLine("DQS Out Delay", value, "", "");
+
+ if(helper.ReadRegisterField("DRAM", "CTL20", "WR_DQS_SHIFT", value))
+ AddLine("DQS Write Delay", value, "", "");
+ }
+
+}
+
+static TmplAnalyserFactory< EmiAnalyser > g_emi_factory(true, "EMI Analyser"); \ No newline at end of file
diff --git a/utils/regtools/qeditor/std_analysers.h b/utils/regtools/qeditor/std_analysers.h
new file mode 100644
index 0000000000..98c5fa0f98
--- /dev/null
+++ b/utils/regtools/qeditor/std_analysers.h
@@ -0,0 +1,95 @@
+#ifndef _STDANALYSER_H_
+#define _STDANALYSER_H_
+
+#include "analyser.h"
+
+#include <QGroupBox>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QTableWidget>
+#include <QHeaderView>
+#include <QToolBox>
+#include <QComboBox>
+#include <QLabel>
+#include <QLineEdit>
+#include "analyser.h"
+#include "collapsiblepanel.h"
+
+/**
+ * Clock analyser
+ */
+
+class ClockAnalyser : public Analyser
+{
+ Q_OBJECT
+public:
+ ClockAnalyser(const soc_t& soc, IoBackend *backend);
+ virtual ~ClockAnalyser();
+ virtual QWidget *GetWidget();
+ static bool SupportSoc(const QString& soc_name);
+
+private:
+ QString GetFreq(unsigned freq);
+
+ enum
+ {
+ DISABLED = 0,
+ INVALID = -1,
+ FROM_PARENT = -2,
+ };
+
+ QTreeWidgetItem *AddClock(QTreeWidgetItem *parent, const QString& name, int freq, int mul = 1, int div = 1);
+ int GetClockFreq(QTreeWidgetItem *item);
+ void FillTree();
+
+private:
+ QGroupBox *m_group;
+ QTreeWidget *m_tree_widget;
+};
+
+/**
+ * EMI analyser
+ */
+class EmiAnalyser : public Analyser
+{
+ Q_OBJECT
+public:
+ EmiAnalyser(const soc_t& soc, IoBackend *backend);
+ virtual ~EmiAnalyser();
+ virtual QWidget *GetWidget();
+
+ static bool SupportSoc(const QString& soc_name);
+
+private slots:
+ void OnChangeDisplayMode(int index);
+
+private:
+ enum DisplayMode
+ {
+ DisplayCycles,
+ DisplayRawHex,
+ DisplayTime,
+ };
+
+ enum
+ {
+ NONE = -999999,
+ INVALID = -1000000
+ };
+
+ void NewGroup(const QString& name);
+ void AddLine(const QString& name, int value, const QString& unit, const QString& comment = "");
+ void AddCycleLine(const QString& name, unsigned raw_val, float val, int digits, const QString& comment = "");
+ void FillTable();
+
+private:
+ QGroupBox *m_group;
+ QComboBox *m_display_selector;
+ QToolBox *m_panel;
+ DisplayMode m_display_mode;
+ unsigned m_emi_freq;
+ QLineEdit *m_emi_freq_label;
+};
+
+#endif /* _STDANALYSER_H_ */