2010-11-18 05:00:23 +01:00
|
|
|
/*
|
2014-07-09 23:16:57 +02:00
|
|
|
* Copyright (c) 2010-2014 Stephen Williams (steve@icarus.com)
|
2010-11-18 05:00:23 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2010-11-18 05:00:23 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "vpi_config.h"
|
|
|
|
|
# include "sv_vpi_user.h"
|
2010-11-22 02:24:46 +01:00
|
|
|
# include <stdlib.h>
|
2011-10-12 04:14:17 +02:00
|
|
|
# include <string.h>
|
2010-11-18 05:00:23 +01:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/*
|
|
|
|
|
* The compiletf routine for the enumeration next() and prev() methods.
|
|
|
|
|
*/
|
|
|
|
|
static PLI_INT32 ivl_enum_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
2010-11-18 05:00:23 +01:00
|
|
|
{
|
|
|
|
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
2011-10-12 04:14:17 +02:00
|
|
|
vpiHandle arg_enum, arg_var, arg_count;
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* These routines must have arguments. */
|
2010-11-18 05:00:23 +01:00
|
|
|
if (argv == 0) {
|
2011-10-12 04:14:17 +02:00
|
|
|
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);
|
2010-11-18 05:00:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Check for the enumeration type argument. */
|
2010-11-18 05:00:23 +01:00
|
|
|
arg_enum = vpi_scan(argv);
|
|
|
|
|
if (arg_enum == 0) {
|
2011-10-12 04:14:17 +02:00
|
|
|
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);
|
2010-11-18 05:00:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-10-12 04:14:17 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Check for the enumeration variable. */
|
|
|
|
|
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);
|
2010-11-18 05:00:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-10-12 04:14:17 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* 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);
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* 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);
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* 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);
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|
2011-10-12 04:14:17 +02:00
|
|
|
|
2010-11-18 05:00:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/*
|
|
|
|
|
* 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)
|
2010-11-22 02:24:46 +01:00
|
|
|
{
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Two integer values are easy. */
|
2010-11-22 02:24:46 +01:00
|
|
|
if (ref1->format == vpiIntVal && ref2->format == vpiIntVal)
|
|
|
|
|
return ref1->value.integer == ref2->value.integer;
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* For two vectors compare them word by word. */
|
2010-11-22 02:24:46 +01:00
|
|
|
if (ref1->format == vpiVectorVal && ref2->format == vpiVectorVal) {
|
2011-10-12 04:14:17 +02:00
|
|
|
PLI_INT32 words = (wid-1)/32 + 1;
|
|
|
|
|
PLI_INT32 idx;
|
2010-11-22 02:24:46 +01:00
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < words ; idx += 1) {
|
2011-10-12 04:14:17 +02:00
|
|
|
if (ref1->value.vector[idx].aval !=
|
|
|
|
|
ref2->value.vector[idx].aval) return 0;
|
|
|
|
|
if (ref1->value.vector[idx].bval !=
|
|
|
|
|
ref2->value.vector[idx].bval) return 0;
|
2010-11-22 02:24:46 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Swap the order so the code below can be used. */
|
2010-11-22 02:24:46 +01:00
|
|
|
if (ref1->format == vpiVectorVal && ref2->format == vpiIntVal) {
|
|
|
|
|
s_vpi_value*tmp = ref1;
|
|
|
|
|
ref1 = ref2;
|
|
|
|
|
ref2 = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Compare an integer to a vector. */
|
2010-11-22 02:24:46 +01:00
|
|
|
if (ref1->format == vpiIntVal && ref2->format == vpiVectorVal) {
|
2011-10-12 04:14:17 +02:00
|
|
|
PLI_INT32 aval = ref1->value.integer;
|
|
|
|
|
PLI_INT32 words = (wid-1)/32 + 1;
|
|
|
|
|
PLI_INT32 idx;
|
2010-11-22 02:24:46 +01:00
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < words ; idx += 1) {
|
2011-10-12 04:14:17 +02:00
|
|
|
if (aval != ref2->value.vector[idx].aval) return 0;
|
|
|
|
|
if (ref2->value.vector[idx].bval) return 0;
|
2010-11-22 02:24:46 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
aval = 0;
|
2010-11-22 02:24:46 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Unsupported types. */
|
2010-11-22 02:24:46 +01:00
|
|
|
vpi_printf("XXXX formats are: %d vs %d\n", ref1->format, ref2->format);
|
|
|
|
|
assert(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/*
|
|
|
|
|
* 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)
|
2010-11-18 05:00:23 +01:00
|
|
|
{
|
|
|
|
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
|
|
|
|
vpiHandle arg_enum = vpi_scan(argv);
|
2011-10-12 04:14:17 +02:00
|
|
|
vpiHandle arg_var = vpi_scan(argv);
|
|
|
|
|
vpiHandle arg_count = vpi_scan(argv);
|
|
|
|
|
|
|
|
|
|
vpiHandle enum_list;
|
|
|
|
|
vpiHandle cur;
|
|
|
|
|
PLI_INT32 var_width = vpi_get(vpiSize, arg_var);
|
|
|
|
|
PLI_UINT32 enum_size = vpi_get(vpiSize, arg_enum);
|
|
|
|
|
PLI_UINT32 count = 1;
|
|
|
|
|
PLI_UINT32 loc = 0;
|
|
|
|
|
|
|
|
|
|
s_vpi_value cur_val, var_val;
|
|
|
|
|
|
|
|
|
|
/* Get the count value if one was given. */
|
|
|
|
|
if (arg_count) {
|
|
|
|
|
s_vpi_value count_val;
|
|
|
|
|
|
|
|
|
|
/* Get the count value. */
|
|
|
|
|
count_val.format = vpiIntVal;
|
|
|
|
|
vpi_get_value(arg_count, &count_val);
|
|
|
|
|
count = count_val.value.integer;
|
|
|
|
|
/* Remove any multiple loops around the enumeration. */
|
|
|
|
|
count %= enum_size;
|
|
|
|
|
/* 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 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;
|
2010-11-22 02:24:46 +01:00
|
|
|
}
|
2011-10-12 04:14:17 +02:00
|
|
|
var_val.value.vector = nvec;
|
2010-11-22 02:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Search for the current value in the enumeration list. */
|
2011-10-12 18:29:55 +02:00
|
|
|
enum_list = vpi_iterate(vpiEnumConst, arg_enum);
|
2010-11-18 05:00:23 +01:00
|
|
|
assert(enum_list);
|
|
|
|
|
do {
|
2011-10-12 04:14:17 +02:00
|
|
|
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));
|
|
|
|
|
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);
|
|
|
|
|
|
2011-10-12 20:03:12 +02:00
|
|
|
/* The current value was not found in the list so return X/0. */
|
2011-10-12 04:14:17 +02:00
|
|
|
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) {
|
2011-10-17 04:34:51 +02:00
|
|
|
/* Free the current iterator before creating a new
|
|
|
|
|
* one that is at the beginning of the list. */
|
|
|
|
|
vpi_free_object(enum_list);
|
2011-10-12 18:29:55 +02:00
|
|
|
enum_list = vpi_iterate(vpiEnumConst, arg_enum);
|
2011-10-12 04:14:17 +02:00
|
|
|
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
|
2011-10-17 04:34:51 +02:00
|
|
|
* element (at the beginning of the list). Free
|
|
|
|
|
* the current iterator before creating a new
|
|
|
|
|
* one that is at the beginning of the list. */
|
|
|
|
|
vpi_free_object(enum_list);
|
2011-10-12 18:29:55 +02:00
|
|
|
enum_list = vpi_iterate(vpiEnumConst, arg_enum);
|
2011-10-12 04:14:17 +02:00
|
|
|
assert(enum_list);
|
|
|
|
|
count = loc - count;
|
|
|
|
|
}
|
|
|
|
|
} else assert(0);
|
|
|
|
|
|
|
|
|
|
/* Find the correct element. */
|
|
|
|
|
while (count) {
|
|
|
|
|
cur = vpi_scan(enum_list);
|
|
|
|
|
count -= 1;
|
2010-11-22 02:24:46 +01:00
|
|
|
}
|
2011-10-12 04:14:17 +02:00
|
|
|
assert(cur != 0);
|
2010-11-22 02:24:46 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Free the iterator. */
|
2010-11-18 05:00:23 +01:00
|
|
|
vpi_free_object(enum_list);
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Get the value and return it. */
|
|
|
|
|
cur_val.format = vpiObjTypeVal;
|
|
|
|
|
vpi_get_value(cur, &cur_val);
|
|
|
|
|
vpi_put_value(sys, &cur_val, 0, vpiNoDelay);
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/*
|
|
|
|
|
* The compiletf routine for the enumeration name() method.
|
|
|
|
|
*/
|
|
|
|
|
static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
2010-11-18 05:00:23 +01:00
|
|
|
{
|
|
|
|
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
2011-10-12 04:14:17 +02:00
|
|
|
vpiHandle arg_enum, arg_var;
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* This routine must have arguments. */
|
|
|
|
|
if (argv == 0) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Check for the enumeration type argument. */
|
|
|
|
|
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);
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* Check for the enumeration variable. */
|
|
|
|
|
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);
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/* 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);
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2010-11-18 05:00:23 +01:00
|
|
|
|
2011-10-12 04:14:17 +02:00
|
|
|
/*
|
|
|
|
|
* Implement the name() enumeration method.
|
|
|
|
|
*/
|
|
|
|
|
static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name)
|
|
|
|
|
{
|
2011-10-12 20:03:12 +02:00
|
|
|
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;
|
|
|
|
|
|
2014-07-09 23:16:57 +02:00
|
|
|
(void)name; /* Parameter is not used. */
|
|
|
|
|
|
2011-10-12 20:03:12 +02:00
|
|
|
/* 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);
|
2010-11-18 05:00:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void v2009_enum_register(void)
|
|
|
|
|
{
|
|
|
|
|
s_vpi_systf_data tf_data;
|
2011-10-12 04:14:17 +02:00
|
|
|
vpiHandle res;
|
|
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
|
|
|
|
tf_data.calltf = ivl_enum_method_name_calltf;
|
|
|
|
|
tf_data.compiletf = ivl_enum_method_name_compiletf;
|
|
|
|
|
tf_data.sizetf = 0;
|
|
|
|
|
tf_data.tfname = "$ivl_enum_method$name";
|
|
|
|
|
tf_data.user_data = "$ivl_enum_method$name";
|
|
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
/* This is not a user defined system function so hide it. */
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2010-11-18 05:00:23 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
2011-10-12 04:14:17 +02:00
|
|
|
tf_data.calltf = ivl_enum_method_next_prev_calltf;
|
|
|
|
|
tf_data.compiletf = ivl_enum_method_next_prev_compiletf;
|
2010-11-18 05:00:23 +01:00
|
|
|
tf_data.sizetf = 0;
|
2011-10-12 04:14:17 +02:00
|
|
|
tf_data.tfname = "$ivl_enum_method$next";
|
|
|
|
|
tf_data.user_data = "$ivl_enum_method$next";
|
|
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
/* This is not a user defined system function so hide it. */
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2010-11-18 05:00:23 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
2011-10-12 04:14:17 +02:00
|
|
|
tf_data.calltf = ivl_enum_method_next_prev_calltf;
|
|
|
|
|
tf_data.compiletf = ivl_enum_method_next_prev_compiletf;
|
2010-11-18 05:00:23 +01:00
|
|
|
tf_data.sizetf = 0;
|
2011-10-12 04:14:17 +02:00
|
|
|
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);
|
2010-11-18 05:00:23 +01:00
|
|
|
}
|