diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 32410a651..0917ecba6 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -23,7 +23,11 @@
 #include "kernel/celltypes.h"
 #include "kernel/cellaigs.h"
 #include "kernel/log.h"
+#include <algorithm>
 #include <string>
+#include <regex>
+#include <vector>
+#include <cmath>
 
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
@@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0;
 static const FDirection FD_IN = 0x1;
 static const FDirection FD_OUT = 0x2;
 static const FDirection FD_INOUT = 0x3;
+static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
 
 // Get a port direction with respect to a specific module.
 FDirection getPortFDirection(IdString id, Module *module)
@@ -173,6 +178,26 @@ struct FirrtlWorker
 	void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
 	{
 		std::string cell_type = fid(cell->type);
+		std::string instanceOf;
+		// If this is a parameterized module, its parent module is encoded in the cell type
+		if (cell->type.substr(0, 8) == "$paramod")
+		{
+			std::string::iterator it;
+			for (it = cell_type.begin(); it < cell_type.end(); it++)
+			{
+				switch (*it) {
+					case '\\': /* FALL_THROUGH */
+					case '=': /* FALL_THROUGH */
+					case '\'': /* FALL_THROUGH */
+					case '$': instanceOf.append("_"); break;
+					default: instanceOf.append(1, *it); break;
+				}
+			}
+		}
+		else
+		{
+			instanceOf = cell_type;
+		}
 
 		std::string cell_name = cellname(cell);
 		std::string cell_name_comment;
@@ -182,7 +207,13 @@ struct FirrtlWorker
 			cell_name_comment = "";
 		// Find the module corresponding to this instance.
 		auto instModule = design->module(cell->type);
-		wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str()));
+		// If there is no instance for this, just return.
+		if (instModule == NULL)
+		{
+			log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
+			return;
+		}
+		wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
 
 		for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
 			if (it->second.size() > 0) {
@@ -194,20 +225,20 @@ struct FirrtlWorker
 				std::string source, sink;
 				switch (dir) {
 					case FD_INOUT:
-						log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second));
+						log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
 					case FD_OUT:
 						source = firstName;
 						sink = secondName;
 						break;
 					case FD_NODIRECTION:
-						log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second));
+						log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
 						/* FALL_THROUGH */
 					case FD_IN:
 						source = secondName;
 						sink = firstName;
 						break;
 					default:
-						log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir);
+						log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
 						break;
 				}
 				wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
@@ -217,6 +248,20 @@ struct FirrtlWorker
 
 	}
 
+	// Given an expression for a shift amount, and a maximum width,
+	//  generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
+	std::string gen_dshl(const string b_expr, const int b_padded_width)
+	{
+		string result = b_expr;
+		if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
+			int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
+			string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
+			// Deal with the difference in semantics between FIRRTL and verilog
+			result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
+		}
+		return result;
+	}
+
 	void run()
 	{
 		f << stringf("  module %s:\n", make_id(module->name));
@@ -225,6 +270,12 @@ struct FirrtlWorker
 		for (auto wire : module->wires())
 		{
 			const auto wireName = make_id(wire->name);
+			// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
+			if (wire->attributes.count("\\init")) {
+				log_warning("Initial value (%s) for (%s.%s) not supported\n",
+							wire->attributes.at("\\init").as_string().c_str(),
+							log_id(module), log_id(wire));
+			}
 			if (wire->port_id)
 			{
 				if (wire->port_input && wire->port_output)
@@ -240,7 +291,8 @@ struct FirrtlWorker
 
 		for (auto cell : module->cells())
 		{
-		  // Is this cell is a module instance?
+			bool extract_y_bits = false;		// Assume no extraction of final bits will be required.
+		    // Is this cell is a module instance?
 			if (cell->type[0] != '$')
 			{
 				process_instance(cell, wire_exprs);
@@ -264,21 +316,21 @@ struct FirrtlWorker
 				}
 
 				string primop;
-                                bool always_uint = false;
+				bool always_uint = false;
 				if (cell->type == "$not") primop = "not";
-				if (cell->type == "$neg") primop = "neg";
-				if (cell->type == "$logic_not") {
+				else if (cell->type == "$neg") primop = "neg";
+				else if (cell->type == "$logic_not") {
                                         primop = "eq";
                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str());
                                 }
-				if (cell->type == "$reduce_and") primop = "andr";
-				if (cell->type == "$reduce_or") primop = "orr";
-				if (cell->type == "$reduce_xor") primop = "xorr";
-				if (cell->type == "$reduce_xnor") {
+				else if (cell->type == "$reduce_and") primop = "andr";
+				else if (cell->type == "$reduce_or") primop = "orr";
+				else if (cell->type == "$reduce_xor") primop = "xorr";
+				else if (cell->type == "$reduce_xnor") {
                                         primop = "not";
                                         a_expr = stringf("xorr(%s)", a_expr.c_str());
                                 }
-				if (cell->type == "$reduce_bool") {
+				else if (cell->type == "$reduce_bool") {
 					primop = "neq";
 					// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
 					bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
@@ -297,14 +349,15 @@ struct FirrtlWorker
 				continue;
 			}
 			if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
-                                        "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
-                                        "$logic_and", "$logic_or"))
+							  "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
+							  "$logic_and", "$logic_or"))
 			{
 				string y_id = make_id(cell->name);
 				bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
 				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				string b_expr = make_expr(cell->getPort("\\B"));
+				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
 
 				if (cell->parameters.at("\\A_SIGNED").as_bool()) {
@@ -315,67 +368,93 @@ struct FirrtlWorker
 					if (cell->parameters.at("\\B_SIGNED").as_bool()) {
 						b_expr = "asSInt(" + b_expr + ")";
 					}
-					b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+					if (b_padded_width < y_width) {
+						auto b_sig = cell->getPort("\\B");
+						b_padded_width = y_width;
+					}
 				}
 
-				a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+				auto a_sig = cell->getPort("\\A");
 
 				if (cell->parameters.at("\\A_SIGNED").as_bool()  & (cell->type == "$shr")) {
 					a_expr = "asUInt(" + a_expr + ")";
 				}
 
 				string primop;
-                                bool always_uint = false;
+				bool always_uint = false;
 				if (cell->type == "$add") primop = "add";
-				if (cell->type == "$sub") primop = "sub";
-				if (cell->type == "$mul") primop = "mul";
-				if (cell->type == "$div") primop = "div";
-				if (cell->type == "$mod") primop = "rem";
-				if (cell->type == "$and") {
+				else if (cell->type == "$sub") primop = "sub";
+				else if (cell->type == "$mul") primop = "mul";
+				else if (cell->type == "$div") primop = "div";
+				else if (cell->type == "$mod") primop = "rem";
+				else if (cell->type == "$and") {
                                         primop = "and";
                                         always_uint = true;
                                 }
-				if (cell->type == "$or" ) {
+				else if (cell->type == "$or" ) {
                                         primop =  "or";
                                         always_uint = true;
                                 }
-				if (cell->type == "$xor") {
+				else if (cell->type == "$xor") {
                                         primop = "xor";
                                         always_uint = true;
                                 }
-				if ((cell->type == "$eq") | (cell->type == "$eqx")) {
+				else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
                                         primop = "eq";
                                         always_uint = true;
                                 }
-				if ((cell->type == "$ne") | (cell->type == "$nex")) {
+				else if ((cell->type == "$ne") | (cell->type == "$nex")) {
                                         primop = "neq";
                                         always_uint = true;
                                 }
-				if (cell->type == "$gt") {
+				else if (cell->type == "$gt") {
                                         primop = "gt";
                                         always_uint = true;
                                 }
-				if (cell->type == "$ge") {
+				else if (cell->type == "$ge") {
                                         primop = "geq";
                                         always_uint = true;
                                 }
-				if (cell->type == "$lt") {
+				else if (cell->type == "$lt") {
                                         primop = "lt";
                                         always_uint = true;
                                 }
-				if (cell->type == "$le") {
+				else if (cell->type == "$le") {
                                         primop = "leq";
                                         always_uint = true;
                                 }
-				if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
-				if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
-				if ((cell->type == "$logic_and")) {
+				else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
+					// FIRRTL will widen the result (y) by the amount of the shift.
+					// We'll need to offset this by extracting the un-widened portion as Verilog would do.
+					extract_y_bits = true;
+					// Is the shift amount constant?
+					auto b_sig = cell->getPort("\\B");
+					if (b_sig.is_fully_const()) {
+						primop = "shl";
+					} else {
+						primop = "dshl";
+						// Convert from FIRRTL left shift semantics.
+						b_expr = gen_dshl(b_expr, b_padded_width);
+					}
+				}
+				else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
+					// We don't need to extract a specific range of bits.
+					extract_y_bits = false;
+					// Is the shift amount constant?
+					auto b_sig = cell->getPort("\\B");
+					if (b_sig.is_fully_const()) {
+						primop = "shr";
+					} else {
+						primop = "dshr";
+					}
+				}
+				else if ((cell->type == "$logic_and")) {
                                         primop = "and";
                                         a_expr = "neq(" + a_expr + ", UInt(0))";
                                         b_expr = "neq(" + b_expr + ", UInt(0))";
                                         always_uint = true;
                                 }
-				if ((cell->type == "$logic_or")) {
+				else if ((cell->type == "$logic_or")) {
                                         primop = "or";
                                         a_expr = "neq(" + a_expr + ", UInt(0))";
                                         b_expr = "neq(" + b_expr + ", UInt(0))";
@@ -388,6 +467,11 @@ struct FirrtlWorker
 
 				string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
 
+				// Deal with FIRRTL's "shift widens" semantics
+				if (extract_y_bits) {
+					expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+				}
+
 				if ((is_signed && !always_uint) || cell->type.in("$sub"))
 					expr = stringf("asUInt(%s)", expr.c_str());
 
@@ -513,7 +597,65 @@ struct FirrtlWorker
 				continue;
 			}
 
-			log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+			// This may be a parameterized module - paramod.
+			if (cell->type.substr(0, 8) == "$paramod")
+			{
+				process_instance(cell, wire_exprs);
+				continue;
+			}
+			if (cell->type == "$shiftx") {
+				// assign y = a[b +: y_width];
+				// We'll extract the correct bits as part of the primop.
+
+				string y_id = make_id(cell->name);
+				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
+				string a_expr = make_expr(cell->getPort("\\A"));
+				// Get the initial bit selector
+				string b_expr = make_expr(cell->getPort("\\B"));
+				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+				if (cell->getParam("\\B_SIGNED").as_bool()) {
+					// Use validif to constrain the selection (test the sign bit)
+					auto b_string = b_expr.c_str();
+					int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
+					b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
+				}
+				string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
+
+				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str()));
+				register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+				continue;
+			}
+			if (cell->type == "$shift") {
+				// assign y = a >> b;
+				//  where b may be negative
+
+				string y_id = make_id(cell->name);
+				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
+				string a_expr = make_expr(cell->getPort("\\A"));
+				string b_expr = make_expr(cell->getPort("\\B"));
+				auto b_string = b_expr.c_str();
+				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
+				string expr;
+				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+				if (cell->getParam("\\B_SIGNED").as_bool()) {
+					// We generate a left or right shift based on the sign of b.
+					std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
+					std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+					expr = stringf("mux(%s < 0, %s, %s)",
+									 b_string,
+									 dshl.c_str(),
+									 dshr.c_str()
+									 );
+				} else {
+					expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+				}
+				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str()));
+				register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+				continue;
+			}
+			log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
 		}
 
 		for (auto conn : module->connections())
@@ -629,38 +771,53 @@ struct FirrtlBackend : public Backend {
 		log("    write_firrtl [options] [filename]\n");
 		log("\n");
 		log("Write a FIRRTL netlist of the current design.\n");
+		log("The following commands are executed by this command:\n");
+		log("        pmuxtree\n");
 		log("\n");
 	}
 	void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 	{
-		size_t argidx;
-		for (argidx = 1; argidx < args.size(); argidx++)
-		{
-			// if (args[argidx] == "-aig") {
-			// 	aig_mode = true;
-			// 	continue;
-			// }
-			break;
+		size_t argidx = args.size();	// We aren't expecting any arguments.
+
+		// If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
+		if (filename == "") {
+			if (argidx > 0 && args[argidx - 1][0] != '-') {
+				// extra_args and friends need to see this argument.
+				argidx -= 1;
+				filename = args[argidx];
+			}
 		}
 		extra_args(f, filename, args, argidx);
 
+		if (!design->full_selection())
+			log_cmd_error("This command only operates on fully selected designs!\n");
+
 		log_header(design, "Executing FIRRTL backend.\n");
+		log_push();
 
-		Module *top = design->top_module();
-
-		if (top == nullptr)
-			log_error("No top module found!\n");
+		Pass::call(design, stringf("pmuxtree"));
 
 		namecache.clear();
 		autoid_counter = 0;
 
+		// Get the top module, or a reasonable facsimile - we need something for the circuit name.
+		Module *top = design->top_module();
+		Module *last = nullptr;
+		// Generate module and wire names.
 		for (auto module : design->modules()) {
 			make_id(module->name);
+			last = module;
+			if (top == nullptr && module->get_bool_attribute("\\top")) {
+				top = module;
+			}
 			for (auto wire : module->wires())
 				if (wire->port_id)
 					make_id(wire->name);
 		}
 
+		if (top == nullptr)
+			top = last;
+
 		*f << stringf("circuit %s:\n", make_id(top->name));
 
 		for (auto module : design->modules())
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 7b3a60e61..4b5a13941 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -1065,43 +1065,46 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 			use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
 			rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
 			rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
+			if (use_rd_clk)
 			{
-				std::ostringstream os;
-				dump_sigspec(os, sig_rd_clk);
-				clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
-				if( clk_to_lof_body.count(clk_domain_str) == 0 )
-					clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
-			}
-			if (use_rd_clk && !rd_transparent)
-			{
-				// for clocked read ports make something like:
-				//   reg [..] temp_id;
-				//   always @(posedge clk)
-				//      if (rd_en) temp_id <= array_reg[r_addr];
-				//   assign r_data = temp_id;
-				std::string temp_id = next_auto_id();
-				lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
 				{
 					std::ostringstream os;
-					if (sig_rd_en != RTLIL::SigBit(true))
+					dump_sigspec(os, sig_rd_clk);
+					clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
+					if( clk_to_lof_body.count(clk_domain_str) == 0 )
+						clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
+				}
+				if (!rd_transparent)
+				{
+					// for clocked read ports make something like:
+					//   reg [..] temp_id;
+					//   always @(posedge clk)
+					//      if (rd_en) temp_id <= array_reg[r_addr];
+					//   assign r_data = temp_id;
+					std::string temp_id = next_auto_id();
+					lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
 					{
-						os << stringf("if (");
-						dump_sigspec(os, sig_rd_en);
-						os << stringf(") ");
+						std::ostringstream os;
+						if (sig_rd_en != RTLIL::SigBit(true))
+						{
+							os << stringf("if (");
+							dump_sigspec(os, sig_rd_en);
+							os << stringf(") ");
+						}
+						os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
+						dump_sigspec(os, sig_rd_addr);
+						os << stringf("];\n");
+						clk_to_lof_body[clk_domain_str].push_back(os.str());
+					}
+					{
+						std::ostringstream os;
+						dump_sigspec(os, sig_rd_data);
+						std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
+						clk_to_lof_body[""].push_back(line);
 					}
-					os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
-					dump_sigspec(os, sig_rd_addr);
-					os << stringf("];\n");
-					clk_to_lof_body[clk_domain_str].push_back(os.str());
 				}
+				else
 				{
-					std::ostringstream os;
-					dump_sigspec(os, sig_rd_data);
-					std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
-					clk_to_lof_body[""].push_back(line);
-				}
-			} else {
-				if (rd_transparent) {
 					// for rd-transparent read-ports make something like:
 					//   reg [..] temp_id;
 					//   always @(posedge clk)
@@ -1121,15 +1124,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 						std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
 						clk_to_lof_body[""].push_back(line);
 					}
-				} else {
-					// for non-clocked read-ports make something like:
-					//   assign r_data = array_reg[r_addr];
-					std::ostringstream os, os2;
-					dump_sigspec(os, sig_rd_data);
-					dump_sigspec(os2, sig_rd_addr);
-					std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
-					clk_to_lof_body[""].push_back(line);
 				}
+			} else {
+				// for non-clocked read-ports make something like:
+				//   assign r_data = array_reg[r_addr];
+				std::ostringstream os, os2;
+				dump_sigspec(os, sig_rd_data);
+				dump_sigspec(os2, sig_rd_addr);
+				std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
+				clk_to_lof_body[""].push_back(line);
 			}
 		}
 
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 9531dd356..e66625228 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -942,16 +942,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 
 	// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
 	case AST_CONSTANT:
+	case AST_REALVALUE:
 		{
 			if (width_hint < 0)
 				detectSignWidth(width_hint, sign_hint);
-
 			is_signed = sign_hint;
-			return RTLIL::SigSpec(bitsAsConst());
-		}
 
-	case AST_REALVALUE:
-		{
+			if (type == AST_CONSTANT)
+				return RTLIL::SigSpec(bitsAsConst());
+
 			RTLIL::SigSpec sig = realAsConst(width_hint);
 			log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
 			return sig;
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 3a6ac2746..048daee55 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -72,7 +72,8 @@ struct FsmOpt
 
 			new_transition_table.swap(fsm_data.transition_table);
 			new_state_table.swap(fsm_data.state_table);
-			fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
+			if (fsm_data.reset_state != -1)
+				fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
 		}
 	}
 
diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh
index d5708c456..c22ab6928 100755
--- a/tests/asicworld/run-test.sh
+++ b/tests/asicworld/run-test.sh
@@ -11,4 +11,4 @@ do
 done
 shift "$((OPTIND-1))"
 
-exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS="-e" *.v
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS+="-e" *.v
diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl
new file mode 100644
index 000000000..c782a2bd6
--- /dev/null
+++ b/tests/asicworld/xfirrtl
@@ -0,0 +1,24 @@
+# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures.
+code_hdl_models_arbiter.v	error: reg rst; cannot be driven by primitives or continuous assignment.
+code_hdl_models_clk_div_45.v	yosys issue: 2nd PMUXTREE pass yields: ERROR: Negative edge clock on FF clk_div_45.$procdff$49.
+code_hdl_models_d_ff_gates.v	combinational loop
+code_hdl_models_d_latch_gates.v	combinational loop
+code_hdl_models_dff_async_reset.v	$adff
+code_hdl_models_tff_async_reset.v	$adff
+code_hdl_models_uart.v	$adff
+code_specman_switch_fabric.v	subfield assignment (bits() <= ...)
+code_tidbits_asyn_reset.v	$adff
+code_tidbits_reg_seq_example.v	$adff
+code_verilog_tutorial_always_example.v	empty module
+code_verilog_tutorial_escape_id.v	make_id issues (name begins with a digit)
+code_verilog_tutorial_explicit.v	firrtl backend bug (empty module)
+code_verilog_tutorial_first_counter.v	error: reg rst; cannot be driven by primitives or continuous assignment.
+code_verilog_tutorial_fsm_full.v	error: reg reset; cannot be driven by primitives or continuous assignment.
+code_verilog_tutorial_if_else.v	empty module (everything is under 'always @ (posedge clk)')
+[code_verilog_tutorial_n_out_primitive.v	empty module
+code_verilog_tutorial_parallel_if.v	empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_simple_function.v	empty module (no hardware)
+code_verilog_tutorial_simple_if.v	empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_task_global.v	empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_v2k_reg.v		empty module
+code_verilog_tutorial_which_clock.v	 $adff
diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl
new file mode 100644
index 000000000..00e89b389
--- /dev/null
+++ b/tests/simple/xfirrtl
@@ -0,0 +1,26 @@
+# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures.
+arraycells.v	inst id[0] of
+dff_different_styles.v
+generate.v	combinational loop
+hierdefparam.v	inst id[0] of
+i2c_master_tests.v   $adff
+macros.v	drops modules
+mem2reg.v	drops modules
+mem_arst.v	$adff
+memory.v	$adff
+multiplier.v	inst id[0] of
+muxtree.v	drops modules
+omsp_dbg_uart.v	$adff
+operators.v	$pow
+paramods.v	subfield assignment (bits() <= ...)
+partsel.v	drops modules
+process.v	drops modules
+realexpr.v	drops modules
+scopes.v	original verilog issues ( -x where x isn't declared signed)
+sincos.v	$adff
+specify.v	no code (empty module generates error
+subbytes.v	$adff
+task_func.v	drops modules
+values.v	combinational loop
+vloghammer.v	combinational loop
+wreduce.v	original verilog issues ( -x where x isn't declared signed)
diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk
index c68678929..e0f2bcdc1 100644
--- a/tests/tools/autotest.mk
+++ b/tests/tools/autotest.mk
@@ -1,7 +1,7 @@
 
-EXTRA_FLAGS=
-SEED=
-
+# Don't bother defining default values for SEED and EXTRA_FLAGS.
+# Their "natural" default values should be sufficient,
+#   and they may be overridden in the environment.
 ifneq ($(strip $(SEED)),)
 SEEDOPT=-S$(SEED)
 endif
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 800fa3ad5..6fdd1e80a 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -17,12 +17,18 @@ scriptfiles=""
 scriptopt=""
 toolsdir="$(cd $(dirname $0); pwd)"
 warn_iverilog_git=false
+# The following are used in verilog to firrtl regression tests.
+# Typically these will be passed as environment variables:
+#EXTRA_FLAGS="--firrtl2verilog 'java -cp /.../firrtl/utils/bin/firrtl.jar firrtl.Driver'"
+# The tests are skipped if firrtl2verilog is the empty string (the default).
+firrtl2verilog=""
+xfirrtl="../xfirrtl"
 
 if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
 	( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
 fi
 
-while getopts xmGl:wkjvref:s:p:n:S:I:B: opt; do
+while getopts xmGl:wkjvref:s:p:n:S:I:B:-: opt; do
 	case "$opt" in
 		x)
 			use_xsim=true ;;
@@ -61,8 +67,24 @@ while getopts xmGl:wkjvref:s:p:n:S:I:B: opt; do
 			minclude_opts="$minclude_opts +incdir+$OPTARG" ;;
         B)
 			backend_opts="$backend_opts $OPTARG" ;;
+		-)
+			case "${OPTARG}" in
+			    xfirrtl)
+			    	xfirrtl="${!OPTIND}"
+				OPTIND=$(( $OPTIND + 1 ))
+				;;
+			    firrtl2verilog)
+			    	firrtl2verilog="${!OPTIND}"
+				OPTIND=$(( $OPTIND + 1 ))
+				;;
+			    *)
+			    	if [ "$OPTERR" == 1 ] && [ "${optspec:0:1}" != ":" ]; then
+				    echo "Unknown option --${OPTARG}" >&2
+				fi
+				;;
+			esac;;
 		*)
-			echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] verilog-files\n" >&2
+			echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2
 			exit 1
 	esac
 done
@@ -111,6 +133,8 @@ do
 		fn=$(basename $fn)
 		bn=$(basename $bn)
 
+		rm -f ${bn}_ref.fir
+
 		egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v
 
 		if [ ! -f ../${bn}_tb.v ]; then
@@ -150,6 +174,13 @@ do
 		else
 			test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v
 			test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v
+			if [ -n "$firrtl2verilog" ]; then
+			    if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
+				"$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v
+				$firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v  -X verilog
+				test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
+			    fi
+			fi
 		fi
 		touch ../${bn}.log
 	}
@@ -162,14 +193,18 @@ do
 		( set -ex; body; ) > ${bn}.err 2>&1
 	fi
 
+	did_firrtl=""
+	if [ -f ${bn}.out/${bn}_ref.fir ]; then
+	    did_firrtl="+FIRRTL "
+	fi
 	if [ -f ${bn}.log ]; then
 		mv ${bn}.err ${bn}.log
-		echo "${status_prefix}-> ok"
+		echo "${status_prefix}${did_firrtl}-> ok"
 	elif [ -f ${bn}.skip ]; then
 		mv ${bn}.err ${bn}.skip
 		echo "${status_prefix}-> skip"
 	else
-		echo "${status_prefix}-> ERROR!"
+		echo "${status_prefix}${did_firrtl}-> ERROR!"
 		if $warn_iverilog_git; then
 			echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog."
 		fi