Skip to content

Commit 8be0049

Browse files
committed
updated UNISIM gate libs and gate details widget
1 parent a7fd6e9 commit 8be0049

4 files changed

Lines changed: 193 additions & 51 deletions

File tree

plugins/gate_libraries/definitions/XILINX_UNISIM.hgl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": 4,
2+
"version": 6,
33
"library": "XILINX_UNISIM",
44
"gate_locations": {
55
"data_category": "generic",
@@ -152456,7 +152456,17 @@
152456152456
"lut_config": {
152457152457
"bit_order": "descending",
152458152458
"data_category": "generic",
152459-
"data_identifier": "INIT"
152459+
"output_pins": [
152460+
{
152461+
"pin": "O6",
152462+
"data_identifier": "INIT"
152463+
},
152464+
{
152465+
"pin": "O5",
152466+
"data_identifier": "INIT",
152467+
"bit_count": 32
152468+
}
152469+
]
152460152470
},
152461152471
"pin_groups": [
152462152472
{

plugins/gate_libraries/definitions/XILINX_UNISIM_hal.hgl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": 4,
2+
"version": 6,
33
"library": "XILINX_UNISIM_WITH_HAL_TYPES",
44
"gate_locations": {
55
"data_category": "generic",
@@ -154091,7 +154091,17 @@
154091154091
"lut_config": {
154092154092
"bit_order": "descending",
154093154093
"data_category": "generic",
154094-
"data_identifier": "INIT"
154094+
"output_pins": [
154095+
{
154096+
"pin": "O6",
154097+
"data_identifier": "INIT"
154098+
},
154099+
{
154100+
"pin": "O5",
154101+
"data_identifier": "INIT",
154102+
"bit_count": 32
154103+
}
154104+
]
154095154105
},
154096154106
"pin_groups": [
154097154107
{

plugins/gui/include/gui/selection_details_widget/gate_details_tab_widget.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
#include "gui/selection_details_widget/data_table_widget.h"
3333
#include "gui/selection_details_widget/groupings_of_item_widget.h"
3434

35+
class QButtonGroup;
36+
class QVBoxLayout;
37+
3538
namespace hal
3639
{
3740
class Gate;
@@ -75,6 +78,7 @@ namespace hal
7578
private Q_SLOTS:
7679

7780
void handleGateBooleanFunctionChanged(Gate* g);
81+
void handleLutPinSelectionChanged(int id);
7882

7983

8084
private:
@@ -139,8 +143,12 @@ namespace hal
139143
DetailsFrameWidget* mLatchFrame;
140144

141145
//lut tab
142-
BooleanFunctionTable* mLutFunctionTable;
143-
DetailsFrameWidget* mLutFrame;
146+
QButtonGroup* mLutPinButtonGroup;
147+
QWidget* mLutRadioWidget;
148+
QVBoxLayout* mLutRadioLayout;
149+
std::vector<std::string> mCurrentLutPins;
150+
std::string mSelectedLutPin;
151+
DetailsFrameWidget* mLutFrame;
144152

145153
QLabel* mLutConfigLabel;
146154
DetailsFrameWidget* mLutConfigurationFrame;

plugins/gui/src/selection_details_widget/gate_details_tab_widget.cpp

Lines changed: 159 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@
77
#include "gui/selection_details_widget/details_frame_widget.h"
88
#include "gui/selection_details_widget/gate_details_widget/gate_info_table.h"
99
#include "gui/selection_details_widget/gate_details_widget/gate_pin_tree.h"
10+
#include "gui/user_action/action_add_boolean_function.h"
1011
#include "gui/user_action/action_set_object_data.h"
1112
#include "gui/validator/hexadecimal_validator.h"
1213
#include "hal_core/netlist/gate.h"
1314
#include "hal_core/netlist/gate_library/gate_type_component/ff_component.h"
1415
#include "hal_core/netlist/gate_library/gate_type_component/gate_type_component.h"
1516
#include "hal_core/netlist/gate_library/gate_type_component/init_component.h"
1617
#include "hal_core/netlist/gate_library/gate_type_component/latch_component.h"
18+
#include "hal_core/netlist/gate_library/gate_type_component/lut_component.h"
1719
#include "hal_core/netlist/gate_library/gate_type_component/state_component.h"
1820

1921
#include <QApplication>
22+
#include <QButtonGroup>
23+
#include <QHBoxLayout>
24+
#include <QRadioButton>
25+
#include <QVBoxLayout>
2026
#include <QClipboard>
2127
#include <QDebug>
2228
#include "gui/comment_system/widgets/comment_widget.h"
@@ -50,13 +56,15 @@ namespace hal
5056
addTab("Pins", mPinsFrame, false);
5157

5258
//(ff / latch / lut) tab - would love to use seperate tabs, but it's a hassle to hide multiple individual tabs witouth setTabVisible() from qt 5.15
53-
mFfFunctionTable = new BooleanFunctionTable(this);
59+
mFfFunctionTable = new BooleanFunctionTable(this);
5460
mLatchFunctionTable = new BooleanFunctionTable(this);
55-
mLutFunctionTable = new BooleanFunctionTable(this);
56-
mLutFunctionTable->setContextMenuPlainDescr(true);
57-
mLutFunctionTable->setContextMenuPythonPlainDescr(true);
58-
mLutFunctionTable->enableChangeBooleanFunctionOption(true);
59-
mLutTable = new LUTTableWidget(this);
61+
mLutPinButtonGroup = new QButtonGroup(this);
62+
mLutPinButtonGroup->setExclusive(true);
63+
mLutRadioWidget = new QWidget(this);
64+
mLutRadioLayout = new QVBoxLayout(mLutRadioWidget);
65+
mLutRadioLayout->setContentsMargins(4, 4, 4, 4);
66+
mLutRadioLayout->setSpacing(4);
67+
mLutTable = new LUTTableWidget(this);
6068
mLutConfigLabel = new QLabel("default", this);
6169
mLutConfigLabel->setContextMenuPolicy(Qt::CustomContextMenu);
6270
mLutConfigLabel->setWordWrap(true);
@@ -65,9 +73,14 @@ namespace hal
6573

6674
mFfFrame = new DetailsFrameWidget(mFfFunctionTable, "FF Information", this);
6775
mLatchFrame = new DetailsFrameWidget(mLatchFunctionTable, "Latch Information", this);
68-
mLutFrame = new DetailsFrameWidget(mLutFunctionTable, "Boolean Function", this);
76+
mLutFrame = new DetailsFrameWidget(mLutRadioWidget, "Boolean Functions", this);
6977
mLutConfigurationFrame = new DetailsFrameWidget(mLutConfigLabel, "Configuration String", this);
7078
mTruthTableFrame = new DetailsFrameWidget(mLutTable, "Truth Table", this);
79+
// DetailsFrameWidget sets Expanding vertical policy on all content widgets, which causes the
80+
// container to distribute vertical space equally. Override for the two compact LUT frames so
81+
// they stay at their natural content height and the truth table gets any remaining space.
82+
mLutFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
83+
mLutConfigurationFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
7184

7285
QList<DetailsFrameWidget*> framesFfLatchLutTab({mFfFrame, mLatchFrame, mLutFrame, mLutConfigurationFrame, mTruthTableFrame});
7386
mMultiTabIndex = addTab("(FF / Latch / LUT)", framesFfLatchLutTab); //save index of multi tab -> needed for show / hide
@@ -231,23 +244,81 @@ namespace hal
231244
}
232245
}
233246

247+
void GateDetailsTabWidget::handleLutPinSelectionChanged(int id)
248+
{
249+
if (mCurrentGate == nullptr || id < 0 || id >= static_cast<int>(mCurrentLutPins.size()))
250+
return;
251+
252+
const std::string& pinName = mCurrentLutPins[id];
253+
mSelectedLutPin = pinName;
254+
255+
BooleanFunction bf = mCurrentGate->get_boolean_function(pinName);
256+
mLutTable->setBooleanFunction(bf, QString::fromStdString(pinName));
257+
258+
GateType* gt = mCurrentGate->get_type();
259+
InitComponent* init_component = gt->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
260+
if (init_component == nullptr)
261+
{
262+
mLutConfigLabel->setText(" Could not load init string.");
263+
return;
264+
}
265+
std::string initKey = init_component->get_init_identifiers()[0];
266+
u32 bit_offset = 0;
267+
u32 bit_count = 0;
268+
if (LUTComponent* lc = gt->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lc != nullptr)
269+
{
270+
if (const LUTComponent::LUTOutputConfig* cfg = lc->get_output_pin_config(pinName); cfg != nullptr)
271+
{
272+
initKey = cfg->init_identifier;
273+
bit_offset = cfg->bit_offset;
274+
bit_count = cfg->bit_count;
275+
}
276+
}
277+
const std::string raw_str = std::get<1>(mCurrentGate->get_data(init_component->get_init_category(), initKey));
278+
if (bit_count > 0 && !raw_str.empty())
279+
{
280+
try
281+
{
282+
const u64 full_val = std::stoull(raw_str, nullptr, 16);
283+
const u64 mask = (bit_count == 64) ? UINT64_MAX : ((1ULL << bit_count) - 1);
284+
const u64 sliced = (full_val >> bit_offset) & mask;
285+
mLutConfigLabel->setText(" 0x" + QString::number(static_cast<qulonglong>(sliced), 16).toUpper().rightJustified(bit_count / 4, QLatin1Char('0')));
286+
}
287+
catch (...)
288+
{
289+
mLutConfigLabel->setText(" 0x" + QString::fromStdString(raw_str));
290+
}
291+
}
292+
else
293+
{
294+
mLutConfigLabel->setText(" 0x" + QString::fromStdString(raw_str));
295+
}
296+
}
297+
234298
void GateDetailsTabWidget::handleLutConfigContextMenuRequested(QPoint pos)
235299
{
300+
auto resolveInitKey = [this](InitComponent* ic) -> std::string {
301+
std::string key = ic->get_init_identifiers()[0];
302+
if (LUTComponent* lc = mCurrentGate->get_type()->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lc != nullptr)
303+
if (const LUTComponent::LUTOutputConfig* cfg = lc->get_output_pin_config(mSelectedLutPin); cfg != nullptr)
304+
key = cfg->init_identifier;
305+
return key;
306+
};
307+
236308
QMenu menu;
237309

238310
menu.addAction("Configuration string to clipboard", [this]() { QApplication::clipboard()->setText(mLutConfigLabel->text().remove(" 0x")); });
239-
menu.addAction("Change configuration string", [this]() {
311+
menu.addAction("Change configuration string", [this, resolveInitKey]() {
240312
InputDialog ipd("Change configuration string", "New configuration string", mLutConfigLabel->text().remove("0x"));
241313
HexadecimalValidator hexValidator;
242314
ipd.addValidator(&hexValidator);
243315
if (ipd.exec() == QDialog::Accepted && !ipd.textValue().isEmpty())
244316
{
245-
if (InitComponent* init_component = mCurrentGate->get_type()->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
246-
init_component != nullptr)
317+
if (InitComponent* ic = mCurrentGate->get_type()->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); }); ic != nullptr)
247318
{
248-
std::string cat = init_component->get_init_category(), key = init_component->get_init_identifiers()[0];
249-
QString data_type = "bit_vector";
250-
ActionSetObjectData* act = new ActionSetObjectData(QString::fromStdString(cat), QString::fromStdString(key), data_type, ipd.textValue().toUpper());
319+
std::string cat = ic->get_init_category();
320+
std::string key = resolveInitKey(ic);
321+
ActionSetObjectData* act = new ActionSetObjectData(QString::fromStdString(cat), QString::fromStdString(key), "bit_vector", ipd.textValue().toUpper());
251322
act->setObject(UserActionObject(mCurrentGate->get_id(), UserActionObjectType::Gate));
252323
act->exec();
253324
setGate(mCurrentGate); //must update config string and data table, no signal for that
@@ -256,11 +327,11 @@ namespace hal
256327
log_error("gui", "Could not load InitComponent from gate with id {}.", mCurrentGate->get_id());
257328
}
258329
});
259-
menu.addAction(QIcon(":/icons/python"), "Get configuration string", [this]() {
260-
if (InitComponent* init_component = mCurrentGate->get_type()->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
261-
init_component != nullptr)
330+
menu.addAction(QIcon(":/icons/python"), "Get configuration string", [this, resolveInitKey]() {
331+
if (InitComponent* ic = mCurrentGate->get_type()->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); }); ic != nullptr)
262332
{
263-
std::string cat = init_component->get_init_category(), key = init_component->get_init_identifiers()[0];
333+
std::string cat = ic->get_init_category();
334+
std::string key = resolveInitKey(ic);
264335
QApplication::clipboard()->setText(PyCodeProvider::pyCodeGateData(mCurrentGate->get_id(), QString::fromStdString(cat), QString::fromStdString(key)));
265336
}
266337
else
@@ -388,40 +459,83 @@ namespace hal
388459
{
389460
case GateDetailsTabWidget::GateTypeCategory::lut: {
390461
const std::vector<std::string> lutPins = gate->get_type()->get_pin_names([](const GatePin* p) { return p->get_type() == PinType::lut; });
391-
// LUT Boolean Function Table only shows the LUT function
392-
QVector<QSharedPointer<BooleanFunctionTableEntry>> lutEntries;
393-
for (auto bfEntry : otherFunctionList)
394-
{
395-
if (std::find(lutPins.begin(), lutPins.end(), bfEntry->getEntryIdentifier().toStdString()) != lutPins.end())
396-
{
397-
lutEntries.append(bfEntry);
398-
}
399-
}
400462

401-
mLutFunctionTable->setEntries(lutEntries);
402-
mLutFunctionTable->setGateInformation(gate);
403-
404-
//Setup lut config (init) string
405-
if (InitComponent* init_component = gt->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); }); init_component != nullptr)
406-
{
407-
auto typeAndValue = gate->get_data(init_component->get_init_category(), init_component->get_init_identifiers()[0]);
408-
mLutConfigLabel->setText(" 0x" + QString::fromStdString(std::get<1>(typeAndValue)));
409-
}
410-
else
463+
// Clear existing radio buttons and layout
464+
const auto existingButtons = mLutPinButtonGroup->buttons();
465+
for (QAbstractButton* btn : existingButtons)
466+
mLutPinButtonGroup->removeButton(btn);
467+
while (QLayoutItem* item = mLutRadioLayout->takeAt(0))
411468
{
412-
mLutConfigLabel->setText(" Could not load init string.");
469+
if (QWidget* w = item->widget())
470+
w->deleteLater();
471+
delete item;
413472
}
473+
mCurrentLutPins.clear();
414474

415-
// The table is only updated if the gate has a LUT pin
416-
if (lutPins.size() > 0)
475+
// Build one radio-button row per LUT output pin
476+
int idx = 0;
477+
for (const std::string& pin : lutPins)
417478
{
418-
// All LUT pins have the same boolean function
419-
std::basic_string<char> outPin = lutPins.front();
420-
421-
// Fill the LUL truth table
422-
BooleanFunction lutFunction = gate->get_boolean_function(outPin);
423-
mLutTable->setBooleanFunction(lutFunction, QString::fromStdString(outPin));
479+
BooleanFunction bf = gate->get_boolean_function(pin);
480+
QString rowText = QString::fromStdString(pin) + " = " + QString::fromStdString(bf.to_string());
481+
482+
QWidget* row = new QWidget(mLutRadioWidget);
483+
QHBoxLayout* rowLayout = new QHBoxLayout(row);
484+
rowLayout->setContentsMargins(0, 0, 0, 0);
485+
rowLayout->setSpacing(4);
486+
487+
QRadioButton* rb = new QRadioButton(row);
488+
mLutPinButtonGroup->addButton(rb, idx);
489+
490+
QLabel* fnLabel = new QLabel(rowText, row);
491+
fnLabel->setWordWrap(true);
492+
fnLabel->setContextMenuPolicy(Qt::CustomContextMenu);
493+
connect(fnLabel, &QLabel::customContextMenuRequested, this, [this, pin, fnLabel](QPoint pos) {
494+
if (!mCurrentGate) return;
495+
const BooleanFunction bf = mCurrentGate->get_boolean_function(pin);
496+
const QString bfStr = QString::fromStdString(bf.to_string());
497+
const u32 gateId = mCurrentGate->get_id();
498+
const QString pinQStr = QString::fromStdString(pin);
499+
QMenu menu;
500+
menu.addAction("Boolean function to clipboard", [bfStr]() {
501+
QApplication::clipboard()->setText(bfStr);
502+
});
503+
menu.addAction("Change Boolean function", [this, pinQStr]() {
504+
InputDialog ipd("Change Boolean function", "New function", "");
505+
if (ipd.exec() == QDialog::Accepted && !ipd.textValue().isEmpty())
506+
{
507+
auto funcRes = BooleanFunction::from_string(ipd.textValue().toStdString());
508+
if (funcRes.is_ok())
509+
{
510+
ActionAddBooleanFunction* act = new ActionAddBooleanFunction(pinQStr, funcRes.get(), mCurrentGate->get_id());
511+
act->exec();
512+
}
513+
}
514+
});
515+
const QString pyCode = PyCodeProvider::pyCodeGateBooleanFunction(gateId, pinQStr);
516+
if (!pyCode.isEmpty())
517+
menu.addAction(QIcon(":/icons/python"), "Get boolean function", [pyCode]() {
518+
QApplication::clipboard()->setText(pyCode);
519+
});
520+
menu.exec(fnLabel->mapToGlobal(pos));
521+
});
522+
523+
rowLayout->addWidget(rb, 0, Qt::AlignTop);
524+
rowLayout->addWidget(fnLabel, 1);
525+
mLutRadioLayout->addWidget(row);
526+
mCurrentLutPins.push_back(pin);
527+
528+
connect(rb, &QRadioButton::toggled, this, [this, idx](bool checked) {
529+
if (checked) handleLutPinSelectionChanged(idx);
530+
});
531+
++idx;
424532
}
533+
mLutRadioLayout->addStretch();
534+
535+
// Select the first pin by default; the toggled signal drives the config label and truth table
536+
if (!mCurrentLutPins.empty())
537+
if (QAbstractButton* firstBtn = mLutPinButtonGroup->button(0))
538+
firstBtn->setChecked(true);
425539
break;
426540
}
427541
case GateDetailsTabWidget::GateTypeCategory::ff: {

0 commit comments

Comments
 (0)