diff --git a/PGenerate.h b/PGenerate.h index 39be19f47..b29c60b25 100644 --- a/PGenerate.h +++ b/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); diff --git a/design_dump.cc b/design_dump.cc index 427a9a8da..03821c044 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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_ <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; } } diff --git a/elab_scope.cc b/elab_scope.cc index 7cc2eeddd..c954da025 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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(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(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::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(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, diff --git a/elaborate.cc b/elaborate.cc index 0845329e5..50481b044 100644 --- a/elaborate.cc +++ b/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::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::const_iterator scope_list_it_t; for (scope_list_it_t cur = scope_list_.begin() ; cur != scope_list_.end() ; cur ++ ) { diff --git a/net_expr.cc b/net_expr.cc index 0bd86acff..73dd924f6 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -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()); } diff --git a/parse.y b/parse.y index a5d0679fc..818372c7c 100644 --- a/parse.y +++ b/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 diff --git a/pform.cc b/pform.cc index 3da43e8e4..425a2162e 100644 --- a/pform.cc +++ b/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) diff --git a/pform.h b/pform.h index 2ae8d0c57..5dc556f30 100644 --- a/pform.h +++ b/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(); diff --git a/pform_dump.cc b/pform_dump.cc index 6db7ccce1..addc8932c 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -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 diff --git a/set_width.cc b/set_width.cc index 4dcc72e44..8b3257340 100644 --- a/set_width.cc +++ b/set_width.cc @@ -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; } - diff --git a/t-dll.cc b/t-dll.cc index 958cbdc46..2e2e06316 100644 --- a/t-dll.cc +++ b/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()); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index fbb4acf44..aae63e41c 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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); } diff --git a/vvp/arith.cc b/vvp/arith.cc index a984d68d6..7ee51a451 100644 --- a/vvp/arith.cc +++ b/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); } diff --git a/vvp/arith.h b/vvp/arith.h index bd238edc3..acc85b263 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -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_ { diff --git a/vvp/compile.cc b/vvp/compile.cc index e7337d8bc..c826f5910 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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); } diff --git a/vvp/compile.h b/vvp/compile.h index 92270a794..49da17e13 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -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); diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 93641eb9d..c0513c65a 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -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; } diff --git a/vvp/parse.y b/vvp/parse.y index 7fda09d4d..9cd696016 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -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); diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 5c4c30658..9c170d907 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -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 struct __vpiHandle*vpi_handle(T obj) +template vpiHandle vpi_handle(T obj) { return &obj->base; } /* diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 2da64524a..8f54bf05f 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -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; diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 7f32ade93..8b163f803 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -258,6 +258,8 @@ extern vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a, vvp_bit4_t val_if_equal); template 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