Merge branch 'master' of ssh://steve-icarus@icarus.com/home/u/icarus/steve/git/verilog
This commit is contained in:
commit
110bc2e6eb
16
PGenerate.h
16
PGenerate.h
|
|
@ -37,7 +37,17 @@ class PGate;
|
|||
class PWire;
|
||||
|
||||
/*
|
||||
* This represents a generate scheme.
|
||||
* This represents a generate scheme. The interpretation of the
|
||||
* members depends on the scheme_type.
|
||||
*
|
||||
* GS_LOOP
|
||||
*
|
||||
* GS_CASE
|
||||
* loop_test is the expression to be compared.
|
||||
* generates contains only GS_CASE_ITEM schemes.
|
||||
* GS_CASE_ITEM
|
||||
* The parent points to the GS_CASE that contains this item.
|
||||
* the loop_test is compared with the parent->loop_test expression.
|
||||
*/
|
||||
class PGenerate : public LineInfo {
|
||||
|
||||
|
|
@ -50,7 +60,8 @@ class PGenerate : public LineInfo {
|
|||
const unsigned id_number;
|
||||
perm_string scope_name;
|
||||
|
||||
enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE};
|
||||
enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE,
|
||||
GS_CASE, GS_CASE_ITEM};
|
||||
scheme_t scheme_type;
|
||||
|
||||
// generate loops have an index variable and three
|
||||
|
|
@ -88,6 +99,7 @@ class PGenerate : public LineInfo {
|
|||
private:
|
||||
bool generate_scope_loop_(Design*des, NetScope*container);
|
||||
bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag);
|
||||
bool generate_scope_case_(Design*des, NetScope*container);
|
||||
|
||||
// Elaborate_scope within a generated scope.
|
||||
void elaborate_subscope_(Design*des, NetScope*scope);
|
||||
|
|
|
|||
|
|
@ -348,7 +348,14 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
|
|||
o << setw(ind) << "" << "constant " << width_ << "'b";
|
||||
for (unsigned idx = width_ ; idx > 0 ; idx -= 1)
|
||||
o << value_[idx-1];
|
||||
o << ": " << name() << endl;
|
||||
o << ": " << name();
|
||||
if (rise_time())
|
||||
o << " #(" << *rise_time()
|
||||
<< "," << *fall_time()
|
||||
<< "," << *decay_time() << ")";
|
||||
else
|
||||
o << " #(.,.,.)";
|
||||
o << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
|
|
@ -465,9 +472,14 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
|
|||
break;
|
||||
}
|
||||
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
|
||||
<< name() << " #(" << rise_time()
|
||||
<< "," << fall_time() << "," << decay_time() << ") "
|
||||
<< " off=" << off_ << " wid=" << wid_ <<endl;
|
||||
<< name();
|
||||
if (rise_time())
|
||||
o << " #(" << *rise_time()
|
||||
<< "," << *fall_time()
|
||||
<< "," << *decay_time() << ")";
|
||||
else
|
||||
o << " #(.,.,.)";
|
||||
o << " off=" << off_ << " wid=" << wid_ <<endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
|
@ -535,9 +547,11 @@ void NetSysFunc::dump_node(ostream&o, unsigned ind) const
|
|||
void NetUserFunc::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "USER FUNC: "
|
||||
<< scope_path(def_)
|
||||
<< " #(" <<*rise_time()<<","<<*fall_time() << "," <<*decay_time() << ")"
|
||||
<< endl;
|
||||
<< scope_path(def_);
|
||||
if (rise_time())
|
||||
o << " #(" <<*rise_time()
|
||||
<<","<<*fall_time()
|
||||
<< "," <<*decay_time() << ")" << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: cfparse_misc.h,v 1.6 2004/02/15 18:03:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The vlltype supports the passing of detailed source file location
|
||||
|
|
|
|||
12
elab_net.cc
12
elab_net.cc
|
|
@ -1142,14 +1142,6 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
|
|||
// The power is signed if either its operands are signed.
|
||||
bool arith_is_signed = lsig->get_signed() || rsig->get_signed();
|
||||
|
||||
/* For now we only support real values. */
|
||||
if (lsig->data_type() != IVL_VT_REAL && arith_is_signed) {
|
||||
cerr << get_fileline() << ": sorry: Signed bit based power (**) is "
|
||||
<< "currently unsupported in continuous assignments." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned rwidth = lwidth;
|
||||
if (rwidth == 0) {
|
||||
/* Reals are always 1 wide and lsig/rsig types match here. */
|
||||
|
|
@ -1157,7 +1149,9 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
|
|||
rwidth = 1;
|
||||
lwidth = 1;
|
||||
} else {
|
||||
/* Nothing for now. Need integer value.*/
|
||||
/* This is incorrect! a * (2^b - 1) is close. */
|
||||
rwidth = lsig->vector_width() + rsig->vector_width();
|
||||
lwidth = rwidth;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -315,6 +315,15 @@ bool PGenerate::generate_scope(Design*des, NetScope*container)
|
|||
case GS_ELSE:
|
||||
return generate_scope_condit_(des, container, true);
|
||||
|
||||
case GS_CASE:
|
||||
return generate_scope_case_(des, container);
|
||||
return true;
|
||||
|
||||
case GS_CASE_ITEM:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Case item outside of a case generate scheme?" << endl;
|
||||
return false;
|
||||
|
||||
default:
|
||||
cerr << get_fileline() << ": sorry: Generate of this sort"
|
||||
<< " is not supported yet!" << endl;
|
||||
|
|
@ -345,7 +354,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
genvar = init->value().as_long();
|
||||
delete init_ex;
|
||||
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
|
||||
|
||||
container->genvar_tmp = loop_index;
|
||||
|
|
@ -367,7 +376,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create generated scope " << use_name << endl;
|
||||
|
||||
|
|
@ -386,7 +395,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
genvar_verinum);
|
||||
scope->set_localparam(loop_index, gp);
|
||||
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create implicit localparam "
|
||||
<< loop_index << " = " << genvar_verinum << endl;
|
||||
|
|
@ -398,7 +407,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
|
||||
NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
|
||||
assert(step);
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: genvar step from "
|
||||
<< genvar << " to " << step->value().as_long() << endl;
|
||||
|
||||
|
|
@ -428,7 +437,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
|||
// scope.
|
||||
if ( (test->value().as_long() == 0 && !else_flag)
|
||||
|| (test->value().as_long() != 0 && else_flag) ) {
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: Generate condition "
|
||||
<< (else_flag? "(else)" : "(if)")
|
||||
<< " value=" << test->value() << ": skip generation"
|
||||
|
|
@ -445,7 +454,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
|||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
if (debug_elaborate)
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: Generate condition "
|
||||
<< (else_flag? "(else)" : "(if)")
|
||||
<< " value=" << test->value() << ": Generate scope="
|
||||
|
|
@ -459,6 +468,71 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
{
|
||||
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex);
|
||||
assert(case_value_co);
|
||||
|
||||
// The name of the scope to generate, whatever that item is.
|
||||
hname_t use_name (scope_name);
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: Generate case "
|
||||
<< "switch value=" << case_value_co->value() << endl;
|
||||
|
||||
PGenerate*default_item = 0;
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generator_it_t;
|
||||
generator_it_t cur = generates.begin();
|
||||
while (cur != generates.end()) {
|
||||
PGenerate*item = *cur;
|
||||
assert( item->scheme_type == PGenerate::GS_CASE_ITEM );
|
||||
|
||||
// Detect that the item is a default.
|
||||
if (item->loop_test == 0) {
|
||||
default_item = item;
|
||||
cur ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
NetExpr*item_value_ex = elab_and_eval(des, container, item->loop_test, -1);
|
||||
NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex);
|
||||
assert(item_value_co);
|
||||
|
||||
// If we stumble on the item that matches, then break
|
||||
// out now.
|
||||
if (case_value_co->value() == item_value_co->value()) {
|
||||
delete item_value_co;
|
||||
break;
|
||||
}
|
||||
|
||||
delete item_value_co;
|
||||
cur ++;
|
||||
}
|
||||
|
||||
delete case_value_co;
|
||||
case_value_co = 0;
|
||||
|
||||
PGenerate*item = (cur == generates.end())? default_item : *cur;
|
||||
if (item == 0) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "No generate items found" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Generate case matches item at "
|
||||
<< item->get_fileline() << endl;
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
item->elaborate_subscope_(des, scope);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
|
||||
{
|
||||
// Scan the generated scope for nested generate schemes,
|
||||
|
|
|
|||
21
elaborate.cc
21
elaborate.cc
|
|
@ -3554,6 +3554,27 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
|
|||
{
|
||||
bool flag = true;
|
||||
|
||||
// Handle the special case that this is a CASE scheme. In this
|
||||
// case the PGenerate itself does not have the generated
|
||||
// item. Look instead for the case ITEM that has a scope
|
||||
// generated for it.
|
||||
if (scheme_type == PGenerate::GS_CASE) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: generate case"
|
||||
<< " elaborating in scope "
|
||||
<< scope_path(container) << "." << endl;
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++) {
|
||||
PGenerate*item = *cur;
|
||||
if (! item->scope_list_.empty()) {
|
||||
flag &= item->elaborate(des, container);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
typedef list<NetScope*>::const_iterator scope_list_it_t;
|
||||
for (scope_list_it_t cur = scope_list_.begin()
|
||||
; cur != scope_list_.end() ; cur ++ ) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2008 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
|
||||
|
|
@ -258,7 +258,8 @@ NetEBPow::NetEBPow(char op, NetExpr*l, NetExpr*r)
|
|||
: NetEBinary(op, l, r)
|
||||
{
|
||||
assert(op == 'p');
|
||||
expr_width(l->expr_width());
|
||||
/* This is incorrect! a * (2^b - 1) is close. */
|
||||
expr_width(l->expr_width()+r->expr_width());
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
|
|
|
|||
18
parse.y
18
parse.y
|
|
@ -1920,6 +1920,12 @@ module_item
|
|||
generate_block_opt %prec less_than_K_else
|
||||
{ pform_endgenerate(); }
|
||||
|
||||
| K_case '(' expression ')'
|
||||
{ pform_start_generate_case(@1, $3); }
|
||||
generate_case_items
|
||||
K_endcase
|
||||
{ pform_endgenerate(); }
|
||||
|
||||
/* specify blocks are parsed but ignored. */
|
||||
|
||||
| K_specify K_endspecify
|
||||
|
|
@ -1984,6 +1990,18 @@ module_item
|
|||
|
||||
generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); }
|
||||
|
||||
generate_case_items
|
||||
: generate_case_items generate_case_item
|
||||
| generate_case_item
|
||||
;
|
||||
|
||||
generate_case_item
|
||||
: expression ':' { pform_generate_case_item(@1, $1); } generate_block
|
||||
{ pform_endgenerate(); }
|
||||
| K_default ':' { pform_generate_case_item(@1, 0); } generate_block
|
||||
{ pform_endgenerate(); }
|
||||
;
|
||||
|
||||
module_item_list
|
||||
: module_item_list module_item
|
||||
| module_item
|
||||
|
|
|
|||
53
pform.cc
53
pform.cc
|
|
@ -412,6 +412,51 @@ void pform_start_generate_else(const struct vlltype&li)
|
|||
pform_cur_generate->loop_step = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The GS_CASE version of the PGenerate contains only case items. The
|
||||
* items in turn contain the generated items themselves.
|
||||
*/
|
||||
void pform_start_generate_case(const struct vlltype&li, PExpr*expr)
|
||||
{
|
||||
PGenerate*gen = new PGenerate(scope_generate_counter++);
|
||||
|
||||
FILE_NAME(gen, li);
|
||||
|
||||
gen->parent = pform_cur_generate;
|
||||
pform_cur_generate = gen;
|
||||
|
||||
pform_cur_generate->scheme_type = PGenerate::GS_CASE;
|
||||
|
||||
pform_cur_generate->loop_init = 0;
|
||||
pform_cur_generate->loop_test = expr;
|
||||
pform_cur_generate->loop_step = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The generate case item is a special case schema that takes its id
|
||||
* from the case schema that it is a part of. The idea is that the
|
||||
* case schema can only instantiate exactly one item, so the items
|
||||
* need not have a unique number.
|
||||
*/
|
||||
void pform_generate_case_item(const struct vlltype&li, PExpr*expr)
|
||||
{
|
||||
assert(pform_cur_generate);
|
||||
assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE);
|
||||
|
||||
PGenerate*gen = new PGenerate(pform_cur_generate->id_number);
|
||||
|
||||
FILE_NAME(gen, li);
|
||||
|
||||
gen->parent = pform_cur_generate;
|
||||
pform_cur_generate = gen;
|
||||
|
||||
pform_cur_generate->scheme_type = PGenerate::GS_CASE_ITEM;
|
||||
|
||||
pform_cur_generate->loop_init = 0;
|
||||
pform_cur_generate->loop_test = expr;
|
||||
pform_cur_generate->loop_step = 0;
|
||||
}
|
||||
|
||||
void pform_generate_block_name(char*name)
|
||||
{
|
||||
assert(pform_cur_generate != 0);
|
||||
|
|
@ -439,10 +484,14 @@ void pform_endgenerate()
|
|||
PGenerate*cur = pform_cur_generate;
|
||||
pform_cur_generate = cur->parent;
|
||||
|
||||
if (pform_cur_generate != 0)
|
||||
if (pform_cur_generate != 0) {
|
||||
assert(cur->scheme_type == PGenerate::GS_CASE_ITEM
|
||||
|| pform_cur_generate->scheme_type != PGenerate::GS_CASE);
|
||||
pform_cur_generate->generates.push_back(cur);
|
||||
else
|
||||
} else {
|
||||
assert(cur->scheme_type != PGenerate::GS_CASE_ITEM);
|
||||
pform_cur_module->generate_schemes.push_back(cur);
|
||||
}
|
||||
}
|
||||
|
||||
bool pform_expression_is_constant(const PExpr*ex)
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -188,6 +188,8 @@ extern void pform_start_generate_for(const struct vlltype&li,
|
|||
PExpr*next);
|
||||
extern void pform_start_generate_if(const struct vlltype&li, PExpr*test);
|
||||
extern void pform_start_generate_else(const struct vlltype&li);
|
||||
extern void pform_start_generate_case(const struct vlltype&lp, PExpr*test);
|
||||
extern void pform_generate_case_item(const struct vlltype&lp, PExpr*test);
|
||||
extern void pform_generate_block_name(char*name);
|
||||
extern void pform_endgenerate();
|
||||
|
||||
|
|
|
|||
|
|
@ -854,6 +854,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const
|
|||
case GS_ELSE:
|
||||
out << " else !(" << *loop_test << ")";
|
||||
break;
|
||||
case GS_CASE:
|
||||
out << " case (" << *loop_test << ")";
|
||||
break;
|
||||
case GS_CASE_ITEM:
|
||||
if (loop_test)
|
||||
out << " (" << *loop_test << ") == (" << *parent->loop_test << ")";
|
||||
else
|
||||
out << " default:";
|
||||
break;
|
||||
}
|
||||
|
||||
if (scope_name)
|
||||
|
|
@ -882,7 +891,7 @@ void PGenerate::dump(ostream&out, unsigned indent) const
|
|||
(*idx)->dump(out, indent+2);
|
||||
}
|
||||
|
||||
out << " endgenerate" << endl;
|
||||
out << setw(indent) << "" << "endgenerate" << endl;
|
||||
}
|
||||
|
||||
void Module::dump(ostream&out) const
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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
|
||||
|
|
@ -185,8 +185,7 @@ bool NetEBMult::set_width(unsigned w, bool)
|
|||
|
||||
bool NetEBPow::set_width(unsigned w, bool last_chance)
|
||||
{
|
||||
bool flag = left_->set_width(w, last_chance);
|
||||
return flag;
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -445,4 +444,3 @@ bool NetEUReduce::set_width(unsigned w, bool)
|
|||
{
|
||||
return w == 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
1
t-dll.cc
1
t-dll.cc
|
|
@ -1777,6 +1777,7 @@ void dll_target::lpm_pow(const NetPow*net)
|
|||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_POW;
|
||||
FILE_NAME(obj, net);
|
||||
obj->name = net->name();
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
|
|
|
|||
|
|
@ -1708,9 +1708,16 @@ static void draw_lpm_add(ivl_lpm_t net)
|
|||
case IVL_LPM_POW:
|
||||
if (dto == IVL_VT_REAL)
|
||||
type = "pow.r";
|
||||
else if (ivl_lpm_signed(net))
|
||||
assert(0); /* No support for signed bit based signals. */
|
||||
else
|
||||
else if (ivl_lpm_signed(net)) {
|
||||
type = "pow.s";
|
||||
if (width > 8*sizeof(long)) {
|
||||
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
|
||||
"result must be no more than %d bits.\n",
|
||||
ivl_lpm_file(net), ivl_lpm_lineno(net),
|
||||
8*sizeof(long));
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
type = "pow";
|
||||
break;
|
||||
default:
|
||||
|
|
@ -2145,17 +2152,19 @@ static void draw_lpm_part(ivl_lpm_t net)
|
|||
unsigned width, base;
|
||||
ivl_nexus_t sel;
|
||||
|
||||
const char*dly = draw_lpm_output_delay(net);
|
||||
|
||||
width = ivl_lpm_width(net);
|
||||
base = ivl_lpm_base(net);
|
||||
sel = ivl_lpm_data(net,1);
|
||||
|
||||
if (sel == 0) {
|
||||
fprintf(vvp_out, "L_%p .part %s",
|
||||
net, draw_net_input(ivl_lpm_data(net, 0)));
|
||||
fprintf(vvp_out, "L_%p%s .part %s",
|
||||
net, dly, draw_net_input(ivl_lpm_data(net, 0)));
|
||||
fprintf(vvp_out, ", %u, %u;\n", base, width);
|
||||
} else {
|
||||
fprintf(vvp_out, "L_%p .part/v %s",
|
||||
net, draw_net_input(ivl_lpm_data(net,0)));
|
||||
fprintf(vvp_out, "L_%p%s .part/v %s",
|
||||
net, dly, draw_net_input(ivl_lpm_data(net,0)));
|
||||
fprintf(vvp_out, ", %s", draw_net_input(sel));
|
||||
fprintf(vvp_out, ", %u;\n", width);
|
||||
}
|
||||
|
|
|
|||
34
vvp/arith.cc
34
vvp/arith.cc
|
|
@ -400,8 +400,8 @@ void vvp_arith_mult::wide(vvp_ipoint_t base, bool push)
|
|||
|
||||
// Power
|
||||
|
||||
vvp_arith_pow::vvp_arith_pow(unsigned wid)
|
||||
: vvp_arith_(wid)
|
||||
vvp_arith_pow::vvp_arith_pow(unsigned wid, bool signed_flag)
|
||||
: vvp_arith_(wid), signed_flag_(signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -413,17 +413,31 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
|||
{
|
||||
dispatch_operand_(ptr, bit);
|
||||
|
||||
vvp_vector2_t a2 (op_a_);
|
||||
vvp_vector2_t b2 (op_b_);
|
||||
vvp_vector4_t res4;
|
||||
if (signed_flag_) {
|
||||
if (op_a_.has_xz() || op_b_.has_xz()) {
|
||||
vvp_send_vec4(ptr.ptr()->out, x_val_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a2.is_NaN() || b2.is_NaN()) {
|
||||
vvp_send_vec4(ptr.ptr()->out, x_val_);
|
||||
return;
|
||||
double ad, bd;
|
||||
vector4_to_value(op_a_, ad, true);
|
||||
vector4_to_value(op_b_, bd, true);
|
||||
|
||||
res4 = double_to_vector4(pow(ad, bd), wid_);
|
||||
} else {
|
||||
vvp_vector2_t a2 (op_a_);
|
||||
vvp_vector2_t b2 (op_b_);
|
||||
|
||||
if (a2.is_NaN() || b2.is_NaN()) {
|
||||
vvp_send_vec4(ptr.ptr()->out, x_val_);
|
||||
return;
|
||||
}
|
||||
|
||||
vvp_vector2_t result = pow(a2, b2);
|
||||
res4 = vector2_to_vector4(result, wid_);
|
||||
}
|
||||
|
||||
vvp_vector2_t result = pow(a2, b2);
|
||||
|
||||
vvp_vector4_t res4 = vector2_to_vector4(result, wid_);
|
||||
vvp_send_vec4(ptr.ptr()->out, res4);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,9 +162,11 @@ class vvp_arith_mult : public vvp_arith_ {
|
|||
class vvp_arith_pow : public vvp_arith_ {
|
||||
|
||||
public:
|
||||
explicit vvp_arith_pow(unsigned wid);
|
||||
explicit vvp_arith_pow(unsigned wid, bool signed_flag);
|
||||
~vvp_arith_pow();
|
||||
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
|
||||
private:
|
||||
bool signed_flag_;
|
||||
};
|
||||
|
||||
class vvp_arith_sub : public vvp_arith_ {
|
||||
|
|
|
|||
|
|
@ -921,7 +921,10 @@ void compile_arith_div(char*label, long wid, bool signed_flag,
|
|||
assert( wid > 0 );
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "%s; .arith/div has wrong number of symbols\n", label);
|
||||
char *suffix = "";
|
||||
if (signed_flag) suffix = ".s";
|
||||
fprintf(stderr, "%s; .arith/div%s has wrong number of "
|
||||
"symbols\n", label, suffix);
|
||||
compile_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
|
@ -998,18 +1001,26 @@ void compile_arith_mult_r(char*label, unsigned argc, struct symb_s*argv)
|
|||
}
|
||||
|
||||
|
||||
void compile_arith_pow(char*label, long wid,
|
||||
void compile_arith_pow(char*label, long wid, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
assert( wid > 0 );
|
||||
/* For now we need to do a double to long cast, so the number
|
||||
of bits is limited. This should be caught in the compiler. */
|
||||
if (signed_flag) {
|
||||
assert( wid <= (long)(8*sizeof(long)) );
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "%s .arith/pow has wrong number of symbols\n", label);
|
||||
char *suffix = "";
|
||||
if (signed_flag) suffix = ".s";
|
||||
fprintf(stderr, "%s .arith/pow%s has wrong number of "
|
||||
"symbols\n", label, suffix);
|
||||
compile_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
vvp_arith_ *arith = new vvp_arith_pow(wid);
|
||||
vvp_arith_ *arith = new vvp_arith_pow(wid, signed_flag);
|
||||
make_arith(arith, label, argc, argv);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ extern void compile_part_select_var(char*label, char*src,
|
|||
* This is called by the parser to make the various arithmetic and
|
||||
* comparison functors.
|
||||
*/
|
||||
extern void compile_arith_pow(char*label, long width,
|
||||
extern void compile_arith_pow(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_div(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
".arith/mult.r" { return K_ARITH_MULT_R; }
|
||||
".arith/pow" { return K_ARITH_POW; }
|
||||
".arith/pow.r" { return K_ARITH_POW_R; }
|
||||
".arith/pow.s" { return K_ARITH_POW_S; }
|
||||
".arith/sub" { return K_ARITH_SUB; }
|
||||
".arith/sub.r" { return K_ARITH_SUB_R; }
|
||||
".arith/sum" { return K_ARITH_SUM; }
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_ALIAS K_ALIAS_S K_ALIAS_R
|
||||
%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MOD_R
|
||||
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
||||
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R
|
||||
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S
|
||||
%token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT
|
||||
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
|
||||
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
|
||||
|
|
@ -288,7 +288,7 @@ statement
|
|||
|
||||
| T_LABEL K_ARITH_POW T_NUMBER ',' symbols ';'
|
||||
{ struct symbv_s obj = $5;
|
||||
compile_arith_pow($1, $3, obj.cnt, obj.vect);
|
||||
compile_arith_pow($1, $3, false, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
| T_LABEL K_ARITH_POW_R T_NUMBER ',' symbols ';'
|
||||
|
|
@ -296,6 +296,11 @@ statement
|
|||
compile_arith_pow_r($1, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
| T_LABEL K_ARITH_POW_S T_NUMBER ',' symbols ';'
|
||||
{ struct symbv_s obj = $5;
|
||||
compile_arith_pow($1, $3, true, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
| T_LABEL K_ARITH_SUB T_NUMBER ',' symbols ';'
|
||||
{ struct symbv_s obj = $5;
|
||||
compile_arith_sub($1, $3, obj.cnt, obj.vect);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ struct __vpirt {
|
|||
* "base" that is a __vpiHandle object. This template can convert any
|
||||
* of those structures into a vpiHandle object.
|
||||
*/
|
||||
template <class T> struct __vpiHandle*vpi_handle(T obj)
|
||||
template <class T> vpiHandle vpi_handle(T obj)
|
||||
{ return &obj->base; }
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -697,6 +697,32 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that)
|
|||
return out;
|
||||
}
|
||||
|
||||
/* The width is guaranteed to not be larger than a long.
|
||||
* If the double is outside the integer range (+/-) the
|
||||
* largest/smallest integer value is returned. */
|
||||
vvp_vector4_t double_to_vector4(double val, unsigned wid)
|
||||
{
|
||||
long span = 1l << (wid-1);
|
||||
double dmin = -1l * span;
|
||||
double dmax = span - 1l;
|
||||
|
||||
if (val > dmax) val = dmax;
|
||||
if (val < dmin) val = dmin;
|
||||
|
||||
vvp_vector4_t res (wid);
|
||||
long bits = lround(val);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
vvp_bit4_t bit = BIT4_0;
|
||||
|
||||
if (bits & 1L) bit = BIT4_1;
|
||||
|
||||
res.set_bit(idx, bit);
|
||||
bits >>= 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val)
|
||||
{
|
||||
unsigned long res = 0;
|
||||
|
|
|
|||
|
|
@ -258,6 +258,8 @@ extern vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
|
|||
vvp_bit4_t val_if_equal);
|
||||
template <class T> extern T coerce_to_width(const T&that, unsigned width);
|
||||
|
||||
extern vvp_vector4_t double_to_vector4(double val, unsigned wid);
|
||||
|
||||
/*
|
||||
* These functions extract the value of the vector as a native type,
|
||||
* if possible, and return true to indicate success. If the vector has
|
||||
|
|
|
|||
Loading…
Reference in New Issue