Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl

This commit is contained in:
Nick Gasson 2008-08-29 18:38:49 +01:00
commit ed929a37bb
15 changed files with 339 additions and 190 deletions

View File

@ -3381,29 +3381,6 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
verinum(1)); verinum(1));
} while (0); } while (0);
/* If this is an always block and we have no or zero delay then
* a runtime infinite loop will happen. If we possible have some
* delay then print a warning that an infinite loop is possible.
*/
if (type() == PProcess::PR_ALWAYS) {
DelayType dly_type = top->statement()->delay_type();
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
cerr << get_fileline() << ": error: always statement"
<< " does not have any delay." << endl;
cerr << get_fileline() << ": : A runtime infinite"
<< " loop will occur." << endl;
des->errors += 1;
return false;
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
cerr << get_fileline() << ": warning: always statement"
<< " may not have any delay." << endl;
cerr << get_fileline() << ": : A runtime infinite"
<< " loop may be possible." << endl;
}
}
return true; return true;
} }
@ -3871,6 +3848,37 @@ class later_defparams : public elaborator_work_item_t {
} }
}; };
bool Design::check_always_delay() const
{
bool result_flag = true;
for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) {
/* If this is an always block and we have no or zero delay then
* a runtime infinite loop will happen. If we possible have some
* delay then print a warning that an infinite loop is possible.
*/
if (pr->type() == NetProcTop::KALWAYS) {
DelayType dly_type = pr->statement()->delay_type();
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
cerr << pr->get_fileline() << ": error: always"
<< " statement does not have any delay." << endl;
cerr << pr->get_fileline() << ": : A runtime"
<< " infinite loop will occur." << endl;
result_flag = false;
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
cerr << pr->get_fileline() << ": warning: always"
<< " statement may not have any delay." << endl;
cerr << pr->get_fileline() << ": : A runtime"
<< " infinite loop may be possible." << endl;
}
}
}
return result_flag;
}
/* /*
* This function is the root of all elaboration. The input is the list * This function is the root of all elaboration. The input is the list
* of root module names. The function locates the Module definitions * of root module names. The function locates the Module definitions
@ -3906,7 +3914,7 @@ Design* elaborate(list<perm_string>roots)
// Get the module definition for this root instance. // Get the module definition for this root instance.
Module *rmod = (*mod).second; Module *rmod = (*mod).second;
// Make the root scope. This makes a NetScoep object and // Make the root scope. This makes a NetScope object and
// pushes it into the list of root scopes in the Design. // pushes it into the list of root scopes in the Design.
NetScope*scope = des->make_root_scope(*root); NetScope*scope = des->make_root_scope(*root);
@ -3919,7 +3927,7 @@ Design* elaborate(list<perm_string>roots)
des->set_precision(rmod->time_precision); des->set_precision(rmod->time_precision);
// Save this scope, along with its defintion, in the // Save this scope, along with its definition, in the
// "root_elems" list for later passes. // "root_elems" list for later passes.
struct root_elem *r = new struct root_elem; struct root_elem *r = new struct root_elem;
r->mod = rmod; r->mod = rmod;
@ -3997,8 +4005,14 @@ Design* elaborate(list<perm_string>roots)
rc &= rmod->elaborate(des, scope); rc &= rmod->elaborate(des, scope);
} }
if (rc == false) { if (rc == false) {
delete des;
return 0;
}
// Now that everything is fully elaborated verify that we do
// not have an always block with no delay (an infinite loop).
if (des->check_always_delay() == false) {
delete des; delete des;
des = 0; des = 0;
} }

View File

@ -1588,6 +1588,12 @@ static int load_next_input()
if(depend_file) if(depend_file)
fprintf(depend_file, "%s\n", istack->path); fprintf(depend_file, "%s\n", istack->path);
/* This works around an issue in flex yyrestart() where it
* uses yyin to create a new buffer when one does not exist.
* I would have assumed that it would use the file argument.
* The problem is that we have deleted the buffer and freed
* yyin (isp->file) above. */
yyin = 0;
yyrestart(istack->file); yyrestart(istack->file);
return 1; return 1;
} }

View File

@ -2575,6 +2575,7 @@ DelayType NetBlock::delay_type() const
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
DelayType dt = cur->delay_type(); DelayType dt = cur->delay_type();
if (dt > result) result = dt; if (dt > result) result = dt;
if (dt == DEFINITE_DELAY) break;
} }
return result; return result;
@ -2609,7 +2610,9 @@ DelayType NetCondit::delay_type() const
if (else_) { if (else_) {
result = combine_delays(if_->delay_type(), else_->delay_type()); result = combine_delays(if_->delay_type(), else_->delay_type());
} else { } else {
result = if_->delay_type(); /* Because of the indeterminate conditional value the
* best we can have for this case is a possible delay. */
result = combine_delays(if_->delay_type(), NO_DELAY);
} }
return result; return result;

View File

@ -3715,6 +3715,7 @@ class Design {
// PROCESSES // PROCESSES
void add_process(NetProcTop*); void add_process(NetProcTop*);
void delete_process(NetProcTop*); void delete_process(NetProcTop*);
bool check_always_delay() const;
// Iterate over the design... // Iterate over the design...
void dump(ostream&) const; void dump(ostream&) const;

View File

@ -245,16 +245,16 @@ bool eval_as_double(double&value, NetExpr*expr)
} }
/* /*
* At the parser level, a name component it a name with a collection * At the parser level, a name component is a name with a collection
* of expressions. For example foo[N] is the name "foo" and the index * of expressions. For example foo[N] is the name "foo" and the index
* expression "N". This function takes as input the name component and * expression "N". This function takes as input the name component and
* returns the path component name. It will evaulate the index * returns the path component name. It will evaluate the index
* expression if it is present. * expression if it is present.
*/ */
hname_t eval_path_component(Design*des, NetScope*scope, hname_t eval_path_component(Design*des, NetScope*scope,
const name_component_t&comp) const name_component_t&comp)
{ {
// No index exression, so the path component is an undecorated // No index expression, so the path component is an undecorated
// name, for example "foo". // name, for example "foo".
if (comp.index.empty()) if (comp.index.empty())
return hname_t(comp.name); return hname_t(comp.name);
@ -284,7 +284,7 @@ hname_t eval_path_component(Design*des, NetScope*scope,
} }
// Darn, the expression doesn't evaluate to a constant. That's // Darn, the expression doesn't evaluate to a constant. That's
// and error to be reported. And make up a fake index value to // an error to be reported. And make up a fake index value to
// return to the caller. // return to the caller.
cerr << index.msb->get_fileline() << ": error: " cerr << index.msb->get_fileline() << ": error: "
<< "Scope index expression is not constant: " << "Scope index expression is not constant: "

View File

@ -29,6 +29,13 @@
#define snprintf _snprintf #define snprintf _snprintf
#endif #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[] = { static const char* magic_sfuncs[] = {
"$time", "$time",
"$stime", "$stime",
@ -68,6 +75,153 @@ static int is_fixed_memory_word(ivl_expr_t net)
return 0; 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, static void draw_vpi_taskfunc_args(const char*call_string,
ivl_statement_t tnet, ivl_statement_t tnet,
ivl_expr_t fnet) ivl_expr_t fnet)
@ -77,11 +231,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
? ivl_stmt_parm_count(tnet) ? ivl_stmt_parm_count(tnet)
: ivl_expr_parms(fnet); : ivl_expr_parms(fnet);
struct args_info { struct args_info *args = calloc(parm_count, sizeof(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]; char buffer[4096];
@ -154,121 +304,9 @@ static void draw_vpi_taskfunc_args(const char*call_string,
break; break;
case IVL_EX_SIGNAL: case IVL_EX_SIGNAL:
/* If the signal node is narrower then the signal case IVL_EX_SELECT:
itself, then this is a part select so I'm going if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue;
to need to evaluate the expression. else break;
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;
}
/* Everything else will need to be evaluated and /* Everything else will need to be evaluated and
passed as a constant to the vpi task. */ 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); fprintf(vvp_out, "%s", call_string);
for (idx = 0 ; idx < parm_count ; idx += 1) { for (idx = 0 ; idx < parm_count ; idx += 1) {
fprintf(vvp_out, ", %s", args[idx].text); fprintf(vvp_out, ", %s", args[idx].text);
free(args[idx].text); free(args[idx].text);
if (args[idx].vec_flag) { struct args_info*ptr;
if (args[idx].vec.wid > 0) /* Clear the nested children vectors. */
clr_vector(args[idx].vec); for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) {
else if (ptr->vec_flag) {
clr_word(args[idx].vec.base); 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

@ -1670,22 +1670,31 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
vvp_errors += 1; vvp_errors += 1;
} }
/* Detect the special case that the entire number fits in an
immediate. In this case we generate a single %movi
instruction. */
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) { if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) {
unsigned long val = get_number_immediate(exp); unsigned long val = get_number_immediate(exp);
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid); fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
return res; return res;
} }
/* Use %movi as much as possible to build the value into the
destination. Use the %mov to handle the remaining general
bits. */
idx = 0; idx = 0;
unsigned long val = 0;
unsigned val_bits = 0;
unsigned val_addr = res.base;
while (idx < nwid) { while (idx < nwid) {
unsigned cnt; char src = 0;
char src = '?';
switch (bits[idx]) { switch (bits[idx]) {
case '0': case '0':
src = '0'; val_bits += 1;
break; break;
case '1': case '1':
src = '1'; val |= 1UL << val_bits;
val_bits += 1;
break; break;
case 'x': case 'x':
src = '2'; src = '2';
@ -1695,14 +1704,29 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
break; break;
} }
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1) if (val_bits >= IMM_WID
if (bits[idx+cnt] != bits[idx]) || (val_bits>0 && src != 0)
break; || (val_bits>0 && idx+1==nwid)) {
fprintf(vvp_out, " %%movi %u, %lu, %u;\n",
val_addr, val, val_bits);
val_addr += val_bits;
val_bits = 0;
val = 0;
}
fprintf(vvp_out, " %%mov %u, %c, %u;\n", if (src != 0) {
res.base+idx, src, cnt); assert(val_bits == 0);
unsigned cnt;
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1)
if (bits[idx+cnt] != bits[idx])
break;
idx += cnt; fprintf(vvp_out, " %%mov %u, %c, %u;\n", val_addr, src, cnt);
val_addr += cnt;
idx += cnt-1;
}
idx += 1;
} }
/* Pad the number up to the expression width. */ /* Pad the number up to the expression width. */

View File

@ -63,7 +63,7 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name)
vpi_printf("%s $clog2 takes at most one argument.\n", msg); vpi_printf("%s $clog2 takes at most one argument.\n", msg);
vpi_printf("%*s Found %u extra argument%s.\n", vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s"); (int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1); vpi_control(vpiFinish, 1);
} }

View File

@ -75,6 +75,7 @@ struct __vpiArray {
class vvp_fun_arrayport*ports_; class vvp_fun_arrayport*ports_;
struct __vpiCallback *vpi_callbacks; struct __vpiCallback *vpi_callbacks;
bool signed_flag;
}; };
struct __vpiArrayIterator { struct __vpiArrayIterator {
@ -452,7 +453,8 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
unsigned index = decode_array_word_pointer(obj, parent); unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals->width(); unsigned width = parent->vals->width();
vpip_vec4_get_value(parent->vals->get_word(index), width, false, value); vpip_vec4_get_value(parent->vals->get_word(index), width,
parent->signed_flag, value);
} }
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags) static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
@ -635,7 +637,7 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
unsigned index = obj->get_address(); unsigned index = obj->get_address();
vvp_vector4_t tmp = array_get_word(parent, index); vvp_vector4_t tmp = array_get_word(parent, index);
vpip_vec4_get_value(tmp, parent->vals_width, false, value); vpip_vec4_get_value(tmp, parent->vals_width, parent->signed_flag, value);
} }
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
@ -756,11 +758,14 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
} }
static vpiHandle vpip_make_array(char*label, const char*name, static vpiHandle vpip_make_array(char*label, const char*name,
int first_addr, int last_addr) int first_addr, int last_addr,
bool signed_flag)
{ {
struct __vpiArray*obj = (struct __vpiArray*) struct __vpiArray*obj = (struct __vpiArray*)
malloc(sizeof(struct __vpiArray)); malloc(sizeof(struct __vpiArray));
obj->signed_flag = signed_flag;
// Assume increasing addresses. // Assume increasing addresses.
assert(last_addr >= first_addr); assert(last_addr >= first_addr);
unsigned array_count = last_addr+1-first_addr; unsigned array_count = last_addr+1-first_addr;
@ -833,7 +838,8 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
void compile_var_array(char*label, char*name, int last, int first, void compile_var_array(char*label, char*name, int last, int first,
int msb, int lsb, char signed_flag) int msb, int lsb, char signed_flag)
{ {
vpiHandle obj = vpip_make_array(label, name, first, last); vpiHandle obj = vpip_make_array(label, name, first, last,
signed_flag != 0);
struct __vpiArray*arr = ARRAY_HANDLE(obj); struct __vpiArray*arr = ARRAY_HANDLE(obj);
@ -853,7 +859,7 @@ void compile_var_array(char*label, char*name, int last, int first,
void compile_real_array(char*label, char*name, int last, int first, void compile_real_array(char*label, char*name, int last, int first,
int msb, int lsb) int msb, int lsb)
{ {
vpiHandle obj = vpip_make_array(label, name, first, last); vpiHandle obj = vpip_make_array(label, name, first, last, true);
struct __vpiArray*arr = ARRAY_HANDLE(obj); struct __vpiArray*arr = ARRAY_HANDLE(obj);
vvp_array_t array = array_find(label); vvp_array_t array = array_find(label);
@ -874,7 +880,7 @@ void compile_real_array(char*label, char*name, int last, int first,
void compile_net_array(char*label, char*name, int last, int first) void compile_net_array(char*label, char*name, int last, int first)
{ {
vpiHandle obj = vpip_make_array(label, name, first, last); vpiHandle obj = vpip_make_array(label, name, first, last, false);
struct __vpiArray*arr = ARRAY_HANDLE(obj); struct __vpiArray*arr = ARRAY_HANDLE(obj);
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
@ -981,7 +987,8 @@ void array_word_change(vvp_array_t array, unsigned long addr)
if (cur->cb_data.value) if (cur->cb_data.value)
vpip_vec4_get_value(array->vals->get_word(addr), vpip_vec4_get_value(array->vals->get_word(addr),
array->vals_width, array->vals_width,
false, cur->cb_data.value); array->signed_flag,
cur->cb_data.value);
callback_execute(cur); callback_execute(cur);
prev = cur; prev = cur;
@ -1170,6 +1177,23 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol)
return &(obj->base); 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) void compile_array_cleanup(void)
{ {

View File

@ -105,7 +105,7 @@ static struct __vpiModPath*modpath_dst = 0;
%type <table> udp_table %type <table> udp_table
%type <argv> argument_opt argument_list %type <argv> argument_opt argument_list
%type <vpi> argument %type <vpi> argument symbol_access
%type <cdelay> delay delay_opt %type <cdelay> delay delay_opt
%% %%
@ -831,21 +831,29 @@ argument
{ $$ = 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 '>' | symbol_access
{ $$ = $1; }
;
symbol_access
: K_A '<' T_SYMBOL ',' T_NUMBER '>'
{ $$ = vpip_make_vthr_A($3, $5); } { $$ = vpip_make_vthr_A($3, $5); }
| K_A '<' T_SYMBOL ',' T_NUMBER T_NUMBER '>' | K_A '<' T_SYMBOL ',' T_NUMBER T_NUMBER '>'
{ $$ = vpip_make_vthr_A($3, $5, $6); } { $$ = vpip_make_vthr_A($3, $5, $6); }
| K_A '<' T_SYMBOL ',' T_SYMBOL '>' | K_A '<' T_SYMBOL ',' T_SYMBOL '>'
{ $$ = vpip_make_vthr_A($3, $5); } { $$ = 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 '>' | K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $7); } { $$ = vpip_make_PV($3, $5, $7); }
| K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>' | K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, -$6, $8); } { $$ = vpip_make_PV($3, -$6, $8); }
| K_PV '<' T_SYMBOL ',' T_SYMBOL ',' T_NUMBER '>' | K_PV '<' T_SYMBOL ',' T_SYMBOL ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $7); } { $$ = 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 '>' | K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_PV($3, $5, $6, $8); } { $$ = vpip_make_PV($3, $5, $6, $8); }
;
/* functor operands can only be a list of symbols. */ /* functor operands can only be a list of symbols. */
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, int base, int width);
extern vpiHandle vpip_make_PV(char*name, char*symbol, 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 vpiHandle vpip_make_PV(char*name, int tbase, int twid, int width);
extern struct __vpiPV* vpip_PV_from_handle(vpiHandle obj); 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_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*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 * 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; 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) vpiHandle vpip_make_PV(char*var, int tbase, int twid, int width)
{ {
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));

View File

@ -1626,7 +1626,10 @@ static unsigned long* divide_bits(unsigned long*ap, unsigned long*bp, unsigned w
unsigned cur_ptr = cur-1; unsigned cur_ptr = cur-1;
unsigned long cur_res; unsigned long cur_res;
if (ap[cur_ptr+btop] >= bp[btop]) { if (ap[cur_ptr+btop] >= bp[btop]) {
cur_res = ap[cur_ptr+btop] / bp[btop]; unsigned long high = 0;
if (cur_ptr+btop+1 < words)
high = ap[cur_ptr+btop+1];
cur_res = divide2words(ap[cur_ptr+btop], bp[btop], high);
} else if (cur_ptr+btop+1 >= words) { } else if (cur_ptr+btop+1 >= words) {
continue; continue;
@ -1749,6 +1752,9 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
assert(adra >= 4); assert(adra >= 4);
// Get the values, left in right, in binary form. If there is
// a problem with either (caused by an X or Z bit) then we
// know right away that the entire result is X.
unsigned long*ap = vector_to_array(thr, adra, wid); unsigned long*ap = vector_to_array(thr, adra, wid);
if (ap == 0) { if (ap == 0) {
vvp_vector4_t tmp(wid, BIT4_X); vvp_vector4_t tmp(wid, BIT4_X);
@ -1764,6 +1770,7 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
return true; return true;
} }
// Sign extend the bits in the array to fill out the array.
unsigned long sign_mask = 0; unsigned long sign_mask = 0;
if (unsigned long sign_bits = (words*CPU_WORD_BITS) - wid) { if (unsigned long sign_bits = (words*CPU_WORD_BITS) - wid) {
sign_mask = -1UL << (CPU_WORD_BITS-sign_bits); sign_mask = -1UL << (CPU_WORD_BITS-sign_bits);
@ -1773,6 +1780,7 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
bp[words-1] |= sign_mask; bp[words-1] |= sign_mask;
} }
// If the value fits in a single word, then use the native divide.
if (wid <= CPU_WORD_BITS) { if (wid <= CPU_WORD_BITS) {
if (bp[0] == 0) { if (bp[0] == 0) {
vvp_vector4_t tmp(wid, BIT4_X); vvp_vector4_t tmp(wid, BIT4_X);

View File

@ -2144,22 +2144,19 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&)
assert(0); assert(0);
} }
void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bits, void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid) unsigned base, unsigned wid, unsigned vwid)
{ {
cerr << "internal error: " << typeid(*this).name() << ": " cerr << "internal error: " << typeid(*this).name() << ": "
<< "recv_vec4_pv(" << bits << ", " << base << "recv_vec4_pv(" << bit << ", " << base
<< ", " << wid << ", " << vwid << ") not implemented" << endl; << ", " << wid << ", " << vwid << ") not implemented" << endl;
assert(0); assert(0);
} }
void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t, const vvp_vector8_t&bits, void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid) unsigned base, unsigned wid, unsigned vwid)
{ {
cerr << "internal error: " << typeid(*this).name() << ": " recv_vec4_pv(port, reduce4(bit), base, wid, vwid);
<< "recv_vec8_pv(" << bits << ", " << base
<< ", " << wid << ", " << vwid << ") not implemented" << endl;
assert(0);
} }
void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)

View File

@ -859,8 +859,9 @@ struct vvp_net_t {
* port. The value is a vvp_vector4_t. * port. The value is a vvp_vector4_t.
* *
* Most nodes do not care about the specific strengths of bits, so the * Most nodes do not care about the specific strengths of bits, so the
* default behavior for recv_vec8 is to reduce the operand to a * default behavior for recv_vec8 and recv_vec8_pv is to reduce the
* vvp_vector4_t and pass it on to the recv_vec4 method. * operand to a vvp_vector4_t and pass it on to the recv_vec4 or
* recv_vec4_pv method.
*/ */
class vvp_net_fun_t { class vvp_net_fun_t {