3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-23 09:05:32 +00:00

Merge branch 'master' into clk2ff-better-names

This commit is contained in:
Claire Xen 2022-02-11 16:03:12 +01:00 committed by GitHub
commit 49545c73f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
757 changed files with 49469 additions and 8717 deletions

29
kernel/binding.cc Normal file
View file

@ -0,0 +1,29 @@
/*
* 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 "binding.h"
YOSYS_NAMESPACE_BEGIN
RTLIL::Binding::Binding(RTLIL::IdString target_type,
RTLIL::IdString target_name)
: target_type(target_type), target_name(target_name)
{}
YOSYS_NAMESPACE_END

60
kernel/binding.h Normal file
View file

@ -0,0 +1,60 @@
/* -*- c++ -*-
* 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.
*
*/
#ifndef BINDING_H
#define BINDING_H
#include "kernel/rtlil.h"
YOSYS_NAMESPACE_BEGIN
struct RTLIL::Binding
{
// Represents a bind construct.
//
// The target of the binding is represented by target_type and
// target_name (see comments above the fields).
Binding(RTLIL::IdString target_type,
RTLIL::IdString target_name);
virtual ~Binding() {}
// Return a string describing the binding
virtual std::string describe() const = 0;
protected:
// May be empty. If not, it's the name of the module or interface to
// bind to.
RTLIL::IdString target_type;
// If target_type is nonempty (the usual case), this is a hierarchical
// reference to the bind target. If target_type is empty, we have to
// wait until the hierarchy pass to figure out whether this was the name
// of a module/interface type or an instance.
RTLIL::IdString target_name;
// An attribute name which contains an ID that's unique across binding
// instances (used to ensure we don't apply a binding twice to a module)
RTLIL::IdString attr_name;
};
YOSYS_NAMESPACE_END
#endif

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -609,5 +609,56 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo
return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
}
RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
{
std::vector<RTLIL::State> t = arg1.bits;
for (int i = GetSize(arg2)-1; i >= 0; i--)
{
RTLIL::State sel = arg2.bits.at(i);
std::vector<RTLIL::State> new_t;
if (sel == State::S0)
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
else if (sel == State::S1)
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
else
for (int j = 0; j < GetSize(t)/2; j++)
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
t.swap(new_t);
}
return t;
}
RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
{
int width = GetSize(arg1);
int s_width = GetSize(arg2);
std::vector<RTLIL::State> res;
for (int i = 0; i < (1 << s_width); i++)
{
bool ne = false;
bool x = false;
for (int j = 0; j < s_width; j++) {
bool bit = i & 1 << j;
if (arg2[j] == (bit ? RTLIL::S0 : RTLIL::S1))
ne = true;
else if (arg2[j] != RTLIL::S0 && arg2[j] != RTLIL::S1)
x = true;
}
if (ne) {
for (int j = 0; j < width; j++)
res.push_back(State::S0);
} else if (x) {
for (int j = 0; j < width; j++)
res.push_back(arg1.bits[j] == State::S0 ? State::S0 : State::Sx);
} else {
for (int j = 0; j < width; j++)
res.push_back(arg1.bits[j]);
}
}
return res;
}
YOSYS_NAMESPACE_END

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -142,6 +142,36 @@ void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
}
}
void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
int width = GetSize(cell->getPort(ID::Y));
int a_width = GetSize(cell->getPort(ID::A));
int s_width = GetSize(cell->getPort(ID::S));
for (int i = 0; i < width; i++)
{
for (int k = i; k < a_width; k += width)
db->add_edge(cell, ID::A, k, ID::Y, i, -1);
for (int k = 0; k < s_width; k++)
db->add_edge(cell, ID::S, k, ID::Y, i, -1);
}
}
void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
int width = GetSize(cell->getPort(ID::Y));
int a_width = GetSize(cell->getPort(ID::A));
int s_width = GetSize(cell->getPort(ID::S));
for (int i = 0; i < width; i++)
{
db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1);
for (int k = 0; k < s_width; k++)
db->add_edge(cell, ID::S, k, ID::Y, i, -1);
}
}
PRIVATE_NAMESPACE_END
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
@ -187,6 +217,16 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
return true;
}
if (cell->type == ID($bmux)) {
bmux_op(this, cell);
return true;
}
if (cell->type == ID($demux)) {
demux_op(this, cell);
return true;
}
// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
// FIXME: $lut $sop $alu $lcu $macc $fa

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -127,6 +127,9 @@ struct CellTypes
for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);
for (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))
setup_type(type, {ID::A, ID::S}, {ID::Y}, true);
setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
@ -142,6 +145,8 @@ struct CellTypes
setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q});
setup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q});
setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q});
setup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q});
setup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q});
setup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q});
setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});
setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});
@ -155,9 +160,13 @@ struct CellTypes
setup_internals_ff();
setup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA});
setup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA});
setup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
setup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
setup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
setup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool<RTLIL::IdString>());
setup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});
setup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});
setup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT});
}
@ -220,6 +229,15 @@ struct CellTypes
for (auto c4 : list_np)
setup_type(stringf("$_DFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
setup_type(stringf("$_ALDFF_%c%c_", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
setup_type(stringf("$_ALDFFE_%c%c%c_", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
@ -396,6 +414,16 @@ struct CellTypes
return ret;
}
if (cell->type == ID($bmux))
{
return const_bmux(arg1, arg2);
}
if (cell->type == ID($demux))
{
return const_demux(arg1, arg2);
}
if (cell->type == ID($lut))
{
int width = cell->parameters.at(ID::WIDTH).as_int();
@ -405,21 +433,7 @@ struct CellTypes
t.push_back(State::S0);
t.resize(1 << width);
for (int i = width-1; i >= 0; i--) {
RTLIL::State sel = arg1.bits.at(i);
std::vector<RTLIL::State> new_t;
if (sel == State::S0)
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
else if (sel == State::S1)
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
else
for (int j = 0; j < GetSize(t)/2; j++)
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
t.swap(new_t);
}
log_assert(GetSize(t) == 1);
return t;
return const_bmux(t, arg1);
}
if (cell->type == ID($sop))

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -135,8 +135,6 @@ struct ConstEval
if (cell->hasPort(ID::S)) {
sig_s = cell->getPort(ID::S);
if (!eval(sig_s, undef, cell))
return false;
}
if (cell->hasPort(ID::A))
@ -151,6 +149,9 @@ struct ConstEval
int count_maybe_set_s_bits = 0;
int count_set_s_bits = 0;
if (!eval(sig_s, undef, cell))
return false;
for (int i = 0; i < sig_s.size(); i++)
{
RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
@ -198,6 +199,36 @@ struct ConstEval
else
set(sig_y, y_values.front());
}
else if (cell->type == ID($bmux))
{
if (!eval(sig_s, undef, cell))
return false;
if (sig_s.is_fully_def()) {
int sel = sig_s.as_int();
int width = GetSize(sig_y);
SigSpec res = sig_a.extract(sel * width, width);
if (!eval(res, undef, cell))
return false;
set(sig_y, res.as_const());
} else {
if (!eval(sig_a, undef, cell))
return false;
set(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));
}
}
else if (cell->type == ID($demux))
{
if (!eval(sig_a, undef, cell))
return false;
if (sig_a.is_fully_zero()) {
set(sig_y, Const(0, GetSize(sig_y)));
} else {
if (!eval(sig_s, undef, cell))
return false;
set(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));
}
}
else if (cell->type == ID($fa))
{
RTLIL::SigSpec sig_c = cell->getPort(ID::C);

View file

@ -11,9 +11,12 @@ X(abc9_mergeability)
X(abc9_scc_id)
X(abcgroup)
X(ABITS)
X(AD)
X(ADDR)
X(allconst)
X(allseq)
X(ALOAD)
X(ALOAD_POLARITY)
X(always_comb)
X(always_ff)
X(always_latch)
@ -32,6 +35,7 @@ X(bugpoint_keep)
X(B_WIDTH)
X(C)
X(cells_not_processed)
X(CE_OVER_SRST)
X(CFG_ABITS)
X(CFG_DBITS)
X(CFG_INIT)
@ -46,6 +50,7 @@ X(CLK_POLARITY)
X(CLR)
X(CLR_POLARITY)
X(CO)
X(COLLISION_X_MASK)
X(CONFIG)
X(CONFIG_WIDTH)
X(CTRL_IN)
@ -95,6 +100,7 @@ X(hdlname)
X(hierconn)
X(I)
X(INIT)
X(INIT_VALUE)
X(init)
X(initial_top)
X(interface_modport)
@ -133,19 +139,31 @@ X(onehot)
X(P)
X(parallel_case)
X(parameter)
X(PORTID)
X(PRIORITY)
X(PRIORITY_MASK)
X(Q)
X(qwp_position)
X(R)
X(RD_ADDR)
X(RD_ARST)
X(RD_ARST_VALUE)
X(RD_CE_OVER_SRST)
X(RD_CLK)
X(RD_CLK_ENABLE)
X(RD_CLK_POLARITY)
X(RD_COLLISION_X_MASK)
X(RD_DATA)
X(RD_EN)
X(RD_INIT_VALUE)
X(RD_PORTS)
X(RD_SRST)
X(RD_SRST_VALUE)
X(RD_TRANSPARENCY_MASK)
X(RD_TRANSPARENT)
X(RD_WIDE_CONTINUATION)
X(reg)
X(reprocess_after)
X(S)
X(SET)
X(SET_POLARITY)
@ -161,6 +179,7 @@ X(SRC_WIDTH)
X(SRST)
X(SRST_POLARITY)
X(SRST_VALUE)
X(sta_arrival)
X(STATE_BITS)
X(STATE_NUM)
X(STATE_NUM_LOG2)
@ -195,6 +214,7 @@ X(T_LIMIT_TYP)
X(to_delete)
X(top)
X(TRANS_NUM)
X(TRANSPARENCY_MASK)
X(TRANSPARENT)
X(TRANS_TABLE)
X(T_RISE_MAX)
@ -220,6 +240,8 @@ X(WR_CLK_POLARITY)
X(WR_DATA)
X(WR_EN)
X(WR_PORTS)
X(WR_PRIORITY_MASK)
X(WR_WIDE_CONTINUATION)
X(X)
X(Y)
X(Y_WIDTH)

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -118,7 +118,7 @@ int main(int argc, char **argv)
if (argc == 2)
{
// Run the first argument as a script file
run_frontend(argv[1], "script", 0, 0, 0);
run_frontend(argv[1], "script");
}
}
@ -202,12 +202,13 @@ int main(int argc, char **argv)
std::string output_filename = "";
std::string scriptfile = "";
std::string depsfile = "";
std::string topmodule = "";
bool scriptfile_tcl = false;
bool got_output_filename = false;
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
bool timing_details = false;
bool run_shell = true;
bool mode_v = false;
bool mode_q = false;
@ -288,6 +289,9 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
printf(" -r <module_name>\n");
printf(" elaborate command line arguments using the specified top module\n");
printf("\n");
printf(" -D <macro>[=<value>]\n");
printf(" set the specified Verilog define (via \"read -define\")\n");
printf("\n");
@ -342,7 +346,7 @@ int main(int argc, char **argv)
}
int opt;
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:x:")) != -1)
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:")) != -1)
{
switch (opt)
{
@ -366,6 +370,7 @@ int main(int argc, char **argv)
exit(0);
case 'S':
passes_commands.push_back("synth");
run_shell = false;
break;
case 'g':
log_force_debug++;
@ -378,19 +383,23 @@ int main(int argc, char **argv)
break;
case 'H':
passes_commands.push_back("help");
run_shell = false;
break;
case 'h':
passes_commands.push_back(stringf("help %s", optarg));
run_shell = false;
break;
case 'b':
backend_command = optarg;
run_shell = false;
break;
case 'p':
passes_commands.push_back(optarg);
run_shell = false;
break;
case 'o':
output_filename = optarg;
got_output_filename = true;
run_shell = false;
break;
case 'l':
case 'L':
@ -422,10 +431,12 @@ int main(int argc, char **argv)
case 's':
scriptfile = optarg;
scriptfile_tcl = false;
run_shell = false;
break;
case 'c':
scriptfile = optarg;
scriptfile_tcl = true;
run_shell = false;
break;
case 'W':
log_warn_regexes.push_back(YS_REGEX_COMPILE(optarg));
@ -436,6 +447,9 @@ int main(int argc, char **argv)
case 'e':
log_werror_regexes.push_back(YS_REGEX_COMPILE(optarg));
break;
case 'r':
topmodule = optarg;
break;
case 'D':
vlog_defines.push_back(optarg);
break;
@ -506,12 +520,6 @@ int main(int argc, char **argv)
for (auto &fn : plugin_filenames)
load_plugin(fn, {});
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
if (!got_output_filename)
backend_command = "";
shell(yosys_design);
}
if (!vlog_defines.empty()) {
std::string vdef_cmd = "read -define";
for (auto vdef : vlog_defines)
@ -520,7 +528,11 @@ int main(int argc, char **argv)
}
while (optind < argc)
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
if (run_frontend(argv[optind++], frontend_command))
run_shell = false;
if (!topmodule.empty())
run_pass("hierarchy -top " + topmodule);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@ -531,13 +543,15 @@ int main(int argc, char **argv)
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
#endif
} else
run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
run_frontend(scriptfile, "script");
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it);
if (!backend_command.empty())
if (run_shell)
shell(yosys_design);
else
run_backend(output_filename, backend_command);
yosys_design->check();

755
kernel/ff.cc Normal file
View file

@ -0,0 +1,755 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
*
* 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/ff.h"
USING_YOSYS_NAMESPACE
FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name)
{
cell = cell_;
sig_q = cell->getPort(ID::Q);
width = GetSize(sig_q);
attributes = cell->attributes;
if (initvals)
val_init = (*initvals)(sig_q);
std::string type_str = cell->type.str();
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
if (cell->type == ID($ff)) {
has_gclk = true;
sig_d = cell->getPort(ID::D);
} else if (cell->type == ID($sr)) {
// No data input at all.
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
has_aload = true;
sig_aload = cell->getPort(ID::EN);
pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
sig_ad = cell->getPort(ID::D);
} else {
has_clk = true;
sig_clk = cell->getPort(ID::CLK);
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
sig_d = cell->getPort(ID::D);
}
if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
has_ce = true;
sig_ce = cell->getPort(ID::EN);
pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
}
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
has_sr = true;
sig_clr = cell->getPort(ID::CLR);
sig_set = cell->getPort(ID::SET);
pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
}
if (cell->type.in(ID($aldff), ID($aldffe))) {
has_aload = true;
sig_aload = cell->getPort(ID::ALOAD);
pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
sig_ad = cell->getPort(ID::AD);
}
if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
has_arst = true;
sig_arst = cell->getPort(ID::ARST);
pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
val_arst = cell->getParam(ID::ARST_VALUE);
}
if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
has_srst = true;
sig_srst = cell->getPort(ID::SRST);
pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
val_srst = cell->getParam(ID::SRST_VALUE);
ce_over_srst = cell->type == ID($sdffce);
}
} else if (cell->type == ID($_FF_)) {
is_fine = true;
has_gclk = true;
sig_d = cell->getPort(ID::D);
} else if (type_str.substr(0, 5) == "$_SR_") {
is_fine = true;
has_sr = true;
pol_set = type_str[5] == 'P';
pol_clr = type_str[6] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_ce = true;
pol_ce = type_str[8] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[7] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[8] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[8] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[10] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::L);
sig_ad = cell->getPort(ID::AD);
} else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_aload = true;
pol_aload = type_str[10] == 'P';
sig_aload = cell->getPort(ID::L);
sig_ad = cell->getPort(ID::AD);
has_ce = true;
pol_ce = type_str[11] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[9] == 'P';
pol_clr = type_str[10] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[10] == 'P';
pol_clr = type_str[11] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
has_ce = true;
pol_ce = type_str[12] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[8] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[9] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[9] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[11] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[10] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[12] == 'P';
sig_ce = cell->getPort(ID::E);
ce_over_srst = true;
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::E);
has_arst = true;
pol_arst = type_str[10] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[11] == 'P';
sig_aload = cell->getPort(ID::E);
has_sr = true;
pol_set = type_str[12] == 'P';
pol_clr = type_str[13] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else {
log_assert(0);
}
if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
// Plain D latches with const D treated specially.
has_aload = false;
has_arst = true;
sig_arst = sig_aload;
pol_arst = pol_aload;
val_arst = sig_ad.as_const();
}
}
FfData FfData::slice(const std::vector<int> &bits) {
FfData res(module, initvals, NEW_ID);
res.sig_clk = sig_clk;
res.sig_ce = sig_ce;
res.sig_aload = sig_aload;
res.sig_arst = sig_arst;
res.sig_srst = sig_srst;
res.has_clk = has_clk;
res.has_gclk = has_gclk;
res.has_ce = has_ce;
res.has_aload = has_aload;
res.has_arst = has_arst;
res.has_srst = has_srst;
res.has_sr = has_sr;
res.ce_over_srst = ce_over_srst;
res.is_fine = is_fine;
res.pol_clk = pol_clk;
res.pol_ce = pol_ce;
res.pol_aload = pol_aload;
res.pol_arst = pol_arst;
res.pol_srst = pol_srst;
res.pol_clr = pol_clr;
res.pol_set = pol_set;
res.attributes = attributes;
for (int i : bits) {
res.sig_q.append(sig_q[i]);
if (has_clk || has_gclk)
res.sig_d.append(sig_d[i]);
if (has_aload)
res.sig_ad.append(sig_ad[i]);
if (has_sr) {
res.sig_clr.append(sig_clr[i]);
res.sig_set.append(sig_set[i]);
}
if (has_arst)
res.val_arst.bits.push_back(val_arst[i]);
if (has_srst)
res.val_srst.bits.push_back(val_srst[i]);
if (initvals)
res.val_init.bits.push_back(val_init[i]);
}
res.width = GetSize(res.sig_q);
return res;
}
void FfData::add_dummy_ce() {
if (has_ce)
return;
has_ce = true;
pol_ce = true;
sig_ce = State::S1;
ce_over_srst = false;
}
void FfData::add_dummy_srst() {
if (has_srst)
return;
has_srst = true;
pol_srst = true;
sig_srst = State::S0;
val_srst = Const(State::Sx, width);
ce_over_srst = false;
}
void FfData::add_dummy_arst() {
if (has_arst)
return;
has_arst = true;
pol_arst = true;
sig_arst = State::S0;
val_arst = Const(State::Sx, width);
}
void FfData::add_dummy_aload() {
if (has_aload)
return;
has_aload = true;
pol_aload = true;
sig_aload = State::S0;
sig_ad = Const(State::Sx, width);
}
void FfData::add_dummy_sr() {
if (has_sr)
return;
has_sr = true;
pol_clr = true;
pol_set = true;
sig_clr = Const(State::S0, width);
sig_set = Const(State::S0, width);
}
void FfData::add_dummy_clk() {
if (has_clk)
return;
has_clk = true;
pol_clk = true;
sig_clk = State::S0;
sig_d = Const(State::Sx, width);
}
void FfData::arst_to_aload() {
log_assert(has_arst);
log_assert(!has_aload);
pol_aload = pol_arst;
sig_aload = sig_arst;
sig_ad = val_arst;
has_aload = true;
has_arst = false;
}
void FfData::arst_to_sr() {
log_assert(has_arst);
log_assert(!has_sr);
pol_clr = pol_arst;
pol_set = pol_arst;
sig_clr = Const(pol_arst ? State::S0 : State::S1, width);
sig_set = Const(pol_arst ? State::S0 : State::S1, width);
has_sr = true;
has_arst = false;
for (int i = 0; i < width; i++) {
if (val_arst[i] == State::S1)
sig_set[i] = sig_arst;
else
sig_clr[i] = sig_arst;
}
}
void FfData::aload_to_sr() {
log_assert(has_aload);
log_assert(!has_sr);
has_sr = true;
has_aload = false;
if (!is_fine) {
pol_clr = false;
pol_set = true;
if (pol_aload) {
sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload);
sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload);
} else {
sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload);
sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload);
}
} else {
pol_clr = pol_aload;
pol_set = pol_aload;
if (pol_aload) {
sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad);
sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad);
} else {
sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad);
sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad);
}
}
}
void FfData::convert_ce_over_srst(bool val) {
if (!has_ce || !has_srst || ce_over_srst == val)
return;
if (val) {
// sdffe to sdffce
if (!is_fine) {
if (pol_ce) {
if (pol_srst) {
sig_ce = module->Or(NEW_ID, sig_ce, sig_srst);
} else {
SigSpec tmp = module->Not(NEW_ID, sig_srst);
sig_ce = module->Or(NEW_ID, sig_ce, tmp);
}
} else {
if (pol_srst) {
SigSpec tmp = module->Not(NEW_ID, sig_srst);
sig_ce = module->And(NEW_ID, sig_ce, tmp);
} else {
sig_ce = module->And(NEW_ID, sig_ce, sig_srst);
}
}
} else {
if (pol_ce) {
if (pol_srst) {
sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst);
} else {
sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst);
}
} else {
if (pol_srst) {
sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst);
} else {
sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst);
}
}
}
} else {
// sdffce to sdffe
if (!is_fine) {
if (pol_srst) {
if (pol_ce) {
sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce);
} else {
SigSpec tmp = module->Not(NEW_ID, sig_ce);
sig_srst = cell->module->And(NEW_ID, sig_srst, tmp);
}
} else {
if (pol_ce) {
SigSpec tmp = module->Not(NEW_ID, sig_ce);
sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp);
} else {
sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce);
}
}
} else {
if (pol_srst) {
if (pol_ce) {
sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce);
} else {
sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce);
}
} else {
if (pol_ce) {
sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce);
} else {
sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce);
}
}
}
}
ce_over_srst = val;
}
void FfData::unmap_ce() {
if (!has_ce)
return;
log_assert(has_clk);
if (has_srst && ce_over_srst)
unmap_srst();
if (!is_fine) {
if (pol_ce)
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
else
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
} else {
if (pol_ce)
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
else
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
}
has_ce = false;
}
void FfData::unmap_srst() {
if (!has_srst)
return;
if (has_ce && !ce_over_srst)
unmap_ce();
if (!is_fine) {
if (pol_srst)
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
else
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
} else {
if (pol_srst)
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
else
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
}
has_srst = false;
}
Cell *FfData::emit() {
remove();
if (!width)
return nullptr;
if (!has_aload && !has_clk && !has_gclk && !has_sr) {
if (has_arst) {
// Convert this case to a D latch.
arst_to_aload();
} else {
// No control inputs left. Turn into a const driver.
module->connect(sig_q, val_init);
return nullptr;
}
}
if (initvals)
initvals->set_init(sig_q, val_init);
if (!is_fine) {
if (has_gclk) {
log_assert(!has_clk);
log_assert(!has_ce);
log_assert(!has_aload);
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFf(name, sig_d, sig_q);
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
else if (has_arst)
cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
else
cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
} else {
if (has_sr) {
if (has_ce)
cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
else
cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
if (has_ce)
cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
else
cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
} else if (has_aload) {
if (has_ce)
cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
else
cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
} else if (has_srst) {
if (has_ce)
if (ce_over_srst)
cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
else
cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
else
cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
} else {
if (has_ce)
cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
else
cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
}
}
} else {
if (has_gclk) {
log_assert(!has_clk);
log_assert(!has_ce);
log_assert(!has_aload);
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFfGate(name, sig_d, sig_q);
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
else if (has_arst)
cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
else
cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
} else {
if (has_sr) {
if (has_ce)
cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
else
cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
if (has_ce)
cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
else
cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
} else if (has_aload) {
if (has_ce)
cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
else
cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
} else if (has_srst) {
if (has_ce)
if (ce_over_srst)
cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
else
cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
else
cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
} else {
if (has_ce)
cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
else
cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
}
}
}
cell->attributes = attributes;
return cell;
}
void FfData::remove() {
if (cell) {
remove_init();
module->remove(cell);
cell = nullptr;
}
}
namespace {
State invert(State s) {
switch (s) {
case State::S0: return State::S1;
case State::S1: return State::S0;
default: return s;
}
}
}
void FfData::flip_bits(const pool<int> &bits) {
if (!bits.size())
return;
remove_init();
Wire *new_q = module->addWire(NEW_ID, width);
for (auto bit: bits) {
if (has_arst)
val_arst[bit] = invert(val_arst[bit]);
if (has_srst)
val_srst[bit] = invert(val_srst[bit]);
val_init[bit] = invert(val_init[bit]);
}
if (has_sr && cell) {
log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
}
if (is_fine) {
if (has_sr) {
bool new_pol_clr = pol_set;
SigSpec new_sig_clr;
if (pol_set) {
if (pol_clr) {
new_sig_clr = module->AndnotGate(NEW_ID, sig_set, sig_clr);
} else {
new_sig_clr = module->AndGate(NEW_ID, sig_set, sig_clr);
}
} else {
if (pol_clr) {
new_sig_clr = module->OrGate(NEW_ID, sig_set, sig_clr);
} else {
new_sig_clr = module->OrnotGate(NEW_ID, sig_set, sig_clr);
}
}
pol_set = pol_clr;
sig_set = sig_clr;
pol_clr = new_pol_clr;
sig_clr = new_sig_clr;
}
if (has_clk || has_gclk)
sig_d = module->NotGate(NEW_ID, sig_d);
if (has_aload)
sig_ad = module->NotGate(NEW_ID, sig_ad);
module->addNotGate(NEW_ID, new_q, sig_q);
}
else
{
if (has_sr) {
SigSpec not_clr;
if (!pol_clr) {
not_clr = sig_clr;
sig_clr = module->Not(NEW_ID, sig_clr);
pol_clr = true;
} else {
not_clr = module->Not(NEW_ID, sig_clr);
}
if (!pol_set) {
sig_set = module->Not(NEW_ID, sig_set);
pol_set = true;
}
SigSpec masked_set = module->And(NEW_ID, sig_set, not_clr);
for (auto bit: bits) {
sig_set[bit] = sig_clr[bit];
sig_clr[bit] = masked_set[bit];
}
}
Const mask = Const(State::S0, width);
for (auto bit: bits)
mask.bits[bit] = State::S1;
if (has_clk || has_gclk)
sig_d = module->Xor(NEW_ID, sig_d, mask);
if (has_aload)
sig_ad = module->Xor(NEW_ID, sig_ad, mask);
module->addXor(NEW_ID, new_q, mask, sig_q);
}
sig_q = new_q;
}

View file

@ -25,460 +25,190 @@
YOSYS_NAMESPACE_BEGIN
// Describes a flip-flop or a latch.
//
// If has_gclk, this is a formal verification FF with implicit global clock:
// Q is simply previous cycle's D.
//
// Otherwise, the FF/latch can have any number of features selected by has_*
// attributes that determine Q's value (in order of decreasing priority):
//
// - on start, register is initialized to val_init
// - if has_sr is present:
// - sig_clr is per-bit async clear, and sets the corresponding bit to 0
// if active
// - sig_set is per-bit async set, and sets the corresponding bit to 1
// if active
// - if has_arst is present:
// - sig_arst is whole-reg async reset, and sets the whole register to val_arst
// - if has_aload is present:
// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole
// register to sig_ad
// - if has_clk is present, and we're currently on a clock edge:
// - if has_ce is present and ce_over_srst is true:
// - ignore clock edge (don't change value) unless sig_ce is active
// - if has_srst is present:
// - sig_srst is whole-reg sync reset and sets the register to val_srst
// - if has_ce is present and ce_over_srst is false:
// - ignore clock edge (don't change value) unless sig_ce is active
// - set whole reg to sig_d
// - if nothing of the above applies, the reg value remains unchanged
//
// Since the yosys FF cell library isn't fully generic, not all combinations
// of the features above can be supported:
//
// - only one of has_srst, has_arst, has_sr can be used
// - if has_clk is used together with has_aload, then has_srst, has_arst,
// has_sr cannot be used
//
// The valid feature combinations are thus:
//
// - has_clk + optional has_ce [dff/dffe]
// - has_clk + optional has_ce + has_arst [adff/adffe]
// - has_clk + optional has_ce + has_aload [aldff/aldffe]
// - has_clk + optional has_ce + has_sr [dffsr/dffsre]
// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce]
// - has_aload [dlatch]
// - has_aload + has_arst [adlatch]
// - has_aload + has_sr [dlatchsr]
// - has_sr [sr]
// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
// - empty set [not a cell — will be emitted as a simple direct connection]
struct FfData {
Module *module;
FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output.
SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
// The async data input, present if has_aload.
SigSpec sig_ad;
// The sync clock, present if has_clk.
SigSpec sig_clk;
SigSpec sig_en;
// The clock enable, present if has_ce.
SigSpec sig_ce;
// The async load enable, present if has_aload.
SigSpec sig_aload;
// The async reset, preset if has_arst.
SigSpec sig_arst;
// The sync reset, preset if has_srst.
SigSpec sig_srst;
// The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
// The async set (per-lane), present if has_sr.
SigSpec sig_set;
bool has_d;
// True if this is a clocked (edge-sensitive) flip-flop.
bool has_clk;
bool has_en;
// True if this is a $ff, exclusive with every other has_*.
bool has_gclk;
// True if this FF has a clock enable. Depends on has_clk.
bool has_ce;
// True if this FF has async load function — this includes D latches.
// If this and has_clk are both set, has_arst and has_sr cannot be set.
bool has_aload;
// True if this FF has sync set/reset. Depends on has_clk, exclusive
// with has_arst, has_sr, has_aload.
bool has_srst;
// True if this FF has async set/reset. Exclusive with has_srst,
// has_sr. If this and has_clk are both set, has_aload cannot be set.
bool has_arst;
// True if this FF has per-bit async set + clear. Exclusive with
// has_srst, has_arst. If this and has_clk are both set, has_aload
// cannot be set.
bool has_sr;
// If has_ce and has_srst are both set, determines their relative
// priorities: if true, inactive ce disables srst; if false, srst
// operates independent of ce.
bool ce_over_srst;
// True if this FF is a fine cell, false if it is a coarse cell.
// If true, width must be 1.
bool is_fine;
// Polarities, corresponding to sig_*. True means active-high, false
// means active-low.
bool pol_clk;
bool pol_en;
bool pol_ce;
bool pol_aload;
bool pol_arst;
bool pol_srst;
bool pol_clr;
bool pol_set;
// The value loaded by sig_arst.
Const val_arst;
// The value loaded by sig_srst.
Const val_srst;
// The initial value at power-up.
Const val_init;
Const val_d;
bool d_is_const;
// The FF data width in bits.
int width;
dict<IdString, Const> attributes;
FfData(FfInitVals *initvals, Cell *cell = nullptr) : initvals(initvals) {
FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
width = 0;
has_d = true;
has_clk = false;
has_en = false;
has_gclk = false;
has_ce = false;
has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
pol_clk = false;
pol_en = false;
pol_aload = false;
pol_ce = false;
pol_arst = false;
pol_srst = false;
pol_clr = false;
pol_set = false;
d_is_const = false;
if (!cell)
return;
sig_q = cell->getPort(ID::Q);
width = GetSize(sig_q);
attributes = cell->attributes;
if (initvals)
val_init = (*initvals)(sig_q);
std::string type_str = cell->type.str();
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
if (cell->type == ID($sr)) {
has_d = false;
} else {
sig_d = cell->getPort(ID::D);
}
if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
has_clk = true;
sig_clk = cell->getPort(ID::CLK);
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
}
if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
has_en = true;
sig_en = cell->getPort(ID::EN);
pol_en = cell->getParam(ID::EN_POLARITY).as_bool();
}
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
has_sr = true;
sig_clr = cell->getPort(ID::CLR);
sig_set = cell->getPort(ID::SET);
pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
}
if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
has_arst = true;
sig_arst = cell->getPort(ID::ARST);
pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
val_arst = cell->getParam(ID::ARST_VALUE);
}
if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
has_srst = true;
sig_srst = cell->getPort(ID::SRST);
pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
val_srst = cell->getParam(ID::SRST_VALUE);
ce_over_srst = cell->type == ID($sdffce);
}
} else if (cell->type == ID($_FF_)) {
is_fine = true;
sig_d = cell->getPort(ID::D);
} else if (type_str.substr(0, 5) == "$_SR_") {
is_fine = true;
has_d = false;
has_sr = true;
pol_set = type_str[5] == 'P';
pol_clr = type_str[6] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_en = true;
pol_en = type_str[8] == 'P';
sig_en = cell->getPort(ID::E);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[7] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[8] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[8] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
has_en = true;
pol_en = type_str[10] == 'P';
sig_en = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[9] == 'P';
pol_clr = type_str[10] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[10] == 'P';
pol_clr = type_str[11] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
has_en = true;
pol_en = type_str[12] == 'P';
sig_en = cell->getPort(ID::E);
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[8] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[9] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[9] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
has_en = true;
pol_en = type_str[11] == 'P';
sig_en = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[10] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
has_en = true;
pol_en = type_str[12] == 'P';
sig_en = cell->getPort(ID::E);
ce_over_srst = true;
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_en = true;
pol_en = type_str[9] == 'P';
sig_en = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_en = true;
pol_en = type_str[9] == 'P';
sig_en = cell->getPort(ID::E);
has_arst = true;
pol_arst = type_str[10] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_en = true;
pol_en = type_str[11] == 'P';
sig_en = cell->getPort(ID::E);
has_sr = true;
pol_set = type_str[12] == 'P';
pol_clr = type_str[13] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else {
log_assert(0);
}
if (has_d && sig_d.is_fully_const()) {
d_is_const = true;
val_d = sig_d.as_const();
if (has_en && !has_clk && !has_sr && !has_arst) {
// Plain D latches with const D treated specially.
has_en = has_d = false;
has_arst = true;
sig_arst = sig_en;
pol_arst = pol_en;
val_arst = val_d;
}
}
}
FfData(FfInitVals *initvals, Cell *cell_);
// Returns a FF identical to this one, but only keeping bit indices from the argument.
FfData slice(const std::vector<int> &bits) {
FfData res(initvals);
res.sig_clk = sig_clk;
res.sig_en = sig_en;
res.sig_arst = sig_arst;
res.sig_srst = sig_srst;
res.has_d = has_d;
res.has_clk = has_clk;
res.has_en = has_en;
res.has_arst = has_arst;
res.has_srst = has_srst;
res.has_sr = has_sr;
res.ce_over_srst = ce_over_srst;
res.is_fine = is_fine;
res.pol_clk = pol_clk;
res.pol_en = pol_en;
res.pol_arst = pol_arst;
res.pol_srst = pol_srst;
res.pol_clr = pol_clr;
res.pol_set = pol_set;
res.attributes = attributes;
for (int i : bits) {
res.sig_q.append(sig_q[i]);
if (has_d)
res.sig_d.append(sig_d[i]);
if (has_sr) {
res.sig_clr.append(sig_clr[i]);
res.sig_set.append(sig_set[i]);
}
if (has_arst)
res.val_arst.bits.push_back(val_arst[i]);
if (has_srst)
res.val_srst.bits.push_back(val_srst[i]);
res.val_init.bits.push_back(val_init[i]);
}
res.width = GetSize(res.sig_q);
// Slicing bits out may cause D to become const.
if (has_d && res.sig_d.is_fully_const()) {
res.d_is_const = true;
res.val_d = res.sig_d.as_const();
}
return res;
FfData slice(const std::vector<int> &bits);
void add_dummy_ce();
void add_dummy_srst();
void add_dummy_arst();
void add_dummy_aload();
void add_dummy_sr();
void add_dummy_clk();
void arst_to_aload();
void arst_to_sr();
void aload_to_sr();
// Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and
// fixes up control signals appropriately to preserve semantics.
void convert_ce_over_srst(bool val);
void unmap_ce();
void unmap_srst();
void unmap_ce_srst() {
unmap_ce();
unmap_srst();
}
void unmap_ce(Module *module) {
if (!has_en)
return;
log_assert(has_clk);
if (has_srst && ce_over_srst)
unmap_srst(module);
Cell *emit();
if (!is_fine) {
if (pol_en)
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
else
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
} else {
if (pol_en)
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
else
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
}
has_en = false;
// Removes init attribute from the Q output, but keeps val_init unchanged.
// It will be automatically reattached on emit. Use this before changing sig_q.
void remove_init() {
if (initvals)
initvals->remove_init(sig_q);
}
void unmap_srst(Module *module) {
if (!has_srst)
return;
if (has_en && !ce_over_srst)
unmap_ce(module);
void remove();
if (!is_fine) {
if (pol_srst)
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
else
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
} else {
if (pol_srst)
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
else
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
}
has_srst = false;
}
void unmap_ce_srst(Module *module) {
unmap_ce(module);
unmap_srst(module);
}
Cell *emit(Module *module, IdString name) {
if (!width)
return nullptr;
if (!has_d && !has_sr) {
if (has_arst) {
// Convert this case to a D latch.
has_d = has_en = true;
has_arst = false;
sig_d = val_arst;
sig_en = sig_arst;
pol_en = pol_arst;
} else {
// No control inputs left. Turn into a const driver.
initvals->remove_init(sig_q);
module->connect(sig_q, val_init);
return nullptr;
}
}
initvals->set_init(sig_q, val_init);
Cell *cell;
if (!is_fine) {
if (!has_d) {
log_assert(has_sr);
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk && !has_en) {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFf(name, sig_d, sig_q);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
else if (has_arst)
cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
else
cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
} else {
if (has_sr) {
if (has_en)
cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
else
cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
if (has_en)
cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
else
cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
} else if (has_srst) {
if (has_en)
if (ce_over_srst)
cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
else
cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
else
cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
} else {
if (has_en)
cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
else
cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
}
}
} else {
if (!has_d) {
log_assert(has_sr);
cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk && !has_en) {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFfGate(name, sig_d, sig_q);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
else if (has_arst)
cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
else
cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
} else {
if (has_sr) {
if (has_en)
cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
else
cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
if (has_en)
cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, pol_arst);
else
cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
} else if (has_srst) {
if (has_en)
if (ce_over_srst)
cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
else
cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
else
cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
} else {
if (has_en)
cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
else
cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
}
}
}
cell->attributes = attributes;
return cell;
}
// Flip the sense of the given bit slices of the FF: insert inverters on data
// inputs and output, flip the corresponding init/reset bits, swap clr/set
// inputs with proper priority fix.
void flip_bits(const pool<int> &bits);
};
YOSYS_NAMESPACE_END

View file

@ -28,7 +28,6 @@ YOSYS_NAMESPACE_BEGIN
struct FfInitVals
{
const SigMap *sigmap;
RTLIL::Module *module;
dict<SigBit, std::pair<State,SigBit>> initbits;
void set(const SigMap *sigmap_, RTLIL::Module *module)

359
kernel/ffmerge.cc Normal file
View file

@ -0,0 +1,359 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
*
* 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/ffmerge.h"
USING_YOSYS_NAMESPACE
bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) {
for (auto bit : (*sigmap)(sig))
if (sigbit_users_count[bit] != 0)
return false;
return true;
}
bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
ff = FfData(module, initvals, NEW_ID);
sigmap->apply(sig);
bool found = false;
for (auto bit : sig)
{
if (bit.wire == NULL || sigbit_users_count[bit] == 0) {
ff.width++;
ff.sig_q.append(bit);
ff.sig_d.append(bit);
ff.sig_clr.append(State::Sx);
ff.sig_set.append(State::Sx);
ff.val_init.bits.push_back(State::Sx);
ff.val_srst.bits.push_back(State::Sx);
ff.val_arst.bits.push_back(State::Sx);
continue;
}
if (sigbit_users_count[bit] != 1)
return false;
auto &sinks = dff_sink[bit];
if (sinks.size() != 1)
return false;
Cell *cell;
int idx;
std::tie(cell, idx) = *sinks.begin();
bits.insert(std::make_pair(cell, idx));
FfData cur_ff(initvals, cell);
// Reject latches and $ff.
if (!cur_ff.has_clk)
return false;
log_assert((*sigmap)(cur_ff.sig_d[idx]) == bit);
if (!found) {
ff.sig_clk = cur_ff.sig_clk;
ff.sig_ce = cur_ff.sig_ce;
ff.sig_aload = cur_ff.sig_aload;
ff.sig_srst = cur_ff.sig_srst;
ff.sig_arst = cur_ff.sig_arst;
ff.has_clk = cur_ff.has_clk;
ff.has_ce = cur_ff.has_ce;
ff.has_aload = cur_ff.has_aload;
ff.has_srst = cur_ff.has_srst;
ff.has_arst = cur_ff.has_arst;
ff.has_sr = cur_ff.has_sr;
ff.ce_over_srst = cur_ff.ce_over_srst;
ff.pol_clk = cur_ff.pol_clk;
ff.pol_ce = cur_ff.pol_ce;
ff.pol_aload = cur_ff.pol_aload;
ff.pol_arst = cur_ff.pol_arst;
ff.pol_srst = cur_ff.pol_srst;
ff.pol_clr = cur_ff.pol_clr;
ff.pol_set = cur_ff.pol_set;
} else {
if (ff.has_clk != cur_ff.has_clk)
return false;
if (ff.has_ce != cur_ff.has_ce)
return false;
if (ff.has_aload != cur_ff.has_aload)
return false;
if (ff.has_srst != cur_ff.has_srst)
return false;
if (ff.has_arst != cur_ff.has_arst)
return false;
if (ff.has_sr != cur_ff.has_sr)
return false;
if (ff.has_clk) {
if (ff.sig_clk != cur_ff.sig_clk)
return false;
if (ff.pol_clk != cur_ff.pol_clk)
return false;
}
if (ff.has_ce) {
if (ff.sig_ce != cur_ff.sig_ce)
return false;
if (ff.pol_ce != cur_ff.pol_ce)
return false;
}
if (ff.has_aload) {
if (ff.sig_aload != cur_ff.sig_aload)
return false;
if (ff.pol_aload != cur_ff.pol_aload)
return false;
}
if (ff.has_srst) {
if (ff.sig_srst != cur_ff.sig_srst)
return false;
if (ff.pol_srst != cur_ff.pol_srst)
return false;
if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
return false;
}
if (ff.has_arst) {
if (ff.sig_arst != cur_ff.sig_arst)
return false;
if (ff.pol_arst != cur_ff.pol_arst)
return false;
}
if (ff.has_sr) {
if (ff.pol_clr != cur_ff.pol_clr)
return false;
if (ff.pol_set != cur_ff.pol_set)
return false;
}
}
ff.width++;
ff.sig_d.append(cur_ff.sig_d[idx]);
ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
ff.sig_q.append(cur_ff.sig_q[idx]);
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
ff.val_arst.bits.push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx);
ff.val_srst.bits.push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx);
ff.val_init.bits.push_back(cur_ff.val_init[idx]);
found = true;
}
return found;
}
bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
ff = FfData(module, initvals, NEW_ID);
sigmap->apply(sig);
bool found = false;
pool<int> const_bits;
for (auto bit : sig)
{
if (bit.wire == NULL) {
const_bits.insert(ff.width);
ff.width++;
ff.sig_q.append(bit);
ff.sig_d.append(bit);
// These two will be fixed up later.
ff.sig_clr.append(State::Sx);
ff.sig_set.append(State::Sx);
ff.val_init.bits.push_back(bit.data);
ff.val_srst.bits.push_back(bit.data);
ff.val_arst.bits.push_back(bit.data);
continue;
}
if (!dff_driver.count(bit))
return false;
Cell *cell;
int idx;
std::tie(cell, idx) = dff_driver[bit];
bits.insert(std::make_pair(cell, idx));
FfData cur_ff(initvals, cell);
log_assert((*sigmap)(cur_ff.sig_q[idx]) == bit);
if (!found) {
ff.sig_clk = cur_ff.sig_clk;
ff.sig_ce = cur_ff.sig_ce;
ff.sig_aload = cur_ff.sig_aload;
ff.sig_srst = cur_ff.sig_srst;
ff.sig_arst = cur_ff.sig_arst;
ff.has_clk = cur_ff.has_clk;
ff.has_gclk = cur_ff.has_gclk;
ff.has_ce = cur_ff.has_ce;
ff.has_aload = cur_ff.has_aload;
ff.has_srst = cur_ff.has_srst;
ff.has_arst = cur_ff.has_arst;
ff.has_sr = cur_ff.has_sr;
ff.ce_over_srst = cur_ff.ce_over_srst;
ff.pol_clk = cur_ff.pol_clk;
ff.pol_ce = cur_ff.pol_ce;
ff.pol_aload = cur_ff.pol_aload;
ff.pol_arst = cur_ff.pol_arst;
ff.pol_srst = cur_ff.pol_srst;
ff.pol_clr = cur_ff.pol_clr;
ff.pol_set = cur_ff.pol_set;
} else {
if (ff.has_gclk != cur_ff.has_gclk)
return false;
if (ff.has_clk != cur_ff.has_clk)
return false;
if (ff.has_ce != cur_ff.has_ce)
return false;
if (ff.has_aload != cur_ff.has_aload)
return false;
if (ff.has_srst != cur_ff.has_srst)
return false;
if (ff.has_arst != cur_ff.has_arst)
return false;
if (ff.has_sr != cur_ff.has_sr)
return false;
if (ff.has_clk) {
if (ff.sig_clk != cur_ff.sig_clk)
return false;
if (ff.pol_clk != cur_ff.pol_clk)
return false;
}
if (ff.has_ce) {
if (ff.sig_ce != cur_ff.sig_ce)
return false;
if (ff.pol_ce != cur_ff.pol_ce)
return false;
}
if (ff.has_aload) {
if (ff.sig_aload != cur_ff.sig_aload)
return false;
if (ff.pol_aload != cur_ff.pol_aload)
return false;
}
if (ff.has_srst) {
if (ff.sig_srst != cur_ff.sig_srst)
return false;
if (ff.pol_srst != cur_ff.pol_srst)
return false;
if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
return false;
}
if (ff.has_arst) {
if (ff.sig_arst != cur_ff.sig_arst)
return false;
if (ff.pol_arst != cur_ff.pol_arst)
return false;
}
if (ff.has_sr) {
if (ff.pol_clr != cur_ff.pol_clr)
return false;
if (ff.pol_set != cur_ff.pol_set)
return false;
}
}
ff.width++;
ff.sig_d.append((ff.has_clk || ff.has_gclk) ? cur_ff.sig_d[idx] : State::Sx);
ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
ff.sig_q.append(cur_ff.sig_q[idx]);
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
ff.val_arst.bits.push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx);
ff.val_srst.bits.push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx);
ff.val_init.bits.push_back(cur_ff.val_init[idx]);
found = true;
}
if (found && ff.has_sr) {
for (auto i: const_bits) {
if (ff.sig_d[i] == State::S0) {
ff.sig_set[i] = ff.pol_set ? State::S0 : State::S1;
} else if (ff.sig_d[i] == State::S1) {
ff.sig_clr[i] = ff.pol_clr ? State::S0 : State::S1;
}
}
}
return found;
}
void FfMergeHelper::remove_output_ff(const pool<std::pair<Cell *, int>> &bits) {
for (auto &it : bits) {
Cell *cell = it.first;
int idx = it.second;
SigSpec q = cell->getPort(ID::Q);
initvals->remove_init(q[idx]);
dff_driver.erase((*sigmap)(q[idx]));
q[idx] = module->addWire(stringf("$ffmerge_disconnected$%d", autoidx++));
cell->setPort(ID::Q, q);
}
}
void FfMergeHelper::mark_input_ff(const pool<std::pair<Cell *, int>> &bits) {
for (auto &it : bits) {
Cell *cell = it.first;
int idx = it.second;
if (cell->hasPort(ID::D)) {
SigSpec d = cell->getPort(ID::D);
// The user count was already at least 1
// (for the D port). Bump it as it is now connected
// to the merged-to cell as well. This suffices for
// it to not be considered for output merging.
sigbit_users_count[d[idx]]++;
}
}
}
void FfMergeHelper::set(FfInitVals *initvals_, RTLIL::Module *module_)
{
clear();
initvals = initvals_;
sigmap = initvals->sigmap;
module = module_;
for (auto wire : module->wires()) {
if (wire->port_output)
for (auto bit : (*sigmap)(wire))
sigbit_users_count[bit]++;
}
for (auto cell : module->cells()) {
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
if (cell->hasPort(ID::D)) {
SigSpec d = (*sigmap)(cell->getPort(ID::D));
for (int i = 0; i < GetSize(d); i++)
dff_sink[d[i]].insert(std::make_pair(cell, i));
}
SigSpec q = (*sigmap)(cell->getPort(ID::Q));
for (int i = 0; i < GetSize(q); i++)
dff_driver[q[i]] = std::make_pair(cell, i);
}
for (auto &conn : cell->connections())
if (!cell->known() || cell->input(conn.first))
for (auto bit : (*sigmap)(conn.second))
sigbit_users_count[bit]++;
}
}
void FfMergeHelper::clear() {
dff_driver.clear();
dff_sink.clear();
sigbit_users_count.clear();
}

141
kernel/ffmerge.h Normal file
View file

@ -0,0 +1,141 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
*
* 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.
*
*/
#ifndef FFMERGE_H
#define FFMERGE_H
#include "kernel/ffinit.h"
#include "kernel/ff.h"
YOSYS_NAMESPACE_BEGIN
// A helper class for passes that want to merge FFs on the input or output
// of a cell into the cell itself.
//
// The procedure is:
//
// 1. Construct this class (at beginning of processing for a given module).
// 2. For every considered cell:
//
// a. Call find_output_ff for every considered output.
// b. Call find_input_ff for every considered input.
// c. Look at the FF description returned (if any) from each call, reject
// results that cannot be merged into given cell for any reason.
// If both inputs and outputs are being merged, take care of FF bits that
// are returned in both input and output results (a FF bit cannot be
// merged to both). Decide on the final set of FF bits to merge.
// d. Call remove_output_ff for every find_output_ff result that will be used
// for merging. This removes the actual FF bits from design and from index.
// e. Call mark_input_ff for every find_input_ff result that will be used
// for merging. This updates the index disallowing further usage of these
// FF bits for output FF merging, if they were eligible before. The actual
// FF bits are still left in the design and can be merged into other inputs.
// If the FF bits are not otherwise used, they will be removed by later
// opt passes.
// f. Merge the FFs into the cell.
//
// Note that, if both inputs and outputs are being considered for merging in
// a single pass, the result may be nondeterministic (depending on cell iteration
// order) because a given FF bit could be eligible for both input and output merge,
// perhaps in different cells. For this reason, it may be a good idea to separate
// input and output merging.
struct FfMergeHelper
{
const SigMap *sigmap;
RTLIL::Module *module;
FfInitVals *initvals;
dict<SigBit, std::pair<Cell*, int>> dff_driver;
dict<SigBit, pool<std::pair<Cell*, int>>> dff_sink;
dict<SigBit, int> sigbit_users_count;
// Returns true if all bits in sig are completely unused.
bool is_output_unused(RTLIL::SigSpec sig);
// Finds the FF to merge into a given cell output. Takes sig, which
// is the current cell output — it will be the sig_d of the found FF.
// If found, returns true, and fills the two output arguments.
//
// For every bit of sig, this function finds a FF bit that has
// the same sig_d, and fills the output FfData according to the FF
// bits found. This function will only consider FF bits that are
// the only user of the given sig bits — if any bit in sig is used
// by anything other than a single FF, this function will return false.
//
// The returned FfData structure does not correspond to any actual FF
// cell in the design — it is the amalgamation of extracted FF bits,
// possibly coming from several FF cells.
//
// If some of the bits in sig have no users at all, this function
// will accept them as well (and fill returned FfData with dummy values
// for the given bit, effectively synthesizing an unused FF bit of the
// appropriate type). However, if all bits in sig are completely
// unused, this function will fail and return false (having no idea
// what kind of FF to produce) — use the above helper if that case
// is important to handle.
//
// Note that this function does not remove the FF bits returned from
// the design — this is so that the caller can decide whether to accept
// this FF for merging or not. If the result is accepted,
// remove_output_ff should be called on the second output argument.
bool find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);
// Like above, but returns a FF to merge into a given cell input. Takes
// sig_q, which is the current cell input — it will search for FFs with
// matching sig_q.
//
// As opposed to find_output_ff, this function doesn't care about usage
// counts, and may return FF bits that also have other fanout. This
// should not be a problem for input FF merging.
//
// As a special case, if some of the bits in sig_q are constant, this
// function will accept them as well, by synthesizing in-place
// a constant-input FF bit (with matching initial value and reset value).
// However, this will not work if the input is all-constant — if the caller
// cares about this case, it needs to check for it explicitely.
bool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);
// To be called on find_output_ff result that will be merged. This
// marks the given FF bits as used up (and not to be considered for
// further merging as inputs), and reconnects their Q ports to a dummy
// wire (since the wire previously connected there will now be driven
// by the merged-to cell instead).
void remove_output_ff(const pool<std::pair<Cell *, int>> &bits);
// To be called on find_input_ff result that will be merged. This
// marks the given FF bits as used, and disallows merging them as
// outputs. They can, however, still be merged as inputs again
// (perhaps for another cell).
void mark_input_ff(const pool<std::pair<Cell *, int>> &bits);
void set(FfInitVals *initvals_, RTLIL::Module *module_);
void clear();
FfMergeHelper(FfInitVals *initvals, RTLIL::Module *module) {
set(initvals, module);
}
FfMergeHelper() {}
};
YOSYS_NAMESPACE_END
#endif

252
kernel/fstdata.cc Normal file
View file

@ -0,0 +1,252 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2022 Miodrag Milanovic <micko@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/fstdata.h"
USING_YOSYS_NAMESPACE
FstData::FstData(std::string filename) : ctx(nullptr)
{
const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
if (!ctx)
log_error("Error opening '%s'\n", filename.c_str());
int scale = (int)fstReaderGetTimescale(ctx);
timescale = pow(10.0, scale);
timescale_str = "";
int unit = 0;
int zeros = 0;
if (scale > 0) {
zeros = scale;
} else {
if ((scale % 3) == 0) {
zeros = (-scale % 3);
unit = (-scale / 3);
} else {
zeros = 3 - (-scale % 3);
unit = (-scale / 3) + 1;
}
}
for (int i=0;i<zeros; i++) timescale_str += "0";
timescale_str += g_units[unit];
extractVarNames();
}
FstData::~FstData()
{
if (ctx)
fstReaderClose(ctx);
}
uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
fstHandle FstData::getHandle(std::string name) {
if (name_to_handle.find(name) != name_to_handle.end())
return name_to_handle[name];
else
return 0;
};
static std::string remove_spaces(std::string str)
{
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
return str;
}
void FstData::extractVarNames()
{
struct fstHier *h;
intptr_t snum = 0;
while ((h = fstReaderIterateHier(ctx))) {
switch (h->htyp) {
case FST_HT_SCOPE: {
snum++;
std::string fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, (void *)(snum));
scopes.push_back(fst_scope_name);
break;
}
case FST_HT_UPSCOPE: {
fstReaderPopScope(ctx);
snum = fstReaderGetCurrentScopeLen(ctx) ? (intptr_t)fstReaderGetCurrentScopeUserInfo(ctx) : 0;
break;
}
case FST_HT_VAR: {
FstVar var;
var.id = h->u.var.handle;
var.is_alias = h->u.var.is_alias;
var.name = remove_spaces(h->u.var.name);
var.scope = scopes.back();
var.width = h->u.var.length;
vars.push_back(var);
if (!var.is_alias)
handle_to_var[h->u.var.handle] = var;
std::string clean_name;
for(size_t i=0;i<strlen(h->u.var.name);i++)
{
char c = h->u.var.name[i];
if(c==' ') break;
clean_name += c;
}
if (clean_name[0]=='\\')
clean_name = clean_name.substr(1);
//log("adding %s.%s\n",var.scope.c_str(), clean_name.c_str());
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
break;
}
}
}
}
static void reconstruct_edges_varlen(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
{
FstData *ptr = (FstData*)user_data;
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
}
static void reconstruct_edges(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
{
FstData *ptr = (FstData*)user_data;
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
}
void FstData::reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{
std::string val = std::string((const char *)pnt_value);
std::string prev = last_data[pnt_facidx];
if (pnt_time>=start_time) {
if (prev!="1" && val=="1")
edges.push_back(pnt_time);
if (prev!="0" && val=="0")
edges.push_back(pnt_time);
}
last_data[pnt_facidx] = val;
}
std::vector<uint64_t> FstData::getAllEdges(std::vector<fstHandle> &signal, uint64_t start, uint64_t end)
{
start_time = start;
end_time = end;
last_data.clear();
for(auto &s : signal) {
last_data[s] = "x";
}
edges.clear();
fstReaderSetLimitTimeRange(ctx, start_time, end_time);
fstReaderClrFacProcessMaskAll(ctx);
for(const auto sig : signal)
fstReaderSetFacProcessMask(ctx,sig);
fstReaderIterBlocks2(ctx, reconstruct_edges, reconstruct_edges_varlen, this, nullptr);
return edges;
}
static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
{
FstData *ptr = (FstData*)user_data;
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
}
static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
{
FstData *ptr = (FstData*)user_data;
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
}
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{
if (sample_times_ndx >= sample_times.size()) return;
uint64_t time = sample_times[sample_times_ndx];
// if we are past the timestamp
if (pnt_time > time) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time,c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time] = index;
}
sample_times_ndx++;
}
// always update last_data
last_data[pnt_facidx] = std::string((const char *)pnt_value);
}
void FstData::reconstructAtTimes(std::vector<fstHandle> &signal, std::vector<uint64_t> time)
{
handle_to_data.clear();
time_to_index.clear();
last_data.clear();
sample_times_ndx = 0;
sample_times = time;
fstReaderSetUnlimitedTimeRange(ctx);
fstReaderClrFacProcessMaskAll(ctx);
for(const auto sig : signal)
fstReaderSetFacProcessMask(ctx,sig);
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
if (time_to_index[signal.back()].count(time.back())==0) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time.back()] = index;
}
}
}
void FstData::reconstructAllAtTimes(std::vector<uint64_t> time)
{
handle_to_data.clear();
time_to_index.clear();
last_data.clear();
sample_times_ndx = 0;
sample_times = time;
fstReaderSetUnlimitedTimeRange(ctx);
fstReaderSetFacProcessMaskAll(ctx);
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
if (time_to_index[1].count(time.back())==0) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time.back()] = index;
}
}
}
std::string FstData::valueAt(fstHandle signal, uint64_t time)
{
if (handle_to_data.find(signal) == handle_to_data.end())
log_error("Signal id %d not found\n", (int)signal);
auto &data = handle_to_data[signal];
if (time_to_index[signal].count(time)!=0) {
size_t index = time_to_index[signal][time];
return data.at(index).second;
} else {
log_error("No data for signal %d at time %d\n", (int)signal, (int)time);
}
}

81
kernel/fstdata.h Normal file
View file

@ -0,0 +1,81 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2022 Miodrag Milanovic <micko@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.
*
*/
#ifndef FSTDATA_H
#define FSTDATA_H
#include "kernel/yosys.h"
#include "libs/fst/fstapi.h"
YOSYS_NAMESPACE_BEGIN
struct FstVar
{
fstHandle id;
std::string name;
bool is_alias;
std::string scope;
int width;
};
class FstData
{
public:
FstData(std::string filename);
~FstData();
uint64_t getStartTime();
uint64_t getEndTime();
std::vector<FstVar>& getVars() { return vars; };
void reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
std::vector<uint64_t> getAllEdges(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time);
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
void reconstructAtTimes(std::vector<fstHandle> &signal,std::vector<uint64_t> time);
void reconstructAllAtTimes(std::vector<uint64_t> time);
std::string valueAt(fstHandle signal, uint64_t time);
fstHandle getHandle(std::string name);
double getTimescale() { return timescale; }
const char *getTimescaleString() { return timescale_str.c_str(); }
private:
void extractVarNames();
struct fstReaderContext *ctx;
std::vector<std::string> scopes;
std::vector<FstVar> vars;
std::map<fstHandle, FstVar> handle_to_var;
std::map<std::string, fstHandle> name_to_handle;
std::map<fstHandle, std::vector<std::pair<uint64_t, std::string>>> handle_to_data;
std::map<fstHandle, std::string> last_data;
std::map<fstHandle, std::map<uint64_t, size_t>> time_to_index;
std::vector<uint64_t> sample_times;
size_t sample_times_ndx;
double timescale;
std::string timescale_str;
uint64_t start_time;
uint64_t end_time;
std::vector<uint64_t> edges;
};
YOSYS_NAMESPACE_END
#endif

View file

@ -6,7 +6,7 @@
// means.
// -------------------------------------------------------
// Written by Clifford Wolf <clifford@clifford.at> in 2014
// Written by Claire Xenia Wolf <claire@yosyshq.com> in 2014
// -------------------------------------------------------
#ifndef HASHLIB_H
@ -66,6 +66,12 @@ struct hash_int_ops {
}
};
template<> struct hash_ops<bool> : hash_int_ops
{
static inline unsigned int hash(bool a) {
return a ? 1 : 0;
}
};
template<> struct hash_ops<int32_t> : hash_int_ops
{
static inline unsigned int hash(int32_t a) {

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -71,8 +71,6 @@ int string_buf_index = -1;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
static bool check_expected_logs = true;
static bool display_error_log_msg = true;
static void log_id_cache_clear()
{
@ -339,8 +337,7 @@ static void logv_error_with_prefix(const char *prefix,
f = stderr;
log_last_error = vstringf(format, ap);
if (display_error_log_msg)
log("%s%s", prefix, log_last_error.c_str());
log("%s%s", prefix, log_last_error.c_str());
log_flush();
log_make_debug = bak_log_make_debug;
@ -349,8 +346,7 @@ static void logv_error_with_prefix(const char *prefix,
if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern))
item.second.current_count++;
if (check_expected_logs)
log_check_expected();
log_check_expected();
if (log_error_atexit)
log_error_atexit();
@ -667,9 +663,14 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
void log_check_expected()
{
check_expected_logs = false;
// copy out all of the expected logs so that they cannot be re-checked
// or match against themselves
dict<std::string, LogExpectedItem> expect_log, expect_warning, expect_error;
std::swap(expect_warning, log_expect_warning);
std::swap(expect_log, log_expect_log);
std::swap(expect_error, log_expect_error);
for (auto &item : log_expect_warning) {
for (auto &item : expect_warning) {
if (item.second.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
@ -681,7 +682,7 @@ void log_check_expected()
}
}
for (auto &item : log_expect_log) {
for (auto &item : expect_log) {
if (item.second.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
@ -693,7 +694,7 @@ void log_check_expected()
}
}
for (auto &item : log_expect_error)
for (auto &item : expect_error)
if (item.second.current_count == item.second.expected_count) {
log_warn_regexes.clear();
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
@ -705,7 +706,6 @@ void log_check_expected()
_Exit(0);
#endif
} else {
display_error_log_msg = false;
log_warn_regexes.clear();
log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
}

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -24,9 +24,29 @@
#include <time.h>
// In GCC 4.8 std::regex is not working correctlty, in order to make features
// using regular expressions to work replacement regex library is used
#if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8)
// In the libstdc++ headers that are provided by GCC 4.8, std::regex is not
// working correctly. In order to make features using regular expressions
// work, a replacement regex library is used. Just checking for GCC version
// is not enough though, because at least on RHEL7/CentOS7 even when compiling
// with Clang instead of GCC, the GCC 4.8 headers are still used for std::regex.
// We have to check the version of the libstdc++ headers specifically, not the
// compiler version. GCC headers of libstdc++ before version 3.4 define
// __GLIBCPP__, later versions define __GLIBCXX__. GCC 7 and newer additionaly
// define _GLIBCXX_RELEASE with a version number.
// Include limits std C++ header, so we get the version macros defined:
#if defined(__cplusplus)
# include <limits>
#endif
// Check if libstdc++ is from GCC
#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
// Check if version could be 4.8 or lower (this also matches for some 4.9 and
// 5.0 releases). See:
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
# if !defined(_GLIBCXX_RELEASE) && (defined(__GLIBCPP__) || __GLIBCXX__ <= 20150623)
# define YS_HAS_BAD_STD_REGEX
# endif
#endif
#if defined(YS_HAS_BAD_STD_REGEX)
#include <boost/xpressive/xpressive.hpp>
#define YS_REGEX_TYPE boost::xpressive::sregex
#define YS_REGEX_MATCH_TYPE boost::xpressive::smatch

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

File diff suppressed because it is too large Load diff

View file

@ -21,38 +21,76 @@
#define MEM_H
#include "kernel/yosys.h"
#include "kernel/ffinit.h"
YOSYS_NAMESPACE_BEGIN
struct MemRd {
dict<IdString, Const> attributes;
struct MemRd : RTLIL::AttrObject {
bool removed;
Cell *cell;
bool clk_enable, clk_polarity;
bool transparent;
SigSpec clk, en, addr, data;
MemRd() : cell(nullptr) {}
int wide_log2;
bool clk_enable, clk_polarity, ce_over_srst;
Const arst_value, srst_value, init_value;
// One bit for every write port, true iff simultanous read on this
// port and write on the other port will bypass the written data
// to this port's output (default behavior is to read old value).
// Can only be set for write ports that have the same clock domain.
std::vector<bool> transparency_mask;
// One bit for every write port, true iff simultanous read on this
// port and write on the other port will return an all-X (don't care)
// value. Mutually exclusive with transparency_mask.
// Can only be set for write ports that have the same clock domain.
// For optimization purposes, this will also be set if we can
// determine that the two ports can never be active simultanously
// (making the above vacuously true).
std::vector<bool> collision_x_mask;
SigSpec clk, en, arst, srst, addr, data;
MemRd() : removed(false), cell(nullptr) {}
// Returns the address of given subword index accessed by this port.
SigSpec sub_addr(int sub) {
SigSpec res = addr;
for (int i = 0; i < wide_log2; i++)
res[i] = State(sub >> i & 1);
return res;
}
};
struct MemWr {
dict<IdString, Const> attributes;
struct MemWr : RTLIL::AttrObject {
bool removed;
Cell *cell;
int wide_log2;
bool clk_enable, clk_polarity;
std::vector<bool> priority_mask;
SigSpec clk, en, addr, data;
MemWr() : cell(nullptr) {}
MemWr() : removed(false), cell(nullptr) {}
// Returns the address of given subword index accessed by this port.
SigSpec sub_addr(int sub) {
SigSpec res = addr;
for (int i = 0; i < wide_log2; i++)
res[i] = State(sub >> i & 1);
return res;
}
std::pair<SigSpec, std::vector<int>> compress_en();
SigSpec decompress_en(const std::vector<int> &swizzle, SigSpec sig);
};
struct MemInit {
dict<IdString, Const> attributes;
struct MemInit : RTLIL::AttrObject {
bool removed;
Cell *cell;
Const addr;
Const data;
MemInit() : cell(nullptr) {}
Const en;
MemInit() : removed(false), cell(nullptr) {}
};
struct Mem {
struct Mem : RTLIL::AttrObject {
Module *module;
IdString memid;
dict<IdString, Const> attributes;
bool packed;
RTLIL::Memory *mem;
Cell *cell;
@ -61,15 +99,128 @@ struct Mem {
std::vector<MemRd> rd_ports;
std::vector<MemWr> wr_ports;
// Removes this memory from the module. The data in helper structures
// is unaffected except for the cell/mem fields.
void remove();
// Commits all changes in helper structures into the module — ports and
// inits marked as removed are actually removed, new ports/inits create
// new cells, modified port/inits are commited into their existing
// cells. Note that this reindexes the ports and inits array (actually
// removing the ports/inits marked as removed).
void emit();
void remove_wr_port(int idx);
void remove_rd_port(int idx);
// Marks all inits as removed.
void clear_inits();
// Coalesces inits: whenever two inits have overlapping or touching
// address ranges, they are combined into one, with the higher-priority
// one's data overwriting the other. Running this results in
// an inits list equivalent to the original, in which all entries
// cover disjoint (and non-touching) address ranges, and all enable
// masks are all-1.
void coalesce_inits();
// Checks consistency of this memory and all its ports/inits, using
// log_assert.
void check();
// Gathers all initialization data into a single big const covering
// the whole memory. For all non-initialized bits, Sx will be returned.
Const get_init_data() const;
// Constructs and returns the helper structures for all memories
// in a module.
static std::vector<Mem> get_all_memories(Module *module);
// Constructs and returns the helper structures for all selected
// memories in a module.
static std::vector<Mem> get_selected_memories(Module *module);
Cell *extract_rdff(int idx);
// Converts a synchronous read port into an asynchronous one by
// extracting the data (or, in some rare cases, address) register
// into a separate cell, together with any soft-transparency
// logic necessary to preserve its semantics. Returns the created
// register cell, if any. Note that in some rare cases this function
// may succeed and perform a conversion without creating a new
// register — a nullptr result doesn't imply nothing was done.
Cell *extract_rdff(int idx, FfInitVals *initvals);
// Splits all wide ports in this memory into equivalent narrow ones.
// This function performs no modifications at all to the actual
// netlist unless and until emit() is called.
void narrow();
// If write port idx2 currently has priority over write port idx1,
// inserts extra logic on idx1's enable signal to disable writes
// when idx2 is writing to the same address, then removes the priority
// from the priority mask. If there is a memory port that is
// transparent with idx1, but not with idx2, that port is converted
// to use soft transparency logic.
void emulate_priority(int idx1, int idx2, FfInitVals *initvals);
// Creates soft-transparency logic on read port ridx, bypassing the
// data from write port widx. Should only be called when ridx is
// transparent wrt widx in the first place. Once we're done, the
// transparency_mask bit will be cleared, and the collision_x_mask
// bit will be set instead (since whatever value is read will be
// replaced by the soft transparency logic).
void emulate_transparency(int widx, int ridx, FfInitVals *initvals);
// Prepares for merging write port idx2 into idx1 (where idx1 < idx2).
// Specifically, takes care of priority masks: any priority relations
// that idx2 had are replicated onto idx1, unless they conflict with
// priorities already present on idx1, in which case emulate_priority
// is called. Likewise, ensures transparency and undefined collision
// masks of all read ports have the same values for both ports,
// calling emulate_transparency if necessary.
void prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals);
// Prepares for merging read port idx2 into idx1.
// Specifically, makes sure the transparency and undefined collision
// masks of both ports are equal, by changing undefined behavior
// of one port to the other's defined behavior, or by calling
// emulate_transparency if necessary.
void prepare_rd_merge(int idx1, int idx2, FfInitVals *initvals);
// Prepares the memory for widening a port to a given width. This
// involves ensuring that start_offset and size are aligned to the
// target width.
void widen_prep(int wide_log2);
// Widens a write port up to a given width. The newly port is
// equivalent to the original, made by replicating enable/data bits
// and masking enable bits with decoders on the low part of the
// original address.
void widen_wr_port(int idx, int wide_log2);
// Emulates a sync read port's enable functionality in soft logic,
// changing the actual read port's enable to be always-on.
void emulate_rden(int idx, FfInitVals *initvals);
// Emulates a sync read port's initial/reset value functionality in
// soft logic, removing it from the actual read port.
void emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals);
// Given a read port with ce_over_srst set, converts it to a port
// with ce_over_srst unset without changing its behavior by adding
// emulation logic.
void emulate_rd_ce_over_srst(int idx);
// Given a read port with ce_over_srst unset, converts it to a port
// with ce_over_srst set without changing its behavior by adding
// emulation logic.
void emulate_rd_srst_over_ce(int idx);
// Returns true iff emulate_read_first makes sense to call.
bool emulate_read_first_ok();
// Emulates all read-first read-write port relationships in terms of
// all-transparent ports, by delaying all write ports by one cycle.
// This can only be used when all read ports and all write ports are
// in the same clock domain.
void emulate_read_first(FfInitVals *initvals);
Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
};

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -380,9 +380,11 @@ struct ModWalker
}
}
ModWalker(RTLIL::Design *design) : design(design), module(NULL)
ModWalker(RTLIL::Design *design, RTLIL::Module *module = nullptr) : design(design), module(NULL)
{
ct.setup(design);
ct.setup(design);
if (module)
setup(module);
}
void setup(RTLIL::Module *module, CellTypes *filter_ct = NULL)
@ -395,6 +397,8 @@ struct ModWalker
signal_consumers.clear();
signal_inputs.clear();
signal_outputs.clear();
cell_inputs.clear();
cell_outputs.clear();
for (auto &it : module->wires_)
add_wire(it.second);

102
kernel/qcsat.cc Normal file
View file

@ -0,0 +1,102 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
*
* 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/qcsat.h"
USING_YOSYS_NAMESPACE
std::vector<int> QuickConeSat::importSig(SigSpec sig)
{
sig = modwalker.sigmap(sig);
for (auto bit : sig)
bits_queue.insert(bit);
return satgen.importSigSpec(sig);
}
int QuickConeSat::importSigBit(SigBit bit)
{
bit = modwalker.sigmap(bit);
bits_queue.insert(bit);
return satgen.importSigBit(bit);
}
void QuickConeSat::prepare()
{
while (!bits_queue.empty())
{
pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, bits_queue);
for (auto bit : bits_queue)
if (bit.wire && bit.wire->get_bool_attribute(ID::onehot) && !imported_onehot.count(bit.wire))
{
std::vector<int> bits = satgen.importSigSpec(bit.wire);
for (int i : bits)
for (int j : bits)
if (i != j)
ez->assume(ez->NOT(i), j);
imported_onehot.insert(bit.wire);
}
bits_queue.clear();
for (auto &pbit : portbits)
{
if (imported_cells.count(pbit.cell))
continue;
if (cell_complexity(pbit.cell) > max_cell_complexity)
continue;
if (max_cell_outs && GetSize(modwalker.cell_outputs[pbit.cell]) > max_cell_outs)
continue;
auto &inputs = modwalker.cell_inputs[pbit.cell];
bits_queue.insert(inputs.begin(), inputs.end());
satgen.importCell(pbit.cell);
imported_cells.insert(pbit.cell);
}
if (max_cell_count && GetSize(imported_cells) > max_cell_count)
break;
}
}
int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
{
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($_BUF_)))
return 0;
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
ID($reduce_xnor), ID($reduce_bool),
ID($logic_not), ID($logic_and), ID($logic_or),
ID($eq), ID($ne), ID($eqx), ID($nex), ID($fa),
ID($mux), ID($pmux), ID($bmux), ID($demux), ID($lut), ID($sop),
ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
ID($_MUX_), ID($_NMUX_), ID($_MUX4_), ID($_MUX8_), ID($_MUX16_),
ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
return 1;
if (cell->type.in(ID($neg), ID($add), ID($sub), ID($alu), ID($lcu),
ID($lt), ID($le), ID($gt), ID($ge)))
return 2;
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
return 3;
if (cell->type.in(ID($mul), ID($macc), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
return 4;
// Unknown cell.
return 5;
}

76
kernel/qcsat.h Normal file
View file

@ -0,0 +1,76 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
*
* 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.
*
*/
#ifndef QCSAT_H
#define QCSAT_H
#include "kernel/satgen.h"
#include "kernel/modtools.h"
YOSYS_NAMESPACE_BEGIN
// This is a helper class meant for easy construction of quick SAT queries
// to a combinatorial input cone of some set of signals, meant for SAT-based
// optimizations. Various knobs are provided to set just how much of the
// cone should be included in the model — since this class is meant for
// optimization, it should not be a correctness problem when some cells are
// skipped and the solver spuriously returns SAT with a solution that
// cannot exist in reality due to skipped constraints (ie. only UNSAT results
// from this class should be considered binding).
struct QuickConeSat {
ModWalker &modwalker;
ezSatPtr ez;
SatGen satgen;
// The effort level knobs.
// The maximum "complexity level" of cells that will be imported.
// - 1: bitwise operations, muxes, equality comparisons, lut, sop, fa
// - 2: addition, subtraction, greater/less than comparisons, lcu
// - 3: shifts
// - 4: multiplication, division, power
int max_cell_complexity = 2;
// The maximum number of cells to import, or 0 for no limit.
int max_cell_count = 0;
// If non-0, skip importing cells with more than this number of output bits.
int max_cell_outs = 0;
// Internal state.
pool<RTLIL::Cell*> imported_cells;
pool<RTLIL::Wire*> imported_onehot;
pool<RTLIL::SigBit> bits_queue;
QuickConeSat(ModWalker &modwalker) : modwalker(modwalker), ez(), satgen(ez.get(), &modwalker.sigmap) {}
// Imports a signal into the SAT solver, queues its input cone to be
// imported in the next prepare() call.
std::vector<int> importSig(SigSpec sig);
int importSigBit(SigBit bit);
// Imports the input cones of all previously importSig'd signals into
// the SAT solver.
void prepare();
// Returns the "complexity level" of a given cell.
static int cell_complexity(RTLIL::Cell *cell);
};
YOSYS_NAMESPACE_END
#endif

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/macc.h"
#include "kernel/celltypes.h"
#include "kernel/binding.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/verilog/preproc.h"
#include "backends/rtlil/rtlil_backend.h"
@ -57,6 +58,8 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
ID($dffsre),
ID($adff),
ID($adffe),
ID($aldff),
ID($aldffe),
ID($sdff),
ID($sdffe),
ID($sdffce),
@ -117,6 +120,18 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
ID($_DFFE_PP0P_),
ID($_DFFE_PP1N_),
ID($_DFFE_PP1P_),
ID($_ALDFF_NN_),
ID($_ALDFF_NP_),
ID($_ALDFF_PN_),
ID($_ALDFF_PP_),
ID($_ALDFFE_NNN_),
ID($_ALDFFE_NNP_),
ID($_ALDFFE_NPN_),
ID($_ALDFFE_NPP_),
ID($_ALDFFE_PNN_),
ID($_ALDFFE_PNP_),
ID($_ALDFFE_PPN_),
ID($_ALDFFE_PPP_),
ID($_SDFF_NN0_),
ID($_SDFF_NN1_),
ID($_SDFF_NP0_),
@ -363,6 +378,26 @@ bool RTLIL::Const::is_fully_undef() const
return true;
}
bool RTLIL::Const::is_onehot(int *pos) const
{
cover("kernel.rtlil.const.is_onehot");
bool found = false;
for (int i = 0; i < GetSize(*this); i++) {
auto &bit = bits[i];
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
return false;
if (bit == RTLIL::State::S1) {
if (found)
return false;
if (pos)
*pos = i;
found = true;
}
}
return found;
}
bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
{
return attributes.count(id);
@ -445,6 +480,35 @@ vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
return split_tokens(get_string_attribute(ID::hdlname), " ");
}
void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<int> &data)
{
std::stringstream attrval;
for (auto &i : data) {
if (attrval.tellp() > 0)
attrval << " ";
attrval << i;
}
attributes[id] = RTLIL::Const(attrval.str());
}
vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
{
vector<int> data;
auto it = attributes.find(id);
if (it != attributes.end())
for (const auto &s : split_tokens(attributes.at(id).decode_string())) {
char *end = nullptr;
errno = 0;
long value = strtol(s.c_str(), &end, 10);
if (end != s.c_str() + s.size())
log_cmd_error("Literal for intvec attribute has invalid format");
if (errno == ERANGE || value < INT_MIN || value > INT_MAX)
log_cmd_error("Literal for intvec attribute is out of range");
data.push_back(value);
}
return data;
}
bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
{
if (full_selection)
@ -551,8 +615,10 @@ RTLIL::Design::Design()
RTLIL::Design::~Design()
{
for (auto it = modules_.begin(); it != modules_.end(); ++it)
delete it->second;
for (auto &pr : modules_)
delete pr.second;
for (auto n : bindings_)
delete n;
for (auto n : verilog_packages)
delete n;
for (auto n : verilog_globals)
@ -580,6 +646,11 @@ RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
return modules_.count(name) ? modules_.at(name) : NULL;
}
const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
RTLIL::Module *RTLIL::Design::top_module()
{
RTLIL::Module *module = nullptr;
@ -611,9 +682,16 @@ void RTLIL::Design::add(RTLIL::Module *module)
}
}
void RTLIL::Design::add(RTLIL::Binding *binding)
{
log_assert(binding != nullptr);
bindings_.push_back(binding);
}
RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
{
log_assert(modules_.count(name) == 0);
if (modules_.count(name) != 0)
log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name.c_str());
log_assert(refcount_modules_ == 0);
RTLIL::Module *module = new RTLIL::Module;
@ -807,12 +885,12 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
return result;
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn(bool include_wb) const
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (it.second->get_blackbox_attribute())
if (it.second->get_blackbox_attribute(include_wb))
continue;
else if (selected_whole_module(it.first))
result.push_back(it.second);
@ -838,14 +916,16 @@ RTLIL::Module::Module()
RTLIL::Module::~Module()
{
for (auto it = wires_.begin(); it != wires_.end(); ++it)
delete it->second;
for (auto it = memories.begin(); it != memories.end(); ++it)
delete it->second;
for (auto it = cells_.begin(); it != cells_.end(); ++it)
delete it->second;
for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
for (auto &pr : wires_)
delete pr.second;
for (auto &pr : memories)
delete pr.second;
for (auto &pr : cells_)
delete pr.second;
for (auto &pr : processes)
delete pr.second;
for (auto binding : bindings_)
delete binding;
#ifdef WITH_PYTHON
RTLIL::Module::get_all_modules()->erase(hashidx_);
#endif
@ -885,9 +965,14 @@ void RTLIL::Module::makeblackbox()
set_bool_attribute(ID::blackbox);
}
void RTLIL::Module::reprocess_module(RTLIL::Design *, const dict<RTLIL::IdString, RTLIL::Module *> &)
void RTLIL::Module::expand_interfaces(RTLIL::Design *, const dict<RTLIL::IdString, RTLIL::Module *> &)
{
log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
log_error("Class doesn't support expand_interfaces (module: `%s')!\n", id2cstr(name));
}
bool RTLIL::Module::reprocess_if_necessary(RTLIL::Design *)
{
return false;
}
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dict<RTLIL::IdString, RTLIL::Const> &, bool mayfail)
@ -1166,6 +1251,22 @@ namespace {
return;
}
if (cell->type == ID($bmux)) {
port(ID::A, param(ID::WIDTH) << param(ID::S_WIDTH));
port(ID::S, param(ID::S_WIDTH));
port(ID::Y, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($demux)) {
port(ID::A, param(ID::WIDTH));
port(ID::S, param(ID::S_WIDTH));
port(ID::Y, param(ID::WIDTH) << param(ID::S_WIDTH));
check_expected();
return;
}
if (cell->type == ID($lut)) {
param(ID::LUT);
port(ID::A, param(ID::WIDTH));
@ -1300,6 +1401,32 @@ namespace {
return;
}
if (cell->type == ID($aldff)) {
param_bool(ID::CLK_POLARITY);
param_bool(ID::ALOAD_POLARITY);
port(ID::CLK, 1);
port(ID::ALOAD, 1);
port(ID::D, param(ID::WIDTH));
port(ID::AD, param(ID::WIDTH));
port(ID::Q, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($aldffe)) {
param_bool(ID::CLK_POLARITY);
param_bool(ID::EN_POLARITY);
param_bool(ID::ALOAD_POLARITY);
port(ID::CLK, 1);
port(ID::EN, 1);
port(ID::ALOAD, 1);
port(ID::D, param(ID::WIDTH));
port(ID::AD, param(ID::WIDTH));
port(ID::Q, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($dlatch)) {
param_bool(ID::EN_POLARITY);
port(ID::EN, 1);
@ -1366,6 +1493,26 @@ namespace {
return;
}
if (cell->type == ID($memrd_v2)) {
param(ID::MEMID);
param_bool(ID::CLK_ENABLE);
param_bool(ID::CLK_POLARITY);
param(ID::TRANSPARENCY_MASK);
param(ID::COLLISION_X_MASK);
param_bool(ID::CE_OVER_SRST);
param_bits(ID::ARST_VALUE, param(ID::WIDTH));
param_bits(ID::SRST_VALUE, param(ID::WIDTH));
param_bits(ID::INIT_VALUE, param(ID::WIDTH));
port(ID::CLK, 1);
port(ID::EN, 1);
port(ID::ARST, 1);
port(ID::SRST, 1);
port(ID::ADDR, param(ID::ABITS));
port(ID::DATA, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($memwr)) {
param(ID::MEMID);
param_bool(ID::CLK_ENABLE);
@ -1379,6 +1526,20 @@ namespace {
return;
}
if (cell->type == ID($memwr_v2)) {
param(ID::MEMID);
param_bool(ID::CLK_ENABLE);
param_bool(ID::CLK_POLARITY);
param(ID::PORTID);
param(ID::PRIORITY_MASK);
port(ID::CLK, 1);
port(ID::EN, param(ID::WIDTH));
port(ID::ADDR, param(ID::ABITS));
port(ID::DATA, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($meminit)) {
param(ID::MEMID);
param(ID::PRIORITY);
@ -1388,6 +1549,16 @@ namespace {
return;
}
if (cell->type == ID($meminit_v2)) {
param(ID::MEMID);
param(ID::PRIORITY);
port(ID::ADDR, param(ID::ABITS));
port(ID::DATA, param(ID::WIDTH) * param(ID::WORDS));
port(ID::EN, param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($mem)) {
param(ID::MEMID);
param(ID::SIZE);
@ -1410,6 +1581,38 @@ namespace {
return;
}
if (cell->type == ID($mem_v2)) {
param(ID::MEMID);
param(ID::SIZE);
param(ID::OFFSET);
param(ID::INIT);
param_bits(ID::RD_CLK_ENABLE, max(1, param(ID::RD_PORTS)));
param_bits(ID::RD_CLK_POLARITY, max(1, param(ID::RD_PORTS)));
param_bits(ID::RD_TRANSPARENCY_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
param_bits(ID::RD_COLLISION_X_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
param_bits(ID::RD_WIDE_CONTINUATION, max(1, param(ID::RD_PORTS)));
param_bits(ID::RD_CE_OVER_SRST, max(1, param(ID::RD_PORTS)));
param_bits(ID::RD_ARST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
param_bits(ID::RD_SRST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
param_bits(ID::RD_INIT_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS)));
param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS)));
param_bits(ID::WR_WIDE_CONTINUATION, max(1, param(ID::WR_PORTS)));
param_bits(ID::WR_PRIORITY_MASK, max(1, param(ID::WR_PORTS) * param(ID::WR_PORTS)));
port(ID::RD_CLK, param(ID::RD_PORTS));
port(ID::RD_EN, param(ID::RD_PORTS));
port(ID::RD_ARST, param(ID::RD_PORTS));
port(ID::RD_SRST, param(ID::RD_PORTS));
port(ID::RD_ADDR, param(ID::RD_PORTS) * param(ID::ABITS));
port(ID::RD_DATA, param(ID::RD_PORTS) * param(ID::WIDTH));
port(ID::WR_CLK, param(ID::WR_PORTS));
port(ID::WR_EN, param(ID::WR_PORTS) * param(ID::WIDTH));
port(ID::WR_ADDR, param(ID::WR_PORTS) * param(ID::ABITS));
port(ID::WR_DATA, param(ID::WR_PORTS) * param(ID::WIDTH));
check_expected();
return;
}
if (cell->type == ID($tribuf)) {
port(ID::A, param(ID::WIDTH));
port(ID::Y, param(ID::WIDTH));
@ -1535,6 +1738,15 @@ namespace {
ID($_DFFE_PP0N_), ID($_DFFE_PP0P_), ID($_DFFE_PP1N_), ID($_DFFE_PP1P_)))
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; }
if (cell->type.in(
ID($_ALDFF_NN_), ID($_ALDFF_NP_), ID($_ALDFF_PN_), ID($_ALDFF_PP_)))
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); check_expected(); return; }
if (cell->type.in(
ID($_ALDFFE_NNN_), ID($_ALDFFE_NNP_), ID($_ALDFFE_NPN_), ID($_ALDFFE_NPP_),
ID($_ALDFFE_PNN_), ID($_ALDFFE_PNP_), ID($_ALDFFE_PPN_), ID($_ALDFFE_PPP_)))
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); port(ID::E,1); check_expected(); return; }
if (cell->type.in(
ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
@ -1640,7 +1852,7 @@ void RTLIL::Module::check()
log_assert(!it.second->type.empty());
for (auto &it2 : it.second->connections()) {
log_assert(!it2.first.empty());
it2.second.check();
it2.second.check(this);
}
for (auto &it2 : it.second->attributes)
log_assert(!it2.first.empty());
@ -1686,8 +1898,8 @@ void RTLIL::Module::check()
for (auto &it : connections_) {
log_assert(it.first.size() == it.second.size());
log_assert(!it.first.has_const());
it.first.check();
it.second.check();
it.first.check(this);
it.second.check(this);
}
for (auto &it : attributes)
@ -1813,6 +2025,20 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this;
}
void RTLIL::Module::add(RTLIL::Process *process)
{
log_assert(!process->name.empty());
log_assert(count_id(process->name) == 0);
processes[process->name] = process;
process->module = this;
}
void RTLIL::Module::add(RTLIL::Binding *binding)
{
log_assert(binding != nullptr);
bindings_.push_back(binding);
}
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
@ -1869,6 +2095,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell)
delete cell;
}
void RTLIL::Module::remove(RTLIL::Process *process)
{
log_assert(processes.count(process->name) != 0);
processes.erase(process->name);
delete process;
}
void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
{
log_assert(wires_[wire->name] == wire);
@ -2094,11 +2327,19 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor
return mem;
}
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
{
RTLIL::Process *proc = new RTLIL::Process;
proc->name = name;
add(proc);
return proc;
}
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other)
{
RTLIL::Process *proc = other->clone();
proc->name = name;
processes[name] = proc;
add(proc);
return proc;
}
@ -2219,6 +2460,26 @@ DEF_METHOD(Mux, ID($mux), 0)
DEF_METHOD(Pmux, ID($pmux), 1)
#undef DEF_METHOD
#define DEF_METHOD(_func, _type, _demux) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \
cell->parameters[ID::S_WIDTH] = sig_s.size(); \
cell->setPort(ID::A, sig_a); \
cell->setPort(ID::S, sig_s); \
cell->setPort(ID::Y, sig_y); \
cell->set_src_attribute(src); \
return cell; \
} \
RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \
RTLIL::SigSpec sig_y = addWire(NEW_ID, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \
add ## _func(name, sig_a, sig_s, sig_y, src); \
return sig_y; \
}
DEF_METHOD(Bmux, ID($bmux), 0)
DEF_METHOD(Demux, ID($demux), 1)
#undef DEF_METHOD
#define DEF_METHOD_2(_func, _type, _P1, _P2) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
@ -2533,6 +2794,40 @@ RTLIL::Cell* RTLIL::Module::addAdffe(RTLIL::IdString name, const RTLIL::SigSpec
return cell;
}
RTLIL::Cell* RTLIL::Module::addAldff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, ID($aldff));
cell->parameters[ID::CLK_POLARITY] = clk_polarity;
cell->parameters[ID::ALOAD_POLARITY] = aload_polarity;
cell->parameters[ID::WIDTH] = sig_q.size();
cell->setPort(ID::CLK, sig_clk);
cell->setPort(ID::ALOAD, sig_aload);
cell->setPort(ID::D, sig_d);
cell->setPort(ID::AD, sig_ad);
cell->setPort(ID::Q, sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAldffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, ID($aldffe));
cell->parameters[ID::CLK_POLARITY] = clk_polarity;
cell->parameters[ID::EN_POLARITY] = en_polarity;
cell->parameters[ID::ALOAD_POLARITY] = aload_polarity;
cell->parameters[ID::WIDTH] = sig_q.size();
cell->setPort(ID::CLK, sig_clk);
cell->setPort(ID::EN, sig_en);
cell->setPort(ID::ALOAD, sig_aload);
cell->setPort(ID::D, sig_d);
cell->setPort(ID::AD, sig_ad);
cell->setPort(ID::Q, sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addSdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
{
@ -2723,6 +3018,33 @@ RTLIL::Cell* RTLIL::Module::addAdffeGate(RTLIL::IdString name, const RTLIL::SigS
return cell;
}
RTLIL::Cell* RTLIL::Module::addAldffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_ALDFF_%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N'));
cell->setPort(ID::C, sig_clk);
cell->setPort(ID::L, sig_aload);
cell->setPort(ID::D, sig_d);
cell->setPort(ID::AD, sig_ad);
cell->setPort(ID::Q, sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAldffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_ALDFFE_%c%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
cell->setPort(ID::C, sig_clk);
cell->setPort(ID::L, sig_aload);
cell->setPort(ID::E, sig_en);
cell->setPort(ID::D, sig_d);
cell->setPort(ID::AD, sig_ad);
cell->setPort(ID::Q, sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addSdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
bool srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
{
@ -2894,6 +3216,13 @@ RTLIL::Memory::Memory()
#endif
}
RTLIL::Process::Process() : module(nullptr)
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
hashidx_ = hashidx_count;
}
RTLIL::Cell::Cell() : module(nullptr)
{
static unsigned int hashidx_count = 123456789;
@ -3065,14 +3394,21 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
return;
if (type == ID($mux) || type == ID($pmux)) {
if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
if (type == ID($pmux))
if (type != ID($mux))
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
check();
return;
}
if (type == ID($demux)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
check();
return;
}
if (type == ID($lut) || type == ID($sop)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
return;
@ -3119,6 +3455,16 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
check();
}
bool RTLIL::Cell::has_memid() const
{
return type.in(ID($memwr), ID($memwr_v2), ID($memrd), ID($memrd_v2), ID($meminit), ID($meminit_v2));
}
bool RTLIL::Cell::is_mem_cell() const
{
return type.in(ID($mem), ID($mem_v2)) || has_memid();
}
RTLIL::SigChunk::SigChunk()
{
wire = NULL;
@ -3275,8 +3621,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
{
cover("kernel.rtlil.sigspec.init.const");
chunks_.emplace_back(value);
width_ = chunks_.back().width;
if (GetSize(value) != 0) {
chunks_.emplace_back(value);
width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0;
check();
}
@ -3285,8 +3635,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
{
cover("kernel.rtlil.sigspec.init.chunk");
chunks_.emplace_back(chunk);
width_ = chunks_.back().width;
if (chunk.width != 0) {
chunks_.emplace_back(chunk);
width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0;
check();
}
@ -3295,8 +3649,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
{
cover("kernel.rtlil.sigspec.init.wire");
chunks_.emplace_back(wire);
width_ = chunks_.back().width;
if (wire->width != 0) {
chunks_.emplace_back(wire);
width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0;
check();
}
@ -3305,8 +3663,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
{
cover("kernel.rtlil.sigspec.init.wire_part");
chunks_.emplace_back(wire, offset, width);
width_ = chunks_.back().width;
if (width != 0) {
chunks_.emplace_back(wire, offset, width);
width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0;
check();
}
@ -3315,8 +3677,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
{
cover("kernel.rtlil.sigspec.init.str");
chunks_.emplace_back(str);
width_ = chunks_.back().width;
if (str.size() != 0) {
chunks_.emplace_back(str);
width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0;
check();
}
@ -3325,7 +3691,8 @@ RTLIL::SigSpec::SigSpec(int val, int width)
{
cover("kernel.rtlil.sigspec.init.int");
chunks_.emplace_back(val, width);
if (width != 0)
chunks_.emplace_back(val, width);
width_ = width;
hash_ = 0;
check();
@ -3335,7 +3702,8 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
{
cover("kernel.rtlil.sigspec.init.state");
chunks_.emplace_back(bit, width);
if (width != 0)
chunks_.emplace_back(bit, width);
width_ = width;
hash_ = 0;
check();
@ -3345,11 +3713,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
{
cover("kernel.rtlil.sigspec.init.bit");
if (bit.wire == NULL)
chunks_.emplace_back(bit.data, width);
else
for (int i = 0; i < width; i++)
chunks_.push_back(bit);
if (width != 0) {
if (bit.wire == NULL)
chunks_.emplace_back(bit.data, width);
else
for (int i = 0; i < width; i++)
chunks_.push_back(bit);
}
width_ = width;
hash_ = 0;
check();
@ -3794,7 +4164,13 @@ void RTLIL::SigSpec::remove_const()
width_ = 0;
for (auto &chunk : chunks_)
if (chunk.wire != NULL) {
new_chunks.push_back(chunk);
if (!new_chunks.empty() &&
new_chunks.back().wire == chunk.wire &&
new_chunks.back().offset + new_chunks.back().width == chunk.offset) {
new_chunks.back().width += chunk.width;
} else {
new_chunks.push_back(chunk);
}
width_ += chunk.width;
}
@ -3941,7 +4317,7 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const
}
#ifndef NDEBUG
void RTLIL::SigSpec::check() const
void RTLIL::SigSpec::check(Module *mod) const
{
if (width_ > 64)
{
@ -3954,6 +4330,7 @@ void RTLIL::SigSpec::check() const
int w = 0;
for (size_t i = 0; i < chunks_.size(); i++) {
const RTLIL::SigChunk &chunk = chunks_[i];
log_assert(chunk.width != 0);
if (chunk.wire == NULL) {
if (i > 0)
log_assert(chunks_[i-1].wire != NULL);
@ -3966,6 +4343,8 @@ void RTLIL::SigSpec::check() const
log_assert(chunk.width >= 0);
log_assert(chunk.offset + chunk.width <= chunk.wire->width);
log_assert(chunk.data.size() == 0);
if (mod != nullptr)
log_assert(chunk.wire->module == mod);
}
w += chunk.width;
}
@ -3976,6 +4355,12 @@ void RTLIL::SigSpec::check() const
{
cover("kernel.rtlil.sigspec.check.unpacked");
if (mod != nullptr) {
for (size_t i = 0; i < bits_.size(); i++)
if (bits_[i].wire != nullptr)
log_assert(bits_[i].wire->module == mod);
}
log_assert(width_ == GetSize(bits_));
log_assert(chunks_.empty());
}
@ -4164,6 +4549,19 @@ bool RTLIL::SigSpec::has_marked_bits() const
return false;
}
bool RTLIL::SigSpec::is_onehot(int *pos) const
{
cover("kernel.rtlil.sigspec.is_onehot");
pack();
if (!is_fully_const())
return false;
log_assert(GetSize(chunks_) <= 1);
if (width_)
return RTLIL::Const(chunks_[0].data).is_onehot(pos);
return false;
}
bool RTLIL::SigSpec::as_bool() const
{
cover("kernel.rtlil.sigspec.as_bool");
@ -4537,6 +4935,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
new_syncrule->type = type;
new_syncrule->signal = signal;
new_syncrule->actions = actions;
new_syncrule->mem_write_actions = mem_write_actions;
return new_syncrule;
}

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -69,8 +69,10 @@ namespace RTLIL
struct SigSpec;
struct CaseRule;
struct SwitchRule;
struct MemWriteAction;
struct SyncRule;
struct Process;
struct Binding;
typedef std::pair<SigSpec, SigSpec> SigSig;
@ -165,7 +167,8 @@ namespace RTLIL
log_assert(p[0] == '$' || p[0] == '\\');
log_assert(p[1] != 0);
for (const char *c = p; *c; c++)
log_assert((unsigned)*c > (unsigned)' ');
if ((unsigned)*c <= (unsigned)' ')
log_error("Found control character or space (0x%02hhx) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
#ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) {
@ -482,6 +485,9 @@ namespace RTLIL
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
// This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().
// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
@ -660,6 +666,7 @@ struct RTLIL::Const
bool is_fully_ones() const;
bool is_fully_def() const;
bool is_fully_undef() const;
bool is_onehot(int *pos = nullptr) const;
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
RTLIL::Const ret;
@ -714,6 +721,9 @@ struct RTLIL::AttrObject
void set_hdlname_attribute(const vector<string> &hierarchy);
vector<string> get_hdlname_attribute() const;
void set_intvec_attribute(RTLIL::IdString id, const vector<int> &data);
vector<int> get_intvec_attribute(RTLIL::IdString id) const;
};
struct RTLIL::SigChunk
@ -752,7 +762,7 @@ struct RTLIL::SigBit
SigBit();
SigBit(RTLIL::State bit);
SigBit(bool bit);
explicit SigBit(bool bit);
SigBit(RTLIL::Wire *wire);
SigBit(RTLIL::Wire *wire, int offset);
SigBit(const RTLIL::SigChunk &chunk);
@ -834,7 +844,7 @@ public:
SigSpec(const std::vector<RTLIL::SigBit> &bits);
SigSpec(const pool<RTLIL::SigBit> &bits);
SigSpec(const std::set<RTLIL::SigBit> &bits);
SigSpec(bool bit);
explicit SigSpec(bool bit);
SigSpec(RTLIL::SigSpec &&other) {
width_ = other.width_;
@ -932,6 +942,7 @@ public:
bool is_fully_undef() const;
bool has_const() const;
bool has_marked_bits() const;
bool is_onehot(int *pos = nullptr) const;
bool as_bool() const;
int as_int(bool is_signed = false) const;
@ -960,9 +971,9 @@ public:
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
#ifndef NDEBUG
void check() const;
void check(Module *mod = nullptr) const;
#else
void check() const { }
void check(Module *mod = nullptr) const { (void)mod; }
#endif
};
@ -1029,6 +1040,8 @@ struct RTLIL::Design
int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Binding*> bindings_;
std::vector<AST::AstNode*> verilog_packages, verilog_globals;
std::unique_ptr<define_map_t> verilog_defines;
@ -1041,6 +1054,7 @@ struct RTLIL::Design
RTLIL::ObjRange<RTLIL::Module*> modules();
RTLIL::Module *module(RTLIL::IdString name);
const RTLIL::Module *module(RTLIL::IdString name) const;
RTLIL::Module *top_module();
bool has(RTLIL::IdString id) const {
@ -1048,6 +1062,8 @@ struct RTLIL::Design
}
void add(RTLIL::Module *module);
void add(RTLIL::Binding *binding);
RTLIL::Module *addModule(RTLIL::IdString name);
void remove(RTLIL::Module *module);
void rename(RTLIL::Module *module, RTLIL::IdString new_name);
@ -1110,7 +1126,7 @@ struct RTLIL::Design
std::vector<RTLIL::Module*> selected_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules_warn() const;
std::vector<RTLIL::Module*> selected_whole_modules_warn(bool include_wb = false) const;
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
#endif
@ -1124,6 +1140,7 @@ struct RTLIL::Module : public RTLIL::AttrObject
protected:
void add(RTLIL::Wire *wire);
void add(RTLIL::Cell *cell);
void add(RTLIL::Process *process);
public:
RTLIL::Design *design;
@ -1134,7 +1151,9 @@ public:
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
std::vector<RTLIL::SigSig> connections_;
std::vector<RTLIL::SigSig> connections_;
std::vector<RTLIL::Binding*> bindings_;
RTLIL::IdString name;
idict<RTLIL::IdString> avail_parameters;
@ -1147,7 +1166,8 @@ public:
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail = false);
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id);
virtual void reprocess_module(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
virtual bool reprocess_if_necessary(RTLIL::Design *design);
virtual void sort();
virtual void check();
@ -1189,12 +1209,24 @@ public:
return it == cells_.end() ? nullptr : it->second;
}
const RTLIL::Wire* wire(RTLIL::IdString id) const{
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
const RTLIL::Cell* cell(RTLIL::IdString id) const {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
void add(RTLIL::Binding *binding);
// Removing wires is expensive. If you have to remove wires, remove them all at once.
void remove(const pool<RTLIL::Wire*> &wires);
void remove(RTLIL::Cell *cell);
void remove(RTLIL::Process *process);
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
@ -1214,6 +1246,7 @@ public:
RTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other);
RTLIL::Process *addProcess(RTLIL::IdString name);
RTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other);
// The add* methods create a cell and return the created cell. All signals must exist in advance.
@ -1266,6 +1299,8 @@ public:
RTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = "");
RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
@ -1286,6 +1321,8 @@ public:
RTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
RTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
RTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = "");
RTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = "");
RTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = "");
RTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
RTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
@ -1323,6 +1360,10 @@ public:
bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
RTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
RTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = "");
RTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = "");
RTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = "");
RTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
@ -1339,7 +1380,6 @@ public:
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Bu0 (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
@ -1386,6 +1426,8 @@ public:
RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
@ -1511,6 +1553,9 @@ public:
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
#endif
bool has_memid() const;
bool is_mem_cell() const;
};
struct RTLIL::CaseRule : public RTLIL::AttrObject
@ -1520,7 +1565,6 @@ struct RTLIL::CaseRule : public RTLIL::AttrObject
std::vector<RTLIL::SwitchRule*> switches;
~CaseRule();
void optimize();
bool empty() const;
@ -1543,11 +1587,21 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
RTLIL::SwitchRule *clone() const;
};
struct RTLIL::MemWriteAction : RTLIL::AttrObject
{
RTLIL::IdString memid;
RTLIL::SigSpec address;
RTLIL::SigSpec data;
RTLIL::SigSpec enable;
RTLIL::Const priority_mask;
};
struct RTLIL::SyncRule
{
RTLIL::SyncType type;
RTLIL::SigSpec signal;
std::vector<RTLIL::SigSig> actions;
std::vector<RTLIL::MemWriteAction> mem_write_actions;
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
@ -1556,12 +1610,21 @@ struct RTLIL::SyncRule
struct RTLIL::Process : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
protected:
// use module->addProcess() and module->remove() to create or destroy processes
friend struct RTLIL::Module;
Process();
~Process();
public:
RTLIL::IdString name;
RTLIL::Module *module;
RTLIL::CaseRule root_case;
std::vector<RTLIL::SyncRule*> syncs;
~Process();
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const;
@ -1695,6 +1758,11 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
functor(it.first);
functor(it.second);
}
for (auto &it : mem_write_actions) {
functor(it.address);
functor(it.data);
functor(it.enable);
}
}
template<typename T>
@ -1704,6 +1772,11 @@ void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
for (auto &it : actions) {
functor(it.first, it.second);
}
for (auto &it : mem_write_actions) {
functor(it.address);
functor(it.data);
functor(it.enable);
}
}
template<typename T>

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -252,6 +252,106 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
if (cell->type == ID($bmux))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> undef_a, undef_s, undef_y;
if (model_undef)
{
undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
}
if (GetSize(s) == 0) {
ez->vec_set(a, y);
if (model_undef)
ez->vec_set(undef_a, undef_y);
} else {
for (int i = GetSize(s)-1; i >= 0; i--)
{
std::vector<int> out = (i == 0) ? y : ez->vec_var(a.size() / 2);
std::vector<int> yy = model_undef ? ez->vec_var(out.size()) : out;
std::vector<int> a0(a.begin(), a.begin() + a.size() / 2);
std::vector<int> a1(a.begin() + a.size() / 2, a.end());
ez->assume(ez->vec_eq(ez->vec_ite(s.at(i), a1, a0), yy));
if (model_undef)
{
std::vector<int> undef_out = (i == 0) ? undef_y : ez->vec_var(a.size() / 2);
std::vector<int> undef_a0(undef_a.begin(), undef_a.begin() + a.size() / 2);
std::vector<int> undef_a1(undef_a.begin() + a.size() / 2, undef_a.end());
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a0, a1));
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a0, undef_a1));
std::vector<int> yX = ez->vec_ite(undef_s.at(i), undef_ab, ez->vec_ite(s.at(i), undef_a1, undef_a0));
ez->assume(ez->vec_eq(yX, undef_out));
undefGating(out, yy, undef_out);
undef_a = undef_out;
}
a = out;
}
}
return true;
}
if (cell->type == ID($demux))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> undef_a, undef_s, undef_y;
if (model_undef)
{
undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
}
if (GetSize(s) == 0) {
ez->vec_set(a, y);
if (model_undef)
ez->vec_set(undef_a, undef_y);
} else {
for (int i = 0; i < (1 << GetSize(s)); i++)
{
std::vector<int> ss;
for (int j = 0; j < GetSize(s); j++) {
if (i & 1 << j)
ss.push_back(s[j]);
else
ss.push_back(ez->NOT(s[j]));
}
int sss = ez->expression(ezSAT::OpAnd, ss);
for (int j = 0; j < GetSize(a); j++) {
ez->SET(ez->AND(sss, a[j]), yy.at(i * GetSize(a) + j));
}
if (model_undef)
{
int s0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(ss), ez->vec_not(undef_s)));
int us = ez->AND(ez->NOT(s0), ez->expression(ezSAT::OpOr, undef_s));
for (int j = 0; j < GetSize(a); j++) {
int a0 = ez->AND(ez->NOT(a[j]), ez->NOT(undef_a[j]));
int yX = ez->AND(ez->OR(us, undef_a[j]), ez->NOT(ez->OR(s0, a0)));
ez->SET(yX, undef_y.at(i * GetSize(a) + j));
}
}
}
if (model_undef)
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == ID($pmux))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
@ -1081,7 +1181,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
FfData ff(nullptr, cell);
// Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first.
if (!ff.has_d || ff.has_arst || ff.has_sr || (ff.has_en && !ff.has_clk))
if (ff.has_aload || ff.has_arst || ff.has_sr)
return false;
if (timestep == 1)
@ -1094,7 +1194,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_d;
if (model_undef)
undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
int undef_srst;
@ -1108,21 +1208,21 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
else
std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
}
if (ff.has_en) {
int en = importDefSigSpec(ff.sig_en, timestep-1).at(0);
if (ff.has_ce) {
int ce = importDefSigSpec(ff.sig_ce, timestep-1).at(0);
std::vector<int> old_q = importDefSigSpec(ff.sig_q, timestep-1);
int undef_en;
int undef_ce;
std::vector<int> undef_old_q;
if (model_undef) {
undef_en = importUndefSigSpec(ff.sig_en, timestep-1).at(0);
undef_ce = importUndefSigSpec(ff.sig_ce, timestep-1).at(0);
undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1);
}
if (ff.pol_en)
std::tie(d, undef_d) = mux(en, undef_en, old_q, undef_old_q, d, undef_d);
if (ff.pol_ce)
std::tie(d, undef_d) = mux(ce, undef_ce, old_q, undef_old_q, d, undef_d);
else
std::tie(d, undef_d) = mux(en, undef_en, d, undef_d, old_q, undef_old_q);
std::tie(d, undef_d) = mux(ce, undef_ce, d, undef_d, old_q, undef_old_q);
}
if (ff.has_srst && !(ff.has_en && ff.ce_over_srst)) {
if (ff.has_srst && !(ff.has_ce && ff.ce_over_srst)) {
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
int undef_srst;

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* (C) 2020 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@ -49,9 +49,9 @@ struct TimingInfo
struct ModuleTiming
{
RTLIL::IdString type;
dict<BitBit, int> comb;
dict<NameBit, int> arrival, required;
dict<NameBit, std::pair<int,NameBit>> arrival, required;
bool has_inputs;
};
dict<RTLIL::IdString, ModuleTiming> data;
@ -120,11 +120,10 @@ struct TimingInfo
}
}
else if (cell->type == ID($specify3)) {
auto src = cell->getPort(ID::SRC);
auto src = cell->getPort(ID::SRC).as_bit();
auto dst = cell->getPort(ID::DST);
for (const auto &c : src.chunks())
if (!c.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
if (!src.wire || !src.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
for (const auto &c : dst.chunks())
if (!c.wire->port_output)
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
@ -136,34 +135,49 @@ struct TimingInfo
max = 0;
}
for (const auto &d : dst) {
auto &v = t.arrival[NameBit(d)];
v = std::max(v, max);
auto r = t.arrival.insert(NameBit(d));
auto &v = r.first->second;
if (r.second || v.first < max) {
v.first = max;
v.second = NameBit(src);
}
}
}
else if (cell->type == ID($specrule)) {
auto type = cell->getParam(ID::TYPE).decode_string();
if (type != "$setup" && type != "$setuphold")
IdString type = cell->getParam(ID::TYPE).decode_string();
if (type != ID($setup) && type != ID($setuphold))
continue;
auto src = cell->getPort(ID::SRC);
auto dst = cell->getPort(ID::DST);
auto dst = cell->getPort(ID::DST).as_bit();
for (const auto &c : src.chunks())
if (!c.wire->port_input)
if (!c.wire || !c.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
for (const auto &c : dst.chunks())
if (!c.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
if (!dst.wire || !dst.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
int max = cell->getParam(ID::T_LIMIT_MAX).as_int();
if (max < 0) {
log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
max = 0;
}
for (const auto &s : src) {
auto &v = t.required[NameBit(s)];
v = std::max(v, max);
auto r = t.required.insert(NameBit(s));
auto &v = r.first->second;
if (r.second || v.first < max) {
v.first = max;
v.second = NameBit(dst);
}
}
}
}
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
if (wire->port_input) {
t.has_inputs = true;
break;
}
}
return t;
}

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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

View file

@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -67,6 +67,7 @@
# define INIT_MODULE initlibyosys
extern "C" void INIT_MODULE();
#endif
#include <signal.h>
#endif
#include <limits.h>
@ -137,7 +138,7 @@ void yosys_banner()
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
log(" | Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> |\n");
log(" | Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
@ -540,6 +541,7 @@ void yosys_setup()
PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
Py_Initialize();
PyRun_SimpleString("import sys");
signal(SIGINT, SIG_DFL);
#endif
Pass::init_register();
@ -814,7 +816,9 @@ std::string proc_self_dirname()
path = (char *) realloc((void *) path, buflen);
while (buflen > 0 && path[buflen-1] != '/')
buflen--;
return std::string(path, buflen);
std::string str(path, buflen);
free(path);
return str;
}
#elif defined(_WIN32)
std::string proc_self_dirname()
@ -969,7 +973,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
}
}
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
bool run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *from_to_label)
{
if (design == nullptr)
design = yosys_design;
@ -979,11 +983,11 @@ void run_frontend(std::string filename, std::string command, std::string *backen
if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0)
filename_trim.erase(filename_trim.size()-3);
if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0)
command = "verilog";
command = " -vlog2k";
else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0)
command = "verilog -sv";
command = " -sv";
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0)
command = "vhdl";
command = " -vhdl";
else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0)
command = "blif";
else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0)
@ -1069,10 +1073,12 @@ void run_frontend(std::string filename, std::string command, std::string *backen
if (filename != "-")
fclose(f);
if (backend_command != NULL && *backend_command == "auto")
*backend_command = "";
return true;
}
return;
if (command == "tcl") {
Pass::call(design, vector<string>({command, filename}));
return true;
}
if (filename == "-") {
@ -1081,16 +1087,15 @@ void run_frontend(std::string filename, std::string command, std::string *backen
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
}
if (command == "tcl")
Pass::call(design, vector<string>({command, filename}));
else
if (command[0] == ' ') {
auto argv = split_tokens("read" + command);
argv.push_back(filename);
Pass::call(design, argv);
} else
Frontend::frontend_call(design, NULL, filename, command);
design->check();
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
{
run_frontend(filename, command, nullptr, nullptr, design);
design->check();
return false;
}
void run_pass(std::string command, RTLIL::Design *design)
@ -1404,7 +1409,7 @@ struct ScriptCmdPass : public Pass {
else if (args.size() == 2)
run_frontend(args[1], "script", design);
else if (args.size() == 3)
run_frontend(args[1], "script", NULL, &args[2], design);
run_frontend(args[1], "script", design, &args[2]);
else
extra_args(args, 2, design, false);
}

View file

@ -1,7 +1,7 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 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
@ -33,7 +33,7 @@
// This header is very boring. It just defines some general things that
// belong nowhere else and includes the interesting headers.
//
// Find more information in the "CodingReadme" file.
// Find more information in the "guidelines/GettingStarted" file.
#ifndef YOSYS_H
@ -147,9 +147,7 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p
# define YS_ATTRIBUTE(...)
#endif
#if __cplusplus >= 201703L
# define YS_MAYBE_UNUSED [[maybe_unused]];
#elif defined(__GNUC__) || defined(__clang__)
#if defined(__GNUC__) || defined(__clang__)
# define YS_MAYBE_UNUSED __attribute__((__unused__))
#else
# define YS_MAYBE_UNUSED
@ -222,6 +220,7 @@ namespace RTLIL {
struct Wire;
struct Cell;
struct Memory;
struct Process;
struct Module;
struct Design;
struct Monitor;
@ -245,6 +244,7 @@ namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
@ -253,6 +253,7 @@ namespace hashlib {
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
@ -349,8 +350,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern);
void rewrite_filename(std::string &filename);
void run_pass(std::string command, RTLIL::Design *design = nullptr);
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
bool run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr, std::string *from_to_label = nullptr);
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void shell(RTLIL::Design *design);