Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl
This commit is contained in:
commit
ed929a37bb
66
elaborate.cc
66
elaborate.cc
|
|
@ -3381,29 +3381,6 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
|
|||
verinum(1));
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
* 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.
|
||||
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.
|
||||
NetScope*scope = des->make_root_scope(*root);
|
||||
|
||||
|
|
@ -3919,7 +3927,7 @@ Design* elaborate(list<perm_string>roots)
|
|||
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.
|
||||
struct root_elem *r = new struct root_elem;
|
||||
r->mod = rmod;
|
||||
|
|
@ -3997,8 +4005,14 @@ Design* elaborate(list<perm_string>roots)
|
|||
rc &= rmod->elaborate(des, scope);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
des = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1588,6 +1588,12 @@ static int load_next_input()
|
|||
if(depend_file)
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2575,6 +2575,7 @@ DelayType NetBlock::delay_type() const
|
|||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type();
|
||||
if (dt > result) result = dt;
|
||||
if (dt == DEFINITE_DELAY) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -2609,7 +2610,9 @@ DelayType NetCondit::delay_type() const
|
|||
if (else_) {
|
||||
result = combine_delays(if_->delay_type(), else_->delay_type());
|
||||
} 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;
|
||||
|
|
|
|||
|
|
@ -3715,6 +3715,7 @@ class Design {
|
|||
// PROCESSES
|
||||
void add_process(NetProcTop*);
|
||||
void delete_process(NetProcTop*);
|
||||
bool check_always_delay() const;
|
||||
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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.
|
||||
*/
|
||||
hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
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".
|
||||
if (comp.index.empty())
|
||||
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
|
||||
// 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.
|
||||
cerr << index.msb->get_fileline() << ": error: "
|
||||
<< "Scope index expression is not constant: "
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1670,22 +1670,31 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
|||
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)) {
|
||||
unsigned long val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
|
||||
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;
|
||||
unsigned long val = 0;
|
||||
unsigned val_bits = 0;
|
||||
unsigned val_addr = res.base;
|
||||
while (idx < nwid) {
|
||||
unsigned cnt;
|
||||
char src = '?';
|
||||
char src = 0;
|
||||
switch (bits[idx]) {
|
||||
case '0':
|
||||
src = '0';
|
||||
val_bits += 1;
|
||||
break;
|
||||
case '1':
|
||||
src = '1';
|
||||
val |= 1UL << val_bits;
|
||||
val_bits += 1;
|
||||
break;
|
||||
case 'x':
|
||||
src = '2';
|
||||
|
|
@ -1695,14 +1704,29 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
|||
break;
|
||||
}
|
||||
|
||||
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1)
|
||||
if (bits[idx+cnt] != bits[idx])
|
||||
break;
|
||||
if (val_bits >= IMM_WID
|
||||
|| (val_bits>0 && src != 0)
|
||||
|| (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",
|
||||
res.base+idx, src, cnt);
|
||||
if (src != 0) {
|
||||
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. */
|
||||
|
|
|
|||
|
|
@ -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 Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
38
vvp/array.cc
38
vvp/array.cc
|
|
@ -75,6 +75,7 @@ struct __vpiArray {
|
|||
|
||||
class vvp_fun_arrayport*ports_;
|
||||
struct __vpiCallback *vpi_callbacks;
|
||||
bool signed_flag;
|
||||
};
|
||||
|
||||
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 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)
|
||||
|
|
@ -635,7 +637,7 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
|||
|
||||
unsigned index = obj->get_address();
|
||||
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)
|
||||
|
|
@ -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,
|
||||
int first_addr, int last_addr)
|
||||
int first_addr, int last_addr,
|
||||
bool signed_flag)
|
||||
{
|
||||
struct __vpiArray*obj = (struct __vpiArray*)
|
||||
malloc(sizeof(struct __vpiArray));
|
||||
|
||||
obj->signed_flag = signed_flag;
|
||||
|
||||
// Assume increasing addresses.
|
||||
assert(last_addr >= 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,
|
||||
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);
|
||||
|
||||
|
|
@ -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,
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
vpip_vec4_get_value(array->vals->get_word(addr),
|
||||
array->vals_width,
|
||||
false, cur->cb_data.value);
|
||||
array->signed_flag,
|
||||
cur->cb_data.value);
|
||||
|
||||
callback_execute(cur);
|
||||
prev = cur;
|
||||
|
|
@ -1170,6 +1177,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)
|
||||
{
|
||||
|
|
|
|||
14
vvp/parse.y
14
vvp/parse.y
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -1626,7 +1626,10 @@ static unsigned long* divide_bits(unsigned long*ap, unsigned long*bp, unsigned w
|
|||
unsigned cur_ptr = cur-1;
|
||||
unsigned long cur_res;
|
||||
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) {
|
||||
continue;
|
||||
|
|
@ -1749,6 +1752,9 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
|
|||
|
||||
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);
|
||||
if (ap == 0) {
|
||||
vvp_vector4_t tmp(wid, BIT4_X);
|
||||
|
|
@ -1764,6 +1770,7 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Sign extend the bits in the array to fill out the array.
|
||||
unsigned long sign_mask = 0;
|
||||
if (unsigned long sign_bits = (words*CPU_WORD_BITS) - wid) {
|
||||
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;
|
||||
}
|
||||
|
||||
// If the value fits in a single word, then use the native divide.
|
||||
if (wid <= CPU_WORD_BITS) {
|
||||
if (bp[0] == 0) {
|
||||
vvp_vector4_t tmp(wid, BIT4_X);
|
||||
|
|
|
|||
|
|
@ -2144,22 +2144,19 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&)
|
|||
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)
|
||||
{
|
||||
cerr << "internal error: " << typeid(*this).name() << ": "
|
||||
<< "recv_vec4_pv(" << bits << ", " << base
|
||||
<< "recv_vec4_pv(" << bit << ", " << base
|
||||
<< ", " << wid << ", " << vwid << ") not implemented" << endl;
|
||||
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)
|
||||
{
|
||||
cerr << "internal error: " << typeid(*this).name() << ": "
|
||||
<< "recv_vec8_pv(" << bits << ", " << base
|
||||
<< ", " << wid << ", " << vwid << ") not implemented" << endl;
|
||||
assert(0);
|
||||
recv_vec4_pv(port, reduce4(bit), base, wid, vwid);
|
||||
}
|
||||
|
||||
void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
|
||||
|
|
|
|||
|
|
@ -859,8 +859,9 @@ struct vvp_net_t {
|
|||
* port. The value is a vvp_vector4_t.
|
||||
*
|
||||
* 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
|
||||
* vvp_vector4_t and pass it on to the recv_vec4 method.
|
||||
* default behavior for recv_vec8 and recv_vec8_pv is to reduce the
|
||||
* operand to a vvp_vector4_t and pass it on to the recv_vec4 or
|
||||
* recv_vec4_pv method.
|
||||
*/
|
||||
class vvp_net_fun_t {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue