Add support for passing array words to system tasks.

Array words don't have a vpiHandle with a label, so the %vpi_call
needs a special syntac for arguments that reference array words.
This syntax creates an array word reference that persists and can
be used at a VPI object by system tasks.
This commit is contained in:
Stephen Williams 2008-05-20 16:21:54 -07:00
parent d71a1cb9c1
commit 2dcb1514a2
5 changed files with 229 additions and 166 deletions

View File

@ -72,9 +72,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
unsigned parm_count = tnet unsigned parm_count = tnet
? ivl_stmt_parm_count(tnet) ? ivl_stmt_parm_count(tnet)
: ivl_expr_parms(fnet); : ivl_expr_parms(fnet);
struct vector_info *vec = 0x0;
unsigned int vecs= 0; struct args_info {
unsigned int veci= 0; char*text;
int vec_flag; /* True if the vec must be released. */
struct vector_info vec;
} *args = calloc(parm_count, sizeof(struct args_info));
char buffer[4096];
ivl_parameter_t par; ivl_parameter_t par;
@ -92,17 +97,56 @@ static void draw_vpi_taskfunc_args(const char*call_string,
with VPI handles of their own. Therefore, skip with VPI handles of their own. Therefore, skip
them in the process of evaluating expressions. */ them in the process of evaluating expressions. */
case IVL_EX_NONE: case IVL_EX_NONE:
args[idx].text = strdup("\" \"");
continue;
case IVL_EX_ARRAY: case IVL_EX_ARRAY:
case IVL_EX_NUMBER: snprintf(buffer, sizeof buffer,
"v%p", ivl_expr_signal(expr));
args[idx].text = strdup(buffer);
continue;
case IVL_EX_NUMBER: {
unsigned bit, wid = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
char*dp;
snprintf(buffer, sizeof buffer,
"%u'%sb", wid, ivl_expr_signed(expr)? "s" : "");
dp = buffer + strlen(buffer);
for (bit = wid ; bit > 0 ; bit -= 1)
*dp++ = bits[bit-1];
*dp++ = 0;
assert(dp - buffer <= sizeof buffer);
args[idx].text = strdup(buffer);
continue;
}
case IVL_EX_STRING: case IVL_EX_STRING:
if (( par = ivl_expr_parameter(expr) )) {
snprintf(buffer, sizeof buffer, "P_%p", par);
} else {
snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr));
}
args[idx].text = strdup(buffer);
continue;
case IVL_EX_EVENT: case IVL_EX_EVENT:
snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr));
args[idx].text = strdup(buffer);
continue;
case IVL_EX_SCOPE: case IVL_EX_SCOPE:
snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr));
args[idx].text = strdup(buffer);
continue; continue;
case IVL_EX_SFUNC: case IVL_EX_SFUNC:
if (is_magic_sfunc(ivl_expr_name(expr))) if (is_magic_sfunc(ivl_expr_name(expr))) {
snprintf(buffer, sizeof buffer, "%s", ivl_expr_name(expr));
args[idx].text = strdup(buffer);
continue; continue;
}
break; break;
case IVL_EX_SIGNAL: case IVL_EX_SIGNAL:
@ -125,21 +169,47 @@ static void draw_vpi_taskfunc_args(const char*call_string,
} else if (ivl_expr_signed(expr) != } else if (ivl_expr_signed(expr) !=
ivl_signal_signed(ivl_expr_signal(expr))) { ivl_signal_signed(ivl_expr_signal(expr))) {
break; break;
} else if (! is_fixed_memory_word(expr)){ } else if (is_fixed_memory_word(expr)) {
break; /* This is a word of a non-array, or a word
} else { of a net array, so we can address the
/* Some array selects need to be evaluated. */ word directly. */
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr); ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex && !number_is_immediate(word_ex, if (word_ex) {
8*sizeof(unsigned))) { /* Some array select have been evaluated. */
break; if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
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; 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))) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex)
break;
case IVL_EX_MEMORY: snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
if (!ivl_expr_oper1(expr)) { args[idx].text = strdup(buffer);
continue; continue;
} }
@ -149,143 +219,43 @@ static void draw_vpi_taskfunc_args(const char*call_string,
break; break;
} }
vec = (struct vector_info *)
realloc(vec, (vecs+1)*sizeof(struct vector_info));
switch (ivl_expr_value(expr)) { switch (ivl_expr_value(expr)) {
case IVL_VT_LOGIC: case IVL_VT_LOGIC:
case IVL_VT_BOOL: case IVL_VT_BOOL:
vec[vecs] = draw_eval_expr(expr, 0); args[idx].vec_flag = 1;
args[idx].vec = draw_eval_expr(expr, 0);
snprintf(buffer, sizeof buffer,
"T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid,
ivl_expr_signed(expr)? "s" : "u");
break; break;
case IVL_VT_REAL: case IVL_VT_REAL:
vec[vecs].base = draw_eval_real(expr); args[idx].vec_flag = 1;
vec[vecs].wid = 0; args[idx].vec.base = draw_eval_real(expr);
args[idx].vec.wid = 0;
snprintf(buffer, sizeof buffer,
"W<%u,r>", args[idx].vec.base);
break; break;
default: default:
assert(0); assert(0);
} }
vecs++; args[idx].text = strdup(buffer);
} }
fprintf(vvp_out, "%s", call_string); fprintf(vvp_out, "%s", call_string);
for (idx = 0 ; idx < parm_count ; idx += 1) { for (idx = 0 ; idx < parm_count ; idx += 1) {
ivl_expr_t expr = tnet
? ivl_stmt_parm(tnet, idx)
: ivl_expr_parm(fnet, idx);
switch (ivl_expr_type(expr)) { fprintf(vvp_out, ", %s", args[idx].text);
case IVL_EX_NONE: free(args[idx].text);
fprintf(vvp_out, ", \" \""); if (args[idx].vec_flag) {
continue; if (args[idx].vec.wid > 0)
clr_vector(args[idx].vec);
case IVL_EX_ARRAY: else
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr)); clr_word(args[idx].vec.base);
continue;
case IVL_EX_NUMBER: {
unsigned bit, wid = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
fprintf(vvp_out, ", %u'%sb", wid,
ivl_expr_signed(expr)? "s" : "");
for (bit = wid ; bit > 0 ; bit -= 1)
fputc(bits[bit-1], vvp_out);
continue;
}
case IVL_EX_SIGNAL:
/* If this is a part select, then the value was
calculated above. Otherwise, just pass the
signal. */
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)){
break;
} else {
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))) {
break;
}
use_word = get_number_immediate(word_ex);
}
fprintf(vvp_out, ", v%p_%u", sig, use_word);
continue;
}
assert(0);
continue;
case IVL_EX_STRING:
if (( par = ivl_expr_parameter(expr) )) {
fprintf(vvp_out, ", P_%p", par);
} else {
fprintf(vvp_out, ", \"%s\"",
ivl_expr_string(expr));
}
continue;
case IVL_EX_EVENT:
fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
continue;
case IVL_EX_SCOPE:
fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
continue;
case IVL_EX_SFUNC:
if (is_magic_sfunc(ivl_expr_name(expr))) {
fprintf(vvp_out, ", %s", ivl_expr_name(expr));
continue;
}
break;
default:
break;
} }
assert(veci < vecs);
switch (ivl_expr_value(expr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
break;
case IVL_VT_REAL:
fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
break;
default:
assert(0);
}
veci++;
} }
assert(veci == vecs); free(args);
if (vecs) {
for (idx = 0; idx < vecs; idx++) {
if (vec[idx].wid > 0)
clr_vector(vec[idx]);
else if (vec[idx].wid == 0)
clr_word(vec[idx].base);
}
free(vec);
}
fprintf(vvp_out, ";\n"); fprintf(vvp_out, ";\n");
} }

View File

@ -77,6 +77,12 @@ struct __vpiArrayIndex {
unsigned done; unsigned done;
}; };
struct __vpiArrayVthrA {
struct __vpiHandle base;
struct __vpiArray*array;
unsigned address;
};
/* /*
* The vpiArrayWord is magic. It is used as the handle to return when * The vpiArrayWord is magic. It is used as the handle to return when
* vpi code tries to index or scan an array of variable words. The * vpi code tries to index or scan an array of variable words. The
@ -117,6 +123,10 @@ static int vpi_array_var_word_get(int code, vpiHandle);
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value); static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int); static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
static int vpi_array_vthr_A_get(int code, vpiHandle);
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
static const struct __vpirt vpip_arraymem_rt = { static const struct __vpirt vpip_arraymem_rt = {
vpiMemory, vpiMemory,
vpi_array_get, vpi_array_get,
@ -167,12 +177,27 @@ static const struct __vpirt vpip_array_var_word_rt = {
0 0
}; };
static const struct __vpirt vpip_array_vthr_A_rt = {
vpiMemoryWord,
&vpi_array_vthr_A_get,
0,
&vpi_array_vthr_A_get_value,
&vpi_array_vthr_A_put_value,
0,
0,
0,
0
};
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \ # define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
(struct __vpiArray*)ref) (struct __vpiArray*)ref)
# define ARRAY_VAR_WORD(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \ # define ARRAY_VAR_WORD(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \
(struct __vpiArrayWord*)ref) (struct __vpiArrayWord*)ref)
# define ARRAY_VTHR_A_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \
(struct __vpiArrayVthrA*)ref)
static void array_make_vals_words(struct __vpiArray*parent) static void array_make_vals_words(struct __vpiArray*parent)
{ {
assert(parent->vals_words == 0); assert(parent->vals_words == 0);
@ -399,6 +424,53 @@ static int array_index_free_object(vpiHandle ref)
return 1; return 1;
} }
static int vpi_array_vthr_A_get(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiLineNo:
return 0; // Not implemented for now!
case vpiSize:
assert(parent->vals);
return parent->vals_width;
default:
return 0;
}
}
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref);
struct __vpiArray*parent = obj->array;
assert(parent);
assert(parent->vals);
assert(obj->address < parent->array_count);
vpip_vec4_get_value(parent->vals[obj->address],
parent->vals_width, false, value);
}
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
{
struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref);
struct __vpiArray*parent = obj->array;
unsigned index = obj->address;
assert(parent);
assert(obj->address < parent->array_count);
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
array_set_word(parent, index, 0, val);
return ref;
}
void array_set_word(vvp_array_t arr, void array_set_word(vvp_array_t arr,
unsigned address, unsigned address,
unsigned part_off, unsigned part_off,
@ -773,3 +845,19 @@ void compile_array_alias(char*label, char*name, char*src)
free(name); free(name);
free(src); free(src);
} }
vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
{
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);
obj->address = addr;
assert(addr < obj->array->array_count);
return &(obj->base);
}

View File

@ -190,6 +190,7 @@
return T_NUMBER; } return T_NUMBER; }
"&A" { return K_A; }
/* Handle some specialized constant/literals as symbols. */ /* Handle some specialized constant/literals as symbols. */

View File

@ -65,7 +65,7 @@ static struct __vpiModPath*modpath_dst = 0;
vvp_delay_t*cdelay; vvp_delay_t*cdelay;
}; };
%token K_ALIAS K_ALIAS_S K_ALIAS_R %token K_A K_ALIAS K_ALIAS_S K_ALIAS_R
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD %token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
%token K_ARITH_MOD_R %token K_ARITH_MOD_R
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
@ -766,38 +766,40 @@ argument_opt
; ;
argument_list argument_list
: argument : argument
{ struct argv_s tmp; { struct argv_s tmp;
argv_init(&tmp); argv_init(&tmp);
argv_add(&tmp, $1); argv_add(&tmp, $1);
$$ = tmp; $$ = tmp;
} }
| argument_list ',' argument | argument_list ',' argument
{ struct argv_s tmp = $1; { struct argv_s tmp = $1;
argv_add(&tmp, $3); argv_add(&tmp, $3);
$$ = tmp; $$ = tmp;
} }
| T_SYMBOL | T_SYMBOL
{ struct argv_s tmp; { struct argv_s tmp;
argv_init(&tmp); argv_init(&tmp);
argv_sym_add(&tmp, $1); argv_sym_add(&tmp, $1);
$$ = tmp; $$ = tmp;
} }
| argument_list ',' T_SYMBOL | argument_list ',' T_SYMBOL
{ struct argv_s tmp = $1; { struct argv_s tmp = $1;
argv_sym_add(&tmp, $3); argv_sym_add(&tmp, $3);
$$ = tmp; $$ = tmp;
} }
; ;
argument argument
: T_STRING : T_STRING
{ $$ = vpip_make_string_const($1); } { $$ = vpip_make_string_const($1); }
| T_VECTOR | T_VECTOR
{ $$ = vpip_make_binary_const($1.idx, $1.text); { $$ = vpip_make_binary_const($1.idx, $1.text);
free($1.text); free($1.text);
} }
; | K_A '<' T_SYMBOL ',' T_NUMBER '>'
{ $$ = vpip_make_vthr_A($3, $5); }
;
/* functor operands can only be a list of symbols. */ /* functor operands can only be a list of symbols. */

View File

@ -433,6 +433,8 @@ 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_word(unsigned base, const char*type);
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
/* /*
* This function is called before any compilation to load VPI * This function is called before any compilation to load VPI
* modules. This gives the modules a chance to announce their * modules. This gives the modules a chance to announce their