diff options
| author | Henry Cook | 2015-08-06 18:39:12 -0700 |
|---|---|---|
| committer | Henry Cook | 2015-08-08 16:38:25 -0700 |
| commit | c22364ee6495e8796b2db5ae2549f7164f0aee1d (patch) | |
| tree | b55a5758d89a817849ba607a64d3e458a1a6afed /src/main/resources | |
| parent | 6a3dfce4c9bf675d21e826567e6632549277e376 (diff) | |
verilog emulator resources
Diffstat (limited to 'src/main/resources')
| -rw-r--r-- | src/main/resources/sim_api.h | 156 | ||||
| -rw-r--r-- | src/main/resources/vpi.cpp | 130 | ||||
| -rw-r--r-- | src/main/resources/vpi.h | 212 |
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 |
