From 8e68e31801751664725dbb4b2c43920640ccb71d Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Tue, 20 Sep 2022 20:14:46 +0000 Subject: [PATCH] Initial PoC for calling pypowersim from within C code --- .../video/libvpx/pypowersim_wrapper_common.h | 108 ++++++++++++++++++ .../video/libvpx/pypowersim_wrapper_example.c | 65 +++++++++++ 2 files changed, 173 insertions(+) create mode 100644 media/video/libvpx/pypowersim_wrapper_common.h create mode 100644 media/video/libvpx/pypowersim_wrapper_example.c diff --git a/media/video/libvpx/pypowersim_wrapper_common.h b/media/video/libvpx/pypowersim_wrapper_common.h new file mode 100644 index 00000000..3b442b5c --- /dev/null +++ b/media/video/libvpx/pypowersim_wrapper_common.h @@ -0,0 +1,108 @@ +#include +#include +#include + +static const char* PLUGIN_NAME = "pypowersim"; + +typedef struct pypowersim_state { + PyObject *name; + PyObject *plugin_module; + PyObject *binary; + PyObject *bigendian; + PyObject *prog; + PyObject *qemu_cosim; + PyObject *initial_regs; + PyObject *initial_sprs; + PyObject *svstate; + PyObject *mmu; + PyObject *initial_cr; + PyObject *initial_mem; + PyObject *initial_fprs; + PyObject *initial_pc; + PyObject *args; + PyObject *simulator; + PyObject *result_obj; +} pypowersim_state_t; + +pypowersim_state_t *pypowersim_prepare(void) { + // Initialize Python C API + Py_Initialize(); + // Add pypowersim directory to Python path + PyObject* sysPath = PySys_GetObject((char*)"path"); + PyObject* curDir = PyUnicode_FromString("../../../src/openpower/decoder/isa/"); + PyList_Append(sysPath, curDir); + Py_DECREF(curDir); + + // Allocate memory for state + pypowersim_state_t *state = malloc(sizeof(pypowersim_state_t)); + if (!state) { + printf("Error creating pypowersim_state object\n"); + exit(1); + } + // Set plugin name and module + state->name = PyUnicode_FromString(PLUGIN_NAME); + state->plugin_module = PyImport_Import(state->name); + Py_DECREF(state->name); + if (!state->plugin_module) { + PyErr_Print(); + printf("Error importing module\n"); + exit(1); + } + // Set simulator object + state->simulator = PyObject_GetAttrString(state->plugin_module, "run_a_simulation"); + Py_DECREF(state->plugin_module); + if (!state->simulator) { + PyErr_Print(); + printf("Error retrieving 'run_a_simulation'\n"); + exit(1); + } + + // Little Endian for now + state->bigendian = Py_False; + state->prog = Py_None; + state->qemu_cosim = Py_False; + // Set and clear 128 GPRs + state->initial_regs = PyList_New(128); + for (int i=0; i < 128; i++) { + PyList_SetItem(state->initial_regs, i, PyLong_FromLong(0)); + } + // Create SPRs to all bits set + state->initial_sprs= PyDict_New(); + PyDict_SetItemString(state->initial_sprs, "LR", PyLong_FromLong(0xffffff)); + // Set empty SVSTATE + state->svstate = PyLong_FromLong(0); + // Set no MMU + state->mmu = Py_None; + // Set no initial CR + state->initial_cr = PyLong_FromLong(0); + // Set empty initial Memory + state->initial_mem = PyDict_New(); + // Set and Clear 128 FPR + state->initial_fprs = PyList_New(128); + for (int i=0; i < 128; i++) { + PyList_SetItem(state->initial_fprs, i, PyLong_FromLong(0)); + } + // Set initial Program Counter + state->initial_pc= PyLong_FromLong(0x0); + + return state; +} + +void pypowersim_prepareargs(pypowersim_state_t *state) { + // Set the tuple with the state objects + state->args = PyTuple_Pack(12, state->binary, state->bigendian, state->prog, state->qemu_cosim, + state->initial_regs, state->initial_sprs, state->svstate, state->mmu, + state->initial_cr, state->initial_mem, state->initial_fprs, state->initial_pc ); + if (!state->args) { + PyErr_Print(); + Py_DECREF(state->simulator); + printf("Error building args tuple\n"); + exit(1); + } +} + +void pypowersim_finalize(void) { + // Finalize Python C API + Py_Finalize(); +} + diff --git a/media/video/libvpx/pypowersim_wrapper_example.c b/media/video/libvpx/pypowersim_wrapper_example.c new file mode 100644 index 00000000..faa43920 --- /dev/null +++ b/media/video/libvpx/pypowersim_wrapper_example.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "pypowersim_wrapper_common.h" + +int test_function(int x) { + int result = 0; + for (int i=0; i < x; i++) + result += 2*i; + return result; +} + +int test_function_wrapper(int x) { + // Create the pypowersim_state + pypowersim_state_t *state = pypowersim_prepare(); + + // Change the relevant elements, mandatory: body + // + state->binary = PyBytes_FromStringAndSize((const char *)&test_function, 1000); + // Set GPR #3 to the argument x + PyList_SetItem(state->initial_regs, 3, PyLong_FromLong(x)); + + // Prepare the args object + pypowersim_prepareargs(state); + + // Call the function and get the resulting object + state->result_obj = PyObject_CallObject(state->simulator, state->args); + Py_DECREF(state->simulator); + Py_DECREF(state->args); + if (!state->result_obj) { + PyErr_Print(); + printf("Error invoking 'run_a_simulation'\n"); + } + + // Get the GPRs from the result_obj + PyObject *final_regs = PyObject_GetAttrString(state->result_obj, "gpr"); + if (!final_regs) { + PyErr_Print(); + Py_DECREF(state->result_obj); + printf("Error getting final GPRs\n"); + } + + // GPR #3 holds the return value as an integer + PyObject *key = PyLong_FromLong(3); + PyObject *itm = PyDict_GetItem(final_regs, key); + PyObject *value = PyObject_GetAttrString(itm, "value"); + uint64_t val = PyLong_AsLongLong(value); + + Py_DECREF(state->result_obj); + + // Return value + return val; +} + +int main(int argc, char* argv[]) { + for (int i=0; i < 20; i++) { + int result = test_function_wrapper(i); + printf("i = %d, result = %d\n", i, result); + } + pypowersim_finalize(); + return 0; +} + + -- 2.30.2