mirror of https://github.com/YosysHQ/yosys.git
Merge from upstream
This commit is contained in:
commit
cc733fd11b
|
|
@ -1,7 +1,11 @@
|
|||
## user config
|
||||
/Makefile.conf
|
||||
|
||||
## build artifacts
|
||||
# compiler intermediate files
|
||||
*.o
|
||||
*.d
|
||||
*.dwo
|
||||
.*.swp
|
||||
*.gch
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
|
@ -26,6 +30,11 @@ __pycache__
|
|||
/Makefile.conf
|
||||
/Brewfile.lock.json
|
||||
/viz.js
|
||||
*.so.dSYM/
|
||||
|
||||
# compiler output files
|
||||
/kernel/version_*.cc
|
||||
/share
|
||||
/yosys
|
||||
/yosys.exe
|
||||
/yosys.js
|
||||
|
|
@ -41,14 +50,12 @@ __pycache__
|
|||
/yosys-witness-script.py
|
||||
/yosys-filterlib
|
||||
/yosys-filterlib.exe
|
||||
/kernel/*.pyh
|
||||
/kernel/python_wrappers.cc
|
||||
/kernel/version_*.cc
|
||||
/share
|
||||
/yosys-win32-mxebin-*
|
||||
/yosys-win32-vcxsrc-*
|
||||
/yosysjs-*
|
||||
/libyosys.so
|
||||
|
||||
# build directories
|
||||
/tests/unit/bintest/
|
||||
/tests/unit/objtest/
|
||||
/tests/ystests
|
||||
|
|
@ -56,12 +63,42 @@ __pycache__
|
|||
/tests/arch/quicklogic/qlf_k6n10f/run-test.mk
|
||||
/tests/verilog/roundtrip_proc_1.v
|
||||
/tests/verilog/roundtrip_proc_2.v
|
||||
/build
|
||||
/result
|
||||
/dist
|
||||
/*.egg-info
|
||||
/build
|
||||
/venv
|
||||
|
||||
# pyosys
|
||||
/kernel/*.pyh
|
||||
/kernel/python_wrappers.cc
|
||||
/boost
|
||||
/ffi
|
||||
/doxygen
|
||||
/venv
|
||||
/*.whl
|
||||
/*.egg-info
|
||||
|
||||
# yosysjs dependency
|
||||
/viz.js
|
||||
|
||||
# other
|
||||
/coverage.info
|
||||
/coverage_html
|
||||
|
||||
|
||||
# these really belong in global gitignore since they're not specific to this project but rather to user tool choice
|
||||
# but too many people don't have a global gitignore configured:
|
||||
# https://docs.github.com/en/get-started/git-basics/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer
|
||||
__pycache__
|
||||
*~
|
||||
.*.swp
|
||||
/.cache
|
||||
/.vscode
|
||||
/.cproject
|
||||
/.project
|
||||
/.settings
|
||||
/qtcreator.files
|
||||
/qtcreator.includes
|
||||
/qtcreator.config
|
||||
/qtcreator.creator
|
||||
/qtcreator.creator.user
|
||||
/compile_commands.json
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -176,7 +176,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.55+112
|
||||
YOSYS_VER := 0.55+146
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'.' -f3)
|
||||
|
|
@ -925,6 +925,7 @@ MK_TEST_DIRS =
|
|||
# MK_TEST_DIRS += tests/arch/quicklogic/pp3
|
||||
# MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
|
||||
# MK_TEST_DIRS += tests/arch/xilinx
|
||||
MK_TEST_DIRS += tests/bugpoint
|
||||
MK_TEST_DIRS += tests/opt
|
||||
MK_TEST_DIRS += tests/sat
|
||||
MK_TEST_DIRS += tests/sim
|
||||
|
|
|
|||
2
abc
2
abc
|
|
@ -1 +1 @@
|
|||
Subproject commit fb5050530d8aba2a99f8e4ffb846e072017af232
|
||||
Subproject commit f24c672683db09bdf783a8a01f3dd4081dcc8f83
|
||||
|
|
@ -1180,9 +1180,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
f << stringf(" = ~((");
|
||||
dump_cell_expr_port(f, cell, "A", false);
|
||||
f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
|
||||
f << (cell->type == ID($_AOI3_) ? " & " : " | ");
|
||||
dump_cell_expr_port(f, cell, "B", false);
|
||||
f << stringf(cell->type == ID($_AOI3_) ? ") |" : ") &");
|
||||
f << (cell->type == ID($_AOI3_) ? ") |" : ") &");
|
||||
dump_attributes(f, "", cell->attributes, " ");
|
||||
f << stringf(" ");
|
||||
dump_cell_expr_port(f, cell, "C", false);
|
||||
|
|
@ -1195,13 +1195,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
f << stringf(" = ~((");
|
||||
dump_cell_expr_port(f, cell, "A", false);
|
||||
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
|
||||
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
|
||||
dump_cell_expr_port(f, cell, "B", false);
|
||||
f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
|
||||
f << (cell->type == ID($_AOI4_) ? ") |" : ") &");
|
||||
dump_attributes(f, "", cell->attributes, " ");
|
||||
f << stringf(" (");
|
||||
dump_cell_expr_port(f, cell, "C", false);
|
||||
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
|
||||
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
|
||||
dump_cell_expr_port(f, cell, "D", false);
|
||||
f << stringf("));\n");
|
||||
return true;
|
||||
|
|
@ -1412,10 +1412,10 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
int s_width = cell->getPort(ID::S).size();
|
||||
std::string func_name = cellname(cell);
|
||||
|
||||
f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
|
||||
f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
|
||||
f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
|
||||
f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
|
||||
f << stringf("%s" "function [%d:0] %s;\n", indent, width-1, func_name);
|
||||
f << stringf("%s" " input [%d:0] a;\n", indent, width-1);
|
||||
f << stringf("%s" " input [%d:0] b;\n", indent, s_width*width-1);
|
||||
f << stringf("%s" " input [%d:0] s;\n", indent, s_width-1);
|
||||
|
||||
dump_attributes(f, indent + " ", cell->attributes);
|
||||
if (noparallelcase)
|
||||
|
|
@ -1424,7 +1424,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
if (!noattr)
|
||||
f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
|
||||
f << stringf("%s" " casez (s)", indent.c_str());
|
||||
f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
|
||||
f << (noattr ? " // synopsys parallel_case\n" : "\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < s_width; i++)
|
||||
|
|
@ -2637,7 +2637,7 @@ struct VerilogBackend : public Backend {
|
|||
Pass::call(design, "clean_zerowidth");
|
||||
log_pop();
|
||||
|
||||
design->sort();
|
||||
design->sort_modules();
|
||||
|
||||
*f << stringf("/* Generated by %s */\n", yosys_maybe_version());
|
||||
|
||||
|
|
@ -2650,6 +2650,7 @@ struct VerilogBackend : public Backend {
|
|||
continue;
|
||||
}
|
||||
log("Dumping module `%s'.\n", module->name.c_str());
|
||||
module->sort();
|
||||
dump_module(*f, "", module);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil
|
|||
msg_type == VERIFIC_IGNORE ? "IGNORE" :
|
||||
msg_type == VERIFIC_INFO ? "INFO" :
|
||||
msg_type == VERIFIC_COMMENT ? "COMMENT" :
|
||||
msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id);
|
||||
msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id ? message_id : "");
|
||||
|
||||
string message = linefile ? stringf("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile)) : "";
|
||||
message += vstringf(msg, args);
|
||||
|
|
@ -3052,6 +3052,9 @@ std::set<std::string> import_tops(const char* work, std::map<std::string,Netlist
|
|||
return top_mod_names;
|
||||
}
|
||||
|
||||
static bool set_verific_global_flags = true;
|
||||
static bool already_imported = false;
|
||||
|
||||
void verific_cleanup()
|
||||
{
|
||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||
|
|
@ -3075,6 +3078,7 @@ void verific_cleanup()
|
|||
Libset::Reset();
|
||||
Message::Reset();
|
||||
RuntimeFlags::DeleteAllFlags();
|
||||
set_verific_global_flags = true;
|
||||
LineFile::DeleteAllLineFiles();
|
||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||
verific_incdirs.clear();
|
||||
|
|
@ -3538,7 +3542,6 @@ struct VerificPass : public Pass {
|
|||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
static bool set_verific_global_flags = true;
|
||||
|
||||
if (check_noverific_env())
|
||||
log_cmd_error("This version of Yosys is built without Verific support.\n"
|
||||
|
|
@ -4353,6 +4356,9 @@ struct VerificPass : public Pass {
|
|||
if ((unsigned long)verific_sva_fsm_limit >= sizeof(1ull)*8)
|
||||
log_cmd_error("-L %d: limit too large; maximum allowed value is %zu.\n", verific_sva_fsm_limit, sizeof(1ull)*8-1);
|
||||
|
||||
if (already_imported)
|
||||
log_warning("Note that all Verific flags were reset to defaults after last -import.\n");
|
||||
|
||||
std::set<std::string> top_mod_names;
|
||||
|
||||
if (mode_all)
|
||||
|
|
@ -4430,6 +4436,7 @@ struct VerificPass : public Pass {
|
|||
}
|
||||
|
||||
verific_cleanup();
|
||||
already_imported = true;
|
||||
goto check_error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,3 +286,4 @@ X(A_WIDTHS)
|
|||
X(B_WIDTHS)
|
||||
X(C_WIDTHS)
|
||||
X(C_SIGNED)
|
||||
X(raise_error)
|
||||
|
|
|
|||
149
kernel/io.cc
149
kernel/io.cc
|
|
@ -384,4 +384,153 @@ std::string escape_filename_spaces(const std::string& filename)
|
|||
return out;
|
||||
}
|
||||
|
||||
void format_emit_unescaped(std::string &result, std::string_view fmt)
|
||||
{
|
||||
result.reserve(result.size() + fmt.size());
|
||||
for (size_t i = 0; i < fmt.size(); ++i) {
|
||||
char ch = fmt[i];
|
||||
result.push_back(ch);
|
||||
if (ch == '%' && i + 1 < fmt.size() && fmt[i + 1] == '%') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string unescape_format_string(std::string_view fmt)
|
||||
{
|
||||
std::string result;
|
||||
format_emit_unescaped(result, fmt);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string string_view_stringf(std::string_view spec, ...)
|
||||
{
|
||||
std::string fmt(spec);
|
||||
char format_specifier = fmt[fmt.size() - 1];
|
||||
switch (format_specifier) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
// Strip any length modifier off `fmt`
|
||||
std::string long_fmt;
|
||||
for (size_t i = 0; i + 1 < fmt.size(); ++i) {
|
||||
char ch = fmt[i];
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
|
||||
break;
|
||||
}
|
||||
long_fmt.push_back(ch);
|
||||
}
|
||||
// Add `lld` or whatever
|
||||
long_fmt += "ll";
|
||||
long_fmt.push_back(format_specifier);
|
||||
fmt = long_fmt;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, spec);
|
||||
std::string result = vstringf(fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, Arg arg)
|
||||
{
|
||||
// Delegate nontrivial formats to the C library.
|
||||
switch (num_dynamic_ints) {
|
||||
case DynamicIntCount::NONE:
|
||||
result += string_view_stringf(spec, arg);
|
||||
return;
|
||||
case DynamicIntCount::ONE:
|
||||
result += string_view_stringf(spec, dynamic_ints[0], arg);
|
||||
return;
|
||||
case DynamicIntCount::TWO:
|
||||
result += string_view_stringf(spec, dynamic_ints[0], dynamic_ints[1], arg);
|
||||
return;
|
||||
}
|
||||
YOSYS_ABORT("Internal error");
|
||||
}
|
||||
|
||||
void format_emit_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, long long arg)
|
||||
{
|
||||
if (spec == "%d") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += std::to_string(arg);
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
|
||||
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, unsigned long long arg)
|
||||
{
|
||||
if (spec == "%u") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += std::to_string(arg);
|
||||
return;
|
||||
}
|
||||
if (spec == "%c") {
|
||||
result += static_cast<char>(arg);
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
|
||||
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, double arg)
|
||||
{
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
|
||||
void format_emit_char_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const char *arg)
|
||||
{
|
||||
if (spec == "%s") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += arg;
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
|
||||
void format_emit_string(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const std::string &arg)
|
||||
{
|
||||
if (spec == "%s") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += arg;
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg.c_str());
|
||||
}
|
||||
|
||||
void format_emit_string_view(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, std::string_view arg)
|
||||
{
|
||||
if (spec == "%s") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
// We can output the string without creating a temporary copy.
|
||||
result += arg;
|
||||
return;
|
||||
}
|
||||
// Delegate nontrivial formats to the C library. We need to construct
|
||||
// a temporary string to ensure null termination.
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, std::string(arg).c_str());
|
||||
}
|
||||
|
||||
void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const void *arg)
|
||||
{
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
392
kernel/io.h
392
kernel/io.h
|
|
@ -1,5 +1,6 @@
|
|||
#include <string>
|
||||
#include <stdarg.h>
|
||||
#include <type_traits>
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#ifndef YOSYS_IO_H
|
||||
|
|
@ -50,18 +51,391 @@ inline std::string vstringf(const char *fmt, va_list ap)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
||||
inline std::string stringf(const char *fmt, ...)
|
||||
enum ConversionSpecifier : uint8_t
|
||||
{
|
||||
std::string string;
|
||||
va_list ap;
|
||||
CONVSPEC_NONE,
|
||||
// Specifier not understood/supported
|
||||
CONVSPEC_ERROR,
|
||||
// Consumes a "long long"
|
||||
CONVSPEC_SIGNED_INT,
|
||||
// Consumes a "unsigned long long"
|
||||
CONVSPEC_UNSIGNED_INT,
|
||||
// Consumes a "double"
|
||||
CONVSPEC_DOUBLE,
|
||||
// Consumes a "const char*"
|
||||
CONVSPEC_CHAR_PTR,
|
||||
// Consumes a "void*"
|
||||
CONVSPEC_VOID_PTR,
|
||||
};
|
||||
|
||||
va_start(ap, fmt);
|
||||
string = vstringf(fmt, ap);
|
||||
va_end(ap);
|
||||
constexpr ConversionSpecifier parse_conversion_specifier(char ch, char prev_ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
return CONVSPEC_SIGNED_INT;
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'm':
|
||||
return CONVSPEC_UNSIGNED_INT;
|
||||
case 'c':
|
||||
if (prev_ch == 'l' || prev_ch == 'q' || prev_ch == 'L') {
|
||||
// wchar not supported
|
||||
return CONVSPEC_ERROR;
|
||||
}
|
||||
return CONVSPEC_UNSIGNED_INT;
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'a':
|
||||
case 'A':
|
||||
return CONVSPEC_DOUBLE;
|
||||
case 's':
|
||||
if (prev_ch == 'l' || prev_ch == 'q' || prev_ch == 'L') {
|
||||
// wchar not supported
|
||||
return CONVSPEC_ERROR;
|
||||
}
|
||||
return CONVSPEC_CHAR_PTR;
|
||||
case 'p':
|
||||
return CONVSPEC_VOID_PTR;
|
||||
case '$': // positional parameters
|
||||
case 'n':
|
||||
case 'S':
|
||||
return CONVSPEC_ERROR;
|
||||
default:
|
||||
return CONVSPEC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return string;
|
||||
enum class DynamicIntCount : uint8_t {
|
||||
NONE = 0,
|
||||
ONE = 1,
|
||||
TWO = 2,
|
||||
};
|
||||
|
||||
// Describes a printf-style format conversion specifier found in a format string.
|
||||
struct FoundFormatSpec
|
||||
{
|
||||
// The start offset of the conversion spec in the format string.
|
||||
int start;
|
||||
// The end offset of the conversion spec in the format string.
|
||||
int end;
|
||||
ConversionSpecifier spec;
|
||||
// Number of int args consumed by '*' dynamic width/precision args.
|
||||
DynamicIntCount num_dynamic_ints;
|
||||
};
|
||||
|
||||
// Ensure there is no format spec.
|
||||
constexpr void ensure_no_format_spec(std::string_view fmt, int index, bool *has_escapes)
|
||||
{
|
||||
int fmt_size = static_cast<int>(fmt.size());
|
||||
// A trailing '%' is not a format spec.
|
||||
while (index + 1 < fmt_size) {
|
||||
if (fmt[index] != '%') {
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (fmt[index + 1] != '%') {
|
||||
YOSYS_ABORT("More format conversion specifiers than arguments");
|
||||
}
|
||||
*has_escapes = true;
|
||||
index += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the next format conversion specifier (starting with '%').
|
||||
// Returns CONVSPEC_NONE if there isn't a format conversion specifier.
|
||||
constexpr FoundFormatSpec find_next_format_spec(std::string_view fmt, int fmt_start, bool *has_escapes)
|
||||
{
|
||||
int index = fmt_start;
|
||||
int fmt_size = static_cast<int>(fmt.size());
|
||||
while (index < fmt_size) {
|
||||
if (fmt[index] != '%') {
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
int p = index + 1;
|
||||
uint8_t num_dynamic_ints = 0;
|
||||
while (true) {
|
||||
if (p == fmt_size) {
|
||||
return {0, 0, CONVSPEC_NONE, DynamicIntCount::NONE};
|
||||
}
|
||||
if (fmt[p] == '%') {
|
||||
*has_escapes = true;
|
||||
index = p + 1;
|
||||
break;
|
||||
}
|
||||
if (fmt[p] == '*') {
|
||||
if (num_dynamic_ints >= 2) {
|
||||
return {0, 0, CONVSPEC_ERROR, DynamicIntCount::NONE};
|
||||
}
|
||||
++num_dynamic_ints;
|
||||
}
|
||||
ConversionSpecifier spec = parse_conversion_specifier(fmt[p], fmt[p - 1]);
|
||||
if (spec != CONVSPEC_NONE) {
|
||||
return {index, p + 1, spec, static_cast<DynamicIntCount>(num_dynamic_ints)};
|
||||
}
|
||||
++p;
|
||||
}
|
||||
}
|
||||
return {0, 0, CONVSPEC_NONE, DynamicIntCount::NONE};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr typename std::enable_if<sizeof...(Args) == 0>::type
|
||||
check_format(std::string_view fmt, int fmt_start, bool *has_escapes, FoundFormatSpec*, DynamicIntCount)
|
||||
{
|
||||
ensure_no_format_spec(fmt, fmt_start, has_escapes);
|
||||
}
|
||||
|
||||
// Check that the format string `fmt.substr(fmt_start)` is valid for the given type arguments.
|
||||
// Fills `specs` with the FoundFormatSpecs found in the format string.
|
||||
// `int_args_consumed` is the number of int arguments already consumed to satisfy the
|
||||
// dynamic width/precision args for the next format conversion specifier.
|
||||
template <typename Arg, typename... Args>
|
||||
constexpr void check_format(std::string_view fmt, int fmt_start, bool *has_escapes, FoundFormatSpec* specs,
|
||||
DynamicIntCount int_args_consumed)
|
||||
{
|
||||
FoundFormatSpec found = find_next_format_spec(fmt, fmt_start, has_escapes);
|
||||
if (found.num_dynamic_ints > int_args_consumed) {
|
||||
// We need to consume at least one more int for the dynamic
|
||||
// width/precision of this format conversion specifier.
|
||||
if constexpr (!std::is_convertible_v<Arg, int>) {
|
||||
YOSYS_ABORT("Expected dynamic int argument");
|
||||
}
|
||||
check_format<Args...>(fmt, fmt_start, has_escapes, specs,
|
||||
static_cast<DynamicIntCount>(static_cast<uint8_t>(int_args_consumed) + 1));
|
||||
return;
|
||||
}
|
||||
switch (found.spec) {
|
||||
case CONVSPEC_NONE:
|
||||
YOSYS_ABORT("Expected format conversion specifier for argument");
|
||||
break;
|
||||
case CONVSPEC_ERROR:
|
||||
YOSYS_ABORT("Found unsupported format conversion specifier");
|
||||
break;
|
||||
case CONVSPEC_SIGNED_INT:
|
||||
if constexpr (!std::is_convertible_v<Arg, long long>) {
|
||||
YOSYS_ABORT("Expected type convertible to signed integer");
|
||||
}
|
||||
*specs = found;
|
||||
break;
|
||||
case CONVSPEC_UNSIGNED_INT:
|
||||
if constexpr (!std::is_convertible_v<Arg, unsigned long long>) {
|
||||
YOSYS_ABORT("Expected type convertible to unsigned integer");
|
||||
}
|
||||
*specs = found;
|
||||
break;
|
||||
case CONVSPEC_DOUBLE:
|
||||
if constexpr (!std::is_convertible_v<Arg, double>) {
|
||||
YOSYS_ABORT("Expected type convertible to double");
|
||||
}
|
||||
*specs = found;
|
||||
break;
|
||||
case CONVSPEC_CHAR_PTR:
|
||||
if constexpr (!std::is_convertible_v<Arg, const char *> &&
|
||||
!std::is_convertible_v<Arg, const std::string &> &&
|
||||
!std::is_convertible_v<Arg, const std::string_view &>) {
|
||||
YOSYS_ABORT("Expected type convertible to char *");
|
||||
}
|
||||
*specs = found;
|
||||
break;
|
||||
case CONVSPEC_VOID_PTR:
|
||||
if constexpr (!std::is_convertible_v<Arg, const void *>) {
|
||||
YOSYS_ABORT("Expected pointer type");
|
||||
}
|
||||
*specs = found;
|
||||
break;
|
||||
}
|
||||
check_format<Args...>(fmt, found.end, has_escapes, specs + 1, DynamicIntCount::NONE);
|
||||
}
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `long long'.
|
||||
void format_emit_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, long long arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `unsigned long long'.
|
||||
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, unsigned long long arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `double'.
|
||||
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, double arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `const char*'.
|
||||
void format_emit_char_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const char *arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `std::string'.
|
||||
void format_emit_string(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const std::string &arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `std::string_view'.
|
||||
void format_emit_string_view(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, std::string_view arg);
|
||||
|
||||
// Emit the string representation of `arg` that has been converted to a `double'.
|
||||
void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, const void *arg);
|
||||
|
||||
// Emit the string representation of `arg` according to the given `FoundFormatSpec`,
|
||||
// appending it to `result`.
|
||||
template <typename Arg>
|
||||
inline void format_emit_one(std::string &result, std::string_view fmt, const FoundFormatSpec &ffspec,
|
||||
int *dynamic_ints, const Arg& arg)
|
||||
{
|
||||
std::string_view spec = fmt.substr(ffspec.start, ffspec.end - ffspec.start);
|
||||
DynamicIntCount num_dynamic_ints = ffspec.num_dynamic_ints;
|
||||
switch (ffspec.spec) {
|
||||
case CONVSPEC_SIGNED_INT:
|
||||
if constexpr (std::is_convertible_v<Arg, long long>) {
|
||||
long long s = arg;
|
||||
format_emit_long_long(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CONVSPEC_UNSIGNED_INT:
|
||||
if constexpr (std::is_convertible_v<Arg, unsigned long long>) {
|
||||
unsigned long long s = arg;
|
||||
format_emit_unsigned_long_long(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CONVSPEC_DOUBLE:
|
||||
if constexpr (std::is_convertible_v<Arg, double>) {
|
||||
double s = arg;
|
||||
format_emit_double(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CONVSPEC_CHAR_PTR:
|
||||
if constexpr (std::is_convertible_v<Arg, const char *>) {
|
||||
const char *s = arg;
|
||||
format_emit_char_ptr(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
if constexpr (std::is_convertible_v<Arg, const std::string &>) {
|
||||
const std::string &s = arg;
|
||||
format_emit_string(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
if constexpr (std::is_convertible_v<Arg, const std::string_view &>) {
|
||||
const std::string_view &s = arg;
|
||||
format_emit_string_view(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CONVSPEC_VOID_PTR:
|
||||
if constexpr (std::is_convertible_v<Arg, const void *>) {
|
||||
const void *s = arg;
|
||||
format_emit_void_ptr(result, spec, dynamic_ints, num_dynamic_ints, s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
YOSYS_ABORT("Internal error");
|
||||
}
|
||||
|
||||
// Append the format string `fmt` to `result`, assuming there are no format conversion
|
||||
// specifiers other than "%%" and therefore no arguments. Unescape "%%".
|
||||
void format_emit_unescaped(std::string &result, std::string_view fmt);
|
||||
std::string unescape_format_string(std::string_view fmt);
|
||||
|
||||
inline void format_emit(std::string &result, std::string_view fmt, int fmt_start,
|
||||
bool has_escapes, const FoundFormatSpec*, int*, DynamicIntCount)
|
||||
{
|
||||
fmt = fmt.substr(fmt_start);
|
||||
if (has_escapes) {
|
||||
format_emit_unescaped(result, fmt);
|
||||
} else {
|
||||
result += fmt;
|
||||
}
|
||||
}
|
||||
// Format `args` according to `fmt` (starting at `fmt_start`) and `specs` and append to `result`.
|
||||
// `num_dynamic_ints` in `dynamic_ints[]` have already been collected to provide as
|
||||
// dynamic width/precision args for the next format conversion specifier.
|
||||
template <typename Arg, typename... Args>
|
||||
inline void format_emit(std::string &result, std::string_view fmt, int fmt_start, bool has_escapes,
|
||||
const FoundFormatSpec* specs, int *dynamic_ints, DynamicIntCount num_dynamic_ints,
|
||||
const Arg &arg, const Args &... args)
|
||||
{
|
||||
if (specs->num_dynamic_ints > num_dynamic_ints) {
|
||||
// Collect another int for the dynamic width precision/args
|
||||
// for the next format conversion specifier.
|
||||
if constexpr (std::is_convertible_v<Arg, int>) {
|
||||
dynamic_ints[static_cast<uint8_t>(num_dynamic_ints)] = arg;
|
||||
} else {
|
||||
YOSYS_ABORT("Internal error");
|
||||
}
|
||||
format_emit(result, fmt, fmt_start, has_escapes, specs, dynamic_ints,
|
||||
static_cast<DynamicIntCount>(static_cast<uint8_t>(num_dynamic_ints) + 1), args...);
|
||||
return;
|
||||
}
|
||||
std::string_view str = fmt.substr(fmt_start, specs->start - fmt_start);
|
||||
if (has_escapes) {
|
||||
format_emit_unescaped(result, str);
|
||||
} else {
|
||||
result += str;
|
||||
}
|
||||
format_emit_one(result, fmt, *specs, dynamic_ints, arg);
|
||||
format_emit(result, fmt, specs->end, has_escapes, specs + 1, dynamic_ints, DynamicIntCount::NONE, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline std::string format_emit_toplevel(std::string_view fmt, bool has_escapes, const FoundFormatSpec* specs, const Args &... args)
|
||||
{
|
||||
std::string result;
|
||||
int dynamic_ints[2] = { 0, 0 };
|
||||
format_emit(result, fmt, 0, has_escapes, specs, dynamic_ints, DynamicIntCount::NONE, args...);
|
||||
return result;
|
||||
}
|
||||
template <>
|
||||
inline std::string format_emit_toplevel(std::string_view fmt, bool has_escapes, const FoundFormatSpec*)
|
||||
{
|
||||
if (!has_escapes) {
|
||||
return std::string(fmt);
|
||||
}
|
||||
return unescape_format_string(fmt);
|
||||
}
|
||||
|
||||
// This class parses format strings to build a list of `FoundFormatSpecs` in `specs`.
|
||||
// When the compiler supports `consteval` (C++20), this parsing happens at compile time and
|
||||
// type errors will be reported at compile time. Otherwise the parsing happens at
|
||||
// runtime and type errors will trigger an `abort()` at runtime.
|
||||
template <typename... Args>
|
||||
class FmtString
|
||||
{
|
||||
public:
|
||||
// Implicit conversion from const char * means that users can pass
|
||||
// C string constants which are automatically parsed.
|
||||
YOSYS_CONSTEVAL FmtString(const char *p) : fmt(p)
|
||||
{
|
||||
check_format<Args...>(fmt, 0, &has_escapes, specs, DynamicIntCount::NONE);
|
||||
}
|
||||
std::string format(const Args &... args)
|
||||
{
|
||||
return format_emit_toplevel(fmt, has_escapes, specs, args...);
|
||||
}
|
||||
private:
|
||||
std::string_view fmt;
|
||||
bool has_escapes = false;
|
||||
FoundFormatSpec specs[sizeof...(Args)] = {};
|
||||
};
|
||||
|
||||
template <typename T> struct WrapType { using type = T; };
|
||||
template <typename T> using TypeIdentity = typename WrapType<T>::type;
|
||||
|
||||
template <typename... Args>
|
||||
inline std::string stringf(FmtString<TypeIdentity<Args>...> fmt, Args... args)
|
||||
{
|
||||
return fmt.format(args...);
|
||||
}
|
||||
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
bool RTLIL::IdString::destruct_guard_ok = false;
|
||||
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
|
||||
std::vector<char*> RTLIL::IdString::global_id_storage_;
|
||||
dict<char*, int> RTLIL::IdString::global_id_index_;
|
||||
std::unordered_map<std::string_view, int> RTLIL::IdString::global_id_index_;
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
std::vector<int> RTLIL::IdString::global_refcount_storage_;
|
||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
|
||||
|
|
@ -1149,6 +1149,12 @@ void RTLIL::Design::sort()
|
|||
it.second->sort();
|
||||
}
|
||||
|
||||
void RTLIL::Design::sort_modules()
|
||||
{
|
||||
scratchpad.sort();
|
||||
modules_.sort(sort_by_id_str());
|
||||
}
|
||||
|
||||
void RTLIL::Design::check()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace RTLIL
|
||||
|
|
@ -122,7 +125,7 @@ struct RTLIL::IdString
|
|||
} destruct_guard;
|
||||
|
||||
static std::vector<char*> global_id_storage_;
|
||||
static dict<char*, int> global_id_index_;
|
||||
static std::unordered_map<std::string_view, int> global_id_index_;
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
static std::vector<int> global_refcount_storage_;
|
||||
static std::vector<int> global_free_idx_list_;
|
||||
|
|
@ -1376,6 +1379,7 @@ struct RTLIL::Design
|
|||
std::string scratchpad_get_string(const std::string &varname, const std::string &default_value = std::string()) const;
|
||||
|
||||
void sort();
|
||||
void sort_modules();
|
||||
void check();
|
||||
void optimize();
|
||||
|
||||
|
|
|
|||
|
|
@ -134,6 +134,15 @@
|
|||
# define YS_COLD
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_consteval
|
||||
#define YOSYS_CONSTEVAL consteval
|
||||
#else
|
||||
// If we can't use consteval we can at least make it constexpr.
|
||||
#define YOSYS_CONSTEVAL constexpr
|
||||
#endif
|
||||
|
||||
#define YOSYS_ABORT(s) abort()
|
||||
|
||||
#include "kernel/io.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
|
|
|||
|
|
@ -20,6 +20,16 @@
|
|||
#include "kernel/yosys.h"
|
||||
#include "backends/rtlil/rtlil_backend.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <csignal>
|
||||
# define WIFEXITED(x) 1
|
||||
# define WIFSIGNALED(x) 0
|
||||
# define WIFSTOPPED(x) 0
|
||||
# define WEXITSTATUS(x) ((x) & 0xff)
|
||||
# define WTERMSIG(x) SIGTERM
|
||||
# define WSTOPSIG(x) 0
|
||||
#endif
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
using namespace RTLIL_BACKEND;
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -50,6 +60,10 @@ struct BugpointPass : public Pass {
|
|||
log(" -grep \"<string>\"\n");
|
||||
log(" only consider crashes that place this string in the log file.\n");
|
||||
log("\n");
|
||||
log(" -expect-return <int>\n");
|
||||
log(" only consider crashes that return the specified value. e.g. SEGFAULT\n");
|
||||
log(" returns a value of 139.\n");
|
||||
log("\n");
|
||||
log(" -fast\n");
|
||||
log(" run `proc_clean; clean -purge` after each minimization step. converges\n");
|
||||
log(" faster, but produces larger testcases, and may fail to produce any\n");
|
||||
|
|
@ -60,6 +74,17 @@ struct BugpointPass : public Pass {
|
|||
log(" finishing. produces smaller and more useful testcases, but may fail to\n");
|
||||
log(" produce any testcase at all if the crash is related to dangling wires.\n");
|
||||
log("\n");
|
||||
log(" -runner \"<prefix>\"\n");
|
||||
log(" child process wrapping command, e.g., \"timeout 30\", or valgrind.\n");
|
||||
log("\n");
|
||||
log(" -err-grep \"<string>\"\n");
|
||||
log(" only consider crashes that print this string on stderr. useful for\n");
|
||||
log(" errors outside of yosys.\n");
|
||||
log("\n");
|
||||
log(" -suffix \"<string>\"\n");
|
||||
log(" add suffix to generated file names. useful when running more than one\n");
|
||||
log(" instance of bugpoint in the same directory. limited to 8 characters.\n");
|
||||
log("\n");
|
||||
log("It is possible to constrain which parts of the design will be considered for\n");
|
||||
log("removal. Unless one or more of the following options are specified, all parts\n");
|
||||
log("will be considered.\n");
|
||||
|
|
@ -89,24 +114,39 @@ struct BugpointPass : public Pass {
|
|||
log(" -updates\n");
|
||||
log(" try to remove process updates from syncs.\n");
|
||||
log("\n");
|
||||
log(" -runner \"<prefix>\"\n");
|
||||
log(" child process wrapping command, e.g., \"timeout 30\", or valgrind.\n");
|
||||
log(" -wires\n");
|
||||
log(" try to remove wires. wires with a (* bugpoint_keep *) attribute will be\n");
|
||||
log(" skipped.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
bool run_yosys(RTLIL::Design *design, string runner, string yosys_cmd, string yosys_arg)
|
||||
int run_yosys(RTLIL::Design *design, string runner, string yosys_cmd, string yosys_arg, string suffix, bool catch_err)
|
||||
{
|
||||
design->sort();
|
||||
|
||||
std::ofstream f("bugpoint-case.il");
|
||||
string bugpoint_file = "bugpoint-case";
|
||||
if (suffix.size())
|
||||
bugpoint_file += stringf(".%.8s", suffix.c_str());
|
||||
|
||||
std::ofstream f(bugpoint_file + ".il");
|
||||
RTLIL_BACKEND::dump_design(f, design, /*only_selected=*/false, /*flag_m=*/true, /*flag_n=*/false);
|
||||
f.close();
|
||||
|
||||
string yosys_cmdline = stringf("%s %s -qq -L bugpoint-case.log %s bugpoint-case.il", runner.c_str(), yosys_cmd.c_str(), yosys_arg.c_str());
|
||||
return run_command(yosys_cmdline) == 0;
|
||||
string yosys_cmdline = stringf("%s %s -qq -L %s.log %s %s.il", runner.c_str(), yosys_cmd.c_str(), bugpoint_file.c_str(), yosys_arg.c_str(), bugpoint_file.c_str());
|
||||
if (catch_err) yosys_cmdline += stringf(" 2>%s.err", bugpoint_file.c_str());
|
||||
auto status = run_command(yosys_cmdline);
|
||||
// we're not processing lines, which means we're getting raw system() returns
|
||||
if(WIFEXITED(status))
|
||||
return WEXITSTATUS(status);
|
||||
else if(WIFSIGNALED(status))
|
||||
return WTERMSIG(status);
|
||||
else if(WIFSTOPPED(status))
|
||||
return WSTOPSIG(status);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_logfile(string grep)
|
||||
bool check_logfile(string grep, string suffix, bool err=false)
|
||||
{
|
||||
if (grep.empty())
|
||||
return true;
|
||||
|
|
@ -114,7 +154,13 @@ struct BugpointPass : public Pass {
|
|||
if (grep.size() > 2 && grep.front() == '"' && grep.back() == '"')
|
||||
grep = grep.substr(1, grep.size() - 2);
|
||||
|
||||
std::ifstream f("bugpoint-case.log");
|
||||
string bugpoint_file = "bugpoint-case";
|
||||
if (suffix.size())
|
||||
bugpoint_file += stringf(".%.8s", suffix.c_str());
|
||||
bugpoint_file += err ? ".err" : ".log";
|
||||
|
||||
std::ifstream f(bugpoint_file);
|
||||
|
||||
while (!f.eof())
|
||||
{
|
||||
string line;
|
||||
|
|
@ -125,6 +171,11 @@ struct BugpointPass : public Pass {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool check_logfiles(string grep, string err_grep, string suffix)
|
||||
{
|
||||
return check_logfile(grep, suffix) && check_logfile(err_grep, suffix, true);
|
||||
}
|
||||
|
||||
RTLIL::Design *clean_design(RTLIL::Design *design, bool do_clean = true, bool do_delete = false)
|
||||
{
|
||||
if (!do_clean)
|
||||
|
|
@ -399,7 +450,9 @@ struct BugpointPass : public Pass {
|
|||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
string yosys_cmd = "yosys", yosys_arg, grep, runner;
|
||||
string yosys_cmd = "yosys", yosys_arg, grep, err_grep, runner, suffix;
|
||||
bool flag_expect_return = false, has_check = false, check_err = false;
|
||||
int expect_return_value = 0;
|
||||
bool fast = false, clean = false;
|
||||
bool modules = false, ports = false, cells = false, connections = false, processes = false, assigns = false, updates = false, wires = false, has_part = false;
|
||||
|
||||
|
|
@ -426,9 +479,25 @@ struct BugpointPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (args[argidx] == "-grep" && argidx + 1 < args.size()) {
|
||||
has_check = true;
|
||||
grep = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-err-grep" && argidx + 1 < args.size()) {
|
||||
has_check = true;
|
||||
check_err = true;
|
||||
err_grep = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-expect-return") {
|
||||
flag_expect_return = true;
|
||||
++argidx;
|
||||
if (argidx >= args.size())
|
||||
log_cmd_error("No expected return value specified.\n");
|
||||
|
||||
expect_return_value = atoi(args[argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-fast") {
|
||||
fast = true;
|
||||
continue;
|
||||
|
|
@ -485,6 +554,14 @@ struct BugpointPass : public Pass {
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-suffix" && argidx + 1 < args.size()) {
|
||||
suffix = args[++argidx];
|
||||
if (suffix.size() && suffix.at(0) == '"') {
|
||||
log_assert(suffix.back() == '"');
|
||||
suffix = suffix.substr(1, suffix.size() - 2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -492,6 +569,9 @@ struct BugpointPass : public Pass {
|
|||
if (yosys_arg.empty())
|
||||
log_cmd_error("Missing -script or -command option.\n");
|
||||
|
||||
if (flag_expect_return && expect_return_value == 0 && !has_check)
|
||||
log_cmd_error("Nothing to match on for -expect-return 0; change value or use -grep.\n");
|
||||
|
||||
if (!has_part)
|
||||
{
|
||||
modules = true;
|
||||
|
|
@ -508,10 +588,15 @@ struct BugpointPass : public Pass {
|
|||
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||
|
||||
RTLIL::Design *crashing_design = clean_design(design, clean);
|
||||
if (run_yosys(crashing_design, runner, yosys_cmd, yosys_arg))
|
||||
int retval = run_yosys(crashing_design, runner, yosys_cmd, yosys_arg, suffix, check_err);
|
||||
if (flag_expect_return && retval != expect_return_value)
|
||||
log_cmd_error("The provided script file or command and Yosys binary returned value %d instead of expected %d on this design!\n", retval, expect_return_value);
|
||||
if (!flag_expect_return && retval == 0)
|
||||
log_cmd_error("The provided script file or command and Yosys binary do not crash on this design!\n");
|
||||
if (!check_logfile(grep))
|
||||
if (!check_logfile(grep, suffix))
|
||||
log_cmd_error("The provided grep string is not found in the log file!\n");
|
||||
if (!check_logfile(err_grep, suffix, true))
|
||||
log_cmd_error("The provided grep string is not found in stderr log!\n");
|
||||
|
||||
int seed = 0;
|
||||
bool found_something = false, stage2 = false;
|
||||
|
|
@ -521,21 +606,37 @@ struct BugpointPass : public Pass {
|
|||
{
|
||||
simplified = clean_design(simplified, fast, /*do_delete=*/true);
|
||||
|
||||
bool crashes;
|
||||
if (clean)
|
||||
{
|
||||
RTLIL::Design *testcase = clean_design(simplified);
|
||||
crashes = !run_yosys(testcase, runner, yosys_cmd, yosys_arg);
|
||||
retval = run_yosys(testcase, runner, yosys_cmd, yosys_arg, suffix, check_err);
|
||||
delete testcase;
|
||||
}
|
||||
else
|
||||
{
|
||||
crashes = !run_yosys(simplified, runner, yosys_cmd, yosys_arg);
|
||||
retval = run_yosys(simplified, runner, yosys_cmd, yosys_arg, suffix, check_err);
|
||||
}
|
||||
|
||||
if (crashes && check_logfile(grep))
|
||||
bool crashes = false;
|
||||
if (flag_expect_return && retval == expect_return_value && check_logfiles(grep, err_grep, suffix))
|
||||
{
|
||||
log("Testcase matches expected crash.\n");
|
||||
crashes = true;
|
||||
}
|
||||
else if (!flag_expect_return && retval == 0)
|
||||
log("Testcase does not crash.\n");
|
||||
else if (!flag_expect_return && check_logfiles(grep, err_grep, suffix))
|
||||
{
|
||||
log("Testcase crashes.\n");
|
||||
crashes = true;
|
||||
}
|
||||
else
|
||||
// flag_expect_return && !(retval == expect_return_value && check_logfiles(grep, err_grep, suffix))
|
||||
// !flag_expect_return && !(retval == 0 && check_logfiles(grep, err_grep, suffix))
|
||||
log("Testcase does not match expected crash.\n");
|
||||
|
||||
if (crashes)
|
||||
{
|
||||
if (crashing_design != design)
|
||||
delete crashing_design;
|
||||
crashing_design = simplified;
|
||||
|
|
@ -543,7 +644,6 @@ struct BugpointPass : public Pass {
|
|||
}
|
||||
else
|
||||
{
|
||||
log("Testcase does not crash.\n");
|
||||
delete simplified;
|
||||
seed++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ The rules for this property are as follows:
|
|||
|
||||
- for every available width, the width needs to be a multiple of the byte size,
|
||||
or the byte size needs to be larger than the width
|
||||
- if the byte size is larger than the width, the byte enable signel is assumed
|
||||
- if the byte size is larger than the width, the byte enable signal is assumed
|
||||
to be one bit wide and cover the whole port
|
||||
- otherwise, the byte enable signal has one bit for every `byte` bits of the
|
||||
data port
|
||||
|
|
@ -176,7 +176,7 @@ Eg. for the following properties:
|
|||
The cost of a given cell will be assumed to be `(8 - 7) + 7 * (used_bits / 14)`.
|
||||
|
||||
If `widthscale` is used, The pass will attach a `BITS_USED` parameter to mapped
|
||||
calls, with a bitmask of which data bits of the memory are actually in use.
|
||||
cells, with a bitmask of which data bits of the memory are actually in use.
|
||||
The parameter width will be the widest width in the `widths` property, and
|
||||
the bit correspondence is defined accordingly.
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ one of the following values:
|
|||
- `zero`: the memory contents are zero, memories can be mapped to this cell iff
|
||||
their initialization value is entirely zero or undef
|
||||
- `any`: the memory contents can be arbitrarily selected, and the initialization
|
||||
will be passes as the `INIT` parameter to the mapped cell
|
||||
will be passed as the `INIT` parameter to the mapped cell
|
||||
- `no_undef`: like `any`, but only 0 and 1 bit values are supported (the pass will
|
||||
convert any x bits to 0)
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ Ports come in 5 kinds:
|
|||
- `ar`: asynchronous read port
|
||||
- `sr`: synchronous read port
|
||||
- `sw`: synchronous write port
|
||||
- `arsw`: simultanous synchronous write + asynchronous read with common address (commonly found in LUT RAMs)
|
||||
- `arsw`: simultaneous synchronous write + asynchronous read with common address (commonly found in LUT RAMs)
|
||||
- `srsw`: synchronous write + synchronous read with common address
|
||||
|
||||
The port properties available are:
|
||||
|
|
@ -419,7 +419,7 @@ If not provided, `none` is assumed for all three properties.
|
|||
|
||||
The `wrprio` property is only allowed on write ports and defines a priority relationship
|
||||
between port — when `wrprio "B";` is used in definition of port `"A"`, and both ports
|
||||
simultanously write to the same memory cell, the value written by port `"A"` will have
|
||||
simultaneously write to the same memory cell, the value written by port `"A"` will have
|
||||
precedence.
|
||||
|
||||
This property is optional, and can be used multiple times as necessary. If no relationship
|
||||
|
|
@ -493,7 +493,7 @@ will disallow combining the RAM option `ABC = 2` with port option `DEF = "GHI"`.
|
|||
|
||||
## Ifdefs
|
||||
|
||||
To allow reusing a library for multiple FPGA families with slighly differing
|
||||
To allow reusing a library for multiple FPGA families with slightly differing
|
||||
capabilities, `ifdef` (and `ifndef`) blocks are provided:
|
||||
|
||||
ifdef IS_FANCY_FPGA_WITH_CONFIGURABLE_ASYNC_RESET {
|
||||
|
|
|
|||
|
|
@ -24,11 +24,25 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string_view>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
IdString concat_name(RTLIL::Cell *cell, IdString object_name, const std::string &separator = ".")
|
||||
template <typename... Args>
|
||||
[[nodiscard]] std::string concat_views(const Args&... views) {
|
||||
static_assert((std::is_convertible_v<Args, std::string_view> && ...),
|
||||
"All arguments must be convertible to std::string_view.");
|
||||
const std::size_t total_size = (std::string_view(views).size() + ... + 0);
|
||||
|
||||
std::string result;
|
||||
result.reserve(total_size);
|
||||
|
||||
(result.append(views), ...);
|
||||
return result;
|
||||
}
|
||||
|
||||
IdString concat_name(RTLIL::Cell *cell, IdString const &object_name, const std::string &separator = ".")
|
||||
{
|
||||
return stringf("%s%s%s", cell->name.c_str(), separator.c_str(), object_name.c_str() + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
OBJS += passes/tests/test_autotb.o
|
||||
OBJS += passes/tests/test_cell.o
|
||||
OBJS += passes/tests/test_abcloop.o
|
||||
OBJS += passes/tests/raise_error.o
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct RaiseErrorPass : public Pass {
|
||||
RaiseErrorPass() : Pass("raise_error", "raise errors from attributes") { }
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" raise_error [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Test error handling by raising arbitrary errors. This pass iterates over the\n");
|
||||
log("design (or selection of it) checking for objects with the 'raise_error'\n");
|
||||
log("attribute set. Assigning 'raise_error' to a string more than one character long\n");
|
||||
log("will log that string as an error message before exiting. Assigning 'raise_error'\n");
|
||||
log("to an integer (less than 256) will exit with that value as the exit code.\n");
|
||||
log("\n");
|
||||
log(" -stderr\n");
|
||||
log(" Log error messages directly to stderr instead of using 'log_error'.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(vector<string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing RAISE_ERROR pass.\n");
|
||||
|
||||
bool use_stderr = false;
|
||||
|
||||
int argidx;
|
||||
for (argidx = 1; argidx < GetSize(args); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-stderr") {
|
||||
use_stderr = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
extra_args(args, argidx, design, true);
|
||||
|
||||
RTLIL::NamedObject *err_obj = nullptr;
|
||||
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
if (mod->has_attribute(ID::raise_error)) {
|
||||
err_obj = mod->clone();
|
||||
break;
|
||||
}
|
||||
for (auto memb : mod->selected_members()) {
|
||||
if (memb->has_attribute(ID::raise_error)) {
|
||||
err_obj = memb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (err_obj != nullptr) break;
|
||||
}
|
||||
|
||||
if (err_obj != nullptr) {
|
||||
log("Raising error from '%s'.\n", log_id(err_obj));
|
||||
auto err_no = err_obj->attributes[ID::raise_error].as_int();
|
||||
if (err_no < 256) {
|
||||
log_flush();
|
||||
} else {
|
||||
auto err_msg = err_obj->get_string_attribute(ID::raise_error);
|
||||
if (use_stderr) {
|
||||
std::cerr << err_msg << std::endl;
|
||||
err_no = 1;
|
||||
} else {
|
||||
log_error("%s\n", err_msg.c_str());
|
||||
}
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
_exit(err_no);
|
||||
#else
|
||||
_Exit(err_no);
|
||||
#endif
|
||||
} else {
|
||||
log("'raise_error' attribute not found\n");
|
||||
}
|
||||
}
|
||||
} RaiseErrorPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
bram1_cmp
|
||||
bram1.mk
|
||||
bram1_[0-9]*/
|
||||
bram2.log
|
||||
bram2_syn.v
|
||||
bram2_tb
|
||||
dsp_work*/
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
*.log
|
||||
*.out
|
||||
*.err
|
||||
run-test.mk
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
/*_ref.v
|
||||
/*.log
|
||||
/neg.out/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
*.log
|
||||
*.json
|
||||
/run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
/*.log
|
||||
/run-test.mk
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
*.vm
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
/*.log
|
||||
/run-test.mk
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
/*_uut.v
|
||||
/test_macc
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
*.out
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
run-test.mk
|
||||
|
|
@ -1 +0,0 @@
|
|||
*.log
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
bugpoint-case.*
|
||||
*.log
|
||||
*.err
|
||||
*.temp
|
||||
run-test.mk
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
write_file fail.temp << EOF
|
||||
logger -expect error "Missing -script or -command option." 1
|
||||
bugpoint -suffix fail -yosys ../../yosys
|
||||
EOF
|
||||
exec -expect-return 0 -- ../../yosys -qq mods.il -s fail.temp
|
||||
|
||||
write_file fail.temp << EOF
|
||||
logger -expect error "do not crash on this design" 1
|
||||
bugpoint -suffix fail -yosys ../../yosys -command "dump"
|
||||
EOF
|
||||
exec -expect-return 0 -- ../../yosys -qq mods.il -s fail.temp
|
||||
|
||||
write_file fail.temp << EOF
|
||||
logger -expect error "returned value 3 instead of expected 7" 1
|
||||
bugpoint -suffix fail -yosys ../../yosys -command raise_error -expect-return 7
|
||||
EOF
|
||||
exec -expect-return 0 -- ../../yosys -qq mods.il -s fail.temp
|
||||
|
||||
write_file fail.temp << EOF
|
||||
logger -expect error "not found in the log file!" 1
|
||||
bugpoint -suffix fail -yosys ../../yosys -command raise_error -grep "nope"
|
||||
EOF
|
||||
exec -expect-return 0 -- ../../yosys -qq mods.il -s fail.temp
|
||||
|
||||
write_file fail.temp << EOF
|
||||
logger -expect error "not found in stderr log!" 1
|
||||
bugpoint -suffix fail -yosys ../../yosys -command raise_error -err-grep "nope"
|
||||
EOF
|
||||
exec -expect-return 0 -- ../../yosys -qq mods.il -s fail.temp
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
read_rtlil mods.il
|
||||
select -assert-count 7 w:*
|
||||
select -assert-mod-count 3 =*
|
||||
select -assert-count 4 c:*
|
||||
design -stash base
|
||||
|
||||
# everything is removed by default
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# don't remove wires
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3 -modules -cells
|
||||
select -assert-count 3 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# don't remove cells or their connections
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3 -wires -modules
|
||||
select -assert-count 5 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-count 4 c:*
|
||||
|
||||
# don't remove cells but do remove their connections
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3 -wires -modules -connections
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-count 4 c:*
|
||||
|
||||
# don't remove modules
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3 -wires -cells
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 3 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# can keep wires
|
||||
design -load base
|
||||
setattr -set bugpoint_keep 1 w:w_b
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3
|
||||
select -assert-count 2 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# a wire with keep won't keep the cell/module containing it
|
||||
design -load base
|
||||
setattr -set bugpoint_keep 1 w:w_o
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# can keep cells (and do it without the associated module)
|
||||
design -load base
|
||||
setattr -set bugpoint_keep 1 c:c_a
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-count 1 c:*
|
||||
|
||||
# can keep modules
|
||||
design -load base
|
||||
setattr -mod -set bugpoint_keep 1 m_a
|
||||
bugpoint -suffix mods -yosys ../../yosys -command raise_error -expect-return 3
|
||||
select -assert-count 1 w:*
|
||||
select -assert-mod-count 2 =*
|
||||
select -assert-none c:*
|
||||
|
||||
# minimize to just the path connecting w_a and w_c
|
||||
# which happens via w_b, w_i, w_o, m_a, c_a and c_b
|
||||
write_file script.temp << EOF
|
||||
select -assert-none w:w_a %co* w:w_c %ci* %i
|
||||
EOF
|
||||
design -load base
|
||||
bugpoint -suffix mods -yosys ../../yosys -script script.temp -grep "Assertion failed"
|
||||
select -assert-count 5 w:*
|
||||
select -assert-mod-count 2 =*
|
||||
select -assert-count 2 c:*
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
module \m_a
|
||||
wire input 1 \w_i
|
||||
wire output 2 \w_o
|
||||
connect \w_o \w_i
|
||||
end
|
||||
|
||||
module \m_b
|
||||
wire input 1 \w_i
|
||||
wire output 2 \w_o
|
||||
end
|
||||
|
||||
attribute \top 1
|
||||
module \top
|
||||
attribute \raise_error 3
|
||||
wire \w_a
|
||||
wire \w_b
|
||||
wire \w_c
|
||||
|
||||
cell \m_a \c_a
|
||||
connect \w_i \w_a
|
||||
connect \w_o \w_b
|
||||
end
|
||||
|
||||
cell \m_a \c_b
|
||||
connect \w_i \w_b
|
||||
connect \w_o \w_c
|
||||
end
|
||||
|
||||
cell \m_b \c_c
|
||||
connect \w_i \w_c
|
||||
connect \w_o \w_a
|
||||
end
|
||||
|
||||
cell \m_b \c_d
|
||||
connect \w_i 1'0
|
||||
connect \w_o 1'1
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
read_rtlil procs.il
|
||||
select -assert-count 2 p:*
|
||||
design -stash err_q
|
||||
|
||||
# processes get removed by default
|
||||
design -load err_q
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4
|
||||
select -assert-none p:*
|
||||
|
||||
# individual processes can be kept
|
||||
design -load err_q
|
||||
setattr -set bugpoint_keep 1 p:proc_a
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4
|
||||
select -assert-count 1 p:*
|
||||
|
||||
# all processes can be kept
|
||||
design -load err_q
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4 -wires
|
||||
select -assert-count 2 p:*
|
||||
|
||||
# d and clock are connected after proc
|
||||
design -load err_q
|
||||
proc
|
||||
select -assert-count 3 w:d %co
|
||||
select -assert-count 3 w:clock %co
|
||||
|
||||
# no assigns means no d
|
||||
design -load err_q
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4 -assigns
|
||||
proc
|
||||
select -assert-count 1 w:d %co
|
||||
|
||||
# no updates means no clock
|
||||
design -load err_q
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4 -updates
|
||||
proc
|
||||
select -assert-count 1 w:clock %co
|
||||
|
||||
# can remove ports
|
||||
design -load err_q
|
||||
select -assert-count 5 x:*
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4 -ports
|
||||
select -assert-none x:*
|
||||
|
||||
# can keep ports
|
||||
design -load err_q
|
||||
setattr -set bugpoint_keep 1 i:d o:q
|
||||
bugpoint -suffix procs -yosys ../../yosys -command raise_error -expect-return 4 -ports
|
||||
select -assert-count 2 x:*
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
module \ff_with_en_and_sync_reset
|
||||
wire $0\q[1:1]
|
||||
wire $0\q[0:0]
|
||||
attribute \raise_error 4
|
||||
wire width 2 output 5 \q
|
||||
wire width 2 input 4 \d
|
||||
wire input 3 \enable
|
||||
wire input 2 \reset
|
||||
wire input 1 \clock
|
||||
|
||||
process \proc_a
|
||||
assign $0\q[0:0] \q [0]
|
||||
switch \reset
|
||||
case 1'1
|
||||
assign $0\q[0:0] 1'0
|
||||
case
|
||||
switch \enable
|
||||
case 1'1
|
||||
assign $0\q[0:0] \d [0]
|
||||
case
|
||||
end
|
||||
end
|
||||
sync posedge \clock
|
||||
update \q [0] $0\q[0:0]
|
||||
end
|
||||
|
||||
process \proc_b
|
||||
assign $0\q[1:1] \q [1]
|
||||
switch \reset
|
||||
case 1'1
|
||||
assign $0\q[1:1] 1'0
|
||||
case
|
||||
switch \enable
|
||||
case 1'1
|
||||
assign $0\q[1:1] \d [1]
|
||||
case
|
||||
end
|
||||
end
|
||||
sync posedge \clock
|
||||
update \q [1] $0\q[1:1]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
read_verilog -noblackbox << EOF
|
||||
(* raise_error=7 *)
|
||||
module top();
|
||||
endmodule
|
||||
|
||||
(* raise_error="help me" *)
|
||||
module other();
|
||||
endmodule
|
||||
|
||||
(* raise_error *)
|
||||
module def();
|
||||
endmodule
|
||||
EOF
|
||||
select -assert-mod-count 3 =*
|
||||
design -stash read
|
||||
|
||||
# raise_error with int exits with status
|
||||
design -load read
|
||||
bugpoint -suffix error -yosys ../../yosys -command raise_error -expect-return 7
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-mod-count 1 top
|
||||
|
||||
# raise_error with string prints message and exits with 1
|
||||
design -load read
|
||||
rename top abc
|
||||
bugpoint -suffix error -yosys ../../yosys -command raise_error -grep "help me" -expect-return 1
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-mod-count 1 other
|
||||
|
||||
# raise_error with no value exits with 1
|
||||
design -load read
|
||||
rename def zzy
|
||||
delete other
|
||||
bugpoint -suffix error -yosys ../../yosys -command raise_error -expect-return 1
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-mod-count 1 zzy
|
||||
|
||||
# raise_error -stderr prints to stderr and exits with 1
|
||||
design -load read
|
||||
rename top abc
|
||||
bugpoint -suffix error -yosys ../../yosys -command "raise_error -stderr" -err-grep "help me" -expect-return 1
|
||||
select -assert-mod-count 1 =*
|
||||
select -assert-mod-count 1 other
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
generate_mk --yosys-scripts
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
*.log
|
||||
iverilog-*
|
||||
yosys-*
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
*.log
|
||||
*.out
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
*.log
|
||||
/*.filtered
|
||||
*.verilogsim
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
*.log
|
||||
|
|
@ -1,5 +1,2 @@
|
|||
t_*.log
|
||||
t_*.out
|
||||
t_*.v
|
||||
t_*.ys
|
||||
run-test.mk
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
*.log
|
||||
*.out
|
||||
*.dmp
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
/*.log
|
||||
|
|
@ -1 +0,0 @@
|
|||
*.log
|
||||
|
|
@ -1 +0,0 @@
|
|||
*.log
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
*.log
|
||||
run-test.mk
|
||||
*.vcd
|
||||
*.fst
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
/*.log
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
+*_synth.v
|
||||
+*_testbench
|
||||
*.out
|
||||
*.fst
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
*.log
|
||||
*.out
|
||||
*.err
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
*.v
|
||||
*.sv
|
||||
*.log
|
||||
*.out
|
||||
*.bak
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
*.log
|
||||
*.out
|
||||
/*.mk
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
/*.sel
|
||||
/write_gzip.v
|
||||
/write_gzip.v.gz
|
||||
/run-test.mk
|
||||
/plugin.so
|
||||
/plugin.so.dSYM
|
||||
/temp
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
|
|
@ -1,7 +1,3 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/*.err
|
||||
/run-test.mk
|
||||
/const_arst.v
|
||||
/const_sr.v
|
||||
/doubleslash.v
|
||||
|
|
|
|||
Loading…
Reference in New Issue