summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/resources/Makefile35
-rw-r--r--src/main/resources/emulator.h3
-rw-r--r--src/main/resources/emulator_api.h684
-rw-r--r--src/main/resources/emulator_mod.h1800
-rw-r--r--src/main/resources/vpi_user.cc562
5 files changed, 3084 insertions, 0 deletions
diff --git a/src/main/resources/Makefile b/src/main/resources/Makefile
new file mode 100644
index 00000000..221179a3
--- /dev/null
+++ b/src/main/resources/Makefile
@@ -0,0 +1,35 @@
+# Chisel parallel make template.
+
+HFILES = @HFILES@
+ONCEONLY = @ONCEONLY@
+UNOPTIMIZED = @UNOPTIMIZED@
+OPTIMIZED = @OPTIMIZED@
+
+EXEC = @EXEC@
+OPTIM0 = @OPTIM0@
+OPTIM1 = @OPTIM1@
+OPTIM2 = @OPTIM2@
+CPPFLAGS = @CPPFLAGS@
+CXXFLAGS = @CXXFLAGS@
+LDFLAGS = @LDFLAGS@
+CXX = @CXX@
+
+default: $(EXEC)
+
+clean:
+ $(RM) $(EXEC) $(ONCEONLY) $(UNOPTIMIZED) $(OPTIMIZED)
+
+$(ONCEONLY) $(UNOPTIMIZED) $(OPTIMIZED): $(HFILES)
+
+$(EXEC): $(ONCEONLY) $(UNOPTIMIZED) $(OPTIMIZED) Makefile
+ $(CXX) -o $@ $(filter-out Makefile,$^)
+
+$(ONCEONLY): %.o: %.cpp
+ $(CXX) -c -o $@ $(OPTIM0) $(CPPFLAGS) $(CXXFLAGS) $<
+
+$(UNOPTIMIZED): %.o: %.cpp
+ $(CXX) -c -o $@ $(OPTIM1) $(CPPFLAGS) $(CXXFLAGS) $<
+
+$(OPTIMIZED): %.o: %.cpp
+ $(CXX) -c -o $@ $(OPTIM2) $(CPPFLAGS) $(CXXFLAGS) $<
+ \ No newline at end of file
diff --git a/src/main/resources/emulator.h b/src/main/resources/emulator.h
new file mode 100644
index 00000000..1286f432
--- /dev/null
+++ b/src/main/resources/emulator.h
@@ -0,0 +1,3 @@
+// metaheader for the Chisel emulator and API
+#include "emulator_mod.h"
+#include "emulator_api.h"
diff --git a/src/main/resources/emulator_api.h b/src/main/resources/emulator_api.h
new file mode 100644
index 00000000..38b50963
--- /dev/null
+++ b/src/main/resources/emulator_api.h
@@ -0,0 +1,684 @@
+// Header for Chisel emulator API
+#ifndef __IS_EMULATOR_API__
+#define __IS_EMULATOR_API__
+
+#include "emulator_mod.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+
+#include <string>
+#include <sstream>
+#include <map>
+#include <cassert>
+#include <cerrno>
+
+/**
+ * Converts an integer to a std::string without needing additional libraries
+ * or C++11.
+ */
+static std::string itos(int in) {
+ std::stringstream out;
+ out << in;
+ return out.str();
+}
+
+/**
+ * Copy one val_t array to another.
+ * nb must be the exact number of bits the val_t represents.
+ */
+static __attribute__((unused)) void val_cpy(val_t* dst, val_t* src, int nb) {
+ for (int i=0; i<val_n_words(nb); i++) {
+ dst[i] = src[i];
+ }
+}
+
+/**
+ * Empty a val_t array (sets to zero).
+ * nb must be the exact number of bits the val_t represents.
+ */
+static void val_empty(val_t* dst, int nb) {
+ for (int i=0; i<val_n_words(nb); i++) {
+ dst[i] = 0;
+ }
+}
+
+/**
+ * Set a val_t array to a integer number. Obviously, the maximum integer
+ * is capped by the width of a single val_t element.
+ * nb must be the exact number of bits the val_t represents.
+ */
+static __attribute__((unused)) void val_set(val_t* dst, val_t nb, val_t num) {
+ val_empty(dst, nb);
+ dst[0] = num;
+}
+
+/**
+ * Sets a dat_t from a string, where the input radix is automatically determined
+ * from the string (or defaults to 10).
+ * Returns true on success.
+ */
+template <int w>
+bool dat_from_str(std::string in, dat_t<w>& res, int pos = 0) {
+ int radix = 10;
+ int negate = 0;
+
+ /* Handle leading minus sign. */
+ if (!in.substr(pos, 1).compare("-")) {
+ pos++;
+ negate = 1;
+ }
+
+ if (!in.substr(pos, 1).compare("d")) {
+ radix = 10;
+ pos++;
+ } else if (!in.substr(pos, 1).compare("h")
+ || !in.substr(pos, 1).compare("x")) {
+ radix = 16;
+ pos++;
+ } else if (!in.substr(pos, 2).compare("0h")
+ || !in.substr(pos, 2).compare("0x")) {
+ radix = 16;
+ pos += 2;
+ } else if (!in.substr(pos, 1).compare("b")) {
+ radix = 2;
+ pos++;
+ } else if (!in.substr(pos, 2).compare("0b")) {
+ radix = 2;
+ pos += 2;
+ }
+
+ const int log_max_radix = 4;
+ assert(radix <= (1 << log_max_radix));
+
+ dat_t<w> curr_base = 1;
+ res = 0;
+
+ for (int rpos=in.length()-1; rpos>=pos; rpos--) {
+ char c = in[rpos];
+ val_t c_val = 0;
+ if (c == '_') {
+ continue;
+ }
+ if (c >= '0' && c <= '9') {
+ c_val = c - '0';
+ } else if (c >= 'a' && c <= 'z') {
+ c_val = c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'Z') {
+ c_val = c - 'A' + 10;
+ } else {
+ std::cerr << "dat_from_str: Invalid character '" << c << "' in '" << in << "'" << std::endl;
+ return false;
+ }
+ if (c_val > radix /* || c_val < 0 */) {
+ std::cerr << "dat_from_str: Invalid character '" << c << "'" <<
+ std::endl;
+ return false;
+ }
+
+ dat_t<w> temp_prod = curr_base * dat_t<log_max_radix>(c_val);
+ res = res + temp_prod;
+ curr_base = curr_base * dat_t<log_max_radix+1>(radix);
+ }
+ if (negate) {
+ res = -res;
+ }
+ return true;
+}
+
+// API base class, providing common functions
+class api_base {
+public:
+ api_base(const char* new_name, const char* new_path) :
+ name(new_name),
+ path(new_path)
+ {}
+ // returns the fully qualified name of this object (path + dot + name)
+ std::string get_pathname() {
+ if (*path == '\0') {
+ return name;
+ } else {
+ return get_path() + "." + name;
+ }
+ }
+ // returns the short name of this object
+ std::string get_name() {
+ return name;
+ }
+ // returns the path of this object (without a trailing dot)
+ std::string get_path() {
+ return path;
+ }
+protected:
+ const char* name;
+ const char* path;
+};
+
+// API base (non width templated) class for API accessors to dat_t
+class dat_api_base : public api_base {
+public:
+ dat_api_base(const char* new_name, const char* new_path) :
+ api_base(new_name, new_path)
+ {}
+ // returns the value of this wire as a string, or empty string on failure
+ virtual std::string get_value() = 0;
+ // sets the value of this wire from a string, returning true on success
+ virtual bool set_value(std::string value) = 0;
+ // returns the bitwidth of this wire
+ virtual std::string get_width() = 0;
+};
+
+// dat_api dummy class, does nothing except for return errors
+// to be used when a real dat_api object can't be found
+class dat_dummy : public dat_api_base {
+public:
+ dat_dummy() :
+ dat_api_base("error", "")
+ {}
+ std::string get_value() {
+ return "error";
+ }
+
+ bool set_value(std::string value) {
+ return false;
+ }
+
+ std::string get_width() {
+ return "error";
+ }
+};
+
+template<int w> class dat_api : public dat_api_base {
+public:
+ dat_api(dat_t<w>* new_dat, const char* new_name, const char* new_path) :
+ dat_api_base(new_name, new_path),
+ dat_ptr(new_dat)
+ {}
+
+ std::string get_value() {
+ return dat_ptr->to_str();
+ }
+
+ bool set_value(std::string value) {
+ return dat_from_str<w>(value, *dat_ptr);
+ }
+
+ std::string get_width() {
+ return itos(w);
+ }
+
+protected:
+ dat_t<w>* dat_ptr;
+};
+
+// API base (non width/depth templated) class for API accessors to mem_t
+class mem_api_base : public api_base {
+public:
+ mem_api_base(const char* new_name, const char* new_path) :
+ api_base(new_name, new_path)
+ {}
+ // return the value of an element as a string, or empty string on failure
+ virtual std::string get_element(std::string index) = 0;
+ // sets the value of an element from a string, returning true on success
+ virtual bool set_element(std::string index, std::string value) = 0;
+ // returns the bitwidth of a memory element
+ virtual std::string get_width() = 0;
+ // returns the number of memory elements
+ virtual std::string get_depth() = 0;
+};
+
+// mem_api dummy class, does nothing except for return errors
+// to be used when a real mem_api object can't be found
+class mem_dummy : public mem_api_base {
+public:
+ mem_dummy() :
+ mem_api_base("error", "")
+ {}
+ string get_element(std::string index) {
+ return "error";
+ }
+
+ bool set_element(std::string index, std::string value) {
+ return false;
+ }
+
+ std::string get_width() {
+ return "error";
+ }
+
+ std::string get_depth() {
+ return "error";
+ }
+};
+
+template<int w, int d> class mem_api : public mem_api_base {
+public:
+ mem_api(mem_t<w, d>* new_mem, const char* new_name, const char* new_path) :
+ mem_api_base(new_name, new_path),
+ mem_ptr(new_mem)
+ {}
+
+ string get_element(std::string index) {
+ int index_int = atoi(index.c_str());
+ return mem_ptr->contents[index_int].to_str();
+ }
+
+ bool set_element(std::string index, std::string value) {
+ int index_int = atoi(index.c_str());
+ return dat_from_str<w>(value, mem_ptr->contents[index_int]);
+ }
+
+ std::string get_width() {
+ return itos(w);
+ }
+
+ std::string get_depth() {
+ return itos(d);
+ }
+
+protected:
+ mem_t<w, d>* mem_ptr;
+};
+
+class mod_api_t {
+public:
+ mod_api_t():
+ teefile(NULL)
+ {}
+
+ void init(mod_t* new_module) {
+ module = new_module;
+ init_mapping_table();
+ }
+
+ void set_teefile(FILE* new_teefile) {
+ teefile = new_teefile;
+ }
+
+ mod_t* get_module() {
+ return module;
+ }
+
+ // API basic functions
+ std::string get_host_name() {return "C++ Emulator API";}
+ std::string get_api_version() {return "0";}
+ std::string get_api_support() {return "PeekPoke Introspection";}
+
+ // External access functions & helpers
+ std::vector< std::string > tokenize(std::string str) {
+ std::vector< std::string > res;
+ int i = 0;
+ int c = ' ';
+ while ( i < str.size() ) {
+ while (isspace(c)) {
+ if (i >= str.size()) return res;
+ c = str[i++];
+ }
+ std::string s;
+ while (!isspace(c) && i < str.size()) {
+ s.push_back(c);
+ c = str[i++];
+ }
+ if (i >= str.size()) s.push_back(c);
+ if (s.size() > 0)
+ res.push_back(s);
+ }
+ return res;
+ }
+
+ // helper to verify command length, returning false and printing an error
+ // to stderr if the length isn't in the specified range
+ bool check_command_length(std::vector<std::string>& tokenized_command,
+ int min_args, int max_args=-1) {
+ if (tokenized_command.size() - 1 < min_args) {
+ std::cerr << tokenized_command[0] << " expects at least " << min_args
+ << " args, got " << tokenized_command.size() - 1
+ << std::endl;
+ return false;
+ } else if (max_args >= 0 && tokenized_command.size() - 1 > max_args) {
+ std::cerr << tokenized_command[0] << " expects at most " << max_args
+ << " args, got " << tokenized_command.size() - 1
+ << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ // Evaluates an API command, returning the reply as a string (without
+ // the trailing newline).
+ // Errors return "error", printing a more detailed description to stderr.
+ // TODO: find a way to pass errors in-line, so transport layers other than
+ // stdin/stdout (like TCP/IP) are possible while also communicating errors.
+ std::string eval_command(string command) {
+ std::vector<std::string> tokens = tokenize(command);
+ if (tokens.size() == 0) {
+ std::cerr << "Empty command: '" << command << "'" << std::endl;
+ return "error";
+ }
+ if (tokens[0] == "get_host_name") {
+ // IN: get_host_name
+ // OUT: API host's name (arbitrary string)
+ if (!check_command_length(tokens, 0, 0)) { return "error"; }
+ return get_host_name();
+ } else if (tokens[0] == "get_api_version") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: get_api_version
+ // OUT: API version supported by this host
+ if (!check_command_length(tokens, 0, 0)) { return "error"; }
+ return get_api_version();
+ } else if (tokens[0] == "get_api_support") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: get_api_support
+ // OUT: list of supported API features
+ if (!check_command_length(tokens, 0, 0)) { return "error"; }
+ return get_api_support();
+ } else if (tokens[0] == "clock") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: clock <num_cycles>
+ // OUT: actual number of cycles stepped
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ int cycles = atoi(tokens[1].c_str());
+ module->propagate_changes();
+ for (int i=0; i<cycles; i++) {
+ module->clock(dat_t<1>(0));
+ }
+ return itos(cycles);
+ } else if (tokens[0] == "tick") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: tick
+ // OUT: ok (on success)
+ // Update registers without propagation
+ // updating registers.
+ module->clock_hi(dat_t<1>(0));
+ return "ok";
+ } else if (tokens[0] == "propagate") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: propagate
+ // OUT: ok (on success)
+ // This function propagates the combinational logic, without
+ // updating registers.
+ module->propagate_changes();
+ return "ok";
+ } else if (tokens[0] == "step") {
+ // IN: step <num_cycles>
+ // OUT: actual number of cycles stepped
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ int n = atoi(tokens[1].c_str());
+ module->propagate_changes();
+ int ret = module->step(false, n);
+ // Do we have print output to report?
+ int nBytes = module->has_output();
+ if (nBytes > 0) {
+ cout << "PRINT" << " " << nBytes << " " << module->drain_output();
+ }
+ return itos(ret);
+ } else if (tokens[0] == "set_clocks") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: set_clocks
+ // OUT: ???
+ // I'm not really sure what this is supposed to do, but it was
+ // in the old command API, so it's here now
+ std::vector< int > periods;
+ for (int i = 1; i < tokens.size(); i++) {
+ int period = atoi(tokens[i].c_str());
+ periods.push_back(period);
+ }
+ module->setClocks(periods);
+ return "ok";
+
+ } else if (tokens[0] == "reset") {
+ // IN: reset <num_cycles>
+ // OUT: actual number of cycles in reset
+ if (!check_command_length(tokens, 0, 1)) { return "error"; }
+ int cycles = 1;
+ if (tokens.size() >= 2) {
+ cycles = atoi(tokens[1].c_str());
+ }
+ for (int i=0; i<cycles; i++) {
+ module->clock_lo(dat_t<1>(1));
+ module->clock_hi(dat_t<1>(1));
+ }
+ module->clock_lo(dat_t<1>(0));
+ return itos(cycles);
+ } else if (tokens[0] == "peek") {
+ // LEGACY FUNCTION: do not use in new code
+ // IN: peek <node_name> | peek <mem_name> <mem_index>
+ // OUT: value
+ if (!check_command_length(tokens, 1, 2)) { return "error"; }
+ cerr << "peek is deprecated, use wire_peek or mem_peek" << std::endl;
+ module->propagate_changes();
+ if (tokens.size() == 2) {
+ return get_dat_by_name(tokens[1])->get_value();
+ } else if (tokens.size() == 3) {
+ return get_mem_by_name(tokens[1])->get_element(tokens[2]);
+ }
+ } else if (tokens[0] == "poke") {
+ // LEGACY FUNCTION: do not use in new code
+ // IN: poke <node_name> <value> | poke <mem_name> <mem_index> <value>
+ // OUT: true (on success), false (on failure)
+ if (!check_command_length(tokens, 2, 3)) { return ""; }
+ cerr << "poke is deprecated, use wire_poke or mem_poke" << std::endl;
+ bool success;
+ if (tokens.size() == 3) {
+ success = get_dat_by_name(tokens[1])->set_value(tokens[2]);
+ } else if (tokens.size() == 4) {
+ success = get_mem_by_name(tokens[1])->set_element(tokens[2], tokens[3]);
+ }
+ std::string result;
+ if (success) {
+ result = "true";
+ module->mark_stale();
+ } else {
+ result = "false";
+ }
+ return result;
+ } else if (tokens[0] == "wire_peek") {
+ // IN: wire_peek <node_name>
+ // OUT: value
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ module->propagate_changes();
+ return get_dat_by_name(tokens[1])->get_value();
+ } else if (tokens[0] == "wire_poke") {
+ // IN: wire_poke <node_name> <value>
+ // OUT: ok (on success)
+ if (!check_command_length(tokens, 2, 2)) { return "error"; }
+ bool success = get_dat_by_name(tokens[1])->set_value(tokens[2]);
+ std::string result;
+ if (success) {
+ result = "ok";
+ module->mark_stale();
+ } else {
+ result = "error";
+ }
+ return result;
+ } else if (tokens[0] == "mem_peek") {
+ // IN: mem_peek <mem_name> <mem_index>
+ // OUT: value
+ if (!check_command_length(tokens, 2, 2)) { return "error"; }
+ module->propagate_changes();
+ return get_mem_by_name(tokens[1])->get_element(tokens[2]);
+ } else if (tokens[0] == "mem_poke") {
+ // IN: mem_poke <mem_name> <mem_index> <value>
+ // OUT: ok (on success)
+ if (!check_command_length(tokens, 3, 3)) { return "error"; }
+ bool success = get_mem_by_name(tokens[1])->set_element(tokens[2], tokens[3]);
+ std::string result;
+ if (success) {
+ result = "ok";
+ module->mark_stale();
+ } else {
+ result = "error";
+ }
+ return result;
+ return success ? "ok" : "error";
+ } else if (tokens[0] == "trace") {
+ // IN: trace n <node_name>+
+ // OUT: values
+ // TODO: ADD MEM PEEK SUPPORT
+ stringstream ss;
+ if (!check_command_length(tokens, 2)) { return "bad"; }
+ int n = atoi(tokens[1].c_str());
+ for (int t = 0; t < n; t++) {
+ for (int i = 2; i < tokens.size(); i++)
+ ss << " " << get_dat_by_name(tokens[i])->get_value();
+ int ret = module->step(false, 1);
+ // if (!ret)
+ // return "error";
+ }
+ return ss.str();
+ } else if (tokens[0] == "list_wires") {
+ // IN: list_wires
+ // OUT: list of wires
+ if (!check_command_length(tokens, 0, 0)) { return "error"; }
+ std::string out = "";
+ for (std::map<const char*, dat_api_base*>::iterator it = dat_table.begin(); it != dat_table.end(); it++) {
+ out = out + it->second->get_pathname() + " ";
+ }
+ if (out.size() >= 1) {
+ return out.substr(0, out.size() - 1);
+ } else {
+ return "";
+ }
+ } else if (tokens[0] == "list_mems") {
+ // IN: list_mems
+ // OUT: list of memories
+ if (!check_command_length(tokens, 0, 0)) { return "error"; }
+ std::string out = "";
+ for (std::map<const char*, mem_api_base*>::iterator it = mem_table.begin(); it != mem_table.end(); it++) {
+ out = out + it->second->get_pathname() + " ";
+ }
+ if (out.size() >= 1) {
+ return out.substr(0, out.size() - 1);
+ } else {
+ return "";
+ }
+ } else if (tokens[0] == "wire_width") {
+ // IN: wire_width <node>
+ // OUT: bitwidth of wire
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ return get_dat_by_name(tokens[1])->get_width();
+ } else if (tokens[0] == "mem_width") {
+ // IN: mem_width <node>
+ // OUT: bitwidth of memory element
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ return get_mem_by_name(tokens[1])->get_width();
+ } else if (tokens[0] == "mem_depth") {
+ // IN: mem_depth <node>
+ // OUT: elements in memory
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ return get_mem_by_name(tokens[1])->get_depth();
+ } else if (tokens[0] == "referenced_snapshot_save") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: referenced_snapshot_save <name>
+ // OUT: Reference name (an arbitrary string) for saved snapshot
+ // of current state, should be equivalent to the input.
+ // Caution: the state may not be self-consistent (i.e. clk_lo
+ // does not need to have been applied before this, and calls to
+ // clk_lo immediately after restoring may change the state).
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ module->propagate_changes();
+ mod_t *snapshot = module->clone();
+ snapshot_table[tokens[1]] = snapshot;
+ return tokens[1];
+ } else if (tokens[0] == "referenced_snapshot_restore") {
+ // BETA FUNCTION: semantics subject to change, use with caution
+ // IN: referenced_snapshot_restore <name>
+ // OUT: ok (on success)
+ if (!check_command_length(tokens, 1, 1)) { return "error"; }
+ mod_t *snapshot = get_snapshot_by_reference(tokens[1]);
+ if (snapshot == NULL) { return "error"; }
+ bool success = module->set_circuit_from(snapshot);
+ std::string result;
+ if (success) {
+ result = "ok";
+ module->mark_stale();
+ } else {
+ result = "error";
+ }
+ return result;
+ } else {
+ std::cerr << "Unknown command: '" << tokens[0] << "'" << std::endl;
+ }
+ return "error";
+ }
+
+ void read_eval_print_loop() {
+ while (true) {
+ std::string str_in;
+ do {
+ std::getline(cin, str_in);
+ } while (cin.fail() && errno == EINTR);
+
+ if (!cin.good()) {
+ break;
+ }
+
+ if (teefile != NULL) {
+ fprintf(teefile, "%s\n", str_in.c_str());
+ fflush(teefile);
+ }
+ if (str_in == "quit") {
+ break;
+ } else {
+ cout << eval_command(str_in) << std::endl;
+ }
+ }
+ }
+
+protected:
+ FILE* teefile;
+ mod_t* module;
+
+ // Mapping table functions
+ virtual void init_mapping_table() = 0;
+
+ dat_api_base* get_dat_by_name(std::string name) {
+ if (dat_table.find(name.c_str()) != dat_table.end()) {
+ return dat_table[name.c_str()];
+ } else {
+ std::cerr << "Unable to find dat '" << name << "'" << std::endl;
+ return &this_dat_dummy;
+ }
+ }
+ mem_api_base* get_mem_by_name(std::string name) {
+ if (mem_table.find(name.c_str()) != mem_table.end()) {
+ return mem_table[name.c_str()];
+ } else {
+ std::cerr << "Unable to find mem '" << name << "'" << std::endl;
+ return &this_mem_dummy;
+ }
+ }
+
+ mod_t* get_snapshot_by_reference(std::string name) {
+ if (snapshot_table.find(name) != snapshot_table.end()) {
+ return snapshot_table[name];
+ } else {
+ std::cerr << "Unable to find snapshot reference '" << name << "'" << std::endl;
+ return NULL;
+ }
+ }
+
+ class string_comparator {
+ public:
+ bool operator()(const char* x, const char* y) const {
+ return strcmp(x, y) < 0;
+ }
+ };
+
+ std::map<const char*, dat_api_base*, string_comparator> dat_table;
+ std::map<const char*, mem_api_base*, string_comparator> mem_table;
+ // TODO: replace the dummy with explicit NULL checks - this is simple
+ // but a bit inelegant
+ dat_dummy this_dat_dummy;
+ mem_dummy this_mem_dummy;
+
+ // Snapshot functions
+ std::map<std::string, mod_t*> snapshot_table;
+};
+
+#pragma GCC diagnostic pop
+
+#endif
diff --git a/src/main/resources/emulator_mod.h b/src/main/resources/emulator_mod.h
new file mode 100644
index 00000000..0d4929d3
--- /dev/null
+++ b/src/main/resources/emulator_mod.h
@@ -0,0 +1,1800 @@
+// Header for Chisel emulator module
+// defines the mod_t class as well as bit operation functions
+
+#ifndef __IS_EMULATOR_MOD__
+#define __IS_EMULATOR_MOD__
+
+#pragma GCC diagnostic push
+#ifdef __clang__
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#else
+#pragma GCC diagnostic ignored "-Wpragmas"
+#endif // __clang__
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wparentheses"
+#pragma GCC diagnostic ignored "-Wreturn-type"
+#pragma GCC diagnostic ignored "-Wchar-subscripts"
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wreorder"
+#pragma GCC diagnostic ignored "-Wsometimes-uninitialized"
+#pragma GCC diagnostic ignored "-pedantic"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <limits.h>
+#include <math.h>
+#include <vector>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+#include <map>
+#include <stdlib.h>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <stdexcept>
+
+using namespace std;
+
+typedef uint64_t val_t;
+typedef int64_t sval_t;
+typedef uint32_t half_val_t;
+#if defined(__GNUC__) && defined(__SIZEOF_INT128__)
+#define __HAVE_DUB_VAL_T__
+typedef unsigned __int128 dub_val_t;
+#endif
+
+union flo2int_t {
+ float f;
+ val_t i;
+};
+
+inline float toFloat (val_t x) {
+ flo2int_t f2i;
+ f2i.i = x;
+ return f2i.f;
+}
+
+inline val_t fromFloat (float x) {
+ flo2int_t f2i;
+ f2i.f = x;
+ return f2i.i;
+}
+
+union dbl2int_t {
+ double f;
+ val_t i;
+};
+
+inline double toDouble (val_t x) {
+ dbl2int_t f2i;
+ f2i.i = x;
+ return f2i.f;
+}
+
+inline val_t fromDouble (double x) {
+ dbl2int_t f2i;
+ f2i.f = x;
+ return f2i.i;
+}
+
+#define TERNARY(c, t, f) ((f) ^ (((f) ^ (t)) & -(c)))
+
+#if defined(__GNUC__) && defined(__x86_64__)
+#define TERNARY_1(c, t, f) ({ \
+ val_t __res; \
+ if (!__builtin_constant_p(c)) { \
+ __res = (f); \
+ val_t __t = (t); \
+ uint8_t __c = (c); \
+ asm ("testb $1, %1; cmovne %2, %0" : "+r"(__res) : "rm"(__c), "rm"(__t) : "cc"); \
+ } else __res = TERNARY(c, t, f); \
+ __res; })
+#else
+#define TERNARY_1(c, t, f) TERNARY(c, t, f)
+#endif
+
+#define MASK(v, c) ((v) & -(val_t)(c))
+#ifndef MIN
+#define MIN(a, b) TERNARY((a) < (b), (a), (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) TERNARY((a) > (b), (a), (b))
+#endif
+#define CLAMP(a, min, max) MAX(MIN(a, max), min)
+
+template<uint32_t x, uint32_t shifted=0, bool sticky=false> struct CeilLog {
+ static uint32_t const v = CeilLog<(x >> 1), shifted + 1, sticky | (x & 1)>::v;
+};
+
+template<uint32_t shifted, bool sticky> struct CeilLog<0, shifted, sticky> {
+ static uint32_t const v = -1;
+};
+
+template<uint32_t shifted, bool sticky> struct CeilLog<1, shifted, sticky> {
+ static uint32_t const v = sticky ? shifted + 1 : shifted;
+};
+
+#define val_n_bits() (sizeof(val_t)*8)
+#define val_n_half_bits() (val_n_bits()/2)
+#define val_all_ones() val_all_ones_or_zeroes(1)
+#define val_all_ones_or_zeroes(bit) (val_t(0) - val_t(bit))
+#define val_n_words(n_bits) (1+((n_bits)-1)/val_n_bits())
+#define val_n_half_words(n_bits) (1+((n_bits)-1)/val_n_half_bits())
+#define val_top_bit(v) (val_t(v) >> (val_n_bits()-1))
+#define val_n_full_words(n_bits) ((n_bits)/val_n_bits())
+#define val_n_word_bits(n_bits) ((n_bits) % val_n_bits())
+inline val_t val_n_nibs( void ) { return val_n_bits()>>2; }
+inline val_t val_half_mask( void ) { return (((val_t)1)<<(val_n_half_bits()))-1; }
+inline val_t val_lo_half( val_t n_bits ) { return n_bits & val_half_mask(); }
+inline val_t val_hi_half( val_t n_bits ) { return n_bits >> val_n_half_bits(); }
+inline val_t val_n_rem_word_bits( val_t n_bits ) { return val_n_bits() - val_n_word_bits(n_bits); }
+//inline val_t dub_val_lo_half( dub_val_t bits ) { return (val_t)bits; }
+//inline val_t dub_val_hi_half( dub_val_t bits ) { return (val_t)(bits >> val_n_bits()); }
+
+
+inline void val_to_half_vals ( val_t *fvals, half_val_t *hvals, int nf ) {
+ for (int i = 0; i < nf; i++) {
+ hvals[i*2] = val_lo_half(fvals[i]);
+ hvals[i*2+1] = val_hi_half(fvals[i]);
+ }
+}
+inline void half_val_to_vals ( half_val_t *hvals, val_t *vals, int nf ) {
+ for (int i = 0; i < nf; i++)
+ vals[i] = ((val_t)hvals[i*2+1] << val_n_half_bits()) | hvals[i*2];
+}
+
+template <int w> class dat_t;
+template <int w> class datz_t;
+
+template <int w> int datz_eq(dat_t<w> d1, datz_t<w> d2);
+
+template <int w> inline dat_t<w> DAT(val_t value) {
+ dat_t<w> res(value);
+ return res; }
+
+template <int w> inline dat_t<w> DAT(val_t val1, val_t val0) {
+ dat_t<w> res; res.values[0] = val0; res.values[1] = val1; return res;
+}
+
+const static char hex_digs[] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+static void add_n (val_t d[], val_t s0[], val_t s1[], int nw, int nb) {
+ val_t carry = 0;
+ for (int i = 0; i < nw; i++) {
+ d[i] = s0[i] + s1[i] + carry;
+ carry = ((s0[i] + s1[i]) < s0[i]) || (d[i] < carry);
+ }
+}
+
+static void neg_n (val_t d[], val_t s0[], int nw, int nb) {
+ val_t borrow = 0;
+ for (int i = 0; i < nw; i++) {
+ d[i] = -s0[i] - borrow;
+ borrow = s0[i] || d[i];
+ }
+}
+
+static void sub_n (val_t d[], val_t s0[], val_t s1[], int nw, int nb) {
+ val_t borrow = 0;
+ for (int i = 0; i < nw; i++) {
+ d[i] = s0[i] - s1[i] - borrow;
+ borrow = (s0[i] < (s0[i] - s1[i])) || (s0[i] - s1[i]) < d[i];
+ }
+}
+
+static void mul_n (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
+// Adapted from Hacker's Delight, from Knuth
+#if BYTE_ORDER != LITTLE_ENDIAN
+# error mul_n assumes a little-endian architecture
+#endif
+ int nbd = nb0 + nb1;
+ for (int i = 0; i < val_n_words(nbd); i++)
+ d[i] = 0;
+
+ half_val_t* w = reinterpret_cast<half_val_t*>(d);
+ half_val_t* u = reinterpret_cast<half_val_t*>(s0);
+ half_val_t* v = reinterpret_cast<half_val_t*>(s1);
+ int m = val_n_half_words(nb0), n = val_n_half_words(nb1), p = val_n_half_words(nbd);
+
+ for (int j = 0; j < n; j++) {
+ val_t k = 0;
+ for (int i = 0; i < MIN(m, p-j); i++) {
+ val_t t = (val_t)u[i]*v[j] + w[i+j] + k;
+ w[i+j] = t;
+ k = t >> val_n_half_bits();
+ }
+ if (j+m < p)
+ w[j+m] = k;
+ }
+}
+
+static void rsha_n (val_t d[], val_t s0[], int amount, int nw, int w) {
+
+ int n_shift_bits = amount % val_n_bits();
+ int n_shift_words = amount / val_n_bits();
+ int n_rev_shift_bits = val_n_bits() - n_shift_bits;
+ int is_zero_carry = n_shift_bits == 0;
+ int msb = s0[nw-1] >> (w - nw*val_n_bits() - 1);
+ val_t carry = 0;
+
+ if (msb == 0)
+ for (int i = 0; i < n_shift_words; i++) {
+ d[nw-i-1] = 0;
+ }
+
+ for (int i = nw-1; i >= n_shift_words; i--) {
+ val_t val = s0[i];
+ d[i-n_shift_words] = val >> n_shift_bits | carry;
+ carry = is_zero_carry ? 0 : val << n_rev_shift_bits;
+ }
+
+ if (msb == 0) {
+ return;
+ }
+
+ int boundary = (w - amount);
+
+ for (int i = nw-1; i >= 0; i--) {
+ int idx = i*val_n_bits();
+ if (idx > boundary) {
+ d[i] = val_all_ones();
+ } else {
+ d[i] = d[i] | (val_all_ones() << (boundary - idx));
+ d[nw-1] = d[nw-1] & (val_all_ones() >> ((nw-1)*val_n_bits() - w));
+ return;
+ }
+ }
+}
+
+static void rsh_n (val_t d[], val_t s0[], int amount, int nw) {
+ val_t carry = 0;
+ int n_shift_bits = amount % val_n_bits();
+ int n_shift_words = amount / val_n_bits();
+ int n_rev_shift_bits = val_n_bits() - n_shift_bits;
+ int is_zero_carry = n_shift_bits == 0;
+ for (int i = 0; i < n_shift_words; i++)
+ d[nw-i-1] = 0;
+ for (int i = nw-1; i >= n_shift_words; i--) {
+ val_t val = s0[i];
+ d[i-n_shift_words] = val >> n_shift_bits | carry;
+ carry = is_zero_carry ? 0 : val << n_rev_shift_bits;
+ }
+}
+
+static void lsh_n (val_t d[], val_t s0[], int amount, int nwd, int nws) {
+ val_t carry = 0;
+ int n_shift_bits = amount % val_n_bits();
+ int n_shift_words = amount / val_n_bits();
+ int n_rev_shift_bits = val_n_bits() - n_shift_bits;
+ int is_zero_carry = n_shift_bits == 0;
+ for (int i = 0; i < nwd; i++)
+ d[i] = 0;
+ for (int i = 0; i < (nws-n_shift_words); i++) {
+ val_t val = s0[i];
+ d[i+n_shift_words] = val << n_shift_bits | carry;
+ carry = is_zero_carry ? 0 : val >> n_rev_shift_bits;
+ }
+}
+
+static inline val_t mask_val(int n) {
+ val_t res = val_all_ones() >> (val_n_bits()-n);
+ return res;
+}
+
+static inline void mask_n (val_t d[], int nw, int nb) {
+ int n_full_words = val_n_full_words(nb);
+ int n_word_bits = val_n_word_bits(nb);
+ for (int i = 0; i < n_full_words; i++)
+ d[i] = val_all_ones();
+ for (int i = n_full_words; i < nw; i++)
+ d[i] = 0;
+ if (n_word_bits > 0)
+ d[n_full_words] = mask_val(n_word_bits);
+}
+
+static inline val_t log2_1 (val_t v) {
+#ifdef __GNUC__
+ return TERNARY(v != 0, val_n_bits() - 1 - __builtin_clzll(v), 0);
+#else
+ val_t r;
+ val_t shift;
+ r = (v > 0xFFFFFFFF) << 5; v >>= r;
+ shift = (v > 0xFFFF ) << 4; v >>= shift; r |= shift;
+ shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
+ shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
+ shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
+ r |= (v >> 1);
+ return r;
+#endif
+}
+
+static inline val_t reverse_1 (val_t v) {
+ v = ((v >> 1) & 0x5555555555555555) | ((v & 0x5555555555555555) << 1);
+ v = ((v >> 2) & 0x3333333333333333) | ((v & 0x3333333333333333) << 2);
+ v = ((v >> 4) & 0x0F0F0F0F0F0F0F0F) | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
+ v = ((v >> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8);
+ v = ((v >> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16);
+ v = ( v >> 32 ) | ( v << 32);
+ return v;
+}
+
+static inline val_t priority_encode_1 (val_t v) {
+#ifdef __GNUC__
+ return TERNARY(v != 0, __builtin_ctzll(v), 0);
+#else
+ if (v == 0)
+ return 0;
+ val_t r;
+ val_t shift;
+ r = !(v & 0xFFFFFFFF) << 5; v >>= r;
+ shift = !(v & 0xFFFF ) << 4; v >>= shift; r |= shift;
+ shift = !(v & 0xFF ) << 3; v >>= shift; r |= shift;
+ shift = !(v & 0xF ) << 2; v >>= shift; r |= shift;
+ shift = !(v & 0x3 ) << 1; v >>= shift; r |= shift;
+ shift = !(v & 0x1 ) << 0; v >>= shift; r |= shift;
+ return r;
+#endif
+}
+
+#define ispow2(x) (((x) & ((x)-1)) == 0)
+static inline val_t nextpow2_1(val_t x) {
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+ x++;
+ return x;
+}
+
+/*
+#define __FLOAT_WORD_ORDER LITTLE_ENDIAN
+
+static inline uint32_t log2_1_32 (uint32_t v) {
+ union { uint32_t u[2]; double d; } t; // temp
+
+ t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000;
+ t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v;
+ t.d -= 4503599627370496.0;
+ return (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF;
+}
+
+static inline val_t log2_1 (val_t v) {
+ uint32_t r_lo = (uint32_t)v;
+ uint32_t r_hi = (uint32_t)(v >> 32);
+ return (((val_t)log2_1_32(r_hi)) << 32)|((val_t)log2_1_32(r_lo));
+}
+*/
+
+/*
+static inline val_t log2_1 (val_t v) {
+ v |= (v >> 1);
+ v |= (v >> 2);
+ v |= (v >> 4);
+ v |= (v >> 8);
+ v |= (v >> 16);
+ v |= (v >> 32);
+ return ones64(v) - 1;
+}
+*/
+
+/*
+static inline val_t log2_1 (val_t v) {
+ val_t res = 0;
+ while (v >>= 1)
+ res++;
+ return res;
+}
+*/
+
+static inline val_t log2_n (val_t s0[], int nw) {
+ val_t off = (nw-1)*val_n_bits();
+ for (int i = nw-1; i >= 0; i--) {
+ val_t s0i = s0[i];
+ if (s0i > 0) {
+ val_t res = log2_1(s0i);
+ return res + off;
+ }
+ off -= val_n_bits();
+ }
+ return 0;
+}
+
+template <int nw>
+struct bit_word_funs {
+ static void fill (val_t d[], val_t s0) {
+ for (int i = 0; i < nw; i++)
+ d[i] = s0;
+ }
+ static void fill_nb (val_t d[], val_t s0, int nb) {
+ mask_n(d, nw, nb);
+ for (int i = 0; i < nw; i++)
+ d[i] = d[i] & s0;
+ // printf("FILL-NB N\n");
+ }
+ static void copy (val_t d[], val_t s0[], int sww) {
+ if (sww > nw) {
+ for (int i = 0; i < nw; i++) {
+ // printf("A I %d\n", i); fflush(stdout);
+ d[i] = s0[i];
+ }
+ } else {
+ for (int i = 0; i < sww; i++) {
+ // printf("B I %d\n", i); fflush(stdout);
+ d[i] = s0[i];
+ }
+ for (int i = sww; i < nw; i++) {
+ // printf("C I %d\n", i); fflush(stdout);
+ d[i] = 0;
+ }
+ }
+ }
+ static void mask (val_t d[], int nb) {
+ mask_n(d, nw, nb);
+ }
+ static void add (val_t d[], val_t s0[], val_t s1[], int nb) {
+ add_n(d, s0, s1, nw, nb);
+ }
+ static void neg (val_t d[], val_t s0[], int nb) {
+ neg_n(d, s0, nw, nb);
+ }
+ static void sub (val_t d[], val_t s0[], val_t s1[], int nb) {
+ sub_n(d, s0, s1, nw, nb);
+ }
+ static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
+ mul_n(d, s0, s1, nb0, nb1);
+ }
+ static void bit_xor (val_t d[], val_t s0[], val_t s1[]) {
+ for (int i = 0; i < nw; i++)
+ d[i] = s0[i] ^ s1[i];
+ }
+ static void bit_and (val_t d[], val_t s0[], val_t s1[]) {
+ for (int i = 0; i < nw; i++)
+ d[i] = s0[i] & s1[i];
+ }
+ static void bit_or (val_t d[], val_t s0[], val_t s1[]) {
+ for (int i = 0; i < nw; i++)
+ d[i] = s0[i] | s1[i];
+ }
+ static void bit_neg (val_t d[], val_t s0[], int nb) {
+ val_t msk[nw];
+ mask_n(msk, nw, nb);
+ for (int i = 0; i < nw; i++)
+ d[i] = ~s0[i] & msk[i];
+ }
+ static bool ltu (val_t s0[], val_t s1[]) {
+ val_t diff[nw];
+ sub(diff, s0, s1, nw*val_n_bits());
+ return val_top_bit(diff[nw-1]);
+ }
+ static bool lt (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1;
+ if (msb_0 != msb_1) {
+ return msb_0;
+ } else {
+ val_t diff[nw];
+ sub(diff, s0, s1, nw*val_n_bits());
+ return val_top_bit(diff[nw-1]);
+ }
+ }
+ static bool lteu (val_t s0[], val_t s1[]) {
+ val_t diff[nw];
+ sub(diff, s1, s0, nw*val_n_bits());
+ return !val_top_bit(diff[nw-1]);
+ }
+ static bool lte (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1;
+ if (msb_0 != msb_1) {
+ return msb_0;
+ } else {
+ val_t diff[nw];
+ sub(diff, s1, s0, nw*val_n_bits());
+ return !val_top_bit(diff[nw-1]);
+ }
+ }
+ static bool eq (val_t s0[], val_t s1[]) {
+ for (int i = 0; i < nw; i++)
+ if (s0[i] != s1[i])
+ return false;
+ return true;
+ }
+ static bool neq (val_t s0[], val_t s1[]) {
+ return !eq(s0, s1);
+ }
+ static void rsha (val_t d[], val_t s0[], int amount, int w) {
+ rsha_n(d, s0, amount, nw, w);
+ }
+ static void rsh (val_t d[], val_t s0[], int amount) {
+ rsh_n(d, s0, amount, nw);
+ }
+ static void lsh (val_t d[], val_t s0[], int amount) {
+ lsh_n(d, s0, amount, nw, nw);
+ }
+ static void extract (val_t d[], val_t s0[], int e, int s, int nb) {
+ // TODO: FINISH THIS
+ const int bw = e-s+1;
+ val_t msk[nw];
+ mask_n(msk, nw, nb);
+ if (s == 0) {
+ // printf("EXT E %d S %d NW %d NB %d: ", e, s, nw, nb);
+ for (int i = 0; i < nw; i++) {
+ d[i] = s0[i] & msk[i];
+ // printf("%d:%llx ", i, d[i]);
+ }
+ } else {
+ rsh_n(d, s0, s, nw);
+ // printf("EXT E %d S %d NW %d NB %d: ", e, s, nw, nb);
+ for (int i = 0; i < nw; i++) {
+ // printf("I%d:R%llx:M%llx:", i, d[i], msk[i]);
+ d[i] = d[i] & msk[i];
+ // printf("D%llx ", d[i]);
+ }
+ }
+ // printf("\n");
+ }
+
+ static void inject (val_t d[], val_t s0[], int e, int s) {
+ // Opposite of extract: Assign s0 to a subfield of d.
+ const int bw = e-s+1;
+ val_t msk[nw];
+ val_t msk_lsh[nw];
+ val_t s0_lsh[nw];
+ mask_n(msk, nw, bw);
+ lsh_n(msk_lsh, msk, s, nw, nw);
+ lsh_n(s0_lsh, s0, s, nw, nw);
+ for (int i = 0; i < nw; i++) {
+ d[i] = (d[i] & ~msk_lsh[i]) | (s0_lsh[i] & msk_lsh[i]);
+ }
+ }
+
+ static void set (val_t d[], val_t s0[]) {
+ for (int i = 0; i < nw; i++)
+ d[i] = s0[i];
+ }
+ static void log2 (val_t d[], val_t s0[]) {
+ d[0] = log2_n(s0, nw);
+ }
+};
+
+template <>
+struct bit_word_funs<1> {
+ static void fill (val_t d[], val_t s0) {
+ d[0] = s0;
+ }
+ static void fill_nb (val_t d[], val_t s0, int nb) {
+ d[0] = mask_val(nb) & s0;
+ }
+ static void copy (val_t d[], val_t s0[], int sww) {
+ d[0] = s0[0];
+ }
+ static void mask (val_t d[], int nb) {
+ d[0] = mask_val(nb);
+ }
+ static void add (val_t d[], val_t s0[], val_t s1[], int nb) {
+ d[0] = (s0[0] + s1[0]) & mask_val(nb);
+ }
+ static void sub (val_t d[], val_t s0[], val_t s1[], int nb) {
+ d[0] = (s0[0] - s1[0]) & mask_val(nb);
+ }
+ static void neg (val_t d[], val_t s0[], int nb) {
+ d[0] = (- s0[0]) & mask_val(nb);
+ }
+ static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
+ d[0] = s0[0] * s1[0];
+ }
+ static bool ltu (val_t s0[], val_t s1[]) {
+ return (s0[0] < s1[0]);
+ }
+ static bool lt (val_t s0[], val_t s1[], int w) {
+ sval_t a = s0[0] << (val_n_bits() - w);
+ sval_t b = s1[0] << (val_n_bits() - w);
+ return (a < b);
+ }
+ static bool lteu (val_t s0[], val_t s1[]) {
+ return (s0[0] <= s1[0]);
+ }
+ static bool lte (val_t s0[], val_t s1[], int w) {
+ sval_t a = s0[0] << (val_n_bits() - w);
+ sval_t b = s1[0] << (val_n_bits() - w);
+ return (a <= b);
+ }
+ static void bit_neg (val_t d[], val_t s0[], int nb) {
+ d[0] = ~s0[0] & mask_val(nb);
+ }
+ static void bit_xor (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] ^ s1[0]);
+ }
+ static void bit_and (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] & s1[0]);
+ }
+ static void bit_or (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] | s1[0]);
+ }
+ static bool eq (val_t s0[], val_t s1[]) {
+ return s0[0] == s1[0];
+ }
+ static bool neq (val_t s0[], val_t s1[]) {
+ return s0[0] != s1[0];
+ }
+ static void lsh (val_t d[], val_t s0[], int amount) {
+ d[0] = (s0[0] << amount);
+ }
+ static void rsh (val_t d[], val_t s0[], int amount) {
+ d[0] = (s0[0] >> amount);
+ }
+ static void rsha (val_t d[], val_t s0[], int amount, int w) {
+ d[0] = s0[0] << (val_n_bits() - w);
+ d[0] = (sval_t(d[0]) >> (val_n_bits() - w + amount)) & mask_val(w);
+ }
+ static void extract (val_t d[], val_t s0[], int e, int s, int nb) {
+ const int bw = e-s+1;
+ d[0] = (s0[0] >> s) & mask_val(bw);
+ }
+
+ static void inject (val_t d[], val_t s0[], int e, int s) {
+ // Opposite of extract: Assign s0 to a subfield of d.
+ const int bw = e-s+1;
+ val_t msk = mask_val(bw);
+ d[0] = ((s0[0] & msk) << s) | (d[0] & ~(msk << s));
+ }
+
+ static void set (val_t d[], val_t s0[]) {
+ d[0] = s0[0];
+ }
+ static void log2 (val_t d[], val_t s0[]) {
+ d[0] = log2_1(s0[0]);
+ }
+};
+
+template <>
+struct bit_word_funs<2> {
+ static void fill (val_t d[], val_t s0) {
+ d[0] = s0;
+ d[1] = s0;
+ }
+ static void fill_nb (val_t d[], val_t s0, int nb) {
+ d[0] = s0;
+ d[1] = mask_val(nb - val_n_bits()) & s0;
+ }
+ static void copy (val_t d[], val_t s0[], int sww) {
+ d[0] = s0[0];
+ d[1] = sww > 1 ? s0[1] : 0;
+ }
+ static void mask (val_t d[], int nb) {
+ d[0] = val_all_ones();
+ d[1] = mask_val(nb - val_n_bits());
+ }
+ static void add (val_t d[], val_t x[], val_t y[], int nb) {
+ val_t x0 = x[0];
+ val_t sum0 = x0 + y[0];
+ val_t carry0 = (sum0 < x0);
+ d[0] = sum0;
+ val_t sum1 = x[1] + y[1] + carry0;
+ d[1] = sum1;
+ }
+ static void sub (val_t d[], val_t s0[], val_t s1[], int nb) {
+ val_t d0 = s0[0] - s1[0];
+ d[1] = s0[1] - s1[1] - (s0[0] < d0);
+ d[0] = d0;
+ }
+ static void neg (val_t d[], val_t s0[], int nb) {
+ val_t d0 = -s0[0];
+ d[1] = -s0[1] - (s0[0] != 0);
+ d[0] = d0;
+ }
+ static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
+#ifdef __HAVE_DUB_VAL_T__
+ dub_val_t a = s0[0], b = s1[0];
+ if (nb0 > val_n_bits()) a |= dub_val_t(s0[1]) << val_n_bits();
+ if (nb1 > val_n_bits()) b |= dub_val_t(s1[1]) << val_n_bits();
+ dub_val_t res = a * b;
+ d[0] = res;
+ d[1] = res >> val_n_bits();
+#else
+ mul_n(d, s0, s1, nb0, nb1);
+#endif
+ }
+ static bool ltu (val_t s0[], val_t s1[]) {
+ return ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] < s1[0]));
+ }
+ static bool lt (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - val_n_bits() - 1)) & 0x1;
+ int cond = msb_0 ^ msb_1;
+ return (cond && msb_0)
+ || (!cond && ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] < s1[0])));
+ }
+ static bool lteu (val_t s0[], val_t s1[]) {
+ return ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] <= s1[0]));
+ }
+ static bool lte (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - val_n_bits() - 1)) & 0x1;
+ int cond = msb_0 ^ msb_1;
+ return (cond && msb_0)
+ || (!cond && ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] <= s1[0])));
+ }
+ static void bit_xor (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] ^ s1[0]);
+ d[1] = (s0[1] ^ s1[1]);
+ }
+ static void bit_and (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] & s1[0]);
+ d[1] = (s0[1] & s1[1]);
+ }
+ static void bit_or (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] | s1[0]);
+ d[1] = (s0[1] | s1[1]);
+ }
+ static void bit_neg (val_t d[], val_t s0[], int nb) {
+ d[0] = ~s0[0];
+ d[1] = ~s0[1] & mask_val(nb - val_n_bits());
+ }
+ static bool eq (val_t s0[], val_t s1[]) {
+ return (s0[0] == s1[0]) & (s0[1] == s1[1]);
+ }
+ static bool neq (val_t s0[], val_t s1[]) {
+ return (s0[0] != s1[0]) | (s0[1] != s1[1]);
+ }
+ static void extract (val_t d[], val_t s0[], int e, int s, int nb) {
+ val_t msk[2];
+ const int bw = e-s+1;
+ mask_n(msk, 2, bw);
+ if (s == 0) {
+ d[0] = s0[0] & msk[0];
+ d[1] = s0[1] & msk[1];
+ } else {
+ rsh(d, s0, s);
+ d[0] = d[0] & msk[0];
+ d[1] = d[1] & msk[1];
+ }
+ }
+
+ static void inject (val_t d[], val_t s0[], int e, int s) {
+ // Opposite of extract: Assign s0 to a subfield of d.
+ const int bw = e-s+1;
+ val_t msk[2];
+ val_t msk_lsh[2];
+ val_t s0_lsh[2];
+ mask_n(msk, 2, bw);
+ lsh_n(msk_lsh, msk, s, 2, 2);
+ lsh_n(s0_lsh, s0, s, 2, 2);
+ d[0] = (d[0] & ~msk_lsh[0]) | (s0_lsh[0] & msk_lsh[0]);
+ d[1] = (d[1] & ~msk_lsh[1]) | (s0_lsh[1] & msk_lsh[1]);
+ }
+
+ static void rsha (val_t d[], val_t s0[], int amount, int w) {
+ sval_t hi = s0[1] << (2*val_n_bits() - w);
+ if (amount >= val_n_bits()) {
+ d[0] = hi >> (amount - w + val_n_bits());
+ d[1] = hi >> (val_n_bits() - 1);
+ d[1] = d[1] >> (2*val_n_bits() - w);
+ } else if (amount == 0) {
+ d[0] = s0[0];
+ d[1] = s0[1];
+ } else {
+ int s = 2*val_n_bits() - w + amount;
+ d[0] = s0[0] >> amount;
+ d[0] = d[0] | ((hi >> (2*val_n_bits() - w)) << (val_n_bits() - amount));
+ d[1] = hi >> (s >= val_n_bits() ? val_n_bits()-1 : s);
+ d[1] = d[1] & mask_val(w - val_n_bits());
+ }
+ }
+ static void rsh (val_t d[], val_t s0[], int amount) {
+ if (amount >= val_n_bits()) {
+ d[1] = 0;
+ d[0] = s0[1] >> (amount - val_n_bits());
+ } else if (amount == 0) {
+ d[0] = s0[0];
+ d[1] = s0[1];
+ } else {
+ d[1] = s0[1] >> amount;
+ d[0] = (s0[1] << (val_n_bits() - amount)) | (s0[0] >> amount);
+ }
+ }
+ static void lsh (val_t d[], val_t s0[], int amount) {
+ if (amount == 0)
+ {
+ d[1] = s0[1];
+ d[0] = s0[0];
+ } else if (amount >= val_n_bits()) {
+ d[1] = s0[0] << (amount - val_n_bits());
+ d[0] = 0;
+ } else {
+ d[1] = (s0[1] << amount) | (s0[0] >> (val_n_bits() - amount));
+ d[0] = (s0[0] << amount);
+ }
+ }
+ static void set (val_t d[], val_t s0[]) {
+ d[0] = s0[0];
+ d[1] = s0[1];
+ }
+ static void log2 (val_t d[], val_t s0[]) {
+ val_t s01 = s0[1];
+ if (s01 > 0)
+ d[0] = log2_1(s01) + val_n_bits();
+ else
+ d[0] = log2_1(s0[0]);
+ // d[0] = log2_n(s0, 2);
+ }
+};
+template <>
+struct bit_word_funs<3> {
+ static void fill (val_t d[], val_t s0) {
+ d[0] = s0;
+ d[1] = s0;
+ d[2] = s0;
+ }
+ static void fill_nb (val_t d[], val_t s0, int nb) {
+ d[0] = s0;
+ d[1] = s0;
+ d[2] = mask_val(nb - 2*val_n_bits()) & s0;
+ }
+ static void copy (val_t d[], val_t s0[], int sww) {
+ d[0] = s0[0];
+ d[1] = sww > 1 ? s0[1] : 0;
+ d[2] = sww > 2 ? s0[2] : 0;
+ }
+ static void mask (val_t d[], int nb) {
+ d[0] = val_all_ones();
+ d[1] = val_all_ones();
+ d[2] = mask_val(nb - 2*val_n_bits());
+ }
+ static void add (val_t d[], val_t s0[], val_t s1[], int nb) {
+ add_n(d, s0, s1, 3, nb);
+ }
+ static void sub (val_t d[], val_t s0[], val_t s1[], int nb) {
+ sub_n(d, s0, s1, 3, nb);
+ }
+ static void neg (val_t d[], val_t s0[], int nb) {
+ neg_n(d, s0, 3, nb);
+ }
+ static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
+ mul_n(d, s0, s1, nb0, nb1);
+ }
+ static bool ltu (val_t s0[], val_t s1[]) {
+ return ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] < s1[0])))));
+ }
+ static bool lt (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - 2*val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - 2*val_n_bits() - 1)) & 0x1;
+ int cond = msb_0 ^ msb_1;
+ return (cond && msb_0)
+ || (!cond && (((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] < s1[0])))))));
+ }
+ static bool lteu (val_t s0[], val_t s1[]) {
+ return ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] <= s1[0])))));
+ }
+ static bool lte (val_t s0[], val_t s1[], int w) {
+ int msb_0 = (s0[1] >> (w - 2*val_n_bits() - 1)) & 0x1;
+ int msb_1 = (s1[1] >> (w - 2*val_n_bits() - 1)) & 0x1;
+ int cond = msb_0 ^ msb_1;
+ return (cond && msb_0)
+ || (!cond && ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] <= s1[0]))))));
+ }
+ static void bit_xor (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] ^ s1[0]);
+ d[1] = (s0[1] ^ s1[1]);
+ d[2] = (s0[2] ^ s1[2]);
+ }
+ static void bit_and (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] & s1[0]);
+ d[1] = (s0[1] & s1[1]);
+ d[2] = (s0[2] & s1[2]);
+ }
+ static void bit_or (val_t d[], val_t s0[], val_t s1[]) {
+ d[0] = (s0[0] | s1[0]);
+ d[1] = (s0[1] | s1[1]);
+ d[2] = (s0[2] | s1[2]);
+ }
+ static void bit_neg (val_t d[], val_t s0[], int nb) {
+ d[0] = ~s0[0];
+ d[1] = ~s0[1];
+ d[2] = ~s0[2] & mask_val(nb - 2*val_n_bits());
+ }
+ static bool eq (val_t s0[], val_t s1[]) {
+ return (s0[0] == s1[0]) & (s0[1] == s1[1]) & (s0[2] == s1[2]);
+ }
+ static bool neq (val_t s0[], val_t s1[]) {
+ return (s0[0] != s1[0]) | (s0[1] != s1[1]) | (s0[2] != s1[2]);
+ }
+ static void extract (val_t d[], val_t s0[], int e, int s, int nb) {
+ val_t msk[3];
+ const int bw = e-s+1;
+ mask_n(msk, 3, bw);
+ if (s == 0) {
+ d[0] = s0[0] & msk[0];
+ d[1] = s0[1] & msk[1];
+ d[2] = s0[2] & msk[2];
+ } else {
+ rsh(d, s0, s);
+ d[0] = d[0] & msk[0];
+ d[1] = d[1] & msk[1];
+ d[2] = d[2] & msk[2];
+ }
+ }
+
+ static void inject (val_t d[], val_t s0[], int e, int s) {
+ const int bw = e-s+1;
+ val_t msk[3];
+ val_t msk_lsh[3];
+ val_t s0_lsh[3];
+ mask_n(msk, 3, bw);
+ lsh_n(msk_lsh, msk, s, 3, 3);
+ lsh_n(s0_lsh, s0, s, 3, 3);
+ d[0] = (d[0] & ~msk_lsh[0]) | (s0_lsh[0] & msk_lsh[0]);
+ d[1] = (d[1] & ~msk_lsh[1]) | (s0_lsh[1] & msk_lsh[1]);
+ d[2] = (d[2] & ~msk_lsh[2]) | (s0_lsh[2] & msk_lsh[2]);
+ }
+
+ static void rsha (val_t d[], val_t s0[], int amount, int w) {
+ rsha_n(d, s0, amount, 3, w);
+ }
+ static void rsh (val_t d[], val_t s0[], int amount) {
+ rsh_n(d, s0, amount, 3);
+ }
+ static void lsh (val_t d[], val_t s0[], int amount) {
+ lsh_n(d, s0, amount, 3, 3);
+ }
+ static void log2 (val_t d[], val_t s0[]) {
+ d[0] = log2_n(s0, 3);
+ }
+ static void set (val_t d[], val_t s0[]) {
+ d[0] = s0[0];
+ d[1] = s0[1];
+ d[2] = s0[2];
+ }
+};
+
+static val_t __rand_val(val_t* seed) {
+ val_t x = *seed;
+ *seed = (x << 1) ^ (-(sval_t(x) < 0) & 0x1B);
+ return x;
+}
+
+template <int w>
+class dat_t {
+ public:
+ const static int n_words = ((w - 1) / 64) + 1;
+ // const static int n_words = (w >> CeilLog<sizeof(val_t)*8>::v) + 1;
+ val_t values[n_words];
+ inline int width ( void ) { return w; }
+ inline int n_words_of ( void ) { return n_words; }
+ inline bool to_bool ( void ) { return lo_word() != 0; }
+ inline val_t lo_word ( void ) { return values[0]; }
+ inline unsigned long to_ulong ( void ) { return (unsigned long)lo_word(); }
+
+ std::string to_str () {
+ std::string rres, res;
+ int nn = (int)ceilf(w / 4.0);
+ for (int i = 0; i < n_words; i++) {
+ int n_nibs = nn < val_n_nibs() ? nn : val_n_nibs();
+ for (int j = 0; j < n_nibs; j++) {
+ uint8_t nib = (values[i] >> (j*4))&0xf;
+ rres.push_back(hex_digs[nib]);
+ }
+ nn -= val_n_bits()/4;
+ }
+ res.push_back('0');
+ res.push_back('x');
+ for (int i = 0; i < rres.size(); i++)
+ res.push_back(rres[rres.size()-i-1]);
+ return res;
+ }
+ void randomize(val_t* seed) {
+ for (int i = 0; i < n_words; i++)
+ values[i] = __rand_val(seed);
+ if (val_n_word_bits(w))
+ values[n_words-1] &= mask_val(val_n_word_bits(w));
+ }
+ inline dat_t<w> () {
+ }
+ template <int sw>
+ inline dat_t<w> (const dat_t<sw>& src) {
+ bit_word_funs<n_words>::copy(values, (val_t*)src.values, src.n_words);
+ if (sw != w && val_n_word_bits(w))
+ values[n_words-1] &= mask_val(val_n_word_bits(w));
+ }
+ inline dat_t<w> (const dat_t<w>& src) {
+ bit_word_funs<n_words>::set(values, (val_t*)src.values);
+ }
+ static inline dat_t<w> from_vals(val_t val[n_words]) {
+ dat_t<w> res;
+ for (int i = 0; i < n_words; i++)
+ res.values[i] = val[i];
+ return res;
+ }
+ inline dat_t<w> (val_t val) {
+ values[0] = val;
+ for (int i = 1; i < n_words; i++)
+ values[i] = 0;
+ }
+ template <int sw>
+ dat_t<w> mask(dat_t<sw> fill, int n) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::mask(res.values, n);
+ return res;
+ }
+ template <int dw>
+ dat_t<dw> mask(int n) {
+ dat_t<dw> res;
+ return res.mask(*this, n);
+ }
+ template <int n>
+ inline dat_t<n> mask(void) {
+ dat_t<n> res = mask<n>(n);
+ return res;
+ }
+ val_t operator [] (size_t i) {
+ return values[i];
+ }
+ dat_t<w> operator + ( dat_t<w> o ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::add(res.values, values, o.values, w);
+ return res;
+ }
+ dat_t<w> operator - ( dat_t<w> o ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::sub(res.values, values, o.values, w);
+ return res;
+ }
+ dat_t<w> operator - ( ) {
+ return ~(*this) + DAT<w>(1);
+ }
+ template <int w2>
+ dat_t<w+w2> operator * ( dat_t<w2> o ) {
+ dat_t<w+w2> res;
+ bit_word_funs<val_n_words(w+w2)>::mul(res.values, values, o.values, w, w2);
+ return res;
+ }
+ template <int w2>
+ dat_t<w+w2> fix_times_fix( dat_t<w2> o ) {
+ if (w+w2 <= val_n_bits()) {
+ sval_t a = sval_t(values[0] << (val_n_bits()-w)) >> (val_n_bits()-w);
+ sval_t b = sval_t(o.values[0] << (val_n_bits()-w2)) >> (val_n_bits()-w2);
+ return dat_t<w+w2>((a * b) & mask_val(w+w2));
+ } else {
+ val_t sgn_a = msb();
+ dat_t<w> abs_a = sgn_a ? -(*this) : (*this);
+ val_t sgn_b = o.msb();
+ dat_t<w2> abs_b = sgn_b ? -o : o;
+ dat_t<w+w2> res = abs_a * abs_b;
+ return (sgn_a ^ sgn_b) ? -res : res;
+ }
+ }
+ dat_t<w> operator / ( dat_t<w> o ) {
+ dat_t<w> res(0);
+ if (o == 0) {
+ res.fill_bit(1);
+ } else if (n_words == 1) {
+ res.values[0] = values[0] / o.values[0];
+ } else {
+ dat_t<2*w> p = *this, d = o;
+ d = d << w;
+
+ for (int i = w-1; i >= 0; i--) {
+ p = p << 1;
+ if (p >= d) {
+ p = p - d;
+ res.values[i / val_n_bits()] |= val_t(1) << (i % val_n_bits());
+ }
+ }
+ }
+ return res;
+ }
+ dat_t<w> operator % ( dat_t<w> o ) {
+ return *this - *this / o * o;
+ }
+ dat_t<w+w> ufix_times_fix( dat_t<w> o ) {
+ return o.fix_times_ufix(*this);
+ }
+ template<int w2>
+ dat_t<w+w2> fix_times_ufix( dat_t<w2> o ) {
+ if (w+w2 <= val_n_bits()) {
+ sval_t a = sval_t(values[0] << (val_n_bits()-w)) >> (val_n_bits()-w);
+ return dat_t<w+w2>((a * o.values[0]) & mask_val(w+w2));
+ } else {
+ val_t sgn_a = msb();
+ dat_t<w> abs_a = sgn_a ? -(*this) : (*this);
+ dat_t<w+w2> res = abs_a * o;
+ return sgn_a ? -res : res;
+ }
+ }
+ inline bool operator < ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::ltu(values, o.values);
+ }
+ inline bool operator <= ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::lteu(values, o.values);
+ }
+ inline bool operator > ( dat_t<w> o ) {
+ return o < *this;
+ }
+ inline bool operator >= ( dat_t<w> o ) {
+ return o <= *this;
+ }
+ inline bool lt ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::lt(values, o.values, w);
+ }
+ inline bool lte ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::lte(values, o.values, w);
+ }
+ inline bool gt ( dat_t<w> o ) {
+ return o.lt(*this);
+ }
+ inline bool gte ( dat_t<w> o ) {
+ return o.lte(*this);
+ }
+ dat_t<w> operator ^ ( dat_t<w> o ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::bit_xor(res.values, values, o.values);
+ return res;
+ }
+ dat_t<w> operator & ( dat_t<w> o ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::bit_and(res.values, values, o.values);
+ return res;
+ }
+ dat_t<w> operator | ( dat_t<w> o ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::bit_or(res.values, values, o.values);
+ return res;
+ }
+ dat_t<w> operator ~ ( void ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::bit_neg(res.values, values, w);
+ return res;
+ }
+ inline dat_t<1> operator ! ( void ) {
+ return DAT<1>(!lo_word());
+ }
+ dat_t<1> operator && ( dat_t<1> o ) {
+ return DAT<1>(lo_word() & o.lo_word());
+ }
+ dat_t<1> operator || ( dat_t<1> o ) {
+ return DAT<1>(lo_word() | o.lo_word());
+ }
+ bool operator == ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::eq(values, o.values);
+ }
+ bool operator == ( datz_t<w> o ) {
+ return o == *this;
+ }
+ bool operator != ( dat_t<w> o ) {
+ return bit_word_funs<n_words>::neq(values, o.values);
+ }
+ dat_t<w> operator << ( int amount ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::lsh(res.values, values, amount);
+ if (val_n_word_bits(w))
+ res.values[n_words-1] &= mask_val(val_n_word_bits(w));
+ return res;
+ }
+ inline dat_t<w> operator << ( dat_t<w> o ) {
+ return *this << o.lo_word();
+ }
+ dat_t<w> operator >> ( int amount ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::rsh(res.values, values, amount);
+ return res;
+ }
+ inline dat_t<w> operator >> ( dat_t<w> o ) {
+ return *this >> o.lo_word();
+ }
+ dat_t<w> rsha ( dat_t<w> o) {
+ dat_t<w> res;
+ int amount = o.lo_word();
+ bit_word_funs<n_words>::rsha(res.values, values, amount, w);
+ return res;
+ }
+ dat_t<w>& operator = ( dat_t<w> o ) {
+ bit_word_funs<n_words>::set(values, o.values);
+ return *this;
+ }
+ dat_t<w> fill_bit( val_t bit ) {
+ dat_t<w> res;
+ val_t word = 0L - bit;
+ bit_word_funs<n_words>::fill_nb(res.values, word, w);
+ return res;
+ }
+ // TODO: SPEED THIS UP
+ dat_t<w> fill_byte( val_t byte, int nb, int n ) {
+ dat_t<w> res;
+ bit_word_funs<n_words>::fill(res.values, 0L);
+ for (size_t i = 0; i < n; i++)
+ res = (res << nb) | byte;
+ return res;
+ }
+ template <int dw, int n>
+ dat_t<dw> fill( void ) {
+ // TODO: GET RID OF IF'S
+ dat_t<dw> res;
+ if (w == 1) {
+ return res.fill_bit(lo_word());
+ } else {
+ return res.fill_byte(lo_word(), w, n);
+ }
+ }
+ template <int dw, int nw>
+ dat_t<dw> fill( dat_t<nw> n ) {
+ // TODO: GET RID OF IF'S
+ dat_t<dw> res;
+ if (w == 1) {
+ return res.fill_bit(lo_word()&1);
+ } else {
+ return res.fill_byte(lo_word(), w, n);
+ }
+ }
+ template <int dw>
+ dat_t<dw> extract() {
+ dat_t<dw> res;
+ int i;
+ for (i = 0; i < val_n_full_words(dw); i++)
+ res.values[i] = values[i];
+ if (val_n_word_bits(dw))
+ res.values[i] = values[i] & mask_val(val_n_word_bits(dw));
+ return res;
+ }
+ template <int dw>
+ dat_t<dw> extract(val_t e, val_t s) {
+ dat_t<w> x = (*this >> s);
+ return x.extract<dw>();
+ }
+ template <int dw, int iwe, int iws>
+ inline dat_t<dw> extract(dat_t<iwe> e, dat_t<iws> s) {
+ return extract<dw>(e.lo_word(), s.lo_word());
+ }
+
+ template <int sw>
+ dat_t<w> inject(dat_t<sw> src, val_t e, val_t s) {
+ // Modify this.values in place.
+ dat_t<w> inject_src(src); // Enlarged if needed to match inject_dst
+ bit_word_funs<n_words>::inject(values, inject_src.values, e, s);
+ return *this;
+ }
+
+ template <int sw, int iwe, int iws>
+ inline dat_t<w> inject(dat_t<sw> src, dat_t<iwe> e, dat_t<iws> s) {
+ return inject<w>(src, e.lo_word(), s.lo_word());
+ }
+
+
+ template <int dw>
+ inline dat_t<dw> log2() {
+ dat_t<dw> res;
+ bit_word_funs<n_words>::log2(res.values, values);
+ return res;
+ }
+ inline val_t bit(val_t b) {
+ return (values[val_n_full_words(b)] >> val_n_word_bits(b)) & 1;
+ }
+ inline val_t msb() {
+ return values[n_words-1] >> val_n_word_bits(w-1);
+ }
+ template <int iw>
+ inline dat_t<1> bit(dat_t<iw> b) {
+ return bit(b.lo_word());
+ }
+};
+
+template <int w>
+std::string dat_to_str(const dat_t<w>& x) {
+ char s[w];
+ s[dat_to_str(s, x)] = 0;
+ return s;
+}
+
+static __inline__ int n_digits(int w, int base) {
+ return (int)ceil(log(2)/log(base)*w);
+}
+
+template <int w>
+int dat_to_str(char* s, dat_t<w> x, int base = 16, char pad = '0') {
+ int n_digs = n_digits(w, base);
+ int j = n_digs-1, digit;
+
+ do {
+ if (ispow2(base)) {
+ digit = x.lo_word() & (base-1);
+ x = x >> log2_1(base);
+ } else {
+ digit = (x % base).lo_word();
+ x = x / base;
+ }
+ s[j] = (digit >= 10 ? 'a'-10 : '0') + digit;
+ } while (--j >= 0 && x != 0);
+
+ for ( ; j >= 0; j--)
+ s[j] = pad;
+
+ return n_digs;
+}
+
+static __inline__ int dat_to_str(char* s, val_t x, int base = 16, char pad = '0') {
+ return dat_to_str<sizeof(val_t)*8>(s, dat_t<sizeof(val_t)*8>(x), base, pad);
+}
+
+template <int w>
+int fix_to_str(char* s, dat_t<w> x, int base = 16, char pad = '0') {
+ bool neg = x.msb();
+ s[0] = neg;
+ int len = dat_to_str<w>(s+1, neg ? -x : x, base, pad);
+ return len+1;
+}
+
+static __inline__ int flo_digits(int m, int e) {
+ return 2 + n_digits(m, 10) + 2 + n_digits(e, 10);
+}
+
+template <int w>
+int flo_to_str(char* s, dat_t<w> x, char pad = ' ') {
+ char buf[1000];
+ int n_digs = (w == 32) ? flo_digits(32, 8) : flo_digits(52, 11);
+ double val = (w == 32) ? toFloat(x.values[0]) : toDouble(x.values[0]);
+ // sprintf(buf, "%d %d%*e", w, n_digs, n_digs, val);
+ sprintf(buf, "%*e", n_digs, val);
+ assert(strlen(buf) <= n_digs);
+ for (int i = 0; i < n_digs; i++)
+ s[i] = (i < strlen(buf)) ? buf[i] : pad;
+ s[n_digs] = 0;
+ // printf("N-DIGS = %d BUF %lu PAD %lu\n", n_digs, strlen(buf), n_digs-strlen(buf));
+ // return strlen(buf);
+ return n_digs;
+}
+
+template <int w>
+int dat_as_str(char* s, const dat_t<w>& x) {
+ int i, j;
+ for (i = 0, j = (w/8-1)*8; i < w/8; i++, j -= 8) {
+ char ch = x.values[j/val_n_bits()] >> (j % val_n_bits());
+ if (ch == 0) break;
+ s[i] = ch;
+ }
+ for ( ; i < w/8; i++)
+ s[i] = ' ';
+ return w/8;
+}
+
+static __inline__ int dat_as_str(char* s, val_t x) {
+ return dat_as_str(s, dat_t<sizeof(val_t)*8>(x));
+}
+
+#if __cplusplus >= 201103L
+static void __attribute__((unused)) dat_format(char* s, const char* fmt)
+{
+ for (char c; (c = *fmt); fmt++) {
+ if (c == '%' && *++fmt != '%')
+ abort();
+ *s++ = c;
+ }
+}
+
+template <typename T, typename... Args>
+static void dat_format(char* s, const char* fmt, T value, Args... args)
+{
+ while (*fmt) {
+ if (*fmt == '%') {
+ switch(fmt[1]) {
+ case 'e': s += flo_to_str(s, value, ' '); break;
+ case 'h': s += dat_to_str(s, value, 16, '0'); break;
+ case 'b': s += dat_to_str(s, value, 2, '0'); break;
+ case 'd': s += dat_to_str(s, value, 10, ' '); break;
+ case 's': s += dat_as_str(s, value); break;
+ case '%': *s++ = '%'; break;
+ default: abort();
+ }
+ return dat_format(s, fmt + 2, args...);
+ } else {
+ *s++ = *fmt++;
+ }
+ }
+ abort();
+}
+
+template <int w, typename... Args>
+static dat_t<w> dat_format(const char* fmt, Args... args)
+{
+#if BYTE_ORDER != LITTLE_ENDIAN
+# error dat_format assumes a little-endian architecture
+#endif
+ char str[w/8+1];
+ dat_format(str, fmt, args...);
+
+ dat_t<w> res;
+ res.values[res.n_words-1] = 0;
+ for (int i = 0; i < w/8; i++)
+ ((char*)res.values)[w/8-1-i] = str[i];
+ return res;
+}
+
+template <int w, typename... Args>
+static ssize_t dat_fprintf(FILE *f, const char* fmt, Args... args)
+{
+ char str[w/8+1];
+ dat_format(str, fmt, args...);
+ return fwrite(str, 1, w/8, f);
+}
+
+template <int w, typename... Args>
+static ssize_t dat_prints(std::ostream& s, const char* fmt, Args... args)
+{
+ char str[w/8+1];
+ dat_format(str, fmt, args...);
+ s.write(str, w/8);
+ ssize_t ret = s.good() ? w/8 : -1;
+ return ret;
+}
+#endif /* C++11 */
+
+template <int w, int sw> inline dat_t<w> DAT(dat_t<sw> dat) {
+ dat_t<w> res(dat);
+ return res;
+}
+
+template <int w> inline dat_t<w> LIT(val_t value) {
+ return DAT<w>(value);
+}
+
+template <int w>
+inline dat_t<w> mux ( dat_t<1> t, dat_t<w> c, dat_t<w> a ) {
+ dat_t<w> mask;
+ bit_word_funs<val_n_words(w)>::fill(mask.values, -t.lo_word());
+ return a ^ ((a ^ c) & mask);
+}
+
+template <int w>
+class datz_t : public dat_t<w> {
+ public:
+ dat_t<w> mask;
+ inline bool operator == ( dat_t<w> o ) {
+ dat_t<w> masked = (o & mask);
+ return (o & mask) == (dat_t<w>)*this;
+ }
+};
+
+template <int w> datz_t<w> inline LITZ(val_t value, val_t mask) {
+ datz_t<w> res; res.mask.values[0] = mask; res.values[0] = value; return res;
+}
+
+template < int w, int w1, int w2 >
+inline dat_t<w> cat(dat_t<w1> d1, dat_t<w2> d2) {
+ if (w <= val_n_bits() && w1 + w2 == w)
+ return DAT<w>(d1.values[0] << (w2 & (val_n_bits()-1)) | d2.values[0]);
+ return DAT<w>((DAT<w>(d1) << w2) | DAT<w>(d2));
+}
+
+template < int w1 >
+inline dat_t<1> reduction_and(dat_t<w1> d) {
+ return DAT<1>(d == ~DAT<w1>(0));
+}
+
+template < int w1 >
+inline dat_t<1> reduction_or(dat_t<w1> d) {
+ return DAT<1>(d != DAT<w1>(0));
+}
+
+// I am O(n) where n is number of bits in val_t. Future optimization would be log(n).
+template < int w1 >
+inline dat_t<1> reduction_xor(dat_t<w1> d) {
+ dat_t<1> res = DAT<1>(0);
+ val_t word = d.values[0];
+
+ for (int i = 1; i < d.n_words_of(); i++)
+ word ^= d.values[i];
+ for (int i = 0; i < sizeof(val_t)*8; i++) {
+ res = res ^ DAT<1>(word & 1);
+ word = word >> 1;
+ }
+
+ return res;
+}
+
+template <int w, int d>
+class mem_t {
+ public:
+ dat_t<w> contents[d];
+ val_t dummy_seed;
+ val_t* seedp;
+
+ int width() {
+ return w;
+ }
+ int length() {
+ return d;
+ }
+
+ template <int iw>
+ dat_t<w> get (dat_t<iw> idx) {
+ return get(idx.lo_word() & (nextpow2_1(d)-1));
+ }
+ dat_t<w> get (val_t idx) {
+ if (!ispow2(d) && idx >= d) {
+ dat_t<w> res;
+ res.randomize(seedp);
+ return res;
+ }
+ return contents[idx];
+ }
+ val_t get (val_t idx, int word) {
+ if (!ispow2(d) && idx >= d)
+ return __rand_val(seedp) & (word == val_n_words(w) && val_n_word_bits(w) ? mask_val(w) : -1L);
+ return contents[idx].values[word];
+ }
+
+ template <int iw>
+ void put (dat_t<iw> idx, dat_t<w> val) {
+ put(idx.lo_word(), val);
+ }
+ void put (val_t idx, dat_t<w> val) {
+ if (ispow2(d) || idx < d)
+ contents[idx] = val;
+ }
+ val_t put (val_t idx, int word, val_t val) {
+ if (ispow2(d) || idx < d)
+ contents[idx].values[word] = val;
+ }
+
+ void print ( void ) {
+ for (int j = 0; j < d/4; j++) {
+ for (int i = 0; i < 4; i++) {
+ int idx = j*4+i;
+ printf("|%2d: %16llx| ", idx, contents[idx].lo_word());
+ }
+ printf("\n");
+ }
+ }
+ mem_t<w,d> () {
+ dummy_seed = 1;
+ seedp = &dummy_seed;
+ for (int i = 0; i < d; i++)
+ contents[i] = DAT<w>(0);
+ }
+ void randomize(val_t* seed) {
+ seedp = seed;
+ for (int i = 0; i < d; i++)
+ contents[i].randomize(seed);
+ }
+ size_t read_hex(const char *hexFileName) {
+ ifstream ifp(hexFileName);
+ if (ifp.fail()) {
+ printf("[error] Unable to open hex data file %s\n", hexFileName);
+ return -1;
+ }
+ std::string hex_line;
+ dat_t<w> hex_dat;
+ for (int addr = 0; addr < d && !ifp.eof();) {
+ getline(ifp, hex_line);
+ if (dat_from_hex(hex_line, hex_dat) > 0) {
+ contents[addr++] = hex_dat;
+ }
+ }
+ ifp.close();
+ return 0;
+ }
+};
+
+static __attribute__((unused)) char hex_to_char[] = "0123456789abcdef";
+
+static int char_to_hex[] = {
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
+
+// dat_from_hex: Read a hex value from a std::string into a given dat_t variable.
+// Author: B. Richards, for parsing data formatted for Verilog $readmemh
+// Arguments:
+// hex_line A string containing hex numbers with embedded x, _ characters
+// res A dat_t object to fill in with a return value
+// offset Starting index in hex_line
+// Return value:
+// Success: returns next character offset
+// Fail: 0
+template <int w>
+size_t dat_from_hex(std::string hex_line, dat_t<w>& res, size_t offset = 0) {
+ size_t first_digit, last_digit, comment;
+
+ // Scan for the hex data bounds.
+ comment = hex_line.find_first_of("/", offset);
+ first_digit = hex_line.find_first_of("0123456789abcdefABCDEF", offset);
+ if (first_digit == std::string::npos) return 0;
+ if (comment != std::string::npos && comment < first_digit) return 0;
+ last_digit = hex_line.find_first_not_of("0123456789abcdefABCDEF_xX", first_digit);
+ if (last_digit == std::string::npos) {
+ last_digit = hex_line.length() - 1;
+ } else {
+ last_digit--;
+ }
+
+ // Convert the hex data to a dat_t, from right to left.
+ int digit_val;
+ val_t word_accum = 0;
+ int digit, w_index, bit;
+ for (digit = last_digit, w_index = 0, bit = 0; digit >= (int)first_digit && w_index < res.n_words; digit--) {
+ digit_val = char_to_hex[hex_line[digit]];
+ if (digit_val >= 0) {
+ word_accum |= ((val_t)digit_val) << bit;
+ bit += 4;
+ if (bit == 64) {
+ res.values[w_index] = word_accum;
+ word_accum = 0L;
+ bit = 0;
+ w_index++;
+ }
+ }
+ }
+ if (bit != 0) {
+ res.values[w_index] = word_accum;
+ }
+ // Return a pointer to the character after the converted value.
+ return last_digit + 1;
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("no-stack-protector")
+
+template <int s, int w>
+void dat_dump (FILE* f, const dat_t<w>& val, val_t name) {
+ size_t pos = 0;
+ char str[1 + w + 1 + s + 1];
+
+ str[pos++] = 'b';
+ for (int i = 0; i < w; i++)
+ str[pos + w-i-1] = '0' + ((val.values[i/val_n_bits()] >> (i%val_n_bits())) & 1);
+ pos += w;
+
+ str[pos++] = ' ';
+ for (int i = 0; i < s; i++) {
+ str[pos++] = name;
+ name >>= 8;
+ }
+ str[pos++] = '\n';
+
+ fwrite(str, 1, sizeof(str), f);
+}
+
+#pragma GCC pop_options
+
+inline std::string read_tok(FILE* f) {
+ std::string res;
+ bool is_skipping = true;
+ for (;;) {
+ char c = fgetc(f);
+ if (feof(f))
+ return res;
+ if (is_skipping) {
+ if (char_to_hex[c] != -1) {
+ res.push_back(c);
+ is_skipping = false;
+ }
+ } else {
+ if (char_to_hex[c] == -1) {
+ ungetc(c, f);
+ return res;
+ }
+ res.push_back(c);
+ }
+ }
+}
+
+template <int s, int w, int d>
+void dat_dump(FILE* file, const mem_t<w,d>& val, val_t name) {
+}
+
+template <int w, int d> mem_t<w,d> MEM( void );
+
+class mod_t {
+ public:
+ mod_t():
+ dumpfile(NULL),
+ is_stale(false),
+ printStream()
+ {}
+ std::vector< mod_t* > children;
+ virtual void init ( val_t rand_init=false ) { };
+ virtual void clock_lo ( dat_t<1> reset ) { };
+ virtual void clock_hi ( dat_t<1> reset ) { };
+ virtual int clock ( dat_t<1> reset ) { };
+ virtual void setClocks ( std::vector< int >& periods ) { };
+
+ // Returns a clone of this object's circuit state (both registers and wires).
+ // Currently, it is undefined what happens to other state (like dumpfile and
+ // timestep), so use with care.
+ virtual mod_t* clone() = 0;
+ // Sets this module's circuit state (registers and wires) from the src mod_t.
+ // For mod_t subclasses, src must be the same class.
+ // Returns true on success, and false on failure. Currently, no guarantees
+ // are made about state consistency on failure,
+ virtual bool set_circuit_from(mod_t* src) = 0;
+
+ virtual void print ( FILE* f ) { };
+ virtual void print ( std::ostream& s ) { };
+ virtual void dump ( FILE* f, int t ) { };
+
+ void set_dumpfile(FILE* f) {
+ dumpfile = f;
+ }
+
+ int timestep;
+
+ void dump () {
+ if (dumpfile != NULL) dump(dumpfile, timestep);
+ timestep += 1;
+ }
+
+ int step (bool is_reset, int n) {
+ int delta = 0;
+ dat_t<1> reset = LIT<1>(is_reset);
+ for (int i = 0; i < n; i++) {
+ if (is_reset) {
+ clock_lo(reset);
+ }
+ // Collect any print output.
+ print(printStream);
+ dump();
+ delta += clock(reset);
+ }
+ return delta;
+ }
+
+ void mark_stale (void) {
+ is_stale = true;
+ }
+
+ void propagate_changes (void) {
+ if (is_stale) clock_lo(LIT<1>(false));
+ is_stale = false;
+ }
+
+ int has_output(void) {
+ return printStream.tellp();
+ }
+
+ std::string drain_output(void) {
+ return printStream.str();
+ }
+
+ // Since we have an element with a deleted copy constructor - printStream,
+ // we need to provide our own explicit copy constructor.
+ mod_t(const mod_t& src) {
+ children = src.children;
+ timestep = src.timestep;
+ is_stale = src.is_stale;
+ dumpfile = src.dumpfile;
+ }
+
+ protected:
+ bool is_stale;
+ FILE* dumpfile;
+ std::basic_ostringstream< char > printStream;
+};
+
+#define ASSERT(cond, msg) { \
+ if (!(cond)) \
+ throw std::runtime_error("Assertion failed: " msg); \
+}
+
+#pragma GCC diagnostic pop
+#endif
diff --git a/src/main/resources/vpi_user.cc b/src/main/resources/vpi_user.cc
new file mode 100644
index 00000000..f24d8e39
--- /dev/null
+++ b/src/main/resources/vpi_user.cc
@@ -0,0 +1,562 @@
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <set>
+#include <map>
+#include <queue>
+#include <ctime>
+#include <vpi_user.h>
+
+using namespace std;
+
+/*==========================================================================
+ User Functions
+=============================================================================*/
+int32_t wire_poke_calltf(char *user_data) {
+ queue<vpiHandle> modules;
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // First argument: <node_name>
+ s_vpi_value node_s;
+ node_s.format = vpiStringVal;
+ vpi_get_value(vpi_scan(arg_iter), &node_s);
+ // Second argument: <value>
+ s_vpi_value value_s;
+ value_s.format = vpiIntVal;
+ vpi_get_value(vpi_scan(arg_iter), &value_s);
+ vpi_free_object(arg_iter);
+
+ vpiHandle test_handle = vpi_scan(vpi_iterate(vpiModule, NULL));
+ vpiHandle top_handle = vpi_scan(vpi_iterate(vpiModule, test_handle));
+ // Construct node paths
+ string testname = vpi_get_str(vpiDefName, test_handle);
+ istringstream iss(node_s.value.str);
+ string nodename;
+ iss >> nodename;
+ ostringstream oss;
+ oss << testname << "." << nodename;
+ string nodepath = oss.str();
+
+ // Examine the regs in the testbench
+ // in order to give the correct input values
+ string modulepath = vpi_get_str(vpiFullName, top_handle);
+ string testpath = testname + nodepath.substr(modulepath.length(), nodepath.length() - modulepath.length());
+ vpiHandle reg_iter = vpi_iterate(vpiReg, test_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (testpath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpi_put_value(reg_handle, &value_s, NULL, vpiNoDelay);
+ vpi_printf("ok\n");
+ return 0;
+ }
+ }
+
+ // Start from the top module
+ modules.push(top_handle);
+
+ bool found = false;
+ while (!modules.empty()) {
+ vpiHandle mod_handle = modules.front();
+ modules.pop();
+
+ // Iterate its net
+ vpiHandle net_iter = vpi_iterate(vpiNet, mod_handle);
+ while (vpiHandle net_handle = vpi_scan(net_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, net_handle)) {
+ vpi_put_value(net_handle, &value_s, NULL, vpiNoDelay);
+ found = true;
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ // Iterate its reg
+ vpiHandle reg_iter = vpi_iterate(vpiReg, mod_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpi_put_value(reg_handle, &value_s, NULL, vpiNoDelay);
+ found = true;
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ vpiHandle sub_iter = vpi_iterate(vpiModule, mod_handle);
+ while (vpiHandle sub_handle = vpi_scan(sub_iter)) {
+ modules.push(sub_handle);
+ }
+ }
+
+ if (found)
+ vpi_printf("ok\n");
+ else
+ vpi_printf("error\n");
+
+ return 0;
+}
+
+int32_t wire_peek_calltf(char *user_data) {
+ queue<vpiHandle> modules;
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // First argument: <node_name>
+ s_vpi_value node_s;
+ node_s.format = vpiStringVal;
+ vpi_get_value(vpi_scan(arg_iter), &node_s);
+ vpi_free_object(arg_iter);
+
+ vpiHandle test_handle = vpi_scan(vpi_iterate(vpiModule, NULL));
+ vpiHandle top_handle = vpi_scan(vpi_iterate(vpiModule, test_handle));
+ // Construct node paths
+ string testname = vpi_get_str(vpiDefName, test_handle);
+ istringstream iss(node_s.value.str);
+ string nodename;
+ iss >> nodename;
+ ostringstream oss;
+ oss << testname << "." << nodename;
+ string nodepath = oss.str();
+ // Start from the top module
+ modules.push(top_handle);
+
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ bool found = false;
+ while (!modules.empty()) {
+ vpiHandle mod_handle = modules.front();
+ modules.pop();
+
+ // Iterate its net
+ vpiHandle net_iter = vpi_iterate(vpiNet, mod_handle);
+ while (vpiHandle net_handle = vpi_scan(net_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, net_handle)) {
+ vpi_get_value(net_handle, &value_s);
+ found = true;
+ }
+ }
+ if (found) break;
+
+ // Iterate its reg
+ vpiHandle reg_iter = vpi_iterate(vpiReg, mod_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpi_get_value(reg_handle, &value_s);
+ found = true;
+ }
+ }
+ if (found) break;
+
+ vpiHandle sub_iter = vpi_iterate(vpiModule, mod_handle);
+ while (vpiHandle sub_handle = vpi_scan(sub_iter)) {
+ modules.push(sub_handle);
+ }
+ }
+
+ if (found)
+ vpi_printf("0x%s\n", value_s.value.str);
+ else
+ vpi_printf("error\n");
+
+ return 0;
+}
+
+int32_t mem_poke_calltf(char *user_data) {
+ queue<vpiHandle> modules;
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // First argument: <mem_name>
+ s_vpi_value node_s;
+ node_s.format = vpiStringVal;
+ vpi_get_value(vpi_scan(arg_iter), &node_s);
+ // Second argument: <mem_index>
+ s_vpi_value index_s;
+ index_s.format = vpiIntVal;
+ vpi_get_value(vpi_scan(arg_iter), &index_s);
+ // Third argument: <value>
+ s_vpi_value value_s;
+ value_s.format = vpiIntVal;
+ vpi_get_value(vpi_scan(arg_iter), &value_s);
+
+ vpiHandle test_handle = vpi_scan(vpi_iterate(vpiModule, NULL));
+ vpiHandle top_handle = vpi_scan(vpi_iterate(vpiModule, test_handle));
+ // Construct node paths
+ string testname = vpi_get_str(vpiDefName, test_handle);
+ istringstream iss(node_s.value.str);
+ string nodename;
+ iss >> nodename;
+ ostringstream oss;
+ oss << testname << "." << nodename;
+ string nodepath = oss.str();
+ oss << "[" << index_s.value.integer << "]";
+ string elmpath = oss.str();
+
+ // Examine the reg arrays in the testbench
+ // in order to give the correct input values
+ string modulepath = vpi_get_str(vpiFullName, top_handle);
+ string testpath = testname + nodepath.substr(modulepath.length(), nodepath.length() - modulepath.length());
+ vpiHandle reg_iter = vpi_iterate(vpiRegArray, test_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (testpath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpiHandle elm_iter = vpi_iterate(vpiReg, reg_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ if (elmpath == vpi_get_str(vpiFullName, elm_handle)) {
+ vpi_put_value(elm_handle, &value_s, NULL, vpiNoDelay);
+ vpi_printf("ok\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+ // Start from the top module
+ modules.push(top_handle);
+
+ bool found = false;
+ while (!modules.empty()) {
+ vpiHandle mod_handle = modules.front();
+ modules.pop();
+
+ // Iterate its net arrays
+ vpiHandle net_iter = vpi_iterate(vpiNetArray, mod_handle);
+ while (vpiHandle net_handle = vpi_scan(net_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, net_handle)) {
+ vpiHandle elm_iter = vpi_iterate(vpiNet, net_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ if (elmpath == vpi_get_str(vpiFullName, elm_handle)){
+ vpi_put_value(elm_handle, &value_s, NULL, vpiNoDelay);
+ found = true;
+ }
+ if (found) break;
+ }
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ // Iterate its reg arrays
+ vpiHandle reg_iter = vpi_iterate(vpiRegArray, mod_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpiHandle elm_iter = vpi_iterate(vpiReg, reg_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ if (elmpath == vpi_get_str(vpiFullName, elm_handle)){
+ vpi_put_value(elm_handle, &value_s, NULL, vpiNoDelay);
+ found = true;
+ }
+ if (found) break;
+ }
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ vpiHandle sub_iter = vpi_iterate(vpiModule, mod_handle);
+ while (vpiHandle sub_handle = vpi_scan(sub_iter)) {
+ modules.push(sub_handle);
+ }
+ }
+
+ if (found)
+ vpi_printf("ok\n");
+ else
+ vpi_printf("error\n");
+}
+
+int32_t mem_peek_calltf(char *user_data) {
+ queue<vpiHandle> modules;
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // First argument: <node_name>
+ s_vpi_value node_s;
+ node_s.format = vpiStringVal;
+ vpi_get_value(vpi_scan(arg_iter), &node_s);
+ // Second argument: <mem_index>
+ s_vpi_value index_s;
+ index_s.format = vpiIntVal;
+ vpi_get_value(vpi_scan(arg_iter), &index_s);
+
+ vpiHandle test_handle = vpi_scan(vpi_iterate(vpiModule, NULL));
+ vpiHandle top_handle = vpi_scan(vpi_iterate(vpiModule, test_handle));
+ // Construct node paths
+ string testname = vpi_get_str(vpiDefName, test_handle);
+ istringstream iss(node_s.value.str);
+ string nodename;
+ iss >> nodename;
+ ostringstream oss;
+ oss << testname << "." << nodename;
+ string nodepath = oss.str();
+ oss << "[" << index_s.value.integer << "]";
+ string elmpath = oss.str();
+ // Start from the top module
+ modules.push(top_handle);
+
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ bool found = false;
+ while (!modules.empty()) {
+ vpiHandle mod_handle = modules.front();
+ modules.pop();
+
+ // Iterate its net arrays
+ vpiHandle net_iter = vpi_iterate(vpiNetArray, mod_handle);
+ while (vpiHandle net_handle = vpi_scan(net_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, net_handle)) {
+ vpiHandle elm_iter = vpi_iterate(vpiNet, net_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ if (elmpath == vpi_get_str(vpiFullName, elm_handle)){
+ vpi_get_value(elm_handle, &value_s);
+ found = true;
+ }
+ if (found) break;
+ }
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ // Iterate its reg arrays
+ vpiHandle reg_iter = vpi_iterate(vpiRegArray, mod_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ if (nodepath == vpi_get_str(vpiFullName, reg_handle)) {
+ vpiHandle elm_iter = vpi_iterate(vpiReg, reg_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ if (elmpath == vpi_get_str(vpiFullName, elm_handle)){
+ vpi_get_value(elm_handle, &value_s);
+ found = true;
+ }
+ if (found) break;
+ }
+ }
+ if (found) break;
+ }
+ if (found) break;
+
+ vpiHandle sub_iter = vpi_iterate(vpiModule, mod_handle);
+ while (vpiHandle sub_handle = vpi_scan(sub_iter)) {
+ modules.push(sub_handle);
+ }
+ }
+
+ if (found)
+ vpi_printf("0x%s\n", value_s.value.str);
+ else
+ vpi_printf("error\n");
+}
+
+/*==========================================================================
+ Compile Time Functions
+=============================================================================*/
+
+int32_t wire_poke_compiletf (char *user_data) {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle), arg_handle;
+ bool error = false;
+
+ if (arg_iter == NULL) {
+ vpi_printf("ERROR: $wire_poke requires at least two argument(nodename, hex_value)\n");
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiStringConst) {
+ vpi_printf("ERROR: $wire_poke requires the first argument as a string(nodename)\n");
+ error = true;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiHexConst) {
+ vpi_printf("ERROR: $wire_poke requires the second argument as a hex number(value)\n");
+ error = true;
+ }
+
+ if (vpi_scan(arg_iter) != NULL) {
+ vpi_printf("ERROR: $wire_poke requires only two arguments(nodename, hex_value))\n");
+ error = true;
+ }
+
+ if (error) {
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+ return 0;
+}
+
+int32_t wire_peek_compiletf (char *user_data) {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle), arg_handle;
+ bool error = false;
+
+ if (arg_iter == NULL) {
+ vpi_printf("ERROR: $wire_peek requires at least one argument(nodename)\n");
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiStringConst) {
+ vpi_printf("ERROR: $wire_peek requires the first argument as a string(nodename)\n");
+ error = true;
+ }
+
+ if (vpi_scan(arg_iter) != NULL) {
+ vpi_printf("ERROR: $wire_peek requires only one arguments(nodename))\n");
+ error = true;
+ }
+
+ if (error) {
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+ return 0;
+}
+
+int32_t mem_poke_compiletf (char *user_data) {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle), arg_handle;
+ bool error = false;
+
+ if (arg_iter == NULL) {
+ vpi_printf("ERROR: $mem_poke requires at least three argument(nodename, offset, hex_value)\n");
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiStringConst) {
+ vpi_printf("ERROR: $mem_poke requires the first argument as a string(nodename)\n");
+ error = true;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiIntegerVar && vpi_get(vpiType, arg_handle) != vpiDecConst) {
+ vpi_printf("ERROR: $mem_poke requires the second argument as a integer(offset)\n");
+ error = true;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiHexConst) {
+ vpi_printf("ERROR: $mem_poke requires the third argument as a hex string(value)\n");
+ error = true;
+ }
+
+ if (vpi_scan(arg_iter) != NULL) {
+ vpi_printf("ERROR: $mem_poke requires only three arguments(nodename, offset, hex_value))\n");
+ error = true;
+ }
+
+ if (error) {
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+ return 0;
+}
+
+int32_t mem_peek_compiletf (char *user_data) {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle), arg_handle;
+ bool error = false;
+
+ if (arg_iter == NULL) {
+ vpi_printf("ERROR: $mem_peek requires at least two argument(nodename, offset, hex_value)\n");
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiReg && vpi_get(vpiType, arg_handle) != vpiStringConst) {
+ vpi_printf("ERROR: $mem_peek requires the first argument as a string(nodename)\n");
+ error = true;
+ }
+
+ arg_handle = vpi_scan(arg_iter);
+ if (vpi_get(vpiType, arg_handle) != vpiIntegerVar && vpi_get(vpiType, arg_handle) != vpiDecConst) {
+ vpi_printf("ERROR: $mem_peek requires the second argument as a integer(offset)\n");
+ error = true;
+ }
+
+ if (vpi_scan(arg_iter) != NULL) {
+ vpi_printf("ERROR: $mem_peek requires only two arguments(nodename, offset))\n");
+ error = true;
+ }
+
+ if (error) {
+ vpi_control(vpiFinish, 1); /* abort simulation */
+ return 0;
+ }
+ return 0;
+}
+
+
+/*==========================================================================
+ Registration Functions
+=============================================================================*/
+
+void wire_poke_registration() {
+ s_vpi_systf_data tf_data;
+
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = "$wire_poke";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = wire_poke_calltf;
+ tf_data.compiletf = wire_poke_compiletf;
+ tf_data.user_data = NULL;
+
+ vpi_register_systf(&tf_data);
+
+ return;
+}
+
+void wire_peek_registration() {
+ s_vpi_systf_data tf_data;
+
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = "$wire_peek";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = wire_peek_calltf;
+ tf_data.compiletf = wire_peek_compiletf;
+ tf_data.user_data = NULL;
+
+ vpi_register_systf(&tf_data);
+
+ return;
+}
+
+void mem_poke_registration() {
+ s_vpi_systf_data tf_data;
+
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = "$mem_poke";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = mem_poke_calltf;
+ tf_data.compiletf = mem_poke_compiletf;
+ tf_data.user_data = NULL;
+
+ vpi_register_systf(&tf_data);
+
+ return;
+}
+
+void mem_peek_registration() {
+ s_vpi_systf_data tf_data;
+
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = "$mem_peek";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = mem_peek_calltf;
+ tf_data.compiletf = mem_peek_compiletf;
+ tf_data.user_data = NULL;
+
+ vpi_register_systf(&tf_data);
+
+ return;
+}
+
+/*==========================================================================
+ Start-up Array
+=============================================================================*/
+void (*vlog_startup_routines[]) () = {
+ wire_poke_registration,
+ wire_peek_registration,
+ mem_poke_registration,
+ mem_peek_registration,
+ 0
+};