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:
parent
d71a1cb9c1
commit
2dcb1514a2
|
|
@ -72,9 +72,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
unsigned parm_count = tnet
|
||||
? ivl_stmt_parm_count(tnet)
|
||||
: ivl_expr_parms(fnet);
|
||||
struct vector_info *vec = 0x0;
|
||||
unsigned int vecs= 0;
|
||||
unsigned int veci= 0;
|
||||
|
||||
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));
|
||||
|
||||
char buffer[4096];
|
||||
|
||||
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
|
||||
them in the process of evaluating expressions. */
|
||||
case IVL_EX_NONE:
|
||||
args[idx].text = strdup("\" \"");
|
||||
continue;
|
||||
|
||||
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:
|
||||
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:
|
||||
snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
case IVL_EX_SCOPE:
|
||||
snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
|
|
@ -125,21 +169,47 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
} else if (! is_fixed_memory_word(expr)){
|
||||
break;
|
||||
} else {
|
||||
/* Some array selects need to be evaluated. */
|
||||
} 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 && !number_is_immediate(word_ex,
|
||||
8*sizeof(unsigned))) {
|
||||
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;
|
||||
}
|
||||
|
||||
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))) {
|
||||
use_word = get_number_immediate(word_ex);
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
|
||||
case IVL_EX_MEMORY:
|
||||
if (!ivl_expr_oper1(expr)) {
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -149,143 +219,43 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
break;
|
||||
}
|
||||
|
||||
vec = (struct vector_info *)
|
||||
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
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;
|
||||
case IVL_VT_REAL:
|
||||
vec[vecs].base = draw_eval_real(expr);
|
||||
vec[vecs].wid = 0;
|
||||
args[idx].vec_flag = 1;
|
||||
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;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
vecs++;
|
||||
args[idx].text = strdup(buffer);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "%s", call_string);
|
||||
|
||||
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)) {
|
||||
case IVL_EX_NONE:
|
||||
fprintf(vvp_out, ", \" \"");
|
||||
continue;
|
||||
|
||||
case IVL_EX_ARRAY:
|
||||
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
free(args);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
|
|
|
|||
88
vvp/array.cc
88
vvp/array.cc
|
|
@ -77,6 +77,12 @@ struct __vpiArrayIndex {
|
|||
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
|
||||
* 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 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 = {
|
||||
vpiMemory,
|
||||
vpi_array_get,
|
||||
|
|
@ -167,12 +177,27 @@ static const struct __vpirt vpip_array_var_word_rt = {
|
|||
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), \
|
||||
(struct __vpiArray*)ref)
|
||||
|
||||
# define ARRAY_VAR_WORD(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \
|
||||
(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)
|
||||
{
|
||||
assert(parent->vals_words == 0);
|
||||
|
|
@ -399,6 +424,53 @@ static int array_index_free_object(vpiHandle ref)
|
|||
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,
|
||||
unsigned address,
|
||||
unsigned part_off,
|
||||
|
|
@ -773,3 +845,19 @@ void compile_array_alias(char*label, char*name, char*src)
|
|||
free(name);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@
|
|||
return T_NUMBER; }
|
||||
|
||||
|
||||
"&A" { return K_A; }
|
||||
|
||||
/* Handle some specialized constant/literals as symbols. */
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
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_MOD_R
|
||||
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
||||
|
|
@ -797,6 +797,8 @@ argument
|
|||
{ $$ = vpip_make_binary_const($1.idx, $1.text);
|
||||
free($1.text);
|
||||
}
|
||||
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||
;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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_A(char*symbol, unsigned index);
|
||||
|
||||
/*
|
||||
* This function is called before any compilation to load VPI
|
||||
* modules. This gives the modules a chance to announce their
|
||||
|
|
|
|||
Loading…
Reference in New Issue