Make &A and &PV nestable.

This patch makes it so that &A and &PV can nest for the symbol
argument. This allows nested array selects, etc.
This commit is contained in:
Cary R 2008-08-27 16:26:18 -07:00 committed by Stephen Williams
parent 3ed0c4e809
commit 370ff9719f
5 changed files with 219 additions and 131 deletions

View File

@ -29,6 +29,13 @@
#define snprintf _snprintf
#endif
struct args_info {
char*text;
int vec_flag; /* True if the vec must be released. */
struct vector_info vec;
struct args_info *child; /* Arguments can be nested. */
};
static const char* magic_sfuncs[] = {
"$time",
"$stime",
@ -68,6 +75,153 @@ static int is_fixed_memory_word(ivl_expr_t net)
return 0;
}
static int get_vpi_taskfunc_signal_arg(struct args_info *result,
ivl_expr_t expr)
{
char buffer[4096];
switch (ivl_expr_type(expr)) {
case IVL_EX_SIGNAL:
/* If the signal node is narrower then the signal itself,
then this is a part select so I'm going to need to
evaluate the expression.
Also, if the signedness of the expression is different
from the signedness of the signal. This could be
caused by a $signed or $unsigned system function.
If I don't need to do any evaluating, then skip it as
I'll be passing the handle to the signal itself. */
if (ivl_expr_width(expr) !=
ivl_signal_width(ivl_expr_signal(expr))) {
/* This should never happen since we have IVL_EX_SELECT. */
return 0;
} else if (ivl_expr_signed(expr) !=
ivl_signal_signed(ivl_expr_signal(expr))) {
return 0;
} else if (is_fixed_memory_word(expr)) {
/* This is a word of a non-array, or a word of a net
array, so we can address the word directly. */
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex,
8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex) return 0;
assert(word_ex == 0);
snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word);
result->text = strdup(buffer);
return 1;
} else {
/* What's left, this is the work of a var array.
Create the right code to handle it. */
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex,
8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex && (ivl_expr_type(word_ex)==IVL_EX_SIGNAL ||
ivl_expr_type(word_ex)==IVL_EX_SELECT)) {
/* Special case: the index is a signal/select. */
result->child = calloc(1, sizeof(struct args_info));
if (get_vpi_taskfunc_signal_arg(result->child,
word_ex)) {
snprintf(buffer, sizeof buffer, "&A<v%p, %s >",
sig, result->child->text);
free(result->child->text);
} else {
free(result->child);
result->child = NULL;
return 0;
}
} else if (word_ex) {
/* Fallback case: evaluate expression. */
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&A<v%p, %u %u>",
sig, av.base, av.wid);
result->vec = av;
result->vec_flag = 1;
} else {
snprintf(buffer, sizeof buffer, "&A<v%p, %u>",
sig, use_word);
}
result->text = strdup(buffer);
return 1;
}
case IVL_EX_SELECT: {
ivl_expr_t vexpr = ivl_expr_oper1(expr);
assert(vexpr);
/* This code is only for signals or selects. */
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL &&
ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0;
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
if (ivl_expr_oper1(vexpr)) return 0;
ivl_expr_t bexpr = ivl_expr_oper2(expr);
assert(bexpr);
/* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL ||
ivl_expr_type(bexpr) == IVL_EX_SELECT) {
/* Special case: the base is a signal/select. */
result->child = calloc(1, sizeof(struct args_info));
if (get_vpi_taskfunc_signal_arg(result->child, bexpr)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %s, %u>",
ivl_expr_signal(vexpr),
result->child->text,
ivl_expr_width(expr));
free(result->child->text);
} else {
free(result->child);
result->child = NULL;
return 0;
}
} else {
/* Fallback case: evaluate the expression. */
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr),
rv.base, rv.wid,
ivl_expr_width(expr));
result->vec = rv;
result->vec_flag = 1;
}
result->text = strdup(buffer);
return 1;
}
default:
return 0;
}
}
static void draw_vpi_taskfunc_args(const char*call_string,
ivl_statement_t tnet,
ivl_expr_t fnet)
@ -77,11 +231,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
? ivl_stmt_parm_count(tnet)
: ivl_expr_parms(fnet);
struct args_info {
char*text;
int vec_flag; /* True if the vec must be released. */
struct vector_info vec;
} *args = calloc(parm_count, sizeof(struct args_info));
struct args_info *args = calloc(parm_count, sizeof(struct args_info));
char buffer[4096];
@ -154,121 +304,9 @@ static void draw_vpi_taskfunc_args(const char*call_string,
break;
case IVL_EX_SIGNAL:
/* If the signal node is narrower then the signal
itself, then this is a part select so I'm going
to need to evaluate the expression.
Also, if the signedness of the expression is
different from the signedness of the
signal. This could be caused by a $signed or
$unsigned system function.
If I don't need to do any evaluating, then skip
it as I'll be passing the handle to the signal
itself. */
if (ivl_expr_width(expr) !=
ivl_signal_width(ivl_expr_signal(expr))) {
break;
} else if (ivl_expr_signed(expr) !=
ivl_signal_signed(ivl_expr_signal(expr))) {
break;
} else if (is_fixed_memory_word(expr)) {
/* This is a word of a non-array, or a word
of a net array, so we can address the
word directly. */
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex)
break;
assert(word_ex == 0);
snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word);
args[idx].text = strdup(buffer);
continue;
} else {
/* What's left, this is the work of a var
array. Create the right code to handle
it. */
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex && ivl_expr_type(word_ex)==IVL_EX_SIGNAL) {
/* Special case: the index is a signal. */
snprintf(buffer, sizeof buffer,
"&A<v%p, v%p_0 >", sig,
ivl_expr_signal(word_ex));
} else if (word_ex) {
/* Fallback case: evaluate expression. */
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer,
"&A<v%p, %u %u>", sig, av.base, av.wid);
args[idx].vec = av;
args[idx].vec_flag = 1;
} else {
snprintf(buffer, sizeof buffer,
"&A<v%p, %u>", sig, use_word);
}
args[idx].text = strdup(buffer);
continue;
}
case IVL_EX_SELECT: {
ivl_expr_t vexpr = ivl_expr_oper1(expr);
assert(vexpr);
/* This code is only for signals. */
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break;
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
if (ivl_expr_oper1(vexpr)) break;
ivl_expr_t bexpr = ivl_expr_oper2(expr);
assert(bexpr);
/* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL) {
/* Sepcial case: the base is a signal. */
snprintf(buffer, sizeof buffer, "&PV<v%p_0, v%p_0, %u>",
ivl_expr_signal(vexpr),
ivl_expr_signal(bexpr),
ivl_expr_width(expr));
} else {
/* Fallback case: evaluate the expression. */
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr),
rv.base, rv.wid,
ivl_expr_width(expr));
}
args[idx].text = strdup(buffer);
continue;
}
case IVL_EX_SELECT:
if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue;
else break;
/* Everything else will need to be evaluated and
passed as a constant to the vpi task. */
@ -301,14 +339,22 @@ static void draw_vpi_taskfunc_args(const char*call_string,
fprintf(vvp_out, "%s", call_string);
for (idx = 0 ; idx < parm_count ; idx += 1) {
fprintf(vvp_out, ", %s", args[idx].text);
free(args[idx].text);
if (args[idx].vec_flag) {
if (args[idx].vec.wid > 0)
clr_vector(args[idx].vec);
else
clr_word(args[idx].vec.base);
struct args_info*ptr;
/* Clear the nested children vectors. */
for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) {
if (ptr->vec_flag) {
if (ptr->vec.wid > 0) clr_vector(ptr->vec);
else clr_word(ptr->vec.base);
}
}
/* Free the nested children. */
ptr = args[idx].child;
while (ptr != NULL) {
struct args_info*tptr = ptr;
ptr = ptr->child;
free(tptr);
}
}

View File

@ -1170,6 +1170,23 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol)
return &(obj->base);
}
vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle)
{
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
malloc(sizeof (struct __vpiArrayVthrA));
obj->base.vpi_type = &vpip_array_vthr_A_rt;
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address_handle = handle;
obj->address = 0;
obj->wid = 0;
return &(obj->base);
}
void compile_array_cleanup(void)
{

View File

@ -105,7 +105,7 @@ static struct __vpiModPath*modpath_dst = 0;
%type <table> udp_table
%type <argv> argument_opt argument_list
%type <vpi> argument
%type <vpi> argument symbol_access
%type <cdelay> delay delay_opt
%%
@ -831,21 +831,29 @@ argument
{ $$ = vpip_make_binary_const($1.idx, $1.text);
free($1.text);
}
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
| symbol_access
{ $$ = $1; }
;
symbol_access
: K_A '<' T_SYMBOL ',' T_NUMBER '>'
{ $$ = vpip_make_vthr_A($3, $5); }
| K_A '<' T_SYMBOL ',' T_NUMBER T_NUMBER '>'
{ $$ = vpip_make_vthr_A($3, $5, $6); }
| K_A '<' T_SYMBOL ',' T_SYMBOL '>'
{ $$ = vpip_make_vthr_A($3, $5); }
| K_A '<' T_SYMBOL ',' symbol_access '>'
{ $$ = vpip_make_vthr_A($3, $5); }
| K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $7); }
| K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, -$6, $8); }
| K_PV '<' T_SYMBOL ',' T_SYMBOL ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $7); }
| K_PV '<' T_SYMBOL ',' symbol_access ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $7); }
| K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $6, $8); }
;
/* functor operands can only be a list of symbols. */
symbols

View File

@ -239,6 +239,7 @@ struct __vpiPV {
};
extern vpiHandle vpip_make_PV(char*name, int base, int width);
extern vpiHandle vpip_make_PV(char*name, char*symbol, int width);
extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width);
extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, int width);
extern struct __vpiPV* vpip_PV_from_handle(vpiHandle obj);
@ -456,9 +457,10 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
vpiHandle vpip_make_vthr_A(char*label, unsigned index);
vpiHandle vpip_make_vthr_A(char*label, char*symbol);
vpiHandle vpip_make_vthr_A(char*symbol, unsigned tbase, unsigned twid);
vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid);
vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle);
/*
* This function is called before any compilation to load VPI

View File

@ -1171,6 +1171,21 @@ vpiHandle vpip_make_PV(char*var, char*symbol, int width)
return &obj->base;
}
vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width)
{
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));
obj->base.vpi_type = &vpip_PV_rt;
obj->parent = vvp_lookup_handle(var);
obj->sbase = handle;
obj->tbase = 0;
obj->twid = 0;
obj->width = (unsigned) width;
obj->net = 0;
functor_ref_lookup(&obj->net, var);
return &obj->base;
}
vpiHandle vpip_make_PV(char*var, int tbase, int twid, int width)
{
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));