Rework enumeration next() and prev() methods to support count argument.
Rework the actual next() and prev() methods to correctly process the numeric count argument. Also rework the compiletf routine to give better error messages and combine the call routine for the two methods. Add a compiletf routine that checks the arguments and then report that the name() method is not currently implemented.
This commit is contained in:
parent
4692756eb9
commit
b905c699d1
44
elab_expr.cc
44
elab_expr.cc
|
|
@ -1355,8 +1355,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
|
||||||
"take an argument." << endl;
|
"take an argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
sys_expr = new NetESFunc("$ivl_method$name", IVL_VT_STRING, 0, 1);
|
sys_expr = new NetESFunc("$ivl_enum_method$name", IVL_VT_STRING, 0, 2);
|
||||||
sys_expr->parm(0, expr);
|
sys_expr->parm(0, new NetENetenum(netenum));
|
||||||
|
sys_expr->parm(1, expr);
|
||||||
|
|
||||||
// The "next()" method returns the next enumeration value.
|
// The "next()" method returns the next enumeration value.
|
||||||
} else if (method_name == "next") {
|
} else if (method_name == "next") {
|
||||||
|
|
@ -1366,16 +1367,11 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
|
||||||
"most one argument." << endl;
|
"most one argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
sys_expr = new NetESFunc("$ivl_method$next", netenum,
|
sys_expr = new NetESFunc("$ivl_enum_method$next", netenum,
|
||||||
2 + (args != 0));
|
2 + (args != 0));
|
||||||
sys_expr->parm(0, new NetENetenum(netenum));
|
sys_expr->parm(0, new NetENetenum(netenum));
|
||||||
sys_expr->parm(1, expr);
|
sys_expr->parm(1, expr);
|
||||||
if (args != 0) sys_expr->parm(2, count);
|
if (args != 0) sys_expr->parm(2, count);
|
||||||
if (args != 0) {
|
|
||||||
cerr << li->get_fileline() << ": sorry: enumeration method "
|
|
||||||
<< use_path << ".next() cannot currently take an argument." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The "prev()" method returns the previous enumeration value.
|
// The "prev()" method returns the previous enumeration value.
|
||||||
} else if (method_name == "prev") {
|
} else if (method_name == "prev") {
|
||||||
|
|
@ -1385,16 +1381,11 @@ if (args != 0) {
|
||||||
"most one argument." << endl;
|
"most one argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
sys_expr = new NetESFunc("$ivl_method$prev", netenum,
|
sys_expr = new NetESFunc("$ivl_enum_method$prev", netenum,
|
||||||
2 + (args != 0));
|
2 + (args != 0));
|
||||||
sys_expr->parm(0, new NetENetenum(netenum));
|
sys_expr->parm(0, new NetENetenum(netenum));
|
||||||
sys_expr->parm(1, expr);
|
sys_expr->parm(1, expr);
|
||||||
if (args != 0) sys_expr->parm(2, count);
|
if (args != 0) sys_expr->parm(2, count);
|
||||||
if (args != 0) {
|
|
||||||
cerr << li->get_fileline() << ": sorry: enumeration method "
|
|
||||||
<< use_path << ".prev() cannot currently take an argument." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an unknown enumeration method.
|
// This is an unknown enumeration method.
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1455,13 +1446,12 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||||
if (net != 0) {
|
if (net != 0) {
|
||||||
netenum_t*netenum = net->enumeration();
|
netenum_t*netenum = net->enumeration();
|
||||||
if (netenum) {
|
if (netenum) {
|
||||||
// We may need the elaborated version of the
|
// We may need the net expression for the
|
||||||
// enumeration variable so elaborate it now.
|
// enumeration variable so get it.
|
||||||
PEIdent pexpr(use_path);
|
NetESignal*expr = new NetESignal(net);
|
||||||
NetExpr*expr = pexpr.elaborate_expr(des, scope,
|
expr->set_line(*this);
|
||||||
expr_wid,
|
// This expression cannot be a select!
|
||||||
NO_FLAGS);
|
assert(use_path.back().index.empty());
|
||||||
assert(expr);
|
|
||||||
|
|
||||||
PExpr*tmp = parms_.size() ? parms_[0] : 0;
|
PExpr*tmp = parms_.size() ? parms_[0] : 0;
|
||||||
return check_for_enum_methods(this, des, scope,
|
return check_for_enum_methods(this, des, scope,
|
||||||
|
|
@ -2288,12 +2278,12 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||||
if (net != 0) {
|
if (net != 0) {
|
||||||
netenum_t*netenum = net->enumeration();
|
netenum_t*netenum = net->enumeration();
|
||||||
if (netenum) {
|
if (netenum) {
|
||||||
// We may need the elaborated version of the
|
// We may need the net expression for the
|
||||||
// enumeration variable so elaborate it now.
|
// enumeration variable so get it.
|
||||||
NetExpr*expr = elaborate_expr_net(des, scope, net,
|
NetESignal*expr = new NetESignal(net);
|
||||||
found_in, expr_wid,
|
expr->set_line(*this);
|
||||||
NO_FLAGS);
|
// This expression cannot be a select!
|
||||||
assert(expr);
|
assert(use_path.back().index.empty());
|
||||||
|
|
||||||
return check_for_enum_methods(this, des, scope,
|
return check_for_enum_methods(this, des, scope,
|
||||||
netenum,
|
netenum,
|
||||||
|
|
|
||||||
504
vpi/v2009_enum.c
504
vpi/v2009_enum.c
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -20,243 +20,455 @@
|
||||||
# include "vpi_config.h"
|
# include "vpi_config.h"
|
||||||
# include "sv_vpi_user.h"
|
# include "sv_vpi_user.h"
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
static void missing_arguments(vpiHandle sys)
|
/*
|
||||||
{
|
* The compiletf routine for the enumeration next() and prev() methods.
|
||||||
vpi_printf("%s:%d: error: Invalid/missing arguments next/prev method\n",
|
*/
|
||||||
vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo,sys));
|
static PLI_INT32 ivl_enum_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLI_INT32 ivl_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
|
||||||
{
|
{
|
||||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||||
vpiHandle arg_enum, arg_item, arg_extra;
|
vpiHandle arg_enum, arg_var, arg_count;
|
||||||
|
|
||||||
|
/* These routines must have arguments. */
|
||||||
if (argv == 0) {
|
if (argv == 0) {
|
||||||
missing_arguments(sys);
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("No arguments given for enum method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for the enumeration type argument. */
|
||||||
arg_enum = vpi_scan(argv);
|
arg_enum = vpi_scan(argv);
|
||||||
if (arg_enum == 0) {
|
if (arg_enum == 0) {
|
||||||
missing_arguments(sys);
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("No enumeration type argument given for enum "
|
||||||
|
"method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_item = vpi_scan(argv);
|
|
||||||
if (arg_item == 0) {
|
|
||||||
missing_arguments(sys);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure there are no excess arguments */
|
|
||||||
arg_extra = vpi_scan(argv);
|
|
||||||
if (arg_extra != 0) {
|
|
||||||
missing_arguments(sys);
|
|
||||||
vpi_free_object(argv);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The first argument must be an enum typespec */
|
|
||||||
if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) {
|
if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) {
|
||||||
missing_arguments(sys);
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
return 0;
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The first argument to enum method %s() must be an "
|
||||||
|
"enumeration type, found a %s.\n", name,
|
||||||
|
vpi_get_str(vpiType, arg_enum));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The return value and input value must be the same size */
|
/* Check for the enumeration variable. */
|
||||||
if (vpi_get(vpiSize,sys) != vpi_get(vpiSize,arg_item)) {
|
arg_var = vpi_scan(argv);
|
||||||
missing_arguments(sys);
|
if (arg_var == 0) {
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("No enumeration variable argument given for enum "
|
||||||
|
"method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
switch(vpi_get(vpiType, arg_var)) {
|
||||||
|
case vpiBitVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiLongIntVar:
|
||||||
|
case vpiReg:
|
||||||
|
case vpiShortIntVar:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The second argument to enum method %s() must be an "
|
||||||
|
"enumeration variable, found a %s.\n", name,
|
||||||
|
vpi_get_str(vpiType, arg_var));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can have an optional numeric count value. */
|
||||||
|
arg_count = vpi_scan(argv);
|
||||||
|
if (arg_count) {
|
||||||
|
switch(vpi_get(vpiType, arg_count)) {
|
||||||
|
case vpiBitVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiLongIntVar:
|
||||||
|
case vpiMemoryWord:
|
||||||
|
case vpiNet:
|
||||||
|
case vpiPartSelect:
|
||||||
|
case vpiRealVar:
|
||||||
|
case vpiReg:
|
||||||
|
case vpiShortIntVar:
|
||||||
|
case vpiTimeVar:
|
||||||
|
break;
|
||||||
|
case vpiConstant:
|
||||||
|
case vpiParameter:
|
||||||
|
if (vpi_get(vpiConstType, arg_count) != vpiStringConst) break;
|
||||||
|
default:
|
||||||
|
vpi_printf("%s:%d: compiler error: ",
|
||||||
|
vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The second argument to enum method %s() must be "
|
||||||
|
"numeric, found a %s.\n", name,
|
||||||
|
vpi_get_str(vpiType, arg_count));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a count argument then check to see if any extra
|
||||||
|
* arguments were given. */
|
||||||
|
if (arg_count && (vpi_scan(argv) != 0)) {
|
||||||
|
vpi_free_object(argv);
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("Extra argument(s) given to enum method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The method return value and the enum variable must be the
|
||||||
|
* same size */
|
||||||
|
if (vpi_get(vpiSize, sys) != vpi_get(vpiSize, arg_var)) {
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The enum method %s() return width (%d) must match "
|
||||||
|
"the enum variable width (%d).\n", name,
|
||||||
|
(int) vpi_get(vpiSize, sys),
|
||||||
|
(int) vpi_get(vpiSize, arg_var));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_value_eequal(s_vpi_value*ref1, s_vpi_value*ref2, long wid)
|
/*
|
||||||
|
* Compare it two values are equal to each other.
|
||||||
|
*/
|
||||||
|
static int compare_value_eequal(s_vpi_value*ref1, s_vpi_value*ref2,
|
||||||
|
PLI_INT32 wid)
|
||||||
{
|
{
|
||||||
|
/* Two integer values are easy. */
|
||||||
if (ref1->format == vpiIntVal && ref2->format == vpiIntVal)
|
if (ref1->format == vpiIntVal && ref2->format == vpiIntVal)
|
||||||
return ref1->value.integer == ref2->value.integer;
|
return ref1->value.integer == ref2->value.integer;
|
||||||
|
|
||||||
|
/* For two vectors compare them word by word. */
|
||||||
if (ref1->format == vpiVectorVal && ref2->format == vpiVectorVal) {
|
if (ref1->format == vpiVectorVal && ref2->format == vpiVectorVal) {
|
||||||
int words = (wid-1)/32 + 1;
|
PLI_INT32 words = (wid-1)/32 + 1;
|
||||||
int idx;
|
PLI_INT32 idx;
|
||||||
|
|
||||||
for (idx = 0 ; idx < words ; idx += 1) {
|
for (idx = 0 ; idx < words ; idx += 1) {
|
||||||
if (ref1->value.vector[idx].aval != ref2->value.vector[idx].aval)
|
if (ref1->value.vector[idx].aval !=
|
||||||
return 0;
|
ref2->value.vector[idx].aval) return 0;
|
||||||
if (ref1->value.vector[idx].bval != ref2->value.vector[idx].bval)
|
if (ref1->value.vector[idx].bval !=
|
||||||
return 0;
|
ref2->value.vector[idx].bval) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Swap the order so the code below can be used. */
|
||||||
if (ref1->format == vpiVectorVal && ref2->format == vpiIntVal) {
|
if (ref1->format == vpiVectorVal && ref2->format == vpiIntVal) {
|
||||||
s_vpi_value*tmp = ref1;
|
s_vpi_value*tmp = ref1;
|
||||||
ref1 = ref2;
|
ref1 = ref2;
|
||||||
ref2 = tmp;
|
ref2 = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare an integer to a vector. */
|
||||||
if (ref1->format == vpiIntVal && ref2->format == vpiVectorVal) {
|
if (ref1->format == vpiIntVal && ref2->format == vpiVectorVal) {
|
||||||
int use_aval = ref1->value.integer;
|
PLI_INT32 aval = ref1->value.integer;
|
||||||
int words = (wid-1)/32 + 1;
|
PLI_INT32 words = (wid-1)/32 + 1;
|
||||||
int idx;
|
PLI_INT32 idx;
|
||||||
|
|
||||||
for (idx = 0 ; idx < words ; idx += 1) {
|
for (idx = 0 ; idx < words ; idx += 1) {
|
||||||
if (use_aval != ref2->value.vector[idx].aval)
|
if (aval != ref2->value.vector[idx].aval) return 0;
|
||||||
return 0;
|
if (ref2->value.vector[idx].bval) return 0;
|
||||||
if (0 != ref2->value.vector[idx].bval)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
use_aval = 0;
|
aval = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unsupported types. */
|
||||||
vpi_printf("XXXX formats are: %d vs %d\n", ref1->format, ref2->format);
|
vpi_printf("XXXX formats are: %d vs %d\n", ref1->format, ref2->format);
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 ivl_method_next_calltf(PLI_BYTE8*data)
|
/*
|
||||||
|
* If the current value is not found in the enumeration. Then we need to
|
||||||
|
* return X/0 for the next()/prev() value.
|
||||||
|
*/
|
||||||
|
static void fill_handle_with_init(vpiHandle arg, int is_two_state)
|
||||||
|
{
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_INT32 words = ((vpi_get(vpiSize, arg) - 1) / 32) + 1;
|
||||||
|
PLI_INT32 idx;
|
||||||
|
p_vpi_vecval val_ptr = (p_vpi_vecval) malloc(words*sizeof(s_vpi_vecval));
|
||||||
|
PLI_INT32 fill = (is_two_state) ? 0x0 : 0xffffffff;
|
||||||
|
|
||||||
|
assert(val_ptr);
|
||||||
|
|
||||||
|
/* Fill the vector with X. */
|
||||||
|
for (idx=0; idx < words; idx += 1) {
|
||||||
|
val_ptr[idx].aval = fill;
|
||||||
|
val_ptr[idx].bval = fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the vector to the argument. */
|
||||||
|
val.format = vpiVectorVal;
|
||||||
|
val.value.vector = val_ptr;
|
||||||
|
vpi_put_value(arg, &val, 0, vpiNoDelay);
|
||||||
|
free(val_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement the next()/prev() enumeration methods.
|
||||||
|
*/
|
||||||
|
static PLI_INT32 ivl_enum_method_next_prev_calltf(PLI_BYTE8*name)
|
||||||
{
|
{
|
||||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||||
vpiHandle arg_enum = vpi_scan(argv);
|
vpiHandle arg_enum = vpi_scan(argv);
|
||||||
vpiHandle arg_item = vpi_scan(argv);
|
vpiHandle arg_var = vpi_scan(argv);
|
||||||
vpiHandle arg_extra = vpi_scan(argv);
|
vpiHandle arg_count = vpi_scan(argv);
|
||||||
|
|
||||||
vpiHandle enum_list = 0;
|
vpiHandle enum_list;
|
||||||
vpiHandle memb = 0, first_memb = 0;
|
vpiHandle cur;
|
||||||
long use_width = 0;
|
PLI_INT32 var_width = vpi_get(vpiSize, arg_var);
|
||||||
long item_width = vpi_get(vpiSize, arg_item);
|
PLI_UINT32 enum_size = vpi_get(vpiSize, arg_enum);
|
||||||
|
PLI_UINT32 count = 1;
|
||||||
|
PLI_UINT32 loc = 0;
|
||||||
|
|
||||||
s_vpi_value memb_value, item_value;
|
s_vpi_value cur_val, var_val;
|
||||||
|
|
||||||
assert(arg_extra == 0);
|
/* Get the count value if one was given. */
|
||||||
|
if (arg_count) {
|
||||||
|
s_vpi_value count_val;
|
||||||
|
|
||||||
item_value.format = vpiObjTypeVal;
|
/* Get the count value. */
|
||||||
vpi_get_value(arg_item, &item_value);
|
count_val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg_count, &count_val);
|
||||||
/* If this value is a vector value, then make a safe copy of
|
count = count_val.value.integer;
|
||||||
the vector so that other vpi functions don't trash it. */
|
/* Remove any multiple loops around the enumeration. */
|
||||||
if (item_value.format == vpiVectorVal) {
|
count %= enum_size;
|
||||||
unsigned idx;
|
/* Free the argument iterator. */
|
||||||
unsigned hwid = (item_width - 1)/32 + 1;
|
vpi_free_object(argv);
|
||||||
s_vpi_vecval*op = calloc(hwid, sizeof(s_vpi_vecval));
|
|
||||||
for (idx = 0 ; idx < hwid ; idx += 1) {
|
|
||||||
op[idx].aval = item_value.value.vector[idx].aval;
|
|
||||||
op[idx].bval = item_value.value.vector[idx].bval;
|
|
||||||
}
|
|
||||||
item_value.value.vector = op;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the current value. */
|
||||||
|
var_val.format = vpiObjTypeVal;
|
||||||
|
vpi_get_value(arg_var, &var_val);
|
||||||
|
|
||||||
|
/* If the count is zero then just return the current value. */
|
||||||
|
if (count == 0) {
|
||||||
|
vpi_put_value(sys, &var_val, 0, vpiNoDelay);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(vpiMember, arg_enum);
|
enum_list = vpi_iterate(vpiMember, arg_enum);
|
||||||
assert(enum_list);
|
assert(enum_list);
|
||||||
|
|
||||||
/* Search for the current value in the member list. */
|
|
||||||
do {
|
do {
|
||||||
memb = vpi_scan(enum_list);
|
cur = vpi_scan(enum_list);
|
||||||
if (first_memb == 0) {
|
if (cur == 0) break;
|
||||||
first_memb = memb;
|
|
||||||
use_width = vpi_get(vpiSize, first_memb);
|
cur_val.format = vpiObjTypeVal;
|
||||||
assert(use_width == vpi_get(vpiSize, arg_item));
|
vpi_get_value(cur, &cur_val);
|
||||||
|
assert(var_width == vpi_get(vpiSize, cur));
|
||||||
|
loc += 1;
|
||||||
|
} 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 X. This
|
||||||
|
* gives 0 for two-state variables. */
|
||||||
|
if (cur == 0) {
|
||||||
|
/* This only works correctly since we don't really define the
|
||||||
|
* the correct base typespec. */
|
||||||
|
int is_two_state = vpi_get(vpiBaseTypespec, arg_enum) != vpiReg;
|
||||||
|
fill_handle_with_init(sys, is_two_state);
|
||||||
|
} else {
|
||||||
|
if (strcmp(name, "$ivl_enum_method$next") == 0) {
|
||||||
|
/* Check to see if we need to wrap to the beginning. */
|
||||||
|
if (loc + count > enum_size) {
|
||||||
|
enum_list = vpi_iterate(vpiMember, arg_enum);
|
||||||
|
assert(enum_list);
|
||||||
|
count -= (enum_size - loc);
|
||||||
|
}
|
||||||
|
} else if (strcmp(name, "$ivl_enum_method$prev") == 0) {
|
||||||
|
/* Because of wrapping the count could be either before
|
||||||
|
* or after the current element. */
|
||||||
|
if (loc <= count ) {
|
||||||
|
/* The element we want is after the current
|
||||||
|
* element. */
|
||||||
|
count = enum_size - count;
|
||||||
|
} else {
|
||||||
|
/* The element we want is before the current
|
||||||
|
* element (at the beginning of the list). */
|
||||||
|
enum_list = vpi_iterate(vpiMember, arg_enum);
|
||||||
|
assert(enum_list);
|
||||||
|
count = loc - count;
|
||||||
|
}
|
||||||
|
} else assert(0);
|
||||||
|
|
||||||
|
/* Find the correct element. */
|
||||||
|
while (count) {
|
||||||
|
cur = vpi_scan(enum_list);
|
||||||
|
count -= 1;
|
||||||
}
|
}
|
||||||
if (memb == 0) break;
|
assert(cur != 0);
|
||||||
|
|
||||||
memb_value.format = vpiObjTypeVal;
|
/* Free the iterator. */
|
||||||
vpi_get_value(memb, &memb_value);
|
|
||||||
|
|
||||||
} while (! compare_value_eequal(&item_value, &memb_value, use_width));
|
|
||||||
|
|
||||||
if (memb != 0)
|
|
||||||
memb = vpi_scan(enum_list);
|
|
||||||
|
|
||||||
if (memb != 0)
|
|
||||||
vpi_free_object(enum_list);
|
vpi_free_object(enum_list);
|
||||||
|
|
||||||
if (memb == 0) {
|
/* Get the value and return it. */
|
||||||
memb = first_memb;
|
cur_val.format = vpiObjTypeVal;
|
||||||
memb_value.format = vpiIntVal;
|
vpi_get_value(cur, &cur_val);
|
||||||
|
vpi_put_value(sys, &cur_val, 0, vpiNoDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free any stached copy of the vector. */
|
|
||||||
if (item_value.format == vpiVectorVal)
|
|
||||||
free(item_value.value.vector);
|
|
||||||
|
|
||||||
vpi_get_value(memb, &memb_value);
|
|
||||||
vpi_put_value(sys, &memb_value, 0, vpiNoDelay);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 ivl_method_prev_calltf(PLI_BYTE8*data)
|
/*
|
||||||
|
* The compiletf routine for the enumeration name() method.
|
||||||
|
*/
|
||||||
|
static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
{
|
{
|
||||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||||
vpiHandle arg_enum = vpi_scan(argv);
|
vpiHandle arg_enum, arg_var;
|
||||||
vpiHandle arg_item = vpi_scan(argv);
|
|
||||||
vpiHandle arg_extra = vpi_scan(argv);
|
|
||||||
|
|
||||||
vpiHandle enum_list = 0;
|
/* This routine must have arguments. */
|
||||||
vpiHandle memb = 0, prev = 0, last_memb = 0;
|
if (argv == 0) {
|
||||||
int use_wid = 0;
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
s_vpi_value memb_value, item_value;
|
vpi_printf("No arguments given for enum method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
assert(arg_extra == 0);
|
return 0;
|
||||||
|
|
||||||
item_value.format = vpiIntVal;
|
|
||||||
vpi_get_value(arg_item, &item_value);
|
|
||||||
|
|
||||||
enum_list = vpi_iterate(vpiMember, arg_enum);
|
|
||||||
assert(enum_list);
|
|
||||||
|
|
||||||
/* Search for the current value in the member list. */
|
|
||||||
do {
|
|
||||||
prev = memb;
|
|
||||||
memb = vpi_scan(enum_list);
|
|
||||||
if (memb == 0) break;
|
|
||||||
if (use_wid == 0)
|
|
||||||
use_wid = vpi_get(vpiSize, memb);
|
|
||||||
|
|
||||||
last_memb = memb;
|
|
||||||
memb_value.format = vpiIntVal;
|
|
||||||
vpi_get_value(memb, &memb_value);
|
|
||||||
} while (! compare_value_eequal(&memb_value, &item_value, use_wid));
|
|
||||||
|
|
||||||
while (memb) {
|
|
||||||
last_memb = memb;
|
|
||||||
memb = vpi_scan(enum_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev == 0)
|
/* Check for the enumeration type argument. */
|
||||||
prev = last_memb;
|
arg_enum = vpi_scan(argv);
|
||||||
|
if (arg_enum == 0) {
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("No enumeration type argument given for enum "
|
||||||
|
"method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) {
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The first argument to enum method %s() must be an "
|
||||||
|
"enumeration type, found a %s.\n", name,
|
||||||
|
vpi_get_str(vpiType, arg_enum));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
vpi_get_value(prev, &memb_value);
|
/* Check for the enumeration variable. */
|
||||||
vpi_put_value(sys, &memb_value, 0, vpiNoDelay);
|
arg_var = vpi_scan(argv);
|
||||||
|
if (arg_var == 0) {
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("No enumeration variable argument given for enum "
|
||||||
|
"method %s().\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch(vpi_get(vpiType, arg_var)) {
|
||||||
|
case vpiBitVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiLongIntVar:
|
||||||
|
case vpiReg:
|
||||||
|
case vpiShortIntVar:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("The second argument to enum method %s() must be an "
|
||||||
|
"enumeration variable, found a %s.\n", name,
|
||||||
|
vpi_get_str(vpiType, arg_var));
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only two arguments are supported. */
|
||||||
|
if (vpi_scan(argv) != 0) {
|
||||||
|
vpi_free_object(argv);
|
||||||
|
vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys),
|
||||||
|
(int) vpi_get(vpiLineNo,sys));
|
||||||
|
vpi_printf("Extra argument(s) given to enum method %s().\n", 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement the name() enumeration method.
|
||||||
|
*/
|
||||||
|
static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void v2009_enum_register(void)
|
void v2009_enum_register(void)
|
||||||
{
|
{
|
||||||
s_vpi_systf_data tf_data;
|
s_vpi_systf_data tf_data;
|
||||||
|
vpiHandle res;
|
||||||
|
|
||||||
tf_data.type = vpiSysFunc;
|
tf_data.type = vpiSysFunc;
|
||||||
tf_data.calltf = ivl_method_next_calltf;
|
tf_data.calltf = ivl_enum_method_name_calltf;
|
||||||
tf_data.compiletf = ivl_method_next_prev_compiletf;
|
tf_data.compiletf = ivl_enum_method_name_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.tfname = "$ivl_method$next";
|
tf_data.tfname = "$ivl_enum_method$name";
|
||||||
tf_data.user_data = "$ivl_method$next";
|
tf_data.user_data = "$ivl_enum_method$name";
|
||||||
vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
|
/* This is not a user defined system function so hide it. */
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
tf_data.type = vpiSysFunc;
|
tf_data.type = vpiSysFunc;
|
||||||
tf_data.calltf = ivl_method_prev_calltf;
|
tf_data.calltf = ivl_enum_method_next_prev_calltf;
|
||||||
tf_data.compiletf = 0;
|
tf_data.compiletf = ivl_enum_method_next_prev_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.tfname = "$ivl_method$prev";
|
tf_data.tfname = "$ivl_enum_method$next";
|
||||||
tf_data.user_data = "$ivl_method$prev";
|
tf_data.user_data = "$ivl_enum_method$next";
|
||||||
vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
|
/* This is not a user defined system function so hide it. */
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
|
tf_data.type = vpiSysFunc;
|
||||||
|
tf_data.calltf = ivl_enum_method_next_prev_calltf;
|
||||||
|
tf_data.compiletf = ivl_enum_method_next_prev_compiletf;
|
||||||
|
tf_data.sizetf = 0;
|
||||||
|
tf_data.tfname = "$ivl_enum_method$prev";
|
||||||
|
tf_data.user_data = "$ivl_enum_method$prev";
|
||||||
|
res = vpi_register_systf(&tf_data);
|
||||||
|
/* This is not a user defined system function so hide it. */
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue