mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
Merge remote-tracking branch 'origin/master' into xaig_dff
This commit is contained in:
commit
94f15f023c
47 changed files with 2053 additions and 184 deletions
|
@ -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
|
||||
|
|
130
passes/cmds/scratchpad.cc
Normal file
130
passes/cmds/scratchpad.cc
Normal file
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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); 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,43 @@ 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 << log_id(key);
|
||||
const Const &value = std::get<2>(sums.front());
|
||||
if (exists && 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 +1152,43 @@ 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 << log_id(key);
|
||||
const Const &value = std::get<2>(sums.front());
|
||||
if (exists && 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 +1314,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");
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue