From 45a668fc46f51b0d94dba700944a7ded3a6d1b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Mon, 9 May 2022 00:51:47 +0200 Subject: [PATCH] Added comdel system generation // todo display generation --- CMakeLists.txt | 2 +- comdel/display/component_display.cpp | 26 +- comdel/display/component_display.h | 68 +++++ comdel/display/schema_display.cpp | 14 +- comdel/display/schema_display.h | 1 - comdel/domain/comdel_generator.cpp | 273 ++++++++++++++++++ comdel/domain/comdel_generator.h | 16 + comdel/domain/connectioninstance.cpp | 10 + comdel/domain/connectioninstance.h | 2 + comdel/domain/pin.cpp | 2 +- comdel/domain/pin.h | 2 +- comdel/domain/schema.cpp | 19 ++ comdel/domain/schema.h | 3 + comdel/parser/astnode.h | 2 +- .../simplified FRISC model/frisc_library.csl | 6 +- mainwindow.cpp | 54 ++-- mainwindow.h | 2 + 17 files changed, 450 insertions(+), 52 deletions(-) create mode 100644 comdel/domain/comdel_generator.cpp create mode 100644 comdel/domain/comdel_generator.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 36d327c..5c9413d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,5 +38,5 @@ add_executable(SchemeEditor comdel/parser/comdellexer.cpp main.cpp mainwindow.ui - comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/dialogmanager.cpp comdel/display/dialogmanager.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h) + comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/dialogmanager.cpp comdel/display/dialogmanager.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h) target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index 5cd65d9..2ac3d9c 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -5,10 +5,30 @@ #include #include -#include "dialogmanager.h" - namespace display { +void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { + QMenu menu; + menu.addAction("Izmjeni ime", [this](){}); + menu.addSeparator(); + for(auto attr: this->instance->attributes) { + bool enabled = attr.attribute.getPopup().has_value(); + + auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr.name), + [&attr, this]() {}); + action->setEnabled(enabled); + } + menu.exec(event->screenPos()); +} + + +void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { + QMenu menu; + menu.addAction("Izmjeni ime", [this](){}); + menu.exec(event->screenPos()); +} + +/* ComponentWrapper *ComponentWrapper::ofWire(domain::WireInstance *wire) { auto component = new ComponentWrapper(); component->wireInstance = wire; @@ -125,5 +145,5 @@ void PinItem::clear() { delete item; } } - +*/ } // namespace display diff --git a/comdel/display/component_display.h b/comdel/display/component_display.h index 6259656..6b1a76b 100644 --- a/comdel/display/component_display.h +++ b/comdel/display/component_display.h @@ -8,6 +8,7 @@ namespace display { +/* class ComponentItem: public QGraphicsItemGroup { public: @@ -68,6 +69,73 @@ private: ComponentItem *componentItem; std::vector pinItems; }; + */ + +class Pin: public QGraphicsItemGroup +{ +private: + domain::Pin pin; +public: + Pin(domain::Pin pin): pin(pin) { + pin.getDisplay().render(this); + } +}; + +class Component: public QGraphicsItemGroup +{ +private: + std::shared_ptr instance; +public: + Component(const std::shared_ptr& instance): instance(instance) { + instance->component.getDisplay().render(this); + } + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; +}; + +class Bus: public QGraphicsItemGroup +{ +public: + Bus(const std::shared_ptr& instance) { + instance->bus.getDisplay()->render(this); + } + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; +}; + +class ComponentGroup: public QGraphicsItemGroup +{ +private: + std::shared_ptr componentInstance; + +public: + explicit ComponentGroup(const std::shared_ptr& instance): componentInstance(instance) { + setFlag(ItemIsMovable, true); + setHandlesChildEvents(false); + + addToGroup(new display::Component(instance)); + + for(auto &pin: instance->component.getPins()) { + addToGroup(new display::Pin(pin)); + } + + setPos(instance->position.first, instance->position.second); + } +}; + +class BusGroup: public QGraphicsItemGroup +{ +private: + std::shared_ptr busInstance; + +public: + explicit BusGroup(const std::shared_ptr& instance): busInstance(instance) { + setFlag(ItemIsMovable, true); + setHandlesChildEvents(false); + + addToGroup(new display::Bus(instance)); + + setPos(instance->position.first, instance->position.second); + } +}; } // namespace display diff --git a/comdel/display/schema_display.cpp b/comdel/display/schema_display.cpp index 20c6515..7ff29c3 100644 --- a/comdel/display/schema_display.cpp +++ b/comdel/display/schema_display.cpp @@ -9,20 +9,18 @@ Schema::Schema() } -void Schema::setSchema(domain::Schema* schema) +void Schema::setSchema(domain::Schema* _schema) { scene.clear(); - this->schema = schema; + this->schema = _schema; if(schema != nullptr) { for(auto &instance: schema->componentInstances) { - ComponentWrapper *component = ComponentWrapper::ofComponent(instance.get()); - component->setPos(instance->position.first, instance->position.second); - scene.addItem(component); + scene.addItem(new display::ComponentGroup(instance)); } for(auto &instance: schema->busInstances) { - ComponentWrapper *bus = ComponentWrapper::ofBus(instance.get()); - bus->setPos(instance->position.first, instance->position.second); - scene.addItem(bus); + if(instance->bus.getDisplay().has_value()) { + scene.addItem(new display::BusGroup(instance)); + } } } } diff --git a/comdel/display/schema_display.h b/comdel/display/schema_display.h index 2e60997..06a4a86 100644 --- a/comdel/display/schema_display.h +++ b/comdel/display/schema_display.h @@ -20,7 +20,6 @@ private: QGraphicsScene scene; domain::Schema* schema; - }; } // namespace display diff --git a/comdel/domain/comdel_generator.cpp b/comdel/domain/comdel_generator.cpp new file mode 100644 index 0000000..92983ee --- /dev/null +++ b/comdel/domain/comdel_generator.cpp @@ -0,0 +1,273 @@ +// +// Created by bbr on 08.05.22.. +// + +#include +#include "comdel_generator.h" + +namespace domain { + +void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer) { + buffer << "@source " << librarySource << std::endl << std::endl; + + buffer << "@schema {" << std::endl; + + for(auto &componentInstance: schema->componentInstances) { + buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl; + buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl; + + for(auto &attribute: componentInstance->attributes) { + buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; + } + + buffer << "\t}" << std::endl << std::endl; + } + + for(auto &busInstance: schema->busInstances) { + buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl; + buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl; + buffer << "\t\t" << "@size " << busInstance->size << std::endl; + buffer << "\t}" << std::endl << std::endl; + } + + for(auto &conn: schema->connections) { + auto busConn = dynamic_cast(conn.get()); + if(busConn) { + buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl; + + for(auto attribute: busConn->attributes) { + buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; + } + + buffer << "\t" << "}" << std::endl; + } + auto dirConn = dynamic_cast(conn.get()); + if(dirConn) { + buffer << "\t" << "@connection (" << dirConn->instance->name << "." << dirConn->connection.getComponent().pin << ", " + << dirConn->bus->name << ", " + << dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin + << ") {" << std::endl; + + for(auto attribute: dirConn->attributes) { + buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; + } + + buffer << "\t" << "}" << std::endl; + } + } + + buffer << "}" << std::endl; +} + +std::set createImports(Schema *schema); + +std::map generateWires(Schema *schema, ostream &ostream); + + void generateSubComponents(Schema *schema, map &wires, ostream &buffer); + + void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer) { + buffer << library.getHeader() << std::endl; + + std::set imports = createImports(schema); + + for(auto& import: imports) { + buffer << "#include \"" << library.getComponentDirectory() << "\\" << import << "\"" << std::endl; + } + + buffer << "\n\n" << std::endl; + + buffer << "component System" << std::endl << "{" << std::endl; + + auto wires = generateWires(schema, buffer); + + generateSubComponents(schema, wires, buffer); + + buffer << "}"; +} + +void generateWire(std::string &name, Wire& wire, ostream &buffer); + +std::map generateWires(Schema *schema, ostream &buffer) { + std::set usedNames; + std::map usedMappings; + for(auto &bus: schema->busInstances) { + buffer << "\t//" << bus->name << std::endl; + for(auto& wire: bus->bus.getWires()) { + std::string name = wire.getName(); + if(usedNames.count(wire.getName()) > 0) { + name = bus->name + "__" + wire.getName(); + } + if(wire.isHidden()) { + name = "--" + name; + } + usedNames.insert(name); + usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name)); + + generateWire(name, wire, buffer); + } + buffer << std::endl << std::endl; + } + return usedMappings; +} + +void generateWire(std::string &name, Wire& wire, ostream &buffer) { + buffer << "\t"; + switch (wire.getType()) { + case Wire::R_WIRE: + buffer << "r_wire"; + break; + case Wire::WIRED_AND: + buffer << "wired_and"; + break; + case Wire::WIRED_OR: + buffer << "wired_or"; + break; + default: + buffer << "wire"; + } + + if(wire.getWidth() != 1) { + buffer << "<" << wire.getWidth() << ">"; + } + buffer << " " << name << ";" << std::endl; +} + +std::set createImports(Schema *schema) { + std::set importSet; + for(auto &component: schema->componentInstances) { + importSet.insert(component->component.getSource()); + } + return importSet; +} + +void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map wireNames, stringstream &buffer); + + void + generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin, + map &wireNames, + stringstream &buffer); + + void generateSubComponents(Schema *schema, map &wires, ostream &buffer) { + + buffer << "\t// components --------------------------------------------" << std::endl; + + for(auto& component: schema->componentInstances) { + buffer << "\tsubcomponent " << component->component.getName() << " " << component->name; + if(!component->attributes.empty()) { + buffer << "<"; + buffer << component->attributes[0].value.stringify(); + for(int i=1; iattributes.size(); i++) { + buffer << ", " << component->attributes[i].value.stringify(); + } + buffer << ">"; + } + + stringstream tempOutput; + + for(auto &pin: component->component.getPins()) { + if(schema->hasConnection(component->name, pin.getName())) { + auto conn = schema->getConnection(component->name, pin.getName()); + auto busConn = dynamic_cast(conn); + if(busConn != nullptr) { + for(auto wire: busConn->connection.getWires()) { + if(wire.isType(Value::ATTRIBUTE_REFERENCE)) { + auto attribute = busConn->getAttribute(wire.asReference()); + if(wire.isType(Value::WIRE_REFERENCE)) { + tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", "; + } else if(wire.isType(Value::NIL)) { + tempOutput << "*, "; + } else { + tempOutput << attribute.value.stringify() << ", "; + } + } else { + if(wire.isType(Value::WIRE_REFERENCE)) { + tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; + } else if(wire.isType(Value::NIL)) { + tempOutput << "*, "; + } else { + tempOutput << wire.stringify() << ", "; + } + } + } + } + auto dirConn = dynamic_cast(conn); + if(dirConn != nullptr) { + if(dirConn->bus->bus.getType() == Bus::AUTOMATIC) { + generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); + } else { + generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); + } + } + } else { + // if no connection exists than defaults must exist + for(auto& wire: *pin.getWires()) { + tempOutput << wire.stringify() << ", "; + } + } + } + + auto wireList = tempOutput.str(); + wireList.pop_back(); + wireList.pop_back(); // remove last COMMA(", ") + + buffer << "(" << wireList << ");" << std::endl; + } +} + +void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map &wireNames, stringstream &buffer) { + std::vector wires; + std::string selected; + std::vector defaults; + if(connection->instance->name == name && connection->connection.getComponent().pin == pin) { + wires = connection->connection.getWires(); + selected = connection->attributes[0].value.asReference(); + defaults = *connection->instance->component.getPin(pin).getWires(); + } else { + wires = *connection->connection.getSecondWires(); + selected = connection->attributes[1].value.asReference(); + defaults = *connection->secondInstance->component.getPin(pin).getWires(); + } + + for(int i=0; ibus->name + "." + connection->bus->bus.getWires()[0].getName()] << ", "; + } else { + buffer << defaults[i].stringify(); + } + } else { + buffer << wires[i].stringify() << ", "; + } + } +} + +void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map wireNames, stringstream &buffer) { + std::vector wires; + if(connection->instance->name == name && connection->connection.getComponent().pin == pin) { + wires = connection->connection.getWires(); + } else { + wires = *connection->connection.getSecondWires(); + } + for(auto& wire: wires) { + if(wire.isType(Value::ATTRIBUTE_REFERENCE)) { + auto attribute = connection->getAttribute(wire.asReference()); + if(wire.isType(Value::WIRE_REFERENCE)) { + buffer << wireNames[connection->bus->name + "." + attribute.value.asReference()] << ", "; + } else if(wire.isType(Value::NIL)) { + buffer << "*, "; + } else { + buffer << attribute.value.stringify() << ", "; + } + } else { + if(wire.isType(Value::WIRE_REFERENCE)) { + buffer << wireNames[connection->bus->name + "." + wire.asReference()] << ", "; + } else if(wire.isType(Value::NIL)) { + buffer << "*, "; + } else { + buffer << wire.stringify() << ", "; + } + } + } +} + +} // domain \ No newline at end of file diff --git a/comdel/domain/comdel_generator.h b/comdel/domain/comdel_generator.h new file mode 100644 index 0000000..170b5c1 --- /dev/null +++ b/comdel/domain/comdel_generator.h @@ -0,0 +1,16 @@ +#ifndef COMDEL_GENERATOR_H +#define COMDEL_GENERATOR_H + +#include +#include "schema.h" +#include "library.h" + +namespace domain { + +void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer); + +void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer); + +} // domain + +#endif //COMDEL_GENERATOR_H diff --git a/comdel/domain/connectioninstance.cpp b/comdel/domain/connectioninstance.cpp index 963b787..46538f1 100644 --- a/comdel/domain/connectioninstance.cpp +++ b/comdel/domain/connectioninstance.cpp @@ -7,6 +7,16 @@ ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector< : instance(instance), attributes(attributes), connection(connection) {} +InstanceAttribute ConnectionInstance::getAttribute(string attribute) { + for(auto& attr: attributes) { + if(attr.name == attribute) { + return attr; + } + } + throw std::exception(); +} + + BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector attributes, BusInstance *bus, Connection connection) : ConnectionInstance(instance, attributes, connection), bus(bus) {} diff --git a/comdel/domain/connectioninstance.h b/comdel/domain/connectioninstance.h index a04354c..6e3d7e0 100644 --- a/comdel/domain/connectioninstance.h +++ b/comdel/domain/connectioninstance.h @@ -20,6 +20,8 @@ public: std::vector attributes; ConnectionInstance(ComponentInstance *instance, std::vector attributes, Connection connection); + + InstanceAttribute getAttribute(string attribute); }; diff --git a/comdel/domain/pin.cpp b/comdel/domain/pin.cpp index e27e692..183e8b6 100644 --- a/comdel/domain/pin.cpp +++ b/comdel/domain/pin.cpp @@ -18,7 +18,7 @@ Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection conn : name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires) {} -std::string Pin::getName() { +std::string &Pin::getName() { return name; } Pin::PinType Pin::getType() { diff --git a/comdel/domain/pin.h b/comdel/domain/pin.h index 83bf785..843d7b4 100644 --- a/comdel/domain/pin.h +++ b/comdel/domain/pin.h @@ -50,7 +50,7 @@ private: public: Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional> wires); - std::string getName(); + std::string &getName(); PinType getType(); std::string getTooltip(); Display &getDisplay(); diff --git a/comdel/domain/schema.cpp b/comdel/domain/schema.cpp index bbe9037..6e475a8 100644 --- a/comdel/domain/schema.cpp +++ b/comdel/domain/schema.cpp @@ -6,4 +6,23 @@ Schema::Schema() { } +bool Schema::hasConnection(string& component, string& pin) { + return getConnection(component, pin) != nullptr; +} + +ConnectionInstance* Schema::getConnection(string& component, string& pin) { + for(auto& conn: connections) { + if(conn->instance->name == component && conn->connection.getComponent().pin == pin) { + return conn.get(); + } + auto dirConn = dynamic_cast(conn.get()); + if(dirConn != nullptr) { + if(dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) { + return dirConn; + } + } + } + return nullptr; +} + } // namespace domain diff --git a/comdel/domain/schema.h b/comdel/domain/schema.h index f8d4e61..bcdadba 100644 --- a/comdel/domain/schema.h +++ b/comdel/domain/schema.h @@ -35,6 +35,9 @@ public: } return nullptr; } + + bool hasConnection(string& component, string& pin); + ConnectionInstance* getConnection(string& component, string& pin); }; } // namespace domain diff --git a/comdel/parser/astnode.h b/comdel/parser/astnode.h index a1b41b7..3d44f63 100644 --- a/comdel/parser/astnode.h +++ b/comdel/parser/astnode.h @@ -217,7 +217,7 @@ struct WireNode: public AstNode IdentifierNode name; NumberNode size; - bool hidden; + bool hidden = false; bool hasTerminateWith; ValueNode terminateWith; diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index 523a163..bcffd85 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -273,9 +273,9 @@ INT2 wired_and, INT3 wired_and, SIZE<3>, - IACK, - BREQ, - BACK + IACK hidden, + BREQ hidden, + BACK hidden } } @bus PIOSabirnica automatic { diff --git a/mainwindow.cpp b/mainwindow.cpp index 47e8186..e0dc26b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -13,6 +13,7 @@ #include #include #include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -37,6 +38,7 @@ void MainWindow::setupUi() ui->toolBar->addAction("Load library", this, &MainWindow::onLoadLibrary); ui->toolBar->addAction("Load schema", this, &MainWindow::onLoadSchema); ui->toolBar->addAction("Save schema", this, &MainWindow::onStoreScheme); + ui->toolBar->addAction("Generate system", this, &MainWindow::onGenerateComdel); connect(ui->actionValidate, &QAction::triggered, this, &MainWindow::onValidateSchema); @@ -156,45 +158,31 @@ void MainWindow::onStoreScheme() { std::ostringstream buffer; - buffer << "@source " << this->librarySource << std::endl << std::endl; - - buffer << "@schema {" << std::endl; - - for(auto &componentInstance: schema->componentInstances) { - buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl; - buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl; - - for(auto &attribute: componentInstance->attributes) { - buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; - } - - buffer << "\t}" << std::endl << std::endl; - } - - for(auto &busInstance: schema->busInstances) { - buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl; - buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl; - buffer << "\t\t" << "@size " << busInstance->size << std::endl; - buffer << "\t}" << std::endl << std::endl; - } - - for(auto &conn: schema->connections) { - auto busConn = dynamic_cast(conn.get()); - if(busConn) { - buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl; - buffer << "\t" << "}" << std::endl; - } - } - - buffer << "}" << std::endl; - - auto value = buffer.str(); + domain::generateSchemaFile(librarySource, schema, buffer); std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary); out< validationErrors; + }; #endif // MAIN_WINDOW_H