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.
// 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));
/* This can not have have a X/Z value so clear flag 4. */
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. */
errors += show_stmt_assign_darray_pattern(net);
} 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. */
} else if (ivl_expr_type(rval) == IVL_EX_NEW) {
// There is no l-value mux, and the r-value expression is
// a "new" expression. Handle this by simply storing the
// new object to the lval.
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;

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_S(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_VEC4(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/s", of_DIV_S, 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/vec4", of_DUP_VEC4,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.
* dup/real
* dup/vec4
* %dup/real
* %dup/vec4
* %dup/obj
These opcodes duplicate the value on the top of the stack for the
corresponding type.

View File

@ -3002,6 +3002,19 @@ bool of_DIV_WR(vthread_t thr, vvp_code_t)
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)
{
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);
}
/*
* %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)
{
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;
}
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)
{
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];
}
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)
{
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];
}
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 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];
}
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)
{
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];
}
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()
{
}

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 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);
};
@ -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 get_word(unsigned adr, vvp_vector4_t&value);
void shallow_copy(const vvp_object*obj);
vvp_object* duplicate(void) const;
vvp_vector4_t get_bitstream(bool as_vec4);
private:
@ -77,6 +76,7 @@ class vvp_darray_vec4 : public vvp_darray {
void set_word(unsigned adr, const vvp_vector4_t&value);
void get_word(unsigned adr, vvp_vector4_t&value);
void shallow_copy(const vvp_object*obj);
vvp_object* duplicate(void) const;
vvp_vector4_t get_bitstream(bool as_vec4);
private:
@ -112,6 +112,7 @@ class vvp_darray_real : public vvp_darray {
void set_word(unsigned adr, double value);
void get_word(unsigned adr, double&value);
void shallow_copy(const vvp_object*obj);
vvp_object* duplicate(void) const;
vvp_vector4_t get_bitstream(bool as_vec4);
private:
@ -128,6 +129,7 @@ class vvp_darray_string : public vvp_darray {
void set_word(unsigned adr, const std::string&value);
void get_word(unsigned adr, std::string&value);
void shallow_copy(const vvp_object*obj);
vvp_object* duplicate(void) const;
private:
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 get_word(unsigned adr, vvp_object_t&value);
void shallow_copy(const vvp_object*obj);
//virtual vvp_object* duplicate(void) const;
private:
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
* 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*)
{
cerr << "XXXX shallow_copy(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
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
#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
* 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 void shallow_copy(const vvp_object*that);
virtual vvp_object* duplicate(void) const;
static void cleanup(void);
@ -63,6 +64,9 @@ class vvp_object_t {
inline void shallow_copy(const vvp_object_t&that)
{ 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;
private: