mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-27 00:18:46 +00:00
Merge updates from 'master' into krys/docs
This commit is contained in:
commit
98d0e749d6
107 changed files with 12414 additions and 1274 deletions
|
@ -385,17 +385,17 @@ Aig::Aig(Cell *cell)
|
|||
goto optimize;
|
||||
}
|
||||
|
||||
if (cell->type.in({ID($lt), ID($gt), ID($le), ID($ge)}))
|
||||
if (cell->type.in(ID($lt), ID($gt), ID($le), ID($ge)))
|
||||
{
|
||||
int width = std::max(GetSize(cell->getPort(ID::A)),
|
||||
GetSize(cell->getPort(ID::B))) + 1;
|
||||
vector<int> A = mk.inport_vec(ID::A, width);
|
||||
vector<int> B = mk.inport_vec(ID::B, width);
|
||||
|
||||
if (cell->type.in({ID($gt), ID($ge)}))
|
||||
if (cell->type.in(ID($gt), ID($ge)))
|
||||
std::swap(A, B);
|
||||
|
||||
int carry = mk.bool_node(!cell->type.in({ID($le), ID($ge)}));
|
||||
int carry = mk.bool_node(!cell->type.in(ID($le), ID($ge)));
|
||||
for (auto &n : B)
|
||||
n = mk.not_gate(n);
|
||||
vector<int> Y = mk.adder(A, B, carry);
|
||||
|
|
|
@ -101,6 +101,12 @@ struct CellTypes
|
|||
setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);
|
||||
setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool<RTLIL::IdString>(), true);
|
||||
setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);
|
||||
setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y});
|
||||
setup_type(ID($get_tag), {ID::A}, {ID::Y});
|
||||
setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($original_tag), {ID::A}, {ID::Y});
|
||||
setup_type(ID($future_ff), {ID::A}, {ID::Y});
|
||||
}
|
||||
|
||||
void setup_internals_eval()
|
||||
|
|
|
@ -22,6 +22,8 @@ X(always_ff)
|
|||
X(always_latch)
|
||||
X(anyconst)
|
||||
X(anyseq)
|
||||
X(ARGS)
|
||||
X(ARGS_WIDTH)
|
||||
X(ARST)
|
||||
X(ARST_POLARITY)
|
||||
X(ARST_VALUE)
|
||||
|
@ -86,6 +88,7 @@ X(equiv_merged)
|
|||
X(equiv_region)
|
||||
X(extract_order)
|
||||
X(F)
|
||||
X(FORMAT)
|
||||
X(force_downto)
|
||||
X(force_upto)
|
||||
X(fsm_encoding)
|
||||
|
@ -205,6 +208,7 @@ X(syn_romstyle)
|
|||
X(S_WIDTH)
|
||||
X(T)
|
||||
X(TABLE)
|
||||
X(TAG)
|
||||
X(techmap_autopurge)
|
||||
X(_TECHMAP_BITS_CONNMAP_)
|
||||
X(_TECHMAP_CELLNAME_)
|
||||
|
@ -233,6 +237,10 @@ X(TRANS_NUM)
|
|||
X(TRANSPARENCY_MASK)
|
||||
X(TRANSPARENT)
|
||||
X(TRANS_TABLE)
|
||||
X(TRG)
|
||||
X(TRG_ENABLE)
|
||||
X(TRG_POLARITY)
|
||||
X(TRG_WIDTH)
|
||||
X(T_RISE_MAX)
|
||||
X(T_RISE_MIN)
|
||||
X(T_RISE_TYP)
|
||||
|
|
758
kernel/fmt.cc
Normal file
758
kernel/fmt.cc
Normal file
|
@ -0,0 +1,758 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2020 whitequark <whitequark@whitequark.org>
|
||||
*
|
||||
* 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 "libs/bigint/BigUnsigned.hh"
|
||||
#include "kernel/fmt.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
void Fmt::append_string(const std::string &str) {
|
||||
FmtPart part = {};
|
||||
part.type = FmtPart::STRING;
|
||||
part.str = str;
|
||||
parts.push_back(part);
|
||||
}
|
||||
|
||||
void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
||||
std::string fmt = cell->getParam(ID(FORMAT)).decode_string();
|
||||
RTLIL::SigSpec args = cell->getPort(ID(ARGS));
|
||||
parts.clear();
|
||||
|
||||
FmtPart part;
|
||||
for (size_t i = 0; i < fmt.size(); i++) {
|
||||
if (fmt.substr(i, 2) == "}}") {
|
||||
part.str += '}';
|
||||
++i;
|
||||
} else if (fmt.substr(i, 2) == "{{") {
|
||||
part.str += '{';
|
||||
++i;
|
||||
} else if (fmt[i] == '}')
|
||||
log_assert(false && "Unexpected '}' in format string");
|
||||
else if (fmt[i] == '{') {
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
}
|
||||
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
size_t arg_size = 0;
|
||||
for (; i < fmt.size(); i++) {
|
||||
if (fmt[i] >= '0' && fmt[i] <= '9') {
|
||||
arg_size *= 10;
|
||||
arg_size += fmt[i] - '0';
|
||||
} else if (fmt[i] == ':') {
|
||||
++i;
|
||||
break;
|
||||
} else {
|
||||
log_assert(false && "Unexpected character in format substitution");
|
||||
}
|
||||
}
|
||||
if (i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
if ((size_t)args.size() < arg_size)
|
||||
log_assert(false && "Format part overruns arguments");
|
||||
part.sig = args.extract(0, arg_size);
|
||||
args.remove(0, arg_size);
|
||||
|
||||
if (fmt[i] == '>')
|
||||
part.justify = FmtPart::RIGHT;
|
||||
else if (fmt[i] == '<')
|
||||
part.justify = FmtPart::LEFT;
|
||||
else
|
||||
log_assert(false && "Unexpected justification in format substitution");
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
if (fmt[i] == '0' || fmt[i] == ' ')
|
||||
part.padding = fmt[i];
|
||||
else
|
||||
log_assert(false && "Unexpected padding in format substitution");
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
for (; i < fmt.size(); i++) {
|
||||
if (fmt[i] >= '0' && fmt[i] <= '9') {
|
||||
part.width *= 10;
|
||||
part.width += fmt[i] - '0';
|
||||
continue;
|
||||
} else if (fmt[i] == 'b') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 2;
|
||||
} else if (fmt[i] == 'o') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 8;
|
||||
} else if (fmt[i] == 'd') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 10;
|
||||
} else if (fmt[i] == 'h') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 16;
|
||||
} else if (fmt[i] == 'c') {
|
||||
part.type = FmtPart::CHARACTER;
|
||||
} else if (fmt[i] == 't') {
|
||||
part.type = FmtPart::TIME;
|
||||
} else if (fmt[i] == 'r') {
|
||||
part.type = FmtPart::TIME;
|
||||
part.realtime = true;
|
||||
} else {
|
||||
log_assert(false && "Unexpected character in format substitution");
|
||||
}
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
if (i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
if (part.type == FmtPart::INTEGER) {
|
||||
if (fmt[i] == '+') {
|
||||
part.plus = true;
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
}
|
||||
|
||||
if (fmt[i] == 'u')
|
||||
part.signed_ = false;
|
||||
else if (fmt[i] == 's')
|
||||
part.signed_ = true;
|
||||
else
|
||||
log_assert(false && "Unexpected character in format substitution");
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
}
|
||||
|
||||
if (fmt[i] != '}')
|
||||
log_assert(false && "Expected '}' after format substitution");
|
||||
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
} else {
|
||||
part.str += fmt[i];
|
||||
}
|
||||
}
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
parts.push_back(part);
|
||||
}
|
||||
}
|
||||
|
||||
void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
||||
std::string fmt;
|
||||
RTLIL::SigSpec args;
|
||||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
for (char c : part.str) {
|
||||
if (c == '{')
|
||||
fmt += "{{";
|
||||
else if (c == '}')
|
||||
fmt += "}}";
|
||||
else
|
||||
fmt += c;
|
||||
}
|
||||
break;
|
||||
|
||||
case FmtPart::TIME:
|
||||
log_assert(part.sig.size() == 0);
|
||||
YS_FALLTHROUGH
|
||||
case FmtPart::CHARACTER:
|
||||
log_assert(part.sig.size() % 8 == 0);
|
||||
YS_FALLTHROUGH
|
||||
case FmtPart::INTEGER:
|
||||
args.append(part.sig);
|
||||
fmt += '{';
|
||||
fmt += std::to_string(part.sig.size());
|
||||
fmt += ':';
|
||||
if (part.justify == FmtPart::RIGHT)
|
||||
fmt += '>';
|
||||
else if (part.justify == FmtPart::LEFT)
|
||||
fmt += '<';
|
||||
else log_abort();
|
||||
log_assert(part.width == 0 || part.padding != '\0');
|
||||
fmt += part.padding != '\0' ? part.padding : ' ';
|
||||
if (part.width > 0)
|
||||
fmt += std::to_string(part.width);
|
||||
if (part.type == FmtPart::INTEGER) {
|
||||
switch (part.base) {
|
||||
case 2: fmt += 'b'; break;
|
||||
case 8: fmt += 'o'; break;
|
||||
case 10: fmt += 'd'; break;
|
||||
case 16: fmt += 'h'; break;
|
||||
default: log_abort();
|
||||
}
|
||||
if (part.plus)
|
||||
fmt += '+';
|
||||
fmt += part.signed_ ? 's' : 'u';
|
||||
} else if (part.type == FmtPart::CHARACTER) {
|
||||
fmt += 'c';
|
||||
} else if (part.type == FmtPart::TIME) {
|
||||
if (part.realtime)
|
||||
fmt += 'r';
|
||||
else
|
||||
fmt += 't';
|
||||
} else log_abort();
|
||||
fmt += '}';
|
||||
break;
|
||||
|
||||
default: log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
cell->setParam(ID(FORMAT), fmt);
|
||||
cell->setParam(ID(ARGS_WIDTH), args.size());
|
||||
cell->setPort(ID(ARGS), args);
|
||||
}
|
||||
|
||||
static size_t compute_required_decimal_places(size_t size, bool signed_)
|
||||
{
|
||||
BigUnsigned max;
|
||||
if (!signed_)
|
||||
max.setBit(size, true);
|
||||
else
|
||||
max.setBit(size - 1, true);
|
||||
size_t places = 0;
|
||||
while (!max.isZero()) {
|
||||
places++;
|
||||
max /= 10;
|
||||
}
|
||||
if (signed_)
|
||||
places++;
|
||||
return places;
|
||||
}
|
||||
|
||||
static size_t compute_required_nondecimal_places(size_t size, unsigned base)
|
||||
{
|
||||
log_assert(base != 10);
|
||||
BigUnsigned max;
|
||||
max.setBit(size - 1, true);
|
||||
size_t places = 0;
|
||||
while (!max.isZero()) {
|
||||
places++;
|
||||
max /= base;
|
||||
}
|
||||
return places;
|
||||
}
|
||||
|
||||
// Only called for integers, either when:
|
||||
//
|
||||
// (a) passed without a format string (e.g. "$display(a);"), or
|
||||
//
|
||||
// (b) the corresponding format specifier has no leading zero, e.g. "%b",
|
||||
// "%20h", "%-10d".
|
||||
//
|
||||
// In these cases, for binary/octal/hex, we always zero-pad to the size of the
|
||||
// signal; i.e. whether "%h" or "%10h" or "%-20h" is used, if the corresponding
|
||||
// signal is 32'h1234, "00001234" will always be a substring of the output.
|
||||
//
|
||||
// For case (a), we have no specified width, so there is nothing more to do.
|
||||
//
|
||||
// For case (b), because we are only called with no leading zero on the
|
||||
// specifier, any specified width beyond the signal size is therefore space
|
||||
// padding, whatever the justification.
|
||||
//
|
||||
// For decimal, we do no zero-padding, instead space-padding to the size
|
||||
// required for the signal's largest value. This is per other Verilog
|
||||
// implementations, and intuitively makes sense as decimal representations lack
|
||||
// a discrete mapping of digits to bit groups. Decimals may also show sign and
|
||||
// must accommodate this, whereas other representations do not.
|
||||
void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part)
|
||||
{
|
||||
if (part.base == 10) {
|
||||
size_t places = compute_required_decimal_places(part.sig.size(), part.signed_);
|
||||
part.padding = ' ';
|
||||
part.width = std::max(part.width, places);
|
||||
parts.push_back(part);
|
||||
return;
|
||||
}
|
||||
|
||||
part.padding = '0';
|
||||
|
||||
size_t places = compute_required_nondecimal_places(part.sig.size(), part.base);
|
||||
if (part.width < places) {
|
||||
part.justify = FmtPart::RIGHT;
|
||||
part.width = places;
|
||||
parts.push_back(part);
|
||||
} else if (part.width == places) {
|
||||
parts.push_back(part);
|
||||
} else if (part.width > places) {
|
||||
auto gap = std::string(part.width - places, ' ');
|
||||
part.width = places;
|
||||
|
||||
if (part.justify == FmtPart::RIGHT) {
|
||||
append_string(gap);
|
||||
parts.push_back(part);
|
||||
} else {
|
||||
part.justify = FmtPart::RIGHT;
|
||||
parts.push_back(part);
|
||||
append_string(gap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name)
|
||||
{
|
||||
parts.clear();
|
||||
|
||||
auto arg = args.begin();
|
||||
for (; arg != args.end(); ++arg) {
|
||||
switch (arg->type) {
|
||||
case VerilogFmtArg::INTEGER: {
|
||||
FmtPart part = {};
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.sig = arg->sig;
|
||||
part.base = default_base;
|
||||
part.signed_ = arg->signed_;
|
||||
apply_verilog_automatic_sizing_and_add(part);
|
||||
break;
|
||||
}
|
||||
|
||||
case VerilogFmtArg::STRING: {
|
||||
if (arg == args.begin() || !sformat_like) {
|
||||
const auto fmtarg = arg;
|
||||
const std::string &fmt = fmtarg->str;
|
||||
FmtPart part = {};
|
||||
for (size_t i = 0; i < fmt.size(); i++) {
|
||||
if (fmt[i] != '%') {
|
||||
part.str += fmt[i];
|
||||
} else if (fmt.substr(i, 2) == "%%") {
|
||||
i++;
|
||||
part.str += '%';
|
||||
} else if (fmt.substr(i, 2) == "%l" || fmt.substr(i, 2) == "%L") {
|
||||
i++;
|
||||
part.str += module_name.str();
|
||||
} else if (fmt.substr(i, 2) == "%m" || fmt.substr(i, 2) == "%M") {
|
||||
i++;
|
||||
part.str += module_name.str();
|
||||
} else {
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
}
|
||||
if (++i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
if (++arg == args.end()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
}
|
||||
part.sig = arg->sig;
|
||||
part.signed_ = arg->signed_;
|
||||
|
||||
for (; i < fmt.size(); i++) {
|
||||
if (fmt[i] == '-') {
|
||||
// left justify; not in IEEE 1800-2017 or verilator but iverilog has it
|
||||
part.justify = FmtPart::LEFT;
|
||||
} else if (fmt[i] == '+') {
|
||||
// always show sign; not in IEEE 1800-2017 or verilator but iverilog has it
|
||||
part.plus = true;
|
||||
} else break;
|
||||
}
|
||||
if (i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
bool has_leading_zero = false, has_width = false;
|
||||
for (; i < fmt.size(); i++) {
|
||||
if (fmt[i] >= '0' && fmt[i] <= '9') {
|
||||
if (fmt[i] == '0' && !has_width) {
|
||||
has_leading_zero = true;
|
||||
} else {
|
||||
has_width = true;
|
||||
part.width *= 10;
|
||||
part.width += fmt[i] - '0';
|
||||
}
|
||||
continue;
|
||||
} else if (fmt[i] == 'b' || fmt[i] == 'B') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 2;
|
||||
} else if (fmt[i] == 'o' || fmt[i] == 'O') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 8;
|
||||
} else if (fmt[i] == 'd' || fmt[i] == 'D') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 10;
|
||||
} else if (fmt[i] == 'h' || fmt[i] == 'H' ||
|
||||
fmt[i] == 'x' || fmt[i] == 'X') {
|
||||
// hex digits always printed in lowercase for %h%x as well as %H%X
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 16;
|
||||
} else if (fmt[i] == 'c' || fmt[i] == 'C') {
|
||||
part.type = FmtPart::CHARACTER;
|
||||
part.sig.extend_u0(8);
|
||||
// %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog
|
||||
} else if (fmt[i] == 's' || fmt[i] == 'S') {
|
||||
part.type = FmtPart::CHARACTER;
|
||||
if ((part.sig.size() % 8) != 0)
|
||||
part.sig.extend_u0((part.sig.size() + 7) / 8 * 8);
|
||||
// %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog
|
||||
part.padding = ' ';
|
||||
} else if (fmt[i] == 't' || fmt[i] == 'T') {
|
||||
if (arg->type == VerilogFmtArg::TIME) {
|
||||
part.type = FmtPart::TIME;
|
||||
part.realtime = arg->realtime;
|
||||
if (!has_width && !has_leading_zero)
|
||||
part.width = 20;
|
||||
} else {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
|
||||
}
|
||||
} else {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
if (part.padding == '\0')
|
||||
part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' ';
|
||||
|
||||
if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus)
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
|
||||
if (part.type == FmtPart::INTEGER && !has_leading_zero)
|
||||
apply_verilog_automatic_sizing_and_add(part);
|
||||
else
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
}
|
||||
}
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
parts.push_back(part);
|
||||
}
|
||||
} else {
|
||||
FmtPart part = {};
|
||||
part.type = FmtPart::STRING;
|
||||
part.str = arg->str;
|
||||
parts.push_back(part);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: log_abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||
{
|
||||
std::vector<VerilogFmtArg> args;
|
||||
VerilogFmtArg fmt = {};
|
||||
fmt.type = VerilogFmtArg::STRING;
|
||||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
for (char c : part.str) {
|
||||
if (c == '%')
|
||||
fmt.str += "%%";
|
||||
else
|
||||
fmt.str += c;
|
||||
}
|
||||
break;
|
||||
|
||||
case FmtPart::INTEGER: {
|
||||
VerilogFmtArg arg = {};
|
||||
arg.type = VerilogFmtArg::INTEGER;
|
||||
arg.sig = part.sig;
|
||||
arg.signed_ = part.signed_;
|
||||
args.push_back(arg);
|
||||
|
||||
fmt.str += '%';
|
||||
if (part.plus)
|
||||
fmt.str += '+';
|
||||
if (part.justify == FmtPart::LEFT)
|
||||
fmt.str += '-';
|
||||
if (part.width == 0) {
|
||||
fmt.str += '0';
|
||||
} else if (part.width > 0) {
|
||||
log_assert(part.padding == ' ' || part.padding == '0');
|
||||
if (part.base != 10 || part.padding == '0')
|
||||
fmt.str += '0';
|
||||
fmt.str += std::to_string(part.width);
|
||||
}
|
||||
switch (part.base) {
|
||||
case 2: fmt.str += 'b'; break;
|
||||
case 8: fmt.str += 'o'; break;
|
||||
case 10: fmt.str += 'd'; break;
|
||||
case 16: fmt.str += 'h'; break;
|
||||
default: log_abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::CHARACTER: {
|
||||
VerilogFmtArg arg;
|
||||
arg.type = VerilogFmtArg::INTEGER;
|
||||
arg.sig = part.sig;
|
||||
args.push_back(arg);
|
||||
|
||||
fmt.str += '%';
|
||||
if (part.justify == FmtPart::LEFT)
|
||||
fmt.str += '-';
|
||||
if (part.sig.size() == 8) {
|
||||
if (part.width > 0) {
|
||||
log_assert(part.padding == '0' || part.padding == ' ');
|
||||
if (part.padding == '0')
|
||||
fmt.str += part.padding;
|
||||
fmt.str += std::to_string(part.width);
|
||||
}
|
||||
fmt.str += 'c';
|
||||
} else {
|
||||
log_assert(part.sig.size() % 8 == 0);
|
||||
if (part.width > 0) {
|
||||
log_assert(part.padding == ' '); // no zero padding
|
||||
fmt.str += std::to_string(part.width);
|
||||
}
|
||||
fmt.str += 's';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::TIME: {
|
||||
VerilogFmtArg arg;
|
||||
arg.type = VerilogFmtArg::TIME;
|
||||
if (part.realtime)
|
||||
arg.realtime = true;
|
||||
args.push_back(arg);
|
||||
|
||||
fmt.str += '%';
|
||||
if (part.plus)
|
||||
fmt.str += '+';
|
||||
if (part.justify == FmtPart::LEFT)
|
||||
fmt.str += '-';
|
||||
log_assert(part.padding == ' ' || part.padding == '0');
|
||||
if (part.padding == '0' && part.width > 0)
|
||||
fmt.str += '0';
|
||||
fmt.str += std::to_string(part.width);
|
||||
fmt.str += 't';
|
||||
break;
|
||||
}
|
||||
|
||||
default: log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
args.insert(args.begin(), fmt);
|
||||
return args;
|
||||
}
|
||||
|
||||
void Fmt::emit_cxxrtl(std::ostream &f, std::function<void(const RTLIL::SigSpec &)> emit_sig) const
|
||||
{
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
f << " << \"";
|
||||
for (char c : part.str) {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
YS_FALLTHROUGH
|
||||
case '"':
|
||||
f << '\\' << c;
|
||||
break;
|
||||
case '\a':
|
||||
f << "\\a";
|
||||
break;
|
||||
case '\b':
|
||||
f << "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
f << "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
f << "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
f << "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
f << "\\t";
|
||||
break;
|
||||
case '\v':
|
||||
f << "\\v";
|
||||
break;
|
||||
default:
|
||||
f << c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
f << '"';
|
||||
break;
|
||||
|
||||
case FmtPart::INTEGER:
|
||||
case FmtPart::CHARACTER: {
|
||||
f << " << value_formatted<" << part.sig.size() << ">(";
|
||||
emit_sig(part.sig);
|
||||
f << ", " << (part.type == FmtPart::CHARACTER);
|
||||
f << ", " << (part.justify == FmtPart::LEFT);
|
||||
f << ", (char)" << (int)part.padding;
|
||||
f << ", " << part.width;
|
||||
f << ", " << part.base;
|
||||
f << ", " << part.signed_;
|
||||
f << ", " << part.plus;
|
||||
f << ')';
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::TIME: {
|
||||
// CXXRTL only records steps taken, so there's no difference between
|
||||
// the values taken by $time and $realtime.
|
||||
f << " << value_formatted<64>(";
|
||||
f << "value<64>{steps}";
|
||||
f << ", " << (part.type == FmtPart::CHARACTER);
|
||||
f << ", " << (part.justify == FmtPart::LEFT);
|
||||
f << ", (char)" << (int)part.padding;
|
||||
f << ", " << part.width;
|
||||
f << ", " << part.base;
|
||||
f << ", " << part.signed_;
|
||||
f << ", " << part.plus;
|
||||
f << ')';
|
||||
break;
|
||||
}
|
||||
|
||||
default: log_abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Fmt::render() const
|
||||
{
|
||||
std::string str;
|
||||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
str += part.str;
|
||||
break;
|
||||
|
||||
case FmtPart::INTEGER:
|
||||
case FmtPart::TIME:
|
||||
case FmtPart::CHARACTER: {
|
||||
std::string buf;
|
||||
if (part.type == FmtPart::INTEGER) {
|
||||
RTLIL::Const value = part.sig.as_const();
|
||||
|
||||
if (part.base != 10) {
|
||||
size_t minimum_size = 0;
|
||||
for (size_t index = 0; index < (size_t)value.size(); index++)
|
||||
if (value[index] != State::S0)
|
||||
minimum_size = index + 1;
|
||||
value = value.extract(0, minimum_size);
|
||||
}
|
||||
|
||||
if (part.base == 2) {
|
||||
buf = value.as_string();
|
||||
} else if (part.base == 8 || part.base == 16) {
|
||||
size_t step = (part.base == 16) ? 4 : 3;
|
||||
for (size_t index = 0; index < (size_t)value.size(); index += step) {
|
||||
RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index));
|
||||
bool has_x = false, all_x = true, has_z = false, all_z = true;
|
||||
for (State bit : subvalue) {
|
||||
if (bit == State::Sx)
|
||||
has_x = true;
|
||||
else
|
||||
all_x = false;
|
||||
if (bit == State::Sz)
|
||||
has_z = true;
|
||||
else
|
||||
all_z = false;
|
||||
}
|
||||
if (all_x)
|
||||
buf += 'x';
|
||||
else if (all_z)
|
||||
buf += 'z';
|
||||
else if (has_x)
|
||||
buf += 'X';
|
||||
else if (has_z)
|
||||
buf += 'Z';
|
||||
else
|
||||
buf += "0123456789abcdef"[subvalue.as_int()];
|
||||
}
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
} else if (part.base == 10) {
|
||||
bool has_x = false, all_x = true, has_z = false, all_z = true;
|
||||
for (State bit : value) {
|
||||
if (bit == State::Sx)
|
||||
has_x = true;
|
||||
else
|
||||
all_x = false;
|
||||
if (bit == State::Sz)
|
||||
has_z = true;
|
||||
else
|
||||
all_z = false;
|
||||
}
|
||||
if (all_x)
|
||||
buf += 'x';
|
||||
else if (all_z)
|
||||
buf += 'z';
|
||||
else if (has_x)
|
||||
buf += 'X';
|
||||
else if (has_z)
|
||||
buf += 'Z';
|
||||
else {
|
||||
bool negative = part.signed_ && value[value.size() - 1];
|
||||
RTLIL::Const absvalue;
|
||||
if (negative)
|
||||
absvalue = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
|
||||
else
|
||||
absvalue = value;
|
||||
log_assert(absvalue.is_fully_def());
|
||||
if (absvalue.is_fully_zero())
|
||||
buf += '0';
|
||||
while (!absvalue.is_fully_zero()) {
|
||||
buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int();
|
||||
absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size());
|
||||
}
|
||||
if (negative || part.plus)
|
||||
buf += negative ? '-' : '+';
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
}
|
||||
} else log_abort();
|
||||
} else if (part.type == FmtPart::CHARACTER) {
|
||||
buf = part.sig.as_const().decode_string();
|
||||
} else if (part.type == FmtPart::TIME) {
|
||||
// We only render() during initial, so time is always zero.
|
||||
buf = "0";
|
||||
}
|
||||
|
||||
log_assert(part.width == 0 || part.padding != '\0');
|
||||
if (part.justify == FmtPart::RIGHT && buf.size() < part.width) {
|
||||
size_t pad_width = part.width - buf.size();
|
||||
if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) {
|
||||
str += buf.front();
|
||||
buf.erase(0, 1);
|
||||
}
|
||||
str += std::string(pad_width, part.padding);
|
||||
}
|
||||
str += buf;
|
||||
if (part.justify == FmtPart::LEFT && buf.size() < part.width)
|
||||
str += std::string(part.width - buf.size(), part.padding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
106
kernel/fmt.h
Normal file
106
kernel/fmt.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2020 whitequark <whitequark@whitequark.org>
|
||||
*
|
||||
* 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 FMT_H
|
||||
#define FMT_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// Verilog format argument, such as the arguments in:
|
||||
// $display("foo %d bar %01x", 4'b0, $signed(2'b11))
|
||||
struct VerilogFmtArg {
|
||||
enum {
|
||||
STRING = 0,
|
||||
INTEGER = 1,
|
||||
TIME = 2,
|
||||
} type;
|
||||
|
||||
// All types
|
||||
std::string filename;
|
||||
unsigned first_line;
|
||||
|
||||
// STRING type
|
||||
std::string str;
|
||||
|
||||
// INTEGER type
|
||||
RTLIL::SigSpec sig;
|
||||
bool signed_ = false;
|
||||
|
||||
// TIME type
|
||||
bool realtime = false;
|
||||
};
|
||||
|
||||
// RTLIL format part, such as the substitutions in:
|
||||
// "foo {4:> 4du} bar {2:<01hs}"
|
||||
struct FmtPart {
|
||||
enum {
|
||||
STRING = 0,
|
||||
INTEGER = 1,
|
||||
CHARACTER = 2,
|
||||
TIME = 3,
|
||||
} type;
|
||||
|
||||
// STRING type
|
||||
std::string str;
|
||||
|
||||
// INTEGER/CHARACTER types
|
||||
RTLIL::SigSpec sig;
|
||||
|
||||
// INTEGER/CHARACTER/TIME types
|
||||
enum {
|
||||
RIGHT = 0,
|
||||
LEFT = 1,
|
||||
} justify = RIGHT;
|
||||
char padding = '\0';
|
||||
size_t width = 0;
|
||||
|
||||
// INTEGER type
|
||||
unsigned base = 10;
|
||||
bool signed_ = false;
|
||||
bool plus = false;
|
||||
|
||||
// TIME type
|
||||
bool realtime = false;
|
||||
};
|
||||
|
||||
struct Fmt {
|
||||
public:
|
||||
std::vector<FmtPart> parts;
|
||||
|
||||
void append_string(const std::string &str);
|
||||
|
||||
void parse_rtlil(const RTLIL::Cell *cell);
|
||||
void emit_rtlil(RTLIL::Cell *cell) const;
|
||||
|
||||
void parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name);
|
||||
std::vector<VerilogFmtArg> emit_verilog() const;
|
||||
|
||||
void emit_cxxrtl(std::ostream &f, std::function<void(const RTLIL::SigSpec &)> emit_sig) const;
|
||||
|
||||
std::string render() const;
|
||||
|
||||
private:
|
||||
void apply_verilog_automatic_sizing_and_add(FmtPart &part);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1252,12 +1252,12 @@ void Mem::prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals) {
|
|||
// If transparent with only one, emulate it, and remove the collision-X
|
||||
// flag that emulate_transparency will set (to align with the other port).
|
||||
if (rport.transparency_mask[idx1]) {
|
||||
emulate_transparency(i, idx1, initvals);
|
||||
emulate_transparency(idx1, i, initvals);
|
||||
rport.collision_x_mask[idx1] = false;
|
||||
continue;
|
||||
}
|
||||
if (rport.transparency_mask[idx2]) {
|
||||
emulate_transparency(i, idx2, initvals);
|
||||
emulate_transparency(idx2, i, initvals);
|
||||
rport.collision_x_mask[idx2] = false;
|
||||
continue;
|
||||
}
|
||||
|
|
120
kernel/rtlil.cc
120
kernel/rtlil.cc
|
@ -1720,6 +1720,18 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($print)) {
|
||||
param(ID(FORMAT));
|
||||
param_bool(ID::TRG_ENABLE);
|
||||
param(ID::TRG_POLARITY);
|
||||
param(ID::PRIORITY);
|
||||
port(ID::EN, 1);
|
||||
port(ID::TRG, param(ID::TRG_WIDTH));
|
||||
port(ID::ARGS, param(ID::ARGS_WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||
if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||
if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; }
|
||||
|
@ -1816,6 +1828,40 @@ namespace {
|
|||
ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_)))
|
||||
{ port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
|
||||
|
||||
if (cell->type.in(ID($set_tag))) {
|
||||
param(ID::WIDTH);
|
||||
param(ID::TAG);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::SET, param(ID::WIDTH));
|
||||
port(ID::CLR, param(ID::WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
if (cell->type.in(ID($get_tag),ID($original_tag))) {
|
||||
param(ID::WIDTH);
|
||||
param(ID::TAG);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
if (cell->type.in(ID($overwrite_tag))) {
|
||||
param(ID::WIDTH);
|
||||
param(ID::TAG);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::SET, param(ID::WIDTH));
|
||||
port(ID::CLR, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
if (cell->type.in(ID($future_ff))) {
|
||||
param(ID::WIDTH);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
error(__LINE__);
|
||||
}
|
||||
};
|
||||
|
@ -3234,6 +3280,80 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string
|
|||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src)
|
||||
{
|
||||
RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size());
|
||||
Cell *cell = addCell(name, ID($set_tag));
|
||||
cell->parameters[ID::WIDTH] = sig_a.size();
|
||||
cell->parameters[ID::TAG] = tag;
|
||||
cell->setPort(ID::A, sig_a);
|
||||
cell->setPort(ID::SET, sig_s);
|
||||
cell->setPort(ID::CLR, sig_c);
|
||||
cell->setPort(ID::Y, sig);
|
||||
cell->set_src_attribute(src);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src)
|
||||
{
|
||||
Cell *cell = addCell(name, ID($set_tag));
|
||||
cell->parameters[ID::WIDTH] = sig_a.size();
|
||||
cell->parameters[ID::TAG] = tag;
|
||||
cell->setPort(ID::A, sig_a);
|
||||
cell->setPort(ID::SET, sig_s);
|
||||
cell->setPort(ID::CLR, sig_c);
|
||||
cell->setPort(ID::Y, sig_y);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src)
|
||||
{
|
||||
RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size());
|
||||
Cell *cell = addCell(name, ID($get_tag));
|
||||
cell->parameters[ID::WIDTH] = sig_a.size();
|
||||
cell->parameters[ID::TAG] = tag;
|
||||
cell->setPort(ID::A, sig_a);
|
||||
cell->setPort(ID::Y, sig);
|
||||
cell->set_src_attribute(src);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src)
|
||||
{
|
||||
RTLIL::Cell *cell = addCell(name, ID($overwrite_tag));
|
||||
cell->parameters[ID::WIDTH] = sig_a.size();
|
||||
cell->parameters[ID::TAG] = tag;
|
||||
cell->setPort(ID::A, sig_a);
|
||||
cell->setPort(ID::SET, sig_s);
|
||||
cell->setPort(ID::CLR, sig_c);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src)
|
||||
{
|
||||
RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size());
|
||||
Cell *cell = addCell(name, ID($original_tag));
|
||||
cell->parameters[ID::WIDTH] = sig_a.size();
|
||||
cell->parameters[ID::TAG] = tag;
|
||||
cell->setPort(ID::A, sig_a);
|
||||
cell->setPort(ID::Y, sig);
|
||||
cell->set_src_attribute(src);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec RTLIL::Module::FutureFF(RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src)
|
||||
{
|
||||
RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size());
|
||||
Cell *cell = addCell(name, ID($future_ff));
|
||||
cell->parameters[ID::WIDTH] = sig_e.size();
|
||||
cell->setPort(ID::A, sig_e);
|
||||
cell->setPort(ID::Y, sig);
|
||||
cell->set_src_attribute(src);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::Wire::Wire()
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
|
|
|
@ -1465,6 +1465,13 @@ public:
|
|||
RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = "");
|
||||
RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = "");
|
||||
|
||||
RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = "");
|
||||
RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = "");
|
||||
RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = "");
|
||||
RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = "");
|
||||
RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = "");
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue