diff options
Diffstat (limited to 'utils/regtools/qeditor/regtab.cpp')
-rw-r--r-- | utils/regtools/qeditor/regtab.cpp | 392 |
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 | |||
19 | RegTreeItem::RegTreeItem(const QString& string, int type) | ||
20 | :QTreeWidgetItem(QStringList(string), type) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | void 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 | |||
32 | RegTab::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 | |||
113 | void 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 | |||
128 | void 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 | |||
135 | void 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 | |||
165 | void RegTab::OnDataChanged() | ||
166 | { | ||
167 | OnRegItemChanged(m_reg_tree->currentItem(), m_reg_tree->currentItem()); | ||
168 | } | ||
169 | |||
170 | void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) | ||
171 | { | ||
172 | (void) previous; | ||
173 | OnRegItemClicked(current, 0); | ||
174 | } | ||
175 | |||
176 | void 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 | |||
192 | void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous) | ||
193 | { | ||
194 | (void) previous; | ||
195 | OnAnalyserClicked(current); | ||
196 | } | ||
197 | |||
198 | void 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 | |||
208 | void 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 | |||
341 | void 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 | |||
349 | void 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 | |||
364 | void 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 | |||
379 | void RegTab::FillAnalyserList() | ||
380 | { | ||
381 | m_analysers_list->clear(); | ||
382 | m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.name.c_str())); | ||
383 | } | ||
384 | |||
385 | void 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 | } | ||