mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 00:55:32 +00:00
Merge branch 'YosysHQ:main' into master
This commit is contained in:
commit
e3f633fae6
29 changed files with 1110 additions and 551 deletions
3
Makefile
3
Makefile
|
@ -141,7 +141,7 @@ LIBS += -lrt
|
|||
endif
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.39+147
|
||||
YOSYS_VER := 0.39+165
|
||||
|
||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||
|
@ -628,6 +628,7 @@ $(eval $(call add_include_file,kernel/sigtools.h))
|
|||
$(eval $(call add_include_file,kernel/timinginfo.h))
|
||||
$(eval $(call add_include_file,kernel/utils.h))
|
||||
$(eval $(call add_include_file,kernel/yosys.h))
|
||||
$(eval $(call add_include_file,kernel/yosys_common.h))
|
||||
$(eval $(call add_include_file,kernel/yw.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
|
||||
|
|
|
@ -625,11 +625,11 @@ struct value : public expr_base<value<Bits>> {
|
|||
value<Bits + 1> remainder;
|
||||
value<Bits + 1> dividend = sext<Bits + 1>();
|
||||
value<Bits + 1> divisor = other.template sext<Bits + 1>();
|
||||
if (dividend.is_neg()) dividend = dividend.neg();
|
||||
if (divisor.is_neg()) divisor = divisor.neg();
|
||||
if (is_neg()) dividend = dividend.neg();
|
||||
if (other.is_neg()) divisor = divisor.neg();
|
||||
std::tie(quotient, remainder) = dividend.udivmod(divisor);
|
||||
if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg();
|
||||
if (dividend.is_neg()) remainder = remainder.neg();
|
||||
if (is_neg() != other.is_neg()) quotient = quotient.neg();
|
||||
if (is_neg()) remainder = remainder.neg();
|
||||
return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
|
||||
}
|
||||
};
|
||||
|
@ -1010,22 +1010,24 @@ struct observer {
|
|||
// Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
|
||||
struct fmt_part {
|
||||
enum {
|
||||
STRING = 0,
|
||||
LITERAL = 0,
|
||||
INTEGER = 1,
|
||||
CHARACTER = 2,
|
||||
VLOG_TIME = 3,
|
||||
STRING = 2,
|
||||
UNICHAR = 3,
|
||||
VLOG_TIME = 4,
|
||||
} type;
|
||||
|
||||
// STRING type
|
||||
// LITERAL type
|
||||
std::string str;
|
||||
|
||||
// INTEGER/CHARACTER types
|
||||
// INTEGER/STRING/UNICHAR types
|
||||
// + value<Bits> val;
|
||||
|
||||
// INTEGER/CHARACTER/VLOG_TIME types
|
||||
// INTEGER/STRING/VLOG_TIME types
|
||||
enum {
|
||||
RIGHT = 0,
|
||||
LEFT = 1,
|
||||
NUMERIC = 2,
|
||||
} justify; // = RIGHT;
|
||||
char padding; // = '\0';
|
||||
size_t width; // = 0;
|
||||
|
@ -1033,7 +1035,14 @@ struct fmt_part {
|
|||
// INTEGER type
|
||||
unsigned base; // = 10;
|
||||
bool signed_; // = false;
|
||||
bool plus; // = false;
|
||||
enum {
|
||||
MINUS = 0,
|
||||
PLUS_MINUS = 1,
|
||||
SPACE_MINUS = 2,
|
||||
} sign; // = MINUS;
|
||||
bool hex_upper; // = false;
|
||||
bool show_base; // = false;
|
||||
bool group; // = false;
|
||||
|
||||
// VLOG_TIME type
|
||||
bool realtime; // = false;
|
||||
|
@ -1049,11 +1058,12 @@ struct fmt_part {
|
|||
// We might want to replace some of these bit() calls with direct
|
||||
// chunk access if it turns out to be slow enough to matter.
|
||||
std::string buf;
|
||||
std::string prefix;
|
||||
switch (type) {
|
||||
case STRING:
|
||||
case LITERAL:
|
||||
return str;
|
||||
|
||||
case CHARACTER: {
|
||||
case STRING: {
|
||||
buf.reserve(Bits/8);
|
||||
for (int i = 0; i < Bits; i += 8) {
|
||||
char ch = 0;
|
||||
|
@ -1067,35 +1077,76 @@ struct fmt_part {
|
|||
break;
|
||||
}
|
||||
|
||||
case UNICHAR: {
|
||||
uint32_t codepoint = val.template get<uint32_t>();
|
||||
if (codepoint >= 0x10000)
|
||||
buf += (char)(0xf0 | (codepoint >> 18));
|
||||
else if (codepoint >= 0x800)
|
||||
buf += (char)(0xe0 | (codepoint >> 12));
|
||||
else if (codepoint >= 0x80)
|
||||
buf += (char)(0xc0 | (codepoint >> 6));
|
||||
else
|
||||
buf += (char)codepoint;
|
||||
if (codepoint >= 0x10000)
|
||||
buf += (char)(0x80 | ((codepoint >> 12) & 0x3f));
|
||||
if (codepoint >= 0x800)
|
||||
buf += (char)(0x80 | ((codepoint >> 6) & 0x3f));
|
||||
if (codepoint >= 0x80)
|
||||
buf += (char)(0x80 | ((codepoint >> 0) & 0x3f));
|
||||
break;
|
||||
}
|
||||
|
||||
case INTEGER: {
|
||||
size_t width = Bits;
|
||||
bool negative = signed_ && val.is_neg();
|
||||
if (negative) {
|
||||
prefix = "-";
|
||||
val = val.neg();
|
||||
} else {
|
||||
switch (sign) {
|
||||
case MINUS: break;
|
||||
case PLUS_MINUS: prefix = "+"; break;
|
||||
case SPACE_MINUS: prefix = " "; break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t val_width = Bits;
|
||||
if (base != 10) {
|
||||
width = 0;
|
||||
val_width = 1;
|
||||
for (size_t index = 0; index < Bits; index++)
|
||||
if (val.bit(index))
|
||||
width = index + 1;
|
||||
val_width = index + 1;
|
||||
}
|
||||
|
||||
if (base == 2) {
|
||||
for (size_t i = width; i > 0; i--)
|
||||
buf += (val.bit(i - 1) ? '1' : '0');
|
||||
if (show_base)
|
||||
prefix += "0b";
|
||||
for (size_t index = 0; index < val_width; index++) {
|
||||
if (group && index > 0 && index % 4 == 0)
|
||||
buf += '_';
|
||||
buf += (val.bit(index) ? '1' : '0');
|
||||
}
|
||||
} else if (base == 8 || base == 16) {
|
||||
if (show_base)
|
||||
prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
|
||||
size_t step = (base == 16) ? 4 : 3;
|
||||
for (size_t index = 0; index < width; index += step) {
|
||||
for (size_t index = 0; index < val_width; index += step) {
|
||||
if (group && index > 0 && index % (4 * step) == 0)
|
||||
buf += '_';
|
||||
uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
|
||||
if (step == 4)
|
||||
value |= val.bit(index + 3) << 3;
|
||||
buf += "0123456789abcdef"[value];
|
||||
buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value];
|
||||
}
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
} else if (base == 10) {
|
||||
bool negative = signed_ && val.is_neg();
|
||||
if (negative)
|
||||
val = val.neg();
|
||||
if (show_base)
|
||||
prefix += "0d";
|
||||
if (val.is_zero())
|
||||
buf += '0';
|
||||
value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
|
||||
size_t index = 0;
|
||||
while (!xval.is_zero()) {
|
||||
if (group && index > 0 && index % 3 == 0)
|
||||
buf += '_';
|
||||
value<(Bits > 4 ? Bits : 4)> quotient, remainder;
|
||||
if (Bits >= 4)
|
||||
std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
|
||||
|
@ -1103,11 +1154,18 @@ struct fmt_part {
|
|||
std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
|
||||
buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
|
||||
xval = quotient;
|
||||
index++;
|
||||
}
|
||||
if (negative || plus)
|
||||
buf += negative ? '-' : '+';
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
} else assert(false && "Unsupported base for fmt_part");
|
||||
if (justify == NUMERIC && group && padding == '0') {
|
||||
int group_size = base == 10 ? 3 : 4;
|
||||
while (prefix.size() + buf.size() < width) {
|
||||
if (buf.size() % (group_size + 1) == group_size)
|
||||
buf += '_';
|
||||
buf += '0';
|
||||
}
|
||||
}
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1123,17 +1181,29 @@ struct fmt_part {
|
|||
|
||||
std::string str;
|
||||
assert(width == 0 || padding != '\0');
|
||||
if (justify == RIGHT && buf.size() < width) {
|
||||
size_t pad_width = width - buf.size();
|
||||
if (padding == '0' && (buf.front() == '+' || buf.front() == '-')) {
|
||||
str += buf.front();
|
||||
buf.erase(0, 1);
|
||||
}
|
||||
str += std::string(pad_width, padding);
|
||||
if (prefix.size() + buf.size() < width) {
|
||||
size_t pad_width = width - prefix.size() - buf.size();
|
||||
switch (justify) {
|
||||
case LEFT:
|
||||
str += prefix;
|
||||
str += buf;
|
||||
str += std::string(pad_width, padding);
|
||||
break;
|
||||
case RIGHT:
|
||||
str += std::string(pad_width, padding);
|
||||
str += prefix;
|
||||
str += buf;
|
||||
break;
|
||||
case NUMERIC:
|
||||
str += prefix;
|
||||
str += std::string(pad_width, padding);
|
||||
str += buf;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
str += prefix;
|
||||
str += buf;
|
||||
}
|
||||
str += buf;
|
||||
if (justify == LEFT && buf.size() < width)
|
||||
str += std::string(width - buf.size(), padding);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1070,7 +1070,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
f << stringf(";\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (cell->type == ID($_BUF_)) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
|
@ -2014,22 +2014,29 @@ void dump_sync_effect(std::ostream &f, std::string indent, const RTLIL::SigSpec
|
|||
|
||||
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
|
||||
{
|
||||
if (simple_lhs) {
|
||||
bool all_chunks_wires = true;
|
||||
for (auto &chunk : left.chunks())
|
||||
if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
|
||||
all_chunks_wires = false;
|
||||
if (!simple_lhs && all_chunks_wires) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, left);
|
||||
f << stringf(" = ");
|
||||
dump_sigspec(f, right);
|
||||
f << stringf(";\n");
|
||||
} else {
|
||||
int offset = 0;
|
||||
for (auto &chunk : left.chunks()) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
|
||||
f << stringf("%s" "always%s\n%s ", indent.c_str(), systemverilog ? "_comb" : " @*", indent.c_str());
|
||||
else
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, chunk);
|
||||
f << stringf(" = ");
|
||||
dump_sigspec(f, right.extract(offset, GetSize(chunk)));
|
||||
f << stringf(";\n");
|
||||
offset += GetSize(chunk);
|
||||
}
|
||||
} else {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, left);
|
||||
f << stringf(" = ");
|
||||
dump_sigspec(f, right);
|
||||
f << stringf(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2276,11 +2283,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
active_initdata[sig[i]] = val[i];
|
||||
}
|
||||
|
||||
if (!module->processes.empty())
|
||||
log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
|
||||
"can't always be mapped directly to Verilog always blocks. Unintended\n"
|
||||
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
|
||||
"processes to logic networks and registers.\n", log_id(module));
|
||||
bool has_sync_rules = false;
|
||||
for (auto process : module->processes)
|
||||
if (!process.second->syncs.empty())
|
||||
has_sync_rules = true;
|
||||
if (has_sync_rules)
|
||||
log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL "
|
||||
"processes can't always be mapped directly to Verilog always blocks. "
|
||||
"unintended changes in simulation behavior are possible! Use \"proc\" "
|
||||
"to convert processes to logic networks and registers.\n", log_id(module));
|
||||
|
||||
f << stringf("\n");
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
|
|
|
@ -619,6 +619,48 @@ Finite state machines
|
|||
|
||||
Add a brief description of the ``$fsm`` cell type.
|
||||
|
||||
Coarse arithmetics
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``$macc`` cell type represents a generalized multiply and accumulate operation. The cell is purely combinational. It outputs the result of summing up a sequence of products and other injected summands.
|
||||
|
||||
.. code-block::
|
||||
|
||||
Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ...
|
||||
+ B[0] + B[1] + ...
|
||||
|
||||
The A port consists of concatenated pairs of multiplier inputs ("factors").
|
||||
A zero length factor2 acts as a constant 1, turning factor1 into a simple summand.
|
||||
|
||||
In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long.
|
||||
|
||||
.. code-block::
|
||||
|
||||
struct A {
|
||||
u(CONFIG.mul_info[0].factor1_len) a0factor1;
|
||||
u(CONFIG.mul_info[0].factor2_len) a0factor2;
|
||||
u(CONFIG.mul_info[1].factor1_len) a1factor1;
|
||||
u(CONFIG.mul_info[1].factor2_len) a1factor2;
|
||||
...
|
||||
};
|
||||
|
||||
The cell's ``CONFIG`` parameter determines the layout of cell port ``A``.
|
||||
The CONFIG parameter carries the following information:
|
||||
|
||||
.. code-block::
|
||||
|
||||
struct CONFIG {
|
||||
u4 num_bits;
|
||||
struct mul_info {
|
||||
bool is_signed;
|
||||
bool is_subtract;
|
||||
u(num_bits) factor1_len;
|
||||
u(num_bits) factor2_len;
|
||||
}[num_ports];
|
||||
};
|
||||
|
||||
B is an array of concatenated 1-bit-wide unsigned integers to also be summed up.
|
||||
|
||||
Specify rules
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
@ -1152,4 +1194,4 @@ file via ABC using the abc pass.
|
|||
|
||||
.. todo:: Add information about ``$lut`` and ``$sop`` cells.
|
||||
|
||||
.. todo:: Add information about ``$alu``, ``$macc``, ``$fa``, and ``$lcu`` cells.
|
||||
.. todo:: Add information about ``$alu``, ``$fa``, and ``$lcu`` cells.
|
||||
|
|
|
@ -790,7 +790,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
Fmt fmt;
|
||||
fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
|
||||
if (ast->str.substr(0, 8) == "$display")
|
||||
fmt.append_string("\n");
|
||||
fmt.append_literal("\n");
|
||||
fmt.emit_rtlil(cell);
|
||||
} else if (!ast->str.empty()) {
|
||||
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
|
||||
|
|
|
@ -1079,7 +1079,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
|||
// when $display()/$write() functions are used in an initial block, print them during synthesis
|
||||
Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base, /*first_arg_at=*/0, /*may_fail=*/true);
|
||||
if (str.substr(0, 8) == "$display")
|
||||
fmt.append_string("\n");
|
||||
fmt.append_literal("\n");
|
||||
log("%s", fmt.render().c_str());
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Formatting of code
|
|||
blank lines.
|
||||
|
||||
- Otherwise stick to the Linux Kernel Coding Style:
|
||||
https://www.kernel.org/doc/Documentation/CodingStyle
|
||||
https://www.kernel.org/doc/Documentation/process/coding-style.rst
|
||||
|
||||
|
||||
C++ Language
|
||||
|
|
306
kernel/fmt.cc
306
kernel/fmt.cc
|
@ -22,9 +22,9 @@
|
|||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
void Fmt::append_string(const std::string &str) {
|
||||
void Fmt::append_literal(const std::string &str) {
|
||||
FmtPart part = {};
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
part.str = str;
|
||||
parts.push_back(part);
|
||||
}
|
||||
|
@ -42,11 +42,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
} else if (fmt.substr(i, 2) == "{{") {
|
||||
part.str += '{';
|
||||
++i;
|
||||
} else if (fmt[i] == '}')
|
||||
} else if (fmt[i] == '}') {
|
||||
log_assert(false && "Unexpected '}' in format string");
|
||||
else if (fmt[i] == '{') {
|
||||
} else if (fmt[i] == '{') {
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
}
|
||||
|
@ -74,19 +74,24 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
part.sig = args.extract(0, arg_size);
|
||||
args.remove(0, arg_size);
|
||||
|
||||
if (fmt[i] == 'U') {
|
||||
part.type = FmtPart::UNICHAR;
|
||||
++i;
|
||||
goto success;
|
||||
}
|
||||
|
||||
if (fmt[i] == '>')
|
||||
part.justify = FmtPart::RIGHT;
|
||||
else if (fmt[i] == '<')
|
||||
part.justify = FmtPart::LEFT;
|
||||
else if (fmt[i] == '=')
|
||||
part.justify = FmtPart::NUMERIC;
|
||||
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");
|
||||
part.padding = fmt[i];
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
|
@ -107,8 +112,12 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
} else if (fmt[i] == 'h') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 16;
|
||||
} else if (fmt[i] == 'H') {
|
||||
part.type = FmtPart::INTEGER;
|
||||
part.base = 16;
|
||||
part.hex_upper = true;
|
||||
} else if (fmt[i] == 'c') {
|
||||
part.type = FmtPart::CHARACTER;
|
||||
part.type = FmtPart::STRING;
|
||||
} else if (fmt[i] == 't') {
|
||||
part.type = FmtPart::VLOG_TIME;
|
||||
} else if (fmt[i] == 'r') {
|
||||
|
@ -124,10 +133,29 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
log_assert(false && "Unexpected end in format substitution");
|
||||
|
||||
if (part.type == FmtPart::INTEGER) {
|
||||
if (fmt[i] == '+') {
|
||||
part.plus = true;
|
||||
if (fmt[i] == '-') {
|
||||
part.sign = FmtPart::MINUS;
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
} else if (fmt[i] == '+') {
|
||||
part.sign = FmtPart::PLUS_MINUS;
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
} else if (fmt[i] == ' ') {
|
||||
part.sign = FmtPart::SPACE_MINUS;
|
||||
if (++i == fmt.size())
|
||||
log_assert(false && "Unexpected end in format substitution");
|
||||
} else {
|
||||
// also accept no sign character and treat like MINUS for compatibility
|
||||
}
|
||||
|
||||
if (fmt[i] == '#') {
|
||||
part.show_base = true;
|
||||
++i;
|
||||
}
|
||||
if (fmt[i] == '_') {
|
||||
part.group = true;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (fmt[i] == 'u')
|
||||
|
@ -140,6 +168,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
log_assert(false && "Unexpected end in format substitution");
|
||||
}
|
||||
|
||||
success:
|
||||
if (fmt[i] != '}')
|
||||
log_assert(false && "Expected '}' after format substitution");
|
||||
|
||||
|
@ -150,7 +179,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
|||
}
|
||||
}
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
parts.push_back(part);
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +190,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
|||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
case FmtPart::LITERAL:
|
||||
for (char c : part.str) {
|
||||
if (c == '{')
|
||||
fmt += "{{";
|
||||
|
@ -172,10 +201,15 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
|||
}
|
||||
break;
|
||||
|
||||
case FmtPart::UNICHAR:
|
||||
log_assert(part.sig.size() <= 32);
|
||||
fmt += "{U}";
|
||||
break;
|
||||
|
||||
case FmtPart::VLOG_TIME:
|
||||
log_assert(part.sig.size() == 0);
|
||||
YS_FALLTHROUGH
|
||||
case FmtPart::CHARACTER:
|
||||
case FmtPart::STRING:
|
||||
log_assert(part.sig.size() % 8 == 0);
|
||||
YS_FALLTHROUGH
|
||||
case FmtPart::INTEGER:
|
||||
|
@ -187,6 +221,8 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
|||
fmt += '>';
|
||||
else if (part.justify == FmtPart::LEFT)
|
||||
fmt += '<';
|
||||
else if (part.justify == FmtPart::NUMERIC)
|
||||
fmt += '=';
|
||||
else log_abort();
|
||||
log_assert(part.width == 0 || part.padding != '\0');
|
||||
fmt += part.padding != '\0' ? part.padding : ' ';
|
||||
|
@ -197,13 +233,18 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
|||
case 2: fmt += 'b'; break;
|
||||
case 8: fmt += 'o'; break;
|
||||
case 10: fmt += 'd'; break;
|
||||
case 16: fmt += 'h'; break;
|
||||
case 16: fmt += part.hex_upper ? 'H' : 'h'; break;
|
||||
default: log_abort();
|
||||
}
|
||||
if (part.plus)
|
||||
fmt += '+';
|
||||
switch (part.sign) {
|
||||
case FmtPart::MINUS: fmt += '-'; break;
|
||||
case FmtPart::PLUS_MINUS: fmt += '+'; break;
|
||||
case FmtPart::SPACE_MINUS: fmt += ' '; break;
|
||||
}
|
||||
fmt += part.show_base ? "#" : "";
|
||||
fmt += part.group ? "_" : "";
|
||||
fmt += part.signed_ ? 's' : 'u';
|
||||
} else if (part.type == FmtPart::CHARACTER) {
|
||||
} else if (part.type == FmtPart::STRING) {
|
||||
fmt += 'c';
|
||||
} else if (part.type == FmtPart::VLOG_TIME) {
|
||||
if (part.realtime)
|
||||
|
@ -299,12 +340,12 @@ void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part)
|
|||
part.width = places;
|
||||
|
||||
if (part.justify == FmtPart::RIGHT) {
|
||||
append_string(gap);
|
||||
append_literal(gap);
|
||||
parts.push_back(part);
|
||||
} else {
|
||||
part.justify = FmtPart::RIGHT;
|
||||
parts.push_back(part);
|
||||
append_string(gap);
|
||||
append_literal(gap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +396,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
part.str += module_name.str();
|
||||
} else {
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
parts.push_back(part);
|
||||
part = {};
|
||||
}
|
||||
|
@ -375,7 +416,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
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;
|
||||
part.sign = FmtPart::PLUS_MINUS;
|
||||
} else break;
|
||||
}
|
||||
if (i == fmt.size()) {
|
||||
|
@ -408,11 +449,11 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
part.type = FmtPart::INTEGER;
|
||||
part.base = 16;
|
||||
} else if (fmt[i] == 'c' || fmt[i] == 'C') {
|
||||
part.type = FmtPart::CHARACTER;
|
||||
part.type = FmtPart::STRING;
|
||||
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;
|
||||
part.type = FmtPart::STRING;
|
||||
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
|
||||
|
@ -435,12 +476,20 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
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.padding == '\0') {
|
||||
if (has_leading_zero && part.justify == FmtPart::RIGHT) {
|
||||
part.padding = '0';
|
||||
part.justify = FmtPart::NUMERIC;
|
||||
} else {
|
||||
part.padding = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus)
|
||||
if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS)
|
||||
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.base != 10)
|
||||
part.signed_ = false;
|
||||
if (part.type == FmtPart::INTEGER && !has_leading_zero)
|
||||
apply_verilog_automatic_sizing_and_add(part);
|
||||
else
|
||||
|
@ -449,12 +498,12 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
}
|
||||
}
|
||||
if (!part.str.empty()) {
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
parts.push_back(part);
|
||||
}
|
||||
} else {
|
||||
FmtPart part = {};
|
||||
part.type = FmtPart::STRING;
|
||||
part.type = FmtPart::LITERAL;
|
||||
part.str = arg->str;
|
||||
parts.push_back(part);
|
||||
}
|
||||
|
@ -474,7 +523,7 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
case FmtPart::LITERAL:
|
||||
for (char c : part.str) {
|
||||
if (c == '%')
|
||||
fmt.str += "%%";
|
||||
|
@ -491,14 +540,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
args.push_back(arg);
|
||||
|
||||
fmt.str += '%';
|
||||
if (part.plus)
|
||||
fmt.str += '+';
|
||||
if (part.sign == FmtPart::PLUS_MINUS || part.sign == FmtPart::SPACE_MINUS)
|
||||
fmt.str += '+'; // treat space/minus as plus/minus
|
||||
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);
|
||||
|
@ -507,13 +555,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
case 2: fmt.str += 'b'; break;
|
||||
case 8: fmt.str += 'o'; break;
|
||||
case 10: fmt.str += 'd'; break;
|
||||
case 16: fmt.str += 'h'; break;
|
||||
case 16: fmt.str += 'h'; break; // treat uppercase hex as lowercase
|
||||
default: log_abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::CHARACTER: {
|
||||
case FmtPart::STRING: {
|
||||
VerilogFmtArg arg;
|
||||
arg.type = VerilogFmtArg::INTEGER;
|
||||
arg.sig = part.sig;
|
||||
|
@ -524,7 +572,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
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);
|
||||
|
@ -533,7 +580,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
} 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';
|
||||
|
@ -541,6 +587,16 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
break;
|
||||
}
|
||||
|
||||
case FmtPart::UNICHAR: {
|
||||
VerilogFmtArg arg;
|
||||
arg.type = VerilogFmtArg::INTEGER;
|
||||
arg.sig = part.sig.extract(0, 7); // only ASCII
|
||||
args.push_back(arg);
|
||||
|
||||
fmt.str += "%c";
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::VLOG_TIME: {
|
||||
VerilogFmtArg arg;
|
||||
arg.type = VerilogFmtArg::TIME;
|
||||
|
@ -549,11 +605,11 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
args.push_back(arg);
|
||||
|
||||
fmt.str += '%';
|
||||
if (part.plus)
|
||||
log_assert(part.sign == FmtPart::MINUS || part.sign == FmtPart::PLUS_MINUS);
|
||||
if (part.sign == FmtPart::PLUS_MINUS)
|
||||
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);
|
||||
|
@ -599,24 +655,35 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
|
|||
os << indent << "buf += fmt_part { ";
|
||||
os << "fmt_part::";
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING: os << "STRING"; break;
|
||||
case FmtPart::LITERAL: os << "LITERAL"; break;
|
||||
case FmtPart::INTEGER: os << "INTEGER"; break;
|
||||
case FmtPart::CHARACTER: os << "CHARACTER"; break;
|
||||
case FmtPart::STRING: os << "STRING"; break;
|
||||
case FmtPart::UNICHAR: os << "UNICHAR"; break;
|
||||
case FmtPart::VLOG_TIME: os << "VLOG_TIME"; break;
|
||||
}
|
||||
os << ", ";
|
||||
os << escape_cxx_string(part.str) << ", ";
|
||||
os << "fmt_part::";
|
||||
switch (part.justify) {
|
||||
case FmtPart::LEFT: os << "LEFT"; break;
|
||||
case FmtPart::RIGHT: os << "RIGHT"; break;
|
||||
case FmtPart::LEFT: os << "LEFT"; break;
|
||||
case FmtPart::RIGHT: os << "RIGHT"; break;
|
||||
case FmtPart::NUMERIC: os << "NUMERIC"; break;
|
||||
}
|
||||
os << ", ";
|
||||
os << "(char)" << (int)part.padding << ", ";
|
||||
os << part.width << ", ";
|
||||
os << part.base << ", ";
|
||||
os << part.signed_ << ", ";
|
||||
os << part.plus << ", ";
|
||||
os << "fmt_part::";
|
||||
switch (part.sign) {
|
||||
case FmtPart::MINUS: os << "MINUS"; break;
|
||||
case FmtPart::PLUS_MINUS: os << "PLUS_MINUS"; break;
|
||||
case FmtPart::SPACE_MINUS: os << "SPACE_MINUS"; break;
|
||||
}
|
||||
os << ", ";
|
||||
os << part.hex_upper << ", ";
|
||||
os << part.show_base << ", ";
|
||||
os << part.group << ", ";
|
||||
os << part.realtime;
|
||||
os << " }.render(";
|
||||
emit_sig(part.sig);
|
||||
|
@ -631,19 +698,62 @@ std::string Fmt::render() const
|
|||
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
case FmtPart::LITERAL:
|
||||
str += part.str;
|
||||
break;
|
||||
|
||||
case FmtPart::UNICHAR: {
|
||||
RTLIL::Const value = part.sig.as_const();
|
||||
uint32_t codepoint = value.as_int();
|
||||
if (codepoint >= 0x10000)
|
||||
str += (char)(0xf0 | (codepoint >> 18));
|
||||
else if (codepoint >= 0x800)
|
||||
str += (char)(0xe0 | (codepoint >> 12));
|
||||
else if (codepoint >= 0x80)
|
||||
str += (char)(0xc0 | (codepoint >> 6));
|
||||
else
|
||||
str += (char)codepoint;
|
||||
if (codepoint >= 0x10000)
|
||||
str += (char)(0x80 | ((codepoint >> 12) & 0x3f));
|
||||
if (codepoint >= 0x800)
|
||||
str += (char)(0x80 | ((codepoint >> 6) & 0x3f));
|
||||
if (codepoint >= 0x80)
|
||||
str += (char)(0x80 | ((codepoint >> 0) & 0x3f));
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::INTEGER:
|
||||
case FmtPart::CHARACTER:
|
||||
case FmtPart::STRING:
|
||||
case FmtPart::VLOG_TIME: {
|
||||
std::string buf;
|
||||
std::string prefix;
|
||||
if (part.type == FmtPart::INTEGER) {
|
||||
RTLIL::Const value = part.sig.as_const();
|
||||
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 (!has_z && !has_x && part.signed_ && value[value.size() - 1]) {
|
||||
prefix = "-";
|
||||
value = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
|
||||
} else {
|
||||
switch (part.sign) {
|
||||
case FmtPart::MINUS: break;
|
||||
case FmtPart::PLUS_MINUS: prefix = "+"; break;
|
||||
case FmtPart::SPACE_MINUS: prefix = " "; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (part.base != 10) {
|
||||
size_t minimum_size = 0;
|
||||
size_t minimum_size = 1;
|
||||
for (size_t index = 0; index < (size_t)value.size(); index++)
|
||||
if (value[index] != State::S0)
|
||||
minimum_size = index + 1;
|
||||
|
@ -651,10 +761,28 @@ std::string Fmt::render() const
|
|||
}
|
||||
|
||||
if (part.base == 2) {
|
||||
buf = value.as_string();
|
||||
if (part.show_base)
|
||||
prefix += "0b";
|
||||
for (size_t index = 0; index < (size_t)value.size(); index++) {
|
||||
if (part.group && index > 0 && index % 4 == 0)
|
||||
buf += '_';
|
||||
RTLIL::State bit = value[index];
|
||||
if (bit == State::Sx)
|
||||
buf += 'x';
|
||||
else if (bit == State::Sz)
|
||||
buf += 'z';
|
||||
else if (bit == State::S1)
|
||||
buf += '1';
|
||||
else /* if (bit == State::S0) */
|
||||
buf += '0';
|
||||
}
|
||||
} else if (part.base == 8 || part.base == 16) {
|
||||
if (part.show_base)
|
||||
prefix += (part.base == 16) ? (part.hex_upper ? "0X" : "0x") : "0o";
|
||||
size_t step = (part.base == 16) ? 4 : 3;
|
||||
for (size_t index = 0; index < (size_t)value.size(); index += step) {
|
||||
if (part.group && index > 0 && index % (4 * step) == 0)
|
||||
buf += '_';
|
||||
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) {
|
||||
|
@ -676,21 +804,11 @@ std::string Fmt::render() const
|
|||
else if (has_z)
|
||||
buf += 'Z';
|
||||
else
|
||||
buf += "0123456789abcdef"[subvalue.as_int()];
|
||||
buf += (part.hex_upper ? "0123456789ABCDEF" : "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 (part.show_base)
|
||||
prefix += "0d";
|
||||
if (all_x)
|
||||
buf += 'x';
|
||||
else if (all_z)
|
||||
|
@ -700,25 +818,29 @@ std::string Fmt::render() const
|
|||
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())
|
||||
log_assert(value.is_fully_def());
|
||||
if (value.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());
|
||||
size_t index = 0;
|
||||
while (!value.is_fully_zero()) {
|
||||
if (part.group && index > 0 && index % 3 == 0)
|
||||
buf += '_';
|
||||
buf += '0' + RTLIL::const_mod(value, 10, false, false, 4).as_int();
|
||||
value = RTLIL::const_div(value, 10, false, false, value.size());
|
||||
index++;
|
||||
}
|
||||
if (negative || part.plus)
|
||||
buf += negative ? '-' : '+';
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
}
|
||||
} else log_abort();
|
||||
} else if (part.type == FmtPart::CHARACTER) {
|
||||
if (part.justify == FmtPart::NUMERIC && part.group && part.padding == '0') {
|
||||
int group_size = part.base == 10 ? 3 : 4;
|
||||
while (prefix.size() + buf.size() < part.width) {
|
||||
if (buf.size() % (group_size + 1) == group_size)
|
||||
buf += '_';
|
||||
buf += '0';
|
||||
}
|
||||
}
|
||||
std::reverse(buf.begin(), buf.end());
|
||||
} else if (part.type == FmtPart::STRING) {
|
||||
buf = part.sig.as_const().decode_string();
|
||||
} else if (part.type == FmtPart::VLOG_TIME) {
|
||||
// We only render() during initial, so time is always zero.
|
||||
|
@ -726,17 +848,29 @@ std::string Fmt::render() const
|
|||
}
|
||||
|
||||
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);
|
||||
if (prefix.size() + buf.size() < part.width) {
|
||||
size_t pad_width = part.width - prefix.size() - buf.size();
|
||||
switch (part.justify) {
|
||||
case FmtPart::LEFT:
|
||||
str += prefix;
|
||||
str += buf;
|
||||
str += std::string(pad_width, part.padding);
|
||||
break;
|
||||
case FmtPart::RIGHT:
|
||||
str += std::string(pad_width, part.padding);
|
||||
str += prefix;
|
||||
str += buf;
|
||||
break;
|
||||
case FmtPart::NUMERIC:
|
||||
str += prefix;
|
||||
str += std::string(pad_width, part.padding);
|
||||
str += buf;
|
||||
break;
|
||||
}
|
||||
str += std::string(pad_width, part.padding);
|
||||
} else {
|
||||
str += prefix;
|
||||
str += buf;
|
||||
}
|
||||
str += buf;
|
||||
if (part.justify == FmtPart::LEFT && buf.size() < part.width)
|
||||
str += std::string(part.width - buf.size(), part.padding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
25
kernel/fmt.h
25
kernel/fmt.h
|
@ -53,22 +53,24 @@ struct VerilogFmtArg {
|
|||
// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!
|
||||
struct FmtPart {
|
||||
enum {
|
||||
STRING = 0,
|
||||
LITERAL = 0,
|
||||
INTEGER = 1,
|
||||
CHARACTER = 2,
|
||||
VLOG_TIME = 3,
|
||||
STRING = 2,
|
||||
UNICHAR = 3,
|
||||
VLOG_TIME = 4,
|
||||
} type;
|
||||
|
||||
// STRING type
|
||||
// LITERAL type
|
||||
std::string str;
|
||||
|
||||
// INTEGER/CHARACTER types
|
||||
// INTEGER/STRING/UNICHAR types
|
||||
RTLIL::SigSpec sig;
|
||||
|
||||
// INTEGER/CHARACTER/VLOG_TIME types
|
||||
// INTEGER/STRING/VLOG_TIME types
|
||||
enum {
|
||||
RIGHT = 0,
|
||||
LEFT = 1,
|
||||
NUMERIC = 2,
|
||||
} justify = RIGHT;
|
||||
char padding = '\0';
|
||||
size_t width = 0;
|
||||
|
@ -76,7 +78,14 @@ struct FmtPart {
|
|||
// INTEGER type
|
||||
unsigned base = 10;
|
||||
bool signed_ = false;
|
||||
bool plus = false;
|
||||
enum {
|
||||
MINUS = 0,
|
||||
PLUS_MINUS = 1,
|
||||
SPACE_MINUS = 2,
|
||||
} sign = MINUS;
|
||||
bool hex_upper = false;
|
||||
bool show_base = false;
|
||||
bool group = false;
|
||||
|
||||
// VLOG_TIME type
|
||||
bool realtime = false;
|
||||
|
@ -86,7 +95,7 @@ struct Fmt {
|
|||
public:
|
||||
std::vector<FmtPart> parts;
|
||||
|
||||
void append_string(const std::string &str);
|
||||
void append_literal(const std::string &str);
|
||||
|
||||
void parse_rtlil(const RTLIL::Cell *cell);
|
||||
void emit_rtlil(RTLIL::Cell *cell) const;
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <regex>
|
||||
|
@ -449,4 +449,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
|
|||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#ifndef REGISTER_H
|
||||
#define REGISTER_H
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct Pass
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#ifndef RTLIL_H
|
||||
#define RTLIL_H
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace RTLIL
|
||||
|
|
346
kernel/yosys.h
346
kernel/yosys.h
|
@ -39,323 +39,7 @@
|
|||
#ifndef YOSYS_H
|
||||
#define YOSYS_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#ifndef _YOSYS_
|
||||
# error It looks like you are trying to build Yosys without the config defines set. \
|
||||
When building Yosys with a custom make system, make sure you set all the \
|
||||
defines the Yosys Makefile would set for your build configuration.
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
# include <tcl.h>
|
||||
# ifdef YOSYS_MXE_HACKS
|
||||
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
|
||||
extern Tcl_Interp *Tcl_CreateInterp(void);
|
||||
extern void Tcl_Preserve(ClientData data);
|
||||
extern void Tcl_Release(ClientData clientData);
|
||||
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
|
||||
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
|
||||
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
|
||||
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
|
||||
extern void Tcl_Finalize(void);
|
||||
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
|
||||
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
|
||||
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
|
||||
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
|
||||
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
|
||||
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
|
||||
# endif
|
||||
# undef CONST
|
||||
# undef INLINE
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# undef NOMINMAX
|
||||
# define NOMINMAX 1
|
||||
# undef YY_NO_UNISTD_H
|
||||
# define YY_NO_UNISTD_H 1
|
||||
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
|
||||
# define strtok_r strtok_s
|
||||
# define strdup _strdup
|
||||
# define snprintf _snprintf
|
||||
# define getcwd _getcwd
|
||||
# define mkdir _mkdir
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
|
||||
# ifndef __MINGW32__
|
||||
# define PATH_MAX MAX_PATH
|
||||
# define isatty _isatty
|
||||
# define fileno _fileno
|
||||
# endif
|
||||
|
||||
// The following defines conflict with our identifiers:
|
||||
# undef CONST
|
||||
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
|
||||
# undef TRANSPARENT
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#define YOSYS_NAMESPACE Yosys
|
||||
#define PRIVATE_NAMESPACE_BEGIN namespace {
|
||||
#define PRIVATE_NAMESPACE_END }
|
||||
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
|
||||
#define YOSYS_NAMESPACE_END }
|
||||
#define YOSYS_NAMESPACE_PREFIX Yosys::
|
||||
#define USING_YOSYS_NAMESPACE using namespace Yosys;
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
|
||||
#elif defined(_MSC_VER)
|
||||
# define YS_ATTRIBUTE(...)
|
||||
#else
|
||||
# define YS_ATTRIBUTE(...)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_MAYBE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define YS_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
# define YS_FALLTHROUGH [[fallthrough]];
|
||||
#elif defined(__clang__)
|
||||
# define YS_FALLTHROUGH [[clang::fallthrough]];
|
||||
#elif defined(__GNUC__)
|
||||
# define YS_FALLTHROUGH [[gnu::fallthrough]];
|
||||
#else
|
||||
# define YS_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// Note: All headers included in hashlib.h must be included
|
||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
|
||||
#ifdef HASHLIB_H
|
||||
# undef HASHLIB_H
|
||||
# include "kernel/hashlib.h"
|
||||
#else
|
||||
# include "kernel/hashlib.h"
|
||||
# undef HASHLIB_H
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
using std::pair;
|
||||
|
||||
using std::make_tuple;
|
||||
using std::make_pair;
|
||||
using std::get;
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
// A primitive shared string implementation that does not
|
||||
// move its .c_str() when the object is copied or moved.
|
||||
struct shared_str {
|
||||
std::shared_ptr<string> content;
|
||||
shared_str() { }
|
||||
shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
|
||||
shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
|
||||
const char *c_str() const { return content->c_str(); }
|
||||
const string &str() const { return *content; }
|
||||
bool operator==(const shared_str &other) const { return *content == *other.content; }
|
||||
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
|
||||
};
|
||||
|
||||
using hashlib::mkhash;
|
||||
using hashlib::mkhash_init;
|
||||
using hashlib::mkhash_add;
|
||||
using hashlib::mkhash_xorshift;
|
||||
using hashlib::hash_ops;
|
||||
using hashlib::hash_cstr_ops;
|
||||
using hashlib::hash_ptr_ops;
|
||||
using hashlib::hash_obj_ops;
|
||||
using hashlib::dict;
|
||||
using hashlib::idict;
|
||||
using hashlib::pool;
|
||||
using hashlib::mfp;
|
||||
|
||||
namespace RTLIL {
|
||||
struct IdString;
|
||||
struct Const;
|
||||
struct SigBit;
|
||||
struct SigSpec;
|
||||
struct Wire;
|
||||
struct Cell;
|
||||
struct Memory;
|
||||
struct Process;
|
||||
struct Module;
|
||||
struct Design;
|
||||
struct Monitor;
|
||||
enum State : unsigned char;
|
||||
}
|
||||
|
||||
namespace AST {
|
||||
struct AstNode;
|
||||
}
|
||||
|
||||
using RTLIL::IdString;
|
||||
using RTLIL::Const;
|
||||
using RTLIL::SigBit;
|
||||
using RTLIL::SigSpec;
|
||||
using RTLIL::Wire;
|
||||
using RTLIL::Cell;
|
||||
using RTLIL::Module;
|
||||
using RTLIL::Design;
|
||||
|
||||
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 {};
|
||||
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
|
||||
|
||||
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 {};
|
||||
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
|
||||
}
|
||||
|
||||
void memhasher_on();
|
||||
void memhasher_off();
|
||||
void memhasher_do();
|
||||
|
||||
extern bool memhasher_active;
|
||||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||
|
||||
void yosys_banner();
|
||||
int ceil_log2(int x) YS_ATTRIBUTE(const);
|
||||
|
||||
inline std::string vstringf(const char *fmt, va_list ap)
|
||||
{
|
||||
// For the common case of strings shorter than 128, save a heap
|
||||
// allocation by using a stack allocated buffer.
|
||||
const int kBufSize = 128;
|
||||
char buf[kBufSize];
|
||||
buf[0] = '\0';
|
||||
va_list apc;
|
||||
va_copy(apc, ap);
|
||||
int n = vsnprintf(buf, kBufSize, fmt, apc);
|
||||
va_end(apc);
|
||||
if (n < kBufSize)
|
||||
return std::string(buf);
|
||||
|
||||
std::string string;
|
||||
char *str = NULL;
|
||||
#if defined(_WIN32 )|| defined(__CYGWIN__)
|
||||
int sz = 2 * kBufSize, rc;
|
||||
while (1) {
|
||||
va_copy(apc, ap);
|
||||
str = (char*)realloc(str, sz);
|
||||
rc = vsnprintf(str, sz, fmt, apc);
|
||||
va_end(apc);
|
||||
if (rc >= 0 && rc < sz)
|
||||
break;
|
||||
sz *= 2;
|
||||
}
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
free(str);
|
||||
}
|
||||
return string;
|
||||
#else
|
||||
if (vasprintf(&str, fmt, ap) < 0)
|
||||
str = NULL;
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
free(str);
|
||||
}
|
||||
return string;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
||||
inline std::string stringf(const char *fmt, ...)
|
||||
{
|
||||
std::string string;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
string = vstringf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
|
||||
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
|
||||
bool patmatch(const char *pattern, const char *string);
|
||||
#if !defined(YOSYS_DISABLE_SPAWN)
|
||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
||||
#endif
|
||||
std::string get_base_tmpdir();
|
||||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
bool check_file_exists(std::string filename, bool is_exec = false);
|
||||
bool check_directory_exists(const std::string& dirname);
|
||||
bool is_absolute_path(std::string filename);
|
||||
void remove_directory(std::string dirname);
|
||||
bool create_directory(const std::string& dirname);
|
||||
std::string escape_filename_spaces(const std::string& filename);
|
||||
|
||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
||||
inline int GetSize(RTLIL::Wire *wire);
|
||||
|
||||
extern int autoidx;
|
||||
extern int yosys_xtrace;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
@ -363,14 +47,6 @@ YOSYS_NAMESPACE_END
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
using RTLIL::State;
|
||||
using RTLIL::SigChunk;
|
||||
using RTLIL::SigSig;
|
||||
|
||||
namespace hashlib {
|
||||
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
|
||||
}
|
||||
|
||||
void yosys_setup();
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
|
@ -385,26 +61,6 @@ Tcl_Interp *yosys_get_tcl_interp();
|
|||
|
||||
extern RTLIL::Design *yosys_design;
|
||||
|
||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
|
||||
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
|
||||
|
||||
#define NEW_ID \
|
||||
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
|
||||
#define NEW_ID_SUFFIX(suffix) \
|
||||
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
|
||||
|
||||
// Create a statically allocated IdString object, using for example ID::A or ID($add).
|
||||
//
|
||||
// Recipe for Converting old code that is using conversion of strings like ID::A and
|
||||
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
|
||||
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
|
||||
//
|
||||
// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
|
||||
//
|
||||
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
|
||||
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
|
||||
namespace ID = RTLIL::ID;
|
||||
|
||||
RTLIL::Design *yosys_get_design();
|
||||
std::string proc_self_dirname();
|
||||
std::string proc_share_dirname();
|
||||
|
|
379
kernel/yosys_common.h
Normal file
379
kernel/yosys_common.h
Normal file
|
@ -0,0 +1,379 @@
|
|||
/* -*- 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 YOSYS_COMMON_H
|
||||
#define YOSYS_COMMON_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#ifndef _YOSYS_
|
||||
# error It looks like you are trying to build Yosys without the config defines set. \
|
||||
When building Yosys with a custom make system, make sure you set all the \
|
||||
defines the Yosys Makefile would set for your build configuration.
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
# include <tcl.h>
|
||||
# ifdef YOSYS_MXE_HACKS
|
||||
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
|
||||
extern Tcl_Interp *Tcl_CreateInterp(void);
|
||||
extern void Tcl_Preserve(ClientData data);
|
||||
extern void Tcl_Release(ClientData clientData);
|
||||
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
|
||||
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
|
||||
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
|
||||
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
|
||||
extern void Tcl_Finalize(void);
|
||||
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
|
||||
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
|
||||
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
|
||||
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
|
||||
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
|
||||
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
|
||||
# endif
|
||||
# undef CONST
|
||||
# undef INLINE
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# undef NOMINMAX
|
||||
# define NOMINMAX 1
|
||||
# undef YY_NO_UNISTD_H
|
||||
# define YY_NO_UNISTD_H 1
|
||||
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
|
||||
# define strtok_r strtok_s
|
||||
# define strdup _strdup
|
||||
# define snprintf _snprintf
|
||||
# define getcwd _getcwd
|
||||
# define mkdir _mkdir
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
|
||||
# ifndef __MINGW32__
|
||||
# define PATH_MAX MAX_PATH
|
||||
# define isatty _isatty
|
||||
# define fileno _fileno
|
||||
# endif
|
||||
|
||||
// The following defines conflict with our identifiers:
|
||||
# undef CONST
|
||||
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
|
||||
# undef TRANSPARENT
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
|
||||
#define YOSYS_NAMESPACE Yosys
|
||||
#define PRIVATE_NAMESPACE_BEGIN namespace {
|
||||
#define PRIVATE_NAMESPACE_END }
|
||||
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
|
||||
#define YOSYS_NAMESPACE_END }
|
||||
#define YOSYS_NAMESPACE_PREFIX Yosys::
|
||||
#define USING_YOSYS_NAMESPACE using namespace Yosys;
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
|
||||
#elif defined(_MSC_VER)
|
||||
# define YS_ATTRIBUTE(...)
|
||||
#else
|
||||
# define YS_ATTRIBUTE(...)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_MAYBE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define YS_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
# define YS_FALLTHROUGH [[fallthrough]];
|
||||
#elif defined(__clang__)
|
||||
# define YS_FALLTHROUGH [[clang::fallthrough]];
|
||||
#elif defined(__GNUC__)
|
||||
# define YS_FALLTHROUGH [[gnu::fallthrough]];
|
||||
#else
|
||||
# define YS_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// Note: All headers included in hashlib.h must be included
|
||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
|
||||
#ifdef HASHLIB_H
|
||||
# undef HASHLIB_H
|
||||
# include "kernel/hashlib.h"
|
||||
#else
|
||||
# include "kernel/hashlib.h"
|
||||
# undef HASHLIB_H
|
||||
#endif
|
||||
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
using std::pair;
|
||||
|
||||
using std::make_tuple;
|
||||
using std::make_pair;
|
||||
using std::get;
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
// A primitive shared string implementation that does not
|
||||
// move its .c_str() when the object is copied or moved.
|
||||
struct shared_str {
|
||||
std::shared_ptr<string> content;
|
||||
shared_str() { }
|
||||
shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
|
||||
shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
|
||||
const char *c_str() const { return content->c_str(); }
|
||||
const string &str() const { return *content; }
|
||||
bool operator==(const shared_str &other) const { return *content == *other.content; }
|
||||
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
|
||||
};
|
||||
|
||||
using hashlib::mkhash;
|
||||
using hashlib::mkhash_init;
|
||||
using hashlib::mkhash_add;
|
||||
using hashlib::mkhash_xorshift;
|
||||
using hashlib::hash_ops;
|
||||
using hashlib::hash_cstr_ops;
|
||||
using hashlib::hash_ptr_ops;
|
||||
using hashlib::hash_obj_ops;
|
||||
using hashlib::dict;
|
||||
using hashlib::idict;
|
||||
using hashlib::pool;
|
||||
using hashlib::mfp;
|
||||
|
||||
namespace RTLIL {
|
||||
struct IdString;
|
||||
struct Const;
|
||||
struct SigBit;
|
||||
struct SigSpec;
|
||||
struct Wire;
|
||||
struct Cell;
|
||||
struct Memory;
|
||||
struct Process;
|
||||
struct Module;
|
||||
struct Design;
|
||||
struct Monitor;
|
||||
struct Selection;
|
||||
struct SigChunk;
|
||||
enum State : unsigned char;
|
||||
|
||||
typedef std::pair<SigSpec, SigSpec> SigSig;
|
||||
|
||||
namespace ID {}
|
||||
}
|
||||
|
||||
namespace AST {
|
||||
struct AstNode;
|
||||
}
|
||||
|
||||
using RTLIL::IdString;
|
||||
using RTLIL::Const;
|
||||
using RTLIL::SigBit;
|
||||
using RTLIL::SigSpec;
|
||||
using RTLIL::Wire;
|
||||
using RTLIL::Cell;
|
||||
using RTLIL::Module;
|
||||
using RTLIL::Design;
|
||||
|
||||
using RTLIL::State;
|
||||
using RTLIL::SigChunk;
|
||||
using RTLIL::SigSig;
|
||||
|
||||
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 {};
|
||||
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
|
||||
|
||||
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 {};
|
||||
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
|
||||
}
|
||||
|
||||
void memhasher_on();
|
||||
void memhasher_off();
|
||||
void memhasher_do();
|
||||
|
||||
extern bool memhasher_active;
|
||||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||
|
||||
void yosys_banner();
|
||||
int ceil_log2(int x) YS_ATTRIBUTE(const);
|
||||
|
||||
inline std::string vstringf(const char *fmt, va_list ap)
|
||||
{
|
||||
// For the common case of strings shorter than 128, save a heap
|
||||
// allocation by using a stack allocated buffer.
|
||||
const int kBufSize = 128;
|
||||
char buf[kBufSize];
|
||||
buf[0] = '\0';
|
||||
va_list apc;
|
||||
va_copy(apc, ap);
|
||||
int n = vsnprintf(buf, kBufSize, fmt, apc);
|
||||
va_end(apc);
|
||||
if (n < kBufSize)
|
||||
return std::string(buf);
|
||||
|
||||
std::string string;
|
||||
char *str = NULL;
|
||||
#if defined(_WIN32 )|| defined(__CYGWIN__)
|
||||
int sz = 2 * kBufSize, rc;
|
||||
while (1) {
|
||||
va_copy(apc, ap);
|
||||
str = (char*)realloc(str, sz);
|
||||
rc = vsnprintf(str, sz, fmt, apc);
|
||||
va_end(apc);
|
||||
if (rc >= 0 && rc < sz)
|
||||
break;
|
||||
sz *= 2;
|
||||
}
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
free(str);
|
||||
}
|
||||
return string;
|
||||
#else
|
||||
if (vasprintf(&str, fmt, ap) < 0)
|
||||
str = NULL;
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
free(str);
|
||||
}
|
||||
return string;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
||||
inline std::string stringf(const char *fmt, ...)
|
||||
{
|
||||
std::string string;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
string = vstringf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
|
||||
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
|
||||
bool patmatch(const char *pattern, const char *string);
|
||||
#if !defined(YOSYS_DISABLE_SPAWN)
|
||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
||||
#endif
|
||||
std::string get_base_tmpdir();
|
||||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
bool check_file_exists(std::string filename, bool is_exec = false);
|
||||
bool check_directory_exists(const std::string& dirname);
|
||||
bool is_absolute_path(std::string filename);
|
||||
void remove_directory(std::string dirname);
|
||||
bool create_directory(const std::string& dirname);
|
||||
std::string escape_filename_spaces(const std::string& filename);
|
||||
|
||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
||||
inline int GetSize(RTLIL::Wire *wire);
|
||||
|
||||
extern int autoidx;
|
||||
extern int yosys_xtrace;
|
||||
|
||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
|
||||
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
|
||||
|
||||
#define NEW_ID \
|
||||
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
|
||||
#define NEW_ID_SUFFIX(suffix) \
|
||||
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
|
||||
|
||||
// Create a statically allocated IdString object, using for example ID::A or ID($add).
|
||||
//
|
||||
// Recipe for Converting old code that is using conversion of strings like ID::A and
|
||||
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
|
||||
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
|
||||
//
|
||||
// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
|
||||
//
|
||||
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
|
||||
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
|
||||
namespace ID = RTLIL::ID;
|
||||
|
||||
namespace hashlib {
|
||||
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
|
||||
}
|
||||
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -36,7 +36,8 @@ struct cell_area_t {
|
|||
struct statdata_t
|
||||
{
|
||||
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
|
||||
X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
|
||||
X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \
|
||||
X(num_processes)
|
||||
|
||||
#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
|
||||
|
||||
|
@ -90,6 +91,11 @@ struct statdata_t
|
|||
|
||||
for (auto wire : mod->selected_wires())
|
||||
{
|
||||
if (wire->port_input || wire->port_output) {
|
||||
num_ports++;
|
||||
num_port_bits += wire->width;
|
||||
}
|
||||
|
||||
if (wire->name.isPublic()) {
|
||||
num_pub_wires++;
|
||||
num_pub_wire_bits += wire->width;
|
||||
|
@ -239,6 +245,8 @@ struct statdata_t
|
|||
log(" Number of wire bits: %6u\n", num_wire_bits);
|
||||
log(" Number of public wires: %6u\n", num_pub_wires);
|
||||
log(" Number of public wire bits: %6u\n", num_pub_wire_bits);
|
||||
log(" Number of ports: %6u\n", num_ports);
|
||||
log(" Number of port bits: %6u\n", num_port_bits);
|
||||
log(" Number of memories: %6u\n", num_memories);
|
||||
log(" Number of memory bits: %6u\n", num_memory_bits);
|
||||
log(" Number of processes: %6u\n", num_processes);
|
||||
|
@ -284,6 +292,8 @@ struct statdata_t
|
|||
log(" \"num_wire_bits\": %u,\n", num_wire_bits);
|
||||
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
|
||||
log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
|
||||
log(" \"num_ports\": %u,\n", num_ports);
|
||||
log(" \"num_port_bits\": %u,\n", num_port_bits);
|
||||
log(" \"num_memories\": %u,\n", num_memories);
|
||||
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
|
||||
log(" \"num_processes\": %u,\n", num_processes);
|
||||
|
@ -494,6 +504,8 @@ struct StatPass : public Pass {
|
|||
design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits);
|
||||
design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires);
|
||||
design->scratchpad_set_int("stat.num_pub_wire_bits", data.num_pub_wire_bits);
|
||||
design->scratchpad_set_int("stat.num_ports", data.num_ports);
|
||||
design->scratchpad_set_int("stat.num_port_bits", data.num_port_bits);
|
||||
design->scratchpad_set_int("stat.num_memories", data.num_memories);
|
||||
design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits);
|
||||
design->scratchpad_set_int("stat.num_processes", data.num_processes);
|
||||
|
|
|
@ -35,3 +35,4 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_map.v))
|
|||
$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
|
||||
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
|
||||
$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v))
|
||||
$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v))
|
||||
|
|
54
techlibs/common/choices/kogge-stone.v
Normal file
54
techlibs/common/choices/kogge-stone.v
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2024 Martin Povišer <povik@cutebit.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.
|
||||
*
|
||||
*/
|
||||
|
||||
(* techmap_celltype = "$lcu" *)
|
||||
module _80_lcu_kogge_stone (P, G, CI, CO);
|
||||
parameter WIDTH = 2;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] P, G;
|
||||
input CI;
|
||||
|
||||
(* force_downto *)
|
||||
output [WIDTH-1:0] CO;
|
||||
|
||||
integer i, j;
|
||||
(* force_downto *)
|
||||
reg [WIDTH-1:0] p, g;
|
||||
|
||||
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
|
||||
|
||||
always @* begin
|
||||
p = P;
|
||||
g = G;
|
||||
|
||||
// in almost all cases CI will be constant zero
|
||||
g[0] = g[0] | (p[0] & CI);
|
||||
|
||||
for (i = 0; i < $clog2(WIDTH); i = i + 1) begin
|
||||
// iterate in reverse so we don't confuse a result from this stage and the previous
|
||||
for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin
|
||||
g[j] = g[j] | p[j] & g[j - 2**i];
|
||||
p[j] = p[j] & p[j - 2**i];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign CO = g;
|
||||
endmodule
|
|
@ -902,18 +902,34 @@ endgenerate
|
|||
endmodule
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
//-
|
||||
//- $macc (A, B, Y)
|
||||
//-
|
||||
//- Multiply and accumulate.
|
||||
//- A building block for summing any number of negated and unnegated signals
|
||||
//- and arithmetic products of pairs of signals. Cell port A concatenates pairs
|
||||
//- of signals to be multiplied together. When the second signal in a pair is zero
|
||||
//- length, a constant 1 is used instead as the second factor. Cell port B
|
||||
//- concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders.
|
||||
//- Typically created by the `alumacc` pass, which transforms $add and $mul
|
||||
//- into $macc cells.
|
||||
module \$macc (A, B, Y);
|
||||
|
||||
parameter A_WIDTH = 0;
|
||||
parameter B_WIDTH = 0;
|
||||
parameter Y_WIDTH = 0;
|
||||
// CONFIG determines the layout of A, as explained below
|
||||
parameter CONFIG = 4'b0000;
|
||||
parameter CONFIG_WIDTH = 4;
|
||||
|
||||
input [A_WIDTH-1:0] A;
|
||||
input [B_WIDTH-1:0] B;
|
||||
output reg [Y_WIDTH-1:0] Y;
|
||||
// In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate:
|
||||
// A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...))
|
||||
// Multiplier ports are pairs of multiplier inputs ("factors").
|
||||
// If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum.
|
||||
input [A_WIDTH-1:0] A; // Cell port A is the concatenation of all arithmetic ports
|
||||
input [B_WIDTH-1:0] B; // Cell port B is the concatenation of single-bit unsigned signals to be also added to the sum
|
||||
output reg [Y_WIDTH-1:0] Y; // Output sum
|
||||
|
||||
// Xilinx XSIM does not like $clog2() below..
|
||||
function integer my_clog2;
|
||||
|
@ -929,10 +945,42 @@ function integer my_clog2;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Bits that a factor's length field in CONFIG per factor in cell port A
|
||||
localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
|
||||
// Number of multiplier ports
|
||||
localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
|
||||
// Minium bit width of an induction variable to iterate over all bits of cell port A
|
||||
localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
|
||||
|
||||
// In this pseudocode, u(foo) means an unsigned int that's foo bits long.
|
||||
// The CONFIG parameter carries the following information:
|
||||
// struct CONFIG {
|
||||
// u4 num_bits;
|
||||
// struct port_field {
|
||||
// bool is_signed;
|
||||
// bool is_subtract;
|
||||
// u(num_bits) factor1_len;
|
||||
// u(num_bits) factor2_len;
|
||||
// }[num_ports];
|
||||
// };
|
||||
|
||||
// The A cell port carries the following information:
|
||||
// struct A {
|
||||
// u(CONFIG.port_field[0].factor1_len) port0factor1;
|
||||
// u(CONFIG.port_field[0].factor2_len) port0factor2;
|
||||
// u(CONFIG.port_field[1].factor1_len) port1factor1;
|
||||
// u(CONFIG.port_field[1].factor2_len) port1factor2;
|
||||
// ...
|
||||
// };
|
||||
// and log(sizeof(A)) is num_abits.
|
||||
// No factor1 may have a zero length.
|
||||
// A factor2 having a zero length implies factor2 is replaced with a constant 1.
|
||||
|
||||
// Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up.
|
||||
// Finally, we have:
|
||||
// Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ...
|
||||
// * B[0] + B[1] + ...
|
||||
|
||||
function [2*num_ports*num_abits-1:0] get_port_offsets;
|
||||
input [CONFIG_WIDTH-1:0] cfg;
|
||||
integer i, cursor;
|
||||
|
|
|
@ -207,7 +207,7 @@ module _90_fa (A, B, C, X, Y);
|
|||
endmodule
|
||||
|
||||
(* techmap_celltype = "$lcu" *)
|
||||
module _90_lcu (P, G, CI, CO);
|
||||
module _90_lcu_brent_kung (P, G, CI, CO);
|
||||
parameter WIDTH = 2;
|
||||
|
||||
(* force_downto *)
|
||||
|
|
|
@ -113,7 +113,31 @@ module EFX_GBUFCE(
|
|||
|
||||
endmodule
|
||||
|
||||
module EFX_RAM_5K(
|
||||
module EFX_RAM_5K
|
||||
# (
|
||||
parameter READ_WIDTH = 20,
|
||||
parameter WRITE_WIDTH = 20,
|
||||
localparam READ_ADDR_WIDTH =
|
||||
(READ_WIDTH == 16) ? 8 : // 256x16
|
||||
(READ_WIDTH == 8) ? 9 : // 512x8
|
||||
(READ_WIDTH == 4) ? 10 : // 1024x4
|
||||
(READ_WIDTH == 2) ? 11 : // 2048x2
|
||||
(READ_WIDTH == 1) ? 12 : // 4096x1
|
||||
(READ_WIDTH == 20) ? 8 : // 256x20
|
||||
(READ_WIDTH == 10) ? 9 : // 512x10
|
||||
(READ_WIDTH == 5) ? 10 : -1, // 1024x5
|
||||
|
||||
localparam WRITE_ADDR_WIDTH =
|
||||
(WRITE_WIDTH == 16) ? 8 : // 256x16
|
||||
(WRITE_WIDTH == 8) ? 9 : // 512x8
|
||||
(WRITE_WIDTH == 4) ? 10 : // 1024x4
|
||||
(WRITE_WIDTH == 2) ? 11 : // 2048x2
|
||||
(WRITE_WIDTH == 1) ? 12 : // 4096x1
|
||||
(WRITE_WIDTH == 20) ? 8 : // 256x20
|
||||
(WRITE_WIDTH == 10) ? 9 : // 512x10
|
||||
(WRITE_WIDTH == 5) ? 10 : -1 // 1024x5
|
||||
)
|
||||
(
|
||||
input [WRITE_WIDTH-1:0] WDATA,
|
||||
input [WRITE_ADDR_WIDTH-1:0] WADDR,
|
||||
input WE,
|
||||
|
@ -126,8 +150,6 @@ module EFX_RAM_5K(
|
|||
(* clkbuf_sink *)
|
||||
input RCLK
|
||||
);
|
||||
parameter READ_WIDTH = 20;
|
||||
parameter WRITE_WIDTH = 20;
|
||||
parameter OUTPUT_REG = 1'b0;
|
||||
parameter RCLK_POLARITY = 1'b1;
|
||||
parameter RE_POLARITY = 1'b1;
|
||||
|
@ -155,25 +177,4 @@ module EFX_RAM_5K(
|
|||
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||
parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||
|
||||
localparam READ_ADDR_WIDTH =
|
||||
(READ_WIDTH == 16) ? 8 : // 256x16
|
||||
(READ_WIDTH == 8) ? 9 : // 512x8
|
||||
(READ_WIDTH == 4) ? 10 : // 1024x4
|
||||
(READ_WIDTH == 2) ? 11 : // 2048x2
|
||||
(READ_WIDTH == 1) ? 12 : // 4096x1
|
||||
(READ_WIDTH == 20) ? 8 : // 256x20
|
||||
(READ_WIDTH == 10) ? 9 : // 512x10
|
||||
(READ_WIDTH == 5) ? 10 : -1; // 1024x5
|
||||
|
||||
localparam WRITE_ADDR_WIDTH =
|
||||
(WRITE_WIDTH == 16) ? 8 : // 256x16
|
||||
(WRITE_WIDTH == 8) ? 9 : // 512x8
|
||||
(WRITE_WIDTH == 4) ? 10 : // 1024x4
|
||||
(WRITE_WIDTH == 2) ? 11 : // 2048x2
|
||||
(WRITE_WIDTH == 1) ? 12 : // 4096x1
|
||||
(WRITE_WIDTH == 20) ? 8 : // 256x20
|
||||
(WRITE_WIDTH == 10) ? 9 : // 512x10
|
||||
(WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -16,7 +16,7 @@ for arch in ../../techlibs/*; do
|
|||
done
|
||||
else
|
||||
echo -n "Test $path ->"
|
||||
iverilog -t null -I$arch $path
|
||||
iverilog -t null -I$arch -g2005-sv $path
|
||||
echo " ok"
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -25,6 +25,11 @@ T rand_int(T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>
|
|||
return dist(generator);
|
||||
}
|
||||
|
||||
int64_t sext(size_t bits, uint64_t value)
|
||||
{
|
||||
return (int64_t)(value << (64 - bits)) >> (64 - bits);
|
||||
}
|
||||
|
||||
struct BinaryOperationBase
|
||||
{
|
||||
void tweak_input(uint64_t &a, uint64_t &b) {}
|
||||
|
@ -246,6 +251,106 @@ struct CtlzTest
|
|||
}
|
||||
} ctlz;
|
||||
|
||||
struct UdivTest : BinaryOperationBase
|
||||
{
|
||||
UdivTest()
|
||||
{
|
||||
std::printf("Randomized tests for value::udivmod (div):\n");
|
||||
test_binary_operation(*this);
|
||||
}
|
||||
|
||||
uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
|
||||
{
|
||||
return std::get<0>(a.udivmod(b));
|
||||
}
|
||||
|
||||
void tweak_input(uint64_t &, uint64_t &b)
|
||||
{
|
||||
if (b == 0) b = 1; // Avoid divide by zero
|
||||
}
|
||||
} udiv;
|
||||
|
||||
struct UmodTest : BinaryOperationBase
|
||||
{
|
||||
UmodTest()
|
||||
{
|
||||
std::printf("Randomized tests for value::udivmod (mod):\n");
|
||||
test_binary_operation(*this);
|
||||
}
|
||||
|
||||
uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
|
||||
{
|
||||
return std::get<1>(a.udivmod(b));
|
||||
}
|
||||
|
||||
void tweak_input(uint64_t &, uint64_t &b)
|
||||
{
|
||||
if (b == 0) b = 1; // Avoid divide by zero
|
||||
}
|
||||
} umod;
|
||||
|
||||
struct SdivTest : BinaryOperationBase
|
||||
{
|
||||
SdivTest()
|
||||
{
|
||||
std::printf("Randomized tests for value::sdivmod (div):\n");
|
||||
test_binary_operation(*this);
|
||||
}
|
||||
|
||||
uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
|
||||
{
|
||||
return (uint64_t)(sext(bits, a) / sext(bits, b));
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
|
||||
{
|
||||
return std::get<0>(a.sdivmod(b));
|
||||
}
|
||||
|
||||
void tweak_input(uint64_t &, uint64_t &b)
|
||||
{
|
||||
if (b == 0) b = 1; // Avoid divide by zero
|
||||
}
|
||||
} sdiv;
|
||||
|
||||
struct SmodTest : BinaryOperationBase
|
||||
{
|
||||
SmodTest()
|
||||
{
|
||||
std::printf("Randomized tests for value::sdivmod (mod):\n");
|
||||
test_binary_operation(*this);
|
||||
}
|
||||
|
||||
uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b)
|
||||
{
|
||||
return (uint64_t)(sext(bits, a) % sext(bits, b));
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
cxxrtl::value<Bits> testing_impl(cxxrtl::value<Bits> a, cxxrtl::value<Bits> b)
|
||||
{
|
||||
return std::get<1>(a.sdivmod(b));
|
||||
}
|
||||
|
||||
void tweak_input(uint64_t &, uint64_t &b)
|
||||
{
|
||||
if (b == 0) b = 1; // Avoid divide by zero
|
||||
}
|
||||
} smod;
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
module RAM_9b1B (
|
||||
module RAM_9b1B
|
||||
#(
|
||||
parameter INIT = 0,
|
||||
parameter OPTION_INIT = "UNDEFINED",
|
||||
parameter PORT_R_WIDTH = 9,
|
||||
parameter PORT_W_WIDTH = 9,
|
||||
parameter PORT_R_CLK_POL = 0,
|
||||
parameter PORT_W_CLK_POL = 0,
|
||||
parameter PORT_W_WR_EN_WIDTH = 1
|
||||
)
|
||||
(
|
||||
input PORT_R_CLK,
|
||||
input [6:0] PORT_R_ADDR,
|
||||
output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA,
|
||||
|
@ -8,14 +18,6 @@ module RAM_9b1B (
|
|||
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA
|
||||
);
|
||||
|
||||
parameter INIT = 0;
|
||||
parameter OPTION_INIT = "UNDEFINED";
|
||||
parameter PORT_R_WIDTH = 9;
|
||||
parameter PORT_W_WIDTH = 9;
|
||||
parameter PORT_R_CLK_POL = 0;
|
||||
parameter PORT_W_CLK_POL = 0;
|
||||
parameter PORT_W_WR_EN_WIDTH = 1;
|
||||
|
||||
reg [8:0] mem [0:15];
|
||||
|
||||
integer i;
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
module RAM_WREN (
|
||||
module RAM_WREN #(
|
||||
parameter ABITS=4,
|
||||
parameter WIDTH=8,
|
||||
parameter PORT_A_WR_EN_WIDTH=1,
|
||||
parameter PORT_A_WR_BE_WIDTH=0,
|
||||
parameter OPTION_BYTESIZE=WIDTH,
|
||||
parameter WB=OPTION_BYTESIZE
|
||||
)(
|
||||
input PORT_A_CLK,
|
||||
input [ABITS-1:0] PORT_A_ADDR,
|
||||
input [WIDTH-1:0] PORT_A_WR_DATA,
|
||||
|
@ -7,13 +14,6 @@ module RAM_WREN (
|
|||
input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE
|
||||
);
|
||||
|
||||
parameter ABITS=4;
|
||||
parameter WIDTH=8;
|
||||
parameter PORT_A_WR_EN_WIDTH=1;
|
||||
parameter PORT_A_WR_BE_WIDTH=0;
|
||||
parameter OPTION_BYTESIZE=WIDTH;
|
||||
parameter WB=OPTION_BYTESIZE;
|
||||
|
||||
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||
|
||||
integer i;
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
// expect-rd-ports 1
|
||||
// expect-rd-clk \clk
|
||||
|
||||
module ram2 (input clk,
|
||||
module ram2 #(
|
||||
parameter SIZE = 5 // Address size
|
||||
) (input clk,
|
||||
input sel,
|
||||
input we,
|
||||
input [SIZE-1:0] adr,
|
||||
input [63:0] dat_i,
|
||||
output reg [63:0] dat_o);
|
||||
parameter SIZE = 5; // Address size
|
||||
|
||||
|
||||
reg [63:0] mem [0:(1 << SIZE)-1];
|
||||
integer i;
|
||||
|
|
1
tests/simple/.gitignore
vendored
1
tests/simple/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
*.log
|
||||
*.out
|
||||
*.err
|
||||
|
|
1
tests/techmap/kogge-stone.ys
Normal file
1
tests/techmap/kogge-stone.ys
Normal file
|
@ -0,0 +1 @@
|
|||
test_cell -s 1711533949 -n 10 -map +/techmap.v -map +/choices/kogge-stone.v $lcu
|
4
tests/verilog/.gitignore
vendored
4
tests/verilog/.gitignore
vendored
|
@ -1,6 +1,10 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/*.err
|
||||
/run-test.mk
|
||||
/const_arst.v
|
||||
/const_sr.v
|
||||
/doubleslash.v
|
||||
/roundtrip_proc_1.v
|
||||
/roundtrip_proc_2.v
|
||||
/assign_to_reg.v
|
||||
|
|
22
tests/verilog/assign_to_reg.ys
Normal file
22
tests/verilog/assign_to_reg.ys
Normal file
|
@ -0,0 +1,22 @@
|
|||
# https://github.com/yosyshq/yosys/issues/2035
|
||||
|
||||
read_ilang <<END
|
||||
module \top
|
||||
wire width 1 input 0 \halfbrite
|
||||
wire width 2 output 1 \r_on
|
||||
process $1
|
||||
assign \r_on [1:0] 2'00
|
||||
assign \r_on [1:0] 2'11
|
||||
switch \halfbrite [0]
|
||||
case 1'1
|
||||
assign \r_on [1] 1'0
|
||||
end
|
||||
end
|
||||
end
|
||||
END
|
||||
proc_prune
|
||||
write_verilog assign_to_reg.v
|
||||
design -reset
|
||||
|
||||
logger -expect-no-warnings
|
||||
read_verilog assign_to_reg.v
|
Loading…
Add table
Add a link
Reference in a new issue