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.o: lexor_keyword.cc parse.h
|
||||||
|
|
||||||
lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf
|
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
|
iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe
|
||||||
./version.exe `head -1 $(srcdir)/iverilog-vpi.man.in`'\n' > $@
|
./version.exe `head -1 $(srcdir)/iverilog-vpi.man.in`'\n' > $@
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ echo "Autoconf in root..."
|
||||||
autoconf -f
|
autoconf -f
|
||||||
|
|
||||||
echo "Precompiling lexor_keyword.gperf"
|
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"
|
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);
|
assert(enum_type->range->size() == 1);
|
||||||
pform_range_t&range = enum_type->range->front();
|
pform_range_t&range = enum_type->range->front();
|
||||||
NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1);
|
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;
|
long msb = 0;
|
||||||
rc_flag = eval_as_long(msb, msb_ex);
|
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,
|
netenum_t*use_enum = new netenum_t(enum_type->base_type,
|
||||||
enum_type->signed_flag,
|
enum_type->signed_flag,
|
||||||
enum_type->integer_flag, msb, lsb,
|
enum_type->integer_flag, msb, lsb,
|
||||||
enum_type->names->size());
|
enum_type->names->size(),
|
||||||
|
enum_type);
|
||||||
|
|
||||||
use_enum->set_line(enum_type->li);
|
use_enum->set_line(enum_type->li);
|
||||||
if (scope)
|
if (scope)
|
||||||
|
|
@ -188,14 +189,18 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
else
|
else
|
||||||
des->add_enumeration_set(enum_type, use_enum);
|
des->add_enumeration_set(enum_type, use_enum);
|
||||||
|
|
||||||
verinum cur_value (0);
|
|
||||||
verinum one_value (1);
|
|
||||||
size_t name_idx = 0;
|
size_t name_idx = 0;
|
||||||
// Find the enumeration width.
|
// Find the enumeration width.
|
||||||
long raw_width = use_enum->packed_width();
|
long raw_width = use_enum->packed_width();
|
||||||
assert(raw_width > 0);
|
assert(raw_width > 0);
|
||||||
unsigned enum_width = (unsigned)raw_width;
|
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 min_value (0);
|
||||||
verinum max_value (0);
|
verinum max_value (0);
|
||||||
if (enum_type->signed_flag) {
|
if (enum_type->signed_flag) {
|
||||||
|
|
@ -206,10 +211,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
min_value.has_sign(true);
|
min_value.has_sign(true);
|
||||||
max_value.has_sign(enum_type->signed_flag);
|
max_value.has_sign(enum_type->signed_flag);
|
||||||
|
// Process the enumeration definition.
|
||||||
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
||||||
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
||||||
|
// Check to see if the enumeration name has a value given.
|
||||||
|
|
||||||
if (cur->parm) {
|
if (cur->parm) {
|
||||||
// There is an explicit value. elaborate/evaluate
|
// There is an explicit value. elaborate/evaluate
|
||||||
// the value and assign it to the enumeration name.
|
// 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);
|
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
||||||
if (val_const == 0) {
|
if (val_const == 0) {
|
||||||
cerr << use_enum->get_fileline()
|
cerr << use_enum->get_fileline()
|
||||||
<< ": error: Enumeration expression is not "
|
<< ": error: Enumeration expression for "
|
||||||
"constant." << endl;
|
<< cur->name <<" is not an integer constant."
|
||||||
|
<< endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cur_value = val_const->value();
|
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 &&
|
if (enum_type->base_type==IVL_VT_BOOL &&
|
||||||
! cur_value.is_defined()) {
|
! cur_value.is_defined()) {
|
||||||
cerr << use_enum->get_fileline()
|
cerr << use_enum->get_fileline()
|
||||||
<< ": error: Enumeration name " << cur->name
|
<< ": error: Enumeration name " << cur->name
|
||||||
<< " cannot have an undefined value." << endl;
|
<< " can not have an undefined value." << endl;
|
||||||
des->errors += 1;
|
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()) {
|
} else if (! cur_value.is_defined()) {
|
||||||
cerr << use_enum->get_fileline()
|
cerr << use_enum->get_fileline()
|
||||||
<< ": error: Enumeration name " << cur->name
|
<< ": error: Enumeration name " << cur->name
|
||||||
<< " cannot have an undefined inferred value." << endl;
|
<< " has an undefined inferred value." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -258,10 +352,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
|
|
||||||
} else if ((two_state_value > max_value) ||
|
} else if ((two_state_value > max_value) ||
|
||||||
(cur_value.has_sign() && (two_state_value < min_value))) {
|
(cur_value.has_sign() && (two_state_value < min_value))) {
|
||||||
|
|
||||||
cerr << use_enum->get_fileline()
|
cerr << use_enum->get_fileline()
|
||||||
<< ": error: Enumeration name " << cur->name
|
<< ": error: Enumeration name " << cur->name
|
||||||
<< " cannot have an out of range value " << cur_value
|
<< " has an inferred value that overflowed." << endl;
|
||||||
<< "." << endl;
|
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,38 +369,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The values are explicitly sized to the width of the
|
rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value);
|
||||||
// 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);
|
|
||||||
if (scope)
|
if (scope)
|
||||||
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
||||||
else
|
else
|
||||||
|
|
@ -321,8 +384,9 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
|
|
||||||
// In case the next name has an implicit value,
|
// In case the next name has an implicit value,
|
||||||
// increment the current value by one.
|
// increment the current value by one.
|
||||||
if (cur_value.is_defined())
|
if (cur_value.is_defined()) {
|
||||||
cur_value = cur_value + one_value;
|
cur_value = cur_value + one_value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use_enum->insert_name_close();
|
use_enum->insert_name_close();
|
||||||
|
|
@ -852,7 +916,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||||
delete[]attr;
|
delete[]attr;
|
||||||
|
|
||||||
// Generate schemes need to have their scopes elaborated, but
|
// 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.
|
// into an elaborate work item.
|
||||||
if (debug_scopes)
|
if (debug_scopes)
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
|
|
@ -1594,7 +1658,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr << get_fileline() << ": error: You cannot instantiate "
|
cerr << get_fileline() << ": error: You can not instantiate "
|
||||||
<< "module " << mod->mod_name() << " within itself." << endl;
|
<< "module " << mod->mod_name() << " within itself." << endl;
|
||||||
cerr << get_fileline() << ": : The offending instance is "
|
cerr << get_fileline() << ": : The offending instance is "
|
||||||
<< get_name() << " within " << scope_path(scn) << "." << endl;
|
<< get_name() << " within " << scope_path(scn) << "." << endl;
|
||||||
|
|
|
||||||
12
elaborate.cc
12
elaborate.cc
|
|
@ -38,6 +38,7 @@
|
||||||
# include "PPackage.h"
|
# include "PPackage.h"
|
||||||
# include "PSpec.h"
|
# include "PSpec.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
|
# include "netenum.h"
|
||||||
# include "netvector.h"
|
# include "netvector.h"
|
||||||
# include "netdarray.h"
|
# include "netdarray.h"
|
||||||
# include "netparray.h"
|
# include "netparray.h"
|
||||||
|
|
@ -2668,7 +2669,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) {
|
if (lv->enumeration() &&
|
||||||
|
! lv->enumeration()->matches(rv->enumeration())) {
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "Enumeration type mismatch in assignment." << endl;
|
<< "Enumeration type mismatch in assignment." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
@ -3003,10 +3005,10 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
||||||
context_width = 1;
|
context_width = 1;
|
||||||
context_unsigned = false;
|
context_unsigned = false;
|
||||||
|
|
||||||
} else if (context_mode > PExpr::SIZED) {
|
} else if (context_mode >= PExpr::LOSSLESS) {
|
||||||
|
|
||||||
/* Expressions may choose a different size if they are
|
/* 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. */
|
process again to get the final expression width. */
|
||||||
|
|
||||||
context_width = test_case_width(des, scope, expr_, context_mode);
|
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)
|
/* Iterate over all the case items (guard/statement pairs)
|
||||||
elaborating them. If the guard has no expression, then this
|
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. */
|
expressions, and each guard is a case. */
|
||||||
unsigned inum = 0;
|
unsigned inum = 0;
|
||||||
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@
|
||||||
* tokenType values are not initialized for the empty table entries.
|
* tokenType values are not initialized for the empty table entries.
|
||||||
*/
|
*/
|
||||||
%define initializer-suffix ,0,0
|
%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 "config.h"
|
||||||
#include "parse_misc.h"
|
#include "parse_misc.h"
|
||||||
|
|
@ -362,7 +364,7 @@ int lexor_keyword_mask = 0;
|
||||||
|
|
||||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
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)
|
if (rc == 0)
|
||||||
return IDENTIFIER;
|
return IDENTIFIER;
|
||||||
else if ((rc->mask & lexor_keyword_mask) == 0)
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
|
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
|
|
||||||
|
# include "compiler.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include <cassert>
|
# include "netmisc.h"
|
||||||
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
NetBlock::NetBlock(Type t, NetScope*ss)
|
NetBlock::NetBlock(Type t, NetScope*ss)
|
||||||
: type_(t), subscope_(ss), last_(0)
|
: 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)
|
NetCase::NetCase(NetCase::TYPE c, NetExpr*ex, unsigned cnt)
|
||||||
: type_(c), expr_(ex), items_(cnt)
|
: type_(c), expr_(ex), items_(cnt)
|
||||||
{
|
{
|
||||||
assert(expr_);
|
ivl_assert(*this, expr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetCase::~NetCase()
|
NetCase::~NetCase()
|
||||||
|
|
@ -92,11 +94,73 @@ NetCase::TYPE NetCase::type() const
|
||||||
|
|
||||||
void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
|
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].guard = e;
|
||||||
items_[idx].statement = p;
|
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)
|
NetDisable::NetDisable(NetScope*tgt)
|
||||||
: target_(tgt)
|
: target_(tgt)
|
||||||
{
|
{
|
||||||
|
|
@ -175,7 +239,7 @@ NetPDelay::~NetPDelay()
|
||||||
|
|
||||||
uint64_t NetPDelay::delay() const
|
uint64_t NetPDelay::delay() const
|
||||||
{
|
{
|
||||||
assert(expr_ == 0);
|
ivl_assert(*this, expr_ == 0);
|
||||||
return delay_;
|
return delay_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
netenum.cc
13
netenum.cc
|
|
@ -24,9 +24,11 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag,
|
netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag,
|
||||||
bool integer_flag, long msb, long lsb, size_t name_count)
|
bool integer_flag, long msb, long lsb, size_t name_count,
|
||||||
: base_type_(btype), signed_flag_(signed_flag), integer_flag_(integer_flag),
|
enum_type_t*enum_type)
|
||||||
msb_(msb), lsb_(lsb), names_(name_count), bits_(name_count)
|
: 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];
|
return bits_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool netenum_t::matches(const netenum_t*other) const
|
||||||
|
{
|
||||||
|
return enum_type_ == other->enum_type_;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,14 @@
|
||||||
|
|
||||||
class NetScope;
|
class NetScope;
|
||||||
|
|
||||||
|
struct enum_type_t;
|
||||||
|
|
||||||
class netenum_t : public LineInfo, public ivl_type_s {
|
class netenum_t : public LineInfo, public ivl_type_s {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,
|
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,
|
||||||
bool isint_flag, long msb, long lsb,
|
bool isint_flag, long msb, long lsb,
|
||||||
size_t name_count);
|
size_t name_count, enum_type_t*enum_type);
|
||||||
~netenum_t();
|
~netenum_t();
|
||||||
|
|
||||||
virtual ivl_variable_type_t base_type() const;
|
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 name_at(size_t idx) const;
|
||||||
perm_string bits_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:
|
private:
|
||||||
ivl_variable_type_t base_type_;
|
ivl_variable_type_t base_type_;
|
||||||
|
enum_type_t*enum_type_;
|
||||||
bool signed_flag_;
|
bool signed_flag_;
|
||||||
bool integer_flag_;
|
bool integer_flag_;
|
||||||
long msb_, lsb_;
|
long msb_, lsb_;
|
||||||
|
|
|
||||||
|
|
@ -2939,6 +2939,8 @@ class NetCase : public NetProc {
|
||||||
|
|
||||||
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
|
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
|
||||||
|
|
||||||
|
void prune();
|
||||||
|
|
||||||
TYPE type() const;
|
TYPE type() const;
|
||||||
const NetExpr*expr() const { return expr_; }
|
const NetExpr*expr() const { return expr_; }
|
||||||
inline unsigned nitems() const { return items_.size(); }
|
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);
|
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);
|
ivl_assert(*this, ge);
|
||||||
verinum gval = ge->value();
|
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]) {
|
||||||
statement_map[sel_idx] = items_[item].statement;
|
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)
|
if (sel_idx > max_guard_value)
|
||||||
max_guard_value = sel_idx;
|
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.
|
// 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);
|
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
|
/* If there is a default clause, synthesize it once and we'll
|
||||||
link it in wherever it is needed. */
|
link it in wherever it is needed. */
|
||||||
NetBus default_bus (scope, nex_map.size());
|
NetBus default_bus (scope, nex_map.size());
|
||||||
|
|
@ -607,12 +632,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stmt == 0) {
|
ivl_assert(*this, stmt);
|
||||||
cerr << get_fileline() << ": error: case " << idx
|
|
||||||
<< " is not accounted for in asynchronous mux." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetBus accumulated_tmp (scope, nex_map.size());
|
NetBus accumulated_tmp (scope, nex_map.size());
|
||||||
for (unsigned pin = 0 ; pin < nex_map.size() ; pin += 1)
|
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)) {
|
if (! top->synth_async(des)) {
|
||||||
cerr << top->get_fileline() << ": internal error: "
|
cerr << top->get_fileline() << ": error: "
|
||||||
<< "is_asynchronous does not match "
|
<< "failed to synthesize asynchronous "
|
||||||
<< "sync_async results." << endl;
|
<< "logic for this process." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
verinum.cc
17
verinum.cc
|
|
@ -587,6 +587,21 @@ bool verinum::is_negative() const
|
||||||
return (bits_[nbits_-1] == V1) && has_sign();
|
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()
|
void verinum::cast_to_int2()
|
||||||
{
|
{
|
||||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
|
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
|
/* If the number is fully defined (no x or z) then print it
|
||||||
out as a decimal number. */
|
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())
|
if (v.has_sign())
|
||||||
o << "'sd" << v.as_long();
|
o << "'sd" << v.as_long();
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class verinum {
|
||||||
~verinum();
|
~verinum();
|
||||||
verinum& operator= (const verinum&);
|
verinum& operator= (const verinum&);
|
||||||
|
|
||||||
// Number of significant bits in this number.
|
// Number of stored bits in this number.
|
||||||
unsigned len() const { return nbits_; }
|
unsigned len() const { return nbits_; }
|
||||||
|
|
||||||
// A number "has a length" if the length was specified fixed
|
// A number "has a length" if the length was specified fixed
|
||||||
|
|
@ -86,6 +86,9 @@ class verinum {
|
||||||
// Comparison for use in sorting algorithms.
|
// Comparison for use in sorting algorithms.
|
||||||
bool is_before(const verinum&that) const;
|
bool is_before(const verinum&that) const;
|
||||||
|
|
||||||
|
// Number of significant bits in this number.
|
||||||
|
unsigned significant_bits() const;
|
||||||
|
|
||||||
// Convert 4-state to 2-state
|
// Convert 4-state to 2-state
|
||||||
void cast_to_int2();
|
void cast_to_int2();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ parse.h: parse.cc
|
||||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||||
|
|
||||||
lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf
|
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@
|
install: all installdirs $(libdir)/ivl$(suffix)/vhdlpp@EXEEXT@
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
* tokenType values are not initialized for the empty table entries.
|
* tokenType values are not initialized for the empty table entries.
|
||||||
*/
|
*/
|
||||||
%define initializer-suffix ,0,0
|
%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 "vhdlpp_config.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
@ -134,7 +135,7 @@ int lexor_keyword_mask = GN_KEYWORD_2008;
|
||||||
|
|
||||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
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)
|
if (rc == 0)
|
||||||
return IDENTIFIER;
|
return IDENTIFIER;
|
||||||
else if ((rc->mask & lexor_keyword_mask) == 0)
|
else if ((rc->mask & lexor_keyword_mask) == 0)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue