3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-03-02 19:56:57 +00:00

Merge branch 'main' into emil/turbo-celltypes

This commit is contained in:
nella 2026-02-25 12:29:06 +01:00 committed by GitHub
commit 2a2c91e78a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
265 changed files with 11258 additions and 3014 deletions

View file

@ -39,6 +39,7 @@ OBJS += passes/techmap/muxcover.o
OBJS += passes/techmap/aigmap.o
OBJS += passes/techmap/tribuf.o
OBJS += passes/techmap/lut2mux.o
OBJS += passes/techmap/lut2bmux.o
OBJS += passes/techmap/nlutmap.o
OBJS += passes/techmap/shregmap.o
OBJS += passes/techmap/deminout.o

View file

@ -143,6 +143,14 @@ struct AbcConfig
bool markgroups = false;
pool<std::string> enabled_gates;
bool cmos_cost = false;
bool is_yosys_abc() const {
#ifdef ABCEXTERNAL
return false;
#else
return exe_file == yosys_abc_executable;
#endif
}
};
struct AbcSigVal {
@ -155,7 +163,12 @@ struct AbcSigVal {
}
};
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
// REUSE_YOSYS_ABC_PROCESSES only works when ABC is built with ENABLE_READLINE.
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN) && defined(YOSYS_ENABLE_READLINE)
#define REUSE_YOSYS_ABC_PROCESSES
#endif
#ifdef REUSE_YOSYS_ABC_PROCESSES
struct AbcProcess
{
pid_t pid;
@ -188,10 +201,10 @@ struct AbcProcess
int status;
int ret = waitpid(pid, &status, 0);
if (ret != pid) {
log_error("waitpid(%d) failed", pid);
log_error("waitpid(%d) failed\n", pid);
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
log_error("ABC failed with status %X", status);
log_error("ABC failed with status %X\n", status);
}
if (from_child_pipe >= 0)
close(from_child_pipe);
@ -203,12 +216,12 @@ std::optional<AbcProcess> spawn_abc(const char* abc_exe, DeferredLogs &logs) {
// fork()s.
int to_child_pipe[2];
if (pipe2(to_child_pipe, O_CLOEXEC) != 0) {
logs.log_error("pipe failed");
logs.log_error("pipe failed\n");
return std::nullopt;
}
int from_child_pipe[2];
if (pipe2(from_child_pipe, O_CLOEXEC) != 0) {
logs.log_error("pipe failed");
logs.log_error("pipe failed\n");
return std::nullopt;
}
@ -221,39 +234,39 @@ std::optional<AbcProcess> spawn_abc(const char* abc_exe, DeferredLogs &logs) {
posix_spawn_file_actions_t file_actions;
if (posix_spawn_file_actions_init(&file_actions) != 0) {
logs.log_error("posix_spawn_file_actions_init failed");
logs.log_error("posix_spawn_file_actions_init failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_addclose(&file_actions, to_child_pipe[1]) != 0) {
logs.log_error("posix_spawn_file_actions_addclose failed");
logs.log_error("posix_spawn_file_actions_addclose failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_addclose(&file_actions, from_child_pipe[0]) != 0) {
logs.log_error("posix_spawn_file_actions_addclose failed");
logs.log_error("posix_spawn_file_actions_addclose failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_adddup2(&file_actions, to_child_pipe[0], STDIN_FILENO) != 0) {
logs.log_error("posix_spawn_file_actions_adddup2 failed");
logs.log_error("posix_spawn_file_actions_adddup2 failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_adddup2(&file_actions, from_child_pipe[1], STDOUT_FILENO) != 0) {
logs.log_error("posix_spawn_file_actions_adddup2 failed");
logs.log_error("posix_spawn_file_actions_adddup2 failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_addclose(&file_actions, to_child_pipe[0]) != 0) {
logs.log_error("posix_spawn_file_actions_addclose failed");
logs.log_error("posix_spawn_file_actions_addclose failed\n");
return std::nullopt;
}
if (posix_spawn_file_actions_addclose(&file_actions, from_child_pipe[1]) != 0) {
logs.log_error("posix_spawn_file_actions_addclose failed");
logs.log_error("posix_spawn_file_actions_addclose failed\n");
return std::nullopt;
}
char arg1[] = "-s";
char* argv[] = { strdup(abc_exe), arg1, nullptr };
if (0 != posix_spawn(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
logs.log_error("posix_spawn %s failed", abc_exe);
if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
logs.log_error("posix_spawnp %s failed (errno=%s)\n", abc_exe, strerror(errno));
return std::nullopt;
}
free(argv[0]);
@ -272,7 +285,7 @@ using AbcSigMap = SigValMap<AbcSigVal>;
struct RunAbcState {
const AbcConfig &config;
std::string tempdir_name;
std::string per_run_tempdir_name;
std::vector<gate_t> signal_list;
bool did_run = false;
bool err = false;
@ -823,16 +836,23 @@ std::string fold_abc_cmd(std::string str)
return new_str;
}
std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
std::string replace_tempdir(std::string text, std::string_view global_tempdir_name, std::string_view per_run_tempdir_name, bool show_tempdir)
{
if (show_tempdir)
return text;
while (1) {
size_t pos = text.find(tempdir_name);
size_t pos = text.find(global_tempdir_name);
if (pos == std::string::npos)
break;
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(global_tempdir_name));
}
while (1) {
size_t pos = text.find(per_run_tempdir_name);
if (pos == std::string::npos)
break;
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(per_run_tempdir_name));
}
std::string selfdir_name = proc_self_dirname();
@ -854,11 +874,12 @@ struct abc_output_filter
bool got_cr;
int escape_seq_state;
std::string linebuf;
std::string tempdir_name;
std::string global_tempdir_name;
std::string per_run_tempdir_name;
bool show_tempdir;
abc_output_filter(RunAbcState& state, std::string tempdir_name, bool show_tempdir)
: state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir)
abc_output_filter(RunAbcState& state, std::string global_tempdir_name, std::string per_run_tempdir_name, bool show_tempdir)
: state(state), global_tempdir_name(global_tempdir_name), per_run_tempdir_name(per_run_tempdir_name), show_tempdir(show_tempdir)
{
got_cr = false;
escape_seq_state = 0;
@ -885,7 +906,7 @@ struct abc_output_filter
return;
}
if (ch == '\n') {
state.logs.log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir));
state.logs.log("ABC: %s\n", replace_tempdir(linebuf, global_tempdir_name, per_run_tempdir_name, show_tempdir));
got_cr = false, linebuf.clear();
return;
}
@ -986,15 +1007,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
const AbcConfig &config = run_abc.config;
if (config.cleanup)
run_abc.tempdir_name = get_base_tmpdir() + "/";
run_abc.per_run_tempdir_name = get_base_tmpdir() + "/";
else
run_abc.tempdir_name = "_tmp_";
run_abc.tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
run_abc.tempdir_name = make_temp_dir(run_abc.tempdir_name);
run_abc.per_run_tempdir_name = "_tmp_";
run_abc.per_run_tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
run_abc.per_run_tempdir_name = make_temp_dir(run_abc.per_run_tempdir_name);
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
module->name.c_str(), replace_tempdir(run_abc.tempdir_name, run_abc.tempdir_name, config.show_tempdir).c_str());
module->name.c_str(), replace_tempdir(run_abc.per_run_tempdir_name, config.global_tempdir_name, run_abc.per_run_tempdir_name, config.show_tempdir).c_str());
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.tempdir_name);
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.per_run_tempdir_name);
if (!config.liberty_files.empty() || !config.genlib_files.empty()) {
std::string dont_use_args;
@ -1060,18 +1081,19 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3);
if (config.abc_dress)
abc_script += stringf("; dress \"%s/input.blif\"", run_abc.tempdir_name);
abc_script += stringf("; write_blif %s/output.blif", run_abc.tempdir_name);
abc_script += stringf("; dress \"%s/input.blif\"", run_abc.per_run_tempdir_name);
abc_script += stringf("; write_blif %s/output.blif", run_abc.per_run_tempdir_name);
abc_script = add_echos_to_abc_cmd(abc_script);
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
abc_script += "; echo \"YOSYS_ABC_DONE\"\n";
#if defined(REUSE_YOSYS_ABC_PROCESSES)
if (config.is_yosys_abc())
abc_script += "; echo; echo \"YOSYS_ABC_DONE\"\n";
#endif
for (size_t i = 0; i+1 < abc_script.size(); i++)
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
abc_script[i+1] = '\n';
std::string buffer = stringf("%s/abc.script", run_abc.tempdir_name);
std::string buffer = stringf("%s/abc.script", run_abc.per_run_tempdir_name);
FILE *f = fopen(buffer.c_str(), "wt");
if (f == nullptr)
log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno));
@ -1127,42 +1149,86 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
handle_loops(assign_map, module);
}
#if defined(REUSE_YOSYS_ABC_PROCESSES)
static bool is_abc_prompt(const std::string &line, std::string &rest) {
size_t pos = 0;
while (true) {
// The prompt may not start at the start of the line, because
// ABC can output progress and maybe other data that isn't
// newline-terminated.
size_t start = line.find("abc ", pos);
if (start == std::string::npos)
return false;
pos = start + 4;
size_t digits = 0;
while (pos + digits < line.size() && line[pos + digits] >= '0' && line[pos + digits] <= '9')
++digits;
if (digits < 2)
return false;
if (line.substr(pos + digits, 2) == "> ") {
rest = line.substr(pos + digits + 2);
return true;
}
}
}
bool read_until_abc_done(abc_output_filter &filt, int fd, DeferredLogs &logs) {
std::string line;
char buf[1024];
bool seen_source_cmd = false;
bool seen_yosys_abc_done = false;
while (true) {
int ret = read(fd, buf, sizeof(buf) - 1);
if (ret < 0) {
logs.log_error("Failed to read from ABC, errno=%d", errno);
logs.log_error("Failed to read from ABC, errno=%d\n", errno);
return false;
}
if (ret == 0) {
logs.log_error("ABC exited prematurely");
logs.log_error("ABC exited prematurely\n");
return false;
}
char *start = buf;
char *end = buf + ret;
while (start < end) {
char *p = static_cast<char*>(memchr(start, '\n', end - start));
if (p == nullptr) {
break;
char *upto = p == nullptr ? end : p + 1;
line.append(start, upto - start);
start = upto;
std::string rest;
bool is_prompt = is_abc_prompt(line, rest);
if (is_prompt && seen_source_cmd) {
// This is the first prompt after we sourced the script.
// We are done here.
// We won't have seen a newline yet since ABC is waiting at the prompt.
if (!seen_yosys_abc_done)
logs.log_error("ABC script did not complete successfully\n");
return seen_yosys_abc_done;
}
line.append(start, p + 1 - start);
if (line.substr(0, 14) == "YOSYS_ABC_DONE") {
// Ignore any leftover output, there should only be a prompt perhaps
return true;
if (line.empty() || line[line.size() - 1] != '\n') {
// No newline yet, wait for more text
continue;
}
filt.next_line(line);
if (is_prompt && rest.substr(0, 7) == "source ")
seen_source_cmd = true;
if (line.substr(0, 14) == "YOSYS_ABC_DONE")
seen_yosys_abc_done = true;
line.clear();
start = p + 1;
}
line.append(start, end - start);
}
}
#endif
#if defined(REUSE_YOSYS_ABC_PROCESSES)
void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
#else
void RunAbcState::run(ConcurrentStack<AbcProcess> &)
#endif
{
std::string buffer = stringf("%s/input.blif", tempdir_name);
std::string buffer = stringf("%s/input.blif", per_run_tempdir_name);
FILE *f = fopen(buffer.c_str(), "wt");
if (f == nullptr) {
logs.log("Opening %s for writing failed: %s\n", buffer, strerror(errno));
@ -1285,15 +1351,19 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
logs.log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
count_gates, GetSize(signal_list), count_input, count_output);
if (count_output > 0)
{
std::string tmp_script_name = stringf("%s/abc.script", tempdir_name);
logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, tempdir_name, config.show_tempdir));
if (count_output == 0) {
log("Don't call ABC as there is nothing to map.\n");
return;
}
int ret;
std::string tmp_script_name = stringf("%s/abc.script", per_run_tempdir_name);
do {
logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir));
errno = 0;
abc_output_filter filt(*this, tempdir_name, config.show_tempdir);
abc_output_filter filt(*this, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir);
#ifdef YOSYS_LINK_ABC
string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name);
string temp_stdouterr_name = stringf("%s/stdouterr.txt", per_run_tempdir_name);
FILE *temp_stdouterr_w = fopen(temp_stdouterr_name.c_str(), "w");
if (temp_stdouterr_w == NULL)
log_error("ABC: cannot open a temporary file for output redirection");
@ -1318,7 +1388,7 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
abc_argv[2] = strdup("-f");
abc_argv[3] = strdup(tmp_script_name.c_str());
abc_argv[4] = 0;
int ret = abc::Abc_RealMain(4, abc_argv);
ret = abc::Abc_RealMain(4, abc_argv);
free(abc_argv[0]);
free(abc_argv[1]);
free(abc_argv[2]);
@ -1333,39 +1403,42 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
for (std::string line; std::getline(temp_stdouterr_r, line); )
filt.next_line(line + "\n");
temp_stdouterr_r.close();
#elif defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
AbcProcess process;
if (std::optional<AbcProcess> process_opt = process_pool.try_pop_back()) {
process = std::move(process_opt.value());
} else if (std::optional<AbcProcess> process_opt = spawn_abc(config.exe_file.c_str(), logs)) {
process = std::move(process_opt.value());
} else {
return;
}
std::string cmd = stringf(
"empty\n"
"source %s\n", tmp_script_name);
int ret = write(process.to_child_pipe, cmd.c_str(), cmd.size());
if (ret != static_cast<int>(cmd.size())) {
logs.log_error("write failed");
return;
}
ret = read_until_abc_done(filt, process.from_child_pipe, logs) ? 0 : 1;
if (ret == 0) {
process_pool.push_back(std::move(process));
}
break;
#else
std::string cmd = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file.c_str(), tempdir_name.c_str());
int ret = run_command(cmd, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
#endif
if (ret != 0) {
logs.log_error("ABC: execution of script \"%s\" failed: return code %d (errno=%d).\n", tmp_script_name, ret, errno);
return;
#if defined(REUSE_YOSYS_ABC_PROCESSES)
if (config.is_yosys_abc()) {
AbcProcess process;
if (std::optional<AbcProcess> process_opt = process_pool.try_pop_back()) {
process = std::move(process_opt.value());
} else if (std::optional<AbcProcess> process_opt = spawn_abc(config.exe_file.c_str(), logs)) {
process = std::move(process_opt.value());
} else {
return;
}
std::string cmd = stringf(
"empty\n"
"source %s\n", tmp_script_name);
ret = write(process.to_child_pipe, cmd.c_str(), cmd.size());
if (ret != static_cast<int>(cmd.size())) {
logs.log_error("write failed");
return;
}
ret = read_until_abc_done(filt, process.from_child_pipe, logs) ? 0 : 1;
if (ret == 0) {
process_pool.push_back(std::move(process));
}
break;
}
did_run = true;
#endif
std::string cmd = stringf("\"%s\" -s -f %s 2>&1", config.exe_file, tmp_script_name);
ret = run_command(cmd, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
#endif
} while (false);
if (ret != 0) {
logs.log_error("ABC: execution of script \"%s\" failed: return code %d (errno=%d).\n", tmp_script_name, ret, errno);
return;
}
log("Don't call ABC as there is nothing to map.\n");
did_run = true;
}
void emit_global_input_files(const AbcConfig &config)
@ -1437,7 +1510,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL
return;
}
std::string buffer = stringf("%s/%s", run_abc.tempdir_name, "output.blif");
std::string buffer = stringf("%s/%s", run_abc.per_run_tempdir_name, "output.blif");
std::ifstream ifs;
ifs.open(buffer);
if (ifs.fail())
@ -1724,7 +1797,7 @@ void AbcModuleState::finish()
if (run_abc.config.cleanup)
{
log("Removing temp directory.\n");
remove_directory(run_abc.tempdir_name);
remove_directory(run_abc.per_run_tempdir_name);
}
log_pop();
}

View file

@ -219,9 +219,7 @@ struct Abc9Pass : public ScriptPass
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if ((arg == "-exe" || arg == "-script" || arg == "-D" ||
/*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" ||
/*arg == "-box" ||*/ arg == "-W" || arg == "-genlib" ||
arg == "-constr" || arg == "-dont_use" || arg == "-liberty") &&
arg == "-lut" || arg == "-luts" || arg == "-W") &&
argidx+1 < args.size()) {
if (arg == "-lut" || arg == "-luts")
lut_mode = true;

View file

@ -248,7 +248,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
}
abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name);
if (design->scratchpad_get_bool("abc9.verify")) {
if (design->scratchpad_get_bool("abc9.verify", true)) {
if (dff_mode)
abc9_script += "; &verify -s";
else

View file

@ -38,7 +38,8 @@ std::vector<Module*> order_modules(Design *design, std::vector<Module *> modules
sort.edge(submodule, m);
}
}
log_assert(sort.sort());
bool is_sorted = sort.sort();
log_assert(is_sorted);
return sort.sorted;
}

View file

@ -415,7 +415,7 @@ struct BufnormPass : public Pass {
return mapped_bits.at(bit);
};
auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst)
auto make_buffer_f = [&](IdString type, const SigSpec &src, const SigSpec &dst)
{
auto it = old_buffers.find(pair<IdString, SigSpec>(type, dst));

View file

@ -78,7 +78,6 @@ struct DffunmapPass : public Pass {
continue;
FfData ff(&initvals, cell);
IdString name = cell->name;
if (!ff.has_clk)
continue;

View file

@ -40,10 +40,10 @@ int bindec(unsigned char v)
r += (~((v & 2) - 1)) & 10;
r += (~((v & 4) - 1)) & 100;
r += (~((v & 8) - 1)) & 1000;
r += (~((v & 16) - 1)) & 10000;
r += (~((v & 32) - 1)) & 100000;
r += (~((v & 64) - 1)) & 1000000;
r += (~((v & 128) - 1)) & 10000000;
r += (~((v & 16) - 1)) & 10'000;
r += (~((v & 32) - 1)) & 100'000;
r += (~((v & 64) - 1)) & 1'000'000;
r += (~((v & 128) - 1)) & 10'000'000;
return r;
}

View file

@ -827,6 +827,17 @@ std::string vlog_identifier(std::string str)
return str;
}
void event2vl_wire(std::string &edge, LibertyExpression& parsed, const std::string& wire)
{
edge.clear();
if (parsed.kind == LibertyExpression::Kind::NOT) {
edge = "negedge " + wire;
// parsed = parsed.children[0];
} else {
edge = "posedge " + wire;
}
}
void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
{
edge.clear();
@ -843,33 +854,160 @@ void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
}
}
void clear_preset_var(std::string var, std::string type)
enum ClearPresetVar {
Error,
L,
H,
T,
X,
};
ClearPresetVar clear_preset_var(std::string type)
{
if (type.find('L') != std::string::npos) {
return ClearPresetVar::L;
}
if (type.find('H') != std::string::npos) {
return ClearPresetVar::H;
}
if (type.find('T') != std::string::npos) {
return ClearPresetVar::T;
}
if (type.find('X') != std::string::npos) {
return ClearPresetVar::X;
}
return ClearPresetVar::X;
}
void print_clear_preset_var(std::string var, ClearPresetVar type)
{
if (type == ClearPresetVar::L) {
printf(" %s <= 0;\n", var.c_str());
return;
}
if (type.find('H') != std::string::npos) {
if (type == ClearPresetVar::H) {
printf(" %s <= 1;\n", var.c_str());
return;
}
if (type.find('T') != std::string::npos) {
if (type == ClearPresetVar::T) {
printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
return;
}
if (type.find('X') != std::string::npos) {
if (type == ClearPresetVar::X) {
printf(" %s <= 'bx;\n", var.c_str());
return;
}
}
struct FfEdge {
std::string edge;
std::string expr;
};
struct FfEdges {
FfEdge clock;
FfEdge clear;
FfEdge preset;
std::string edge;
void wired(FfEdge& edge, const LibertyAst* ast, const std::string& wire, const char* tag) {
auto* found = ast->find(tag);
if (!found)
return;
auto lexer = LibertyExpression::Lexer(found->value);
auto expr = LibertyExpression::parse(lexer);
event2vl_wire(edge.edge, expr, wire);
edge.expr = expr.vlog_str();
}
FfEdges(LibertyAst* child, const std::string& clear_wire, const std::string& preset_wire) {
wired(clear, child, clear_wire, "clear");
wired(preset, child, preset_wire, "preset");
event2vl(child->find("clocked_on"), clock.edge, clock.expr);
edge = "";
if (!clock.edge.empty())
edge += (edge.empty() ? "" : ", ") + clock.edge;
if (!clear.edge.empty())
edge += (edge.empty() ? "" : ", ") + clear.edge;
if (!preset.edge.empty())
edge += (edge.empty() ? "" : ", ") + preset.edge;
}
};
struct FfVar {
std::string var;
std::string edge;
FfEdge clear;
FfEdge preset;
// Value for both asserted
const char* clear_preset_var_name;
std::string next_state;
const char* else_prefix = "";
public:
void proc_header() {
printf(" always @(%s) begin\n", edge.c_str());
}
void proc_footer() {
if (*else_prefix)
printf(" end\n");
printf(" end\n");
}
void proc_cond(FfEdge& edge, const char* value) {
printf(" %sif (%s) begin\n", else_prefix, edge.expr.c_str());
printf(" %s <= %s;\n", var.c_str(), value);
printf(" end\n");
else_prefix = "else ";
}
void proc_cond_clear() { proc_cond(clear, "0"); }
void proc_cond_preset() { proc_cond(preset, "1"); }
void proc_next_state() {
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
printf(" %s <= %s;\n", var.c_str(), next_state.c_str());
}
void proc(LibertyAst* child) {
else_prefix = "";
proc_header();
if (!clear.expr.empty() && !preset.expr.empty()) {
ClearPresetVar clear_preset = clear_preset_var(find_non_null(child, clear_preset_var_name)->value);
if (clear_preset == ClearPresetVar::L) {
proc_cond_clear();
proc_cond_preset();
proc_next_state();
proc_footer();
return;
} else if (clear_preset == ClearPresetVar::H) {
// Notice that preset and clear are swapped
proc_cond_preset();
proc_cond_clear();
proc_next_state();
proc_footer();
return;
} else {
// Boo, we have to emit non-synthesizable verilog
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear.expr.c_str(), preset.expr.c_str());
print_clear_preset_var(var, clear_preset);
printf(" end\n");
else_prefix = "else ";
}
}
if (!clear.expr.empty()) {
proc_cond_clear();
}
if (!preset.expr.empty()) {
proc_cond_preset();
}
proc_next_state();
proc_footer();
}
};
void gen_verilogsim_cell(const LibertyAst *ast)
{
if (ast->find("statetable") != NULL)
return;
CHECK_NV(ast->args.size(), == 1);
printf("module %s (", vlog_identifier(ast->args[0]).c_str());
auto module_name = vlog_identifier(ast->args[0]);
printf("module %s (", module_name.c_str());
bool first = true;
for (auto child : ast->children) {
if (child->id != "pin")
@ -883,13 +1021,29 @@ void gen_verilogsim_cell(const LibertyAst *ast)
for (auto child : ast->children) {
if (child->id != "ff" && child->id != "latch")
continue;
printf(" reg ");
first = true;
std::string iq = "";
for (auto arg : child->args) {
if (first)
printf(" reg ");
printf("%s%s", first ? "" : ", ", vlog_identifier(arg).c_str());
if (first)
iq = vlog_identifier(arg);
first = false;
}
printf(";\n");
if (!first)
printf(";\n");
first = true;
for (auto gchild : child->children) {
if (gchild->id == "clear" || gchild->id == "preset") {
if (first)
printf(" wire ");
printf("%s%s_%s", first ? "" : ", ", iq.c_str(), gchild->id.c_str());
first = false;
}
}
if (!first)
printf(";\n");
}
for (auto child : ast->children) {
@ -909,63 +1063,45 @@ void gen_verilogsim_cell(const LibertyAst *ast)
if (child->id != "ff" || child->args.size() != 2)
continue;
std::string iq_var = vlog_identifier(child->args[0]);
std::string iqn_var = vlog_identifier(child->args[1]);
auto iq_name = vlog_identifier(child->args[0]);
auto clear_wire = iq_name + "_clear";
auto preset_wire = iq_name + "_preset";
FfEdges edges(child, clear_wire, preset_wire);
std::string clock_edge, clock_expr;
event2vl(child->find("clocked_on"), clock_edge, clock_expr);
std::string clear_edge, clear_expr;
event2vl(child->find("clear"), clear_edge, clear_expr);
std::string preset_edge, preset_expr;
event2vl(child->find("preset"), preset_edge, preset_expr);
std::string edge = "";
if (!clock_edge.empty())
edge += (edge.empty() ? "" : ", ") + clock_edge;
if (!clear_edge.empty())
edge += (edge.empty() ? "" : ", ") + clear_edge;
if (!preset_edge.empty())
edge += (edge.empty() ? "" : ", ") + preset_edge;
if (edge.empty())
if (edges.edge.empty())
continue;
printf(" always @(%s) begin\n", edge.c_str());
std::string next_state = func2vl(find_non_null(child, "next_state")->value);
std::string not_next_state = std::string("~(") + next_state + ")";
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
if (!clear_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
printf(" %s <= 0;\n", iq_var.c_str());
printf(" %s <= 1;\n", iqn_var.c_str());
printf(" end\n");
else_prefix = "else ";
}
if (!preset_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
printf(" %s <= 1;\n", iq_var.c_str());
printf(" %s <= 0;\n", iqn_var.c_str());
printf(" end\n");
else_prefix = "else ";
}
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
std::string expr = find_non_null(child, "next_state")->value;
printf(" // %s\n", expr.c_str());
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
if (*else_prefix)
printf(" end\n");
printf(" end\n");
if (edges.clear.expr.length())
std::swap(clear_wire, edges.clear.expr);
if (edges.preset.expr.length())
std::swap(preset_wire, edges.preset.expr);
auto iq = FfVar {
.var = vlog_identifier(child->args[0]),
.edge = edges.edge,
.clear = edges.clear,
.preset = edges.preset,
.clear_preset_var_name = "clear_preset_var1",
.next_state = next_state,
};
auto iqn = FfVar {
.var = vlog_identifier(child->args[1]),
.edge = edges.edge,
// Swapped clear and preset
.clear = edges.preset,
.preset = edges.clear,
.clear_preset_var_name = "clear_preset_var2",
.next_state = not_next_state,
};
iq.proc(child);
iqn.proc(child);
if (edges.clear.expr.length())
printf(" assign %s = %s;\n", edges.clear.expr.c_str(), clear_wire.c_str());
if (edges.preset.expr.length())
printf(" assign %s = %s;\n", edges.preset.expr.c_str(), preset_wire.c_str());
}
for (auto child : ast->children)
@ -990,8 +1126,8 @@ void gen_verilogsim_cell(const LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
print_clear_preset_var(iq_var, clear_preset_var(find_non_null(child, "clear_preset_var1")->value));
print_clear_preset_var(iqn_var, clear_preset_var(find_non_null(child, "clear_preset_var2")->value));
printf(" end\n");
else_prefix = "else ";
}

View file

@ -0,0 +1,58 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.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/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Lut2BmuxPass : public Pass {
Lut2BmuxPass() : Pass("lut2bmux", "convert $lut to $bmux") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" lut2bmux [options] [selection]\n");
log("\n");
log("This pass converts $lut cells to $bmux cells.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing LUT2BMUX pass (convert $lut to $bmux).\n");
size_t argidx = 1;
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
for (auto cell : module->selected_cells()) {
if (cell->type == ID($lut)) {
cell->type = ID($bmux);
cell->setPort(ID::S, cell->getPort(ID::A));
cell->setPort(ID::A, cell->getParam(ID::LUT));
cell->unsetParam(ID::LUT);
cell->fixup_parameters();
log("Converted %s.%s to BMUX cell.\n", log_id(module), log_id(cell));
}
}
}
} Lut2BmuxPass;
PRIVATE_NAMESPACE_END

View file

@ -23,7 +23,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
int lut2mux(Cell *cell)
int lut2mux(Cell *cell, bool word_mode)
{
SigSpec sig_a = cell->getPort(ID::A);
SigSpec sig_y = cell->getPort(ID::Y);
@ -32,7 +32,10 @@ int lut2mux(Cell *cell)
if (GetSize(sig_a) == 1)
{
cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
if (!word_mode)
cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
else
cell->module->addMux(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
}
else
{
@ -44,10 +47,13 @@ int lut2mux(Cell *cell)
Const lut1 = lut.extract(0, GetSize(lut)/2);
Const lut2 = lut.extract(GetSize(lut)/2, GetSize(lut)/2);
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y1, lut1));
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y2, lut2));
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y1, lut1), word_mode);
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y2, lut2), word_mode);
cell->module->addMuxGate(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
if (!word_mode)
cell->module->addMuxGate(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
else
cell->module->addMux(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
}
cell->module->remove(cell);
@ -55,26 +61,33 @@ int lut2mux(Cell *cell)
}
struct Lut2muxPass : public Pass {
Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { }
Lut2muxPass() : Pass("lut2mux", "convert $lut to $mux/$_MUX_") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" lut2mux [options] [selection]\n");
log("\n");
log("This pass converts $lut cells to $_MUX_ gates.\n");
log("This pass converts $lut cells to $mux/$_MUX_ gates.\n");
log("\n");
log(" -word\n");
log(" Convert $lut cells with a single input to word-level $mux gates.\n");
log(" The default is to convert them to bit-level $_MUX_ gates.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
log_header(design, "Executing LUT2MUX pass (convert $lut to $mux/$_MUX_).\n");
log("ARGS:"); for (auto &a: args) log(" [%s]", a.c_str()); log("\n");
size_t argidx;
bool word_mode = false;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-v") {
// continue;
// }
if (args[argidx] == "-word") {
word_mode = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -83,7 +96,7 @@ struct Lut2muxPass : public Pass {
for (auto cell : module->selected_cells()) {
if (cell->type == ID($lut)) {
IdString cell_name = cell->name;
int count = lut2mux(cell);
int count = lut2mux(cell, word_mode);
log("Converted %s.%s to %d MUX cells.\n", log_id(module), log_id(cell_name), count);
}
}

View file

@ -27,7 +27,7 @@
USING_YOSYS_NAMESPACE
YOSYS_NAMESPACE_BEGIN
static void transfer_attr (Cell* to, const Cell* from, const IdString& attr) {
static void transfer_attr (Cell* to, const Cell* from, IdString attr) {
if (from->has_attribute(attr))
to->attributes[attr] = from->attributes.at(attr);
}

View file

@ -333,9 +333,6 @@ struct TechmapWorker
RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
design->select(module, c);
if (c->type.begins_with("\\$"))
c->type = c->type.substr(1);
if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) {
c->type = RTLIL::escape_id(tpl_cell->get_string_attribute(ID::techmap_chtype));
@ -436,13 +433,9 @@ struct TechmapWorker
if (handled_cells.count(cell) > 0)
continue;
std::string cell_type = cell->type.str();
if (in_recursion && cell->type.begins_with("\\$"))
cell_type = cell_type.substr(1);
if (celltypeMap.count(cell_type) == 0) {
if (assert_mode && cell_type.back() != '_')
log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type));
if (celltypeMap.count(cell->type) == 0) {
if (assert_mode && !cell->type.ends_with("_"))
log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell->type));
continue;
}
@ -454,7 +447,7 @@ struct TechmapWorker
if (GetSize(sig) == 0)
continue;
for (auto &tpl_name : celltypeMap.at(cell_type)) {
for (auto &tpl_name : celltypeMap.at(cell->type)) {
RTLIL::Module *tpl = map->module(tpl_name);
RTLIL::Wire *port = tpl->wire(conn.first);
if (port && port->port_input)
@ -481,12 +474,7 @@ struct TechmapWorker
log_assert(cell == module->cell(cell->name));
bool mapped_cell = false;
std::string cell_type = cell->type.str();
if (in_recursion && cell->type.begins_with("\\$"))
cell_type = cell_type.substr(1);
for (auto &tpl_name : celltypeMap.at(cell_type))
for (auto &tpl_name : celltypeMap.at(cell->type))
{
IdString derived_name = tpl_name;
RTLIL::Module *tpl = map->module(tpl_name);
@ -508,8 +496,6 @@ struct TechmapWorker
if (!extmapper_name.empty())
{
cell->type = cell_type;
if ((extern_mode && !in_recursion) || extmapper_name == "wrap")
{
std::string m_name = stringf("$extern:%s:%s", extmapper_name, log_id(cell->type));
@ -935,11 +921,6 @@ struct TechmapWorker
RTLIL::Module *m = design->addModule(m_name);
tpl->cloneInto(m);
for (auto cell : m->cells()) {
if (cell->type.begins_with("\\$"))
cell->type = cell->type.substr(1);
}
module_queue.insert(m);
}
@ -1168,7 +1149,7 @@ struct TechmapPass : public Pass {
std::vector<std::string> map_files;
std::vector<RTLIL::IdString> dont_map;
std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
std::string verilog_frontend = "verilog -nooverwrite -noblackbox -icells";
int max_iter = -1;
size_t argidx;