Added support for memory attribute
This commit is contained in:
parent
bb423c2184
commit
59b19062ff
|
@ -57,4 +57,10 @@ void AttributeDialog::onUpdate() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
void MemoryDialog::onUpdate() {
|
||||
attributeValue->value = value;
|
||||
accept();
|
||||
}
|
||||
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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]() {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -175,17 +175,45 @@ void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name,
|
|||
map <string, string> &wireNames,
|
||||
stringstream &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) {
|
||||
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;
|
||||
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 << component->attributes[0].value.stringify();
|
||||
for(int i=1; i<component->attributes.size(); i++) {
|
||||
buffer << ", " << component->attributes[i].value.stringify();
|
||||
buffer << attributes[0].value.stringify();
|
||||
for(int i=1; i<attributes.size(); i++) {
|
||||
buffer << ", " << attributes[i].value.stringify();
|
||||
}
|
||||
buffer << ">";
|
||||
}
|
||||
|
@ -238,8 +266,14 @@ void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &
|
|||
wireList.pop_back();
|
||||
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) {
|
||||
|
|
|
@ -70,6 +70,12 @@ bool Component::hasAttribute(std::string name, Value::ValueType 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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
@ -141,6 +143,8 @@ public:
|
|||
Schema* loadSchema(SchemaNode node, Library &library);
|
||||
|
||||
vector <Enumeration> createWireEnumeration(vector<Value> vector1);
|
||||
|
||||
std::optional<Popup> createMemoryPopup();
|
||||
};
|
||||
|
||||
} // namespace domain
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
@schema {
|
||||
@instance proc FRISC {
|
||||
@position (0, 0)
|
||||
@attribute _memory null
|
||||
}
|
||||
|
||||
@instance mem Memorija {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue