From f4abc21d8ad79621cc24852bd76abf40a9d9f702 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Thu, 18 Apr 2019 17:42:12 +0200
Subject: Add "whitebox" attribute, add "read_verilog -wb"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 README.md                             |  4 ++++
 backends/blif/blif.cc                 |  6 +++---
 backends/edif/edif.cc                 |  6 +++---
 backends/intersynth/intersynth.cc     |  2 +-
 backends/smt2/smt2.cc                 |  2 +-
 backends/smv/smv.cc                   |  2 +-
 backends/spice/spice.cc               |  2 +-
 backends/table/table.cc               |  2 +-
 backends/verilog/verilog_backend.cc   |  2 +-
 frontends/ast/ast.cc                  | 22 ++++++++++++++++++++--
 frontends/ast/ast.h                   |  4 ++--
 frontends/verilog/verilog_frontend.cc | 14 ++++++++++++--
 frontends/verilog/verilog_frontend.h  |  3 +++
 frontends/verilog/verilog_parser.y    | 10 +++++-----
 kernel/rtlil.cc                       |  6 +++---
 kernel/rtlil.h                        |  4 ++++
 passes/cmds/add.cc                    |  2 +-
 passes/cmds/bugpoint.cc               |  8 ++++----
 passes/cmds/show.cc                   |  4 ++--
 passes/hierarchy/hierarchy.cc         | 10 +++++-----
 passes/hierarchy/uniquify.cc          |  2 +-
 passes/techmap/dfflibmap.cc           |  2 +-
 passes/techmap/techmap.cc             |  4 ++--
 23 files changed, 81 insertions(+), 42 deletions(-)

diff --git a/README.md b/README.md
index d000c5d63..5c94c34e5 100644
--- a/README.md
+++ b/README.md
@@ -312,6 +312,10 @@ Verilog Attributes and non-standard features
   passes to identify input and output ports of cells. The Verilog backend
   also does not output blackbox modules on default.
 
+- The ``whitebox`` attribute on modules triggers the same behavior as
+  ``blackbox``, but is for whitebox modules, i.e. library modules that
+  contain a behavioral model of the cell type.
+
 - The ``dynports`` attribute is used by the Verilog front-end to mark modules
   that have ports with a width that depends on a parameter.
 
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index 0db5ff27c..b6dbd84cb 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -140,7 +140,7 @@ struct BlifDumper
 			return "subckt";
 		if (!design->modules_.count(RTLIL::escape_id(cell_type)))
 			return "gate";
-		if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox"))
+		if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute())
 			return "gate";
 		return "subckt";
 	}
@@ -196,7 +196,7 @@ struct BlifDumper
 		}
 		f << stringf("\n");
 
-		if (module->get_bool_attribute("\\blackbox")) {
+		if (module->get_blackbox_attribute()) {
 			f << stringf(".blackbox\n");
 			f << stringf(".end\n");
 			return;
@@ -640,7 +640,7 @@ struct BlifBackend : public Backend {
 		for (auto module_it : design->modules_)
 		{
 			RTLIL::Module *module = module_it.second;
-			if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
+			if (module->get_blackbox_attribute() && !config.blackbox_mode)
 				continue;
 
 			if (module->processes.size() != 0)
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 7e30b67af..6d9469538 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -178,7 +178,7 @@ struct EdifBackend : public Backend {
 		for (auto module_it : design->modules_)
 		{
 			RTLIL::Module *module = module_it.second;
-			if (module->get_bool_attribute("\\blackbox"))
+			if (module->get_blackbox_attribute())
 				continue;
 
 			if (top_module_name.empty())
@@ -192,7 +192,7 @@ struct EdifBackend : public Backend {
 			for (auto cell_it : module->cells_)
 			{
 				RTLIL::Cell *cell = cell_it.second;
-				if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+				if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) {
 					lib_cell_ports[cell->type];
 					for (auto p : cell->connections())
 						lib_cell_ports[cell->type][p.first] = GetSize(p.second);
@@ -302,7 +302,7 @@ struct EdifBackend : public Backend {
 		*f << stringf("    (technology (numberDefinition))\n");
 		for (auto module : sorted_modules)
 		{
-			if (module->get_bool_attribute("\\blackbox"))
+			if (module->get_blackbox_attribute())
 				continue;
 
 			SigMap sigmap(module);
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 2eb08dbe9..b0e3cd252 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend {
 			RTLIL::Module *module = module_it.second;
 			SigMap sigmap(module);
 
-			if (module->get_bool_attribute("\\blackbox"))
+			if (module->get_blackbox_attribute())
 				continue;
 			if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
 				continue;
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 688535f33..e318a4051 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -1543,7 +1543,7 @@ struct Smt2Backend : public Backend {
 
 		for (auto module : sorted_modules)
 		{
-			if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
+			if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn())
 				continue;
 
 			log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index f379c9c48..d75456c1b 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -739,7 +739,7 @@ struct SmvBackend : public Backend {
 		pool<Module*> modules;
 
 		for (auto module : design->modules())
-			if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn())
+			if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn())
 				modules.insert(module);
 
 		if (template_f.is_open())
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index b6a3f1e77..6738a4bbd 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -212,7 +212,7 @@ struct SpiceBackend : public Backend {
 		for (auto module_it : design->modules_)
 		{
 			RTLIL::Module *module = module_it.second;
-			if (module->get_bool_attribute("\\blackbox"))
+			if (module->get_blackbox_attribute())
 				continue;
 
 			if (module->processes.size() != 0)
diff --git a/backends/table/table.cc b/backends/table/table.cc
index b75169ea4..796f18059 100644
--- a/backends/table/table.cc
+++ b/backends/table/table.cc
@@ -67,7 +67,7 @@ struct TableBackend : public Backend {
 
 		for (auto module : design->modules())
 		{
-			if (module->get_bool_attribute("\\blackbox"))
+			if (module->get_blackbox_attribute())
 				continue;
 
 			SigMap sigmap(module);
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 83d83f488..855409d0b 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -1770,7 +1770,7 @@ struct VerilogBackend : public Backend {
 
 		*f << stringf("/* Generated by %s */\n", yosys_version_str);
 		for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
-			if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
+			if (it->second->get_blackbox_attribute() != blackboxes)
 				continue;
 			if (selected && !design->selected_whole_module(it->first)) {
 				if (design->selected_module(it->first))
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index d48996167..720b3f3d1 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -46,7 +46,7 @@ namespace AST {
 // instantiate global variables (private API)
 namespace AST_INTERNAL {
 	bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
-	bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+	bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_wb, flag_noopt, flag_icells, flag_autowire;
 	AstNode *current_ast, *current_ast_mod;
 	std::map<std::string, AstNode*> current_scope;
 	const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@@ -956,7 +956,18 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 			log("--- END OF AST DUMP ---\n");
 		}
 
+		if (flag_wb) {
+			if (!ast->attributes.count("\\whitebox"))
+				goto blackbox_module;
+			AstNode *n = ast->attributes.at("\\whitebox");
+			if (n->type != AST_CONSTANT)
+				log_file_error(ast->filename, ast->linenum, "Whitebox attribute with non-constant value!\n");
+			if (!n->asBool())
+				goto blackbox_module;
+		}
+
 		if (flag_lib) {
+	blackbox_module:
 			std::vector<AstNode*> new_children;
 			for (auto child : ast->children) {
 				if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@@ -970,6 +981,10 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 				}
 			}
 			ast->children.swap(new_children);
+			if (ast->attributes.count("\\whitebox")) {
+				delete ast->attributes.at("\\whitebox");
+				ast->attributes.erase("\\whitebox");
+			}
 			ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
 		}
 
@@ -1010,6 +1025,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 	current_module->nomem2reg = flag_nomem2reg;
 	current_module->mem2reg = flag_mem2reg;
 	current_module->lib = flag_lib;
+	current_module->wb = flag_wb;
 	current_module->noopt = flag_noopt;
 	current_module->icells = flag_icells;
 	current_module->autowire = flag_autowire;
@@ -1026,7 +1042,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 
 // create AstModule instances for all modules in the AST tree and add them to 'design'
 void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
-		bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
+		bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
 {
 	current_ast = ast;
 	flag_dump_ast1 = dump_ast1;
@@ -1040,6 +1056,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
 	flag_nomem2reg = nomem2reg;
 	flag_mem2reg = mem2reg;
 	flag_lib = lib;
+	flag_wb = wb;
 	flag_noopt = noopt;
 	flag_icells = icells;
 	flag_autowire = autowire;
@@ -1374,6 +1391,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
 	flag_nomem2reg = nomem2reg;
 	flag_mem2reg = mem2reg;
 	flag_lib = lib;
+	flag_wb = wb;
 	flag_noopt = noopt;
 	flag_icells = icells;
 	flag_autowire = autowire;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index ddd59d4be..610e00fbf 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -283,13 +283,13 @@ namespace AST
 
 	// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
 	void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
-			bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
+			bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
 
 	// parametric modules are supported directly by the AST library
 	// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
 	struct AstModule : RTLIL::Module {
 		AstNode *ast;
-		bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
+		bool nolatches, nomeminit, nomem2reg, mem2reg, lib, wb, noopt, icells, autowire;
 		~AstModule() YS_OVERRIDE;
 		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
 		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 504f8b3f3..4e2c5abb5 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -148,6 +148,10 @@ struct VerilogFrontend : public Frontend {
 		log("    -lib\n");
 		log("        only create empty blackbox modules. This implies -DBLACKBOX.\n");
 		log("\n");
+		log("    -wb\n");
+		log("        like -lib, except do not touch modules with the whitebox\n");
+		log("        attribute set. This also implies -DBLACKBOX.\n");
+		log("\n");
 		log("    -noopt\n");
 		log("        don't perform basic optimizations (such as const folding) in the\n");
 		log("        high-level front-end.\n");
@@ -228,6 +232,7 @@ struct VerilogFrontend : public Frontend {
 		norestrict_mode = false;
 		assume_asserts_mode = false;
 		lib_mode = false;
+		wb_mode = false;
 		default_nettype_wire = true;
 
 		log_header(design, "Executing Verilog-2005 frontend.\n");
@@ -329,11 +334,16 @@ struct VerilogFrontend : public Frontend {
 				flag_nodpi = true;
 				continue;
 			}
-			if (arg == "-lib") {
+			if (arg == "-lib" && !wb_mode) {
 				lib_mode = true;
 				defines_map["BLACKBOX"] = string();
 				continue;
 			}
+			if (arg == "-wb" && !lib_mode) {
+				wb_mode = true;
+				defines_map["BLACKBOX"] = string();
+				continue;
+			}
 			if (arg == "-noopt") {
 				flag_noopt = true;
 				continue;
@@ -429,7 +439,7 @@ struct VerilogFrontend : public Frontend {
 		if (flag_nodpi)
 			error_on_dpi_function(current_ast);
 
-		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, wb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
 
 		if (!flag_nopp)
 			delete lexin;
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 523bbc897..b5cf70c57 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -72,6 +72,9 @@ namespace VERILOG_FRONTEND
 	// running in -lib mode
 	extern bool lib_mode;
 
+	// running in -wb mode
+	extern bool wb_mode;
+
 	// lexer input stream
 	extern std::istream *lexin;
 }
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 52685f637..122eb1230 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
 	std::vector<char> case_type_stack;
 	bool do_not_require_port_stubs;
 	bool default_nettype_wire;
-	bool sv_mode, formal_mode, lib_mode;
+	bool sv_mode, formal_mode, lib_mode, wb_mode;
 	bool noassert_mode, noassume_mode, norestrict_mode;
 	bool assume_asserts_mode, assert_assumes_mode;
 	bool current_wire_rand, current_wire_const;
@@ -1906,7 +1906,7 @@ basic_expr:
 		if ($4->substr(0, 1) != "'")
 			frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
 		AstNode *bits = $2;
-		AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+		AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
 		if (val == NULL)
 			log_error("Value conversion failed: `%s'\n", $4->c_str());
 		$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1917,7 +1917,7 @@ basic_expr:
 			frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
 		AstNode *bits = new AstNode(AST_IDENTIFIER);
 		bits->str = *$1;
-		AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+		AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
 		if (val == NULL)
 			log_error("Value conversion failed: `%s'\n", $2->c_str());
 		$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1925,14 +1925,14 @@ basic_expr:
 		delete $2;
 	} |
 	TOK_CONSTVAL TOK_CONSTVAL {
-		$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+		$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
 		if ($$ == NULL || (*$2)[0] != '\'')
 			log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
 		delete $1;
 		delete $2;
 	} |
 	TOK_CONSTVAL {
-		$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+		$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
 		if ($$ == NULL)
 			log_error("Value conversion failed: `%s'\n", $1->c_str());
 		delete $1;
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 9ae20a317..2f8715755 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -589,7 +589,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
 	std::vector<RTLIL::Module*> result;
 	result.reserve(modules_.size());
 	for (auto &it : modules_)
-		if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
+		if (selected_module(it.first) && !it.second->get_blackbox_attribute())
 			result.push_back(it.second);
 	return result;
 }
@@ -599,7 +599,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
 	std::vector<RTLIL::Module*> result;
 	result.reserve(modules_.size());
 	for (auto &it : modules_)
-		if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
+		if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute())
 			result.push_back(it.second);
 	return result;
 }
@@ -609,7 +609,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
 	std::vector<RTLIL::Module*> result;
 	result.reserve(modules_.size());
 	for (auto &it : modules_)
-		if (it.second->get_bool_attribute("\\blackbox"))
+		if (it.second->get_blackbox_attribute())
 			continue;
 		else if (selected_whole_module(it.first))
 			result.push_back(it.second);
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index fb045bc72..176dc3fc2 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -569,6 +569,10 @@ struct RTLIL::AttrObject
 	void set_bool_attribute(RTLIL::IdString id);
 	bool get_bool_attribute(RTLIL::IdString id) const;
 
+	bool get_blackbox_attribute() const {
+		return get_bool_attribute("\\blackbox") || get_bool_attribute("\\whitebox");
+	}
+
 	void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
 	void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
 	pool<string> get_strpool_attribute(RTLIL::IdString id) const;
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index cfccca966..af6f7043d 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
 		RTLIL::Module *mod = design->modules_.at(it.second->type);
 		if (!design->selected_whole_module(mod->name))
 			continue;
-		if (mod->get_bool_attribute("\\blackbox"))
+		if (mod->get_blackbox_attribute())
 			continue;
 		if (it.second->hasPort(name))
 			continue;
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 606276e64..4b22f6d2d 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -128,7 +128,7 @@ struct BugpointPass : public Pass {
 		{
 			for (auto &it : design_copy->modules_)
 			{
-				if (it.second->get_bool_attribute("\\blackbox"))
+				if (it.second->get_blackbox_attribute())
 					continue;
 
 				if (index++ == seed)
@@ -143,7 +143,7 @@ struct BugpointPass : public Pass {
 		{
 			for (auto mod : design_copy->modules())
 			{
-				if (mod->get_bool_attribute("\\blackbox"))
+				if (mod->get_blackbox_attribute())
 					continue;
 
 				for (auto wire : mod->wires())
@@ -168,7 +168,7 @@ struct BugpointPass : public Pass {
 		{
 			for (auto mod : design_copy->modules())
 			{
-				if (mod->get_bool_attribute("\\blackbox"))
+				if (mod->get_blackbox_attribute())
 					continue;
 
 				for (auto &it : mod->cells_)
@@ -186,7 +186,7 @@ struct BugpointPass : public Pass {
 		{
 			for (auto mod : design_copy->modules())
 			{
-				if (mod->get_bool_attribute("\\blackbox"))
+				if (mod->get_blackbox_attribute())
 					continue;
 
 				for (auto cell : mod->cells())
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 58acd302d..8b1b43f44 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -555,7 +555,7 @@ struct ShowWorker
 			if (!design->selected_module(module->name))
 				continue;
 			if (design->selected_whole_module(module->name)) {
-				if (module->get_bool_attribute("\\blackbox")) {
+				if (module->get_blackbox_attribute()) {
 					// log("Skipping blackbox module %s.\n", id2cstr(module->name));
 					continue;
 				} else
@@ -771,7 +771,7 @@ struct ShowPass : public Pass {
 		if (format != "ps" && format != "dot") {
 			int modcount = 0;
 			for (auto &mod_it : design->modules_) {
-				if (mod_it.second->get_bool_attribute("\\blackbox"))
+				if (mod_it.second->get_blackbox_attribute())
 					continue;
 				if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
 					continue;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 88c339e8c..b8ff99884 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -346,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
 		}
 		RTLIL::Module *mod = design->modules_[cell->type];
 
-		if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+		if (design->modules_.at(cell->type)->get_blackbox_attribute()) {
 			if (flag_simcheck)
-				log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
+				log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
 						cell->type.c_str(), module->name.c_str(), cell->name.c_str());
 			continue;
 		}
@@ -451,7 +451,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
 
 	if (indent == 0)
 		log("Top module:  %s\n", mod->name.c_str());
-	else if (!mod->get_bool_attribute("\\blackbox"))
+	else if (!mod->get_blackbox_attribute())
 		log("Used module: %*s%s\n", indent, "", mod->name.c_str());
 	used.insert(mod);
 
@@ -491,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
 
 	int del_counter = 0;
 	for (auto mod : del_modules) {
-		if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
+		if (!purge_lib && mod->get_blackbox_attribute())
 			continue;
 		log("Removing unused module `%s'.\n", mod->name.c_str());
 		design->modules_.erase(mod->name);
@@ -910,7 +910,7 @@ struct HierarchyPass : public Pass {
 			if (m == nullptr)
 				continue;
 
-			if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
+			if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
 				IdString new_m_name = m->derive(design, cell->parameters, true);
 				if (new_m_name.empty())
 					continue;
diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc
index e6154e94f..ad3220918 100644
--- a/passes/hierarchy/uniquify.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -75,7 +75,7 @@ struct UniquifyPass : public Pass {
 					if (tmod == nullptr)
 						continue;
 
-					if (tmod->get_bool_attribute("\\blackbox"))
+					if (tmod->get_blackbox_attribute())
 						continue;
 
 					if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 274177a68..b5c0498d0 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -664,7 +664,7 @@ struct DfflibmapPass : public Pass {
 		logmap_all();
 
 		for (auto &it : design->modules_)
-			if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
+			if (design->selected(it.second) && !it.second->get_blackbox_attribute())
 				dfflibmap(design, it.second, prepare_mode);
 
 		cell_mappings.clear();
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index d0e5e2236..d694e8165 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -472,7 +472,7 @@ struct TechmapWorker
 				RTLIL::Module *tpl = map->modules_[tpl_name];
 				std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
 
-				if (tpl->get_bool_attribute("\\blackbox"))
+				if (tpl->get_blackbox_attribute())
 					continue;
 
 				if (!flatten_mode)
@@ -1209,7 +1209,7 @@ struct FlattenPass : public Pass {
 
 			dict<RTLIL::IdString, RTLIL::Module*> new_modules;
 			for (auto mod : vector<Module*>(design->modules()))
-				if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) {
+				if (used_modules[mod->name] || mod->get_blackbox_attribute()) {
 					new_modules[mod->name] = mod;
 				} else {
 					log("Deleting now unused module %s.\n", log_id(mod));
-- 
cgit v1.2.3


From 290a798cec4dae02886877a342b00c1ba7d5b22d Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 18 Apr 2019 10:19:45 -0700
Subject: Ignore 'whitebox' attr in flatten with "-wb" option

---
 kernel/rtlil.h            |  4 ++--
 passes/techmap/techmap.cc | 24 +++++++++++++++++++-----
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 176dc3fc2..9e396d6f6 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -569,8 +569,8 @@ struct RTLIL::AttrObject
 	void set_bool_attribute(RTLIL::IdString id);
 	bool get_bool_attribute(RTLIL::IdString id) const;
 
-	bool get_blackbox_attribute() const {
-		return get_bool_attribute("\\blackbox") || get_bool_attribute("\\whitebox");
+	bool get_blackbox_attribute(bool ignore_wb=false) const {
+		return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox"));
 	}
 
 	void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index d694e8165..82c815e2e 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -84,6 +84,7 @@ struct TechmapWorker
 	bool flatten_mode;
 	bool recursive_mode;
 	bool autoproc_mode;
+	bool ignore_wb;
 
 	TechmapWorker()
 	{
@@ -92,6 +93,7 @@ struct TechmapWorker
 		flatten_mode = false;
 		recursive_mode = false;
 		autoproc_mode = false;
+		ignore_wb = false;
 	}
 
 	std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
@@ -472,7 +474,7 @@ struct TechmapWorker
 				RTLIL::Module *tpl = map->modules_[tpl_name];
 				std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
 
-				if (tpl->get_blackbox_attribute())
+				if (tpl->get_blackbox_attribute(ignore_wb))
 					continue;
 
 				if (!flatten_mode)
@@ -1145,7 +1147,7 @@ struct FlattenPass : public Pass {
 	{
 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 		log("\n");
-		log("    flatten [selection]\n");
+		log("    flatten [options] [selection]\n");
 		log("\n");
 		log("This pass flattens the design by replacing cells by their implementation. This\n");
 		log("pass is very similar to the 'techmap' pass. The only difference is that this\n");
@@ -1154,17 +1156,29 @@ struct FlattenPass : public Pass {
 		log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n");
 		log("flattened by this command.\n");
 		log("\n");
+		log("    -wb\n");
+		log("        Ignore the 'whitebox' attribute on cell implementations.\n");
+		log("\n");
 	}
 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 	{
 		log_header(design, "Executing FLATTEN pass (flatten design).\n");
 		log_push();
 
-		extra_args(args, 1, design);
-
 		TechmapWorker worker;
 		worker.flatten_mode = true;
 
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++) {
+			if (args[argidx] == "-wb") {
+				worker.ignore_wb = true;
+				continue;
+			}
+			break;
+		}
+		extra_args(args, argidx, design);
+
+
 		std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
 		for (auto module : design->modules())
 			celltypeMap[module->name].insert(module->name);
@@ -1209,7 +1223,7 @@ struct FlattenPass : public Pass {
 
 			dict<RTLIL::IdString, RTLIL::Module*> new_modules;
 			for (auto mod : vector<Module*>(design->modules()))
-				if (used_modules[mod->name] || mod->get_blackbox_attribute()) {
+				if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
 					new_modules[mod->name] = mod;
 				} else {
 					log("Deleting now unused module %s.\n", log_id(mod));
-- 
cgit v1.2.3


From 4ef03e19a8eafc324d3442f0642abf858071fdd4 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 18 Apr 2019 10:30:45 -0700
Subject: write_json to not write contents (cells/wires) of whiteboxes

---
 backends/json/json.cc | 115 ++++++++++++++++++++++++++------------------------
 1 file changed, 59 insertions(+), 56 deletions(-)

diff --git a/backends/json/json.cc b/backends/json/json.cc
index f5c687981..b4f82a3fe 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -130,72 +130,75 @@ struct JsonWriter
 			f << stringf("        }");
 			first = false;
 		}
-		f << stringf("\n      },\n");
+		f << stringf("\n      }");
 
-		f << stringf("      \"cells\": {");
-		first = true;
-		for (auto c : module->cells()) {
-			if (use_selection && !module->selected(c))
-				continue;
-			f << stringf("%s\n", first ? "" : ",");
-			f << stringf("        %s: {\n", get_name(c->name).c_str());
-			f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
-			f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
-			if (aig_mode) {
-				Aig aig(c);
-				if (!aig.name.empty()) {
-					f << stringf("          \"model\": \"%s\",\n", aig.name.c_str());
-					aig_models.insert(aig);
+		if (!module->get_blackbox_attribute()) {
+			f << stringf(",\n      \"cells\": {");
+			first = true;
+			for (auto c : module->cells()) {
+				if (use_selection && !module->selected(c))
+					continue;
+				f << stringf("%s\n", first ? "" : ",");
+				f << stringf("        %s: {\n", get_name(c->name).c_str());
+				f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
+				f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
+				if (aig_mode) {
+					Aig aig(c);
+					if (!aig.name.empty()) {
+						f << stringf("          \"model\": \"%s\",\n", aig.name.c_str());
+						aig_models.insert(aig);
+					}
 				}
-			}
-			f << stringf("          \"parameters\": {");
-			write_parameters(c->parameters);
-			f << stringf("\n          },\n");
-			f << stringf("          \"attributes\": {");
-			write_parameters(c->attributes);
-			f << stringf("\n          },\n");
-			if (c->known()) {
-				f << stringf("          \"port_directions\": {");
+				f << stringf("          \"parameters\": {");
+				write_parameters(c->parameters);
+				f << stringf("\n          },\n");
+				f << stringf("          \"attributes\": {");
+				write_parameters(c->attributes);
+				f << stringf("\n          },\n");
+				if (c->known()) {
+					f << stringf("          \"port_directions\": {");
+					bool first2 = true;
+					for (auto &conn : c->connections()) {
+						string direction = "output";
+						if (c->input(conn.first))
+							direction = c->output(conn.first) ? "inout" : "input";
+						f << stringf("%s\n", first2 ? "" : ",");
+						f << stringf("            %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
+						first2 = false;
+					}
+					f << stringf("\n          },\n");
+				}
+				f << stringf("          \"connections\": {");
 				bool first2 = true;
 				for (auto &conn : c->connections()) {
-					string direction = "output";
-					if (c->input(conn.first))
-						direction = c->output(conn.first) ? "inout" : "input";
 					f << stringf("%s\n", first2 ? "" : ",");
-					f << stringf("            %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
+					f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
 					first2 = false;
 				}
-				f << stringf("\n          },\n");
+				f << stringf("\n          }\n");
+				f << stringf("        }");
+				first = false;
 			}
-			f << stringf("          \"connections\": {");
-			bool first2 = true;
-			for (auto &conn : c->connections()) {
-				f << stringf("%s\n", first2 ? "" : ",");
-				f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
-				first2 = false;
-			}
-			f << stringf("\n          }\n");
-			f << stringf("        }");
-			first = false;
-		}
-		f << stringf("\n      },\n");
+			f << stringf("\n      },\n");
 
-		f << stringf("      \"netnames\": {");
-		first = true;
-		for (auto w : module->wires()) {
-			if (use_selection && !module->selected(w))
-				continue;
-			f << stringf("%s\n", first ? "" : ",");
-			f << stringf("        %s: {\n", get_name(w->name).c_str());
-			f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
-			f << stringf("          \"bits\": %s,\n", get_bits(w).c_str());
-			f << stringf("          \"attributes\": {");
-			write_parameters(w->attributes);
-			f << stringf("\n          }\n");
-			f << stringf("        }");
-			first = false;
+			f << stringf("      \"netnames\": {");
+			first = true;
+			for (auto w : module->wires()) {
+				if (use_selection && !module->selected(w))
+					continue;
+				f << stringf("%s\n", first ? "" : ",");
+				f << stringf("        %s: {\n", get_name(w->name).c_str());
+				f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
+				f << stringf("          \"bits\": %s,\n", get_bits(w).c_str());
+				f << stringf("          \"attributes\": {");
+				write_parameters(w->attributes);
+				f << stringf("\n          }\n");
+				f << stringf("        }");
+				first = false;
+			}
+			f << stringf("\n      }");
 		}
-		f << stringf("\n      }\n");
+		f << stringf("\n");
 
 		f << stringf("    }");
 	}
-- 
cgit v1.2.3


From 8f93999129bfcd957dbb312d804c01525af6d07e Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 18 Apr 2019 23:05:59 -0700
Subject: Revert "write_json to not write contents (cells/wires) of whiteboxes"

This reverts commit 4ef03e19a8eafc324d3442f0642abf858071fdd4.
---
 backends/json/json.cc | 115 ++++++++++++++++++++++++--------------------------
 1 file changed, 56 insertions(+), 59 deletions(-)

diff --git a/backends/json/json.cc b/backends/json/json.cc
index b4f82a3fe..f5c687981 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -130,75 +130,72 @@ struct JsonWriter
 			f << stringf("        }");
 			first = false;
 		}
-		f << stringf("\n      }");
+		f << stringf("\n      },\n");
 
-		if (!module->get_blackbox_attribute()) {
-			f << stringf(",\n      \"cells\": {");
-			first = true;
-			for (auto c : module->cells()) {
-				if (use_selection && !module->selected(c))
-					continue;
-				f << stringf("%s\n", first ? "" : ",");
-				f << stringf("        %s: {\n", get_name(c->name).c_str());
-				f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
-				f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
-				if (aig_mode) {
-					Aig aig(c);
-					if (!aig.name.empty()) {
-						f << stringf("          \"model\": \"%s\",\n", aig.name.c_str());
-						aig_models.insert(aig);
-					}
-				}
-				f << stringf("          \"parameters\": {");
-				write_parameters(c->parameters);
-				f << stringf("\n          },\n");
-				f << stringf("          \"attributes\": {");
-				write_parameters(c->attributes);
-				f << stringf("\n          },\n");
-				if (c->known()) {
-					f << stringf("          \"port_directions\": {");
-					bool first2 = true;
-					for (auto &conn : c->connections()) {
-						string direction = "output";
-						if (c->input(conn.first))
-							direction = c->output(conn.first) ? "inout" : "input";
-						f << stringf("%s\n", first2 ? "" : ",");
-						f << stringf("            %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
-						first2 = false;
-					}
-					f << stringf("\n          },\n");
+		f << stringf("      \"cells\": {");
+		first = true;
+		for (auto c : module->cells()) {
+			if (use_selection && !module->selected(c))
+				continue;
+			f << stringf("%s\n", first ? "" : ",");
+			f << stringf("        %s: {\n", get_name(c->name).c_str());
+			f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
+			f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
+			if (aig_mode) {
+				Aig aig(c);
+				if (!aig.name.empty()) {
+					f << stringf("          \"model\": \"%s\",\n", aig.name.c_str());
+					aig_models.insert(aig);
 				}
-				f << stringf("          \"connections\": {");
+			}
+			f << stringf("          \"parameters\": {");
+			write_parameters(c->parameters);
+			f << stringf("\n          },\n");
+			f << stringf("          \"attributes\": {");
+			write_parameters(c->attributes);
+			f << stringf("\n          },\n");
+			if (c->known()) {
+				f << stringf("          \"port_directions\": {");
 				bool first2 = true;
 				for (auto &conn : c->connections()) {
+					string direction = "output";
+					if (c->input(conn.first))
+						direction = c->output(conn.first) ? "inout" : "input";
 					f << stringf("%s\n", first2 ? "" : ",");
-					f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
+					f << stringf("            %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
 					first2 = false;
 				}
-				f << stringf("\n          }\n");
-				f << stringf("        }");
-				first = false;
+				f << stringf("\n          },\n");
 			}
-			f << stringf("\n      },\n");
-
-			f << stringf("      \"netnames\": {");
-			first = true;
-			for (auto w : module->wires()) {
-				if (use_selection && !module->selected(w))
-					continue;
-				f << stringf("%s\n", first ? "" : ",");
-				f << stringf("        %s: {\n", get_name(w->name).c_str());
-				f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
-				f << stringf("          \"bits\": %s,\n", get_bits(w).c_str());
-				f << stringf("          \"attributes\": {");
-				write_parameters(w->attributes);
-				f << stringf("\n          }\n");
-				f << stringf("        }");
-				first = false;
+			f << stringf("          \"connections\": {");
+			bool first2 = true;
+			for (auto &conn : c->connections()) {
+				f << stringf("%s\n", first2 ? "" : ",");
+				f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
+				first2 = false;
 			}
-			f << stringf("\n      }");
+			f << stringf("\n          }\n");
+			f << stringf("        }");
+			first = false;
+		}
+		f << stringf("\n      },\n");
+
+		f << stringf("      \"netnames\": {");
+		first = true;
+		for (auto w : module->wires()) {
+			if (use_selection && !module->selected(w))
+				continue;
+			f << stringf("%s\n", first ? "" : ",");
+			f << stringf("        %s: {\n", get_name(w->name).c_str());
+			f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
+			f << stringf("          \"bits\": %s,\n", get_bits(w).c_str());
+			f << stringf("          \"attributes\": {");
+			write_parameters(w->attributes);
+			f << stringf("\n          }\n");
+			f << stringf("        }");
+			first = false;
 		}
-		f << stringf("\n");
+		f << stringf("\n      }\n");
 
 		f << stringf("    }");
 	}
-- 
cgit v1.2.3


From 5b915f01539c993466e83593ee8ae69b45360b81 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sat, 20 Apr 2019 11:04:46 +0200
Subject: Add "wbflip" command

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 kernel/rtlil.cc        |  7 +++++--
 kernel/rtlil.h         |  2 +-
 passes/cmds/setattr.cc | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 2f8715755..f6f08bb9e 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -207,9 +207,12 @@ bool RTLIL::Const::is_fully_undef() const
 	return true;
 }
 
-void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id)
+void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
 {
-	attributes[id] = RTLIL::Const(1);
+	if (value)
+		attributes[id] = RTLIL::Const(1);
+	else if (attributes.count(id))
+		attributes.erase(id);
 }
 
 bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 9e396d6f6..330a81c3b 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -566,7 +566,7 @@ struct RTLIL::AttrObject
 {
 	dict<RTLIL::IdString, RTLIL::Const> attributes;
 
-	void set_bool_attribute(RTLIL::IdString id);
+	void set_bool_attribute(RTLIL::IdString id, bool value=true);
 	bool get_bool_attribute(RTLIL::IdString id) const;
 
 	bool get_blackbox_attribute(bool ignore_wb=false) const {
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index d38a6b3da..b9fcc3e7a 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -128,6 +128,45 @@ struct SetattrPass : public Pass {
 	}
 } SetattrPass;
 
+struct WbflipPass : public Pass {
+	WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { }
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    wbflip [selection]\n");
+		log("\n");
+		log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n");
+		log("vice-versa. Blackbox cells are not effected by this command.\n");
+		log("\n");
+	}
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+	{
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++)
+		{
+			std::string arg = args[argidx];
+			// if (arg == "-mod") {
+			// 	flag_mod = true;
+			// 	continue;
+			// }
+			break;
+		}
+		extra_args(args, argidx, design);
+
+		for (Module *module : design->modules())
+		{
+			if (!design->selected(module))
+				continue;
+
+			if (module->get_bool_attribute("\\blackbox"))
+				continue;
+
+			module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox"));
+		}
+	}
+} WbflipPass;
+
 struct SetparamPass : public Pass {
 	SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
 	void help() YS_OVERRIDE
-- 
cgit v1.2.3


From b7445ef3871b38360440d5c83dbac45c96b67277 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sat, 20 Apr 2019 11:10:05 +0200
Subject: Check blackbox attribute in techmap/simplemap

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/techmap/simplemap.cc | 2 +-
 passes/techmap/techmap.cc   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 660b60601..f3da80c66 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -599,7 +599,7 @@ struct SimplemapPass : public Pass {
 		simplemap_get_mappers(mappers);
 
 		for (auto mod : design->modules()) {
-			if (!design->selected(mod))
+			if (!design->selected(mod) || mod->get_blackbox_attribute())
 				continue;
 			std::vector<RTLIL::Cell*> cells = mod->cells();
 			for (auto cell : cells) {
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 82c815e2e..416bf4f1c 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -385,7 +385,7 @@ struct TechmapWorker
 	{
 		std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
 
-		if (!design->selected(module))
+		if (!design->selected(module) || module->get_blackbox_attribute())
 			return false;
 
 		bool log_continue = false;
-- 
cgit v1.2.3


From f3ad8d680a3195ab9525b0a8b3f8dbff9d5e6e24 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sat, 20 Apr 2019 11:23:24 +0200
Subject: Add "techmap -wb", use in formal flows

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/equiv/equiv_opt.cc | 2 +-
 passes/sat/miter.cc       | 8 ++++----
 passes/techmap/techmap.cc | 9 ++++++++-
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index 86550a69b..e5dda9c24 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -134,7 +134,7 @@ struct EquivOptPass:public ScriptPass
 				opts = " -map <filename> ...";
 			else
 				opts = techmap_opts;
-			run("techmap -D EQUIV -autoproc" + opts);
+			run("techmap -wb -D EQUIV -autoproc" + opts);
 		}
 
 		if (check_label("prove")) {
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index d37f1b126..1a886af70 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
 
 	if (flag_flatten) {
 		log_push();
-		Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
+		Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;");
 		log_pop();
 	}
 }
@@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
 
 	if (flag_flatten) {
 		log_push();
-		Pass::call_on_module(design, module, "flatten;;");
+		Pass::call_on_module(design, module, "flatten -wb;;");
 		log_pop();
 	}
 
@@ -385,7 +385,7 @@ struct MiterPass : public Pass {
 		log("        also create an 'assert' cell that checks if trigger is always low.\n");
 		log("\n");
 		log("    -flatten\n");
-		log("        call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
+		log("        call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
 		log("\n");
 		log("\n");
 		log("    miter -assert [options] module [miter_name]\n");
@@ -399,7 +399,7 @@ struct MiterPass : public Pass {
 		log("        keep module output ports.\n");
 		log("\n");
 		log("    -flatten\n");
-		log("        call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
+		log("        call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
 		log("\n");
 	}
 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 416bf4f1c..ee319b6e6 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -385,7 +385,7 @@ struct TechmapWorker
 	{
 		std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
 
-		if (!design->selected(module) || module->get_blackbox_attribute())
+		if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
 			return false;
 
 		bool log_continue = false;
@@ -927,6 +927,9 @@ struct TechmapPass : public Pass {
 		log("    -autoproc\n");
 		log("        Automatically call \"proc\" on implementations that contain processes.\n");
 		log("\n");
+		log("    -wb\n");
+		log("        Ignore the 'whitebox' attribute on cell implementations.\n");
+		log("\n");
 		log("    -assert\n");
 		log("        this option will cause techmap to exit with an error if it can't map\n");
 		log("        a selected cell. only cell types that end on an underscore are accepted\n");
@@ -1070,6 +1073,10 @@ struct TechmapPass : public Pass {
 				worker.autoproc_mode = true;
 				continue;
 			}
+			if (args[argidx] == "-wb") {
+				worker.ignore_wb = true;
+				continue;
+			}
 			break;
 		}
 		extra_args(args, argidx, design);
-- 
cgit v1.2.3