diff options
author | Marcelina KoĆcielnicka <mwk@0x04.net> | 2021-03-09 20:42:14 +0100 |
---|---|---|
committer | Marcelina KoĆcielnicka <mwk@0x04.net> | 2021-03-15 17:19:19 +0100 |
commit | 3d9698153fc7f01cef0dec99cc834ffecec766a5 (patch) | |
tree | a55d576a9654c825fb352574044217392c701897 | |
parent | a55bf6375b38a955de4589a66e4d2992ac7dd621 (diff) | |
download | yosys-3d9698153fc7f01cef0dec99cc834ffecec766a5.tar.gz yosys-3d9698153fc7f01cef0dec99cc834ffecec766a5.tar.bz2 yosys-3d9698153fc7f01cef0dec99cc834ffecec766a5.zip |
json: Add support for memories.
Previously, memories were silently discarded by the JSON backend, making
round-tripping modules with them crash.
Since there are already some users using JSON to implement custom
external passes that use memories (and infer width/size from memory
ports), let's fix this by just making JSON backend and frontend support
memories as first-class objects.
Processes are still not supported, and will now cause a hard error.
Fixes #1908.
-rw-r--r-- | backends/json/json.cc | 42 | ||||
-rw-r--r-- | frontends/json/jsonparse.cc | 46 |
2 files changed, 88 insertions, 0 deletions
diff --git a/backends/json/json.cc b/backends/json/json.cc index eeadc1b89..b13105f64 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -135,6 +135,10 @@ struct JsonWriter // reserve 0 and 1 to avoid confusion with "0" and "1" sigidcounter = 2; + if (module->has_processes()) { + log_error("Module %s contains processes, which are not supported by JSON backend.\n", log_id(module)); + } + f << stringf(" %s: {\n", get_name(module->name).c_str()); f << stringf(" \"attributes\": {"); @@ -216,6 +220,27 @@ struct JsonWriter } f << stringf("\n },\n"); + if (!module->memories.empty()) { + f << stringf(" \"memories\": {"); + first = true; + for (auto &it : module->memories) { + if (use_selection && !module->selected(it.second)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(it.second->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", it.second->name[0] == '$' ? "1" : "0"); + f << stringf(" \"attributes\": {"); + write_parameters(it.second->attributes); + f << stringf("\n },\n"); + f << stringf(" \"width\": %d,\n", it.second->width); + f << stringf(" \"start_offset\": %d,\n", it.second->start_offset); + f << stringf(" \"size\": %d\n", it.second->size); + f << stringf(" }"); + first = false; + } + f << stringf("\n },\n"); + } + f << stringf(" \"netnames\": {"); first = true; for (auto w : module->wires()) { @@ -332,6 +357,10 @@ struct JsonBackend : public Backend { log(" <cell_name>: <cell_details>,\n"); log(" ...\n"); log(" },\n"); + log(" \"memories\": {\n"); + log(" <memory_name>: <memory_details>,\n"); + log(" ...\n"); + log(" },\n"); log(" \"netnames\": {\n"); log(" <net_name>: <net_details>,\n"); log(" ...\n"); @@ -379,6 +408,19 @@ struct JsonBackend : public Backend { log(" },\n"); log(" }\n"); log("\n"); + log("And <memory_details> is:\n"); + log("\n"); + log(" {\n"); + log(" \"hide_name\": <1 | 0>,\n"); + log(" \"attributes\": {\n"); + log(" <attribute_name>: <attribute_value>,\n"); + log(" ...\n"); + log(" },\n"); + log(" \"width\": <memory width>\n"); + log(" \"start_offset\": <the lowest valid memory address>\n"); + log(" \"size\": <memory size>\n"); + log(" }\n"); + log("\n"); log("And <net_details> is:\n"); log("\n"); log(" {\n"); diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 312f6d3be..d897ac20b 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -539,6 +539,52 @@ void json_import(Design *design, string &modname, JsonNode *node) json_parse_attr_param(cell->parameters, cell_node->data_dict.at("parameters")); } } + + if (node->data_dict.count("memories")) + { + JsonNode *memories_node = node->data_dict.at("memories"); + + if (memories_node->type != 'D') + log_error("JSON memories node is not a dictionary.\n"); + + for (auto &memory_node_it : memories_node->data_dict) + { + IdString memory_name = RTLIL::escape_id(memory_node_it.first.c_str()); + JsonNode *memory_node = memory_node_it.second; + + RTLIL::Memory *mem = new RTLIL::Memory; + mem->name = memory_name; + + if (memory_node->type != 'D') + log_error("JSON memory node '%s' is not a dictionary.\n", log_id(memory_name)); + + if (memory_node->data_dict.count("width") == 0) + log_error("JSON memory node '%s' has no width attribute.\n", log_id(memory_name)); + JsonNode *width_node = memory_node->data_dict.at("width"); + if (width_node->type != 'N') + log_error("JSON memory node '%s' has a non-number width.\n", log_id(memory_name)); + mem->width = width_node->data_number; + + if (memory_node->data_dict.count("size") == 0) + log_error("JSON memory node '%s' has no size attribute.\n", log_id(memory_name)); + JsonNode *size_node = memory_node->data_dict.at("size"); + if (size_node->type != 'N') + log_error("JSON memory node '%s' has a non-number size.\n", log_id(memory_name)); + mem->size = size_node->data_number; + + mem->start_offset = 0; + if (memory_node->data_dict.count("start_offset") != 0) { + JsonNode *val = memory_node->data_dict.at("start_offset"); + if (val->type == 'N') + mem->start_offset = val->data_number; + } + + if (memory_node->data_dict.count("attributes")) + json_parse_attr_param(mem->attributes, memory_node->data_dict.at("attributes")); + + module->memories[mem->name] = mem; + } + } } struct JsonFrontend : public Frontend { |