From a6bcbc3d1d5a8dfcfffd2ac421da40a71bdbecf5 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 13 Sep 2019 08:40:58 +0100 Subject: [PATCH 1/5] Remove obsolete private VPI functions. --- vpi/sys_darray.c | 302 --------------------------------------------- vpi/v2009_string.c | 126 +------------------ 2 files changed, 1 insertion(+), 427 deletions(-) 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); } From 832adc5c7459354fbaeeabf313b902e088242969 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 14 Sep 2019 00:29:49 +0100 Subject: [PATCH 2/5] Improve handling of invalid packed and unpacked dimensions. As reported on iverilog-devel on 2018-10-12, a dimension size of zero could case the compiler to go into an infinite loop. Further tests showed that unsized or queue dimensions entered as packed dimensions would cause the compiler to crash. --- elab_sig.cc | 55 ++++++------------------ elab_type.cc | 6 +-- netmisc.cc | 116 +++++++++++++++++++++++++++++++++++---------------- netmisc.h | 8 +++- parse.y | 6 +-- 5 files changed, 104 insertions(+), 87 deletions(-) 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/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..4ca0c34e1 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 @@ -2346,9 +2346,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; } From 02ee1c65d0eca257b61463a0ae458f0995f063ef Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 16 Sep 2019 20:35:27 +0100 Subject: [PATCH 3/5] Support dynamic array initialisation in variable declarations. --- PWire.cc | 1 + elab_expr.cc | 9 ++++----- elaborate.cc | 13 +++++++++++-- parse.y | 23 +++++++++++++++++++++++ pform.cc | 6 +++--- 5 files changed, 42 insertions(+), 10 deletions(-) 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/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/parse.y b/parse.y index 4ca0c34e1..fb5177873 100644 --- a/parse.y +++ b/parse.y @@ -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; + } ; @@ -5692,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); From d6391490e31aad0032461791d9c5c1e388c58748 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 16 Sep 2019 20:39:19 +0100 Subject: [PATCH 4/5] Resize vector before assigning to a dynamic array word. Failing to do this leads to an assertion failure in vvp. --- tgt-vvp/stmt_assign.c | 1 + 1 file changed, 1 insertion(+) 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. */ From 41ac0b26214b01d9ae02673932c590fb44f2e0d6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 16 Sep 2019 20:42:32 +0100 Subject: [PATCH 5/5] Include wires in items imported by an "import ::*". --- pform_package.cc | 6 ++++++ 1 file changed, 6 insertions(+) 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);