Revert bad merge from vhdl branch

This commit is contained in:
Stephen Williams 2010-10-02 11:02:27 -07:00
parent 7f2cb6afcd
commit ec49f10e2d
83 changed files with 1254 additions and 1140 deletions

View File

@ -30,7 +30,7 @@ SHELL = /bin/sh
# The "suffix" is used as an installation suffix. It modifies certain
# key install paths/files such that a build and install of Icarus Verilog
# with the same $(prefix) but a different $(suffix) will not interfere.
# The normal configuratin leaves suffix empty
# The normal configuration leaves suffix empty
suffix = @install_suffix@
prefix = @prefix@
@ -240,7 +240,7 @@ iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe
tail -n +2 $(srcdir)/iverilog-vpi.man.in >> $@
iverilog-vpi.ps: iverilog-vpi.man
$(MAN) -t iverilog-vpi.man > iverilog-vpi.ps
$(MAN) -t ./iverilog-vpi.man > iverilog-vpi.ps
iverilog-vpi.pdf: iverilog-vpi.ps
$(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf

View File

@ -1,7 +1,7 @@
#ifndef __discipline_H
#define __discipline_H
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2010 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
@ -55,8 +55,8 @@ class ivl_discipline_s : public LineInfo {
perm_string name() const { return name_; }
ivl_dis_domain_t domain() const { return domain_; }
const ivl_nature_t potential() const { return potential_; }
const ivl_nature_t flow() const { return flow_; }
ivl_nature_t potential() const { return potential_; }
ivl_nature_t flow() const { return flow_; }
private:
perm_string name_;

View File

@ -89,7 +89,7 @@ iverilog.man: $(srcdir)/iverilog.man.in ../version.exe
tail -n +2 $(srcdir)/iverilog.man.in >> $@
iverilog.ps: iverilog.man
$(MAN) -t iverilog.man > iverilog.ps
$(MAN) -t ./iverilog.man > iverilog.ps
iverilog.pdf: iverilog.ps
$(PS2PDF) iverilog.ps iverilog.pdf

View File

@ -169,8 +169,8 @@ typedef struct t_command_file {
p_command_file cmd_file_head = NULL; /* The FIFO head */
p_command_file cmd_file_tail = NULL; /* The FIFO tail */
/* Temprarily store parameter definition from command line and
* parse it after we have delt with command file
/* Temporarily store parameter definition from command line and
* parse it after we have dealt with command file
*/
static const char** defparm_base = 0;
static int defparm_size = 0;
@ -777,10 +777,10 @@ int main(int argc, char **argv)
turning the last two \ characters to null. Then we append
the lib\ivl$(suffix) to finish. */
{ char *s;
char basepath[4096], tmp[4096];
GetModuleFileName(NULL, tmp, sizeof tmp);
char basepath[4096], tmppath[4096];
GetModuleFileName(NULL, tmppath, sizeof tmppath);
/* Convert to a short name to remove any embedded spaces. */
GetShortPathName(tmp, basepath, sizeof basepath);
GetShortPathName(tmppath, basepath, sizeof basepath);
strncpy(ivl_root, basepath, MAXSIZE);
ivl_root[MAXSIZE-1] = 0;
s = strrchr(ivl_root, sep);
@ -1105,7 +1105,7 @@ int main(int argc, char **argv)
/* If we are planning on opening a dependencies file, then
open and truncate it here. The other phases of compilation
will append to the file, so this is necessray to make sure
will append to the file, so this is necessary to make sure
it starts out empty. */
if (depfile) {
FILE*fd = fopen(depfile, "w");

View File

@ -729,7 +729,7 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
return tmp;
}
// Falback, handle the general case.
// Fallback, handle the general case.
if (expr_wid > 0)
lp = pad_to_width(lp, expr_wid, *this);
tmp = new NetEBShift(op_, lp, rp);
@ -2494,11 +2494,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
return result_ex;
}
if (par_msv >= par_lsv) {
if (par_lsv != 0) base = make_add_expr(base, -par_lsv);
} else {
base = make_sub_expr(par_lsv-wid+1, base);
}
base = normalize_variable_base(base, par_msv, par_lsv, wid, true);
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
@ -2578,13 +2574,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
return result_ex;
}
if (par_msv >= par_lsv) {
if (long offset = par_lsv+wid-1) {
base = make_add_expr(base, -offset);
}
} else {
base = make_sub_expr(par_lsv, base);
}
base = normalize_variable_base(base, par_msv, par_lsv, wid, false);
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
@ -2742,17 +2732,10 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
} else {
if (par_me) {
long par_mv = par_me->value().as_long();
long par_lv = par_le->value().as_long();
if (par_mv >= par_lv) {
mtmp = par_lv
? make_add_expr(mtmp, 0-par_lv)
: mtmp;
} else {
if (par_lv != 0)
mtmp = make_add_expr(mtmp, 0-par_mv);
mtmp = make_sub_expr(par_lv-par_mv, mtmp);
}
mtmp = normalize_variable_base(mtmp,
par_me->value().as_long(),
par_le->value().as_long(),
1, true);
}
/* The value is constant, but the bit select
@ -2869,7 +2852,8 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
// expression to calculate the canonical address.
if (long base = net->array_first()) {
word_index = make_add_expr(word_index, 0-base);
word_index = normalize_variable_array_base(
word_index, base, net->array_count());
eval_expr(word_index);
}
}
@ -3092,12 +3076,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
return ss;
}
if (net->msi() > net->lsi()) {
if (long offset = net->lsi())
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(net->lsi()-wid+1, base);
}
base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true);
NetESelect*ss = new NetESelect(net, base, wid);
ss->set_line(*this);
@ -3184,12 +3163,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
return ss;
}
if (net->msi() > net->lsi()) {
if (long offset = net->lsi()+wid-1)
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(net->lsi(), base);
}
base = normalize_variable_base(base, net->msi(), net->lsi(), wid, false);
NetESelect*ss = new NetESelect(net, base, wid);
ss->set_line(*this);
@ -3294,12 +3268,8 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
if (net->sig()->msb() < net->sig()->lsb()) {
ex = make_sub_expr(net->sig()->lsb(), ex);
} else {
ex = make_add_expr(ex, - net->sig()->lsb());
}
ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(),
1, true);
NetESelect*ss = new NetESelect(net, ex, 1);
ss->set_line(*this);
@ -3537,7 +3507,7 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
// evaluation of ternary expressions, but it doesn't disallow
// it. The disadvantage of doing this is that semantic errors
// in the unused clause will be missed, but people don't seem
// to mind, and do apreciate the optimization available here.
// to mind, and do appreciate the optimization available here.
if (NetEConst*tmp = dynamic_cast<NetEConst*> (con)) {
verinum cval = tmp->value();
ivl_assert(*this, cval.len()==1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2010 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
@ -269,7 +269,8 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
// expression to calculate the canonical address.
if (long base = reg->array_first()) {
word = make_add_expr(word, 0-base);
word = normalize_variable_array_base(word, base,
reg->array_count());
eval_expr(word);
}
@ -342,7 +343,6 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
index_tail.msb->test_width(des, scope, integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
// Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit
// width of 1.
@ -357,10 +357,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select expression.
if (reg->msb() < reg->lsb())
mux = make_sub_expr(reg->lsb(), mux);
else if (reg->lsb() != 0)
mux = make_add_expr(mux, - reg->lsb());
mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true);
lv->set_part(mux, 1);
@ -535,20 +532,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
} else {
/* Correct the mux for the range of the vector. */
if (use_sel == index_component_t::SEL_IDX_UP) {
if (reg->msb() > reg->lsb()) {
if (long offset = reg->lsb())
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(reg->lsb()-wid+1, base);
}
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
wid, true);
} else {
// This is assumed to be a SEL_IDX_DO.
if (reg->msb() > reg->lsb()) {
if (long offset = reg->lsb()+wid-1)
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(reg->lsb(), base);
}
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
wid, false);
}
}

View File

@ -1228,6 +1228,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
<< *this << endl;
}
if (solving()) {
cerr << get_fileline() << ": warning: Recursive parameter "
"reference found involving " << *this << "." << endl;
return 0;
}
assert(scope_);
perm_string name = (*reference_).first;
const NetExpr*expr = (*reference_).second.expr;
@ -1239,35 +1245,35 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
<< *this << " cannot be evaluated." << endl;
return 0;
}
// ivl_assert(*this, expr);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
// If the parameter that I refer to is already evaluated, then
// return the constant value.
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
if (const NetEConst*tmp = dynamic_cast<const NetEConst*>(expr)) {
verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
}
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
if (const NetECReal*tmp = dynamic_cast<const NetECReal*>(expr)) {
verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
}
// Try to evaluate the expression. If I cannot, then the
// expression is not a constant expression and I fail here.
solving(true);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
NetExpr*res = nexpr->eval_tree();
solving(false);
if (res == 0) {
cerr << get_fileline() << ": internal error: Unable to evaluate "
<< "parameter " << name << " expression: "
cerr << get_fileline() << ": internal error: Unable to evaluate ";
if (expr_type() == IVL_VT_REAL) cerr << "real ";
cerr << "parameter " << name << " expression: "
<< *nexpr << endl;
delete nexpr;
return 0;

View File

@ -907,7 +907,7 @@ NetNet* NetEUnary::synthesize(Design*des, NetScope*scope, NetExpr*root)
return sig;
}
cerr << get_fileline() << ": iternal error: "
cerr << get_fileline() << ": internal error: "
<< "NetEUnary::synthesize cannot handle op_=" << op_ << endl;
des->errors += 1;
return expr_->synthesize(des, scope, root);

View File

@ -607,7 +607,7 @@ extern double ivl_const_real(ivl_net_const_t net);
*
* The discipline domain will not be IVL_DIS_NONE. The "none" domain
* is a place-holder internally for incomplete parsing, and is also
* available for code generaters to use.
* available for code generators to use.
*/
extern const char*ivl_discipline_name(ivl_discipline_t net);
extern ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net);
@ -1696,7 +1696,7 @@ extern int ivl_scope_time_units(ivl_scope_t net);
*
* ivl_signal_discipline
* If the signal has been declared with a domain (Verilog-AMS) then
* this function wil return a non-nil ivl_discipline_t.
* this function will return a non-nil ivl_discipline_t.
*
* ivl_signal_msb
* ivl_signal_lsb

View File

@ -1179,7 +1179,7 @@ static void process_ucdrive(const char*txt)
cp += strspn(cp, " \t");
if (strncmp(cp, "//", 2) != 0 &&
(size_t)(cp-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid `unconnected_dirve directive (extra "
VLerror(yylloc, "Invalid `unconnected_drive directive (extra "
"garbage after precision).");
return;
}

View File

@ -341,8 +341,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
eval_expr((*cur).second.msb);
if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< ": error: Unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.msb << endl;
des->errors += 1;
@ -357,8 +356,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
eval_expr((*cur).second.lsb);
if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< ": error: Unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.lsb << endl;
des->errors += 1;
@ -384,10 +382,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
<< ": error: Unable to evaluate real parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
@ -396,11 +394,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " << *expr << endl;
<< ": error: Unable to evaluate parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
@ -408,8 +405,9 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
default:
cerr << expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
<< "Unhandled expression type?" << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
@ -522,7 +520,13 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
res = tmp;
} else {
ivl_assert(*expr, 0);
cerr << expr->get_fileline()
<< ": error: "
<< "Unable to evaluate real parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
@ -533,12 +537,23 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
res = new NetECReal(val);
res->set_line(*tmp);
} else {
ivl_assert(*expr, 0);
cerr << expr->get_fileline()
<< ": error: "
<< "Unable to evaluate parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
default:
ivl_assert(*expr, 0);
cerr << expr->get_fileline()
<< ": internal error: "
<< "Unhandled expression type?" << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
break;
}
@ -586,7 +601,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
if (! from_flag) {
cerr << res->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< " is out of range for real parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
@ -612,7 +627,7 @@ void NetScope::evaluate_parameters(Design*des)
// Resolve the expression type (signed/unsigned) if the
// expression is present. It is possible to not be
// present if there are earlier errors en elaboration.
// present if there are earlier errors in elaboration.
if (cur->second.expr)
cur->second.expr->resolve_pexpr_type();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2010 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
@ -488,18 +488,21 @@ const NetScope* NetECRealParam::scope() const
NetEParam::NetEParam()
: des_(0), scope_(0)
{
solving_ = false;
}
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
{
cast_signed_base_(reference_->second.signed_flag);
solving_ = false;
}
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
: des_(d), scope_(s), reference_(ref)
{
cast_signed_base_(reference_->second.signed_flag);
solving_ = false;
}
NetEParam::~NetEParam()
@ -519,10 +522,21 @@ ivl_variable_type_t NetEParam::expr_type() const
NetEParam* NetEParam::dup_expr() const
{
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
tmp->solving(solving_);
tmp->set_line(*this);
return tmp;
}
void NetEParam::solving(bool arg)
{
solving_ = arg;
}
bool NetEParam::solving() const
{
return solving_;
}
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid)
: expr_(exp), base_(base)
{

View File

@ -1829,7 +1829,7 @@ class NetPartSelect : public NetNode {
* that makes sense for the technology.
*
* A NetBUFZ is transparent if strengths are passed through it without
* change. A NetBUFZ is non-transparent if values other then HiZ are
* change. A NetBUFZ is non-transparent if values other than HiZ are
* converted to the strength of the output.
*/
class NetBUFZ : public NetNode {
@ -3574,6 +3574,8 @@ class NetEParam : public NetExpr {
virtual ivl_variable_type_t expr_type() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetEParam* dup_expr() const;
void solving(bool arg);
bool solving() const;
virtual void dump(ostream&) const;
@ -3582,6 +3584,7 @@ class NetEParam : public NetExpr {
NetScope*scope_;
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
ref_t reference_;
bool solving_;
NetEParam(class Design*des, NetScope*scope, ref_t ref);
};

View File

@ -161,7 +161,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
* NetEBAdd node that has the input expression and an expression made
* from the constant value.
*/
NetExpr* make_add_expr(NetExpr*expr, long val)
static NetExpr* make_add_expr(NetExpr*expr, long val)
{
if (val == 0)
return expr;
@ -190,10 +190,14 @@ NetExpr* make_add_expr(NetExpr*expr, long val)
return res;
}
NetExpr* make_sub_expr(long val, NetExpr*expr)
/*
* Subtract an existing expression from a signed constant.
*/
static NetExpr* make_sub_expr(long val, NetExpr*expr)
{
verinum val_v (val, expr->expr_width());
val_v.has_sign(true);
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
@ -203,6 +207,150 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
/*
* This routine is used to calculate the number of bits needed to
* contain the given number.
*/
static unsigned num_bits(long arg)
{
unsigned res = 0;
/* For a negative value we have room for one extra value, but
* we have a signed result so we need an extra bit for this. */
if (arg < 0) {
arg = -arg - 1;
res += 1;
}
/* Calculate the number of bits needed here. */
while (arg) {
res += 1;
arg >>= 1;
}
return res;
}
/*
* This routine generates the normalization expression needed for a variable
* bit select or a variable base expression for an indexed part select.
*/
NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up)
{
long offset = lsb;
if (msb < lsb) {
/* Correct the offset if needed. */
if (is_up) offset -= wid - 1;
/* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(offset);
/* We need enough space for the larger of the offset or the
* base expression. */
if (min_wid < base->expr_width()) min_wid = base->expr_width();
/* Now that we have the minimum needed width increase it by
* one to make room for the normalization calculation. */
min_wid += 1;
/* Pad the base expression to the correct width. */
base = pad_to_width(base, min_wid, *base);
/* If the base expression is unsigned and either the lsb
* is negative or it does not fill the width of the base
* expression then we could generate negative normalized
* values so cast the expression to signed to get the
* math correct. */
if ((lsb < 0 || num_bits(lsb+1) <= base->expr_width()) &&
! base->has_sign()) {
/* We need this extra select to hide the signed
* property from the padding above. It will be
* removed automatically during code generation. */
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
tmp->set_line(*base);
tmp->cast_signed(true);
base = tmp;
}
/* Normalize the expression. */
base = make_sub_expr(offset, base);
} else {
/* Correct the offset if needed. */
if (!is_up) offset += wid - 1;
/* If the offset is zero then just return the base (index)
* expression. */
if (offset == 0) return base;
/* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(-offset);
/* We need enough space for the larger of the offset or the
* base expression. */
if (min_wid < base->expr_width()) min_wid = base->expr_width();
/* Now that we have the minimum needed width increase it by
* one to make room for the normalization calculation. */
min_wid += 1;
/* Pad the base expression to the correct width. */
base = pad_to_width(base, min_wid, *base);
/* If the offset is greater than zero then we need to do
* signed math to get the location value correct. */
if (offset > 0 && ! base->has_sign()) {
/* We need this extra select to hide the signed
* property from the padding above. It will be
* removed automatically during code generation. */
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
tmp->set_line(*base);
tmp->cast_signed(true);
base = tmp;
}
/* Normalize the expression. */
base = make_add_expr(base, -offset);
}
return base;
}
/*
* This routine generates the normalization expression needed for a variable
* array word select.
*/
NetExpr *normalize_variable_array_base(NetExpr *base, long offset,
unsigned count)
{
assert(offset != 0);
/* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(-offset);
/* We need enough space for the larger of the offset or the base
* expression. */
if (min_wid < base->expr_width()) min_wid = base->expr_width();
/* Now that we have the minimum needed width increase it by one
* to make room for the normalization calculation. */
min_wid += 1;
/* Pad the base expression to the correct width. */
base = pad_to_width(base, min_wid, *base);
/* If the offset is greater than zero then we need to do signed
* math to get the location value correct. */
if (offset > 0 && ! base->has_sign()) {
/* We need this extra select to hide the signed property
* from the padding above. It will be removed automatically
* during code generation. */
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
tmp->set_line(*base);
tmp->cast_signed(true);
base = tmp;
}
/* Normalize the expression. */
base = make_add_expr(base, -offset);
/* We should not need to do this, but .array/port does not
* handle a small signed index correctly and it is a major
* effort to fix it. For now we will just pad the expression
* enough so that any negative value when converted to
* unsigned is larger than the maximum array word. */
if (base->has_sign()) {
unsigned range_wid = num_bits(count-1) + 1;
if (min_wid < range_wid) {
base = pad_to_width(base, range_wid, *base);
}
}
return base;
}
NetEConst* make_const_x(unsigned long wid)
{
verinum xxx (verinum::Vx, wid);
@ -289,8 +437,15 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope,
void eval_expr(NetExpr*&expr, int prune_width)
{
assert(expr);
if (dynamic_cast<NetEConst*>(expr)) return;
if (dynamic_cast<NetECReal*>(expr)) return;
/* Resize a constant if allowed and needed. */
if (NetEConst *tmp = dynamic_cast<NetEConst*>(expr)) {
if (prune_width <= 0) return;
if (tmp->has_width()) return;
if ((unsigned)prune_width <= tmp->expr_width()) return;
expr = pad_to_width(expr, (unsigned)prune_width, *expr);
return;
}
NetExpr*tmp = expr->eval_tree(prune_width);
if (tmp != 0) {

View File

@ -91,6 +91,15 @@ extern NetExpr*condition_reduce(NetExpr*expr);
*/
extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
/*
* These functions generate an equation to normalize an expression using
* the provided vector/array information.
*/
extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up);
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
unsigned count);
/*
* This function takes as input a NetNet signal and adds a constant
* value to it. If the val is 0, then simply return sig. Otherwise,
@ -99,23 +108,6 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
/*
* These functions make various sorts of expressions, given operands
* of certain type. The order of the operands is preserved in cases
* where order matters.
*
* make_add_expr
* Make a NetEBAdd expression with <expr> the first argument and
* <val> the second. This may get turned into a subtract if <val> is
* less than zero. If val is exactly zero, then return <expr> as is.
*
* make_sub_expr
* Make a NetEBAdd(subtract) node that subtracts the given
* expression from the integer value.
*/
extern NetExpr*make_add_expr(NetExpr*expr, long val);
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
/*
* Make a NetEConst object that contains only X bits.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2010 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
@ -131,14 +131,12 @@ void nodangle_f::signal(Design*des, NetNet*sig)
if (sig->get_refs() > 0)
return;
/* Cannot delete the ports of tasks or functions. There are
too many places where they are referenced. */
if ((sig->port_type() != NetNet::NOT_A_PORT)
&& (sig->scope()->type() == NetScope::TASK))
return;
if ((sig->port_type() != NetNet::NOT_A_PORT)
&& (sig->scope()->type() == NetScope::FUNC))
/* Cannot delete the ports of tasks, functions or modules. There
are too many places where they are referenced. */
if ((sig->port_type() != NetNet::NOT_A_PORT) &&
((sig->scope()->type() == NetScope::TASK) ||
(sig->scope()->type() == NetScope::FUNC) ||
(sig->scope()->type() == NetScope::MODULE)))
return;
/* Can't delete ports of cells. */

View File

@ -78,7 +78,7 @@ extern bool have_timeunit_decl;
extern bool have_timeprec_decl;
/*
* Export there functions because we have to generate PENumber class
* Export these functions because we have to generate PENumber class
* in pform.cc for user defparam definition from command file.
*/
extern verinum*make_unsized_dec(const char*txt);

View File

@ -65,7 +65,7 @@ void parm_to_defparam_list(const string&param)
// Resolve hierarchical name for defparam. Remember
// to deal with bit select for generate scopes. Bit
// select expression should be constant interger.
// select expression should be constant integer.
pform_name_t name;
char *nkey = key;
char *ptr = strchr(key, '.');
@ -144,7 +144,7 @@ void parm_to_defparam_list(const string&param)
char *num = strchr(value, '\'');
if (num != 0) {
verinum *val;
// BASED_NUMBER, somthing like - scope.parameter='b11
// BASED_NUMBER, something like - scope.parameter='b11
// make sure to check 'h' first because 'b'&'d' may be included
// in hex format
if (strchr(num, 'h') || strchr(num, 'H'))

View File

@ -50,7 +50,7 @@ dep:
mv $*.d dep
O = vhdl.o state.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \
stmt.o expr.o lpm.o support.o cast.o logic.o
stmt.o expr.o lpm.o display.o support.o cast.o logic.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl

View File

@ -58,8 +58,6 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
return to_vector(to->get_name(), to->get_width());
case VHDL_TYPE_STD_LOGIC:
return to_std_logic();
case VHDL_TYPE_STRING:
return to_string();
case VHDL_TYPE_STD_ULOGIC:
return to_std_ulogic();
default:
@ -118,25 +116,6 @@ vhdl_expr *vhdl_expr::to_integer()
return conv;
}
vhdl_expr *vhdl_expr::to_string()
{
bool numeric = type_->get_name() == VHDL_TYPE_UNSIGNED
|| type_->get_name() == VHDL_TYPE_SIGNED;
if (numeric) {
vhdl_fcall *image = new vhdl_fcall("integer'image", vhdl_type::string());
image->add_expr(this->cast(vhdl_type::integer()));
return image;
}
else {
// Assume type'image exists
vhdl_fcall *image = new vhdl_fcall(type_->get_string() + "'image",
vhdl_type::string());
image->add_expr(this);
return image;
}
}
/*
* Convert a generic expression to a Boolean.
*/

200
tgt-vhdl/display.cc Normal file
View File

@ -0,0 +1,200 @@
/*
* VHDL implementation of $display.
*
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "vhdl_target.h"
#include <iostream>
#include <cstring>
#include <cassert>
#include <cctype>
#include <sstream>
static const char *DISPLAY_LINE = "Verilog_Display_Line";
/*
* Write a VHDL expression into the current display line.
*/
static void display_write(stmt_container *container, vhdl_expr *expr)
{
vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
vhdl_var_ref *ref =
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
write->add_expr(ref);
vhdl_type_name_t type = expr->get_type()->get_name();
if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
vhdl_type integer(VHDL_TYPE_INTEGER);
write->add_expr(expr->cast(&integer));
}
else if (type != VHDL_TYPE_STRING) {
// Need to add a call to Type'Image for types not
// supported by std.textio
std::string name(expr->get_type()->get_string());
name += "'Image";
vhdl_fcall *cast
= new vhdl_fcall(name.c_str(), vhdl_type::string());
cast->add_expr(expr);
write->add_expr(cast);
}
else
write->add_expr(expr);
container->add_stmt(write);
}
/*
* Write the value of DISPLAY_LINE to the output.
*/
static void display_line(stmt_container *container)
{
vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
vhdl_var_ref *output_ref =
new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
write_line->add_expr(output_ref);
vhdl_var_ref *ref =
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
write_line->add_expr(ref);
container->add_stmt(write_line);
}
/*
* Parse an octal escape sequence.
*/
static char parse_octal(const char *p)
{
assert(*p && *(p+1) && *(p+2));
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
return (*p - '0') * 64
+ (*(p+1) - '0') * 8
+ (*(p+2) - '0') * 1;
}
static void flush_string(std::ostringstream &ss, stmt_container *container)
{
display_write(container, new vhdl_const_string(ss.str().c_str()));
// Clear the stream
ss.str("");
}
// This should display the hierarchical module name, but we don't support
// this in VHDL. So just emit a warning.
static void display_m(stmt_container* container)
{
cerr << "Warning: no VHDL translation for %m format code" << endl;
}
/*
* Generate VHDL for the $display system task.
* This is implemented using the functions in std.textio. Each
* parameter is written to a line variable in the process and
* then the line is written to the special variable `Output'
* (which represents the console). Subsequent $displays will
* use the same line variable.
*
* It's possible, although quite unlikely, that there will be
* name collision with an existing variable called
* `Verilog_Display_Line' -- do something about this?
*/
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool newline)
{
if (!proc->get_scope()->have_declared(DISPLAY_LINE)) {
vhdl_var_decl *line_var =
new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
line_var->set_comment("For generating $display output");
proc->get_scope()->add_decl(line_var);
}
// Write the data into the line
int count = ivl_stmt_parm_count(stmt), i = 0;
while (i < count) {
// $display may have an empty parameter, in which case
// the expression will be null
// The behaviour here seems to be to output a space
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
if (net == NULL) {
display_write(container, new vhdl_const_string(" "));
continue;
}
if (ivl_expr_type(net) == IVL_EX_STRING) {
ostringstream ss;
for (const char *p = ivl_expr_string(net); *p; p++) {
if (*p == '\\') {
// Octal escape
char ch = parse_octal(p+1);
if (ch == '\n') {
flush_string(ss, container);
display_line(container);
}
else
ss << ch;
p += 3;
}
else if (*p == '%' && *(++p) != '%') {
flush_string(ss, container);
// Skip over width for now
while (isdigit(*p)) ++p;
switch (*p) {
case 'm':
display_m(container);
break;
default:
{
assert(i < count);
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
assert(netp);
vhdl_expr *base = translate_expr(netp);
if (NULL == base)
return 1;
display_write(container, base);
}
}
}
else
ss << *p;
}
// Call Write on any non-empty string data left in the buffer
if (!ss.str().empty())
display_write(container, new vhdl_const_string(ss.str().c_str()));
}
else {
vhdl_expr *base = translate_expr(net);
if (NULL == base)
return 1;
display_write(container, base);
}
}
if (newline)
display_line(container);
return 0;
}

View File

@ -477,7 +477,7 @@ static vhdl_expr *translate_select(ivl_expr_t e)
new vhdl_type(*from->get_type()));
}
else if (from_var_ref->get_type()->get_name() != VHDL_TYPE_STD_LOGIC) {
// We can use the more idomatic VHDL slice notation on a
// We can use the more idiomatic VHDL slice notation on a
// single variable reference
vhdl_type integer(VHDL_TYPE_INTEGER);
from_var_ref->set_slice(base->cast(&integer), ivl_expr_width(e) - 1);

View File

@ -57,13 +57,16 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
// However, if no statements were added to the container
// by draw_stmt, don't bother adding a wait as `emit'
// will optimise the process out of the output
bool is_initial = ivl_process_type(proc) == IVL_PR_INITIAL;
bool is_empty = vhdl_proc->get_container()->empty();
if (ivl_process_type(proc) == IVL_PR_INITIAL) {
// Get rid of any useless `wait for 0 ns's at the end of the process
prune_wait_for_0(vhdl_proc->get_container());
if (is_initial && !is_empty) {
// The above pruning might have removed all logic from the process
if (!vhdl_proc->get_container()->empty()) {
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
vhdl_proc->get_container()->add_stmt(wait);
}
}
// Add a comment indicating where it came from
ivl_scope_t scope = ivl_process_scope(proc);

View File

@ -926,26 +926,6 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth)
<< " (" << ivl_scope_def_file(scope) << ":"
<< ivl_scope_def_lineno(scope) << ")";
unsigned nparams = ivl_scope_params(scope);
for (unsigned i = 0; i < nparams; i++) {
ivl_parameter_t param = ivl_scope_param(scope, i);
ss << "\n " << ivl_parameter_basename(param) << " = ";
ivl_expr_t value = ivl_parameter_expr(param);
switch (ivl_expr_type(value)) {
case IVL_EX_STRING:
ss << "\"" << ivl_expr_string(value) << "\"";
break;
case IVL_EX_NUMBER:
ss << ivl_expr_uvalue(value);
break;
default:
assert(false);
}
}
arch->set_comment(ss.str());
ent->set_comment(ss.str());

View File

@ -25,9 +25,8 @@
#include <algorithm>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <cstring>
#include <iostream>
using namespace std;
@ -68,7 +67,7 @@ struct signal_defn_t {
static entity_list_t g_entities;
// Store the mapping of ivl scope names to entity names
typedef map<ivl_scope_t, string> scope_name_map_t;
typedef map<string, string> scope_name_map_t;
static scope_name_map_t g_scope_names;
typedef std::map<ivl_signal_t, signal_defn_t> signal_defn_map_t;
@ -78,9 +77,10 @@ static vhdl_entity *g_active_entity = NULL;
// Set of scopes that are treated as the default examples of
// that type. Any other scopes of the same type are ignored.
typedef vector<ivl_scope_t> default_scopes_t;
typedef set<ivl_scope_t> default_scopes_t;
static default_scopes_t g_default_scopes;
// True if signal `sig' has already been encountered by the code
// generator. This means we have already assigned it to a VHDL code
// object and possibly renamed it.
@ -179,31 +179,18 @@ vhdl_entity* find_entity(ivl_scope_t scope)
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
if (is_default_scope_instance(scope)) {
scope_name_map_t::iterator it = g_scope_names.find(scope);
scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope));
if (it != g_scope_names.end())
return find_entity((*it).second);
else
return NULL;
}
else {
const char *tname = ivl_scope_tname(scope);
for (scope_name_map_t::iterator it = g_scope_names.begin();
it != g_scope_names.end(); ++it) {
if (strcmp(tname, ivl_scope_tname((*it).first)) == 0)
return find_entity((*it).second);
}
return NULL;
}
}
// Add an entity/architecture pair to the list of entities to emit.
void remember_entity(vhdl_entity* ent, ivl_scope_t scope)
{
g_entities.push_back(ent);
g_scope_names[scope] = ent->get_name();
g_scope_names[ivl_scope_tname(scope)] = ent->get_name();
}
// Print all VHDL entities, in order, to the specified output stream.
@ -241,52 +228,12 @@ void set_active_entity(vhdl_entity *ent)
{
g_active_entity = ent;
}
/*
* True if two scopes have the same type name.
*/
static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b)
{
if (strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) != 0)
return false;
unsigned nparams_a = ivl_scope_params(a);
unsigned nparams_b = ivl_scope_params(b);
if (nparams_a != nparams_b)
return false;
for (unsigned i = 0; i < nparams_a; i++) {
ivl_parameter_t param_a = ivl_scope_param(a, i);
ivl_parameter_t param_b = ivl_scope_param(b, i);
if (strcmp(ivl_parameter_basename(param_a),
ivl_parameter_basename(param_b)) != 0)
return false;
ivl_expr_t value_a = ivl_parameter_expr(param_a);
ivl_expr_t value_b = ivl_parameter_expr(param_b);
if (ivl_expr_type(value_a) != ivl_expr_type(value_b))
return false;
switch (ivl_expr_type(value_a)) {
case IVL_EX_STRING:
if (strcmp(ivl_expr_string(value_a), ivl_expr_string(value_b)) != 0)
return false;
break;
case IVL_EX_NUMBER:
if (ivl_expr_uvalue(value_a) != ivl_expr_uvalue(value_b))
return false;
break;
default:
assert(false);
}
}
return true;
return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0;
}
/*
@ -299,7 +246,7 @@ bool seen_this_scope_type(ivl_scope_t s)
if (find_if(g_default_scopes.begin(), g_default_scopes.end(),
bind1st(ptr_fun(same_scope_type_name), s))
== g_default_scopes.end()) {
g_default_scopes.push_back(s);
g_default_scopes.insert(s);
return false;
}
else

View File

@ -1,7 +1,7 @@
/*
* VHDL code generation for statements.
*
* Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk)
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,9 +30,6 @@
#include <set>
#include <algorithm>
static void emit_wait_for_0(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, vhdl_expr *expr);
/*
* VHDL has no real equivalent of Verilog's $finish task. The
* current solution is to use `assert false ...' to terminate
@ -54,114 +51,12 @@ static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container,
container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish"));
}
else {
container->add_stmt(
new vhdl_report_stmt(new vhdl_const_string("SIMULATION FINISHED"),
SEVERITY_FAILURE));
container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
}
return 0;
}
static char parse_octal(const char *p)
{
assert(*p && *(p+1) && *(p+2));
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
return (*p - '0') * 64
+ (*(p+1) - '0') * 8
+ (*(p+2) - '0') * 1;
}
// Generate VHDL report statements for Verilog $display/$write
static int draw_stask_display(vhdl_procedural *proc,
stmt_container *container,
ivl_statement_t stmt)
{
vhdl_binop_expr *text = new vhdl_binop_expr(VHDL_BINOP_CONCAT,
vhdl_type::string());
const int count = ivl_stmt_parm_count(stmt);
int i = 0;
while (i < count) {
// $display may have an empty parameter, in which case
// the expression will be null
// The behaviour here seems to be to output a space
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
if (net == NULL) {
text->add_expr(new vhdl_const_string(" "));
continue;
}
if (ivl_expr_type(net) == IVL_EX_STRING) {
ostringstream ss;
for (const char *p = ivl_expr_string(net); *p; p++) {
if (*p == '\\') {
// Octal escape
char ch = parse_octal(p+1);
if (ch == '\n') {
// Is there a better way of handling newlines?
// Maybe generate another report statement
}
else
ss << ch;
p += 3;
}
else if (*p == '%' && *(++p) != '%') {
// Flush the output string up to this point
text->add_expr(new vhdl_const_string(ss.str()));
ss.str("");
// Skip over width for now
while (isdigit(*p)) ++p;
switch (*p) {
case 'm':
// TOOD: we can get the module name via attributes
cerr << "Warning: no VHDL translation for %m format code"
<< endl;
break;
default:
{
assert(i < count);
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
assert(netp);
vhdl_expr *base = translate_expr(netp);
if (NULL == base)
return 1;
emit_wait_for_0(proc, container, stmt, base);
text->add_expr(base->cast(text->get_type()));
}
}
}
else
ss << *p;
}
// Emit any non-empty string data left in the buffer
if (!ss.str().empty())
text->add_expr(new vhdl_const_string(ss.str()));
}
else {
vhdl_expr *base = translate_expr(net);
if (NULL == base)
return 1;
emit_wait_for_0(proc, container, stmt, base);
text->add_expr(base->cast(text->get_type()));
}
}
if (count == 0)
text->add_expr(new vhdl_const_string(""));
container->add_stmt(new vhdl_report_stmt(text));
return 0;
}
/*
* Generate VHDL for system tasks (like $display). Not all of
* these are supported.
@ -172,9 +67,9 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container,
const char *name = ivl_stmt_name(stmt);
if (strcmp(name, "$display") == 0)
return draw_stask_display(proc, container, stmt);
return draw_stask_display(proc, container, stmt, true);
else if (strcmp(name, "$write") == 0)
return draw_stask_display(proc, container, stmt);
return draw_stask_display(proc, container, stmt, false);
else if (strcmp(name, "$finish") == 0)
return draw_stask_finish(proc, container, stmt);
else {
@ -236,6 +131,27 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
return 0;
}
/*
* The VHDL code generator inserts `wait for 0 ns' after each
* not-last-in-block blocking assignment.
* If this is immediately followed by another `wait for ...' then
* we might as well not emit the first zero-time wait.
*/
void prune_wait_for_0(stmt_container *container)
{
vhdl_wait_stmt *wait0;
stmt_container::stmt_list_t &stmts = container->get_stmts();
while (stmts.size() > 0
&& (wait0 = dynamic_cast<vhdl_wait_stmt*>(stmts.back()))) {
if (wait0->get_type() == VHDL_WAIT_FOR0) {
delete wait0;
stmts.pop_back();
}
else
break;
}
}
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
{
ivl_signal_t sig = ivl_lval_sig(lval);
@ -347,68 +263,12 @@ bool check_valid_assignment(vhdl_decl::assign_type_t atype, vhdl_procedural *pro
return true;
}
// Generate a "wait for 0 ns" statement to emulate the behaviour of
// Verilog blocking assignment using VHDL signals. This is only generated
// if we read from the target of a blocking assignment in the same
// process (i.e. it is only generated when required, not for every
// blocking assignment). An example:
//
// begin
// x = 5;
// if (x == 2)
// y = 7;
// end
//
// Becomes:
//
// x <= 5;
// wait for 0 ns; -- Required to implement assignment semantics
// if x = 2 then
// y <= 7; -- No need for wait here, not read
// end if;
//
static void emit_wait_for_0(vhdl_procedural *proc,
stmt_container *container,
ivl_statement_t stmt,
vhdl_expr *expr)
{
vhdl_var_set_t read;
expr->find_vars(read);
bool need_wait_for_0 = false;
for (vhdl_var_set_t::const_iterator it = read.begin();
it != read.end(); ++it) {
if (proc->is_blocking_target(*it))
need_wait_for_0 = true;
}
stmt_container::stmt_list_t &stmts = container->get_stmts();
bool last_was_wait =
!stmts.empty() && dynamic_cast<vhdl_wait_stmt*>(stmts.back());
if (need_wait_for_0 && !last_was_wait) {
debug_msg("Generated wait-for-0 for %s:%d",
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt));
vhdl_seq_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR0);
ostringstream ss;
ss << "Read target of blocking assignment ("
<< ivl_stmt_file(stmt)
<< ":" << ivl_stmt_lineno(stmt) << ")";
wait->set_comment(ss.str());
container->add_stmt(wait);
proc->added_wait_stmt();
}
}
// Generate an assignment of type T for the Verilog statement stmt.
// If a statement was generated then `assign_type' will contain the
// type of assignment that was generated; this should be initialised
// to some sensible default.
void make_assignment(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool emul_blocking,
ivl_statement_t stmt, bool blocking,
vhdl_decl::assign_type_t& assign_type)
{
list<vhdl_var_ref*> lvals;
@ -426,23 +286,14 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
if (rhs == NULL)
return;
emit_wait_for_0(proc, container, stmt, rhs);
if (rhs2)
emit_wait_for_0(proc, container, stmt, rhs2);
if (lvals.size() == 1) {
vhdl_var_ref *lhs = lvals.front();
rhs = rhs->cast(lhs->get_type());
ivl_expr_t i_delay;
vhdl_expr *after = NULL;
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) {
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
if (after == NULL)
return;
emit_wait_for_0(proc, container, stmt, after);
}
// Find the declaration of the LHS so we know what type
// of assignment statement to generate (is it a signal,
@ -450,9 +301,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
assign_type = decl->assignment_type();
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
proc->add_blocking_target(lhs);
// A small optimisation is to expand ternary RHSs into an
// if statement (eliminates a function call and produces
// more idiomatic code)
@ -465,8 +313,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
if (NULL == test)
return;
emit_wait_for_0(proc, container, stmt, test);
if (!check_valid_assignment(decl->assignment_type(), proc, stmt))
return;
@ -522,7 +368,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
decl->set_initial(NULL); // Default initial value
else {
decl->set_initial(rhs);
proc->get_scope()->hoisted_initialiser(true);
delete lhs;
return;
}
@ -563,13 +408,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
ivl_expr_t i_delay;
vhdl_expr *after = NULL;
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) {
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
if (after == NULL)
return;
emit_wait_for_0(proc, container, stmt, after);
}
// Find the declaration of the LHS so we know what type
// of assignment statement to generate (is it a signal,
@ -588,11 +428,10 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
container->add_stmt(a);
width_so_far += lval_width;
}
}
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
proc->add_blocking_target(*it);
}
}
return;
}
/*
@ -615,9 +454,25 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK;
bool emulate_blocking = proc->get_scope()->allow_signal_assignment();
if (proc->get_scope()->allow_signal_assignment()) {
// Blocking assignment is implemented as non-blocking assignment
// followed by a zero-time wait
// This follows the Verilog semantics fairly closely.
make_assignment(proc, container, stmt, emulate_blocking, assign_type);
make_assignment(proc, container, stmt, false, assign_type);
// Don't generate a zero-wait if either:
// a) this is the last statement in the process
// c) a blocking assignment was generated
if (!is_last && assign_type == vhdl_decl::ASSIGN_NONBLOCK) {
prune_wait_for_0(container);
container->add_stmt
(new vhdl_wait_stmt(VHDL_WAIT_FOR0));
proc->added_wait_stmt();
}
}
else
make_assignment(proc, container, stmt, true, assign_type);
return 0;
}
@ -647,6 +502,8 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
return 1;
}
prune_wait_for_0(container);
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
vhdl_wait_stmt *wait =
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
@ -886,14 +743,11 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
// If this container is the top-level statement (i.e. it is the
// first thing inside a process) then we can extract these
// events out into the sensitivity list as long as we haven't
// promoted any preceding assignments to initialisers
bool is_top_level =
container == proc->get_container()
&& container->empty()
&& !proc->get_scope()->hoisted_initialiser();
// events out into the sensitivity list
bool is_top_level = container == proc->get_container()
&& container->empty();
// See if this can be implemented in a more idomatic way before we
// See if this can be implemented in a more idiomatic way before we
// fall back on the generic translation
if (is_top_level && draw_synthesisable_wait(proc, container, stmt))
return 0;
@ -1022,10 +876,7 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
if (NULL == test)
return 1;
emit_wait_for_0(proc, container, stmt, test);
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
container->add_stmt(vhdif);
ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt);
if (cond_true_stmt)
@ -1035,6 +886,8 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
if (cond_false_stmt)
draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last);
container->add_stmt(vhdif);
return 0;
}
@ -1550,13 +1403,9 @@ int draw_while(vhdl_procedural *proc, stmt_container *container,
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
test = test->cast(&boolean);
emit_wait_for_0(proc, container, stmt, test);
vhdl_while_stmt *loop = new vhdl_while_stmt(test);
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
emit_wait_for_0(proc, loop->get_container(), stmt, test);
container->add_stmt(loop);
return 0;
}

View File

@ -81,21 +81,10 @@ void vhdl_element::emit_comment(std::ostream &of, int level,
{
if (comment_.size() > 0) {
if (end_of_line)
of << " ";
of << "-- " << comment_;
else {
// Comment may contain embedded newlines
of << "-- ";
for (string::const_iterator it = comment_.begin();
it != comment_.end(); ++it) {
if (*it == '\n') {
if (!end_of_line)
newline(of, level);
of << "-- ";
}
else
of << *it;
}
newline(of, level);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* VHDL abstract syntax elements.
*
* Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk)
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -31,8 +31,7 @@
using namespace std;
vhdl_scope::vhdl_scope()
: parent_(NULL), init_(false), sig_assign_(true),
hoisted_init_(false)
: parent_(NULL), init_(false), sig_assign_(true)
{
}
@ -101,16 +100,6 @@ vhdl_scope *vhdl_scope::get_parent() const
return parent_;
}
bool vhdl_scope::hoisted_initialiser() const
{
return hoisted_init_;
}
void vhdl_scope::hoisted_initialiser(bool h)
{
hoisted_init_ = h;
}
vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__)
: depth(depth__), name_(name), arch_(arch),
time_unit_(TIME_UNIT_NS)
@ -135,6 +124,7 @@ void vhdl_entity::emit(std::ostream &of, int level) const
of << "library ieee;" << std::endl;
of << "use ieee.std_logic_1164.all;" << std::endl;
of << "use ieee.numeric_std.all;" << std::endl;
of << "use std.textio.all;" << std::endl;
of << std::endl;
emit_comment(of, level);
@ -203,16 +193,6 @@ void vhdl_arch::emit(std::ostream &of, int level) const
blank_line(of, level); // Extra blank line after architectures;
}
void vhdl_procedural::add_blocking_target(vhdl_var_ref* ref)
{
blocking_targets_.insert(ref->get_name());
}
bool vhdl_procedural::is_blocking_target(vhdl_var_ref* ref) const
{
return blocking_targets_.find(ref->get_name()) != blocking_targets_.end();
}
void vhdl_process::add_sensitivity(const std::string &name)
{
sens_.push_back(name);
@ -419,7 +399,6 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const
}
of << ";";
emit_comment(of, level, true);
}
vhdl_decl::~vhdl_decl()
@ -619,7 +598,11 @@ void vhdl_var_ref::emit(std::ostream &of, int level) const
void vhdl_const_string::emit(std::ostream &of, int level) const
{
of << "\"" << value_ << "\"";
// In some instances a string literal can be ambiguous between
// a String type and some other types (e.g. std_logic_vector)
// The explicit cast to String removes this ambiguity (although
// isn't always strictly necessary)
of << "String'(\"" << value_ << "\")";
}
void vhdl_null_stmt::emit(std::ostream &of, int level) const
@ -647,7 +630,7 @@ vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt()
void vhdl_abstract_assign_stmt::find_vars(vhdl_var_set_t& read,
vhdl_var_set_t& write)
{
lhs_->find_vars(write);
write.insert(lhs_);
rhs_->find_vars(read);
}
@ -783,42 +766,10 @@ void vhdl_cassign_stmt::emit(std::ostream &of, int level) const
of << ";";
}
vhdl_report_stmt::vhdl_report_stmt(vhdl_expr *text,
vhdl_severity_t severity)
: severity_(severity),
text_(text)
{
}
void vhdl_report_stmt::emit(ostream& of, int level) const
{
of << "report ";
text_->emit(of, level);
if (severity_ != SEVERITY_NOTE) {
const char *levels[] = { "note", "warning", "error", "failure" };
of << " severity " << levels[severity_];
}
of << ";";
}
void vhdl_report_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write)
{
text_->find_vars(read);
}
vhdl_assert_stmt::vhdl_assert_stmt(const char *reason)
: vhdl_report_stmt(new vhdl_const_string(reason), SEVERITY_FAILURE)
{
}
void vhdl_assert_stmt::emit(std::ostream &of, int level) const
{
of << "assert false"; // TODO: Allow arbitrary expression
vhdl_report_stmt::emit(of, level);
of << " report \"" << reason_ << "\" severity failure;";
}
vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test)

View File

@ -52,8 +52,7 @@ public:
virtual vhdl_expr *to_std_logic();
virtual vhdl_expr *to_std_ulogic();
virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w);
virtual vhdl_expr *to_string();
virtual void find_vars(vhdl_var_set_t& read) {}
virtual void find_vars(vhdl_var_set_t& read) const {}
protected:
static void open_parens(ostream& of);
@ -177,7 +176,7 @@ private:
class vhdl_const_string : public vhdl_expr {
public:
vhdl_const_string(const string& value)
vhdl_const_string(const char *value)
: vhdl_expr(vhdl_type::string(), true), value_(value) {}
void emit(std::ostream &of, int level) const;
@ -271,7 +270,7 @@ private:
*/
class vhdl_fcall : public vhdl_expr {
public:
vhdl_fcall(const string& name, vhdl_type *rtype)
vhdl_fcall(const char *name, vhdl_type *rtype)
: vhdl_expr(rtype), name_(name) {};
~vhdl_fcall() {}
@ -454,32 +453,15 @@ public:
};
enum vhdl_severity_t {
SEVERITY_NOTE,
SEVERITY_WARNING,
SEVERITY_ERROR,
SEVERITY_FAILURE
};
class vhdl_report_stmt : public vhdl_seq_stmt {
class vhdl_assert_stmt : public vhdl_seq_stmt {
public:
vhdl_report_stmt(vhdl_expr *text,
vhdl_severity_t severity = SEVERITY_NOTE);
virtual ~vhdl_report_stmt() {}
vhdl_assert_stmt(const char *reason)
: reason_(reason) {}
virtual void emit(ostream& of, int level) const;
void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write);
void emit(std::ostream &of, int level) const;
void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write) {}
private:
vhdl_severity_t severity_;
vhdl_expr *text_;
};
class vhdl_assert_stmt : public vhdl_report_stmt {
public:
vhdl_assert_stmt(const char *reason);
void emit(ostream &of, int level) const;
std::string reason_;
};
@ -622,7 +604,7 @@ public:
enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK, ASSIGN_CONST };
// Get the sort of assignment statement to generate for
// assignemnts to this declaration
// assignments to this declaration
// For some sorts of declarations it doesn't make sense
// to assign to it so calling assignment_type just raises
// an assertion failure
@ -788,8 +770,6 @@ public:
bool initializing() const { return init_; }
void set_initializing(bool i);
bool hoisted_initialiser() const;
void hoisted_initialiser(bool h);
void set_allow_signal_assignment(bool b) { sig_assign_ = b; }
bool allow_signal_assignment() const { return sig_assign_; }
@ -797,7 +777,6 @@ private:
decl_list_t decls_;
vhdl_scope *parent_;
bool init_, sig_assign_;
bool hoisted_init_;
};
@ -816,24 +795,15 @@ public:
void added_wait_stmt() { contains_wait_stmt_ = true; }
bool contains_wait_stmt() const { return contains_wait_stmt_; }
// Managing set of blocking assignment targets in this block
void add_blocking_target(vhdl_var_ref* ref);
bool is_blocking_target(vhdl_var_ref* ref) const;
protected:
stmt_container stmts_;
vhdl_scope scope_;
// If this is true then the body contains a `wait' statement
// embedded in it somewhere
// If this is the case then we can't use a sensitvity list for
// If this is the case then we can't use a sensitivity list for
// the process
bool contains_wait_stmt_;
// The set of variable we have performed a blocking
// assignment to
set<string> blocking_targets_;
};

View File

@ -1,4 +1,3 @@
// -*- mode: c++ -*-
#ifndef INC_VHDL_TARGET_H
#define INC_VHDL_TARGET_H
@ -30,7 +29,9 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex);
string make_safe_name(ivl_signal_t sig);
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool newline = true);
void prune_wait_for_0(stmt_container *container);
void require_support_function(support_function_t f);
#endif /* #ifndef INC_VHDL_TARGET_H */

View File

@ -105,12 +105,13 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz)
{
int idx, level;
unsigned idx, level;
unsigned width = ivl_lpm_width(net);
unsigned swidth = ivl_lpm_selects(net);
char*select_input;
assert(ivl_lpm_size(net) == (1 << swidth));
assert(swidth < sizeof(unsigned));
assert(ivl_lpm_size(net) == (1U << swidth));
select_input = strdup(draw_net_input(ivl_lpm_select(net)));

View File

@ -94,7 +94,8 @@ static char* draw_C4_to_string(ivl_net_const_t cptr)
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
char bitchar = bits[ivl_const_width(cptr)-idx-1];
*dp++ = bitchar;
assert((dp - result) < result_len);
assert(dp >= result);
assert((unsigned)(dp - result) < result_len);
}
strcpy(dp, ">");
@ -144,7 +145,8 @@ static char* draw_C8_to_string(ivl_net_const_t cptr,
assert(0);
break;
}
assert(dp - result < nresult);
assert(dp >= result);
assert((unsigned)(dp - result) < nresult);
}
strcpy(dp, ">");
@ -260,7 +262,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
assert(dp >= result);
assert((unsigned)(dp - result) <= result_len);
return result;
} else {
char val[4];
@ -279,7 +282,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
assert(dp >= result);
assert((unsigned)(dp - result) <= result_len);
return result;
}
}
@ -297,7 +301,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
assert(dp >= result);
assert((unsigned)(dp - result) <= result_len);
} else {
char val[4];
@ -316,7 +321,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
assert(dp >= result);
assert((unsigned)(dp - result) <= result_len);
}
@ -705,7 +711,7 @@ static void draw_net_input_x(ivl_nexus_t nex,
if (res == IVL_SIT_UWIRE) {
if (ndrivers > 1) {
unsigned uidx;
ivl_signal_t usig;
ivl_signal_t usig = 0;
/* Find the uwire signal. */
for (uidx = 0 ; uidx < ivl_nexus_ptrs(nex) ; uidx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, uidx);

View File

@ -156,7 +156,7 @@ int draw_ufunc_real(ivl_expr_t expr)
ivl_scope_t def = ivl_expr_def(expr);
ivl_signal_t retval = ivl_scope_port(def, 0);
int res = 0;
int idx;
unsigned idx;
/* If this is an automatic function, allocate the local storage. */
if (ivl_scope_is_auto(def)) {

View File

@ -282,7 +282,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
for (bit = wid ; bit > 0 ; bit -= 1)
*dp++ = bits[bit-1];
*dp++ = 0;
assert(dp - buffer <= sizeof buffer);
assert(dp >= buffer);
assert((unsigned)(dp - buffer) <= sizeof buffer);
}
args[idx].text = strdup(buffer);
continue;

View File

@ -929,9 +929,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
case 'G':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
long imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
rv.base, imm, rv.wid);
} else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
@ -945,9 +945,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
case 'L':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
long imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
lv.base, imm, lv.wid);
} else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
@ -961,9 +961,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
case '<':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
long imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
lv.base, imm, lv.wid);
} else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
@ -976,9 +976,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
case '>':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
long imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
rv.base, imm, rv.wid);
} else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
@ -1942,7 +1942,7 @@ static struct vector_info draw_number_expr(ivl_expr_t expr, unsigned wid)
/*
* This little helper function generates the instructions to pad a
* vector in place. It is assumed that the calling function has set up
* the first sub_sidth bits of the dest vector, and the signed_flag is
* the first sub_width bits of the dest vector, and the signed_flag is
* true if the extension is to be signed.
*/
static void pad_in_place(struct vector_info dest, unsigned sub_width, int signed_flag)
@ -2609,7 +2609,7 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr,
fprintf(vvp_out, " %%mov %u, %u, %u; Pad sub-expression to match width\n",
res.base, subv.base, subv.wid);
if (ivl_expr_signed(sube)) {
int idx;
unsigned idx;
for (idx = subv.wid ; idx < res.wid ; idx += 1) {
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
res.base+idx, subv.base+subv.wid-1);

View File

@ -166,7 +166,7 @@ static int draw_number_real(ivl_expr_t expr)
/* If this is a negative number, then arrange for the 2's
complement to be calculated as we scan through the
value. Real values are sign-magnitude, and this negation
gets us a magnitide. */
gets us a magnitude. */
int negate = 0;
int carry = 0;

View File

@ -28,7 +28,7 @@
static ivl_signal_t find_path_source_port(ivl_delaypath_t path)
{
int idx;
unsigned idx;
ivl_nexus_t nex = ivl_path_source(path);
ivl_scope_t path_scope = ivl_path_scope(path);

View File

@ -260,9 +260,43 @@ const char*drive_string(ivl_drive_t drive)
* on. The last net is selected as the output of the nexus.
*/
/*
* When checking if we can elide a buffer we need to keep the buffer
* if both the input and output for the buffer are connected only
* to netlist signals. This routine performs this check on the
* given nexus.
*/
static unsigned is_netlist_signal(ivl_net_logic_t net, ivl_nexus_t nex)
{
unsigned idx, rtn;
/* Assume that this is a netlist signal. */
rtn = 1;
for (idx = 0; idx < ivl_nexus_ptrs(nex); idx += 1) {
ivl_nexus_ptr_t nptr;
ivl_signal_t sptr;
nptr = ivl_nexus_ptr(nex, idx);
/* Skip a pointer to the buffer we're checking. */
if (ivl_nexus_ptr_log(nptr) == net) continue;
/* Check to see if this is a netlist signal. */
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && !ivl_signal_local(sptr)) continue;
/* If we get here then this is not just a netlist signal. */
rtn = 0;
break;
}
return rtn;
}
/*
* This tests a bufz device against an output receiver, and determines
* if the device can be skipped. If this function returns true, then a
* if the device can be skipped. If this function returns false, then a
* gate will be generated for this node. Otherwise, the code generator
* will connect its input to its output and skip the gate.
*/
@ -311,6 +345,14 @@ int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
if (drive_count != 1)
return 0;
/* If both the input and output are netlist signal then we cannot
elide a BUFZ since it represents a continuous assignment. */
if (is_netlist_signal(net, ivl_logic_pin(net, 0)) &&
is_netlist_signal(net, ivl_logic_pin(net, 1)) &&
(ivl_logic_type(net) == IVL_LO_BUFZ)) {
return 0;
}
return 1;
}
@ -887,14 +929,15 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
/* Get all the input label that I will use for parameters to
the functor that I create later. */
ninp = ivl_logic_pins(lptr) - 1;
assert(ninp >= 0);
input_strings = calloc(ninp, sizeof(char*));
for (pdx = 0 ; pdx < ninp ; pdx += 1)
for (pdx = 0 ; pdx < (unsigned)ninp ; pdx += 1)
input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));
level = 0;
while (ninp) {
int inst;
for (inst = 0; inst < ninp; inst += 4) {
unsigned inst;
for (inst = 0; inst < (unsigned)ninp; inst += 4) {
if (ninp > 4)
fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
lptr, level, inst, lcasc, vector_width);
@ -907,7 +950,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
fprintf(vvp_out, " [%u %u]", str0, str1);
}
for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) {
for (pdx = inst; pdx < (unsigned)ninp && pdx < inst+4 ; pdx += 1) {
if (level) {
fprintf(vvp_out, ", L_%p/%d/%d",
lptr, level - 1, pdx*4);

View File

@ -42,6 +42,10 @@
#define FST_MACOSX
#endif
#if defined(__CYGWIN__) && defined(__GNUC__)
#define FST_USE_FWRITE_COMBINING
#endif
/***********************/
/*** ***/
@ -375,7 +379,7 @@ return(rc);
static int fstWriterVarint(FILE *handle, uint64_t v)
{
uint64_t nxt;
unsigned char buf[32];
unsigned char buf[10]; /* ceil(64/7) = 10 */
unsigned char *pnt = buf;
int len;
@ -391,6 +395,50 @@ fstFwrite(buf, len, 1, handle);
return(len);
}
#ifndef FST_USE_FWRITE_COMBINING
static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v)
{
uint64_t nxt;
unsigned char buf[10 + sizeof(uint32_t)];
unsigned char *pnt = buf + sizeof(uint32_t);
int len;
memcpy(buf, u, sizeof(uint32_t));
while((nxt = v>>7))
{
*(pnt++) = (v&0x7f) | 0x80;
v = nxt;
}
*(pnt++) = (v&0x7f);
len = pnt-buf;
fstFwrite(buf, len, 1, handle);
return(len);
}
#else
static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v, const void *dbuf, size_t siz)
{
uint64_t nxt;
unsigned char buf[10 + sizeof(uint32_t) + siz]; /* gcc extension ok for cygwin */
unsigned char *pnt = buf + sizeof(uint32_t);
int len;
memcpy(buf, u, sizeof(uint32_t));
while((nxt = v>>7))
{
*(pnt++) = (v&0x7f) | 0x80;
v = nxt;
}
*(pnt++) = (v&0x7f);
memcpy(pnt, dbuf, siz);
len = pnt-buf + siz;
fstFwrite(buf, len, 1, handle);
return(len);
}
#endif
/***********************/
/*** ***/
@ -1555,7 +1603,6 @@ size_t len;
if((xc) && (handle <= xc->maxhandle))
{
uint32_t prev_chg;
uint32_t fpos;
uint32_t *vm4ip;
@ -1573,14 +1620,15 @@ if((xc) && (handle <= xc->maxhandle))
if(!xc->is_initial_time)
{
prev_chg = vm4ip[2];
fpos = xc->vchn_siz;
fstFwrite(&prev_chg, 1, sizeof(uint32_t), xc->vchn_handle);
xc->vchn_siz += 4;
xc->vchn_siz += fstWriterVarint(xc->vchn_handle, xc->tchn_idx - vm4ip[3]);
/* cygwin runs faster if these writes are combined, so the new fstWriterUint32WithVarint function, but should help with regular */
#ifndef FST_USE_FWRITE_COMBINING
xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3]); /* prev_chg is vm4ip[2] */
fstFwrite(buf, len, 1, xc->vchn_handle);
xc->vchn_siz += len;
#else
xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
#endif
vm4ip[3] = xc->tchn_idx;
vm4ip[2] = fpos;
}

View File

@ -265,7 +265,8 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
unsigned int ini_size = 512; /* The initial size of the buffer. */
/* Make sure the width fits in the initial buffer. */
if (width+1 > ini_size) ini_size = width + 1;
assert(width >= -1);
if ((unsigned int)(width+1) > ini_size) ini_size = width + 1;
/* The default return value is the full format. */
result = malloc(ini_size*sizeof(char));

View File

@ -545,7 +545,7 @@ static unsigned fread_word(FILE *fp, vpiHandle word,
* my local vector. */
val.format = vpiVectorVal;
vpi_get_value(word, &val);
for (bidx = 0; bidx < words; bidx += 1) {
for (bidx = 0; (unsigned)bidx < words; bidx += 1) {
vector[bidx].aval = val.value.vector[bidx].aval;
vector[bidx].bval = val.value.vector[bidx].bval;
}
@ -682,10 +682,11 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name)
vector = calloc(words, sizeof(s_vpi_vecval));
bpe = (width+7)/8;
assert(count >= 0);
if (is_mem) {
unsigned idx;
rtn = 0;
for (idx = 0; idx < count; idx += 1) {
for (idx = 0; idx < (unsigned)count; idx += 1) {
vpiHandle word;
word = vpi_handle_by_index(mem_reg, start+(signed)idx);
rtn += fread_word(fp, word, words, bpe, vector);

View File

@ -71,7 +71,8 @@ void sdf_select_instance(const char*celltype, const char*cellinst)
const char*src = cellinst;
const char*dp;
while ( (dp=strchr(src, '.')) ) {
int len = dp - src;
unsigned len = dp - src;
assert(dp >= src);
assert(len < sizeof buffer);
strncpy(buffer, src, len);
buffer[len] = 0;

View File

@ -59,7 +59,7 @@ all: dep vvp@EXEEXT@ libvpi.a vvp.man
clean:
rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc
rm -rf dep vvp@EXEEXT@ libvpi.a parse.output vvp.man vvp.pdf vvp.exp
rm -rf dep vvp@EXEEXT@ libvpi.a parse.output vvp.man vvp.ps vvp.pdf vvp.exp
distclean: clean
rm -f Makefile config.log
@ -152,8 +152,11 @@ vvp.man: $(srcdir)/vvp.man.in ../version.exe
../version.exe `head -1 $(srcdir)/vvp.man.in`'\n' > $@
tail -n +2 $(srcdir)/vvp.man.in >> $@
vvp.pdf: vvp.man
$(MAN) -t $(srcdir)/vvp.man | $(PS2PDF) - vvp.pdf
vvp.ps: vvp.man
$(MAN) -t ./vvp.man > vvp.ps
vvp.pdf: vvp.ps
$(PS2PDF) vvp.ps vvp.pdf
ifeq (@MINGW32@,yes)
ifeq ($(MAN),none)

View File

@ -1503,7 +1503,6 @@ void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj)
void vpip_array_change(struct __vpiCallback*cb, vpiHandle obj)
{
struct __vpiArray*arr = ARRAY_HANDLE(obj);
cb->extra_data = -1; // This is a callback for every element.
cb->next = arr->vpi_callbacks;

View File

@ -30,7 +30,7 @@
*
* port-0: D input
* port-1: Clock input
* port-2: Clock Enagle input
* port-2: Clock Enable input
* port-3: Asynchronous D input.
*/
class vvp_dff : public vvp_net_fun_t {

View File

@ -373,7 +373,7 @@ register to read the repetition count from (signed or unsigned).
%evctl/i sets the repetition to an immediate unsigned value.
%evctl/c clears the event control information. This is needed if a
%assign/e may be skiped since the %assign/e statements clear the
%assign/e may be skipped since the %assign/e statements clear the
event control information and the other %evctl statements assert
that this information has been cleared. You can get an assert if
this information is not managed correctly.

View File

@ -972,7 +972,7 @@ bool of_ASSIGN_V0(vthread_t thr, vvp_code_t cp)
vvp_net_ptr_t ptr (cp->net, 0);
if (bit >= 4) {
// If the vector is not a synthetic one, then have the
// scheduler pluck it direcly out of my vector space.
// scheduler pluck it directly out of my vector space.
schedule_assign_plucked_vector(ptr, delay, thr->bits4, bit, wid);
} else {
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
@ -2078,7 +2078,7 @@ static unsigned long* divide_bits(unsigned long*ap, unsigned long*bp, unsigned w
ap[cur_ptr+btop+1]);
}
// cur_res is a guestimate of the result this far. It
// cur_res is a guesstimate of the result this far. It
// may be 1 too big. (But it will also be >0) Try it,
// and if the difference comes out negative, then adjust.

View File

@ -291,7 +291,7 @@ vvp_island* compile_find_island(const char*island)
*
* The <src> is a label in the domain outside the island, and the
* <label> is in the domain inside the island. Since this port is
* bi-directional, the <label> is also avaliable in the domain outside
* bi-directional, the <label> is also available in the domain outside
* the island. The outside should use the <label> to access the nexus
* that this port represents, because the island will resolve internal
* drivers with the external driver and make the output available on

View File

@ -1212,7 +1212,7 @@ void vvp_vector4_t::mov(unsigned dst, unsigned src, unsigned cnt)
// Here we know that either the source or
// destination is unaligned, and also we know that
// the count is less then a full word.
// the count is less than a full word.
unsigned long vmask = (1UL << trans) - 1;
unsigned long tmp;

View File

@ -65,7 +65,6 @@ typedef void*vvp_context_item_t;
inline vvp_context_t vvp_allocate_context(unsigned nitem)
{
return (vvp_context_t)malloc((2 + nitem) * sizeof(void*));
}
@ -915,7 +914,7 @@ inline bool vvp_vector8_t::eeq(const vvp_vector8_t&that) const
return true;
if (size_ <= sizeof val_)
// This is equivilent to memcmp(val_, that.val_, sizeof val_)==0
// This is equivalent to memcmp(val_, that.val_, sizeof val_)==0
return ptr_ == that.ptr_;
else
return memcmp(ptr_, that.ptr_, size_) == 0;
@ -1164,7 +1163,7 @@ class vvp_net_fil_t : public vvp_vpi_callback {
// bit value. If bits were changed by the force mask, then the
// method returns REPL and the caller should propagate the rep
// value instead. If the function returns STOP, then all the
// output bits are filtered by the force mask ans there is
// output bits are filtered by the force mask and there is
// nothing to propagate.
virtual prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,
unsigned base, unsigned vwid);
@ -1185,7 +1184,7 @@ class vvp_net_fil_t : public vvp_vpi_callback {
virtual unsigned filter_size() const =0;
public:
// Suport for force methods. These are calloed by the
// Support for force methods. These are called by the
// vvp_net_t::force_* methods to set the force value and mask
// for the filter.
virtual void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) =0;
@ -1228,7 +1227,7 @@ class vvp_net_fil_t : public vvp_vpi_callback {
// These templates are similar to filter_mask_, but are
// idempotent. Then do not trigger callbacks or otherwise
// cause any locak changes. These methods are used to test
// cause any local changes. These methods are used to test
// arbitrary values against the force mask.
template <class T> prop_t filter_input_mask_(const T&val, const T&force, T&rep) const;

View File

@ -91,7 +91,7 @@ class vvp_fun_signal_base : public vvp_net_fun_t {
/*
* Variables and wires can have their values accessed, so this base
* class offers the unified concept of an acessible value.
* class offers the unified concept of an accessible value.
*/
class vvp_signal_value {
public:
@ -280,7 +280,7 @@ class vvp_wire_vec4 : public vvp_wire_base {
vvp_wire_vec4(unsigned wid, vvp_bit4_t init);
// The main filter behavior for this class. These methods take
// the value that the node is driven to, and applies the firce
// the value that the node is driven to, and applies the force
// filters. In wires, this also saves the driven value, so
// that when a force is released, we can revert to the driven value.
prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,