diff --git a/comdel/domain/attribute.h b/comdel/domain/attribute.h index 8fc3256..f00b15a 100644 --- a/comdel/domain/attribute.h +++ b/comdel/domain/attribute.h @@ -1,6 +1,7 @@ #ifndef DOMAIN_ATTRIBUTE_H #define DOMAIN_ATTRIBUTE_H +#include #include #include "rule.h" @@ -45,6 +46,11 @@ public: bool isEnumerated(); std::vector &getEnumeration(); + void setEnumeration(std::vector enums) { + enumerated = true; + enumeration = std::move(enums); + } + }; class Attribute diff --git a/comdel/domain/bus.h b/comdel/domain/bus.h index d422243..dbaab10 100644 --- a/comdel/domain/bus.h +++ b/comdel/domain/bus.h @@ -47,7 +47,7 @@ public: enum BusType { AUTOMATIC, REGULAR, - AUTOMATIC_SINGLE + SINGLE_AUTOMATIC }; private: std::string name; diff --git a/comdel/domain/pin.h b/comdel/domain/pin.h index 2f86449..83bf785 100644 --- a/comdel/domain/pin.h +++ b/comdel/domain/pin.h @@ -14,8 +14,8 @@ class PinConnection { public: enum ConnectionType { - CHECK_ONLY, - AUTOMATICALLY + REQUIRED, + OPTIONAL }; private: diff --git a/comdel/domain/schemacreator.cpp b/comdel/domain/schemacreator.cpp index 7bef32d..271501d 100644 --- a/comdel/domain/schemacreator.cpp +++ b/comdel/domain/schemacreator.cpp @@ -69,6 +69,8 @@ Value toType(ValueNode node) { Bus::BusType toType(BusNode::BusType type) { if(type == BusNode::AUTOMATIC) { return Bus::AUTOMATIC; + } else if(type == BusNode::SINGLE_AUTOMATIC) { + return Bus::SINGLE_AUTOMATIC; } return Bus::REGULAR; } @@ -85,10 +87,10 @@ Pin::PinType toType(PinNode::PinType type) { PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) { - if(type == PinConnectionNode::AUTOMATICALLY) { - return PinConnection::AUTOMATICALLY; + if(type == PinConnectionNode::OPTIONAL) { + return PinConnection::OPTIONAL; } - return PinConnection::CHECK_ONLY; + return PinConnection::REQUIRED; } @@ -187,7 +189,7 @@ std::optional SchemaCreator::loadBus(BusNode node) errors.emplace_back(node.span, "missing @display"); return nullopt; } - if(node.display && (type == Bus::AUTOMATIC || type == Bus::AUTOMATIC_SINGLE)) { + if(node.display && (type == Bus::AUTOMATIC || type == Bus::SINGLE_AUTOMATIC)) { errors.emplace_back(node.span, "automatic bus cannot have a @display"); return nullopt; } @@ -212,6 +214,11 @@ std::optional SchemaCreator::loadBus(BusNode node) } } + if(type == Bus::SINGLE_AUTOMATIC && wires.size() != 1) { + errors.emplace_back(node.span, "singleAutomatic bus must have exactly 1 wire defined"); + return nullopt; + } + return Bus(name, tooltip, type, count, wires, display); } @@ -223,7 +230,7 @@ std::optional SchemaCreator::loadAddressSpace(AddressSpaceNode nod std::optional SchemaCreator::loadConnection(ConnectionNode node) { - push(ComdelContext("connection", false, true, false)); + push(ComdelContext("connection", false, true, false, false)); std::string bus = node.bus.value; auto busInstance = getBus(bus); @@ -231,6 +238,10 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) errors.emplace_back(node.span, "bus does not exist"); } + if(busInstance->getType() == Bus::SINGLE_AUTOMATIC) { + current().inSingleAutomaticConnection = true; + } + if(busInstance->getType() == Bus::REGULAR) { ConnectionComponent first{node.first.component.value, node.first.pin.value}; @@ -285,7 +296,7 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) pop(); return Connection(first, nullopt, bus, attributes, wires, nullopt); - } else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::AUTOMATIC_SINGLE) { + } else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::SINGLE_AUTOMATIC) { ConnectionComponent first{node.first.component.value, node.first.pin.value}; if(!node.second.has_value()) { @@ -310,6 +321,10 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) current().wires.push_back(wire.getName()); } + if(node.attributes.size() != 2 && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { + errors.emplace_back(node.span, "singleAutomatic must contain 2 attributes"); + } + std::vector attributes; for(auto & attribute : node.attributes) { auto attr = loadAttribute(attribute); @@ -330,7 +345,9 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) firstWires.push_back(Value::fromNull()); } else if(firstWire.is(ValueNode::INT)) { firstWires.push_back(Value::fromInt(firstWire.asInt())); - } else if(firstWire.is(ValueNode::IDENTIFIER)) { + } else if(firstWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { + firstWires.push_back(Value::fromString(firstWire.asString())); + } else if(firstWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) { if(attributeNames.count(firstWire.asIdentifier())) { firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); } else if(wireNames.count(firstWire.asIdentifier())) { @@ -339,7 +356,7 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) errors.emplace_back(firstWire.span, "unknown identifier"); } } else { - errors.emplace_back(firstWire.span, "unknown value type"); + errors.emplace_back(firstWire.span, "unsupported value type"); } } @@ -350,7 +367,9 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) secondWires.push_back(Value::fromNull()); } else if(secondWire.is(ValueNode::INT)) { secondWires.push_back(Value::fromInt(secondWire.asInt())); - } else if(secondWire.is(ValueNode::IDENTIFIER)) { + } else if(secondWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { + secondWires.push_back(Value::fromString(secondWire.asString())); + } else if(secondWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) { if(attributeNames.count(secondWire.asIdentifier())) { secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); } else if(wireNames.count(secondWire.asIdentifier())) { @@ -359,7 +378,25 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) errors.emplace_back(secondWire.span, "unknown identifier"); } } else { - errors.emplace_back(secondWire.span, "unknown value type"); + errors.emplace_back(secondWire.span, "unsupported value type"); + } + } + + if(busInstance->getType() == Bus::SINGLE_AUTOMATIC && attributes.size() == 2) { + if(!attributes[0].getPopup().has_value()) { + errors.emplace_back(node.attributes[0].span, "@popup is required"); + } 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)); + } + + if(!attributes[1].getPopup().has_value()) { + errors.emplace_back(node.attributes[1].span, "@popup is required"); + } 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)); } } @@ -375,7 +412,7 @@ std::optional SchemaCreator::loadConnection(ConnectionNode node) std::optional SchemaCreator::loadComponent(ComponentNode node) { - push(ComdelContext(node.name.value, true, false, false)); + push(ComdelContext(node.name.value, true, false, false, false)); std::string name = node.name.value; @@ -581,7 +618,7 @@ std::optional SchemaCreator::loadAttribute(AttributeNode node) errors.emplace_back(node.name.span, "unsupported type"); } } - if(current().inConnection) { // TODO remove identifier + if(current().inConnection && !current().inSingleAutomaticConnection) { // TODO remove identifier if (node.type == ValueNode::WIRE || node.type == ValueNode::IDENTIFIER) { if(current().doesWireExists(node.defaultValue->asIdentifier())) { value = Value::fromReference(node.defaultValue->asIdentifier(), Value::WIRE_REFERENCE); @@ -593,6 +630,13 @@ std::optional SchemaCreator::loadAttribute(AttributeNode node) errors.emplace_back(node.name.span, "unsupported type"); } } + if(current().inSingleAutomaticConnection) { + if (node.type == ValueNode::STRING) { + value = Value::fromString(node.defaultValue->asString()); + } else { + errors.emplace_back(node.name.span, "unsupported type"); + } + } current().attributes.emplace_back(name, value); @@ -864,4 +908,14 @@ std::shared_ptr SchemaCreator::loadBusInstance(InstanceNode instanc return std::make_shared(name, position, bus, static_cast(size)); } +vector SchemaCreator::createWireEnumeration(vector wireValues) { + vector wires; + for(auto& wire: wireValues) { + if(wire.isType(Value::STRING)) { + wires.emplace_back(wire.asString(), wire); + } + } + return wires; +} + } // namespace domain diff --git a/comdel/domain/schemacreator.h b/comdel/domain/schemacreator.h index d0360b1..8ab600a 100644 --- a/comdel/domain/schemacreator.h +++ b/comdel/domain/schemacreator.h @@ -18,10 +18,11 @@ struct ComdelContext { std::string name; bool inComponent; bool inConnection; + bool inSingleAutomaticConnection; bool inBus; - ComdelContext(std::string name, bool inComponent, bool inConnection, bool inBus) - : name(name), inComponent(inComponent), inConnection(inConnection), inBus(inBus) + ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus) + : name(name), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus) {} bool doesAttributeExists(std::string name, Value::ValueType type) { @@ -117,7 +118,7 @@ class SchemaCreator this->context.push_back(current()); current().name = name; } else { - ComdelContext con(name, false, false, false); + ComdelContext con(name, false, false, false, false); push(con); } } @@ -138,6 +139,8 @@ public: std::optional loadLibrary(LibraryNode node); Schema* loadSchema(SchemaNode node, Library &library); + + vector createWireEnumeration(vector vector1); }; } // namespace domain diff --git a/comdel/parser/astnode.h b/comdel/parser/astnode.h index 62801c0..a1b41b7 100644 --- a/comdel/parser/astnode.h +++ b/comdel/parser/astnode.h @@ -181,8 +181,8 @@ struct DisplayNode: public AstNode struct PinConnectionNode: public AstNode { enum ConnectionType { - CHECK_ONLY, - AUTOMATICALLY + REQUIRED, + OPTIONAL }; StringNode message; @@ -273,7 +273,8 @@ struct BusNode: public AstNode { enum BusType { AUTOMATIC, - REGULAR + REGULAR, + SINGLE_AUTOMATIC }; EnumNode type; diff --git a/comdel/parser/comdelparser.cpp b/comdel/parser/comdelparser.cpp index 6465fad..3bb85e5 100644 --- a/comdel/parser/comdelparser.cpp +++ b/comdel/parser/comdelparser.cpp @@ -465,6 +465,7 @@ PResult ComdelParser::parseComponent() APPEND_OR_SET_ERR(component.rules, parseRule()); } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -583,6 +584,7 @@ PResult ComdelParser::parseBus() { RETURN_IF_NOT_TOKEN(TokenType::RBRACE); } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -607,11 +609,13 @@ PResult> ComdelParser::parseBusType() { type = EnumNode(BusNode::AUTOMATIC); } else if(tokenType.value().value == "regular") { type = EnumNode(BusNode::REGULAR); + } else if(tokenType.value().value == "singleAutomatic") { + type = EnumNode(BusNode::SINGLE_AUTOMATIC); } else { - type = PError(SourceError{current().span, "expected 'automatic' or 'regular'"}); + type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"}); } } else { - type = PError(SourceError{current().span, "expected 'automatic' or 'regular'"}); + type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"}); } return type; } @@ -728,6 +732,7 @@ PResult ComdelParser::parsePin() { pin.wires = *wires; } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -771,15 +776,15 @@ PResult> ComdelParser::parseConnecti if(check(TokenType::IDENTIFIER)) { auto identifier = parseIdentifier(); - if(identifier.value().value == "check_only") { - type = EnumNode(PinConnectionNode::CHECK_ONLY); - } else if(identifier.value().value == "automatically") { - type = EnumNode(PinConnectionNode::AUTOMATICALLY); + if(identifier.value().value == "required") { + type = EnumNode(PinConnectionNode::REQUIRED); + } else if(identifier.value().value == "optional") { + type = EnumNode(PinConnectionNode::OPTIONAL); } else { - return PError(SourceError{current().span, "expected identifiers 'check_only' or 'automatically'"}); + return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"}); } } else { - return PError(SourceError{current().span, "expected identifiers 'check_only' or 'automatically'"}); + return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"}); } return spanner(type); @@ -948,6 +953,7 @@ PResult ComdelParser::parsePopup() { ); } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -965,7 +971,7 @@ PResult ComdelParser::parsePopup() { /**************************************************************************** * -* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS) {" + CONNECTION + "}" +* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}" * ****************************************************************************/ PResult ComdelParser::parseConnection() { @@ -984,7 +990,6 @@ PResult ComdelParser::parseConnection() { if(check(TokenType::COMMA)) { auto conn = ConnectionComponentNode{}; RETURN_IF_NOT_TOKEN(TokenType::COMMA); - RETURN_IF_NOT_TOKEN(TokenType::LPAREN); ASSIGN_OR_RETURN_IF_ERR(conn.component, parseIdentifier()); RETURN_IF_NOT_TOKEN(TokenType::DOT); ASSIGN_OR_RETURN_IF_ERR(conn.pin, parseIdentifier()); @@ -1016,6 +1021,7 @@ PResult ComdelParser::parseConnection() { wireCount++; } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -1251,6 +1257,7 @@ PResult ComdelParser::parseInstance() { instance.size = *number; } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); @@ -1324,13 +1331,16 @@ PResult ComdelParser::parseConnectionInstance() { } PResult ComdelParser::parseConnectionWire() { + auto spanner = getSpanner(); if(check(TokenType::NUMBER)) { - return ValueNode::ofInt(parseNumber()->value); + return spanner(ValueNode::ofInt(parseNumber()->value)); } else if(check(TokenType::NIL)) { bump(); - return ValueNode::ofNull(); + return spanner(ValueNode::ofNull()); + } else if(check(TokenType::STRING)) { + return spanner(ValueNode::ofString(parseString()->value)); } else if(check(TokenType::IDENTIFIER)) { - return ValueNode::ofIdentifier(parseIdentifier()->value); + return spanner(ValueNode::ofIdentifier(parseIdentifier()->value)); } else { return unexpected(); } diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index f7205fc..523a163 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -17,7 +17,7 @@ @component FRISC processor { @instanceName "procesor" - @tooltip "procesor FRISC, mora postojati jedan" + @tooltip "Procesor FRISC, mora postojati jedan" @count (1, 1) @source "FRISC.cdl" @display { @@ -51,7 +51,7 @@ } @pin glavniPin inOut { @tooltip "pin za spajanje na glavnu sabirnicu" - @connection check_only("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu") + @connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu") @display { /* pin { @@ -146,7 +146,7 @@ @pin glavniPin inOut { @tooltip "pin za spajanje na glavnu sabirnicu" - @connection check_only("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu") + @connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu") @display { /* pin { @@ -214,7 +214,7 @@ @pin glavniPin in { @tooltip "pin za spajanje na glavnu sabirnicu" - @connection check_only("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu") + @connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu") @display { /* pin { @@ -235,7 +235,7 @@ @pin dodatnaPoveznica in { @tooltip "pin za spajanje na pomocnu sabirnicu" - @connection check_only("COMDEL se ne može stvoriti. DMA nije spojen na nesto!") + @connection optional("COMDEL se ne može stvoriti. DMA nije spojen na nesto!") @display { pin { x: 0; y: 0; w: 0; h: 0; @@ -285,6 +285,14 @@ 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} @@ -307,4 +315,28 @@ } } @wires{ADR, DATA, READ, WRITE, SIZE, WAIT, interupt, BREQ, BACK} +} + +@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 79714ea..b57dd57 100644 --- a/examples/simplified FRISC model/schema.csl +++ b/examples/simplified FRISC model/schema.csl @@ -17,7 +17,14 @@ @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