summaryrefslogtreecommitdiff
path: root/utils/regtools/qeditor/regtab.cpp
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 /utils/regtools/qeditor/regtab.cpp
parent902306378e38ce571f4595ae8dabb2acd2412faa (diff)
downloadrockbox-c323381f0b3ee68b0093442335e8e7cbb112858a.tar.gz
rockbox-c323381f0b3ee68b0093442335e8e7cbb112858a.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
Diffstat (limited to 'utils/regtools/qeditor/regtab.cpp')
-rw-r--r--utils/regtools/qeditor/regtab.cpp392
1 files changed, 392 insertions, 0 deletions
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 @@
1#include "regtab.h"
2
3#include <QSplitter>
4#include <QVBoxLayout>
5#include <QGroupBox>
6#include <QAbstractListModel>
7#include <QMessageBox>
8#include <QSizePolicy>
9#include <QHBoxLayout>
10#include <QStringBuilder>
11#include <QLabel>
12#include <QGridLayout>
13#include <QTableWidget>
14#include <QHeaderView>
15#include <QFileDialog>
16#include "backend.h"
17#include "analyser.h"
18
19RegTreeItem::RegTreeItem(const QString& string, int type)
20 :QTreeWidgetItem(QStringList(string), type)
21{
22}
23
24void RegTreeItem::SetPath(int dev_idx, int dev_addr_idx, int reg_idx, int reg_addr_idx)
25{
26 m_dev_idx = dev_idx;
27 m_dev_addr_idx = dev_addr_idx;
28 m_reg_idx = reg_idx;
29 m_reg_addr_idx = reg_addr_idx;
30}
31
32RegTab::RegTab(Backend *backend, QTabWidget *parent)
33 :m_backend(backend)
34{
35 m_splitter = new QSplitter();
36 QWidget *left = new QWidget;
37 m_splitter->addWidget(left);
38 QVBoxLayout *left_layout = new QVBoxLayout;
39 left->setLayout(left_layout);
40
41 QGroupBox *top_group = new QGroupBox("SOC selection");
42 QVBoxLayout *top_group_layout = new QVBoxLayout;
43 m_soc_selector = new QComboBox;
44 top_group_layout->addWidget(m_soc_selector);
45 top_group->setLayout(top_group_layout);
46
47 m_reg_tree = new QTreeWidget();
48 m_reg_tree->setColumnCount(1);
49 m_reg_tree->setHeaderLabel(QString("Name"));
50
51 m_analysers_list = new QListWidget;
52
53 m_type_selector = new QTabWidget;
54 m_type_selector->addTab(m_reg_tree, "Registers");
55 m_type_selector->addTab(m_analysers_list, "Analyzers");
56 m_type_selector->setTabPosition(QTabWidget::West);
57
58 left_layout->addWidget(top_group);
59 left_layout->addWidget(m_type_selector);
60
61 m_right_panel = new QVBoxLayout;
62 QGroupBox *data_sel_group = new QGroupBox("Data selection");
63 QHBoxLayout *data_sel_layout = new QHBoxLayout;
64 m_data_selector = new QComboBox;
65 m_data_selector->addItem(QIcon::fromTheme("face-sad"), "None", QVariant(DataSelNothing));
66 m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile));
67 m_data_sel_edit = new QLineEdit;
68 m_data_sel_edit->setReadOnly(true);
69 m_data_soc_label = new QLabel;
70 QPushButton *data_sel_reload = new QPushButton;
71 data_sel_reload->setIcon(QIcon::fromTheme("view-refresh"));
72 data_sel_layout->addWidget(m_data_selector);
73 data_sel_layout->addWidget(m_data_sel_edit);
74 data_sel_layout->addWidget(m_data_soc_label);
75 data_sel_layout->addWidget(data_sel_reload);
76 data_sel_group->setLayout(data_sel_layout);
77 m_data_soc_label->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
78
79 m_right_panel->addWidget(data_sel_group);
80 m_right_content = new QWidget;
81 QVBoxLayout *l = new QVBoxLayout;
82 l->addStretch();
83 m_right_content->setLayout(l);
84 m_right_panel->addWidget(m_right_content);
85 QWidget *w = new QWidget;
86 w->setLayout(m_right_panel);
87 m_splitter->addWidget(w);
88
89 m_io_backend = m_backend->CreateDummyIoBackend();
90
91 parent->addTab(m_splitter, "Register Tab");
92
93 connect(m_soc_selector, SIGNAL(currentIndexChanged(const QString&)),
94 this, SLOT(OnSocChanged(const QString&)));
95 connect(m_backend, SIGNAL(OnSocListChanged()), this, SLOT(OnSocListChanged()));
96 connect(m_reg_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
97 this, SLOT(OnRegItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
98 connect(m_reg_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
99 SLOT(OnRegItemClicked(QTreeWidgetItem *, int)));
100 connect(m_data_selector, SIGNAL(activated(int)),
101 this, SLOT(OnDataSelChanged(int)));
102 connect(m_data_soc_label, SIGNAL(linkActivated(const QString&)), this,
103 SLOT(OnDataSocActivated(const QString&)));
104 connect(m_analysers_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
105 this, SLOT(OnAnalyserChanged(QListWidgetItem *, QListWidgetItem *)));
106 connect(m_analysers_list, SIGNAL(itemClicked(QListWidgetItem *)), this,
107 SLOT(OnAnalyserClicked(QListWidgetItem *)));
108
109 OnSocListChanged();
110 OnDataSelChanged(DataSelNothing);
111}
112
113void RegTab::SetDataSocName(const QString& socname)
114{
115 if(socname.size() != 0)
116 {
117 m_data_soc_label->setText("<a href=\"" + socname + "\">" + socname + "</a>");
118 m_data_soc_label->setTextFormat(Qt::RichText);
119 m_data_soc_label->show();
120 }
121 else
122 {
123 m_data_soc_label->setText("");
124 m_data_soc_label->hide();
125 }
126}
127
128void RegTab::OnDataSocActivated(const QString& str)
129{
130 int index = m_soc_selector->findText(str);
131 if(index != -1)
132 m_soc_selector->setCurrentIndex(index);
133}
134
135void RegTab::OnDataSelChanged(int index)
136{
137 if(index == -1)
138 return;
139 QVariant var = m_data_selector->itemData(index);
140 if(var == DataSelFile)
141 {
142 QFileDialog *fd = new QFileDialog(m_data_selector);
143 fd->setFilter("Textual files (*.txt);;All files (*)");
144 fd->setDirectory(Settings::Get()->value("regtab/loaddatadir", QDir::currentPath()).toString());
145 if(fd->exec())
146 {
147 QStringList filenames = fd->selectedFiles();
148 delete m_io_backend;
149 m_io_backend = m_backend->CreateFileIoBackend(filenames[0]);
150 m_data_sel_edit->setText(filenames[0]);
151 SetDataSocName(m_io_backend->GetSocName());
152 OnDataSocActivated(m_io_backend->GetSocName());
153 }
154 Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
155 }
156 else
157 {
158 delete m_io_backend;
159 m_io_backend = m_backend->CreateDummyIoBackend();
160 SetDataSocName("");
161 }
162 OnDataChanged();
163}
164
165void RegTab::OnDataChanged()
166{
167 OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem());
168}
169
170void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
171{
172 (void) previous;
173 OnRegItemClicked(current, 0);
174}
175
176void RegTab::OnRegItemClicked(QTreeWidgetItem *current, int col)
177{
178 (void) col;
179 if(current == 0)
180 return;
181 RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
182 if(item->type() != RegTreeRegType)
183 return;
184 soc_dev_t& dev = m_cur_soc.dev[item->GetDevIndex()];
185 soc_dev_addr_t& dev_addr = dev.addr[item->GetDevAddrIndex()];
186 soc_reg_t& reg = dev.reg[item->GetRegIndex()];
187 soc_reg_addr_t& reg_addr = reg.addr[item->GetRegAddrIndex()];
188
189 DisplayRegister(dev, dev_addr, reg, reg_addr);
190}
191
192void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous)
193{
194 (void) previous;
195 OnAnalyserClicked(current);
196}
197
198void RegTab::OnAnalyserClicked(QListWidgetItem *current)
199{
200 if(current == 0)
201 return;
202 delete m_right_content;
203 AnalyserFactory *ana = AnalyserFactory::GetAnalyserByName(current->text());
204 m_right_content = ana->Create(m_cur_soc, m_io_backend)->GetWidget();
205 m_right_panel->addWidget(m_right_content);
206}
207
208void RegTab::DisplayRegister(soc_dev_t& dev, soc_dev_addr_t& dev_addr,
209 soc_reg_t& reg, soc_reg_addr_t& reg_addr)
210{
211 (void) dev;
212 delete m_right_content;
213
214 QVBoxLayout *right_layout = new QVBoxLayout;
215
216 QString reg_name;
217 reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
218 QStringList names;
219 QVector< soc_addr_t > addresses;
220 names.append(reg_name);
221 addresses.append(reg_addr.addr);
222 if(reg.flags & REG_HAS_SCT)
223 {
224 names.append(reg_name + "_SET");
225 names.append(reg_name + "_CLR");
226 names.append(reg_name + "_TOG");
227 addresses.append(reg_addr.addr + 4);
228 addresses.append(reg_addr.addr + 8);
229 addresses.append(reg_addr.addr + 12);
230 }
231
232 QString str;
233 str += "<table align=left>";
234 for(int i = 0; i < names.size(); i++)
235 str += "<tr><td><b>" + names[i] + "</b></td></tr>";
236 str += "</table>";
237 QLabel *label_names = new QLabel;
238 label_names->setTextFormat(Qt::RichText);
239 label_names->setText(str);
240
241 QString str_addr;
242 str_addr += "<table align=left>";
243 for(int i = 0; i < names.size(); i++)
244 str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
245 str_addr += "</table>";
246 QLabel *label_addr = new QLabel;
247 label_addr->setTextFormat(Qt::RichText);
248 label_addr->setText(str_addr);
249
250 QHBoxLayout *top_layout = new QHBoxLayout;
251 top_layout->addStretch();
252 top_layout->addWidget(label_names);
253 top_layout->addWidget(label_addr);
254 top_layout->addStretch();
255
256 soc_word_t value;
257 bool has_value = m_io_backend->ReadRegister(QString().sprintf("HW.%s.%s",
258 dev_addr.name.c_str(), reg_addr.name.c_str()), value);
259
260 QHBoxLayout *raw_val_layout = 0;
261 if(has_value)
262 {
263 QLabel *raw_val_name = new QLabel;
264 raw_val_name->setText("Raw value:");
265 QLineEdit *raw_val_edit = new QLineEdit;
266 raw_val_edit->setReadOnly(true);
267 raw_val_edit->setText(QString().sprintf("0x%08x", value));
268 raw_val_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
269 raw_val_layout = new QHBoxLayout;
270 raw_val_layout->addStretch();
271 raw_val_layout->addWidget(raw_val_name);
272 raw_val_layout->addWidget(raw_val_edit);
273 raw_val_layout->addStretch();
274 }
275
276 QTableWidget *value_table = new QTableWidget;
277 value_table->setRowCount(reg.field.size());
278 value_table->setColumnCount(4);
279 for(size_t i = 0; i < reg.field.size(); i++)
280 {
281 QString bits_str;
282 if(reg.field[i].first_bit == reg.field[i].last_bit)
283 bits_str.sprintf("%d", reg.field[i].first_bit);
284 else
285 bits_str.sprintf("%d:%d", reg.field[i].last_bit, reg.field[i].first_bit);
286 QTableWidgetItem *item = new QTableWidgetItem(bits_str);
287 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
288 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
289 value_table->setItem(i, 0, item);
290 item = new QTableWidgetItem(QString(reg.field[i].name.c_str()));
291 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
292 value_table->setItem(i, 1, item);
293 item = new QTableWidgetItem();
294 if(has_value)
295 {
296 const soc_reg_field_t& field = reg.field[i];
297 soc_word_t v = (value & field.bitmask()) >> field.first_bit;
298 QString value_name;
299 for(size_t j = 0; j < field.value.size(); j++)
300 if(v == field.value[j].value)
301 value_name = field.value[j].name.c_str();
302 const char *fmt = "%lu";
303 // heuristic
304 if((field.last_bit - field.first_bit + 1) > 16)
305 fmt = "0x%lx";
306 item->setText(QString().sprintf(fmt, (unsigned long)v));
307 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
308
309 if(value_name.size() != 0)
310 {
311 QTableWidgetItem *t = new QTableWidgetItem(value_name);
312 t->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
313 t->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
314 value_table->setItem(i, 3, t);
315 }
316 }
317 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
318 value_table->setItem(i, 2, item);
319 }
320 value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
321 value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
322 value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
323 value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
324 value_table->verticalHeader()->setVisible(false);
325 value_table->resizeColumnsToContents();
326 value_table->horizontalHeader()->setStretchLastSection(true);
327 value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
328
329 right_layout->addLayout(top_layout);
330 if(raw_val_layout)
331 right_layout->addLayout(raw_val_layout);
332 //right_layout->addWidget(bits_label);
333 right_layout->addWidget(value_table);
334 //right_layout->addStretch();
335
336 m_right_content = new QGroupBox("Register Description");
337 m_right_content->setLayout(right_layout);
338 m_right_panel->addWidget(m_right_content);
339}
340
341void RegTab::OnSocListChanged()
342{
343 m_soc_selector->clear();
344 QStringList socs = m_backend->GetSocNameList();
345 for(int i = 0; i < socs.size(); i++)
346 m_soc_selector->addItem(socs[i]);
347}
348
349void RegTab::FillDevSubTree(RegTreeItem *item)
350{
351 soc_dev_t& sd = m_cur_soc.dev[item->GetDevIndex()];
352 for(size_t i = 0; i < sd.reg.size(); i++)
353 {
354 soc_reg_t& reg = sd.reg[i];
355 for(size_t j = 0; j < reg.addr.size(); j++)
356 {
357 RegTreeItem *reg_item = new RegTreeItem(reg.addr[j].name.c_str(), RegTreeRegType);
358 reg_item->SetPath(item->GetDevIndex(), item->GetDevAddrIndex(), i, j);
359 item->addChild(reg_item);
360 }
361 }
362}
363
364void RegTab::FillRegTree()
365{
366 for(size_t i = 0; i < m_cur_soc.dev.size(); i++)
367 {
368 soc_dev_t& sd = m_cur_soc.dev[i];
369 for(size_t j = 0; j < sd.addr.size(); j++)
370 {
371 RegTreeItem *dev_item = new RegTreeItem(sd.addr[j].name.c_str(), RegTreeDevType);
372 dev_item->SetPath(i, j);
373 FillDevSubTree(dev_item);
374 m_reg_tree->addTopLevelItem(dev_item);
375 }
376 }
377}
378
379void RegTab::FillAnalyserList()
380{
381 m_analysers_list->clear();
382 m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.name.c_str()));
383}
384
385void RegTab::OnSocChanged(const QString& soc)
386{
387 m_reg_tree->clear();
388 if(!m_backend->GetSocByName(soc, m_cur_soc))
389 return;
390 FillRegTree();
391 FillAnalyserList();
392}