diff --git a/elaborate.cc b/elaborate.cc index f1c3c0553..e149693cf 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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; diff --git a/netlist.cc b/netlist.cc index c0650959e..328e1a42b 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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_; diff --git a/netlist.h b/netlist.h index ae546bc94..66eb0890e 100644 --- a/netlist.h +++ b/netlist.h @@ -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; diff --git a/parse.y b/parse.y index 86d5de910..07063d4dd 100644 --- a/parse.y +++ b/parse.y @@ -3718,6 +3718,7 @@ expr_mintypmax expression_list_with_nuls : expression_list_with_nuls ',' expression { list*tmp = $1; + if (tmp->empty()) tmp->push_back(0); tmp->push_back($3); $$ = tmp; } @@ -3728,11 +3729,11 @@ expression_list_with_nuls } | { list*tmp = new list; - tmp->push_back(0); $$ = tmp; } | expression_list_with_nuls ',' { list*tmp = $1; + if (tmp->empty()) tmp->push_back(0); tmp->push_back(0); $$ = tmp; } diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index c8c16c00d..e0fcbad7f 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -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 diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index ee0372b80..c005d770a 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -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), diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 8d2a98d5b..3107baffa 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -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"); diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 36e3cf543..97670f71f 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -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 */ diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 9d3cd2b7b..aaef9cb45 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -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) { diff --git a/vpi_user.h b/vpi_user.h index 05a3c3c4b..fd2cf4190 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -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; diff --git a/vvp/arith.cc b/vvp/arith.cc index 9348227a2..409cb71a0 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -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) diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index c7b2baf50..02f4ba7a7 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -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 , 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 , , @@ -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 Pull the top vec4 vector from the stack and split it into two diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2051b1176..935aea1ff 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 73852fcba..cd75646be 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -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 bool vector4_to_value(const vvp_vector4_t&vec, T&val) +template 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 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) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index c143fa571..b1ffd3cc7 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -558,7 +558,14 @@ template extern bool vector4_to_value(const vvp_vector4_t&a, T&val, bool is_signed, bool is_arithmetic =true); -template extern bool vector4_to_value(const vvp_vector4_t&a, T&val); +template extern bool vector4_to_value(const vvp_vector4_t&a, + bool&overflow_flag, T&val); + +template 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);