From e6bab9227430a62744d2e48e00ce39b0d47ccf60 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 27 Feb 2022 20:28:30 -0800 Subject: [PATCH] Implement the string val-to-a methods These methods are tasks that write into the "this" object the value passed as an argument, converted using the appropriate base. --- elaborate.cc | 41 +++++++++ vpi/v2009_string.c | 213 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 6 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index a0aed45db..a54a4b822 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -45,6 +45,7 @@ # include "netvector.h" # include "netdarray.h" # include "netparray.h" +# include "netscalar.h" # include "netclass.h" # include "netmisc.h" # include "util.h" @@ -3721,6 +3722,14 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, use_path.push_front(name_component_t(perm_string::literal(THIS_TOKEN))); } + if (debug_elaborate) { + cerr << get_fileline() << ": PCallTask::elaborate_method_: " + << "use_path=" << use_path + << ", method_name=" << method_name + << ", add_this_flag=" << add_this_flag + << endl; + } + // There is no signal to search for so this cannot be a method. if (use_path.empty()) return 0; @@ -3733,6 +3742,38 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, if (net == 0) return 0; + if (debug_elaborate) { + cerr << get_fileline() << ": PCallTask::elaborate_method_: " + << "Try to match method " << method_name + << " of object " << net->name() + << "." << endl; + if (net->net_type()) + cerr << get_fileline() << ": PCallTask::elaborate_method_: " + << net->name() << ".net_type() --> " + << *net->net_type() << endl; + cerr << get_fileline() << ": PCallTask::elaborate_method_: " + << net->name() << ".data_type() --> " << net->data_type() << endl; + } + + // Is this a method of a "string" type? + if (dynamic_cast(net->net_type())) { + if (method_name=="itoa") + return elaborate_sys_task_method_(des, scope, net, method_name, + "$ivl_string_method$itoa"); + else if (method_name=="hextoa") + return elaborate_sys_task_method_(des, scope, net, method_name, + "$ivl_string_method$hextoa"); + else if (method_name=="octtoa") + return elaborate_sys_task_method_(des, scope, net, method_name, + "$ivl_string_method$octtoa"); + else if (method_name=="bintoa") + return elaborate_sys_task_method_(des, scope, net, method_name, + "$ivl_string_method$bintoa"); + else if (method_name=="realtoa") + return elaborate_sys_task_method_(des, scope, net, method_name, + "$ivl_string_method$realtoa"); + } + // Is this a delete method for dynamic arrays or queues? if (net->darray_type()) { if (method_name=="delete") diff --git a/vpi/v2009_string.c b/vpi/v2009_string.c index dedf4c43d..4ffcd1108 100644 --- a/vpi/v2009_string.c +++ b/vpi/v2009_string.c @@ -24,7 +24,7 @@ # include # include -static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 one_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv; @@ -34,7 +34,7 @@ static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires a string argument.\n", name); + vpi_printf("%s requires a single argument.\n", name); vpip_set_return_value(1); vpi_control(vpiFinish, 1); return 0; @@ -56,6 +56,55 @@ static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } +static PLI_INT32 two_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s missing arguments.\n", name); + vpip_set_return_value(1); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s missing object argument.\n", name); + vpip_set_return_value(1); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s missing method argument.\n", name); + vpip_set_return_value(1); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (arg != 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s has too many arguments.\n", name); + vpip_set_return_value(1); + vpi_control(vpiFinish, 1); + return 0; + } + + return 0; +} + static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); @@ -211,6 +260,116 @@ static PLI_INT32 atohex_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } +/* + * Convert a val to a text string that represents the value. The base + * is the integer base to use for the conversion. The base will be one + * of the values 2, 8, 10, or 16. If the input value is negative, then + * extract the sign out (and put a '-' in the beginning of the string and + * write the digits for the abs(val). For example, if the input value + * is -11 and base is 8, then the text output will be "-13". + */ +static void value_to_text_base(char*text, long val, long base) +{ + static const char digit_map[16] = "0123456789abcdef"; + char* ptr; + + assert(base <= 16); + if (val == 0) { + text[0] = '0'; + text[1] = 0; + return; + } + + if (val < 0) { + *text++ = '-'; + val = 0-val; + } + + ptr = text; + while (val != 0) { + long digit = val % base; + val /= base; + *(ptr++) = digit_map[digit]; + *ptr = 0; + } + + /* Now the text string is valid, but digits are reversed. */ + ptr -= 1; + while (text < ptr) { + char tmp = *ptr; + *ptr = *text; + *text = tmp; + ptr -= 1; + text += 1; + } +} + +/* + * This function implements the .itoa(arg) method. + * The first argument to this task is the object, and the second + * is the value to interpret. + */ +static PLI_INT32 xtoa_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle obj, arg; + s_vpi_value value; + char text_buf[64]; + long use_base; + + use_base = strtoul(name, 0, 10); + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + obj = vpi_scan(argv); + assert(obj); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + value.format = vpiIntVal; + vpi_get_value(arg, &value); + + value_to_text_base(text_buf, value.value.integer, use_base); + + value.format = vpiStringVal; + value.value.str = text_buf; + vpi_put_value(obj, &value, 0, vpiNoDelay); + + return 0; +} + +static PLI_INT32 realtoa_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle obj, arg; + s_vpi_value value; + char text_buf[64]; + + (void) name; + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + obj = vpi_scan(argv); + assert(obj); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + value.format = vpiRealVal; + vpi_get_value(arg, &value); + + snprintf(text_buf, sizeof text_buf, "%g", value.value.real); + + value.format = vpiStringVal; + value.value.str = text_buf; + vpi_put_value(obj, &value, 0, vpiNoDelay); + + return 0; +} + void v2009_string_register(void) { s_vpi_systf_data tf_data; @@ -220,7 +379,7 @@ void v2009_string_register(void) tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$ivl_string_method$len"; tf_data.calltf = len_calltf; - tf_data.compiletf = one_string_arg_compiletf; + tf_data.compiletf = one_arg_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$ivl_string_method$len"; res = vpi_register_systf(&tf_data); @@ -230,7 +389,7 @@ void v2009_string_register(void) tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$ivl_string_method$atoi"; tf_data.calltf = atoi_calltf; - tf_data.compiletf = one_string_arg_compiletf; + tf_data.compiletf = one_arg_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$ivl_string_method$atoi"; res = vpi_register_systf(&tf_data); @@ -240,7 +399,7 @@ void v2009_string_register(void) tf_data.sysfunctype = vpiRealFunc; tf_data.tfname = "$ivl_string_method$atoreal"; tf_data.calltf = atoreal_calltf; - tf_data.compiletf = one_string_arg_compiletf; + tf_data.compiletf = one_arg_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$ivl_string_method$atoreal"; res = vpi_register_systf(&tf_data); @@ -250,9 +409,51 @@ void v2009_string_register(void) tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$ivl_string_method$atohex"; tf_data.calltf = atohex_calltf; - tf_data.compiletf = one_string_arg_compiletf; + tf_data.compiletf = one_arg_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$ivl_string_method$atohex"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$ivl_string_method$itoa"; + tf_data.calltf = xtoa_calltf; + tf_data.compiletf = two_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "10"; + res = vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$ivl_string_method$hextoa"; + tf_data.calltf = xtoa_calltf; + tf_data.compiletf = two_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "16"; + res = vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$ivl_string_method$octtoa"; + tf_data.calltf = xtoa_calltf; + tf_data.compiletf = two_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "8"; + res = vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$ivl_string_method$bintoa"; + tf_data.calltf = xtoa_calltf; + tf_data.compiletf = two_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "2"; + res = vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$ivl_string_method$realtoa"; + tf_data.calltf = realtoa_calltf; + tf_data.compiletf = two_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_string_method$realtoa"; + res = vpi_register_systf(&tf_data); + + vpip_make_systf_system_defined(res); }