From e38b5d9fb7c44495cf98d0c3062ff2c294d357ed Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Nov 2014 09:11:54 +0000 Subject: [PATCH 01/12] Eliminate unnecessary rerun of test_width in case statement elaboration. Also fix a typo in a comment. --- elaborate.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 3095394b6..ece48b0a3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3003,10 +3003,10 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const context_width = 1; context_unsigned = false; - } else if (context_mode > PExpr::SIZED) { + } else if (context_mode >= PExpr::LOSSLESS) { /* Expressions may choose a different size if they are - in an unsized context, so we need to run through the + in a lossless context, so we need to run through the process again to get the final expression width. */ context_width = test_case_width(des, scope, expr_, context_mode); @@ -3069,7 +3069,7 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const /* Iterate over all the case items (guard/statement pairs) elaborating them. If the guard has no expression, then this - is a "default" cause. Otherwise, the guard has one or more + is a "default" case. Otherwise, the guard has one or more expressions, and each guard is a case. */ unsigned inum = 0; for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) { From 0237297e9386184e472bbc661cd0edbe268f09d6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Nov 2014 12:37:32 +0000 Subject: [PATCH 02/12] Added pruning of case statement expressions. When unsized literals are used in case item expressions, it is likely that the calculated expression width will be larger than necessary to unambiguously select the correct case item (particularly when using "strict" expression elaboration). This patch adds an optimisation step that prunes the expressions to the minimum necessary width. --- elaborate.cc | 2 ++ net_proc.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++++---- netlist.h | 2 ++ verinum.cc | 15 +++++++++++ verinum.h | 5 +++- 5 files changed, 92 insertions(+), 6 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index ece48b0a3..17d37c098 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3110,6 +3110,8 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const } } + res->prune(); + return res; } diff --git a/net_proc.cc b/net_proc.cc index 93c746b6d..2aedec7c2 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -19,8 +19,10 @@ # include "config.h" +# include "compiler.h" # include "netlist.h" -# include +# include "netmisc.h" +# include "ivl_assert.h" NetBlock::NetBlock(Type t, NetScope*ss) : type_(t), subscope_(ss), last_(0) @@ -73,7 +75,7 @@ const NetProc* NetBlock::proc_next(const NetProc*cur) const NetCase::NetCase(NetCase::TYPE c, NetExpr*ex, unsigned cnt) : type_(c), expr_(ex), items_(cnt) { - assert(expr_); + ivl_assert(*this, expr_); } NetCase::~NetCase() @@ -92,11 +94,73 @@ NetCase::TYPE NetCase::type() const void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p) { - assert(idx < items_.size()); + ivl_assert(*this, idx < items_.size()); items_[idx].guard = e; items_[idx].statement = p; } +void NetCase::prune() +{ + // Test whether the case expression has been padded out + NetESelect*padded_expr = dynamic_cast(expr_); + if ((padded_expr == 0) || (padded_expr->select() != 0)) + return; + + // If so, run through the case item expressions to find + // the minimum number of bits needed to unambiguously + // select the correct case item. + const NetExpr*unpadded_expr = padded_expr->sub_expr(); + unsigned padded_width = padded_expr->expr_width(); + unsigned prune_width = unpadded_expr->expr_width(); + for (unsigned idx = 0; idx < items_.size(); idx += 1) { + // If there is no guard expression, this is the default + // case, so skip it. + if (items_[idx].guard == 0) + continue; + + // If the guard expression is not constant, assume + // all bits are needed, so no pruning can be done. + NetEConst*gc = dynamic_cast(items_[idx].guard); + if (gc == 0) + return; + + unsigned sig_bits = gc->value().significant_bits(); + if (sig_bits > prune_width) + prune_width = sig_bits; + + // If all the padding bits are needed, no pruning + // can be done. + if (prune_width >= padded_width) + return; + } + ivl_assert(*this, prune_width < padded_width); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: pruning case expressions to " + << prune_width << " bits." << endl; + } + + // Prune the case expression + expr_ = pad_to_width(unpadded_expr->dup_expr(), prune_width, *expr_); + delete padded_expr; + + // Prune the case item expressions + for (unsigned idx = 0; idx < items_.size(); idx += 1) { + if (items_[idx].guard == 0) + continue; + + NetEConst*gc = dynamic_cast(items_[idx].guard); + ivl_assert(*this, gc); + + verinum value(gc->value(), prune_width); + NetEConst*tmp = new NetEConst(value); + tmp->set_line(*gc); + delete gc; + + items_[idx].guard = tmp; + } +} + NetDisable::NetDisable(NetScope*tgt) : target_(tgt) { @@ -175,7 +239,7 @@ NetPDelay::~NetPDelay() uint64_t NetPDelay::delay() const { - assert(expr_ == 0); + ivl_assert(*this, expr_ == 0); return delay_; } diff --git a/netlist.h b/netlist.h index d50213f44..e3f4393f9 100644 --- a/netlist.h +++ b/netlist.h @@ -2939,6 +2939,8 @@ class NetCase : public NetProc { void set_case(unsigned idx, NetExpr*ex, NetProc*st); + void prune(); + TYPE type() const; const NetExpr*expr() const { return expr_; } inline unsigned nitems() const { return items_.size(); } diff --git a/verinum.cc b/verinum.cc index 250df8293..d5ad29dab 100644 --- a/verinum.cc +++ b/verinum.cc @@ -587,6 +587,21 @@ bool verinum::is_negative() const return (bits_[nbits_-1] == V1) && has_sign(); } +unsigned verinum::significant_bits() const +{ + unsigned sbits = nbits_; + + if (has_sign_) { + V sign_bit = bits_[sbits-1]; + while ((sbits > 1) && (bits_[sbits-2] == sign_bit)) + sbits -= 1; + } else { + while ((sbits > 1) && (bits_[sbits-1] == verinum::V0)) + sbits -= 1; + } + return sbits; +} + void verinum::cast_to_int2() { for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) { diff --git a/verinum.h b/verinum.h index e7f311920..dfae90958 100644 --- a/verinum.h +++ b/verinum.h @@ -59,7 +59,7 @@ class verinum { ~verinum(); verinum& operator= (const verinum&); - // Number of significant bits in this number. + // Number of stored bits in this number. unsigned len() const { return nbits_; } // A number "has a length" if the length was specified fixed @@ -86,6 +86,9 @@ class verinum { // Comparison for use in sorting algorithms. bool is_before(const verinum&that) const; + // Number of significant bits in this number. + unsigned significant_bits() const; + // Convert 4-state to 2-state void cast_to_int2(); From f1711618224ac611e04b2163a69fd8578cf9a115 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Nov 2014 15:26:15 +0000 Subject: [PATCH 03/12] Fix for br962 - pop from dynamic array is not padded to correct width. When the expression width is greater than the dynamic array width, we need to generate code to pad the popped value to the correct width. --- tgt-vvp/eval_expr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 82c4bd428..de35503c9 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -3148,6 +3148,8 @@ static struct vector_info draw_ternary_expr(ivl_expr_t expr, unsigned wid) static struct vector_info draw_darray_pop(ivl_expr_t expr, unsigned wid) { + unsigned swid = ivl_expr_width(expr); + struct vector_info res; ivl_expr_t arg; const char*fb; @@ -3160,11 +3162,16 @@ static struct vector_info draw_darray_pop(ivl_expr_t expr, unsigned wid) res.base = allocate_vector(wid); res.wid = wid; + if (swid > res.wid) + swid = res.wid; + arg = ivl_expr_parm(expr, 0); assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); fprintf(vvp_out, " %%qpop/%s v%p_0, %u, %u;\n", fb, - ivl_expr_signal(arg), res.base, res.wid); + ivl_expr_signal(arg), res.base, swid); + + pad_expr_in_place(expr, res, swid); return res; } From c2e53f0d63e79ab18cc3c93e80ca698cbccda588 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Nov 2014 15:36:52 +0000 Subject: [PATCH 04/12] Fix for br963 - vvp qpop instructions need to call thr_check_addr. --- vvp/vthread.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 908c5b297..db0111773 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4879,6 +4879,7 @@ bool of_QPOP_B(vthread_t thr, vvp_code_t cp) { unsigned bit = cp->bit_idx[0]; unsigned wid = cp->bit_idx[1]; + thr_check_addr(thr, bit+wid-1); vvp_net_t*net = cp->net; vvp_fun_signal_object*obj = dynamic_cast (net->fun); @@ -4903,6 +4904,7 @@ bool of_QPOP_F(vthread_t thr, vvp_code_t cp) { unsigned bit = cp->bit_idx[0]; unsigned wid = cp->bit_idx[1]; + thr_check_addr(thr, bit+wid-1); vvp_net_t*net = cp->net; vvp_fun_signal_object*obj = dynamic_cast (net->fun); From 1e7509a02128e9eebc4b954a0e5d41f04ffadd5b Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 2 Nov 2014 11:44:37 -0800 Subject: [PATCH 05/12] Update enumeration elaboration checks --- elab_scope.cc | 172 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 57 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index d3977c25e..236031907 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -188,28 +188,31 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, else des->add_enumeration_set(enum_type, use_enum); - verinum cur_value (0); - verinum one_value (1); size_t name_idx = 0; // Find the enumeration width. long raw_width = use_enum->packed_width(); assert(raw_width > 0); unsigned enum_width = (unsigned)raw_width; - // Find the minimum and maximum allowed enumeration values. - verinum min_value (0); + // Define the default start value and the increment value to be the + // correct type for this enumeration. + verinum cur_value ((uint64_t)0, enum_width); + cur_value.has_sign(enum_type->signed_flag); + verinum one_value ((uint64_t)1, enum_width); + one_value.has_sign(enum_type->signed_flag); + // Find the maximum allowed enumeration value. verinum max_value (0); if (enum_type->signed_flag) { - min_value = -pow(verinum(2), verinum(enum_width-1)); max_value = pow(verinum(2), verinum(enum_width-1)) - one_value; } else { max_value = pow(verinum(2), verinum(enum_width)) - one_value; } - min_value.has_sign(true); max_value.has_sign(enum_type->signed_flag); + // Variable to indicate when a defined value wraps. + bool implicit_wrapped = false; + // Process the enumeration definition. for (list::const_iterator cur = enum_type->names->begin() ; cur != enum_type->names->end() ; ++ cur, name_idx += 1) { - - + // Check to see if the enumeration name has a value given. if (cur->parm) { // There is an explicit value. elaborate/evaluate // the value and assign it to the enumeration name. @@ -217,41 +220,125 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, NetEConst*val_const = dynamic_cast (val); if (val_const == 0) { cerr << use_enum->get_fileline() - << ": error: Enumeration expression is not " - "constant." << endl; + << ": error: Enumeration expression for " + << cur->name <<" is not constant." << endl; des->errors += 1; continue; } cur_value = val_const->value(); + // Clear the implicit wrapped flag if a parameter is given. + implicit_wrapped = false; + // A 2-state value can not have a constant with X/Z bits. if (enum_type->base_type==IVL_VT_BOOL && ! cur_value.is_defined()) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name - << " cannot have an undefined value." << endl; + << " can not have an undefined value." << endl; des->errors += 1; - continue; } + // If the constant has a defined width then it must match + // the enumeration width. In strict mode unsized integers + // are incorrectly given a defined size of integer width so + // handle that. Unfortunately this allows 32'd0 to work + // just like 0 which is wrong. + if (cur_value.has_len() && + (cur_value.len() != enum_width) && + (! gn_strict_expr_width_flag || + (cur_value.len() != integer_width))) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " << cur->name + << " has an incorrectly sized value." << endl; + des->errors += 1; + } + + // If we are padding/truncating a negative value for an + // unsigned enumeration that is an error. + if ((cur_value.len() != enum_width) && + ! enum_type->signed_flag && cur_value.is_negative()) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " << cur->name + << " has a negative value." << endl; + des->errors += 1; + } + + // Narrower values need to be padded to the width of the + // enumeration and defined to have the specified width. + if (cur_value.len() < enum_width) { + cur_value = pad_to_width(cur_value, enum_width); + } + + // Some wider values can be truncated. + if (cur_value.len() > enum_width) { + unsigned check_width = enum_width - 1; + // Check that the upper bits match the MSB + for (unsigned idx = enum_width; + idx < cur_value.len(); + idx += 1) { + if (cur_value[idx] != cur_value[check_width]) { + // If this is an unsigned enumeration + // then zero padding is okay. + if (! enum_type->signed_flag && + (idx == enum_width) && + (cur_value[idx] == verinum::V0)) { + check_width += 1; + continue; + } + if (cur_value.is_defined()) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " + << cur->name + << " has a value that is too " + << ((cur_value > max_value) ? + "large" : "small") + << " " << cur_value << "." + << endl; + } else { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " + << cur->name + << " has trimmed bits that do " + << "not match the enumeration " + << "MSB: " << cur_value << "." + << endl; + } + des->errors += 1; + break; + } + } + // If this is an unsigned value then make sure + // The upper bits are not 1. + if (! cur_value.has_sign() && + (cur_value[enum_width] == verinum::V1)) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " + << cur->name + << " has a value that is too large: " + << cur_value << "." << endl; + des->errors += 1; + break; + } + cur_value = verinum(cur_value, enum_width); + } + + // At this point the value has the correct size and needs + // to have the correct sign attribute set. + cur_value.has_len(true); + cur_value.has_sign(enum_type->signed_flag); } else if (! cur_value.is_defined()) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name - << " cannot have an undefined inferred value." << endl; + << " has an undefined inferred value." << endl; des->errors += 1; continue; } - // The enumeration value must fit into the enumeration bits. - // Cast any undefined bits to zero so the comparisons below - // return just true (1) or false (0). - verinum two_state_value = cur_value; - two_state_value.cast_to_int2(); - if ((two_state_value > max_value) || - (cur_value.has_sign() && (two_state_value < min_value))) { + // Check to see if an implicitly wrapped value is used. + if (implicit_wrapped) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name - << " cannot have an out of range value " << cur_value - << "." << endl; + << " has an inferred value that overflowed." << endl; des->errors += 1; } @@ -265,38 +352,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, des->errors += 1; } - // The values are explicitly sized to the width of the - // base type of the enumeration. - verinum tmp_val (0); - if (cur_value.len() < enum_width) { - // Pad the current value if it is narrower than the final - // width of the enum. - tmp_val = pad_to_width (cur_value, enum_width); - tmp_val.has_len(true); - } else { - // Truncate an oversized value. We report out of bound - // defined values above. Undefined values need to be - // checked here. This may create duplicates. - tmp_val = verinum(cur_value, enum_width); - // For an undefined value verify that all the trimmed bits - // match the MSB of the final enumeration value. - if (! cur_value.is_defined()) for (unsigned idx = enum_width; - idx < cur_value.len(); - idx += 1) { - if (cur_value[idx] != tmp_val[enum_width-1]) { - cerr << use_enum->get_fileline() - << ": error: Enumeration name " << cur->name - << " cannot have trimmed bits that do not " - << "match the enumeration MSB " << cur_value - << "." << endl; - des->errors += 1; - break; - } - } - } - tmp_val.has_sign(enum_type->signed_flag); - - rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val); + rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value); if (scope) rc_flag &= scope->add_enumeration_name(use_enum, cur->name); else @@ -311,8 +367,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, // In case the next name has an implicit value, // increment the current value by one. - if (cur_value.is_defined()) + if (cur_value.is_defined()) { + if (cur_value == max_value) implicit_wrapped = true; cur_value = cur_value + one_value; + } } use_enum->insert_name_close(); @@ -842,7 +900,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, delete[]attr; // Generate schemes need to have their scopes elaborated, but - // we cannot do that until defparams are run, so push it off + // we can not do that until defparams are run, so push it off // into an elaborate work item. if (debug_scopes) cerr << get_fileline() << ": debug: " @@ -1584,7 +1642,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const continue; } - cerr << get_fileline() << ": error: You cannot instantiate " + cerr << get_fileline() << ": error: You can not instantiate " << "module " << mod->mod_name() << " within itself." << endl; cerr << get_fileline() << ": : The offending instance is " << get_name() << " within " << scope_path(scn) << "." << endl; From 4660e0bf2f000ba8b67ea0001120c555a2409ed2 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 2 Nov 2014 20:25:35 -0800 Subject: [PATCH 06/12] Another tweak to the enumeration elaboration code --- elab_scope.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 236031907..a2f4c8e6b 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -253,8 +253,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, } // If we are padding/truncating a negative value for an - // unsigned enumeration that is an error. - if ((cur_value.len() != enum_width) && + // unsigned enumeration that is an error or if the new + // value does not have a defined width. + if (((cur_value.len() != enum_width) || + ! cur_value.has_len()) && ! enum_type->signed_flag && cur_value.is_negative()) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name From cc9fcfd13d793b359ddea133c6aaf440c45741e6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 3 Nov 2014 19:41:29 -0800 Subject: [PATCH 07/12] Only a literal constant size has to match the enumeration width. --- elab_scope.cc | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index a2f4c8e6b..a28f116c2 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -168,7 +168,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, assert(enum_type->range->size() == 1); pform_range_t&range = enum_type->range->front(); NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1); long msb = 0; rc_flag = eval_as_long(msb, msb_ex); @@ -221,7 +221,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, if (val_const == 0) { cerr << use_enum->get_fileline() << ": error: Enumeration expression for " - << cur->name <<" is not constant." << endl; + << cur->name <<" is not an integral constant." + << endl; des->errors += 1; continue; } @@ -237,18 +238,19 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, << " can not have an undefined value." << endl; des->errors += 1; } - // If the constant has a defined width then it must match - // the enumeration width. In strict mode unsized integers - // are incorrectly given a defined size of integer width so - // handle that. Unfortunately this allows 32'd0 to work - // just like 0 which is wrong. - if (cur_value.has_len() && - (cur_value.len() != enum_width) && - (! gn_strict_expr_width_flag || - (cur_value.len() != integer_width))) { + // If the literal constant has a defined width then it + // must match the enumeration width. In strict mode + // unsized integers are incorrectly given a defined size + // of integer width so handle that. Unfortunately this + // allows 32'd0 to work just like 0 which is wrong. + if (dynamic_cast(cur->parm) && + cur_value.has_len() && + (cur_value.len() != enum_width) && + (! gn_strict_expr_width_flag || + (cur_value.len() != integer_width))) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name - << " has an incorrectly sized value." << endl; + << " has an incorrectly sized constant." << endl; des->errors += 1; } From 2e8c4e3dbce6668a9799f325dc731041910d48b9 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 4 Nov 2014 11:21:12 -0800 Subject: [PATCH 08/12] Basic patch from github #44 --- Makefile.in | 2 +- autoconf.sh | 4 ++-- lexor_keyword.gperf | 6 ++++-- vhdlpp/Makefile.in | 2 +- vhdlpp/lexor_keyword.gperf | 7 ++++--- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Makefile.in b/Makefile.in index acef67ec7..2304cda5b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -267,7 +267,7 @@ lexor.cc: $(srcdir)/lexor.lex lexor_keyword.o: lexor_keyword.cc parse.h lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf - gperf -o -i 7 -C -k 1-4,6,9,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false) + gperf -o -i 7 -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false) iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe ./version.exe `head -1 $(srcdir)/iverilog-vpi.man.in`'\n' > $@ diff --git a/autoconf.sh b/autoconf.sh index 0840ac287..8eee0af8e 100644 --- a/autoconf.sh +++ b/autoconf.sh @@ -10,7 +10,7 @@ echo "Autoconf in root..." autoconf -f echo "Precompiling lexor_keyword.gperf" -gperf -o -i 7 -C -k 1-4,6,9,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc +gperf -o -i 7 -C -k 1-4,6,9,\$ -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc echo "Precompiling vhdlpp/lexor_keyword.gperf" -(cd vhdlpp ; gperf -o -i 7 --ignore-case -C -k 1-4,6,9,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc ) +(cd vhdlpp ; gperf -o -i 7 --ignore-case -C -k 1-4,6,9,\$ -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc ) diff --git a/lexor_keyword.gperf b/lexor_keyword.gperf index 34e994e4a..4bb8d0629 100644 --- a/lexor_keyword.gperf +++ b/lexor_keyword.gperf @@ -3,9 +3,11 @@ * tokenType values are not initialized for the empty table entries. */ %define initializer-suffix ,0,0 +%language=C++ +%define class-name Lkwd %{ -/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */ +/* Command-line: gperf -o -i 7 -C -k '1-4,6,9,$' -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf */ #include "config.h" #include "parse_misc.h" @@ -362,7 +364,7 @@ int lexor_keyword_mask = 0; int lexor_keyword_code(const char*str, unsigned nstr) { - const struct lexor_keyword*rc = check_identifier(str, nstr); + const struct lexor_keyword*rc = Lkwd::check_identifier(str, nstr); if (rc == 0) return IDENTIFIER; else if ((rc->mask & lexor_keyword_mask) == 0) diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index e3622a7c3..ce796c588 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -124,7 +124,7 @@ parse.h: parse.cc lexor_keyword.o: lexor_keyword.cc parse.h lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf - gperf -o -i 7 --ignore-case -C -k 1-4,6,9,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false) + gperf -o -i 7 --ignore-case -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false) install: all installdirs $(libdir)/ivl$(suffix)/vhdlpp@EXEEXT@ diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 647798f27..42fd1bc0d 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -3,9 +3,10 @@ * tokenType values are not initialized for the empty table entries. */ %define initializer-suffix ,0,0 - +%language=C++ +%define class-name Lkwd %{ -/* Command-line: gperf -o -i 1 --ignore-case -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */ +/* Command-line: gperf -o -i 7 --ignore-case -C -k '1-4,6,9,$' -H keyword_hash -N check_identifier -t lexor_keyword.gperf */ #include "vhdlpp_config.h" #include @@ -134,7 +135,7 @@ int lexor_keyword_mask = GN_KEYWORD_2008; int lexor_keyword_code(const char*str, unsigned nstr) { - const struct lexor_keyword*rc = check_identifier(str, nstr); + const struct lexor_keyword*rc = Lkwd::check_identifier(str, nstr); if (rc == 0) return IDENTIFIER; else if ((rc->mask & lexor_keyword_mask) == 0) From 2e9c4cde55fd73c39cd8d64c38defa94f5a0dde4 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 4 Nov 2014 12:09:48 -0800 Subject: [PATCH 09/12] More refined check for enumeration width and constant width --- elab_scope.cc | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index a28f116c2..d352261a6 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -221,7 +221,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, if (val_const == 0) { cerr << use_enum->get_fileline() << ": error: Enumeration expression for " - << cur->name <<" is not an integral constant." + << cur->name <<" is not an integer constant." << endl; des->errors += 1; continue; @@ -238,20 +238,17 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, << " can not have an undefined value." << endl; des->errors += 1; } - // If the literal constant has a defined width then it - // must match the enumeration width. In strict mode - // unsized integers are incorrectly given a defined size - // of integer width so handle that. Unfortunately this - // allows 32'd0 to work just like 0 which is wrong. - if (dynamic_cast(cur->parm) && - cur_value.has_len() && - (cur_value.len() != enum_width) && - (! gn_strict_expr_width_flag || - (cur_value.len() != integer_width))) { - cerr << use_enum->get_fileline() - << ": error: Enumeration name " << cur->name - << " has an incorrectly sized constant." << endl; - des->errors += 1; + // If this is a literal constant and it has a defined + // width then the width must match the enumeration width. + if (PENumber *tmp = dynamic_cast(cur->parm)) { + if (tmp->value().has_len() && + (tmp->value().len() != enum_width)) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " << cur->name + << " has an incorrectly sized constant." + << endl; + des->errors += 1; + } } // If we are padding/truncating a negative value for an From 6948c27c2d01de7257a47308c17f7f907ace1747 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 4 Nov 2014 14:55:40 -0800 Subject: [PATCH 10/12] Enumerations are compatible if their type definitions match. --- elab_scope.cc | 3 ++- elaborate.cc | 4 +++- netenum.cc | 13 ++++++++++--- netenum.h | 8 +++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index d352261a6..6e594c241 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -180,7 +180,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, enum_type->integer_flag, msb, lsb, - enum_type->names->size()); + enum_type->names->size(), + enum_type); use_enum->set_line(enum_type->li); if (scope) diff --git a/elaborate.cc b/elaborate.cc index 17d37c098..95005c140 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -38,6 +38,7 @@ # include "PPackage.h" # include "PSpec.h" # include "netlist.h" +# include "netenum.h" # include "netvector.h" # include "netdarray.h" # include "netparray.h" @@ -2668,7 +2669,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const return bl; } - if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) { + if (lv->enumeration() && + ! lv->enumeration()->matches(rv->enumeration())) { cerr << get_fileline() << ": error: " << "Enumeration type mismatch in assignment." << endl; des->errors += 1; diff --git a/netenum.cc b/netenum.cc index cab73a55c..0ec7ca33d 100644 --- a/netenum.cc +++ b/netenum.cc @@ -24,9 +24,11 @@ using namespace std; netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, - bool integer_flag, long msb, long lsb, size_t name_count) -: base_type_(btype), signed_flag_(signed_flag), integer_flag_(integer_flag), - msb_(msb), lsb_(lsb), names_(name_count), bits_(name_count) + bool integer_flag, long msb, long lsb, size_t name_count, + enum_type_t*enum_type) +: base_type_(btype), enum_type_(enum_type), signed_flag_(signed_flag), + integer_flag_(integer_flag), msb_(msb), lsb_(lsb), + names_(name_count), bits_(name_count) { } @@ -161,3 +163,8 @@ perm_string netenum_t::bits_at(size_t idx) const { return bits_[idx]; } + +bool netenum_t::matches(const netenum_t*other) const +{ + return enum_type_ == other->enum_type_; +} diff --git a/netenum.h b/netenum.h index 64c2aac6a..8ff8a9063 100644 --- a/netenum.h +++ b/netenum.h @@ -29,12 +29,14 @@ class NetScope; +struct enum_type_t; + class netenum_t : public LineInfo, public ivl_type_s { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, bool isint_flag, long msb, long lsb, - size_t name_count); + size_t name_count, enum_type_t*enum_type); ~netenum_t(); virtual ivl_variable_type_t base_type() const; @@ -67,8 +69,12 @@ class netenum_t : public LineInfo, public ivl_type_s { perm_string name_at(size_t idx) const; perm_string bits_at(size_t idx) const; + // Check if two enumerations have the same definition. + bool matches(const netenum_t*other) const; + private: ivl_variable_type_t base_type_; + enum_type_t*enum_type_; bool signed_flag_; bool integer_flag_; long msb_, lsb_; From 4e94b81a4bc0380ae7c27f46848688d764f88db6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 5 Nov 2014 14:40:15 -0800 Subject: [PATCH 11/12] On a 32 bit system you can print a 32 bit value as a long (verinum) --- verinum.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verinum.cc b/verinum.cc index d5ad29dab..3c889311a 100644 --- a/verinum.cc +++ b/verinum.cc @@ -780,7 +780,7 @@ ostream& operator<< (ostream&o, const verinum&v) /* If the number is fully defined (no x or z) then print it out as a decimal number. */ - if (v.is_defined() && v.len() < 8*sizeof(long)) { + if (v.is_defined() && v.len() <= 8*sizeof(long)) { if (v.has_sign()) o << "'sd" << v.as_long(); else From 754899c99e9ea73c6edf7f4f5a56fdca228df0ae Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 9 Nov 2014 20:11:03 +0000 Subject: [PATCH 12/12] Make asynchronous case statement synthesis more robust. Added various error/warning messages for behaviour not supported in synthesis. Also give correct behaviour when multiple case item expressions evaluate to the same constant value. --- synth2.cc | 60 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/synth2.cc b/synth2.cc index dcc80895d..22c191b56 100644 --- a/synth2.cc +++ b/synth2.cc @@ -384,7 +384,6 @@ bool NetCase::synth_async(Design*des, NetScope*scope, index of the mux value, and the statement is bound to that index. */ - unsigned long max_guard_value = 0; mapstatement_map; NetProc*statement_default = 0; @@ -395,28 +394,48 @@ bool NetCase::synth_async(Design*des, NetScope*scope, } NetEConst*ge = dynamic_cast(items_[item].guard); + if (ge == 0) { + cerr << items_[item].guard->get_fileline() << ": sorry: " + << "variable case item expressions with a variable " + << "case select expression are not supported in " + << "synthesis. " << endl; + des->errors += 1; + return false; + } ivl_assert(*this, ge); verinum gval = ge->value(); - unsigned sel_idx = gval.as_ulong(); + unsigned long sel_idx = gval.as_ulong(); - assert(items_[item].statement); + if (statement_map[sel_idx]) { + cerr << ge->get_fileline() << ": warning: duplicate case " + << "value '" << sel_idx << "' detected. This case is " + << "unreachable." << endl; + delete items_[item].statement; + items_[item].statement = 0; + continue; + } + + ivl_assert(*this, items_[item].statement); statement_map[sel_idx] = items_[item].statement; - - if (sel_idx > max_guard_value) - max_guard_value = sel_idx; } - // The mux_size is the number of inputs that are selected. - unsigned mux_size = max_guard_value + 1; - - // If the sel_width can select more than just the explicit - // guard values, and there is a default statement, then adjust - // the mux size to allow for the implicit selections. - if (statement_default && ((1U< mux_size)) { - mux_size = 1<errors += 1; + return false; } + if (sel_width >= 8*sizeof(unsigned)) { + cerr << get_fileline() << ": sorry: mux select width of " + << sel_width << " bits is too large for synthesis." << endl; + des->errors += 1; + return false; + } + + unsigned mux_size = 1U << sel_width; /* If there is a default clause, synthesize it once and we'll link it in wherever it is needed. */ @@ -481,12 +500,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, continue; } - if (stmt == 0) { - cerr << get_fileline() << ": error: case " << idx - << " is not accounted for in asynchronous mux." << endl; - des->errors += 1; - continue; - } + ivl_assert(*this, stmt); NetBus accumulated_tmp (scope, nex_map.size()); for (unsigned pin = 0 ; pin < nex_map.size() ; pin += 1) @@ -1785,9 +1799,9 @@ void synth2_f::process(Design*des, NetProcTop*top) } if (! top->synth_async(des)) { - cerr << top->get_fileline() << ": internal error: " - << "is_asynchronous does not match " - << "sync_async results." << endl; + cerr << top->get_fileline() << ": error: " + << "failed to synthesize asynchronous " + << "logic for this process." << endl; des->errors += 1; return; }