diff --git a/comdel/domain/comdelvalidator.cpp b/comdel/domain/comdelvalidator.cpp index da9736a..7e749e4 100644 --- a/comdel/domain/comdelvalidator.cpp +++ b/comdel/domain/comdelvalidator.cpp @@ -1,4 +1,5 @@ #include "comdelvalidator.h" +#include "library.h" namespace domain { @@ -15,6 +16,78 @@ std::vector ComdelValidator::validateSchema(Schema &schema, Val return errors; } + std::vector ComdelValidator::validateInstanceCount(Schema& schema, Library& library, ValidationContext context) { + std::vector errors; + + // validate instance count + std::map instanceMap; + for(auto& inst: schema.componentInstances) { + instanceMap[inst->component.getName()]++; + } + + for(auto comp: library.getComponents()) { + int count = instanceMap[comp.getName()]; + + context.attributes["componentName"] = Value::fromString(comp.getName()); + context.attributes["min"] = Value::fromInt(comp.getCount().first); + context.attributes["max"] = Value::fromInt(comp.getCount().second); + context.attributes["count"] = Value::fromInt(count); + + if(count < comp.getCount().first) { + auto message = populateMessage("Not enough instances of component '{componentName}' required at least {min}, found {count}", context); + errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message}); + } else if(count > comp.getCount().second) { + auto message = populateMessage("To many instances of component '{componentName}' allow at most {max}, found {count}", context); + errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message}); + } + } + + + // validate bus instance count + std::map busInstanceMap; + for(auto& inst: schema.busInstances) { + busInstanceMap[inst->bus.getName()]++; + } + + for(auto bus: library.getBuses()) { + int count = busInstanceMap[bus.getName()]; + + context.attributes["busName"] = Value::fromString(bus.getName()); + context.attributes["min"] = Value::fromInt(bus.getCount().first); + context.attributes["max"] = Value::fromInt(bus.getCount().second); + context.attributes["count"] = Value::fromInt(count); + + if(count < bus.getCount().first) { + auto message = populateMessage("Not enough instances of bus '{busName}' required at least {min}, found {count}", context); + errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message}); + } else if(count > bus.getCount().second) { + auto message = populateMessage("To many instances of bus '{busName}' allow at most {max}, found {count}", context); + errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message}); + } + } + + return errors; + } + + std::vector ComdelValidator::validatePinConnections(Schema &schema, Library &library, ValidationContext context) { + std::vector errors; + + for(auto& inst: schema.componentInstances) { + for(auto& pin: inst->component.getPins()) { + if(pin.getConnection().getType() == PinConnection::REQUIRED) { + if(!connectionExists(schema, inst, pin)) { + context.instance = inst.get(); + context.attributes["instanceName"] = Value::fromString(inst->name); + auto message = populateMessage(pin.getConnection().getMessage(), context); + errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message}); + } + } + } + } + + return errors; + } + std::vector ComdelValidator::validateComponent(ComponentInstance* instance, ValidationContext context) { std::vector errors; @@ -89,4 +162,26 @@ string ComdelValidator::replacePlaceholder(string source, string key, Value valu return source; } + bool ComdelValidator::connectionExists(Schema &schema, shared_ptr &component, Pin &pin) { + for(auto conn: schema.connections) { + auto busConnection = dynamic_cast(conn.get()); + if(busConnection != nullptr) { + if(busConnection->instance->name == component->name && busConnection->connection.getComponent().pin == pin.getName()) { + return true; + } + } + + auto directConnection = dynamic_cast(conn.get()); + if(directConnection != nullptr) { + if(directConnection->instance->name == component->name && busConnection->connection.getComponent().pin == pin.getName()) { + return true; + } + if(directConnection->secondInstance->name == component->name && busConnection->connection.getSecondComponent()->pin == pin.getName()) { + return true; + } + } + } + return false; + } + } \ No newline at end of file diff --git a/comdel/domain/comdelvalidator.h b/comdel/domain/comdelvalidator.h index 387b478..f8c608b 100644 --- a/comdel/domain/comdelvalidator.h +++ b/comdel/domain/comdelvalidator.h @@ -3,6 +3,7 @@ #include "instance.h" #include "schema.h" +#include "library.h" namespace domain { @@ -29,6 +30,9 @@ public: std::vector validateAttribute(InstanceAttribute *attribute, ValidationContext context); std::optional validateRule(Rule rule, ValidationContext context); + std::vector validateInstanceCount(Schema &schema, Library& library, ValidationContext context); + std::vector validatePinConnections(Schema &schema, Library& library, ValidationContext context); + ComdelValidator(std::vector validators) { for(auto* validator: validators) { validator->clear(); @@ -42,6 +46,8 @@ private: std::string populateMessage(string message, ValidationContext context); string replacePlaceholder(string message, const string name, Value value); + + bool connectionExists(Schema &schema, shared_ptr &component, Pin &pin); }; } diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index 7d15539..a4d7075 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -51,22 +51,14 @@ x: 0; y:0; w:100; h:100; } } - @pin glavniPin inOut { + @pin glavniPin in { @tooltip "pin za spajanje na glavnu sabirnicu" @connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu") @display { - /* - pin { - x: 100; y: 50; - fillColor: white; - lineColor: red; - fillColorConnected: white; - lineColorConnected: black; - side: left; - size: 20; - }*/ pin { x: 42; y: 100; w: 16; h:16; + type: "in"; + orientation: "bottom"; } } } @@ -183,7 +175,9 @@ } */ pin { - x: 42; y: -16; w: 16; h: 16; + x: 42; y: -16; w: 16; h:16; + type: "out"; + orientation: "top"; } } } @@ -192,7 +186,7 @@ @component DMA { @instanceName "dma" @tooltip "DMA-kontroler" - @count (1,1000) + @count (0,1000) @source "dma.cdl" @attribute pocetnaAdresa int default 0 { @@ -303,20 +297,13 @@ } } @bus PIOSabirnica automatic { + @count (0, 20) @wires { PIO_DATA<8>, READY, STROBE } } -@bus Test singleAutomatic { - @tooltip "sabirnica za spajanje FRISC a s memorijama i UI/jedinicama" - @count (1,1) - - @wires { - CONNECTOR, - } -} @connection (FRISC.glavniPin, glavnaSabirnica) { @wires{ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, IACK, 1, null} @@ -344,23 +331,4 @@ @connection (DMA.glavniPin, PIOSabirnica, FRISC.glavniPin) { @wires{PIO_DATA, READY, STROBE} @wires{PIO_DATA, READY, STROBE} -} - -@connection (FRISC.glavniPin, Test, Memorija.glavniPin) { - @wires{null, "READY", null} - @wires{"PIO_DATA", null, null} - - @attribute dmaPoveznica string default "" { - @popup automatic { - @title "Spoji DMA kraj" - @text "Odaberite poveznicu za dma kraja" - } - } - - @attribute mmaPoveznica string default "" { - @popup automatic { - @title "Spoji MMA kraj" - @text "Odaberite poveznicu za mma kraja" - } - } } \ No newline at end of file diff --git a/examples/simplified FRISC model/schema.csl b/examples/simplified FRISC model/schema.csl index 5f286ac..3bed09f 100644 --- a/examples/simplified FRISC model/schema.csl +++ b/examples/simplified FRISC model/schema.csl @@ -1,33 +1,27 @@ @source "frisc_library.csl" @schema { - @instance proc FRISC { - @position (0, 0) - @attribute _memory null - } + @instance proc FRISC { + @position (0, 0) + @attribute _memory null + } - @instance mem Memorija { - @position (0, 250) - @attribute sinkroniziran false - @attribute brzina 1 - @attribute kapacitet 1024 - @attribute size 8 - @attribute pocetnaAdresa 1023 - } + @instance mem Memorija { + @position (0, 250) + @attribute sinkroniziran false + @attribute brzina 1 + @attribute kapacitet 1024 + @attribute size 8 + @attribute pocetnaAdresa 1024 + } - @instance bus glavnaSabirnica { - @position (0, 200) - @size 100 - } + @instance bus glavnaSabirnica { + @position (0, 200) + @size 100 + } - @instance testBus Test {} - - @connection (proc.glavniPin, bus) {} - - @connection (mem.glavniPin, bus) {} - - @connection (proc.glavniPin, testBus, mem.glavniPin) { - @attribute dmaPoveznica "READY" - @attribute mmaPoveznica "PIO_DATA" - } -} \ No newline at end of file + @connection (proc.glavniPin, bus) { + } + @connection (mem.glavniPin, bus) { + } +} diff --git a/examples/simplified FRISC model/schema2.csl b/examples/simplified FRISC model/schema2.csl index 520b98e..9f26b51 100644 --- a/examples/simplified FRISC model/schema2.csl +++ b/examples/simplified FRISC model/schema2.csl @@ -3,7 +3,7 @@ @schema { @instance proc FRISC { @position (0, 0) - @attribute _memory mem + @attribute _memory null } @instance mem Memorija { @@ -12,7 +12,7 @@ @attribute brzina 1 @attribute kapacitet 1024 @attribute size 8 - @attribute pocetnaAdresa 1023 + @attribute pocetnaAdresa 1024 } @instance bus glavnaSabirnica { @@ -20,17 +20,6 @@ @size 100 } - @instance testBus Test { - @position (0, 200) - @size 0 - } - - @connection (proc.glavniPin, bus) { - } @connection (mem.glavniPin, bus) { } - @connection (proc.glavniPin, testBus, mem.glavniPin) { - @attribute dmaPoveznica "READY" - @attribute mmaPoveznica "PIO_DATA" - } } diff --git a/mainwindow.cpp b/mainwindow.cpp index e3a7b80..33cb6f9 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -209,6 +209,12 @@ void MainWindow::onValidateSchema(bool /*toggled*/) { } auto errors = validator.validateSchema(*schema, context); + auto countValidation = validator.validateInstanceCount(*schema, *library, context); + errors.insert(errors.end(), countValidation.begin(), countValidation.end()); + + auto pinValidation = validator.validatePinConnections(*schema, *library, context); + errors.insert(errors.end(), pinValidation.begin(), pinValidation.end()); + errors.erase(std::remove_if( errors.begin(), errors.end(), [](const domain::ValidationError& error) { return error.type == domain::Action::WARNING;}), errors.end());