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:
Stephen Williams 2020-11-26 12:35:16 -08:00
parent 7277f4e807
commit 3c2fb6a601
9 changed files with 117 additions and 17 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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} },

View File

@ -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.

View File

@ -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;

View File

@ -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()
{ {
} }

View File

@ -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_;

View File

@ -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;
}

View File

@ -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: