From 92c0b50af898907e7dc613265e91ff221f22ef2d Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 3 Jul 2024 09:27:19 +0200 Subject: [PATCH 01/22] logic_evaluator plugin added --- plugins/.gitignore | 2 + plugins/logic_evaluator/CMakeLists.txt | 24 ++++++ .../include/logic_evaluator/logic_evaluator.h | 74 +++++++++++++++++++ .../logic_evaluator/plugin_logic_evaluator.h | 50 +++++++++++++ .../logic_evaluator/src/logic_evaluator.cpp | 45 +++++++++++ .../src/plugin_logic_evaluator.cpp | 47 ++++++++++++ 6 files changed, 242 insertions(+) create mode 100644 plugins/logic_evaluator/CMakeLists.txt create mode 100644 plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h create mode 100644 plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h create mode 100644 plugins/logic_evaluator/src/logic_evaluator.cpp create mode 100644 plugins/logic_evaluator/src/plugin_logic_evaluator.cpp diff --git a/plugins/.gitignore b/plugins/.gitignore index b88558e8765..ea9c06df369 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -23,6 +23,8 @@ !hgl_writer/**/* !liberty_parser* !liberty_parser/**/* +!logic_evaluator* +!logic_evaluator/**/* !netlist_preprocessing* !netlist_preprocessing/**/* !python_shell* diff --git a/plugins/logic_evaluator/CMakeLists.txt b/plugins/logic_evaluator/CMakeLists.txt new file mode 100644 index 00000000000..f873e3bd2e8 --- /dev/null +++ b/plugins/logic_evaluator/CMakeLists.txt @@ -0,0 +1,24 @@ +option(PL_LOGIC_EVALUATOR "PL_LOGIC_EVALUATOR" ON) +if(PL_LOGIC_EVALUATOR OR BUILD_ALL_PLUGINS) + + find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) + + if(Qt5Core_FOUND) + message(VERBOSE "Qt5Core_INCLUDE_DIRS: ${Qt5Core_INCLUDE_DIRS}") + elseif(NOT Qt5Core_FOUND) + message(STATUS "Qt5Core not found for logic_evaluator") + endif(Qt5Core_FOUND) + + + file(GLOB_RECURSE LOGIC_EVALUATOR_INC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) + file(GLOB_RECURSE LOGIC_EVALUATOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + file(GLOB_RECURSE LOGIC_EVALUATOR_PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/python/*.cpp) + qt5_wrap_cpp(MOC_HDR ${LOGIC_EVALUATOR_INC}) + + hal_add_plugin(logic_evaluator + SHARED + HEADER ${LOGIC_EVALUATOR_INC} + SOURCES ${LOGIC_EVALUATOR_SRC} ${LOGIC_EVALUATOR_PYTHON_SRC} ${MOC_HDR} + LINK_LIBRARIES PUBLIC gui Qt5::Core Qt5::Gui Qt5::Widgets) + +endif() diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h new file mode 100644 index 00000000000..c4e0b96b7e5 --- /dev/null +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h @@ -0,0 +1,74 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" +#include "hal_core/netlist/gate.h" +#include "hal_core/netlist/net.h" +#include "hal_core/netlist/netlist_writer/netlist_writer.h" +#include "gui/content_widget/content_widget.h" +#include "gui/content_manager/content_manager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QStatusBar; +class QProgressBar; +class QCloseEvent; + +namespace hal +{ + /* forward declaration */ + class Netlist; + + /** + * @ingroup netlist_writer + */ + class NETLIST_API LogicEvaluator : public QObject + { + Q_OBJECT + + public: + + LogicEvaluator(QWidget* parent = nullptr); + ~LogicEvaluator(); + + void setGates(std::vector gates); + + private Q_SLOTS: + + public Q_SLOTS: + + private: + }; +} // namespace hal diff --git a/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h new file mode 100644 index 00000000000..98c05642cca --- /dev/null +++ b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h @@ -0,0 +1,50 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/plugin_system/plugin_interface_base.h" +#include + +Q_DECLARE_METATYPE(std::string) + +namespace hal +{ + + class LogicEvaluator; + class NetlistSimulator; + + class PLUGIN_API LogicEvaluatorPlugin : public BasePluginInterface + { + public: + std::string get_name() const override; + std::string get_version() const override; + std::string get_description() const override; + + void on_load() override; + void on_unload() override; + std::set get_dependencies() const override; + }; +} // namespace hal diff --git a/plugins/logic_evaluator/src/logic_evaluator.cpp b/plugins/logic_evaluator/src/logic_evaluator.cpp new file mode 100644 index 00000000000..ee9e0767e54 --- /dev/null +++ b/plugins/logic_evaluator/src/logic_evaluator.cpp @@ -0,0 +1,45 @@ +#include "logic_evaluator/logic_evaluator.h" + +#include "hal_core/netlist/gate.h" +#include "hal_core/netlist/net.h" +#include "hal_core/netlist/netlist.h" +#include "hal_core/utilities/log.h" +#include "hal_core/plugin_system/plugin_manager.h" +#include "gui/gui_globals.h" +#include "gui/gui_utils/graphics.h" +#include "gui/toolbar/toolbar.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hal_core/plugin_system/plugin_manager.h" + +namespace hal +{ + + + LogicEvaluator::LogicEvaluator(QWidget *parent) + : QObject(parent) + { + } + + LogicEvaluator::~LogicEvaluator() + { + } + + void LogicEvaluator::setGates(std::vector gates) + { + } + +} // namespace hal diff --git a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp new file mode 100644 index 00000000000..01cc644fb95 --- /dev/null +++ b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp @@ -0,0 +1,47 @@ +#include "logic_evaluator/plugin_logic_evaluator.h" + +#include "hal_core/netlist/netlist_writer/netlist_writer_manager.h" +#include "logic_evaluator/logic_evaluator.h" +#include "gui/content_manager/content_manager.h" +#include "gui/gui_globals.h" +#include + +namespace hal +{ + extern std::unique_ptr create_plugin_instance() + { + return std::make_unique(); + } + + std::string LogicEvaluatorPlugin::get_name() const + { + return std::string("waveform_viewer"); + } + + std::string LogicEvaluatorPlugin::get_version() const + { + return std::string("0.7"); + } + + std::string LogicEvaluatorPlugin::get_description() const + { + return std::string("GUI to control simulation and view resulting waveforms"); + } + + std::set LogicEvaluatorPlugin::get_dependencies() const + { + std::set retval; + retval.insert("netlist_simulator_controller"); + retval.insert("hal_gui"); + return retval; + } + + void LogicEvaluatorPlugin::on_load() + { + qRegisterMetaType(); + } + + void LogicEvaluatorPlugin::on_unload() + { + } +} // namespace hal From 013c31dcb83102c0f1f89d079fff480bffa91b13 Mon Sep 17 00:00:00 2001 From: joern274 Date: Sat, 13 Jul 2024 00:14:00 +0200 Subject: [PATCH 02/22] Added logic evaluator plugin, first working version --- CHANGELOG.md | 1 + .../hal_core/plugin_system/plugin_parameter.h | 2 +- plugins/gui/resources/stylesheet/dark.qss | 154 ++++++ .../main_window/plugin_parameter_dialog.cpp | 12 + .../python/python_bindings.cpp | 1 + plugins/logic_evaluator/CMakeLists.txt | 2 +- ...c_evaluator.h => logic_evaluator_dialog.h} | 92 ++-- .../logic_evaluator_pingroup.h | 103 ++++ .../logic_evaluator/plugin_logic_evaluator.h | 28 + .../logic_evaluator/src/logic_evaluator.cpp | 45 -- .../src/logic_evaluator_dialog.cpp | 493 ++++++++++++++++++ .../src/logic_evaluator_pingroup.cpp | 191 +++++++ .../src/plugin_logic_evaluator.cpp | 69 ++- 13 files changed, 1105 insertions(+), 88 deletions(-) rename plugins/logic_evaluator/include/logic_evaluator/{logic_evaluator.h => logic_evaluator_dialog.h} (51%) create mode 100644 plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_pingroup.h delete mode 100644 plugins/logic_evaluator/src/logic_evaluator.cpp create mode 100644 plugins/logic_evaluator/src/logic_evaluator_dialog.cpp create mode 100644 plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index bd8da86d07f..fe55d53fed6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. * changed API so that no instance of the plugin needs to be created anymore to apply its algorithms * changed propagation logic for better results * miscellaneous + * added logic evaluator plugin * added backward compatibility for view management * bugfixes * fixed incompatibility between shipped zlib and QuaZip libraries diff --git a/include/hal_core/plugin_system/plugin_parameter.h b/include/hal_core/plugin_system/plugin_parameter.h index 60d54da14cd..05dad548186 100644 --- a/include/hal_core/plugin_system/plugin_parameter.h +++ b/include/hal_core/plugin_system/plugin_parameter.h @@ -32,7 +32,7 @@ namespace hal class PluginParameter { public: - enum ParameterType { Absent, Boolean, Color, ComboBox, Dictionary, ExistingDir, Float, Gate, Integer, Module, NewFile, PushButton, String, TabName }; + enum ParameterType { Absent, Boolean, Color, ComboBox, Dictionary, ExistingDir, Float, Gate, Integer, Label, Module, NewFile, PushButton, String, TabName }; private: ParameterType m_type; std::string m_tagname; diff --git a/plugins/gui/resources/stylesheet/dark.qss b/plugins/gui/resources/stylesheet/dark.qss index 2a1c41c4427..b65dc9f9a9b 100755 --- a/plugins/gui/resources/stylesheet/dark.qss +++ b/plugins/gui/resources/stylesheet/dark.qss @@ -1511,3 +1511,157 @@ hal--Overlay background : rgba(0, 0, 0, 150); } +hal--LogicEvaluatorDialog +{ + font-size : 14px; + color : #A9B7C6; + background : #515253; +} + +hal--LogicEvaluatorPingroup +{ + background : #717273; + border : 2px solid gray; + padding-top : 4px; + padding-bottom : 4px; + padding-left : 0px; + padding-right : 0px; +} + + +hal--LogicEvaluatorPingroup[output="true"] +{ + border-color : #A0A5A8 #414243 #414243 black; + border-width : 2 2 2 0; +} + +hal--LogicEvaluatorPingroup[output="false"] +{ + border-color : #A0A5A8 black #414243 #A0A5A8; + border-width : 2 0 2 2; +} + +hal--LogicEvaluatorValue +{ + min-width : 48; + max-width : 48; + min-height : 28; + max-height : 28; +} + +hal--LogicEvaluatorValue QSpinBox +{ + color : #CBD2D0; + font-family : "Iosevka"; + font-style : normal; + background-color : rgb(28, 28, 29); + border : none; +} + +hal--LogicEvaluatorValue QSpinBox::up-button +{ + color : #CBD2D0; + background-color : #505152; + border-style : solid; + border-color : #808182 #313233 #313233 #808182; + border-width : 1; +} + +hal--LogicEvaluatorValue QSpinBox::down-button +{ + color : #CBD2D0; + background-color : #505152; + border-style : solid; + border-color : #808182 #313233 #313233 #808182; + border-width : 1; +} + +/* +hal--LogicEvaluatorValue QSpinBox::up-arrow +{ + color : #CBD2D0; + background-color : rgb(128, 28, 29); +} + +hal--LogicEvaluatorValue QSpinBox::down-arrow +{ + color : #CBD2D0; + background-color : rgb(28, 28, 128); +} +*/ + +hal--LogicEvaluatorValue QLabel +{ + color : #CBD2D0; + font-family : "Iosevka"; + font-style : normal; + background-color : rgb(28, 28, 29); + border : none; +} + +hal--LogicEvaluatorPingroup > QLabel +{ + color : white; + font-family : "Iosevka"; + font-style : bold; + border : none; + background-color : none; + max-height : 28; +} + +QLabel > QCheckBox +{ + color : white; + font-family : "Iosevka"; + font-style : bold; + font-size : 10px; + border : none; + background-color : black; + max-height : 28; +} + +hal--LogicEvaluatorPingroup QCheckBox +{ + font : bold "Iosevka"; + color : white; + background : black; + padding-top : 4px; + padding-bottom : 4px; + padding-left : 8px; + padding-right : 8px; + min-width : 250px; +} + +hal--LogicEvaluatorPingroup QCheckBox::indicator:checked +{ + background : rgb(255,0,0); + border : 1px solid black; +} + +hal--LogicEvaluatorPingroup QCheckBox::indicator:unchecked +{ + background : rgb(0,170,255); + border : 1px solid black; +} + +hal--LogicEvaluatorDialog > QLabel +{ + border-style : solid; + border-color : #A0A5A8 black #414243 black; + border-width : 2 0 2 0; + font-size : 14pt; + font-style : normal; + background : black; + color : white; + min-width : 160px; +} + +QLabel > QLabel +{ + border : none; + font-size : 14pt; + font-style : normal; + background : black; + color : white; + min-width : 160px; +} diff --git a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp index 8fbd041683f..166f97be22e 100644 --- a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp +++ b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp @@ -132,6 +132,13 @@ namespace hal { mWidgetMap[parTagname] = floatBox; break; } + case PluginParameter::Label: + { + QLabel* label = new QLabel(this); + label->setText(parDefault); + mWidgetMap[parTagname] = label; + break; + } case PluginParameter::String: { QLineEdit* ledit = new QLineEdit(this); @@ -246,6 +253,11 @@ namespace hal { par.set_value(QString::number(floatBox->value()).toStdString()); break; } + case PluginParameter::Label: + { + par.set_value(std::string()); + break; + } case PluginParameter::String: { const QLineEdit* ledit = static_cast(w); diff --git a/plugins/gui_extension_demo/python/python_bindings.cpp b/plugins/gui_extension_demo/python/python_bindings.cpp index 41ab6935f64..4075fe5e849 100644 --- a/plugins/gui_extension_demo/python/python_bindings.cpp +++ b/plugins/gui_extension_demo/python/python_bindings.cpp @@ -60,6 +60,7 @@ namespace hal .value("Module", PluginParameter::Gate, R"(Module ID.)") .value("NewFile", PluginParameter::NewFile, R"(New file name.)") .value("PushButton", PluginParameter::PushButton, R"(Push Button.)") + .value("Label", PluginParameter::Label, R"(Text Label.)") .value("String", PluginParameter::String, R"(String value.)") .value("TabName", PluginParameter::TabName, R"(Tab name for structuring other elements.)") .export_values(); diff --git a/plugins/logic_evaluator/CMakeLists.txt b/plugins/logic_evaluator/CMakeLists.txt index f873e3bd2e8..0e0db794751 100644 --- a/plugins/logic_evaluator/CMakeLists.txt +++ b/plugins/logic_evaluator/CMakeLists.txt @@ -19,6 +19,6 @@ if(PL_LOGIC_EVALUATOR OR BUILD_ALL_PLUGINS) SHARED HEADER ${LOGIC_EVALUATOR_INC} SOURCES ${LOGIC_EVALUATOR_SRC} ${LOGIC_EVALUATOR_PYTHON_SRC} ${MOC_HDR} - LINK_LIBRARIES PUBLIC gui Qt5::Core Qt5::Gui Qt5::Widgets) + LINK_LIBRARIES PUBLIC gui netlist_simulator_controller Qt5::Core Qt5::Gui Qt5::Widgets) endif() diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h similarity index 51% rename from plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h rename to plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h index c4e0b96b7e5..f3f40cc45c0 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h @@ -1,20 +1,20 @@ // MIT License -// +// // Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. // Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. // Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. // Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,50 +25,62 @@ #pragma once -#include "hal_core/defines.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist_writer/netlist_writer.h" -#include "gui/content_widget/content_widget.h" -#include "gui/content_manager/content_manager.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include #include -#include -#include +#include +#include +#include +#include "hal_core/netlist/boolean_function.h" -class QStatusBar; -class QProgressBar; -class QCloseEvent; +namespace hal { + class SimulationInput; -namespace hal -{ - /* forward declaration */ - class Netlist; + class Gate; - /** - * @ingroup netlist_writer - */ - class NETLIST_API LogicEvaluator : public QObject - { - Q_OBJECT + class Net; - public: + class LogicEvaluatorPingroup; - LogicEvaluator(QWidget* parent = nullptr); - ~LogicEvaluator(); + class LogicEvaluatorDialog : public QDialog + { + Q_OBJECT - void setGates(std::vector gates); + struct SharedLibHandle + { + QString fnSharedLib; + void* handle; + int (*get)(int); + void (*set)(int,int); + void (*calc)(void); + void close(); + SharedLibHandle() : handle(nullptr), get(nullptr), set(nullptr), calc(nullptr) {;} + ~SharedLibHandle() { close(); }; + }; - private Q_SLOTS: + SimulationInput* mSimulationInput; + QList mEvaluationOrder; + QList mInputs; + QList mOutputs; + SharedLibHandle mSharedLib; + QHash mExternalArrayIndex; + QHash mSignals; + QCheckBox* mCheckCompiled; + QCheckBox* mCheckIndicate; + void calculateEvaluationOrder(); + void recalcCompiled(); + void recalcInterpreted(); + void visualizeResultsInNetlist(); + void omitNetlistVisualization(); public Q_SLOTS: - - private: + void recalc(); + private Q_SLOTS: + void handleCompiledStateChanged(int state); + void handleIndicateStateChanged(int state); + public: + LogicEvaluatorDialog(std::vector& gates, bool skipCompile, QWidget* parent = nullptr); + ~LogicEvaluatorDialog(); + bool compile(); }; -} // namespace hal +} diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_pingroup.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_pingroup.h new file mode 100644 index 00000000000..2e95957abc1 --- /dev/null +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_pingroup.h @@ -0,0 +1,103 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "hal_core/netlist/boolean_function.h" + +namespace hal { + + class Net; + + class LogicEvaluatorHexSpinbox : public QSpinBox + { + Q_OBJECT + protected: + QValidator::State validate(QString &input, int &pos) const override; + int valueFromText(const QString &text) const override; + virtual QString textFromValue(int val) const override; + public: + LogicEvaluatorHexSpinbox(QWidget* parent = nullptr); + }; + + class LogicEvaluatorCheckBox : public QCheckBox + { + Q_OBJECT + const Net* mNet; + public: + LogicEvaluatorCheckBox(const Net* n, QWidget* parent = nullptr); + QPair getValue() const; + void setValue(const Net* n, BooleanFunction::Value val); + }; + + class LogicEvaluatorValue : public QWidget + { + Q_OBJECT + QLabel* mLabel; + LogicEvaluatorHexSpinbox* mSpinBox; + + private Q_SLOT: + void handleSpinBoxValueChanged(int val); + Q_SIGNALS: + void valueChanged(int val); + public: + LogicEvaluatorValue(int nbits, QWidget* parent = nullptr); + int value() const; + void setValue(int val); + bool isLabel() const { return mLabel!=nullptr; } + }; + + class LogicEvaluatorPingroup : public QFrame + { + Q_OBJECT + Q_PROPERTY(bool output READ output WRITE setOutput); + + QList mPinList; + LogicEvaluatorValue* mGroupValue; + bool mOutput; + + void constructor(const std::vector& nets, const QString& grpName = QString()); + Q_SIGNALS: + void triggerRecalc(); + private Q_SLOT: + void handleGroupValueChanged(int val); + void handleCheckStateChanged(int state); + public: + LogicEvaluatorPingroup(const std::vector& nets, bool outp, const QString& grpName, QWidget* parent = nullptr); + LogicEvaluatorPingroup(const Net*, bool outp, QWidget* parent = nullptr); + bool output() const { return mOutput; } + void setOutput(bool outp) { mOutput = outp; } + int size() const { return mPinList.size(); } + QPair getValue(int index) const; + void setValue(const Net* n, BooleanFunction::Value val); + }; +} diff --git a/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h index 98c05642cca..3654cd0790c 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h +++ b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h @@ -26,6 +26,7 @@ #pragma once #include "hal_core/plugin_system/plugin_interface_base.h" +#include "hal_core/plugin_system/gui_extension_interface.h" #include Q_DECLARE_METATYPE(std::string) @@ -39,6 +40,8 @@ namespace hal class PLUGIN_API LogicEvaluatorPlugin : public BasePluginInterface { public: + LogicEvaluatorPlugin(); + std::string get_name() const override; std::string get_version() const override; std::string get_description() const override; @@ -47,4 +50,29 @@ namespace hal void on_unload() override; std::set get_dependencies() const override; }; + + class GuiExtensionLogicEvaluator : public GuiExtensionInterface + { + + static bool acceptGate(const Gate* g); + public: + /** + * @brief Default constructor for `GuiExtensionEvaluator`. + */ + GuiExtensionLogicEvaluator() = default; + + /** + * @brief Get a vector of configurable parameters. + * + * @returns The vector of parameters. + */ + std::vector get_parameter() const override; + + /** + * @brief Set values for a vector of configurable parameters. + * + * @param[in] params - The parameters including their values. + */ + void set_parameter(const std::vector& params) override; + }; } // namespace hal diff --git a/plugins/logic_evaluator/src/logic_evaluator.cpp b/plugins/logic_evaluator/src/logic_evaluator.cpp deleted file mode 100644 index ee9e0767e54..00000000000 --- a/plugins/logic_evaluator/src/logic_evaluator.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "logic_evaluator/logic_evaluator.h" - -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/utilities/log.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "gui/gui_globals.h" -#include "gui/gui_utils/graphics.h" -#include "gui/toolbar/toolbar.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hal_core/plugin_system/plugin_manager.h" - -namespace hal -{ - - - LogicEvaluator::LogicEvaluator(QWidget *parent) - : QObject(parent) - { - } - - LogicEvaluator::~LogicEvaluator() - { - } - - void LogicEvaluator::setGates(std::vector gates) - { - } - -} // namespace hal diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp new file mode 100644 index 00000000000..d485e56e90e --- /dev/null +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -0,0 +1,493 @@ +#include "logic_evaluator/logic_evaluator_dialog.h" +#include "logic_evaluator/logic_evaluator_pingroup.h" +#include "netlist_simulator_controller/simulation_input.h" +#include "hal_core/netlist/gate.h" +#include "gui/gui_globals.h" +#include "gui/grouping/grouping_manager_widget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hal { + + const char* LOGIC_EVALUATOR_GET = "logic_evaluator_get"; + const char* LOGIC_EVALUATOR_SET = "logic_evaluator_set"; + const char* LOGIC_EVALUATOR_CALC = "logic_evaluator_calc"; + const char* COMPILER = "gcc"; + + LogicEvaluatorDialog::LogicEvaluatorDialog(std::vector &gates, bool skipCompile, QWidget *parent) + : QDialog(parent), mSimulationInput(new SimulationInput), mCheckCompiled(nullptr), mCheckIndicate(nullptr) + { + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle("Logic Evaluator"); + + mSimulationInput->add_gates(gates); + mSimulationInput->compute_net_groups(); + + calculateEvaluationOrder(); + QHBoxLayout* topLayout = new QHBoxLayout(this); + topLayout->setSpacing(0); + QVBoxLayout* inpLayout = new QVBoxLayout; + inpLayout->setSpacing(4); + QVBoxLayout* outLayout = new QVBoxLayout; + outLayout->setSpacing(4); + + // input pingroups + std::unordered_set inputNets = mSimulationInput->get_input_nets(); + for (SimulationInput::NetGroup grp : mSimulationInput->get_net_groups()) + { + if (!grp.is_input) continue; + for (const Net* n : grp.get_nets()) + { + auto it = inputNets.find(n); + if (it != inputNets.end()) inputNets.erase(it); + } + LogicEvaluatorPingroup* lep = new LogicEvaluatorPingroup(grp.get_nets(), false, QString::fromStdString(grp.get_name()), this); + connect(lep, &LogicEvaluatorPingroup::triggerRecalc, this, &LogicEvaluatorDialog::recalc); + mInputs.append(lep); + inpLayout->addWidget(lep); + } + + // input single pins + for (const Net* n : inputNets) + { + LogicEvaluatorPingroup* lep = new LogicEvaluatorPingroup(n, false, this); + connect(lep, &LogicEvaluatorPingroup::triggerRecalc, this, &LogicEvaluatorDialog::recalc); + mInputs.append(lep); + inpLayout->addWidget(lep); + } + + // output pingroups + std::unordered_set outputNets(mSimulationInput->get_output_nets().begin(),mSimulationInput->get_output_nets().end()); + for (SimulationInput::NetGroup grp : mSimulationInput->get_net_groups()) + { + if (grp.is_input) continue; + bool isOutputGroup = true; + + std::vector temp; + for (const Net* n : grp.get_nets()) + { + auto it = outputNets.find(n); + if (it == outputNets.end()) + { + isOutputGroup = false; + break; + } + else + { + outputNets.erase(it); + temp.push_back(n); + } + } + if (!isOutputGroup) + { + for (const Net* n : temp) + outputNets.insert(n); + continue; + } + LogicEvaluatorPingroup* lep = new LogicEvaluatorPingroup(grp.get_nets(), true, QString::fromStdString(grp.get_name()), this); + connect(lep, &LogicEvaluatorPingroup::triggerRecalc, this, &LogicEvaluatorDialog::recalc); + mOutputs.append(lep); + outLayout->addWidget(lep); + } + + // output single pins + for (const Net* n : outputNets) + { + QStringList netName; + netName.append(QString::fromStdString(n->get_name())); + LogicEvaluatorPingroup* lep = new LogicEvaluatorPingroup(n, true, this); + connect(lep, &LogicEvaluatorPingroup::triggerRecalc, this, &LogicEvaluatorDialog::recalc); + mOutputs.append(lep); + outLayout->addWidget(lep); + } + + QLabel* bbox = new QLabel(this); + bbox->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + + inpLayout->addStretch(); + outLayout->addStretch(); + topLayout->addLayout(inpLayout); + topLayout->addWidget(bbox); + topLayout->addLayout(outLayout); + + if (!skipCompile) + compile(); + + QGridLayout* labLayout = new QGridLayout(bbox); + QLabel* ngates = new QLabel(QString("%1 Gate%2").arg(gates.size()).arg(gates.size()==1?"":"s"),bbox); + ngates->setAlignment(Qt::AlignHCenter); + labLayout->addWidget(ngates,0,0); + mCheckCompiled = new QCheckBox("Run compiled logic", bbox); + mCheckCompiled->setChecked(!skipCompile); + mCheckIndicate = new QCheckBox("Show in graphic view", bbox); + labLayout->addWidget(mCheckCompiled,2,0); + labLayout->addWidget(mCheckIndicate,3,0); + connect(mCheckCompiled, &QCheckBox::stateChanged, this, &LogicEvaluatorDialog::handleCompiledStateChanged); + connect(mCheckIndicate, &QCheckBox::stateChanged, this, &LogicEvaluatorDialog::handleIndicateStateChanged); + + QStyle* s = style(); + + s->unpolish(this); + s->polish(this); + + recalc(); + } + + LogicEvaluatorDialog::~LogicEvaluatorDialog() + { + delete mSimulationInput; + } + + void LogicEvaluatorDialog::handleCompiledStateChanged(int state) + { + if (state==Qt::Checked && !mSharedLib.handle) + compile(); + } + + void LogicEvaluatorDialog::handleIndicateStateChanged(int state) + { + if (state==Qt::Checked) + recalc(); + else + omitNetlistVisualization(); + } + + void LogicEvaluatorDialog::SharedLibHandle::close() + { + if (handle) + { + dlclose(handle); + handle = nullptr; + } + QFile::remove(fnSharedLib); + } + + bool LogicEvaluatorDialog::compile() + { + // get input signals + QMap pinVars; + QString codeEvalFunction; + mExternalArrayIndex.clear(); + + for (const LogicEvaluatorPingroup* lepg : mInputs) + { + for (int i=0; isize(); i++) + { + QPair v = lepg->getValue(i); + const Net* n = v.first; + int sz = mExternalArrayIndex.size(); + codeEvalFunction += QString(" // input[%1] - Net %2 <%3>;\n").arg(sz).arg(n->get_id()).arg(n->get_name().c_str()); + mExternalArrayIndex[n] = sz; + } + } + + // propagate by gates + for (const Gate* g : mEvaluationOrder) + { + for (const GatePin* gp : g->get_type()->get_input_pins()) + { + QString pinName = QString::fromStdString(gp->get_name()); + pinVars[pinName]++; + const Net* n = g->get_fan_in_net(gp); + int inx = mExternalArrayIndex.value(n,-1); + if (inx < 0) return false; + codeEvalFunction += QString(" %1 = logic_evaluator_signals[%2];\n").arg(pinName).arg(inx); + } + for (const GatePin* gp : g->get_type()->get_output_pins()) + { + QString pinName = QString::fromStdString(gp->get_name()); + pinVars[pinName]++; + const Net* n = g->get_fan_out_net(gp); + if (!mExternalArrayIndex.contains(n)) + { + int sz = mExternalArrayIndex.size(); + mExternalArrayIndex[n] = sz; + } + codeEvalFunction += QString(" %1 = %2;\n").arg(pinName).arg(QString::fromStdString(g->get_boolean_function(gp).to_string())); + int inx = mExternalArrayIndex.value(n,-1); + if (inx < 0) return false; + codeEvalFunction += QString(" logic_evaluator_signals[%1] = %2;\n").arg(inx).arg(pinName); + } + } + + for (LogicEvaluatorPingroup* lepg : mOutputs) + { + int k = lepg->size(); + for (int i=0; igetValue(i).first; + int inx = mExternalArrayIndex.value(n,-1); + if (inx < 0) return false; + codeEvalFunction += QString(" // output[%1] - Net %2 <%3>;\n").arg(inx).arg(n->get_id()).arg(n->get_name().c_str()); + } + } + QString ccode; + ccode += QString("int logic_evaluator_signals[%1];\n\n").arg(mExternalArrayIndex.size()); + ccode += "void " + QString(LOGIC_EVALUATOR_SET); + ccode += "(int inx, int val) {\n" + " logic_evaluator_signals[inx] = val;\n" + "}\n\n"; + ccode += "int " + QString(LOGIC_EVALUATOR_GET); + ccode += "(int inx) {\n" + " return logic_evaluator_signals[inx];\n" + "}\n\n"; + ccode += "void " + QString(LOGIC_EVALUATOR_CALC); + ccode += "() {\n"; + for (QString var : pinVars.keys()) + { + ccode += QString(" int %1;\n").arg(var); + } + ccode += codeEvalFunction + "\n}\n"; + + // write code to file + QTemporaryFile ftemp(QDir().temp().absoluteFilePath("logic_evaluator_shared_lib_XXXXXX.c")); + ftemp.setAutoRemove(true); + if (!ftemp.open()) + return false; + mSharedLib.fnSharedLib = ftemp.fileName(); + mSharedLib.fnSharedLib.replace(QRegularExpression("\.c$"), QString(".%1").arg(LIBRARY_FILE_EXTENSION)); + ftemp.write(ccode.toUtf8()); + ftemp.close(); + + // compile code + QProcess proc(this); + QStringList args; + args << "-shared" << "-Wall" << "-Werror" << "-fpic" << "-o" << mSharedLib.fnSharedLib << ftemp.fileName(); + if (proc.execute(COMPILER, args) < 0) + { + log_warning("logic_evaluator", "Failed to run compiler '{}', cannot compile logic.", COMPILER); + return false; + } + proc.waitForStarted(); + proc.waitForFinished(); + + if (proc.exitCode() || proc.exitStatus() != QProcess::NormalExit) + { + log_warning("logic_evaluator", "Failed to compile '{}', stdout: '{}', stderr: '{}", ftemp.fileName().toStdString(), proc.readAllStandardOutput().constData(), proc.readAllStandardError().constData()); + return false; + } + + // load shared libraray + + mSharedLib.handle = dlopen(mSharedLib.fnSharedLib.toUtf8().constData(), RTLD_LAZY); + if (!mSharedLib.handle) + { + log_warning("logic_evaluator", "Failed to load shared library '{}' dlerror: '{}'.", mSharedLib.fnSharedLib.toStdString(), dlerror()); + return false; + } + + // reset errors + dlerror(); + + mSharedLib.get = (int(*)(int)) dlsym(mSharedLib.handle, LOGIC_EVALUATOR_GET); + const char* dlsymError = dlerror(); + if (dlsymError) { + log_warning("logic_evaluator", "Cannot resolve symbol '{}' in shared library, dlerror: '{}'.", LOGIC_EVALUATOR_GET, dlsymError); + mSharedLib.close(); + return false; + } + + mSharedLib.set = (void(*)(int,int)) dlsym(mSharedLib.handle, LOGIC_EVALUATOR_SET); + dlsymError = dlerror(); + if (dlsymError) { + log_warning("logic_evaluator", "Cannot resolve symbol '{}' in shared library, dlerror: '{}'.", LOGIC_EVALUATOR_SET, dlsymError); + mSharedLib.close(); + return false; + } + + mSharedLib.calc = (void(*)(void)) dlsym(mSharedLib.handle, LOGIC_EVALUATOR_CALC); + dlsymError = dlerror(); + if (dlsymError) { + log_warning("logic_evaluator", "Cannot resolve symbol '{}' in shared library, dlerror: '{}'.", LOGIC_EVALUATOR_CALC, dlsymError); + mSharedLib.close(); + return false; + } + + return true; + } + + void LogicEvaluatorDialog::recalc() + { + mSignals.clear(); + if (mCheckCompiled->isChecked() && mSharedLib.handle) + recalcCompiled(); + else + recalcInterpreted(); + + for (LogicEvaluatorPingroup* lepg : mOutputs) + { + int k = lepg->size(); + for (int i=0; igetValue(i).first; + lepg->setValue(n, mSignals.value(n, BooleanFunction::Value::X)); + } + } + + if (mCheckIndicate->isChecked()) + visualizeResultsInNetlist(); + } + + void LogicEvaluatorDialog::recalcCompiled() + { + for (const LogicEvaluatorPingroup* lepg : mInputs) + { + for (int i=0; isize(); i++) + { + QPair v = lepg->getValue(i); + const Net* n = v.first; + int inx = mExternalArrayIndex.value(n,-1); + if (inx < 0) + { + log_warning("logic_evaluator", "No shared library index for input net id={} '{}'.", n->get_id(), n->get_name()); + return; + } + mSharedLib.set(inx, (int) v.second); + } + } + + mSharedLib.calc(); + + for (auto it=mExternalArrayIndex.begin(); it!=mExternalArrayIndex.end(); ++it) + { + const Net* n = it.key(); + int val = mSharedLib.get(it.value()); + mSignals[n] = (BooleanFunction::Value) val; + } + } + + void LogicEvaluatorDialog::recalcInterpreted() + { + // get input signals + for (const LogicEvaluatorPingroup* lepg : mInputs) + { + for (int i=0; isize(); i++) + { + QPair v = lepg->getValue(i); + mSignals[v.first] = v.second; + } + } + + // propagate by gates + for (const Gate* g : mEvaluationOrder) + { + std::unordered_map gateSignals; + for (const GatePin* gp : g->get_type()->get_input_pins()) + { + const Net* n = g->get_fan_in_net(gp); + gateSignals[gp->get_name()] = mSignals.value(n, BooleanFunction::Value::X); + } + for (const GatePin* gp : g->get_type()->get_output_pins()) + { + const Net* n = g->get_fan_out_net(gp); + auto res = g->get_boolean_function(gp).evaluate(gateSignals); + if (res.is_ok()) + mSignals[n] = res.get(); + else + log_warning("logic_evaluator", "Failed to evaluate boolean function '{}'.", g->get_boolean_function(gp).to_string()); + } + } + } + + void LogicEvaluatorDialog::calculateEvaluationOrder() + { + mEvaluationOrder.clear(); + QHash > undeterminedInput; + + // setup hash, declare all inpus as undetermined; + for (const Gate* g: mSimulationInput->get_gates()) + { + undeterminedInput.insert(g, g->get_fan_in_nets()); + } + + std::unordered_set inputSignals = mSimulationInput->get_input_nets(); + + int resolved = 1; + while (!undeterminedInput.isEmpty() && resolved) + { + resolved = 0; + std::unordered_set outputSignals; + auto it = undeterminedInput.begin(); + while (it != undeterminedInput.end()) + { + auto jt = it.value().begin(); + while (jt != it.value().end()) + { + if (inputSignals.find(*jt) == inputSignals.end()) + ++jt; + else + jt = it.value().erase(jt); + } + + // has no more undetermined inputs ? + if (it.value().empty()) + { + mEvaluationOrder.append(it.key()); + for (const Net* n : it.key()->get_fan_out_nets()) + outputSignals.insert(n); + it = undeterminedInput.erase(it); + ++resolved; + } + else + { + ++it; + } + } + inputSignals = outputSignals; + } + if (!undeterminedInput.isEmpty()) + { + std::string leftover; + for (const Gate* g : undeterminedInput.keys()) + leftover += " [" + std::to_string(g->get_id()) + ',' + g->get_name() + ']'; + log_warning("logic_evaluator", "Cannot determine evaluation order, {} gate(s) left with undetermined input: {}.", undeterminedInput.size(), leftover); + } + } + + void LogicEvaluatorDialog::visualizeResultsInNetlist() + { + GroupingTableModel* gtm = gContentManager->getGroupingManagerWidget()->getModel(); + const char* color[] = {"#707071", "#102080", "#802010" }; + static const char* grpNames[3] = {"x state", "0 state", "1 state"}; + Grouping* grp[3]; + for (int i=0; i<3; i++) + { + grp[i] = gtm->groupingByName(grpNames[i]); + if (!grp[i]) + { + grp[i] = gNetlist->create_grouping(grpNames[i]); + gtm->recolorGrouping(grp[i]->get_id(),QColor(color[i])); + } + } + + for (auto it = mSignals.constBegin(); it != mSignals.constEnd(); ++it) + { + int grpIndex = 1 + (int) it.value(); + Q_ASSERT(grpIndex >= 0 && grpIndex <= 2); + grp[grpIndex]->assign_net(const_cast(it.key()),true); + } + } + + void LogicEvaluatorDialog::omitNetlistVisualization() + { + GroupingTableModel* gtm = gContentManager->getGroupingManagerWidget()->getModel(); + static const char* grpNames[3] = {"x state", "0 state", "1 state"}; + for (int i=0; i<3; i++) + { + Grouping* grp = gtm->groupingByName(grpNames[i]); + if (grp) gNetlist->delete_grouping(grp); + } + } + +} diff --git a/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp b/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp new file mode 100644 index 00000000000..f6576e96680 --- /dev/null +++ b/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp @@ -0,0 +1,191 @@ +#include "logic_evaluator/logic_evaluator_pingroup.h" +#include +#include +#include +#include "hal_core/netlist/net.h" + +namespace hal { + + LogicEvaluatorHexSpinbox::LogicEvaluatorHexSpinbox(QWidget* parent) + : QSpinBox(parent) + {;} + + int LogicEvaluatorHexSpinbox::valueFromText(const QString &text) const + { + return text.toInt(nullptr,16); + } + + QString LogicEvaluatorHexSpinbox::textFromValue(int val) const + { + return QString::number(val,16).toUpper(); + } + + QValidator::State LogicEvaluatorHexSpinbox::validate(QString &input, int &pos) const + { + Q_UNUSED(pos); + if (input.isEmpty()) + return QValidator::Intermediate; + bool ok; + int val = input.toInt(&ok,16); + if (ok && 0 <= val && val <= maximum()) + return QValidator::Acceptable; + return QValidator::Invalid; + } + +//------------------------------------------------------------------- + + LogicEvaluatorValue::LogicEvaluatorValue(int nbits, QWidget* parent) + : QWidget(parent), mLabel(nullptr), mSpinBox(nullptr) + { + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + if (nbits > 1) + { + mSpinBox = new LogicEvaluatorHexSpinbox(this); + mSpinBox->setMinimum(0); + mSpinBox->setMaximum((1 << nbits)-1); + mSpinBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + connect(mSpinBox, qOverload(&QSpinBox::valueChanged), this, &LogicEvaluatorValue::handleSpinBoxValueChanged); + layout->addWidget(mSpinBox); + } + else + { + mLabel = new QLabel(this); + layout->addWidget(mLabel); + } + } + + void LogicEvaluatorValue::handleSpinBoxValueChanged(int val) + { + Q_EMIT valueChanged(val); + } + + int LogicEvaluatorValue::value() const + { + if (mSpinBox) + return mSpinBox->value(); + return mLabel->text().toInt(); + } + + void LogicEvaluatorValue::setValue(int val) + { + if (mSpinBox) + mSpinBox->setValue(val); + else + mLabel->setText(QString::number(val,16)); + } + + //------------------------------------------------------------------- + + LogicEvaluatorCheckBox::LogicEvaluatorCheckBox(const Net* n, QWidget* parent) + : QCheckBox(QString::fromStdString(n->get_name()),parent), mNet(n) + {;} + + QPair LogicEvaluatorCheckBox::getValue() const + { + return QPair(mNet, isChecked()?BooleanFunction::Value::ONE:BooleanFunction::Value::ZERO); + } + + void LogicEvaluatorCheckBox::setValue(const Net* n, BooleanFunction::Value val) + { + if (n != mNet) return; + setChecked(val==BooleanFunction::Value::ONE); + } + //------------------------------------------------------------------- + + LogicEvaluatorPingroup::LogicEvaluatorPingroup(const std::vector &nets, bool outp, const QString& grpName, QWidget* parent) + : QFrame(parent), mOutput(outp) + { + constructor(nets,grpName); + } + + LogicEvaluatorPingroup::LogicEvaluatorPingroup(const Net* net, bool outp, QWidget* parent) + : QFrame(parent), mOutput(outp) + { + std::vector nets; + nets.push_back(net); + constructor(nets); + } + + void LogicEvaluatorPingroup::constructor(const std::vector &nets, const QString &grpName) + { + int nbits = nets.size(); + QHBoxLayout* topLayout = new QHBoxLayout(this); + topLayout->setAlignment(Qt::AlignTop); + topLayout->setContentsMargins(mOutput?0:8,4,mOutput?8:0,4); + QVBoxLayout* valLayout = new QVBoxLayout; + valLayout->setSpacing(4); + valLayout->setMargin(0); + + if (!grpName.isEmpty()) + { + QLabel* lab = new QLabel(grpName, this); + valLayout->addWidget(lab,0,Qt::AlignBottom|Qt::AlignHCenter); + } + mGroupValue = new LogicEvaluatorValue(mOutput?0:nbits, this); + connect(mGroupValue, &LogicEvaluatorValue::valueChanged, this, &LogicEvaluatorPingroup::handleGroupValueChanged); + valLayout->addWidget(mGroupValue,0, Qt::AlignTop|Qt::AlignHCenter); + + QVBoxLayout* pinLayout = new QVBoxLayout; + for (const Net* net : nets) + { + LogicEvaluatorCheckBox* lecb = new LogicEvaluatorCheckBox(net, this); + connect(lecb, &QCheckBox::stateChanged, this, &LogicEvaluatorPingroup::handleCheckStateChanged); + if (mOutput) lecb->setDisabled(true); + mPinList.prepend(lecb); + pinLayout->addWidget(lecb); + } + + if (mOutput) + { + topLayout->addLayout(pinLayout); + topLayout->addSpacing(20); + topLayout->addLayout(valLayout); + } + else + { + topLayout->addLayout(valLayout); + topLayout->addSpacing(20); + topLayout->addLayout(pinLayout); + } + mGroupValue->setValue(0); + } + + void LogicEvaluatorPingroup::handleCheckStateChanged(int state) + { + Q_UNUSED(state); + + int mask = 1 << (mPinList.size()-1); + int val = 0; + for (LogicEvaluatorCheckBox* cb : mPinList) + { + if (cb->isChecked()) val |= mask; + mask >>= 1; + } + mGroupValue->setValue(val); + if (mGroupValue->isLabel()) + Q_EMIT triggerRecalc(); + } + + void LogicEvaluatorPingroup::handleGroupValueChanged(int val) + { + int mask = 1 << (mPinList.size()-1); + for (LogicEvaluatorCheckBox* cb : mPinList) + { + cb->setChecked(val&mask); + mask >>= 1; + } + Q_EMIT triggerRecalc(); + } + + QPair LogicEvaluatorPingroup::getValue(int index) const + { + return mPinList.at(index)->getValue(); + } + + void LogicEvaluatorPingroup::setValue(const Net* n, BooleanFunction::Value val) + { + for (LogicEvaluatorCheckBox* cb : mPinList) + cb->setValue(n,val); + } +} diff --git a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp index 01cc644fb95..28b460c65d2 100644 --- a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp +++ b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp @@ -1,13 +1,20 @@ #include "logic_evaluator/plugin_logic_evaluator.h" #include "hal_core/netlist/netlist_writer/netlist_writer_manager.h" -#include "logic_evaluator/logic_evaluator.h" +#include "hal_core/netlist/gate.h" +#include "logic_evaluator/logic_evaluator_dialog.h" #include "gui/content_manager/content_manager.h" #include "gui/gui_globals.h" +#include "gui/gui_api/gui_api.h" #include namespace hal { + LogicEvaluatorPlugin::LogicEvaluatorPlugin() + { + m_extensions.push_back(new GuiExtensionLogicEvaluator); + } + extern std::unique_ptr create_plugin_instance() { return std::make_unique(); @@ -44,4 +51,64 @@ namespace hal void LogicEvaluatorPlugin::on_unload() { } + + //--------------------------------------- + + std::vector GuiExtensionLogicEvaluator::get_parameter() const + { + std::vector retval; + retval.push_back(PluginParameter(PluginParameter::Label, "help", "", + "Press 'Launch' to launch logic evaluator\n" + "with the gates that are currently selected.\n\n" + "Per default boolean logic gets compiled and\n" + "evaluated by compiled binary code. If 'skip' is\n" + "checked the compile step gets omitted and the\n" + "build-in BooleanFunction class does the evaluation.")); + retval.push_back(PluginParameter(PluginParameter::Boolean, "skip", "Skip compilation", "false")); + retval.push_back(PluginParameter(PluginParameter::PushButton, "exec", "Launch")); + return retval; + } + + void GuiExtensionLogicEvaluator::set_parameter(const std::vector& params) + { + bool launchPressed = false; + bool skipCompile = false; + for (const PluginParameter& pp : params) + { + if (pp.get_tagname() == "exec" && pp.get_value() == "clicked") + launchPressed = true; + if (pp.get_tagname() == "skip") + skipCompile = (pp.get_value() == "true"); + } + + if (!launchPressed) return; + + std::unordered_set gates; + for (Gate* g : GuiApi().getSelectedGates()) + if (acceptGate(g)) + gates.insert(g); + for (Module* m : GuiApi().getSelectedModules()) + for (Gate* g : m->get_gates(nullptr,true)) + if (acceptGate(g)) + gates.insert(g); + + if (gates.empty()) + { + log_warning("logic_evaluator", "No pure logical gates in selection, logic evaluator not launched."); + return; + } + + std::vector vgates(gates.begin(), gates.end()); + LogicEvaluatorDialog* led = new LogicEvaluatorDialog(vgates, skipCompile); + led->show(); + } + + bool GuiExtensionLogicEvaluator::acceptGate(const Gate *g) + { + const GateType* gt = g->get_type(); + if (gt->has_property(GateTypeProperty::ff)) return false; + if (gt->has_property(GateTypeProperty::latch)) return false; + return true; + } + } // namespace hal From 573e5a14e810de5e9e5a12863aa5f4398ef777fd Mon Sep 17 00:00:00 2001 From: joern274 Date: Sat, 13 Jul 2024 09:18:40 +0200 Subject: [PATCH 03/22] Uncheck compile flag if compiler did not produce desired result --- plugins/logic_evaluator/src/logic_evaluator_dialog.cpp | 8 +++++++- plugins/logic_evaluator/src/plugin_logic_evaluator.cpp | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index d485e56e90e..fc666950ca7 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -129,7 +129,7 @@ namespace hal { ngates->setAlignment(Qt::AlignHCenter); labLayout->addWidget(ngates,0,0); mCheckCompiled = new QCheckBox("Run compiled logic", bbox); - mCheckCompiled->setChecked(!skipCompile); + mCheckCompiled->setChecked(mSharedLib.handle!=nullptr); mCheckIndicate = new QCheckBox("Show in graphic view", bbox); labLayout->addWidget(mCheckCompiled,2,0); labLayout->addWidget(mCheckIndicate,3,0); @@ -152,7 +152,11 @@ namespace hal { void LogicEvaluatorDialog::handleCompiledStateChanged(int state) { if (state==Qt::Checked && !mSharedLib.handle) + { compile(); + if (!mSharedLib.handle) + mCheckCompiled->setChecked(false); + } } void LogicEvaluatorDialog::handleIndicateStateChanged(int state) @@ -314,6 +318,8 @@ namespace hal { return false; } + log_info("logic_evaluator", "Temporary shared library '{}' successfully build and loaded.", mSharedLib.fnSharedLib.toStdString()); + return true; } diff --git a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp index 28b460c65d2..8b16cd89732 100644 --- a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp +++ b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp @@ -46,6 +46,7 @@ namespace hal void LogicEvaluatorPlugin::on_load() { qRegisterMetaType(); + LogManager::get_instance()->add_channel("logic_evaluator", {LogManager::create_stdout_sink(), LogManager::create_file_sink(), LogManager::create_gui_sink()}, "info"); } void LogicEvaluatorPlugin::on_unload() From 4db33651f6efcc4124f81de61b8ba651f0786a27 Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 16 Jul 2024 14:56:13 +0200 Subject: [PATCH 04/22] Changes to logic evaluator layout --- .../logic_evaluator/logic_evaluator_dialog.h | 11 +++-- .../src/logic_evaluator_dialog.cpp | 40 +++++++++---------- .../src/logic_evaluator_pingroup.cpp | 7 +++- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h index f3f40cc45c0..08a99c4d810 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "hal_core/netlist/boolean_function.h" namespace hal { @@ -65,8 +67,9 @@ namespace hal { SharedLibHandle mSharedLib; QHash mExternalArrayIndex; QHash mSignals; - QCheckBox* mCheckCompiled; - QCheckBox* mCheckIndicate; + QMenuBar* mMenuBar; + QAction* mActionCompile; + QAction* mActionIndicate; void calculateEvaluationOrder(); void recalcCompiled(); @@ -76,8 +79,8 @@ namespace hal { public Q_SLOTS: void recalc(); private Q_SLOTS: - void handleCompiledStateChanged(int state); - void handleIndicateStateChanged(int state); + void handleCompiledToggled(bool checked); + void handleIndicateToggled(bool checked); public: LogicEvaluatorDialog(std::vector& gates, bool skipCompile, QWidget* parent = nullptr); ~LogicEvaluatorDialog(); diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index fc666950ca7..420f8e685ae 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -26,7 +26,7 @@ namespace hal { const char* COMPILER = "gcc"; LogicEvaluatorDialog::LogicEvaluatorDialog(std::vector &gates, bool skipCompile, QWidget *parent) - : QDialog(parent), mSimulationInput(new SimulationInput), mCheckCompiled(nullptr), mCheckIndicate(nullptr) + : QDialog(parent), mSimulationInput(new SimulationInput), mActionCompile(nullptr), mActionIndicate(nullptr) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Logic Evaluator"); @@ -112,30 +112,28 @@ namespace hal { outLayout->addWidget(lep); } - QLabel* bbox = new QLabel(this); + QLabel* bbox = new QLabel(QString("%1 Gate%2").arg(gates.size()).arg(gates.size()==1?"":"s"),this); bbox->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + mMenuBar = new QMenuBar(this); + QMenu* options = mMenuBar->addMenu("Options"); + mActionCompile = options->addAction("Run compiled logic"); + connect(mActionCompile, &QAction::toggled, this, &LogicEvaluatorDialog::handleCompiledToggled); + mActionCompile->setCheckable(true); + mActionIndicate = options->addAction("Show in graphic view"); + connect(mActionIndicate, &QAction::toggled, this, &LogicEvaluatorDialog::handleIndicateToggled); + mActionIndicate->setCheckable(true); + inpLayout->addStretch(); outLayout->addStretch(); topLayout->addLayout(inpLayout); topLayout->addWidget(bbox); topLayout->addLayout(outLayout); + topLayout->setMenuBar(mMenuBar); if (!skipCompile) compile(); - QGridLayout* labLayout = new QGridLayout(bbox); - QLabel* ngates = new QLabel(QString("%1 Gate%2").arg(gates.size()).arg(gates.size()==1?"":"s"),bbox); - ngates->setAlignment(Qt::AlignHCenter); - labLayout->addWidget(ngates,0,0); - mCheckCompiled = new QCheckBox("Run compiled logic", bbox); - mCheckCompiled->setChecked(mSharedLib.handle!=nullptr); - mCheckIndicate = new QCheckBox("Show in graphic view", bbox); - labLayout->addWidget(mCheckCompiled,2,0); - labLayout->addWidget(mCheckIndicate,3,0); - connect(mCheckCompiled, &QCheckBox::stateChanged, this, &LogicEvaluatorDialog::handleCompiledStateChanged); - connect(mCheckIndicate, &QCheckBox::stateChanged, this, &LogicEvaluatorDialog::handleIndicateStateChanged); - QStyle* s = style(); s->unpolish(this); @@ -149,19 +147,19 @@ namespace hal { delete mSimulationInput; } - void LogicEvaluatorDialog::handleCompiledStateChanged(int state) + void LogicEvaluatorDialog::handleCompiledToggled(bool checked) { - if (state==Qt::Checked && !mSharedLib.handle) + if (checked && !mSharedLib.handle) { compile(); if (!mSharedLib.handle) - mCheckCompiled->setChecked(false); + mActionCompile->setChecked(false); } } - void LogicEvaluatorDialog::handleIndicateStateChanged(int state) + void LogicEvaluatorDialog::handleIndicateToggled(bool checked) { - if (state==Qt::Checked) + if (checked) recalc(); else omitNetlistVisualization(); @@ -326,7 +324,7 @@ namespace hal { void LogicEvaluatorDialog::recalc() { mSignals.clear(); - if (mCheckCompiled->isChecked() && mSharedLib.handle) + if (mActionCompile->isChecked() && mSharedLib.handle) recalcCompiled(); else recalcInterpreted(); @@ -341,7 +339,7 @@ namespace hal { } } - if (mCheckIndicate->isChecked()) + if (mActionIndicate->isChecked()) visualizeResultsInNetlist(); } diff --git a/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp b/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp index f6576e96680..618e7c039ce 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_pingroup.cpp @@ -131,7 +131,12 @@ namespace hal { { LogicEvaluatorCheckBox* lecb = new LogicEvaluatorCheckBox(net, this); connect(lecb, &QCheckBox::stateChanged, this, &LogicEvaluatorPingroup::handleCheckStateChanged); - if (mOutput) lecb->setDisabled(true); + if (mOutput) + lecb->setDisabled(true); + else + { + lecb->setLayoutDirection(Qt::RightToLeft); + } mPinList.prepend(lecb); pinLayout->addWidget(lecb); } From 05d9f29340a1d9cfbaf3a12e136581369d9016fd Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 17 Jul 2024 22:51:23 +0200 Subject: [PATCH 05/22] Showing evaluated gates in tree view --- .../include/gui/module_model/module_model.h | 10 ++ plugins/gui/resources/stylesheet/dark.qss | 30 +--- plugins/gui/src/module_model/module_model.cpp | 41 +++++ .../include/logic_evaluator/select_gates.h | 67 +++++++ .../src/logic_evaluator_dialog.cpp | 11 +- plugins/logic_evaluator/src/select_gates.cpp | 170 ++++++++++++++++++ 6 files changed, 299 insertions(+), 30 deletions(-) create mode 100644 plugins/logic_evaluator/include/logic_evaluator/select_gates.h create mode 100644 plugins/logic_evaluator/src/select_gates.cpp diff --git a/plugins/gui/include/gui/module_model/module_model.h b/plugins/gui/include/gui/module_model/module_model.h index 5e22b8a66b0..b74c5c3fa69 100644 --- a/plugins/gui/include/gui/module_model/module_model.h +++ b/plugins/gui/include/gui/module_model/module_model.h @@ -36,6 +36,7 @@ #include #include #include +#include #include namespace hal @@ -153,6 +154,15 @@ namespace hal */ void populateTree(const QVector& modIds = {}, const QVector& gatIds = {}, const QVector& netIds = {}); + /** + * Clears current tree item model and repopulates it by a list of gates. This function will + * automatically load all parent modules to gates listed. Thus gates will be shown at their + * place within the module hierarchy. + * + * @param gates std::vector of gates to be added to the item model. + */ + void populateFromGatelist(const std::vector& gates); + /** * Add a module to the item model. For the specified module new ModuleItems are created and stored. * diff --git a/plugins/gui/resources/stylesheet/dark.qss b/plugins/gui/resources/stylesheet/dark.qss index b65dc9f9a9b..897090a0e99 100755 --- a/plugins/gui/resources/stylesheet/dark.qss +++ b/plugins/gui/resources/stylesheet/dark.qss @@ -1609,17 +1609,6 @@ hal--LogicEvaluatorPingroup > QLabel max-height : 28; } -QLabel > QCheckBox -{ - color : white; - font-family : "Iosevka"; - font-style : bold; - font-size : 10px; - border : none; - background-color : black; - max-height : 28; -} - hal--LogicEvaluatorPingroup QCheckBox { font : bold "Iosevka"; @@ -1644,24 +1633,11 @@ hal--LogicEvaluatorPingroup QCheckBox::indicator:unchecked border : 1px solid black; } -hal--LogicEvaluatorDialog > QLabel +hal--LogicEvaluatorDialog > QTreeView { border-style : solid; border-color : #A0A5A8 black #414243 black; - border-width : 2 0 2 0; - font-size : 14pt; - font-style : normal; + border-width : 2 2 2 2; background : black; - color : white; - min-width : 160px; -} - -QLabel > QLabel -{ - border : none; - font-size : 14pt; - font-style : normal; - background : black; - color : white; - min-width : 160px; + min-width : 300px; } diff --git a/plugins/gui/src/module_model/module_model.cpp b/plugins/gui/src/module_model/module_model.cpp index e428195be7e..5516cf0b1a1 100644 --- a/plugins/gui/src/module_model/module_model.cpp +++ b/plugins/gui/src/module_model/module_model.cpp @@ -118,6 +118,47 @@ namespace hal endResetModel(); } + void ModuleModel::populateFromGatelist(const std::vector &gates) + { + setIsModifying(true); + beginResetModel(); + clear(); + + QMap parentMap; + for (const Gate* g : gates) + { + Module* parentModule = g->get_module(); + ModuleItem* parentItem; + bool insertToRoot = true; + ModuleItem* childItem = new ModuleItem(g->get_id(), ModuleItem::TreeItemType::Gate); + + while (parentModule && insertToRoot) + { + parentItem = parentMap.value(parentModule); + if (!parentItem) + { + parentItem = new ModuleItem(parentModule->get_id(), ModuleItem::TreeItemType::Module); + parentMap.insert(parentModule, parentItem); + } + else + { + insertToRoot = false; + } + parentItem->appendChild(childItem); + parentModule = parentModule->get_parent_module(); + childItem = parentItem; + } + + if (insertToRoot) + { + mRootItem->appendChild(parentItem); + } + } + + setIsModifying(false); + endResetModel(); + } + void ModuleModel::populateTree(const QVector& modIds, const QVector& gateIds, const QVector& netIds) { setIsModifying(true); diff --git a/plugins/logic_evaluator/include/logic_evaluator/select_gates.h b/plugins/logic_evaluator/include/logic_evaluator/select_gates.h new file mode 100644 index 00000000000..9a8ebc58915 --- /dev/null +++ b/plugins/logic_evaluator/include/logic_evaluator/select_gates.h @@ -0,0 +1,67 @@ + // MIT License + // + // Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. + // Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. + // Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. + // Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + + #pragma once + + #include + #include + #include + #include "gui/module_model/module_model.h" + + namespace hal { + class Gate; + + class SelectGateItem : public ModuleItem + { + Qt::CheckState mState; + public: + SelectGateItem(u32 id, ModuleItem::TreeItemType type) + : ModuleItem(id, type) {;} + Qt::CheckState state() const { return mState; } + void setState(Qt::CheckState stat) { mState = stat; } + }; + + class SelectGateModel : public ModuleModel + { + Q_OBJECT + int insertModuleRecursion(const Module* mod, SelectGateItem* parentItem = nullptr); + QPair setCheckedRecursion(bool applySet, BaseTreeItem* parentItem, const QSet& selectedGateIds = QSet() ); + void setModuleStateRecursion(SelectGateItem* item, Qt::CheckState stat); + public: + SelectGateModel(QObject* parent = nullptr); + void setChecked(const std::vector &gates); + Qt::ItemFlags flags(const QModelIndex &index) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + }; + + class SelectGates : public QDialog + { + Q_OBJECT + QTreeView* mTreeView; + public: + SelectGates(const std::vector &gates, QWidget* parent = nullptr); + }; + } diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index 420f8e685ae..a0a0fe85173 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -4,6 +4,8 @@ #include "hal_core/netlist/gate.h" #include "gui/gui_globals.h" #include "gui/grouping/grouping_manager_widget.h" +#include "gui/module_model/module_model.h" +#include "logic_evaluator/select_gates.h" #include #include @@ -112,8 +114,11 @@ namespace hal { outLayout->addWidget(lep); } - QLabel* bbox = new QLabel(QString("%1 Gate%2").arg(gates.size()).arg(gates.size()==1?"":"s"),this); - bbox->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + QTreeView* tview = new QTreeView(this); + ModuleModel* tmodel = new ModuleModel(this); + tmodel->populateFromGatelist(gates); + tview->setModel(tmodel); + tview->expandAll(); mMenuBar = new QMenuBar(this); QMenu* options = mMenuBar->addMenu("Options"); @@ -127,7 +132,7 @@ namespace hal { inpLayout->addStretch(); outLayout->addStretch(); topLayout->addLayout(inpLayout); - topLayout->addWidget(bbox); + topLayout->addWidget(tview); topLayout->addLayout(outLayout); topLayout->setMenuBar(mMenuBar); diff --git a/plugins/logic_evaluator/src/select_gates.cpp b/plugins/logic_evaluator/src/select_gates.cpp new file mode 100644 index 00000000000..53c6e7e2ccc --- /dev/null +++ b/plugins/logic_evaluator/src/select_gates.cpp @@ -0,0 +1,170 @@ +#include "logic_evaluator/select_gates.h" +#include "hal_core/netlist/gate.h" +#include "gui/gui_globals.h" +#include +#include + +namespace hal { + QVariant SelectGateModel::data(const QModelIndex& index, int role) const + { + const SelectGateItem* item = dynamic_cast(getItemFromIndex(index)); + + switch (role) + { + case Qt::ForegroundRole: + if (item && item->getType() == ModuleItem::TreeItemType::Gate && item->state() == Qt::Checked) + return QColor("#FFE8A0"); //TODO : style file + break; + case Qt::BackgroundRole: + if (item && item->getType() == ModuleItem::TreeItemType::Gate && item->state() == Qt::Checked) + return QColor("#102030"); + break; + case Qt::CheckStateRole: + if (item && !index.column()) return item->state(); + break; + } + return ModuleModel::data(index, role); + } + + bool SelectGateModel::setData(const QModelIndex& index, const QVariant& value, int role) + { + if (role != Qt::CheckStateRole) return false; + SelectGateItem* item = dynamic_cast(getItemFromIndex(index)); + if (!item) return false; + switch(item->getType()) { + case ModuleItem::TreeItemType::Module: + setModuleStateRecursion(item, (Qt::CheckState) value.toInt()); + break; + case ModuleItem::TreeItemType::Gate: + item->setState((Qt::CheckState) value.toInt()); + setCheckedRecursion(false, mRootItem); + break; + case ModuleItem::TreeItemType::Net: + Q_ASSERT(1==0); + break; + } + return true; + } + + void SelectGateModel::setModuleStateRecursion(SelectGateItem* item, Qt::CheckState stat) + { + item->setState(stat); + QModelIndex inx0 = getIndexFromItem(item); + QModelIndex inx1 = createIndex(inx0.row(), 2, inx0.internalPointer()); + Q_EMIT dataChanged(inx0,inx1); + for (BaseTreeItem* bti : item->getChildren()) + { + SelectGateItem* child = dynamic_cast(bti); + setModuleStateRecursion(child,stat); + } + } + + + SelectGateModel::SelectGateModel(QObject* parent) + { + insertModuleRecursion(gNetlist->get_top_module()); + } + + int SelectGateModel::insertModuleRecursion(const Module* mod, SelectGateItem* parentItem) + { + SelectGateItem* child = new SelectGateItem(mod->get_id(), ModuleItem::TreeItemType::Module); + for (const Module* subm : mod->get_submodules()) + insertModuleRecursion(subm, child); + for (const Gate* g : mod->get_gates(nullptr, false)) + { + child->appendChild(new SelectGateItem(g->get_id(), ModuleItem::TreeItemType::Gate)); + } + if (parentItem) + parentItem->appendChild(child); + else + mRootItem->appendChild(child); + } + + QPair SelectGateModel::setCheckedRecursion(bool applySet, BaseTreeItem *parentItem, const QSet &selectedGateIds) + { + bool hasChecked = false; + bool hasUnchecked = false; + for (BaseTreeItem* bti : parentItem->getChildren()) + { + QPair res = setCheckedRecursion(applySet, bti, selectedGateIds); + if (res.first) hasChecked = true; + if (res.second) hasUnchecked = true; + } + SelectGateItem* item = dynamic_cast(parentItem); + if (item) + { + Qt::CheckState lastState; + switch (item->getType()) { + case ModuleItem::TreeItemType::Module: + lastState = item->state(); + if (hasChecked && hasUnchecked) + item->setState(Qt::PartiallyChecked); + else if (hasChecked) + item->setState(Qt::Checked); + else + item->setState(Qt::Unchecked); + if (!applySet && item->state() != lastState) + { + QModelIndex inx = getIndexFromItem(item); + Q_EMIT dataChanged(inx,inx); + } + break; + case ModuleItem::TreeItemType::Gate: + if (applySet) + { + if (selectedGateIds.contains(item->id())) + { + item->setState(Qt::Checked); + hasChecked = true; + } + else + { + item->setState(Qt::Unchecked); + hasUnchecked = true; + } + } + else + { + if (item->state() == Qt::Checked) + hasChecked = true; + else + hasUnchecked = true; + } + break; + case ModuleItem::TreeItemType::Net: + Q_ASSERT(1==0); + break; + } + } + return QPair(hasChecked,hasUnchecked); + } + + void SelectGateModel::setChecked(const std::vector &gates) + { + QSet selectedGateIds; + + for (const Gate* g : gates) + selectedGateIds.insert(g->get_id()); + + setCheckedRecursion(true, mRootItem, selectedGateIds); + } + + Qt::ItemFlags SelectGateModel::flags(const QModelIndex &index) const + { + Qt::ItemFlags retval = ModuleModel::flags(index); + if (index.column()) return retval; + return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; + } + + SelectGates::SelectGates(const std::vector& gates, QWidget* parent) + : QDialog(parent) + { + QGridLayout* layout = new QGridLayout(this); + mTreeView = new QTreeView(this); + SelectGateModel* model = new SelectGateModel(this); + model->setChecked(gates); + mTreeView->setModel(model); + mTreeView->expandAll(); + layout->addWidget(mTreeView); + } +} From 83db7100b56f6469eff27e3491329614d635e047 Mon Sep 17 00:00:00 2001 From: joern274 Date: Sun, 21 Jul 2024 23:39:06 +0200 Subject: [PATCH 06/22] can apply filter on gates to select --- plugins/gui/resources/stylesheet/dark.qss | 9 +- .../logic_evaluator/logic_evaluator_dialog.h | 4 +- ...gates.h => logic_evaluator_select_gates.h} | 40 +++++- .../logic_evaluator/plugin_logic_evaluator.h | 30 ++++- .../src/logic_evaluator_dialog.cpp | 21 ++- ...s.cpp => logic_evaluator_select_gates.cpp} | 120 ++++++++++++++++-- .../src/plugin_logic_evaluator.cpp | 44 +++++++ 7 files changed, 246 insertions(+), 22 deletions(-) rename plugins/logic_evaluator/include/logic_evaluator/{select_gates.h => logic_evaluator_select_gates.h} (66%) rename plugins/logic_evaluator/src/{select_gates.cpp => logic_evaluator_select_gates.cpp} (55%) diff --git a/plugins/gui/resources/stylesheet/dark.qss b/plugins/gui/resources/stylesheet/dark.qss index 897090a0e99..f96443036d0 100755 --- a/plugins/gui/resources/stylesheet/dark.qss +++ b/plugins/gui/resources/stylesheet/dark.qss @@ -1639,5 +1639,12 @@ hal--LogicEvaluatorDialog > QTreeView border-color : #A0A5A8 black #414243 black; border-width : 2 2 2 2; background : black; - min-width : 300px; + min-width : 400px; +} + +hal--LogicEvaluatorSelectGates +{ + qproperty-selForeground : #FFE8A0; + qproperty-selBackground : #102030; + min-width : 400px; } diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h index 08a99c4d810..a7fea8ddf08 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h @@ -60,6 +60,7 @@ namespace hal { ~SharedLibHandle() { close(); }; }; + std::vector mGates; SimulationInput* mSimulationInput; QList mEvaluationOrder; QList mInputs; @@ -81,8 +82,9 @@ namespace hal { private Q_SLOTS: void handleCompiledToggled(bool checked); void handleIndicateToggled(bool checked); + void handleRelaunchTriggered(); public: - LogicEvaluatorDialog(std::vector& gates, bool skipCompile, QWidget* parent = nullptr); + LogicEvaluatorDialog(const std::vector& gates, bool skipCompile, QWidget* parent = nullptr); ~LogicEvaluatorDialog(); bool compile(); }; diff --git a/plugins/logic_evaluator/include/logic_evaluator/select_gates.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h similarity index 66% rename from plugins/logic_evaluator/include/logic_evaluator/select_gates.h rename to plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h index 9a8ebc58915..e8f7a5d97e8 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/select_gates.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h @@ -26,6 +26,7 @@ #pragma once #include + #include #include #include #include "gui/module_model/module_model.h" @@ -33,35 +34,66 @@ namespace hal { class Gate; + class ModuleProxyModel; + + class Searchbar; + class SelectGateItem : public ModuleItem { Qt::CheckState mState; + bool mSelectable; public: - SelectGateItem(u32 id, ModuleItem::TreeItemType type) - : ModuleItem(id, type) {;} + SelectGateItem(u32 id, ModuleItem::TreeItemType type, bool isSel = true) + : ModuleItem(id, type), mState(Qt::Unchecked), mSelectable(isSel) {;} Qt::CheckState state() const { return mState; } + bool isSelectable() const { return mSelectable; } + void setSelectable(bool isSel) { mSelectable = isSel; } void setState(Qt::CheckState stat) { mState = stat; } }; + class LogicEvaluatorSelectGates; + class SelectGateModel : public ModuleModel { Q_OBJECT + std::vector mSelectedGates; + LogicEvaluatorSelectGates* mParentDialog; + int insertModuleRecursion(const Module* mod, SelectGateItem* parentItem = nullptr); QPair setCheckedRecursion(bool applySet, BaseTreeItem* parentItem, const QSet& selectedGateIds = QSet() ); void setModuleStateRecursion(SelectGateItem* item, Qt::CheckState stat); + void setSelectedGatesRecursion(SelectGateItem* item = nullptr); public: SelectGateModel(QObject* parent = nullptr); void setChecked(const std::vector &gates); Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + const std::vector& selectedGates(); }; - class SelectGates : public QDialog + class LogicEvaluatorSelectGates : public QDialog { Q_OBJECT + + Q_PROPERTY(QColor selBackground READ selBackground WRITE setSelBackground) + Q_PROPERTY(QColor selForeground READ selForeground WRITE setSelForeground) + QTreeView* mTreeView; + SelectGateModel* mSelectGateModel; + ModuleProxyModel* mProxyModel; + Searchbar* mSearchbar; + QCheckBox* mCompile; + QColor mSelBackground; + QColor mSelForeground; + public Q_SLOTS: + void accept() override; public: - SelectGates(const std::vector &gates, QWidget* parent = nullptr); + LogicEvaluatorSelectGates(const std::vector &gates, QWidget* parent = nullptr); + + QColor selBackground() const { return mSelBackground; } + void setSelBackground(QColor bg) { mSelBackground = bg; } + QColor selForeground() const { return mSelForeground; } + void setSelForeground(QColor fg) { mSelForeground = fg; } }; } diff --git a/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h index 3654cd0790c..deaf0dd6fe4 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h +++ b/plugins/logic_evaluator/include/logic_evaluator/plugin_logic_evaluator.h @@ -54,8 +54,8 @@ namespace hal class GuiExtensionLogicEvaluator : public GuiExtensionInterface { - static bool acceptGate(const Gate* g); public: + static bool acceptGate(const Gate* g); /** * @brief Default constructor for `GuiExtensionEvaluator`. */ @@ -74,5 +74,33 @@ namespace hal * @param[in] params - The parameters including their values. */ void set_parameter(const std::vector& params) override; + + + /** + * Contribution to context menu. + * This function gets called when a context menu in GUI graphical netlist view pops up. Plugins that + * want to add their own entries in context menu will return one ContextMenuContribution record per + * entry line. + * + * @param[in] nl - The current netlist in GUI + * @param[in] mods - List of selected modules + * @param[in] gats - List of selected gates + * @param[in] nets - List of selected nets + * @return + */ + virtual std::vector get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gats, const std::vector& nets) override; + + /** + * Call from GUI to execute function. + * This function gets called when user selected a plugin contribution (see get_context_contribution) in + * context menu of GUI graphical netlist view or when user clicked a push button in contributed plugin menu + * + * @param[in] tag - The function tagname (unique identifier) + * @param[in] nl - The current netlist in GUI + * @param[in] mods - List of selected modules + * @param[in] gats - List of selected gates + * @param[in] nets - List of selected nets + */ + virtual void execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gats, const std::vector& nets) override; }; } // namespace hal diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index a0a0fe85173..ec5ddad1194 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -5,7 +5,7 @@ #include "gui/gui_globals.h" #include "gui/grouping/grouping_manager_widget.h" #include "gui/module_model/module_model.h" -#include "logic_evaluator/select_gates.h" +#include "logic_evaluator/logic_evaluator_select_gates.h" #include #include @@ -27,11 +27,11 @@ namespace hal { const char* LOGIC_EVALUATOR_CALC = "logic_evaluator_calc"; const char* COMPILER = "gcc"; - LogicEvaluatorDialog::LogicEvaluatorDialog(std::vector &gates, bool skipCompile, QWidget *parent) - : QDialog(parent), mSimulationInput(new SimulationInput), mActionCompile(nullptr), mActionIndicate(nullptr) + LogicEvaluatorDialog::LogicEvaluatorDialog(const std::vector& gates, bool skipCompile, QWidget *parent) + : QDialog(parent), mGates(gates), mSimulationInput(new SimulationInput), mActionCompile(nullptr), mActionIndicate(nullptr) { setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle("Logic Evaluator"); + setWindowTitle(QString("Logic Evaluator %1 Gates").arg(gates.size())); mSimulationInput->add_gates(gates); mSimulationInput->compute_net_groups(); @@ -119,6 +119,9 @@ namespace hal { tmodel->populateFromGatelist(gates); tview->setModel(tmodel); tview->expandAll(); + tview->setColumnWidth(0,250); + tview->setColumnWidth(1,40); + tview->setColumnWidth(2,110); mMenuBar = new QMenuBar(this); QMenu* options = mMenuBar->addMenu("Options"); @@ -128,6 +131,8 @@ namespace hal { mActionIndicate = options->addAction("Show in graphic view"); connect(mActionIndicate, &QAction::toggled, this, &LogicEvaluatorDialog::handleIndicateToggled); mActionIndicate->setCheckable(true); + QAction* relaunch = mMenuBar->addAction("Relaunch"); + connect(relaunch, &QAction::triggered, this, &LogicEvaluatorDialog::handleRelaunchTriggered); inpLayout->addStretch(); outLayout->addStretch(); @@ -136,6 +141,8 @@ namespace hal { topLayout->addLayout(outLayout); topLayout->setMenuBar(mMenuBar); + tview->setMinimumWidth(400); + if (!skipCompile) compile(); @@ -152,6 +159,12 @@ namespace hal { delete mSimulationInput; } + void LogicEvaluatorDialog::handleRelaunchTriggered() + { + LogicEvaluatorSelectGates lesg(mGates, this); + lesg.exec(); + } + void LogicEvaluatorDialog::handleCompiledToggled(bool checked) { if (checked && !mSharedLib.handle) diff --git a/plugins/logic_evaluator/src/select_gates.cpp b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp similarity index 55% rename from plugins/logic_evaluator/src/select_gates.cpp rename to plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp index 53c6e7e2ccc..08750a94b5f 100644 --- a/plugins/logic_evaluator/src/select_gates.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp @@ -1,7 +1,12 @@ -#include "logic_evaluator/select_gates.h" +#include "logic_evaluator/logic_evaluator_select_gates.h" +#include "logic_evaluator/logic_evaluator_dialog.h" +#include "logic_evaluator/plugin_logic_evaluator.h" +#include "gui/module_model/module_proxy_model.h" +#include "gui/searchbar/searchbar.h" #include "hal_core/netlist/gate.h" #include "gui/gui_globals.h" #include +#include #include namespace hal { @@ -13,13 +18,24 @@ namespace hal { { case Qt::ForegroundRole: if (item && item->getType() == ModuleItem::TreeItemType::Gate && item->state() == Qt::Checked) - return QColor("#FFE8A0"); //TODO : style file + { + if (mParentDialog) + return mParentDialog->selForeground(); + else + return ModuleModel::data(index, role); + } break; case Qt::BackgroundRole: if (item && item->getType() == ModuleItem::TreeItemType::Gate && item->state() == Qt::Checked) - return QColor("#102030"); + { + if (mParentDialog) + return mParentDialog->selBackground(); + else + return ModuleModel::data(index, role); + } break; case Qt::CheckStateRole: + if (!item->isSelectable()) return QVariant(); if (item && !index.column()) return item->state(); break; } @@ -55,29 +71,36 @@ namespace hal { for (BaseTreeItem* bti : item->getChildren()) { SelectGateItem* child = dynamic_cast(bti); + if (!child->isSelectable()) continue; setModuleStateRecursion(child,stat); } } SelectGateModel::SelectGateModel(QObject* parent) + : mParentDialog(dynamic_cast(parent)) { insertModuleRecursion(gNetlist->get_top_module()); } int SelectGateModel::insertModuleRecursion(const Module* mod, SelectGateItem* parentItem) { + int countCheckable = 0; SelectGateItem* child = new SelectGateItem(mod->get_id(), ModuleItem::TreeItemType::Module); for (const Module* subm : mod->get_submodules()) - insertModuleRecursion(subm, child); + countCheckable += insertModuleRecursion(subm, child); for (const Gate* g : mod->get_gates(nullptr, false)) { - child->appendChild(new SelectGateItem(g->get_id(), ModuleItem::TreeItemType::Gate)); + bool isSel = GuiExtensionLogicEvaluator::acceptGate(g); + child->appendChild(new SelectGateItem(g->get_id(), ModuleItem::TreeItemType::Gate, isSel)); + if (isSel) ++countCheckable; } + if (!countCheckable) child->setSelectable(false); if (parentItem) parentItem->appendChild(child); else mRootItem->appendChild(child); + return countCheckable; } QPair SelectGateModel::setCheckedRecursion(bool applySet, BaseTreeItem *parentItem, const QSet &selectedGateIds) @@ -93,6 +116,7 @@ namespace hal { SelectGateItem* item = dynamic_cast(parentItem); if (item) { + if (!item->isSelectable()) return QPair(false,false); Qt::CheckState lastState; switch (item->getType()) { case ModuleItem::TreeItemType::Module: @@ -139,6 +163,42 @@ namespace hal { return QPair(hasChecked,hasUnchecked); } + void SelectGateModel::setSelectedGatesRecursion(SelectGateItem* item) + { + BaseTreeItem* parentItem = nullptr; + if (item) + { + if (!item->isSelectable()) return; + switch (item->getType()) { + case ModuleItem::TreeItemType::Module: + parentItem = item; + break; + case ModuleItem::TreeItemType::Gate: + if (item->state() == Qt::Checked) + { + Gate*g = gNetlist->get_gate_by_id(item->id()); + if (g) mSelectedGates.push_back(g); + } + break; + case ModuleItem::TreeItemType::Net: + Q_ASSERT(1==0); + break; + } + } + else + parentItem = mRootItem; + + if (parentItem) + for (BaseTreeItem* childItem : parentItem->getChildren()) + setSelectedGatesRecursion(static_cast(childItem)); + } + + const std::vector& SelectGateModel::selectedGates() + { + setSelectedGatesRecursion(); + return mSelectedGates; + } + void SelectGateModel::setChecked(const std::vector &gates) { QSet selectedGateIds; @@ -153,18 +213,56 @@ namespace hal { { Qt::ItemFlags retval = ModuleModel::flags(index); if (index.column()) return retval; - return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; + const SelectGateItem* item = dynamic_cast(getItemFromIndex(index)); + if (!item->isSelectable()) return Qt::NoItemFlags; + return retval | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; } - SelectGates::SelectGates(const std::vector& gates, QWidget* parent) + LogicEvaluatorSelectGates::LogicEvaluatorSelectGates(const std::vector& gates, QWidget* parent) : QDialog(parent) { + setWindowTitle("Select combinatorical gates for logic evaluator"); QGridLayout* layout = new QGridLayout(this); mTreeView = new QTreeView(this); - SelectGateModel* model = new SelectGateModel(this); - model->setChecked(gates); - mTreeView->setModel(model); + mSelectGateModel = new SelectGateModel(this); + mProxyModel = new ModuleProxyModel(this); + mProxyModel->setSourceModel(mSelectGateModel); + mProxyModel->toggleFilterGates(); + mSelectGateModel->setChecked(gates); + mTreeView->setModel(mProxyModel); + mTreeView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); mTreeView->expandAll(); - layout->addWidget(mTreeView); + mTreeView->setColumnWidth(0,250); + mTreeView->setColumnWidth(1,40); + mTreeView->setColumnWidth(2,110); + + QDialogButtonBox* bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(bbox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(bbox, &QDialogButtonBox::rejected, this , &QDialog::reject); + bbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + mSearchbar = new Searchbar(this); + connect(mSearchbar, &Searchbar::triggerNewSearch, mProxyModel, &ModuleProxyModel::startSearch); + + mCompile = new QCheckBox("Compile selected logic", this); + mCompile->setChecked(true); + + layout->addWidget(mTreeView,0,0,1,2); + layout->addWidget(mSearchbar, 1,0,1,2); + layout->addWidget(mCompile, 2,0,1,2); + layout->addWidget(bbox, 3,1); + mTreeView->setMinimumWidth(400); + + QStyle* s = style(); + s->unpolish(this); + s->polish(this); + } + + void LogicEvaluatorSelectGates::accept() + { + LogicEvaluatorDialog* led = new LogicEvaluatorDialog(mSelectGateModel->selectedGates(),mCompile->isChecked()); + led->show(); + led->raise(); + QDialog::accept(); } } diff --git a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp index 8b16cd89732..40412ec3714 100644 --- a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp +++ b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp @@ -109,7 +109,51 @@ namespace hal const GateType* gt = g->get_type(); if (gt->has_property(GateTypeProperty::ff)) return false; if (gt->has_property(GateTypeProperty::latch)) return false; + if (gt->has_property(GateTypeProperty::ram)) return false; return true; } + std::vector GuiExtensionLogicEvaluator::get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gats, const std::vector& nets) + { + std::vector retval; + if (nl && (!mods.empty() || !gats.empty())) + retval.push_back({this,"context", "Launch logic evaluator"}); + return retval; + } + + void GuiExtensionLogicEvaluator::execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gats, const std::vector& nets) + { + if (nl && (!mods.empty() || !gats.empty())) + { + std::unordered_set gates; + for (u32 gatId : gats) + { + Gate* g = nl->get_gate_by_id(gatId); + if (g && acceptGate(g)) + gates.insert(g); + } + for (u32 modId : mods) + { + Module* m = nl->get_module_by_id(modId); + if (m) + { + for (Gate* g : m->get_gates(nullptr,true)) + if (acceptGate(g)) + gates.insert(g); + } + } + + if (gates.empty()) + { + log_warning("logic_evaluator", "No pure logical gates in selection, logic evaluator not launched."); + return; + } + + std::vector vgates(gates.begin(), gates.end()); + LogicEvaluatorDialog* led = new LogicEvaluatorDialog(vgates, false); + led->show(); + + } + } + } // namespace hal From 95392229cec01bc68b3acd15578786554d86b778 Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 23 Jul 2024 00:28:06 +0200 Subject: [PATCH 07/22] Added feature truth table --- .../logic_evaluator/logic_evaluator_dialog.h | 4 + .../logic_evaluator_select_gates.h | 11 +- .../logic_evaluator_truthtable.h | 82 +++++++++ .../src/logic_evaluator_dialog.cpp | 56 ++++++- .../src/logic_evaluator_select_gates.cpp | 32 ++-- .../src/logic_evaluator_truthtable.cpp | 158 ++++++++++++++++++ .../src/plugin_logic_evaluator.cpp | 9 +- 7 files changed, 336 insertions(+), 16 deletions(-) create mode 100644 plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h create mode 100644 plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h index a7fea8ddf08..de68f9649b1 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_dialog.h @@ -44,6 +44,8 @@ namespace hal { class LogicEvaluatorPingroup; + class LogicEvaluatorTruthtableModel; + class LogicEvaluatorDialog : public QDialog { Q_OBJECT @@ -71,6 +73,7 @@ namespace hal { QMenuBar* mMenuBar; QAction* mActionCompile; QAction* mActionIndicate; + LogicEvaluatorTruthtableModel* mTruthtable; void calculateEvaluationOrder(); void recalcCompiled(); @@ -83,6 +86,7 @@ namespace hal { void handleCompiledToggled(bool checked); void handleIndicateToggled(bool checked); void handleRelaunchTriggered(); + void handleTruthtableTriggered(); public: LogicEvaluatorDialog(const std::vector& gates, bool skipCompile, QWidget* parent = nullptr); ~LogicEvaluatorDialog(); diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h index e8f7a5d97e8..6810817bfa8 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_select_gates.h @@ -26,11 +26,13 @@ #pragma once #include - #include #include #include #include "gui/module_model/module_model.h" + class QDialogButtonBox; + class QCheckBox; + namespace hal { class Gate; @@ -63,13 +65,15 @@ QPair setCheckedRecursion(bool applySet, BaseTreeItem* parentItem, const QSet& selectedGateIds = QSet() ); void setModuleStateRecursion(SelectGateItem* item, Qt::CheckState stat); void setSelectedGatesRecursion(SelectGateItem* item = nullptr); + Q_SIGNALS: + void selectionStateChanged(bool empty); public: SelectGateModel(QObject* parent = nullptr); void setChecked(const std::vector &gates); Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; - const std::vector& selectedGates(); + const std::vector& selectedGates() const {return mSelectedGates; } }; class LogicEvaluatorSelectGates : public QDialog @@ -84,10 +88,13 @@ ModuleProxyModel* mProxyModel; Searchbar* mSearchbar; QCheckBox* mCompile; + QDialogButtonBox* mButtonBox; QColor mSelBackground; QColor mSelForeground; public Q_SLOTS: void accept() override; + private Q_SLOTS: + void handleSelectionStateChanged(bool empty); public: LogicEvaluatorSelectGates(const std::vector &gates, QWidget* parent = nullptr); diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h new file mode 100644 index 00000000000..a0d531b752f --- /dev/null +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h @@ -0,0 +1,82 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace hal { + class Net; + + class LogicEvaluatorTruthtableColumn + { + int mRows; + int* mArray; + public: + LogicEvaluatorTruthtableColumn(int nrows, QList values); + ~LogicEvaluatorTruthtableColumn(); + int data(int irow) const; + bool lessThan(const LogicEvaluatorTruthtableColumn& other, int irow) const; + }; + + class LogicEvaluatorTruthtableModel : public QAbstractTableModel + { + Q_OBJECT + public: + enum DisplayFormat{ ZeroOne, LowHigh, BlueRed, MAXFORMAT }; + private: + DisplayFormat mDisplayFormat; + QList mInputList; + QList mOutputList; + QList mColumnList; + int mInputSize; + int mOutputSize; + public Q_SLOTS: + void sortModel(int irow); + public: + LogicEvaluatorTruthtableModel(const QList& inpList, const QList& outList, QObject* parent = nullptr); + ~LogicEvaluatorTruthtableModel(); + void setDisplayFormat(DisplayFormat df); + void addColumn(LogicEvaluatorTruthtableColumn* letc); + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + }; + + class LogicEvaluatorTruthtable : public QDialog + { + Q_OBJECT + QAction* mActionDisplayFormat[LogicEvaluatorTruthtableModel::MAXFORMAT]; + LogicEvaluatorTruthtableModel* mModel; + private Q_SLOT: + void handleDisplayFormatChanged(QAction* act); + public: + LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent = nullptr); + + }; +} diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index ec5ddad1194..7dbac9a235b 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -6,6 +6,7 @@ #include "gui/grouping/grouping_manager_widget.h" #include "gui/module_model/module_model.h" #include "logic_evaluator/logic_evaluator_select_gates.h" +#include "logic_evaluator/logic_evaluator_truthtable.h" #include #include @@ -33,6 +34,12 @@ namespace hal { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(QString("Logic Evaluator %1 Gates").arg(gates.size())); + if (gates.empty()) + { + log_warning("logic_evaluator", "No eligible gates selected for logic evaluator, window will close"); + close(); + } + mSimulationInput->add_gates(gates); mSimulationInput->compute_net_groups(); @@ -133,6 +140,8 @@ namespace hal { mActionIndicate->setCheckable(true); QAction* relaunch = mMenuBar->addAction("Relaunch"); connect(relaunch, &QAction::triggered, this, &LogicEvaluatorDialog::handleRelaunchTriggered); + QAction* ttable = mMenuBar->addAction("Truth Table"); + connect(ttable, &QAction::triggered, this, &LogicEvaluatorDialog::handleTruthtableTriggered); inpLayout->addStretch(); outLayout->addStretch(); @@ -162,7 +171,52 @@ namespace hal { void LogicEvaluatorDialog::handleRelaunchTriggered() { LogicEvaluatorSelectGates lesg(mGates, this); - lesg.exec(); + if (lesg.exec() == QDialog::Accepted) + lower(); + } + + void LogicEvaluatorDialog::handleTruthtableTriggered() + { + if (!mSharedLib.handle) return; + if (!mTruthtable) + { + QList inpList; + QList outList; + for (const LogicEvaluatorPingroup* lepg : mInputs) + for (int i=lepg->size()-1; i>=0; i--) + inpList.append(lepg->getValue(i).first); + for (const LogicEvaluatorPingroup* lepg : mOutputs) + for (int i=lepg->size()-1; i>=0; i--) + outList.append(lepg->getValue(i).first); + if (inpList.isEmpty() || outList.isEmpty()) return; + mTruthtable = new LogicEvaluatorTruthtableModel(inpList,outList,this); + + int maxInput = 1 << inpList.size(); + + for (int inputVal = 0; inputVal < maxInput; inputVal++) + { + QList values; + int mask = 1; + for (const Net* n : inpList) + { + int bitVal = (inputVal&mask) ? 1 : 0; + values.append(bitVal); + mSharedLib.set(mExternalArrayIndex[n], bitVal); + mask <<= 1; + } + mSharedLib.calc(); + for (const Net* n : outList) + { + int bitVal = mSharedLib.get(mExternalArrayIndex[n]); + values.append(bitVal); + } + mTruthtable->addColumn(new LogicEvaluatorTruthtableColumn(inpList.size()+outList.size(),values)); + } + } + if (!mTruthtable) return; + + LogicEvaluatorTruthtable lett(mTruthtable, this); + lett.exec(); } void LogicEvaluatorDialog::handleCompiledToggled(bool checked) diff --git a/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp index 08750a94b5f..3d0c458e036 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp @@ -7,6 +7,7 @@ #include "gui/gui_globals.h" #include #include +#include #include namespace hal { @@ -59,6 +60,10 @@ namespace hal { Q_ASSERT(1==0); break; } + bool stateWasEmpty = mSelectedGates.empty(); + setSelectedGatesRecursion(); + if (stateWasEmpty != mSelectedGates.empty()) + Q_EMIT selectionStateChanged(mSelectedGates.empty()); return true; } @@ -165,6 +170,9 @@ namespace hal { void SelectGateModel::setSelectedGatesRecursion(SelectGateItem* item) { + if (!item) + mSelectedGates.clear(); + BaseTreeItem* parentItem = nullptr; if (item) { @@ -193,12 +201,6 @@ namespace hal { setSelectedGatesRecursion(static_cast(childItem)); } - const std::vector& SelectGateModel::selectedGates() - { - setSelectedGatesRecursion(); - return mSelectedGates; - } - void SelectGateModel::setChecked(const std::vector &gates) { QSet selectedGateIds; @@ -207,6 +209,7 @@ namespace hal { selectedGateIds.insert(g->get_id()); setCheckedRecursion(true, mRootItem, selectedGateIds); + setSelectedGatesRecursion(); } Qt::ItemFlags SelectGateModel::flags(const QModelIndex &index) const @@ -236,10 +239,12 @@ namespace hal { mTreeView->setColumnWidth(1,40); mTreeView->setColumnWidth(2,110); - QDialogButtonBox* bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - connect(bbox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(bbox, &QDialogButtonBox::rejected, this , &QDialog::reject); - bbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + mButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(mButtonBox, &QDialogButtonBox::rejected, this , &QDialog::reject); + mButtonBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + connect(mSelectGateModel, &SelectGateModel::selectionStateChanged, this, &LogicEvaluatorSelectGates::handleSelectionStateChanged); + mButtonBox->button(QDialogButtonBox::Ok)->setDisabled(mSelectGateModel->selectedGates().empty()); mSearchbar = new Searchbar(this); connect(mSearchbar, &Searchbar::triggerNewSearch, mProxyModel, &ModuleProxyModel::startSearch); @@ -250,7 +255,7 @@ namespace hal { layout->addWidget(mTreeView,0,0,1,2); layout->addWidget(mSearchbar, 1,0,1,2); layout->addWidget(mCompile, 2,0,1,2); - layout->addWidget(bbox, 3,1); + layout->addWidget(mButtonBox, 3,1); mTreeView->setMinimumWidth(400); QStyle* s = style(); @@ -258,6 +263,11 @@ namespace hal { s->polish(this); } + void LogicEvaluatorSelectGates::handleSelectionStateChanged(bool empty) + { + mButtonBox->button(QDialogButtonBox::Ok)->setDisabled(empty); + } + void LogicEvaluatorSelectGates::accept() { LogicEvaluatorDialog* led = new LogicEvaluatorDialog(mSelectGateModel->selectedGates(),mCompile->isChecked()); diff --git a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp new file mode 100644 index 00000000000..c712fce88e2 --- /dev/null +++ b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp @@ -0,0 +1,158 @@ +#include "logic_evaluator/logic_evaluator_truthtable.h" +#include "hal_core/netlist/net.h" + +#include +#include +#include +#include +#include + +namespace hal { + LogicEvaluatorTruthtableColumn::LogicEvaluatorTruthtableColumn(int nrows, QList values) + : mRows(nrows) + { + mArray = new int[mRows]; + for (int i=0; i &inpList, const QList &outList, QObject* parent) + : mDisplayFormat(MAXFORMAT), // will be set by setDisplayFormat + mInputList(inpList), mOutputList(outList), mInputSize(inpList.size()), mOutputSize(outList.size()) + {;} + + LogicEvaluatorTruthtableModel::~LogicEvaluatorTruthtableModel() + { + for (LogicEvaluatorTruthtableColumn* letc : mColumnList) + delete letc; + } + + void LogicEvaluatorTruthtableModel::addColumn(LogicEvaluatorTruthtableColumn* letc) + { + mColumnList.append(letc); + } + + void LogicEvaluatorTruthtableModel::sortModel(int irow) + { + std::sort(mColumnList.begin(),mColumnList.end(),[irow](const LogicEvaluatorTruthtableColumn* a, const LogicEvaluatorTruthtableColumn* b){return a->lessThan(*b,irow); } ); + Q_EMIT dataChanged(index(0,0),index(rowCount()-1,columnCount()-1)); + } + + QVariant LogicEvaluatorTruthtableModel::data(const QModelIndex& index, int role) const + { + int val = mColumnList.at(index.column())->data(index.row()); + + switch (role) + { + case Qt::DisplayRole: + switch (mDisplayFormat) { + case ZeroOne: + return val; + case LowHigh: + return val ? "H" : "L"; + case BlueRed: + return QChar(0x2588); + } + break; + case Qt::ForegroundRole: + if (mDisplayFormat == BlueRed) + return val ? QColor("#FF0000") : QColor("#00A0FF"); + break; + case Qt::BackgroundRole: + if (index.row() >= mInputSize) + return QColor("#080930"); + return QColor("302A12"); + break; + case Qt::TextAlignmentRole: + return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); + default: + break; + } + return QVariant(); + } + + QVariant LogicEvaluatorTruthtableModel::headerData(int section, Qt::Orientation orientation, int role) const + { + if (role!=Qt::DisplayRole) return QAbstractTableModel::headerData(section, orientation, role); + if (orientation == Qt::Horizontal) + return QString::number(section, 16); + if (section < mInputSize) + return QString::fromStdString(mInputList.at(section)->get_name()); + return QString::fromStdString(mOutputList.at(section-mInputSize)->get_name()); + } + + int LogicEvaluatorTruthtableModel::rowCount(const QModelIndex &parent) const + { + Q_UNUSED(parent); + return mInputSize + mOutputSize; + } + + int LogicEvaluatorTruthtableModel::columnCount(const QModelIndex &parent) const + { + Q_UNUSED(parent); + return (1 << mInputList.size()); + } + + LogicEvaluatorTruthtable::LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent) + : mModel(model) + { + QGridLayout* layout = new QGridLayout(this); + QMenuBar* menuBar = new QMenuBar(this); + QMenu* displForm = menuBar->addMenu("Format"); + + const char* displayFormatLabel[] = {"0 / 1", "L / H", "blue / red"}; + QActionGroup* actGroup = new QActionGroup(this); + for (int i=0; i< LogicEvaluatorTruthtableModel::MAXFORMAT; i++) + { + mActionDisplayFormat[i] = displForm->addAction(displayFormatLabel[i]); + mActionDisplayFormat[i]->setCheckable(true); + actGroup->addAction(mActionDisplayFormat[i]); + } + connect(actGroup, &QActionGroup::triggered, this, &LogicEvaluatorTruthtable::handleDisplayFormatChanged); + mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]->setChecked(true); + handleDisplayFormatChanged(mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]); + + QTableView* view = new QTableView(this); + view->setModel(mModel); + for (int icol=0; icolcolumnCount(); icol++) + view->setColumnWidth(icol, 32); + connect(view->verticalHeader(), &QHeaderView::sectionClicked, mModel, &LogicEvaluatorTruthtableModel::sortModel); + layout->addWidget(view); + layout->setMenuBar(menuBar); + } + + void LogicEvaluatorTruthtableModel::setDisplayFormat(DisplayFormat df) + { + if (df == mDisplayFormat) return; + mDisplayFormat = df; + Q_EMIT dataChanged(index(0,0),index(rowCount()-1,columnCount()-1)); + } + + void LogicEvaluatorTruthtable::handleDisplayFormatChanged(QAction* act) + { + for (int i=0; isetDisplayFormat((LogicEvaluatorTruthtableModel::DisplayFormat)i); + break; + } + } +} diff --git a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp index 40412ec3714..6cbc5d1cd73 100644 --- a/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp +++ b/plugins/logic_evaluator/src/plugin_logic_evaluator.cpp @@ -3,6 +3,7 @@ #include "hal_core/netlist/netlist_writer/netlist_writer_manager.h" #include "hal_core/netlist/gate.h" #include "logic_evaluator/logic_evaluator_dialog.h" +#include "logic_evaluator/logic_evaluator_select_gates.h" #include "gui/content_manager/content_manager.h" #include "gui/gui_globals.h" #include "gui/gui_api/gui_api.h" @@ -95,7 +96,9 @@ namespace hal if (gates.empty()) { - log_warning("logic_evaluator", "No pure logical gates in selection, logic evaluator not launched."); + std::vector emptyList; + LogicEvaluatorSelectGates lesg(emptyList); + lesg.exec(); return; } @@ -145,7 +148,9 @@ namespace hal if (gates.empty()) { - log_warning("logic_evaluator", "No pure logical gates in selection, logic evaluator not launched."); + std::vector emptyList; + LogicEvaluatorSelectGates lesg(emptyList); + lesg.exec(); return; } From 75560bb6982b6ed72a99a768a17db88dbb080f05 Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 24 Jul 2024 00:39:04 +0200 Subject: [PATCH 08/22] Sort feature for truth table added --- .../logic_evaluator_truthtable.h | 27 ++++- .../src/logic_evaluator_dialog.cpp | 17 ++- .../src/logic_evaluator_truthtable.cpp | 107 +++++++++++++++++- 3 files changed, 140 insertions(+), 11 deletions(-) diff --git a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h index a0d531b752f..29c74e38c45 100644 --- a/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h +++ b/plugins/logic_evaluator/include/logic_evaluator/logic_evaluator_truthtable.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace hal { class Net; @@ -40,7 +41,7 @@ namespace hal { LogicEvaluatorTruthtableColumn(int nrows, QList values); ~LogicEvaluatorTruthtableColumn(); int data(int irow) const; - bool lessThan(const LogicEvaluatorTruthtableColumn& other, int irow) const; + bool lessThan(const LogicEvaluatorTruthtableColumn& other, const QList& sortRows) const; }; class LogicEvaluatorTruthtableModel : public QAbstractTableModel @@ -56,10 +57,14 @@ namespace hal { int mInputSize; int mOutputSize; public Q_SLOTS: - void sortModel(int irow); + void sortModelRow(int irow); + void sortModelRows(const QList& sortRows); public: LogicEvaluatorTruthtableModel(const QList& inpList, const QList& outList, QObject* parent = nullptr); ~LogicEvaluatorTruthtableModel(); + QList getNets() const { return mInputList + mOutputList; } + QMap selectedColumn(int icol) const; + void setDisplayFormat(DisplayFormat df); void addColumn(LogicEvaluatorTruthtableColumn* letc); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; @@ -68,15 +73,29 @@ namespace hal { int columnCount(const QModelIndex &parent = QModelIndex()) const override; }; + class LogicEvaluatorTruthtableSort : public QDialog + { + Q_OBJECT + QComboBox* mSortKey[5]; + QList mNets; + public: + LogicEvaluatorTruthtableSort(QList& nets, QWidget* parent = nullptr); + QList sortOrder() const; + }; + class LogicEvaluatorTruthtable : public QDialog { Q_OBJECT QAction* mActionDisplayFormat[LogicEvaluatorTruthtableModel::MAXFORMAT]; + QAction* mActionSort; LogicEvaluatorTruthtableModel* mModel; + int mColumnDubbleClicked; private Q_SLOT: void handleDisplayFormatChanged(QAction* act); + void handleSortTriggered(); + void handleColumnDubbleClicked(int icol); public: - LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent = nullptr); - + LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent = nullptr); + QMap selectedColumn() const; }; } diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index 7dbac9a235b..a1c916a370c 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -189,6 +189,11 @@ namespace hal { for (int i=lepg->size()-1; i>=0; i--) outList.append(lepg->getValue(i).first); if (inpList.isEmpty() || outList.isEmpty()) return; + if (inpList.size() > 10) + { + log_warning("logic_evaluator", "Cannot generate truth table for {} logic inputs.", inpList.size()); + return; + } mTruthtable = new LogicEvaluatorTruthtableModel(inpList,outList,this); int maxInput = 1 << inpList.size(); @@ -216,7 +221,17 @@ namespace hal { if (!mTruthtable) return; LogicEvaluatorTruthtable lett(mTruthtable, this); - lett.exec(); + if (lett.exec() == QDialog::Accepted) + { + QMap vals = lett.selectedColumn(); + for (auto it = vals.constBegin(); it != vals.constEnd(); ++it) + { + const Net* n = it.key(); + BooleanFunction::Value bv = it.value() ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO; + for (LogicEvaluatorPingroup* lepg : mInputs) + lepg->setValue(n,bv); + } + } } void LogicEvaluatorDialog::handleCompiledToggled(bool checked) diff --git a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp index c712fce88e2..5e35799e04f 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include namespace hal { LogicEvaluatorTruthtableColumn::LogicEvaluatorTruthtableColumn(int nrows, QList values) @@ -18,9 +20,14 @@ namespace hal { } } - bool LogicEvaluatorTruthtableColumn::lessThan(const LogicEvaluatorTruthtableColumn& other, int irow) const + bool LogicEvaluatorTruthtableColumn::lessThan(const LogicEvaluatorTruthtableColumn& other, const QList &sortRows) const { - return mArray[irow] < other.mArray[irow]; + for (int irow : sortRows) + { + if (mArray[irow] < other.mArray[irow]) return true; + if (mArray[irow] > other.mArray[irow]) return false; + } + return false; // equal } LogicEvaluatorTruthtableColumn::~LogicEvaluatorTruthtableColumn() @@ -50,9 +57,18 @@ namespace hal { mColumnList.append(letc); } - void LogicEvaluatorTruthtableModel::sortModel(int irow) + void LogicEvaluatorTruthtableModel::sortModelRow(int irow) + { + QList sortRows; + sortRows.append(irow); + std::sort(mColumnList.begin(),mColumnList.end(),[sortRows](const LogicEvaluatorTruthtableColumn* a, const LogicEvaluatorTruthtableColumn* b){return a->lessThan(*b,sortRows); } ); + Q_EMIT dataChanged(index(0,0),index(rowCount()-1,columnCount()-1)); + } + + void LogicEvaluatorTruthtableModel::sortModelRows(const QList& sortRows) { - std::sort(mColumnList.begin(),mColumnList.end(),[irow](const LogicEvaluatorTruthtableColumn* a, const LogicEvaluatorTruthtableColumn* b){return a->lessThan(*b,irow); } ); + if (sortRows.isEmpty()) return; + std::sort(mColumnList.begin(),mColumnList.end(),[sortRows](const LogicEvaluatorTruthtableColumn* a, const LogicEvaluatorTruthtableColumn* b){return a->lessThan(*b,sortRows); } ); Q_EMIT dataChanged(index(0,0),index(rowCount()-1,columnCount()-1)); } @@ -111,8 +127,51 @@ namespace hal { return (1 << mInputList.size()); } + //-------------------------------- + LogicEvaluatorTruthtableSort::LogicEvaluatorTruthtableSort(QList& nets, QWidget* parent) + : QDialog(parent), mNets(nets) + { + QVBoxLayout* layout = new QVBoxLayout(this); + const char* ordinal[] = { "st", "nd", "th"}; + for (int i=0; i<5; i++) + { + if (i) layout->addStretch(); + layout->addWidget(new QLabel(QString("%1%2 sort key").arg(i+1).arg(i<3?ordinal[i]:ordinal[2]),this)); + mSortKey[i] = new QComboBox(this); + mSortKey[i]->addItem("--not used--", (const void*) nullptr); + for (const Net* n : mNets) + mSortKey[i]->addItem(QString::fromStdString(n->get_name()),(const void*)n); + layout->addWidget(mSortKey[i]); + } + QDialogButtonBox* bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(bbox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(bbox, &QDialogButtonBox::rejected, this , &QDialog::reject); + bbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + layout->addWidget(bbox); + } + + QList LogicEvaluatorTruthtableSort::sortOrder() const + { + QList retval; + QSet selected; + for (int i=0; i<5; i++) + { + int inx = mSortKey[i]->currentIndex(); + if (!inx) break; + --inx; // skip not used entry + const Net* n = mNets.at(inx); + if (!selected.contains(n)) + { + retval.append(inx); + selected.insert(n); + } + } + return retval; + } + + //-------------------------------- LogicEvaluatorTruthtable::LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent) - : mModel(model) + : mModel(model), mColumnDubbleClicked(-1) { QGridLayout* layout = new QGridLayout(this); QMenuBar* menuBar = new QMenuBar(this); @@ -130,11 +189,15 @@ namespace hal { mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]->setChecked(true); handleDisplayFormatChanged(mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]); + QAction* actSort = menuBar->addAction("Sort"); + connect(actSort, &QAction::triggered, this, &LogicEvaluatorTruthtable::handleSortTriggered); + QTableView* view = new QTableView(this); view->setModel(mModel); for (int icol=0; icolcolumnCount(); icol++) view->setColumnWidth(icol, 32); - connect(view->verticalHeader(), &QHeaderView::sectionClicked, mModel, &LogicEvaluatorTruthtableModel::sortModel); + connect(view->verticalHeader(), &QHeaderView::sectionClicked, mModel, &LogicEvaluatorTruthtableModel::sortModelRow); + connect(view->horizontalHeader(), &QHeaderView::sectionDoubleClicked, this, &LogicEvaluatorTruthtable::handleColumnDubbleClicked); layout->addWidget(view); layout->setMenuBar(menuBar); } @@ -146,6 +209,38 @@ namespace hal { Q_EMIT dataChanged(index(0,0),index(rowCount()-1,columnCount()-1)); } + void LogicEvaluatorTruthtable::handleSortTriggered() + { + QList nets = mModel->getNets(); + LogicEvaluatorTruthtableSort lets(nets,this); + if (lets.exec() == QDialog::Accepted) + { + mModel->sortModelRows(lets.sortOrder()); + } + } + + void LogicEvaluatorTruthtable::handleColumnDubbleClicked(int icol) + { + mColumnDubbleClicked = icol; + accept(); + } + + QMap LogicEvaluatorTruthtableModel::selectedColumn(int icol) const + { + QMap retval; + if (icol < 0 || icol >= mColumnList.size()) return retval; + LogicEvaluatorTruthtableColumn* letc = mColumnList.at(icol); + int irow = 0; + for (const Net* n : mInputList) + retval[n] = letc->data(irow++); + return retval; + } + + QMap LogicEvaluatorTruthtable::selectedColumn() const + { + return mModel->selectedColumn(mColumnDubbleClicked); + } + void LogicEvaluatorTruthtable::handleDisplayFormatChanged(QAction* act) { for (int i=0; i Date: Wed, 24 Jul 2024 15:13:40 +0200 Subject: [PATCH 09/22] Minor bugfix --- plugins/gui_extension_demo/python/python_bindings.cpp | 1 + plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp | 2 +- plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/gui_extension_demo/python/python_bindings.cpp b/plugins/gui_extension_demo/python/python_bindings.cpp index 4075fe5e849..93ed06a2c1b 100644 --- a/plugins/gui_extension_demo/python/python_bindings.cpp +++ b/plugins/gui_extension_demo/python/python_bindings.cpp @@ -54,6 +54,7 @@ namespace hal .value("ComboBox", PluginParameter::ComboBox, R"(Combo box to select string from semicolon separated input list.)") .value("Dictionary", PluginParameter::Dictionary, R"(Key value pairs (string).)") .value("ExistingDir", PluginParameter::ExistingDir, R"(Existing directory.)") + .value("ExistingFile",PluginParameter::ExistingFile,R"(Existing file.)") .value("Float", PluginParameter::Float, R"(Floating point number.)") .value("Gate", PluginParameter::Gate, R"(Gate ID.)") .value("Integer", PluginParameter::Integer, R"(Integer number.)") diff --git a/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp index 3d0c458e036..53c50ce0769 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_select_gates.cpp @@ -270,7 +270,7 @@ namespace hal { void LogicEvaluatorSelectGates::accept() { - LogicEvaluatorDialog* led = new LogicEvaluatorDialog(mSelectGateModel->selectedGates(),mCompile->isChecked()); + LogicEvaluatorDialog* led = new LogicEvaluatorDialog(mSelectGateModel->selectedGates(),!mCompile->isChecked()); led->show(); led->raise(); QDialog::accept(); diff --git a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp index 5e35799e04f..b91b4a6388b 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp @@ -173,6 +173,7 @@ namespace hal { LogicEvaluatorTruthtable::LogicEvaluatorTruthtable(LogicEvaluatorTruthtableModel* model, QWidget* parent) : mModel(model), mColumnDubbleClicked(-1) { + setWindowTitle("Truth Table from Logic Evaluator"); QGridLayout* layout = new QGridLayout(this); QMenuBar* menuBar = new QMenuBar(this); QMenu* displForm = menuBar->addMenu("Format"); From a2503ca03570057025997921db3bf01eb14de93d Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 24 Jul 2024 15:27:58 +0200 Subject: [PATCH 10/22] Fix 'compile' check mark on start --- plugins/logic_evaluator/src/logic_evaluator_dialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index a1c916a370c..b599d5c10ea 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -135,6 +135,7 @@ namespace hal { mActionCompile = options->addAction("Run compiled logic"); connect(mActionCompile, &QAction::toggled, this, &LogicEvaluatorDialog::handleCompiledToggled); mActionCompile->setCheckable(true); + mActionCompile->setChecked(false); mActionIndicate = options->addAction("Show in graphic view"); connect(mActionIndicate, &QAction::toggled, this, &LogicEvaluatorDialog::handleIndicateToggled); mActionIndicate->setCheckable(true); @@ -153,7 +154,9 @@ namespace hal { tview->setMinimumWidth(400); if (!skipCompile) - compile(); + { + mActionCompile->setChecked(true); + } QStyle* s = style(); From 1b7e6506af8006e07ba3d7b74d718286c29d66ca Mon Sep 17 00:00:00 2001 From: "julian.speith" Date: Mon, 29 Jul 2024 14:11:51 +0200 Subject: [PATCH 11/22] fixed default param and docs --- src/python_bindings/bindings/netlist_factory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python_bindings/bindings/netlist_factory.cpp b/src/python_bindings/bindings/netlist_factory.cpp index 5cf5263cea8..6b45d1c270b 100644 --- a/src/python_bindings/bindings/netlist_factory.cpp +++ b/src/python_bindings/bindings/netlist_factory.cpp @@ -16,11 +16,11 @@ namespace hal .def( "load_netlist", - [](const std::filesystem::path& netlist_file, const std::filesystem::path& gate_library_file) { + [](const std::filesystem::path& netlist_file, const std::filesystem::path& gate_library_file = std::filesystem::path()) { return std::shared_ptr(netlist_factory::load_netlist(netlist_file, gate_library_file)); }, py::arg("netlist_file"), - py::arg("gate_library_file") = "", + py::arg("gate_library_file") = std::filesystem::path(), R"( Create a netlist from the given file using the specified gate library file. Will either deserialize ``.hal`` file or call parser plugin for other formats. @@ -42,7 +42,7 @@ namespace hal Will either deserialize ``.hal`` file or call parser plugin for other formats. :param pathlib.Path netlist_file: Path to the file. - :param pathlib.Path gate_library_file: Path to the gate library file. + :param hal_py.GateLibrary gate_library_file: Path to the gate library file. :returns: The netlist on success, ``None`` otherwise. :rtype: hal_py.Netlist or None )") From 50b676472ea5e7a33ce6e6284bc6356f5159d40e Mon Sep 17 00:00:00 2001 From: "julian.speith" Date: Mon, 29 Jul 2024 14:22:28 +0200 Subject: [PATCH 12/22] minor fixes --- CHANGELOG.md | 4 ++++ CURRENT_VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10819f7f397..d05598854ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [4.4.1](v4.4.1) - 2024-07-29 14:21:42+02:00 (urgency: medium) +* fixed `hal_py.GateLibrary.gate_types` pybind +* fixed `hal_py.NetlistFactory.load_netlist` pybind + ## [4.4.0](v4.4.0) - 2024-07-19 15:55:24+02:00 (urgency: medium) * **WARNING:** this release breaks the API of the `boolean_influence` and `bitorder_propagation` plugin * **WARNING:** this release contains many new unstable plugin APIs that will likely change in the future diff --git a/CURRENT_VERSION b/CURRENT_VERSION index fdc6698807a..cca25a93cd0 100644 --- a/CURRENT_VERSION +++ b/CURRENT_VERSION @@ -1 +1 @@ -4.4.0 +4.4.1 From d45395dbd511a9e4fbb56b83fded6936fb2d161e Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 30 Jul 2024 14:23:42 +0200 Subject: [PATCH 13/22] Changed menu structure to make it work on stupid MacOS --- plugins/logic_evaluator/src/logic_evaluator_dialog.cpp | 5 +++-- plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index b599d5c10ea..2d5c7177d89 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -139,9 +139,10 @@ namespace hal { mActionIndicate = options->addAction("Show in graphic view"); connect(mActionIndicate, &QAction::toggled, this, &LogicEvaluatorDialog::handleIndicateToggled); mActionIndicate->setCheckable(true); - QAction* relaunch = mMenuBar->addAction("Relaunch"); + QMenu* launch = mMenuBar->addMenu("Launch"); + QAction* relaunch = launch->addAction("Relaunch"); connect(relaunch, &QAction::triggered, this, &LogicEvaluatorDialog::handleRelaunchTriggered); - QAction* ttable = mMenuBar->addAction("Truth Table"); + QAction* ttable = launch->addAction("Truth Table"); connect(ttable, &QAction::triggered, this, &LogicEvaluatorDialog::handleTruthtableTriggered); inpLayout->addStretch(); diff --git a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp index b91b4a6388b..fe879e6ec90 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_truthtable.cpp @@ -190,7 +190,8 @@ namespace hal { mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]->setChecked(true); handleDisplayFormatChanged(mActionDisplayFormat[LogicEvaluatorTruthtableModel::ZeroOne]); - QAction* actSort = menuBar->addAction("Sort"); + QMenu* sortMenu = menuBar->addMenu("Sort"); + QAction* actSort = sortMenu->addAction("Sort"); connect(actSort, &QAction::triggered, this, &LogicEvaluatorTruthtable::handleSortTriggered); QTableView* view = new QTableView(this); From 2610215def32df0a3d6660483a59539c0f640696 Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 31 Jul 2024 00:00:55 +0200 Subject: [PATCH 14/22] Bypass pin names in code (name might not qualify as ANSI-C-variable) --- .../src/logic_evaluator_dialog.cpp | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index 2d5c7177d89..758099849ee 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -269,7 +269,6 @@ namespace hal { bool LogicEvaluatorDialog::compile() { // get input signals - QMap pinVars; QString codeEvalFunction; mExternalArrayIndex.clear(); @@ -288,29 +287,29 @@ namespace hal { // propagate by gates for (const Gate* g : mEvaluationOrder) { - for (const GatePin* gp : g->get_type()->get_input_pins()) - { - QString pinName = QString::fromStdString(gp->get_name()); - pinVars[pinName]++; - const Net* n = g->get_fan_in_net(gp); - int inx = mExternalArrayIndex.value(n,-1); - if (inx < 0) return false; - codeEvalFunction += QString(" %1 = logic_evaluator_signals[%2];\n").arg(pinName).arg(inx); - } for (const GatePin* gp : g->get_type()->get_output_pins()) { QString pinName = QString::fromStdString(gp->get_name()); - pinVars[pinName]++; - const Net* n = g->get_fan_out_net(gp); - if (!mExternalArrayIndex.contains(n)) + const Net* nOut = g->get_fan_out_net(gp); + if (!mExternalArrayIndex.contains(nOut)) { int sz = mExternalArrayIndex.size(); - mExternalArrayIndex[n] = sz; + mExternalArrayIndex[nOut] = sz; } - codeEvalFunction += QString(" %1 = %2;\n").arg(pinName).arg(QString::fromStdString(g->get_boolean_function(gp).to_string())); - int inx = mExternalArrayIndex.value(n,-1); - if (inx < 0) return false; - codeEvalFunction += QString(" logic_evaluator_signals[%1] = %2;\n").arg(inx).arg(pinName); + + QString theFunction = QString::fromStdString(g->get_boolean_function(gp).to_string()); + for (const GatePin* gp : g->get_type()->get_input_pins()) + { + QString pinName = QString::fromStdString(gp->get_name()); + const Net* nIn = g->get_fan_in_net(gp); + int inxIn = mExternalArrayIndex.value(nIn,-1); + if (inxIn < 0) return false; + QString ccVar = QString("logic_evaluator_signals[%1]").arg(inxIn); + theFunction.replace(pinName, ccVar); + } + int inxOut = mExternalArrayIndex.value(nOut,-1); + if (inxOut < 0) return false; + codeEvalFunction += QString(" logic_evaluator_signals[%1] = %2;\n").arg(inxOut).arg(theFunction); } } @@ -337,10 +336,6 @@ namespace hal { "}\n\n"; ccode += "void " + QString(LOGIC_EVALUATOR_CALC); ccode += "() {\n"; - for (QString var : pinVars.keys()) - { - ccode += QString(" int %1;\n").arg(var); - } ccode += codeEvalFunction + "\n}\n"; // write code to file From d650001f9efca9d440be318224d26cdea53c3044 Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 31 Jul 2024 11:14:22 +0200 Subject: [PATCH 15/22] Allow to reference output pins as input when compiling boolean functions --- .../src/logic_evaluator_dialog.cpp | 15 ++++++++++++--- .../src/simulation_input.cpp | 6 +++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp index 758099849ee..bc4082d683e 100644 --- a/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp +++ b/plugins/logic_evaluator/src/logic_evaluator_dialog.cpp @@ -287,9 +287,11 @@ namespace hal { // propagate by gates for (const Gate* g : mEvaluationOrder) { + QMap referableOutputPins; + for (const GatePin* gp : g->get_type()->get_output_pins()) { - QString pinName = QString::fromStdString(gp->get_name()); + QString pinNameOut = QString::fromStdString(gp->get_name()); const Net* nOut = g->get_fan_out_net(gp); if (!mExternalArrayIndex.contains(nOut)) { @@ -300,16 +302,23 @@ namespace hal { QString theFunction = QString::fromStdString(g->get_boolean_function(gp).to_string()); for (const GatePin* gp : g->get_type()->get_input_pins()) { - QString pinName = QString::fromStdString(gp->get_name()); + QString pinNameIn = QString::fromStdString(gp->get_name()); const Net* nIn = g->get_fan_in_net(gp); int inxIn = mExternalArrayIndex.value(nIn,-1); if (inxIn < 0) return false; QString ccVar = QString("logic_evaluator_signals[%1]").arg(inxIn); - theFunction.replace(pinName, ccVar); + theFunction.replace(pinNameIn, ccVar); + } + for (auto it = referableOutputPins.constBegin(); it != referableOutputPins.constEnd(); ++it) + { + theFunction.replace(it.key(),it.value()); } + int inxOut = mExternalArrayIndex.value(nOut,-1); if (inxOut < 0) return false; codeEvalFunction += QString(" logic_evaluator_signals[%1] = %2;\n").arg(inxOut).arg(theFunction); + + referableOutputPins[pinNameOut] = QString("logic_evaluator_signals[%1]").arg(inxOut); } } diff --git a/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp b/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp index bcd58d5ee39..b3e48f4d31f 100644 --- a/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp +++ b/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp @@ -14,7 +14,11 @@ namespace hal { { for (GatePin* gp : gate_pin_group->get_pins()) { - Net* n = gate->get_fan_in_net(gp); + Net* n = nullptr; + if (gp->get_direction() == PinDirection::input || gp->get_direction() == PinDirection::inout) + n = gate->get_fan_in_net(gp); + else + n = gate->get_fan_out_net(gp); if (n) retval.push_back(n); } } From 07152f1a9b5768cef8dcffa4dbb7ae5fb14a8246 Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 2 Aug 2024 00:12:04 +0200 Subject: [PATCH 16/22] bugfix: keep y-position map and vector in sync --- .../src/graph_widget/layouters/graph_layouter.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 0d56740554c..45ed9523f49 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -778,7 +778,6 @@ namespace hal int iy0 = mNodeBoundingBox.y() * 2; float y0 = mCoordY[iy0].preLanes() * sLaneSpacing + sVRoadPadding; mCoordY[iy0].setOffset(y0); - mYValues.append(mCoordY.value(iy0).lanePosition(0)); auto ityLast = mCoordY.begin(); for (auto itNext = ityLast + 1; itNext != mCoordY.end(); ++itNext) { @@ -789,7 +788,6 @@ namespace hal { // netjunction -> endpoint itNext->setOffsetYje(ityLast.value(), mJunctionMinDistanceY.value(iy1)); - mYValues.append(itNext.value().lanePosition(0)); } else { @@ -802,6 +800,16 @@ namespace hal } ityLast = itNext; } + + iy0 = mNodeBoundingBox.y() * 2; + auto ity = mCoordY.find(iy0); + while(ity != mCoordY.end()) + { + std::cerr << iy0 << " mYValues[" << mYValues.size() << "] = " << ity.value().lanePosition(0) << std::endl; + mYValues.append(ity.value().lanePosition(0)); + iy0 += 2; + ity = mCoordY.find(iy0); + } } void GraphLayouter::placeGates() From c177aeabbbe763e43959842f004bcdeb8ac7a6fa Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 2 Aug 2024 00:13:48 +0200 Subject: [PATCH 17/22] Debug statement removed --- plugins/gui/src/graph_widget/layouters/graph_layouter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 45ed9523f49..9a465eaaae1 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -805,7 +805,6 @@ namespace hal auto ity = mCoordY.find(iy0); while(ity != mCoordY.end()) { - std::cerr << iy0 << " mYValues[" << mYValues.size() << "] = " << ity.value().lanePosition(0) << std::endl; mYValues.append(ity.value().lanePosition(0)); iy0 += 2; ity = mCoordY.find(iy0); From a19a602041a6f9a5590acc62f14337134faffa2f Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 2 Aug 2024 14:19:55 +0200 Subject: [PATCH 18/22] Bugfix : clear list of blocked context's after removing the lock --- plugins/gui/src/python/python_editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/gui/src/python/python_editor.cpp b/plugins/gui/src/python/python_editor.cpp index b986c7c716f..fd18cbfd866 100644 --- a/plugins/gui/src/python/python_editor.cpp +++ b/plugins/gui/src/python/python_editor.cpp @@ -868,6 +868,7 @@ namespace hal GraphContext* ctx = gGraphContextManager->getContextById(ctxId); if (ctx) ctx->endChange(); } + mBlockedContextIds.clear(); mFileModifiedBar->setHidden(true); } From ac2454cea9b1b8a520b18f6cccb86c30a4c9baac Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 6 Aug 2024 15:48:11 +0200 Subject: [PATCH 19/22] Bugfix : proxy model was pointing to proxy instead of source model --- plugins/gui/include/gui/module_dialog/module_dialog.h | 3 --- plugins/gui/src/module_dialog/module_dialog.cpp | 11 +++-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/plugins/gui/include/gui/module_dialog/module_dialog.h b/plugins/gui/include/gui/module_dialog/module_dialog.h index 994d29807d1..dba29e66fca 100644 --- a/plugins/gui/include/gui/module_dialog/module_dialog.h +++ b/plugins/gui/include/gui/module_dialog/module_dialog.h @@ -133,9 +133,6 @@ namespace hal { QTabWidget* mTabWidget; ModuleProxyModel* mModuleTreeProxyModel; - ModuleSelectProxy* mModuleTableProxyModel; - ModuleSelectModel* mModuleSelectModel; - Searchbar* mSearchbar; QAction* mToggleSearchbar; ModuleSelectExclude mSelectExclude; diff --git a/plugins/gui/src/module_dialog/module_dialog.cpp b/plugins/gui/src/module_dialog/module_dialog.cpp index 4e2a651c25f..c5b00c9f4a4 100644 --- a/plugins/gui/src/module_dialog/module_dialog.cpp +++ b/plugins/gui/src/module_dialog/module_dialog.cpp @@ -96,11 +96,6 @@ namespace hal { mTreeView->setModel(mModuleTreeProxyModel); mTreeView->expandAll(); - mModuleTableProxyModel = new ModuleSelectProxy(this), - mModuleTableProxyModel->setSourceModel(mTableView->model()); - mTableView->setModel(mModuleTableProxyModel); - - mButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); layout->addWidget(mButtonBox, 3, 0, 1, 3, Qt::AlignHCenter); @@ -116,7 +111,7 @@ namespace hal { if(mTabWidget->currentWidget() == mTreeView) mSearchbar->setColumnNames(mModuleTreeProxyModel->getColumnNames()); else - mSearchbar->setColumnNames(mModuleTableProxyModel->getColumnNames()); + mSearchbar->setColumnNames(static_cast(mTableView->model())->getColumnNames()); connect(mTabWidget, &QTabWidget::currentChanged, this, &ModuleDialog::handleCurrentTabChanged); connect(mToggleSearchbar, &QAction::triggered, this, &ModuleDialog::handleToggleSearchbar); @@ -128,7 +123,7 @@ namespace hal { connect(mTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ModuleDialog::handleTreeSelectionChanged); connect(mSearchbar, &Searchbar::triggerNewSearch, mModuleTreeProxyModel, &ModuleProxyModel::startSearch); - connect(mSearchbar, &Searchbar::triggerNewSearch, mModuleTableProxyModel, &ModuleSelectProxy::startSearch); + connect(mSearchbar, &Searchbar::triggerNewSearch, static_cast(mTableView->model()), &ModuleSelectProxy::startSearch); } void ModuleDialog::enableButtons() @@ -247,7 +242,7 @@ namespace hal { if(mTabWidget->currentWidget() == mTreeView) mSearchbar->setColumnNames(mModuleTreeProxyModel->getColumnNames()); else - mSearchbar->setColumnNames(mModuleTableProxyModel->getColumnNames()); + mSearchbar->setColumnNames(static_cast(mTableView->model())->getColumnNames()); mTreeView->clearSelection(); mTableView->clearSelection(); mSearchbar->clear(); From 3a54c188924b4067dc2d0113fee1ba398d1c2337 Mon Sep 17 00:00:00 2001 From: "julian.speith" Date: Sun, 18 Aug 2024 14:23:34 -0700 Subject: [PATCH 20/22] added hawkeye readme --- plugins/hawkeye/.gitignore | 3 ++- plugins/hawkeye/README.md | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 plugins/hawkeye/README.md diff --git a/plugins/hawkeye/.gitignore b/plugins/hawkeye/.gitignore index 3ab9044d6ce..f8e4f04ad70 100644 --- a/plugins/hawkeye/.gitignore +++ b/plugins/hawkeye/.gitignore @@ -9,4 +9,5 @@ !documentation/**/* !scripts* !scripts/**/* -!.gitignore \ No newline at end of file +!.gitignore +!README.md \ No newline at end of file diff --git a/plugins/hawkeye/README.md b/plugins/hawkeye/README.md new file mode 100644 index 00000000000..df5bc80a18f --- /dev/null +++ b/plugins/hawkeye/README.md @@ -0,0 +1,5 @@ +# HAWKEYE + +This plugin was developed in the context of the academic publication titled "HAWKEYE - Recovering Symmetric Cryptography From Hardware Circuits" by Gregor Leaner, Christof Paar, Julian Speith, and Lukas Stennes published at IACR Crypto'24. You can find the paper on [IACR ePrint](https://eprint.iacr.org/2024/860.pdf) (free of charge) and [SpringerLink](https://link.springer.com/chapter/10.1007/978-3-031-68385-5_11). + +For an example application of HAWKEYE and to reproduce the results from the paper, we refer the reader to the [paper artifacts](https://artifacts.iacr.org/crypto/2024/a9/) hosted by the IACR. \ No newline at end of file From 493058b673ac37d687320b2e774ca8f4405c30ae Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 19 Aug 2024 14:15:44 +0200 Subject: [PATCH 21/22] Bugfix: GUI plugin mangager must not show entry if plugin has been removed --- .../gui/plugin_relay/gui_plugin_manager.h | 3 +++ .../src/plugin_relay/gui_plugin_manager.cpp | 26 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h b/plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h index bb5277a4eb0..6a08bc7aa19 100644 --- a/plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h +++ b/plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h @@ -62,6 +62,7 @@ namespace hal { bool mUserInterface; bool mGuiExtensions; QString mCliOptions; + bool mFileFound; public: GuiPluginEntry(const QFileInfo& info); @@ -72,6 +73,8 @@ namespace hal { bool isLoaded() const { return mState == AutoLoad || mState == UserLoad; } bool isPlugin() const { return mState != NotAPlugin; } void updateFromLoaded(const BasePluginInterface* bpif, bool isUser, const QDateTime& modified = QDateTime()); + bool isFileFound() const { return mFileFound; } + void setFileFound(bool fnd) { mFileFound = fnd; } }; class GuiPluginManager; diff --git a/plugins/gui/src/plugin_relay/gui_plugin_manager.cpp b/plugins/gui/src/plugin_relay/gui_plugin_manager.cpp index 96dba50feb4..261f44e4620 100644 --- a/plugins/gui/src/plugin_relay/gui_plugin_manager.cpp +++ b/plugins/gui/src/plugin_relay/gui_plugin_manager.cpp @@ -308,6 +308,7 @@ namespace hal { if (gpe) { needUpdate = gpe->mFileModified != info.lastModified(); + gpe->setFileFound(true); } else { @@ -386,18 +387,25 @@ namespace hal { mEntries.clear(); mAvoid.clear(); mLookup.clear(); - for (auto it = pluginEntries.constBegin(); it != pluginEntries.constEnd(); ++it) + auto it = pluginEntries.begin(); + while (it != pluginEntries.end()) { GuiPluginEntry* gpe = it.value(); - if (gpe->isPlugin()) + if (gpe->isFileFound()) { - mLookup.insert(gpe->mName,mEntries.size()); - mEntries.append(gpe); + if (gpe->isPlugin()) + { + mLookup.insert(gpe->mName,mEntries.size()); + mEntries.append(gpe); + } + else + { + mAvoid.append(gpe); + } + ++it; } else - { - mAvoid.append(gpe); - } + it = pluginEntries.erase(it); } persist(); } @@ -732,7 +740,8 @@ namespace hal { mFileModified(info.lastModified()), mFeature(FacExtensionInterface::FacUnknown), mUserInterface(false), - mGuiExtensions(false) + mGuiExtensions(false), + mFileFound(true) {;} QVariant GuiPluginEntry::data(int icol) const @@ -782,6 +791,7 @@ namespace hal { } GuiPluginEntry::GuiPluginEntry(const QSettings *settings) + : mFileFound(false) { mState = (State) settings->value("state").toInt(); mName = settings->value("name").toString(); From 9efd164a1abcc21613016091fd4d6be30814d527 Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 30 Aug 2024 22:07:26 +0200 Subject: [PATCH 22/22] Wait unlimited time for simulation process to finish --- .../netlist_simulator_controller/src/simulation_process.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/simulator/netlist_simulator_controller/src/simulation_process.cpp b/plugins/simulator/netlist_simulator_controller/src/simulation_process.cpp index 715c5b7c4df..0ce8485bb6e 100644 --- a/plugins/simulator/netlist_simulator_controller/src/simulation_process.cpp +++ b/plugins/simulator/netlist_simulator_controller/src/simulation_process.cpp @@ -253,7 +253,7 @@ namespace hal else { log_warning("simulation_plugin", "No QApplication running, event loop not entered, will poll for process to finish."); - if (!mProcess->waitForFinished()) return false; + if (!mProcess->waitForFinished(-1)) return false; handleReadyReadStandardError(); handleReadyReadStandardOutput(); }