Merge branch 'master' into vec4-stack
This was a challenging merge... Conflicts: elab_scope.cc synth2.cc tgt-vvp/eval_expr.c vvp/vthread.cc
This commit is contained in:
commit
2aeb3871ed
|
|
@ -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' > $@
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
162
elab_scope.cc
162
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);
|
||||
|
|
@ -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)
|
||||
|
|
@ -188,14 +189,18 @@ 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.
|
||||
// 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 min_value (0);
|
||||
verinum max_value (0);
|
||||
if (enum_type->signed_flag) {
|
||||
|
|
@ -206,10 +211,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
}
|
||||
min_value.has_sign(true);
|
||||
max_value.has_sign(enum_type->signed_flag);
|
||||
// Process the enumeration definition.
|
||||
for (list<named_pexpr_t>::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,26 +222,115 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
NetEConst*val_const = dynamic_cast<NetEConst*> (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 an integer constant."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
cur_value = val_const->value();
|
||||
|
||||
// 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 this is a literal constant and it has a defined
|
||||
// width then the width must match the enumeration width.
|
||||
if (PENumber *tmp = dynamic_cast<PENumber*>(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
|
||||
// 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
|
||||
<< " 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;
|
||||
}
|
||||
|
|
@ -258,10 +352,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
|
||||
} else if ((two_state_value > max_value) ||
|
||||
(cur_value.has_sign() && (two_state_value < min_value))) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -275,38 +369,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
|
||||
|
|
@ -321,8 +384,9 @@ 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()) {
|
||||
cur_value = cur_value + one_value;
|
||||
}
|
||||
}
|
||||
|
||||
use_enum->insert_name_close();
|
||||
|
|
@ -852,7 +916,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: "
|
||||
|
|
@ -1594,7 +1658,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;
|
||||
|
|
|
|||
12
elaborate.cc
12
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;
|
||||
|
|
@ -3003,10 +3005,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 +3071,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) {
|
||||
|
|
@ -3110,6 +3112,8 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
|||
}
|
||||
}
|
||||
|
||||
res->prune();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
74
net_proc.cc
74
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 <cassert>
|
||||
# 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<NetESelect*>(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<NetEConst*>(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<NetEConst*>(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_;
|
||||
}
|
||||
|
||||
|
|
|
|||
13
netenum.cc
13
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_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
|
|
|||
44
synth2.cc
44
synth2.cc
|
|
@ -502,16 +502,33 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
NetEConst*ge = dynamic_cast<NetEConst*>(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);
|
||||
statement_map[sel_idx] = 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;
|
||||
}
|
||||
|
||||
if (sel_idx > max_guard_value)
|
||||
max_guard_value = sel_idx;
|
||||
|
||||
ivl_assert(*this, items_[item].statement);
|
||||
statement_map[sel_idx] = items_[item].statement;
|
||||
}
|
||||
|
||||
// The mux_size is the number of inputs that are selected.
|
||||
|
|
@ -544,6 +561,14 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
|||
esig = mux_selector_reduce_width(des, scope, *this, esig, sel_need);
|
||||
}
|
||||
|
||||
if (!statement_default && (statement_map.size() != ((size_t)1 << sel_width))) {
|
||||
cerr << get_fileline() << ": sorry: Latch inferred from "
|
||||
<< "incomplete case statement. This is not supported "
|
||||
<< "in synthesis." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If there is a default clause, synthesize it once and we'll
|
||||
link it in wherever it is needed. */
|
||||
NetBus default_bus (scope, nex_map.size());
|
||||
|
|
@ -607,12 +632,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)
|
||||
|
|
@ -1911,9 +1931,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;
|
||||
}
|
||||
|
|
|
|||
17
verinum.cc
17
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) {
|
||||
|
|
@ -765,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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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@
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <cstring>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue