Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2019-11-21 18:35:55 -08:00
commit f147cf9c61
15 changed files with 109 additions and 80 deletions

View File

@ -3719,7 +3719,7 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
} else if (task->type() == NetScope::FUNC) {
NetFuncDef*tmp = task->func_def();
if (tmp->return_sig() != 0) {
if (!tmp->is_void()) {
cerr << get_fileline() << ": error: "
<< "Calling a non-void function as a task." << endl;
des->errors += 1;

View File

@ -2524,6 +2524,20 @@ NetETernary::~NetETernary()
delete false_val_;
}
const netenum_t* NetETernary::enumeration() const
{
// If the condition can evaluate to an ambiguous value,
// the result may be blended, and so is not guaranteed
// to be a valid enumeration value.
if (cond_->expr_type() != IVL_VT_BOOL)
return 0;
if (true_val_->enumeration() != false_val_->enumeration())
return 0;
return true_val_->enumeration();
}
const NetExpr* NetETernary::cond_expr() const
{
return cond_;

View File

@ -4757,6 +4757,8 @@ class NetETernary : public NetExpr {
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f, unsigned wid, bool signed_flag);
~NetETernary();
const netenum_t* enumeration() const;
const NetExpr*cond_expr() const;
const NetExpr*true_expr() const;
const NetExpr*false_expr() const;

View File

@ -3718,6 +3718,7 @@ expr_mintypmax
expression_list_with_nuls
: expression_list_with_nuls ',' expression
{ list<PExpr*>*tmp = $1;
if (tmp->empty()) tmp->push_back(0);
tmp->push_back($3);
$$ = tmp;
}
@ -3728,11 +3729,11 @@ expression_list_with_nuls
}
|
{ list<PExpr*>*tmp = new list<PExpr*>;
tmp->push_back(0);
$$ = tmp;
}
| expression_list_with_nuls ','
{ list<PExpr*>*tmp = $1;
if (tmp->empty()) tmp->push_back(0);
tmp->push_back(0);
$$ = tmp;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2019 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -138,6 +138,8 @@ static expr_sign_t expr_get_unary_sign_type(ivl_expr_t expr)
case 'X':
/* The reduction operators always act as if the argument is
* unsigned. */
case '!':
/* The logical negation operator works on either type. */
break;
case 'r':
/* For a cast to real the expression should be signed and no

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2019 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,6 +26,10 @@ const char *func_rtn_name = 0;
static void emit_func_return(ivl_signal_t sig)
{
// Handle SV void functions.
if (sig == 0)
return;
if (ivl_signal_dimensions(sig) > 0) {
fprintf(stderr, "%s:%u: vlog95 error: A function cannot return "
"an array.\n", ivl_signal_file(sig),

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2017 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2019 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -667,6 +667,7 @@ static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned idx, ports = ivl_scope_ports(scope);
unsigned first_arg = is_void_function(scope) ? 1 : 0;
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
ivl_signal_t lsig = ivl_lval_sig(lval);
const char *sig_name;
@ -682,7 +683,7 @@ static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
if (scope != ivl_signal_scope(lsig)) return ports;
/* It must be an input or inout port of the task. */
sig_name = ivl_signal_basename(lsig);
for (idx = 0; idx < ports; idx += 1) {
for (idx = first_arg; idx < ports; idx += 1) {
ivl_signal_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_INPUT) &&
@ -699,6 +700,7 @@ static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
static unsigned utask_out_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned idx, ports = ivl_scope_ports(scope);
unsigned first_arg = is_void_function(scope) ? 1 : 0;
ivl_expr_t rval = ivl_stmt_rval(stmt);
ivl_signal_t rsig = 0;
ivl_expr_type_t expr_type = ivl_expr_type(rval);
@ -731,7 +733,7 @@ static unsigned utask_out_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
if (ivl_signal_dimensions(rsig)) return ports;
/* It must be an output or inout port of the task. */
sig_name = ivl_signal_basename(rsig);
for (idx = 0; idx < ports; idx += 1) {
for (idx = first_arg; idx < ports; idx += 1) {
ivl_signal_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_OUTPUT) &&
@ -794,6 +796,7 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
unsigned lineno = ivl_stmt_lineno(stmt);
unsigned start, stop, is_auto = 0;
ivl_scope_t task_scope = 0;
unsigned is_void_func = 0;
port_expr_t port_exprs;
/* Check to see if the block is of the basic form first. */
for (idx = 0; idx < count; idx += 1) {
@ -809,7 +812,8 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) {
task_idx = idx;
task_scope = ivl_stmt_call(tmp);
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK);
is_void_func = is_void_function(task_scope);
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK || is_void_func);
continue;
}
/* For an automatic task the FREE must be last. */
@ -871,7 +875,8 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
}
/* Verify that all the ports were defined. */
for (idx = 0; idx < ports; idx += 1) {
start = is_void_func ? 1 : 0;
for (idx = start; idx < ports; idx += 1) {
if (port_exprs[idx].type == IVL_SIP_NONE) {
free(port_exprs);
return 0;
@ -880,14 +885,18 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
/* Now that we have the arguments figured out, print the task call. */
fprintf(vlog_out, "%*c", get_indent(), ' ');
if (is_void_func)
fprintf(vlog_out, "if (");
emit_scope_path(scope, task_scope);
fprintf(vlog_out, "(");
emit_port(scope, port_exprs[0]);
for (idx = 1; idx < ports; idx += 1) {
emit_port(scope, port_exprs[start]);
for (idx = start + 1; idx < ports; idx += 1) {
fprintf(vlog_out, ", ");
emit_port(scope, port_exprs[idx]);
}
free(port_exprs);
if (is_void_func)
fprintf(vlog_out, ")");
fprintf(vlog_out, ");");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -1419,10 +1428,16 @@ static void emit_stmt_trigger(ivl_scope_t scope, ivl_statement_t stmt)
static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt)
{
ivl_scope_t task_scope = ivl_stmt_call(stmt);
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK);
assert(ivl_scope_ports(task_scope) == 0);
assert((ivl_scope_type(task_scope) == IVL_SCT_TASK
&& ivl_scope_ports(task_scope) == 0)
|| (is_void_function(task_scope)
&& ivl_scope_ports(task_scope) == 1));
fprintf(vlog_out, "%*c", get_indent(), ' ');
if (is_void_function(task_scope))
fprintf(vlog_out, "if (");
emit_scope_path(scope, task_scope);
if (is_void_function(task_scope))
fprintf(vlog_out, "(1'bx))");
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");

View File

@ -1,7 +1,7 @@
#ifndef IVL_vlog95_priv_H
#define IVL_vlog95_priv_H
/*
* Copyright (C) 2010-2017 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2019 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -162,4 +162,10 @@ extern void free_emitted_scope_list(void);
*/
extern void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex);
static inline unsigned is_void_function(ivl_scope_t scope)
{
return ivl_scope_type(scope) == IVL_SCT_FUNCTION
&& ivl_scope_port(scope, 0) == 0;
}
#endif /* IVL_vlog95_priv_H */

View File

@ -186,7 +186,7 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
delays.time_type = vpiScaledRealTime;
delays.mtm_flag = 0;
delays.append_flag = 0;
delays.plusere_flag = 0;
delays.pulsere_flag = 0;
vpi_get_delays(path, &delays);
for (idx = 0 ; idx < delval_list->count ; idx += 1) {

View File

@ -231,7 +231,7 @@ typedef struct t_vpi_delay {
PLI_INT32 time_type; /* vpiScaledRealTime, vpiSimTime */
PLI_INT32 mtm_flag;
PLI_INT32 append_flag;
PLI_INT32 plusere_flag;
PLI_INT32 pulsere_flag;
} s_vpi_delay, *p_vpi_delay;

View File

@ -955,13 +955,14 @@ void vvp_shiftl::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift;
if (! vector4_to_value(op_b_, shift)) {
if (! vector4_to_value(op_b_, overflow_flag, shift)) {
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
if (shift > out.size())
if (overflow_flag || shift > out.size())
shift = out.size();
for (unsigned idx = 0 ; idx < shift ; idx += 1)
@ -989,13 +990,14 @@ void vvp_shiftr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift;
if (! vector4_to_value(op_b_, shift)) {
if (! vector4_to_value(op_b_, overflow_flag, shift)) {
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
if (shift > out.size())
if (overflow_flag || shift > out.size())
shift = out.size();
for (unsigned idx = shift ; idx < out.size() ; idx += 1)

View File

@ -621,12 +621,13 @@ or z, then the index register gets the value 0. The %ix/vec4/s
instruction is the same, except that it assumes the source vector is
sign extended to fit the index register.
The instruction also writes into bit 4 a 1 if any of the bits of the
The instruction also writes into flag 4 a 1 if any of the bits of the
input vector are x or z. This is a flag that the 0 value written into
the index register is really the result of calculating from unknown
bits.
bits. It writes an X into flag 4 if the vec4 value overflows the index
register.
4: unknown value
4: unknown value or overflow
5: (reserved)
6: (reserved)
@ -634,8 +635,8 @@ bits.
* %ix/getv/s <idx>, <functor-label>
These instructions are like the %ix/vec4 instructions, except that they
read directly from a functor label instead of from thread bits. They
set bit 4 just like %ix/get.
read directly from a functor label instead of from thread bits. They set
flag 4 just like %ix/get (overflow is not currently checked by ix/getv/s).
* %ix/load <idx>, <low>, <high>
@ -1106,8 +1107,6 @@ The instruction also checks flag bit 4. If it is true, the result is
replaced with X instead of a shifted result. This is intended to
detect that the index contents were not valid.
For a negative shift, %shiftr will pad the value with 'bx.
* %split/vec4 <wid>
Pull the top vec4 vector from the stack and split it into two

View File

@ -3311,8 +3311,9 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
vvp_vector4_t vec;
sig->vec4_value(vec);
bool overflow_flag;
uint64_t val;
bool known_flag = vector4_to_value(vec, val);
bool known_flag = vector4_to_value(vec, overflow_flag, val);
if (known_flag)
thr->words[index].w_uint = val;
@ -3320,7 +3321,7 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
thr->words[index].w_uint = 0;
/* Set bit 4 as a flag if the input is unknown. */
thr->flags[4] = known_flag ? BIT4_0 : BIT4_1;
thr->flags[4] = known_flag ? (overflow_flag ? BIT4_X : BIT4_0) : BIT4_1;
return true;
}
@ -3376,12 +3377,19 @@ static uint64_t vec4_to_index(vthread_t thr, bool signed_flag)
thr->flags[4] = BIT4_0;
assert(sizeof(bits[0]) <= sizeof(v));
//assert(val_size <= 8*sizeof(v));
v = 0;
for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) {
uint64_t tmp = bits[idx/8/sizeof(bits[0])];
v |= tmp << idx;
if (idx < 8*sizeof(v)) {
v |= tmp << idx;
} else {
bool overflow = signed_flag && (v >> 63) ? ~tmp != 0 : tmp != 0;
if (overflow) {
thr->flags[4] = BIT4_X;
break;
}
}
}
// Set the high bits that are not necessarily filled in by the
@ -5402,16 +5410,16 @@ bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t cp)
bool of_SHIFTL(vthread_t thr, vvp_code_t cp)
{
int use_index = cp->number;
int shift = thr->words[use_index].w_int;
uint64_t shift = thr->words[use_index].w_uint;
vvp_vector4_t&val = thr->peek_vec4();
int wid = val.size();
unsigned wid = val.size();
if (thr->flags[4] == BIT4_1) {
// The result is 'bx if the shift amount is undefined
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift >= wid) {
} else if (thr->flags[4] == BIT4_X || shift >= wid) {
// Shift is so big that all value is shifted out. Write
// a constant 0 result.
val = vvp_vector4_t(wid, BIT4_0);
@ -5421,18 +5429,6 @@ bool of_SHIFTL(vthread_t thr, vvp_code_t cp)
vvp_vector4_t tmp (shift, BIT4_0);
val.set_vec(0, tmp);
val.set_vec(shift, blk);
} else if (shift < -wid) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift < 0) {
// Negative left shift is a right shift.
// For a negative shift, we pad with 'bx.
int use_shift = -shift;
vvp_vector4_t blk = val.subvalue(use_shift, wid-use_shift);
vvp_vector4_t tmp (use_shift, BIT4_X);
val.set_vec(0, blk);
val.set_vec(wid-use_shift, tmp);
}
return true;
@ -5447,15 +5443,15 @@ bool of_SHIFTL(vthread_t thr, vvp_code_t cp)
bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
{
int use_index = cp->number;
int shift = thr->words[use_index].w_int;
uint64_t shift = thr->words[use_index].w_uint;
vvp_vector4_t val = thr->pop_vec4();
int wid = val.size();
unsigned wid = val.size();
if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift > wid) {
} else if (thr->flags[4] == BIT4_X || shift > wid) {
val = vvp_vector4_t(wid, BIT4_0);
} else if (shift > 0) {
@ -5463,18 +5459,6 @@ bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
vvp_vector4_t tmp (shift, BIT4_0);
val.set_vec(0, blk);
val.set_vec(wid-shift, tmp);
} else if (shift < -wid) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift < 0) {
// Negative right shift is a left shift.
// For a negative shift, we pad with 'bx.
int use_shift = -shift;
vvp_vector4_t blk = val.subvalue(0, wid-use_shift);
vvp_vector4_t tmp (use_shift, BIT4_X);
val.set_vec(0, tmp);
val.set_vec(use_shift, blk);
}
thr->push_vec4(val);
@ -5487,17 +5471,17 @@ bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp)
{
int use_index = cp->number;
int shift = thr->words[use_index].w_int;
uint64_t shift = thr->words[use_index].w_uint;
vvp_vector4_t val = thr->pop_vec4();
int wid = val.size();
unsigned wid = val.size();
vvp_bit4_t sign_bit = val.value(val.size()-1);
if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift > wid) {
} else if (thr->flags[4] == BIT4_X || shift > wid) {
val = vvp_vector4_t(wid, sign_bit);
} else if (shift > 0) {
@ -5505,16 +5489,6 @@ bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp)
vvp_vector4_t tmp (shift, sign_bit);
val.set_vec(0, blk);
val.set_vec(wid-shift, tmp);
} else if (shift < -wid) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift < 0) {
int use_shift = -shift;
vvp_vector4_t blk = val.subvalue(0, wid-use_shift);
vvp_vector4_t tmp(use_shift, BIT4_X);
val.set_vec(0, tmp);
val.set_vec(use_shift, blk);
}
thr->push_vec4(val);

View File

@ -2042,20 +2042,21 @@ template bool vector4_to_value(const vvp_vector4_t&vec, uint32_t&val,
template bool vector4_to_value(const vvp_vector4_t&vec, uint64_t&val,
bool is_signed, bool is_arithmetic);
template <class T> bool vector4_to_value(const vvp_vector4_t&vec, T&val)
template <class T> bool vector4_to_value(const vvp_vector4_t&vec,
bool&overflow_flag, T&val)
{
T res = 0;
T msk = 1;
overflow_flag = false;
unsigned size = vec.size();
for (unsigned idx = 0 ; idx < size ; idx += 1) {
switch (vec.value(idx)) {
case BIT4_0:
break;
case BIT4_1:
// On overflow, return the maximum value of type T
if (msk == 0)
res = ~msk;
overflow_flag = true;
else
res |= msk;
break;
@ -2070,9 +2071,11 @@ template <class T> bool vector4_to_value(const vvp_vector4_t&vec, T&val)
return true;
}
template bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val);
template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag,
unsigned long&val);
#ifndef UL_AND_TIME64_SAME
template bool vector4_to_value(const vvp_vector4_t&vec, vvp_time64_t&val);
template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag,
vvp_time64_t&val);
#endif
bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag)

View File

@ -558,7 +558,14 @@ template <class T> extern bool vector4_to_value(const vvp_vector4_t&a, T&val,
bool is_signed,
bool is_arithmetic =true);
template <class T> extern bool vector4_to_value(const vvp_vector4_t&a, T&val);
template <class T> extern bool vector4_to_value(const vvp_vector4_t&a,
bool&overflow_flag, T&val);
template <class T> inline bool vector4_to_value(const vvp_vector4_t&a, T&val)
{
bool overflow_flag;
return vector4_to_value(a, overflow_flag, val);
}
extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);