Revert bad merge from vhdl branch
This commit is contained in:
parent
7f2cb6afcd
commit
ec49f10e2d
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
58
elab_expr.cc
58
elab_expr.cc
|
|
@ -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);
|
||||
|
|
|
|||
27
elab_lval.cc
27
elab_lval.cc
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
26
eval_tree.cc
26
eval_tree.cc
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
16
net_expr.cc
16
net_expr.cc
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
161
netmisc.cc
161
netmisc.cc
|
|
@ -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) {
|
||||
|
|
|
|||
26
netmisc.h
26
netmisc.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
16
nodangle.cc
16
nodangle.cc
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
4
pform.cc
4
pform.cc
|
|
@ -65,7 +65,7 @@ void parm_to_defparam_list(const string¶m)
|
|||
|
||||
// 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¶m)
|
|||
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'))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
265
tgt-vhdl/stmt.cc
265
tgt-vhdl/stmt.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,21 +81,10 @@ void vhdl_element::emit_comment(std::ostream &of, int level,
|
|||
{
|
||||
if (comment_.size() > 0) {
|
||||
if (end_of_line)
|
||||
of << " -- " << comment_;
|
||||
else {
|
||||
// Comment may contain embedded newlines
|
||||
of << "-- ";
|
||||
for (string::const_iterator it = comment_.begin();
|
||||
it != comment_.end(); ++it) {
|
||||
if (*it == '\n') {
|
||||
of << " ";
|
||||
of << "-- " << comment_;
|
||||
if (!end_of_line)
|
||||
newline(of, level);
|
||||
of << "-- ";
|
||||
}
|
||||
else
|
||||
of << *it;
|
||||
}
|
||||
newline(of, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 << "assert false"; // TODO: Allow arbitrary expression
|
||||
of << " report \"" << reason_ << "\" severity failure;";
|
||||
}
|
||||
|
||||
vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test)
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
62
vpi/fstapi.c
62
vpi/fstapi.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue