From 59b19062ffa061361879c83ffa10224c3dccd541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Sun, 15 May 2022 23:55:03 +0200 Subject: [PATCH] Added support for memory attribute --- comdel/display/attribute_dialog.cpp | 6 + comdel/display/attribute_dialog.h | 72 ++++++++++- comdel/display/component_display.cpp | 10 +- comdel/domain/comdel_generator.cpp | 134 ++++++++++++-------- comdel/domain/component.cpp | 8 +- comdel/domain/schemacreator.cpp | 35 ++++- comdel/domain/schemacreator.h | 6 +- comdel/domain/value.cpp | 32 ++++- comdel/domain/value.h | 15 +++ comdel/parser/astnode.cpp | 11 +- comdel/parser/astnode.h | 6 +- comdel/parser/comdelparser.cpp | 14 +- examples/simplified FRISC model/schema.csl | 1 + examples/simplified FRISC model/schema2.csl | 13 +- 14 files changed, 293 insertions(+), 70 deletions(-) diff --git a/comdel/display/attribute_dialog.cpp b/comdel/display/attribute_dialog.cpp index 71d86e1..684a8ae 100644 --- a/comdel/display/attribute_dialog.cpp +++ b/comdel/display/attribute_dialog.cpp @@ -57,4 +57,10 @@ void AttributeDialog::onUpdate() { } + + void MemoryDialog::onUpdate() { + attributeValue->value = value; + accept(); + } + } \ No newline at end of file diff --git a/comdel/display/attribute_dialog.h b/comdel/display/attribute_dialog.h index dcbab51..c086511 100644 --- a/comdel/display/attribute_dialog.h +++ b/comdel/display/attribute_dialog.h @@ -64,7 +64,7 @@ public: auto* combo = new QComboBox(this); auto enumeration = attribute->attribute.getPopup()->getEnumeration(); for(auto entry: enumeration) { - combo->addItem(QString::fromStdString(entry.getName()), QVariant::fromValue(NULL)); + combo->addItem(QString::fromStdString(entry.getName())); } connect(combo, QOverload::of(&QComboBox::currentIndexChanged), this, &AttributeDialog::onEnumerationChanged); @@ -144,6 +144,76 @@ public slots: }; + + class MemoryDialog: public QDialog { + domain::Value value; + + domain::InstanceAttribute* attributeValue; + std::vector memoryInstances; + + public: + MemoryDialog(domain::InstanceAttribute *attribute, std::vector> instances) { + memoryInstances = std::vector(); + + setAttribute(Qt::WA_DeleteOnClose); + + attributeValue = attribute; + + this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName())); + + for(auto& instance: instances) { + if(instance->component.getType() == domain::Component::MEMORY) { + memoryInstances.push_back(instance->name); + } + } + + auto layout = new QVBoxLayout(this); + this->setLayout(layout); + auto popup = *attribute->attribute.getPopup(); + + layout->addWidget(new QLabel(popup.getTitle().c_str())); + layout->addWidget(new QLabel(popup.getText().c_str())); + + value = attribute->value; + + auto* combo = new QComboBox(this); + for(auto& entry: memoryInstances) { + combo->addItem(QString::fromStdString(entry)); + } + combo->addItem("null"); + + connect(combo, QOverload::of(&QComboBox::currentIndexChanged), this, &MemoryDialog::onMemoryChanged); + layout->addWidget(combo); + + combo->setCurrentIndex(memoryInstances.size()); + for(int i=0; ivalue.asMemoryReference().has_value() && attributeValue->value.asMemoryReference() == memoryInstances[i]) { + combo->setCurrentIndex(i); + break; + } + } + + auto button = new QPushButton("Ažuriraj"); + connect(button, &QPushButton::clicked, this, &MemoryDialog::onUpdate); + + layout->addWidget(button); + } + + public slots: + + void onMemoryChanged(int index) { + if(index == memoryInstances.size()) { + value = domain::Value::fromMemoryReference(std::nullopt); + } else { + value = domain::Value::fromMemoryReference(memoryInstances[index]); + } + } + + void onUpdate(); + + }; + + class ErrorDialog: public QDialog { public: diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index 6fb3447..14cd4ae 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -1,6 +1,7 @@ #include "component_display.h" #include "attribute_dialog.h" #include "name_dialog.h" +#include "mainwindow.h" #include #include @@ -22,8 +23,13 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name), [attr]() { - auto dialog = new AttributeDialog(attr); - dialog->exec(); + if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { + auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances); + dialog->exec(); + } else { + auto dialog = new AttributeDialog(attr); + dialog->exec(); + } }); action->setEnabled(enabled); } diff --git a/comdel/domain/comdel_generator.cpp b/comdel/domain/comdel_generator.cpp index 01fe21b..232611c 100644 --- a/comdel/domain/comdel_generator.cpp +++ b/comdel/domain/comdel_generator.cpp @@ -175,71 +175,105 @@ void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, map &wireNames, stringstream &buffer); -void generateSubComponents(Schema *schema, map &wires, ostream &buffer) { + void generateComponent(Schema *schema, map &wires, ostream &buffer, + shared_ptr &component); + + 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 << ">"; + if(component->component.getType() == Component::MEMORY) { + generateComponent(schema, wires, buffer, component); } + } + for(auto& component: schema->componentInstances) { + if(component->component.getType() != Component::MEMORY) { + generateComponent(schema, wires, buffer, component); + } + } +} - stringstream tempOutput; +void generateComponent(Schema *schema, map &wires, ostream &buffer, + shared_ptr &component) { + buffer << "\tsubcomponent " << component->component.getName() << " " << component->name; - 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() << ", "; - } + std::optional memory; + + std::vector attributes; + for(auto& attr: component->attributes) { + if(attr.name != "_memory") { + attributes.push_back(attr); + } else if(attr.name == "_memory" && attr.value.asMemoryReference().has_value()) { + memory = attr; + } + } + + if(!attributes.empty()) { + buffer << "<"; + buffer << attributes[0].value.stringify(); + for(int i=1; i"; + } + + 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 { - if(wire.isType(Value::WIRE_REFERENCE)) { - tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; - } else if(wire.isType(Value::NIL)) { - tempOutput << "*, "; - } else { - tempOutput << wire.stringify() << ", "; - } + 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 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; } + + auto wireList = tempOutput.str(); + wireList.pop_back(); + wireList.pop_back(); // remove last COMMA(", ") + + buffer << "(" << wireList << ")"; + + if(memory.has_value()) { + buffer << " uses " << *memory->value.asMemoryReference(); + } + + buffer << ";" << std::endl; + } void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map &wireNames, stringstream &buffer) { diff --git a/comdel/domain/component.cpp b/comdel/domain/component.cpp index 83cd5ec..f671b9d 100644 --- a/comdel/domain/component.cpp +++ b/comdel/domain/component.cpp @@ -67,7 +67,13 @@ Attribute Component::getAttribute(std::string attribute) { } bool Component::hasAttribute(std::string name, Value::ValueType type) { for(uint i=0; i SchemaCreator::loadComponent(ComponentNode node) attributes.push_back(*attribute); } } + if(type == Component::PROCESSOR) { + attributes.push_back(*createMemoryAttribute()); + } context[context.size() -1 ].attributes = attributes; @@ -885,12 +900,20 @@ shared_ptr SchemaCreator::loadComponentInstance(InstanceNode for(auto& attr: instance.attributes) { if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) { auto attribute = component.getAttribute(attr.name.value); - attributes.emplace_back(attribute.getName(), toType(attr.value), attribute); + attributes.emplace_back(attribute.getName(), toType(attr.value, attribute.getDefault().getType()), attribute); } else { errors.emplace_back(SourceError(attr.name.span, "unknown attribute")); } } + if(attributes.size() < component.getAttributes().size()) { + for(auto& attr: component.getAttributes()) { + if(std::count_if(attributes.begin(), attributes.end(), [&attr](InstanceAttribute& attribute){ return attr.getName() == attribute.name; }) == 0) { + errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getName() + "'")); + } + } + } + return std::make_shared(name, attributes, position, component); } std::shared_ptr SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) { @@ -918,4 +941,12 @@ vector SchemaCreator::createWireEnumeration(vector wireValue return wires; } +std::optional SchemaCreator::createMemoryAttribute() { + return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup()); +} + + std::optional SchemaCreator::createMemoryPopup() { + return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector{}, vector{}); + } + } // namespace domain diff --git a/comdel/domain/schemacreator.h b/comdel/domain/schemacreator.h index a0a8af2..9479b4b 100644 --- a/comdel/domain/schemacreator.h +++ b/comdel/domain/schemacreator.h @@ -79,6 +79,8 @@ class SchemaCreator std::shared_ptr loadComponentInstance(InstanceNode instance, Library &library); std::shared_ptr loadBusInstance(InstanceNode instance, Library &library); + std::optional createMemoryAttribute(); + std::optional getBus(std::string name) { for(auto &bus: buses) { if(bus.getName() == name) { @@ -140,7 +142,9 @@ public: Schema* loadSchema(SchemaNode node, Library &library); - vector createWireEnumeration(vector vector1); + vector createWireEnumeration(vector vector1); + + std::optional createMemoryPopup(); }; } // namespace domain diff --git a/comdel/domain/value.cpp b/comdel/domain/value.cpp index 08e5d37..54ba553 100644 --- a/comdel/domain/value.cpp +++ b/comdel/domain/value.cpp @@ -68,6 +68,16 @@ std::string Value::asReference() { throw std::exception(); } + +std::optional Value::asMemoryReference() { + return memoryReference; +} + + domain::ComponentInstance *Value::asMemory() { + return memory; + } + + void Value::setInt(long long value) { if(isType(Value::INT)) { this->intValue = value; @@ -124,11 +134,11 @@ Value Value::fromReference(std::string value, Value::ValueType type) { val.reference = value; return val; } + Value Value::ofType(Value::ValueType type) { Value val; val.type = type; return val; - } Value Value::fromNull() { @@ -151,9 +161,29 @@ std::string Value::stringify() { case ADDRESS_SPACE_REFERENCE: case ATTRIBUTE_REFERENCE: return reference; + case MEMORY_REFERENCE: + if(memoryReference->empty()) { + return "null"; + } else { + return memoryReference.value(); + } default: throw std::exception(); } } + Value Value::fromMemoryReference(std::optional value) { + Value val; + val.type = MEMORY_REFERENCE; + val.memoryReference = value; + return val; + } + + Value Value::fromMemory(domain::ComponentInstance *memory) { + Value val; + val.type = MEMORY; + val.memory = memory; + return val; + } + } // namespace domain diff --git a/comdel/domain/value.h b/comdel/domain/value.h index d2c1ff4..3af0497 100644 --- a/comdel/domain/value.h +++ b/comdel/domain/value.h @@ -9,6 +9,8 @@ namespace domain { + class ComponentInstance; + class Value { public: @@ -19,6 +21,8 @@ public: ADDRESS_SPACE, ADDRESS_SPACE_REFERENCE, ATTRIBUTE_REFERENCE, + MEMORY_REFERENCE, + MEMORY, WIRE_REFERENCE, NIL, UNDEFINED, @@ -30,6 +34,9 @@ private: bool boolValue; std::optional addressSpace; std::string reference; + domain::ComponentInstance *memory; + + std::optional memoryReference; ValueType type; @@ -53,6 +60,10 @@ public: case ATTRIBUTE_REFERENCE: case ADDRESS_SPACE_REFERENCE: return value.asReference() == reference; + case MEMORY_REFERENCE: + return value.asMemoryReference() == memoryReference; + case MEMORY: + return value.asMemory() == memory; case BOOL: return value.asBool() == boolValue; default: @@ -71,6 +82,8 @@ public: std::string asString(); bool asBool(); std::string asReference(); + std::optional asMemoryReference(); + domain::ComponentInstance* asMemory(); AddressSpace asAddressSpace(); void setInt(long long intValue); @@ -87,6 +100,8 @@ public: static Value fromAddressSpace(AddressSpace addressSpace); static Value fromReference(std::string value, ValueType type); static Value ofType(ValueType type); + static Value fromMemoryReference(std::optional memoryReference); + static Value fromMemory(domain::ComponentInstance *memory); }; } // namespace domain diff --git a/comdel/parser/astnode.cpp b/comdel/parser/astnode.cpp index bea8bd7..a833331 100644 --- a/comdel/parser/astnode.cpp +++ b/comdel/parser/astnode.cpp @@ -94,9 +94,16 @@ ValueNode ValueNode::ofNull() { return value; } -ValueNode ValueNode::ofWire(std::string _value) { +ValueNode ValueNode::ofWire(std::optional _value) { ValueNode value; value.type = EnumNode(WIRE); - value.identifierValue = std::optional(_value); + value.identifierValue = _value; + return value; +} + +ValueNode ValueNode::ofMemory(std::optional _value) { + ValueNode value; + value.type = EnumNode(MEMORY); + value.identifierValue = _value; return value; } diff --git a/comdel/parser/astnode.h b/comdel/parser/astnode.h index 3d44f63..83e3222 100644 --- a/comdel/parser/astnode.h +++ b/comdel/parser/astnode.h @@ -77,6 +77,7 @@ public: BOOL, WIRE, IDENTIFIER, + MEMORY, NIL, }; @@ -88,7 +89,7 @@ private: std::optional identifierValue; public: - ValueNode() = default;; + ValueNode() = default; ValueType getType() { return type.value; @@ -104,8 +105,9 @@ public: static ValueNode ofInt(long long _value); static ValueNode ofString(std::string _value); static ValueNode ofIdentifier(std::string _value); + static ValueNode ofMemory(std::optional _value); static ValueNode ofNull(); - static ValueNode ofWire(std::string _value); + static ValueNode ofWire(std::optional _value); }; struct ConditionNode diff --git a/comdel/parser/comdelparser.cpp b/comdel/parser/comdelparser.cpp index 3bb85e5..c75d5d5 100644 --- a/comdel/parser/comdelparser.cpp +++ b/comdel/parser/comdelparser.cpp @@ -438,7 +438,7 @@ PResult ComdelParser::parseComponent() ASSIGN_OR_RETURN_IF_ERR(component.name, parseIdentifier()); - auto type = parseComponentType(); + ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType()); RETURN_IF_NOT_TOKEN(TokenType::LBRACE); @@ -853,13 +853,23 @@ PResult ComdelParser::parseAttribute() { } else { return unexpected(); } + } else if(attribute.type == ValueNode::MEMORY) { + if(check(TokenType::IDENTIFIER)) { + auto identifier = parseIdentifier(); + attribute.defaultValue = ValueNode::ofMemory(identifier->value); + } else if(check(TokenType::NIL)) { + bump(); + attribute.defaultValue = ValueNode::ofMemory(std::nullopt); + } else { + return unexpected(); + } } else if(attribute.type == ValueNode::WIRE) { if(check(TokenType::IDENTIFIER)) { auto identifier = parseIdentifier(); attribute.defaultValue = ValueNode::ofWire(identifier->value); } else if(check(TokenType::NIL)) { bump(); - attribute.defaultValue = ValueNode::ofNull(); + attribute.defaultValue = ValueNode::ofWire(std::nullopt); } else { return unexpected(); } diff --git a/examples/simplified FRISC model/schema.csl b/examples/simplified FRISC model/schema.csl index 3d1e795..5f286ac 100644 --- a/examples/simplified FRISC model/schema.csl +++ b/examples/simplified FRISC model/schema.csl @@ -3,6 +3,7 @@ @schema { @instance proc FRISC { @position (0, 0) + @attribute _memory null } @instance mem Memorija { diff --git a/examples/simplified FRISC model/schema2.csl b/examples/simplified FRISC model/schema2.csl index 849d2b4..520b98e 100644 --- a/examples/simplified FRISC model/schema2.csl +++ b/examples/simplified FRISC model/schema2.csl @@ -1,11 +1,12 @@ @source "frisc_library.csl" @schema { - @instance procesor2 FRISC { + @instance proc FRISC { @position (0, 0) + @attribute _memory mem } - @instance memorija2 Memorija { + @instance mem Memorija { @position (0, 250) @attribute sinkroniziran false @attribute brzina 1 @@ -14,7 +15,7 @@ @attribute pocetnaAdresa 1023 } - @instance bus2 glavnaSabirnica { + @instance bus glavnaSabirnica { @position (0, 200) @size 100 } @@ -24,11 +25,11 @@ @size 0 } - @connection (procesor2.glavniPin, bus2) { + @connection (proc.glavniPin, bus) { } - @connection (memorija2.glavniPin, bus2) { + @connection (mem.glavniPin, bus) { } - @connection (procesor2.glavniPin, testBus, memorija2.glavniPin) { + @connection (proc.glavniPin, testBus, mem.glavniPin) { @attribute dmaPoveznica "READY" @attribute mmaPoveznica "PIO_DATA" }