Merge pull request #1501 from YosysHQ/dave/mem_copy_attr

memory_collect: Copy attr from RTLIL::Memory to  cell
diff --git a/CHANGELOG b/CHANGELOG
index 1fc139d..a49c27b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -51,6 +51,8 @@
     - "synth_ice40 -dsp" to infer DSP blocks
     - Added latch support to synth_xilinx
     - Added "check -mapped"
+    - Added checking of SystemVerilog always block types (always_comb,
+      always_latch and always_ff)
 
 Yosys 0.8 .. Yosys 0.9
 ----------------------
diff --git a/Makefile b/Makefile
index 845a97b..6e7681c 100644
--- a/Makefile
+++ b/Makefile
@@ -718,6 +718,7 @@
 	+cd tests/arch/ecp5 && bash run-test.sh $(SEEDOPT)
 	+cd tests/arch/efinix && bash run-test.sh $(SEEDOPT)
 	+cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT)
+	+cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
 	+cd tests/rpc && bash run-test.sh
 	@echo ""
 	@echo "  Passed \"make test\"."
diff --git a/README.md b/README.md
index db7810c..1ce5d47 100644
--- a/README.md
+++ b/README.md
@@ -343,6 +343,13 @@
 - The ``clkbuf_sink`` attribute can be set on an input port of a module to
   request clock buffer insertion by the ``clkbufmap`` pass.
 
+- The ``clkbuf_inv`` attribute can be set on an output port of a module
+  with the value set to the name of an input port of that module.  When
+  the ``clkbufmap`` would otherwise insert a clock buffer on this output,
+  it will instead try inserting the clock buffer on the input port (this
+  is used to implement clock inverter cells that clock buffer insertion
+  will "see through").
+
 - The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent
   automatic clock buffer insertion by ``clkbufmap``. This behaviour can be
   overridden by providing a custom selection to ``clkbufmap``.
@@ -371,6 +378,11 @@
   for example, to specify the clk-to-Q delay of a flip-flop for consideration
   during techmapping.
 
+- The frontend sets attributes ``always_comb``, ``always_latch`` and
+  ``always_ff`` on processes derived from SystemVerilog style always blocks
+  according to the type of the always. These are checked for correctness in
+  ``proc_dlatch``.
+
 - In addition to the ``(* ... *)`` attribute syntax, Yosys supports
   the non-standard ``{* ... *}`` attribute syntax to set default attributes
   for everything that comes after the ``{* ... *}`` statement. (Reset
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 46890b0..a77949b 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -153,11 +153,6 @@
 			if (wire->port_input)
 				sigmap.add(wire);
 
-		// promote output wires
-		for (auto wire : module->wires())
-			if (wire->port_output)
-				sigmap.add(wire);
-
 		for (auto wire : module->wires())
 		{
 			bool keep = wire->attributes.count("\\keep");
@@ -173,12 +168,13 @@
 				}
 
 				if (keep)
-					keep_bits.insert(bit);
+					keep_bits.insert(wirebit);
 
 				if (wire->port_input || keep) {
 					if (bit != wirebit)
 						alias_map[bit] = wirebit;
 					input_bits.insert(wirebit);
+					undriven_bits.erase(bit);
 				}
 
 				if (wire->port_output || keep) {
@@ -186,6 +182,8 @@
 						if (bit != wirebit)
 							alias_map[wirebit] = bit;
 						output_bits.insert(wirebit);
+						if (!wire->port_input)
+							unused_bits.erase(bit);
 					}
 					else
 						log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit));
@@ -193,12 +191,6 @@
 			}
 		}
 
-		for (auto bit : input_bits)
-			undriven_bits.erase(sigmap(bit));
-		for (auto bit : output_bits)
-			if (!bit.wire->port_input)
-				unused_bits.erase(bit);
-
 		// TODO: Speed up toposort -- ultimately we care about
 		//       box ordering, but not individual AIG cells
 		dict<SigBit, pool<IdString>> bit_drivers, bit_users;
@@ -824,7 +816,7 @@
 		log("        write ASCII version of AIGER format\n");
 		log("\n");
 		log("    -map <filename>\n");
-		log("        write an extra file with port and latch symbols\n");
+		log("        write an extra file with port and box symbols\n");
 		log("\n");
 		log("    -vmap <filename>\n");
 		log("        like -map, but more verbose\n");
diff --git a/examples/gowin/demo.cst b/examples/gowin/demo.cst
index 22d7eb6..c8f89dc 100644
--- a/examples/gowin/demo.cst
+++ b/examples/gowin/demo.cst
@@ -1,41 +1,10 @@
-// 50 MHz Clock
-IO_LOC "clk" D11;
-
-// LEDs
-IO_LOC "leds[0]"  D22;
-IO_LOC "leds[1]"  E22;
-IO_LOC "leds[2]"  G22;
-IO_LOC "leds[3]"  J22;
-IO_LOC "leds[4]"  L22;
-IO_LOC "leds[5]"  L19;
-IO_LOC "leds[6]"  L20;
-IO_LOC "leds[7]"  M21;
-IO_LOC "leds[8]"  N19;
-IO_LOC "leds[9]"  R19;
-IO_LOC "leds[10]" T18;
-IO_LOC "leds[11]" AA22;
-IO_LOC "leds[12]" U18;
-IO_LOC "leds[13]" V20;
-IO_LOC "leds[14]" AA21;
-IO_LOC "leds[15]" AB21;
-
-
-// 7-Segment Display
-IO_LOC "seg7dig[0]" E20;
-IO_LOC "seg7dig[1]" G18;
-IO_LOC "seg7dig[2]" G20;
-IO_LOC "seg7dig[3]" F21;
-IO_LOC "seg7dig[4]" J20;
-IO_LOC "seg7dig[5]" H21;
-IO_LOC "seg7dig[6]" H18;
-IO_LOC "seg7dig[7]" D20;
-IO_LOC "seg7sel[0]" C19;
-IO_LOC "seg7sel[1]" B22;
-IO_LOC "seg7sel[2]" C20;
-IO_LOC "seg7sel[3]" C21;
-
-// Switches
-IO_LOC "sw[0]" AB20;
-IO_LOC "sw[1]" AB19;
-IO_LOC "sw[2]" AB18;
-IO_LOC "sw[3]" AB17;
+IO_LOC "clk" 35;
+//IO_LOC "rst_n" 77;
+IO_LOC "leds[0]" 79;
+IO_LOC "leds[1]" 80;
+IO_LOC "leds[2]" 81;
+IO_LOC "leds[3]" 82;
+IO_LOC "leds[4]" 83;
+IO_LOC "leds[5]" 84;
+IO_LOC "leds[6]" 85;
+IO_LOC "leds[7]" 86;
\ No newline at end of file
diff --git a/examples/gowin/demo.v b/examples/gowin/demo.v
index 6ea1083..485fec9 100644
--- a/examples/gowin/demo.v
+++ b/examples/gowin/demo.v
@@ -1,9 +1,7 @@
 module demo (
 	input clk,
-	input [3:0] sw,
 	output [15:0] leds,
-	output [7:0] seg7dig,
-	output [3:0] seg7sel
+	output unused
 );
 	localparam PRESCALE = 20;
 	reg [PRESCALE+3:0] counter = 0;
diff --git a/examples/gowin/device.cfg b/examples/gowin/device.cfg
new file mode 100644
index 0000000..f6ab821
--- /dev/null
+++ b/examples/gowin/device.cfg
@@ -0,0 +1,16 @@
+set JTAG regular_io = false
+set SSPI regular_io = false
+set MSPI regular_io = false
+set READY regular_io = false
+set DONE regular_io = false
+set RECONFIG_N regular_io = false
+set MODE regular_io = false
+set CRC_check = true
+set compress = false
+set encryption = false
+set security_bit_enable = true
+set bsram_init_fuse_print = true
+set download_speed = 250/100
+set spi_flash_address = 0x00FFF000
+set format = txt
+set background_programming = false
diff --git a/examples/gowin/pnr.cfg b/examples/gowin/pnr.cfg
new file mode 100644
index 0000000..a1b43cc
--- /dev/null
+++ b/examples/gowin/pnr.cfg
@@ -0,0 +1,8 @@
+-sdf
+-oc
+-ibs
+-posp
+-o
+-warning_all
+-tt
+-timing
diff --git a/examples/gowin/run.sh b/examples/gowin/run.sh
index 33a7b5c..cd26010 100644
--- a/examples/gowin/run.sh
+++ b/examples/gowin/run.sh
@@ -1,8 +1,7 @@
 #!/bin/bash
 set -ex
 yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v
-$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW2A55-PBGA484-6 \
-		-warning_all -out demo_out.v -rpt demo.rpt -tr demo_tr.html -bit demo.bit
+$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW1NR-9-QFN88-6 -pn GW1NR-LV9QN88C6/I5 -cfg device.cfg -bit -tr -ph -timing -gpa -rpt -warning_all
 
 # post place&route simulation (icarus verilog)
 if false; then
diff --git a/examples/gowin/run.tcl b/examples/gowin/run.tcl
new file mode 100644
index 0000000..39da11c
--- /dev/null
+++ b/examples/gowin/run.tcl
@@ -0,0 +1,9 @@
+# gw_sh run.tcl
+exec yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v
+add_file -cst demo.cst
+add_file -sdc demo.sdc
+add_file -vm demo_syn.v
+add_file -cfg device.cfg
+set_option -device GW1NR-9-QFN88-6
+set_option -pn GW1NR-LV9QN88C6/I5
+run_pnr -opt pnr.cfg
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index a5c4aa2..843e7b9 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -130,7 +130,7 @@
 
 bool is_blackbox(Netlist *nl)
 {
-	if (nl->IsBlackBox())
+	if (nl->IsBlackBox() || nl->IsEmptyBox())
 		return true;
 
 	const char *attr = nl->GetAttValue("blackbox");
@@ -784,15 +784,15 @@
 		merge_past_ffs_clock(it.second, it.first.first, it.first.second);
 }
 
-void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
+void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo, bool norename)
 {
 	std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
 	std::string module_name = netlist_name;
 
-	if (nl->IsOperator()) {
+	if (nl->IsOperator() || nl->IsPrimitive()) {
 		module_name = "$verific$" + module_name;
 	} else {
-		if (*nl->Name()) {
+		if (!norename && *nl->Name()) {
 			module_name += "(";
 			module_name += nl->Name();
 			module_name += ")";
@@ -1409,7 +1409,7 @@
 
 		std::string inst_type = inst->View()->Owner()->Name();
 
-		if (inst->View()->IsOperator()) {
+		if (inst->View()->IsOperator() || inst->View()->IsPrimitive()) {
 			inst_type = "$verific$" + inst_type;
 		} else {
 			if (*inst->View()->Name()) {
@@ -1899,7 +1899,7 @@
 		Netlist *nl = *nl_todo.begin();
 		if (nl_done.count(nl) == 0) {
 			VerificImporter importer(false, false, false, false, false, false, false);
-			importer.import_netlist(design, nl, nl_todo);
+			importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == top);
 		}
 		nl_todo.erase(nl);
 		nl_done.insert(nl);
@@ -2373,6 +2373,8 @@
 			if (argidx > GetSize(args) && args[argidx].compare(0, 1, "-") == 0)
 				cmd_error(args, argidx, "unknown option");
 
+			std::set<std::string> top_mod_names;
+
 			if (mode_all)
 			{
 				log("Running hier_tree::ElaborateAll().\n");
@@ -2401,6 +2403,7 @@
 				for (; argidx < GetSize(args); argidx++)
 				{
 					const char *name = args[argidx].c_str();
+					top_mod_names.insert(name);
 					VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
 
 					if (veri_lib) {
@@ -2466,7 +2469,7 @@
 				if (nl_done.count(nl) == 0) {
 					VerificImporter importer(mode_gates, mode_keep, mode_nosva,
 							mode_names, mode_verific, mode_autocover, mode_fullinit);
-					importer.import_netlist(design, nl, nl_todo);
+					importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->Owner()->Name()));
 				}
 				nl_todo.erase(nl);
 				nl_done.insert(nl);
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index 5cbd78f..2ccfcd4 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -93,7 +93,7 @@
 	void merge_past_ffs_clock(pool<RTLIL::Cell*> &candidates, SigBit clock, bool clock_pol);
 	void merge_past_ffs(pool<RTLIL::Cell*> &candidates);
 
-	void import_netlist(RTLIL::Design *design, Verific::Netlist *nl, std::set<Verific::Netlist*> &nl_todo);
+	void import_netlist(RTLIL::Design *design, Verific::Netlist *nl, std::set<Verific::Netlist*> &nl_todo, bool norename = false);
 };
 
 void verific_import_sva_assert(VerificImporter *importer, Verific::Instance *inst);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
index 909e9b4..49c0c40 100644
--- a/frontends/verific/verificsva.cc
+++ b/frontends/verific/verificsva.cc
@@ -36,6 +36,8 @@
 // basic_property:
 //   sequence
 //   not basic_property
+//   nexttime basic_property
+//   nexttime[N] basic_property
 //   sequence #-# basic_property
 //   sequence #=# basic_property
 //   basic_property or basic_property           (cover only)
@@ -1264,6 +1266,26 @@
 			return node;
 		}
 
+		if (inst->Type() == PRIM_SVA_NEXTTIME || inst->Type() == PRIM_SVA_S_NEXTTIME)
+		{
+			const char *sva_low_s = inst->GetAttValue("sva:low");
+			const char *sva_high_s = inst->GetAttValue("sva:high");
+
+			int sva_low = atoi(sva_low_s);
+			int sva_high = atoi(sva_high_s);
+			log_assert(sva_low == sva_high);
+
+			int node = start_node;
+
+			for (int i = 0; i < sva_low; i++) {
+				int next_node = fsm.createNode();
+				fsm.createEdge(node, next_node);
+				node = next_node;
+			}
+
+			return parse_sequence(fsm, node, inst->GetInput());
+		}
+
 		if (inst->Type() == PRIM_SVA_SEQ_CONCAT)
 		{
 			const char *sva_low_s = inst->GetAttValue("sva:low");
@@ -1590,15 +1612,25 @@
 			Instance *consequent_inst = net_to_ast_driver(consequent_net);
 
 			if (consequent_inst && (consequent_inst->Type() == PRIM_SVA_UNTIL || consequent_inst->Type() == PRIM_SVA_S_UNTIL ||
-					consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH))
+					consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH ||
+					consequent_inst->Type() == PRIM_SVA_ALWAYS || consequent_inst->Type() == PRIM_SVA_S_ALWAYS))
 			{
 				bool until_with = consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH;
 
-				Net *until_net = consequent_inst->GetInput2();
-				consequent_net = consequent_inst->GetInput1();
-				consequent_inst = net_to_ast_driver(consequent_net);
+				Net *until_net = nullptr;
+				if (consequent_inst->Type() == PRIM_SVA_ALWAYS || consequent_inst->Type() == PRIM_SVA_S_ALWAYS)
+				{
+					consequent_net = consequent_inst->GetInput();
+					consequent_inst = net_to_ast_driver(consequent_net);
+				}
+				else
+				{
+					until_net = consequent_inst->GetInput2();
+					consequent_net = consequent_inst->GetInput1();
+					consequent_inst = net_to_ast_driver(consequent_net);
+				}
 
-				SigBit until_sig = parse_expression(until_net);
+				SigBit until_sig = until_net ? parse_expression(until_net) : RTLIL::S0;
 				SigBit not_until_sig = module->Not(NEW_ID, until_sig);
 				antecedent_fsm.createEdge(node, node, not_until_sig);
 
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 4acfb41..c8984c2 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -188,9 +188,9 @@
 "unique0"      { SV_KEYWORD(TOK_UNIQUE); }
 "priority"     { SV_KEYWORD(TOK_PRIORITY); }
 
-"always_comb"  { SV_KEYWORD(TOK_ALWAYS); }
-"always_ff"    { SV_KEYWORD(TOK_ALWAYS); }
-"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
+"always_comb"  { SV_KEYWORD(TOK_ALWAYS_COMB); }
+"always_ff"    { SV_KEYWORD(TOK_ALWAYS_FF); }
+"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); }
 
  /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
     to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 77f6d20..daea3b4 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -141,6 +141,7 @@
 %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
 %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
 %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
+%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
 %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
 %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
 %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
@@ -156,7 +157,7 @@
 %type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int
 %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
 %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id
-%type <boolean> opt_signed opt_property unique_case_attr
+%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
 %type <al> attr case_attr
 
 %type <specify_target_ptr> specify_target
@@ -1581,10 +1582,28 @@
 		free_attr($1);
 	};
 
+always_comb_or_latch:
+	TOK_ALWAYS_COMB {
+		$$ = false;
+	} |
+	TOK_ALWAYS_LATCH {
+		$$ = true;
+	};
+
+always_or_always_ff:
+	TOK_ALWAYS {
+		$$ = false;
+	} |
+	TOK_ALWAYS_FF {
+		$$ = true;
+	};
+
 always_stmt:
-	attr TOK_ALWAYS {
+	attr always_or_always_ff {
 		AstNode *node = new AstNode(AST_ALWAYS);
 		append_attr(node, $1);
+		if ($2)
+			node->attributes[ID(always_ff)] = AstNode::mkconst_int(1, false);
 		ast_stack.back()->children.push_back(node);
 		ast_stack.push_back(node);
 	} always_cond {
@@ -1595,6 +1614,22 @@
 		ast_stack.pop_back();
 		ast_stack.pop_back();
 	} |
+	attr always_comb_or_latch {
+		AstNode *node = new AstNode(AST_ALWAYS);
+		append_attr(node, $1);
+		if ($2)
+			node->attributes[ID(always_latch)] = AstNode::mkconst_int(1, false);
+		else
+			node->attributes[ID(always_comb)] = AstNode::mkconst_int(1, false);
+		ast_stack.back()->children.push_back(node);
+		ast_stack.push_back(node);
+		AstNode *block = new AstNode(AST_BLOCK);
+		ast_stack.back()->children.push_back(block);
+		ast_stack.push_back(block);
+	} behavioral_stmt {
+		ast_stack.pop_back();
+		ast_stack.pop_back();
+	} |
 	attr TOK_INITIAL {
 		AstNode *node = new AstNode(AST_INITIAL);
 		append_attr(node, $1);
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 712bc25..cee63bd 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -35,6 +35,7 @@
 		log("\n");
 		log("This pass calls all the other memory_* passes in a useful order:\n");
 		log("\n");
+		log("    opt_mem\n");
 		log("    memory_dff [-nordff]                (-memx implies -nordff)\n");
 		log("    opt_clean\n");
 		log("    memory_share\n");
@@ -81,6 +82,7 @@
 		}
 		extra_args(args, argidx, design);
 
+		Pass::call(design, "opt_mem");
 		Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff");
 		Pass::call(design, "opt_clean");
 		Pass::call(design, "memory_share");
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index eb07e94..002c1a6 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -1,6 +1,7 @@
 
 OBJS += passes/opt/opt.o
 OBJS += passes/opt/opt_merge.o
+OBJS += passes/opt/opt_mem.o
 OBJS += passes/opt/opt_muxtree.o
 OBJS += passes/opt/opt_reduce.o
 OBJS += passes/opt/opt_rmdff.o
diff --git a/passes/opt/opt_mem.cc b/passes/opt/opt_mem.cc
new file mode 100644
index 0000000..98d3551
--- /dev/null
+++ b/passes/opt/opt_mem.cc
@@ -0,0 +1,143 @@
+/*
+ *  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 OptMemWorker
+{
+	RTLIL::Design *design;
+	RTLIL::Module *module;
+	SigMap sigmap;
+	bool restart;
+
+	dict<IdString, vector<IdString>> memrd, memwr, meminit;
+	pool<IdString> remove_mem, remove_cells;
+
+	OptMemWorker(RTLIL::Module *module) : design(module->design), module(module), sigmap(module), restart(false)
+	{
+		for (auto &it : module->memories)
+		{
+			memrd[it.first];
+			memwr[it.first];
+			meminit[it.first];
+		}
+
+		for (auto cell : module->cells())
+		{
+			if (cell->type == ID($memrd)) {
+				IdString id = cell->getParam(ID(MEMID)).decode_string();
+				memrd.at(id).push_back(cell->name);
+			}
+
+			if (cell->type == ID($memwr)) {
+				IdString id = cell->getParam(ID(MEMID)).decode_string();
+				memwr.at(id).push_back(cell->name);
+			}
+
+			if (cell->type == ID($meminit)) {
+				IdString id = cell->getParam(ID(MEMID)).decode_string();
+				meminit.at(id).push_back(cell->name);
+			}
+		}
+	}
+
+	~OptMemWorker()
+	{
+		for (auto it : remove_mem)
+		{
+			for (auto cell_name : memrd[it])
+				module->remove(module->cell(cell_name));
+			for (auto cell_name : memwr[it])
+				module->remove(module->cell(cell_name));
+			for (auto cell_name : meminit[it])
+				module->remove(module->cell(cell_name));
+
+			delete module->memories.at(it);
+			module->memories.erase(it);
+		}
+
+		for (auto cell_name : remove_cells)
+			module->remove(module->cell(cell_name));
+	}
+
+	int run(RTLIL::Memory *mem)
+	{
+		if (restart || remove_mem.count(mem->name))
+			return 0;
+
+		if (memwr.at(mem->name).empty() && meminit.at(mem->name).empty()) {
+			log("Removing memory %s.%s with no write ports or init data.\n", log_id(module), log_id(mem));
+			remove_mem.insert(mem->name);
+			return 1;
+		}
+
+		return 0;
+	}
+};
+
+struct OptMemPass : public Pass {
+	OptMemPass() : Pass("opt_mem", "optimize memories") { }
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    opt_mem [options] [selection]\n");
+		log("\n");
+		log("This pass performs various optimizations on memories in the design.\n");
+		log("\n");
+	}
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+	{
+		log_header(design, "Executing OPT_MEM pass (optimize memories).\n");
+
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++) {
+			// if (args[argidx] == "-nomux") {
+			// 	mode_nomux = true;
+			// 	continue;
+			// }
+			break;
+		}
+		extra_args(args, argidx, design);
+
+		int total_count = 0;
+		for (auto module : design->selected_modules()) {
+			while (1) {
+				int cnt = 0;
+				OptMemWorker worker(module);
+				for (auto &it : module->memories)
+					if (module->selected(it.second))
+						cnt += worker.run(it.second);
+				if (!cnt && !worker.restart)
+					break;
+				total_count += cnt;
+			}
+		}
+
+		if (total_count)
+			design->scratchpad_set_bool("opt.did_something", true);
+		log("Performed a total of %d transformations.\n", total_count);
+	}
+} OptMemPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 2c45670..f59f978 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -83,7 +83,9 @@
 	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig && semantics == other.semantics; }
 };
 
-#define BITWISE_OPS ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($and), ID($or), ID($xor), ID($xnor)
+#define FINE_BITWISE_OPS ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)
+
+#define BITWISE_OPS FINE_BITWISE_OPS, ID($and), ID($or), ID($xor), ID($xnor)
 
 #define REDUCTION_OPS ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($reduce_nand)
 
@@ -250,14 +252,19 @@
 		shared_op->setPort(ID(CO), alu_co.extract(0, conn_width));
 	}
 
-	shared_op->setParam(ID(Y_WIDTH), conn_width);
+	bool is_fine = shared_op->type.in(FINE_BITWISE_OPS);
+
+	if (!is_fine)
+		shared_op->setParam(ID(Y_WIDTH), conn_width);
 
 	if (decode_port(shared_op, ID::A, &assign_map) == operand) {
 		shared_op->setPort(ID::B, mux_to_oper);
-		shared_op->setParam(ID(B_WIDTH), max_width);
+		if (!is_fine)
+			shared_op->setParam(ID(B_WIDTH), max_width);
 	} else {
 		shared_op->setPort(ID::A, mux_to_oper);
-		shared_op->setParam(ID(A_WIDTH), max_width);
+		if (!is_fine)
+			shared_op->setParam(ID(A_WIDTH), max_width);
 	}
 }
 
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg
index 604aa22..0ba5290 100644
--- a/passes/pmgen/xilinx_dsp.pmg
+++ b/passes/pmgen/xilinx_dsp.pmg
@@ -98,16 +98,16 @@
 	if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
 		// Only care about those bits that are used
 		int i;
-		for (i = 0; i < GetSize(P); i++) {
-			if (nusers(P[i]) <= 1)
+		for (i = GetSize(P)-1; i >= 0; i--)
+			if (nusers(P[i]) > 1)
 				break;
-			sigM.append(P[i]);
-		}
+		i++;
 		log_assert(nusers(P.extract_end(i)) <= 1);
 		// This sigM could have no users if downstream sinks (e.g. $add) is
 		//   narrower than $mul result, for example
-		if (sigM.empty())
+		if (i == 0)
 			reject;
+		sigM = P.extract(0, i);
 	}
 	else
 		sigM = P;
@@ -460,6 +460,8 @@
 
 code
 	dff = nullptr;
+	if (GetSize(argQ) == 0)
+		reject;
 	for (const auto &c : argQ.chunks()) {
 		// Abandon matches when 'Q' is a constant
 		if (!c.wire)
diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg
index a570430..5cd3416 100644
--- a/passes/pmgen/xilinx_dsp_CREG.pmg
+++ b/passes/pmgen/xilinx_dsp_CREG.pmg
@@ -63,12 +63,12 @@
 	if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
 		// Only care about those bits that are used
 		int i;
-		for (i = 0; i < GetSize(P); i++) {
-			if (nusers(P[i]) <= 1)
+		for (i = GetSize(P)-1; i >= 0; i--)
+			if (nusers(P[i]) > 1)
 				break;
-			sigP.append(P[i]);
-		}
+		i++;
 		log_assert(nusers(P.extract_end(i)) <= 1);
+		sigP = P.extract(0, i);
 	}
 	else
 		sigP = P;
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index d9d5dfb..a0c8351 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -349,6 +349,10 @@
 			continue;
 		}
 
+		if (proc->get_bool_attribute(ID(always_ff)))
+			log_error("Found non edge/level sensitive event in always_ff process `%s.%s'.\n",
+					db.module->name.c_str(), proc->name.c_str());
+
 		for (auto ss : sr->actions)
 		{
 			db.sigmap.apply(ss.first);
@@ -383,8 +387,12 @@
 	int offset = 0;
 	for (auto chunk : nolatches_bits.first.chunks()) {
 		SigSpec lhs = chunk, rhs = nolatches_bits.second.extract(offset, chunk.width);
-		log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n",
-				db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+		if (proc->get_bool_attribute(ID(always_latch)))
+			log_error("No latch inferred for signal `%s.%s' from always_latch process `%s.%s'.\n",
+					db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+		else
+			log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n",
+					db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
 		db.module->connect(lhs, rhs);
 		offset += chunk.width;
 	}
@@ -410,8 +418,12 @@
 			cell->set_src_attribute(src);
 			db.generated_dlatches.insert(cell);
 
-			log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
-					db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
+			if (proc->get_bool_attribute(ID(always_comb)))
+				log_error("Latch inferred for signal `%s.%s' from always_comb process `%s.%s'.\n",
+						db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+			else
+				log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
+						db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
 		}
 
 		offset += width;
diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc
index 246932d..b9cd688 100644
--- a/passes/techmap/clkbufmap.cc
+++ b/passes/techmap/clkbufmap.cc
@@ -115,6 +115,8 @@
 		// Cell type, port name, bit index.
 		pool<pair<IdString, pair<IdString, int>>> sink_ports;
 		pool<pair<IdString, pair<IdString, int>>> buf_ports;
+		dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out;
+		dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in;
 
 		// Process submodules before module using them.
 		std::vector<Module *> modules_sorted;
@@ -133,6 +135,14 @@
 					if (wire->get_bool_attribute("\\clkbuf_sink"))
 						for (int i = 0; i < GetSize(wire); i++)
 							sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
+					auto it = wire->attributes.find("\\clkbuf_inv");
+					if (it != wire->attributes.end()) {
+						IdString in_name = RTLIL::escape_id(it->second.decode_string());
+						for (int i = 0; i < GetSize(wire); i++) {
+							inv_ports_out[make_pair(module->name, make_pair(wire->name, i))] = make_pair(in_name, i);
+							inv_ports_in[make_pair(module->name, make_pair(in_name, i))] = make_pair(wire->name, i);
+						}
+					}
 				}
 				continue;
 			}
@@ -157,6 +167,37 @@
 				if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
 					buf_wire_bits.insert(sigmap(port.second[i]));
 
+			// Third, propagate tags through inverters.
+			bool retry = true;
+			while (retry) {
+				retry = false;
+				for (auto cell : module->cells())
+				for (auto port : cell->connections())
+				for (int i = 0; i < port.second.size(); i++) {
+					auto it = inv_ports_out.find(make_pair(cell->type, make_pair(port.first, i)));
+					auto bit = sigmap(port.second[i]);
+					// If output of an inverter is connected to a sink, mark it as buffered,
+					// and request a buffer on the inverter's input instead.
+					if (it != inv_ports_out.end() && !buf_wire_bits.count(bit) && sink_wire_bits.count(bit)) {
+						buf_wire_bits.insert(bit);
+						auto other_bit = sigmap(cell->getPort(it->second.first)[it->second.second]);
+						sink_wire_bits.insert(other_bit);
+						retry = true;
+					}
+					// If input of an inverter is marked as already-buffered,
+					// mark its output already-buffered as well.
+					auto it2 = inv_ports_in.find(make_pair(cell->type, make_pair(port.first, i)));
+					if (it2 != inv_ports_in.end() && buf_wire_bits.count(bit)) {
+						auto other_bit = sigmap(cell->getPort(it2->second.first)[it2->second.second]);
+						if (!buf_wire_bits.count(other_bit)) {
+							buf_wire_bits.insert(other_bit);
+							retry = true;
+						}
+					}
+
+				}
+			};
+
 			// Collect all driven bits.
 			for (auto cell : module->cells())
 			for (auto port : cell->connections())
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
index 21bbcae..014c686 100644
--- a/techlibs/coolrunner2/synth_coolrunner2.cc
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -194,8 +194,6 @@
 			if (!json_file.empty() || help_mode)
 				run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
 		}
-
-		log_pop();
 	}
 } SynthCoolrunner2Pass;
 
diff --git a/techlibs/gowin/.gitignore b/techlibs/gowin/.gitignore
new file mode 100644
index 0000000..d6c48e9
--- /dev/null
+++ b/techlibs/gowin/.gitignore
@@ -0,0 +1,2 @@
+brams_init.mk
+bram_init_*.vh
diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc
index 6f21593..d285370 100644
--- a/techlibs/gowin/Makefile.inc
+++ b/techlibs/gowin/Makefile.inc
@@ -15,3 +15,13 @@
 
 $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh))
 
+EXTRA_OBJS += techlibs/gowin/brams_init.mk
+.SECONDARY: techlibs/gowin/brams_init.mk
+
+techlibs/gowin/brams_init.mk: techlibs/gowin/brams_init.py
+	$(Q) mkdir -p techlibs/gowin
+	$(P) python3 $<
+	$(Q) touch $@
+
+techlibs/gowin/bram_init_16.vh: techlibs/gowin/brams_init.mk
+$(eval $(call add_gen_share_file,share/gowin,techlibs/gowin/bram_init_16.vh))
diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v
index e15de64..b6f9e8c 100644
--- a/techlibs/gowin/arith_map.v
+++ b/techlibs/gowin/arith_map.v
@@ -40,15 +40,15 @@
    \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
 
    wire [Y_WIDTH-1:0] 	AA = A_buf;
-   wire [Y_WIDTH-1:0] 	BB = BI ? ~B_buf : B_buf;
+   wire [Y_WIDTH-1:0] 	BB = B_buf;
    wire [Y_WIDTH-1:0] 	C = {CO, CI};
 
    genvar 		i;
    generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
-      ALU #(.ALU_MODE(32'b0))
+      ALU #(.ALU_MODE(2)) // ADDSUB I3 ? add : sub
       alu(.I0(AA[i]),
 	  .I1(BB[i]),
-	  .I3(1'b0),
+	  .I3(~BI),
 	  .CIN(C[i]),
 	  .COUT(CO[i]),
 	  .SUM(Y[i])
diff --git a/techlibs/gowin/bram.txt b/techlibs/gowin/bram.txt
index b5f9a98..e406f9c 100644
--- a/techlibs/gowin/bram.txt
+++ b/techlibs/gowin/bram.txt
@@ -1,6 +1,7 @@
 bram $__GW1NR_SDP
-# uncomment when done
-#  init 1
+  init 1
+  abits 9 @a9d36
+  dbits 32 @a9d36
   abits 10 @a10d18
   dbits 16 @a10d18
   abits 11 @a11d9
@@ -14,7 +15,8 @@
   groups 2
   ports  1 1
   wrmode 1 0
-  enable 1 1 @a10d18
+  enable 4 1 @a9d36
+  enable 2 1 @a10d18
   enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
   transp 0 0
   clocks 2 3
@@ -24,6 +26,6 @@
 match $__GW1NR_SDP
   min bits 2048
   min efficiency 5
-  shuffle_enable B
+  shuffle_enable A
   make_transp
 endmatch
diff --git a/techlibs/gowin/brams_init.py b/techlibs/gowin/brams_init.py
new file mode 100755
index 0000000..b78eb8d
--- /dev/null
+++ b/techlibs/gowin/brams_init.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python3
+
+with open("techlibs/gowin/bram_init_16.vh", "w") as f:
+    for i in range(0, 0x40):
+        low = i << 8
+        hi = ((i+1) << 8)-1
+        snippet = "INIT[%d:%d]" % (hi, low)
+        print(".INIT_RAM_%02X({%s})," % (i, snippet), file=f)
diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v
index e963cfa..fbebc4a 100644
--- a/techlibs/gowin/brams_map.v
+++ b/techlibs/gowin/brams_map.v
@@ -8,26 +8,28 @@
 module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
 	parameter CFG_ABITS = 10;
 	parameter CFG_DBITS = 16;
-	parameter CFG_ENABLE_A = 3;
-
-        parameter [16383:0] INIT = 16384'hx;
-        parameter CLKPOL2 = 1;
-        parameter CLKPOL3 = 1;
+	parameter CFG_ENABLE_A = 1;
+	parameter [16383:0] INIT = 16384'hx;
+	parameter CLKPOL2 = 1;
+	parameter CLKPOL3 = 1;
 
 	input CLK2;
 	input CLK3;
 
 	input [CFG_ABITS-1:0] A1ADDR;
 	input [CFG_DBITS-1:0] A1DATA;   
-        input [CFG_ENABLE_A-1:0] A1EN;
+	input [CFG_ENABLE_A-1:0] A1EN;
 
 	input [CFG_ABITS-1:0] B1ADDR;
 	output [CFG_DBITS-1:0] B1DATA;
 	input B1EN;
 
+	wire [31-CFG_DBITS:0] open;
+
 	
 	generate if (CFG_DBITS == 1) begin
 		SDP   #(
+      `include "bram_init_16.vh"
 			.READ_MODE(0),
 			.BIT_WIDTH_0(1),
 			.BIT_WIDTH_1(1),
@@ -38,10 +40,14 @@
 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
 			.WREB(1'b0),   .CEB(B1EN),
 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-			.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
+			.DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
+			.DO({open, B1DATA}),
+			.ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
 		);
 	end else if (CFG_DBITS == 2) begin
 		SDP    #(
+      `include "bram_init_16.vh"
 			.READ_MODE(0),
 			.BIT_WIDTH_0(2),
 			.BIT_WIDTH_1(2),
@@ -52,10 +58,14 @@
 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
 			.WREB(1'b0),   .CEB(B1EN),
 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                        .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
+			.DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
+			.DO({open, B1DATA}),
+			.ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
 		);
 	end else if (CFG_DBITS <= 4) begin
 		SDP    #(
+      `include "bram_init_16.vh"
 			.READ_MODE(0),
 			.BIT_WIDTH_0(4),
 			.BIT_WIDTH_1(4),
@@ -66,10 +76,14 @@
 			.WREA(A1EN),   .OCE(1'b0),
 			.WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                        .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
+			.DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
+			.DO({open, B1DATA}),
+			.ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
 		);
 	end else if (CFG_DBITS <= 8) begin
 		SDP    #(
+      `include "bram_init_16.vh"
 			.READ_MODE(0),
 			.BIT_WIDTH_0(8),
 			.BIT_WIDTH_1(8),
@@ -80,10 +94,14 @@
 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
 			.WREB(1'b0),   .CEB(B1EN),
 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                        .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
+			.DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
+			.DO({open, B1DATA}),
+			.ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
 		);
 	end else if (CFG_DBITS <= 16) begin
 		SDP    #(
+      `include "bram_init_16.vh"
 			.READ_MODE(0),
 			.BIT_WIDTH_0(16),
 			.BIT_WIDTH_1(16),
@@ -91,10 +109,31 @@
 			.RESET_MODE("SYNC")
 		) _TECHMAP_REPLACE_ (
 			.CLKA(CLK2),   .CLKB(CLK3),
-			.WREA(A1EN),   .OCE(1'b0),
+			.WREA(|A1EN),   .OCE(1'b0),
 			.WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                        .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
+			.DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
+			.DO({open, B1DATA}),
+			.ADA({A1ADDR, {(12-CFG_ABITS){1'b0}}, A1EN}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
+		);
+	end else if (CFG_DBITS <= 32) begin
+		SDP    #(
+      `include "bram_init_16.vh"
+			.READ_MODE(0),
+			.BIT_WIDTH_0(32),
+			.BIT_WIDTH_1(32),
+			.BLK_SEL(3'b000),
+			.RESET_MODE("SYNC")
+		) _TECHMAP_REPLACE_ (
+			.CLKA(CLK2),   .CLKB(CLK3),
+			.WREA(|A1EN),   .OCE(1'b0),
+			.WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
+			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
+			.DI(A1DATA),
+			.DO(B1DATA),
+			.ADA({A1ADDR, {(10-CFG_ABITS){1'b0}}, A1EN}),
+			.ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
 		);
 	end else begin
 		wire TECHMAP_FAIL = 1'b1;
diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v
index ebdc88a..9845e56 100644
--- a/techlibs/gowin/cells_map.v
+++ b/techlibs/gowin/cells_map.v
@@ -1,9 +1,83 @@
-module  \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
-module  \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF  #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
+//All DFF* have INIT, but the hardware is always initialised to the reset
+//value regardless. The parameter is ignored.
 
+// DFFN      D Flip-Flop with Negative-Edge Clock
+module  \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
+// DFF       D Flip-Flop
+module  \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
+
+// DFFE      D Flip-Flop with Clock Enable
+module  \$_DFFE_PP_ (input D, C, E, output Q); DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); endmodule
+module  \$_DFFE_PN_ (input D, C, E, output Q); DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E)); endmodule
+
+// DFFNE     D Flip-Flop with Negative-Edge Clock and Clock Enable
+module  \$_DFFE_NP_ (input D, C, E, output Q); DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); endmodule
+module  \$_DFFE_NN_ (input D, C, E, output Q); DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E)); endmodule
+
+// DFFR      D Flip-Flop with Synchronous Reset
 module  \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule
 module  \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
-module  \$__DFFS_PP1_ (input D, C, R, output Q); DFFR  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
+
+// DFFNR     D Flip-Flop with Negative-Edge Clock and Synchronous Reset
+module  \$__DFFS_NN0_ (input D, C, R, output Q); DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule
+module  \$__DFFS_NP0_ (input D, C, R, output Q); DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
+
+// DFFRE     D Flip-Flop with Clock Enable and Synchronous Reset
+module  \$__DFFSE_PN0 (input D, C, R, E, output Q); DFFRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R), .CE(E)); endmodule
+module  \$__DFFSE_PP0 (input D, C, R, E, output Q); DFFRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R), .CE(E)); endmodule
+
+// DFFNRE    D Flip-Flop with Negative-Edge Clock,Clock Enable, and Synchronous Reset
+module  \$__DFFNSE_PN0 (input D, C, R, E, output Q); DFFNRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R), .CE(E)); endmodule
+module  \$__DFFNSE_PP0 (input D, C, R, E, output Q); DFFNRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R), .CE(E)); endmodule
+
+// DFFS      D Flip-Flop with Synchronous Set
+module  \$__DFFS_PN1_ (input D, C, R, output Q); DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R)); endmodule
+module  \$__DFFS_PP1_ (input D, C, R, output Q); DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R)); endmodule
+
+// DFFNS     D Flip-Flop with Negative-Edge Clock and Synchronous Set
+module  \$__DFFS_NN1_ (input D, C, R, output Q); DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R)); endmodule
+module  \$__DFFS_NP1_ (input D, C, R, output Q); DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R)); endmodule
+
+// DFFSE     D Flip-Flop with Clock Enable and Synchronous Set
+module  \$__DFFSE_PN1 (input D, C, R, E, output Q); DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R), .CE(E)); endmodule
+module  \$__DFFSE_PP1 (input D, C, R, E, output Q); DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R), .CE(E)); endmodule
+
+// DFFNSE    D Flip-Flop with Negative-Edge Clock,Clock Enable,and Synchronous Set
+module  \$__DFFSE_NN1 (input D, C, R, E, output Q); DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R), .CE(E)); endmodule
+module  \$__DFFSE_NP1 (input D, C, R, E, output Q); DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R), .CE(E)); endmodule
+
+// DFFP      D Flip-Flop with Asynchronous Preset
+module  \$_DFF_PP1_ (input D, C, R, output Q); DFFP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R)); endmodule
+module  \$_DFF_PN1_ (input D, C, R, output Q); DFFP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R)); endmodule
+
+// DFFNP     D Flip-Flop with Negative-Edge Clock and Asynchronous Preset
+module  \$_DFF_NP1_ (input D, C, R, output Q); DFFNP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R)); endmodule
+module  \$_DFF_NN1_ (input D, C, R, output Q); DFFNP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R)); endmodule
+
+// DFFC      D Flip-Flop with Asynchronous Clear
+module  \$_DFF_PP0_ (input D, C, R, output Q); DFFC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R)); endmodule
+module  \$_DFF_PN0_ (input D, C, R, output Q); DFFC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R)); endmodule
+
+// DFFNC     D Flip-Flop with Negative-Edge Clock and Asynchronous Clear
+module  \$_DFF_NP0_ (input D, C, R, output Q); DFFNC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R)); endmodule
+module  \$_DFF_NN0_ (input D, C, R, output Q); DFFNC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R)); endmodule
+
+// DFFPE     D Flip-Flop with Clock Enable and Asynchronous Preset
+module  \$__DFFE_PP1 (input D, C, R, E, output Q); DFFPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R), .CE(E)); endmodule
+module  \$__DFFE_PN1 (input D, C, R, E, output Q); DFFPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R), .CE(E)); endmodule
+
+// DFFNPE    D Flip-Flop with Negative-Edge Clock,Clock Enable, and Asynchronous Preset
+module  \$__DFFE_NP1 (input D, C, R, E, output Q); DFFNPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R), .CE(E)); endmodule
+module  \$__DFFE_NN1 (input D, C, R, E, output Q); DFFNPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R), .CE(E)); endmodule
+
+// DFFCE     D Flip-Flop with Clock Enable and Asynchronous Clear
+module  \$__DFFE_PP0 (input D, C, R, E, output Q); DFFCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R), .CE(E)); endmodule
+module  \$__DFFE_PN0 (input D, C, R, E, output Q); DFFCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R), .CE(E)); endmodule
+
+// DFFNCE    D Flip-Flop with Negative-Edge Clock,Clock Enable and Asynchronous Clear
+module  \$__DFFE_NP0 (input D, C, R, E, output Q); DFFNCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R), .CE(E)); endmodule
+module  \$__DFFE_NN0 (input D, C, R, E, output Q); DFFNCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R), .CE(E)); endmodule
+
 
 module \$lut (A, Y);
   parameter WIDTH = 0;
@@ -28,6 +102,30 @@
     if (WIDTH == 4) begin
       LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.F(Y),
         .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+    end else
+    if (WIDTH == 5) begin
+      wire f0, f1;
+      \$lut #(.LUT(LUT[15: 0]), .WIDTH(4)) lut0 (.A(A[3:0]), .Y(f0));
+      \$lut #(.LUT(LUT[31:16]), .WIDTH(4)) lut1 (.A(A[3:0]), .Y(f1));
+      MUX2_LUT5 mux5(.I0(f0), .I1(f1), .S0(A[4]), .O(Y));
+    end else
+    if (WIDTH == 6) begin
+      wire f0, f1;
+      \$lut #(.LUT(LUT[31: 0]), .WIDTH(5)) lut0 (.A(A[4:0]), .Y(f0));
+      \$lut #(.LUT(LUT[63:32]), .WIDTH(5)) lut1 (.A(A[4:0]), .Y(f1));
+      MUX2_LUT6 mux6(.I0(f0), .I1(f1), .S0(A[5]), .O(Y));
+    end else
+    if (WIDTH == 7) begin
+      wire f0, f1;
+      \$lut #(.LUT(LUT[63: 0]), .WIDTH(6)) lut0 (.A(A[5:0]), .Y(f0));
+      \$lut #(.LUT(LUT[127:64]), .WIDTH(6)) lut1 (.A(A[5:0]), .Y(f1));
+      MUX2_LUT7 mux7(.I0(f0), .I1(f1), .S0(A[6]), .O(Y));
+    end else
+    if (WIDTH == 8) begin
+      wire f0, f1;
+      \$lut #(.LUT(LUT[127: 0]), .WIDTH(7)) lut0 (.A(A[6:0]), .Y(f0));
+      \$lut #(.LUT(LUT[255:128]), .WIDTH(7)) lut1 (.A(A[6:0]), .Y(f1));
+      MUX2_LUT8 mux8(.I0(f0), .I1(f1), .S0(A[7]), .O(Y));
     end else begin
       wire _TECHMAP_FAIL_ = 1;
     end
diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v
index ebb238b..a67855d 100644
--- a/techlibs/gowin/cells_sim.v
+++ b/techlibs/gowin/cells_sim.v
@@ -24,6 +24,41 @@
 	assign F = I0 ? s1[1] : s1[0];
 endmodule
 
+module MUX2 (O, I0, I1, S0);
+  input I0,I1;
+  input S0;
+  output O;
+  assign O = S0 ? I1 : I0;
+endmodule
+
+module MUX2_LUT5 (O, I0, I1, S0);
+  input I0,I1;
+  input S0;
+  output O;
+  MUX2 mux2_lut5 (O, I0, I1, S0);
+endmodule
+
+module MUX2_LUT6 (O, I0, I1, S0);
+  input I0,I1;
+  input S0;
+  output O;
+  MUX2 mux2_lut6 (O, I0, I1, S0);
+endmodule
+
+module MUX2_LUT7 (O, I0, I1, S0);
+  input I0,I1;
+  input S0;
+  output O;
+  MUX2 mux2_lut7 (O, I0, I1, S0);
+endmodule
+
+module MUX2_LUT8 (O, I0, I1, S0);
+  input I0,I1;
+  input S0;
+  output O;
+  MUX2 mux2_lut8 (O, I0, I1, S0);
+endmodule
+
 module DFF (output reg Q, input CLK, D);
 	parameter [0:0] INIT = 1'b0;
 	initial Q = INIT;
@@ -31,6 +66,112 @@
 		Q <= D;
 endmodule
 
+module DFFE (output reg Q, input D, CLK, CE);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK) begin
+    if (CE)
+      Q <= D;
+  end
+endmodule // DFFE (positive clock edge; clock enable)
+
+
+module DFFS (output reg Q, input D, CLK, SET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK) begin
+    if (SET)
+      Q <= 1'b1;
+    else
+      Q <= D;	
+  end
+endmodule // DFFS (positive clock edge; synchronous set)
+
+
+module DFFSE (output reg Q, input D, CLK, CE, SET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK) begin
+    if (SET)
+      Q <= 1'b1;
+    else if (CE)
+      Q <= D;
+end
+endmodule // DFFSE (positive clock edge; synchronous set takes precedence over clock enable)
+
+
+module DFFR (output reg Q, input D, CLK, RESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK) begin
+    if (RESET)
+      Q <= 1'b0;
+    else
+      Q <= D;
+  end
+endmodule // DFFR (positive clock edge; synchronous reset)
+
+
+module DFFRE (output reg Q, input D, CLK, CE, RESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK) begin
+    if (RESET)
+      Q <= 1'b0;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFRE (positive clock edge; synchronous reset takes precedence over clock enable)
+
+
+module DFFP (output reg Q, input D, CLK, PRESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK or posedge PRESET) begin
+    if(PRESET)
+      Q <= 1'b1;
+    else
+      Q <= D;
+  end
+endmodule // DFFP (positive clock edge; asynchronous preset)
+
+
+module DFFPE (output reg Q, input D, CLK, CE, PRESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK or posedge PRESET) begin
+    if(PRESET)
+      Q <= 1'b1;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFPE (positive clock edge; asynchronous preset; clock enable)
+
+
+module DFFC (output reg Q, input D, CLK, CLEAR);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK or posedge CLEAR) begin
+    if(CLEAR)
+      Q <= 1'b0;
+    else
+      Q <= D;
+  end
+endmodule // DFFC (positive clock edge; asynchronous clear)
+
+
+module DFFCE (output reg Q, input D, CLK, CE, CLEAR);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(posedge CLK or posedge CLEAR) begin
+    if(CLEAR)
+      Q <= 1'b0;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFCE (positive clock edge; asynchronous clear; clock enable)
+
+
 module DFFN (output reg Q, input CLK, D);
 	parameter [0:0] INIT = 1'b0;
 	initial Q = INIT;
@@ -38,16 +179,112 @@
 		Q <= D;
 endmodule
 
-module DFFR (output reg Q, input D, CLK, RESET);
-	parameter [0:0] INIT = 1'b0;
-	initial Q = INIT;
-	always @(posedge CLK) begin
-        if (RESET)
-                Q <= 1'b0;
-        else
-                Q <= D;
-	end
-endmodule // DFFR (positive clock edge; synchronous reset)
+module DFFNE (output reg Q, input D, CLK, CE);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK) begin
+    if (CE)
+      Q <= D;
+  end
+endmodule // DFFNE (negative clock edge; clock enable)
+
+
+module DFFNS (output reg Q, input D, CLK, SET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK) begin
+    if (SET)
+      Q <= 1'b1;
+    else
+      Q <= D;	
+  end
+endmodule // DFFNS (negative clock edge; synchronous set)
+
+
+module DFFNSE (output reg Q, input D, CLK, CE, SET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK) begin
+    if (SET)
+      Q <= 1'b1;
+    else if (CE)
+      Q <= D;
+end
+endmodule // DFFNSE (negative clock edge; synchronous set takes precedence over clock enable)
+
+
+module DFFNR (output reg Q, input D, CLK, RESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK) begin
+    if (RESET)
+      Q <= 1'b0;
+    else
+      Q <= D;
+  end
+endmodule // DFFNR (negative clock edge; synchronous reset)
+
+
+module DFFNRE (output reg Q, input D, CLK, CE, RESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK) begin
+    if (RESET)
+      Q <= 1'b0;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFNRE (negative clock edge; synchronous reset takes precedence over clock enable)
+
+
+module DFFNP (output reg Q, input D, CLK, PRESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK or posedge PRESET) begin
+    if(PRESET)
+      Q <= 1'b1;
+    else
+      Q <= D;
+  end
+endmodule // DFFNP (negative clock edge; asynchronous preset)
+
+
+module DFFNPE (output reg Q, input D, CLK, CE, PRESET);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK or posedge PRESET) begin
+    if(PRESET)
+      Q <= 1'b1;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFNPE (negative clock edge; asynchronous preset; clock enable)
+
+
+module DFFNC (output reg Q, input D, CLK, CLEAR);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK or posedge CLEAR) begin
+    if(CLEAR)
+      Q <= 1'b0;
+    else
+      Q <= D;
+  end
+endmodule // DFFNC (negative clock edge; asynchronous clear)
+
+
+module DFFNCE (output reg Q, input D, CLK, CE, CLEAR);
+  parameter [0:0] INIT = 1'b0;
+  initial Q = INIT;
+  always @(negedge CLK or posedge CLEAR) begin
+    if(CLEAR)
+      Q <= 1'b0;
+    else if (CE)
+      Q <= D;
+  end
+endmodule // DFFNCE (negative clock edge; asynchronous clear; clock enable)
+
+// TODO add more DFF sim cells
 
 module VCC(output V);
 	assign V = 1;
@@ -65,14 +302,98 @@
 	assign O = I;
 endmodule
 
+module TBUF (O, I, OEN);
+  input I, OEN;
+  output O;
+  assign O = OEN ? I : 1'bz;
+endmodule
+
+module IOBUF (O, IO, I, OEN);
+  input I,OEN;
+  output O;
+  inout IO;
+  assign IO = OEN ? I : 1'bz;
+  assign I = IO;
+endmodule
+
 module GSR (input GSRI);
 	wire GSRO = GSRI;
 endmodule
 
-module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM);
-   parameter [3:0] ALU_MODE = 0; // default 0 = ADD
-   assign  {COUT, SUM} = CIN + I1 + I0;
-endmodule // alu
+module ALU (SUM, COUT, I0, I1, I3, CIN);
+
+input I0;
+input I1;
+input I3;
+input CIN;
+output SUM;
+output COUT;
+
+localparam ADD = 0;
+localparam SUB = 1;
+localparam ADDSUB = 2;
+localparam NE = 3;
+localparam GE = 4;
+localparam LE = 5;
+localparam CUP = 6;
+localparam CDN = 7;
+localparam CUPCDN = 8;
+localparam MULT = 9;
+
+parameter ALU_MODE = 0;
+
+reg S, C;
+
+assign SUM = S ^ CIN;
+assign COUT = S? CIN : C;
+
+always @* begin
+	case (ALU_MODE)
+		ADD: begin
+			S = I0 ^ I1;
+			C = I0;
+		end
+		SUB: begin
+			S = I0 ^ ~I1;
+			C = I0;
+		end
+		ADDSUB: begin
+			S = I3? I0 ^ I1 : I0 ^ ~I1;
+			C = I0;
+		end
+		NE: begin
+			S = I0 ^ ~I1;
+			C = 1'b1;
+		end
+		GE: begin
+			S = I0 ^ ~I1;
+			C = I0;
+		end
+		LE: begin
+			S = ~I0 ^ I1;
+			C = I1;
+		end
+		CUP: begin
+			S = I0;
+			C = 1'b0;
+		end
+		CDN: begin
+			S = ~I0;
+			C = 1'b1;
+		end
+		CUPCDN: begin
+			S = I3? I0 : ~I0;
+			C = I0;
+		end
+		MULT: begin
+			S = I0 & I1;
+			C = I0 & I1;
+		end
+	endcase
+end
+
+endmodule
+
 
 module RAM16S4 (DO, DI, AD, WRE, CLK);
    parameter WIDTH  = 4;
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc
index ac3dbfb..3c14264 100644
--- a/techlibs/gowin/synth_gowin.cc
+++ b/techlibs/gowin/synth_gowin.cc
@@ -64,6 +64,12 @@
 		log("    -retime\n");
 		log("        run 'abc' with -dff option\n");
 		log("\n");
+		log("    -nowidelut\n");
+		log("        do not use muxes to implement LUTs larger than LUT4s\n");
+		log("\n");
+		log("    -abc9\n");
+		log("        use new ABC9 flow (EXPERIMENTAL)\n");
+		log("\n");
 		log("\n");
 		log("The following commands are executed by this synthesis command:\n");
 		help_script();
@@ -71,7 +77,7 @@
 	}
 
 	string top_opt, vout_file;
-	bool retime, nobram, nodram, flatten, nodffe;
+	bool retime, nobram, nodram, flatten, nodffe, nowidelut, abc9;
 
 	void clear_flags() YS_OVERRIDE
 	{
@@ -82,6 +88,8 @@
 		nobram = false;
 		nodffe = false;
 		nodram = false;
+		nowidelut = false;
+		abc9 = false;
 	}
 
 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -128,6 +136,14 @@
 				flatten = false;
 				continue;
 			}
+			if (args[argidx] == "-nowidelut") {
+				nowidelut = true;
+				continue;
+			}
+			if (args[argidx] == "-abc9") {
+				abc9 = true;
+				continue;
+			}
 			break;
 		}
 		extra_args(args, argidx, design);
@@ -163,8 +179,8 @@
 		{
 			run("synth -run coarse");
 		}
-		
-                if (!nobram && check_label("bram", "(skip if -nobram)"))
+
+		if (!nobram && check_label("bram", "(skip if -nobram)"))
 		{
 			run("memory_bram -rules +/gowin/bram.txt");
 			run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v");
@@ -186,6 +202,7 @@
 			run("techmap -map +/techmap.v");
 			if (retime || help_mode)
 				run("abc -dff", "(only if -retime)");
+			run("splitnets");
 		}
 
 		if (check_label("map_ffs"))
@@ -202,16 +219,25 @@
 
 		if (check_label("map_luts"))
 		{
-			run("abc -lut 4");
+			if (nowidelut && abc9) {
+				run("abc9 -lut 4");
+			} else if (nowidelut && !abc9) {
+				run("abc -lut 4");
+			} else if (!nowidelut && abc9) {
+				run("abc9 -lut 4:8");
+			} else if (!nowidelut && !abc9) {
+				run("abc -lut 4:8");
+			}
 			run("clean");
 		}
 
 		if (check_label("map_cells"))
 		{
 			run("techmap -map +/gowin/cells_map.v");
-			run("hilomap -hicell VCC V -locell GND G");
-			run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)");
-			run("dffinit  -ff DFF Q INIT");
+			run("setundef -undriven -params -zero");
+			run("hilomap -singleton -hicell VCC V -locell GND G");
+			run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O "
+				"-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)");
 			run("clean");
 
 		}
@@ -226,7 +252,7 @@
 		if (check_label("vout"))
 		{
 			if (!vout_file.empty() || help_mode)
-				run(stringf("write_verilog -nodec -attr2comment -defparam -renameprefix gen %s",
+				 run(stringf("write_verilog -decimal -attr2comment -defparam -renameprefix gen %s",
 						help_mode ? "<file-name>" : vout_file.c_str()));
 		}
 	}
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 03985b1..1be43f9 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -59,6 +59,34 @@
   assign O = I;
 endmodule
 
+module IOBUF (
+    (* iopad_external_pin *)
+    inout IO,
+    output O,
+    input I,
+    input T
+);
+    parameter integer DRIVE = 12;
+    parameter IBUF_LOW_PWR = "TRUE";
+    parameter IOSTANDARD = "DEFAULT";
+    parameter SLEW = "SLOW";
+    assign IO = T ? 1'bz : I;
+    assign O = IO;
+endmodule
+
+module OBUFT (
+    (* iopad_external_pin *)
+    output O,
+    input I,
+    input T
+);
+    parameter CAPACITANCE = "DONT_CARE";
+    parameter integer DRIVE = 12;
+    parameter IOSTANDARD = "DEFAULT";
+    parameter SLEW = "SLOW";
+    assign O = T ? 1'bz : I;
+endmodule
+
 module BUFG(
     (* clkbuf_driver *)
     output O,
@@ -126,7 +154,11 @@
 //   assign O = IO, IO = T ? 1'bz : I;
 // endmodule
 
-module INV(output O, input I);
+module INV(
+    (* clkbuf_inv = "I" *)
+    output O,
+    input I
+);
   assign O = !I;
 endmodule
 
@@ -581,6 +613,515 @@
   endgenerate
 endmodule
 
+// DSP
+
+// Virtex 2, Virtex 2 Pro, Spartan 3.
+
+// Asynchronous mode.
+
+module MULT18X18 (
+    input signed [17:0] A,
+    input signed [17:0] B,
+    output signed [35:0] P
+);
+
+assign P = A * B;
+
+endmodule
+
+// Synchronous mode.
+
+module MULT18X18S (
+    input signed [17:0] A,
+    input signed [17:0] B,
+    output reg signed [35:0] P,
+    (* clkbuf_sink *)
+    input C,
+    input CE,
+    input R
+);
+
+always @(posedge C)
+	if (R)
+		P <= 0;
+	else if (CE)
+		P <= A * B;
+
+endmodule
+
+// Spartan 3E, Spartan 3A.
+
+module MULT18X18SIO (
+    input signed [17:0] A,
+    input signed [17:0] B,
+    output signed [35:0] P,
+    (* clkbuf_sink *)
+    input CLK,
+    input CEA,
+    input CEB,
+    input CEP,
+    input RSTA,
+    input RSTB,
+    input RSTP,
+    input signed [17:0] BCIN,
+    output signed [17:0] BCOUT
+);
+
+parameter integer AREG = 1;
+parameter integer BREG = 1;
+parameter B_INPUT = "DIRECT";
+parameter integer PREG = 1;
+
+// The multiplier.
+wire signed [35:0] P_MULT;
+assign P_MULT = A_MULT * B_MULT;
+
+// The cascade output.
+assign BCOUT = B_MULT;
+
+// The B input multiplexer.
+wire signed [17:0] B_MUX;
+assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN;
+
+// The registers.
+reg signed [17:0] A_REG;
+reg signed [17:0] B_REG;
+reg signed [35:0] P_REG;
+
+initial begin
+	A_REG = 0;
+	B_REG = 0;
+	P_REG = 0;
+end
+
+always @(posedge CLK) begin
+	if (RSTA)
+		A_REG <= 0;
+	else if (CEA)
+		A_REG <= A;
+
+	if (RSTB)
+		B_REG <= 0;
+	else if (CEB)
+		B_REG <= B_MUX;
+
+	if (RSTP)
+		P_REG <= 0;
+	else if (CEP)
+		P_REG <= P_MULT;
+end
+
+// The register enables.
+wire signed [17:0] A_MULT;
+wire signed [17:0] B_MULT;
+assign A_MULT = (AREG == 1) ? A_REG : A;
+assign B_MULT = (BREG == 1) ? B_REG : B_MUX;
+assign P = (PREG == 1) ? P_REG : P_MULT;
+
+endmodule
+
+// Spartan 3A DSP.
+
+module DSP48A (
+    input signed [17:0] A,
+    input signed [17:0] B,
+    input signed [47:0] C,
+    input signed [17:0] D,
+    input signed [47:0] PCIN,
+    input CARRYIN,
+    input [7:0] OPMODE,
+    output signed [47:0] P,
+    output signed [17:0] BCOUT,
+    output signed [47:0] PCOUT,
+    output CARRYOUT,
+    (* clkbuf_sink *)
+    input CLK,
+    input CEA,
+    input CEB,
+    input CEC,
+    input CED,
+    input CEM,
+    input CECARRYIN,
+    input CEOPMODE,
+    input CEP,
+    input RSTA,
+    input RSTB,
+    input RSTC,
+    input RSTD,
+    input RSTM,
+    input RSTCARRYIN,
+    input RSTOPMODE,
+    input RSTP
+);
+
+parameter integer A0REG = 0;
+parameter integer A1REG = 1;
+parameter integer B0REG = 0;
+parameter integer B1REG = 1;
+parameter integer CREG = 1;
+parameter integer DREG = 1;
+parameter integer MREG = 1;
+parameter integer CARRYINREG = 1;
+parameter integer OPMODEREG = 1;
+parameter integer PREG = 1;
+parameter CARRYINSEL = "CARRYIN";
+parameter RSTTYPE = "SYNC";
+
+// This is a strict subset of Spartan 6 -- reuse its model.
+
+DSP48A1 #(
+	.A0REG(A0REG),
+	.A1REG(A1REG),
+	.B0REG(B0REG),
+	.B1REG(B1REG),
+	.CREG(CREG),
+	.DREG(DREG),
+	.MREG(MREG),
+	.CARRYINREG(CARRYINREG),
+	.CARRYOUTREG(0),
+	.OPMODEREG(OPMODEREG),
+	.PREG(PREG),
+	.CARRYINSEL(CARRYINSEL),
+	.RSTTYPE(RSTTYPE)
+) upgrade (
+	.A(A),
+	.B(B),
+	.C(C),
+	.D(D),
+	.PCIN(PCIN),
+	.CARRYIN(CARRYIN),
+	.OPMODE(OPMODE),
+	// M unconnected
+	.P(P),
+	.BCOUT(BCOUT),
+	.PCOUT(PCOUT),
+	.CARRYOUT(CARRYOUT),
+	// CARRYOUTF unconnected
+	.CLK(CLK),
+	.CEA(CEA),
+	.CEB(CEB),
+	.CEC(CEC),
+	.CED(CED),
+	.CEM(CEM),
+	.CECARRYIN(CECARRYIN),
+	.CEOPMODE(CEOPMODE),
+	.CEP(CEP),
+	.RSTA(RSTA),
+	.RSTB(RSTB),
+	.RSTC(RSTC),
+	.RSTD(RSTD),
+	.RSTM(RSTM),
+	.RSTCARRYIN(RSTCARRYIN),
+	.RSTOPMODE(RSTOPMODE),
+	.RSTP(RSTP)
+);
+
+endmodule
+
+// Spartan 6.
+
+module DSP48A1 (
+    input signed [17:0] A,
+    input signed [17:0] B,
+    input signed [47:0] C,
+    input signed [17:0] D,
+    input signed [47:0] PCIN,
+    input CARRYIN,
+    input [7:0] OPMODE,
+    output signed [35:0] M,
+    output signed [47:0] P,
+    output signed [17:0] BCOUT,
+    output signed [47:0] PCOUT,
+    output CARRYOUT,
+    output CARRYOUTF,
+    (* clkbuf_sink *)
+    input CLK,
+    input CEA,
+    input CEB,
+    input CEC,
+    input CED,
+    input CEM,
+    input CECARRYIN,
+    input CEOPMODE,
+    input CEP,
+    input RSTA,
+    input RSTB,
+    input RSTC,
+    input RSTD,
+    input RSTM,
+    input RSTCARRYIN,
+    input RSTOPMODE,
+    input RSTP
+);
+
+parameter integer A0REG = 0;
+parameter integer A1REG = 1;
+parameter integer B0REG = 0;
+parameter integer B1REG = 1;
+parameter integer CREG = 1;
+parameter integer DREG = 1;
+parameter integer MREG = 1;
+parameter integer CARRYINREG = 1;
+parameter integer CARRYOUTREG = 1;
+parameter integer OPMODEREG = 1;
+parameter integer PREG = 1;
+parameter CARRYINSEL = "OPMODE5";
+parameter RSTTYPE = "SYNC";
+
+wire signed [35:0] M_MULT;
+wire signed [47:0] P_IN;
+wire signed [17:0] A0_OUT;
+wire signed [17:0] B0_OUT;
+wire signed [17:0] A1_OUT;
+wire signed [17:0] B1_OUT;
+wire signed [17:0] B1_IN;
+wire signed [47:0] C_OUT;
+wire signed [17:0] D_OUT;
+wire signed [7:0] OPMODE_OUT;
+wire CARRYIN_OUT;
+wire CARRYOUT_IN;
+wire CARRYIN_IN;
+reg signed [47:0] XMUX;
+reg signed [47:0] ZMUX;
+
+// The registers.
+reg signed [17:0] A0_REG;
+reg signed [17:0] A1_REG;
+reg signed [17:0] B0_REG;
+reg signed [17:0] B1_REG;
+reg signed [47:0] C_REG;
+reg signed [17:0] D_REG;
+reg signed [35:0] M_REG;
+reg signed [47:0] P_REG;
+reg [7:0] OPMODE_REG;
+reg CARRYIN_REG;
+reg CARRYOUT_REG;
+
+initial begin
+	A0_REG = 0;
+	A1_REG = 0;
+	B0_REG = 0;
+	B1_REG = 0;
+	C_REG = 0;
+	D_REG = 0;
+	M_REG = 0;
+	P_REG = 0;
+	OPMODE_REG = 0;
+	CARRYIN_REG = 0;
+	CARRYOUT_REG = 0;
+end
+
+generate
+
+if (RSTTYPE == "SYNC") begin
+	always @(posedge CLK) begin
+		if (RSTA) begin
+			A0_REG <= 0;
+			A1_REG <= 0;
+		end else if (CEA) begin
+			A0_REG <= A;
+			A1_REG <= A0_OUT;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTB) begin
+			B0_REG <= 0;
+			B1_REG <= 0;
+		end else if (CEB) begin
+			B0_REG <= B;
+			B1_REG <= B1_IN;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTC) begin
+			C_REG <= 0;
+		end else if (CEC) begin
+			C_REG <= C;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTD) begin
+			D_REG <= 0;
+		end else if (CED) begin
+			D_REG <= D;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTM) begin
+			M_REG <= 0;
+		end else if (CEM) begin
+			M_REG <= M_MULT;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTP) begin
+			P_REG <= 0;
+		end else if (CEP) begin
+			P_REG <= P_IN;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTOPMODE) begin
+			OPMODE_REG <= 0;
+		end else if (CEOPMODE) begin
+			OPMODE_REG <= OPMODE;
+		end
+	end
+
+	always @(posedge CLK) begin
+		if (RSTCARRYIN) begin
+			CARRYIN_REG <= 0;
+			CARRYOUT_REG <= 0;
+		end else if (CECARRYIN) begin
+			CARRYIN_REG <= CARRYIN_IN;
+			CARRYOUT_REG <= CARRYOUT_IN;
+		end
+	end
+end else begin
+	always @(posedge CLK, posedge RSTA) begin
+		if (RSTA) begin
+			A0_REG <= 0;
+			A1_REG <= 0;
+		end else if (CEA) begin
+			A0_REG <= A;
+			A1_REG <= A0_OUT;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTB) begin
+		if (RSTB) begin
+			B0_REG <= 0;
+			B1_REG <= 0;
+		end else if (CEB) begin
+			B0_REG <= B;
+			B1_REG <= B1_IN;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTC) begin
+		if (RSTC) begin
+			C_REG <= 0;
+		end else if (CEC) begin
+			C_REG <= C;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTD) begin
+		if (RSTD) begin
+			D_REG <= 0;
+		end else if (CED) begin
+			D_REG <= D;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTM) begin
+		if (RSTM) begin
+			M_REG <= 0;
+		end else if (CEM) begin
+			M_REG <= M_MULT;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTP) begin
+		if (RSTP) begin
+			P_REG <= 0;
+		end else if (CEP) begin
+			P_REG <= P_IN;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTOPMODE) begin
+		if (RSTOPMODE) begin
+			OPMODE_REG <= 0;
+		end else if (CEOPMODE) begin
+			OPMODE_REG <= OPMODE;
+		end
+	end
+
+	always @(posedge CLK, posedge RSTCARRYIN) begin
+		if (RSTCARRYIN) begin
+			CARRYIN_REG <= 0;
+			CARRYOUT_REG <= 0;
+		end else if (CECARRYIN) begin
+			CARRYIN_REG <= CARRYIN_IN;
+			CARRYOUT_REG <= CARRYOUT_IN;
+		end
+	end
+end
+
+endgenerate
+
+// The register enables.
+assign A0_OUT = (A0REG == 1) ? A0_REG : A;
+assign A1_OUT = (A1REG == 1) ? A1_REG : A0_OUT;
+assign B0_OUT = (B0REG == 1) ? B0_REG : B;
+assign B1_OUT = (B1REG == 1) ? B1_REG : B1_IN;
+assign C_OUT = (CREG == 1) ? C_REG : C;
+assign D_OUT = (DREG == 1) ? D_REG : D;
+assign M = (MREG == 1) ? M_REG : M_MULT;
+assign P = (PREG == 1) ? P_REG : P_IN;
+assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE;
+assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN_IN;
+assign CARRYOUT = (CARRYOUTREG == 1) ? CARRYOUT_REG : CARRYOUT_IN;
+assign CARRYOUTF = CARRYOUT;
+
+// The pre-adder.
+wire signed [17:0] PREADDER;
+assign B1_IN = OPMODE_OUT[4] ? PREADDER : B0_OUT;
+assign PREADDER = OPMODE_OUT[6] ? D_OUT - B0_OUT : D_OUT + B0_OUT;
+
+// The multiplier.
+assign M_MULT = A1_OUT * B1_OUT;
+
+// The carry in selection.
+assign CARRYIN_IN = (CARRYINSEL == "OPMODE5") ? OPMODE_OUT[5] : CARRYIN;
+
+// The post-adder inputs.
+always @* begin
+	case (OPMODE_OUT[1:0])
+		2'b00: XMUX <= 0;
+		2'b01: XMUX <= M;
+		2'b10: XMUX <= P;
+		2'b11: XMUX <= {D_OUT[11:0], B1_OUT, A1_OUT};
+		default: XMUX <= 48'hxxxxxxxxxxxx;
+	endcase
+end
+
+always @* begin
+	case (OPMODE_OUT[3:2])
+		2'b00: ZMUX <= 0;
+		2'b01: ZMUX <= PCIN;
+		2'b10: ZMUX <= P;
+		2'b11: ZMUX <= C_OUT;
+		default: ZMUX <= 48'hxxxxxxxxxxxx;
+	endcase
+end
+
+// The post-adder.
+wire signed [48:0] X_EXT;
+wire signed [48:0] Z_EXT;
+assign X_EXT = XMUX;
+assign Z_EXT = ZMUX;
+assign {CARRYOUT_IN, P_IN} = OPMODE_OUT[7] ? (Z_EXT - (X_EXT + CARRYIN_OUT)) : (Z_EXT + X_EXT + CARRYIN_OUT);
+
+// Cascade outputs.
+assign BCOUT = B1_OUT;
+assign PCOUT = P;
+
+endmodule
+
+// TODO: DSP48 (Virtex 4).
+
+// TODO: DSP48E (Virtex 5).
+
+// Virtex 6, Series 7.
+
 module DSP48E1 (
     output [29:0] ACOUT,
     output [17:0] BCOUT,
@@ -1043,3 +1584,5 @@
     endgenerate
 
 endmodule
+
+// TODO: DSP48E2 (Ultrascale).
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index ef7ce85..82e403f 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -204,11 +204,11 @@
     Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}),
 
     # Multipliers and DSP.
-    Cell('MULT18X18'), # Spartan 3
-    Cell('MULT18X18S', port_attrs={'C': ['clkbuf_sink']}), # Spartan 3
-    Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E
-    Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP
-    Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6
+    # Cell('MULT18X18'), # Virtex 2, Spartan 3
+    # Cell('MULT18X18S', port_attrs={'C': ['clkbuf_sink']}), # Spartan 3
+    # Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E
+    # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP
+    # Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6
     Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
     Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5
     #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7
@@ -326,7 +326,7 @@
     Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
     Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
     # I/O.
-    Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
+    # Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
     Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}),
     Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}),
     Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}),
@@ -342,7 +342,7 @@
     Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
     Cell('OBUFDS_DPHY', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
     # Output + tristate.
-    Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}),
+    # Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}),
     Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
     # Pulls.
     Cell('KEEPER'),
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index 72a3b6c..671d16e 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -6218,133 +6218,6 @@
     input SLEEP;
 endmodule
 
-module MULT18X18 (...);
-    output [35:0] P;
-    input [17:0] A;
-    input [17:0] B;
-endmodule
-
-module MULT18X18S (...);
-    output [35:0] P;
-    input [17:0] A;
-    input [17:0] B;
-    (* clkbuf_sink *)
-    input C;
-    input CE;
-    input R;
-endmodule
-
-module MULT18X18SIO (...);
-    parameter integer AREG = 1;
-    parameter integer BREG = 1;
-    parameter B_INPUT = "DIRECT";
-    parameter integer PREG = 1;
-    output [17:0] BCOUT;
-    output [35:0] P;
-    input [17:0] A;
-    input [17:0] B;
-    input [17:0] BCIN;
-    input CEA;
-    input CEB;
-    input CEP;
-    (* clkbuf_sink *)
-    input CLK;
-    input RSTA;
-    input RSTB;
-    input RSTP;
-endmodule
-
-module DSP48A (...);
-    parameter integer A0REG = 0;
-    parameter integer A1REG = 1;
-    parameter integer B0REG = 0;
-    parameter integer B1REG = 1;
-    parameter integer CARRYINREG = 1;
-    parameter CARRYINSEL = "CARRYIN";
-    parameter integer CREG = 1;
-    parameter integer DREG = 1;
-    parameter integer MREG = 1;
-    parameter integer OPMODEREG = 1;
-    parameter integer PREG = 1;
-    parameter RSTTYPE = "SYNC";
-    output [17:0] BCOUT;
-    output CARRYOUT;
-    output [47:0] P;
-    output [47:0] PCOUT;
-    input [17:0] A;
-    input [17:0] B;
-    input [47:0] C;
-    input CARRYIN;
-    input CEA;
-    input CEB;
-    input CEC;
-    input CECARRYIN;
-    input CED;
-    input CEM;
-    input CEOPMODE;
-    input CEP;
-    (* clkbuf_sink *)
-    input CLK;
-    input [17:0] D;
-    input [7:0] OPMODE;
-    input [47:0] PCIN;
-    input RSTA;
-    input RSTB;
-    input RSTC;
-    input RSTCARRYIN;
-    input RSTD;
-    input RSTM;
-    input RSTOPMODE;
-    input RSTP;
-endmodule
-
-module DSP48A1 (...);
-    parameter integer A0REG = 0;
-    parameter integer A1REG = 1;
-    parameter integer B0REG = 0;
-    parameter integer B1REG = 1;
-    parameter integer CARRYINREG = 1;
-    parameter integer CARRYOUTREG = 1;
-    parameter CARRYINSEL = "OPMODE5";
-    parameter integer CREG = 1;
-    parameter integer DREG = 1;
-    parameter integer MREG = 1;
-    parameter integer OPMODEREG = 1;
-    parameter integer PREG = 1;
-    parameter RSTTYPE = "SYNC";
-    output [17:0] BCOUT;
-    output CARRYOUT;
-    output CARRYOUTF;
-    output [35:0] M;
-    output [47:0] P;
-    output [47:0] PCOUT;
-    input [17:0] A;
-    input [17:0] B;
-    input [47:0] C;
-    input CARRYIN;
-    input CEA;
-    input CEB;
-    input CEC;
-    input CECARRYIN;
-    input CED;
-    input CEM;
-    input CEOPMODE;
-    input CEP;
-    (* clkbuf_sink *)
-    input CLK;
-    input [17:0] D;
-    input [7:0] OPMODE;
-    input [47:0] PCIN;
-    input RSTA;
-    input RSTB;
-    input RSTC;
-    input RSTCARRYIN;
-    input RSTD;
-    input RSTM;
-    input RSTOPMODE;
-    input RSTP;
-endmodule
-
 module DSP48 (...);
     parameter integer AREG = 1;
     parameter integer BREG = 1;
@@ -8287,18 +8160,6 @@
     input IB;
 endmodule
 
-module IOBUF (...);
-    parameter integer DRIVE = 12;
-    parameter IBUF_LOW_PWR = "TRUE";
-    parameter IOSTANDARD = "DEFAULT";
-    parameter SLEW = "SLOW";
-    output O;
-    (* iopad_external_pin *)
-    inout IO;
-    input I;
-    input T;
-endmodule
-
 module IOBUF_DCIEN (...);
     parameter integer DRIVE = 12;
     parameter IBUF_LOW_PWR = "TRUE";
@@ -8500,17 +8361,6 @@
     input LPTX_T;
 endmodule
 
-module OBUFT (...);
-    parameter CAPACITANCE = "DONT_CARE";
-    parameter integer DRIVE = 12;
-    parameter IOSTANDARD = "DEFAULT";
-    parameter SLEW = "SLOW";
-    (* iopad_external_pin *)
-    output O;
-    input I;
-    input T;
-endmodule
-
 module OBUFTDS (...);
     parameter CAPACITANCE = "DONT_CARE";
     parameter IOSTANDARD = "DEFAULT";
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
index 13d3c32..62d5016 100644
--- a/techlibs/xilinx/lut_map.v
+++ b/techlibs/xilinx/lut_map.v
@@ -56,8 +56,12 @@
 
   generate
     if (WIDTH == 1) begin
-      LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
-        .I0(A[0]));
+      if (P_LUT == 2'b01) begin
+        INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0]));
+      end else begin
+        LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+          .I0(A[0]));
+      end
     end else
     if (WIDTH == 2) begin
       LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
diff --git a/tests/arch/gowin/.gitignore b/tests/arch/gowin/.gitignore
new file mode 100644
index 0000000..b48f808
--- /dev/null
+++ b/tests/arch/gowin/.gitignore
@@ -0,0 +1,3 @@
+/*.log
+/*.out
+/run-test.mk
diff --git a/tests/arch/gowin/add_sub.ys b/tests/arch/gowin/add_sub.ys
new file mode 100644
index 0000000..9b53dc0
--- /dev/null
+++ b/tests/arch/gowin/add_sub.ys
@@ -0,0 +1,13 @@
+read_verilog ../common/add_sub.v
+hierarchy -top top
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:ALU
+select -assert-count 8 t:OBUF
+select -assert-count 8 t:IBUF
+select -assert-count 1 t:GND
+select -assert-count 1 t:VCC
+select -assert-none t:ALU t:OBUF t:IBUF t:GND t:VCC %% t:* %D
+
diff --git a/tests/arch/gowin/adffs.ys b/tests/arch/gowin/adffs.ys
new file mode 100644
index 0000000..fc7ee01
--- /dev/null
+++ b/tests/arch/gowin/adffs.ys
@@ -0,0 +1,55 @@
+read_verilog ../common/adffs.v
+design -save read
+
+hierarchy -top adff
+proc
+equiv_opt -async2sync -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adff # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:DFFC
+select -assert-count 3 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFFC t:IBUF t:OBUF %% t:* %D
+
+
+design -load read
+hierarchy -top adffn
+proc
+equiv_opt -async2sync -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adffn # Constrain all select calls below inside the top module
+select -assert-count 1 t:DFFC
+select -assert-count 1 t:LUT1
+select -assert-count 3 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFFC t:IBUF t:OBUF t:LUT1 %% t:* %D
+
+
+design -load read
+hierarchy -top dffs
+proc
+equiv_opt -async2sync -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffs # Constrain all select calls below inside the top module
+select -assert-count 1 t:DFFS
+select -assert-count 4 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFFS t:IBUF t:OBUF %% t:* %D
+
+
+design -load read
+hierarchy -top ndffnr
+proc
+equiv_opt -async2sync -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd ndffnr # Constrain all select calls below inside the top module
+select -assert-count 1 t:DFFNR
+select -assert-count 1 t:LUT1
+select -assert-count 4 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFFNR t:IBUF t:OBUF t:LUT1 %% t:* %D
diff --git a/tests/arch/gowin/counter.ys b/tests/arch/gowin/counter.ys
new file mode 100644
index 0000000..920479d
--- /dev/null
+++ b/tests/arch/gowin/counter.ys
@@ -0,0 +1,15 @@
+read_verilog ../common/counter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 8 t:DFFC
+select -assert-count 8 t:ALU
+select -assert-count 1 t:GND
+select -assert-count 1 t:VCC
+select -assert-count 2 t:IBUF
+select -assert-count 8 t:OBUF
+select -assert-none t:DFFC t:ALU t:GND t:VCC t:IBUF t:OBUF %% t:* %D
diff --git a/tests/arch/gowin/dffs.ys b/tests/arch/gowin/dffs.ys
new file mode 100644
index 0000000..9c01221
--- /dev/null
+++ b/tests/arch/gowin/dffs.ys
@@ -0,0 +1,25 @@
+read_verilog ../common/dffs.v
+design -save read
+
+hierarchy -top dff
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dff # Constrain all select calls below inside the top module
+select -assert-count 1 t:DFF
+select -assert-count 2 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFF t:IBUF t:OBUF %% t:* %D
+
+design -load read
+hierarchy -top dffe
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffe # Constrain all select calls below inside the top module
+select -assert-count 1 t:DFFE
+select -assert-count 3 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:DFFE t:IBUF t:OBUF %% t:* %D
diff --git a/tests/arch/gowin/fsm.ys b/tests/arch/gowin/fsm.ys
new file mode 100644
index 0000000..ce45045
--- /dev/null
+++ b/tests/arch/gowin/fsm.ys
@@ -0,0 +1,11 @@
+read_verilog ../common/fsm.v
+hierarchy -top fsm
+proc
+flatten
+
+equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin # equivalency check
+miter -equiv -make_assert -flatten gold gate miter
+sat -verify -show-all -dump_vcd x.vcd -prove-asserts -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
+
+#design -load postopt
+#shell
diff --git a/tests/arch/gowin/logic.ys b/tests/arch/gowin/logic.ys
new file mode 100644
index 0000000..d2b9e45
--- /dev/null
+++ b/tests/arch/gowin/logic.ys
@@ -0,0 +1,13 @@
+read_verilog ../common/logic.v
+hierarchy -top top
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:LUT1
+select -assert-count 6 t:LUT2
+select -assert-count 2 t:LUT4
+select -assert-count 8 t:IBUF
+select -assert-count 10 t:OBUF
+select -assert-none t:LUT1 t:LUT2 t:LUT4 t:IBUF t:OBUF %% t:* %D
diff --git a/tests/arch/gowin/memory.ys b/tests/arch/gowin/memory.ys
new file mode 100644
index 0000000..8f88cdd
--- /dev/null
+++ b/tests/arch/gowin/memory.ys
@@ -0,0 +1,18 @@
+read_verilog ../common/memory.v
+hierarchy -top top
+proc
+memory -nomap
+equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin
+memory
+opt -full
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+#ERROR: Called with -verify and proof did fail!
+#sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
+sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
+
+design -load postopt
+cd top
+select -assert-count 8 t:RAM16S4
+# other logic present that is not simple
+#select -assert-none t:RAM16S4 %% t:* %D
diff --git a/tests/arch/gowin/mux.ys b/tests/arch/gowin/mux.ys
new file mode 100644
index 0000000..afad29a
--- /dev/null
+++ b/tests/arch/gowin/mux.ys
@@ -0,0 +1,49 @@
+read_verilog ../common/mux.v
+design -save read
+
+hierarchy -top mux2
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux2 # Constrain all select calls below inside the top module
+select -assert-count 1 t:LUT3
+select -assert-count 3 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:LUT3 t:IBUF t:OBUF %% t:* %D
+
+design -load read
+hierarchy -top mux4
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux4 # Constrain all select calls below inside the top module
+select -assert-count 4 t:LUT4
+select -assert-count 2 t:MUX2_LUT5
+select -assert-count 1 t:MUX2_LUT6
+select -assert-count 6 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
+
+design -load read
+hierarchy -top mux8
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux8 # Constrain all select calls below inside the top module
+select -assert-count 11 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
+
+design -load read
+hierarchy -top mux16
+proc
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux16 # Constrain all select calls below inside the top module
+select -assert-count 20 t:IBUF
+select -assert-count 1 t:OBUF
+
+select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:MUX2_LUT6 t:MUX2_LUT7 t:MUX2_LUT8 t:IBUF t:OBUF %% t:* %D
diff --git a/tests/arch/gowin/run-test.sh b/tests/arch/gowin/run-test.sh
new file mode 100755
index 0000000..bf19b88
--- /dev/null
+++ b/tests/arch/gowin/run-test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -e
+{
+echo "all::"
+for x in *.ys; do
+	echo "all:: run-$x"
+	echo "run-$x:"
+	echo "	@echo 'Running $x..'"
+	echo "	@../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
+done
+for s in *.sh; do
+	if [ "$s" != "run-test.sh" ]; then
+		echo "all:: run-$s"
+		echo "run-$s:"
+		echo "	@echo 'Running $s..'"
+		echo "	@bash $s"
+	fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/arch/gowin/shifter.ys b/tests/arch/gowin/shifter.ys
new file mode 100644
index 0000000..b43b1e8
--- /dev/null
+++ b/tests/arch/gowin/shifter.ys
@@ -0,0 +1,12 @@
+read_verilog ../common/shifter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 8  t:DFF
+select -assert-count 2  t:IBUF
+select -assert-count 8  t:OBUF
+select -assert-none t:DFF t:IBUF t:OBUF %% t:* %D
diff --git a/tests/arch/gowin/tribuf.ys b/tests/arch/gowin/tribuf.ys
new file mode 100644
index 0000000..5855b9d
--- /dev/null
+++ b/tests/arch/gowin/tribuf.ys
@@ -0,0 +1,13 @@
+read_verilog ../common/tribuf.v
+hierarchy -top tristate
+proc
+tribuf
+flatten
+synth
+equiv_opt -assert -map +/gowin/cells_sim.v -map +/simcells.v synth_gowin # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd tristate # Constrain all select calls below inside the top module
+#Internal cell type used. Need support it.
+select -assert-count 1 t:TBUF
+select -assert-count 2 t:IBUF
+select -assert-none t:TBUF t:IBUF %% t:* %D
diff --git a/tests/arch/xilinx/adffs.ys b/tests/arch/xilinx/adffs.ys
index 12c3441..e73bfe0 100644
--- a/tests/arch/xilinx/adffs.ys
+++ b/tests/arch/xilinx/adffs.ys
@@ -20,9 +20,9 @@
 cd adffn # Constrain all select calls below inside the top module
 select -assert-count 1 t:BUFG
 select -assert-count 1 t:FDCE
-select -assert-count 1 t:LUT1
+select -assert-count 1 t:INV
 
-select -assert-none t:BUFG t:FDCE t:LUT1 %% t:* %D
+select -assert-none t:BUFG t:FDCE t:INV %% t:* %D
 
 
 design -load read
diff --git a/tests/arch/xilinx/counter.ys b/tests/arch/xilinx/counter.ys
index 57b645d..604acdb 100644
--- a/tests/arch/xilinx/counter.ys
+++ b/tests/arch/xilinx/counter.ys
@@ -8,7 +8,7 @@
 
 select -assert-count 1 t:BUFG
 select -assert-count 8 t:FDCE
-select -assert-count 1 t:LUT1
+select -assert-count 1 t:INV
 select -assert-count 7 t:MUXCY
 select -assert-count 8 t:XORCY
-select -assert-none t:BUFG t:FDCE t:LUT1 t:MUXCY t:XORCY %% t:* %D
+select -assert-none t:BUFG t:FDCE t:INV t:MUXCY t:XORCY %% t:* %D
diff --git a/tests/arch/xilinx/latches.ys b/tests/arch/xilinx/latches.ys
index fe7887e..c87a8e3 100644
--- a/tests/arch/xilinx/latches.ys
+++ b/tests/arch/xilinx/latches.ys
@@ -18,9 +18,9 @@
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd latchn # Constrain all select calls below inside the top module
 select -assert-count 1 t:LDCE
-select -assert-count 1 t:LUT1
+select -assert-count 1 t:INV
 
-select -assert-none t:LDCE t:LUT1 %% t:* %D
+select -assert-none t:LDCE t:INV %% t:* %D
 
 
 design -load read
diff --git a/tests/arch/xilinx/logic.ys b/tests/arch/xilinx/logic.ys
index c0f6da3..d5b5c1a 100644
--- a/tests/arch/xilinx/logic.ys
+++ b/tests/arch/xilinx/logic.ys
@@ -5,7 +5,7 @@
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd top # Constrain all select calls below inside the top module
 
-select -assert-count 1 t:LUT1
+select -assert-count 1 t:INV
 select -assert-count 6 t:LUT2
 select -assert-count 2 t:LUT4
-select -assert-none t:LUT1 t:LUT2 t:LUT4 %% t:* %D
+select -assert-none t:INV t:LUT2 t:LUT4 %% t:* %D
diff --git a/tests/opt/bug1525.ys b/tests/opt/bug1525.ys
new file mode 100644
index 0000000..972bc0a
--- /dev/null
+++ b/tests/opt/bug1525.ys
@@ -0,0 +1,13 @@
+read_verilog << EOF
+module top(...);
+input A1, A2, B, S;
+output O;
+
+assign O = S ? (A1 & B) : (A2 & B);
+
+endmodule
+EOF
+
+simplemap
+opt_share
+dump
diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v
index 64b625e..4d5879e 100644
--- a/tests/simple_abc9/abc9.v
+++ b/tests/simple_abc9/abc9.v
@@ -218,12 +218,6 @@
 endmodule
 
 // Citation: https://github.com/alexforencich/verilog-ethernet
-// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test022" abc9.v -q
-// returns before b4321a31
-//   Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [7] is used but has no
-//   driver.
-//   Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [3] is used but has no
-//   driver.
 module abc9_test022
 (
     input  wire        clk,
@@ -237,9 +231,6 @@
 endmodule
 
 // Citation: https://github.com/riscv/riscv-bitmanip
-// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test023" abc9.v -q
-// returns before 14233843
-//   Warning: Wire abc9_test023.\dout [1] is used but has no driver.
 module abc9_test023 #(
 	parameter integer N = 2,
 	parameter integer M = 2
diff --git a/tests/techmap/clkbufmap.ys b/tests/techmap/clkbufmap.ys
index f127786..b81a35e 100644
--- a/tests/techmap/clkbufmap.ys
+++ b/tests/techmap/clkbufmap.ys
@@ -4,6 +4,7 @@
 module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule
 module latch (input e, d, output q); endmodule
 module clkgen (output o); endmodule
+module inv ((* clkbuf_inv = "i" *) output o, input i); endmodule
 
 module top(input clk1, clk2, clk3, d, e, output [4:0] q);
 wire clk4, clk5, clk6;
@@ -17,12 +18,18 @@
 endmodule
 
 module sub(output sclk4, output sclk5, output sclk6, input sd, output sq);
+wire sclk7, sclk8, sclk9;
+wire siq;
 wire tmp;
 clkgen s7(.o(sclk4));
 clkgen s8(.o(sclk5));
 clkgen s9(.o(tmp));
-clkbuf s10(.i(tmp), .o(sclk6));
-dff s11(.clk(sclk4), .d(sd), .q(sq));
+clkbuf s10(.i(tmp), .o(sclk7));
+dff s11(.clk(sclk4), .d(sd), .q(siq));
+inv s15(.i(sclk7), .o(sclk6));
+clkgen s12(.o(sclk8));
+inv s13(.o(sclk9), .i(sclk8));
+dff s14(.clk(sclk9), .d(siq), .q(sq));
 endmodule
 EOT
 
@@ -34,7 +41,7 @@
 design -load ref
 clkbufmap -buf clkbuf o:i
 select -assert-count 3 top/t:clkbuf
-select -assert-count 2 sub/t:clkbuf
+select -assert-count 3 sub/t:clkbuf
 select -set clk1 w:clk1 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf'
 select -assert-count 1 @clk1                        # Check there is one such fanout
 select -assert-count 1 @clk1 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout
@@ -51,6 +58,10 @@
 select -assert-count 1 @sclk4
 select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i
 select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i
+select -set sclk8 w:sclk8 %a %ci t:clkbuf %i
+select -assert-count 1 @sclk8
+select -assert-count 1 @sclk8 %x:+[o] %co c:s13 %i
+select -assert-count 1 @sclk8 %x:+[i] %ci c:s12 %i
 
 # ----------------------
 
@@ -72,7 +83,7 @@
 setattr -set buffer_type "bufg" w:clk2
 clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d
 select -assert-count 3 top/t:clkbuf
-select -assert-count 2 sub/t:clkbuf
+select -assert-count 3 sub/t:clkbuf
 select -set clk1 w:clk1 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf'
 select -assert-count 1 @clk1                        # Check there is one such fanout
 select -assert-count 1 @clk1 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout
@@ -93,4 +104,4 @@
 select -assert-count 0 w:clk1 %a %co t:clkbuf %i
 select -assert-count 0 w:clk2 %a %co t:clkbuf %i
 select -assert-count 0 top/t:clkbuf
-select -assert-count 1 sub/t:clkbuf
+select -assert-count 2 sub/t:clkbuf
diff --git a/tests/various/bug1462.ys b/tests/various/bug1462.ys
new file mode 100644
index 0000000..15cab51
--- /dev/null
+++ b/tests/various/bug1462.ys
@@ -0,0 +1,11 @@
+read_verilog << EOF
+module top(...);
+input wire [31:0] A;
+output wire [31:0] P;
+
+assign P = A * 32'h12300000;
+
+endmodule
+EOF
+
+synth_xilinx
diff --git a/tests/various/bug1480.ys b/tests/various/bug1480.ys
new file mode 100644
index 0000000..84faea0
--- /dev/null
+++ b/tests/various/bug1480.ys
@@ -0,0 +1,18 @@
+read_verilog << EOF
+module top(...);
+
+input signed [17:0] A;
+input signed [17:0] B;
+output X;
+output Y;
+
+wire [35:0] P;
+assign P = A * B;
+
+assign X = P[0];
+assign Y = P[35];
+
+endmodule
+EOF
+
+synth_xilinx
diff --git a/tests/various/svalways.sh b/tests/various/svalways.sh
new file mode 100755
index 0000000..2cc09f8
--- /dev/null
+++ b/tests/various/svalways.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+trap 'echo "ERROR in svalways.sh" >&2; exit 1' ERR
+
+# Good case
+../../yosys -f "verilog -sv" -qp proc - <<EOT
+module top(input clk, en, d, output reg p, q, r);
+
+always_ff @(posedge clk)
+	p <= d;
+
+always_comb
+	q = ~d;
+
+always_latch
+	if (en) r = d;
+
+endmodule
+EOT
+
+# Incorrect always_comb syntax
+((../../yosys -f "verilog -sv" -qp proc -|| true) <<EOT
+module top(input d, output reg q);
+
+always_comb @(d)
+	q = ~d;
+
+endmodule
+EOT
+) 2>&1 | grep -F "<stdin>:3: ERROR: syntax error, unexpected '@'" > /dev/null
+
+# Incorrect use of always_comb
+((../../yosys -f "verilog -sv" -qp proc -|| true) <<EOT
+module top(input en, d, output reg q);
+
+always_comb
+	if (en) q = d;
+
+endmodule
+EOT
+) 2>&1 | grep -F "ERROR: Latch inferred for signal \`\\top.\\q' from always_comb process" > /dev/null
+
+# Incorrect use of always_latch
+((../../yosys -f "verilog -sv" -qp proc -|| true) <<EOT
+module top(input en, d, output reg q);
+
+always_latch
+	q = !d;
+
+endmodule
+EOT
+) 2>&1 | grep -F "ERROR: No latch inferred for signal \`\\top.\\q' from always_latch process" > /dev/null
+
+# Incorrect use of always_ff
+((../../yosys -f "verilog -sv" -qp proc -|| true) <<EOT
+module top(input en, d, output reg q);
+
+always_ff @(*)
+	q = !d;
+
+endmodule
+EOT
+) 2>&1 | grep -F "ERROR: Found non edge/level sensitive event in always_ff process" > /dev/null