mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	Merge branch 'YosysHQ:main' into master
This commit is contained in:
		
						commit
						e3f633fae6
					
				
					 29 changed files with 1110 additions and 551 deletions
				
			
		
							
								
								
									
										3
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -141,7 +141,7 @@ LIBS += -lrt
 | 
			
		|||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
YOSYS_VER := 0.39+147
 | 
			
		||||
YOSYS_VER := 0.39+165
 | 
			
		||||
 | 
			
		||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
 | 
			
		||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
 | 
			
		||||
| 
						 | 
				
			
			@ -628,6 +628,7 @@ $(eval $(call add_include_file,kernel/sigtools.h))
 | 
			
		|||
$(eval $(call add_include_file,kernel/timinginfo.h))
 | 
			
		||||
$(eval $(call add_include_file,kernel/utils.h))
 | 
			
		||||
$(eval $(call add_include_file,kernel/yosys.h))
 | 
			
		||||
$(eval $(call add_include_file,kernel/yosys_common.h))
 | 
			
		||||
$(eval $(call add_include_file,kernel/yw.h))
 | 
			
		||||
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
 | 
			
		||||
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -625,11 +625,11 @@ struct value : public expr_base<value<Bits>> {
 | 
			
		|||
		value<Bits + 1> remainder;
 | 
			
		||||
		value<Bits + 1> dividend = sext<Bits + 1>();
 | 
			
		||||
		value<Bits + 1> divisor = other.template sext<Bits + 1>();
 | 
			
		||||
		if (dividend.is_neg()) dividend = dividend.neg();
 | 
			
		||||
		if (divisor.is_neg()) divisor = divisor.neg();
 | 
			
		||||
		if (is_neg()) dividend = dividend.neg();
 | 
			
		||||
		if (other.is_neg()) divisor = divisor.neg();
 | 
			
		||||
		std::tie(quotient, remainder) = dividend.udivmod(divisor);
 | 
			
		||||
		if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg();
 | 
			
		||||
		if (dividend.is_neg()) remainder = remainder.neg();
 | 
			
		||||
		if (is_neg() != other.is_neg()) quotient = quotient.neg();
 | 
			
		||||
		if (is_neg()) remainder = remainder.neg();
 | 
			
		||||
		return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1010,22 +1010,24 @@ struct observer {
 | 
			
		|||
// Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
 | 
			
		||||
struct fmt_part {
 | 
			
		||||
	enum {
 | 
			
		||||
		STRING    = 0,
 | 
			
		||||
		LITERAL   = 0,
 | 
			
		||||
		INTEGER   = 1,
 | 
			
		||||
		CHARACTER = 2,
 | 
			
		||||
		VLOG_TIME = 3,
 | 
			
		||||
		STRING    = 2,
 | 
			
		||||
		UNICHAR   = 3,
 | 
			
		||||
		VLOG_TIME = 4,
 | 
			
		||||
	} type;
 | 
			
		||||
 | 
			
		||||
	// STRING type
 | 
			
		||||
	// LITERAL type
 | 
			
		||||
	std::string str;
 | 
			
		||||
 | 
			
		||||
	// INTEGER/CHARACTER types
 | 
			
		||||
	// INTEGER/STRING/UNICHAR types
 | 
			
		||||
	// + value<Bits> val;
 | 
			
		||||
 | 
			
		||||
	// INTEGER/CHARACTER/VLOG_TIME types
 | 
			
		||||
	// INTEGER/STRING/VLOG_TIME types
 | 
			
		||||
	enum {
 | 
			
		||||
		RIGHT	= 0,
 | 
			
		||||
		LEFT	= 1,
 | 
			
		||||
		NUMERIC	= 2,
 | 
			
		||||
	} justify; // = RIGHT;
 | 
			
		||||
	char padding; // = '\0';
 | 
			
		||||
	size_t width; // = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1033,7 +1035,14 @@ struct fmt_part {
 | 
			
		|||
	// INTEGER type
 | 
			
		||||
	unsigned base; // = 10;
 | 
			
		||||
	bool signed_; // = false;
 | 
			
		||||
	bool plus; // = false;
 | 
			
		||||
	enum {
 | 
			
		||||
		MINUS		= 0,
 | 
			
		||||
		PLUS_MINUS	= 1,
 | 
			
		||||
		SPACE_MINUS	= 2,
 | 
			
		||||
	} sign; // = MINUS;
 | 
			
		||||
	bool hex_upper; // = false;
 | 
			
		||||
	bool show_base; // = false;
 | 
			
		||||
	bool group; // = false;
 | 
			
		||||
 | 
			
		||||
	// VLOG_TIME type
 | 
			
		||||
	bool realtime; // = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1049,11 +1058,12 @@ struct fmt_part {
 | 
			
		|||
		// We might want to replace some of these bit() calls with direct
 | 
			
		||||
		// chunk access if it turns out to be slow enough to matter.
 | 
			
		||||
		std::string buf;
 | 
			
		||||
		std::string prefix;
 | 
			
		||||
		switch (type) {
 | 
			
		||||
			case STRING:
 | 
			
		||||
			case LITERAL:
 | 
			
		||||
				return str;
 | 
			
		||||
 | 
			
		||||
			case CHARACTER: {
 | 
			
		||||
			case STRING: {
 | 
			
		||||
				buf.reserve(Bits/8);
 | 
			
		||||
				for (int i = 0; i < Bits; i += 8) {
 | 
			
		||||
					char ch = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1067,35 +1077,76 @@ struct fmt_part {
 | 
			
		|||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case UNICHAR: {
 | 
			
		||||
				uint32_t codepoint = val.template get<uint32_t>();
 | 
			
		||||
				if (codepoint >= 0x10000)
 | 
			
		||||
					buf += (char)(0xf0 |  (codepoint >> 18));
 | 
			
		||||
				else if (codepoint >= 0x800)
 | 
			
		||||
					buf += (char)(0xe0 |  (codepoint >> 12));
 | 
			
		||||
				else if (codepoint >= 0x80)
 | 
			
		||||
					buf += (char)(0xc0 |  (codepoint >>  6));
 | 
			
		||||
				else
 | 
			
		||||
					buf += (char)codepoint;
 | 
			
		||||
				if (codepoint >= 0x10000)
 | 
			
		||||
					buf += (char)(0x80 | ((codepoint >> 12) & 0x3f));
 | 
			
		||||
				if (codepoint >= 0x800)
 | 
			
		||||
					buf += (char)(0x80 | ((codepoint >>  6) & 0x3f));
 | 
			
		||||
				if (codepoint >= 0x80)
 | 
			
		||||
					buf += (char)(0x80 | ((codepoint >>  0) & 0x3f));
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case INTEGER: {
 | 
			
		||||
				size_t width = Bits;
 | 
			
		||||
				bool negative = signed_ && val.is_neg();
 | 
			
		||||
				if (negative) {
 | 
			
		||||
					prefix = "-";
 | 
			
		||||
					val = val.neg();
 | 
			
		||||
				} else {
 | 
			
		||||
					switch (sign) {
 | 
			
		||||
						case MINUS:       break;
 | 
			
		||||
						case PLUS_MINUS:  prefix = "+"; break;
 | 
			
		||||
						case SPACE_MINUS: prefix = " "; break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				size_t val_width = Bits;
 | 
			
		||||
				if (base != 10) {
 | 
			
		||||
					width = 0;
 | 
			
		||||
					val_width = 1;
 | 
			
		||||
					for (size_t index = 0; index < Bits; index++)
 | 
			
		||||
						if (val.bit(index))
 | 
			
		||||
							width = index + 1;
 | 
			
		||||
							val_width = index + 1;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (base == 2) {
 | 
			
		||||
					for (size_t i = width; i > 0; i--)
 | 
			
		||||
						buf += (val.bit(i - 1) ? '1' : '0');
 | 
			
		||||
					if (show_base)
 | 
			
		||||
						prefix += "0b";
 | 
			
		||||
					for (size_t index = 0; index < val_width; index++) {
 | 
			
		||||
						if (group && index > 0 && index % 4 == 0)
 | 
			
		||||
							buf += '_';
 | 
			
		||||
						buf += (val.bit(index) ? '1' : '0');
 | 
			
		||||
					}
 | 
			
		||||
				} else if (base == 8 || base == 16) {
 | 
			
		||||
					if (show_base)
 | 
			
		||||
						prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
 | 
			
		||||
					size_t step = (base == 16) ? 4 : 3;
 | 
			
		||||
					for (size_t index = 0; index < width; index += step) {
 | 
			
		||||
					for (size_t index = 0; index < val_width; index += step) {
 | 
			
		||||
						if (group && index > 0 && index % (4 * step) == 0)
 | 
			
		||||
							buf += '_';
 | 
			
		||||
						uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
 | 
			
		||||
						if (step == 4)
 | 
			
		||||
							value |= val.bit(index + 3) << 3;
 | 
			
		||||
						buf += "0123456789abcdef"[value];
 | 
			
		||||
						buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value];
 | 
			
		||||
					}
 | 
			
		||||
					std::reverse(buf.begin(), buf.end());
 | 
			
		||||
				} else if (base == 10) {
 | 
			
		||||
					bool negative = signed_ && val.is_neg();
 | 
			
		||||
					if (negative)
 | 
			
		||||
						val = val.neg();
 | 
			
		||||
					if (show_base)
 | 
			
		||||
						prefix += "0d";
 | 
			
		||||
					if (val.is_zero())
 | 
			
		||||
						buf += '0';
 | 
			
		||||
					value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
 | 
			
		||||
					size_t index = 0;
 | 
			
		||||
					while (!xval.is_zero()) {
 | 
			
		||||
						if (group && index > 0 && index % 3 == 0)
 | 
			
		||||
							buf += '_';
 | 
			
		||||
						value<(Bits > 4 ? Bits : 4)> quotient, remainder;
 | 
			
		||||
						if (Bits >= 4)
 | 
			
		||||
							std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
 | 
			
		||||
| 
						 | 
				
			
			@ -1103,11 +1154,18 @@ struct fmt_part {
 | 
			
		|||
							std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
 | 
			
		||||
						buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
 | 
			
		||||
						xval = quotient;
 | 
			
		||||
						index++;
 | 
			
		||||
					}
 | 
			
		||||
					if (negative || plus)
 | 
			
		||||
						buf += negative ? '-' : '+';
 | 
			
		||||
					std::reverse(buf.begin(), buf.end());
 | 
			
		||||
				} else assert(false && "Unsupported base for fmt_part");
 | 
			
		||||
				if (justify == NUMERIC && group && padding == '0') {
 | 
			
		||||
					int group_size = base == 10 ? 3 : 4;
 | 
			
		||||
					while (prefix.size() + buf.size() < width) {
 | 
			
		||||
						if (buf.size() % (group_size + 1) == group_size)
 | 
			
		||||
							buf += '_';
 | 
			
		||||
						buf += '0';
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				std::reverse(buf.begin(), buf.end());
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1123,17 +1181,29 @@ struct fmt_part {
 | 
			
		|||
 | 
			
		||||
		std::string str;
 | 
			
		||||
		assert(width == 0 || padding != '\0');
 | 
			
		||||
		if (justify == RIGHT && buf.size() < width) {
 | 
			
		||||
			size_t pad_width = width - buf.size();
 | 
			
		||||
			if (padding == '0' && (buf.front() == '+' || buf.front() == '-')) {
 | 
			
		||||
				str += buf.front();
 | 
			
		||||
				buf.erase(0, 1);
 | 
			
		||||
			}
 | 
			
		||||
			str += std::string(pad_width, padding);
 | 
			
		||||
		if (prefix.size() + buf.size() < width) {
 | 
			
		||||
			size_t pad_width = width - prefix.size() - buf.size();
 | 
			
		||||
			switch (justify) {
 | 
			
		||||
				case LEFT:
 | 
			
		||||
					str += prefix;
 | 
			
		||||
					str += buf;
 | 
			
		||||
					str += std::string(pad_width, padding);
 | 
			
		||||
					break;
 | 
			
		||||
				case RIGHT:
 | 
			
		||||
					str += std::string(pad_width, padding);
 | 
			
		||||
					str += prefix;
 | 
			
		||||
					str += buf;
 | 
			
		||||
					break;
 | 
			
		||||
				case NUMERIC:
 | 
			
		||||
					str += prefix;
 | 
			
		||||
					str += std::string(pad_width, padding);
 | 
			
		||||
					str += buf;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
		} else {
 | 
			
		||||
			str += prefix;
 | 
			
		||||
			str += buf;
 | 
			
		||||
		}
 | 
			
		||||
		str += buf;
 | 
			
		||||
		if (justify == LEFT && buf.size() < width)
 | 
			
		||||
			str += std::string(width - buf.size(), padding);
 | 
			
		||||
		return str;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1070,7 +1070,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 | 
			
		|||
		f << stringf(";\n");
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if (cell->type == ID($_BUF_)) {
 | 
			
		||||
		f << stringf("%s" "assign ", indent.c_str());
 | 
			
		||||
		dump_sigspec(f, cell->getPort(ID::Y));
 | 
			
		||||
| 
						 | 
				
			
			@ -2014,22 +2014,29 @@ void dump_sync_effect(std::ostream &f, std::string indent, const RTLIL::SigSpec
 | 
			
		|||
 | 
			
		||||
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
 | 
			
		||||
{
 | 
			
		||||
	if (simple_lhs) {
 | 
			
		||||
	bool all_chunks_wires = true;
 | 
			
		||||
	for (auto &chunk : left.chunks())
 | 
			
		||||
		if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
 | 
			
		||||
			all_chunks_wires = false;
 | 
			
		||||
	if (!simple_lhs && all_chunks_wires) {
 | 
			
		||||
		f << stringf("%s" "assign ", indent.c_str());
 | 
			
		||||
		dump_sigspec(f, left);
 | 
			
		||||
		f << stringf(" = ");
 | 
			
		||||
		dump_sigspec(f, right);
 | 
			
		||||
		f << stringf(";\n");
 | 
			
		||||
	} else {
 | 
			
		||||
		int offset = 0;
 | 
			
		||||
		for (auto &chunk : left.chunks()) {
 | 
			
		||||
			f << stringf("%s" "assign ", indent.c_str());
 | 
			
		||||
			if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
 | 
			
		||||
				f << stringf("%s" "always%s\n%s  ", indent.c_str(), systemverilog ? "_comb" : " @*", indent.c_str());
 | 
			
		||||
			else
 | 
			
		||||
				f << stringf("%s" "assign ", indent.c_str());
 | 
			
		||||
			dump_sigspec(f, chunk);
 | 
			
		||||
			f << stringf(" = ");
 | 
			
		||||
			dump_sigspec(f, right.extract(offset, GetSize(chunk)));
 | 
			
		||||
			f << stringf(";\n");
 | 
			
		||||
			offset += GetSize(chunk);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		f << stringf("%s" "assign ", indent.c_str());
 | 
			
		||||
		dump_sigspec(f, left);
 | 
			
		||||
		f << stringf(" = ");
 | 
			
		||||
		dump_sigspec(f, right);
 | 
			
		||||
		f << stringf(";\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2276,11 +2283,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
 | 
			
		|||
					active_initdata[sig[i]] = val[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (!module->processes.empty())
 | 
			
		||||
		log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
 | 
			
		||||
				"can't always be mapped directly to Verilog always blocks. Unintended\n"
 | 
			
		||||
				"changes in simulation behavior are possible! Use \"proc\" to convert\n"
 | 
			
		||||
				"processes to logic networks and registers.\n", log_id(module));
 | 
			
		||||
	bool has_sync_rules = false;
 | 
			
		||||
	for (auto process : module->processes)
 | 
			
		||||
		if (!process.second->syncs.empty())
 | 
			
		||||
			has_sync_rules = true;
 | 
			
		||||
	if (has_sync_rules)
 | 
			
		||||
		log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL "
 | 
			
		||||
				"processes can't always be mapped directly to Verilog always blocks. "
 | 
			
		||||
				"unintended changes in simulation behavior are possible! Use \"proc\" "
 | 
			
		||||
				"to convert processes to logic networks and registers.\n", log_id(module));
 | 
			
		||||
 | 
			
		||||
	f << stringf("\n");
 | 
			
		||||
	for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -619,6 +619,48 @@ Finite state machines
 | 
			
		|||
 | 
			
		||||
Add a brief description of the ``$fsm`` cell type.
 | 
			
		||||
 | 
			
		||||
Coarse arithmetics
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The ``$macc`` cell type represents a generalized multiply and accumulate operation. The cell is purely combinational. It outputs the result of summing up a sequence of products and other injected summands.
 | 
			
		||||
 | 
			
		||||
.. code-block::
 | 
			
		||||
 | 
			
		||||
	Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ...
 | 
			
		||||
	     + B[0] + B[1] + ...
 | 
			
		||||
 | 
			
		||||
The A port consists of concatenated pairs of multiplier inputs ("factors").
 | 
			
		||||
A zero length factor2 acts as a constant 1, turning factor1 into a simple summand.
 | 
			
		||||
 | 
			
		||||
In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long.
 | 
			
		||||
 | 
			
		||||
.. code-block::
 | 
			
		||||
 | 
			
		||||
	struct A {
 | 
			
		||||
		u(CONFIG.mul_info[0].factor1_len) a0factor1;
 | 
			
		||||
		u(CONFIG.mul_info[0].factor2_len) a0factor2;
 | 
			
		||||
		u(CONFIG.mul_info[1].factor1_len) a1factor1;
 | 
			
		||||
		u(CONFIG.mul_info[1].factor2_len) a1factor2;
 | 
			
		||||
		...
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
The cell's ``CONFIG`` parameter determines the layout of cell port ``A``.
 | 
			
		||||
The CONFIG parameter carries the following information:
 | 
			
		||||
 | 
			
		||||
.. code-block::
 | 
			
		||||
 | 
			
		||||
	struct CONFIG {
 | 
			
		||||
		u4 num_bits;
 | 
			
		||||
		struct mul_info {
 | 
			
		||||
			bool is_signed;
 | 
			
		||||
			bool is_subtract;
 | 
			
		||||
			u(num_bits) factor1_len;
 | 
			
		||||
			u(num_bits) factor2_len;
 | 
			
		||||
		}[num_ports];
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
B is an array of concatenated 1-bit-wide unsigned integers to also be summed up.
 | 
			
		||||
 | 
			
		||||
Specify rules
 | 
			
		||||
~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1152,4 +1194,4 @@ file via ABC using the abc pass.
 | 
			
		|||
 | 
			
		||||
.. todo:: Add information about ``$lut`` and ``$sop`` cells.
 | 
			
		||||
 | 
			
		||||
.. todo:: Add information about ``$alu``, ``$macc``, ``$fa``, and ``$lcu`` cells.
 | 
			
		||||
.. todo:: Add information about ``$alu``, ``$fa``, and ``$lcu`` cells.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -790,7 +790,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				Fmt fmt;
 | 
			
		||||
				fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
 | 
			
		||||
				if (ast->str.substr(0, 8) == "$display")
 | 
			
		||||
					fmt.append_string("\n");
 | 
			
		||||
					fmt.append_literal("\n");
 | 
			
		||||
				fmt.emit_rtlil(cell);
 | 
			
		||||
			} else if (!ast->str.empty()) {
 | 
			
		||||
				log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1079,7 +1079,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
 | 
			
		|||
				// when $display()/$write() functions are used in an initial block, print them during synthesis
 | 
			
		||||
				Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base, /*first_arg_at=*/0, /*may_fail=*/true);
 | 
			
		||||
				if (str.substr(0, 8) == "$display")
 | 
			
		||||
					fmt.append_string("\n");
 | 
			
		||||
					fmt.append_literal("\n");
 | 
			
		||||
				log("%s", fmt.render().c_str());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ Formatting of code
 | 
			
		|||
  blank lines.
 | 
			
		||||
 | 
			
		||||
- Otherwise stick to the Linux Kernel Coding Style:
 | 
			
		||||
    https://www.kernel.org/doc/Documentation/CodingStyle
 | 
			
		||||
    https://www.kernel.org/doc/Documentation/process/coding-style.rst
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
C++ Language
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										306
									
								
								kernel/fmt.cc
									
										
									
									
									
								
							
							
						
						
									
										306
									
								
								kernel/fmt.cc
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -22,9 +22,9 @@
 | 
			
		|||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
 | 
			
		||||
void Fmt::append_string(const std::string &str) {
 | 
			
		||||
void Fmt::append_literal(const std::string &str) {
 | 
			
		||||
	FmtPart part = {};
 | 
			
		||||
	part.type = FmtPart::STRING;
 | 
			
		||||
	part.type = FmtPart::LITERAL;
 | 
			
		||||
	part.str = str;
 | 
			
		||||
	parts.push_back(part);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -42,11 +42,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
		} else if (fmt.substr(i, 2) == "{{") {
 | 
			
		||||
			part.str += '{';
 | 
			
		||||
			++i;
 | 
			
		||||
		} else if (fmt[i] == '}')
 | 
			
		||||
		} else if (fmt[i] == '}') {
 | 
			
		||||
			log_assert(false && "Unexpected '}' in format string");
 | 
			
		||||
		else if (fmt[i] == '{') {
 | 
			
		||||
		} else if (fmt[i] == '{') {
 | 
			
		||||
			if (!part.str.empty()) {
 | 
			
		||||
				part.type = FmtPart::STRING;
 | 
			
		||||
				part.type = FmtPart::LITERAL;
 | 
			
		||||
				parts.push_back(part);
 | 
			
		||||
				part = {};
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -74,19 +74,24 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
			part.sig = args.extract(0, arg_size);
 | 
			
		||||
			args.remove(0, arg_size);
 | 
			
		||||
 | 
			
		||||
			if (fmt[i] == 'U') {
 | 
			
		||||
				part.type = FmtPart::UNICHAR;
 | 
			
		||||
				++i;
 | 
			
		||||
				goto success;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (fmt[i] == '>')
 | 
			
		||||
				part.justify = FmtPart::RIGHT;
 | 
			
		||||
			else if (fmt[i] == '<')
 | 
			
		||||
				part.justify = FmtPart::LEFT;
 | 
			
		||||
			else if (fmt[i] == '=')
 | 
			
		||||
				part.justify = FmtPart::NUMERIC;
 | 
			
		||||
			else
 | 
			
		||||
				log_assert(false && "Unexpected justification in format substitution");
 | 
			
		||||
			if (++i == fmt.size())
 | 
			
		||||
				log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
 | 
			
		||||
			if (fmt[i] == '0' || fmt[i] == ' ')
 | 
			
		||||
				part.padding = fmt[i];
 | 
			
		||||
			else
 | 
			
		||||
				log_assert(false && "Unexpected padding in format substitution");
 | 
			
		||||
			part.padding = fmt[i];
 | 
			
		||||
			if (++i == fmt.size())
 | 
			
		||||
				log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,8 +112,12 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
				} else if (fmt[i] == 'h') {
 | 
			
		||||
					part.type = FmtPart::INTEGER;
 | 
			
		||||
					part.base = 16;
 | 
			
		||||
				} else if (fmt[i] == 'H') {
 | 
			
		||||
					part.type = FmtPart::INTEGER;
 | 
			
		||||
					part.base = 16;
 | 
			
		||||
					part.hex_upper = true;
 | 
			
		||||
				} else if (fmt[i] == 'c') {
 | 
			
		||||
					part.type = FmtPart::CHARACTER;
 | 
			
		||||
					part.type = FmtPart::STRING;
 | 
			
		||||
				} else if (fmt[i] == 't') {
 | 
			
		||||
					part.type = FmtPart::VLOG_TIME;
 | 
			
		||||
				} else if (fmt[i] == 'r') {
 | 
			
		||||
| 
						 | 
				
			
			@ -124,10 +133,29 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
				log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
 | 
			
		||||
			if (part.type == FmtPart::INTEGER) {
 | 
			
		||||
				if (fmt[i] == '+') {
 | 
			
		||||
					part.plus = true;
 | 
			
		||||
				if (fmt[i] == '-') {
 | 
			
		||||
					part.sign = FmtPart::MINUS;
 | 
			
		||||
					if (++i == fmt.size())
 | 
			
		||||
						log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
				} else if (fmt[i] == '+') {
 | 
			
		||||
					part.sign = FmtPart::PLUS_MINUS;
 | 
			
		||||
					if (++i == fmt.size())
 | 
			
		||||
						log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
				} else if (fmt[i] == ' ') {
 | 
			
		||||
					part.sign = FmtPart::SPACE_MINUS;
 | 
			
		||||
					if (++i == fmt.size())
 | 
			
		||||
						log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
				} else {
 | 
			
		||||
					// also accept no sign character and treat like MINUS for compatibility
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (fmt[i] == '#') {
 | 
			
		||||
					part.show_base = true;
 | 
			
		||||
					++i;
 | 
			
		||||
				}
 | 
			
		||||
				if (fmt[i] == '_') {
 | 
			
		||||
					part.group = true;
 | 
			
		||||
					++i;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (fmt[i] == 'u')
 | 
			
		||||
| 
						 | 
				
			
			@ -140,6 +168,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
					log_assert(false && "Unexpected end in format substitution");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		success:
 | 
			
		||||
			if (fmt[i] != '}')
 | 
			
		||||
				log_assert(false && "Expected '}' after format substitution");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +179,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!part.str.empty()) {
 | 
			
		||||
		part.type = FmtPart::STRING;
 | 
			
		||||
		part.type = FmtPart::LITERAL;
 | 
			
		||||
		parts.push_back(part);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +190,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
 | 
			
		|||
 | 
			
		||||
	for (auto &part : parts) {
 | 
			
		||||
		switch (part.type) {
 | 
			
		||||
			case FmtPart::STRING:
 | 
			
		||||
			case FmtPart::LITERAL:
 | 
			
		||||
				for (char c : part.str) {
 | 
			
		||||
					if (c == '{')
 | 
			
		||||
						fmt += "{{";
 | 
			
		||||
| 
						 | 
				
			
			@ -172,10 +201,15 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
 | 
			
		|||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case FmtPart::UNICHAR:
 | 
			
		||||
				log_assert(part.sig.size() <= 32);
 | 
			
		||||
				fmt += "{U}";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case FmtPart::VLOG_TIME:
 | 
			
		||||
				log_assert(part.sig.size() == 0);
 | 
			
		||||
				YS_FALLTHROUGH
 | 
			
		||||
			case FmtPart::CHARACTER:
 | 
			
		||||
			case FmtPart::STRING:
 | 
			
		||||
				log_assert(part.sig.size() % 8 == 0);
 | 
			
		||||
				YS_FALLTHROUGH
 | 
			
		||||
			case FmtPart::INTEGER:
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +221,8 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
 | 
			
		|||
					fmt += '>';
 | 
			
		||||
				else if (part.justify == FmtPart::LEFT)
 | 
			
		||||
					fmt += '<';
 | 
			
		||||
				else if (part.justify == FmtPart::NUMERIC)
 | 
			
		||||
					fmt += '=';
 | 
			
		||||
				else log_abort();
 | 
			
		||||
				log_assert(part.width == 0 || part.padding != '\0');
 | 
			
		||||
				fmt += part.padding != '\0' ? part.padding : ' ';
 | 
			
		||||
| 
						 | 
				
			
			@ -197,13 +233,18 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
 | 
			
		|||
						case  2: fmt += 'b'; break;
 | 
			
		||||
						case  8: fmt += 'o'; break;
 | 
			
		||||
						case 10: fmt += 'd'; break;
 | 
			
		||||
						case 16: fmt += 'h'; break;
 | 
			
		||||
						case 16: fmt += part.hex_upper ? 'H' : 'h'; break;
 | 
			
		||||
						default: log_abort();
 | 
			
		||||
					}
 | 
			
		||||
					if (part.plus)
 | 
			
		||||
						fmt += '+';
 | 
			
		||||
					switch (part.sign) {
 | 
			
		||||
						case FmtPart::MINUS:       fmt += '-'; break;
 | 
			
		||||
						case FmtPart::PLUS_MINUS:  fmt += '+'; break;
 | 
			
		||||
						case FmtPart::SPACE_MINUS: fmt += ' '; break;
 | 
			
		||||
					}
 | 
			
		||||
					fmt += part.show_base ? "#" : "";
 | 
			
		||||
					fmt += part.group ? "_" : "";
 | 
			
		||||
					fmt += part.signed_ ? 's' : 'u';
 | 
			
		||||
				} else if (part.type == FmtPart::CHARACTER) {
 | 
			
		||||
				} else if (part.type == FmtPart::STRING) {
 | 
			
		||||
					fmt += 'c';
 | 
			
		||||
				} else if (part.type == FmtPart::VLOG_TIME) {
 | 
			
		||||
					if (part.realtime)
 | 
			
		||||
| 
						 | 
				
			
			@ -299,12 +340,12 @@ void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part)
 | 
			
		|||
		part.width = places;
 | 
			
		||||
 | 
			
		||||
		if (part.justify == FmtPart::RIGHT) {
 | 
			
		||||
			append_string(gap);
 | 
			
		||||
			append_literal(gap);
 | 
			
		||||
			parts.push_back(part);
 | 
			
		||||
		} else {
 | 
			
		||||
			part.justify = FmtPart::RIGHT;
 | 
			
		||||
			parts.push_back(part);
 | 
			
		||||
			append_string(gap);
 | 
			
		||||
			append_literal(gap);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +396,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
 | 
			
		|||
							part.str += module_name.str();
 | 
			
		||||
						} else {
 | 
			
		||||
							if (!part.str.empty()) {
 | 
			
		||||
								part.type = FmtPart::STRING;
 | 
			
		||||
								part.type = FmtPart::LITERAL;
 | 
			
		||||
								parts.push_back(part);
 | 
			
		||||
								part = {};
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			@ -375,7 +416,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
 | 
			
		|||
									part.justify = FmtPart::LEFT;
 | 
			
		||||
								} else if (fmt[i] == '+') {
 | 
			
		||||
									// always show sign; not in IEEE 1800-2017 or verilator but iverilog has it
 | 
			
		||||
									part.plus = true;
 | 
			
		||||
									part.sign = FmtPart::PLUS_MINUS;
 | 
			
		||||
								} else break;
 | 
			
		||||
							}
 | 
			
		||||
							if (i == fmt.size()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -408,11 +449,11 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
 | 
			
		|||
									part.type = FmtPart::INTEGER;
 | 
			
		||||
									part.base = 16;
 | 
			
		||||
								} else if (fmt[i] == 'c' || fmt[i] == 'C') {
 | 
			
		||||
									part.type = FmtPart::CHARACTER;
 | 
			
		||||
									part.type = FmtPart::STRING;
 | 
			
		||||
									part.sig.extend_u0(8);
 | 
			
		||||
									// %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog
 | 
			
		||||
								} else if (fmt[i] == 's' || fmt[i] == 'S') {
 | 
			
		||||
									part.type = FmtPart::CHARACTER;
 | 
			
		||||
									part.type = FmtPart::STRING;
 | 
			
		||||
									if ((part.sig.size() % 8) != 0)
 | 
			
		||||
										part.sig.extend_u0((part.sig.size() + 7) / 8 * 8);
 | 
			
		||||
									// %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog
 | 
			
		||||
| 
						 | 
				
			
			@ -435,12 +476,20 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
 | 
			
		|||
								log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if (part.padding == '\0')
 | 
			
		||||
								part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' ';
 | 
			
		||||
							if (part.padding == '\0') {
 | 
			
		||||
								if (has_leading_zero && part.justify == FmtPart::RIGHT) {
 | 
			
		||||
									part.padding = '0';
 | 
			
		||||
									part.justify = FmtPart::NUMERIC;
 | 
			
		||||
								} else {
 | 
			
		||||
									part.padding = ' ';
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus)
 | 
			
		||||
							if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS)
 | 
			
		||||
								log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
 | 
			
		||||
 | 
			
		||||
							if (part.base != 10)
 | 
			
		||||
								part.signed_ = false;
 | 
			
		||||
							if (part.type == FmtPart::INTEGER && !has_leading_zero)
 | 
			
		||||
								apply_verilog_automatic_sizing_and_add(part);
 | 
			
		||||
							else
 | 
			
		||||
| 
						 | 
				
			
			@ -449,12 +498,12 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
 | 
			
		|||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (!part.str.empty()) {
 | 
			
		||||
						part.type = FmtPart::STRING;
 | 
			
		||||
						part.type = FmtPart::LITERAL;
 | 
			
		||||
						parts.push_back(part);
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					FmtPart part = {};
 | 
			
		||||
					part.type = FmtPart::STRING;
 | 
			
		||||
					part.type = FmtPart::LITERAL;
 | 
			
		||||
					part.str = arg->str;
 | 
			
		||||
					parts.push_back(part);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -474,7 +523,7 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
 | 
			
		||||
	for (auto &part : parts) {
 | 
			
		||||
		switch (part.type) {
 | 
			
		||||
			case FmtPart::STRING:
 | 
			
		||||
			case FmtPart::LITERAL:
 | 
			
		||||
				for (char c : part.str) {
 | 
			
		||||
					if (c == '%')
 | 
			
		||||
						fmt.str += "%%";
 | 
			
		||||
| 
						 | 
				
			
			@ -491,14 +540,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
				args.push_back(arg);
 | 
			
		||||
 | 
			
		||||
				fmt.str += '%';
 | 
			
		||||
				if (part.plus)
 | 
			
		||||
					fmt.str += '+';
 | 
			
		||||
				if (part.sign == FmtPart::PLUS_MINUS || part.sign == FmtPart::SPACE_MINUS)
 | 
			
		||||
					fmt.str += '+'; // treat space/minus as plus/minus
 | 
			
		||||
				if (part.justify == FmtPart::LEFT)
 | 
			
		||||
					fmt.str += '-';
 | 
			
		||||
				if (part.width == 0) {
 | 
			
		||||
					fmt.str += '0';
 | 
			
		||||
				} else if (part.width > 0) {
 | 
			
		||||
					log_assert(part.padding == ' ' || part.padding == '0');
 | 
			
		||||
					if (part.base != 10 || part.padding == '0')
 | 
			
		||||
						fmt.str += '0';
 | 
			
		||||
					fmt.str += std::to_string(part.width);
 | 
			
		||||
| 
						 | 
				
			
			@ -507,13 +555,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
					case  2: fmt.str += 'b'; break;
 | 
			
		||||
					case  8: fmt.str += 'o'; break;
 | 
			
		||||
					case 10: fmt.str += 'd'; break;
 | 
			
		||||
					case 16: fmt.str += 'h'; break;
 | 
			
		||||
					case 16: fmt.str += 'h'; break; // treat uppercase hex as lowercase
 | 
			
		||||
					default: log_abort();
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case FmtPart::CHARACTER: {
 | 
			
		||||
			case FmtPart::STRING: {
 | 
			
		||||
				VerilogFmtArg arg;
 | 
			
		||||
				arg.type = VerilogFmtArg::INTEGER;
 | 
			
		||||
				arg.sig = part.sig;
 | 
			
		||||
| 
						 | 
				
			
			@ -524,7 +572,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
					fmt.str += '-';
 | 
			
		||||
				if (part.sig.size() == 8) {
 | 
			
		||||
					if (part.width > 0) {
 | 
			
		||||
						log_assert(part.padding == '0' || part.padding == ' ');
 | 
			
		||||
						if (part.padding == '0')
 | 
			
		||||
							fmt.str += part.padding;
 | 
			
		||||
						fmt.str += std::to_string(part.width);
 | 
			
		||||
| 
						 | 
				
			
			@ -533,7 +580,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
				} else {
 | 
			
		||||
					log_assert(part.sig.size() % 8 == 0);
 | 
			
		||||
					if (part.width > 0) {
 | 
			
		||||
						log_assert(part.padding == ' '); // no zero padding
 | 
			
		||||
						fmt.str += std::to_string(part.width);
 | 
			
		||||
					}
 | 
			
		||||
					fmt.str += 's';
 | 
			
		||||
| 
						 | 
				
			
			@ -541,6 +587,16 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case FmtPart::UNICHAR: {
 | 
			
		||||
				VerilogFmtArg arg;
 | 
			
		||||
				arg.type = VerilogFmtArg::INTEGER;
 | 
			
		||||
				arg.sig = part.sig.extract(0, 7); // only ASCII
 | 
			
		||||
				args.push_back(arg);
 | 
			
		||||
 | 
			
		||||
				fmt.str += "%c";
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case FmtPart::VLOG_TIME: {
 | 
			
		||||
				VerilogFmtArg arg;
 | 
			
		||||
				arg.type = VerilogFmtArg::TIME;
 | 
			
		||||
| 
						 | 
				
			
			@ -549,11 +605,11 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
 | 
			
		|||
				args.push_back(arg);
 | 
			
		||||
 | 
			
		||||
				fmt.str += '%';
 | 
			
		||||
				if (part.plus)
 | 
			
		||||
				log_assert(part.sign == FmtPart::MINUS || part.sign == FmtPart::PLUS_MINUS);
 | 
			
		||||
				if (part.sign == FmtPart::PLUS_MINUS)
 | 
			
		||||
					fmt.str += '+';
 | 
			
		||||
				if (part.justify == FmtPart::LEFT)
 | 
			
		||||
					fmt.str += '-';
 | 
			
		||||
				log_assert(part.padding == ' ' || part.padding == '0');
 | 
			
		||||
				if (part.padding == '0' && part.width > 0)
 | 
			
		||||
					fmt.str += '0';
 | 
			
		||||
				fmt.str += std::to_string(part.width);
 | 
			
		||||
| 
						 | 
				
			
			@ -599,24 +655,35 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
 | 
			
		|||
		os << indent << "buf += fmt_part { ";
 | 
			
		||||
		os << "fmt_part::";
 | 
			
		||||
		switch (part.type) {
 | 
			
		||||
			case FmtPart::STRING:    os << "STRING";    break;
 | 
			
		||||
			case FmtPart::LITERAL:   os << "LITERAL";   break;
 | 
			
		||||
			case FmtPart::INTEGER:   os << "INTEGER";   break;
 | 
			
		||||
			case FmtPart::CHARACTER: os << "CHARACTER"; break;
 | 
			
		||||
			case FmtPart::STRING:    os << "STRING";    break;
 | 
			
		||||
			case FmtPart::UNICHAR:   os << "UNICHAR";   break;
 | 
			
		||||
			case FmtPart::VLOG_TIME: os << "VLOG_TIME"; break;
 | 
			
		||||
		}
 | 
			
		||||
		os << ", ";
 | 
			
		||||
		os << escape_cxx_string(part.str) << ", ";
 | 
			
		||||
		os << "fmt_part::";
 | 
			
		||||
		switch (part.justify) {
 | 
			
		||||
			case FmtPart::LEFT:  os << "LEFT";  break;
 | 
			
		||||
			case FmtPart::RIGHT: os << "RIGHT"; break;
 | 
			
		||||
			case FmtPart::LEFT:    os << "LEFT";    break;
 | 
			
		||||
			case FmtPart::RIGHT:   os << "RIGHT";   break;
 | 
			
		||||
			case FmtPart::NUMERIC: os << "NUMERIC"; break;
 | 
			
		||||
		}
 | 
			
		||||
		os << ", ";
 | 
			
		||||
		os << "(char)" << (int)part.padding << ", ";
 | 
			
		||||
		os << part.width << ", ";
 | 
			
		||||
		os << part.base << ", ";
 | 
			
		||||
		os << part.signed_ << ", ";
 | 
			
		||||
		os << part.plus << ", ";
 | 
			
		||||
		os << "fmt_part::";
 | 
			
		||||
		switch (part.sign) {
 | 
			
		||||
			case FmtPart::MINUS:       os << "MINUS";       break;
 | 
			
		||||
			case FmtPart::PLUS_MINUS:  os << "PLUS_MINUS";  break;
 | 
			
		||||
			case FmtPart::SPACE_MINUS: os << "SPACE_MINUS"; break;
 | 
			
		||||
		}
 | 
			
		||||
		os << ", ";
 | 
			
		||||
		os << part.hex_upper << ", ";
 | 
			
		||||
		os << part.show_base << ", ";
 | 
			
		||||
		os << part.group << ", ";
 | 
			
		||||
		os << part.realtime;
 | 
			
		||||
		os << " }.render(";
 | 
			
		||||
		emit_sig(part.sig);
 | 
			
		||||
| 
						 | 
				
			
			@ -631,19 +698,62 @@ std::string Fmt::render() const
 | 
			
		|||
 | 
			
		||||
	for (auto &part : parts) {
 | 
			
		||||
		switch (part.type) {
 | 
			
		||||
			case FmtPart::STRING:
 | 
			
		||||
			case FmtPart::LITERAL:
 | 
			
		||||
				str += part.str;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case FmtPart::UNICHAR: {
 | 
			
		||||
				RTLIL::Const value = part.sig.as_const();
 | 
			
		||||
				uint32_t codepoint = value.as_int();
 | 
			
		||||
				if (codepoint >= 0x10000)
 | 
			
		||||
					str += (char)(0xf0 |  (codepoint >> 18));
 | 
			
		||||
				else if (codepoint >= 0x800)
 | 
			
		||||
					str += (char)(0xe0 |  (codepoint >> 12));
 | 
			
		||||
				else if (codepoint >= 0x80)
 | 
			
		||||
					str += (char)(0xc0 |  (codepoint >>  6));
 | 
			
		||||
				else
 | 
			
		||||
					str += (char)codepoint;
 | 
			
		||||
				if (codepoint >= 0x10000)
 | 
			
		||||
					str += (char)(0x80 | ((codepoint >> 12) & 0x3f));
 | 
			
		||||
				if (codepoint >= 0x800)
 | 
			
		||||
					str += (char)(0x80 | ((codepoint >>  6) & 0x3f));
 | 
			
		||||
				if (codepoint >= 0x80)
 | 
			
		||||
					str += (char)(0x80 | ((codepoint >>  0) & 0x3f));
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case FmtPart::INTEGER:
 | 
			
		||||
			case FmtPart::CHARACTER:
 | 
			
		||||
			case FmtPart::STRING:
 | 
			
		||||
			case FmtPart::VLOG_TIME: {
 | 
			
		||||
				std::string buf;
 | 
			
		||||
				std::string prefix;
 | 
			
		||||
				if (part.type == FmtPart::INTEGER) {
 | 
			
		||||
					RTLIL::Const value = part.sig.as_const();
 | 
			
		||||
					bool has_x = false, all_x = true, has_z = false, all_z = true;
 | 
			
		||||
					for (State bit : value) {
 | 
			
		||||
						if (bit == State::Sx)
 | 
			
		||||
							has_x = true;
 | 
			
		||||
						else
 | 
			
		||||
							all_x = false;
 | 
			
		||||
						if (bit == State::Sz)
 | 
			
		||||
							has_z = true;
 | 
			
		||||
						else
 | 
			
		||||
							all_z = false;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (!has_z && !has_x && part.signed_ && value[value.size() - 1]) {
 | 
			
		||||
						prefix = "-";
 | 
			
		||||
						value = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
 | 
			
		||||
					} else {
 | 
			
		||||
						switch (part.sign) {
 | 
			
		||||
							case FmtPart::MINUS:       break;
 | 
			
		||||
							case FmtPart::PLUS_MINUS:  prefix = "+"; break;
 | 
			
		||||
							case FmtPart::SPACE_MINUS: prefix = " "; break;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (part.base != 10) {
 | 
			
		||||
						size_t minimum_size = 0;
 | 
			
		||||
						size_t minimum_size = 1;
 | 
			
		||||
						for (size_t index = 0; index < (size_t)value.size(); index++)
 | 
			
		||||
							if (value[index] != State::S0)
 | 
			
		||||
								minimum_size = index + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -651,10 +761,28 @@ std::string Fmt::render() const
 | 
			
		|||
					}
 | 
			
		||||
 | 
			
		||||
					if (part.base == 2) {
 | 
			
		||||
						buf = value.as_string();
 | 
			
		||||
						if (part.show_base)
 | 
			
		||||
							prefix += "0b";
 | 
			
		||||
						for (size_t index = 0; index < (size_t)value.size(); index++) {
 | 
			
		||||
							if (part.group && index > 0 && index % 4 == 0)
 | 
			
		||||
								buf += '_';
 | 
			
		||||
							RTLIL::State bit = value[index];
 | 
			
		||||
							if (bit == State::Sx)
 | 
			
		||||
								buf += 'x';
 | 
			
		||||
							else if (bit == State::Sz)
 | 
			
		||||
								buf += 'z';
 | 
			
		||||
							else if (bit == State::S1)
 | 
			
		||||
								buf += '1';
 | 
			
		||||
							else /* if (bit == State::S0) */
 | 
			
		||||
								buf += '0';
 | 
			
		||||
						}
 | 
			
		||||
					} else if (part.base == 8 || part.base == 16) {
 | 
			
		||||
						if (part.show_base)
 | 
			
		||||
							prefix += (part.base == 16) ? (part.hex_upper ? "0X" : "0x") : "0o";
 | 
			
		||||
						size_t step = (part.base == 16) ? 4 : 3;
 | 
			
		||||
						for (size_t index = 0; index < (size_t)value.size(); index += step) {
 | 
			
		||||
							if (part.group && index > 0 && index % (4 * step) == 0)
 | 
			
		||||
								buf += '_';
 | 
			
		||||
							RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index));
 | 
			
		||||
							bool has_x = false, all_x = true, has_z = false, all_z = true;
 | 
			
		||||
							for (State bit : subvalue) {
 | 
			
		||||
| 
						 | 
				
			
			@ -676,21 +804,11 @@ std::string Fmt::render() const
 | 
			
		|||
							else if (has_z)
 | 
			
		||||
								buf += 'Z';
 | 
			
		||||
							else
 | 
			
		||||
								buf += "0123456789abcdef"[subvalue.as_int()];
 | 
			
		||||
								buf += (part.hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[subvalue.as_int()];
 | 
			
		||||
						}
 | 
			
		||||
						std::reverse(buf.begin(), buf.end());
 | 
			
		||||
					} else if (part.base == 10) {
 | 
			
		||||
						bool has_x = false, all_x = true, has_z = false, all_z = true;
 | 
			
		||||
						for (State bit : value) {
 | 
			
		||||
							if (bit == State::Sx)
 | 
			
		||||
								has_x = true;
 | 
			
		||||
							else
 | 
			
		||||
								all_x = false;
 | 
			
		||||
							if (bit == State::Sz)
 | 
			
		||||
								has_z = true;
 | 
			
		||||
							else
 | 
			
		||||
								all_z = false;
 | 
			
		||||
						}
 | 
			
		||||
						if (part.show_base)
 | 
			
		||||
							prefix += "0d";
 | 
			
		||||
						if (all_x)
 | 
			
		||||
							buf += 'x';
 | 
			
		||||
						else if (all_z)
 | 
			
		||||
| 
						 | 
				
			
			@ -700,25 +818,29 @@ std::string Fmt::render() const
 | 
			
		|||
						else if (has_z)
 | 
			
		||||
							buf += 'Z';
 | 
			
		||||
						else {
 | 
			
		||||
							bool negative = part.signed_ && value[value.size() - 1];
 | 
			
		||||
							RTLIL::Const absvalue;
 | 
			
		||||
							if (negative)
 | 
			
		||||
								absvalue = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
 | 
			
		||||
							else
 | 
			
		||||
								absvalue = value;
 | 
			
		||||
							log_assert(absvalue.is_fully_def());
 | 
			
		||||
							if (absvalue.is_fully_zero())
 | 
			
		||||
							log_assert(value.is_fully_def());
 | 
			
		||||
							if (value.is_fully_zero())
 | 
			
		||||
								buf += '0';
 | 
			
		||||
							while (!absvalue.is_fully_zero())	{
 | 
			
		||||
								buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int();
 | 
			
		||||
								absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size());
 | 
			
		||||
							size_t index = 0;
 | 
			
		||||
							while (!value.is_fully_zero())	{
 | 
			
		||||
								if (part.group && index > 0 && index % 3 == 0)
 | 
			
		||||
									buf += '_';
 | 
			
		||||
								buf += '0' + RTLIL::const_mod(value, 10, false, false, 4).as_int();
 | 
			
		||||
								value = RTLIL::const_div(value, 10, false, false, value.size());
 | 
			
		||||
								index++;
 | 
			
		||||
							}
 | 
			
		||||
							if (negative || part.plus)
 | 
			
		||||
								buf += negative ? '-' : '+';
 | 
			
		||||
							std::reverse(buf.begin(), buf.end());
 | 
			
		||||
						}
 | 
			
		||||
					} else log_abort();
 | 
			
		||||
				} else if (part.type == FmtPart::CHARACTER) {
 | 
			
		||||
					if (part.justify == FmtPart::NUMERIC && part.group && part.padding == '0') {
 | 
			
		||||
						int group_size = part.base == 10 ? 3 : 4;
 | 
			
		||||
						while (prefix.size() + buf.size() < part.width) {
 | 
			
		||||
							if (buf.size() % (group_size + 1) == group_size)
 | 
			
		||||
								buf += '_';
 | 
			
		||||
							buf += '0';
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					std::reverse(buf.begin(), buf.end());
 | 
			
		||||
				} else if (part.type == FmtPart::STRING) {
 | 
			
		||||
					buf = part.sig.as_const().decode_string();
 | 
			
		||||
				} else if (part.type == FmtPart::VLOG_TIME) {
 | 
			
		||||
					// We only render() during initial, so time is always zero.
 | 
			
		||||
| 
						 | 
				
			
			@ -726,17 +848,29 @@ std::string Fmt::render() const
 | 
			
		|||
				}
 | 
			
		||||
 | 
			
		||||
				log_assert(part.width == 0 || part.padding != '\0');
 | 
			
		||||
				if (part.justify == FmtPart::RIGHT && buf.size() < part.width) {
 | 
			
		||||
					size_t pad_width = part.width - buf.size();
 | 
			
		||||
					if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) {
 | 
			
		||||
						str += buf.front();
 | 
			
		||||
						buf.erase(0, 1);
 | 
			
		||||
				if (prefix.size() + buf.size() < part.width) {
 | 
			
		||||
					size_t pad_width = part.width - prefix.size() - buf.size();
 | 
			
		||||
					switch (part.justify) {
 | 
			
		||||
						case FmtPart::LEFT:
 | 
			
		||||
							str += prefix;
 | 
			
		||||
							str += buf;
 | 
			
		||||
							str += std::string(pad_width, part.padding);
 | 
			
		||||
							break;
 | 
			
		||||
						case FmtPart::RIGHT:
 | 
			
		||||
							str += std::string(pad_width, part.padding);
 | 
			
		||||
							str += prefix;
 | 
			
		||||
							str += buf;
 | 
			
		||||
							break;
 | 
			
		||||
						case FmtPart::NUMERIC:
 | 
			
		||||
							str += prefix;
 | 
			
		||||
							str += std::string(pad_width, part.padding);
 | 
			
		||||
							str += buf;
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					str += std::string(pad_width, part.padding);
 | 
			
		||||
				} else {
 | 
			
		||||
					str += prefix;
 | 
			
		||||
					str += buf;
 | 
			
		||||
				}
 | 
			
		||||
				str += buf;
 | 
			
		||||
				if (part.justify == FmtPart::LEFT && buf.size() < part.width)
 | 
			
		||||
					str += std::string(part.width - buf.size(), part.padding);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								kernel/fmt.h
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								kernel/fmt.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -53,22 +53,24 @@ struct VerilogFmtArg {
 | 
			
		|||
// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!
 | 
			
		||||
struct FmtPart {
 | 
			
		||||
	enum {
 | 
			
		||||
		STRING  	= 0,
 | 
			
		||||
		LITERAL  	= 0,
 | 
			
		||||
		INTEGER 	= 1,
 | 
			
		||||
		CHARACTER = 2,
 | 
			
		||||
		VLOG_TIME = 3,
 | 
			
		||||
		STRING    = 2,
 | 
			
		||||
		UNICHAR   = 3,
 | 
			
		||||
		VLOG_TIME = 4,
 | 
			
		||||
	} type;
 | 
			
		||||
 | 
			
		||||
	// STRING type
 | 
			
		||||
	// LITERAL type
 | 
			
		||||
	std::string str;
 | 
			
		||||
 | 
			
		||||
	// INTEGER/CHARACTER types
 | 
			
		||||
	// INTEGER/STRING/UNICHAR types
 | 
			
		||||
	RTLIL::SigSpec sig;
 | 
			
		||||
 | 
			
		||||
	// INTEGER/CHARACTER/VLOG_TIME types
 | 
			
		||||
	// INTEGER/STRING/VLOG_TIME types
 | 
			
		||||
	enum {
 | 
			
		||||
		RIGHT	= 0,
 | 
			
		||||
		LEFT	= 1,
 | 
			
		||||
		NUMERIC	= 2,
 | 
			
		||||
	} justify = RIGHT;
 | 
			
		||||
	char padding = '\0';
 | 
			
		||||
	size_t width = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +78,14 @@ struct FmtPart {
 | 
			
		|||
	// INTEGER type
 | 
			
		||||
	unsigned base = 10;
 | 
			
		||||
	bool signed_ = false;
 | 
			
		||||
	bool plus = false;
 | 
			
		||||
	enum {
 | 
			
		||||
		MINUS		= 0,
 | 
			
		||||
		PLUS_MINUS	= 1,
 | 
			
		||||
		SPACE_MINUS	= 2,
 | 
			
		||||
	} sign = MINUS;
 | 
			
		||||
	bool hex_upper = false;
 | 
			
		||||
	bool show_base = false;
 | 
			
		||||
	bool group = false;
 | 
			
		||||
 | 
			
		||||
	// VLOG_TIME type
 | 
			
		||||
	bool realtime = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +95,7 @@ struct Fmt {
 | 
			
		|||
public:
 | 
			
		||||
	std::vector<FmtPart> parts;
 | 
			
		||||
 | 
			
		||||
	void append_string(const std::string &str);
 | 
			
		||||
	void append_literal(const std::string &str);
 | 
			
		||||
 | 
			
		||||
	void parse_rtlil(const RTLIL::Cell *cell);
 | 
			
		||||
	void emit_rtlil(RTLIL::Cell *cell) const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,11 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
#ifndef LOG_H
 | 
			
		||||
#define LOG_H
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#include <regex>
 | 
			
		||||
| 
						 | 
				
			
			@ -449,4 +449,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
 | 
			
		|||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,12 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
#ifndef REGISTER_H
 | 
			
		||||
#define REGISTER_H
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
struct Pass
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,12 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
#ifndef RTLIL_H
 | 
			
		||||
#define RTLIL_H
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
namespace RTLIL
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										346
									
								
								kernel/yosys.h
									
										
									
									
									
								
							
							
						
						
									
										346
									
								
								kernel/yosys.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -39,323 +39,7 @@
 | 
			
		|||
#ifndef YOSYS_H
 | 
			
		||||
#define YOSYS_H
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <istream>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_PYTHON
 | 
			
		||||
#include <Python.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef _YOSYS_
 | 
			
		||||
#  error It looks like you are trying to build Yosys without the config defines set. \
 | 
			
		||||
         When building Yosys with a custom make system, make sure you set all the \
 | 
			
		||||
         defines the Yosys Makefile would set for your build configuration.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef YOSYS_ENABLE_TCL
 | 
			
		||||
#  include <tcl.h>
 | 
			
		||||
#  ifdef YOSYS_MXE_HACKS
 | 
			
		||||
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
 | 
			
		||||
extern Tcl_Interp *Tcl_CreateInterp(void);
 | 
			
		||||
extern void Tcl_Preserve(ClientData data);
 | 
			
		||||
extern void Tcl_Release(ClientData clientData);
 | 
			
		||||
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
 | 
			
		||||
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
 | 
			
		||||
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
 | 
			
		||||
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
 | 
			
		||||
extern void Tcl_Finalize(void);
 | 
			
		||||
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
 | 
			
		||||
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
 | 
			
		||||
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
 | 
			
		||||
#  endif
 | 
			
		||||
#  undef CONST
 | 
			
		||||
#  undef INLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#  undef NOMINMAX
 | 
			
		||||
#  define NOMINMAX 1
 | 
			
		||||
#  undef YY_NO_UNISTD_H
 | 
			
		||||
#  define YY_NO_UNISTD_H 1
 | 
			
		||||
 | 
			
		||||
#  include <windows.h>
 | 
			
		||||
#  include <io.h>
 | 
			
		||||
#  include <direct.h>
 | 
			
		||||
 | 
			
		||||
#  define strtok_r strtok_s
 | 
			
		||||
#  define strdup _strdup
 | 
			
		||||
#  define snprintf _snprintf
 | 
			
		||||
#  define getcwd _getcwd
 | 
			
		||||
#  define mkdir _mkdir
 | 
			
		||||
#  define popen _popen
 | 
			
		||||
#  define pclose _pclose
 | 
			
		||||
 | 
			
		||||
#  ifndef __MINGW32__
 | 
			
		||||
#    define PATH_MAX MAX_PATH
 | 
			
		||||
#    define isatty _isatty
 | 
			
		||||
#    define fileno _fileno
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
// The following defines conflict with our identifiers:
 | 
			
		||||
#  undef CONST
 | 
			
		||||
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
 | 
			
		||||
#  undef TRANSPARENT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PATH_MAX
 | 
			
		||||
#  define PATH_MAX 4096
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define YOSYS_NAMESPACE          Yosys
 | 
			
		||||
#define PRIVATE_NAMESPACE_BEGIN  namespace {
 | 
			
		||||
#define PRIVATE_NAMESPACE_END    }
 | 
			
		||||
#define YOSYS_NAMESPACE_BEGIN    namespace Yosys {
 | 
			
		||||
#define YOSYS_NAMESPACE_END      }
 | 
			
		||||
#define YOSYS_NAMESPACE_PREFIX   Yosys::
 | 
			
		||||
#define USING_YOSYS_NAMESPACE    using namespace Yosys;
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#  define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
#  define YS_ATTRIBUTE(...)
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_ATTRIBUTE(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#  define YS_MAYBE_UNUSED __attribute__((__unused__))
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_MAYBE_UNUSED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __cplusplus >= 201703L
 | 
			
		||||
#  define YS_FALLTHROUGH [[fallthrough]];
 | 
			
		||||
#elif defined(__clang__)
 | 
			
		||||
#  define YS_FALLTHROUGH [[clang::fallthrough]];
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
#  define YS_FALLTHROUGH [[gnu::fallthrough]];
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_FALLTHROUGH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
// Note: All headers included in hashlib.h must be included
 | 
			
		||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
 | 
			
		||||
#ifdef HASHLIB_H
 | 
			
		||||
#  undef HASHLIB_H
 | 
			
		||||
#  include "kernel/hashlib.h"
 | 
			
		||||
#else
 | 
			
		||||
#  include "kernel/hashlib.h"
 | 
			
		||||
#  undef HASHLIB_H
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using std::vector;
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::tuple;
 | 
			
		||||
using std::pair;
 | 
			
		||||
 | 
			
		||||
using std::make_tuple;
 | 
			
		||||
using std::make_pair;
 | 
			
		||||
using std::get;
 | 
			
		||||
using std::min;
 | 
			
		||||
using std::max;
 | 
			
		||||
 | 
			
		||||
// A primitive shared string implementation that does not
 | 
			
		||||
// move its .c_str() when the object is copied or moved.
 | 
			
		||||
struct shared_str {
 | 
			
		||||
	std::shared_ptr<string> content;
 | 
			
		||||
	shared_str() { }
 | 
			
		||||
	shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
 | 
			
		||||
	shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
 | 
			
		||||
	const char *c_str() const { return content->c_str(); }
 | 
			
		||||
	const string &str() const { return *content; }
 | 
			
		||||
	bool operator==(const shared_str &other) const { return *content == *other.content; }
 | 
			
		||||
	unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using hashlib::mkhash;
 | 
			
		||||
using hashlib::mkhash_init;
 | 
			
		||||
using hashlib::mkhash_add;
 | 
			
		||||
using hashlib::mkhash_xorshift;
 | 
			
		||||
using hashlib::hash_ops;
 | 
			
		||||
using hashlib::hash_cstr_ops;
 | 
			
		||||
using hashlib::hash_ptr_ops;
 | 
			
		||||
using hashlib::hash_obj_ops;
 | 
			
		||||
using hashlib::dict;
 | 
			
		||||
using hashlib::idict;
 | 
			
		||||
using hashlib::pool;
 | 
			
		||||
using hashlib::mfp;
 | 
			
		||||
 | 
			
		||||
namespace RTLIL {
 | 
			
		||||
	struct IdString;
 | 
			
		||||
	struct Const;
 | 
			
		||||
	struct SigBit;
 | 
			
		||||
	struct SigSpec;
 | 
			
		||||
	struct Wire;
 | 
			
		||||
	struct Cell;
 | 
			
		||||
	struct Memory;
 | 
			
		||||
	struct Process;
 | 
			
		||||
	struct Module;
 | 
			
		||||
	struct Design;
 | 
			
		||||
	struct Monitor;
 | 
			
		||||
	enum State : unsigned char;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace AST {
 | 
			
		||||
	struct AstNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using RTLIL::IdString;
 | 
			
		||||
using RTLIL::Const;
 | 
			
		||||
using RTLIL::SigBit;
 | 
			
		||||
using RTLIL::SigSpec;
 | 
			
		||||
using RTLIL::Wire;
 | 
			
		||||
using RTLIL::Cell;
 | 
			
		||||
using RTLIL::Module;
 | 
			
		||||
using RTLIL::Design;
 | 
			
		||||
 | 
			
		||||
namespace hashlib {
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
 | 
			
		||||
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void memhasher_on();
 | 
			
		||||
void memhasher_off();
 | 
			
		||||
void memhasher_do();
 | 
			
		||||
 | 
			
		||||
extern bool memhasher_active;
 | 
			
		||||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
 | 
			
		||||
 | 
			
		||||
void yosys_banner();
 | 
			
		||||
int ceil_log2(int x) YS_ATTRIBUTE(const);
 | 
			
		||||
 | 
			
		||||
inline std::string vstringf(const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
        // For the common case of strings shorter than 128, save a heap
 | 
			
		||||
        // allocation by using a stack allocated buffer.
 | 
			
		||||
        const int kBufSize = 128;
 | 
			
		||||
        char buf[kBufSize];
 | 
			
		||||
        buf[0] = '\0';
 | 
			
		||||
        va_list apc;
 | 
			
		||||
        va_copy(apc, ap);
 | 
			
		||||
        int n = vsnprintf(buf, kBufSize, fmt, apc);
 | 
			
		||||
        va_end(apc);
 | 
			
		||||
        if (n < kBufSize)
 | 
			
		||||
          return std::string(buf);
 | 
			
		||||
 | 
			
		||||
        std::string string;
 | 
			
		||||
        char *str = NULL;
 | 
			
		||||
#if defined(_WIN32 )|| defined(__CYGWIN__)
 | 
			
		||||
        int sz = 2 * kBufSize, rc;
 | 
			
		||||
        while (1) {
 | 
			
		||||
		va_copy(apc, ap);
 | 
			
		||||
		str = (char*)realloc(str, sz);
 | 
			
		||||
		rc = vsnprintf(str, sz, fmt, apc);
 | 
			
		||||
		va_end(apc);
 | 
			
		||||
		if (rc >= 0 && rc < sz)
 | 
			
		||||
			break;
 | 
			
		||||
		sz *= 2;
 | 
			
		||||
	}
 | 
			
		||||
	if (str != NULL) {
 | 
			
		||||
		string = str;
 | 
			
		||||
		free(str);
 | 
			
		||||
	}
 | 
			
		||||
	return string;
 | 
			
		||||
#else
 | 
			
		||||
        if (vasprintf(&str, fmt, ap) < 0)
 | 
			
		||||
          str = NULL;
 | 
			
		||||
        if (str != NULL) {
 | 
			
		||||
          string = str;
 | 
			
		||||
          free(str);
 | 
			
		||||
        }
 | 
			
		||||
	return string;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
 | 
			
		||||
 | 
			
		||||
inline std::string stringf(const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	std::string string;
 | 
			
		||||
	va_list ap;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	string = vstringf(fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
 | 
			
		||||
	return string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int readsome(std::istream &f, char *s, int n);
 | 
			
		||||
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
 | 
			
		||||
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
 | 
			
		||||
bool patmatch(const char *pattern, const char *string);
 | 
			
		||||
#if !defined(YOSYS_DISABLE_SPAWN)
 | 
			
		||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
 | 
			
		||||
#endif
 | 
			
		||||
std::string get_base_tmpdir();
 | 
			
		||||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
 | 
			
		||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
 | 
			
		||||
bool check_file_exists(std::string filename, bool is_exec = false);
 | 
			
		||||
bool check_directory_exists(const std::string& dirname);
 | 
			
		||||
bool is_absolute_path(std::string filename);
 | 
			
		||||
void remove_directory(std::string dirname);
 | 
			
		||||
bool create_directory(const std::string& dirname);
 | 
			
		||||
std::string escape_filename_spaces(const std::string& filename);
 | 
			
		||||
 | 
			
		||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
 | 
			
		||||
inline int GetSize(RTLIL::Wire *wire);
 | 
			
		||||
 | 
			
		||||
extern int autoidx;
 | 
			
		||||
extern int yosys_xtrace;
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -363,14 +47,6 @@ YOSYS_NAMESPACE_END
 | 
			
		|||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
using RTLIL::State;
 | 
			
		||||
using RTLIL::SigChunk;
 | 
			
		||||
using RTLIL::SigSig;
 | 
			
		||||
 | 
			
		||||
namespace hashlib {
 | 
			
		||||
	template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void yosys_setup();
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_PYTHON
 | 
			
		||||
| 
						 | 
				
			
			@ -385,26 +61,6 @@ Tcl_Interp *yosys_get_tcl_interp();
 | 
			
		|||
 | 
			
		||||
extern RTLIL::Design *yosys_design;
 | 
			
		||||
 | 
			
		||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
 | 
			
		||||
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
 | 
			
		||||
 | 
			
		||||
#define NEW_ID \
 | 
			
		||||
	YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
 | 
			
		||||
#define NEW_ID_SUFFIX(suffix) \
 | 
			
		||||
	YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
 | 
			
		||||
 | 
			
		||||
// Create a statically allocated IdString object, using for example ID::A or ID($add).
 | 
			
		||||
//
 | 
			
		||||
// Recipe for Converting old code that is using conversion of strings like ID::A and
 | 
			
		||||
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
 | 
			
		||||
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
 | 
			
		||||
//
 | 
			
		||||
//  sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
 | 
			
		||||
//
 | 
			
		||||
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
 | 
			
		||||
        static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
 | 
			
		||||
namespace ID = RTLIL::ID;
 | 
			
		||||
 | 
			
		||||
RTLIL::Design *yosys_get_design();
 | 
			
		||||
std::string proc_self_dirname();
 | 
			
		||||
std::string proc_share_dirname();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										379
									
								
								kernel/yosys_common.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								kernel/yosys_common.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,379 @@
 | 
			
		|||
/* -*- 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.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef YOSYS_COMMON_H
 | 
			
		||||
#define YOSYS_COMMON_H
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <istream>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_PYTHON
 | 
			
		||||
#include <Python.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef _YOSYS_
 | 
			
		||||
#  error It looks like you are trying to build Yosys without the config defines set. \
 | 
			
		||||
         When building Yosys with a custom make system, make sure you set all the \
 | 
			
		||||
         defines the Yosys Makefile would set for your build configuration.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef YOSYS_ENABLE_TCL
 | 
			
		||||
#  include <tcl.h>
 | 
			
		||||
#  ifdef YOSYS_MXE_HACKS
 | 
			
		||||
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
 | 
			
		||||
extern Tcl_Interp *Tcl_CreateInterp(void);
 | 
			
		||||
extern void Tcl_Preserve(ClientData data);
 | 
			
		||||
extern void Tcl_Release(ClientData clientData);
 | 
			
		||||
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
 | 
			
		||||
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
 | 
			
		||||
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
 | 
			
		||||
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
 | 
			
		||||
extern void Tcl_Finalize(void);
 | 
			
		||||
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
 | 
			
		||||
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
 | 
			
		||||
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
 | 
			
		||||
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
 | 
			
		||||
#  endif
 | 
			
		||||
#  undef CONST
 | 
			
		||||
#  undef INLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#  undef NOMINMAX
 | 
			
		||||
#  define NOMINMAX 1
 | 
			
		||||
#  undef YY_NO_UNISTD_H
 | 
			
		||||
#  define YY_NO_UNISTD_H 1
 | 
			
		||||
 | 
			
		||||
#  include <windows.h>
 | 
			
		||||
#  include <io.h>
 | 
			
		||||
#  include <direct.h>
 | 
			
		||||
 | 
			
		||||
#  define strtok_r strtok_s
 | 
			
		||||
#  define strdup _strdup
 | 
			
		||||
#  define snprintf _snprintf
 | 
			
		||||
#  define getcwd _getcwd
 | 
			
		||||
#  define mkdir _mkdir
 | 
			
		||||
#  define popen _popen
 | 
			
		||||
#  define pclose _pclose
 | 
			
		||||
 | 
			
		||||
#  ifndef __MINGW32__
 | 
			
		||||
#    define PATH_MAX MAX_PATH
 | 
			
		||||
#    define isatty _isatty
 | 
			
		||||
#    define fileno _fileno
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
// The following defines conflict with our identifiers:
 | 
			
		||||
#  undef CONST
 | 
			
		||||
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
 | 
			
		||||
#  undef TRANSPARENT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PATH_MAX
 | 
			
		||||
#  define PATH_MAX 4096
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define YOSYS_NAMESPACE          Yosys
 | 
			
		||||
#define PRIVATE_NAMESPACE_BEGIN  namespace {
 | 
			
		||||
#define PRIVATE_NAMESPACE_END    }
 | 
			
		||||
#define YOSYS_NAMESPACE_BEGIN    namespace Yosys {
 | 
			
		||||
#define YOSYS_NAMESPACE_END      }
 | 
			
		||||
#define YOSYS_NAMESPACE_PREFIX   Yosys::
 | 
			
		||||
#define USING_YOSYS_NAMESPACE    using namespace Yosys;
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#  define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
#  define YS_ATTRIBUTE(...)
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_ATTRIBUTE(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#  define YS_MAYBE_UNUSED __attribute__((__unused__))
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_MAYBE_UNUSED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __cplusplus >= 201703L
 | 
			
		||||
#  define YS_FALLTHROUGH [[fallthrough]];
 | 
			
		||||
#elif defined(__clang__)
 | 
			
		||||
#  define YS_FALLTHROUGH [[clang::fallthrough]];
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
#  define YS_FALLTHROUGH [[gnu::fallthrough]];
 | 
			
		||||
#else
 | 
			
		||||
#  define YS_FALLTHROUGH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
// Note: All headers included in hashlib.h must be included
 | 
			
		||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
 | 
			
		||||
#ifdef HASHLIB_H
 | 
			
		||||
#  undef HASHLIB_H
 | 
			
		||||
#  include "kernel/hashlib.h"
 | 
			
		||||
#else
 | 
			
		||||
#  include "kernel/hashlib.h"
 | 
			
		||||
#  undef HASHLIB_H
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using std::vector;
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::tuple;
 | 
			
		||||
using std::pair;
 | 
			
		||||
 | 
			
		||||
using std::make_tuple;
 | 
			
		||||
using std::make_pair;
 | 
			
		||||
using std::get;
 | 
			
		||||
using std::min;
 | 
			
		||||
using std::max;
 | 
			
		||||
 | 
			
		||||
// A primitive shared string implementation that does not
 | 
			
		||||
// move its .c_str() when the object is copied or moved.
 | 
			
		||||
struct shared_str {
 | 
			
		||||
	std::shared_ptr<string> content;
 | 
			
		||||
	shared_str() { }
 | 
			
		||||
	shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
 | 
			
		||||
	shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
 | 
			
		||||
	const char *c_str() const { return content->c_str(); }
 | 
			
		||||
	const string &str() const { return *content; }
 | 
			
		||||
	bool operator==(const shared_str &other) const { return *content == *other.content; }
 | 
			
		||||
	unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using hashlib::mkhash;
 | 
			
		||||
using hashlib::mkhash_init;
 | 
			
		||||
using hashlib::mkhash_add;
 | 
			
		||||
using hashlib::mkhash_xorshift;
 | 
			
		||||
using hashlib::hash_ops;
 | 
			
		||||
using hashlib::hash_cstr_ops;
 | 
			
		||||
using hashlib::hash_ptr_ops;
 | 
			
		||||
using hashlib::hash_obj_ops;
 | 
			
		||||
using hashlib::dict;
 | 
			
		||||
using hashlib::idict;
 | 
			
		||||
using hashlib::pool;
 | 
			
		||||
using hashlib::mfp;
 | 
			
		||||
 | 
			
		||||
namespace RTLIL {
 | 
			
		||||
	struct IdString;
 | 
			
		||||
	struct Const;
 | 
			
		||||
	struct SigBit;
 | 
			
		||||
	struct SigSpec;
 | 
			
		||||
	struct Wire;
 | 
			
		||||
	struct Cell;
 | 
			
		||||
	struct Memory;
 | 
			
		||||
	struct Process;
 | 
			
		||||
	struct Module;
 | 
			
		||||
	struct Design;
 | 
			
		||||
	struct Monitor;
 | 
			
		||||
    struct Selection;
 | 
			
		||||
	struct SigChunk;
 | 
			
		||||
	enum State : unsigned char;
 | 
			
		||||
 | 
			
		||||
	typedef std::pair<SigSpec, SigSpec> SigSig;
 | 
			
		||||
 | 
			
		||||
    namespace ID {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace AST {
 | 
			
		||||
	struct AstNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using RTLIL::IdString;
 | 
			
		||||
using RTLIL::Const;
 | 
			
		||||
using RTLIL::SigBit;
 | 
			
		||||
using RTLIL::SigSpec;
 | 
			
		||||
using RTLIL::Wire;
 | 
			
		||||
using RTLIL::Cell;
 | 
			
		||||
using RTLIL::Module;
 | 
			
		||||
using RTLIL::Design;
 | 
			
		||||
 | 
			
		||||
using RTLIL::State;
 | 
			
		||||
using RTLIL::SigChunk;
 | 
			
		||||
using RTLIL::SigSig;
 | 
			
		||||
 | 
			
		||||
namespace hashlib {
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
 | 
			
		||||
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
 | 
			
		||||
	template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void memhasher_on();
 | 
			
		||||
void memhasher_off();
 | 
			
		||||
void memhasher_do();
 | 
			
		||||
 | 
			
		||||
extern bool memhasher_active;
 | 
			
		||||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
 | 
			
		||||
 | 
			
		||||
void yosys_banner();
 | 
			
		||||
int ceil_log2(int x) YS_ATTRIBUTE(const);
 | 
			
		||||
 | 
			
		||||
inline std::string vstringf(const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
        // For the common case of strings shorter than 128, save a heap
 | 
			
		||||
        // allocation by using a stack allocated buffer.
 | 
			
		||||
        const int kBufSize = 128;
 | 
			
		||||
        char buf[kBufSize];
 | 
			
		||||
        buf[0] = '\0';
 | 
			
		||||
        va_list apc;
 | 
			
		||||
        va_copy(apc, ap);
 | 
			
		||||
        int n = vsnprintf(buf, kBufSize, fmt, apc);
 | 
			
		||||
        va_end(apc);
 | 
			
		||||
        if (n < kBufSize)
 | 
			
		||||
          return std::string(buf);
 | 
			
		||||
 | 
			
		||||
        std::string string;
 | 
			
		||||
        char *str = NULL;
 | 
			
		||||
#if defined(_WIN32 )|| defined(__CYGWIN__)
 | 
			
		||||
        int sz = 2 * kBufSize, rc;
 | 
			
		||||
        while (1) {
 | 
			
		||||
		va_copy(apc, ap);
 | 
			
		||||
		str = (char*)realloc(str, sz);
 | 
			
		||||
		rc = vsnprintf(str, sz, fmt, apc);
 | 
			
		||||
		va_end(apc);
 | 
			
		||||
		if (rc >= 0 && rc < sz)
 | 
			
		||||
			break;
 | 
			
		||||
		sz *= 2;
 | 
			
		||||
	}
 | 
			
		||||
	if (str != NULL) {
 | 
			
		||||
		string = str;
 | 
			
		||||
		free(str);
 | 
			
		||||
	}
 | 
			
		||||
	return string;
 | 
			
		||||
#else
 | 
			
		||||
        if (vasprintf(&str, fmt, ap) < 0)
 | 
			
		||||
          str = NULL;
 | 
			
		||||
        if (str != NULL) {
 | 
			
		||||
          string = str;
 | 
			
		||||
          free(str);
 | 
			
		||||
        }
 | 
			
		||||
	return string;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
 | 
			
		||||
 | 
			
		||||
inline std::string stringf(const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	std::string string;
 | 
			
		||||
	va_list ap;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	string = vstringf(fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
 | 
			
		||||
	return string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int readsome(std::istream &f, char *s, int n);
 | 
			
		||||
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
 | 
			
		||||
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
 | 
			
		||||
bool patmatch(const char *pattern, const char *string);
 | 
			
		||||
#if !defined(YOSYS_DISABLE_SPAWN)
 | 
			
		||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
 | 
			
		||||
#endif
 | 
			
		||||
std::string get_base_tmpdir();
 | 
			
		||||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
 | 
			
		||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
 | 
			
		||||
bool check_file_exists(std::string filename, bool is_exec = false);
 | 
			
		||||
bool check_directory_exists(const std::string& dirname);
 | 
			
		||||
bool is_absolute_path(std::string filename);
 | 
			
		||||
void remove_directory(std::string dirname);
 | 
			
		||||
bool create_directory(const std::string& dirname);
 | 
			
		||||
std::string escape_filename_spaces(const std::string& filename);
 | 
			
		||||
 | 
			
		||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
 | 
			
		||||
inline int GetSize(RTLIL::Wire *wire);
 | 
			
		||||
 | 
			
		||||
extern int autoidx;
 | 
			
		||||
extern int yosys_xtrace;
 | 
			
		||||
 | 
			
		||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
 | 
			
		||||
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
 | 
			
		||||
 | 
			
		||||
#define NEW_ID \
 | 
			
		||||
	YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
 | 
			
		||||
#define NEW_ID_SUFFIX(suffix) \
 | 
			
		||||
	YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
 | 
			
		||||
 | 
			
		||||
// Create a statically allocated IdString object, using for example ID::A or ID($add).
 | 
			
		||||
//
 | 
			
		||||
// Recipe for Converting old code that is using conversion of strings like ID::A and
 | 
			
		||||
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
 | 
			
		||||
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
 | 
			
		||||
//
 | 
			
		||||
//  sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
 | 
			
		||||
//
 | 
			
		||||
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
 | 
			
		||||
        static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
 | 
			
		||||
namespace ID = RTLIL::ID;
 | 
			
		||||
 | 
			
		||||
namespace hashlib {
 | 
			
		||||
	template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,8 @@ struct cell_area_t {
 | 
			
		|||
struct statdata_t
 | 
			
		||||
{
 | 
			
		||||
	#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
 | 
			
		||||
			X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
 | 
			
		||||
			X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \
 | 
			
		||||
			X(num_processes)
 | 
			
		||||
 | 
			
		||||
	#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -90,6 +91,11 @@ struct statdata_t
 | 
			
		|||
 | 
			
		||||
		for (auto wire : mod->selected_wires())
 | 
			
		||||
		{
 | 
			
		||||
			if (wire->port_input || wire->port_output) {
 | 
			
		||||
				num_ports++;
 | 
			
		||||
				num_port_bits += wire->width;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (wire->name.isPublic()) {
 | 
			
		||||
				num_pub_wires++;
 | 
			
		||||
				num_pub_wire_bits += wire->width;
 | 
			
		||||
| 
						 | 
				
			
			@ -239,6 +245,8 @@ struct statdata_t
 | 
			
		|||
		log("   Number of wire bits:         %6u\n", num_wire_bits);
 | 
			
		||||
		log("   Number of public wires:      %6u\n", num_pub_wires);
 | 
			
		||||
		log("   Number of public wire bits:  %6u\n", num_pub_wire_bits);
 | 
			
		||||
		log("   Number of ports:             %6u\n", num_ports);
 | 
			
		||||
		log("   Number of port bits:         %6u\n", num_port_bits);
 | 
			
		||||
		log("   Number of memories:          %6u\n", num_memories);
 | 
			
		||||
		log("   Number of memory bits:       %6u\n", num_memory_bits);
 | 
			
		||||
		log("   Number of processes:         %6u\n", num_processes);
 | 
			
		||||
| 
						 | 
				
			
			@ -284,6 +292,8 @@ struct statdata_t
 | 
			
		|||
		log("         \"num_wire_bits\":     %u,\n", num_wire_bits);
 | 
			
		||||
		log("         \"num_pub_wires\":     %u,\n", num_pub_wires);
 | 
			
		||||
		log("         \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
 | 
			
		||||
		log("         \"num_ports\":         %u,\n", num_ports);
 | 
			
		||||
		log("         \"num_port_bits\":     %u,\n", num_port_bits);
 | 
			
		||||
		log("         \"num_memories\":      %u,\n", num_memories);
 | 
			
		||||
		log("         \"num_memory_bits\":   %u,\n", num_memory_bits);
 | 
			
		||||
		log("         \"num_processes\":     %u,\n", num_processes);
 | 
			
		||||
| 
						 | 
				
			
			@ -494,6 +504,8 @@ struct StatPass : public Pass {
 | 
			
		|||
			design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_pub_wire_bits", data.num_pub_wire_bits);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_ports", data.num_ports);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_port_bits", data.num_port_bits);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_memories", data.num_memories);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits);
 | 
			
		||||
			design->scratchpad_set_int("stat.num_processes", data.num_processes);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,3 +35,4 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_map.v))
 | 
			
		|||
$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
 | 
			
		||||
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
 | 
			
		||||
$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v))
 | 
			
		||||
$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										54
									
								
								techlibs/common/choices/kogge-stone.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								techlibs/common/choices/kogge-stone.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2024  Martin Povišer <povik@cutebit.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  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.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(* techmap_celltype = "$lcu" *)
 | 
			
		||||
module _80_lcu_kogge_stone (P, G, CI, CO);
 | 
			
		||||
	parameter WIDTH = 2;
 | 
			
		||||
 | 
			
		||||
	(* force_downto *)
 | 
			
		||||
	input [WIDTH-1:0] P, G;
 | 
			
		||||
	input CI;
 | 
			
		||||
 | 
			
		||||
	(* force_downto *)
 | 
			
		||||
	output [WIDTH-1:0] CO;
 | 
			
		||||
 | 
			
		||||
	integer i, j;
 | 
			
		||||
	(* force_downto *)
 | 
			
		||||
	reg [WIDTH-1:0] p, g;
 | 
			
		||||
 | 
			
		||||
	wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
 | 
			
		||||
 | 
			
		||||
	always @* begin
 | 
			
		||||
		p = P;
 | 
			
		||||
		g = G;
 | 
			
		||||
 | 
			
		||||
		// in almost all cases CI will be constant zero
 | 
			
		||||
		g[0] = g[0] | (p[0] & CI);
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < $clog2(WIDTH); i = i + 1) begin
 | 
			
		||||
			// iterate in reverse so we don't confuse a result from this stage and the previous
 | 
			
		||||
			for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin
 | 
			
		||||
				g[j] = g[j] | p[j] & g[j - 2**i];
 | 
			
		||||
				p[j] = p[j] & p[j - 2**i];
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	assign CO = g;
 | 
			
		||||
endmodule
 | 
			
		||||
| 
						 | 
				
			
			@ -902,18 +902,34 @@ endgenerate
 | 
			
		|||
endmodule
 | 
			
		||||
 | 
			
		||||
// --------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
//-
 | 
			
		||||
//-     $macc (A, B, Y)
 | 
			
		||||
//-
 | 
			
		||||
//- Multiply and accumulate.
 | 
			
		||||
//- A building block for summing any number of negated and unnegated signals
 | 
			
		||||
//- and arithmetic products of pairs of signals. Cell port A concatenates pairs
 | 
			
		||||
//- of signals to be multiplied together. When the second signal in a pair is zero
 | 
			
		||||
//- length, a constant 1 is used instead as the second factor. Cell port B
 | 
			
		||||
//- concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders.
 | 
			
		||||
//- Typically created by the `alumacc` pass, which transforms $add and $mul
 | 
			
		||||
//- into $macc cells.
 | 
			
		||||
module \$macc (A, B, Y);
 | 
			
		||||
 | 
			
		||||
parameter A_WIDTH = 0;
 | 
			
		||||
parameter B_WIDTH = 0;
 | 
			
		||||
parameter Y_WIDTH = 0;
 | 
			
		||||
// CONFIG determines the layout of A, as explained below
 | 
			
		||||
parameter CONFIG = 4'b0000;
 | 
			
		||||
parameter CONFIG_WIDTH = 4;
 | 
			
		||||
 | 
			
		||||
input [A_WIDTH-1:0] A;
 | 
			
		||||
input [B_WIDTH-1:0] B;
 | 
			
		||||
output reg [Y_WIDTH-1:0] Y;
 | 
			
		||||
// In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate:
 | 
			
		||||
// A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...))
 | 
			
		||||
// Multiplier ports are pairs of multiplier inputs ("factors").
 | 
			
		||||
// If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum.
 | 
			
		||||
input [A_WIDTH-1:0] A; // Cell port A is the concatenation of all arithmetic ports
 | 
			
		||||
input [B_WIDTH-1:0] B; // Cell port B is the concatenation of single-bit unsigned signals to be also added to the sum
 | 
			
		||||
output reg [Y_WIDTH-1:0] Y; // Output sum
 | 
			
		||||
 | 
			
		||||
// Xilinx XSIM does not like $clog2() below..
 | 
			
		||||
function integer my_clog2;
 | 
			
		||||
| 
						 | 
				
			
			@ -929,10 +945,42 @@ function integer my_clog2;
 | 
			
		|||
	end
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
// Bits that a factor's length field in CONFIG per factor in cell port A
 | 
			
		||||
localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
 | 
			
		||||
// Number of multiplier ports
 | 
			
		||||
localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
 | 
			
		||||
// Minium bit width of an induction variable to iterate over all bits of cell port A
 | 
			
		||||
localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
 | 
			
		||||
 | 
			
		||||
// In this pseudocode, u(foo) means an unsigned int that's foo bits long.
 | 
			
		||||
// The CONFIG parameter carries the following information:
 | 
			
		||||
//	struct CONFIG {
 | 
			
		||||
//		u4 num_bits;
 | 
			
		||||
//		struct port_field {
 | 
			
		||||
//			bool is_signed;
 | 
			
		||||
//			bool is_subtract;
 | 
			
		||||
//			u(num_bits) factor1_len;
 | 
			
		||||
//			u(num_bits) factor2_len;
 | 
			
		||||
//		}[num_ports];
 | 
			
		||||
//	};
 | 
			
		||||
 | 
			
		||||
// The A cell port carries the following information:
 | 
			
		||||
//	struct A {
 | 
			
		||||
//		u(CONFIG.port_field[0].factor1_len) port0factor1;
 | 
			
		||||
//		u(CONFIG.port_field[0].factor2_len) port0factor2;
 | 
			
		||||
//		u(CONFIG.port_field[1].factor1_len) port1factor1;
 | 
			
		||||
//		u(CONFIG.port_field[1].factor2_len) port1factor2;
 | 
			
		||||
//		...
 | 
			
		||||
//	};
 | 
			
		||||
// and log(sizeof(A)) is num_abits.
 | 
			
		||||
// No factor1 may have a zero length.
 | 
			
		||||
// A factor2 having a zero length implies factor2 is replaced with a constant 1.
 | 
			
		||||
 | 
			
		||||
// Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up.
 | 
			
		||||
// Finally, we have:
 | 
			
		||||
// Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ...
 | 
			
		||||
//     * B[0] + B[1] + ...
 | 
			
		||||
 | 
			
		||||
function [2*num_ports*num_abits-1:0] get_port_offsets;
 | 
			
		||||
	input [CONFIG_WIDTH-1:0] cfg;
 | 
			
		||||
	integer i, cursor;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,7 +207,7 @@ module _90_fa (A, B, C, X, Y);
 | 
			
		|||
endmodule
 | 
			
		||||
 | 
			
		||||
(* techmap_celltype = "$lcu" *)
 | 
			
		||||
module _90_lcu (P, G, CI, CO);
 | 
			
		||||
module _90_lcu_brent_kung (P, G, CI, CO);
 | 
			
		||||
	parameter WIDTH = 2;
 | 
			
		||||
 | 
			
		||||
	(* force_downto *)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,31 @@ module EFX_GBUFCE(
 | 
			
		|||
   
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module EFX_RAM_5K(
 | 
			
		||||
module EFX_RAM_5K
 | 
			
		||||
# (
 | 
			
		||||
   parameter READ_WIDTH = 20,
 | 
			
		||||
   parameter WRITE_WIDTH = 20,
 | 
			
		||||
   localparam READ_ADDR_WIDTH = 
 | 
			
		||||
			    (READ_WIDTH == 16) ? 8 :  // 256x16
 | 
			
		||||
			    (READ_WIDTH == 8)  ? 9 :  // 512x8
 | 
			
		||||
			    (READ_WIDTH == 4)  ? 10 : // 1024x4
 | 
			
		||||
			    (READ_WIDTH == 2)  ? 11 : // 2048x2
 | 
			
		||||
			    (READ_WIDTH == 1)  ? 12 : // 4096x1
 | 
			
		||||
			    (READ_WIDTH == 20) ? 8 :  // 256x20
 | 
			
		||||
			    (READ_WIDTH == 10) ? 9 :  // 512x10
 | 
			
		||||
			    (READ_WIDTH == 5)  ? 10 : -1, // 1024x5
 | 
			
		||||
   
 | 
			
		||||
   localparam WRITE_ADDR_WIDTH = 
 | 
			
		||||
			    (WRITE_WIDTH == 16) ? 8 :  // 256x16
 | 
			
		||||
			    (WRITE_WIDTH == 8)  ? 9 :  // 512x8
 | 
			
		||||
			    (WRITE_WIDTH == 4)  ? 10 : // 1024x4
 | 
			
		||||
			    (WRITE_WIDTH == 2)  ? 11 : // 2048x2
 | 
			
		||||
			    (WRITE_WIDTH == 1)  ? 12 : // 4096x1
 | 
			
		||||
			    (WRITE_WIDTH == 20) ? 8 :  // 256x20
 | 
			
		||||
			    (WRITE_WIDTH == 10) ? 9 :  // 512x10
 | 
			
		||||
			    (WRITE_WIDTH == 5)  ? 10 : -1 // 1024x5
 | 
			
		||||
)
 | 
			
		||||
(
 | 
			
		||||
   input [WRITE_WIDTH-1:0] WDATA,
 | 
			
		||||
   input [WRITE_ADDR_WIDTH-1:0] WADDR,
 | 
			
		||||
   input WE, 
 | 
			
		||||
| 
						 | 
				
			
			@ -126,8 +150,6 @@ module EFX_RAM_5K(
 | 
			
		|||
   (* clkbuf_sink *)
 | 
			
		||||
   input RCLK
 | 
			
		||||
);
 | 
			
		||||
   parameter READ_WIDTH = 20;
 | 
			
		||||
   parameter WRITE_WIDTH = 20;
 | 
			
		||||
   parameter OUTPUT_REG = 1'b0;
 | 
			
		||||
   parameter RCLK_POLARITY  = 1'b1;
 | 
			
		||||
   parameter RE_POLARITY    = 1'b1;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,25 +177,4 @@ module EFX_RAM_5K(
 | 
			
		|||
   parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
			
		||||
   parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
			
		||||
   parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
			
		||||
 | 
			
		||||
   localparam READ_ADDR_WIDTH = 
 | 
			
		||||
			    (READ_WIDTH == 16) ? 8 :  // 256x16
 | 
			
		||||
			    (READ_WIDTH == 8)  ? 9 :  // 512x8
 | 
			
		||||
			    (READ_WIDTH == 4)  ? 10 : // 1024x4
 | 
			
		||||
			    (READ_WIDTH == 2)  ? 11 : // 2048x2
 | 
			
		||||
			    (READ_WIDTH == 1)  ? 12 : // 4096x1
 | 
			
		||||
			    (READ_WIDTH == 20) ? 8 :  // 256x20
 | 
			
		||||
			    (READ_WIDTH == 10) ? 9 :  // 512x10
 | 
			
		||||
			    (READ_WIDTH == 5)  ? 10 : -1; // 1024x5
 | 
			
		||||
   
 | 
			
		||||
   localparam WRITE_ADDR_WIDTH = 
 | 
			
		||||
			    (WRITE_WIDTH == 16) ? 8 :  // 256x16
 | 
			
		||||
			    (WRITE_WIDTH == 8)  ? 9 :  // 512x8
 | 
			
		||||
			    (WRITE_WIDTH == 4)  ? 10 : // 1024x4
 | 
			
		||||
			    (WRITE_WIDTH == 2)  ? 11 : // 2048x2
 | 
			
		||||
			    (WRITE_WIDTH == 1)  ? 12 : // 4096x1
 | 
			
		||||
			    (WRITE_WIDTH == 20) ? 8 :  // 256x20
 | 
			
		||||
			    (WRITE_WIDTH == 10) ? 9 :  // 512x10
 | 
			
		||||
			    (WRITE_WIDTH == 5)  ? 10 : -1; // 1024x5
 | 
			
		||||
   
 | 
			
		||||
endmodule
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ for arch in ../../techlibs/*; do
 | 
			
		|||
			done
 | 
			
		||||
		else
 | 
			
		||||
			echo -n "Test $path ->"
 | 
			
		||||
			iverilog -t null -I$arch $path
 | 
			
		||||
			iverilog -t null -I$arch -g2005-sv $path
 | 
			
		||||
			echo " ok"
 | 
			
		||||
		fi
 | 
			
		||||
	done
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,11 @@ T rand_int(T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>
 | 
			
		|||
	return dist(generator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t sext(size_t bits, uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
	return (int64_t)(value << (64 - bits)) >> (64 - bits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct BinaryOperationBase
 | 
			
		||||
{
 | 
			
		||||
	void tweak_input(uint64_t &a, uint64_t &b) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -246,6 +251,106 @@ struct CtlzTest
 | 
			
		|||
	}
 | 
			
		||||
} ctlz;
 | 
			
		||||
 | 
			
		||||
struct UdivTest : BinaryOperationBase
 | 
			
		||||
{
 | 
			
		||||
	UdivTest()
 | 
			
		||||
	{
 | 
			
		||||
		std::printf("Randomized tests for value::udivmod (div):\n");
 | 
			
		||||
		test_binary_operation(*this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
 | 
			
		||||
	{
 | 
			
		||||
		return a / b;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t Bits>
 | 
			
		||||
	cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
 | 
			
		||||
	{
 | 
			
		||||
		return std::get<0>(a.udivmod(b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tweak_input(uint64_t &, uint64_t &b)
 | 
			
		||||
	{
 | 
			
		||||
		if (b == 0) b = 1; // Avoid divide by zero
 | 
			
		||||
	}
 | 
			
		||||
} udiv;
 | 
			
		||||
 | 
			
		||||
struct UmodTest : BinaryOperationBase
 | 
			
		||||
{
 | 
			
		||||
	UmodTest()
 | 
			
		||||
	{
 | 
			
		||||
		std::printf("Randomized tests for value::udivmod (mod):\n");
 | 
			
		||||
		test_binary_operation(*this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
 | 
			
		||||
	{
 | 
			
		||||
		return a % b;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t Bits>
 | 
			
		||||
	cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
 | 
			
		||||
	{
 | 
			
		||||
		return std::get<1>(a.udivmod(b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tweak_input(uint64_t &, uint64_t &b)
 | 
			
		||||
	{
 | 
			
		||||
		if (b == 0) b = 1; // Avoid divide by zero
 | 
			
		||||
	}
 | 
			
		||||
} umod;
 | 
			
		||||
 | 
			
		||||
struct SdivTest : BinaryOperationBase
 | 
			
		||||
{
 | 
			
		||||
	SdivTest()
 | 
			
		||||
	{
 | 
			
		||||
		std::printf("Randomized tests for value::sdivmod (div):\n");
 | 
			
		||||
		test_binary_operation(*this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
 | 
			
		||||
	{
 | 
			
		||||
		return (uint64_t)(sext(bits, a) / sext(bits, b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t Bits>
 | 
			
		||||
	cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
 | 
			
		||||
	{
 | 
			
		||||
		return std::get<0>(a.sdivmod(b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tweak_input(uint64_t &, uint64_t &b)
 | 
			
		||||
	{
 | 
			
		||||
		if (b == 0) b = 1; // Avoid divide by zero
 | 
			
		||||
	}
 | 
			
		||||
} sdiv;
 | 
			
		||||
 | 
			
		||||
struct SmodTest : BinaryOperationBase
 | 
			
		||||
{
 | 
			
		||||
	SmodTest()
 | 
			
		||||
	{
 | 
			
		||||
		std::printf("Randomized tests for value::sdivmod (mod):\n");
 | 
			
		||||
		test_binary_operation(*this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
 | 
			
		||||
	{
 | 
			
		||||
		return (uint64_t)(sext(bits, a) % sext(bits, b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t Bits>
 | 
			
		||||
	cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
 | 
			
		||||
	{
 | 
			
		||||
		return std::get<1>(a.sdivmod(b));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tweak_input(uint64_t &, uint64_t &b)
 | 
			
		||||
	{
 | 
			
		||||
		if (b == 0) b = 1; // Avoid divide by zero
 | 
			
		||||
	}
 | 
			
		||||
} smod;
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,14 @@
 | 
			
		|||
module RAM_9b1B (
 | 
			
		||||
module RAM_9b1B 
 | 
			
		||||
#(
 | 
			
		||||
	parameter INIT = 0,
 | 
			
		||||
	parameter OPTION_INIT = "UNDEFINED",
 | 
			
		||||
	parameter PORT_R_WIDTH = 9,
 | 
			
		||||
	parameter PORT_W_WIDTH = 9,
 | 
			
		||||
	parameter PORT_R_CLK_POL = 0,
 | 
			
		||||
	parameter PORT_W_CLK_POL = 0,
 | 
			
		||||
	parameter PORT_W_WR_EN_WIDTH = 1
 | 
			
		||||
)
 | 
			
		||||
(
 | 
			
		||||
	input PORT_R_CLK,
 | 
			
		||||
	input [6:0] PORT_R_ADDR,
 | 
			
		||||
	output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA,
 | 
			
		||||
| 
						 | 
				
			
			@ -8,14 +18,6 @@ module RAM_9b1B (
 | 
			
		|||
	input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
parameter INIT = 0;
 | 
			
		||||
parameter OPTION_INIT = "UNDEFINED";
 | 
			
		||||
parameter PORT_R_WIDTH = 9;
 | 
			
		||||
parameter PORT_W_WIDTH = 9;
 | 
			
		||||
parameter PORT_R_CLK_POL = 0;
 | 
			
		||||
parameter PORT_W_CLK_POL = 0;
 | 
			
		||||
parameter PORT_W_WR_EN_WIDTH = 1;
 | 
			
		||||
 | 
			
		||||
reg [8:0] mem [0:15];
 | 
			
		||||
 | 
			
		||||
integer i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,11 @@
 | 
			
		|||
module RAM_WREN (
 | 
			
		||||
module RAM_WREN #(
 | 
			
		||||
	parameter ABITS=4,
 | 
			
		||||
	parameter WIDTH=8,
 | 
			
		||||
	parameter PORT_A_WR_EN_WIDTH=1,
 | 
			
		||||
	parameter PORT_A_WR_BE_WIDTH=0,
 | 
			
		||||
	parameter OPTION_BYTESIZE=WIDTH,
 | 
			
		||||
	parameter WB=OPTION_BYTESIZE
 | 
			
		||||
)(
 | 
			
		||||
	input PORT_A_CLK,
 | 
			
		||||
	input [ABITS-1:0] PORT_A_ADDR,
 | 
			
		||||
	input [WIDTH-1:0] PORT_A_WR_DATA,
 | 
			
		||||
| 
						 | 
				
			
			@ -7,13 +14,6 @@ module RAM_WREN (
 | 
			
		|||
	input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
parameter ABITS=4;
 | 
			
		||||
parameter WIDTH=8;
 | 
			
		||||
parameter PORT_A_WR_EN_WIDTH=1;
 | 
			
		||||
parameter PORT_A_WR_BE_WIDTH=0;
 | 
			
		||||
parameter OPTION_BYTESIZE=WIDTH;
 | 
			
		||||
parameter WB=OPTION_BYTESIZE;
 | 
			
		||||
 | 
			
		||||
reg [WIDTH-1:0] mem [0:2**ABITS-1];
 | 
			
		||||
 | 
			
		||||
integer i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,15 @@
 | 
			
		|||
// expect-rd-ports 1
 | 
			
		||||
// expect-rd-clk \clk
 | 
			
		||||
 | 
			
		||||
module ram2 (input clk,
 | 
			
		||||
module ram2 #(
 | 
			
		||||
             parameter  SIZE = 5 // Address size
 | 
			
		||||
          ) (input clk,
 | 
			
		||||
             input             sel,
 | 
			
		||||
             input             we, 
 | 
			
		||||
             input [SIZE-1:0]  adr, 
 | 
			
		||||
             input [63:0]      dat_i, 
 | 
			
		||||
             output reg [63:0] dat_o);
 | 
			
		||||
   parameter  SIZE = 5; // Address size
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
   reg [63:0] mem [0:(1 << SIZE)-1];
 | 
			
		||||
   integer    i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								tests/simple/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/simple/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,2 +1,3 @@
 | 
			
		|||
*.log
 | 
			
		||||
*.out
 | 
			
		||||
*.err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								tests/techmap/kogge-stone.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/techmap/kogge-stone.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
test_cell -s 1711533949 -n 10 -map +/techmap.v -map +/choices/kogge-stone.v $lcu
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/verilog/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								tests/verilog/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,10 @@
 | 
			
		|||
/*.log
 | 
			
		||||
/*.out
 | 
			
		||||
/*.err
 | 
			
		||||
/run-test.mk
 | 
			
		||||
/const_arst.v
 | 
			
		||||
/const_sr.v
 | 
			
		||||
/doubleslash.v
 | 
			
		||||
/roundtrip_proc_1.v
 | 
			
		||||
/roundtrip_proc_2.v
 | 
			
		||||
/assign_to_reg.v
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								tests/verilog/assign_to_reg.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/verilog/assign_to_reg.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
# https://github.com/yosyshq/yosys/issues/2035
 | 
			
		||||
 | 
			
		||||
read_ilang <<END
 | 
			
		||||
module \top
 | 
			
		||||
  wire width 1 input 0 \halfbrite
 | 
			
		||||
  wire width 2 output 1 \r_on
 | 
			
		||||
  process $1
 | 
			
		||||
    assign \r_on [1:0] 2'00
 | 
			
		||||
    assign \r_on [1:0] 2'11
 | 
			
		||||
    switch \halfbrite [0]
 | 
			
		||||
      case 1'1
 | 
			
		||||
        assign \r_on [1] 1'0
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
END
 | 
			
		||||
proc_prune
 | 
			
		||||
write_verilog assign_to_reg.v
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
logger -expect-no-warnings
 | 
			
		||||
read_verilog assign_to_reg.v
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue