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/ivtest/ivltests/sv_string6.v b/ivtest/ivltests/sv_string6.v new file mode 100644 index 000000000..e0423b570 --- /dev/null +++ b/ivtest/ivltests/sv_string6.v @@ -0,0 +1,56 @@ +// Test the various string.Xtoa() methods + +module testbench; + string str; + int val; + real valr; + + + task test_string_value(string str, string reference); + if (str != reference) begin + $display("FAILED -- str=%0s, should be %s", str, reference); + $finish; + end + endtask // test_string_value + + initial begin + val = 11; + valr = 11.1; + + str.itoa(val); + test_string_value(str, "11"); + + str.hextoa(val); + test_string_value(str, "b"); + + str.octtoa(val); + test_string_value(str, "13"); + + str.bintoa(val); + test_string_value(str, "1011"); + + str.realtoa(valr); + test_string_value(str, "11.1"); + + val = -11; + valr = -11.1; + + str.itoa(val); + test_string_value(str, "-11"); + + str.hextoa(val); + test_string_value(str, "-b"); + + str.octtoa(val); + test_string_value(str, "-13"); + + str.bintoa(val); + test_string_value(str, "-1011"); + + str.realtoa(valr); + test_string_value(str, "-11.1"); + + $display("PASSED"); + + end +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 789b5e44e..4f73cad6a 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -525,6 +525,7 @@ sv_string2 normal,-g2009 ivltests sv_string3 normal,-g2009 ivltests sv_string4 normal,-g2009 ivltests sv_string5 normal,-g2009 ivltests +sv_string6 normal,-g2009 ivltests sv_timeunit_prec1 normal,-g2005-sv ivltests sv_timeunit_prec2 normal,-g2009 ivltests sv_timeunit_prec3a normal,-g2005-sv ivltests gold=sv_timeunit_prec3a.gold 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); }