aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/scratchpad.cc130
-rw-r--r--passes/equiv/equiv_opt.cc18
-rw-r--r--passes/memory/memory_bram.cc102
-rw-r--r--passes/opt/opt_expr.cc2
-rw-r--r--passes/pmgen/ice40_wrapcarry.cc75
6 files changed, 316 insertions, 12 deletions
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index c7edc30fb..07a5d3ddc 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -32,3 +32,4 @@ OBJS += passes/cmds/chtype.o
OBJS += passes/cmds/blackbox.o
OBJS += passes/cmds/ltp.o
OBJS += passes/cmds/bugpoint.o
+OBJS += passes/cmds/scratchpad.o
diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc
new file mode 100644
index 000000000..7ec55b78e
--- /dev/null
+++ b/passes/cmds/scratchpad.cc
@@ -0,0 +1,130 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Nina Engelhardt <nak@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ScratchpadPass : public Pass {
+ ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" scratchpad [options]\n");
+ log("\n");
+ log("This pass allows to read and modify values from the scratchpad of the current\n");
+ log("design. Options:\n");
+ log("\n");
+ log(" -get <identifier>\n");
+ log(" print the value saved in the scratchpad under the given identifier.\n");
+ log("\n");
+ log(" -set <identifier> <value>\n");
+ log(" save the given value in the scratchpad under the given identifier.\n");
+ log("\n");
+ log(" -unset <identifier>\n");
+ log(" remove the entry for the given identifier from the scratchpad.\n");
+ log("\n");
+ log(" -copy <identifier_from> <identifier_to>\n");
+ log(" copy the value of the first identifier to the second identifier.\n");
+ log("\n");
+ log(" -assert <identifier> <value>\n");
+ log(" assert that the entry for the given identifier is set to the given value.\n");
+ log("\n");
+ log(" -assert-set <identifier>\n");
+ log(" assert that the entry for the given identifier exists.\n");
+ log("\n");
+ log(" -assert-unset <identifier>\n");
+ log(" assert that the entry for the given identifier does not exist.\n");
+ log("\n");
+ log("The identifier may not contain whitespace. By convention, it is usually prefixed\n");
+ log("by the name of the pass that uses it, e.g. 'opt.did_something'. If the value\n");
+ log("contains whitespace, it must be enclosed in double quotes.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-get" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier)){
+ log("%s\n", design->scratchpad_get_string(identifier).c_str());
+ } else {
+ log("\"%s\" not set\n", identifier.c_str());
+ }
+ continue;
+ }
+ if (args[argidx] == "-set" && argidx+2 < args.size()) {
+ string identifier = args[++argidx];
+ string value = args[++argidx];
+ if (value.front() == '\"' && value.back() == '\"') value = value.substr(1, value.size() - 2);
+ design->scratchpad_set_string(identifier, value);
+ continue;
+ }
+ if (args[argidx] == "-unset" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ design->scratchpad_unset(identifier);
+ continue;
+ }
+ if (args[argidx] == "-copy" && argidx+2 < args.size()) {
+ string identifier_from = args[++argidx];
+ string identifier_to = args[++argidx];
+ if (design->scratchpad.count(identifier_from) == 0) log_error("\"%s\" not set\n", identifier_from.c_str());
+ string value = design->scratchpad_get_string(identifier_from);
+ design->scratchpad_set_string(identifier_to, value);
+ continue;
+ }
+ if (args[argidx] == "-assert" && argidx+2 < args.size()) {
+ string identifier = args[++argidx];
+ string expected = args[++argidx];
+ if (expected.front() == '\"' && expected.back() == '\"') expected = expected.substr(1, expected.size() - 2);
+ if (design->scratchpad.count(identifier) == 0)
+ log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ string value = design->scratchpad_get_string(identifier);
+ if (value != expected) {
+ log_error("Assertion failed: scratchpad entry '%s' is set to '%s' instead of the asserted '%s'\n",
+ identifier.c_str(), value.c_str(), expected.c_str());
+ }
+ continue;
+ }
+ if (args[argidx] == "-assert-set" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier) == 0)
+ log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ continue;
+ }
+ if (args[argidx] == "-assert-unset" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier) > 0)
+ log_error("Assertion failed: scratchpad entry '%s' is defined\n", identifier.c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design, false);
+ }
+} ScratchpadPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index c7e6d71a6..7c6c2e685 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -44,6 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" expand the modules in this file before proving equivalence. this is\n");
log(" useful for handling architecture-specific primitives.\n");
log("\n");
+ log(" -blacklist <file>\n");
+ log(" Do not match cells or signals that match the names in the file\n");
+ log(" (passed to equiv_make).\n");
+ log("\n");
log(" -assert\n");
log(" produce an error if the circuits are not equivalent.\n");
log("\n");
@@ -61,13 +65,14 @@ struct EquivOptPass:public ScriptPass
log("\n");
}
- std::string command, techmap_opts;
+ std::string command, techmap_opts, make_opts;
bool assert, undef, multiclock, async2sync;
void clear_flags() YS_OVERRIDE
{
command = "";
techmap_opts = "";
+ make_opts = "";
assert = false;
undef = false;
multiclock = false;
@@ -93,6 +98,10 @@ struct EquivOptPass:public ScriptPass
techmap_opts += " -map " + args[++argidx];
continue;
}
+ if (args[argidx] == "-blacklist" && argidx + 1 < args.size()) {
+ make_opts += " -blacklist " + args[++argidx];
+ continue;
+ }
if (args[argidx] == "-assert") {
assert = true;
continue;
@@ -170,7 +179,12 @@ struct EquivOptPass:public ScriptPass
run("clk2fflogic", "(only with -multiclock)");
if (async2sync || help_mode)
run("async2sync", " (only with -async2sync)");
- run("equiv_make gold gate equiv");
+ string opts;
+ if (help_mode)
+ opts = " -blacklist <filename> ...";
+ else
+ opts = make_opts;
+ run("equiv_make" + opts + " gold gate equiv");
if (help_mode)
run("equiv_induct [-undef] equiv");
else if (undef)
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index aa8f94149..e0970d192 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -134,6 +134,7 @@ struct rules_t
dict<string, int> min_limits, max_limits;
bool or_next_if_better, make_transp, make_outreg;
char shuffle_enable;
+ vector<vector<std::tuple<bool,IdString,Const>>> attributes;
};
dict<IdString, vector<bram_t>> brams;
@@ -327,6 +328,20 @@ struct rules_t
continue;
}
+ if (GetSize(tokens) >= 2 && tokens[0] == "attribute") {
+ data.attributes.emplace_back();
+ for (int idx = 1; idx <= GetSize(tokens)-1; idx++) {
+ size_t c1 = tokens[idx][0] == '!' ? 1 : 0;
+ size_t c2 = tokens[idx].find("=");
+ bool exists = (c1 == 0);
+ IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
+ Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
+
+ data.attributes.back().emplace_back(exists, key, val);
+ }
+ continue;
+ }
+
syntax_error();
}
}
@@ -724,7 +739,7 @@ grow_read_ports:;
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
if (pi.clocks != 0) {
- if (wr_ports == 1 && wr_clkdom != clkdom) {
+ if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
@@ -813,6 +828,45 @@ grow_read_ports:;
return false;
}
+ for (const auto &sums : match.attributes) {
+ bool found = false;
+ for (const auto &term : sums) {
+ bool exists = std::get<0>(term);
+ IdString key = std::get<1>(term);
+ const Const &value = std::get<2>(term);
+ auto it = cell->attributes.find(key);
+ if (it == cell->attributes.end()) {
+ if (exists)
+ continue;
+ found = true;
+ break;
+ }
+ else if (!exists)
+ continue;
+ if (it->second != value)
+ continue;
+ found = true;
+ break;
+ }
+ if (!found) {
+ std::stringstream ss;
+ bool exists = std::get<0>(sums.front());
+ if (!exists)
+ ss << "!";
+ IdString key = std::get<1>(sums.front());
+ ss << key.str();
+ const Const &value = std::get<2>(sums.front());
+ if (exists)
+ ss << "=";
+ if (value != Const(1))
+ ss << "\"" << value.decode_string() << "\"";
+
+ log(" Rule for bram type %s rejected: requirement 'attribute %s ...' not met.\n",
+ log_id(match.name), ss.str().c_str());
+ return false;
+ }
+ }
+
if (mode == 1)
return true;
}
@@ -1100,6 +1154,45 @@ void handle_cell(Cell *cell, const rules_t &rules)
goto next_match_rule;
}
+ for (const auto &sums : match.attributes) {
+ bool found = false;
+ for (const auto &term : sums) {
+ bool exists = std::get<0>(term);
+ IdString key = std::get<1>(term);
+ const Const &value = std::get<2>(term);
+ auto it = cell->attributes.find(key);
+ if (it == cell->attributes.end()) {
+ if (exists)
+ continue;
+ found = true;
+ break;
+ }
+ else if (!exists)
+ continue;
+ if (it->second != value)
+ continue;
+ found = true;
+ break;
+ }
+ if (!found) {
+ std::stringstream ss;
+ bool exists = std::get<0>(sums.front());
+ if (!exists)
+ ss << "!";
+ IdString key = std::get<1>(sums.front());
+ ss << key.str();
+ const Const &value = std::get<2>(sums.front());
+ if (exists)
+ ss << "=";
+ if (value != Const(1))
+ ss << "\"" << value.decode_string() << "\"";
+
+ log(" Rule for bram type %s (variant %d) rejected: requirement 'attribute %s ...' not met.\n",
+ log_id(bram.name), bram.variant, ss.str().c_str());
+ goto next_match_rule;
+ }
+ }
+
log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
if (or_next_if_better || !best_rule_cache.empty())
@@ -1225,6 +1318,13 @@ struct MemoryBramPass : public Pass {
log(" dcells ....... number of cells in 'data-direction'\n");
log(" cells ........ total number of cells (acells*dcells*dups)\n");
log("\n");
+ log("A match containing the command 'attribute' followed by a list of space\n");
+ log("separated 'name[=string_value]' values requires that the memory contains any\n");
+ log("one of the given attribute name and string values (where specified), or name\n");
+ log("and integer 1 value (if no string_value given, since Verilog will interpret\n");
+ log("'(* attr *)' as '(* attr=1 *)').\n");
+ log("A name prefixed with '!' indicates that the attribute must not exist.\n");
+ log("\n");
log("The interface for the created bram instances is derived from the bram\n");
log("description. Use 'techmap' to convert the created bram instances into\n");
log("instances of the actual bram cells of your target architecture.\n");
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 6cf66fb95..4a2f170b8 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -978,7 +978,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
- log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
+ log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
cell->setPort(ID::A, cell->getPort(ID::B));
diff --git a/passes/pmgen/ice40_wrapcarry.cc b/passes/pmgen/ice40_wrapcarry.cc
index 69ef3cd82..6e154147f 100644
--- a/passes/pmgen/ice40_wrapcarry.cc
+++ b/passes/pmgen/ice40_wrapcarry.cc
@@ -50,6 +50,14 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
cell->setPort("\\O", st.lut->getPort("\\O"));
cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT"));
+ for (const auto &a : st.carry->attributes)
+ cell->attributes[stringf("\\SB_CARRY.%s", a.first.c_str())] = a.second;
+ for (const auto &a : st.lut->attributes)
+ cell->attributes[stringf("\\SB_LUT4.%s", a.first.c_str())] = a.second;
+ cell->attributes[ID(SB_LUT4.name)] = Const(st.lut->name.str());
+ if (st.carry->get_bool_attribute(ID::keep) || st.lut->get_bool_attribute(ID::keep))
+ cell->attributes[ID::keep] = true;
+
pm.autoremove(st.carry);
pm.autoremove(st.lut);
}
@@ -62,28 +70,79 @@ struct Ice40WrapCarryPass : public Pass {
log("\n");
log(" ice40_wrapcarry [selection]\n");
log("\n");
- log("Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUTs,\n");
+ log("Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUT4s,\n");
log("into an internal $__ICE40_CARRY_WRAPPER cell for preservation across technology\n");
- log("mapping.");
+ log("mapping.\n");
+ log("\n");
+ log("Attributes on both cells will have their names prefixed with 'SB_CARRY.' or\n");
+ log("'SB_LUT4.' and attached to the wrapping cell.\n");
+ log("A (* keep *) attribute on either cell will be logically OR-ed together.\n");
+ log("\n");
+ log(" -unwrap\n");
+ log(" unwrap $__ICE40_CARRY_WRAPPER cells back into SB_CARRYs and SB_LUT4s,\n");
+ log(" including restoring their attributes.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
+ bool unwrap = false;
+
log_header(design, "Executing ICE40_WRAPCARRY pass (wrap carries).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- // if (args[argidx] == "-singleton") {
- // singleton_mode = true;
- // continue;
- // }
+ if (args[argidx] == "-unwrap") {
+ unwrap = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto module : design->selected_modules())
- ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
+ for (auto module : design->selected_modules()) {
+ if (!unwrap)
+ ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
+ else {
+ for (auto cell : module->selected_cells()) {
+ if (cell->type != ID($__ICE40_CARRY_WRAPPER))
+ continue;
+
+ auto carry = module->addCell(NEW_ID, ID(SB_CARRY));
+ carry->setPort(ID(I0), cell->getPort(ID(A)));
+ carry->setPort(ID(I1), cell->getPort(ID(B)));
+ carry->setPort(ID(CI), cell->getPort(ID(CI)));
+ carry->setPort(ID(CO), cell->getPort(ID(CO)));
+ module->swap_names(carry, cell);
+ auto lut_name = cell->attributes.at(ID(SB_LUT4.name), Const(NEW_ID.str())).decode_string();
+ auto lut = module->addCell(lut_name, ID($lut));
+ lut->setParam(ID(WIDTH), 4);
+ lut->setParam(ID(LUT), cell->getParam(ID(LUT)));
+ lut->setPort(ID(A), {cell->getPort(ID(I0)), cell->getPort(ID(A)), cell->getPort(ID(B)), cell->getPort(ID(I3)) });
+ lut->setPort(ID(Y), cell->getPort(ID(O)));
+
+ Const src;
+ for (const auto &a : cell->attributes)
+ if (a.first.begins_with("\\SB_CARRY.\\"))
+ carry->attributes[a.first.c_str() + strlen("\\SB_CARRY.")] = a.second;
+ else if (a.first.begins_with("\\SB_LUT4.\\"))
+ lut->attributes[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second;
+ else if (a.first == ID(src))
+ src = a.second;
+ else if (a.first.in(ID(SB_LUT4.name), ID::keep, ID(module_not_derived)))
+ continue;
+ else
+ log_abort();
+
+ if (!src.empty()) {
+ carry->attributes.insert(std::make_pair(ID(src), src));
+ lut->attributes.insert(std::make_pair(ID(src), src));
+ }
+
+ module->remove(cell);
+ }
+ }
+ }
}
} Ice40WrapCarryPass;