aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/calc.cc30
-rw-r--r--kernel/celltypes.h14
-rw-r--r--kernel/driver.cc30
-rw-r--r--kernel/fstdata.cc28
-rw-r--r--kernel/log.cc3
-rw-r--r--kernel/log.h17
-rw-r--r--kernel/mem.cc1
-rw-r--r--kernel/register.cc109
-rw-r--r--kernel/rtlil.h2
-rw-r--r--kernel/satgen.cc27
-rw-r--r--kernel/satgen.h1
-rw-r--r--kernel/yosys.cc12
12 files changed, 244 insertions, 30 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 0865db526..32e8a49fe 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -609,6 +609,36 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo
return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
}
+RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+{
+ log_assert(arg2.size() == arg1.size());
+ if (arg3[0] == State::S0)
+ return arg1;
+ else if (arg3[0] == State::S1)
+ return arg2;
+
+ RTLIL::Const ret = arg1;
+ for (int i = 0; i < ret.size(); i++)
+ if (ret[i] != arg2[i])
+ ret[i] = State::Sx;
+ return ret;
+}
+
+RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+{
+ if (arg3.is_fully_zero())
+ return arg1;
+
+ if (!arg3.is_onehot())
+ return RTLIL::Const(State::Sx, arg1.size());
+
+ for (int i = 0; i < arg3.size(); i++)
+ if (arg3[i] == State::S1)
+ return RTLIL::Const(std::vector<RTLIL::State>(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()));
+
+ log_abort(); // unreachable
+}
+
RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
{
std::vector<RTLIL::State> t = arg1.bits;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index d62ba1506..e617b4603 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -488,16 +488,10 @@ struct CellTypes
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
{
- if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
- RTLIL::Const ret = arg1;
- for (size_t i = 0; i < arg3.bits.size(); i++)
- if (arg3.bits[i] == RTLIL::State::S1) {
- std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
- ret = RTLIL::Const(bits);
- }
- return ret;
- }
-
+ if (cell->type.in(ID($mux), ID($_MUX_)))
+ return const_mux(arg1, arg2, arg3);
+ if (cell->type == ID($pmux))
+ return const_pmux(arg1, arg2, arg3);
if (cell->type == ID($_AOI3_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
if (cell->type == ID($_OAI3_))
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 6d996783e..aa90802c9 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -202,6 +202,11 @@ extern char *yosys_argv0;
extern char yosys_path[PATH_MAX];
};
#endif
+#ifdef YOSYS_ENABLE_TCL
+namespace Yosys {
+ extern int yosys_tcl_iterp_init(Tcl_Interp *interp);
+};
+#endif
int main(int argc, char **argv)
{
@@ -221,6 +226,7 @@ int main(int argc, char **argv)
bool call_abort = false;
bool timing_details = false;
bool run_shell = true;
+ bool run_tcl_shell = false;
bool mode_v = false;
bool mode_q = false;
@@ -284,6 +290,9 @@ int main(int argc, char **argv)
printf("\n");
printf(" -c tcl_scriptfile\n");
printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n");
+ printf("\n");
+ printf(" -C\n");
+ printf(" enters TCL interatcive shell mode\n");
#endif
printf("\n");
printf(" -p command\n");
@@ -358,7 +367,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:B:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVCSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:B:")) != -1)
{
switch (opt)
{
@@ -496,6 +505,9 @@ int main(int argc, char **argv)
case 'B':
perffile = optarg;
break;
+ case 'C':
+ run_tcl_shell = true;
+ break;
default:
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
@@ -570,10 +582,18 @@ int main(int argc, char **argv)
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it);
- if (run_shell)
- shell(yosys_design);
- else
- run_backend(output_filename, backend_command);
+ if (run_tcl_shell) {
+#ifdef YOSYS_ENABLE_TCL
+ Tcl_Main(argc, argv, yosys_tcl_iterp_init);
+#else
+ log_error("Can't exectue TCL shell: this version of yosys is not built with TCL support enabled.\n");
+#endif
+ } else {
+ if (run_shell)
+ shell(yosys_design);
+ else
+ run_backend(output_filename, backend_command);
+ }
yosys_design->check();
for (auto it : saved_designs)
diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc
index b2e574b02..1b8043f9a 100644
--- a/kernel/fstdata.cc
+++ b/kernel/fstdata.cc
@@ -78,7 +78,18 @@ uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
+static void normalize_brackets(std::string &str)
+{
+ for (auto &c : str) {
+ if (c == '<')
+ c = '[';
+ else if (c == '>')
+ c = ']';
+ }
+}
+
fstHandle FstData::getHandle(std::string name) {
+ normalize_brackets(name);
if (name_to_handle.find(name) != name_to_handle.end())
return name_to_handle[name];
else
@@ -120,6 +131,7 @@ void FstData::extractVarNames()
var.is_reg = (fstVarType)h->u.var.typ == FST_VT_VCD_REG;
var.name = remove_spaces(h->u.var.name);
var.scope = fst_scope_name;
+ normalize_brackets(var.scope);
var.width = h->u.var.length;
vars.push_back(var);
if (!var.is_alias)
@@ -134,35 +146,34 @@ void FstData::extractVarNames()
if (clean_name[0]=='\\')
clean_name = clean_name.substr(1);
size_t pos = clean_name.find_last_of("<");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos && clean_name.back() == '>') {
std::string mem_cell = clean_name.substr(0, pos);
+ normalize_brackets(mem_cell);
std::string addr = clean_name.substr(pos+1);
addr.pop_back(); // remove closing bracket
char *endptr;
int mem_addr = strtol(addr.c_str(), &endptr, 16);
if (*endptr) {
- log_warning("Error parsing memory address in : %s\n", clean_name.c_str());
+ log_debug("Error parsing memory address in : %s\n", clean_name.c_str());
} else {
memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id;
- name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle;
- continue;
}
}
pos = clean_name.find_last_of("[");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos && clean_name.back() == ']') {
std::string mem_cell = clean_name.substr(0, pos);
+ normalize_brackets(mem_cell);
std::string addr = clean_name.substr(pos+1);
addr.pop_back(); // remove closing bracket
char *endptr;
int mem_addr = strtol(addr.c_str(), &endptr, 10);
if (*endptr) {
- log_warning("Error parsing memory address in : %s\n", clean_name.c_str());
+ log_debug("Error parsing memory address in : %s\n", clean_name.c_str());
} else {
memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id;
- name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle;
- continue;
}
}
+ normalize_brackets(clean_name);
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
break;
}
@@ -241,6 +252,7 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta
past_data = last_data;
callback(last_time);
}
+ past_data = last_data;
callback(end_time);
}
diff --git a/kernel/log.cc b/kernel/log.cc
index 4403dd0c7..af8c422b8 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -352,6 +352,9 @@ static void logv_error_with_prefix(const char *prefix,
log_error_atexit();
YS_DEBUGTRAP_IF_DEBUGGING;
+ const char *e = getenv("YOSYS_ABORT_ON_LOG_ERROR");
+ if (e && atoi(e))
+ abort();
#ifdef EMSCRIPTEN
log_files = backup_log_files;
diff --git a/kernel/log.h b/kernel/log.h
index 3bc9fd978..822816cb4 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -393,6 +393,11 @@ void log_dump_val_worker(RTLIL::IdString v);
void log_dump_val_worker(RTLIL::SigSpec v);
void log_dump_val_worker(RTLIL::State v);
+template<typename K, typename T, typename OPS> static inline void log_dump_val_worker(dict<K, T, OPS> &v);
+template<typename K, typename OPS> static inline void log_dump_val_worker(pool<K, OPS> &v);
+template<typename K> static inline void log_dump_val_worker(std::vector<K> &v);
+template<typename T> static inline void log_dump_val_worker(T *ptr);
+
template<typename K, typename T, typename OPS>
static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
log("{");
@@ -419,6 +424,18 @@ static inline void log_dump_val_worker(pool<K, OPS> &v) {
log(" }");
}
+template<typename K>
+static inline void log_dump_val_worker(std::vector<K> &v) {
+ log("{");
+ bool first = true;
+ for (auto &it : v) {
+ log(first ? " " : ", ");
+ log_dump_val_worker(it);
+ first = false;
+ }
+ log(" }");
+}
+
template<typename T>
static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
diff --git a/kernel/mem.cc b/kernel/mem.cc
index e5e855ef7..ed01a0867 100644
--- a/kernel/mem.cc
+++ b/kernel/mem.cc
@@ -504,6 +504,7 @@ void Mem::check() {
int mask = (1 << max_wide_log2) - 1;
log_assert(!(start_offset & mask));
log_assert(!(size & mask));
+ log_assert(width != 0);
}
namespace {
diff --git a/kernel/register.cc b/kernel/register.cc
index 226963fda..9449890b1 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -822,6 +822,100 @@ struct HelpPass : public Pass {
fclose(f);
}
+ void write_rst(std::string cmd, std::string title, std::string text)
+ {
+ FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt");
+ // make header
+ size_t char_len = cmd.length() + 3 + title.length();
+ std::string title_line = "\n";
+ title_line.insert(0, char_len, '=');
+ fprintf(f, "%s", title_line.c_str());
+ fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str());
+ fprintf(f, "%s\n", title_line.c_str());
+ fprintf(f, ".. raw:: latex\n\n \\begin{comment}\n\n");
+
+ // render html
+ fprintf(f, ":code:`yosys> help %s`\n", cmd.c_str());
+ fprintf(f, "--------------------------------------------------------------------------------\n\n");
+ fprintf(f, ".. container:: cmdref\n");
+ std::stringstream ss;
+ std::string textcp = text;
+ ss << text;
+ bool IsUsage = true;
+ int blank_count = 0;
+ size_t def_strip_count = 0;
+ bool WasDefinition = false;
+ for (std::string line; std::getline(ss, line, '\n');) {
+ // find position of first non space character
+ std::size_t first_pos = line.find_first_not_of(" \t");
+ std::size_t last_pos = line.find_last_not_of(" \t");
+ if (first_pos == std::string::npos) {
+ // skip formatting empty lines
+ if (!WasDefinition)
+ fputc('\n', f);
+ blank_count += 1;
+ continue;
+ }
+
+ // strip leading and trailing whitespace
+ std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
+ bool IsDefinition = stripped_line[0] == '-';
+ IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
+ bool IsDedent = def_strip_count && first_pos <= def_strip_count;
+ bool IsIndent = first_pos == 2 || first_pos == 4;
+ if (cmd.compare(0, 7, "verific") == 0)
+ // verific.cc has strange and different formatting from the rest
+ IsIndent = false;
+
+ // another usage block
+ bool NewUsage = stripped_line.find(cmd) == 0;
+
+ if (IsUsage) {
+ if (stripped_line.compare(0, 4, "See ") == 0) {
+ // description refers to another function
+ fprintf(f, "\n %s\n", stripped_line.c_str());
+ } else {
+ // usage should be the first line of help output
+ fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ }
+ IsUsage = false;
+ } else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) {
+ // another usage block
+ fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ def_strip_count = 0;
+ } else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) {
+ // format definition term
+ fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ def_strip_count = first_pos;
+ } else {
+ if (IsDedent) {
+ fprintf(f, "\n\n ::\n");
+ def_strip_count = first_pos;
+ } else if (WasDefinition) {
+ fprintf(f, " ::\n");
+ WasDefinition = false;
+ }
+ fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str());
+ }
+
+ blank_count = 0;
+ }
+ fputc('\n', f);
+
+ // render latex
+ fprintf(f, ".. raw:: latex\n\n \\end{comment}\n\n");
+ fprintf(f, ".. only:: latex\n\n");
+ fprintf(f, " ::\n\n");
+ std::stringstream ss2;
+ ss2 << textcp;
+ for (std::string line; std::getline(ss2, line, '\n');) {
+ fprintf(f, " %s\n", line.c_str());
+ }
+ fclose(f);
+ }
void execute(std::vector<std::string> args, RTLIL::Design*) override
{
if (args.size() == 1) {
@@ -882,6 +976,21 @@ struct HelpPass : public Pass {
fclose(f);
}
// this option is undocumented as it is for internal use only
+ else if (args[1] == "-write-rst-command-reference-manual") {
+ for (auto &it : pass_register) {
+ std::ostringstream buf;
+ log_streams.push_back(&buf);
+ it.second->help();
+ if (it.second->experimental_flag) {
+ log("\n");
+ log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
+ log("\n");
+ }
+ log_streams.pop_back();
+ write_rst(it.first, it.second->short_help, buf.str());
+ }
+ }
+ // this option is undocumented as it is for internal use only
else if (args[1] == "-write-web-command-reference-manual") {
FILE *f = fopen("templates/cmd_index.in", "wt");
for (auto &it : pass_register) {
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 27ffdff1f..755abf534 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -500,6 +500,8 @@ namespace RTLIL
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
+ RTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
diff --git a/kernel/satgen.cc b/kernel/satgen.cc
index 05eeca76e..2a1fd1711 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -1187,6 +1187,10 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
if (timestep == 1)
{
initial_state.add((*sigmap)(cell->getPort(ID::Q)));
+ if (model_undef && def_formal) {
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep);
+ ez->assume(ez->NOT(ez->vec_reduce_or(undef_q)));
+ }
}
else
{
@@ -1254,13 +1258,18 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
if (cell->type == ID($anyconst))
{
- if (timestep < 2)
+ if (timestep < 2) {
+ if (model_undef && def_formal) {
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ ez->assume(ez->NOT(ez->vec_reduce_or(undef_y)));
+ }
return true;
+ }
std::vector<int> d = importDefSigSpec(cell->getPort(ID::Y), timestep-1);
std::vector<int> q = importDefSigSpec(cell->getPort(ID::Y), timestep);
- std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
+ std::vector<int> qq = (model_undef && !def_formal) ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
@@ -1268,14 +1277,24 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1);
std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
- ez->assume(ez->vec_eq(undef_d, undef_q));
- undefGating(q, qq, undef_q);
+ if (def_formal) {
+ for (auto &undef_q_bit : undef_q)
+ ez->SET(ez->CONST_FALSE, undef_q_bit);
+ } else {
+ ez->assume(ez->vec_eq(undef_d, undef_q));
+ undefGating(q, qq, undef_q);
+ }
}
return true;
}
if (cell->type == ID($anyseq))
{
+ if (model_undef && def_formal) {
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ for (auto &undef_q_bit : undef_q)
+ ez->SET(ez->CONST_FALSE, undef_q_bit);
+ }
return true;
}
diff --git a/kernel/satgen.h b/kernel/satgen.h
index da2cec222..8a89ff9db 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -73,6 +73,7 @@ struct SatGen
std::map<std::pair<std::string, int>, bool> initstates;
bool ignore_div_by_zero;
bool model_undef;
+ bool def_formal = false;
SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) :
ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index a56a066fe..4a22d0a7b 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -740,13 +740,19 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
return TCL_OK;
}
+int yosys_tcl_iterp_init(Tcl_Interp *interp)
+{
+ if (Tcl_Init(interp)!=TCL_OK)
+ log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
+ Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
+ return TCL_OK ;
+}
+
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
yosys_tcl_interp = Tcl_CreateInterp();
- if (Tcl_Init(yosys_tcl_interp)!=TCL_OK)
- log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
- Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
+ yosys_tcl_iterp_init(yosys_tcl_interp);
}
return yosys_tcl_interp;
}