aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie Hung <eddieh@ece.ubc.ca>2019-02-17 11:49:06 -0800
committerEddie Hung <eddieh@ece.ubc.ca>2019-02-17 11:49:06 -0800
commit17cd5f759f74b3f2b96d2035970ebac03509df9a (patch)
tree02262b0e2d32e2753c81ea4ae51ea56c1072506c
parente8f4dc739c5cf1129800aaa88df3f7c6f9c99360 (diff)
parente45f62b0c56717a23099425f078d1e56212aa632 (diff)
downloadyosys-17cd5f759f74b3f2b96d2035970ebac03509df9a.tar.gz
yosys-17cd5f759f74b3f2b96d2035970ebac03509df9a.tar.bz2
yosys-17cd5f759f74b3f2b96d2035970ebac03509df9a.zip
Merge https://github.com/YosysHQ/yosys into dff_init
-rw-r--r--backends/firrtl/firrtl.cc253
-rw-r--r--backends/verilog/verilog_backend.cc79
-rw-r--r--frontends/ast/genrtlil.cc9
-rw-r--r--passes/fsm/fsm_opt.cc3
-rwxr-xr-xtests/asicworld/run-test.sh2
-rw-r--r--tests/asicworld/xfirrtl24
-rw-r--r--tests/simple/xfirrtl26
-rw-r--r--tests/tools/autotest.mk6
-rwxr-xr-xtests/tools/autotest.sh43
9 files changed, 345 insertions, 100 deletions
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);
- log_header(design, "Executing FIRRTL backend.\n");
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
- Module *top = design->top_module();
+ log_header(design, "Executing FIRRTL backend.\n");
+ log_push();
- 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()) );
+ {
+ 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());
+ }
{
- os << stringf("if (");
- dump_sigspec(os, sig_rd_en);
- os << stringf(") ");
+ 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