diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ec6016..885e484 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,5 +37,5 @@ add_executable(SchemeEditor comdel/parser/comdellexer.cpp main.cpp mainwindow.ui - comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.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 comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h) + comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.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 comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h) target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) diff --git a/application.cpp b/application.cpp index 94e963b..c5f0855 100644 --- a/application.cpp +++ b/application.cpp @@ -157,7 +157,7 @@ std::vector Application::validateSchema() { std::vector Application::generateComdel(std::ostringstream &output) { auto errors = validateSchema(); - if (Application::hasErrors(errors)) { + if (!Application::hasErrors(errors)) { // as long as all validation errors are warning we continue with build domain::generate_comdel(schema, library.value(), output); } diff --git a/comdel/display/schema_display.cpp b/comdel/display/schema_display.cpp index 8f86c67..c6a12e3 100644 --- a/comdel/display/schema_display.cpp +++ b/comdel/display/schema_display.cpp @@ -2,6 +2,7 @@ #include "schema_display.h" #include "application.h" #include "attribute_dialog.h" +#include "single_automatic_dialog.h" #include #include @@ -87,27 +88,9 @@ namespace display { if (event->mimeData()->hasFormat("comdel/component")) { auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString()); - auto attributes = std::vector(); - for (auto attr: component.getAttributes()) { - domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); - if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { - if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { - auto dialog = new MemoryDialog(&attribute, schema->componentInstances); - if(dialog->exec() == QDialog::Rejected) { - // if any dialog isn't set, whole creation is rejected - event->ignore(); - return; - } - } else { - auto dialog = new AttributeDialog(&attribute); - if(dialog->exec() == QDialog::Rejected) { - // if any dialog isn't set, whole creation is rejected - event->ignore(); - return; - } - } - } - attributes.push_back(attribute); + auto attributes = populateAttributes(component.getAttributes()); + if(attributes.size() != component.getAttributes().size()) { + return; } auto currentPos = this->mapToScene(event->pos()).toPoint(); @@ -152,15 +135,18 @@ namespace display { auto busInstances = getAvailableConnectionBusses(instance, pin); for (auto &bus: busInstances) { + if(buses[bus->name] == nullptr) { + continue; + } auto rect = buses[bus->name]->boundingRect(); rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height()); if (rect.contains(endPoint)) { auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName()); if (con.has_value()) { - std::vector attributes; - for (auto attr: con->getAttributes()) { - attributes.emplace_back(attr.getName(), attr.getDefault(), attr); + auto attributes = populateAttributes(con->getAttributes()); + if(attributes.size() != con->getAttributes().size()) { + return; } auto conInstance = std::make_shared(instance, attributes, bus, *con); @@ -189,13 +175,16 @@ namespace display { auto con = library->getConnection({instance->component.getName(), pin.getName()}, {name, pinInstance.pin}); if (con.has_value()) { - auto bus = library->getBus(con->getBus()); - auto busInstance = std::make_shared(bus.getName(), bus); - schema->busInstances.push_back(busInstance); + auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0); std::vector attributes; - for (auto attr: con->getAttributes()) { - attributes.emplace_back(attr.getName(), attr.getDefault(), attr); + if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) { + attributes = populateSingleAutomaticConnection(*con); + } else { + attributes = populateAttributes(con->getAttributes()); + } + if(attributes.size() != con->getAttributes().size()) { + return; } auto conInstance = std::make_shared(instance, @@ -294,4 +283,46 @@ namespace display { return instances; } + std::vector Schema::populateAttributes(std::vector& attributes) { + std::vector instanceAttributes; + + for (auto attr: attributes) { + domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); + if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { + if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { + auto dialog = new MemoryDialog(&attribute, schema->componentInstances); + if(dialog->exec() == QDialog::Rejected) { + // if any dialog isn't set, whole creation is rejected + return {}; + } + } else { + auto dialog = new AttributeDialog(&attribute); + if(dialog->exec() == QDialog::Rejected) { + // if any dialog isn't set, whole creation is rejected + return {}; + } + } + } + instanceAttributes.push_back(attribute); + } + return instanceAttributes; + } + + std::vector Schema::populateSingleAutomaticConnection(domain::Connection connection) { + std::vector instanceAttributes; + + for (auto attr: connection.getAttributes()) { + instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr); + } + + auto dialog = new display::SingleAutomaticDialog(instanceAttributes); + if(dialog->exec() == QDialog::Rejected) { + // if dialog is rejected, whole creation is rejected + return {}; + } + + return instanceAttributes; + + } + } // namespace display diff --git a/comdel/display/schema_display.h b/comdel/display/schema_display.h index 053d954..df4bd67 100644 --- a/comdel/display/schema_display.h +++ b/comdel/display/schema_display.h @@ -73,6 +73,10 @@ namespace display { std::vector getAvailableConnectionPins(domain::ComponentInstance *instance, domain::Pin &pin); + + std::vector populateAttributes(std::vector& attributes); + + std::vector populateSingleAutomaticConnection(domain::Connection connection); }; } // namespace display diff --git a/comdel/display/single_automatic_dialog.cpp b/comdel/display/single_automatic_dialog.cpp new file mode 100644 index 0000000..5605e79 --- /dev/null +++ b/comdel/display/single_automatic_dialog.cpp @@ -0,0 +1,75 @@ +// +// Created by bbr on 05.06.22.. +// + +#include "single_automatic_dialog.h" +#include +#include +#include +#include + +namespace display { + SingleAutomaticDialog::SingleAutomaticDialog(std::vector &values): attributes(values) { + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(QString::fromStdString("Postavi poveznicu")); + + firstValue = values[0].value; + secondValue = values[1].value; + + auto *parentLayout = new QVBoxLayout(this); + auto *contentLayout = new QHBoxLayout(this); + auto *firstLayout = new QVBoxLayout(this); + auto *secondLayout = new QVBoxLayout(this); + + parentLayout->addLayout(contentLayout); + contentLayout->addLayout(firstLayout); + contentLayout->addLayout(secondLayout); + this->setLayout(parentLayout); + + setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged); + setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged); + + auto button = new QPushButton("Ažuriraj"); + connect(button, &QPushButton::clicked, this, &SingleAutomaticDialog::onUpdate); + parentLayout->addWidget(button); + } + + void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) { + + auto popup = *attribute.attribute.getPopup(); + + layout->addWidget(new QLabel(popup.getTitle().c_str())); + layout->addWidget(new QLabel(popup.getText().c_str())); + + auto *combo = new QComboBox(this); + auto enumeration = attribute.attribute.getPopup()->getEnumeration(); + for (auto entry: enumeration) { + combo->addItem(QString::fromStdString(entry.getName())); + } + + connect(combo, QOverload::of(&QComboBox::currentIndexChanged), this,handler); + layout->addWidget(combo); + + for (int i = 0; i < enumeration.size(); i++) { + if (attribute.value.equals(enumeration[i].getValue())) { + combo->setCurrentIndex(i); + break; + } + } + } + + void SingleAutomaticDialog::onFirstEnumerationChanged(int index) { + firstValue = attributes[0].attribute.getPopup()->getEnumeration()[index].getValue(); + } + + void SingleAutomaticDialog::onSecondEnumerationChanged(int index) { + secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue(); + } + + void SingleAutomaticDialog::onUpdate() { + attributes[0].value = firstValue; + attributes[1].value = secondValue; + accept(); + } + +} // display \ No newline at end of file diff --git a/comdel/display/single_automatic_dialog.h b/comdel/display/single_automatic_dialog.h new file mode 100644 index 0000000..cc05d28 --- /dev/null +++ b/comdel/display/single_automatic_dialog.h @@ -0,0 +1,35 @@ +// +// Created by bbr on 05.06.22.. +// + +#ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H +#define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H + +#include +#include +#include +#include "comdel/domain/value.h" +#include "comdel/domain/instance_attribute.h" + +namespace display { + + class SingleAutomaticDialog: public QDialog { + domain::Value firstValue; + domain::Value secondValue; + std::vector &attributes; + + public: + explicit SingleAutomaticDialog(std::vector& values); + + void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)); + + public slots: + + void onFirstEnumerationChanged(int index); + void onSecondEnumerationChanged(int index); + void onUpdate(); + }; + +} // display + +#endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H diff --git a/comdel/domain/attribute.cpp b/comdel/domain/attribute.cpp index 90ff708..d780da7 100644 --- a/comdel/domain/attribute.cpp +++ b/comdel/domain/attribute.cpp @@ -59,4 +59,8 @@ namespace domain { return popup; } + void Attribute::setPupup(std::optional popup) { + this->popup = popup; + } + } // namespace domain diff --git a/comdel/domain/attribute.h b/comdel/domain/attribute.h index 6c1daa5..f5e8968 100644 --- a/comdel/domain/attribute.h +++ b/comdel/domain/attribute.h @@ -54,7 +54,7 @@ namespace domain { void setEnumeration(std::vector enums) { enumerated = true; - enumeration = std::move(enums); + enumeration = enums; } }; @@ -71,6 +71,7 @@ namespace domain { Value getDefault(); std::optional getPopup(); + void setPupup(std::optional popup); }; } // namespace domain diff --git a/comdel/domain/component.cpp b/comdel/domain/component.cpp index e6555df..c3b898a 100644 --- a/comdel/domain/component.cpp +++ b/comdel/domain/component.cpp @@ -62,7 +62,7 @@ namespace domain { return false; } - std::vector Component::getAttributes() { + std::vector& Component::getAttributes() { return attributes; } diff --git a/comdel/domain/component.h b/comdel/domain/component.h index 5a8cbab..729b735 100644 --- a/comdel/domain/component.h +++ b/comdel/domain/component.h @@ -60,7 +60,7 @@ namespace domain { Pin getPin(std::string pin); - std::vector getAttributes(); + std::vector& getAttributes(); Attribute getAttribute(std::string attribute); diff --git a/comdel/domain/connection.cpp b/comdel/domain/connection.cpp index 732eb90..c42d09b 100644 --- a/comdel/domain/connection.cpp +++ b/comdel/domain/connection.cpp @@ -20,7 +20,7 @@ namespace domain { return bus; } - std::vector Connection::getAttributes() { + std::vector& Connection::getAttributes() { return attributes; } diff --git a/comdel/domain/connection.h b/comdel/domain/connection.h index 8e2f96c..a0a49c4 100644 --- a/comdel/domain/connection.h +++ b/comdel/domain/connection.h @@ -60,7 +60,7 @@ namespace domain { std::string getBus(); - std::vector getAttributes(); + std::vector& getAttributes(); std::vector getWires(); diff --git a/comdel/domain/schema_creator.cpp b/comdel/domain/schema_creator.cpp index 54e0bde..145511b 100644 --- a/comdel/domain/schema_creator.cpp +++ b/comdel/domain/schema_creator.cpp @@ -438,7 +438,9 @@ namespace domain { } else if (attributes[0].getDefault().getType() != Value::STRING) { errors.emplace_back(node.attributes[0].span, "@attribute must be of type string"); } else { - attributes[0].getPopup()->setEnumeration(createWireEnumeration(firstWires)); + domain::Popup popup = *attributes[0].getPopup(); + popup.setEnumeration(createWireEnumeration(firstWires)); + attributes[0].setPupup(popup); } if (!attributes[1].getPopup().has_value()) { @@ -446,7 +448,9 @@ namespace domain { } else if (attributes[1].getDefault().getType() != Value::STRING) { errors.emplace_back(node.attributes[1].span, "@attribute must be of type string"); } else { - attributes[1].getPopup()->setEnumeration(createWireEnumeration(secondWires)); + domain::Popup popup = *attributes[1].getPopup(); + popup.setEnumeration(createWireEnumeration(secondWires)); + attributes[1].setPupup(popup); } } @@ -935,12 +939,22 @@ namespace domain { auto attribute = connection->getAttribute(attr.name.value); auto value = toType(attr.value); + bool valueFound = false; + + // all connection attributes must be of type enumeration for (auto &en: attribute.getPopup()->getEnumeration()) { - if (en.getValue().asReference() == value.asReference()) { - value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); + if (en.getValue().equals(value)) { + valueFound = true; + break; + } else if(value.isType(Value::UNDEFINED)) { + if(en.getValue().isType(Value::WIRE_REFERENCE) && en.getValue().asReference() == value.asReference()) { + value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); + valueFound = true; + break; + } } } - if (value.isType(Value::UNDEFINED)) { + if (!valueFound) { errors.emplace_back(attr.span, "invalid value"); } diff --git a/comdel/parser/comdel_parser.cpp b/comdel/parser/comdel_parser.cpp index fb970ad..145ae44 100644 --- a/comdel/parser/comdel_parser.cpp +++ b/comdel/parser/comdel_parser.cpp @@ -50,12 +50,11 @@ bool ComdelParser::consume(TokenType tokenType) { do{}while(0) void ComdelParser::bump() { - if (tokens[position].type == TokenType::END_OF_FILE) { - ATLAS_ASSERT_FAIL("Internal parser error, called bump after EOF"); + if (tokens[position].type != TokenType::END_OF_FILE) { + ++position; } else { - tokens[++position]; + ATLAS_ASSERT_FAIL("Internal parser error, called bump after EOF"); } - expectedTokens.clear(); } @@ -1348,7 +1347,7 @@ PResult ComdelParser::parseConnectionWire() { bump(); return spanner(ValueNode::ofNull()); } else if (check(TokenType::STRING)) { - return spanner(ValueNode::ofString(parseString()->value)); + return spanner(ValueNode::ofString(parseString()->asString())); } else if (check(TokenType::IDENTIFIER)) { return spanner(ValueNode::ofIdentifier(parseIdentifier()->value)); } else { diff --git a/examples/simplified FRISC model/comdel.system b/examples/simplified FRISC model/comdel.system index 01d2561..e69de29 100644 --- a/examples/simplified FRISC model/comdel.system +++ b/examples/simplified FRISC model/comdel.system @@ -1,54 +0,0 @@ -// Version 0.0.1 -#include "libraries\frisc\vjezba1\FRISC.cdl" -#include "libraries\frisc\vjezba1\memory.cdl" - - - -component System -{ - clock 100MHz; - //bus - wire<32> ADR; - wire<32> DATA; - wire READ; - wire WRITE; - wired_and WAIT; - wired_and INT0; - wired_and INT1; - wired_and INT2; - wired_and INT3; - wire<3> SIZE; - wire --IACK; - wire --BREQ; - wire --BACK; - - - // components -------------------------------------------- - subcomponent Memorija mem(ADR, DATA, READ, WRITE, SIZE, WAIT, 94534054858378, 0, null, null); - subcomponent FRISC procesor_002(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); - subcomponent FRISC procesor_001(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); - subcomponent FRISC procesor_000(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); - subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); - - display { - component { x: 0; y: 0; ref: "procesor_002"; } - component { x: 0; y: 250; ref: "mem"; } - component { x: -89; y: 74; ref: "procesor_001"; } - component { x: -175; y: 195; ref: "procesor_000"; } - component { x: -195; y: 63; ref: "procesor"; } - - // bus bus - - rectangle { - x: 0; y: 200; - w: 100; h: 20; - } - - - line {x1:50; y1:116; x2:50; y2:210;} - line {x1:50; y1:234; x2:50; y2:210;} - line {x1:-39; y1:190; x2:50; y2:210;} - line {x1:-145; y1:179; x2:50; y2:210;} - line {x1:-125; y1:311; x2:50; y2:210;} - } -} \ No newline at end of file diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index 4561efd..51df581 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -8,13 +8,12 @@ @address pomocniAS(0xFFFF0000,0xFFFFFFFF) @messages { - Ok: "OK"; - Yes: "Da"; - No: "Ne"; - Cancel: "Otkaži"; + ok: "OK"; + yes: "Da"; + no: "Ne"; + cancel: "Odustani"; noneBusLine: "nespojen"; noneValue: "nema vrijednosti"; - generalPinNotConnected: "Opći pin nije spojen niti na jednu sabirnicu"; } @component FRISC processor { @@ -229,7 +228,7 @@ @title "Početna adresa DMA-kontrolera" @text "Zadajte početnu adresu DMA-kontrolera" @rule { - if(contains_address(glavniAS, pocetnaAdresa)) { + if(!contains_address(glavniAS, pocetnaAdresa)) { error("Početna adresa memorije je izvan 32 bitnog adresnog prostora") } } @@ -239,7 +238,7 @@ } } @rule { - if(unique(glavniAS, pocetnaAdresa, 32)) { + if(!unique(glavniAS, pocetnaAdresa, 32)) { error("Adrese memorije nisu jedinstvene u adresnom prostoru (preklapaju se s nekom drugom komponentom)") } } @@ -344,7 +343,7 @@ } } -@bus directRam automatic { +@bus directRam singleAutomatic { @instanceName directRam @wires { INT @@ -381,6 +380,19 @@ } @connection (FRISC.memDirect, directRam, Memorija.memDirect) { - @wires{INT} - @wires{INT} + @attribute procConn string default "INT" { + @popup automatic { + @title "Frisc INT" + @text "Processor interupt 1" + } + } + @attribute memConn string default "INT" { + @popup automatic { + @title "Mem INT" + @text "Memory interupt 1" + } + } + + @wires{"INT", null, 1, "INT2"} + @wires{"INT", null, 1, "INT2"} } \ No newline at end of file diff --git a/examples/simplified FRISC model/schema3.csl b/examples/simplified FRISC model/schema3.csl index 28ba8ba..400c0fc 100644 --- a/examples/simplified FRISC model/schema3.csl +++ b/examples/simplified FRISC model/schema3.csl @@ -2,13 +2,28 @@ @schema { @instance procesor FRISC { - @position (-112, -89) - @attribute _memory memorija2 + @position (-464, -314) + @attribute _memory null } - @instance procesor FRISC { - @position (112, -89) - @attribute _memory null - } + @instance dma DMA { + @position (-269, 46) + @attribute pocetnaAdresa 0 + } + @instance glavnaSabirnica glavnaSabirnica { + @position (-579, -160) + @size 100 + } + + @instance PIOSabirnica PIOSabirnica { + @position (0, 0) + @size 0 + } + + @connection (dma.glavniPin, glavnaSabirnica) { + @attribute interupt INT2 + } + @connection (dma.glavniPin, PIOSabirnica, procesor.glavniPin) { + } } diff --git a/mainwindow.cpp b/mainwindow.cpp index 14e1f3b..fba4ca6 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -135,7 +135,7 @@ void MainWindow::onGenerateComdel() { formatErrors(validationErrors, buff); log->appendPlainText(QString::fromStdString(buff.str())); - if(Application::hasErrors(validationErrors)) { + if(!Application::hasErrors(validationErrors)) { std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary); out<