Merge branch 'master' of ssh://steve-icarus@icarus.com/home/u/icarus/steve/git/verilog

This commit is contained in:
Stephen Williams 2008-02-13 15:27:39 -08:00
commit 110bc2e6eb
23 changed files with 322 additions and 62 deletions

View File

@ -37,7 +37,17 @@ class PGate;
class PWire; 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 { class PGenerate : public LineInfo {
@ -50,7 +60,8 @@ class PGenerate : public LineInfo {
const unsigned id_number; const unsigned id_number;
perm_string scope_name; 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; scheme_t scheme_type;
// generate loops have an index variable and three // generate loops have an index variable and three
@ -88,6 +99,7 @@ class PGenerate : public LineInfo {
private: private:
bool generate_scope_loop_(Design*des, NetScope*container); bool generate_scope_loop_(Design*des, NetScope*container);
bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag); 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. // Elaborate_scope within a generated scope.
void elaborate_subscope_(Design*des, NetScope*scope); void elaborate_subscope_(Design*des, NetScope*scope);

View File

@ -348,7 +348,14 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
o << setw(ind) << "" << "constant " << width_ << "'b"; o << setw(ind) << "" << "constant " << width_ << "'b";
for (unsigned idx = width_ ; idx > 0 ; idx -= 1) for (unsigned idx = width_ ; idx > 0 ; idx -= 1)
o << value_[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); dump_node_pins(o, ind+4);
} }
@ -465,9 +472,14 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
break; break;
} }
o << setw(ind) << "" << "NetPartSelect(" << pt << "): " o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
<< name() << " #(" << rise_time() << name();
<< "," << fall_time() << "," << decay_time() << ") " if (rise_time())
<< " off=" << off_ << " wid=" << wid_ <<endl; o << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
else
o << " #(.,.,.)";
o << " off=" << off_ << " wid=" << wid_ <<endl;
dump_node_pins(o, ind+4); dump_node_pins(o, ind+4);
dump_obj_attr(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 void NetUserFunc::dump_node(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << "USER FUNC: " o << setw(ind) << "" << "USER FUNC: "
<< scope_path(def_) << scope_path(def_);
<< " #(" <<*rise_time()<<","<<*fall_time() << "," <<*decay_time() << ")" if (rise_time())
<< endl; o << " #(" <<*rise_time()
<<","<<*fall_time()
<< "," <<*decay_time() << ")" << endl;
dump_node_pins(o, ind+4); dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4); dump_obj_attr(o, ind+4);
} }

View File

@ -19,9 +19,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * 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 * The vlltype supports the passing of detailed source file location

View File

@ -1142,14 +1142,6 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
// The power is signed if either its operands are signed. // The power is signed if either its operands are signed.
bool arith_is_signed = lsig->get_signed() || rsig->get_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; unsigned rwidth = lwidth;
if (rwidth == 0) { if (rwidth == 0) {
/* Reals are always 1 wide and lsig/rsig types match here. */ /* 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; rwidth = 1;
lwidth = 1; lwidth = 1;
} else { } 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;
} }
} }

View File

@ -315,6 +315,15 @@ bool PGenerate::generate_scope(Design*des, NetScope*container)
case GS_ELSE: case GS_ELSE:
return generate_scope_condit_(des, container, true); 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: default:
cerr << get_fileline() << ": sorry: Generate of this sort" cerr << get_fileline() << ": sorry: Generate of this sort"
<< " is not supported yet!" << endl; << " is not supported yet!" << endl;
@ -345,7 +354,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
genvar = init->value().as_long(); genvar = init->value().as_long();
delete init_ex; delete init_ex;
if (debug_elaborate) if (debug_scopes)
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl; cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
container->genvar_tmp = loop_index; container->genvar_tmp = loop_index;
@ -367,7 +376,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
des->errors += 1; des->errors += 1;
return false; return false;
} }
if (debug_elaborate) if (debug_scopes)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Create generated scope " << use_name << endl; << "Create generated scope " << use_name << endl;
@ -386,7 +395,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
genvar_verinum); genvar_verinum);
scope->set_localparam(loop_index, gp); scope->set_localparam(loop_index, gp);
if (debug_elaborate) if (debug_scopes)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Create implicit localparam " << "Create implicit localparam "
<< loop_index << " = " << genvar_verinum << endl; << 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); NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
NetEConst*step = dynamic_cast<NetEConst*>(step_ex); NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
assert(step); assert(step);
if (debug_elaborate) if (debug_scopes)
cerr << get_fileline() << ": debug: genvar step from " cerr << get_fileline() << ": debug: genvar step from "
<< genvar << " to " << step->value().as_long() << endl; << genvar << " to " << step->value().as_long() << endl;
@ -428,7 +437,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
// scope. // scope.
if ( (test->value().as_long() == 0 && !else_flag) if ( (test->value().as_long() == 0 && !else_flag)
|| (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 " cerr << get_fileline() << ": debug: Generate condition "
<< (else_flag? "(else)" : "(if)") << (else_flag? "(else)" : "(if)")
<< " value=" << test->value() << ": skip generation" << " value=" << test->value() << ": skip generation"
@ -445,7 +454,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
des->errors += 1; des->errors += 1;
return false; return false;
} }
if (debug_elaborate) if (debug_scopes)
cerr << get_fileline() << ": debug: Generate condition " cerr << get_fileline() << ": debug: Generate condition "
<< (else_flag? "(else)" : "(if)") << (else_flag? "(else)" : "(if)")
<< " value=" << test->value() << ": Generate scope=" << " value=" << test->value() << ": Generate scope="
@ -459,6 +468,71 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
return true; 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) void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
{ {
// Scan the generated scope for nested generate schemes, // Scan the generated scope for nested generate schemes,

View File

@ -3554,6 +3554,27 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
{ {
bool flag = true; 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; typedef list<NetScope*>::const_iterator scope_list_it_t;
for (scope_list_it_t cur = scope_list_.begin() for (scope_list_it_t cur = scope_list_.begin()
; cur != scope_list_.end() ; cur ++ ) { ; cur != scope_list_.end() ; cur ++ ) {

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -258,7 +258,8 @@ NetEBPow::NetEBPow(char op, NetExpr*l, NetExpr*r)
: NetEBinary(op, l, r) : NetEBinary(op, l, r)
{ {
assert(op == 'p'); 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()); cast_signed(l->has_sign() || r->has_sign());
} }

18
parse.y
View File

@ -1920,6 +1920,12 @@ module_item
generate_block_opt %prec less_than_K_else generate_block_opt %prec less_than_K_else
{ pform_endgenerate(); } { pform_endgenerate(); }
| K_case '(' expression ')'
{ pform_start_generate_case(@1, $3); }
generate_case_items
K_endcase
{ pform_endgenerate(); }
/* specify blocks are parsed but ignored. */ /* specify blocks are parsed but ignored. */
| K_specify K_endspecify | K_specify K_endspecify
@ -1984,6 +1990,18 @@ module_item
generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } 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_list module_item : module_item_list module_item
| module_item | module_item

View File

@ -412,6 +412,51 @@ void pform_start_generate_else(const struct vlltype&li)
pform_cur_generate->loop_step = 0; 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) void pform_generate_block_name(char*name)
{ {
assert(pform_cur_generate != 0); assert(pform_cur_generate != 0);
@ -439,10 +484,14 @@ void pform_endgenerate()
PGenerate*cur = pform_cur_generate; PGenerate*cur = pform_cur_generate;
pform_cur_generate = cur->parent; 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); 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); pform_cur_module->generate_schemes.push_back(cur);
}
} }
bool pform_expression_is_constant(const PExpr*ex) bool pform_expression_is_constant(const PExpr*ex)

View File

@ -188,6 +188,8 @@ extern void pform_start_generate_for(const struct vlltype&li,
PExpr*next); PExpr*next);
extern void pform_start_generate_if(const struct vlltype&li, PExpr*test); 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_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_generate_block_name(char*name);
extern void pform_endgenerate(); extern void pform_endgenerate();

View File

@ -854,6 +854,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const
case GS_ELSE: case GS_ELSE:
out << " else !(" << *loop_test << ")"; out << " else !(" << *loop_test << ")";
break; 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) if (scope_name)
@ -882,7 +891,7 @@ void PGenerate::dump(ostream&out, unsigned indent) const
(*idx)->dump(out, indent+2); (*idx)->dump(out, indent+2);
} }
out << " endgenerate" << endl; out << setw(indent) << "" << "endgenerate" << endl;
} }
void Module::dump(ostream&out) const void Module::dump(ostream&out) const

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -185,8 +185,7 @@ bool NetEBMult::set_width(unsigned w, bool)
bool NetEBPow::set_width(unsigned w, bool last_chance) bool NetEBPow::set_width(unsigned w, bool last_chance)
{ {
bool flag = left_->set_width(w, last_chance); return w == expr_width();
return flag;
} }
/* /*
@ -445,4 +444,3 @@ bool NetEUReduce::set_width(unsigned w, bool)
{ {
return w == 1; return w == 1;
} }

View File

@ -1777,6 +1777,7 @@ void dll_target::lpm_pow(const NetPow*net)
{ {
ivl_lpm_t obj = new struct ivl_lpm_s; ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_POW; obj->type = IVL_LPM_POW;
FILE_NAME(obj, net);
obj->name = net->name(); obj->name = net->name();
assert(net->scope()); assert(net->scope());
obj->scope = find_scope(des_, net->scope()); obj->scope = find_scope(des_, net->scope());

View File

@ -1708,9 +1708,16 @@ static void draw_lpm_add(ivl_lpm_t net)
case IVL_LPM_POW: case IVL_LPM_POW:
if (dto == IVL_VT_REAL) if (dto == IVL_VT_REAL)
type = "pow.r"; type = "pow.r";
else if (ivl_lpm_signed(net)) else if (ivl_lpm_signed(net)) {
assert(0); /* No support for signed bit based signals. */ type = "pow.s";
else 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"; type = "pow";
break; break;
default: default:
@ -2145,17 +2152,19 @@ static void draw_lpm_part(ivl_lpm_t net)
unsigned width, base; unsigned width, base;
ivl_nexus_t sel; ivl_nexus_t sel;
const char*dly = draw_lpm_output_delay(net);
width = ivl_lpm_width(net); width = ivl_lpm_width(net);
base = ivl_lpm_base(net); base = ivl_lpm_base(net);
sel = ivl_lpm_data(net,1); sel = ivl_lpm_data(net,1);
if (sel == 0) { if (sel == 0) {
fprintf(vvp_out, "L_%p .part %s", fprintf(vvp_out, "L_%p%s .part %s",
net, draw_net_input(ivl_lpm_data(net, 0))); net, dly, draw_net_input(ivl_lpm_data(net, 0)));
fprintf(vvp_out, ", %u, %u;\n", base, width); fprintf(vvp_out, ", %u, %u;\n", base, width);
} else { } else {
fprintf(vvp_out, "L_%p .part/v %s", fprintf(vvp_out, "L_%p%s .part/v %s",
net, draw_net_input(ivl_lpm_data(net,0))); net, dly, draw_net_input(ivl_lpm_data(net,0)));
fprintf(vvp_out, ", %s", draw_net_input(sel)); fprintf(vvp_out, ", %s", draw_net_input(sel));
fprintf(vvp_out, ", %u;\n", width); fprintf(vvp_out, ", %u;\n", width);
} }

View File

@ -400,8 +400,8 @@ void vvp_arith_mult::wide(vvp_ipoint_t base, bool push)
// Power // Power
vvp_arith_pow::vvp_arith_pow(unsigned wid) vvp_arith_pow::vvp_arith_pow(unsigned wid, bool signed_flag)
: vvp_arith_(wid) : 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); dispatch_operand_(ptr, bit);
vvp_vector2_t a2 (op_a_); vvp_vector4_t res4;
vvp_vector2_t b2 (op_b_); 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()) { double ad, bd;
vvp_send_vec4(ptr.ptr()->out, x_val_); vector4_to_value(op_a_, ad, true);
return; 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); vvp_send_vec4(ptr.ptr()->out, res4);
} }

View File

@ -162,9 +162,11 @@ class vvp_arith_mult : public vvp_arith_ {
class vvp_arith_pow : public vvp_arith_ { class vvp_arith_pow : public vvp_arith_ {
public: public:
explicit vvp_arith_pow(unsigned wid); explicit vvp_arith_pow(unsigned wid, bool signed_flag);
~vvp_arith_pow(); ~vvp_arith_pow();
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit); void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
private:
bool signed_flag_;
}; };
class vvp_arith_sub : public vvp_arith_ { class vvp_arith_sub : public vvp_arith_ {

View File

@ -921,7 +921,10 @@ void compile_arith_div(char*label, long wid, bool signed_flag,
assert( wid > 0 ); assert( wid > 0 );
if (argc != 2) { 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; compile_errors += 1;
return; 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) unsigned argc, struct symb_s*argv)
{ {
assert( wid > 0 ); 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) { 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; compile_errors += 1;
return; 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); make_arith(arith, label, argc, argv);
} }

View File

@ -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 * This is called by the parser to make the various arithmetic and
* comparison functors. * 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); unsigned argc, struct symb_s*argv);
extern void compile_arith_div(char*label, long width, bool signed_flag, extern void compile_arith_div(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv); unsigned argc, struct symb_s*argv);

View File

@ -96,6 +96,7 @@
".arith/mult.r" { return K_ARITH_MULT_R; } ".arith/mult.r" { return K_ARITH_MULT_R; }
".arith/pow" { return K_ARITH_POW; } ".arith/pow" { return K_ARITH_POW; }
".arith/pow.r" { return K_ARITH_POW_R; } ".arith/pow.r" { return K_ARITH_POW_R; }
".arith/pow.s" { return K_ARITH_POW_S; }
".arith/sub" { return K_ARITH_SUB; } ".arith/sub" { return K_ARITH_SUB; }
".arith/sub.r" { return K_ARITH_SUB_R; } ".arith/sub.r" { return K_ARITH_SUB_R; }
".arith/sum" { return K_ARITH_SUM; } ".arith/sum" { return K_ARITH_SUM; }

View File

@ -68,7 +68,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_ALIAS K_ALIAS_S K_ALIAS_R %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_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_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_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_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 %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 ';' | T_LABEL K_ARITH_POW T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5; { 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 ';' | T_LABEL K_ARITH_POW_R T_NUMBER ',' symbols ';'
@ -296,6 +296,11 @@ statement
compile_arith_pow_r($1, obj.cnt, obj.vect); 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 ';' | T_LABEL K_ARITH_SUB T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5; { struct symbv_s obj = $5;
compile_arith_sub($1, $3, obj.cnt, obj.vect); compile_arith_sub($1, $3, obj.cnt, obj.vect);

View File

@ -103,7 +103,7 @@ struct __vpirt {
* "base" that is a __vpiHandle object. This template can convert any * "base" that is a __vpiHandle object. This template can convert any
* of those structures into a vpiHandle object. * 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; } { return &obj->base; }
/* /*

View File

@ -697,6 +697,32 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that)
return out; 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) bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val)
{ {
unsigned long res = 0; unsigned long res = 0;

View File

@ -258,6 +258,8 @@ extern vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
vvp_bit4_t val_if_equal); vvp_bit4_t val_if_equal);
template <class T> extern T coerce_to_width(const T&that, unsigned width); 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, * These functions extract the value of the vector as a native type,
* if possible, and return true to indicate success. If the vector has * if possible, and return true to indicate success. If the vector has