Fix dynamic array assignment to make a copy of the rvalue.
IEEE Std 1800-2017 Section 7.6 Array assignments Assignment of a dynamic array creates a duplicate of the source, so that assignments to the copy don't impact the original. Handle all sorts of dynamic array base types.
This commit is contained in:
parent
7277f4e807
commit
3c2fb6a601
|
|
@ -954,7 +954,7 @@ static int show_stmt_assign_darray_pattern(ivl_statement_t net)
|
||||||
|
|
||||||
// FIXME: At the moment we reallocate the array space.
|
// FIXME: At the moment we reallocate the array space.
|
||||||
// This probably should be a resize to avoid values glitching
|
// This probably should be a resize to avoid values glitching
|
||||||
/* Allocate at least enough space for the array patter. */
|
/* Allocate at least enough space for the array pattern. */
|
||||||
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, ivl_expr_parms(rval));
|
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, ivl_expr_parms(rval));
|
||||||
/* This can not have have a X/Z value so clear flag 4. */
|
/* This can not have have a X/Z value so clear flag 4. */
|
||||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||||
|
|
@ -1038,12 +1038,36 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
||||||
elements of the l-value. */
|
elements of the l-value. */
|
||||||
errors += show_stmt_assign_darray_pattern(net);
|
errors += show_stmt_assign_darray_pattern(net);
|
||||||
|
|
||||||
} else {
|
} else if (ivl_expr_type(rval) == IVL_EX_NEW) {
|
||||||
/* There is no l-value mux, so this must be an
|
// There is no l-value mux, and the r-value expression is
|
||||||
assignment to the array as a whole. Evaluate the
|
// a "new" expression. Handle this by simply storing the
|
||||||
"object", and store the evaluated result. */
|
// new object to the lval.
|
||||||
errors += draw_eval_object(rval);
|
errors += draw_eval_object(rval);
|
||||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", var);
|
fprintf(vvp_out, " %%store/obj v%p_0; %s:%u: %s = new ...\n",
|
||||||
|
var, ivl_stmt_file(net), ivl_stmt_lineno(net),
|
||||||
|
ivl_signal_basename(var));
|
||||||
|
|
||||||
|
} else if (ivl_expr_type(rval) == IVL_EX_SIGNAL) {
|
||||||
|
|
||||||
|
// There is no l-value mux, and the r-value expression is
|
||||||
|
// a "signal" expression. Store a duplicate into the lvalue
|
||||||
|
// By using the %dup/obj. Remember to pop the rvalue that
|
||||||
|
// is no longer needed.
|
||||||
|
errors += draw_eval_object(rval);
|
||||||
|
fprintf(vvp_out, " %%dup/obj;\n");
|
||||||
|
fprintf(vvp_out, " %%store/obj v%p_0; %s:%u: %s = <signal>\n",
|
||||||
|
var, ivl_stmt_file(net), ivl_stmt_lineno(net),
|
||||||
|
ivl_signal_basename(var));
|
||||||
|
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// There is no l-value mux, so this must be an
|
||||||
|
// assignment to the array as a whole. Evaluate the
|
||||||
|
// "object", and store the evaluated result.
|
||||||
|
errors += draw_eval_object(rval);
|
||||||
|
fprintf(vvp_out, " %%store/obj v%p_0; %s:%u: %s = <expr type %d>\n",
|
||||||
|
var, ivl_stmt_file(net), ivl_stmt_lineno(net),
|
||||||
|
ivl_signal_basename(var), ivl_expr_type(rval));
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ extern bool of_DISABLE_FORK(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_DIV(vthread_t thr, vvp_code_t code);
|
extern bool of_DIV(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);
|
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
|
||||||
|
extern bool of_DUP_OBJ(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_DUP_REAL(vthread_t thr, vvp_code_t code);
|
extern bool of_DUP_REAL(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_DUP_VEC4(vthread_t thr, vvp_code_t code);
|
extern bool of_DUP_VEC4(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ static const struct opcode_table_s opcode_table[] = {
|
||||||
{ "%div", of_DIV, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%div", of_DIV, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%div/s", of_DIV_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%div/s", of_DIV_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%div/wr", of_DIV_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%div/wr", of_DIV_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
|
{ "%dup/obj", of_DUP_OBJ, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%dup/real", of_DUP_REAL,0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%dup/real", of_DUP_REAL,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%dup/vec4", of_DUP_VEC4,0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%dup/vec4", of_DUP_VEC4,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
|
|
|
||||||
|
|
@ -491,8 +491,9 @@ This opcode divides the left operand by the right operand. If the
|
||||||
right operand is 0, then the result is NaN.
|
right operand is 0, then the result is NaN.
|
||||||
|
|
||||||
|
|
||||||
* dup/real
|
* %dup/real
|
||||||
* dup/vec4
|
* %dup/vec4
|
||||||
|
* %dup/obj
|
||||||
|
|
||||||
These opcodes duplicate the value on the top of the stack for the
|
These opcodes duplicate the value on the top of the stack for the
|
||||||
corresponding type.
|
corresponding type.
|
||||||
|
|
|
||||||
|
|
@ -3002,6 +3002,19 @@ bool of_DIV_WR(vthread_t thr, vvp_code_t)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* %dup/obj
|
||||||
|
* %dup/real
|
||||||
|
* %dup/vec4
|
||||||
|
*
|
||||||
|
* Push a duplicate of the object on the appropriate stack.
|
||||||
|
*/
|
||||||
|
bool of_DUP_OBJ(vthread_t thr, vvp_code_t)
|
||||||
|
{
|
||||||
|
thr->push_object(thr->peek_object().duplicate());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_DUP_REAL(vthread_t thr, vvp_code_t)
|
bool of_DUP_REAL(vthread_t thr, vvp_code_t)
|
||||||
{
|
{
|
||||||
thr->push_real(thr->peek_real(0));
|
thr->push_real(thr->peek_real(0));
|
||||||
|
|
@ -5596,6 +5609,17 @@ bool of_RETLOAD_VEC4(vthread_t thr, vvp_code_t cp)
|
||||||
return retload<vvp_vector4_t>(thr, cp);
|
return retload<vvp_vector4_t>(thr, cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* %scopy
|
||||||
|
*
|
||||||
|
* Pop the top item from the object stack, and shallow_copy() that item into
|
||||||
|
* the new top of the object stack. This will copy at many items as needed
|
||||||
|
* from the source object to fill the target object. If the target object is
|
||||||
|
* larger then the source object, then some items will be left unchanged.
|
||||||
|
*
|
||||||
|
* The object may be any kind of object that supports shallow_copy(),
|
||||||
|
* including dynamic arrays and class objects.
|
||||||
|
*/
|
||||||
bool of_SCOPY(vthread_t thr, vvp_code_t)
|
bool of_SCOPY(vthread_t thr, vvp_code_t)
|
||||||
{
|
{
|
||||||
vvp_object_t tmp;
|
vvp_object_t tmp;
|
||||||
|
|
|
||||||
|
|
@ -67,11 +67,6 @@ void vvp_darray::get_word(unsigned, vvp_object_t&)
|
||||||
cerr << "XXXX get_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
cerr << "XXXX get_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vvp_darray::shallow_copy(const vvp_object*)
|
|
||||||
{
|
|
||||||
cerr << "XXXX shallow_copy(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_vector4_t vvp_darray::get_bitstream(bool)
|
vvp_vector4_t vvp_darray::get_bitstream(bool)
|
||||||
{
|
{
|
||||||
cerr << "XXXX get_bitstream() not implemented for " << typeid(*this).name() << endl;
|
cerr << "XXXX get_bitstream() not implemented for " << typeid(*this).name() << endl;
|
||||||
|
|
@ -122,6 +117,15 @@ template <class TYPE> void vvp_darray_atom<TYPE>::shallow_copy(const vvp_object*
|
||||||
array_[idx] = that->array_[idx];
|
array_[idx] = that->array_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class TYPE> vvp_object* vvp_darray_atom<TYPE>::duplicate(void) const
|
||||||
|
{
|
||||||
|
vvp_darray_atom<TYPE>*that = new vvp_darray_atom<TYPE>(array_.size());
|
||||||
|
for (size_t idx = 0 ; idx < array_.size() ; idx += 1)
|
||||||
|
that->array_[idx] = array_[idx];
|
||||||
|
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
template <class TYPE> vvp_vector4_t vvp_darray_atom<TYPE>::get_bitstream(bool)
|
template <class TYPE> vvp_vector4_t vvp_darray_atom<TYPE>::get_bitstream(bool)
|
||||||
{
|
{
|
||||||
const unsigned word_wid = sizeof(TYPE) * 8;
|
const unsigned word_wid = sizeof(TYPE) * 8;
|
||||||
|
|
@ -192,6 +196,16 @@ void vvp_darray_vec4::shallow_copy(const vvp_object*obj)
|
||||||
array_[idx] = that->array_[idx];
|
array_[idx] = that->array_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_object* vvp_darray_vec4::duplicate(void) const
|
||||||
|
{
|
||||||
|
vvp_darray_vec4*that = new vvp_darray_vec4(array_.size(), word_wid_);
|
||||||
|
|
||||||
|
for (size_t idx = 0 ; idx < array_.size() ; idx += 1)
|
||||||
|
that->array_[idx] = array_[idx];
|
||||||
|
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
vvp_vector4_t vvp_darray_vec4::get_bitstream(bool as_vec4)
|
vvp_vector4_t vvp_darray_vec4::get_bitstream(bool as_vec4)
|
||||||
{
|
{
|
||||||
vvp_vector4_t vec(array_.size() * word_wid_, BIT4_0);
|
vvp_vector4_t vec(array_.size() * word_wid_, BIT4_0);
|
||||||
|
|
@ -344,6 +358,16 @@ void vvp_darray_real::shallow_copy(const vvp_object*obj)
|
||||||
array_[idx] = that->array_[idx];
|
array_[idx] = that->array_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_object* vvp_darray_real::duplicate(void) const
|
||||||
|
{
|
||||||
|
vvp_darray_real*that = new vvp_darray_real(array_.size());
|
||||||
|
|
||||||
|
for (size_t idx = 0 ; idx < array_.size() ; idx += 1)
|
||||||
|
that->array_[idx] = array_[idx];
|
||||||
|
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
vvp_vector4_t vvp_darray_real::get_bitstream(bool)
|
vvp_vector4_t vvp_darray_real::get_bitstream(bool)
|
||||||
{
|
{
|
||||||
const unsigned word_wid = sizeof(double) * 8;
|
const unsigned word_wid = sizeof(double) * 8;
|
||||||
|
|
@ -406,6 +430,16 @@ void vvp_darray_string::shallow_copy(const vvp_object*obj)
|
||||||
array_[idx] = that->array_[idx];
|
array_[idx] = that->array_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_object* vvp_darray_string::duplicate(void) const
|
||||||
|
{
|
||||||
|
vvp_darray_string*that = new vvp_darray_string(array_.size());
|
||||||
|
|
||||||
|
for (size_t idx = 0 ; idx < array_.size() ; idx += 1)
|
||||||
|
that->array_[idx] = array_[idx];
|
||||||
|
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
vvp_queue::~vvp_queue()
|
vvp_queue::~vvp_queue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,6 @@ class vvp_darray : public vvp_object {
|
||||||
virtual void set_word(unsigned adr, const vvp_object_t&value);
|
virtual void set_word(unsigned adr, const vvp_object_t&value);
|
||||||
virtual void get_word(unsigned adr, vvp_object_t&value);
|
virtual void get_word(unsigned adr, vvp_object_t&value);
|
||||||
|
|
||||||
virtual void shallow_copy(const vvp_object*obj);
|
|
||||||
|
|
||||||
virtual vvp_vector4_t get_bitstream(bool as_vec4);
|
virtual vvp_vector4_t get_bitstream(bool as_vec4);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -60,6 +58,7 @@ template <class TYPE> class vvp_darray_atom : public vvp_darray {
|
||||||
void set_word(unsigned adr, const vvp_vector4_t&value);
|
void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||||
void get_word(unsigned adr, vvp_vector4_t&value);
|
void get_word(unsigned adr, vvp_vector4_t&value);
|
||||||
void shallow_copy(const vvp_object*obj);
|
void shallow_copy(const vvp_object*obj);
|
||||||
|
vvp_object* duplicate(void) const;
|
||||||
vvp_vector4_t get_bitstream(bool as_vec4);
|
vvp_vector4_t get_bitstream(bool as_vec4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -77,6 +76,7 @@ class vvp_darray_vec4 : public vvp_darray {
|
||||||
void set_word(unsigned adr, const vvp_vector4_t&value);
|
void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||||
void get_word(unsigned adr, vvp_vector4_t&value);
|
void get_word(unsigned adr, vvp_vector4_t&value);
|
||||||
void shallow_copy(const vvp_object*obj);
|
void shallow_copy(const vvp_object*obj);
|
||||||
|
vvp_object* duplicate(void) const;
|
||||||
vvp_vector4_t get_bitstream(bool as_vec4);
|
vvp_vector4_t get_bitstream(bool as_vec4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -112,6 +112,7 @@ class vvp_darray_real : public vvp_darray {
|
||||||
void set_word(unsigned adr, double value);
|
void set_word(unsigned adr, double value);
|
||||||
void get_word(unsigned adr, double&value);
|
void get_word(unsigned adr, double&value);
|
||||||
void shallow_copy(const vvp_object*obj);
|
void shallow_copy(const vvp_object*obj);
|
||||||
|
vvp_object* duplicate(void) const;
|
||||||
vvp_vector4_t get_bitstream(bool as_vec4);
|
vvp_vector4_t get_bitstream(bool as_vec4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -128,6 +129,7 @@ class vvp_darray_string : public vvp_darray {
|
||||||
void set_word(unsigned adr, const std::string&value);
|
void set_word(unsigned adr, const std::string&value);
|
||||||
void get_word(unsigned adr, std::string&value);
|
void get_word(unsigned adr, std::string&value);
|
||||||
void shallow_copy(const vvp_object*obj);
|
void shallow_copy(const vvp_object*obj);
|
||||||
|
vvp_object* duplicate(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> array_;
|
std::vector<std::string> array_;
|
||||||
|
|
@ -143,6 +145,7 @@ class vvp_darray_object : public vvp_darray {
|
||||||
void set_word(unsigned adr, const vvp_object_t&value);
|
void set_word(unsigned adr, const vvp_object_t&value);
|
||||||
void get_word(unsigned adr, vvp_object_t&value);
|
void get_word(unsigned adr, vvp_object_t&value);
|
||||||
void shallow_copy(const vvp_object*obj);
|
void shallow_copy(const vvp_object*obj);
|
||||||
|
//virtual vvp_object* duplicate(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<vvp_object_t> array_;
|
std::vector<vvp_object_t> array_;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2012-2020 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -37,5 +37,13 @@ vvp_object::~vvp_object()
|
||||||
|
|
||||||
void vvp_object::shallow_copy(const vvp_object*)
|
void vvp_object::shallow_copy(const vvp_object*)
|
||||||
{
|
{
|
||||||
|
cerr << "XXXX shallow_copy(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_object* vvp_object::duplicate(void) const
|
||||||
|
{
|
||||||
|
cerr << "XXXX duplicate() not implemented for " << typeid(*this).name() << endl;
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef IVL_vvp_object_H
|
#ifndef IVL_vvp_object_H
|
||||||
#define IVL_vvp_object_H
|
#define IVL_vvp_object_H
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2012-2020 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -33,6 +33,7 @@ class vvp_object {
|
||||||
virtual ~vvp_object() =0;
|
virtual ~vvp_object() =0;
|
||||||
|
|
||||||
virtual void shallow_copy(const vvp_object*that);
|
virtual void shallow_copy(const vvp_object*that);
|
||||||
|
virtual vvp_object* duplicate(void) const;
|
||||||
|
|
||||||
static void cleanup(void);
|
static void cleanup(void);
|
||||||
|
|
||||||
|
|
@ -63,6 +64,9 @@ class vvp_object_t {
|
||||||
|
|
||||||
inline void shallow_copy(const vvp_object_t&that)
|
inline void shallow_copy(const vvp_object_t&that)
|
||||||
{ ref_->shallow_copy(that.ref_); }
|
{ ref_->shallow_copy(that.ref_); }
|
||||||
|
inline vvp_object_t duplicate(void) const
|
||||||
|
{ return vvp_object_t(ref_->duplicate()); }
|
||||||
|
|
||||||
template <class T> T*peek(void) const;
|
template <class T> T*peek(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue