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) { } else if (task->type() == NetScope::FUNC) {
NetFuncDef*tmp = task->func_def(); NetFuncDef*tmp = task->func_def();
if (tmp->return_sig() != 0) { if (!tmp->is_void()) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
<< "Calling a non-void function as a task." << endl; << "Calling a non-void function as a task." << endl;
des->errors += 1; des->errors += 1;

View File

@ -2524,6 +2524,20 @@ NetETernary::~NetETernary()
delete false_val_; 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 const NetExpr* NetETernary::cond_expr() const
{ {
return cond_; 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(NetExpr*c, NetExpr*t, NetExpr*f, unsigned wid, bool signed_flag);
~NetETernary(); ~NetETernary();
const netenum_t* enumeration() const;
const NetExpr*cond_expr() const; const NetExpr*cond_expr() const;
const NetExpr*true_expr() const; const NetExpr*true_expr() const;
const NetExpr*false_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_with_nuls ',' expression : expression_list_with_nuls ',' expression
{ list<PExpr*>*tmp = $1; { list<PExpr*>*tmp = $1;
if (tmp->empty()) tmp->push_back(0);
tmp->push_back($3); tmp->push_back($3);
$$ = tmp; $$ = tmp;
} }
@ -3728,11 +3729,11 @@ expression_list_with_nuls
} }
| |
{ list<PExpr*>*tmp = new list<PExpr*>; { list<PExpr*>*tmp = new list<PExpr*>;
tmp->push_back(0);
$$ = tmp; $$ = tmp;
} }
| expression_list_with_nuls ',' | expression_list_with_nuls ','
{ list<PExpr*>*tmp = $1; { list<PExpr*>*tmp = $1;
if (tmp->empty()) tmp->push_back(0);
tmp->push_back(0); tmp->push_back(0);
$$ = tmp; $$ = 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 * 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 * 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': case 'X':
/* The reduction operators always act as if the argument is /* The reduction operators always act as if the argument is
* unsigned. */ * unsigned. */
case '!':
/* The logical negation operator works on either type. */
break; break;
case 'r': case 'r':
/* For a cast to real the expression should be signed and no /* 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 * 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 * 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) static void emit_func_return(ivl_signal_t sig)
{ {
// Handle SV void functions.
if (sig == 0)
return;
if (ivl_signal_dimensions(sig) > 0) { if (ivl_signal_dimensions(sig) > 0) {
fprintf(stderr, "%s:%u: vlog95 error: A function cannot return " fprintf(stderr, "%s:%u: vlog95 error: A function cannot return "
"an array.\n", ivl_signal_file(sig), "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 * 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 * 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) static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{ {
unsigned idx, ports = ivl_scope_ports(scope); 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_lval_t lval = ivl_stmt_lval(stmt, 0);
ivl_signal_t lsig = ivl_lval_sig(lval); ivl_signal_t lsig = ivl_lval_sig(lval);
const char *sig_name; 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; if (scope != ivl_signal_scope(lsig)) return ports;
/* It must be an input or inout port of the task. */ /* It must be an input or inout port of the task. */
sig_name = ivl_signal_basename(lsig); 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_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port); ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_INPUT) && 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) static unsigned utask_out_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{ {
unsigned idx, ports = ivl_scope_ports(scope); 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_expr_t rval = ivl_stmt_rval(stmt);
ivl_signal_t rsig = 0; ivl_signal_t rsig = 0;
ivl_expr_type_t expr_type = ivl_expr_type(rval); 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; if (ivl_signal_dimensions(rsig)) return ports;
/* It must be an output or inout port of the task. */ /* It must be an output or inout port of the task. */
sig_name = ivl_signal_basename(rsig); 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_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port); ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_OUTPUT) && 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 lineno = ivl_stmt_lineno(stmt);
unsigned start, stop, is_auto = 0; unsigned start, stop, is_auto = 0;
ivl_scope_t task_scope = 0; ivl_scope_t task_scope = 0;
unsigned is_void_func = 0;
port_expr_t port_exprs; port_expr_t port_exprs;
/* Check to see if the block is of the basic form first. */ /* Check to see if the block is of the basic form first. */
for (idx = 0; idx < count; idx += 1) { 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) { if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) {
task_idx = idx; task_idx = idx;
task_scope = ivl_stmt_call(tmp); 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; continue;
} }
/* For an automatic task the FREE must be last. */ /* 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. */ /* 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) { if (port_exprs[idx].type == IVL_SIP_NONE) {
free(port_exprs); free(port_exprs);
return 0; 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. */ /* Now that we have the arguments figured out, print the task call. */
fprintf(vlog_out, "%*c", get_indent(), ' '); fprintf(vlog_out, "%*c", get_indent(), ' ');
if (is_void_func)
fprintf(vlog_out, "if (");
emit_scope_path(scope, task_scope); emit_scope_path(scope, task_scope);
fprintf(vlog_out, "("); fprintf(vlog_out, "(");
emit_port(scope, port_exprs[0]); emit_port(scope, port_exprs[start]);
for (idx = 1; idx < ports; idx += 1) { for (idx = start + 1; idx < ports; idx += 1) {
fprintf(vlog_out, ", "); fprintf(vlog_out, ", ");
emit_port(scope, port_exprs[idx]); emit_port(scope, port_exprs[idx]);
} }
free(port_exprs); free(port_exprs);
if (is_void_func)
fprintf(vlog_out, ")");
fprintf(vlog_out, ");"); fprintf(vlog_out, ");");
emit_stmt_file_line(stmt); emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n"); 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) static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt)
{ {
ivl_scope_t task_scope = ivl_stmt_call(stmt); ivl_scope_t task_scope = ivl_stmt_call(stmt);
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK); assert((ivl_scope_type(task_scope) == IVL_SCT_TASK
assert(ivl_scope_ports(task_scope) == 0); && ivl_scope_ports(task_scope) == 0)
|| (is_void_function(task_scope)
&& ivl_scope_ports(task_scope) == 1));
fprintf(vlog_out, "%*c", get_indent(), ' '); fprintf(vlog_out, "%*c", get_indent(), ' ');
if (is_void_function(task_scope))
fprintf(vlog_out, "if (");
emit_scope_path(scope, task_scope); emit_scope_path(scope, task_scope);
if (is_void_function(task_scope))
fprintf(vlog_out, "(1'bx))");
fprintf(vlog_out, ";"); fprintf(vlog_out, ";");
emit_stmt_file_line(stmt); emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n"); fprintf(vlog_out, "\n");

View File

@ -1,7 +1,7 @@
#ifndef IVL_vlog95_priv_H #ifndef IVL_vlog95_priv_H
#define 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 * 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 * 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); 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 */ #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.time_type = vpiScaledRealTime;
delays.mtm_flag = 0; delays.mtm_flag = 0;
delays.append_flag = 0; delays.append_flag = 0;
delays.plusere_flag = 0; delays.pulsere_flag = 0;
vpi_get_delays(path, &delays); vpi_get_delays(path, &delays);
for (idx = 0 ; idx < delval_list->count ; idx += 1) { 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 time_type; /* vpiScaledRealTime, vpiSimTime */
PLI_INT32 mtm_flag; PLI_INT32 mtm_flag;
PLI_INT32 append_flag; PLI_INT32 append_flag;
PLI_INT32 plusere_flag; PLI_INT32 pulsere_flag;
} s_vpi_delay, *p_vpi_delay; } 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()); vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift; 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); ptr.ptr()->send_vec4(x_val_, 0);
return; return;
} }
if (shift > out.size()) if (overflow_flag || shift > out.size())
shift = out.size(); shift = out.size();
for (unsigned idx = 0 ; idx < shift ; idx += 1) 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()); vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift; 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); ptr.ptr()->send_vec4(x_val_, 0);
return; return;
} }
if (shift > out.size()) if (overflow_flag || shift > out.size())
shift = out.size(); shift = out.size();
for (unsigned idx = shift ; idx < out.size() ; idx += 1) 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 instruction is the same, except that it assumes the source vector is
sign extended to fit the index register. 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 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 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) 5: (reserved)
6: (reserved) 6: (reserved)
@ -634,8 +635,8 @@ bits.
* %ix/getv/s <idx>, <functor-label> * %ix/getv/s <idx>, <functor-label>
These instructions are like the %ix/vec4 instructions, except that they These instructions are like the %ix/vec4 instructions, except that they
read directly from a functor label instead of from thread bits. They read directly from a functor label instead of from thread bits. They set
set bit 4 just like %ix/get. flag 4 just like %ix/get (overflow is not currently checked by ix/getv/s).
* %ix/load <idx>, <low>, <high> * %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 replaced with X instead of a shifted result. This is intended to
detect that the index contents were not valid. detect that the index contents were not valid.
For a negative shift, %shiftr will pad the value with 'bx.
* %split/vec4 <wid> * %split/vec4 <wid>
Pull the top vec4 vector from the stack and split it into two 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; vvp_vector4_t vec;
sig->vec4_value(vec); sig->vec4_value(vec);
bool overflow_flag;
uint64_t val; uint64_t val;
bool known_flag = vector4_to_value(vec, val); bool known_flag = vector4_to_value(vec, overflow_flag, val);
if (known_flag) if (known_flag)
thr->words[index].w_uint = val; 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; thr->words[index].w_uint = 0;
/* Set bit 4 as a flag if the input is unknown. */ /* 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; return true;
} }
@ -3376,12 +3377,19 @@ static uint64_t vec4_to_index(vthread_t thr, bool signed_flag)
thr->flags[4] = BIT4_0; thr->flags[4] = BIT4_0;
assert(sizeof(bits[0]) <= sizeof(v)); assert(sizeof(bits[0]) <= sizeof(v));
//assert(val_size <= 8*sizeof(v));
v = 0; v = 0;
for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) { for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) {
uint64_t tmp = bits[idx/8/sizeof(bits[0])]; uint64_t tmp = bits[idx/8/sizeof(bits[0])];
if (idx < 8*sizeof(v)) {
v |= tmp << idx; 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 // 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) bool of_SHIFTL(vthread_t thr, vvp_code_t cp)
{ {
int use_index = cp->number; 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(); vvp_vector4_t&val = thr->peek_vec4();
int wid = val.size(); unsigned wid = val.size();
if (thr->flags[4] == BIT4_1) { if (thr->flags[4] == BIT4_1) {
// The result is 'bx if the shift amount is undefined // The result is 'bx if the shift amount is undefined
val = vvp_vector4_t(wid, BIT4_X); 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 // Shift is so big that all value is shifted out. Write
// a constant 0 result. // a constant 0 result.
val = vvp_vector4_t(wid, BIT4_0); 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); vvp_vector4_t tmp (shift, BIT4_0);
val.set_vec(0, tmp); val.set_vec(0, tmp);
val.set_vec(shift, blk); 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; 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) bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
{ {
int use_index = cp->number; 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(); vvp_vector4_t val = thr->pop_vec4();
int wid = val.size(); unsigned wid = val.size();
if (thr->flags[4] == BIT4_1) { if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X); 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); val = vvp_vector4_t(wid, BIT4_0);
} else if (shift > 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); vvp_vector4_t tmp (shift, BIT4_0);
val.set_vec(0, blk); val.set_vec(0, blk);
val.set_vec(wid-shift, tmp); 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); 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) bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp)
{ {
int use_index = cp->number; 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(); 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); vvp_bit4_t sign_bit = val.value(val.size()-1);
if (thr->flags[4] == BIT4_1) { if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X); 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); val = vvp_vector4_t(wid, sign_bit);
} else if (shift > 0) { } 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); vvp_vector4_t tmp (shift, sign_bit);
val.set_vec(0, blk); val.set_vec(0, blk);
val.set_vec(wid-shift, tmp); 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); 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, template bool vector4_to_value(const vvp_vector4_t&vec, uint64_t&val,
bool is_signed, bool is_arithmetic); 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 res = 0;
T msk = 1; T msk = 1;
overflow_flag = false;
unsigned size = vec.size(); unsigned size = vec.size();
for (unsigned idx = 0 ; idx < size ; idx += 1) { for (unsigned idx = 0 ; idx < size ; idx += 1) {
switch (vec.value(idx)) { switch (vec.value(idx)) {
case BIT4_0: case BIT4_0:
break; break;
case BIT4_1: case BIT4_1:
// On overflow, return the maximum value of type T
if (msk == 0) if (msk == 0)
res = ~msk; overflow_flag = true;
else else
res |= msk; res |= msk;
break; break;
@ -2070,9 +2071,11 @@ template <class T> bool vector4_to_value(const vvp_vector4_t&vec, T&val)
return true; 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 #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 #endif
bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag) 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_signed,
bool is_arithmetic =true); 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); extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);