mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into xc7srl
This commit is contained in:
		
						commit
						d8465590ac
					
				
					 14 changed files with 526 additions and 73 deletions
				
			
		| 
						 | 
				
			
			@ -315,6 +315,9 @@ Verilog Attributes and non-standard features
 | 
			
		|||
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
 | 
			
		||||
  that have ports with a width that depends on a parameter.
 | 
			
		||||
 | 
			
		||||
- The ``hdlname'' attribute is used by some passes to document the original
 | 
			
		||||
  (HDL) name of a module when renaming a module.
 | 
			
		||||
 | 
			
		||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
 | 
			
		||||
  never be removed by the optimizer. This is used for example for cells that
 | 
			
		||||
  have hidden connections that are not part of the netlist, such as IO pads.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,6 +106,95 @@ struct FirrtlWorker
 | 
			
		|||
	RTLIL::Design *design;
 | 
			
		||||
	std::string indent;
 | 
			
		||||
 | 
			
		||||
	// Define read/write ports and memories.
 | 
			
		||||
	// We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction.
 | 
			
		||||
	// For the moment, we don't handle $readmemh or $readmemb.
 | 
			
		||||
	// These will be part of a subsequent PR.
 | 
			
		||||
	struct read_port {
 | 
			
		||||
		string name;
 | 
			
		||||
		bool clk_enable;
 | 
			
		||||
		bool clk_parity;
 | 
			
		||||
		bool transparent;
 | 
			
		||||
		RTLIL::SigSpec clk;
 | 
			
		||||
		RTLIL::SigSpec ena;
 | 
			
		||||
		RTLIL::SigSpec addr;
 | 
			
		||||
		read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) {
 | 
			
		||||
			// Current (3/13/2019) conventions:
 | 
			
		||||
			//  generate a constant 0 for clock and a constant 1 for enable if they are undefined.
 | 
			
		||||
			if (!clk.is_fully_def())
 | 
			
		||||
				this->clk = SigSpec(RTLIL::Const(0, 1));
 | 
			
		||||
			if (!ena.is_fully_def())
 | 
			
		||||
				this->ena = SigSpec(RTLIL::Const(1, 1));
 | 
			
		||||
		}
 | 
			
		||||
		string gen_read(const char * indent) {
 | 
			
		||||
			string addr_expr = make_expr(addr);
 | 
			
		||||
			string ena_expr = make_expr(ena);
 | 
			
		||||
			string clk_expr = make_expr(clk);
 | 
			
		||||
			string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
 | 
			
		||||
			string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
 | 
			
		||||
			string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
 | 
			
		||||
			return addr_str + ena_str + clk_str;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
	struct write_port : read_port {
 | 
			
		||||
		RTLIL::SigSpec mask;
 | 
			
		||||
		write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) {
 | 
			
		||||
			if (!clk.is_fully_def())
 | 
			
		||||
				this->clk = SigSpec(RTLIL::Const(0));
 | 
			
		||||
			if (!ena.is_fully_def())
 | 
			
		||||
				this->ena = SigSpec(RTLIL::Const(0));
 | 
			
		||||
			if (!mask.is_fully_def())
 | 
			
		||||
				this->ena = SigSpec(RTLIL::Const(1));
 | 
			
		||||
		}
 | 
			
		||||
	  string gen_read(const char * /* indent */) {
 | 
			
		||||
			log_error("gen_read called on write_port: %s\n", name.c_str());
 | 
			
		||||
			return stringf("gen_read called on write_port: %s\n", name.c_str());
 | 
			
		||||
		}
 | 
			
		||||
		string gen_write(const char * indent) {
 | 
			
		||||
			string addr_expr = make_expr(addr);
 | 
			
		||||
			string ena_expr = make_expr(ena);
 | 
			
		||||
			string clk_expr = make_expr(clk);
 | 
			
		||||
			string mask_expr = make_expr(mask);
 | 
			
		||||
			string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str());
 | 
			
		||||
			string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
 | 
			
		||||
			string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
 | 
			
		||||
			string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
 | 
			
		||||
			return addr_str + ena_str + clk_str + mask_str;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
	/* Memories defined within this module. */
 | 
			
		||||
	 struct memory {
 | 
			
		||||
		 string name;					// memory name
 | 
			
		||||
		 int abits;						// number of address bits
 | 
			
		||||
		 int size;						// size (in units) of the memory
 | 
			
		||||
		 int width;						// size (in bits) of each element
 | 
			
		||||
		 int read_latency;
 | 
			
		||||
		 int write_latency;
 | 
			
		||||
		 vector<read_port> read_ports;
 | 
			
		||||
		 vector<write_port> write_ports;
 | 
			
		||||
		 std::string init_file;
 | 
			
		||||
		 std::string init_file_srcFileSpec;
 | 
			
		||||
		 memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {}
 | 
			
		||||
		 memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
 | 
			
		||||
		 void add_memory_read_port(read_port &rp) {
 | 
			
		||||
			 read_ports.push_back(rp);
 | 
			
		||||
		 }
 | 
			
		||||
		 void add_memory_write_port(write_port &wp) {
 | 
			
		||||
			 write_ports.push_back(wp);
 | 
			
		||||
		 }
 | 
			
		||||
		 void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
 | 
			
		||||
			 this->init_file = init_file;
 | 
			
		||||
			 this->init_file_srcFileSpec = init_file_srcFileSpec;
 | 
			
		||||
		 }
 | 
			
		||||
 | 
			
		||||
	 };
 | 
			
		||||
	dict<string, memory> memories;
 | 
			
		||||
 | 
			
		||||
	void register_memory(memory &m)
 | 
			
		||||
	{
 | 
			
		||||
		memories[m.name] = m;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void register_reverse_wire_map(string id, SigSpec sig)
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < GetSize(sig); i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +205,7 @@ struct FirrtlWorker
 | 
			
		|||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	string make_expr(const SigSpec &sig)
 | 
			
		||||
	static string make_expr(const SigSpec &sig)
 | 
			
		||||
	{
 | 
			
		||||
		string expr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -515,6 +604,7 @@ struct FirrtlWorker
 | 
			
		|||
				int abits = cell->parameters.at("\\ABITS").as_int();
 | 
			
		||||
				int width = cell->parameters.at("\\WIDTH").as_int();
 | 
			
		||||
				int size = cell->parameters.at("\\SIZE").as_int();
 | 
			
		||||
				memory m(mem_id, abits, size, width);
 | 
			
		||||
				int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
 | 
			
		||||
				int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -531,33 +621,24 @@ struct FirrtlWorker
 | 
			
		|||
				if (offset != 0)
 | 
			
		||||
					log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
 | 
			
		||||
 | 
			
		||||
				cell_exprs.push_back(stringf("    mem %s:\n", mem_id.c_str()));
 | 
			
		||||
				cell_exprs.push_back(stringf("      data-type => UInt<%d>\n", width));
 | 
			
		||||
				cell_exprs.push_back(stringf("      depth => %d\n", size));
 | 
			
		||||
 | 
			
		||||
				for (int i = 0; i < rd_ports; i++)
 | 
			
		||||
					cell_exprs.push_back(stringf("      reader => r%d\n", i));
 | 
			
		||||
 | 
			
		||||
				for (int i = 0; i < wr_ports; i++)
 | 
			
		||||
					cell_exprs.push_back(stringf("      writer => w%d\n", i));
 | 
			
		||||
 | 
			
		||||
				cell_exprs.push_back(stringf("      read-latency => 0\n"));
 | 
			
		||||
				cell_exprs.push_back(stringf("      write-latency => 1\n"));
 | 
			
		||||
				cell_exprs.push_back(stringf("      read-under-write => undefined\n"));
 | 
			
		||||
 | 
			
		||||
				for (int i = 0; i < rd_ports; i++)
 | 
			
		||||
				{
 | 
			
		||||
					if (rd_clk_enable[i] != State::S0)
 | 
			
		||||
						log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
 | 
			
		||||
 | 
			
		||||
					SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
 | 
			
		||||
					SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
 | 
			
		||||
					string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits));
 | 
			
		||||
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i));
 | 
			
		||||
 | 
			
		||||
					register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig);
 | 
			
		||||
					string addr_expr = make_expr(addr_sig);
 | 
			
		||||
					string name(stringf("%s.r%d", m.name.c_str(), i));
 | 
			
		||||
					bool clk_enable = false;
 | 
			
		||||
					bool clk_parity = true;
 | 
			
		||||
					bool transparency = false;
 | 
			
		||||
					SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
 | 
			
		||||
					SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1);
 | 
			
		||||
					read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig);
 | 
			
		||||
					m.add_memory_read_port(rp);
 | 
			
		||||
					cell_exprs.push_back(rp.gen_read(indent.c_str()));
 | 
			
		||||
					register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				for (int i = 0; i < wr_ports; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -568,9 +649,16 @@ struct FirrtlWorker
 | 
			
		|||
					if (wr_clk_polarity[i] != State::S1)
 | 
			
		||||
						log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
 | 
			
		||||
 | 
			
		||||
					string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits));
 | 
			
		||||
					string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width));
 | 
			
		||||
					string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i));
 | 
			
		||||
					string name(stringf("%s.w%d", m.name.c_str(), i));
 | 
			
		||||
					bool clk_enable = true;
 | 
			
		||||
					bool clk_parity = true;
 | 
			
		||||
					bool transparency = false;
 | 
			
		||||
					SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits);
 | 
			
		||||
					string addr_expr = make_expr(addr_sig);
 | 
			
		||||
					SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width);
 | 
			
		||||
					string data_expr = make_expr(data_sig);
 | 
			
		||||
					SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i);
 | 
			
		||||
					string clk_expr = make_expr(clk_sig);
 | 
			
		||||
 | 
			
		||||
					SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
 | 
			
		||||
					string wen_expr = make_expr(wen_sig[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -579,13 +667,50 @@ struct FirrtlWorker
 | 
			
		|||
						if (wen_sig[0] != wen_sig[i])
 | 
			
		||||
							log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
 | 
			
		||||
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str()));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str()));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i));
 | 
			
		||||
					cell_exprs.push_back(stringf("    %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str()));
 | 
			
		||||
					SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
 | 
			
		||||
					write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig);
 | 
			
		||||
					m.add_memory_write_port(wp);
 | 
			
		||||
					cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str()));
 | 
			
		||||
					cell_exprs.push_back(wp.gen_write(indent.c_str()));
 | 
			
		||||
				}
 | 
			
		||||
				register_memory(m);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (cell->type.in("$memwr", "$memrd", "$meminit"))
 | 
			
		||||
			{
 | 
			
		||||
				std::string cell_type = fid(cell->type);
 | 
			
		||||
				std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
 | 
			
		||||
				memory *mp = nullptr;
 | 
			
		||||
				if (cell->type == "$meminit" ) {
 | 
			
		||||
					log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
 | 
			
		||||
				} else {
 | 
			
		||||
					// It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition.
 | 
			
		||||
					auto addrSig = cell->getPort("\\ADDR");
 | 
			
		||||
					auto dataSig = cell->getPort("\\DATA");
 | 
			
		||||
					auto enableSig = cell->getPort("\\EN");
 | 
			
		||||
					auto clockSig = cell->getPort("\\CLK");
 | 
			
		||||
					Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
 | 
			
		||||
					Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
 | 
			
		||||
 | 
			
		||||
					mp = &memories.at(mem_id);
 | 
			
		||||
					int portNum = 0;
 | 
			
		||||
					bool transparency = false;
 | 
			
		||||
					string data_expr = make_expr(dataSig);
 | 
			
		||||
					if (cell->type.in("$memwr")) {
 | 
			
		||||
						portNum = (int) mp->write_ports.size();
 | 
			
		||||
						write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(),  transparency, clockSig, enableSig, addrSig, dataSig);
 | 
			
		||||
						mp->add_memory_write_port(wp);
 | 
			
		||||
						cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str()));
 | 
			
		||||
						cell_exprs.push_back(wp.gen_write(indent.c_str()));
 | 
			
		||||
					} else if (cell->type.in("$memrd")) {
 | 
			
		||||
						portNum = (int) mp->read_ports.size();
 | 
			
		||||
						read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(),  transparency, clockSig, enableSig, addrSig);
 | 
			
		||||
						mp->add_memory_read_port(rp);
 | 
			
		||||
						cell_exprs.push_back(rp.gen_read(indent.c_str()));
 | 
			
		||||
						register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -763,6 +888,24 @@ struct FirrtlWorker
 | 
			
		|||
 | 
			
		||||
		f << stringf("\n");
 | 
			
		||||
 | 
			
		||||
		// If we have any memory definitions, output them.
 | 
			
		||||
		for (auto kv : memories) {
 | 
			
		||||
			memory m = kv.second;
 | 
			
		||||
			f << stringf("    mem %s:\n", m.name.c_str());
 | 
			
		||||
			f << stringf("      data-type => UInt<%d>\n", m.width);
 | 
			
		||||
			f << stringf("      depth => %d\n", m.size);
 | 
			
		||||
			for (int i = 0; i < (int) m.read_ports.size(); i += 1) {
 | 
			
		||||
				f << stringf("      reader => r%d\n", i);
 | 
			
		||||
			}
 | 
			
		||||
			for (int i = 0; i < (int) m.write_ports.size(); i += 1) {
 | 
			
		||||
				f << stringf("      writer => w%d\n", i);
 | 
			
		||||
			}
 | 
			
		||||
			f << stringf("      read-latency => %d\n", m.read_latency);
 | 
			
		||||
			f << stringf("      write-latency => %d\n", m.write_latency);
 | 
			
		||||
			f << stringf("      read-under-write => undefined\n");
 | 
			
		||||
		}
 | 
			
		||||
		f << stringf("\n");
 | 
			
		||||
 | 
			
		||||
		for (auto str : cell_exprs)
 | 
			
		||||
			f << str;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1619,30 +1619,35 @@ struct VerificExtNets
 | 
			
		|||
	int portname_cnt = 0;
 | 
			
		||||
 | 
			
		||||
	// a map from Net to the same Net one level up in the design hierarchy
 | 
			
		||||
	std::map<Net*, Net*> net_level_up;
 | 
			
		||||
	std::map<Net*, Net*> net_level_up_drive_up;
 | 
			
		||||
	std::map<Net*, Net*> net_level_up_drive_down;
 | 
			
		||||
 | 
			
		||||
	Net *get_net_level_up(Net *net)
 | 
			
		||||
	Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
 | 
			
		||||
 | 
			
		||||
		if (net_level_up.count(net) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			Netlist *nl = net->Owner();
 | 
			
		||||
 | 
			
		||||
			// Simply return if Netlist is not unique
 | 
			
		||||
			if (nl->NumOfRefs() != 1)
 | 
			
		||||
				return net;
 | 
			
		||||
			log_assert(nl->NumOfRefs() == 1);
 | 
			
		||||
 | 
			
		||||
			Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
 | 
			
		||||
			Netlist *up_nl = up_inst->Owner();
 | 
			
		||||
 | 
			
		||||
			// create new Port
 | 
			
		||||
			string name = stringf("___extnets_%d", portname_cnt++);
 | 
			
		||||
			Port *new_port = new Port(name.c_str(), DIR_OUT);
 | 
			
		||||
			Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
 | 
			
		||||
			nl->Add(new_port);
 | 
			
		||||
			net->Connect(new_port);
 | 
			
		||||
 | 
			
		||||
			// create new Net in up Netlist
 | 
			
		||||
			Net *new_net = new Net(name.c_str());
 | 
			
		||||
			up_nl->Add(new_net);
 | 
			
		||||
			Net *new_net = final_net;
 | 
			
		||||
			if (new_net == nullptr || new_net->Owner() != up_nl) {
 | 
			
		||||
				new_net = new Net(name.c_str());
 | 
			
		||||
				up_nl->Add(new_net);
 | 
			
		||||
			}
 | 
			
		||||
			up_inst->Connect(new_port, new_net);
 | 
			
		||||
 | 
			
		||||
			net_level_up[net] = new_net;
 | 
			
		||||
| 
						 | 
				
			
			@ -1651,6 +1656,39 @@ struct VerificExtNets
 | 
			
		|||
		return net_level_up.at(net);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		while (net->Owner() != dest)
 | 
			
		||||
			net = route_up(net, drive_up, final_net);
 | 
			
		||||
		if (final_net != nullptr)
 | 
			
		||||
			log_assert(net == final_net);
 | 
			
		||||
		return net;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Netlist *find_common_ancestor(Netlist *A, Netlist *B)
 | 
			
		||||
	{
 | 
			
		||||
		std::set<Netlist*> ancestors_of_A;
 | 
			
		||||
 | 
			
		||||
		Netlist *cursor = A;
 | 
			
		||||
		while (1) {
 | 
			
		||||
			ancestors_of_A.insert(cursor);
 | 
			
		||||
			if (cursor->NumOfRefs() != 1)
 | 
			
		||||
				break;
 | 
			
		||||
			cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cursor = B;
 | 
			
		||||
		while (1) {
 | 
			
		||||
			if (ancestors_of_A.count(cursor))
 | 
			
		||||
				return cursor;
 | 
			
		||||
			if (cursor->NumOfRefs() != 1)
 | 
			
		||||
				break;
 | 
			
		||||
			cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void run(Netlist *nl)
 | 
			
		||||
	{
 | 
			
		||||
		MapIter mi, mi2;
 | 
			
		||||
| 
						 | 
				
			
			@ -1674,19 +1712,37 @@ struct VerificExtNets
 | 
			
		|||
			if (verific_verbose)
 | 
			
		||||
				log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
 | 
			
		||||
 | 
			
		||||
			while (net->IsExternalTo(nl))
 | 
			
		||||
			{
 | 
			
		||||
				Net *newnet = get_net_level_up(net);
 | 
			
		||||
				if (newnet == net) break;
 | 
			
		||||
			Netlist *ext_nl = net->Owner();
 | 
			
		||||
 | 
			
		||||
			if (verific_verbose)
 | 
			
		||||
				log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
 | 
			
		||||
 | 
			
		||||
			Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
 | 
			
		||||
 | 
			
		||||
			if (verific_verbose)
 | 
			
		||||
				log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
 | 
			
		||||
 | 
			
		||||
			Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
 | 
			
		||||
			Net *new_net = ca_net;
 | 
			
		||||
 | 
			
		||||
			if (ca_nl != nl)
 | 
			
		||||
			{
 | 
			
		||||
				if (verific_verbose)
 | 
			
		||||
					log("  external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
 | 
			
		||||
				net = newnet;
 | 
			
		||||
					log(" net in common ancestor: %s\n", ca_net->Name());
 | 
			
		||||
 | 
			
		||||
				string name = stringf("___extnets_%d", portname_cnt++);
 | 
			
		||||
				new_net = new Net(name.c_str());
 | 
			
		||||
				nl->Add(new_net);
 | 
			
		||||
 | 
			
		||||
				Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
 | 
			
		||||
				log_assert(n == ca_net);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (verific_verbose)
 | 
			
		||||
				log("  final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
 | 
			
		||||
			todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
 | 
			
		||||
				log(" new local net: %s\n", new_net->Name());
 | 
			
		||||
 | 
			
		||||
			log_assert(!new_net->IsExternalTo(nl));
 | 
			
		||||
			todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto it : todo_connect) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2330,21 +2386,43 @@ struct ReadPass : public Pass {
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("Add directory to global Verilog/SystemVerilog include directories.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    read -verific\n");
 | 
			
		||||
		log("    read -noverific\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
 | 
			
		||||
		log("with -verific will result in an error on Yosys binaries that are built without\n");
 | 
			
		||||
		log("Verific support. The default is to use Verific if it is available.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
#ifdef YOSYS_ENABLE_VERIFIC
 | 
			
		||||
		static bool verific_available = !check_noverific_env();
 | 
			
		||||
#else
 | 
			
		||||
		static bool verific_available = false;
 | 
			
		||||
#endif
 | 
			
		||||
		static bool use_verific = verific_available;
 | 
			
		||||
 | 
			
		||||
		if (args.size() < 2 || args[1][0] != '-')
 | 
			
		||||
			log_cmd_error("Missing mode parameter.\n");
 | 
			
		||||
 | 
			
		||||
		if (args[1] == "-verific" || args[1] == "-noverific") {
 | 
			
		||||
			if (args.size() != 2)
 | 
			
		||||
				log_cmd_error("Additional arguments to -verific/-noverific.\n");
 | 
			
		||||
			if (args[1] == "-verific") {
 | 
			
		||||
				if (!verific_available)
 | 
			
		||||
					log_cmd_error("This version of Yosys is built without Verific support.\n");
 | 
			
		||||
				use_verific = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				use_verific = false;
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (args.size() < 3)
 | 
			
		||||
			log_cmd_error("Missing file name parameter.\n");
 | 
			
		||||
 | 
			
		||||
#ifdef YOSYS_ENABLE_VERIFIC
 | 
			
		||||
		bool use_verific = !check_noverific_env();
 | 
			
		||||
#else
 | 
			
		||||
		bool use_verific = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
 | 
			
		||||
			if (use_verific) {
 | 
			
		||||
				args[0] = "verific";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
 | 
			
		|||
	$(Q) mkdir -p $(dir $@)
 | 
			
		||||
	$(P) flex -o frontends/verilog/verilog_lexer.cc $<
 | 
			
		||||
 | 
			
		||||
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
 | 
			
		||||
 | 
			
		||||
OBJS += frontends/verilog/verilog_parser.tab.o
 | 
			
		||||
OBJS += frontends/verilog/verilog_lexer.o
 | 
			
		||||
OBJS += frontends/verilog/preproc.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
USING_YOSYS_NAMESPACE
 | 
			
		||||
PRIVATE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
 | 
			
		||||
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
 | 
			
		||||
{
 | 
			
		||||
	from_name = RTLIL::escape_id(from_name);
 | 
			
		||||
	to_name = RTLIL::escape_id(to_name);
 | 
			
		||||
| 
						 | 
				
			
			@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
 | 
			
		|||
			Wire *w = it.second;
 | 
			
		||||
			log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
 | 
			
		||||
			module->rename(w, to_name);
 | 
			
		||||
			if (w->port_id)
 | 
			
		||||
			if (w->port_id || flag_output) {
 | 
			
		||||
				if (flag_output)
 | 
			
		||||
					w->port_output = true;
 | 
			
		||||
				module->fixup_ports();
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	for (auto &it : module->cells_)
 | 
			
		||||
		if (it.first == from_name) {
 | 
			
		||||
			if (flag_output)
 | 
			
		||||
				log_cmd_error("Called with -output but the specified object is a cell.\n");
 | 
			
		||||
			log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
 | 
			
		||||
			module->rename(it.second, to_name);
 | 
			
		||||
			return;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,15 +113,26 @@ struct RenamePass : public Pass {
 | 
			
		|||
		log("Rename the specified object. Note that selection patterns are not supported\n");
 | 
			
		||||
		log("by this command.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -output old_name new_name\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Like above, but also make the wire an output. This will fail if the object is\n");
 | 
			
		||||
		log("not a wire.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -src [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Assign names auto-generated from the src attribute to all selected wires and\n");
 | 
			
		||||
		log("cells with private names.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -wire [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Assign auto-generated names based on the wires they drive to all selected\n");
 | 
			
		||||
		log("cells with private names. Ignores cells driving privatly named wires.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -enumerate [-pattern <pattern>] [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Assign short auto-generated names to all selected wires and cells with private\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -124,11 +140,13 @@ struct RenamePass : public Pass {
 | 
			
		|||
		log("The character %% in the pattern is replaced with a integer number. The default\n");
 | 
			
		||||
		log("pattern is '_%%_'.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -hide [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
 | 
			
		||||
		log("with public names. This ignores all selected ports.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    rename -top new_name\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Rename top module.\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +160,7 @@ struct RenamePass : public Pass {
 | 
			
		|||
		bool flag_enumerate = false;
 | 
			
		||||
		bool flag_hide = false;
 | 
			
		||||
		bool flag_top = false;
 | 
			
		||||
		bool flag_output = false;
 | 
			
		||||
		bool got_mode = false;
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +172,11 @@ struct RenamePass : public Pass {
 | 
			
		|||
				got_mode = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-output" && !got_mode) {
 | 
			
		||||
				flag_output = true;
 | 
			
		||||
				got_mode = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-wire" && !got_mode) {
 | 
			
		||||
				flag_wire = true;
 | 
			
		||||
				got_mode = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -322,10 +346,12 @@ struct RenamePass : public Pass {
 | 
			
		|||
			if (!design->selected_active_module.empty())
 | 
			
		||||
			{
 | 
			
		||||
				if (design->modules_.count(design->selected_active_module) > 0)
 | 
			
		||||
					rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
 | 
			
		||||
					rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				if (flag_output)
 | 
			
		||||
					log_cmd_error("Mode -output requires that there is an active module selected.\n");
 | 
			
		||||
				for (auto &mod : design->modules_) {
 | 
			
		||||
					if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
 | 
			
		||||
						to_name = RTLIL::escape_id(to_name);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
 | 
			
		|||
					smod->name = newname;
 | 
			
		||||
					cell->type = newname;
 | 
			
		||||
					smod->set_bool_attribute("\\unique");
 | 
			
		||||
					if (smod->attributes.count("\\hdlname") == 0)
 | 
			
		||||
						smod->attributes["\\hdlname"] = string(log_id(tmod->name));
 | 
			
		||||
					design->add(smod);
 | 
			
		||||
 | 
			
		||||
					did_something = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -641,6 +641,7 @@ grow_read_ports:;
 | 
			
		|||
				pi.sig_data = SigSpec();
 | 
			
		||||
				pi.sig_en = SigSpec();
 | 
			
		||||
				pi.make_outreg = false;
 | 
			
		||||
				pi.make_transp = false;
 | 
			
		||||
			}
 | 
			
		||||
			new_portinfos.push_back(pi);
 | 
			
		||||
			if (pi.dupidx == dup_count-1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -956,6 +957,8 @@ grow_read_ports:;
 | 
			
		|||
					SigSpec addr_ok_q = addr_ok;
 | 
			
		||||
					if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) {
 | 
			
		||||
						addr_ok_q = module->addWire(NEW_ID);
 | 
			
		||||
						if (!pi.sig_en.empty())
 | 
			
		||||
							addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en);
 | 
			
		||||
						module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -340,6 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
 | 
			
		|||
		// evaluate in reverse order to give the first entry the top priority
 | 
			
		||||
		RTLIL::SigSpec initial_val = result;
 | 
			
		||||
		RTLIL::Cell *last_mux_cell = NULL;
 | 
			
		||||
		bool shiftx = initial_val.is_fully_undef();
 | 
			
		||||
		for (size_t i = 0; i < sw->cases.size(); i++) {
 | 
			
		||||
			int case_idx = sw->cases.size() - i - 1;
 | 
			
		||||
			RTLIL::CaseRule *cs2 = sw->cases[case_idx];
 | 
			
		||||
| 
						 | 
				
			
			@ -348,6 +349,33 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
 | 
			
		|||
				append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
 | 
			
		||||
			else
 | 
			
		||||
				result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
 | 
			
		||||
 | 
			
		||||
			// Ignore output values which are entirely don't care
 | 
			
		||||
			if (shiftx && !value.is_fully_undef()) {
 | 
			
		||||
				// Keep checking if case condition is the same as the current case index
 | 
			
		||||
				if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const())
 | 
			
		||||
					shiftx = (cs2->compare.front().as_int() == case_idx);
 | 
			
		||||
				else
 | 
			
		||||
					shiftx = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Transform into a $shiftx where possible
 | 
			
		||||
		if (shiftx && last_mux_cell->type == "$pmux") {
 | 
			
		||||
			// Create bit-blasted $shiftx-es that shifts by the address line used in the case statement
 | 
			
		||||
			auto pmux_b_port = last_mux_cell->getPort("\\B");
 | 
			
		||||
			auto pmux_y_port = last_mux_cell->getPort("\\Y");
 | 
			
		||||
			int width = last_mux_cell->getParam("\\WIDTH").as_int();
 | 
			
		||||
			for (int i = 0; i < width; ++i) {
 | 
			
		||||
				RTLIL::SigSpec a_port;
 | 
			
		||||
				// Because we went in reverse order above, un-reverse $pmux's B port here
 | 
			
		||||
				for (int j = pmux_b_port.size()/width-1; j >= 0; --j)
 | 
			
		||||
					a_port.append(pmux_b_port.extract(j*width+i, 1));
 | 
			
		||||
				// Create a $shiftx that shifts by the address line used in the case statement
 | 
			
		||||
				mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1));
 | 
			
		||||
			}
 | 
			
		||||
			// Disconnect $pmux by replacing its output port with a floating wire
 | 
			
		||||
			last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,20 +33,24 @@ struct CutpointPass : public Pass {
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("This command adds formal cut points to the design.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -undef\n");
 | 
			
		||||
		log("        set cupoint nets to undef (x). the default behavior is to create a\n");
 | 
			
		||||
		log("        $anyseq cell and drive the cutpoint net from that\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
		// bool flag_noinit = false;
 | 
			
		||||
		 bool flag_undef = false;
 | 
			
		||||
 | 
			
		||||
		log_header(design, "Executing CUTPOINT pass.\n");
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
			// if (args[argidx] == "-noinit") {
 | 
			
		||||
			// 	flag_noinit = true;
 | 
			
		||||
			// 	continue;
 | 
			
		||||
			// }
 | 
			
		||||
			if (args[argidx] == "-undef") {
 | 
			
		||||
				flag_undef = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(args, argidx, design);
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +67,7 @@ struct CutpointPass : public Pass {
 | 
			
		|||
					if (wire->port_output)
 | 
			
		||||
						output_wires.push_back(wire);
 | 
			
		||||
				for (auto wire : output_wires)
 | 
			
		||||
					module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire)));
 | 
			
		||||
					module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +80,7 @@ struct CutpointPass : public Pass {
 | 
			
		|||
				log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
 | 
			
		||||
				for (auto &conn : cell->connections()) {
 | 
			
		||||
					if (cell->output(conn.first))
 | 
			
		||||
						module->connect(conn.second, module->Anyseq(NEW_ID, GetSize(conn.second)));
 | 
			
		||||
						module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
 | 
			
		||||
				}
 | 
			
		||||
				module->remove(cell);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +90,7 @@ struct CutpointPass : public Pass {
 | 
			
		|||
					log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
 | 
			
		||||
					Wire *new_wire = module->addWire(NEW_ID, wire);
 | 
			
		||||
					module->swap_names(wire, new_wire);
 | 
			
		||||
					module->connect(new_wire, module->Anyseq(NEW_ID, GetSize(new_wire)));
 | 
			
		||||
					module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire)));
 | 
			
		||||
					wire->port_id = 0;
 | 
			
		||||
					wire->port_input = false;
 | 
			
		||||
					wire->port_output = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +146,7 @@ struct CutpointPass : public Pass {
 | 
			
		|||
							rhs.append(SigBit(new_wire, i));
 | 
			
		||||
						}
 | 
			
		||||
					if (GetSize(lhs))
 | 
			
		||||
					module->connect(lhs, rhs);
 | 
			
		||||
						module->connect(lhs, rhs);
 | 
			
		||||
					module->swap_names(wire, new_wire);
 | 
			
		||||
					wire->port_id = 0;
 | 
			
		||||
					wire->port_input = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +158,7 @@ struct CutpointPass : public Pass {
 | 
			
		|||
 | 
			
		||||
				for (auto chunk : sig.chunks()) {
 | 
			
		||||
					SigSpec s(chunk);
 | 
			
		||||
					module->connect(s, module->Anyseq(NEW_ID, GetSize(s)));
 | 
			
		||||
					module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s)));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,11 +155,13 @@ int LibertyParser::lexer(std::string &str)
 | 
			
		|||
 | 
			
		||||
	// check for a backslash
 | 
			
		||||
	if (c == '\\') {
 | 
			
		||||
		c = f.get();
 | 
			
		||||
		c = f.get();		
 | 
			
		||||
		if (c == '\r')
 | 
			
		||||
			c = f.get();
 | 
			
		||||
		if (c == '\n')
 | 
			
		||||
		if (c == '\n') {
 | 
			
		||||
			line++;
 | 
			
		||||
			return lexer(str);
 | 
			
		||||
		}
 | 
			
		||||
		f.unget();
 | 
			
		||||
		return '\\';
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -186,14 +188,39 @@ LibertyAst *LibertyParser::parse()
 | 
			
		|||
 | 
			
		||||
	int tok = lexer(str);
 | 
			
		||||
 | 
			
		||||
	while (tok == 'n')
 | 
			
		||||
	// there are liberty files in the wild that
 | 
			
		||||
	// have superfluous ';' at the end of
 | 
			
		||||
	// a  { ... }. We simply ignore a ';' here.
 | 
			
		||||
	// and get to the next statement.
 | 
			
		||||
 | 
			
		||||
	while ((tok == 'n') || (tok == ';'))
 | 
			
		||||
		tok = lexer(str);
 | 
			
		||||
 | 
			
		||||
	if (tok == '}' || tok < 0)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (tok != 'v')
 | 
			
		||||
		error();
 | 
			
		||||
	if (tok != 'v') {
 | 
			
		||||
		std::string eReport;
 | 
			
		||||
		switch(tok)
 | 
			
		||||
		{
 | 
			
		||||
		case 'n':
 | 
			
		||||
			error("Unexpected newline.");
 | 
			
		||||
			break;
 | 
			
		||||
		case '[':
 | 
			
		||||
		case ']':
 | 
			
		||||
		case '}':
 | 
			
		||||
		case '{':
 | 
			
		||||
		case '\"':
 | 
			
		||||
		case ':':
 | 
			
		||||
			eReport = "Unexpected '";
 | 
			
		||||
			eReport += static_cast<char>(tok);
 | 
			
		||||
			eReport += "'.";
 | 
			
		||||
			error(eReport);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			error();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LibertyAst *ast = new LibertyAst;
 | 
			
		||||
	ast->id = str;
 | 
			
		||||
| 
						 | 
				
			
			@ -282,8 +309,28 @@ LibertyAst *LibertyParser::parse()
 | 
			
		|||
					}
 | 
			
		||||
					continue;           
 | 
			
		||||
				}
 | 
			
		||||
				if (tok != 'v')
 | 
			
		||||
					error();
 | 
			
		||||
				if (tok != 'v') {
 | 
			
		||||
					std::string eReport;
 | 
			
		||||
					switch(tok)
 | 
			
		||||
					{
 | 
			
		||||
					case 'n':
 | 
			
		||||
						error("Unexpected newline.");
 | 
			
		||||
						break;
 | 
			
		||||
					case '[':
 | 
			
		||||
					case ']':
 | 
			
		||||
					case '}':
 | 
			
		||||
					case '{':
 | 
			
		||||
					case '\"':
 | 
			
		||||
					case ':':
 | 
			
		||||
						eReport = "Unexpected '";
 | 
			
		||||
						eReport += static_cast<char>(tok);
 | 
			
		||||
						eReport += "'.";
 | 
			
		||||
						error(eReport);
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						error();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				ast->args.push_back(arg);
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,8 +142,7 @@ library(supergate) {
 | 
			
		|||
  }
 | 
			
		||||
  
 | 
			
		||||
  /* D-type flip-flop with asynchronous reset and preset */
 | 
			
		||||
  cell (dff) 
 | 
			
		||||
  {
 | 
			
		||||
  cell (dff) {
 | 
			
		||||
    area : 6;
 | 
			
		||||
    ff("IQ", "IQN") {
 | 
			
		||||
      next_state : "D";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								tests/liberty/processdefs.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/liberty/processdefs.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
/********************************************/
 | 
			
		||||
/*                                          */
 | 
			
		||||
/* Supergate cell library for Bench marking */
 | 
			
		||||
/*                                          */
 | 
			
		||||
/* Symbiotic EDA GmbH / Moseley Instruments */
 | 
			
		||||
/* Niels A. Moseley                         */
 | 
			
		||||
/*                                          */
 | 
			
		||||
/* Process: none                            */
 | 
			
		||||
/*                                          */
 | 
			
		||||
/* Date   : 25-03-2019                      */
 | 
			
		||||
/* Version: 1.0                             */
 | 
			
		||||
/*                                          */
 | 
			
		||||
/********************************************/
 | 
			
		||||
 | 
			
		||||
library(processdefs) {
 | 
			
		||||
    technology (cmos);
 | 
			
		||||
    revision : 1.0;
 | 
			
		||||
 | 
			
		||||
    time_unit                     : "1ps";
 | 
			
		||||
    pulling_resistance_unit       : "1kohm";  
 | 
			
		||||
    voltage_unit                  : "1V";
 | 
			
		||||
    current_unit                  : "1uA";  
 | 
			
		||||
 | 
			
		||||
    capacitive_load_unit(1,ff);
 | 
			
		||||
 | 
			
		||||
    default_inout_pin_cap         :  7.0;
 | 
			
		||||
    default_input_pin_cap         :  7.0;
 | 
			
		||||
    default_output_pin_cap        :  0.0;
 | 
			
		||||
    default_fanout_load           :  1.0;
 | 
			
		||||
 | 
			
		||||
    default_wire_load_capacitance : 0.1;
 | 
			
		||||
    default_wire_load_resistance  : 1.0e-3;
 | 
			
		||||
    default_wire_load_area        : 0.0;
 | 
			
		||||
 | 
			
		||||
    nom_process                   :  1.0;
 | 
			
		||||
    nom_temperature               : 25.0;
 | 
			
		||||
    nom_voltage                   :  1.2;
 | 
			
		||||
 | 
			
		||||
    delay_model                   : generic_cmos;
 | 
			
		||||
    
 | 
			
		||||
    define_cell_area(bond_pads,pad_slots)
 | 
			
		||||
    input_voltage(cmos) {
 | 
			
		||||
        vil : 0.3 * VDD ;
 | 
			
		||||
        vih : 0.7 * VDD ;
 | 
			
		||||
        vimin : -0.5 ;
 | 
			
		||||
        vimax : VDD + 0.5 ;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								tests/liberty/semicolextra.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/liberty/semicolextra.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
/*
 | 
			
		||||
 | 
			
		||||
	Test case for https://www.reddit.com/r/yosys/comments/b5texg/yosys_fails_to_parse_apparentlycorrect_liberty/
 | 
			
		||||
 | 
			
		||||
	fall_constraint (SETUP_HOLD) formatting.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
library(supergate) {
 | 
			
		||||
  technology (cmos);
 | 
			
		||||
  revision : 1.0;
 | 
			
		||||
 | 
			
		||||
    cell (DFF) {
 | 
			
		||||
        cell_footprint : dff;
 | 
			
		||||
        area : 50;
 | 
			
		||||
        pin(D) {
 | 
			
		||||
            direction : input;
 | 
			
		||||
            capacitance : 0.002;
 | 
			
		||||
            timing() {
 | 
			
		||||
                related_pin : "CK";
 | 
			
		||||
                timing_type : setup_rising;
 | 
			
		||||
 | 
			
		||||
                fall_constraint (SETUP_HOLD) { values ("0.4000, 0.3000, 0.2000, 0.1000, 0.0000", \
 | 
			
		||||
                    "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \
 | 
			
		||||
                    "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \
 | 
			
		||||
                    "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \
 | 
			
		||||
                    "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); };
 | 
			
		||||
            }
 | 
			
		||||
        }	
 | 
			
		||||
 | 
			
		||||
        pin(CK) {
 | 
			
		||||
            direction : input;
 | 
			
		||||
            clock : true;
 | 
			
		||||
            capacitance : 0.00290;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ff(IQ,IQN) {
 | 
			
		||||
            clocked_on : "CK";
 | 
			
		||||
            next_state : "D";
 | 
			
		||||
        }
 | 
			
		||||
        pin(Q) {
 | 
			
		||||
            direction : output;
 | 
			
		||||
            capacitance : 0.003;
 | 
			
		||||
            max_capacitance : 0.3;
 | 
			
		||||
        }
 | 
			
		||||
        cell_leakage_power : 0.3;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								tests/sva/extnets.sv
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/sva/extnets.sv
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
module top(input i, output o);
 | 
			
		||||
	A A();
 | 
			
		||||
	B B();
 | 
			
		||||
	assign A.i = i;
 | 
			
		||||
	assign o = B.o;
 | 
			
		||||
	always @* assert(o == i);
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module A;
 | 
			
		||||
	wire i, y;
 | 
			
		||||
`ifdef FAIL
 | 
			
		||||
	assign B.x = i;
 | 
			
		||||
`else
 | 
			
		||||
	assign B.x = !i;
 | 
			
		||||
`endif
 | 
			
		||||
	assign y = !B.y;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module B;
 | 
			
		||||
	wire x, y, o;
 | 
			
		||||
	assign y = x, o = A.y;
 | 
			
		||||
endmodule
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue