summaryrefslogtreecommitdiff
path: root/src/main/resources
diff options
context:
space:
mode:
authorHenry Cook2015-08-06 18:39:12 -0700
committerHenry Cook2015-08-08 16:38:25 -0700
commitc22364ee6495e8796b2db5ae2549f7164f0aee1d (patch)
treeb55a5758d89a817849ba607a64d3e458a1a6afed /src/main/resources
parent6a3dfce4c9bf675d21e826567e6632549277e376 (diff)
verilog emulator resources
Diffstat (limited to 'src/main/resources')
-rw-r--r--src/main/resources/sim_api.h156
-rw-r--r--src/main/resources/vpi.cpp130
-rw-r--r--src/main/resources/vpi.h212
3 files changed, 498 insertions, 0 deletions
diff --git a/src/main/resources/sim_api.h b/src/main/resources/sim_api.h
new file mode 100644
index 00000000..f7789141
--- /dev/null
+++ b/src/main/resources/sim_api.h
@@ -0,0 +1,156 @@
+#ifndef __SIM_API_H
+#define __SIM_API_H
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <map>
+
+enum SIM_CMD { RESET, STEP, UPDATE, POKE, PEEK, GETID, SETCLK, FIN };
+
+template<class T> struct sim_data_t {
+ std::vector<T> resets;
+ std::vector<T> inputs;
+ std::vector<T> outputs;
+ std::vector<T> signals;
+ std::map<std::string, size_t> signal_map;
+ std::map<std::string, T> clk_map;
+};
+
+template <class T> class sim_api_t {
+public:
+ void tick() {
+ static bool is_reset = false;
+ // First, Generates output tokens (in hex)
+ generate_tokens();
+ if (is_reset) {
+ start();
+ is_reset = false;
+ }
+
+ // Next, handle commands from the testers
+ bool exit = false;
+ do {
+ size_t cmd;
+ std::cin >> std::dec >> cmd;
+ switch ((SIM_CMD) cmd) {
+ case RESET:
+ reset(); is_reset = true; exit = true; break;
+ case STEP:
+ consume_tokens();
+ step(); exit = true; break;
+ case UPDATE:
+ consume_tokens();
+ update(); exit = true; break;
+ case POKE: poke(); break;
+ case PEEK: peek(); break;
+ case GETID: getid(); break;
+ case SETCLK: setclk(); break;
+ case FIN: finish(); exit = true; break;
+ default: break;
+ }
+ } while (!exit);
+ }
+private:
+ virtual void reset() = 0;
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual void update() = 0;
+ virtual void step() = 0;
+ // Consumes input tokens (in hex)
+ virtual void put_value(T& sig) = 0;
+ // Generate output tokens (in hex)
+ virtual void get_value(T& sig) = 0;
+ // Find a signal of path
+ virtual int search(std::string& path) { return -1; }
+
+ void poke() {
+ size_t id;
+ std::cin >> std::dec >> id;
+ T obj = sim_data.signals[id];
+ if (obj) {
+ put_value(obj);
+ } else {
+ std::cout << "Cannot find the object of id = " << id << std::endl;
+ finish();
+ exit(0);
+ }
+ }
+
+ void peek() {
+ size_t id;
+ std::cin >> std::dec >> id;
+ T obj = sim_data.signals[id];
+ if (obj) {
+ get_value(obj);
+ } else {
+ std::cout << "Cannot find the object of id = " << id << std::endl;
+ finish();
+ exit(0);
+ }
+ }
+
+ void getid() {
+ std::string wire;
+ std::cin >> wire;
+ std::map<std::string, size_t>::iterator it = sim_data.signal_map.find(wire);
+ if (it != sim_data.signal_map.end()) {
+ std::cerr << it->second << std::endl;
+ } else {
+ int id = search(wire);
+ if (id < 0) {
+ std::cout << "Cannot find the object, " << wire<< std::endl;
+ finish();
+ exit(0);
+ }
+ std::cerr << id << std::endl;
+ }
+ }
+
+ void setclk() {
+ std::string clkname;
+ std::cin >> clkname;
+ typename std::map<std::string, T>::iterator it = sim_data.clk_map.find(clkname);
+ if (it != sim_data.clk_map.end()) {
+ put_value(it->second);
+ } else {
+ std::cout << "Cannot find " << clkname << std::endl;
+ }
+ }
+
+ void consume_tokens() {
+ for (size_t i = 0 ; i < sim_data.inputs.size() ; i++) {
+ put_value(sim_data.inputs[i]);
+ }
+ }
+
+ void generate_tokens() {
+ for (size_t i = 0 ; i < sim_data.outputs.size() ; i++) {
+ get_value(sim_data.outputs[i]);
+ }
+ }
+protected:
+ sim_data_t<T> sim_data;
+
+ void read_signal_map(std::string filename) {
+ std::ifstream file(filename.c_str());
+ if (!file) {
+ std::cout << "Cannot open " << filename << std::endl;
+ finish();
+ exit(0);
+ }
+ std::string line;
+ size_t id = 0;
+ while (std::getline(file, line)) {
+ std::istringstream iss(line);
+ std::string path;
+ size_t width, n;
+ iss >> path >> width >> n;
+ sim_data.signal_map[path] = id;
+ id += n;
+ }
+ }
+};
+
+#endif //__SIM_API_H
diff --git a/src/main/resources/vpi.cpp b/src/main/resources/vpi.cpp
new file mode 100644
index 00000000..7850f3b0
--- /dev/null
+++ b/src/main/resources/vpi.cpp
@@ -0,0 +1,130 @@
+#include "vpi.h"
+
+vpi_api_t vpi_api;
+
+/*==========================================================================
+ User Functions
+=============================================================================*/
+
+PLI_INT32 init_clks_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.init_clks();
+ return 0;
+}
+
+PLI_INT32 init_rsts_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.init_rsts();
+ return 0;
+}
+
+PLI_INT32 init_ins_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.init_ins();
+ return 0;
+}
+
+PLI_INT32 init_outs_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.init_outs();
+ return 0;
+}
+
+PLI_INT32 init_sigs_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.init_sigs();
+ return 0;
+}
+
+PLI_INT32 tick_calltf(PLI_BYTE8 *user_data) {
+ vpi_api.tick();
+ return 0;
+}
+
+PLI_INT32 tick_cb(p_cb_data cb_data) {
+ vpi_api.tick();
+ return 0;
+}
+
+/*==========================================================================
+ Registration Functions
+=============================================================================*/
+void init_clks_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$init_clks";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = init_clks_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+void init_rsts_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$init_rsts";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = init_rsts_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+void init_ins_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$init_ins";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = init_ins_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+void init_outs_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$init_outs";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = init_outs_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+void init_sigs_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$init_sigs";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = init_sigs_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+void tick_registration() {
+ s_vpi_systf_data tf_data;
+ tf_data.type = vpiSysTask;
+ tf_data.tfname = (PLI_BYTE8*) "$tick";
+ tf_data.sizetf = NULL;
+ tf_data.calltf = tick_calltf;
+ tf_data.compiletf = NULL;
+ tf_data.user_data = NULL;
+ vpi_register_systf(&tf_data);
+ return;
+}
+
+/*==========================================================================
+ Start-up Array
+=============================================================================*/
+void (*vlog_startup_routines[]) () = {
+ init_clks_registration,
+ init_rsts_registration,
+ init_ins_registration,
+ init_outs_registration,
+ init_sigs_registration,
+ tick_registration,
+ 0
+};
diff --git a/src/main/resources/vpi.h b/src/main/resources/vpi.h
new file mode 100644
index 00000000..09c2dc75
--- /dev/null
+++ b/src/main/resources/vpi.h
@@ -0,0 +1,212 @@
+#ifndef __VPI_H
+#define __VPI_h
+
+#include "vpi_user.h"
+#include "sim_api.h"
+#include <queue>
+
+PLI_INT32 tick_cb(p_cb_data cb_data);
+
+class vpi_api_t: public sim_api_t<vpiHandle> {
+public:
+ void init_clks() {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // Cache clocks
+ while (vpiHandle arg_handle = vpi_scan(arg_iter)) {
+ std::string name = vpi_get_str(vpiName, arg_handle);
+ sim_data.clk_map[name.substr(0, name.rfind("_len"))] = arg_handle;
+ }
+ }
+
+ void init_rsts() {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // Cache Resets
+ while (vpiHandle arg_handle = vpi_scan(arg_iter)) {
+ sim_data.resets.push_back(arg_handle);
+ }
+ }
+
+ void init_ins() {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // Cache Inputs
+ while (vpiHandle arg_handle = vpi_scan(arg_iter)) {
+ sim_data.inputs.push_back(arg_handle);
+ }
+ }
+
+ void init_outs() {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ vpiHandle arg_iter = vpi_iterate(vpiArgument, syscall_handle);
+ // Cache Outputs
+ while (vpiHandle arg_handle = vpi_scan(arg_iter)) {
+ sim_data.outputs.push_back(arg_handle);
+ }
+ }
+
+ void init_sigs() {
+ vpiHandle syscall_handle = vpi_handle(vpiSysTfCall, NULL);
+ top_handle = vpi_scan(vpi_iterate(vpiArgument, syscall_handle));
+ search_signals();
+ }
+
+private:
+ vpiHandle top_handle;
+
+ void put_value(vpiHandle& sig) {
+ std::string value;
+ for (size_t k = 0 ; k < ((vpi_get(vpiSize, sig) - 1) >> 6) + 1 ; k++) {
+ // 64 bit chunks are given
+ std::string v;
+ std::cin >> v;
+ value += v;
+ }
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ value_s.value.str = (PLI_BYTE8*) value.c_str();
+ vpi_put_value(sig, &value_s, NULL, vpiNoDelay);
+ }
+
+ void get_value(vpiHandle& sig) {
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ vpi_get_value(sig, &value_s);
+ std::cerr << value_s.value.str << std::endl;
+ }
+
+ virtual void reset() {
+ for (size_t i = 0 ; i < sim_data.resets.size() ; i++) {
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ value_s.value.str = (PLI_BYTE8*) "1";
+ vpi_put_value(sim_data.resets[i], &value_s, NULL, vpiNoDelay);
+ }
+ }
+
+ virtual void start() {
+ for (size_t i = 0 ; i < sim_data.resets.size() ; i++) {
+ s_vpi_value value_s;
+ value_s.format = vpiHexStrVal;
+ value_s.value.str = (PLI_BYTE8*) "0";
+ vpi_put_value(sim_data.resets[i], &value_s, NULL, vpiNoDelay);
+ }
+ }
+
+ virtual void finish() { vpi_control(vpiFinish, 0); }
+
+ virtual void step() { }
+
+ virtual void update() {
+ s_cb_data data_s;
+ s_vpi_time time_s;
+ time_s.type = vpiSimTime;
+ time_s.low = 0;
+ time_s.high = 0;
+ data_s.reason = cbReadWriteSynch;
+ data_s.cb_rtn = tick_cb;
+ data_s.obj = NULL;
+ data_s.time = &time_s;
+ data_s.value = NULL;
+ data_s.user_data = NULL;
+ vpi_free_object(vpi_register_cb(&data_s));
+ }
+
+ virtual size_t add_signal(vpiHandle& sig_handle, std::string& wire) {
+ size_t id = sim_data.signals.size();
+ sim_data.signals.push_back(sig_handle);
+ sim_data.signal_map[wire] = id;
+ return id;
+ }
+
+ int search_signals(const char *wire = NULL) {
+ int id = -1;
+ std::string wirepath = wire ? wire : "";
+ int dotpos = wirepath.rfind(".");
+ std::string modpath = dotpos > 0 ? wirepath.substr(0, dotpos) : "";
+ std::string wirename = dotpos > 0 ? wirepath.substr(dotpos+1) : "";
+ int sbrpos = wirename.rfind("[");
+ std::string arrname = sbrpos > 0 ? wirename.substr(0, sbrpos) : "";
+ std::queue<vpiHandle> modules;
+ size_t offset = std::string(vpi_get_str(vpiFullName, top_handle)).find(".") + 1;
+
+ // Start from the top module
+ modules.push(top_handle);
+
+ while (!modules.empty()) {
+ vpiHandle mod_handle = modules.front();
+ modules.pop();
+
+ std::string modname = std::string(vpi_get_str(vpiFullName, mod_handle)).substr(offset);
+ // If the module is found
+ if (!wire || modpath == modname) {
+ // Iterate its nets
+ vpiHandle net_iter = vpi_iterate(vpiNet, mod_handle);
+ while (vpiHandle net_handle = vpi_scan(net_iter)) {
+ std::string netname = vpi_get_str(vpiName, net_handle);
+ std::string netpath = modname + "." + netname;
+ size_t netid = (!wire && netname[0] != 'T') || wirename == netname ?
+ add_signal(net_handle, netpath) : 0;
+ id = netid ? netid : id;
+ if (id > 0) break;
+ }
+ if (id > 0) break;
+
+ // Iterate its regs
+ vpiHandle reg_iter = vpi_iterate(vpiReg, mod_handle);
+ while (vpiHandle reg_handle = vpi_scan(reg_iter)) {
+ std::string regname = vpi_get_str(vpiName, reg_handle);
+ std::string regpath = modname + "." + regname;
+ size_t regid = !wire || wirename == regname ?
+ add_signal(reg_handle, regpath) : 0;
+ id = regid ? regid : id;
+ if (id > 0) break;
+ }
+ if (id > 0) break;
+
+ // Iterate its mems
+ vpiHandle mem_iter = vpi_iterate(vpiRegArray, mod_handle);
+ while (vpiHandle mem_handle = vpi_scan(mem_iter)) {
+ std::string memname = vpi_get_str(vpiName, mem_handle);
+ if (!wire || arrname == memname) {
+ vpiHandle elm_iter = vpi_iterate(vpiReg, mem_handle);
+ size_t idx = vpi_get(vpiSize, mem_handle);
+ while (vpiHandle elm_handle = vpi_scan(elm_iter)) {
+ std::string elmname = vpi_get_str(vpiName, elm_handle);
+ std::string elmpath = modname + "." + elmname;
+ size_t elmid = add_signal(elm_handle, elmpath);
+ id = wirename == elmname ? elmid : id;
+ }
+ }
+ if (id > 0) break;
+ }
+ }
+
+ // Find DFF
+ if (!wire || wirepath == modname) {
+ vpiHandle udp_iter = vpi_iterate(vpiPrimitive, mod_handle);
+ while (vpiHandle udp_handle = vpi_scan(udp_iter)) {
+ if (vpi_get(vpiPrimType, udp_handle) == vpiSeqPrim) {
+ id = add_signal(udp_handle, modname);
+ break;
+ }
+ }
+ }
+ if (id > 0) break;
+
+ vpiHandle sub_iter = vpi_iterate(vpiModule, mod_handle);
+ while (vpiHandle sub_handle = vpi_scan(sub_iter)) {
+ modules.push(sub_handle);
+ }
+ }
+
+ return id;
+ }
+
+ virtual int search(std::string& wire) {
+ return search_signals(wire.c_str());
+ }
+};
+
+#endif // __VPI_H