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%.
This commit is contained in:
Cary R 2011-10-12 11:03:12 -07:00 committed by Stephen Williams
parent 52d05c0215
commit 8e3d80679d
2 changed files with 77 additions and 11 deletions

View File

@ -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);
}
}
}

View File

@ -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;
}