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
						24553326dd
					
				
					 53 changed files with 2399 additions and 39 deletions
				
			
		
							
								
								
									
										14
									
								
								.github/issue_template.md
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/issue_template.md
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -4,6 +4,17 @@
 | 
			
		|||
all necessary source files. (You can simply drag&drop a .zip file into
 | 
			
		||||
the issue editor.)*
 | 
			
		||||
 | 
			
		||||
Also, make sure that the issue is actually reproducable in current git
 | 
			
		||||
master of Yosys.
 | 
			
		||||
 | 
			
		||||
See https://stackoverflow.com/help/mcve for some information on how to
 | 
			
		||||
create a Minimal, Complete, and Verifiable example (MCVE).
 | 
			
		||||
 | 
			
		||||
Please do not waste our time with issues that lack sufficient information
 | 
			
		||||
to reproduce the issue easily. We will simply close those issues.
 | 
			
		||||
 | 
			
		||||
Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
 | 
			
		||||
 | 
			
		||||
## Expected behavior
 | 
			
		||||
 | 
			
		||||
*Please describe the behavior you would have expected from the tool.*
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +22,3 @@ the issue editor.)*
 | 
			
		|||
## Actual behavior
 | 
			
		||||
 | 
			
		||||
*Please describe how the behavior you see differs from the expected behavior.*
 | 
			
		||||
 | 
			
		||||
**Important Note:** Nobody will be able to help you and/or fix the issue if you
 | 
			
		||||
do not provide sufficient information for reproducing the problem.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -24,6 +24,8 @@
 | 
			
		|||
/yosys-abc.exe
 | 
			
		||||
/yosys-config
 | 
			
		||||
/yosys-smtbmc
 | 
			
		||||
/yosys-smtbmc.exe
 | 
			
		||||
/yosys-smtbmc-script.py
 | 
			
		||||
/yosys-filterlib
 | 
			
		||||
/yosys-filterlib.exe
 | 
			
		||||
/kernel/version_*.cc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -575,7 +575,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
 | 
			
		|||
	+cd tests/simple && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/hana && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/realmath && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/share && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/fsm && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/techmap && bash run-test.sh
 | 
			
		||||
| 
						 | 
				
			
			@ -585,6 +585,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
 | 
			
		|||
	+cd tests/sat && bash run-test.sh
 | 
			
		||||
	+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
 | 
			
		||||
	+cd tests/opt && bash run-test.sh
 | 
			
		||||
	+cd tests/aiger && bash run-test.sh
 | 
			
		||||
	@echo ""
 | 
			
		||||
	@echo "  Passed \"make test\"."
 | 
			
		||||
	@echo ""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,12 +105,15 @@ Makefile.
 | 
			
		|||
To build Yosys simply type 'make' in this directory.
 | 
			
		||||
 | 
			
		||||
	$ make
 | 
			
		||||
	$ make test
 | 
			
		||||
	$ sudo make install
 | 
			
		||||
 | 
			
		||||
Note that this also downloads, builds and installs ABC (using yosys-abc
 | 
			
		||||
as executable name).
 | 
			
		||||
 | 
			
		||||
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
 | 
			
		||||
 | 
			
		||||
	$ make test
 | 
			
		||||
 | 
			
		||||
Getting Started
 | 
			
		||||
===============
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
 | 
			
		|||
		f << stringf("%s  case ", indent.c_str());
 | 
			
		||||
		for (size_t i = 0; i < (*it)->compare.size(); i++) {
 | 
			
		||||
			if (i > 0)
 | 
			
		||||
				f << stringf(", ");
 | 
			
		||||
				f << stringf(" , ");
 | 
			
		||||
			dump_sigspec(f, (*it)->compare[i]);
 | 
			
		||||
		}
 | 
			
		||||
		f << stringf("\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
 | 
			
		|||
 | 
			
		||||
ifneq ($(CONFIG),mxe)
 | 
			
		||||
ifneq ($(CONFIG),emcc)
 | 
			
		||||
 | 
			
		||||
# MSYS targets support yosys-smtbmc, but require a launcher script
 | 
			
		||||
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
 | 
			
		||||
TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
 | 
			
		||||
# Needed to find the Python interpreter for yosys-smtbmc scripts.
 | 
			
		||||
# Override if necessary, it is only used for msys2 targets.
 | 
			
		||||
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
 | 
			
		||||
 | 
			
		||||
yosys-smtbmc-script.py: backends/smt2/smtbmc.py
 | 
			
		||||
	$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
 | 
			
		||||
		-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
 | 
			
		||||
 | 
			
		||||
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
 | 
			
		||||
	$(P) gcc -DGUI=0 -O -s -o $@ $<
 | 
			
		||||
# Other targets
 | 
			
		||||
else
 | 
			
		||||
TARGETS += yosys-smtbmc
 | 
			
		||||
 | 
			
		||||
yosys-smtbmc: backends/smt2/smtbmc.py
 | 
			
		||||
	$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
 | 
			
		||||
	$(Q) chmod +x $@.new
 | 
			
		||||
	$(Q) mv $@.new $@
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1484,11 +1484,11 @@ else:  # not tempind, covermode
 | 
			
		|||
                            smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
 | 
			
		||||
                            smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
 | 
			
		||||
                            smt_assert_consequent(get_constr_expr(constr_assumes, i))
 | 
			
		||||
                    print_msg("Re-solving with appended steps..")
 | 
			
		||||
                    if smt_check_sat() == "unsat":
 | 
			
		||||
                        print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
 | 
			
		||||
                        retstatus = False
 | 
			
		||||
                        break
 | 
			
		||||
                        print_msg("Re-solving with appended steps..")
 | 
			
		||||
                        if smt_check_sat() == "unsat":
 | 
			
		||||
                            print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
 | 
			
		||||
                            retstatus = False
 | 
			
		||||
                            break
 | 
			
		||||
                    print_anyconsts(step)
 | 
			
		||||
                    for i in range(step, last_check_step+1):
 | 
			
		||||
                        print_failed_asserts(i)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								frontends/aiger/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								frontends/aiger/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
 | 
			
		||||
OBJS += frontends/aiger/aigerparse.o
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										414
									
								
								frontends/aiger/aigerparse.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								frontends/aiger/aigerparse.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,414 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
			
		||||
 *                      Eddie Hung <eddie@fpgeh.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.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
 | 
			
		||||
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
 | 
			
		||||
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#include <libgen.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "kernel/sigtools.h"
 | 
			
		||||
#include "aigerparse.h"
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
#define log_debug log
 | 
			
		||||
 | 
			
		||||
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
 | 
			
		||||
    : design(design), f(f), clk_name(clk_name)
 | 
			
		||||
{
 | 
			
		||||
    module = new RTLIL::Module;
 | 
			
		||||
    module->name = module_name;
 | 
			
		||||
    if (design->module(module->name))
 | 
			
		||||
        log_error("Duplicate definition of module %s!\n", log_id(module->name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AigerReader::parse_aiger()
 | 
			
		||||
{
 | 
			
		||||
    std::string header;
 | 
			
		||||
    f >> header;
 | 
			
		||||
    if (header != "aag" && header != "aig")
 | 
			
		||||
        log_error("Unsupported AIGER file!\n");
 | 
			
		||||
 | 
			
		||||
    // Parse rest of header
 | 
			
		||||
    if (!(f >> M >> I >> L >> O >> A))
 | 
			
		||||
        log_error("Invalid AIGER header\n");
 | 
			
		||||
 | 
			
		||||
    // Optional values
 | 
			
		||||
    B = C = J = F = 0;
 | 
			
		||||
    for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
 | 
			
		||||
        if (f.peek() != ' ') break;
 | 
			
		||||
        if (!(f >> i))
 | 
			
		||||
            log_error("Invalid AIGER header\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string line;
 | 
			
		||||
    std::getline(f, line); // Ignore up to start of next line, as standard
 | 
			
		||||
                           // says anything that follows could be used for
 | 
			
		||||
                           // optional sections
 | 
			
		||||
 | 
			
		||||
    log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
 | 
			
		||||
 | 
			
		||||
    line_count = 1;
 | 
			
		||||
 | 
			
		||||
    if (header == "aag")
 | 
			
		||||
        parse_aiger_ascii();
 | 
			
		||||
    else if (header == "aig")
 | 
			
		||||
        parse_aiger_binary();
 | 
			
		||||
    else
 | 
			
		||||
        log_abort();
 | 
			
		||||
 | 
			
		||||
    // Parse footer (symbol table, comments, etc.)
 | 
			
		||||
    unsigned l1;
 | 
			
		||||
    std::string s;
 | 
			
		||||
    for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
 | 
			
		||||
        if (c == 'i' || c == 'l' || c == 'o') {
 | 
			
		||||
            f.ignore(1);
 | 
			
		||||
            if (!(f >> l1 >> s))
 | 
			
		||||
                log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
 | 
			
		||||
 | 
			
		||||
            if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
 | 
			
		||||
                log_error("Line %u has invalid symbol position!\n", line_count);
 | 
			
		||||
 | 
			
		||||
            RTLIL::Wire* wire;
 | 
			
		||||
            if (c == 'i') wire = inputs[l1];
 | 
			
		||||
            else if (c == 'l') wire = latches[l1];
 | 
			
		||||
            else if (c == 'o') wire = outputs[l1];
 | 
			
		||||
            else log_abort();
 | 
			
		||||
 | 
			
		||||
            module->rename(wire, stringf("\\%s", s.c_str()));
 | 
			
		||||
        }
 | 
			
		||||
        else if (c == 'b' || c == 'j' || c == 'f') {
 | 
			
		||||
            // TODO
 | 
			
		||||
        }
 | 
			
		||||
        else if (c == 'c') {
 | 
			
		||||
            f.ignore(1);
 | 
			
		||||
            if (f.peek() == '\n')
 | 
			
		||||
                break;
 | 
			
		||||
            // Else constraint (TODO)
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    module->fixup_ports();
 | 
			
		||||
    design->add(module);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
 | 
			
		||||
{
 | 
			
		||||
    const unsigned variable = literal >> 1;
 | 
			
		||||
    const bool invert = literal & 1;
 | 
			
		||||
    RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
 | 
			
		||||
    RTLIL::Wire *wire = module->wire(wire_name);
 | 
			
		||||
    if (wire) return wire;
 | 
			
		||||
    log_debug("Creating %s\n", wire_name.c_str());
 | 
			
		||||
    wire = module->addWire(wire_name);
 | 
			
		||||
    if (!invert) return wire;
 | 
			
		||||
    RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
 | 
			
		||||
    RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
 | 
			
		||||
    if (wire_inv) {
 | 
			
		||||
        if (module->cell(wire_inv_name)) return wire;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        log_debug("Creating %s\n", wire_inv_name.c_str());
 | 
			
		||||
        wire_inv = module->addWire(wire_inv_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
 | 
			
		||||
    module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
 | 
			
		||||
 | 
			
		||||
    return wire;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AigerReader::parse_aiger_ascii()
 | 
			
		||||
{
 | 
			
		||||
    std::string line;
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
 | 
			
		||||
    unsigned l1, l2, l3;
 | 
			
		||||
 | 
			
		||||
    // Parse inputs
 | 
			
		||||
    for (unsigned i = 0; i < I; ++i, ++line_count) {
 | 
			
		||||
        if (!(f >> l1))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as an input!\n", line_count);
 | 
			
		||||
        log_debug("%d is an input\n", l1);
 | 
			
		||||
        log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
 | 
			
		||||
        RTLIL::Wire *wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        wire->port_input = true;
 | 
			
		||||
        inputs.push_back(wire);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse latches
 | 
			
		||||
    RTLIL::Wire *clk_wire = nullptr;
 | 
			
		||||
    if (L > 0) {
 | 
			
		||||
        clk_wire = module->wire(clk_name);
 | 
			
		||||
        log_assert(!clk_wire);
 | 
			
		||||
        log_debug("Creating %s\n", clk_name.c_str());
 | 
			
		||||
        clk_wire = module->addWire(clk_name);
 | 
			
		||||
        clk_wire->port_input = true;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned i = 0; i < L; ++i, ++line_count) {
 | 
			
		||||
        if (!(f >> l1 >> l2))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as a latch!\n", line_count);
 | 
			
		||||
        log_debug("%d %d is a latch\n", l1, l2);
 | 
			
		||||
        log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
 | 
			
		||||
        RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
 | 
			
		||||
 | 
			
		||||
        module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
 | 
			
		||||
 | 
			
		||||
        // Reset logic is optional in AIGER 1.9
 | 
			
		||||
        if (f.peek() == ' ') {
 | 
			
		||||
            if (!(f >> l3))
 | 
			
		||||
                log_error("Line %u cannot be interpreted as a latch!\n", line_count);
 | 
			
		||||
 | 
			
		||||
            if (l3 == 0 || l3 == 1)
 | 
			
		||||
                q_wire->attributes["\\init"] = RTLIL::Const(l3);
 | 
			
		||||
            else if (l3 == l1) {
 | 
			
		||||
                //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                log_error("Line %u has invalid reset literal for latch!\n", line_count);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // AIGER latches are assumed to be initialized to zero
 | 
			
		||||
            q_wire->attributes["\\init"] = RTLIL::Const(0);
 | 
			
		||||
        }
 | 
			
		||||
        latches.push_back(q_wire);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse outputs
 | 
			
		||||
    for (unsigned i = 0; i < O; ++i, ++line_count) {
 | 
			
		||||
        if (!(f >> l1))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as an output!\n", line_count);
 | 
			
		||||
 | 
			
		||||
        log_debug("%d is an output\n", l1);
 | 
			
		||||
        RTLIL::Wire *wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        wire->port_output = true;
 | 
			
		||||
        outputs.push_back(wire);
 | 
			
		||||
    }
 | 
			
		||||
    std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse bad state properties
 | 
			
		||||
    for (unsigned i = 0; i < B; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse invariant constraints
 | 
			
		||||
    for (unsigned i = 0; i < C; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse justice properties
 | 
			
		||||
    for (unsigned i = 0; i < J; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse fairness constraints
 | 
			
		||||
    for (unsigned i = 0; i < F; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // Parse AND
 | 
			
		||||
    for (unsigned i = 0; i < A; ++i) {
 | 
			
		||||
        if (!(f >> l1 >> l2 >> l3))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as an AND!\n", line_count);
 | 
			
		||||
 | 
			
		||||
        log_debug("%d %d %d is an AND\n", l1, l2, l3);
 | 
			
		||||
        log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
 | 
			
		||||
        RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
 | 
			
		||||
        RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
 | 
			
		||||
        module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
 | 
			
		||||
    }
 | 
			
		||||
    std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
 | 
			
		||||
{
 | 
			
		||||
    unsigned x = 0, i = 0;
 | 
			
		||||
    unsigned char ch;
 | 
			
		||||
    while ((ch = f.get()) & 0x80)
 | 
			
		||||
        x |= (ch & 0x7f) << (7 * i++);
 | 
			
		||||
    return ref - (x | (ch << (7 * i)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AigerReader::parse_aiger_binary()
 | 
			
		||||
{
 | 
			
		||||
    unsigned l1, l2, l3;
 | 
			
		||||
    std::string line;
 | 
			
		||||
 | 
			
		||||
    // Parse inputs
 | 
			
		||||
    for (unsigned i = 1; i <= I; ++i) {
 | 
			
		||||
        RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
 | 
			
		||||
        wire->port_input = true;
 | 
			
		||||
        inputs.push_back(wire);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse latches
 | 
			
		||||
    RTLIL::Wire *clk_wire = nullptr;
 | 
			
		||||
    if (L > 0) {
 | 
			
		||||
        clk_wire = module->wire(clk_name);
 | 
			
		||||
        log_assert(!clk_wire);
 | 
			
		||||
        log_debug("Creating %s\n", clk_name.c_str());
 | 
			
		||||
        clk_wire = module->addWire(clk_name);
 | 
			
		||||
        clk_wire->port_input = true;
 | 
			
		||||
    }
 | 
			
		||||
    l1 = (I+1) * 2;
 | 
			
		||||
    for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
 | 
			
		||||
        if (!(f >> l2))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as a latch!\n", line_count);
 | 
			
		||||
        log_debug("%d %d is a latch\n", l1, l2);
 | 
			
		||||
        RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
 | 
			
		||||
 | 
			
		||||
        module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
 | 
			
		||||
 | 
			
		||||
        // Reset logic is optional in AIGER 1.9
 | 
			
		||||
        if (f.peek() == ' ') {
 | 
			
		||||
            if (!(f >> l3))
 | 
			
		||||
                log_error("Line %u cannot be interpreted as a latch!\n", line_count);
 | 
			
		||||
 | 
			
		||||
            if (l3 == 0 || l3 == 1)
 | 
			
		||||
                q_wire->attributes["\\init"] = RTLIL::Const(l3);
 | 
			
		||||
            else if (l3 == l1) {
 | 
			
		||||
                //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                log_error("Line %u has invalid reset literal for latch!\n", line_count);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // AIGER latches are assumed to be initialized to zero
 | 
			
		||||
            q_wire->attributes["\\init"] = RTLIL::Const(0);
 | 
			
		||||
        }
 | 
			
		||||
        latches.push_back(q_wire);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse outputs
 | 
			
		||||
    for (unsigned i = 0; i < O; ++i, ++line_count) {
 | 
			
		||||
        if (!(f >> l1))
 | 
			
		||||
            log_error("Line %u cannot be interpreted as an output!\n", line_count);
 | 
			
		||||
 | 
			
		||||
        log_debug("%d is an output\n", l1);
 | 
			
		||||
        RTLIL::Wire *wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        wire->port_output = true;
 | 
			
		||||
        outputs.push_back(wire);
 | 
			
		||||
    }
 | 
			
		||||
    std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse bad state properties
 | 
			
		||||
    for (unsigned i = 0; i < B; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse invariant constraints
 | 
			
		||||
    for (unsigned i = 0; i < C; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse justice properties
 | 
			
		||||
    for (unsigned i = 0; i < J; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // TODO: Parse fairness constraints
 | 
			
		||||
    for (unsigned i = 0; i < F; ++i, ++line_count)
 | 
			
		||||
        std::getline(f, line); // Ignore up to start of next line
 | 
			
		||||
 | 
			
		||||
    // Parse AND
 | 
			
		||||
    l1 = (I+L+1) << 1;
 | 
			
		||||
    for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
 | 
			
		||||
        l2 = parse_next_delta_literal(f, l1);
 | 
			
		||||
        l3 = parse_next_delta_literal(f, l2);
 | 
			
		||||
 | 
			
		||||
        log_debug("%d %d %d is an AND\n", l1, l2, l3);
 | 
			
		||||
        log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
 | 
			
		||||
        RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
 | 
			
		||||
        RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
 | 
			
		||||
        RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
 | 
			
		||||
 | 
			
		||||
        RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
 | 
			
		||||
        and_cell->setPort("\\A", i1_wire);
 | 
			
		||||
        and_cell->setPort("\\B", i2_wire);
 | 
			
		||||
        and_cell->setPort("\\Y", o_wire);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct AigerFrontend : public Frontend {
 | 
			
		||||
    AigerFrontend() : Frontend("aiger", "read AIGER file") { }
 | 
			
		||||
    void help() YS_OVERRIDE
 | 
			
		||||
    {
 | 
			
		||||
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
        log("\n");
 | 
			
		||||
        log("    read_aiger [options] [filename]\n");
 | 
			
		||||
        log("\n");
 | 
			
		||||
        log("Load module from an AIGER file into the current design.\n");
 | 
			
		||||
        log("\n");
 | 
			
		||||
        log("    -module_name <module_name>\n");
 | 
			
		||||
        log("        Name of module to be created (default: <filename>)"
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		                                                   "top" // FIXME
 | 
			
		||||
#else
 | 
			
		||||
		                                                   "<filename>"
 | 
			
		||||
#endif
 | 
			
		||||
                                                           ")\n");
 | 
			
		||||
        log("\n");
 | 
			
		||||
        log("    -clk_name <wire_name>\n");
 | 
			
		||||
        log("        AIGER latches to be transformed into posedge DFFs clocked by wire of");
 | 
			
		||||
        log("        this name (default: clk)\n");
 | 
			
		||||
        log("\n");
 | 
			
		||||
    }
 | 
			
		||||
    void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
			
		||||
    {
 | 
			
		||||
        log_header(design, "Executing AIGER frontend.\n");
 | 
			
		||||
 | 
			
		||||
        RTLIL::IdString clk_name = "\\clk";
 | 
			
		||||
        RTLIL::IdString module_name;
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++) {
 | 
			
		||||
			std::string arg = args[argidx];
 | 
			
		||||
			if (arg == "-module_name" && argidx+1 < args.size()) {
 | 
			
		||||
				module_name = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-clk_name" && argidx+1 < args.size()) {
 | 
			
		||||
				clk_name = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(f, filename, args, argidx);
 | 
			
		||||
 | 
			
		||||
        if (module_name.empty()) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
            module_name = "top"; // FIXME: basename equivalent on Win32?
 | 
			
		||||
#else
 | 
			
		||||
            char* bn = strdup(filename.c_str());
 | 
			
		||||
            module_name = RTLIL::escape_id(bn);
 | 
			
		||||
            free(bn);
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AigerReader reader(design, *f, module_name, clk_name);
 | 
			
		||||
		reader.parse_aiger();
 | 
			
		||||
    }
 | 
			
		||||
} AigerFrontend;
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
							
								
								
									
										51
									
								
								frontends/aiger/aigerparse.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								frontends/aiger/aigerparse.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
			
		||||
 *                      Eddie Hung <eddie@fpgeh.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 ABC_AIGERPARSE
 | 
			
		||||
#define ABC_AIGERPARSE
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
struct AigerReader
 | 
			
		||||
{
 | 
			
		||||
    RTLIL::Design *design;
 | 
			
		||||
    std::istream &f;
 | 
			
		||||
    RTLIL::IdString clk_name;
 | 
			
		||||
    RTLIL::Module *module;
 | 
			
		||||
 | 
			
		||||
    unsigned M, I, L, O, A;
 | 
			
		||||
    unsigned B, C, J, F; // Optional in AIGER 1.9
 | 
			
		||||
    unsigned line_count;
 | 
			
		||||
 | 
			
		||||
    std::vector<RTLIL::Wire*> inputs;
 | 
			
		||||
    std::vector<RTLIL::Wire*> latches;
 | 
			
		||||
    std::vector<RTLIL::Wire*> outputs;
 | 
			
		||||
 | 
			
		||||
    AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
 | 
			
		||||
    void parse_aiger();
 | 
			
		||||
    void parse_aiger_ascii();
 | 
			
		||||
    void parse_aiger_binary();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				}
 | 
			
		||||
 | 
			
		||||
				if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
 | 
			
		||||
			#if 0
 | 
			
		||||
					// this is a valid transformation, but as optimization it is premature.
 | 
			
		||||
					// better: add a default case that assigns 'x' to everything, and let later
 | 
			
		||||
					// optimizations take care of the rest
 | 
			
		||||
					last_generated_case->compare.clear();
 | 
			
		||||
			#else
 | 
			
		||||
					default_case = new RTLIL::CaseRule;
 | 
			
		||||
					addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
 | 
			
		||||
					sw->cases.push_back(default_case);
 | 
			
		||||
			#endif
 | 
			
		||||
				} else {
 | 
			
		||||
					if (default_case == NULL) {
 | 
			
		||||
						default_case = new RTLIL::CaseRule;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2863,7 +2863,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
 | 
			
		|||
 | 
			
		||||
	for (size_t i = 0; i < children.size(); i++) {
 | 
			
		||||
		AstNode *child = children[i];
 | 
			
		||||
		if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
 | 
			
		||||
		// AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
 | 
			
		||||
		// still needs to recursed-into
 | 
			
		||||
		if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (child->type != AST_FUNCTION && child->type != AST_TASK)
 | 
			
		||||
			child->expand_genblock(index_var, prefix, name_map);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -584,7 +584,7 @@ struct BlifFrontend : public Frontend {
 | 
			
		|||
	{
 | 
			
		||||
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    read_blif [filename]\n");
 | 
			
		||||
		log("    read_blif [options] [filename]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Load modules from a BLIF file into the current design.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,6 +81,27 @@ struct CellTypes
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_internals()
 | 
			
		||||
	{
 | 
			
		||||
		setup_internals_eval();
 | 
			
		||||
 | 
			
		||||
		IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
 | 
			
		||||
 | 
			
		||||
		setup_type("$tribuf", {A, EN}, {Y}, true);
 | 
			
		||||
 | 
			
		||||
		setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$equiv", {A, B}, {Y}, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_internals_eval()
 | 
			
		||||
	{
 | 
			
		||||
		std::vector<RTLIL::IdString> unary_ops = {
 | 
			
		||||
			"$not", "$pos", "$neg",
 | 
			
		||||
| 
						 | 
				
			
			@ -111,20 +132,6 @@ struct CellTypes
 | 
			
		|||
		setup_type("$lcu", {P, G, CI}, {CO}, true);
 | 
			
		||||
		setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
 | 
			
		||||
		setup_type("$fa", {A, B, C}, {X, Y}, true);
 | 
			
		||||
 | 
			
		||||
		setup_type("$tribuf", {A, EN}, {Y}, true);
 | 
			
		||||
 | 
			
		||||
		setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
			
		||||
		setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
			
		||||
		setup_type("$equiv", {A, B}, {Y}, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_internals_mem()
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +160,15 @@ struct CellTypes
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_stdcells()
 | 
			
		||||
	{
 | 
			
		||||
		setup_stdcells_eval();
 | 
			
		||||
 | 
			
		||||
		IdString A = "\\A", E = "\\E", Y = "\\Y";
 | 
			
		||||
 | 
			
		||||
		setup_type("$_TBUF_", {A, E}, {Y}, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_stdcells_eval()
 | 
			
		||||
	{
 | 
			
		||||
		IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
 | 
			
		||||
		IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +195,6 @@ struct CellTypes
 | 
			
		|||
		setup_type("$_OAI3_", {A, B, C}, {Y}, true);
 | 
			
		||||
		setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
 | 
			
		||||
		setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
 | 
			
		||||
		setup_type("$_TBUF_", {A, E}, {Y}, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setup_stdcells_mem()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -557,9 +557,11 @@ public:
 | 
			
		|||
	void clear() { hashtable.clear(); entries.clear(); }
 | 
			
		||||
 | 
			
		||||
	iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
			
		||||
	iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
 | 
			
		||||
	iterator end() { return iterator(nullptr, -1); }
 | 
			
		||||
 | 
			
		||||
	const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
			
		||||
	const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
 | 
			
		||||
	const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -881,9 +883,11 @@ public:
 | 
			
		|||
	void clear() { hashtable.clear(); entries.clear(); }
 | 
			
		||||
 | 
			
		||||
	iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
			
		||||
	iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
 | 
			
		||||
	iterator end() { return iterator(nullptr, -1); }
 | 
			
		||||
 | 
			
		||||
	const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
			
		||||
	const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
 | 
			
		||||
	const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -952,6 +956,7 @@ public:
 | 
			
		|||
	void clear() { database.clear(); }
 | 
			
		||||
 | 
			
		||||
	const_iterator begin() const { return database.begin(); }
 | 
			
		||||
	const_iterator element(int n) const { return database.element(n); }
 | 
			
		||||
	const_iterator end() const { return database.end(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1051,6 +1056,7 @@ public:
 | 
			
		|||
	void clear() { database.clear(); parents.clear(); }
 | 
			
		||||
 | 
			
		||||
	const_iterator begin() const { return database.begin(); }
 | 
			
		||||
	const_iterator element(int n) const { return database.element(n); }
 | 
			
		||||
	const_iterator end() const { return database.end(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -760,7 +760,7 @@ namespace {
 | 
			
		|||
 | 
			
		||||
		void check()
 | 
			
		||||
		{
 | 
			
		||||
			if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
 | 
			
		||||
			if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
 | 
			
		||||
					cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2360,7 +2360,7 @@ void RTLIL::Cell::check()
 | 
			
		|||
 | 
			
		||||
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 | 
			
		||||
{
 | 
			
		||||
	if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
 | 
			
		||||
	if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
 | 
			
		||||
			type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										358
									
								
								misc/launcher.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								misc/launcher.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,358 @@
 | 
			
		|||
/* This file comes from the PyPA Setuptools repository, commit 16e452a:
 | 
			
		||||
https://github.com/pypa/setuptools
 | 
			
		||||
Modifications include this comment and inline inclusion of the LICENSE text. */
 | 
			
		||||
 | 
			
		||||
/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE. */
 | 
			
		||||
 | 
			
		||||
/*  Setuptools Script Launcher for Windows
 | 
			
		||||
 | 
			
		||||
    This is a stub executable for Windows that functions somewhat like
 | 
			
		||||
    Effbot's "exemaker", in that it runs a script with the same name but
 | 
			
		||||
    a .py extension, using information from a #! line.  It differs in that
 | 
			
		||||
    it spawns the actual Python executable, rather than attempting to
 | 
			
		||||
    hook into the Python DLL.  This means that the script will run with
 | 
			
		||||
    sys.executable set to the Python executable, where exemaker ends up with
 | 
			
		||||
    sys.executable pointing to itself.  (Which means it won't work if you try
 | 
			
		||||
    to run another Python process using sys.executable.)
 | 
			
		||||
 | 
			
		||||
    To build/rebuild with mingw32, do this in the setuptools project directory:
 | 
			
		||||
 | 
			
		||||
       gcc -DGUI=0           -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
 | 
			
		||||
       gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
 | 
			
		||||
 | 
			
		||||
    To build for Windows RT, install both Visual Studio Express for Windows 8
 | 
			
		||||
    and for Windows Desktop (both freeware), create "win32" application using
 | 
			
		||||
    "Windows Desktop" version, create new "ARM" target via
 | 
			
		||||
    "Configuration Manager" menu and modify ".vcxproj" file by adding
 | 
			
		||||
    "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
 | 
			
		||||
    as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
 | 
			
		||||
    properties.
 | 
			
		||||
 | 
			
		||||
    It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
 | 
			
		||||
    actually run Python in the same process.  Note that using 'exec' instead
 | 
			
		||||
    of 'spawn' doesn't work, because on Windows this leads to the Python
 | 
			
		||||
    executable running in the *background*, attached to the same console
 | 
			
		||||
    window, meaning you get a command prompt back *before* Python even finishes
 | 
			
		||||
    starting.  So, we have to use spawnv() and wait for Python to exit before
 | 
			
		||||
    continuing.  :(
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <tchar.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
int child_pid=0;
 | 
			
		||||
 | 
			
		||||
int fail(char *format, char *data) {
 | 
			
		||||
    /* Print error message to stderr and return 2 */
 | 
			
		||||
    fprintf(stderr, format, data);
 | 
			
		||||
    return 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *quoted(char *data) {
 | 
			
		||||
    int i, ln = strlen(data), nb;
 | 
			
		||||
 | 
			
		||||
    /* We allocate twice as much space as needed to deal with worse-case
 | 
			
		||||
       of having to escape everything. */
 | 
			
		||||
    char *result = calloc(ln*2+3, sizeof(char));
 | 
			
		||||
    char *presult = result;
 | 
			
		||||
 | 
			
		||||
    *presult++ = '"';
 | 
			
		||||
    for (nb=0, i=0; i < ln; i++)
 | 
			
		||||
      {
 | 
			
		||||
        if (data[i] == '\\')
 | 
			
		||||
          nb += 1;
 | 
			
		||||
        else if (data[i] == '"')
 | 
			
		||||
          {
 | 
			
		||||
            for (; nb > 0; nb--)
 | 
			
		||||
              *presult++ = '\\';
 | 
			
		||||
            *presult++ = '\\';
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          nb = 0;
 | 
			
		||||
        *presult++ = data[i];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    for (; nb > 0; nb--)        /* Deal w trailing slashes */
 | 
			
		||||
      *presult++ = '\\';
 | 
			
		||||
 | 
			
		||||
    *presult++ = '"';
 | 
			
		||||
    *presult++ = 0;
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char *loadable_exe(char *exename) {
 | 
			
		||||
    /* HINSTANCE hPython;  DLL handle for python executable */
 | 
			
		||||
    char *result;
 | 
			
		||||
 | 
			
		||||
    /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
 | 
			
		||||
    if (!hPython) return NULL; */
 | 
			
		||||
 | 
			
		||||
    /* Return the absolute filename for spawnv */
 | 
			
		||||
    result = calloc(MAX_PATH, sizeof(char));
 | 
			
		||||
    strncpy(result, exename, MAX_PATH);
 | 
			
		||||
    /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
 | 
			
		||||
 | 
			
		||||
    FreeLibrary(hPython); */
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char *find_exe(char *exename, char *script) {
 | 
			
		||||
    char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
 | 
			
		||||
    char path[_MAX_PATH], c, *result;
 | 
			
		||||
 | 
			
		||||
    /* convert slashes to backslashes for uniform search below */
 | 
			
		||||
    result = exename;
 | 
			
		||||
    while (c = *result++) if (c=='/') result[-1] = '\\';
 | 
			
		||||
 | 
			
		||||
    _splitpath(exename, drive, dir, fname, ext);
 | 
			
		||||
    if (drive[0] || dir[0]=='\\') {
 | 
			
		||||
        return loadable_exe(exename);   /* absolute path, use directly */
 | 
			
		||||
    }
 | 
			
		||||
    /* Use the script's parent directory, which should be the Python home
 | 
			
		||||
       (This should only be used for bdist_wininst-installed scripts, because
 | 
			
		||||
        easy_install-ed scripts use the absolute path to python[w].exe
 | 
			
		||||
    */
 | 
			
		||||
    _splitpath(script, drive, dir, fname, ext);
 | 
			
		||||
    result = dir + strlen(dir) -1;
 | 
			
		||||
    if (*result == '\\') result--;
 | 
			
		||||
    while (*result != '\\' && result>=dir) *result-- = 0;
 | 
			
		||||
    _makepath(path, drive, dir, exename, NULL);
 | 
			
		||||
    return loadable_exe(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char **parse_argv(char *cmdline, int *argc)
 | 
			
		||||
{
 | 
			
		||||
    /* Parse a command line in-place using MS C rules */
 | 
			
		||||
 | 
			
		||||
    char **result = calloc(strlen(cmdline), sizeof(char *));
 | 
			
		||||
    char *output = cmdline;
 | 
			
		||||
    char c;
 | 
			
		||||
    int nb = 0;
 | 
			
		||||
    int iq = 0;
 | 
			
		||||
    *argc = 0;
 | 
			
		||||
 | 
			
		||||
    result[0] = output;
 | 
			
		||||
    while (isspace(*cmdline)) cmdline++;   /* skip leading spaces */
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        c = *cmdline++;
 | 
			
		||||
        if (!c || (isspace(c) && !iq)) {
 | 
			
		||||
            while (nb) {*output++ = '\\'; nb--; }
 | 
			
		||||
            *output++ = 0;
 | 
			
		||||
            result[++*argc] = output;
 | 
			
		||||
            if (!c) return result;
 | 
			
		||||
            while (isspace(*cmdline)) cmdline++;  /* skip leading spaces */
 | 
			
		||||
            if (!*cmdline) return result;  /* avoid empty arg if trailing ws */
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (c == '\\')
 | 
			
		||||
            ++nb;   /* count \'s */
 | 
			
		||||
        else {
 | 
			
		||||
            if (c == '"') {
 | 
			
		||||
                if (!(nb & 1)) { iq = !iq; c = 0; }  /* skip " unless odd # of \ */
 | 
			
		||||
                nb = nb >> 1;   /* cut \'s in half */
 | 
			
		||||
            }
 | 
			
		||||
            while (nb) {*output++ = '\\'; nb--; }
 | 
			
		||||
            if (c) *output++ = c;
 | 
			
		||||
        }
 | 
			
		||||
    } while (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pass_control_to_child(DWORD control_type) {
 | 
			
		||||
    /*
 | 
			
		||||
     * distribute-issue207
 | 
			
		||||
     * passes the control event to child process (Python)
 | 
			
		||||
     */
 | 
			
		||||
    if (!child_pid) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    GenerateConsoleCtrlEvent(child_pid,0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOL control_handler(DWORD control_type) {
 | 
			
		||||
    /*
 | 
			
		||||
     * distribute-issue207
 | 
			
		||||
     * control event handler callback function
 | 
			
		||||
     */
 | 
			
		||||
    switch (control_type) {
 | 
			
		||||
        case CTRL_C_EVENT:
 | 
			
		||||
            pass_control_to_child(0);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int create_and_wait_for_subprocess(char* command) {
 | 
			
		||||
    /*
 | 
			
		||||
     * distribute-issue207
 | 
			
		||||
     * launches child process (Python)
 | 
			
		||||
     */
 | 
			
		||||
    DWORD return_value = 0;
 | 
			
		||||
    LPSTR commandline = command;
 | 
			
		||||
    STARTUPINFOA s_info;
 | 
			
		||||
    PROCESS_INFORMATION p_info;
 | 
			
		||||
    ZeroMemory(&p_info, sizeof(p_info));
 | 
			
		||||
    ZeroMemory(&s_info, sizeof(s_info));
 | 
			
		||||
    s_info.cb = sizeof(STARTUPINFO);
 | 
			
		||||
    // set-up control handler callback funciotn
 | 
			
		||||
    SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
 | 
			
		||||
    if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
 | 
			
		||||
        fprintf(stderr, "failed to create process.\n");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    child_pid = p_info.dwProcessId;
 | 
			
		||||
    // wait for Python to exit
 | 
			
		||||
    WaitForSingleObject(p_info.hProcess, INFINITE);
 | 
			
		||||
    if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
 | 
			
		||||
        fprintf(stderr, "failed to get exit code from process.\n");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return return_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char* join_executable_and_args(char *executable, char **args, int argc)
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * distribute-issue207
 | 
			
		||||
     * CreateProcess needs a long string of the executable and command-line arguments,
 | 
			
		||||
     * so we need to convert it from the args that was built
 | 
			
		||||
     */
 | 
			
		||||
    int len,counter;
 | 
			
		||||
    char* cmdline;
 | 
			
		||||
 | 
			
		||||
    len=strlen(executable)+2;
 | 
			
		||||
    for (counter=1; counter<argc; counter++) {
 | 
			
		||||
        len+=strlen(args[counter])+1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cmdline = (char*)calloc(len, sizeof(char));
 | 
			
		||||
    sprintf(cmdline, "%s", executable);
 | 
			
		||||
    len=strlen(executable);
 | 
			
		||||
    for (counter=1; counter<argc; counter++) {
 | 
			
		||||
        sprintf(cmdline+len, " %s", args[counter]);
 | 
			
		||||
        len+=strlen(args[counter])+1;
 | 
			
		||||
    }
 | 
			
		||||
    return cmdline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int run(int argc, char **argv, int is_gui) {
 | 
			
		||||
 | 
			
		||||
    char python[256];   /* python executable's filename*/
 | 
			
		||||
    char *pyopt;        /* Python option */
 | 
			
		||||
    char script[256];   /* the script's filename */
 | 
			
		||||
 | 
			
		||||
    int scriptf;        /* file descriptor for script file */
 | 
			
		||||
 | 
			
		||||
    char **newargs, **newargsp, **parsedargs; /* argument array for exec */
 | 
			
		||||
    char *ptr, *end;    /* working pointers for string manipulation */
 | 
			
		||||
    char *cmdline;
 | 
			
		||||
    int i, parsedargc;              /* loop counter */
 | 
			
		||||
 | 
			
		||||
    /* compute script name from our .exe name*/
 | 
			
		||||
    GetModuleFileNameA(NULL, script, sizeof(script));
 | 
			
		||||
    end = script + strlen(script);
 | 
			
		||||
    while( end>script && *end != '.')
 | 
			
		||||
        *end-- = '\0';
 | 
			
		||||
    *end-- = '\0';
 | 
			
		||||
    strcat(script, (GUI ? "-script.pyw" : "-script.py"));
 | 
			
		||||
 | 
			
		||||
    /* figure out the target python executable */
 | 
			
		||||
 | 
			
		||||
    scriptf = open(script, O_RDONLY);
 | 
			
		||||
    if (scriptf == -1) {
 | 
			
		||||
        return fail("Cannot open %s\n", script);
 | 
			
		||||
    }
 | 
			
		||||
    end = python + read(scriptf, python, sizeof(python));
 | 
			
		||||
    close(scriptf);
 | 
			
		||||
 | 
			
		||||
    ptr = python-1;
 | 
			
		||||
    while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
 | 
			
		||||
 | 
			
		||||
    *ptr-- = '\0';
 | 
			
		||||
 | 
			
		||||
    if (strncmp(python, "#!", 2)) {
 | 
			
		||||
        /* default to python.exe if no #! header */
 | 
			
		||||
        strcpy(python, "#!python.exe");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parsedargs = parse_argv(python+2, &parsedargc);
 | 
			
		||||
 | 
			
		||||
    /* Using spawnv() can fail strangely if you e.g. find the Cygwin
 | 
			
		||||
       Python, so we'll make sure Windows can find and load it */
 | 
			
		||||
 | 
			
		||||
    ptr = find_exe(parsedargs[0], script);
 | 
			
		||||
    if (!ptr) {
 | 
			
		||||
        return fail("Cannot find Python executable %s\n", parsedargs[0]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* printf("Python executable: %s\n", ptr); */
 | 
			
		||||
 | 
			
		||||
    /* Argument array needs to be
 | 
			
		||||
       parsedargc + argc, plus 1 for null sentinel */
 | 
			
		||||
 | 
			
		||||
    newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
 | 
			
		||||
    newargsp = newargs;
 | 
			
		||||
 | 
			
		||||
    *newargsp++ = quoted(ptr);
 | 
			
		||||
    for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
 | 
			
		||||
 | 
			
		||||
    *newargsp++ = quoted(script);
 | 
			
		||||
    for (i = 1; i < argc; i++)     *newargsp++ = quoted(argv[i]);
 | 
			
		||||
 | 
			
		||||
    *newargsp++ = NULL;
 | 
			
		||||
 | 
			
		||||
    /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
 | 
			
		||||
 | 
			
		||||
    if (is_gui) {
 | 
			
		||||
        /* Use exec, we don't need to wait for the GUI to finish */
 | 
			
		||||
        execv(ptr, (const char * const *)(newargs));
 | 
			
		||||
        return fail("Could not exec %s", ptr);   /* shouldn't get here! */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * distribute-issue207: using CreateProcessA instead of spawnv
 | 
			
		||||
     */
 | 
			
		||||
    cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
 | 
			
		||||
    return create_and_wait_for_subprocess(cmdline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
 | 
			
		||||
    return run(__argc, __argv, GUI);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
    return run(argc, argv, GUI);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
 | 
			
		|||
			new_b.append_bit(it.first.second);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
 | 
			
		||||
			log("  Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
 | 
			
		||||
			module->connect(new_y, new_b);
 | 
			
		||||
			module->connect(new_conn);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
 | 
			
		||||
 | 
			
		||||
		c->setPort("\\A", new_a);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,4 +9,6 @@ OBJS += passes/sat/assertpmux.o
 | 
			
		|||
OBJS += passes/sat/clk2fflogic.o
 | 
			
		||||
OBJS += passes/sat/async2sync.o
 | 
			
		||||
OBJS += passes/sat/supercover.o
 | 
			
		||||
OBJS += passes/sat/fmcombine.o
 | 
			
		||||
OBJS += passes/sat/mutate.o
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										341
									
								
								passes/sat/fmcombine.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								passes/sat/fmcombine.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,341 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
			
		||||
 *
 | 
			
		||||
 *  Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
 *  purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 *  copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "kernel/sigtools.h"
 | 
			
		||||
#include "kernel/celltypes.h"
 | 
			
		||||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
PRIVATE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
struct opts_t
 | 
			
		||||
{
 | 
			
		||||
	bool fwd = false;
 | 
			
		||||
	bool bwd = false;
 | 
			
		||||
	bool nop = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FmcombineWorker
 | 
			
		||||
{
 | 
			
		||||
	const opts_t &opts;
 | 
			
		||||
	Design *design;
 | 
			
		||||
	Module *original = nullptr;
 | 
			
		||||
	Module *module = nullptr;
 | 
			
		||||
	IdString orig_type, combined_type;
 | 
			
		||||
 | 
			
		||||
	FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) :
 | 
			
		||||
			opts(opts), design(design), original(design->module(orig_type)),
 | 
			
		||||
			orig_type(orig_type), combined_type("$fmcombine" + orig_type.str())
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SigSpec import_sig(SigSpec sig, const string &suffix)
 | 
			
		||||
	{
 | 
			
		||||
		SigSpec newsig;
 | 
			
		||||
		for (auto chunk : sig.chunks()) {
 | 
			
		||||
			if (chunk.wire != nullptr)
 | 
			
		||||
				chunk.wire = module->wire(chunk.wire->name.str() + suffix);
 | 
			
		||||
			newsig.append(chunk);
 | 
			
		||||
		}
 | 
			
		||||
		return newsig;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void import_prim_cell(Cell *cell, const string &suffix)
 | 
			
		||||
	{
 | 
			
		||||
		Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
 | 
			
		||||
		c->parameters = cell->parameters;
 | 
			
		||||
		c->attributes = cell->attributes;
 | 
			
		||||
 | 
			
		||||
		for (auto &conn : cell->connections())
 | 
			
		||||
			c->setPort(conn.first, import_sig(conn.second, suffix));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void import_hier_cell(Cell *cell)
 | 
			
		||||
	{
 | 
			
		||||
		if (!cell->parameters.empty())
 | 
			
		||||
			log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell));
 | 
			
		||||
 | 
			
		||||
		FmcombineWorker sub_worker(design, cell->type, opts);
 | 
			
		||||
		sub_worker.generate();
 | 
			
		||||
 | 
			
		||||
		Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type);
 | 
			
		||||
		// c->parameters = cell->parameters;
 | 
			
		||||
		c->attributes = cell->attributes;
 | 
			
		||||
 | 
			
		||||
		for (auto &conn : cell->connections()) {
 | 
			
		||||
			c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold"));
 | 
			
		||||
			c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate"));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void generate()
 | 
			
		||||
	{
 | 
			
		||||
		if (design->module(combined_type)) {
 | 
			
		||||
			// log("Combined module %s already exists.\n", log_id(combined_type));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type));
 | 
			
		||||
		module = design->addModule(combined_type);
 | 
			
		||||
 | 
			
		||||
		for (auto wire : original->wires()) {
 | 
			
		||||
			module->addWire(wire->name.str() + "_gold", wire);
 | 
			
		||||
			module->addWire(wire->name.str() + "_gate", wire);
 | 
			
		||||
		}
 | 
			
		||||
		module->fixup_ports();
 | 
			
		||||
 | 
			
		||||
		for (auto cell : original->cells()) {
 | 
			
		||||
			if (design->module(cell->type) == nullptr) {
 | 
			
		||||
				import_prim_cell(cell, "_gold");
 | 
			
		||||
				import_prim_cell(cell, "_gate");
 | 
			
		||||
			} else {
 | 
			
		||||
				import_hier_cell(cell);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto &conn : original->connections()) {
 | 
			
		||||
			module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold"));
 | 
			
		||||
			module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (opts.nop)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		CellTypes ct;
 | 
			
		||||
		ct.setup_internals_eval();
 | 
			
		||||
		ct.setup_stdcells_eval();
 | 
			
		||||
 | 
			
		||||
		SigMap sigmap(module);
 | 
			
		||||
 | 
			
		||||
		dict<SigBit, SigBit> data_bit_to_eq_net;
 | 
			
		||||
		dict<Cell*, SigSpec> cell_to_eq_nets;
 | 
			
		||||
		dict<SigSpec, SigSpec> reduce_db;
 | 
			
		||||
		dict<SigSpec, SigSpec> invert_db;
 | 
			
		||||
 | 
			
		||||
		for (auto cell : original->cells())
 | 
			
		||||
		{
 | 
			
		||||
			if (!ct.cell_known(cell->type))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			for (auto &conn : cell->connections())
 | 
			
		||||
			{
 | 
			
		||||
				if (!cell->output(conn.first))
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				SigSpec A = import_sig(conn.second, "_gold");
 | 
			
		||||
				SigSpec B = import_sig(conn.second, "_gate");
 | 
			
		||||
				SigBit EQ = module->Eq(NEW_ID, A, B);
 | 
			
		||||
 | 
			
		||||
				for (auto bit : sigmap({A, B}))
 | 
			
		||||
					data_bit_to_eq_net[bit] = EQ;
 | 
			
		||||
 | 
			
		||||
				cell_to_eq_nets[cell].append(EQ);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto cell : original->cells())
 | 
			
		||||
		{
 | 
			
		||||
			if (!ct.cell_known(cell->type))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			bool skip_cell = !cell_to_eq_nets.count(cell);
 | 
			
		||||
			pool<SigBit> src_eq_bits;
 | 
			
		||||
 | 
			
		||||
			for (auto &conn : cell->connections())
 | 
			
		||||
			{
 | 
			
		||||
				if (skip_cell)
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				if (cell->output(conn.first))
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				SigSpec A = import_sig(conn.second, "_gold");
 | 
			
		||||
				SigSpec B = import_sig(conn.second, "_gate");
 | 
			
		||||
 | 
			
		||||
				for (auto bit : sigmap({A, B})) {
 | 
			
		||||
					if (data_bit_to_eq_net.count(bit))
 | 
			
		||||
						src_eq_bits.insert(data_bit_to_eq_net.at(bit));
 | 
			
		||||
					else
 | 
			
		||||
						skip_cell = true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!skip_cell) {
 | 
			
		||||
				SigSpec antecedent = SigSpec(src_eq_bits);
 | 
			
		||||
				antecedent.sort_and_unify();
 | 
			
		||||
 | 
			
		||||
				if (GetSize(antecedent) > 1) {
 | 
			
		||||
					if (reduce_db.count(antecedent) == 0)
 | 
			
		||||
						reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent);
 | 
			
		||||
					antecedent = reduce_db.at(antecedent);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				SigSpec consequent = cell_to_eq_nets.at(cell);
 | 
			
		||||
				consequent.sort_and_unify();
 | 
			
		||||
 | 
			
		||||
				if (GetSize(consequent) > 1) {
 | 
			
		||||
					if (reduce_db.count(consequent) == 0)
 | 
			
		||||
						reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent);
 | 
			
		||||
					consequent = reduce_db.at(consequent);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (opts.fwd)
 | 
			
		||||
					module->addAssume(NEW_ID, consequent, antecedent);
 | 
			
		||||
 | 
			
		||||
				if (opts.bwd)
 | 
			
		||||
				{
 | 
			
		||||
					if (invert_db.count(antecedent) == 0)
 | 
			
		||||
						invert_db[antecedent] = module->Not(NEW_ID, antecedent);
 | 
			
		||||
 | 
			
		||||
					if (invert_db.count(consequent) == 0)
 | 
			
		||||
						invert_db[consequent] = module->Not(NEW_ID, consequent);
 | 
			
		||||
 | 
			
		||||
					module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FmcombinePass : public Pass {
 | 
			
		||||
	FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
 | 
			
		||||
	void help() YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    fmcombine [options] module_name gold_cell gate_cell\n");
 | 
			
		||||
		// log("    fmcombine [options] @gold_cell @gate_cell\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("This pass takes two cells, which are instances of the same module, and replaces\n");
 | 
			
		||||
		log("them with one instance of a special 'combined' module, that effectively\n");
 | 
			
		||||
		log("contains two copies of the original module, plus some formal properties.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("This is useful for formal test benches that check what differences in behavior\n");
 | 
			
		||||
		log("a slight difference in input causes in a module.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -fwd\n");
 | 
			
		||||
		log("        Insert forward hint assumptions into the combined module.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -bwd\n");
 | 
			
		||||
		log("        Insert backward hint assumptions into the combined module.\n");
 | 
			
		||||
		log("        (Backward hints are logically equivalend to fordward hits, but\n");
 | 
			
		||||
		log("        some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -nop\n");
 | 
			
		||||
		log("        Don't insert hint assumptions into the combined module.\n");
 | 
			
		||||
		log("        (This should not provide any speedup over the original design, but\n");
 | 
			
		||||
		log("        strangely sometimes it does.)\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
		opts_t opts;
 | 
			
		||||
		Module *module = nullptr;
 | 
			
		||||
		Cell *gold_cell = nullptr;
 | 
			
		||||
		Cell *gate_cell = nullptr;
 | 
			
		||||
 | 
			
		||||
		log_header(design, "Executing FMCOMBINE pass.\n");
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
			// if (args[argidx] == "-o" && argidx+1 < args.size()) {
 | 
			
		||||
			// 	filename = args[++argidx];
 | 
			
		||||
			// 	continue;
 | 
			
		||||
			// }
 | 
			
		||||
			if (args[argidx] == "-fwd") {
 | 
			
		||||
				opts.fwd = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-bwd") {
 | 
			
		||||
				opts.bwd = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-nop") {
 | 
			
		||||
				opts.nop = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (argidx+2 == args.size())
 | 
			
		||||
		{
 | 
			
		||||
			string gold_name = args[argidx++];
 | 
			
		||||
			string gate_name = args[argidx++];
 | 
			
		||||
			log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet.");
 | 
			
		||||
		}
 | 
			
		||||
		else if (argidx+3 == args.size())
 | 
			
		||||
		{
 | 
			
		||||
			IdString module_name = RTLIL::escape_id(args[argidx++]);
 | 
			
		||||
			IdString gold_name = RTLIL::escape_id(args[argidx++]);
 | 
			
		||||
			IdString gate_name = RTLIL::escape_id(args[argidx++]);
 | 
			
		||||
 | 
			
		||||
			module = design->module(module_name);
 | 
			
		||||
			if (module == nullptr)
 | 
			
		||||
				log_cmd_error("Module %s not found.\n", log_id(module_name));
 | 
			
		||||
 | 
			
		||||
			gold_cell = module->cell(gold_name);
 | 
			
		||||
			if (gold_cell == nullptr)
 | 
			
		||||
				log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module));
 | 
			
		||||
 | 
			
		||||
			gate_cell = module->cell(gate_name);
 | 
			
		||||
			if (gate_cell == nullptr)
 | 
			
		||||
				log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			log_cmd_error("Invalid number of arguments.\n");
 | 
			
		||||
		}
 | 
			
		||||
		// extra_args(args, argidx, design);
 | 
			
		||||
 | 
			
		||||
		if (opts.nop && (opts.fwd || opts.bwd))
 | 
			
		||||
			log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n");
 | 
			
		||||
 | 
			
		||||
		if (!opts.nop && !opts.fwd && !opts.bwd)
 | 
			
		||||
			opts.fwd = true;
 | 
			
		||||
 | 
			
		||||
		if (gold_cell->type != gate_cell->type)
 | 
			
		||||
			log_cmd_error("Types of gold and gate cells do not match.\n");
 | 
			
		||||
		if (!gold_cell->parameters.empty())
 | 
			
		||||
			log_cmd_error("Gold cell has unresolved instance parameters.\n");
 | 
			
		||||
		if (!gate_cell->parameters.empty())
 | 
			
		||||
			log_cmd_error("Gold cell has unresolved instance parameters.\n");
 | 
			
		||||
 | 
			
		||||
		FmcombineWorker worker(design, gold_cell->type, opts);
 | 
			
		||||
		worker.generate();
 | 
			
		||||
		IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell)));
 | 
			
		||||
 | 
			
		||||
		Cell *cell = module->addCell(combined_cell_name, worker.combined_type);
 | 
			
		||||
		cell->attributes = gold_cell->attributes;
 | 
			
		||||
		cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src"));
 | 
			
		||||
 | 
			
		||||
		log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell));
 | 
			
		||||
 | 
			
		||||
		for (auto &conn : gold_cell->connections())
 | 
			
		||||
			cell->setPort(conn.first.str() + "_gold", conn.second);
 | 
			
		||||
		module->remove(gold_cell);
 | 
			
		||||
 | 
			
		||||
		for (auto &conn : gate_cell->connections())
 | 
			
		||||
			cell->setPort(conn.first.str() + "_gate", conn.second);
 | 
			
		||||
		module->remove(gate_cell);
 | 
			
		||||
	}
 | 
			
		||||
} FmcombinePass;
 | 
			
		||||
 | 
			
		||||
PRIVATE_NAMESPACE_END
 | 
			
		||||
							
								
								
									
										905
									
								
								passes/sat/mutate.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										905
									
								
								passes/sat/mutate.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,905 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
			
		||||
 *
 | 
			
		||||
 *  Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
 *  purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 *  copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "kernel/sigtools.h"
 | 
			
		||||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
PRIVATE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
struct mutate_t {
 | 
			
		||||
	string mode;
 | 
			
		||||
	pool<string> src;
 | 
			
		||||
	IdString module, cell;
 | 
			
		||||
	IdString port, wire;
 | 
			
		||||
	int portbit = -1;
 | 
			
		||||
	int ctrlbit = -1;
 | 
			
		||||
	int wirebit = -1;
 | 
			
		||||
	bool used = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mutate_opts_t {
 | 
			
		||||
	int seed = 0;
 | 
			
		||||
	std::string mode;
 | 
			
		||||
	pool<string> src;
 | 
			
		||||
	IdString module, cell, port, wire;
 | 
			
		||||
	int portbit = -1;
 | 
			
		||||
	int ctrlbit = -1;
 | 
			
		||||
	int wirebit = -1;
 | 
			
		||||
 | 
			
		||||
	IdString ctrl_name;
 | 
			
		||||
	int ctrl_width = -1, ctrl_value = -1;
 | 
			
		||||
 | 
			
		||||
	int pick_cover_prcnt = 80;
 | 
			
		||||
 | 
			
		||||
	int weight_cover = 500;
 | 
			
		||||
 | 
			
		||||
	int weight_pq_w = 100;
 | 
			
		||||
	int weight_pq_b = 100;
 | 
			
		||||
	int weight_pq_c = 100;
 | 
			
		||||
	int weight_pq_s = 100;
 | 
			
		||||
 | 
			
		||||
	int weight_pq_mw = 100;
 | 
			
		||||
	int weight_pq_mb = 100;
 | 
			
		||||
	int weight_pq_mc = 100;
 | 
			
		||||
	int weight_pq_ms = 100;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry)
 | 
			
		||||
{
 | 
			
		||||
	if (!opts.mode.empty() && opts.mode != entry.mode)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!opts.src.empty()) {
 | 
			
		||||
		bool found_match = false;
 | 
			
		||||
		for (auto &s : opts.src) {
 | 
			
		||||
			if (entry.src.count(s))
 | 
			
		||||
				found_match = true;
 | 
			
		||||
		}
 | 
			
		||||
		if (!found_match)
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!opts.module.empty() && opts.module != entry.module)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!opts.cell.empty() && opts.cell != entry.cell)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!opts.port.empty() && opts.port != entry.port)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (opts.portbit >= 0 && opts.portbit != entry.portbit)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!opts.wire.empty() && opts.wire != entry.wire)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	database.push_back(entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xs128_t
 | 
			
		||||
{
 | 
			
		||||
	uint32_t x = 123456789;
 | 
			
		||||
	uint32_t y = 0, z = 0, w = 0;
 | 
			
		||||
 | 
			
		||||
	xs128_t(int seed = 0) : w(seed) {
 | 
			
		||||
		next();
 | 
			
		||||
		next();
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void next() {
 | 
			
		||||
		uint32_t t = x ^ (x << 11);
 | 
			
		||||
		x = y, y = z, z = w;
 | 
			
		||||
		w ^= (w >> 19) ^ t ^ (t >> 8);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int operator()() {
 | 
			
		||||
		next();
 | 
			
		||||
		return w & 0x3fffffff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int operator()(int n) {
 | 
			
		||||
		if (n < 2)
 | 
			
		||||
			return 0;
 | 
			
		||||
		while (1) {
 | 
			
		||||
			int k = (*this)(), p = k % n;
 | 
			
		||||
			if ((k - p + n) <= 0x40000000)
 | 
			
		||||
				return p;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct coverdb_t
 | 
			
		||||
{
 | 
			
		||||
	dict<string, int> src_db;
 | 
			
		||||
	dict<tuple<IdString, IdString>, int> wire_db;
 | 
			
		||||
	dict<tuple<IdString, IdString, int>, int> wirebit_db;
 | 
			
		||||
 | 
			
		||||
	void insert(const mutate_t &m) {
 | 
			
		||||
		if (!m.wire.empty()) {
 | 
			
		||||
			wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0;
 | 
			
		||||
			wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		for (auto &s : m.src) {
 | 
			
		||||
			src_db[s] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void update(const mutate_t &m) {
 | 
			
		||||
		if (!m.wire.empty()) {
 | 
			
		||||
			wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++;
 | 
			
		||||
			wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++;
 | 
			
		||||
		}
 | 
			
		||||
		for (auto &s : m.src) {
 | 
			
		||||
			src_db.at(s)++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int score(const mutate_t &m) {
 | 
			
		||||
		int this_score = m.src.empty() ? 0 : 1;
 | 
			
		||||
		if (!m.wire.empty()) {
 | 
			
		||||
			this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5;
 | 
			
		||||
			this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1;
 | 
			
		||||
		}
 | 
			
		||||
		for (auto &s : m.src) {
 | 
			
		||||
			this_score += src_db.at(s) ? 0 : 5;
 | 
			
		||||
		}
 | 
			
		||||
		return this_score;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mutate_queue_t
 | 
			
		||||
{
 | 
			
		||||
	pool<mutate_t*, hash_ptr_ops> db;
 | 
			
		||||
 | 
			
		||||
	mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
			
		||||
		mutate_t *m = nullptr;
 | 
			
		||||
		if (rng(100) < opts.pick_cover_prcnt) {
 | 
			
		||||
			vector<mutate_t*> candidates, rmqueue;
 | 
			
		||||
			int best_score = -1;
 | 
			
		||||
			for (auto p : db) {
 | 
			
		||||
				if (p->used) {
 | 
			
		||||
					rmqueue.push_back(p);
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				int this_score = coverdb.score(*p);
 | 
			
		||||
				if (this_score > best_score) {
 | 
			
		||||
					best_score = this_score;
 | 
			
		||||
					candidates.clear();
 | 
			
		||||
				}
 | 
			
		||||
				if (best_score == this_score)
 | 
			
		||||
					candidates.push_back(p);
 | 
			
		||||
			}
 | 
			
		||||
			for (auto p : rmqueue)
 | 
			
		||||
				db.erase(p);
 | 
			
		||||
			if (!candidates.empty())
 | 
			
		||||
				m = candidates[rng(GetSize(candidates))];
 | 
			
		||||
		}
 | 
			
		||||
		if (m == nullptr) {
 | 
			
		||||
			while (!db.empty()) {
 | 
			
		||||
				int i = rng(GetSize(db));
 | 
			
		||||
				auto it = db.element(i);
 | 
			
		||||
				mutate_t *p = *it;
 | 
			
		||||
				db.erase(it);
 | 
			
		||||
				if (p->used == false) {
 | 
			
		||||
					m = p;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return m;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void add(mutate_t *m) {
 | 
			
		||||
		db.insert(m);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename K, typename T>
 | 
			
		||||
struct mutate_chain_queue_t
 | 
			
		||||
{
 | 
			
		||||
	dict<K, T> db;
 | 
			
		||||
 | 
			
		||||
	mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
			
		||||
		while (!db.empty()) {
 | 
			
		||||
			int i = rng(GetSize(db));
 | 
			
		||||
			auto it = db.element(i);
 | 
			
		||||
			mutate_t *m = it->second.pick(rng, coverdb, opts);
 | 
			
		||||
			if (m != nullptr)
 | 
			
		||||
				return m;
 | 
			
		||||
			db.erase(it);
 | 
			
		||||
		}
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename... Args>
 | 
			
		||||
	void add(mutate_t *m, K key, Args... args) {
 | 
			
		||||
		db[key].add(m, args...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename K, typename T>
 | 
			
		||||
struct mutate_once_queue_t
 | 
			
		||||
{
 | 
			
		||||
	dict<K, T> db;
 | 
			
		||||
 | 
			
		||||
	mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
			
		||||
		while (!db.empty()) {
 | 
			
		||||
			int i = rng(GetSize(db));
 | 
			
		||||
			auto it = db.element(i);
 | 
			
		||||
			mutate_t *m = it->second.pick(rng, coverdb, opts);
 | 
			
		||||
			db.erase(it);
 | 
			
		||||
			if (m != nullptr)
 | 
			
		||||
				return m;
 | 
			
		||||
		}
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename... Args>
 | 
			
		||||
	void add(mutate_t *m, K key, Args... args) {
 | 
			
		||||
		db[key].add(m, args...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng)
 | 
			
		||||
{
 | 
			
		||||
	std::vector<mutate_t> new_database;
 | 
			
		||||
	coverdb_t coverdb;
 | 
			
		||||
 | 
			
		||||
	int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s;
 | 
			
		||||
	total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms;
 | 
			
		||||
 | 
			
		||||
	if (N >= GetSize(database))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire;
 | 
			
		||||
	mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit;
 | 
			
		||||
	mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell;
 | 
			
		||||
	mutate_once_queue_t<string, mutate_queue_t> primary_queue_src;
 | 
			
		||||
 | 
			
		||||
	mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire;
 | 
			
		||||
	mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit;
 | 
			
		||||
	mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell;
 | 
			
		||||
	mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src;
 | 
			
		||||
 | 
			
		||||
	for (auto &m : database)
 | 
			
		||||
	{
 | 
			
		||||
		coverdb.insert(m);
 | 
			
		||||
 | 
			
		||||
		if (!m.wire.empty()) {
 | 
			
		||||
			primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire));
 | 
			
		||||
			primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit));
 | 
			
		||||
			primary_queue_module_wire.add(&m, m.module, m.wire);
 | 
			
		||||
			primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell));
 | 
			
		||||
		primary_queue_module_cell.add(&m, m.module, m.cell);
 | 
			
		||||
 | 
			
		||||
		for (auto &s : m.src) {
 | 
			
		||||
			primary_queue_src.add(&m, s);
 | 
			
		||||
			primary_queue_module_src.add(&m, m.module, s);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vector<mutate_t*> cover_candidates;
 | 
			
		||||
	int best_cover_score = -1;
 | 
			
		||||
	bool skip_cover = false;
 | 
			
		||||
 | 
			
		||||
	while (GetSize(new_database) < N)
 | 
			
		||||
	{
 | 
			
		||||
		int k = rng(total_weight);
 | 
			
		||||
 | 
			
		||||
		k -= opts.weight_cover;
 | 
			
		||||
		if (k < 0) {
 | 
			
		||||
			while (!skip_cover) {
 | 
			
		||||
				if (cover_candidates.empty()) {
 | 
			
		||||
					best_cover_score = -1;
 | 
			
		||||
					for (auto &m : database) {
 | 
			
		||||
						if (m.used || m.src.empty())
 | 
			
		||||
							continue;
 | 
			
		||||
						int this_score = -1;
 | 
			
		||||
						for (auto &s : m.src) {
 | 
			
		||||
							if (this_score == -1 || this_score > coverdb.src_db.at(s))
 | 
			
		||||
								this_score = coverdb.src_db.at(s);
 | 
			
		||||
						}
 | 
			
		||||
						log_assert(this_score != -1);
 | 
			
		||||
						if (best_cover_score == -1 || this_score < best_cover_score) {
 | 
			
		||||
							cover_candidates.clear();
 | 
			
		||||
							best_cover_score = this_score;
 | 
			
		||||
						}
 | 
			
		||||
						if (best_cover_score == this_score)
 | 
			
		||||
							cover_candidates.push_back(&m);
 | 
			
		||||
					}
 | 
			
		||||
					if (best_cover_score == -1) {
 | 
			
		||||
						skip_cover = true;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				mutate_t *m = nullptr;
 | 
			
		||||
				while (!cover_candidates.empty())
 | 
			
		||||
				{
 | 
			
		||||
					int idx = rng(GetSize(cover_candidates));
 | 
			
		||||
					mutate_t *p = cover_candidates[idx];
 | 
			
		||||
					cover_candidates[idx] = cover_candidates.back();
 | 
			
		||||
					cover_candidates.pop_back();
 | 
			
		||||
 | 
			
		||||
					if (p->used)
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					int this_score = -1;
 | 
			
		||||
					for (auto &s : p->src) {
 | 
			
		||||
						if (this_score == -1 || this_score > coverdb.src_db.at(s))
 | 
			
		||||
							this_score = coverdb.src_db.at(s);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (this_score != best_cover_score)
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					m = p;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (m != nullptr) {
 | 
			
		||||
					m->used = true;
 | 
			
		||||
					coverdb.update(*m);
 | 
			
		||||
					new_database.push_back(*m);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#define X(__wght, __queue)                               \
 | 
			
		||||
    k -= __wght;                                         \
 | 
			
		||||
    if (k < 0) {                                         \
 | 
			
		||||
      mutate_t *m = __queue.pick(rng, coverdb, opts);    \
 | 
			
		||||
      if (m != nullptr) {                                \
 | 
			
		||||
        m->used = true;                                  \
 | 
			
		||||
        coverdb.update(*m);                              \
 | 
			
		||||
        new_database.push_back(*m);                      \
 | 
			
		||||
      };                                                 \
 | 
			
		||||
      continue;                                          \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		X(opts.weight_pq_w, primary_queue_wire)
 | 
			
		||||
		X(opts.weight_pq_b, primary_queue_bit)
 | 
			
		||||
		X(opts.weight_pq_c, primary_queue_cell)
 | 
			
		||||
		X(opts.weight_pq_s, primary_queue_src)
 | 
			
		||||
 | 
			
		||||
		X(opts.weight_pq_mw, primary_queue_module_wire)
 | 
			
		||||
		X(opts.weight_pq_mb, primary_queue_module_bit)
 | 
			
		||||
		X(opts.weight_pq_mc, primary_queue_module_cell)
 | 
			
		||||
		X(opts.weight_pq_ms, primary_queue_module_src)
 | 
			
		||||
#undef X
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::swap(new_database, database);
 | 
			
		||||
 | 
			
		||||
	int covered_src_cnt = 0;
 | 
			
		||||
	int covered_wire_cnt = 0;
 | 
			
		||||
	int covered_wirebit_cnt = 0;
 | 
			
		||||
 | 
			
		||||
	for (auto &it : coverdb.src_db)
 | 
			
		||||
		if (it.second)
 | 
			
		||||
			covered_src_cnt++;
 | 
			
		||||
 | 
			
		||||
	for (auto &it : coverdb.wire_db)
 | 
			
		||||
		if (it.second)
 | 
			
		||||
			covered_wire_cnt++;
 | 
			
		||||
 | 
			
		||||
	for (auto &it : coverdb.wirebit_db)
 | 
			
		||||
		if (it.second)
 | 
			
		||||
			covered_wirebit_cnt++;
 | 
			
		||||
 | 
			
		||||
	log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db));
 | 
			
		||||
	log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db));
 | 
			
		||||
	log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N)
 | 
			
		||||
{
 | 
			
		||||
	std::vector<mutate_t> database;
 | 
			
		||||
	xs128_t rng(opts.seed);
 | 
			
		||||
 | 
			
		||||
	for (auto module : design->selected_modules())
 | 
			
		||||
	{
 | 
			
		||||
		if (!opts.module.empty() && module->name != opts.module)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		SigMap sigmap(module);
 | 
			
		||||
		dict<SigBit, int> bit_user_cnt;
 | 
			
		||||
 | 
			
		||||
		for (auto wire : module->wires()) {
 | 
			
		||||
			if (wire->name[0] == '\\' && wire->attributes.count("\\src"))
 | 
			
		||||
				sigmap.add(wire);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto cell : module->cells()) {
 | 
			
		||||
			for (auto &conn : cell->connections()) {
 | 
			
		||||
				if (cell->output(conn.first))
 | 
			
		||||
					continue;
 | 
			
		||||
				for (auto bit : sigmap(conn.second))
 | 
			
		||||
					bit_user_cnt[bit]++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto wire : module->selected_wires())
 | 
			
		||||
		{
 | 
			
		||||
			for (SigBit bit : SigSpec(wire))
 | 
			
		||||
			{
 | 
			
		||||
				SigBit sigbit = sigmap(bit);
 | 
			
		||||
 | 
			
		||||
				if (bit.wire == nullptr || sigbit.wire == nullptr)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				if (!bit.wire->port_id != !sigbit.wire->port_id) {
 | 
			
		||||
					if (bit.wire->port_id)
 | 
			
		||||
						sigmap.add(bit);
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
 | 
			
		||||
					if (bit.wire->name[0] == '\\')
 | 
			
		||||
						sigmap.add(bit);
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto cell : module->selected_cells())
 | 
			
		||||
		{
 | 
			
		||||
			if (!opts.cell.empty() && cell->name != opts.cell)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			for (auto &conn : cell->connections())
 | 
			
		||||
			{
 | 
			
		||||
				for (int i = 0; i < GetSize(conn.second); i++) {
 | 
			
		||||
					mutate_t entry;
 | 
			
		||||
					entry.module = module->name;
 | 
			
		||||
					entry.cell = cell->name;
 | 
			
		||||
					entry.port = conn.first;
 | 
			
		||||
					entry.portbit = i;
 | 
			
		||||
 | 
			
		||||
					for (auto &s : cell->get_strpool_attribute("\\src"))
 | 
			
		||||
						entry.src.insert(s);
 | 
			
		||||
 | 
			
		||||
					SigBit bit = sigmap(conn.second[i]);
 | 
			
		||||
					if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
 | 
			
		||||
						for (auto &s : bit.wire->get_strpool_attribute("\\src"))
 | 
			
		||||
							entry.src.insert(s);
 | 
			
		||||
						entry.wire = bit.wire->name;
 | 
			
		||||
						entry.wirebit = bit.offset;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					entry.mode = "inv";
 | 
			
		||||
					database_add(database, opts, entry);
 | 
			
		||||
 | 
			
		||||
					entry.mode = "const0";
 | 
			
		||||
					database_add(database, opts, entry);
 | 
			
		||||
 | 
			
		||||
					entry.mode = "const1";
 | 
			
		||||
					database_add(database, opts, entry);
 | 
			
		||||
 | 
			
		||||
					entry.mode = "cnot0";
 | 
			
		||||
					entry.ctrlbit = rng(GetSize(conn.second));
 | 
			
		||||
					if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
 | 
			
		||||
						database_add(database, opts, entry);
 | 
			
		||||
 | 
			
		||||
					entry.mode = "cnot1";
 | 
			
		||||
					entry.ctrlbit = rng(GetSize(conn.second));
 | 
			
		||||
					if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
 | 
			
		||||
						database_add(database, opts, entry);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log("Raw database size: %d\n", GetSize(database));
 | 
			
		||||
	if (N != 0) {
 | 
			
		||||
		database_reduce(database, opts, N, rng);
 | 
			
		||||
		log("Reduced database size: %d\n", GetSize(database));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::ofstream fout;
 | 
			
		||||
 | 
			
		||||
	if (!filename.empty()) {
 | 
			
		||||
		fout.open(filename, std::ios::out | std::ios::trunc);
 | 
			
		||||
		if (!fout.is_open())
 | 
			
		||||
			log_error("Could not open file \"%s\" with write access.\n", filename.c_str());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int ctrl_value = opts.ctrl_value;
 | 
			
		||||
 | 
			
		||||
	for (auto &entry : database) {
 | 
			
		||||
		string str = "mutate";
 | 
			
		||||
		if (!opts.ctrl_name.empty())
 | 
			
		||||
			str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
 | 
			
		||||
		str += stringf(" -mode %s", entry.mode.c_str());
 | 
			
		||||
		if (!entry.module.empty())
 | 
			
		||||
			str += stringf(" -module %s", log_id(entry.module));
 | 
			
		||||
		if (!entry.cell.empty())
 | 
			
		||||
			str += stringf(" -cell %s", log_id(entry.cell));
 | 
			
		||||
		if (!entry.port.empty())
 | 
			
		||||
			str += stringf(" -port %s", log_id(entry.port));
 | 
			
		||||
		if (entry.portbit >= 0)
 | 
			
		||||
			str += stringf(" -portbit %d", entry.portbit);
 | 
			
		||||
		if (entry.ctrlbit >= 0)
 | 
			
		||||
			str += stringf(" -ctrlbit %d", entry.ctrlbit);
 | 
			
		||||
		if (!entry.wire.empty())
 | 
			
		||||
			str += stringf(" -wire %s", log_id(entry.wire));
 | 
			
		||||
		if (entry.wirebit >= 0)
 | 
			
		||||
			str += stringf(" -wirebit %d", entry.wirebit);
 | 
			
		||||
		for (auto &s : entry.src)
 | 
			
		||||
			str += stringf(" -src %s", s.c_str());
 | 
			
		||||
		if (filename.empty())
 | 
			
		||||
			log("%s\n", str.c_str());
 | 
			
		||||
		else
 | 
			
		||||
			fout << str << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SigSpec mutate_ctrl_sig(Module *module, IdString name, int width)
 | 
			
		||||
{
 | 
			
		||||
	Wire *ctrl_wire = module->wire(name);
 | 
			
		||||
 | 
			
		||||
	if (ctrl_wire == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module));
 | 
			
		||||
 | 
			
		||||
		ctrl_wire = module->addWire(name, width);
 | 
			
		||||
		ctrl_wire->port_input = true;
 | 
			
		||||
		module->fixup_ports();
 | 
			
		||||
 | 
			
		||||
		for (auto mod : module->design->modules())
 | 
			
		||||
		for (auto cell : mod->cells())
 | 
			
		||||
		{
 | 
			
		||||
			if (cell->type != module->name)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			SigSpec ctrl = mutate_ctrl_sig(mod, name, width);
 | 
			
		||||
 | 
			
		||||
			log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod));
 | 
			
		||||
			cell->setPort(name, ctrl);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_assert(GetSize(ctrl_wire) == width);
 | 
			
		||||
	return ctrl_wire;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts)
 | 
			
		||||
{
 | 
			
		||||
	if (opts.ctrl_name.empty())
 | 
			
		||||
		return State::S1;
 | 
			
		||||
 | 
			
		||||
	SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width);
 | 
			
		||||
	return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig)
 | 
			
		||||
{
 | 
			
		||||
	SigBit ctrl_bit = mutate_ctrl(module, opts);
 | 
			
		||||
	if (ctrl_bit == State::S0)
 | 
			
		||||
		return unchanged_sig;
 | 
			
		||||
	if (ctrl_bit == State::S1)
 | 
			
		||||
		return changed_sig;
 | 
			
		||||
	return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mutate_inv(Design *design, const mutate_opts_t &opts)
 | 
			
		||||
{
 | 
			
		||||
	Module *module = design->module(opts.module);
 | 
			
		||||
	Cell *cell = module->cell(opts.cell);
 | 
			
		||||
 | 
			
		||||
	SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
			
		||||
	SigBit inbit, outbit;
 | 
			
		||||
 | 
			
		||||
	if (cell->input(opts.port))
 | 
			
		||||
	{
 | 
			
		||||
		log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
			
		||||
		SigBit outbit = module->Not(NEW_ID, bit);
 | 
			
		||||
		bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
			
		||||
		SigBit inbit = module->addWire(NEW_ID);
 | 
			
		||||
		SigBit outbit = module->Not(NEW_ID, inbit);
 | 
			
		||||
		module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
			
		||||
		bit = inbit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SigSpec s = cell->getPort(opts.port);
 | 
			
		||||
	s[opts.portbit] = bit;
 | 
			
		||||
	cell->setPort(opts.port, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mutate_const(Design *design, const mutate_opts_t &opts, bool one)
 | 
			
		||||
{
 | 
			
		||||
	Module *module = design->module(opts.module);
 | 
			
		||||
	Cell *cell = module->cell(opts.cell);
 | 
			
		||||
 | 
			
		||||
	SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
			
		||||
	SigBit inbit, outbit;
 | 
			
		||||
 | 
			
		||||
	if (cell->input(opts.port))
 | 
			
		||||
	{
 | 
			
		||||
		log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
			
		||||
		SigBit outbit = one ? State::S1 : State::S0;
 | 
			
		||||
		bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
			
		||||
		SigBit inbit = module->addWire(NEW_ID);
 | 
			
		||||
		SigBit outbit = one ? State::S1 : State::S0;
 | 
			
		||||
		module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
			
		||||
		bit = inbit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SigSpec s = cell->getPort(opts.port);
 | 
			
		||||
	s[opts.portbit] = bit;
 | 
			
		||||
	cell->setPort(opts.port, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
 | 
			
		||||
{
 | 
			
		||||
	Module *module = design->module(opts.module);
 | 
			
		||||
	Cell *cell = module->cell(opts.cell);
 | 
			
		||||
 | 
			
		||||
	SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
			
		||||
	SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit];
 | 
			
		||||
	SigBit inbit, outbit;
 | 
			
		||||
 | 
			
		||||
	if (cell->input(opts.port))
 | 
			
		||||
	{
 | 
			
		||||
		log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
 | 
			
		||||
		SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl);
 | 
			
		||||
		bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
 | 
			
		||||
		SigBit inbit = module->addWire(NEW_ID);
 | 
			
		||||
		SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl);
 | 
			
		||||
		module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
			
		||||
		bit = inbit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SigSpec s = cell->getPort(opts.port);
 | 
			
		||||
	s[opts.portbit] = bit;
 | 
			
		||||
	cell->setPort(opts.port, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct MutatePass : public Pass {
 | 
			
		||||
	MutatePass() : Pass("mutate", "generate or apply design mutations") { }
 | 
			
		||||
	void help() YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    mutate -list N [options] [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Create a list of N mutations using an even sampling.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -o filename\n");
 | 
			
		||||
		log("        Write list to this file instead of console output\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -seed N\n");
 | 
			
		||||
		log("        RNG seed for selecting mutations\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -ctrl name width value\n");
 | 
			
		||||
		log("        Add -ctrl options to the output. Use 'value' for first mutation, then\n");
 | 
			
		||||
		log("        simply count up from there.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -mode name\n");
 | 
			
		||||
		log("    -module name\n");
 | 
			
		||||
		log("    -cell name\n");
 | 
			
		||||
		log("    -port name\n");
 | 
			
		||||
		log("    -portbit int\n");
 | 
			
		||||
		log("    -ctrlbit int\n");
 | 
			
		||||
		log("    -wire name\n");
 | 
			
		||||
		log("    -wirebit int\n");
 | 
			
		||||
		log("    -src string\n");
 | 
			
		||||
		log("        Filter list of mutation candidates to those matching\n");
 | 
			
		||||
		log("        the given parameters.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -cfg option int\n");
 | 
			
		||||
		log("        Set a configuration option. Options available:\n");
 | 
			
		||||
		log("          weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n");
 | 
			
		||||
		log("          weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n");
 | 
			
		||||
		log("          weight_cover pick_cover_prcnt\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    mutate -mode MODE [options]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("Apply the given mutation.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -ctrl name width value\n");
 | 
			
		||||
		log("        Add a control signal with the given name and width. The mutation is\n");
 | 
			
		||||
		log("        activated if the control signal equals the given value.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -module name\n");
 | 
			
		||||
		log("    -cell name\n");
 | 
			
		||||
		log("    -port name\n");
 | 
			
		||||
		log("    -portbit int\n");
 | 
			
		||||
		log("    -ctrlbit int\n");
 | 
			
		||||
		log("        Mutation parameters, as generated by 'mutate -list N'.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -wire name\n");
 | 
			
		||||
		log("    -wirebit int\n");
 | 
			
		||||
		log("    -src string\n");
 | 
			
		||||
		log("        Ignored. (They are generated by -list for documentation purposes.)\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
			
		||||
	{
 | 
			
		||||
		mutate_opts_t opts;
 | 
			
		||||
		string filename;
 | 
			
		||||
		int N = -1;
 | 
			
		||||
 | 
			
		||||
		log_header(design, "Executing MUTATE pass.\n");
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
			if (args[argidx] == "-list" && argidx+1 < args.size()) {
 | 
			
		||||
				N = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-o" && argidx+1 < args.size()) {
 | 
			
		||||
				filename = args[++argidx];
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-seed" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.seed = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-mode" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.mode = args[++argidx];
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-ctrl" && argidx+3 < args.size()) {
 | 
			
		||||
				opts.ctrl_name = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				opts.ctrl_width = atoi(args[++argidx].c_str());
 | 
			
		||||
				opts.ctrl_value = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-module" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.module = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-cell" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.cell = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-port" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.port = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-portbit" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.portbit = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.ctrlbit = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-wire" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.wire = RTLIL::escape_id(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-wirebit" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.wirebit = atoi(args[++argidx].c_str());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-src" && argidx+1 < args.size()) {
 | 
			
		||||
				opts.src.insert(args[++argidx]);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-cfg" && argidx+2 < args.size()) {
 | 
			
		||||
				if (args[argidx+1] == "pick_cover_prcnt") {
 | 
			
		||||
					opts.pick_cover_prcnt = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_cover") {
 | 
			
		||||
					opts.weight_cover = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_w") {
 | 
			
		||||
					opts.weight_pq_w = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_b") {
 | 
			
		||||
					opts.weight_pq_b = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_c") {
 | 
			
		||||
					opts.weight_pq_c = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_s") {
 | 
			
		||||
					opts.weight_pq_s = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_mw") {
 | 
			
		||||
					opts.weight_pq_mw = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_mb") {
 | 
			
		||||
					opts.weight_pq_mb = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_mc") {
 | 
			
		||||
					opts.weight_pq_mc = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (args[argidx+1] == "weight_pq_ms") {
 | 
			
		||||
					opts.weight_pq_ms = atoi(args[argidx+2].c_str());
 | 
			
		||||
					argidx += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(args, argidx, design);
 | 
			
		||||
 | 
			
		||||
		if (N >= 0) {
 | 
			
		||||
			mutate_list(design, opts, filename, N);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (opts.mode == "inv") {
 | 
			
		||||
			mutate_inv(design, opts);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (opts.mode == "const0" || opts.mode == "const1") {
 | 
			
		||||
			mutate_const(design, opts, opts.mode == "const1");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (opts.mode == "cnot0" || opts.mode == "cnot1") {
 | 
			
		||||
			mutate_cnot(design, opts, opts.mode == "cnot1");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_cmd_error("Invalid mode: %s\n", opts.mode.c_str());
 | 
			
		||||
	}
 | 
			
		||||
} MutatePass;
 | 
			
		||||
 | 
			
		||||
PRIVATE_NAMESPACE_END
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,8 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("    map_cells:\n");
 | 
			
		||||
		log("        techmap -map +/xilinx/cells_map.v\n");
 | 
			
		||||
		log("        dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT\n");
 | 
			
		||||
		log("        dffinit -ff FDRE   Q INIT -ff FDCE   Q INIT -ff FDPE   Q INIT -ff FDSE   Q INIT \\\n");
 | 
			
		||||
		log("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
 | 
			
		||||
		log("        clean\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    check:\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +279,8 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
		if (check_label(active, run_from, run_to, "map_cells"))
 | 
			
		||||
		{
 | 
			
		||||
			Pass::call(design, "techmap -map +/xilinx/cells_map.v");
 | 
			
		||||
			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT");
 | 
			
		||||
			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
 | 
			
		||||
					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
 | 
			
		||||
			Pass::call(design, "clean");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								tests/aiger/and.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/aiger/and.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
aag 3 2 0 1 1
 | 
			
		||||
2
 | 
			
		||||
4
 | 
			
		||||
6
 | 
			
		||||
6 2 4
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/and.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/and.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aig 3 2 0 1 1
 | 
			
		||||
6
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/buffer.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/buffer.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aag 1 1 0 1 0
 | 
			
		||||
2
 | 
			
		||||
2
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/buffer.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/buffer.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aig 1 1 0 1 0
 | 
			
		||||
2
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/cnt1.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/cnt1.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aag 1 0 1 0 0 1
 | 
			
		||||
2 3
 | 
			
		||||
2
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/cnt1.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/cnt1.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aig 1 0 1 0 0 1
 | 
			
		||||
3
 | 
			
		||||
2
 | 
			
		||||
							
								
								
									
										8
									
								
								tests/aiger/cnt1e.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/aiger/cnt1e.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
aag 5 1 1 0 3 1
 | 
			
		||||
2
 | 
			
		||||
4 10
 | 
			
		||||
4
 | 
			
		||||
6 5 3
 | 
			
		||||
8 4 2
 | 
			
		||||
10 9 7
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/cnt1e.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/cnt1e.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aig 5 1 1 0 3 1
 | 
			
		||||
10
 | 
			
		||||
4
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/aiger/empty.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/aiger/empty.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
aag 0 0 0 0 0
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/aiger/empty.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/aiger/empty.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
aig 0 0 0 0 0
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/false.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/false.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aag 0 0 0 1 0
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/false.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/false.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aig 0 0 0 1 0
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										14
									
								
								tests/aiger/halfadder.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/aiger/halfadder.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
aag 7 2 0 2 3
 | 
			
		||||
2
 | 
			
		||||
4
 | 
			
		||||
6
 | 
			
		||||
12
 | 
			
		||||
6 13 15
 | 
			
		||||
12 2 4
 | 
			
		||||
14 3 5
 | 
			
		||||
i0 x
 | 
			
		||||
i1 y
 | 
			
		||||
o0 s
 | 
			
		||||
o1 c
 | 
			
		||||
c
 | 
			
		||||
half adder
 | 
			
		||||
							
								
								
									
										9
									
								
								tests/aiger/halfadder.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/aiger/halfadder.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
aig 5 2 0 2 3
 | 
			
		||||
10
 | 
			
		||||
6
 | 
			
		||||
i0 x
 | 
			
		||||
i1 y
 | 
			
		||||
o0 s
 | 
			
		||||
o1 c
 | 
			
		||||
c
 | 
			
		||||
half adder
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/inverter.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/inverter.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aag 1 1 0 1 0
 | 
			
		||||
2
 | 
			
		||||
3
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/inverter.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/inverter.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aig 1 1 0 1 0
 | 
			
		||||
3
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/notcnt1.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/notcnt1.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aag 1 0 1 0 0 1
 | 
			
		||||
2 3
 | 
			
		||||
3
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/notcnt1.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/notcnt1.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aig 1 0 1 0 0 1
 | 
			
		||||
3
 | 
			
		||||
3
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										8
									
								
								tests/aiger/notcnt1e.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/aiger/notcnt1e.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
aag 5 1 1 0 3 1
 | 
			
		||||
2
 | 
			
		||||
4 10
 | 
			
		||||
5
 | 
			
		||||
6 5 3
 | 
			
		||||
8 4 2
 | 
			
		||||
10 9 7
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/notcnt1e.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/notcnt1e.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aig 5 1 1 0 3 1
 | 
			
		||||
10
 | 
			
		||||
5
 | 
			
		||||
b0 AIGER_NEVER
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/aiger/or.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/aiger/or.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
aag 3 2 0 1 1
 | 
			
		||||
2
 | 
			
		||||
4
 | 
			
		||||
7
 | 
			
		||||
6 3 5
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/aiger/or.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/aiger/or.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
aig 3 2 0 1 1
 | 
			
		||||
7
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								tests/aiger/run-test.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								tests/aiger/run-test.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
OPTIND=1
 | 
			
		||||
seed=""    # default to no seed specified
 | 
			
		||||
while getopts "S:" opt
 | 
			
		||||
do
 | 
			
		||||
    case "$opt" in
 | 
			
		||||
	S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
 | 
			
		||||
	   seed="SEED=$arg" ;;
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
shift "$((OPTIND-1))"
 | 
			
		||||
 | 
			
		||||
# check for Icarus Verilog
 | 
			
		||||
if ! which iverilog > /dev/null ; then
 | 
			
		||||
  echo "$0: Error: Icarus Verilog 'iverilog' not found."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "===== AAG ======"
 | 
			
		||||
${MAKE:-make} -f ../tools/autotest.mk $seed *.aag EXTRA_FLAGS="-f aiger"
 | 
			
		||||
 | 
			
		||||
echo "===== AIG ======"
 | 
			
		||||
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.aig EXTRA_FLAGS="-f aiger"
 | 
			
		||||
							
								
								
									
										14
									
								
								tests/aiger/toggle-re.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/aiger/toggle-re.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
aag 7 2 1 2 4
 | 
			
		||||
2
 | 
			
		||||
4
 | 
			
		||||
6 8
 | 
			
		||||
6
 | 
			
		||||
7
 | 
			
		||||
8 4 10
 | 
			
		||||
10 13 15
 | 
			
		||||
12 2 6
 | 
			
		||||
14 3 7
 | 
			
		||||
i0 enable
 | 
			
		||||
i1 reset
 | 
			
		||||
o0 Q
 | 
			
		||||
o1 !Q
 | 
			
		||||
							
								
								
									
										8
									
								
								tests/aiger/toggle-re.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/aiger/toggle-re.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
aig 7 2 1 2 4
 | 
			
		||||
14
 | 
			
		||||
6
 | 
			
		||||
7
 | 
			
		||||
i0 enable
 | 
			
		||||
i1 reset
 | 
			
		||||
o0 Q
 | 
			
		||||
o1 !Q
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/toggle.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/toggle.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aag 1 0 1 2 0
 | 
			
		||||
2 3
 | 
			
		||||
2
 | 
			
		||||
3
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/aiger/toggle.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/aiger/toggle.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
aig 1 0 1 2 0
 | 
			
		||||
3
 | 
			
		||||
2
 | 
			
		||||
3
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/true.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/true.aag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aag 0 0 0 1 0
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/aiger/true.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/true.aig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
aig 0 0 0 1 0
 | 
			
		||||
1
 | 
			
		||||
| 
						 | 
				
			
			@ -90,5 +90,61 @@ generate
 | 
			
		|||
		endcase
 | 
			
		||||
	end
 | 
			
		||||
endgenerate
 | 
			
		||||
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------
 | 
			
		||||
 | 
			
		||||
module gen_test4(a, b);
 | 
			
		||||
 | 
			
		||||
input [3:0] a;
 | 
			
		||||
output [3:0] b;
 | 
			
		||||
 | 
			
		||||
genvar i;
 | 
			
		||||
generate
 | 
			
		||||
	for (i=0; i < 3; i=i+1) begin : foo
 | 
			
		||||
		localparam PREV = i - 1;
 | 
			
		||||
		wire temp;
 | 
			
		||||
		if (i == 0)
 | 
			
		||||
			assign temp = a[0];
 | 
			
		||||
		else
 | 
			
		||||
			assign temp = foo[PREV].temp & a[i];
 | 
			
		||||
		assign b[i] = temp;
 | 
			
		||||
	end
 | 
			
		||||
endgenerate
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------
 | 
			
		||||
 | 
			
		||||
module gen_test5(input_bits, out);
 | 
			
		||||
 | 
			
		||||
parameter WIDTH = 256;
 | 
			
		||||
parameter CHUNK = 4;
 | 
			
		||||
 | 
			
		||||
input [WIDTH-1:0] input_bits;
 | 
			
		||||
output out;
 | 
			
		||||
 | 
			
		||||
genvar step, i, j;
 | 
			
		||||
generate
 | 
			
		||||
	for (step = 1; step <= WIDTH; step = step * CHUNK) begin : steps
 | 
			
		||||
		localparam PREV = step / CHUNK;
 | 
			
		||||
		localparam DIM = WIDTH / step;
 | 
			
		||||
		for (i = 0; i < DIM; i = i + 1) begin : outer
 | 
			
		||||
			localparam LAST_START = i * CHUNK;
 | 
			
		||||
			for (j = 0; j < CHUNK; j = j + 1) begin : inner
 | 
			
		||||
				wire temp;
 | 
			
		||||
				if (step == 1)
 | 
			
		||||
					assign temp = input_bits[i];
 | 
			
		||||
				else if (j == 0)
 | 
			
		||||
					assign temp = steps[PREV].outer[LAST_START].val;
 | 
			
		||||
				else
 | 
			
		||||
					assign temp
 | 
			
		||||
						= steps[step].outer[i].inner[j-1].temp
 | 
			
		||||
						& steps[PREV].outer[LAST_START + j].val;
 | 
			
		||||
			end
 | 
			
		||||
			wire val;
 | 
			
		||||
			assign val = steps[step].outer[i].inner[CHUNK - 1].temp;
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
endgenerate
 | 
			
		||||
assign out = steps[WIDTH].outer[0].val;
 | 
			
		||||
endmodule
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,8 +108,9 @@ shift $((OPTIND - 1))
 | 
			
		|||
 | 
			
		||||
for fn
 | 
			
		||||
do
 | 
			
		||||
	bn=${fn%.v}
 | 
			
		||||
	if [ "$bn" == "$fn" ]; then
 | 
			
		||||
	bn=${fn%.*}
 | 
			
		||||
	ext=${fn##*.}
 | 
			
		||||
	if [[ "$ext" != "v" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then
 | 
			
		||||
		echo "Invalid argument: $fn" >&2
 | 
			
		||||
		exit 1
 | 
			
		||||
	fi
 | 
			
		||||
| 
						 | 
				
			
			@ -132,8 +133,12 @@ do
 | 
			
		|||
		bn=$(basename $bn)
 | 
			
		||||
 | 
			
		||||
		rm -f ${bn}_ref.fir
 | 
			
		||||
 | 
			
		||||
		egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v
 | 
			
		||||
		if [[ "$ext" == "v" ]]; then
 | 
			
		||||
			egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
 | 
			
		||||
		else
 | 
			
		||||
			"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
 | 
			
		||||
			frontend="verilog"
 | 
			
		||||
		fi
 | 
			
		||||
 | 
			
		||||
		if [ ! -f ../${bn}_tb.v ]; then
 | 
			
		||||
			"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +146,8 @@ do
 | 
			
		|||
			cp ../${bn}_tb.v ${bn}_tb.v
 | 
			
		||||
		fi
 | 
			
		||||
		if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
 | 
			
		||||
		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs
 | 
			
		||||
		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
 | 
			
		||||
					"$toolsdir"/../../techlibs/common/simlib.v
 | 
			
		||||
		if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
 | 
			
		||||
 | 
			
		||||
		test_count=0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue