Added support for memory attribute

This commit is contained in:
Borna Rajković 2022-05-15 23:55:03 +02:00
parent bb423c2184
commit 59b19062ff
14 changed files with 293 additions and 70 deletions

View File

@ -57,4 +57,10 @@ void AttributeDialog::onUpdate() {
} }
void MemoryDialog::onUpdate() {
attributeValue->value = value;
accept();
}
} }

View File

@ -64,7 +64,7 @@ public:
auto* combo = new QComboBox(this); auto* combo = new QComboBox(this);
auto enumeration = attribute->attribute.getPopup()->getEnumeration(); auto enumeration = attribute->attribute.getPopup()->getEnumeration();
for(auto entry: enumeration) { for(auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()), QVariant::fromValue(NULL)); combo->addItem(QString::fromStdString(entry.getName()));
} }
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AttributeDialog::onEnumerationChanged); connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AttributeDialog::onEnumerationChanged);
@ -144,6 +144,76 @@ public slots:
}; };
class MemoryDialog: public QDialog {
domain::Value value;
domain::InstanceAttribute* attributeValue;
std::vector<std::string> memoryInstances;
public:
MemoryDialog(domain::InstanceAttribute *attribute, std::vector<std::shared_ptr<domain::ComponentInstance>> instances) {
memoryInstances = std::vector<std::string>();
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<int>::of(&QComboBox::currentIndexChanged), this, &MemoryDialog::onMemoryChanged);
layout->addWidget(combo);
combo->setCurrentIndex(memoryInstances.size());
for(int i=0; i<memoryInstances.size(); i++) {
if(attributeValue->value.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 { class ErrorDialog: public QDialog {
public: public:

View File

@ -1,6 +1,7 @@
#include "component_display.h" #include "component_display.h"
#include "attribute_dialog.h" #include "attribute_dialog.h"
#include "name_dialog.h" #include "name_dialog.h"
#include "mainwindow.h"
#include <QMenu> #include <QMenu>
#include <QGraphicsSceneContextMenuEvent> #include <QGraphicsSceneContextMenuEvent>
@ -22,8 +23,13 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name), auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
[attr]() { [attr]() {
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances);
dialog->exec();
} else {
auto dialog = new AttributeDialog(attr); auto dialog = new AttributeDialog(attr);
dialog->exec(); dialog->exec();
}
}); });
action->setEnabled(enabled); action->setEnabled(enabled);
} }

View File

@ -175,17 +175,45 @@ void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name,
map <string, string> &wireNames, map <string, string> &wireNames,
stringstream &buffer); stringstream &buffer);
void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &buffer) { void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer,
shared_ptr <ComponentInstance> &component);
void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &buffer) {
buffer << "\t// components --------------------------------------------" << std::endl; buffer << "\t// components --------------------------------------------" << std::endl;
for(auto& component: schema->componentInstances) { for(auto& component: schema->componentInstances) {
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);
}
}
}
void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer,
shared_ptr <ComponentInstance> &component) {
buffer << "\tsubcomponent " << component->component.getName() << " " << component->name; buffer << "\tsubcomponent " << component->component.getName() << " " << component->name;
if(!component->attributes.empty()) {
std::optional<InstanceAttribute> memory;
std::vector<InstanceAttribute> 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 << "<";
buffer << component->attributes[0].value.stringify(); buffer << attributes[0].value.stringify();
for(int i=1; i<component->attributes.size(); i++) { for(int i=1; i<attributes.size(); i++) {
buffer << ", " << component->attributes[i].value.stringify(); buffer << ", " << attributes[i].value.stringify();
} }
buffer << ">"; buffer << ">";
} }
@ -238,8 +266,14 @@ void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &
wireList.pop_back(); wireList.pop_back();
wireList.pop_back(); // remove last COMMA(", ") wireList.pop_back(); // remove last COMMA(", ")
buffer << "(" << wireList << ");" << std::endl; buffer << "(" << wireList << ")";
if(memory.has_value()) {
buffer << " uses " << *memory->value.asMemoryReference();
} }
buffer << ";" << std::endl;
} }
void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map <string, string> &wireNames, stringstream &buffer) { void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map <string, string> &wireNames, stringstream &buffer) {

View File

@ -70,6 +70,12 @@ bool Component::hasAttribute(std::string name, Value::ValueType type) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) { if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
return true; return true;
} }
if(attributes[i].getName() == name && (type == Value::NIL && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) {
return true;
}
if(attributes[i].getName() == name && (type == Value::UNDEFINED && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) {
return true;
}
} }
return false; return false;
} }

View File

@ -40,19 +40,31 @@ Value::ValueType toType(ValueNode::ValueType type) {
switch (type) { switch (type) {
case ValueNode::BOOL: case ValueNode::BOOL:
return Value::BOOL; return Value::BOOL;
case ValueNode::MEMORY:
return Value::MEMORY_REFERENCE;
case ValueNode::WIRE: case ValueNode::WIRE:
return Value::WIRE_REFERENCE; return Value::WIRE_REFERENCE;
case ValueNode::STRING: case ValueNode::STRING:
return Value::STRING; return Value::STRING;
case ValueNode::INT: case ValueNode::INT:
return Value::INT; return Value::INT;
case ValueNode::NIL:
return Value::NIL;
default: default:
return Value::UNDEFINED; return Value::UNDEFINED;
} }
} }
Value toType(ValueNode node) { Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) {
if(type == Value::MEMORY_REFERENCE) {
if(node.getType() == ValueNode::NIL) {
return Value::fromMemoryReference(nullopt);
} else {
return Value::fromMemoryReference(node.asIdentifier());
}
}
if(node.getType() == ValueNode::BOOL) { if(node.getType() == ValueNode::BOOL) {
return Value::fromBool(node.asBool()); return Value::fromBool(node.asBool());
} else if(node.getType() == ValueNode::INT) { } else if(node.getType() == ValueNode::INT) {
@ -439,6 +451,9 @@ std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
attributes.push_back(*attribute); attributes.push_back(*attribute);
} }
} }
if(type == Component::PROCESSOR) {
attributes.push_back(*createMemoryAttribute());
}
context[context.size() -1 ].attributes = attributes; context[context.size() -1 ].attributes = attributes;
@ -885,12 +900,20 @@ shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode
for(auto& attr: instance.attributes) { for(auto& attr: instance.attributes) {
if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) { if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) {
auto attribute = component.getAttribute(attr.name.value); 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 { } else {
errors.emplace_back(SourceError(attr.name.span, "unknown attribute")); 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<ComponentInstance>(name, attributes, position, component); return std::make_shared<ComponentInstance>(name, attributes, position, component);
} }
std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) { std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
@ -918,4 +941,12 @@ vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValue
return wires; return wires;
} }
std::optional<Attribute> SchemaCreator::createMemoryAttribute() {
return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup());
}
std::optional<Popup> SchemaCreator::createMemoryPopup() {
return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector<Rule>{}, vector<Enumeration>{});
}
} // namespace domain } // namespace domain

View File

@ -79,6 +79,8 @@ class SchemaCreator
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library); std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library); std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
std::optional<Attribute> createMemoryAttribute();
std::optional<Bus> getBus(std::string name) { std::optional<Bus> getBus(std::string name) {
for(auto &bus: buses) { for(auto &bus: buses) {
if(bus.getName() == name) { if(bus.getName() == name) {
@ -140,7 +142,9 @@ public:
Schema* loadSchema(SchemaNode node, Library &library); Schema* loadSchema(SchemaNode node, Library &library);
vector <Enumeration> createWireEnumeration(vector <Value> vector1); vector <Enumeration> createWireEnumeration(vector<Value> vector1);
std::optional<Popup> createMemoryPopup();
}; };
} // namespace domain } // namespace domain

View File

@ -68,6 +68,16 @@ std::string Value::asReference() {
throw std::exception(); throw std::exception();
} }
std::optional<std::string> Value::asMemoryReference() {
return memoryReference;
}
domain::ComponentInstance *Value::asMemory() {
return memory;
}
void Value::setInt(long long value) { void Value::setInt(long long value) {
if(isType(Value::INT)) { if(isType(Value::INT)) {
this->intValue = value; this->intValue = value;
@ -124,11 +134,11 @@ Value Value::fromReference(std::string value, Value::ValueType type) {
val.reference = value; val.reference = value;
return val; return val;
} }
Value Value::ofType(Value::ValueType type) { Value Value::ofType(Value::ValueType type) {
Value val; Value val;
val.type = type; val.type = type;
return val; return val;
} }
Value Value::fromNull() { Value Value::fromNull() {
@ -151,9 +161,29 @@ std::string Value::stringify() {
case ADDRESS_SPACE_REFERENCE: case ADDRESS_SPACE_REFERENCE:
case ATTRIBUTE_REFERENCE: case ATTRIBUTE_REFERENCE:
return reference; return reference;
case MEMORY_REFERENCE:
if(memoryReference->empty()) {
return "null";
} else {
return memoryReference.value();
}
default: default:
throw std::exception(); throw std::exception();
} }
} }
Value Value::fromMemoryReference(std::optional<std::string> 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 } // namespace domain

View File

@ -9,6 +9,8 @@
namespace domain { namespace domain {
class ComponentInstance;
class Value class Value
{ {
public: public:
@ -19,6 +21,8 @@ public:
ADDRESS_SPACE, ADDRESS_SPACE,
ADDRESS_SPACE_REFERENCE, ADDRESS_SPACE_REFERENCE,
ATTRIBUTE_REFERENCE, ATTRIBUTE_REFERENCE,
MEMORY_REFERENCE,
MEMORY,
WIRE_REFERENCE, WIRE_REFERENCE,
NIL, NIL,
UNDEFINED, UNDEFINED,
@ -30,6 +34,9 @@ private:
bool boolValue; bool boolValue;
std::optional<AddressSpace> addressSpace; std::optional<AddressSpace> addressSpace;
std::string reference; std::string reference;
domain::ComponentInstance *memory;
std::optional<std::string> memoryReference;
ValueType type; ValueType type;
@ -53,6 +60,10 @@ public:
case ATTRIBUTE_REFERENCE: case ATTRIBUTE_REFERENCE:
case ADDRESS_SPACE_REFERENCE: case ADDRESS_SPACE_REFERENCE:
return value.asReference() == reference; return value.asReference() == reference;
case MEMORY_REFERENCE:
return value.asMemoryReference() == memoryReference;
case MEMORY:
return value.asMemory() == memory;
case BOOL: case BOOL:
return value.asBool() == boolValue; return value.asBool() == boolValue;
default: default:
@ -71,6 +82,8 @@ public:
std::string asString(); std::string asString();
bool asBool(); bool asBool();
std::string asReference(); std::string asReference();
std::optional<std::string> asMemoryReference();
domain::ComponentInstance* asMemory();
AddressSpace asAddressSpace(); AddressSpace asAddressSpace();
void setInt(long long intValue); void setInt(long long intValue);
@ -87,6 +100,8 @@ public:
static Value fromAddressSpace(AddressSpace addressSpace); static Value fromAddressSpace(AddressSpace addressSpace);
static Value fromReference(std::string value, ValueType type); static Value fromReference(std::string value, ValueType type);
static Value ofType(ValueType type); static Value ofType(ValueType type);
static Value fromMemoryReference(std::optional<std::string> memoryReference);
static Value fromMemory(domain::ComponentInstance *memory);
}; };
} // namespace domain } // namespace domain

View File

@ -94,9 +94,16 @@ ValueNode ValueNode::ofNull() {
return value; return value;
} }
ValueNode ValueNode::ofWire(std::string _value) { ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
ValueNode value; ValueNode value;
value.type = EnumNode(WIRE); value.type = EnumNode(WIRE);
value.identifierValue = std::optional<std::string>(_value); value.identifierValue = _value;
return value;
}
ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(MEMORY);
value.identifierValue = _value;
return value; return value;
} }

View File

@ -77,6 +77,7 @@ public:
BOOL, BOOL,
WIRE, WIRE,
IDENTIFIER, IDENTIFIER,
MEMORY,
NIL, NIL,
}; };
@ -88,7 +89,7 @@ private:
std::optional<std::string> identifierValue; std::optional<std::string> identifierValue;
public: public:
ValueNode() = default;; ValueNode() = default;
ValueType getType() { ValueType getType() {
return type.value; return type.value;
@ -104,8 +105,9 @@ public:
static ValueNode ofInt(long long _value); static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value); static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value); static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull(); static ValueNode ofNull();
static ValueNode ofWire(std::string _value); static ValueNode ofWire(std::optional<std::string> _value);
}; };
struct ConditionNode struct ConditionNode

View File

@ -438,7 +438,7 @@ PResult<ComponentNode> ComdelParser::parseComponent()
ASSIGN_OR_RETURN_IF_ERR(component.name, parseIdentifier()); 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); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
@ -853,13 +853,23 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
} else { } else {
return unexpected(); 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) { } else if(attribute.type == ValueNode::WIRE) {
if(check(TokenType::IDENTIFIER)) { if(check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier(); auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofWire(identifier->value); attribute.defaultValue = ValueNode::ofWire(identifier->value);
} else if(check(TokenType::NIL)) { } else if(check(TokenType::NIL)) {
bump(); bump();
attribute.defaultValue = ValueNode::ofNull(); attribute.defaultValue = ValueNode::ofWire(std::nullopt);
} else { } else {
return unexpected(); return unexpected();
} }

View File

@ -3,6 +3,7 @@
@schema { @schema {
@instance proc FRISC { @instance proc FRISC {
@position (0, 0) @position (0, 0)
@attribute _memory null
} }
@instance mem Memorija { @instance mem Memorija {

View File

@ -1,11 +1,12 @@
@source "frisc_library.csl" @source "frisc_library.csl"
@schema { @schema {
@instance procesor2 FRISC { @instance proc FRISC {
@position (0, 0) @position (0, 0)
@attribute _memory mem
} }
@instance memorija2 Memorija { @instance mem Memorija {
@position (0, 250) @position (0, 250)
@attribute sinkroniziran false @attribute sinkroniziran false
@attribute brzina 1 @attribute brzina 1
@ -14,7 +15,7 @@
@attribute pocetnaAdresa 1023 @attribute pocetnaAdresa 1023
} }
@instance bus2 glavnaSabirnica { @instance bus glavnaSabirnica {
@position (0, 200) @position (0, 200)
@size 100 @size 100
} }
@ -24,11 +25,11 @@
@size 0 @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 dmaPoveznica "READY"
@attribute mmaPoveznica "PIO_DATA" @attribute mmaPoveznica "PIO_DATA"
} }