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 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<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 {
public:

View File

@ -1,6 +1,7 @@
#include "component_display.h"
#include "attribute_dialog.h"
#include "name_dialog.h"
#include "mainwindow.h"
#include <QMenu>
#include <QGraphicsSceneContextMenuEvent>
@ -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);
}

View File

@ -175,71 +175,105 @@ void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name,
map <string, string> &wireNames,
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;
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; i<component->attributes.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 <string, string> &wires, ostream &buffer,
shared_ptr <ComponentInstance> &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<BusConnectionInstance*>(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<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 << attributes[0].value.stringify();
for(int i=1; i<attributes.size(); i++) {
buffer << ", " << attributes[i].value.stringify();
}
buffer << ">";
}
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<BusConnectionInstance*>(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<DirectConnectionInstance*>(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<DirectConnectionInstance*>(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 <string, string> &wireNames, stringstream &buffer) {

View File

@ -67,7 +67,13 @@ Attribute Component::getAttribute(std::string attribute) {
}
bool Component::hasAttribute(std::string name, Value::ValueType type) {
for(uint i=0; i<attributes.size(); i++) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
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;
}
}

View File

@ -40,19 +40,31 @@ Value::ValueType toType(ValueNode::ValueType type) {
switch (type) {
case ValueNode::BOOL:
return Value::BOOL;
case ValueNode::MEMORY:
return Value::MEMORY_REFERENCE;
case ValueNode::WIRE:
return Value::WIRE_REFERENCE;
case ValueNode::STRING:
return Value::STRING;
case ValueNode::INT:
return Value::INT;
case ValueNode::NIL:
return Value::NIL;
default:
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) {
return Value::fromBool(node.asBool());
} else if(node.getType() == ValueNode::INT) {
@ -439,6 +451,9 @@ std::optional<Component> 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<ComponentInstance> 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<ComponentInstance>(name, attributes, position, component);
}
std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
@ -918,4 +941,12 @@ vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValue
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

View File

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

View File

@ -68,6 +68,16 @@ std::string Value::asReference() {
throw std::exception();
}
std::optional<std::string> 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<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

View File

@ -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> addressSpace;
std::string reference;
domain::ComponentInstance *memory;
std::optional<std::string> 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<std::string> 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<std::string> memoryReference);
static Value fromMemory(domain::ComponentInstance *memory);
};
} // namespace domain

View File

@ -94,9 +94,16 @@ ValueNode ValueNode::ofNull() {
return value;
}
ValueNode ValueNode::ofWire(std::string _value) {
ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
ValueNode value;
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;
}

View File

@ -77,6 +77,7 @@ public:
BOOL,
WIRE,
IDENTIFIER,
MEMORY,
NIL,
};
@ -88,7 +89,7 @@ private:
std::optional<std::string> 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<std::string> _value);
static ValueNode ofNull();
static ValueNode ofWire(std::string _value);
static ValueNode ofWire(std::optional<std::string> _value);
};
struct ConditionNode

View File

@ -438,7 +438,7 @@ PResult<ComponentNode> 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<AttributeNode> 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();
}

View File

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

View File

@ -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"
}