From 3c2fb6a601c2baf82ab1bbbadce0b28dd2a82446 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 26 Nov 2020 12:35:16 -0800 Subject: [PATCH] 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. --- tgt-vvp/stmt_assign.c | 36 +++++++++++++++++++++++++++++------ vvp/codes.h | 1 + vvp/compile.cc | 1 + vvp/opcodes.txt | 5 +++-- vvp/vthread.cc | 24 +++++++++++++++++++++++ vvp/vvp_darray.cc | 44 ++++++++++++++++++++++++++++++++++++++----- vvp/vvp_darray.h | 7 +++++-- vvp/vvp_object.cc | 10 +++++++++- vvp/vvp_object.h | 6 +++++- 9 files changed, 117 insertions(+), 17 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 1b6294b65..f9954309a 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -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 = \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 = \n", + var, ivl_stmt_file(net), ivl_stmt_lineno(net), + ivl_signal_basename(var), ivl_expr_type(rval)); } return errors; diff --git a/vvp/codes.h b/vvp/codes.h index 26497b2c5..41f706cc7 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 3578e0911..fd7bdbaa4 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 96d4b872c..f2bd3d0a2 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -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. diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 4834c99ed..1b452e814 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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(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; diff --git a/vvp/vvp_darray.cc b/vvp/vvp_darray.cc index 808efd72e..4a4306a85 100644 --- a/vvp/vvp_darray.cc +++ b/vvp/vvp_darray.cc @@ -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 void vvp_darray_atom::shallow_copy(const vvp_object* array_[idx] = that->array_[idx]; } +template vvp_object* vvp_darray_atom::duplicate(void) const +{ + vvp_darray_atom*that = new vvp_darray_atom(array_.size()); + for (size_t idx = 0 ; idx < array_.size() ; idx += 1) + that->array_[idx] = array_[idx]; + + return that; +} + template vvp_vector4_t vvp_darray_atom::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() { } diff --git a/vvp/vvp_darray.h b/vvp/vvp_darray.h index 3224079fd..e846f05a5 100644 --- a/vvp/vvp_darray.h +++ b/vvp/vvp_darray.h @@ -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 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 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 array_; diff --git a/vvp/vvp_object.cc b/vvp/vvp_object.cc index d4ce0ec82..15eea3fcd 100644 --- a/vvp/vvp_object.cc +++ b/vvp/vvp_object.cc @@ -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; +} diff --git a/vvp/vvp_object.h b/vvp/vvp_object.h index fe0763864..9946b6c2a 100644 --- a/vvp/vvp_object.h +++ b/vvp/vvp_object.h @@ -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 T*peek(void) const; private: