mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			667 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			667 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  yosys -- Yosys Open SYnthesis Suite
 | 
						|
 *
 | 
						|
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 | 
						|
 *
 | 
						|
 *  Permission to use, copy, modify, and/or distribute this software for any
 | 
						|
 *  purpose with or without fee is hereby granted, provided that the above
 | 
						|
 *  copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
						|
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "kernel/yosys.h"
 | 
						|
 | 
						|
YOSYS_NAMESPACE_BEGIN
 | 
						|
 | 
						|
struct JsonNode
 | 
						|
{
 | 
						|
	char type; // S=String, N=Number, A=Array, D=Dict
 | 
						|
	string data_string;
 | 
						|
	int64_t data_number;
 | 
						|
	vector<JsonNode*> data_array;
 | 
						|
	dict<string, JsonNode*> data_dict;
 | 
						|
	vector<string> data_dict_keys;
 | 
						|
 | 
						|
	JsonNode(std::istream &f)
 | 
						|
	{
 | 
						|
		type = 0;
 | 
						|
		data_number = 0;
 | 
						|
 | 
						|
		while (1)
 | 
						|
		{
 | 
						|
			int ch = f.get();
 | 
						|
 | 
						|
			if (ch == EOF)
 | 
						|
				log_error("Unexpected EOF in JSON file.\n");
 | 
						|
 | 
						|
			if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (ch == '"')
 | 
						|
			{
 | 
						|
				type = 'S';
 | 
						|
 | 
						|
				while (1)
 | 
						|
				{
 | 
						|
					ch = f.get();
 | 
						|
 | 
						|
					if (ch == EOF)
 | 
						|
						log_error("Unexpected EOF in JSON string.\n");
 | 
						|
 | 
						|
					if (ch == '"')
 | 
						|
						break;
 | 
						|
 | 
						|
					if (ch == '\\') {
 | 
						|
						ch = f.get();
 | 
						|
 | 
						|
						switch (ch) {
 | 
						|
							case EOF: log_error("Unexpected EOF in JSON string.\n"); break;
 | 
						|
							case '"':
 | 
						|
							case '/':
 | 
						|
							case '\\':           break;
 | 
						|
							case 'b': ch = '\b'; break;
 | 
						|
							case 'f': ch = '\f'; break;
 | 
						|
							case 'n': ch = '\n'; break;
 | 
						|
							case 'r': ch = '\r'; break;
 | 
						|
							case 't': ch = '\t'; break;
 | 
						|
							case 'u':
 | 
						|
								int val = 0;
 | 
						|
								for (int i = 0; i < 4; i++) {
 | 
						|
									ch = f.get();
 | 
						|
									val <<= 4;
 | 
						|
									if (ch >= '0' && '9' >= ch) {
 | 
						|
										val += ch - '0';
 | 
						|
									} else if (ch >= 'A' && 'F' >= ch) {
 | 
						|
										val += 10 + ch - 'A';
 | 
						|
									} else if (ch >= 'a' && 'f' >= ch) {
 | 
						|
										val += 10 + ch - 'a';
 | 
						|
									} else
 | 
						|
										log_error("Unexpected non-digit character in \\uXXXX sequence: %c.\n", ch);
 | 
						|
								}
 | 
						|
								if (val < 128)
 | 
						|
									ch = val;
 | 
						|
								else
 | 
						|
									log_error("Unsupported \\uXXXX sequence in JSON string: %04X.\n", val);
 | 
						|
								break;
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					data_string += ch;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			if (('0' <= ch && ch <= '9') || ch == '-')
 | 
						|
			{
 | 
						|
				bool negative = false;
 | 
						|
				type = 'N';
 | 
						|
				if (ch == '-') {
 | 
						|
					data_number = 0;
 | 
						|
				       	negative = true;
 | 
						|
				} else {
 | 
						|
					data_number = ch - '0';
 | 
						|
				}
 | 
						|
 | 
						|
				data_string += ch;
 | 
						|
 | 
						|
				while (1)
 | 
						|
				{
 | 
						|
					ch = f.get();
 | 
						|
 | 
						|
					if (ch == EOF)
 | 
						|
						break;
 | 
						|
 | 
						|
					if (ch == '.')
 | 
						|
						goto parse_real;
 | 
						|
 | 
						|
					if (ch < '0' || '9' < ch) {
 | 
						|
						f.unget();
 | 
						|
						break;
 | 
						|
					}
 | 
						|
 | 
						|
					data_number = data_number*10 + (ch - '0');
 | 
						|
					data_string += ch;
 | 
						|
				}
 | 
						|
 | 
						|
				data_number = negative ? -data_number : data_number;
 | 
						|
				data_string = "";
 | 
						|
				break;
 | 
						|
 | 
						|
			parse_real:
 | 
						|
				type = 'S';
 | 
						|
				data_number = 0;
 | 
						|
				data_string += ch;
 | 
						|
 | 
						|
				while (1)
 | 
						|
				{
 | 
						|
					ch = f.get();
 | 
						|
 | 
						|
					if (ch == EOF)
 | 
						|
						break;
 | 
						|
 | 
						|
					if (ch < '0' || '9' < ch) {
 | 
						|
						f.unget();
 | 
						|
						break;
 | 
						|
					}
 | 
						|
 | 
						|
					data_string += ch;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			if (ch == '[')
 | 
						|
			{
 | 
						|
				type = 'A';
 | 
						|
 | 
						|
				while (1)
 | 
						|
				{
 | 
						|
					ch = f.get();
 | 
						|
 | 
						|
					if (ch == EOF)
 | 
						|
						log_error("Unexpected EOF in JSON file.\n");
 | 
						|
 | 
						|
					if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
 | 
						|
						continue;
 | 
						|
 | 
						|
					if (ch == ']')
 | 
						|
						break;
 | 
						|
 | 
						|
					f.unget();
 | 
						|
					data_array.push_back(new JsonNode(f));
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			if (ch == '{')
 | 
						|
			{
 | 
						|
				type = 'D';
 | 
						|
 | 
						|
				while (1)
 | 
						|
				{
 | 
						|
					ch = f.get();
 | 
						|
 | 
						|
					if (ch == EOF)
 | 
						|
						log_error("Unexpected EOF in JSON file.\n");
 | 
						|
 | 
						|
					if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
 | 
						|
						continue;
 | 
						|
 | 
						|
					if (ch == '}')
 | 
						|
						break;
 | 
						|
 | 
						|
					f.unget();
 | 
						|
					JsonNode key(f);
 | 
						|
 | 
						|
					while (1)
 | 
						|
					{
 | 
						|
						ch = f.get();
 | 
						|
 | 
						|
						if (ch == EOF)
 | 
						|
							log_error("Unexpected EOF in JSON file.\n");
 | 
						|
 | 
						|
						if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
 | 
						|
							continue;
 | 
						|
 | 
						|
						f.unget();
 | 
						|
						break;
 | 
						|
					}
 | 
						|
 | 
						|
					JsonNode *value = new JsonNode(f);
 | 
						|
 | 
						|
					if (key.type != 'S')
 | 
						|
						log_error("Unexpected non-string key in JSON dict.\n");
 | 
						|
 | 
						|
					data_dict[key.data_string] = value;
 | 
						|
					data_dict_keys.push_back(key.data_string);
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			log_error("Unexpected character in JSON file: '%c'\n", ch);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	~JsonNode()
 | 
						|
	{
 | 
						|
		for (auto it : data_array)
 | 
						|
			delete it;
 | 
						|
		for (auto &it : data_dict)
 | 
						|
			delete it.second;
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
Const json_parse_attr_param_value(JsonNode *node)
 | 
						|
{
 | 
						|
	Const value;
 | 
						|
 | 
						|
	if (node->type == 'S') {
 | 
						|
		string &s = node->data_string;
 | 
						|
		size_t cursor = s.find_first_not_of("01xz");
 | 
						|
		if (cursor == string::npos) {
 | 
						|
			value = Const::from_string(s);
 | 
						|
		} else if (s.find_first_not_of(' ', cursor) == string::npos) {
 | 
						|
			value = Const(s.substr(0, GetSize(s)-1));
 | 
						|
		} else {
 | 
						|
			value = Const(s);
 | 
						|
		}
 | 
						|
	} else
 | 
						|
	if (node->type == 'N') {
 | 
						|
		value = Const(node->data_number);
 | 
						|
		if (node->data_number < 0)
 | 
						|
			value.flags |= RTLIL::CONST_FLAG_SIGNED;
 | 
						|
	} else
 | 
						|
	if (node->type == 'A') {
 | 
						|
		log_error("JSON attribute or parameter value is an array.\n");
 | 
						|
	} else
 | 
						|
	if (node->type == 'D') {
 | 
						|
		log_error("JSON attribute or parameter value is a dict.\n");
 | 
						|
	} else {
 | 
						|
		log_abort();
 | 
						|
	}
 | 
						|
 | 
						|
	return value;
 | 
						|
}
 | 
						|
 | 
						|
void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
 | 
						|
{
 | 
						|
	if (node->type != 'D')
 | 
						|
		log_error("JSON attributes or parameters node is not a dictionary.\n");
 | 
						|
 | 
						|
	for (auto it : node->data_dict)
 | 
						|
	{
 | 
						|
		IdString key = RTLIL::escape_id(it.first.c_str());
 | 
						|
		Const value = json_parse_attr_param_value(it.second);
 | 
						|
		results[key] = value;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void json_import(Design *design, string &modname, JsonNode *node)
 | 
						|
{
 | 
						|
	log("Importing module %s from JSON tree.\n", modname);
 | 
						|
 | 
						|
	Module *module = new RTLIL::Module;
 | 
						|
	module->name = RTLIL::escape_id(modname.c_str());
 | 
						|
 | 
						|
	if (design->module(module->name))
 | 
						|
		log_error("Re-definition of module %s.\n", log_id(module->name));
 | 
						|
 | 
						|
	design->add(module);
 | 
						|
 | 
						|
	if (node->data_dict.count("attributes"))
 | 
						|
		json_parse_attr_param(module->attributes, node->data_dict.at("attributes"));
 | 
						|
 | 
						|
	dict<int, SigBit> signal_bits;
 | 
						|
 | 
						|
	if (node->data_dict.count("ports"))
 | 
						|
	{
 | 
						|
		JsonNode *ports_node = node->data_dict.at("ports");
 | 
						|
 | 
						|
		if (ports_node->type != 'D')
 | 
						|
			log_error("JSON ports node is not a dictionary.\n");
 | 
						|
 | 
						|
		for (int port_id = 1; port_id <= GetSize(ports_node->data_dict_keys); port_id++)
 | 
						|
		{
 | 
						|
			IdString port_name = RTLIL::escape_id(ports_node->data_dict_keys[port_id-1].c_str());
 | 
						|
			JsonNode *port_node = ports_node->data_dict.at(ports_node->data_dict_keys[port_id-1]);
 | 
						|
 | 
						|
			if (port_node->type != 'D')
 | 
						|
				log_error("JSON port node '%s' is not a dictionary.\n", log_id(port_name));
 | 
						|
 | 
						|
			if (port_node->data_dict.count("direction") == 0)
 | 
						|
				log_error("JSON port node '%s' has no direction attribute.\n", log_id(port_name));
 | 
						|
 | 
						|
			if (port_node->data_dict.count("bits") == 0)
 | 
						|
				log_error("JSON port node '%s' has no bits attribute.\n", log_id(port_name));
 | 
						|
 | 
						|
			JsonNode *port_direction_node = port_node->data_dict.at("direction");
 | 
						|
			JsonNode *port_bits_node = port_node->data_dict.at("bits");
 | 
						|
 | 
						|
			if (port_direction_node->type != 'S')
 | 
						|
				log_error("JSON port node '%s' has non-string direction attribute.\n", log_id(port_name));
 | 
						|
 | 
						|
			if (port_bits_node->type != 'A')
 | 
						|
				log_error("JSON port node '%s' has non-array bits attribute.\n", log_id(port_name));
 | 
						|
 | 
						|
			Wire *port_wire = module->wire(port_name);
 | 
						|
 | 
						|
			if (port_wire == nullptr)
 | 
						|
				port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
 | 
						|
 | 
						|
			if (port_node->data_dict.count("upto") != 0) {
 | 
						|
				JsonNode *val = port_node->data_dict.at("upto");
 | 
						|
				if (val->type == 'N')
 | 
						|
					port_wire->upto = val->data_number != 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if (port_node->data_dict.count("signed") != 0) {
 | 
						|
				JsonNode *val = port_node->data_dict.at("signed");
 | 
						|
				if (val->type == 'N')
 | 
						|
					port_wire->is_signed = val->data_number != 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if (port_node->data_dict.count("offset") != 0) {
 | 
						|
				JsonNode *val = port_node->data_dict.at("offset");
 | 
						|
				if (val->type == 'N')
 | 
						|
					port_wire->start_offset = val->data_number;
 | 
						|
			}
 | 
						|
 | 
						|
			if (port_direction_node->data_string == "input") {
 | 
						|
				port_wire->port_input = true;
 | 
						|
			} else
 | 
						|
			if (port_direction_node->data_string == "output") {
 | 
						|
				port_wire->port_output = true;
 | 
						|
			} else
 | 
						|
			if (port_direction_node->data_string == "inout") {
 | 
						|
				port_wire->port_input = true;
 | 
						|
				port_wire->port_output = true;
 | 
						|
			} else
 | 
						|
				log_error("JSON port node '%s' has invalid '%s' direction attribute.\n", log_id(port_name), port_direction_node->data_string);
 | 
						|
 | 
						|
			port_wire->port_id = port_id;
 | 
						|
 | 
						|
			for (int i = 0; i < GetSize(port_bits_node->data_array); i++)
 | 
						|
			{
 | 
						|
				JsonNode *bitval_node = port_bits_node->data_array.at(i);
 | 
						|
				SigBit sigbit(port_wire, i);
 | 
						|
 | 
						|
				if (bitval_node->type == 'S') {
 | 
						|
					if (bitval_node->data_string == "0")
 | 
						|
						module->connect(sigbit, State::S0);
 | 
						|
					else if (bitval_node->data_string == "1")
 | 
						|
						module->connect(sigbit, State::S1);
 | 
						|
					else if (bitval_node->data_string == "x")
 | 
						|
						module->connect(sigbit, State::Sx);
 | 
						|
					else if (bitval_node->data_string == "z")
 | 
						|
						module->connect(sigbit, State::Sz);
 | 
						|
					else
 | 
						|
						log_error("JSON port node '%s' has invalid '%s' bit string value on bit %d.\n",
 | 
						|
								log_id(port_name), bitval_node->data_string.c_str(), i);
 | 
						|
				} else
 | 
						|
				if (bitval_node->type == 'N') {
 | 
						|
					int bitidx = bitval_node->data_number;
 | 
						|
					if (signal_bits.count(bitidx)) {
 | 
						|
						if (port_wire->port_output) {
 | 
						|
							module->connect(sigbit, signal_bits.at(bitidx));
 | 
						|
						} else {
 | 
						|
							module->connect(signal_bits.at(bitidx), sigbit);
 | 
						|
							signal_bits[bitidx] = sigbit;
 | 
						|
						}
 | 
						|
					} else {
 | 
						|
						signal_bits[bitidx] = sigbit;
 | 
						|
					}
 | 
						|
				} else
 | 
						|
					log_error("JSON port node '%s' has invalid bit value on bit %d.\n", log_id(port_name), i);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		module->fixup_ports();
 | 
						|
	}
 | 
						|
 | 
						|
	if (node->data_dict.count("netnames"))
 | 
						|
	{
 | 
						|
		JsonNode *netnames_node = node->data_dict.at("netnames");
 | 
						|
 | 
						|
		if (netnames_node->type != 'D')
 | 
						|
			log_error("JSON netnames node is not a dictionary.\n");
 | 
						|
 | 
						|
		for (auto &net : netnames_node->data_dict)
 | 
						|
		{
 | 
						|
			IdString net_name = RTLIL::escape_id(net.first.c_str());
 | 
						|
			JsonNode *net_node = net.second;
 | 
						|
 | 
						|
			if (net_node->type != 'D')
 | 
						|
				log_error("JSON netname node '%s' is not a dictionary.\n", log_id(net_name));
 | 
						|
 | 
						|
			if (net_node->data_dict.count("bits") == 0)
 | 
						|
				log_error("JSON netname node '%s' has no bits attribute.\n", log_id(net_name));
 | 
						|
 | 
						|
			JsonNode *bits_node = net_node->data_dict.at("bits");
 | 
						|
 | 
						|
			if (bits_node->type != 'A')
 | 
						|
				log_error("JSON netname node '%s' has non-array bits attribute.\n", log_id(net_name));
 | 
						|
 | 
						|
			Wire *wire = module->wire(net_name);
 | 
						|
 | 
						|
			if (wire == nullptr)
 | 
						|
				wire = module->addWire(net_name, GetSize(bits_node->data_array));
 | 
						|
 | 
						|
			if (net_node->data_dict.count("upto") != 0) {
 | 
						|
				JsonNode *val = net_node->data_dict.at("upto");
 | 
						|
				if (val->type == 'N')
 | 
						|
					wire->upto = val->data_number != 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if (net_node->data_dict.count("offset") != 0) {
 | 
						|
				JsonNode *val = net_node->data_dict.at("offset");
 | 
						|
				if (val->type == 'N')
 | 
						|
					wire->start_offset = val->data_number;
 | 
						|
			}
 | 
						|
 | 
						|
			for (int i = 0; i < GetSize(bits_node->data_array); i++)
 | 
						|
			{
 | 
						|
				JsonNode *bitval_node = bits_node->data_array.at(i);
 | 
						|
				SigBit sigbit(wire, i);
 | 
						|
 | 
						|
				if (bitval_node->type == 'S') {
 | 
						|
					if (bitval_node->data_string == "0")
 | 
						|
						module->connect(sigbit, State::S0);
 | 
						|
					else if (bitval_node->data_string == "1")
 | 
						|
						module->connect(sigbit, State::S1);
 | 
						|
					else if (bitval_node->data_string == "x")
 | 
						|
						module->connect(sigbit, State::Sx);
 | 
						|
					else if (bitval_node->data_string == "z")
 | 
						|
						module->connect(sigbit, State::Sz);
 | 
						|
					else
 | 
						|
						log_error("JSON netname node '%s' has invalid '%s' bit string value on bit %d.\n",
 | 
						|
								log_id(net_name), bitval_node->data_string.c_str(), i);
 | 
						|
				} else
 | 
						|
				if (bitval_node->type == 'N') {
 | 
						|
					int bitidx = bitval_node->data_number;
 | 
						|
					if (signal_bits.count(bitidx)) {
 | 
						|
						if (sigbit != signal_bits.at(bitidx))
 | 
						|
							module->connect(sigbit, signal_bits.at(bitidx));
 | 
						|
					} else {
 | 
						|
						signal_bits[bitidx] = sigbit;
 | 
						|
					}
 | 
						|
				} else
 | 
						|
					log_error("JSON netname node '%s' has invalid bit value on bit %d.\n", log_id(net_name), i);
 | 
						|
			}
 | 
						|
 | 
						|
			if (net_node->data_dict.count("attributes"))
 | 
						|
				json_parse_attr_param(wire->attributes, net_node->data_dict.at("attributes"));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (node->data_dict.count("cells"))
 | 
						|
	{
 | 
						|
		JsonNode *cells_node = node->data_dict.at("cells");
 | 
						|
 | 
						|
		if (cells_node->type != 'D')
 | 
						|
			log_error("JSON cells node is not a dictionary.\n");
 | 
						|
 | 
						|
		for (auto &cell_node_it : cells_node->data_dict)
 | 
						|
		{
 | 
						|
			IdString cell_name = RTLIL::escape_id(cell_node_it.first.c_str());
 | 
						|
			JsonNode *cell_node = cell_node_it.second;
 | 
						|
 | 
						|
			if (cell_node->type != 'D')
 | 
						|
				log_error("JSON cells node '%s' is not a dictionary.\n", log_id(cell_name));
 | 
						|
 | 
						|
			if (cell_node->data_dict.count("type") == 0)
 | 
						|
				log_error("JSON cells node '%s' has no type attribute.\n", log_id(cell_name));
 | 
						|
 | 
						|
			JsonNode *type_node = cell_node->data_dict.at("type");
 | 
						|
 | 
						|
			if (type_node->type != 'S')
 | 
						|
				log_error("JSON cells node '%s' has a non-string type.\n", log_id(cell_name));
 | 
						|
 | 
						|
			IdString cell_type = RTLIL::escape_id(type_node->data_string.c_str());
 | 
						|
 | 
						|
			Cell *cell = module->addCell(cell_name, cell_type);
 | 
						|
 | 
						|
			if (cell_node->data_dict.count("connections") == 0)
 | 
						|
				log_error("JSON cells node '%s' has no connections attribute.\n", log_id(cell_name));
 | 
						|
 | 
						|
			JsonNode *connections_node = cell_node->data_dict.at("connections");
 | 
						|
 | 
						|
			if (connections_node->type != 'D')
 | 
						|
				log_error("JSON cells node '%s' has non-dictionary connections attribute.\n", log_id(cell_name));
 | 
						|
 | 
						|
			for (auto &conn_it : connections_node->data_dict)
 | 
						|
			{
 | 
						|
				IdString conn_name = RTLIL::escape_id(conn_it.first.c_str());
 | 
						|
				JsonNode *conn_node = conn_it.second;
 | 
						|
 | 
						|
				if (conn_node->type != 'A')
 | 
						|
					log_error("JSON cells node '%s' connection '%s' is not an array.\n", log_id(cell_name), log_id(conn_name));
 | 
						|
 | 
						|
				SigSpec sig;
 | 
						|
 | 
						|
				for (int i = 0; i < GetSize(conn_node->data_array); i++)
 | 
						|
				{
 | 
						|
					JsonNode *bitval_node = conn_node->data_array.at(i);
 | 
						|
 | 
						|
					if (bitval_node->type == 'S') {
 | 
						|
						if (bitval_node->data_string == "0")
 | 
						|
							sig.append(State::S0);
 | 
						|
						else if (bitval_node->data_string == "1")
 | 
						|
							sig.append(State::S1);
 | 
						|
						else if (bitval_node->data_string == "x")
 | 
						|
							sig.append(State::Sx);
 | 
						|
						else if (bitval_node->data_string == "z")
 | 
						|
							sig.append(State::Sz);
 | 
						|
						else
 | 
						|
							log_error("JSON cells node '%s' connection '%s' has invalid '%s' bit string value on bit %d.\n",
 | 
						|
									log_id(cell_name), log_id(conn_name), bitval_node->data_string.c_str(), i);
 | 
						|
					} else
 | 
						|
					if (bitval_node->type == 'N') {
 | 
						|
						int bitidx = bitval_node->data_number;
 | 
						|
						if (signal_bits.count(bitidx) == 0)
 | 
						|
							signal_bits[bitidx] = module->addWire(NEW_ID);
 | 
						|
						sig.append(signal_bits.at(bitidx));
 | 
						|
					} else
 | 
						|
						log_error("JSON cells node '%s' connection '%s' has invalid bit value on bit %d.\n",
 | 
						|
								log_id(cell_name), log_id(conn_name), i);
 | 
						|
 | 
						|
				}
 | 
						|
 | 
						|
				cell->setPort(conn_name, sig);
 | 
						|
			}
 | 
						|
 | 
						|
			if (cell_node->data_dict.count("attributes"))
 | 
						|
				json_parse_attr_param(cell->attributes, cell_node->data_dict.at("attributes"));
 | 
						|
 | 
						|
			if (cell_node->data_dict.count("parameters"))
 | 
						|
				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;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// remove duplicates from connections array
 | 
						|
	pool<RTLIL::SigSig> unique_connections(module->connections_.begin(), module->connections_.end());
 | 
						|
	module->connections_ = std::vector<RTLIL::SigSig>(unique_connections.begin(), unique_connections.end());
 | 
						|
}
 | 
						|
 | 
						|
struct JsonFrontend : public Frontend {
 | 
						|
	JsonFrontend() : Frontend("json", "read JSON file") { }
 | 
						|
	void help() override
 | 
						|
	{
 | 
						|
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
						|
		log("\n");
 | 
						|
		log("    read_json [filename]\n");
 | 
						|
		log("\n");
 | 
						|
		log("Load modules from a JSON file into the current design See \"help write_json\"\n");
 | 
						|
		log("for a description of the file format.\n");
 | 
						|
		log("\n");
 | 
						|
	}
 | 
						|
	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
 | 
						|
	{
 | 
						|
		log_header(design, "Executing JSON frontend.\n");
 | 
						|
 | 
						|
		size_t argidx;
 | 
						|
		for (argidx = 1; argidx < args.size(); argidx++) {
 | 
						|
			// std::string arg = args[argidx];
 | 
						|
			// if (arg == "-sop") {
 | 
						|
			// 	sop_mode = true;
 | 
						|
			// 	continue;
 | 
						|
			// }
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		extra_args(f, filename, args, argidx);
 | 
						|
 | 
						|
		JsonNode root(*f);
 | 
						|
 | 
						|
		if (root.type != 'D')
 | 
						|
			log_error("JSON root node is not a dictionary.\n");
 | 
						|
 | 
						|
		if (root.data_dict.count("modules") != 0)
 | 
						|
		{
 | 
						|
			JsonNode *modules = root.data_dict.at("modules");
 | 
						|
 | 
						|
			if (modules->type != 'D')
 | 
						|
				log_error("JSON modules node is not a dictionary.\n");
 | 
						|
 | 
						|
			for (auto &it : modules->data_dict)
 | 
						|
				json_import(design, it.first, it.second);
 | 
						|
		}
 | 
						|
	}
 | 
						|
} JsonFrontend;
 | 
						|
 | 
						|
YOSYS_NAMESPACE_END
 |