From 8e3d80679df0eb6333f4ccde123d9eb180a0657d Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 12 Oct 2011 11:03:12 -0700 Subject: [PATCH] Add an implementation for the enumeration name() method. Add an implementation for the enumeration name() method. This currently only works if the context defines the return width (e.g. the result is assigned to a variable). It does not work in a self-determined context (e.g. as an argument to a system function or in a comparison). This is a limitation in the compiler/code generator/run time not the method implementation provided here. We may need full string support to make this work 100%. --- elab_expr.cc | 19 ++++++++++--- vpi/v2009_enum.c | 69 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index fdb62f78c..ad24ecff3 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1277,6 +1277,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, pform_name_t use_path, perm_string method_name, NetExpr*expr, + unsigned rtn_wid, PExpr*parg, unsigned args) { // The "num()" method returns the number of elements. @@ -1355,10 +1356,21 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, "take an argument." << endl; des->errors += 1; } - sys_expr = new NetESFunc("$ivl_enum_method$name", IVL_VT_STRING, 0, 2); + sys_expr = new NetESFunc("$ivl_enum_method$name", IVL_VT_STRING, + rtn_wid, 2); sys_expr->parm(0, new NetENetenum(netenum)); sys_expr->parm(1, expr); + /* The compiler/code generators need to be fixed to support a + * string return value. In some contexts we could use the + * expression width, but that doesn't always work. */ + if (rtn_wid == 0) { + cerr << li->get_fileline() << ": sorry: Enumeration method " + "name() is not currently supported in this context " + "(self-determined)." << endl; + des->errors += 1; + } + // The "next()" method returns the next enumeration value. } else if (method_name == "next") { if (args > 1) { @@ -1457,7 +1469,8 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return check_for_enum_methods(this, des, scope, netenum, use_path, method_name, expr, - tmp, parms_.size()); + expr_wid, tmp, + parms_.size()); } } } @@ -2288,7 +2301,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return check_for_enum_methods(this, des, scope, netenum, use_path, method_name, - expr, NULL, 0); + expr, expr_wid, NULL, 0); } } } diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index 366185e86..d5b857862 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -296,8 +296,7 @@ static PLI_INT32 ivl_enum_method_next_prev_calltf(PLI_BYTE8*name) /* If the variable is a vector then free the copy we created above. */ if (var_val.format == vpiVectorVal) free(var_val.value.vector); - /* The current value was not found in the list so return X. This - * gives 0 for two-state variables. */ + /* The current value was not found in the list so return X/0. */ if (cur == 0) { /* This only works correctly since we don't really define the * the correct base typespec. */ @@ -420,11 +419,6 @@ static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_control(vpiFinish, 1); } - vpi_printf("%s:%d: sorry: ", vpi_get_str(vpiFile, sys), - (int) vpi_get(vpiLineNo,sys)); - vpi_printf("enum method %s is not currently supported.\n", name); - vpi_control(vpiFinish, 1); - return 0; } @@ -433,7 +427,66 @@ static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) */ static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name) { - assert(0); + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg_enum = vpi_scan(argv); + vpiHandle arg_var = vpi_scan(argv); + + vpiHandle enum_list; + vpiHandle cur; + PLI_INT32 var_width = vpi_get(vpiSize, arg_var); + + s_vpi_value cur_val, var_val; + + /* Free the argument iterator. */ + vpi_free_object(argv); + + /* Get the current value. */ + var_val.format = vpiObjTypeVal; + vpi_get_value(arg_var, &var_val); + + /* If the current value is a vector, then make a safe copy of + it so that other vpi_get_value() calls don't trash the value. */ + if (var_val.format == vpiVectorVal) { + PLI_INT32 idx; + PLI_INT32 words = (var_width - 1)/32 + 1; + p_vpi_vecval nvec = malloc(words*sizeof(s_vpi_vecval)); + for (idx = 0 ; idx < words ; idx += 1) { + nvec[idx].aval = var_val.value.vector[idx].aval; + nvec[idx].bval = var_val.value.vector[idx].bval; + } + var_val.value.vector = nvec; + } + + /* Search for the current value in the enumeration list. */ + enum_list = vpi_iterate(vpiEnumConst, arg_enum); + assert(enum_list); + do { + cur = vpi_scan(enum_list); + if (cur == 0) break; + + cur_val.format = vpiObjTypeVal; + vpi_get_value(cur, &cur_val); + assert(var_width == vpi_get(vpiSize, cur)); + } while (! compare_value_eequal(&cur_val, &var_val, var_width)); + + /* If the variable is a vector then free the copy we created above. */ + if (var_val.format == vpiVectorVal) free(var_val.value.vector); + + /* The current value was not found in the list so return an empty + * string. */ + cur_val.format = vpiStringVal; + if (cur == 0) { + cur_val.value.str = ""; + } else { + cur_val.value.str = vpi_get_str(vpiName, cur); + + /* Free the iterator. */ + vpi_free_object(enum_list); + } + + /* Return the appropriate string value. */ + vpi_put_value(sys, &cur_val, 0, vpiNoDelay); return 0; }