GpiObjHdl *VpiImpl::get_root_handle(const char* name) { vpiHandle root; vpiHandle iterator; GpiObjHdl *rv; std::string root_name = name; // vpi_iterate with a ref of NULL returns the top level module iterator = vpi_iterate(vpiModule, NULL); check_vpi_error(); for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) { if (name == NULL || !strcmp(name, vpi_get_str(vpiFullName, root))) break; } if (!root) { check_vpi_error(); goto error; } //Need to free the iterator if it didn't return NULL if (iterator && !vpi_free_object(iterator)) { LOG_WARN("VPI: Attempting to free root iterator failed!"); check_vpi_error(); } rv = new GpiObjHdl(this, root); rv->initialise(root_name); return rv; error: LOG_CRITICAL("VPI: Couldn't find root handle %s", name); iterator = vpi_iterate(vpiModule, NULL); for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) { LOG_CRITICAL("VPI: Toplevel instances: %s != %s...", name, vpi_get_str(vpiFullName, root)); if (name == NULL || !strcmp(name, vpi_get_str(vpiFullName, root))) break; } return NULL; }
int VpiCbHdl::cleanup_callback(void) { if (m_state == GPI_FREE) return 0; /* If the one-time callback has not come back then * remove it, it is has then free it. The remove is done * internally */ if (m_state == GPI_PRIMED) { if (!m_obj_hdl) { LOG_CRITICAL("VPI: passed a NULL pointer : ABORTING"); } if (!(vpi_remove_cb(get_handle<vpiHandle>()))) { LOG_CRITICAL("VPI: unbale to remove callback : ABORTING"); } check_vpi_error(); } else { #ifndef MODELSIM /* This is disabled for now, causes a small leak going to put back in */ if (!(vpi_free_object(get_handle<vpiHandle>()))) { LOG_CRITICAL("VPI: unbale to free handle : ABORTING"); } #endif } m_obj_hdl = NULL; m_state = GPI_FREE; return 0; }
/* If the user data already has a callback handle then deregister * before getting the new one */ int VpiCbHdl::arm_callback(void) { if (m_state == GPI_PRIMED) { fprintf(stderr, "Attempt to prime an already primed trigger for %s!\n", m_impl->reason_to_string(cb_data.reason)); } // Only a problem if we have not been asked to deregister and register // in the same simultion callback if (m_obj_hdl != NULL && m_state != GPI_DELETE) { fprintf(stderr, "We seem to already be registered, deregistering %s!\n", m_impl->reason_to_string(cb_data.reason)); cleanup_callback(); } vpiHandle new_hdl = vpi_register_cb(&cb_data); if (!new_hdl) { LOG_ERROR("VPI: Unable to register a callback handle for VPI type %s(%d)", m_impl->reason_to_string(cb_data.reason), cb_data.reason); check_vpi_error(); return -1; } else { m_state = GPI_PRIMED; } m_obj_hdl = new_hdl; return 0; }
const char* VpiSignalObjHdl::get_signal_value_str(void) { s_vpi_value value_s = {vpiStringVal}; vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s); check_vpi_error(); return value_s.value.str; }
void VpiImpl::get_sim_time(uint32_t *high, uint32_t *low) { s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; //vpiSimTime; vpi_get_time(NULL, &vpi_time_s); check_vpi_error(); *high = vpi_time_s.high; *low = vpi_time_s.low; }
long VpiSignalObjHdl::get_signal_value_long(void) { FENTER s_vpi_value value_s = {vpiIntVal}; vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s); check_vpi_error(); return value_s.value.integer; }
double VpiSignalObjHdl::get_signal_value_real(void) { FENTER s_vpi_value value_s = {vpiRealVal}; vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s); check_vpi_error(); return value_s.value.real; }
const char* VpiSignalObjHdl::get_signal_value_binstr(void) { FENTER s_vpi_value value_s = {vpiBinStrVal}; p_vpi_value value_p = &value_s; vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), value_p); check_vpi_error(); return value_p->value.str; }
// If the Pything world wants things to shut down then unregister // the callback for end of sim void VpiImpl::sim_end(void) { /* Some sims do not seem to be able to deregister the end of sim callback * so we need to make sure we have tracked this and not call the handler */ if (GPI_DELETE != sim_finish_cb->get_call_state()) { sim_finish_cb->set_call_state(GPI_DELETE); vpi_control(vpiFinish); check_vpi_error(); } }
int VpiSignalObjHdl::set_signal_value(std::string &value) { FENTER s_vpi_value value_s; std::vector<char> writable(value.begin(), value.end()); writable.push_back('\0'); value_s.value.str = &writable[0]; value_s.format = vpiBinStrVal; vpi_put_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s, NULL, vpiNoDelay); check_vpi_error(); FEXIT return 0; }
int VpiSignalObjHdl::set_signal_value(double value) { FENTER s_vpi_value value_s; value_s.value.real = value; value_s.format = vpiRealVal; s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; vpi_time_s.high = 0; vpi_time_s.low = 0; vpi_put_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s, &vpi_time_s, vpiInertialDelay); check_vpi_error(); FEXIT return 0; }
// Value related functions int VpiSignalObjHdl::set_signal_value(long value) { FENTER s_vpi_value value_s; value_s.value.integer = value; value_s.format = vpiIntVal; s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; vpi_time_s.high = 0; vpi_time_s.low = 0; // Use Inertial delay to schedule an event, thus behaving like a verilog testbench vpi_put_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s, &vpi_time_s, vpiInertialDelay); check_vpi_error(); FEXIT return 0; }
int VpiSignalObjHdl::initialise(std::string &name, std::string &fq_name) { int32_t type = vpi_get(vpiType, GpiObjHdl::get_handle<vpiHandle>()); if ((vpiIntVar == type) || (vpiIntegerVar == type) || (vpiIntegerNet == type )) { m_num_elems = 1; } else { m_num_elems = vpi_get(vpiSize, GpiObjHdl::get_handle<vpiHandle>()); if (GpiObjHdl::get_type() == GPI_STRING) { m_indexable = false; // Don't want to iterate over indices m_range_left = 0; m_range_right = m_num_elems-1; } else if (GpiObjHdl::get_type() == GPI_REGISTER) { vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>(); m_indexable = vpi_get(vpiVector, hdl); if (m_indexable) { s_vpi_value val; vpiHandle iter; val.format = vpiIntVal; iter = vpi_iterate(vpiRange, hdl); /* Only ever need the first "range" */ if (iter != NULL) { vpiHandle rangeHdl = vpi_scan(iter); vpi_free_object(iter); if (rangeHdl != NULL) { vpi_get_value(vpi_handle(vpiLeftRange,rangeHdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,rangeHdl),&val); check_vpi_error(); m_range_right = val.value.integer; } else { LOG_CRITICAL("Unable to get Range for indexable object"); } } else { vpi_get_value(vpi_handle(vpiLeftRange,hdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,hdl),&val); check_vpi_error(); m_range_right = val.value.integer; } LOG_DEBUG("VPI: Indexable Object initialised with range [%d:%d] and length >%d<", m_range_left, m_range_right, m_num_elems); } } } LOG_DEBUG("VPI: %s initialised with %d elements", name.c_str(), m_num_elems); return GpiObjHdl::initialise(name, fq_name); }
int VpiArrayObjHdl::initialise(std::string &name, std::string &fq_name) { vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>(); m_indexable = true; int range_idx = 0; /* Need to determine if this is a pseudo-handle to be able to select the correct range */ std::string hdl_name = vpi_get_str(vpiName, hdl); /* Removing the hdl_name from the name will leave the psuedo-indices */ if (hdl_name.length() < name.length()) { std::string idx_str = name.substr(hdl_name.length()); while (idx_str.length() > 0) { std::size_t found = idx_str.find_first_of("]"); if (found != std::string::npos) { ++range_idx; idx_str = idx_str.substr(found+1); } else { break; } } } /* After determining the range_idx, get the range and set the limits */ vpiHandle iter = vpi_iterate(vpiRange, hdl); s_vpi_value val; val.format = vpiIntVal; if (iter != NULL) { vpiHandle rangeHdl; int idx = 0; while ((rangeHdl = vpi_scan(iter)) != NULL) { if (idx == range_idx) { break; } ++idx; } if (rangeHdl == NULL) { LOG_CRITICAL("Unable to get Range for indexable object"); } else { vpi_free_object(iter); // Need to free iterator since exited early vpi_get_value(vpi_handle(vpiLeftRange,rangeHdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,rangeHdl),&val); check_vpi_error(); m_range_right = val.value.integer; } } else if (range_idx == 0) { vpi_get_value(vpi_handle(vpiLeftRange,hdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,hdl),&val); check_vpi_error(); m_range_right = val.value.integer; } else { LOG_CRITICAL("Unable to get Range for indexable object"); } /* vpiSize will return a size that is incorrect for multi-dimensional arrays so use the range * to calculate the m_num_elems. * * For example: * wire [7:0] sig_t4 [0:3][7:4] * * The size of "sig_t4" will be reported as 16 through the vpi interface. */ if (m_range_left > m_range_right) { m_num_elems = m_range_left - m_range_right + 1; } else { m_num_elems = m_range_right - m_range_left + 1; } return GpiObjHdl::initialise(name, fq_name); }