diff --git a/PWire.cc b/PWire.cc index e50e29f80..79db562eb 100644 --- a/PWire.cc +++ b/PWire.cc @@ -67,6 +67,7 @@ bool PWire::set_wire_type(NetNet::Type t) isint_ = true; return true; } + if (t == NetNet::IMPLICIT_REG) return true; return false; case NetNet::REG: if (t == NetNet::INTEGER) { diff --git a/elab_expr.cc b/elab_expr.cc index cb9a88158..224b7da6a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -5397,12 +5397,11 @@ NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope, return tmp; } -/* - * This method should never actually be called. - */ -NetExpr* PENewArray::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const +NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const { - ivl_assert(*this, 0); + cerr << get_fileline() << ": error: The new array constructor may " + "only be used in an assignment to a dynamic array." << endl; + des->errors += 1; return 0; } diff --git a/elab_sig.cc b/elab_sig.cc index d30bd55ea..4b64ff901 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -47,6 +47,8 @@ using namespace std; +#if 0 +/* These functions are not currently used. */ static bool get_const_argument(NetExpr*exp, verinum&res) { switch (exp->expr_type()) { @@ -73,8 +75,6 @@ static bool get_const_argument(NetExpr*exp, verinum&res) return true; } -#if 0 -/* This function is not currently used. */ static bool get_const_argument(NetExpr*exp, long&res) { verinum tmp; @@ -876,13 +876,13 @@ static ivl_type_s*elaborate_type(Design*des, NetScope*scope, return 0; } -static netparray_t* elaborate_parray_type(Design*des, NetScope*scope, +static netparray_t* elaborate_parray_type(Design*des, NetScope*scope, const LineInfo*li, parray_type_t*data_type) { vectorpacked_dimensions; - bool bad_range = evaluate_ranges(des, scope, packed_dimensions, * data_type->dims); - ivl_assert(*data_type, !bad_range); + bool dimensions_ok = evaluate_ranges(des, scope, li, packed_dimensions, * data_type->dims); + ivl_assert(*data_type, dimensions_ok); ivl_type_s*element_type = elaborate_type(des, scope, data_type->base_type); @@ -998,7 +998,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const << " inherits dimensions from var/net." << endl; } - bool bad_range = false; + bool dimensions_ok = true; vector plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { @@ -1006,7 +1006,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const cerr << get_fileline() << ": PWire::elaborate_sig: " << "Evaluate ranges for port " << basename() << endl; } - bad_range |= evaluate_ranges(des, scope, plist, port_); + dimensions_ok &= evaluate_ranges(des, scope, this, plist, port_); nlist = plist; /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; @@ -1014,13 +1014,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const assert(port_set_ || port_.empty()); /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && !net_.empty() && !bad_range) { + if (net_set_ && !net_.empty() && dimensions_ok) { nlist.clear(); if (debug_elaborate) { cerr << get_fileline() << ": PWire::elaborate_sig: " << "Evaluate ranges for net " << basename() << endl; } - bad_range |= evaluate_ranges(des, scope, nlist, net_); + dimensions_ok &= evaluate_ranges(des, scope, this, nlist, net_); } assert(net_set_ || net_.empty()); @@ -1121,39 +1121,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // Cannot handle dynamic arrays of arrays yet. ivl_assert(*this, netdarray==0); - ivl_assert(*this, use_lidx && use_ridx); - - NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true); - NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true); - - if ((lexp == 0) || (rexp == 0)) { - cerr << get_fileline() << ": internal error: There is " - << "a problem evaluating indices for ``" - << name_ << "''." << endl; - des->errors += 1; - return 0; - } - - bool const_flag = true; - verinum lval, rval; - const_flag &= get_const_argument(lexp, lval); - const_flag &= get_const_argument(rexp, rval); - delete rexp; - delete lexp; long index_l, index_r; - if (! const_flag) { - cerr << get_fileline() << ": error: The indices " - << "are not constant for array ``" - << name_ << "''." << endl; - des->errors += 1; - /* Attempt to recover from error, */ - index_l = 0; - index_r = 0; - } else { - index_l = lval.as_long(); - index_r = rval.as_long(); - } + evaluate_range(des, scope, this, *cur, index_l, index_r); + if (abs(index_r - index_l) > warn_dimension_size) { cerr << get_fileline() << ": warning: Array dimension " "is greater than " << warn_dimension_size @@ -1276,7 +1247,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // The trick here is that the parray type has an // arbitrary sub-type, and not just a scalar bit... - netparray_t*use_type = elaborate_parray_type(des, scope, parray_type); + netparray_t*use_type = elaborate_parray_type(des, scope, this, parray_type); // Should not be getting packed dimensions other than // through the parray type declaration. ivl_assert(*this, packed_dimensions.empty()); diff --git a/elab_type.cc b/elab_type.cc index 73d7842dc..41ffa13a7 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2019 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 @@ -257,9 +257,9 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const } vector dimensions; - bool bad_range = evaluate_ranges(des, scope, dimensions, *dims); + bool dimensions_ok = evaluate_ranges(des, scope, this, dimensions, *dims); - if (bad_range) { + if (!dimensions_ok) { cerr << get_fileline() << " : warning: " << "Bad dimensions for type here." << endl; } diff --git a/elaborate.cc b/elaborate.cc index 409b90f42..1feb9e62c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2318,8 +2318,17 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, NetExpr*rv = rval_->elaborate_expr(des, scope, net_type, 0); - ivl_assert(*this, !is_constant_); - return rv; + if (!is_constant_ || !rv) return rv; + + if (dynamic_cast(rv)) return rv; + + cerr << get_fileline() << ": error: " + "The RHS expression must be constant." << endl; + cerr << get_fileline() << " : " + "This expression violates the rule: " << *rv << endl; + des->errors += 1; + delete rv; + return 0; } NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, diff --git a/netmisc.cc b/netmisc.cc index 74d35e501..f9e9a8b44 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1052,50 +1052,94 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, return tmp; } -bool evaluate_ranges(Design*des, NetScope*scope, +bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li, + const pform_range_t&range, long&index_l, long&index_r) +{ + bool dimension_ok = true; + + // Unsized and queue dimensions should be handled before calling + // this function. If we find them here, we are in a context where + // they are not allowed. + if (range.first == 0) { + cerr << li->get_fileline() << ": error: " + "An unsized dimension is not allowed here." << endl; + dimension_ok = false; + des->errors += 1; + } else if (dynamic_cast(range.first)) { + cerr << li->get_fileline() << ": error: " + "A queue dimension is not allowed here." << endl; + dimension_ok = false; + des->errors += 1; + } else { + NetExpr*texpr = elab_and_eval(des, scope, range.first, -1, true); + if (! eval_as_long(index_l, texpr)) { + cerr << range.first->get_fileline() << ": error: " + "Dimensions must be constant." << endl; + cerr << range.first->get_fileline() << " : " + << (range.second ? "This MSB" : "This size") + << " expression violates the rule: " + << *range.first << endl; + dimension_ok = false; + des->errors += 1; + } + delete texpr; + + if (range.second == 0) { + // This is a SystemVerilog [size] dimension. The IEEE + // standard does not allow this in a packed dimension, + // but we do. At least one commercial simulator does too. + if (!dimension_ok) { + // bail out + } else if (index_l > 0) { + index_l = index_l - 1; + index_r = 0; + } else { + cerr << range.first->get_fileline() << ": error: " + "Dimension size must be greater than zero." << endl; + cerr << range.first->get_fileline() << " : " + "This size expression violates the rule: " + << *range.first << endl; + dimension_ok = false; + des->errors += 1; + } + } else { + texpr = elab_and_eval(des, scope, range.second, -1, true); + if (! eval_as_long(index_r, texpr)) { + cerr << range.second->get_fileline() << ": error: " + "Dimensions must be constant." << endl; + cerr << range.second->get_fileline() << " : " + "This LSB expression violates the rule: " + << *range.second << endl; + dimension_ok = false; + des->errors += 1; + } + delete texpr; + } + } + + /* Error recovery */ + if (!dimension_ok) { + index_l = 0; + index_r = 0; + } + + return dimension_ok; +} + +bool evaluate_ranges(Design*des, NetScope*scope, const LineInfo*li, vector&llist, const list&rlist) { - bool bad_msb = false, bad_lsb = false; + bool dimensions_ok = true; for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - long use_msb, use_lsb; - - NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(use_msb, texpr)) { - cerr << cur->first->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->first->get_fileline() << " : " - "This MSB expression violates the rule: " - << *cur->first << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(use_lsb, texpr)) { - cerr << cur->second->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->second->get_fileline() << " : " - "This LSB expression violates the rule: " - << *cur->second << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - - /* Error recovery */ - if (bad_lsb) use_lsb = 0; - if (bad_msb) use_msb = use_lsb; - - llist.push_back(netrange_t(use_msb, use_lsb)); + long index_l, index_r; + dimensions_ok &= evaluate_range(des, scope, li, *cur, index_l, index_r); + llist.push_back(netrange_t(index_l, index_r)); } - return bad_msb | bad_lsb; + return dimensions_ok; } void eval_expr(NetExpr*&expr, int context_width) diff --git a/netmisc.h b/netmisc.h index af639da2b..ec99c0b16 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef IVL_netmisc_H #define IVL_netmisc_H /* - * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -321,7 +321,11 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, bool need_const =false, bool force_unsigned =false); -extern bool evaluate_ranges(Design*des, NetScope*scope, +extern bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li, + const pform_range_t&range, + long&index_l, long&index_r); + +extern bool evaluate_ranges(Design*des, NetScope*scope, const LineInfo*li, std::vector&llist, const std::list&rlist); /* diff --git a/parse.y b/parse.y index a8cbbfbee..fb5177873 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1563,6 +1563,15 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } + | IDENTIFIER dimensions '=' dynamic_array_new + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->index = *$2; + tmp->expr .reset($4); + delete $2; + delete[]$1; + $$ = tmp; + } ; @@ -2346,9 +2355,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ << "Use at least -g2005-sv to remove this warning." << endl; } list *tmp = new list; - pform_range_t index; - index.first = new PENumber(new verinum((uint64_t)0, integer_width)); - index.second = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); + pform_range_t index ($2,0); tmp->push_back(index); $$ = tmp; } @@ -5694,6 +5701,20 @@ register_variable pform_make_var_init(@1, name, $4); $$ = $1; } + | IDENTIFIER dimensions_opt '=' dynamic_array_new + { if (pform_peek_scope()->var_init_needs_explicit_lifetime() + && (var_lifetime == LexicalScope::INHERITED)) { + cerr << @3 << ": warning: Static variable initialization requires " + "explicit lifetime in this context." << endl; + warn_count += 1; + } + perm_string name = lex_strings.make($1); + pform_makewire(@1, name, NetNet::REG, + NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + pform_set_reg_idx(name, $2); + pform_make_var_init(@1, name, $4); + $$ = $1; + } ; register_variable_list diff --git a/pform.cc b/pform.cc index 5940616ed..000cfd1c7 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2710,6 +2710,8 @@ void pform_makewire(const struct vlltype&li, for (list::iterator cur = assign_list->begin() ; cur != assign_list->end() ; ++ cur) { decl_assignment_t* curp = *cur; + pform_makewire(li, curp->name, type, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + pform_set_reg_idx(curp->name, &curp->index); names->push_back(curp->name); } @@ -2722,8 +2724,6 @@ void pform_makewire(const struct vlltype&li, if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { pform_make_var_init(li, first->name, expr); } else { - PWire*cur = pform_get_wire_in_scope(first->name); - assert(cur); PEIdent*lval = new PEIdent(first->name); FILE_NAME(lval, li.text, li.first_line); PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); diff --git a/pform_package.cc b/pform_package.cc index 6014acb7f..72ac9c6b3 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -154,6 +154,12 @@ void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident) scope->imports[cur->first] = pkg; } + for (map::const_iterator cur = pkg->wires.begin() + ; cur != pkg->wires.end() ; ++cur) { + + scope->imports[cur->first] = pkg; + } + for (set::const_iterator cur = pkg->enum_sets.begin() ; cur != pkg->enum_sets.end() ; ++ cur) { scope->enum_sets.insert(*cur); diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 8ad27c450..889371ee7 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1020,6 +1020,7 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) } else if (mux) { draw_eval_vec4(rval); + resize_vec4_wid(rval, ivl_stmt_lwidth(net)); /* The %store/dar/vec4 expects the array index to be in index register 3. Calculate the index in place. */ diff --git a/vpi/sys_darray.c b/vpi/sys_darray.c index 7fe90f4f4..269508677 100644 --- a/vpi/sys_darray.c +++ b/vpi/sys_darray.c @@ -97,287 +97,6 @@ static PLI_INT32 dobject_size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 to_from_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) -{ - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv, arg; - - argv = vpi_iterate(vpiArgument, callh); - if (argv == 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires two arguments.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } - - /* The first argument must be a dynamic array. */ - arg = vpi_scan(argv); /* This should never be zero. */ - assert(arg); - if (vpi_get(vpiType, arg) != vpiArrayVar) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s first argument must be a dynamic array, " - "given a %s.\n", name, vpi_get_str(vpiType, arg)); - vpi_control(vpiFinish, 1); - } - if (vpi_get(vpiArrayType, arg) != vpiDynamicArray) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s first argument must be a dynamic array.\n", name); - vpi_control(vpiFinish, 1); - } -// HERE: Still need to verify that this is not a real or string array. -// That will require adding TypeSpec support to the VPI. - - /* The second argument must be a net, reg or bit variable. */ - arg = vpi_scan(argv); - if (arg == 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires a second argument.\n", name); - vpi_control(vpiFinish, 1); - } - switch(vpi_get(vpiType, arg)) { - case vpiNet: - case vpiReg: - case vpiBitVar: - case vpiIntegerVar: - case vpiConstant: - break; - default: - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s second argument must be a logical net or " - "variable.\n", name); - vpi_control(vpiFinish, 1); - } - - arg = vpi_scan(argv); - if (arg != 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s has too many arguments.\n", name); - vpi_control(vpiFinish, 1); - vpi_free_object(argv); - } - - return 0; -} - -static const size_t BPW = 8 * sizeof(PLI_INT32); -static const size_t BPWM1 = 8 * sizeof(PLI_INT32) - 1; - -static PLI_INT32 to_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) -{ - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle darr = vpi_scan(argv); - vpiHandle vec = vpi_scan(argv); - - vpi_free_object(argv); - - /* Calculate and check the basic array and vector information. */ - int darr_size = vpi_get(vpiSize, darr); - int darr_word_size = vpi_get(vpiSize, vpi_handle_by_index(darr, 0)); - assert(darr_word_size > 0); - int darr_bit_size = darr_size * darr_word_size; - int vec_size = vpi_get(vpiSize, vec); - - if (darr_size <= 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s cannot cast an empty dynamic array.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } - - if (darr_bit_size != vec_size) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s dynamic array and vector size do not match " - "(%d != %d).\n", name, darr_bit_size, vec_size); - vpi_control(vpiFinish, 1); - return 0; - } - - /* Calculate the number of words needed to hold the dynamic array - * bits and allocate enough space for them. */ - size_t vec_words = (darr_bit_size + BPWM1) / BPW; - s_vpi_vecval *vec_val = calloc(vec_words, sizeof(s_vpi_vecval)); - s_vpi_vecval *vec_ptr = vec_val; - - /* The number of words in each array element. */ - unsigned darr_words = (darr_word_size + BPWM1) / BPW; - - /* The offset in bits into the current vector value. */ - unsigned offset = 0; - - /* We want to get each array word as a vector. */ - s_vpi_value darr_val; - darr_val.format = vpiVectorVal; - - /* We have to reverse the order of the dynamic array words. */ - for (PLI_INT32 i = darr_size - 1; i >= 0; --i) { - /* Get the vector value for the current array word. */ - vpiHandle darr_word = vpi_handle_by_index(darr, i); - vpi_get_value(darr_word, &darr_val); - assert(darr_val.format == vpiVectorVal); - /* The number of bits to copy for this array word. */ - unsigned bits_to_copy = (unsigned)darr_word_size; - - /* Copy the current array bits to the vector and update the - * the vector pointer accordingly. */ - for (unsigned j = 0; j < darr_words; ++j) { - /* Get the current array part and copy it into the - * correct place. */ - PLI_UINT32 aval = darr_val.value.vector->aval; - PLI_UINT32 bval = darr_val.value.vector->bval; - assert(offset < BPW); - vec_ptr->aval |= (aval << offset); - vec_ptr->bval |= (bval << offset); - - /* Calculate the new offset into the vector. */ - offset += (bits_to_copy > BPW) ? BPW : bits_to_copy; - - /* If the new offset is past the end of the vector part - * then the next vector part also needs to be used. */ - if (offset >= BPW) { - ++vec_ptr; - - /* Does the current array part also go into the - * next vector part? */ - if (offset > BPW) { - /* This code has not been tested since the - * current implementation only supports dynamic - * array elements of size 8, 16, 32 or 64 bits - * so currently this code is never run. For - * now assert since it has not been checked. */ - assert(0); - - /* Copy the rest of the array part that did not - * fit in the previous vector part to the next - * vector part. */ - offset -= BPW; - vec_ptr->aval |= (aval >> (darr_word_size - - offset)); - vec_ptr->bval |= (bval >> (darr_word_size - - offset)); - /* Start at the beginning of the next vector part. */ - } else { - offset = 0; - } - } - - /* Advance to the next part of the array. */ - bits_to_copy -= BPW; - darr_val.value.vector++; - } - } - - /* Put the result to the vector and free the allocated space. */ - darr_val.format = vpiVectorVal; - darr_val.value.vector = vec_val; - vpi_put_value(vec, &darr_val, 0, vpiNoDelay); - - free(vec_val); - - return 0; -} - -static PLI_INT32 from_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) -{ - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle darr = vpi_scan(argv); - vpiHandle vec = vpi_scan(argv); - - vpi_free_object(argv); - - /* Calculate and check the basic array and vector information. */ - int darr_size = vpi_get(vpiSize, darr); - int darr_word_size = vpi_get(vpiSize, vpi_handle_by_index(darr, 0)); - assert(darr_word_size > 0); - int darr_bit_size = darr_size * darr_word_size; - - int vec_size = vpi_get(vpiSize, vec); - - if (vec_size <= 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s cannot cast an empty vector array.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } - - if (darr_bit_size != vec_size) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s dynamic array and vector size do not match " - "(%d != %d).\n", name, darr_bit_size, vec_size); - vpi_control(vpiFinish, 1); - return 0; - } - - /* Calculate the number of words needed to hold the dynamic array - * word bits and allocate enough space for them. */ - size_t darr_words = (darr_word_size + BPWM1) / BPW; - s_vpi_vecval *darr_val = calloc(darr_words, sizeof(s_vpi_vecval)); - - /* Get the vector value. */ - s_vpi_value vec_val; - vec_val.format = vpiVectorVal; - vpi_get_value(vec, &vec_val); - - /* The offset in bits into the vector value. */ - unsigned offset = 0; - - /* We have to reverse the order of the dynamic array words. */ - for (int i = darr_size - 1; i >= 0; --i) { - unsigned bits_to_copy = darr_word_size; - s_vpi_vecval *darr_ptr = darr_val; - - /* Copy some of the vector bits to the current array word. */ - while (bits_to_copy > 0) { - unsigned copied_bits = (bits_to_copy > BPW) ? BPW : - bits_to_copy; - /* Start with the current vector part. */ - PLI_UINT32 aval = vec_val.value.vector[offset / BPW].aval; - PLI_UINT32 bval = vec_val.value.vector[offset / BPW].bval; - - /* If this isn't aligned then we may need to get bits - * from the next part as well. */ - unsigned rem_bits = offset % BPW; - if (rem_bits) { - aval >>= rem_bits; - aval |= vec_val.value.vector[offset / BPW + 1].aval << - (BPW - rem_bits); - bval >>= rem_bits; - bval |= vec_val.value.vector[offset / BPW + 1].bval << - (BPW - rem_bits); - } - - /* Advance to the next part of the array and vector. */ - darr_ptr->aval = aval; - darr_ptr->bval = bval; - darr_ptr++; - offset += copied_bits; - bits_to_copy -= copied_bits; - } - - /* Put part of the vector to the current dynamic array word. */ - s_vpi_value result; - result.format = vpiVectorVal; - result.value.vector = darr_val; - vpiHandle darr_word = vpi_handle_by_index(darr, i); - vpi_put_value(darr_word, &result, 0, vpiNoDelay); - } - - free(darr_val); - - return 0; -} - void sys_darray_register(void) { s_vpi_systf_data tf_data; @@ -392,25 +111,4 @@ void sys_darray_register(void) tf_data.user_data = "$size"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - - tf_data.type = vpiSysTask; - tf_data.sysfunctype = 0; - tf_data.tfname = "$ivl_darray_method$to_vec"; - tf_data.calltf = to_vec_calltf; - tf_data.compiletf = to_from_vec_compiletf; - tf_data.sizetf = 0; - tf_data.user_data = "$ivl_darray_method$to_vec"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - - tf_data.type = vpiSysTask; - tf_data.sysfunctype = 0; - tf_data.tfname = "$ivl_darray_method$from_vec"; - tf_data.calltf = from_vec_calltf; - tf_data.compiletf = to_from_vec_compiletf; - tf_data.sizetf = 0; - tf_data.user_data = "$ivl_darray_method$from_vec"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - } diff --git a/vpi/v2009_string.c b/vpi/v2009_string.c index 29dd3691d..cb10cf8fe 100644 --- a/vpi/v2009_string.c +++ b/vpi/v2009_string.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2019 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 @@ -78,120 +78,6 @@ static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } - -static PLI_INT32 to_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*user_data) -{ - (void) user_data; /* Parameter is not used. */ - - vpiHandle systf_handle, arg_iterator, arg_handle; - PLI_INT32 arg_type[2]; - - /* obtain a handle to the system task instance */ - systf_handle = vpi_handle(vpiSysTfCall, NULL); - if (systf_handle == NULL) { - vpi_printf("ERROR: $ivl_string_method$to_vec failed to obtain systf handle\n"); - vpi_control(vpiFinish,0); /* abort simulation */ - return 0; - } - - /* obtain handles to system task arguments */ - arg_iterator = vpi_iterate(vpiArgument, systf_handle); - if (arg_iterator == NULL) { - vpi_printf("ERROR: $ivl_string_method$to_vec requires 2 arguments\n"); - vpi_control(vpiFinish, 0); - return 0; - } - - /* check the type of object in system task arguments */ - arg_handle = vpi_scan(arg_iterator); - for(int i = 0; i < 2; ++i) { - arg_type[i] = vpi_get(vpiType, arg_handle); - arg_handle = vpi_scan(arg_iterator); - } - - if (arg_handle != NULL) { /* are there more arguments? */ - vpi_printf("ERROR: $ivl_string_method$to_vec can only have 2 arguments\n"); - vpi_free_object(arg_iterator); - vpi_control(vpiFinish, 0); - return 0; - } - - if ((arg_type[0] != vpiStringVar) || - (arg_type[1] != vpiNet && arg_type[1] != vpiReg)) { - vpi_printf("ERROR: $ivl_string_method$to_vec value arguments must be a string and a net or reg\n"); - vpi_free_object(arg_iterator); - vpi_control(vpiFinish, 0); - return 0; - } - - return 0; -} - -static PLI_INT32 to_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) -{ - (void)name; /* Parameter is not used. */ - - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv, str, vec; - s_vpi_value str_val; - s_vpi_vecval*vec_val; - - /* Fetch arguments */ - argv = vpi_iterate(vpiArgument, callh); - assert(argv); - str = vpi_scan(argv); - assert(str); - vec = vpi_scan(argv); - assert(vec); - vpi_free_object(argv); - - int str_size = vpi_get(vpiSize, str); - int vec_size = vpi_get(vpiSize, vec); - if(str_size <= 0) { - vpi_printf("ERROR: Cannot cast empty string"); - vpi_control(vpiFinish, 0); - return 0; - } - - if(vec_size != str_size * 8) { - vpi_printf("ERROR: String and vector size do not match"); - vpi_control(vpiFinish, 0); - return 0; - } - - str_val.format = vpiStringVal; - vpi_get_value(str, &str_val); - assert(str_val.value.str); - - /* Conversion part */ - int vec_number = ceil((double)str_size / sizeof(PLI_INT32)); - vec_val = calloc(vec_number, sizeof(s_vpi_vecval)); - PLI_BYTE8*str_ptr = &str_val.value.str[str_size - 1]; - - /* We have to reverse the order of string, no memcpy here */ - for(int i = 0; i < vec_number; ++i) { - int copy_size = str_size > (int)sizeof(PLI_INT32) ? - (int)sizeof(PLI_INT32) : str_size; - - /* Clear the part responsible for X & Z values */ - memset(&vec_val[i].bval, 0x00, sizeof(PLI_INT32)); - PLI_BYTE8*dest = (PLI_BYTE8*)&vec_val[i].aval; - - for(int j = 0; j < copy_size; ++j) - *dest++ = *str_ptr--; - - str_size -= copy_size; - } - - str_val.format = vpiVectorVal; - str_val.value.vector = vec_val; - vpi_put_value(vec, &str_val, 0, vpiNoDelay); - - free(vec_val); - - return 0; -} - void v2009_string_register(void) { s_vpi_systf_data tf_data; @@ -206,14 +92,4 @@ void v2009_string_register(void) tf_data.user_data = "$ivl_string_method$len"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - - tf_data.type = vpiSysTask; - tf_data.sysfunctype = 0; - tf_data.tfname = "$ivl_string_method$to_vec"; - tf_data.calltf = to_vec_calltf; - tf_data.compiletf = to_vec_compiletf; - tf_data.sizetf = 0; - tf_data.user_data = "$ivl_string_method$to_vec"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); }