From b99846e0eb002d22613befdffc2c032bfa5a7d8c Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 18 Jul 2011 14:19:32 -0700 Subject: [PATCH 01/18] Make call to pow() unambiguous pow(int, int) is ambiguous since it could use the double version from the math library or the verinum version. This patch makes it obvious that we want to use the double version. --- parse.y | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/parse.y b/parse.y index 2f66e6075..117684044 100644 --- a/parse.y +++ b/parse.y @@ -976,21 +976,21 @@ delay_value_simple delete[]$1; } | TIME_LITERAL - { - int unit; + { int unit; - based_size = 0; - $$ = 0; - if ($1 == 0 || !get_time_unit($1, unit)) - yyerror(@1, "internal error: delay."); - else { - double p = pow(10, unit - pform_get_timeunit()); - double time = atof($1) * p; + based_size = 0; + $$ = 0; + if ($1 == 0 || !get_time_unit($1, unit)) + yyerror(@1, "internal error: delay."); + else { + double p = pow(10.0, + (double)(unit - pform_get_timeunit())); + double time = atof($1) * p; - verireal *v = new verireal(time); - $$ = new PEFNumber(v); - FILE_NAME($$, @1); - } + verireal *v = new verireal(time); + $$ = new PEFNumber(v); + FILE_NAME($$, @1); + } } ; From fd4f07906dd0176b17e7ff6eb06b16cb57388556 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 18 Jul 2011 19:33:03 -0700 Subject: [PATCH 02/18] Check that enum initializations are in range. This patch adds checks to verify that all enum initializations (explicit or implicit) are in range. --- elab_scope.cc | 53 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 984a93af9..da9030141 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -152,6 +152,21 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, verinum cur_value (0); verinum one_value (1); size_t name_idx = 0; + // Find the minimum and maximum allowed enumeration values. + verinum min_value (0); + verinum max_value (0); + if (enum_type->signed_flag) { + min_value = v_not((pow(verinum(2), + verinum(use_enum->base_width()-1)))) + + one_value; + max_value = pow(verinum(2), verinum(use_enum->base_width()-1)) - + one_value; + } else { + max_value = pow(verinum(2), verinum(use_enum->base_width())) - + one_value; + } + min_value.has_sign(true); + max_value.has_sign(enum_type->signed_flag); for (list::const_iterator cur = enum_type->names->begin() ; cur != enum_type->names->end() ; ++ cur, name_idx += 1) { @@ -159,38 +174,60 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, if (cur->parm) { // There is an explicit value. elaborate/evaluate // the value and assign it to the enumeration name. - NetExpr*val = elab_and_eval(des, scope, cur->parm, - use_enum->base_width()); + NetExpr*val = elab_and_eval(des, scope, cur->parm, -1); NetEConst*val_const = dynamic_cast (val); if (val_const == 0) { - cerr << "<>:0: error: Enumeration expression is not constant." << endl; + cerr << "<>:0: error: Enumeration expression is not " + "constant." << endl; des->errors += 1; continue; } cur_value = val_const->value(); - if (enum_type->base_type==IVL_VT_BOOL && ! cur_value.is_defined()) { + if (enum_type->base_type==IVL_VT_BOOL && + ! cur_value.is_defined()) { cerr << "<>:0: error: Enumeration name " << cur->name - << " cannot have a logic value." << endl; + << " cannot have an undefined value." << endl; des->errors += 1; + continue; } } else if (! cur_value.is_defined()) { cerr << "<>:0: error: Enumeration name " << cur->name - << " cannot have an inferred value." << endl; + << " cannot have an undefined inferred value." << endl; des->errors += 1; continue; } + // The enumeration value must fit into the enumeration bits. + if ((cur_value > max_value) || + (cur_value.has_sign() && (cur_value < min_value))) { + cerr << "<>:0: error: Enumeration name " << cur->name + << " cannot have a value equal to " << cur_value + << "." << endl; + des->errors += 1; + } + // The values are explicitly sized to the width of the // base type of the enumeration. - verinum tmp_val (cur_value, use_enum->base_width()); + verinum tmp_val (0); + if (cur_value.len() < use_enum->base_width()) { + // Pad the current value if it is narrower than the final + // width of the enum. + tmp_val = pad_to_width (cur_value, use_enum->base_width()); + tmp_val.has_len(true); + } else { + // Truncate an oversized value. We report out of bound + // values above. This may create duplicates. + tmp_val = verinum(cur_value, use_enum->base_width()); + } tmp_val.has_sign(enum_type->signed_flag); rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val); rc_flag &= scope->add_enumeration_name(use_enum, cur->name); if (! rc_flag) { - cerr << "<>:0: error: Duplicate enumeration name " << cur->name << endl; + cerr << "<>:0: error: Duplicate enumeration name " + << cur->name << endl; des->errors += 1; } From a241bf4f74170bec8ac23ccad90c356a17ecfe8d Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 18 Jul 2011 19:35:55 -0700 Subject: [PATCH 03/18] Fix mixed size verinum negative comparisons. For mixed sized negative operands the verinum comparisons were sometimes returning the wrong value. --- verinum.cc | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/verinum.cc b/verinum.cc index 143c0cac9..d59d47c81 100644 --- a/verinum.cc +++ b/verinum.cc @@ -804,7 +804,8 @@ verinum::V operator <= (const verinum&left, const verinum&right) { verinum::V left_pad = verinum::V0; verinum::V right_pad = verinum::V0; - if (left.has_sign() && right.has_sign()) { + bool signed_calc = left.has_sign() && right.has_sign(); + if (signed_calc) { left_pad = left.get(left.len()-1); right_pad = right.get(right.len()-1); @@ -816,11 +817,23 @@ verinum::V operator <= (const verinum&left, const verinum&right) unsigned idx; for (idx = left.len() ; idx > right.len() ; idx -= 1) { - if (left[idx-1] != right_pad) return verinum::V0; + if (left[idx-1] != right_pad) { + // A change of padding for a negative left argument + // denotes the left value is less than the right. + return (signed_calc && + (left_pad == verinum::V1)) ? verinum::V1 : + verinum::V0; + } } for (idx = right.len() ; idx > left.len() ; idx -= 1) { - if (right[idx-1] != left_pad) return verinum::V1; + if (right[idx-1] != left_pad) { + // A change of padding for a negative right argument + // denotes the left value is not less than the right. + return (signed_calc && + (right_pad == verinum::V1)) ? verinum::V0 : + verinum::V1; + } } idx = right.len(); @@ -843,7 +856,8 @@ verinum::V operator < (const verinum&left, const verinum&right) { verinum::V left_pad = verinum::V0; verinum::V right_pad = verinum::V0; - if (left.has_sign() && right.has_sign()) { + bool signed_calc = left.has_sign() && right.has_sign(); + if (signed_calc) { left_pad = left.get(left.len()-1); right_pad = right.get(right.len()-1); @@ -855,11 +869,23 @@ verinum::V operator < (const verinum&left, const verinum&right) unsigned idx; for (idx = left.len() ; idx > right.len() ; idx -= 1) { - if (left[idx-1] != right_pad) return verinum::V0; + if (left[idx-1] != right_pad) { + // A change of padding for a negative left argument + // denotes the left value is less than the right. + return (signed_calc && + (left_pad == verinum::V1)) ? verinum::V1 : + verinum::V0; + } } for (idx = right.len() ; idx > left.len() ; idx -= 1) { - if (right[idx-1] != left_pad) return verinum::V1; + if (right[idx-1] != left_pad) { + // A change of padding for a negative right argument + // denotes the left value is not less than the right. + return (signed_calc && + (right_pad == verinum::V1)) ? verinum::V0 : + verinum::V1; + } } while (idx > 0) { From 5821139e0f55b713cb4687d91607ea5fba8d74fb Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 18 Jul 2011 20:02:17 -0700 Subject: [PATCH 04/18] vlog95: Add debug code for emitting a nexus. This patch adds debug code that can be used to investigate how a nexus is built. --- tgt-vlog95/logic_lpm.c | 125 +++++++++++++++++++++++++++++++++++++++ tgt-vlog95/misc.c | 1 + tgt-vlog95/vlog95_priv.h | 5 ++ 3 files changed, 131 insertions(+) diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 9196e757a..388a56275 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1542,3 +1542,128 @@ void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig) assert(0); } + +static void dump_drive(ivl_drive_t drive) +{ + switch (drive) { + case IVL_DR_HiZ: fprintf(stderr, "highz"); break; + case IVL_DR_SMALL: fprintf(stderr, "small"); break; + case IVL_DR_MEDIUM: fprintf(stderr, "medium"); break; + case IVL_DR_WEAK: fprintf(stderr, "weak"); break; + case IVL_DR_LARGE: fprintf(stderr, "large"); break; + case IVL_DR_PULL: fprintf(stderr, "pull"); break; + case IVL_DR_STRONG: fprintf(stderr, "strong"); break; + case IVL_DR_SUPPLY: fprintf(stderr, "supply"); break; + } +} + +/* + * Routine to dump the nexus information. + */ +void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + fprintf(stderr, "Dumping nexus from scope: %s\n", + ivl_scope_name(scope)); + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_lpm_t lpm = ivl_nexus_ptr_lpm(nex_ptr); + ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); + ivl_net_logic_t net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); + fprintf(stderr, " %u (", idx); + dump_drive(ivl_nexus_ptr_drive1(nex_ptr)); + fprintf(stderr, "1 ,"); + dump_drive(ivl_nexus_ptr_drive0(nex_ptr)); + fprintf(stderr, "0) "); + if (lpm) { + ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); + assert(! net_const); + assert(! net_logic); + assert(! sig); + fprintf(stderr, "LPM: "); + fprintf(stderr, "%s:%d ", ivl_lpm_file(lpm), + ivl_lpm_lineno(lpm)); + if (scope != lpm_scope) fprintf(stderr, "%s ", + ivl_scope_name(lpm_scope)); + switch (ivl_lpm_type(lpm)) { + case IVL_LPM_ABS: fprintf(stderr, "abs"); break; + case IVL_LPM_ADD: fprintf(stderr, "add"); break; + case IVL_LPM_ARRAY: fprintf(stderr, "array"); break; + case IVL_LPM_CAST_INT: fprintf(stderr, ""); break; + case IVL_LPM_CAST_INT2: fprintf(stderr, ""); break; + case IVL_LPM_CAST_REAL: fprintf(stderr, ""); break; + case IVL_LPM_CONCAT: fprintf(stderr, "concat"); break; + case IVL_LPM_CMP_EEQ: fprintf(stderr, "eeq"); break; + case IVL_LPM_CMP_EQ: fprintf(stderr, "eq"); break; + case IVL_LPM_CMP_GE: fprintf(stderr, "ge"); break; + case IVL_LPM_CMP_GT: fprintf(stderr, "gt"); break; + case IVL_LPM_CMP_NE: fprintf(stderr, "ne"); break; + case IVL_LPM_CMP_NEE: fprintf(stderr, "nee"); break; + case IVL_LPM_DIVIDE: fprintf(stderr, "divide"); break; + case IVL_LPM_FF: fprintf(stderr, "dff"); break; + case IVL_LPM_MOD: fprintf(stderr, "mod"); break; + case IVL_LPM_MULT: fprintf(stderr, "mult"); break; + case IVL_LPM_MUX: fprintf(stderr, "mux"); break; + case IVL_LPM_PART_VP: fprintf(stderr, "part-VP"); break; + case IVL_LPM_PART_PV: fprintf(stderr, "part-PV"); break; + case IVL_LPM_POW: fprintf(stderr, "pow"); break; + case IVL_LPM_RE_AND: fprintf(stderr, "R-AND"); break; + case IVL_LPM_RE_NAND: fprintf(stderr, "R-NAND"); break; + case IVL_LPM_RE_OR: fprintf(stderr, "R-OR"); break; + case IVL_LPM_RE_NOR: fprintf(stderr, "R-NOR"); break; + case IVL_LPM_RE_XNOR: fprintf(stderr, "R-XNOR"); break; + case IVL_LPM_RE_XOR: fprintf(stderr, "R-XOR"); break; + case IVL_LPM_REPEAT: fprintf(stderr, "repeat"); break; + case IVL_LPM_SFUNC: fprintf(stderr, "S-func"); break; + case IVL_LPM_SHIFTL: fprintf(stderr, "shiftl"); break; + case IVL_LPM_SHIFTR: fprintf(stderr, "shiftr"); break; + case IVL_LPM_SIGN_EXT: fprintf(stderr, "sign"); break; + case IVL_LPM_SUB: fprintf(stderr, "sub"); break; + case IVL_LPM_UFUNC: fprintf(stderr, "U-func"); break; + } + } else if (net_const) { + assert(! net_logic); + assert(! sig); + fprintf(stderr, "Const: "); + } else if (net_logic) { + assert(! sig); + fprintf(stderr, "Logic: "); + } else if (sig) { + ivl_scope_t sig_scope = ivl_signal_scope(sig); + fprintf(stderr, "Signal: "); + if (scope != sig_scope) fprintf(stderr, "%s.", + ivl_scope_name(sig_scope)); + fprintf(stderr, "%s", ivl_signal_basename(sig)); +// HERE: Do we need to add support for an array word or is that an LPM. + if (ivl_signal_local(sig)) fprintf(stderr, " (local)"); + switch (ivl_signal_port(sig)) { + case IVL_SIP_INPUT: fprintf(stderr, " input"); break; + case IVL_SIP_OUTPUT: fprintf(stderr, " output"); break; + case IVL_SIP_INOUT: fprintf(stderr, " inout"); break; + case IVL_SIP_NONE: break; + } + switch (ivl_signal_type(sig)) { + case IVL_SIT_NONE: fprintf(stderr, " "); break; + case IVL_SIT_REG: fprintf(stderr, " reg"); break; + case IVL_SIT_TRI: fprintf(stderr, " tri"); break; + case IVL_SIT_TRI0: fprintf(stderr, " tri0"); break; + case IVL_SIT_TRI1: fprintf(stderr, " tri1"); break; + case IVL_SIT_TRIAND: fprintf(stderr, " triand"); break; + case IVL_SIT_TRIOR: fprintf(stderr, " trior"); break; + case IVL_SIT_UWIRE: fprintf(stderr, " uwire"); break; + } + switch (ivl_signal_data_type(sig)) { + case IVL_VT_VOID: fprintf(stderr, " "); break; + case IVL_VT_NO_TYPE: fprintf(stderr, " "); break; + case IVL_VT_REAL: fprintf(stderr, " real"); break; + case IVL_VT_BOOL: fprintf(stderr, " bool"); break; + case IVL_VT_LOGIC: fprintf(stderr, " logic"); break; + case IVL_VT_STRING: fprintf(stderr, " string"); break; + } + } else { + fprintf(stderr, "Error: No/missing information!"); + } + fprintf(stderr, " (%u)\n", ivl_nexus_ptr_pin(nex_ptr)); + } +} diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index e9acba726..aeb728cad 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -641,6 +641,7 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) /* It is possible that the nexus does not have a name. For this * case do not print an actual name. */ fprintf(vlog_out, "/* Empty */"); + dump_nexus_information(scope, nex); } /* diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 2404a9405..492057491 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -122,4 +122,9 @@ extern uint64_t get_uint64_from_number(ivl_expr_t expr, int *return_type); */ extern void free_emitted_scope_list(); +/* + * Debug routine to dump the various pieces of nexus information. +*/ +extern void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex); + #endif /* __vlog95_priv_H */ From e2932cb6b53d0fecc16c86d50a00a148715c9d5c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 19 Jul 2011 21:29:05 -0700 Subject: [PATCH 05/18] Add ExpName::elaborate_rval member function This function is for the time being used in the component instatiation. It is checked, whether an expression is a correct r-value. To be a correct r-value, it must be either port name or signal name. --- vhdlpp/architec_elaborate.cc | 3 +++ vhdlpp/expression.h | 1 + vhdlpp/expression_elaborate.cc | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 6533ee465..e44563681 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -66,6 +66,9 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) continue; } + ExpName* tmp; + if (cur->second && (tmp = dynamic_cast(cur->second))) + errors += tmp->elaborate_rval(ent, arc); /* It is possible for the port to be explicitly unconnected. In that case, the Expression will be nil */ if (cur->second) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index fdec70340..57f06e9d3 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -322,6 +322,7 @@ class ExpName : public Expression { public: // Base methods int elaborate_lval(Entity*ent, Architecture*arc, bool); + int elaborate_rval(Entity*ent, Architecture*arc); const VType* probe_type(Entity*ent, Architecture*arc) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index e2c93374c..84b8e16dd 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -71,6 +71,25 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) return errors; } +int ExpName::elaborate_rval(Entity*ent, Architecture*arc) +{ + int errors = 0; + + if (const InterfacePort*cur = ent->find_port(name_)) { + /* OK */ + + } else if (Signal* fs = arc->find_signal(name_)) { + /* OK */ + + } else { + cerr << get_fileline() << ": error: No port or signal " << name_ + << " to be used as r-value." << endl; + errors += 1; + } + + return errors; +} + int ExpNameALL::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) { return Expression::elaborate_lval(ent, arc, is_sequ); From 4989555646372c8c9ae7d12b8cd76f914dcddc8b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 20 Jul 2011 18:45:13 -0700 Subject: [PATCH 06/18] Fix unary convert of real to bool Sometimes real values are converted to BOOL values, and the NetECast needs to handle it properly. --- netmisc.cc | 10 +++++++++- tgt-vvp/eval_expr.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 6bb216e85..3a544f681 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -184,7 +184,15 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) NetExpr* cast_to_int2(NetExpr*expr) { - NetECast*cast = new NetECast('2', expr, expr->expr_width(), + // Special case: The expression is alreadt BOOL + if (expr->expr_type() == IVL_VT_BOOL) + return expr; + + unsigned use_width = expr->expr_width(); + if (expr->expr_type() == IVL_VT_REAL) + use_width = 64; + + NetECast*cast = new NetECast('2', expr, use_width, expr->has_sign()); cast->set_line(*expr); return cast; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 8d10e52fb..e79043543 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -3118,19 +3118,37 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) local_count += 1; break; - case '2': /* Cast logic to bool */ - assert(ivl_expr_value(sub) == IVL_VT_LOGIC); - res = draw_eval_expr_wid(sub, wid, 0); + case '2': /* Cast expression to bool */ + switch (ivl_expr_value(sub)) { + case IVL_VT_BOOL: + res = draw_eval_expr_wid(sub, wid, 0); + break; - /* Handle special case that value is 0 or 1. */ - if (res.base == 0 || res.base == 1) + case IVL_VT_LOGIC: + res = draw_eval_expr_wid(sub, wid, 0); + + /* Handle special case that value is 0 or 1. */ + if (res.base == 0 || res.base == 1) + break; + if (res.base == 2 || res.base == 2) { + res.base = 0; + break; + } + + fprintf(vvp_out, " %%cast2 %d, %d, %u;\n", res.base, res.base, res.wid); break; - if (res.base == 2 || res.base == 2) { - res.base = 0; + + case IVL_VT_REAL: + word = draw_eval_real(sub); + res.base = allocate_vector(wid); + res.wid = wid; + fprintf(vvp_out, " %%cvt/vr %d, %d, %u;\n", res.base, word, wid); + clr_word(word); break; + + default: + assert(0); } - - fprintf(vvp_out, " %%cast2 %d, %d, %u;\n", res.base, res.base, res.wid); break; case 'i': /* Cast a real value to an integer. */ From 6ca44b48ccec723d790b08f06e346e0dd9285301 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 20 Jul 2011 19:03:24 -0700 Subject: [PATCH 07/18] Add support for C-like assignments operators SystemVerilog extended the assignments operator support to C-like assignment operators and special bitwise assignment operators. For example: a += 1; a -= 1; The list of these operators can be found in SV LRM (1800-2009) section 11.4.1. NOTE: I fixed a few parts of this. In particular, the PEBShift class is used for shift operators. Acked-and-Tested-by: Oswaldo Cadenas Signed-off-by: Prasad Joshi --- lexor.lex | 27 +++++++++++++++++ parse.y | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/lexor.lex b/lexor.lex index ce3916746..d4788e9da 100644 --- a/lexor.lex +++ b/lexor.lex @@ -145,6 +145,20 @@ TU [munpf] "<=" { return K_LE; } ">=" { return K_GE; } "=>" { return K_EG; } +"+=>"|"-=>" { + /* + * Resolve the ambiguity between the += assignment + * operator and +=> polarity edge path operator + * + * +=> should be treated as two separate tokens '+' and + * '=>' (K_EG), therefore we only consume the first + * character of the matched pattern i.e. either + or - + * and push back the rest of the matches text (=>) in + * the input stream. + */ + yyless(1); + return yytext[0]; + } "*>" { return K_SG; } "==" { return K_EQ; } "!=" { return K_NE; } @@ -161,6 +175,19 @@ TU [munpf] "+:" { return K_PO_POS; } "-:" { return K_PO_NEG; } "<+" { return K_CONTRIBUTE; } +"+=" { return K_PLUS_EQ; } +"-=" { return K_MINUS_EQ; } +"*=" { return K_MUL_EQ; } +"/=" { return K_DIV_EQ; } +"%=" { return K_MOD_EQ; } +"&=" { return K_AND_EQ; } +"|=" { return K_OR_EQ; } +"^=" { return K_XOR_EQ; } +"<<=" { return K_LS_EQ; } +">>=" { return K_RS_EQ; } +"<<<=" { return K_LS_EQ; } +">>>=" { return K_RSS_EQ; } + /* Watch out for the tricky case of (*). Cannot parse this as "(*" and ")", but since I know that this is really ( * ), replace it diff --git a/parse.y b/parse.y index 117684044..9d213602e 100644 --- a/parse.y +++ b/parse.y @@ -296,6 +296,7 @@ static list* make_named_number(perm_string name, PExpr*val =0) %token PATHPULSE_IDENTIFIER %token BASED_NUMBER DEC_NUMBER %token REALTIME +%token K_PLUS_EQ K_MINUS_EQ %token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG /* K_CONTRIBUTE is <+, the contribution assign. */ %token K_CONTRIBUTE @@ -455,7 +456,7 @@ static list* make_named_number(perm_string name, PExpr*val =0) %type event_expression_list %type event_expression %type event_control -%type statement statement_or_null +%type statement statement_or_null compressed_statement %type statement_list %type analog_statement @@ -469,6 +470,8 @@ static list* make_named_number(perm_string name, PExpr*val =0) %type atom2_type %token K_TAND +%right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ +%right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ %right '?' ':' %left K_LOR %left K_LAND @@ -4278,6 +4281,8 @@ statement { $$ = 0; yyerror(@1, "error: Error in while loop condition."); } + | compressed_statement ';' + { $$ = $1; } | delay1 statement_or_null { PExpr*del = $1->front(); assert($1->size() == 1); @@ -4421,6 +4426,86 @@ statement } ; +compressed_statement + : lpvalue K_PLUS_EQ expression + { + PEBinary *t = new PEBinary('+', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_MINUS_EQ expression + { + PEBinary *t = new PEBinary('-', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_MUL_EQ expression + { + PEBinary *t = new PEBinary('*', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_DIV_EQ expression + { + PEBinary *t = new PEBinary('/', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_MOD_EQ expression + { + PEBinary *t = new PEBinary('%', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_AND_EQ expression + { + PEBinary *t = new PEBinary('&', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_OR_EQ expression + { + PEBinary *t = new PEBinary('|', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_XOR_EQ expression + { + PEBinary *t = new PEBinary('^', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_LS_EQ expression + { + PEBShift *t = new PEBShift('l', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_RS_EQ expression + { + PEBShift *t = new PEBShift('r', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_RSS_EQ expression + { + PEBShift *t = new PEBShift('R', $1, $3); + PAssign *tmp = new PAssign($1, t); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + statement_list : statement_list statement { svector*tmp = new svector(*$1, $2); From 7d7d01aee2841ef0821d35f8f7b62ff88e177565 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 20 Jul 2011 09:29:19 -0700 Subject: [PATCH 08/18] Remove compile warning. isprint() is defined to take an int and if it is defined as a macro then you can get a warning that a char is being used as an array index. This patch fixes this warning in tgt-vlog95/msic.c --- tgt-vlog95/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index aeb728cad..f94dc0f0b 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -505,7 +505,7 @@ static void emit_number_as_string(ivl_net_const_t net_const) if (val == '"') fprintf(vlog_out, "\\\""); else if (val == '\\') fprintf(vlog_out, "\\\\"); /* Print the printable characters. */ - else if (isprint(val)) fprintf(vlog_out, "%c", val); + else if (isprint((int)val)) fprintf(vlog_out, "%c", val); /* Print the non-printable characters as an octal escape. */ else fprintf(vlog_out, "\\%03o", val); } From fd30d6c921184946896e54bdd861b71faa2b3f49 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 20 Jul 2011 20:46:27 -0700 Subject: [PATCH 09/18] Add more enumeration sequence name error checking. This patch adds code to check for a negative or undefined value used in an enumeration sequence name, it verifies that the count in an enumeration sequence name is not zero and allows more decimal constant values in the enumeration sequence name.. --- parse.y | 81 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/parse.y b/parse.y index 9d213602e..dcae0f02a 100644 --- a/parse.y +++ b/parse.y @@ -197,14 +197,26 @@ static list* make_named_numbers(perm_string name, long first, lon { list*lst = new list; named_pexpr_t tmp; - assert(first <= last); - for (long idx = first ; idx <= last ; idx += 1) { - ostringstream buf; - buf << name.str() << idx << ends; - tmp.name = lex_strings.make(buf.str()); - tmp.parm = val; - val = 0; - lst->push_back(tmp); + // We are counting up. + if (first <= last) { + for (long idx = first ; idx <= last ; idx += 1) { + ostringstream buf; + buf << name.str() << idx << ends; + tmp.name = lex_strings.make(buf.str()); + tmp.parm = val; + val = 0; + lst->push_back(tmp); + } + // We are counting down. + } else { + for (long idx = first ; idx >= last ; idx -= 1) { + ostringstream buf; + buf << name.str() << idx << ends; + tmp.name = lex_strings.make(buf.str()); + tmp.parm = val; + val = 0; + lst->push_back(tmp); + } } return lst; } @@ -219,6 +231,28 @@ static list* make_named_number(perm_string name, PExpr*val =0) return lst; } +static long check_enum_seq_value(const YYLTYPE&loc, verinum *arg, bool zero_ok) +{ + long value = 1; + // We can never have an undefined value in an enumeration name + // declaration sequence. + if (! arg->is_defined()) { + yyerror(loc, "error: undefined value used in enum name sequence."); + // We can never have a negative value in an enumeration name + // declaration sequence. + } else if (arg->is_negative()) { + yyerror(loc, "error: negative value used in enum name sequence."); + } else { + value = arg->as_ulong(); + // We cannot have a zero enumeration name declaration count. + if (! zero_ok && (value == 0)) { + yyerror(loc, "error: zero count used in enum name sequence."); + value = 1; + } + } + return value; +} + %} %union { @@ -388,7 +422,7 @@ static list* make_named_number(perm_string name, PExpr*val =0) %token K_zi_nd K_zi_np K_zi_zd K_zi_zp %type from_exclude -%type number +%type number pos_neg_number %type unsigned_signed_opt signed_unsigned_opt reg_opt %type udp_reg_opt edge_operator automatic_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 @@ -777,22 +811,34 @@ enum_name_list } ; +pos_neg_number + : number + { $$ = $1; + } + | '-' number + { verinum tmp = v_not(*($2)) + verinum(1); + *($2) = tmp; + $$ = $2; + } + ; + enum_name : IDENTIFIER { perm_string name = lex_strings.make($1); delete[]$1; $$ = make_named_number(name); } - | IDENTIFIER '[' DEC_NUMBER ']' + | IDENTIFIER '[' pos_neg_number ']' { perm_string name = lex_strings.make($1); - long count = $3->as_ulong(); + long count = check_enum_seq_value(@1, $3, false); delete[]$1; $$ = make_named_numbers(name, 0, count-1); delete $3; } - | IDENTIFIER '[' DEC_NUMBER ':' DEC_NUMBER ']' + | IDENTIFIER '[' pos_neg_number ':' pos_neg_number ']' { perm_string name = lex_strings.make($1); - $$ = make_named_numbers(name, $3->as_long(), $5->as_long()); + $$ = make_named_numbers(name, check_enum_seq_value(@1, $3, true), + check_enum_seq_value(@1, $5, true)); delete[]$1; delete $3; delete $5; @@ -802,16 +848,17 @@ enum_name delete[]$1; $$ = make_named_number(name, $3); } - | IDENTIFIER '[' DEC_NUMBER ']' '=' expression + | IDENTIFIER '[' pos_neg_number ']' '=' expression { perm_string name = lex_strings.make($1); - long count = $3->as_ulong(); + long count = check_enum_seq_value(@1, $3, false); $$ = make_named_numbers(name, 0, count-1, $6); delete[]$1; delete $3; } - | IDENTIFIER '[' DEC_NUMBER ':' DEC_NUMBER ']' '=' expression + | IDENTIFIER '[' pos_neg_number ':' pos_neg_number ']' '=' expression { perm_string name = lex_strings.make($1); - $$ = make_named_numbers(name, $3->as_long(), $5->as_long(), $8); + $$ = make_named_numbers(name, check_enum_seq_value(@1, $3, true), + check_enum_seq_value(@1, $5, true), $8); delete[]$1; delete $3; delete $5; From 46684bb28e0489f5dc31b516721fd24def385c84 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 14:04:43 +0200 Subject: [PATCH 10/18] Use dynamic allocation for VHDL global built-in types Instead of using automatic variables for global types, I allocate them dynamically. Thanks to it, all type objects can be treated in the same way, as all of them are pointers allocated with `new'. Now we will be able to remove all scopes in the same manner, no matter if it is a global or local scope, by deleting all carried pointers. --- vhdlpp/library.cc | 33 ++++++++++++++++----------------- vhdlpp/vtype.h | 8 ++++---- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 67511b4ef..a981f520d 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -140,7 +140,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) if (all_flag || name == "std_logic_vector") { vector dims (1); res->bind_name(perm_string::literal("std_logic_vector"), - new VTypeArray(&primitive_STDLOGIC, dims, false)); + new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -151,12 +151,12 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); res->bind_name(perm_string::literal("signed"), - new VTypeArray(&primitive_STDLOGIC, dims, true)); + new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); res->bind_name(perm_string::literal("unsigned"), - new VTypeArray(&primitive_BIT, dims, false)); + new VTypeArray(primitive_BIT, dims, false)); } } @@ -167,12 +167,12 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); res->bind_name(perm_string::literal("signed"), - new VTypeArray(&primitive_STDLOGIC, dims, true)); + new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); res->bind_name(perm_string::literal("unsigned"), - new VTypeArray(&primitive_STDLOGIC, dims, false)); + new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -194,20 +194,19 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na } } +const VTypePrimitive* primitive_BOOLEAN = new VTypePrimitive(VTypePrimitive::BOOLEAN); +const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BIT); +const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); +const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); -const VTypePrimitive primitive_BOOLEAN (VTypePrimitive::BOOLEAN); -const VTypePrimitive primitive_BIT (VTypePrimitive::BIT); -const VTypePrimitive primitive_INTEGER (VTypePrimitive::INTEGER); -const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC); - -const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); -const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector (1)); +const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); +const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); void generate_global_types(ActiveScope*res) { - res->bind_name(perm_string::literal("boolean"), &primitive_BOOLEAN); - res->bind_name(perm_string::literal("bit"), &primitive_BIT); - res->bind_name(perm_string::literal("integer"), &primitive_INTEGER); - res->bind_name(perm_string::literal("std_logic"), &primitive_STDLOGIC); - res->bind_name(perm_string::literal("bit_vector"),&primitive_BOOL_VECTOR); + res->bind_name(perm_string::literal("boolean"), primitive_BOOLEAN); + res->bind_name(perm_string::literal("bit"), primitive_BIT); + res->bind_name(perm_string::literal("integer"), primitive_INTEGER); + res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); + res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index d9a5636db..e01849358 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -83,10 +83,10 @@ class VTypePrimitive : public VType { type_t type_; }; -extern const VTypePrimitive primitive_BOOLEAN; -extern const VTypePrimitive primitive_BIT; -extern const VTypePrimitive primitive_INTEGER; -extern const VTypePrimitive primitive_STDLOGIC; +extern const VTypePrimitive* primitive_BOOLEAN; +extern const VTypePrimitive* primitive_BIT; +extern const VTypePrimitive* primitive_INTEGER; +extern const VTypePrimitive* primitive_STDLOGIC; /* * An array is a compound N-dimensional array of element type. The From 21008f2ba99245d76258c7617e05dce28311611b Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 14:26:34 +0200 Subject: [PATCH 11/18] Add missing or fix existing deletes in VHDL parser Thanks to valgrind analysis it turned out that there were objects in the parser that were not being deleted in a proper way. This patch fixes them all. --- vhdlpp/parse.y | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 655b26a1f..4629b2eaf 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -464,7 +464,10 @@ component_declaration } ComponentBase*comp = new ComponentBase(name); - if ($4) comp->set_interface($4); + if ($4) { + comp->set_interface($4); + delete $4; + } active_scope->bind_name(name, comp); delete[]$2; if ($7) delete[] $7; @@ -483,6 +486,7 @@ component_instantiation_statement { perm_string iname = lex_strings.make($1); perm_string cname = lex_strings.make($4); ComponentInstantiation*tmp = new ComponentInstantiation(iname, cname, $5); + delete $5; FILE_NAME(tmp, @1); delete[]$1; delete[]$4; @@ -672,7 +676,7 @@ entity_declaration errormsg(@1, "Syntax error in entity clause. Closing name doesn't match.\n"); yyerrok; } - delete $7; + delete[]$7; } } | K_entity error K_end K_entity_opt identifier_opt ';' From 3764216a88023064444c46eb46572871f7cdca17 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 14:44:25 +0200 Subject: [PATCH 12/18] Use stl stack for for carrying scopes This is rather a cosmetic change. The patch changes the container used for stack of scopes from std::list to std::stack. It suits this particular application a bit better. --- vhdlpp/parse.y | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 4629b2eaf..a6d1bb8cd 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -34,6 +34,7 @@ # include # include # include +# include # include # include # include "parse_types.h" @@ -69,7 +70,7 @@ int parse_sorrys = 0; * manage lexical scopes. */ static ActiveScope*active_scope = new ActiveScope; -static list scope_stack; +static stack scope_stack; /* * When a scope boundary starts, call the push_scope function to push @@ -81,7 +82,7 @@ static list scope_stack; static void push_scope(void) { assert(active_scope); - scope_stack.push_front(active_scope); + scope_stack.push(active_scope); active_scope = new ActiveScope (active_scope); } @@ -89,8 +90,8 @@ static void pop_scope(void) { delete active_scope; assert(scope_stack.size() > 0); - active_scope = scope_stack.front(); - scope_stack.pop_front(); + active_scope = scope_stack.top(); + scope_stack.pop(); } From a5ca9ea8be6cb19cfea79e88f287f1f2fbe46d81 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 16:34:36 +0200 Subject: [PATCH 13/18] Use separate containers for current and previous scopes This patch introduces in ScopeBase separate containers for declarations coming from the current scope and from the previous scopes. Until now, in one scope, all objects were kept in an stl map. When a scope was created inside other scopes, a shallow copy of the map was made. This solution was nice for name shadowing (in new scopes, when a name was encountered, the old objects were overridden by a new one), but didn't allow for distinguishing where the objects were allocated. As a result, it is impossible to know who the owner is and who should delete them. In this commit ScopeBase gets two containers: for old and new objects. If a ScopeBase is made from another ScopeBase object, all objects from the copied object go to an old_XXX container, where XXX depends on the type of the copied objects. When a ScopeBase object is deleted, the objects from new_XXX are deleted and the ones from old_XXX are not touched. This patch adds some complexity to the internals of ScopeBase, but leaves its interface unchanged. --- vhdlpp/architec_emit.cc | 25 +++++-- vhdlpp/debug.cc | 52 ++++++++++----- vhdlpp/scope.cc | 142 +++++++++++++++++++++++++++++++--------- vhdlpp/scope.h | 61 +++++++++++++---- 4 files changed, 212 insertions(+), 68 deletions(-) diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index ce60631af..1305426ab 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -30,12 +30,16 @@ int Scope::emit_signals(ostream&out, Entity*entity, Architecture*arc) { int errors = 0; - for (map::iterator cur = signals_.begin() - ; cur != signals_.end() ; ++cur) { + for (map::iterator cur = old_signals_.begin() + ; cur != old_signals_.end() ; ++cur) { errors += cur->second->emit(out, entity, arc); } + for (map::iterator cur = new_signals_.begin() + ; cur != new_signals_.end() ; ++cur) { + errors += cur->second->emit(out, entity, arc); + } return errors; } @@ -43,12 +47,19 @@ int Architecture::emit(ostream&out, Entity*entity) { int errors = 0; - for (map::iterator cur = constants_.begin() - ; cur != constants_.end() ; ++cur) { + for (map::iterator cur = old_constants_.begin() + ; cur != old_constants_.end() ; ++cur) { - out << "localparam " << cur->first << " = "; - errors += cur->second.val->emit(out, entity, this); - out << ";" << endl; + out << "localparam " << cur->first << " = "; + errors += cur->second->val->emit(out, entity, this); + out << ";" << endl; + } + for (map::iterator cur = new_constants_.begin() + ; cur != new_constants_.end() ; ++cur) { + + out << "localparam " << cur->first << " = "; + errors += cur->second->val->emit(out, entity, this); + out << ";" << endl; } errors += emit_signals(out, entity, this); diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 0847f11a3..54fac14d8 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -79,36 +79,58 @@ void ComponentBase::dump_ports(ostream&out, int indent) const void Scope::dump_scope(ostream&out) const { // Dump types - for (map::const_iterator cur = types_.begin() - ; cur != types_.end() ; ++cur) { + for (map::const_iterator cur = old_types_.begin() + ; cur != old_types_.end() ; ++cur) { out << " " << cur->first << ": "; cur->second->show(out); out << endl; } + for (map::const_iterator cur = new_types_.begin() + ; cur != new_types_.end() ; ++cur) { + out << " " << cur->first << ": "; + cur->second->show(out); + out << endl; + } // Dump constants - for (map::const_iterator cur = constants_.begin() - ; cur != constants_.end() ; ++cur) { + for (map::const_iterator cur = old_constants_.begin() + ; cur != old_constants_.end() ; ++cur) { out << " constant " << cur->first << " = "; out << endl; } - - // Dump signal declarations - for (map::const_iterator cur = signals_.begin() - ; cur != signals_.end() ; ++cur) { - if (cur->second) - cur->second->dump(out, 3); - else - out << " signal " << cur->first.str() << ": ???" << endl; + for (map::const_iterator cur = new_constants_.begin() + ; cur != new_constants_.end() ; ++cur) { + out << " constant " << cur->first << " = "; + out << endl; + } + // Dump signal declarations + for (map::const_iterator cur = old_signals_.begin() + ; cur != old_signals_.end() ; ++cur) { + if (cur->second) + cur->second->dump(out, 3); + else + out << " signal " << cur->first.str() << ": ???" << endl; + } + for (map::const_iterator cur = new_signals_.begin() + ; cur != new_signals_.end() ; ++cur) { + if (cur->second) + cur->second->dump(out, 3); + else + out << " signal " << cur->first.str() << ": ???" << endl; } - // Dump component declarations - for (map::const_iterator cur = components_.begin() - ; cur != components_.end() ; ++cur) { + for (map::const_iterator cur = old_components_.begin() + ; cur != old_components_.end() ; ++cur) { out << " component " << cur->first << " is" << endl; cur->second->dump_ports(out); out << " end component " << cur->first << endl; } + for (map::const_iterator cur = new_components_.begin() + ; cur != new_components_.end() ; ++cur) { + out << " component " << cur->first << " is" << endl; + cur->second->dump_ports(out); + out << " end component " << cur->first << endl; + } } void Entity::dump(ostream&out, int indent) const diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 6f2da84b9..a715e86f4 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -18,61 +18,130 @@ */ # include "scope.h" +# include # include +# include using namespace std; ScopeBase::ScopeBase(const ScopeBase&ref) { - constants_ = ref.constants_; - signals_ = ref.signals_; - components_ = ref.components_; - types_ = ref.types_; + merge(ref.old_constants_.begin(), ref.old_constants_.end(), + ref.new_constants_.begin(), ref.new_constants_.end(), + insert_iterator >( + old_constants_, old_constants_.end()) + ); + merge(ref.old_signals_.begin(), ref.old_signals_.end(), + ref.new_signals_.begin(), ref.new_signals_.end(), + insert_iterator >( + old_signals_, old_signals_.end()) + ); + merge(ref.old_components_.begin(), ref.old_components_.end(), + ref.new_components_.begin(), ref.new_components_.end(), + insert_iterator >( + old_components_, old_components_.end()) + ); + merge(ref.old_types_.begin(), ref.old_types_.end(), + ref.new_types_.begin(), ref.new_types_.end(), + insert_iterator >( + old_types_, old_types_.end()) + ); } ScopeBase::~ScopeBase() { + //freeing of member objects is performed by child classes +} + +void ScopeBase::cleanup() +{ + /* + * A parent scope is destroyed only if all child scopes + * were previously destroyed. There for we can delete all + * objects that were defined in this scope, leaving + * objects from the other scopes untouched. + */ + for(map::iterator it = new_signals_.begin() + ; it != new_signals_.end(); ++it) + delete it->second; + for(map::iterator it = new_components_.begin() + ; it != new_components_.end(); ++it) + delete it->second; + for(map::iterator it = new_types_.begin() + ; it != new_types_.end(); ++it) + delete it->second; + for(map::iterator it = new_constants_.begin() + ; it != new_constants_.end(); ++it) + delete it->second; } const VType*ScopeBase::find_type(perm_string by_name) { - map::const_iterator cur = types_.find(by_name); - if (cur == types_.end()) - return 0; - else + map::const_iterator cur = new_types_.find(by_name); + if (cur == new_types_.end()) { + cur = old_types_.find(by_name); + if (cur == old_types_.end()) + return 0; + else + return cur->second; + } else return cur->second; } bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) { - map::const_iterator cur = constants_.find(by_name); - if (cur == constants_.end()) - return false; - - typ = cur->second.typ; - exp = cur->second.val; - return true; + map::const_iterator cur = new_constants_.find(by_name); + if (cur == new_constants_.end()) { + cur = old_constants_.find(by_name); + if (cur == old_constants_.end()) + return false; + else { + typ = cur->second->typ; + exp = cur->second->val; + return true; + } + } else { + typ = cur->second->typ; + exp = cur->second->val; + return true; + } } void ScopeBase::do_use_from(const ScopeBase*that) { - for (map::const_iterator cur = that->components_.begin() - ; cur != that->components_.end() ; ++ cur) { + for (map::const_iterator cur = that->old_components_.begin() + ; cur != that->old_components_.end() ; ++ cur) { if (cur->second == 0) continue; - components_[cur->first] = cur->second; + old_components_[cur->first] = cur->second; + } + for (map::const_iterator cur = that->new_components_.begin() + ; cur != that->new_components_.end() ; ++ cur) { + if (cur->second == 0) + continue; + old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->types_.begin() - ; cur != that->types_.end() ; ++ cur) { + for (map::const_iterator cur = that->old_types_.begin() + ; cur != that->old_types_.end() ; ++ cur) { if (cur->second == 0) continue; - types_[cur->first] = cur->second; + old_types_[cur->first] = cur->second; + } + for (map::const_iterator cur = that->new_types_.begin() + ; cur != that->new_types_.end() ; ++ cur) { + if (cur->second == 0) + continue; + old_types_[cur->first] = cur->second; } - for (map::const_iterator cur = that->constants_.begin() - ; cur != that->constants_.end() ; ++ cur) { - constants_[cur->first] = cur->second; + for (map::const_iterator cur = that->old_constants_.begin() + ; cur != that->old_constants_.end() ; ++ cur) { + old_constants_[cur->first] = cur->second; + } + for (map::const_iterator cur = that->new_constants_.begin() + ; cur != that->new_constants_.end() ; ++ cur) { + old_constants_[cur->first] = cur->second; } } @@ -87,18 +156,27 @@ Scope::~Scope() ComponentBase* Scope::find_component(perm_string by_name) { - map::const_iterator cur = components_.find(by_name); - if (cur == components_.end()) - return 0; - else + map::const_iterator cur = new_components_.find(by_name); + if (cur == new_components_.end()) { + cur = old_components_.find(by_name); + if (cur == old_components_.end()) + return 0; + else + return cur->second; + } else return cur->second; } Signal* Scope::find_signal(perm_string by_name) { - map::const_iterator cur = signals_.find(by_name); - if (cur == signals_.end()) - return 0; - else + map::const_iterator cur = new_signals_.find(by_name); + if (cur == new_signals_.end()) { + cur = old_signals_.find(by_name); + if (cur == old_signals_.end()) + return 0; + else + return cur->second; + } else { return cur->second; + } } diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index fd5e80272..c17f7932b 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -22,12 +22,12 @@ # include # include # include "StringHeap.h" +# include "entity.h" +# include "expression.h" +# include "vsignal.h" class Architecture; class ComponentBase; -class Entity; -class Expression; -class Signal; class VType; class ScopeBase { @@ -40,18 +40,27 @@ class ScopeBase { const VType* find_type(perm_string by_name); bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); protected: + void cleanup(); + // Signal declarations... - std::map signals_; + std::map old_signals_; //previous scopes + std::map new_signals_; //current scope // Component declarations... - std::map components_; + std::map old_components_; //previous scopes + std::map new_components_; //current scope // Type declarations... - std::map types_; + std::map old_types_; //previous scopes + std::map new_types_; //current scope // Constant declarations... struct const_t { + ~const_t() {delete typ; delete val;} + const_t(const VType*t, Expression* v) : typ(t), val(v) {}; + const VType*typ; Expression*val; }; - std::map constants_; + std::map old_constants_; //previous scopes + std::map new_constants_; //current scope void do_use_from(const ScopeBase*that); }; @@ -90,20 +99,44 @@ class ActiveScope : public ScopeBase { void use_from(const ScopeBase*that) { do_use_from(that); } + + /* All bind_name function check if the given name was present + * in previous scopes. If it is found, it is erased (but the pointer + * is not freed), in order to implement name shadowing. The pointer + * be freed only in the scope where the object was defined. This is + * done in ScopeBase::cleanup() function .*/ + void bind_name(perm_string name, Signal*obj) - { signals_[name] = obj; } + { map::iterator it; + if((it = old_signals_.find(name)) != old_signals_.end() ) + old_signals_.erase(it); + new_signals_[name] = obj; + } void bind_name(perm_string name, ComponentBase*obj) - { components_[name] = obj; } + { map::iterator it; + if((it = old_components_.find(name)) != old_components_.end() ) + old_components_.erase(it); + new_components_[name] = obj; + } - void bind_name(perm_string name, const VType*obj) - { types_[name] = obj; } + void bind_name(perm_string name, const VType* t) + { map::iterator it; + if((it = old_types_.find(name)) != old_types_.end() ) + old_types_.erase(it); + new_types_[name] = t; + } void bind_name(perm_string name, const VType*obj, Expression*val) + { map::iterator it; + if((it = old_constants_.find(name)) != old_constants_.end() ) + old_constants_.erase(it); + new_constants_[name] = new const_t(obj, val); + } + + void destroy_global_scope() { - const_t&tmp = constants_[name]; - tmp.typ = obj; - tmp.val = val; + cleanup(); } }; From a8fae6bbf788cb1e189b960b2aee2e36ff8522b1 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Thu, 21 Jul 2011 11:04:48 +0200 Subject: [PATCH 14/18] Use stl algorithms and templates in ScopeBase destructor This patch applies a more sophisticated method for cleaning containers in VHDL ScopeBase class. --- vhdlpp/scope.cc | 16 ++++------------ vhdlpp/scope.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index a715e86f4..6c27d0ed9 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -61,18 +61,10 @@ void ScopeBase::cleanup() * objects that were defined in this scope, leaving * objects from the other scopes untouched. */ - for(map::iterator it = new_signals_.begin() - ; it != new_signals_.end(); ++it) - delete it->second; - for(map::iterator it = new_components_.begin() - ; it != new_components_.end(); ++it) - delete it->second; - for(map::iterator it = new_types_.begin() - ; it != new_types_.end(); ++it) - delete it->second; - for(map::iterator it = new_constants_.begin() - ; it != new_constants_.end(); ++it) - delete it->second; + delete_all(new_signals_); + delete_all(new_components_); + delete_all(new_types_); + delete_all(new_constants_); } const VType*ScopeBase::find_type(perm_string by_name) diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index c17f7932b..69a8de4a7 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +# include # include # include # include "StringHeap.h" @@ -30,6 +31,16 @@ class Architecture; class ComponentBase; class VType; +template +struct delete_object{ + void operator()(T* item) { delete item; } +}; + +template +struct delete_pair_second{ + void operator()(pair item){ delete item.second; } +}; + class ScopeBase { public: @@ -42,6 +53,16 @@ class ScopeBase { protected: void cleanup(); + //containers' cleaning helper functions + template void delete_all(list& c) + { + for_each(c.begin(), c.end(), ::delete_object()); + } + template void delete_all(map& c) + { + for_each(c.begin(), c.end(), ::delete_pair_second()); + } + // Signal declarations... std::map old_signals_; //previous scopes std::map new_signals_; //current scope From eb98ed9ce24304839b54bc8c0a2e3763438fb0c4 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 18:16:08 +0200 Subject: [PATCH 15/18] Add additional deletion in VHDL classes' destructors Delete dynamically allocated objects in ScopeBase, Architecture, ComponentInstatiation, Entity and Package. --- vhdlpp/architec.cc | 5 +++++ vhdlpp/entity.cc | 6 ++++++ vhdlpp/package.cc | 1 + 3 files changed, 12 insertions(+) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index b3e5cfc4f..580b030a0 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -32,6 +32,8 @@ Architecture::Architecture(perm_string name, const ScopeBase&ref, Architecture::~Architecture() { + delete_all(statements_); + ScopeBase::cleanup(); } Architecture::Statement::Statement() @@ -75,6 +77,9 @@ ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c, ComponentInstantiation::~ComponentInstantiation() { + for(map::iterator it = port_map_.begin() + ; it != port_map_.end(); ++it) + delete it->second; } ProcessStatement::ProcessStatement(perm_string iname, diff --git a/vhdlpp/entity.cc b/vhdlpp/entity.cc index b9ccbff0a..de3846fb2 100644 --- a/vhdlpp/entity.cc +++ b/vhdlpp/entity.cc @@ -33,6 +33,9 @@ ComponentBase::ComponentBase(perm_string name) ComponentBase::~ComponentBase() { + for(std::vector::iterator it = ports_.begin() + ; it != ports_.end(); ++it) + delete *it; } void ComponentBase::set_interface(std::list*ports) @@ -60,6 +63,9 @@ Entity::Entity(perm_string name) Entity::~Entity() { + for(map::reverse_iterator it = arch_.rbegin() + ; it != arch_.rend(); ++it) + delete it->second; } Architecture* Entity::add_architecture(Architecture*that) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 936464569..f36c0b46f 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -26,4 +26,5 @@ Package::Package(perm_string n, const ScopeBase&ref) Package::~Package() { + ScopeBase::cleanup(); } From 50f7e1b69e8c33745a3f33a7af27382392332829 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Wed, 20 Jul 2011 18:19:48 +0200 Subject: [PATCH 16/18] Add parser cleanup to vhdlpp This commit adds removal of global objects in the execution of vhdlpp. This includes deleting design entities and the global parse scope. --- vhdlpp/main.cc | 9 +++++++-- vhdlpp/parse.y | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 87e4cd9cf..b705148b1 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -56,6 +56,7 @@ const char*dump_design_entities_path = 0; const char*dump_libraries_path = 0; extern void dump_libraries(ostream&file); +extern void parser_cleanup(); static void process_debug_token(const char*word) { @@ -141,21 +142,25 @@ int main(int argc, char*argv[]) dump_design_entities(file); } - if (errors > 0) + if (errors > 0) { + parser_cleanup(); return 2; + } errors = elaborate_entities(); if (errors > 0) { fprintf(stderr, "%d errors elaborating design.\n", errors); + parser_cleanup(); return 3; } errors = emit_entities(); if (errors > 0) { fprintf(stderr, "%d errors emitting design.\n", errors); + parser_cleanup(); return 4; } - lex_strings.cleanup(); + parser_cleanup(); return 0; } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index a6d1bb8cd..54bcb8b7f 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -100,6 +100,31 @@ void preload_global_types(void) generate_global_types(active_scope); } +//Remove the scope created at the beginning of parser's work. +//After the parsing active_scope should keep it's address + +static void delete_global_scope(void) +{ + active_scope->destroy_global_scope(); + delete active_scope; +} + +//delete global entities that were gathered over the parsing process +static void delete_design_entities(void) +{ + for(map::iterator cur = design_entities.begin() + ; cur != design_entities.end(); ++cur) + delete cur->second; +} + +//clean the mess caused by the parser +void parser_cleanup(void) +{ + delete_design_entities(); + delete_global_scope(); + lex_strings.cleanup(); +} + const VType*parse_type_by_name(perm_string name) { return active_scope->find_type(name); From e19089e8381890c4acf853dcab082673952c21c9 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Tue, 12 Jul 2011 17:51:25 +0200 Subject: [PATCH 17/18] Use multimap in VHDL Component Instantiations Port map aspects were held in std::maps. Because of that, in case of multiple assignments to the same port, some assignments were lost and in effect vhdlpp produced correct verilog code from a buggy VHDL. Std::map was replaced by std::multimap. Thanks to it we can gather this multiple assignments and detect them in the elaboration phase. --- vhdlpp/architec.cc | 2 +- vhdlpp/architec.h | 2 +- vhdlpp/architec_elaborate.cc | 11 ++++++++++- vhdlpp/architec_emit.cc | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 580b030a0..79ccbb20f 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -71,7 +71,7 @@ ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c, while (! ports->empty()) { named_expr_t*cur = ports->front(); ports->pop_front(); - port_map_[cur->name()] = cur->expr(); + port_map_.insert(make_pair(cur->name(), cur->expr())); } } diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 508bb787a..ba6b8160d 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -122,7 +122,7 @@ class ComponentInstantiation : public Architecture::Statement { perm_string iname_; perm_string cname_; - std::map port_map_; + std::multimap port_map_; }; class ProcessStatement : public Architecture::Statement { diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index e44563681..b58bcc605 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -56,7 +56,7 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) map port_match; - for (map::iterator cur = port_map_.begin() + for (multimap::const_iterator cur = port_map_.begin() ; cur != port_map_.end() ; ++cur) { const InterfacePort*iport = base->find_port(cur->first); if (iport == 0) { @@ -75,6 +75,15 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) cur->second->elaborate_expr(ent, arc, iport->type); } + //each formal (component's) port should be associated at most once + for(multimap::const_iterator cur = port_map_.begin() + ; cur != port_map_.end() ; ++cur) + if(port_map_.count(cur->first) != 1) { + //at least one port is associated twice or more + cerr << cur->second->get_fileline() << ": error: At least one port is associated" + << " twice or more in a single component instantiation." << endl; + errors += 1; + } return errors; } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 1305426ab..52ddb7b54 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -105,7 +105,7 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) out << cname_ << " " << iname_ << "("; const char*comma = ""; - for (map::iterator cur = port_map_.begin() + for (multimap::iterator cur = port_map_.begin() ; cur != port_map_.end() ; ++cur) { // Skip unconnected ports if (cur->second == 0) From 981425fccee4720ef3322d50d037dd15906596eb Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Tue, 12 Jul 2011 18:09:50 +0200 Subject: [PATCH 18/18] Add semantics check in component instantiation There have been applied rules for port and signal association in component instatiation statements described in the VHDL standard. --- vhdlpp/architec_elaborate.cc | 7 +++++-- vhdlpp/expression.h | 3 ++- vhdlpp/expression_elaborate.cc | 25 ++++++++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index b58bcc605..a3767ad95 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -54,10 +54,12 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) return 1; } - map port_match; for (multimap::const_iterator cur = port_map_.begin() ; cur != port_map_.end() ; ++cur) { + /* check if a port from component instantiation + exists in the component declaration + */ const InterfacePort*iport = base->find_port(cur->first); if (iport == 0) { cerr << get_fileline() << ": error: No port " << cur->first @@ -68,9 +70,10 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) ExpName* tmp; if (cur->second && (tmp = dynamic_cast(cur->second))) - errors += tmp->elaborate_rval(ent, arc); + errors += tmp->elaborate_rval(ent, arc, iport); /* It is possible for the port to be explicitly unconnected. In that case, the Expression will be nil */ + if (cur->second) cur->second->elaborate_expr(ent, arc, iport->type); } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 57f06e9d3..d626501aa 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -21,6 +21,7 @@ # include "StringHeap.h" # include "LineInfo.h" +# include "entity.h" # include # include # include @@ -322,7 +323,7 @@ class ExpName : public Expression { public: // Base methods int elaborate_lval(Entity*ent, Architecture*arc, bool); - int elaborate_rval(Entity*ent, Architecture*arc); + int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*); const VType* probe_type(Entity*ent, Architecture*arc) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 84b8e16dd..048474cb8 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -71,13 +71,32 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) return errors; } -int ExpName::elaborate_rval(Entity*ent, Architecture*arc) +int ExpName::elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*lval) { int errors = 0; if (const InterfacePort*cur = ent->find_port(name_)) { - /* OK */ - + /* IEEE 1076-2008, p.80: + * For a formal port IN, associated port should be IN, OUT, INOUT or BUFFER + * For a formal port OUT, associated port should be OUT, INOUT or BUFFER + * For a formal port INOUT, associated prot should be OUT, INOUT or BUFFER + * For a formal port BUFFER, associated port should be OUT, INOUT or BUFFER + */ + switch(lval->mode) { + case PORT_OUT: + //case PORT_INOUT: + if (cur->mode == PORT_IN) { + cerr << get_fileline() << ": error: Connecting " + "formal output port " << lval->name << " to actual input port " + << name_ << "." << endl; + errors += 1; + } + break; + case PORT_IN: + case PORT_NONE: + default: + break; + } } else if (Signal* fs = arc->find_signal(name_)) { /* OK */