mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +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
 |