diff options
Diffstat (limited to 'utils/regtools')
-rw-r--r-- | utils/regtools/qeditor/analyser.cpp | 44 | ||||
-rw-r--r-- | utils/regtools/qeditor/analyser.h | 64 | ||||
-rw-r--r-- | utils/regtools/qeditor/backend.cpp | 156 | ||||
-rw-r--r-- | utils/regtools/qeditor/backend.h | 77 | ||||
-rw-r--r-- | utils/regtools/qeditor/main.cpp | 30 | ||||
-rw-r--r-- | utils/regtools/qeditor/mainwindow.cpp | 108 | ||||
-rw-r--r-- | utils/regtools/qeditor/mainwindow.h | 44 | ||||
-rw-r--r-- | utils/regtools/qeditor/qeditor.pro | 8 | ||||
-rw-r--r-- | utils/regtools/qeditor/regtab.cpp | 392 | ||||
-rw-r--r-- | utils/regtools/qeditor/regtab.h | 85 | ||||
-rw-r--r-- | utils/regtools/qeditor/settings.cpp | 32 | ||||
-rw-r--r-- | utils/regtools/qeditor/settings.h | 21 | ||||
-rw-r--r-- | utils/regtools/qeditor/std_analysers.cpp | 636 | ||||
-rw-r--r-- | utils/regtools/qeditor/std_analysers.h | 95 |
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_ */ |