diff options
Diffstat (limited to 'backends/blif')
-rw-r--r-- | backends/blif/blif.cc | 235 |
1 files changed, 200 insertions, 35 deletions
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index 2734ca321..93953049a 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -2,11 +2,11 @@ * 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 @@ -37,14 +37,18 @@ struct BlifDumperConfig bool conn_mode; bool impltf_mode; bool gates_mode; + bool cname_mode; bool param_mode; + bool attr_mode; bool blackbox_mode; + bool noalias_mode; std::string buf_type, buf_in, buf_out; std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types; std::string true_type, true_out, false_type, false_out, undef_type, undef_out; - BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false), blackbox_mode(false) { } + BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), + cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { } }; struct BlifDumper @@ -55,12 +59,35 @@ struct BlifDumper BlifDumperConfig *config; CellTypes ct; + SigMap sigmap; + dict<SigBit, int> init_bits; + BlifDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) : - f(f), module(module), design(design), config(config), ct(design) + f(f), module(module), design(design), config(config), ct(design), sigmap(module) { + for (Wire *wire : module->wires()) + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + switch (initval[i]) { + case State::S0: + init_bits[initsig[i]] = 0; + break; + case State::S1: + init_bits[initsig[i]] = 1; + break; + case State::Sx: + init_bits[initsig[i]] = 2; + break; + default: + break; + } + } } - std::vector<std::string> cstr_buf; + vector<shared_str> cstr_buf; + pool<SigBit> cstr_bits_seen; const char *cstr(RTLIL::IdString id) { @@ -74,6 +101,8 @@ struct BlifDumper const char *cstr(RTLIL::SigBit sig) { + cstr_bits_seen.insert(sig); + if (sig.wire == NULL) { if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false"; if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true"; @@ -92,6 +121,19 @@ struct BlifDumper return cstr_buf.back().c_str(); } + const char *cstr_init(RTLIL::SigBit sig) + { + sigmap.apply(sig); + + if (init_bits.count(sig) == 0) + return ""; + + string str = stringf(" %d", init_bits.at(sig)); + + cstr_buf.push_back(str); + return cstr_buf.back().c_str(); + } + const char *subckt_or_gate(std::string cell_type) { if (!config->gates_mode) @@ -103,6 +145,26 @@ struct BlifDumper return "subckt"; } + void dump_params(const char *command, dict<IdString, Const> ¶ms) + { + for (auto ¶m : params) { + f << stringf("%s %s ", command, RTLIL::id2cstr(param.first)); + if (param.second.flags & RTLIL::CONST_FLAG_STRING) { + std::string str = param.second.decode_string(); + f << stringf("\""); + for (char ch : str) + if (ch == '"' || ch == '\\') + f << stringf("\\%c", ch); + else if (ch < 32 || ch >= 127) + f << stringf("\\%03o", ch); + else + f << stringf("%c", ch); + f << stringf("\"\n"); + } else + f << stringf("%s\n", param.second.as_string().c_str()); + } + } + void dump() { f << stringf("\n"); @@ -202,6 +264,50 @@ struct BlifDumper continue; } + if (!config->icells_mode && cell->type == "$_NAND_") { + f << stringf(".names %s %s %s\n0- 1\n-0 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_NOR_") { + f << stringf(".names %s %s %s\n00 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_XNOR_") { + f << stringf(".names %s %s %s\n11 1\n00 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_AOI3_") { + f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_OAI3_") { + f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_AOI4_") { + f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), + cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_OAI4_") { + f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), + cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y"))); + continue; + } + if (!config->icells_mode && cell->type == "$_MUX_") { f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n", cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), @@ -210,14 +316,26 @@ struct BlifDumper } if (!config->icells_mode && cell->type == "$_DFF_N_") { - f << stringf(".latch %s %s fe %s\n", - cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C"))); + f << stringf(".latch %s %s fe %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q"))); continue; } if (!config->icells_mode && cell->type == "$_DFF_P_") { - f << stringf(".latch %s %s re %s\n", - cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C"))); + f << stringf(".latch %s %s re %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_DLATCH_N_") { + f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_DLATCH_P_") { + f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); continue; } @@ -226,9 +344,8 @@ struct BlifDumper auto &inputs = cell->getPort("\\A"); auto width = cell->parameters.at("\\WIDTH").as_int(); log_assert(inputs.size() == width); - for (int i = width-1; i >= 0; i--) { + for (int i = width-1; i >= 0; i--) f << stringf(" %s", cstr(inputs.extract(i, 1))); - } auto &output = cell->getPort("\\Y"); log_assert(output.size() == 1); f << stringf(" %s", cstr(output)); @@ -255,6 +372,34 @@ struct BlifDumper continue; } + if (!config->icells_mode && cell->type == "$sop") { + f << stringf(".names"); + auto &inputs = cell->getPort("\\A"); + auto width = cell->parameters.at("\\WIDTH").as_int(); + auto depth = cell->parameters.at("\\DEPTH").as_int(); + vector<State> table = cell->parameters.at("\\TABLE").bits; + while (GetSize(table) < 2*width*depth) + table.push_back(State::S0); + log_assert(inputs.size() == width); + for (int i = 0; i < width; i++) + f << stringf(" %s", cstr(inputs.extract(i, 1))); + auto &output = cell->getPort("\\Y"); + log_assert(output.size() == 1); + f << stringf(" %s", cstr(output)); + f << stringf("\n"); + for (int i = 0; i < depth; i++) { + for (int j = 0; j < width; j++) { + bool pat0 = table.at(2*width*i + 2*j + 0) == State::S1; + bool pat1 = table.at(2*width*i + 2*j + 1) == State::S1; + if (pat0 && !pat1) f << "0"; + else if (!pat0 && pat1) f << "1"; + else f << "-"; + } + f << " 1\n"; + } + continue; + } + f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); for (auto &conn : cell->connections()) for (int i = 0; i < conn.second.size(); i++) { @@ -266,35 +411,31 @@ struct BlifDumper } f << stringf("\n"); + if (config->cname_mode) + f << stringf(".cname %s\n", cstr(cell->name)); + if (config->attr_mode) + dump_params(".attr", cell->attributes); if (config->param_mode) - for (auto ¶m : cell->parameters) { - f << stringf(".param %s ", RTLIL::id2cstr(param.first)); - if (param.second.flags & RTLIL::CONST_FLAG_STRING) { - std::string str = param.second.decode_string(); - f << stringf("\""); - for (char ch : str) - if (ch == '"' || ch == '\\') - f << stringf("\\%c", ch); - else if (ch < 32 || ch >= 127) - f << stringf("\\%03o", ch); - else - f << stringf("%c", ch); - f << stringf("\"\n"); - } else - f << stringf("%s\n", param.second.as_string().c_str()); - } + dump_params(".param", cell->parameters); } for (auto &conn : module->connections()) for (int i = 0; i < conn.first.size(); i++) + { + SigBit lhs_bit = conn.first[i]; + SigBit rhs_bit = conn.second[i]; + + if (config->noalias_mode && cstr_bits_seen.count(lhs_bit) == 0) + continue; + if (config->conn_mode) - f << stringf(".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1))); + f << stringf(".conn %s %s\n", cstr(rhs_bit), cstr(lhs_bit)); else if (!config->buf_type.empty()) - f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)), - config->buf_out.c_str(), cstr(conn.first.extract(i, 1))); + f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), + config->buf_in.c_str(), cstr(rhs_bit), config->buf_out.c_str(), cstr(lhs_bit)); else - f << stringf(".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1))); - + f << stringf(".names %s %s\n1 1\n", cstr(rhs_bit), cstr(lhs_bit)); + } f << stringf(".end\n"); } @@ -334,6 +475,11 @@ struct BlifBackend : public Backend { log(" the wire name to be used for the constant signal and no cell driving\n"); log(" that wire is generated.\n"); log("\n"); + log(" -noalias\n"); + log(" if a net name is aliasing another net name, then by default a net\n"); + log(" without fanout is created that is driven by the other net. This option\n"); + log(" suppresses the generation of this nets without fanout.\n"); + log("\n"); log("The following options can be useful when the generated file is not going to be\n"); log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n"); log("file *.blif when any of this options is used.\n"); @@ -350,8 +496,14 @@ struct BlifBackend : public Backend { log(" do not generate buffers for connected wires. instead use the\n"); log(" non-standard .conn statement.\n"); log("\n"); + log(" -attr\n"); + log(" use the non-standard .attr statement to write cell attributes\n"); + log("\n"); log(" -param\n"); - log(" use the non-standard .param statement to write module parameters\n"); + log(" use the non-standard .param statement to write cell parameters\n"); + log("\n"); + log(" -cname\n"); + log(" use the non-standard .cname statement to write cell names\n"); log("\n"); log(" -blackbox\n"); log(" write blackbox cells with .blackbox statement.\n"); @@ -368,7 +520,7 @@ struct BlifBackend : public Backend { std::string false_type, false_out; BlifDumperConfig config; - log_header("Executing BLIF backend.\n"); + log_header(design, "Executing BLIF backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -417,10 +569,18 @@ struct BlifBackend : public Backend { config.conn_mode = true; continue; } + if (args[argidx] == "-cname") { + config.cname_mode = true; + continue; + } if (args[argidx] == "-param") { config.param_mode = true; continue; } + if (args[argidx] == "-attr") { + config.attr_mode = true; + continue; + } if (args[argidx] == "-blackbox") { config.blackbox_mode = true; continue; @@ -429,6 +589,10 @@ struct BlifBackend : public Backend { config.impltf_mode = true; continue; } + if (args[argidx] == "-noalias") { + config.noalias_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -442,6 +606,7 @@ struct BlifBackend : public Backend { std::vector<RTLIL::Module*> mod_list; + design->sort(); for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; @@ -451,7 +616,7 @@ struct BlifBackend : public Backend { if (module->processes.size() != 0) log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); if (module->memories.size() != 0) - log_error("Found munmapped emories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); if (module->name == RTLIL::escape_id(top_module_name)) { BlifDumper::dump(*f, module, design, config); |