static PyObject *stop_simulator(PyObject *self, PyObject *args) { gpi_sim_end(); return Py_BuildValue("s", "OK!"); }
void embed_sim_init(gpi_sim_info_t *info) { FENTER int i; // Find the simulation root gpi_sim_hdl dut = gpi_get_root_handle(getenv("TOPLEVEL")); if (dut == NULL) { fprintf(stderr, "Unable to find root instance!\n"); gpi_sim_end(); return; } PyObject *cocotb_module, *cocotb_init, *cocotb_args, *cocotb_retval; PyObject *simlog_obj, *simlog_func; PyObject *argv_list, *argc, *arg_dict, *arg_value; cocotb_module = NULL; arg_dict = NULL; //Ensure that the current thread is ready to callthe Python C API PyGILState_STATE gstate = PyGILState_Ensure(); if (get_module_ref(COCOTB_MODULE, &cocotb_module)) goto cleanup; // Create a logger object simlog_obj = PyObject_GetAttrString(cocotb_module, "log"); if (simlog_obj == NULL) { PyErr_Print(); fprintf(stderr, "Failed to to get simlog object\n"); } simlog_func = PyObject_GetAttrString(simlog_obj, "_printRecord"); if (simlog_func == NULL) { PyErr_Print(); fprintf(stderr, "Failed to get the _printRecord method"); goto cleanup; } if (!PyCallable_Check(simlog_func)) { PyErr_Print(); fprintf(stderr, "_printRecord is not callable"); goto cleanup; } set_log_handler(simlog_func); Py_DECREF(simlog_func); simlog_func = PyObject_GetAttrString(simlog_obj, "_willLog"); if (simlog_func == NULL) { PyErr_Print(); fprintf(stderr, "Failed to get the _willLog method"); goto cleanup; } if (!PyCallable_Check(simlog_func)) { PyErr_Print(); fprintf(stderr, "_willLog is not callable"); goto cleanup; } set_log_filter(simlog_func); argv_list = PyList_New(0); for (i = 0; i < info->argc; i++) { arg_value = PyString_FromString(info->argv[i]); PyList_Append(argv_list, arg_value); } arg_dict = PyModule_GetDict(cocotb_module); PyDict_SetItemString(arg_dict, "argv", argv_list); argc = PyInt_FromLong(info->argc); PyDict_SetItemString(arg_dict, "argc", argc); if (!PyCallable_Check(simlog_func)) { PyErr_Print(); fprintf(stderr, "_printRecord is not callable"); goto cleanup; } LOG_INFO("Running on %s version %s", info->product, info->version); LOG_INFO("Python interpreter initialised and cocotb loaded!"); // Now that logging has been set up ok we initialise the testbench if (-1 == PyObject_SetAttrString(cocotb_module, "SIM_NAME", PyString_FromString(info->product))) { PyErr_Print(); fprintf(stderr, "Unable to set SIM_NAME"); goto cleanup; } // Hold onto a reference to our _fail_test function pEventFn = PyObject_GetAttrString(cocotb_module, "_sim_event"); if (!PyCallable_Check(pEventFn)) { PyErr_Print(); fprintf(stderr, "cocotb._sim_event is not callable"); goto cleanup; } Py_INCREF(pEventFn); cocotb_init = PyObject_GetAttrString(cocotb_module, "_initialise_testbench"); // New reference if (cocotb_init == NULL || !PyCallable_Check(cocotb_init)) { if (PyErr_Occurred()) PyErr_Print(); fprintf(stderr, "Cannot find function \"%s\"\n", "_initialise_testbench"); Py_DECREF(cocotb_init); goto cleanup; } cocotb_args = PyTuple_New(1); PyTuple_SetItem(cocotb_args, 0, PyLong_FromLong((long)dut)); // Note: This function “steals” a reference to o. cocotb_retval = PyObject_CallObject(cocotb_init, cocotb_args); if (cocotb_retval != NULL) { LOG_DEBUG("_initialise_testbench successful"); Py_DECREF(cocotb_retval); } else { PyErr_Print(); fprintf(stderr,"Call failed\n"); gpi_sim_end(); goto cleanup; } FEXIT cleanup: if (cocotb_module) { Py_DECREF(cocotb_module); } if (arg_dict) { Py_DECREF(arg_dict); } PyGILState_Release(gstate); }
/** * @name Callback Handling * @brief Handle a callback coming from GPI * @ingroup python_c_api * * GILState before calling: Unknown * * GILState after calling: Unknown * * Makes one call to TAKE_GIL and one call to DROP_GIL * * Returns 0 on success or 1 on a failure. * * Handles a callback from the simulator, all of which call this function. * * We extract the associated context and find the Python function (usually * cocotb.scheduler.react) calling it with a reference to the trigger that * fired. The scheduler can then call next() on all the coroutines that * are waiting on that particular trigger. * * TODO: * - Tidy up return values * - Ensure cleanup correctly in exception cases * */ int handle_gpi_callback(void *user_data) { int ret = 0; to_python(); p_callback_data callback_data_p = (p_callback_data)user_data; if (callback_data_p->id_value != COCOTB_ACTIVE_ID) { fprintf(stderr, "Userdata corrupted!\n"); ret = 1; goto err; } callback_data_p->id_value = COCOTB_INACTIVE_ID; /* Cache the sim time */ gpi_get_sim_time(&cache_time.high, &cache_time.low); PyGILState_STATE gstate; gstate = TAKE_GIL(); // Python allowed if (!PyCallable_Check(callback_data_p->function)) { fprintf(stderr, "Callback fired but function isn't callable?!\n"); ret = 1; goto out; } // Call the callback PyObject *pValue = PyObject_Call(callback_data_p->function, callback_data_p->args, callback_data_p->kwargs); // If the return value is NULL a Python exception has occurred // The best thing to do here is shutdown as any subsequent // calls will go back to python which is now in an unknown state if (pValue == NULL) { fprintf(stderr, "ERROR: called callback function returned NULL\n"); if (PyErr_Occurred()) { fprintf(stderr, "Failed to execute callback due to python exception\n"); PyErr_Print(); } else { fprintf(stderr, "Failed to execute callback\n"); } gpi_sim_end(); ret = 0; goto out; } // Free up our mess Py_DECREF(pValue); // Callbacks may have been re-enabled if (callback_data_p->id_value == COCOTB_INACTIVE_ID) { Py_DECREF(callback_data_p->function); Py_DECREF(callback_data_p->args); // Free the callback data free(callback_data_p); } out: DROP_GIL(gstate); err: to_simulator(); return ret; }