aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG3
-rw-r--r--backends/json/json.cc50
-rw-r--r--frontends/json/jsonparse.cc57
-rw-r--r--kernel/cost.h148
-rw-r--r--kernel/register.cc67
-rw-r--r--passes/cmds/stat.cc22
-rw-r--r--passes/techmap/abc.cc42
-rw-r--r--tests/various/.gitignore2
-rw-r--r--tests/various/write_gzip.ys16
9 files changed, 255 insertions, 152 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 9e9bda6e9..638c36121 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,9 @@ Yosys 0.9 .. Yosys 0.9-dev
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
- Added automatic gzip decompression for frontends
- Added $_NMUX_ cell type
+ - Added automatic gzip compression (based on filename extension) for backends
+ - Improve attribute and parameter encoding in JSON to avoid ambiguities between
+ bit vectors and strings containing [01xz]*
Yosys 0.8 .. Yosys 0.8-dev
--------------------------
diff --git a/backends/json/json.cc b/backends/json/json.cc
index dda4dfedd..107009ee4 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -83,20 +83,43 @@ struct JsonWriter
return str + " ]";
}
+ void write_parameter_value(const Const &value)
+ {
+ if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
+ string str = value.decode_string();
+ int state = 0;
+ for (char c : str) {
+ if (state == 0) {
+ if (c == '0' || c == '1' || c == 'x' || c == 'z')
+ state = 0;
+ else if (c == ' ')
+ state = 1;
+ else
+ state = 2;
+ } else if (state == 1 && c != ' ')
+ state = 2;
+ }
+ if (state < 2)
+ str += " ";
+ f << get_string(str);
+ } else
+ if (GetSize(value) == 32 && value.is_fully_def()) {
+ if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
+ f << stringf("%d", value.as_int());
+ else
+ f << stringf("%u", value.as_int());
+ } else {
+ f << get_string(value.as_string());
+ }
+ }
+
void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
{
bool first = true;
for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str());
- if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
- f << get_string(param.second.decode_string());
- else if (GetSize(param.second.bits) > 32)
- f << get_string(param.second.as_string());
- else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
- f << stringf("%d", param.second.as_int());
- else
- f << stringf("%u", param.second.as_int());
+ write_parameter_value(param.second);
first = false;
}
}
@@ -342,12 +365,13 @@ struct JsonBackend : public Backend {
log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
log("values referenced above are vectors of this integers. Signal bits that are\n");
- log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
- log("a number.\n");
+ log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
+ log("\"z\" instead of a number.\n");
log("\n");
- log("Numeric parameter and attribute values up to 32 bits are written as decimal\n");
- log("values. Numbers larger than that are written as string holding the binary\n");
- log("representation of the value.\n");
+ log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
+ log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
+ log("as string holding the binary representation of the value. Strings are written\n");
+ log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
log("\n");
log("For example the following Verilog code:\n");
log("\n");
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index f5ae8eb72..7aceffbfc 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -25,7 +25,7 @@ struct JsonNode
{
char type; // S=String, N=Number, A=Array, D=Dict
string data_string;
- int data_number;
+ int64_t data_number;
vector<JsonNode*> data_array;
dict<string, JsonNode*> data_dict;
vector<string> data_dict_keys;
@@ -206,6 +206,38 @@ struct JsonNode
}
};
+Const json_parse_attr_param_value(JsonNode *node)
+{
+ Const value;
+
+ if (node->type == 'S') {
+ string &s = node->data_string;
+ size_t cursor = s.find_first_not_of("01xz");
+ if (cursor == string::npos) {
+ value = Const::from_string(s);
+ } else if (s.find_first_not_of(' ', cursor) == string::npos) {
+ value = Const(s.substr(0, GetSize(s)-1));
+ } else {
+ value = Const(s);
+ }
+ } else
+ if (node->type == 'N') {
+ value = Const(node->data_number, 32);
+ if (node->data_number < 0)
+ value.flags |= RTLIL::CONST_FLAG_SIGNED;
+ } else
+ if (node->type == 'A') {
+ log_error("JSON attribute or parameter value is an array.\n");
+ } else
+ if (node->type == 'D') {
+ log_error("JSON attribute or parameter value is a dict.\n");
+ } else {
+ log_abort();
+ }
+
+ return value;
+}
+
void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
{
if (node->type != 'D')
@@ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
for (auto it : node->data_dict)
{
IdString key = RTLIL::escape_id(it.first.c_str());
- JsonNode *value_node = it.second;
- Const value;
-
- if (value_node->type == 'S') {
- string &s = value_node->data_string;
- if (s.find_first_not_of("01xz") == string::npos)
- value = Const::from_string(s);
- else
- value = Const(s);
- } else
- if (value_node->type == 'N') {
- value = Const(value_node->data_number, 32);
- } else
- if (value_node->type == 'A') {
- log_error("JSON attribute or parameter value is an array.\n");
- } else
- if (value_node->type == 'D') {
- log_error("JSON attribute or parameter value is a dict.\n");
- } else {
- log_abort();
- }
-
+ Const value = json_parse_attr_param_value(it.second);
results[key] = value;
}
}
diff --git a/kernel/cost.h b/kernel/cost.h
index e8e077ff5..10fa50fb3 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -24,86 +24,92 @@
YOSYS_NAMESPACE_BEGIN
-int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false);
-
-inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
- RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false)
+struct CellCosts
{
- static dict<RTLIL::IdString, int> gate_cost = {
- { "$_BUF_", 1 },
- { "$_NOT_", 2 },
- { "$_AND_", 4 },
- { "$_NAND_", 4 },
- { "$_OR_", 4 },
- { "$_NOR_", 4 },
- { "$_ANDNOT_", 4 },
- { "$_ORNOT_", 4 },
- { "$_XOR_", 8 },
- { "$_XNOR_", 8 },
- { "$_AOI3_", 6 },
- { "$_OAI3_", 6 },
- { "$_AOI4_", 8 },
- { "$_OAI4_", 8 },
- { "$_MUX_", 4 },
- { "$_NMUX_", 4 }
- };
-
- // match costs in "stat -tech cmos"
- static dict<RTLIL::IdString, int> cmos_gate_cost = {
- { "$_BUF_", 1 },
- { "$_NOT_", 2 },
- { "$_AND_", 6 },
- { "$_NAND_", 4 },
- { "$_OR_", 6 },
- { "$_NOR_", 4 },
- { "$_ANDNOT_", 6 },
- { "$_ORNOT_", 6 },
- { "$_XOR_", 12 },
- { "$_XNOR_", 12 },
- { "$_AOI3_", 6 },
- { "$_OAI3_", 6 },
- { "$_AOI4_", 8 },
- { "$_OAI4_", 8 },
- { "$_MUX_", 12 },
- { "$_NMUX_", 10 }
- };
-
- if (cmos_cost && cmos_gate_cost.count(type))
- return cmos_gate_cost.at(type);
-
- if (gate_cost.count(type))
- return gate_cost.at(type);
-
- if (parameters.empty() && design && design->module(type))
+ static const dict<RTLIL::IdString, int>& default_gate_cost() {
+ static const dict<RTLIL::IdString, int> db = {
+ { "$_BUF_", 1 },
+ { "$_NOT_", 2 },
+ { "$_AND_", 4 },
+ { "$_NAND_", 4 },
+ { "$_OR_", 4 },
+ { "$_NOR_", 4 },
+ { "$_ANDNOT_", 4 },
+ { "$_ORNOT_", 4 },
+ { "$_XOR_", 5 },
+ { "$_XNOR_", 5 },
+ { "$_AOI3_", 6 },
+ { "$_OAI3_", 6 },
+ { "$_AOI4_", 7 },
+ { "$_OAI4_", 7 },
+ { "$_MUX_", 4 },
+ { "$_NMUX_", 4 }
+ };
+ return db;
+ }
+
+ static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
+ static const dict<RTLIL::IdString, int> db = {
+ { "$_BUF_", 1 },
+ { "$_NOT_", 2 },
+ { "$_AND_", 6 },
+ { "$_NAND_", 4 },
+ { "$_OR_", 6 },
+ { "$_NOR_", 4 },
+ { "$_ANDNOT_", 6 },
+ { "$_ORNOT_", 6 },
+ { "$_XOR_", 12 },
+ { "$_XNOR_", 12 },
+ { "$_AOI3_", 6 },
+ { "$_OAI3_", 6 },
+ { "$_AOI4_", 8 },
+ { "$_OAI4_", 8 },
+ { "$_MUX_", 12 },
+ { "$_NMUX_", 10 }
+ };
+ return db;
+ }
+
+ dict<RTLIL::IdString, int> mod_cost_cache;
+ const dict<RTLIL::IdString, int> *gate_cost = nullptr;
+ Design *design = nullptr;
+
+ int get(RTLIL::IdString type) const
{
- RTLIL::Module *mod = design->module(type);
+ if (gate_cost && gate_cost->count(type))
+ return gate_cost->at(type);
- if (mod->attributes.count("\\cost"))
- return mod->attributes.at("\\cost").as_int();
+ log_warning("Can't determine cost of %s cell.\n", log_id(type));
+ return 1;
+ }
- dict<RTLIL::IdString, int> local_mod_cost_cache;
- if (mod_cost_cache == nullptr)
- mod_cost_cache = &local_mod_cost_cache;
+ int get(RTLIL::Cell *cell)
+ {
+ if (gate_cost && gate_cost->count(cell->type))
+ return gate_cost->at(cell->type);
- if (mod_cost_cache->count(mod->name))
- return mod_cost_cache->at(mod->name);
+ if (design && design->module(cell->type) && cell->parameters.empty())
+ {
+ RTLIL::Module *mod = design->module(cell->type);
- int module_cost = 1;
- for (auto c : mod->cells())
- module_cost += get_cell_cost(c, mod_cost_cache);
+ if (mod->attributes.count("\\cost"))
+ return mod->attributes.at("\\cost").as_int();
- (*mod_cost_cache)[mod->name] = module_cost;
- return module_cost;
- }
+ if (mod_cost_cache.count(mod->name))
+ return mod_cost_cache.at(mod->name);
- log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
- return 1;
-}
+ int module_cost = 1;
+ for (auto c : mod->cells())
+ module_cost += get(c);
-inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache, bool cmos_cost)
-{
- return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache, cmos_cost);
-}
+ mod_cost_cache[mod->name] = module_cost;
+ return module_cost;
+ }
+
+ log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
+ return 1;
+ }
+};
YOSYS_NAMESPACE_END
diff --git a/kernel/register.cc b/kernel/register.cc
index 8f8f2c971..e4237cac4 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -41,6 +41,45 @@ void decompress_gzip(const std::string &filename, std::stringstream &out)
}
gzclose(gzf);
}
+
+/*
+An output stream that uses a stringbuf to buffer data internally,
+using zlib to write gzip-compressed data every time the stream is flushed.
+*/
+class gzip_ostream : public std::ostream {
+public:
+ gzip_ostream()
+ {
+ rdbuf(&outbuf);
+ }
+ bool open(const std::string &filename)
+ {
+ return outbuf.open(filename);
+ }
+private:
+ class gzip_streambuf : public std::stringbuf {
+ public:
+ gzip_streambuf() { };
+ bool open(const std::string &filename)
+ {
+ gzf = gzopen(filename.c_str(), "wb");
+ return gzf != nullptr;
+ }
+ virtual int sync() override
+ {
+ gzwrite(gzf, reinterpret_cast<const void *>(str().c_str()), unsigned(str().size()));
+ str("");
+ return 0;
+ }
+ ~gzip_streambuf()
+ {
+ sync();
+ gzclose(gzf);
+ }
+ private:
+ gzFile gzf = nullptr;
+ } outbuf;
+};
PRIVATE_NAMESPACE_END
#endif
@@ -586,14 +625,28 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
filename = arg;
rewrite_filename(filename);
- std::ofstream *ff = new std::ofstream;
- ff->open(filename.c_str(), std::ofstream::trunc);
- yosys_output_files.insert(filename);
- if (ff->fail()) {
- delete ff;
- log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ if (filename.size() > 3 && filename.substr(filename.size()-3) == ".gz") {
+#ifdef YOSYS_ENABLE_ZLIB
+ gzip_ostream *gf = new gzip_ostream;
+ if (!gf->open(filename)) {
+ delete gf;
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ yosys_output_files.insert(filename);
+ f = gf;
+#else
+ log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n");
+#endif
+ } else {
+ std::ofstream *ff = new std::ofstream;
+ ff->open(filename.c_str(), std::ofstream::trunc);
+ yosys_output_files.insert(filename);
+ if (ff->fail()) {
+ delete ff;
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ f = ff;
}
- f = ff;
}
if (called_with_fp)
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 89920ed55..c8e4f3981 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -17,11 +17,10 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "passes/techmap/libparse.h"
-
-#include "kernel/log.h"
+#include "kernel/cost.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -228,25 +227,16 @@ struct statdata_t
{
int tran_cnt = 0;
bool tran_cnt_exact = true;
+ auto &gate_costs = CellCosts::cmos_gate_cost();
for (auto it : num_cells_by_type) {
auto ctype = it.first;
auto cnum = it.second;
- if (ctype == "$_NOT_")
- tran_cnt += 2*cnum;
- else if (ctype.in("$_NAND_", "$_NOR_"))
- tran_cnt += 4*cnum;
- else if (ctype.in("$_AOI3_", "$_OAI3_"))
- tran_cnt += 6*cnum;
- else if (ctype.in("$_AOI4_", "$_OAI4_"))
- tran_cnt += 8*cnum;
- else if (ctype.in("$_NMUX_"))
- tran_cnt += 10*cnum;
- else if (ctype.in("$_MUX_", "$_XOR_", "$_XNOR_"))
- tran_cnt += 12*cnum;
+ if (gate_costs.count(ctype))
+ tran_cnt += cnum * gate_costs.at(ctype);
else if (ctype.in("$_DFF_P_", "$_DFF_N_"))
- tran_cnt += 16*cnum;
+ tran_cnt += cnum * 16;
else
tran_cnt_exact = false;
}
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 41a05c619..c0cfe2f36 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -931,9 +931,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
{
log_header(design, "Executing ABC.\n");
- auto cell_cost = [](IdString cell_type) {
- return get_cell_cost(cell_type, dict<RTLIL::IdString, RTLIL::Const>(), nullptr, nullptr, cmos_cost);
- };
+ auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost();
buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
@@ -941,42 +939,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost("$_BUF_"));
- fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost("$_NOT_"));
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_BUF_"));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NOT_"));
if (enabled_gates.empty() || enabled_gates.count("AND"))
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost("$_AND_"));
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_AND_"));
if (enabled_gates.empty() || enabled_gates.count("NAND"))
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_NAND_"));
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NAND_"));
if (enabled_gates.empty() || enabled_gates.count("OR"))
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost("$_OR_"));
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_OR_"));
if (enabled_gates.empty() || enabled_gates.count("NOR"))
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_NOR_"));
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NOR_"));
if (enabled_gates.empty() || enabled_gates.count("XOR"))
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XOR_"));
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XOR_"));
if (enabled_gates.empty() || enabled_gates.count("XNOR"))
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XNOR_"));
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XNOR_"));
if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
- fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ANDNOT_"));
+ fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ANDNOT_"));
if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
- fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ORNOT_"));
+ fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ORNOT_"));
if (enabled_gates.empty() || enabled_gates.count("AOI3"))
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_AOI3_"));
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_AOI3_"));
if (enabled_gates.empty() || enabled_gates.count("OAI3"))
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_OAI3_"));
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_OAI3_"));
if (enabled_gates.empty() || enabled_gates.count("AOI4"))
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_AOI4_"));
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_AOI4_"));
if (enabled_gates.empty() || enabled_gates.count("OAI4"))
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost("$_OAI4_"));
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_OAI4_"));
if (enabled_gates.empty() || enabled_gates.count("MUX"))
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_MUX_"));
if (enabled_gates.empty() || enabled_gates.count("NMUX"))
- fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_NMUX_"));
+ fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_NMUX_"));
if (map_mux4)
- fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at("$_MUX_"));
if (map_mux8)
- fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at("$_MUX_"));
if (map_mux16)
- fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at("$_MUX_"));
fclose(f);
if (!lut_costs.empty()) {
diff --git a/tests/various/.gitignore b/tests/various/.gitignore
index 7b3e8c68e..31078b298 100644
--- a/tests/various/.gitignore
+++ b/tests/various/.gitignore
@@ -1,2 +1,4 @@
/*.log
/*.out
+/write_gzip.v
+/write_gzip.v.gz
diff --git a/tests/various/write_gzip.ys b/tests/various/write_gzip.ys
new file mode 100644
index 000000000..030ec318e
--- /dev/null
+++ b/tests/various/write_gzip.ys
@@ -0,0 +1,16 @@
+read -vlog2k <<EOT
+module top(input a, output y);
+assign y = !a;
+endmodule
+EOT
+
+prep -top top
+write_verilog write_gzip.v.gz
+design -reset
+
+! rm -f write_gzip.v
+! gunzip write_gzip.v.gz
+read -vlog2k write_gzip.v
+! rm -f write_gzip.v
+hierarchy -top top
+select -assert-any top