/* $Id: synthesize_core.cpp,v 1.70 2003/03/31 19:20:25 sbeyer Exp $ $Log: synthesize_core.cpp,v $ Revision 1.70 2003/03/31 19:20:25 sbeyer * removed 'hx-bug' in bx-routine just a couple of lines later on... Revision 1.69 2003/02/20 15:24:57 dirkl - eliminated hx constants bug Revision 1.68 2002/12/02 14:36:57 sbeyer * ported source to gcc-3.2 (still compiles AND WORKS with gcc-2.9x) Revision 1.67 2002/03/27 21:10:10 dirkl *** empty log message *** Revision 1.66 2002/03/24 12:19:14 dirkl - now it really works Revision 1.65 2002/03/23 18:38:32 dirkl *** empty log message *** Revision 1.64 2002/03/23 17:02:33 dirkl - removed another little bug Revision 1.63 2002/03/23 15:29:40 dirkl - removed a bug in connect_outside functionality (no actuals were supported) Revision 1.62 2002/03/23 15:11:47 dirkl *** empty log message *** Revision 1.61 2002/03/22 19:25:40 dirkl *** empty log message *** Revision 1.60 2002/03/21 16:55:50 dirkl - support for multiple connect_outside functions seems to work Revision 1.59 2002/03/21 15:44:00 dirkl - additional Information about the PVS-files (Output from 'cvs status file') - started support for multiple connect-outside functions Revision 1.58 2002/03/21 13:54:54 dirkl *** empty log message *** Revision 1.57 2002/03/04 09:53:20 dirkl *** empty log message *** Revision 1.56 2002/02/26 13:23:14 sbeyer * fixed bug where RAM lost information about its address width * fixed bug where array of RAM was treated as single bitvector * made pseudo-warning in case of overloaded functions real warning (source code is now REALLY processed further after WARNING output) * in case of (case insensitive) overloading, added location of initial definition to warning/error output * WARNING output no longer reports termination of pvs2hdl Revision 1.55 2002/02/25 23:34:14 dirkl - connections of bus_protocol get now connected to the top-level module(very uggly implementation) Revision 1.54 2001/10/31 17:25:46 dirkl - added support for bx constants (b0 and b1) Revision 1.53 2001/10/25 16:39:01 dirkl - new line for each parameter ==> no more "line too long"-error in VerlogXL Revision 1.52 2001/09/26 08:35:09 sbeyer * added dont care wire warning Revision 1.51 2001/08/25 17:59:24 cj *** empty log message *** Revision 1.50 2001/08/21 11:11:51 sbeyer * completed (really!) int2bv-support Revision 1.49 2001/08/21 09:56:31 sbeyer * completed int2bv-support (hopefully...) Revision 1.48 2001/08/06 14:55:13 sbeyer * added preliminary int2bv-support Revision 1.47 2001/07/19 20:48:24 dirkl - removed uni-saarland bug ;-) Revision 1.46 2001/07/13 12:45:10 dirkl - removed bug with fills, were expression to fill[x](expr) was not simple; the inserted wire has now width 1 and not x Revision 1.45 2001/07/04 13:32:43 dirkl *** empty log message *** Revision 1.44 2001/06/28 23:39:50 dirkl - added support for recursive ' in WITH-expression Revision 1.43 2001/06/28 12:44:47 dirkl - fixed 'core-dump'-bug in synthesize_assignment Revision 1.42 2001/06/28 11:41:43 dirkl - added error-message for parameter-name overloaded by constant-function (causes conflicts because parameter should be used but function IS used during simplifying Revision 1.41 2001/06/22 16:27:36 dirkl - added support for hx constants Revision 1.40 2001/06/22 13:02:57 dirkl *** empty log message *** Revision 1.39 2001/06/22 10:28:29 dirkl - prepared new config-file format - excluded context pvsctl Revision 1.38 2001/06/21 14:30:05 sbeyer * added support for uninterpreted constants (x) Revision 1.37 2001/06/13 12:08:06 sbeyer * fixed '(' recexpr ')'-bug Revision 1.36 2001/06/13 11:30:22 sbeyer * improved code generation for a==TRUE / a==FALSE Revision 1.35 2001/06/13 11:07:12 sbeyer * removed dirkl's first attempt at implementing predefined functions (caused annoying bug) Revision 1.34 2001/06/13 09:52:05 sbeyer * added width computation for register type Revision 1.33 2001/06/12 15:20:40 sbeyer * fixed ram support Revision 1.32 2001/06/12 14:56:45 sbeyer * added reasonable error message for record type overflow * increased supported record size from 200 to 1000 fields Revision 1.31 2001/06/12 11:38:43 dirkl - extended support for predefined function:s Revision 1.30 2001/06/12 11:05:45 sbeyer * added clk propagation to all modules Revision 1.29 2001/06/12 10:05:34 sbeyer * added support for uninterpreted functions (+warning) Revision 1.28 2001/06/11 11:36:53 sbeyer * added nat function support Revision 1.27 2001/06/06 13:18:15 sbeyer * started making ram usage safe (no ram on conditional assignments, etc...) Revision 1.26 2001/06/01 08:57:06 sbeyer * removed reordering of records when it was unnecessary Revision 1.25 2001/05/31 15:29:32 sbeyer * added support for WITH in record expressions Revision 1.24 2001/05/31 14:37:28 sbeyer * fixed LAMBDA bug Revision 1.23 2001/05/31 14:20:39 sbeyer * completed support for arrays * fixed constant support Revision 1.22 2001/05/31 13:49:00 dirkl - debug-output removed Revision 1.21 2001/05/31 13:46:33 dirkl - reordering of record-elements implemented Revision 1.20 2001/05/31 07:45:31 dirkl - minor changes Revision 1.19 2001/05/30 18:07:58 sbeyer * added array and ram support in types * BETA support for function lookup table Revision 1.18 2001/05/17 12:00:24 dirkl - removed bad error in synthesize_if* and synthesize_cond*(condition is not a record!!!) Revision 1.17 2001/05/11 13:37:10 dirkl - added support for IF THEN ELSE with records Revision 1.16 2001/04/20 13:45:34 dirkl - added support for records in conds Revision 1.15 2001/04/09 12:33:32 dirkl - added support for functions without parameters Revision 1.14 2001/03/15 11:19:53 sbeyer wrote own list-merge (ordered merge required) and fixed last is_member-bug Revision 1.13 2001/03/14 17:16:03 sbeyer fixed opsym bug in record expression Revision 1.12 2001/03/14 11:15:13 sbeyer added reasonable error messages for too many/few actuals/parameters (instead of simple core dump) Revision 1.11 2001/02/05 11:14:45 sbeyer added register support Revision 1.10 2001/01/29 11:04:23 sbeyer fixed nat2bv-add_actual-bug, rewrote str_bindings for linux-compatibility Revision 1.9 2001/01/26 16:23:16 sbeyer fixed record bugs, fill bug; proper record treatment in synthesize_simple_expression made postfix obsolete; removed a few obsolete 'wire1=wire2' - assignments started (or rather tried to start) record support for 'if' and 'cond' (a little tricky) Revision 1.8 2001/01/25 15:41:36 sbeyer added cvs log */ #include "synthesize_core.h" #include "config.h" #include "tools.h" #include "constant.h" #include #include using namespace std; // abbreviation for better readability #define ARGS module, vars, width #define SYNTHESIZE(root) synthesize_simple_expression(root,ARGS) #define ARGS1 module, vars, int1 #define SYNTHESIZE1(root) synthesize_simple_expression(root,ARGS1) #define ARGS2 module, vars, int2 #define SYNTHESIZE2(root) synthesize_simple_expression(root,ARGS2) ofstream ostr; string pvs_fileinfo; list synthesized_functions; // true, if functionname is in connect_outside_list connect_outside *is_connect_outside_function(const string &name) { list::iterator i=connect_outsides.begin(); while (i!=connect_outsides.end()) { if ((*i).functionname==name) { return &(*i); } i++; } return NULL; } // gives the next entry in connect_outsides if it exists else NULL connect_outside *next_connect_outside_function(const string &name,string start_ori_name) { bool startit=false; list::iterator i=connect_outsides.begin(); while (i!=connect_outsides.end()) { if (((*i).functionname==name) && startit) { return &(*i); } if ((*i).original_functionname==start_ori_name) startit=true; i++; } return NULL; } bool is_function_in_lookup_table(const string &_name,predefined_function &pred) { list::const_iterator pred_i=predefined_functions.begin(); while (pred_i!=predefined_functions.end()) { if ((*pred_i).function_name==_name) { pred=*pred_i; return true; } *pred_i++; } return false; } ostream &operator << (ostream& ostr, const var &x) { return ostr << x.name << " " << x.tarray; } bool is_constant(const knoten *const root, int& value) { if (root->subtyp==157) // expr -> NUMBER { value=root->sub[0]->wert_int; return true; } return false; } string int_string(int i) { char ret[10]; snprintf(ret,10,"%i",i); return ret; } bool is_var_defined(const list &vars, const string &name, type_array &tarray) { list::const_iterator i=vars.begin(); while (i!=vars.end()) { if (i->name==name) { tarray=i->tarray; return true; } i++; } return false; } void replace_var(list &vars, const var &x) { list::iterator i=vars.begin(); while (i!=vars.end()) { if (i->name==x.name) { vars.erase(i); break; } i++; } vars.push_back(x); } synthesized_function::synthesized_function(const synthesized_function &synth) { name =synth.name; bindings =synth.bindings; parameters =synth.parameters; return_type=synth.return_type; } ostream &operator << (ostream& ostr, const synthesized_function &function) { ostr << "Name: " << function.name << "\nBindings: " << function.bindings << "\nReturn Type: " << function.return_type; list::const_iterator i=function.parameters.begin(); while (i!=function.parameters.end()) ostr << "\nParameter " << *i++; return ostr; } bool is_function_synthesized(const string &_name, const string &_bindings, synthesized_function &function) { list::const_iterator i=synthesized_functions.begin(); while (i!=synthesized_functions.end()) { if (i->name==_name && i->bindings==_bindings) { function = *i; return true; } i++; } return false; } string binding_string(const list &bindings) { string ret; list::const_iterator i=bindings.begin(); while (i!=bindings.end()) ret += '_' + int_string(i++->value); return ret; } string synthesize_elseif(const knoten *const root, const knoten *const else_teil, VerilogModule &module, const list &vars, int &width) { int int1; return '(' + SYNTHESIZE1(root->sub[0]) + ")? (" + SYNTHESIZE(root->sub[1]) + "):\n\t\t\t(" + (root->subtyp==242? SYNTHESIZE(else_teil) : synthesize_elseif(root->sub[2],else_teil,ARGS)+ ')'); } string synthesize_cond_case_list(const knoten *const root, VerilogModule &module, const list &vars, int &width) { int int1; switch (root->subtyp) { case 233 : // cond_case_list -> cond_case // this is the LAST case in the cond case list // -> just add the expr // (treated like ELSE -> expr in the above cond_case_list) return SYNTHESIZE(root->sub[0]->sub[0]); case 234 : // cond_case_list -> cond_case, cond_case_list return '(' + SYNTHESIZE1(root->sub[0]->sub[0]) + ")? (" + SYNTHESIZE(root->sub[0]->sub[1]) + "):\n\t\t\t(" + synthesize_cond_case_list(root->sub[1],ARGS) + ')'; case 235 : // cond_case_list -> cond_case ELSE MINUSGROESSER expr return '(' + SYNTHESIZE1(root->sub[0]->sub[0]) + ")? (" + SYNTHESIZE(root->sub[0]->sub[1]) + "):\n\t\t\t(" + SYNTHESIZE(root->sub[1]) + ')'; default : knot_error(printf("Aufruf von synthesize_cond_case_list mit unzulaessigem Subtyp %i",root->subtyp),root) } } void synthesize_bindlist(const knoten *const root, VerilogModule &module, list &vars) { int i=0; int width; string str,str2; type_array tarray,dummy; list rec_expr; switch (root->subtyp) { case 241 : // bind_list ',' bind // left-to-right evaluation!!! synthesize_bindlist(root->sub[0],module,vars); i=1; // no break!! case 240 : // bind { if (root->sub[i]->subtyp==238) // '(' simplebind_list ')' '=' expr knot_error("simplebind_list not supported",root->sub[i]) if (root->sub[i]->sub[0]->sub[0]->subtyp==332) // opsym knot_error("only id in bind supported, not opsym",root->sub[i]->sub[0]) const char *const &name=root->sub[i]->sub[0]->sub[0]->sub[0]->wert_str; switch(root->sub[i]->sub[0]->subtyp) { case 304 : // idop ':' type_expr // get_type(root->sub[i]->sub[0]->sub[1],dummy); // push_front for 'local shadows global' // vars.push_front(var(name,dummy)); // rec_expr=synthesize_record_expression(root->sub[i]->sub[1],tarray, // module,vars,""); // module.new_wiredefinition(name,tarray); // module.new_assign(name,rec_expr,tarray); // break; case 302 : // idop rec_expr=synthesize_record_expression(root->sub[i]->sub[1],tarray, module,vars,""); // push_front for 'local shadows global' vars.push_front(var(name,tarray)); module.new_wiredefinition(name,tarray); module.new_assign(name,rec_expr,tarray); break; case 303 : // idop pdformals_plus case 305 : // idop pdformals_plus ':' type_expr knot_error(cout << "pdformals in bindlist not supported\n",root) default : knot_error(cout << "bindlist with unexpected subtype\n",root) } break; } default : knot_error(cout << "bindlist with unexpected subtype\n",root) } } // übersetzt eine Expression string synthesize_simple_expression(const knoten *const root, VerilogModule &module, const list &vars, int &width) { int int1, int2, int3; string str1, str2; type_array tarray,dummy; list rec_expr; bool translated; switch (root->subtyp) { case 157 : // expr -> NUMBER knot_error(cout << "expr->NUMBER not supported\n",root); case 165 : // expr '`' ID { list rec_expr= synthesize_record_expression(root->sub[0],tarray,module,vars, inv_compose_record_name(root->sub[1]->wert_str,"")); if (!tarray.name[0].empty()) knot_error(cout << "unexpected record type\n",root); if (tarray.contains_ram()) knot_error(cout << "unexpected ram type\n",root); width=tarray.bitbreite[0]; return rec_expr.front(); } case 166 : // expr '`' NUMBER knot_error(cout << "expr '`' NUMBER not supported\n",root); case 167 : // expr -> expr funarg // functions contain at most one pair of braces // so this can only be a function if 'expr -> name' if (root->sub[0]->subtyp==159 // expr -> name &&(root->sub[0]->sub[0]->subtyp==347 // name -> idop || root->sub[0]->sub[0]->subtyp==348) // name -> idop actuals && root->sub[0]->sub[0]->sub[0]->subtyp==331) // idop -> ID // this name is a function iff it is not a variable if (!is_var_defined(vars,root->sub[0]->sub[0]->sub[0]->sub[0]->wert_str,tarray)) { str1=synthesize_function_call(root,vars,module,tarray,translated); if (!tarray.name[0].empty()) knot_error(cout << "unexpected record type\n",root); if (tarray.contains_ram()) knot_error(cout << "unexpected ram type\n",root); if (!translated) str1=module.wire_name(str1); width=tarray.bitbreite[0]; return str1; } // NO ELSE HERE !!! if (tarray.contains_ram()) knot_error(cout << "no ram read access supported\n",root); // make sure exprlist contains exactly one argument if (root->sub[1]->sub[0]->subtyp!=245) // exprleerlist -> exprlist knot_error(cout << "empty exprlist not supported here\n",root); if (root->sub[1]->sub[0]->sub[0]->subtyp!=246) // exprlist -> expr knot_error(cout << "bit selection takes only one argument\n",root); if (!is_constant(root->sub[1]->sub[0]->sub[0]->sub[0],int1)) knot_error(cout << "argument for bit selection not const\n",root); rec_expr=synthesize_record_expression(root->sub[0],tarray,module,vars,""); if (tarray.name[0].empty() && tarray.type[0]==bitvector) { str1=*rec_expr.begin(); width=tarray.bitbreite[0]; // check for simple name (doesn't need a new wire) if (!module.is_simple_wire_name(str1)) { str2=module.new_wiredefinition(width); module.new_assign(str2,str1); str1=module.wire_name(str2); // translate!!! } if (width!=1) // selection from single bits not supported! str1+='[' + int_string(int1) + ']'; width=1; return str1; } else { str1='(' + int_string(int1) + ')'; if (tarray.is_member(str1,dummy,rec_expr)) { if (!dummy.name[0].empty()) knot_error(cout << "unexpected record type\n",root); if (dummy.contains_ram()) knot_error(cout << "unexpected ram type\n",root); width=dummy.bitbreite[0]; return *rec_expr.begin(); } else knot_error(cout << str1 << " not member of " << tarray,root) } case 159 : // expr -> name if (root->sub[0]->subtyp==347 && // name -> idop root->sub[0]->sub[0]->subtyp==332) // idop -> opsym { width=1; if (root->sub[0]->sub[0]->sub[0]->subtyp==377) // opsym -> TRUE return "1'b1"; if (root->sub[0]->sub[0]->sub[0]->subtyp==378) // opsym -> FALSE return "1'b0"; } if (root->sub[0]->subtyp==347 && // name -> idop root->sub[0]->sub[0]->subtyp==331) // idop -> ID { if (is_var_defined(vars,root->sub[0]->sub[0]->sub[0]->wert_str,tarray)) { if (!tarray.name[0].empty()) knot_error(cout << "unexpected record type\n",root); if (tarray.contains_ram()) knot_error(cout << "unexpected ram type\n",root); width=tarray.bitbreite[0]; return module.wire_name(root->sub[0]->sub[0]->sub[0]->wert_str); } } if ((root->sub[0]->subtyp==348 || // name -> idop actuals root->sub[0]->subtyp==347) // name -> idop && root->sub[0]->sub[0]->subtyp==331) // idop -> ID // name must be a function without arguments (constant function) { str1=synthesize_function_call(root,vars,module,tarray,translated); if (!tarray.name[0].empty()) knot_error(cout << "unexpected record type\n",root); if (tarray.contains_ram()) knot_error(cout << "unexpected ram type\n",root); if (!translated) str1=module.wire_name(str1); width=tarray.bitbreite[0]; return str1; } knot_error(cout << "!!! Unknown Expression !!!\n",root) case 174 : // expr -> expr OR expr return '(' + SYNTHESIZE(root->sub[0]) + " | " + SYNTHESIZE(root->sub[1]) + ')'; case 176 : case 178 : // expr -> expr & expr return '(' + SYNTHESIZE(root->sub[0]) + " & " + SYNTHESIZE(root->sub[1]) + ')'; case 179 : // expr XOR expr return '(' + SYNTHESIZE(root->sub[0]) + " ^ " + SYNTHESIZE(root->sub[1]) + ')'; case 210 : // not expr return "(~" + SYNTHESIZE(root->sub[0]) + ')'; case 163 : // leerer Klammerausdruck return ""; case 164 : // expr -> ( expr_list ) if (root->sub[0]->subtyp==246) // expr_list -> expr return SYNTHESIZE(root->sub[0]->sub[0]); knot_error(cout << "!!! '(' expr_list ')'not supported !!!\n",root); case 182 : // expr -> expr ^ expr if (is_constant(root->sub[1],int1)) // Fall : expr ^ 2 : d.h. zweites Bit des Bitvectors { str1=SYNTHESIZE(root->sub[0]); // check for simple name (doesn't need a new wire) if (!module.is_simple_wire_name(str1)) { str2=module.new_wiredefinition(width); module.new_assign(str2,str1); str1=module.wire_name(str2); // translate!!! } if (width!=1) // selection from single bits not supported! str1+='[' + int_string(int1) + ']'; width=1; return str1; } if (root->sub[1]->subtyp==164) // Fall : expr -> '(' expr_list ')' { if ((root->sub[1]->sub[0]->subtyp==247) // expr_list -> expr ',' expr_list && (is_constant(root->sub[1]->sub[0]->sub[0],int2)) && (root->sub[1]->sub[0]->sub[1]->subtyp==246) // expr_list -> expr && (is_constant(root->sub[1]->sub[0]->sub[1]->sub[0],int3))) { str1=SYNTHESIZE(root->sub[0]); // check for simple name (doesn't need a new wire) if (!module.is_simple_wire_name(str1)) { str2=module.new_wiredefinition(width); module.new_assign(str2,str1); str1=module.wire_name(str2); // translate!!! } if (width!=1) // selection from single bits not supported! str1+='[' + int_string(int2) + ':' + int_string(int3)+ ']'; width=int2-int3+1; return str1; } } knot_error(cout << "^ in this context not supported\n",root); case 168 : // expr -> expr O_OPERATOR expr str1=SYNTHESIZE1(root->sub[0]); str2=SYNTHESIZE2(root->sub[1]); width=int1+int2; return '{' + str1 + "," + str2 + '}'; case 218 : // expr -> IF expr THEN expr ELSE expr ENDIF return "((" + SYNTHESIZE1(root->sub[0]) + ")? (" + SYNTHESIZE(root->sub[1]) + "):\n\t\t\t(" + SYNTHESIZE(root->sub[2]) + "))"; case 219 : // expr -> IF expr THEN expr elseif_plus ELSE expr ENDIF return "((" + SYNTHESIZE1(root->sub[0]) + ")? (" + SYNTHESIZE(root->sub[1]) + "):\n\t\t\t(" + synthesize_elseif(root->sub[2],root->sub[3],ARGS) + "))"; case 231 : // COND cond_case_list ENDCOND return synthesize_cond_case_list(root->sub[0],ARGS); case 196 : // expr -> expr '=' expr width=1; str1=SYNTHESIZE1(root->sub[0]); str2=SYNTHESIZE1(root->sub[1]); if (str1=="1'b1") return str2; else if (str1=="1'b0") return "(~" + str2 + ')'; else if (str2=="1'b1") return str1; else if (str2=="1'b0") return "(~" + str1 + ')'; else return '(' + str1 + "==" + str2 + ')'; case 220 : // LAMBDA lambda_body // only possibility: "lambda_body -> lambda_formals ':' expr" if (root->sub[0]->sub[0]->subtyp!=253) // lambda_formal knot_error(cout << "only one LAMBDA formal supported!\n",root->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->subtyp!=257) // '(' adformals ')'? knot_error(cout << "only '(' adformals ')' LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=93) // adformal? knot_error(cout << "only one adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=95) // typeid? knot_error(cout << "only typeid as adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=337) // idop ':' type_expr? knot_error(cout << "only \"idop ':' type_expr\" as typeid in adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=331) // ID? knot_error(cout << "only ID as idop in \"idop ':' type_expr\" as typeid in adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) // now get the LAMBDA variable name and type str1=root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->wert_str; get_type(root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[1],tarray); if (tarray.type[0]!=bounded_nat) knot_error(cout << "only bounded nat as LAMBDA formal type supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[1]) width=tarray.upper_bound[0]-tarray.lower_bound[0]+1; if (width>1) str2='{'; for (int3=tarray.upper_bound[0];int3>=tarray.lower_bound[0];int3--) { list bindings; bindings.push_front(binding(str1,int3)); knoten *copy=simplify_tree(root->sub[0]->sub[1],bindings); str2 += SYNTHESIZE1(copy); if (int3>tarray.lower_bound[0]) str2 += ",\n\t\t\t"; knoten_speicherfreigeben(copy); if (int1!=1) knot_error(cout << "expr in LAMBDA body must be 1 bit wide\n",root) } if (width>1) str2+='}'; return str2; break; case 228 : // expr WITH '[' assignment_list ']' knot_error(cout<<"WITH not supported for simple types\n",root); break; case 227 : // expr -> LET bind_list IN expr { list neu_vars=vars; synthesize_bindlist(root->sub[0],module,neu_vars); str1=synthesize_simple_expression(root->sub[1],module, neu_vars,width); module.free_local_wire_names(neu_vars.size()-vars.size()); return str1; } default : knot_error(cout << "expression type " << root->subtyp << " not supported\n",root) } } string compose_record_name(const string &prefix, const string &name) { return prefix + REC_DEREF + name; } string inv_compose_record_name(const string &name, const string &postfix) { return REC_DEREF + name + postfix; } list synthesize_assignment(const knoten *const root, const knoten *const expression, type_array &tarray, const list &vars, VerilogModule &module) { list ret; type_array dummy; int width; list::iterator i; switch (root->subtyp) { case 272: // '(' expr_leerlist ')' case 274: // '`' NUMBER case 276: // ID '!' NUMBER case 277: // NUMBER break; case 273: // '`' ID ret=synthesize_record_expression(expression,dummy,module,vars,"gnulp"); if (!tarray.add_member(root->sub[0]->wert_str,dummy)) knot_error(cout << "record type " << tarray << " too complex!", root); return ret; break; case 275: // ID ret=synthesize_record_expression(expression,dummy,module,vars,""); if (!tarray.add_member(root->sub[0]->wert_str,dummy)) knot_error(cout << "record type " << tarray << " too complex!", root); return ret; break; default: knot_error(cout << "unknown subtype " << root->subtyp << " in synthesize_assignment\n",root) } // even in default case return something return ret; } list synthesize_assign_arg_plus(const knoten *const root, const knoten *const expression, type_array &tarray, const list &vars, VerilogModule &module) { list tmp1,tmp2; int i; switch (root->subtyp) { case 270: // assign_arg return synthesize_assignment(root->sub[0],expression,tarray,vars,module); break; case 271: // assign_arg assign_arg_plus { type_array tarray2,tarray3; tmp1=synthesize_assignment(root->sub[0],expression,tarray3,vars,module); tmp2=synthesize_assign_arg_plus(root->sub[1],expression,tarray2,vars,module); // put tarray2 and tarray3 together if (tarray2.num!=tarray3.num) { knot_error(cout << "Different number of entries in tarray.\n",root) } for (i=0;i::const_iterator i=tmp2.begin(); while (i!=tmp2.end()) tmp1.push_back(*i++); return tmp1; } default: knot_error(cout << "unknown subtype " << root->subtyp << " in synthesize_assign_arg_plus\n",root) } } list synthesize_assignment_list(const knoten *const root, type_array &tarray, const list &vars, VerilogModule &module) { list ret,ret2; switch (root->subtyp) { case 248: // assignment if (root->sub[0]->subtyp==269) // assign_arg_plus PIPE_MINUS_GROESSER expr knot_error(cout << "only := assignment supported",root) // assignment -> assign_arg_plus DOPPELPUNKT_GLEICH expr return synthesize_assign_arg_plus(root->sub[0]->sub[0], root->sub[0]->sub[1], tarray,vars,module); case 249: // assignment_list ',' assignment { ret=synthesize_assignment_list(root->sub[0],tarray,vars,module); if (root->sub[1]->subtyp==269) // assign_arg_plus PIPE_MINUS_GROESSER expr knot_error(cout << "only := assignment supported",root->sub[1]) // assignment -> assign_arg_plus DOPPELPUNKT_GLEICH expr ret2=synthesize_assign_arg_plus(root->sub[1]->sub[0], root->sub[1]->sub[1], tarray,vars,module); list::const_iterator i=ret2.begin(); while (i!=ret2.end()) ret.push_back(*i++); return ret; } default: knot_error(cout << "unknown subtype " << root->subtyp << " in synthesize_assignment_list\n",root) } } // we make the module name unique by simply adding an 'x' and the bindings // (XILINX doesn't like '__' in a name for some oblique reason) // since 'bindings' never contais an 'x', this name is unique!!! string unique_module_name(const string &fun_name, const string &bindings) { return fun_name + 'x' + bindings; } string synthesize_function_call(const knoten *const root, const list &vars, VerilogModule &module, type_array &tarray, bool &translated) { defined_function function; list bindings; list parameters; list synth_expr; translated=false; // part 0: check for predefined functions: // * fill[n](bool_value) -> n'b(bool_value)^n // (e.g. fill[2](TRUE) -> 2'b11) // (or fill[2](a^0) -> {2{a^0}}; // * nat2bv[n](integer) -> n'd(integer) // (e.g. nat2bv[4](5) -> 4'd5) // * if (root->sub[0]->subtyp==347 && // name -> idop root->sub[0]->sub[0]->subtyp==331) // idop -> ID { const char *const &name=root->sub[0]->sub[0]->sub[0]->wert_str; if (name[0]=='h' && strlen(name)==2 && (isdigit(name[1]) || name[1]=='A' || name[1]=='B' || name[1]=='C' || name[1]=='D' || name[1]=='E' || name[1]=='F' )) { // hx constant!! string temp="4'h"; temp=temp + string(name)[1]; if (parameter_verbose) cout << "hx-Konstante wurde ersetzt durch " << temp << "!!!\n"; translated=true; tarray.add_member("",bitvector,4); // string wire=module.new_wiredefinition(4); // module.new_assign(wire,temp); // temp=module.wire_name(wire); return temp; } if (name[0]=='b' && strlen(name)==2 && (name[1]=='0' || name[1]=='1')) { // bx constant!! string temp="1'b"; temp=temp+string(name)[1]; if (parameter_verbose) cout << "bx-Konstante wurde ersetzt durch " << temp << "!!!\n"; translated=true; tarray.add_member("",bitvector,1); return temp; } } if (root->sub[0]->subtyp==159 && // expr -> name root->sub[0]->sub[0]->subtyp==348 && // name -> idop actuals root->sub[0]->sub[0]->sub[0]->subtyp==331)// idop -> ID { const char *const &name=root->sub[0]->sub[0]->sub[0]->sub[0]->wert_str; bool nat2bv=string(name)=="nat2bv"; bool int2bv=string(name)=="int2bv"; bool fill=string(name)=="fill"; // bool hex_const=false; // if (string(name)=="h4") hex_const=true; bool predefined_function=nat2bv || fill || int2bv; if (predefined_function) { translated=true; actuals_array act; act.add_actual(string("von ") + name); params_array params; params.add_param(string("von ") + name,0); if (root->sub[1]->sub[0]->subtyp==244) // empty knot_error(cout << name << " can't be called without a parameter!\n",root) // nat2bv expects const parameter add_parameter(root->sub[1]->sub[0]->sub[0],params,bindings,parameters,name,nat2bv||int2bv); // bindings.size() as last parameter distiguishes between nat2bv (=1) and fill (=0) add_actual(root->sub[0]->sub[0]->sub[1]->sub[0],act,bindings,name,bindings.size()); if (!tarray.add_member("",bitvector,bindings.front().value)) knot_error(cout << "record type " << tarray << " too complex!", root); string ret; if (nat2bv || int2bv) { ret=int_string(bindings.front().value)+"'d"+ (int2bv && bindings.back().value<0? // negative n-bit 2's-complement numbers are computed // as binary numbers by adding 2*2^(n-1)=2^n int_string((1 << bindings.front().value) + bindings.back().value) : int_string(bindings.back().value)); } if (fill) { if (!is_bool_constant(parameters.front())) // non-const? { int width; ret=synthesize_simple_expression(parameters.front(),module,vars,width); if (width!=1) knot_error(cout << "Parameter to fill must be single bit, not " << width << " bits!\n",root) if (bindings.front().value!=1) // fill[1] is ignored { // add a new wire for the expression if it is needed if (!module.is_simple_wire_name(ret)) { string wire=module.new_wiredefinition(1); // fill only works on single bits module.new_assign(wire,ret); ret=module.wire_name(wire); } ret='{'+int_string(bindings.front().value) + '{' + ret + "}}"; } } else { int value=get_bool_constant_value(parameters.front()); ret=int_string(bindings.front().value)+"'b"; for (int i=0;i::const_iterator i=synth.parameters.begin(); list::const_iterator j=parameters.begin(); while (i!=synth.parameters.end()) { tarray.empty(); // define the wire AND assign it to the synthesized expression synth_expr=synthesize_record_expression(*j,tarray,module,vars,""); if (tarray!=i->tarray) knot_error(cout << "parameter type doesn't match, found " << tarray << " expected " << i->tarray << "\n",root); string wire=module.new_wiredefinition(i->tarray); module.new_assign(wire,synth_expr,tarray); // and add the wire to the parameters for the function call string str_tmp=module.wire_function_call(wire,i->tarray); if (!str_tmp.empty()) params += ",\n\t\t" + str_tmp; i++; j++; } // and the ouput wire(s) string ret=module.new_wiredefinition(synth.return_type); string str_tmp2=module.wire_function_call(ret,synth.return_type); if (!str_tmp2.empty()) params += ",\n\t\t" + str_tmp2; // finally, synthesize the function call string feedthrough_parameter; if (is_feedthrough_function(synth.name+"x"+synth.bindings,feedthrough_parameter)) module.new_moduleaufruf(unique_module_name(synth.name,synth.bindings),params,feedthrough_parameter); else module.new_moduleaufruf(unique_module_name(synth.name,synth.bindings),params); // return the return type tarray=synth.return_type; // and return the ouput wire return ret; } list synthesize_record_if(const knoten *const root, VerilogModule &module, const list &vars, type_array &tarray, const string &postfix) { type_array tarray_dummy1,tarray_dummy2; // expr ==> IF expr THEN expr ELSE expr ENDIF list listtemp2,listtemp3,listtemp_erg; string stringtemp1; list::const_iterator i2,i3; int width; // synthesize sub-expressions stringtemp1=synthesize_simple_expression(root->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[1],tarray,module,vars,postfix); listtemp3=synthesize_record_expression(root->sub[2],tarray_dummy2,module,vars,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy2)) { knot_error(cout << "Typen in record_if stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy2 << "\n",root) } // put the sub-expressions together i2=listtemp2.begin(); i3=listtemp3.begin(); while (i2!=listtemp2.end()) { listtemp_erg.push_back('('+ stringtemp1 + ") ? (" + *i2 + ") :\n\t\t\t(" + *i3 + ')'); i2++; i3++; } return listtemp_erg; } list synthesize_record_elseif(const knoten *const root, const knoten *const else_teil, VerilogModule &module, const list &vars, type_array &tarray, const string &postfix) { list listtemp2,listtemp3,listtemp_erg; list::const_iterator i2,i3; type_array tarray_dummy1,tarray_dummy2; string stringtemp1; int width; // two cases switch (root->subtyp) { case 242 : // elseif_plus -> ELSIF expr THEN expr // synthesize parts stringtemp1=synthesize_simple_expression(root->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[1],tarray,module,vars,postfix); listtemp3=synthesize_record_expression(else_teil,tarray_dummy2,module,vars,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy2)) { knot_error(cout << "Typen in record_elseif (case 242) stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy2 << "\n",root) } // put everything together i2=listtemp2.begin(); i3=listtemp3.begin(); while (i2!=listtemp2.end()) { listtemp_erg.push_back('('+ stringtemp1 + ") ? (" + *i2 + ") :\n\t\t\t(" + *i3 + ')'); i2++; i3++; } return listtemp_erg; case 243 : // elseif_plus -> ELSIF expr THEN expr elseif_plus // synthesize first parts stringtemp1=synthesize_simple_expression(root->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[1],tarray,module,vars,postfix); // synthesize elseif_plus teil listtemp3=synthesize_record_elseif(root->sub[2],else_teil,module,vars,tarray_dummy2,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy2)) { knot_error(cout << "Typen in record_elseif (case 243) stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy2 << "\n",root) } // gut verrühren und fertig! i2=listtemp2.begin(); i3=listtemp3.begin(); while (i2!=listtemp2.end()) { listtemp_erg.push_back('('+ stringtemp1 + ") ? (" + *i2 + ") :\n\t\t\t(" + *i3 + ')'); i2++; i3++; } return listtemp_erg; default : knot_error(printf("Aufruf von synthesize_record_elseif mit unzulaessigem Subtyp %i",root->subtyp),root) } } list synthesize_record_if_elseif(const knoten *const root, VerilogModule &module, const list &vars, type_array &tarray, const string &postfix) { type_array tarray_dummy1,tarray_dummy2; // expr ==> IF expr THEN expr elseif_plus ELSE expr ENDIF int width; string stringtemp1; list listtemp2,listtemp3,listtemp_erg; list::const_iterator i2,i3; // synthesize first part stringtemp1=synthesize_simple_expression(root->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[1],tarray,module,vars,postfix); // synthesize elseif_plus and ELSE-part listtemp3=synthesize_record_elseif(root->sub[2],root->sub[3],module,vars,tarray_dummy2,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy2)) { knot_error(cout << "Typen in record_if_elseif stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy2 << "\n",root) } // put everything together i2=listtemp2.begin(); i3=listtemp3.begin(); while (i2!=listtemp2.end()) { listtemp_erg.push_back('('+ stringtemp1 + ") ? (" + *i2 + ") :\n\t\t\t(" + *i3 + ')'); i2++; i3++; } return listtemp_erg; } list synthesize_record_cond_case_list(const knoten *const root, VerilogModule &module, const list &vars, type_array &tarray, const string &postfix) { string stringtemp1; int width; list listtemp2,listtemp3,listtemp4; list::const_iterator j,k; type_array tarray_dummy,tarray_dummy2; switch (root->subtyp) { case 233 : // cond_case_list -> cond_case // this is the LAST case in the cond case list // -> just add the expr // (treated like ELSE -> expr in the above cond_case_list) return synthesize_record_expression(root->sub[0]->sub[1],tarray,module,vars,postfix); case 234 : // cond_case_list -> cond_case, cond_case_list stringtemp1=synthesize_simple_expression(root->sub[0]->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[0]->sub[1],tarray,module,vars,postfix); listtemp4=synthesize_record_cond_case_list(root->sub[1],module,vars,tarray_dummy,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy)) { knot_error(cout << "Typen in cond_case_list (case 234) stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy << "\n",root) } j=listtemp2.begin(); k=listtemp4.begin(); while (j!=listtemp2.end()) { listtemp3.push_back('('+ stringtemp1 +")? (" + *j + "):\n\t\t\t(" + *k + ')'); j++; k++; } return listtemp3; case 235 : // cond_case_list -> cond_case ELSE MINUSGROESSER expr stringtemp1=synthesize_simple_expression(root->sub[0]->sub[0],module,vars,width); if (width!=1) { knot_error(cout << "Bitbreite einer Bedingung ungleich 1\n",root) } listtemp2=synthesize_record_expression(root->sub[0]->sub[1],tarray,module,vars,postfix); listtemp4=synthesize_record_expression(root->sub[1],tarray_dummy,module,vars,postfix); if (tarray.contains_ram()) knot_error(cout << "no conditional assignments involving ram are allowed!",root); // check, if both alternatives have same type if (!tarray.simple_equality(tarray_dummy)) { knot_error(cout << "Typen in cond_case_list (case 235) stimmen nicht überein:\n\tTyp 1 : " << tarray <<"\n\tTyp 2 : " << tarray_dummy << "\n",root) } j=listtemp2.begin(); k=listtemp4.begin(); while (j!=listtemp2.end()) { listtemp3.push_back('('+ stringtemp1 +")? (" + *j + "):\n\t\t\t(" + *k + ')'); j++; k++; } return listtemp3; default : knot_error(printf("Aufruf von synthesize_record_cond_case_list mit unzulaessigem Subtyp %i",root->subtyp),root) } } list synthesize_record_expression(const knoten *const root, type_array &tarray, VerilogModule &module, const list &vars, const string &postfix) { int index; int width; string function_out,str_tmp; type_array dummy,dummy2; list neu_vars; list rec_expr,rec_expr2; list::const_iterator i; list::iterator j; bool translated; switch (root->subtyp) { case 159 : // name if (root->sub[0]->subtyp==347 // name -> idop && root->sub[0]->sub[0]->subtyp==331) // idop -> ID { if (is_var_defined(vars,root->sub[0]->sub[0]->sub[0]->wert_str,dummy)) // name is a variable if (dummy.is_member(postfix,tarray)) return module.wire_names(root->sub[0]->sub[0]->sub[0]->wert_str+postfix, tarray); else knot_error(cout << postfix << " not member of " << root->sub[0]->sub[0]->sub[0]->wert_str,root) } if ((root->sub[0]->subtyp==348 || // name -> idop actuals root->sub[0]->subtyp==347) // name -> idop && root->sub[0]->sub[0]->subtyp==331) // idop -> ID { // name must be a function without arguments (constant function) function_out = synthesize_function_call(root,vars,module,dummy,translated); if (dummy.is_member(postfix,tarray)) if (translated) { rec_expr.push_back(function_out); return rec_expr; } else { return module.wire_names(function_out+postfix, tarray); } else knot_error(cout << postfix << " not member of " << dummy,root) } goto label; // treat opsym case (only one left) case 162 : // KLAMMERAUF_RAUTE assignment_list RAUTE_KLAMMERZU rec_expr=synthesize_assignment_list(root->sub[0],dummy,vars,module); if (dummy.is_member(postfix,tarray,rec_expr)) return rec_expr; else knot_error(cout << postfix << " not member of " << dummy,root) case 164 : // expr -> ( expr_list ) if (root->sub[0]->subtyp==246) // expr_list -> expr return synthesize_record_expression(root->sub[0]->sub[0],tarray,module,vars,postfix); knot_error(cout << "!!! '(' expr_list ')'not supported !!!\n",root); case 165 : // expr '`' ID return synthesize_record_expression(root->sub[0],tarray,module,vars, inv_compose_record_name(root->sub[1]->wert_str, postfix)); case 166 : // expr '`' NUMBER knot_error(cout << "expr '`' NUMBER not supported\n",root) case 227 : // expr -> LET bind_list IN expr neu_vars=vars; synthesize_bindlist(root->sub[0],module,neu_vars); return synthesize_record_expression(root->sub[1],tarray,module, neu_vars,postfix); case 228 : // expr WITH '[' assignment_list ']' { rec_expr=synthesize_record_expression(root->sub[0],tarray,module,vars,postfix); rec_expr2=synthesize_assignment_list(root->sub[1],dummy,vars,module); // simple merge rec_expr2 into rec_expr i=rec_expr2.begin(); for (int i_index=0; i_index IF expr THEN expr ELSE expr ENDIF return synthesize_record_if(root,module,vars,tarray,postfix); // return "((" + SYNTHESIZE1(root->sub[0]) + ") ? (" + // SYNTHESIZE case 219 : // expr -> IF expr THEN expr elseif_plus ELSE expr ENDIF return synthesize_record_if_elseif(root,module,vars,tarray,postfix); case 220 : // LAMBDA lambda_body // only possibility: "lambda_body -> lambda_formals ':' expr" if (root->sub[0]->sub[0]->subtyp!=253) // lambda_formal knot_error(cout << "only one LAMBDA formal supported!\n",root->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->subtyp!=257) // '(' adformals ')'? knot_error(cout << "only '(' adformals ')' LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=93) // adformal? knot_error(cout << "only one adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=95) // typeid? knot_error(cout << "only typeid as adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=337) // idop ':' type_expr? knot_error(cout << "only \"idop ':' type_expr\" as typeid in adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) if (root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->subtyp!=331) // ID? knot_error(cout << "only ID as idop in \"idop ':' type_expr\" as typeid in adformal in LAMBDA formals supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]) // now get the LAMBDA variable name and type function_out=root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->wert_str; get_type(root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[1],dummy); if (dummy.type[0]!=bounded_nat) knot_error(cout << "only bounded nat as LAMBDA formal type supported!\n", root->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[0]->sub[1]) for (index=dummy.upper_bound[0];index>=dummy.lower_bound[0];index--) { list bindings; bindings.push_front(binding(function_out,index)); knoten *copy=simplify_tree(root->sub[0]->sub[1],bindings); dummy2.empty(); rec_expr2 = synthesize_record_expression(copy,dummy2,module,vars,postfix); i=rec_expr2.begin(); while (i!=rec_expr2.end()) rec_expr.push_back(*i++); knoten_speicherfreigeben(copy); } // special case : right side was just plain bit if (dummy2.name[0].empty() && dummy2.bitbreite[0]==1 && dummy2.ram_address_width[0]==0) { width=dummy.upper_bound[0]-dummy.lower_bound[0]+1; if (width>1) function_out='{'; else function_out=""; i=rec_expr.begin(); while (i!=rec_expr.end()) { function_out += *i++; if (i!=rec_expr.end()) function_out += ",\n\t\t\t"; } tarray.empty(); rec_expr.clear(); if (!tarray.add_member("",bitvector,width)) knot_error(cout << "record type " << tarray << " too complex!", root); if (width>1) function_out+='}'; rec_expr.push_back(function_out); } else if (!tarray.make_array(dummy2,dummy.lower_bound[0],dummy.upper_bound[0])) knot_error(cout << "record type " << tarray << " too complex!", root); return rec_expr; break; case 231 : // COND cond_case_list ENDCOND return synthesize_record_cond_case_list(root->sub[0],module,vars,tarray,postfix); case 167 : // expr funarg // functions contain at most one pair of braces // so this can only be a function if 'expr -> name' if (root->sub[0]->subtyp!=159) // expr -> name { label2: // make sure exprlist contains exactly one argument if (root->sub[1]->sub[0]->subtyp!=245) // exprleerlist -> exprlist knot_error(cout << "empty exprlist not supported here\n",root); if (root->sub[1]->sub[0]->sub[0]->subtyp!=246) // exprlist -> expr knot_error(cout << "bit selection/array takes only one argument\n",root); if (!is_constant(root->sub[1]->sub[0]->sub[0]->sub[0],index)) knot_error(cout << "argument for bit selection/array not const\n",root); rec_expr=synthesize_record_expression(root->sub[0],dummy,module,vars,""); // test for lambda if (dummy.name[0].empty() && dummy.type[0]==bitvector) { function_out=*rec_expr.begin(); width=dummy.bitbreite[0]; // check for simple name (doesn't need a new wire) if (!module.is_simple_wire_name(function_out)) { str_tmp=module.new_wiredefinition(width); module.new_assign(str_tmp,function_out); function_out=module.wire_name(str_tmp); // translate!!! } if (width!=1) // selection from single bits not supported! function_out+='[' + int_string(index) + ']'; if (!tarray.add_member("",bitvector,1)) knot_error(cout << "record type " << tarray << " too complex!", root); rec_expr2.push_back(function_out); return rec_expr2; } else { function_out='(' + int_string(index) + ')'+postfix; if (dummy.is_member(function_out,tarray,rec_expr)) return rec_expr; else knot_error(cout << function_out << " not member of " << dummy,root) } } else if ((root->sub[0]->sub[0]->subtyp==347 // name -> idop || root->sub[0]->sub[0]->subtyp==348) // name -> idop actuals && root->sub[0]->sub[0]->sub[0]->subtyp==331) // idop -> ID // this name is a function iff it is not a variable if (is_var_defined(vars,root->sub[0]->sub[0]->sub[0]->sub[0]->wert_str,dummy)) { goto label2; // i know gotos are ugly, but i need them here } else { function_out = synthesize_function_call(root,vars,module,dummy,translated); if (dummy.is_member(postfix,tarray)) if (translated) { rec_expr.push_back(function_out); return rec_expr; } else return module.wire_names(function_out+postfix, tarray); else knot_error(cout << postfix << " not member of " << dummy,root) } // else: default !!! (so there is NO BREAK here) default: label: function_out=SYNTHESIZE(root); if (!tarray.add_member("",bitvector,width)) knot_error(cout << "record type " << tarray << " too complex!", root); rec_expr.push_back(function_out); return rec_expr; } } type_array register_tarray; synthesized_function synthesize_function(const defined_function &function, const list &bindings, const string parentname, bool raise_error/*=true*/) { int dummy; knoten *copy; type_array tarray; type_array tarray2; string str_bindings=binding_string(bindings); VerilogModule module(unique_module_name(function.name,str_bindings), raise_error? type_array(): register_tarray); synthesized_function ret(function.name,str_bindings); defined_function dummy2; if (is_function_synthesized(function.name, str_bindings, ret)) { if (parameter_verbose) cout << "Funktion " << function.name << " mit Bindings " << str_bindings << " ist bereits synthetisert...\n"; } else { // synthesize and add to synthesized_functions if (parameter_verbose) cout << "Funktion " << function.name << " mit Bindings " << str_bindings << " wird synthetisiert...\n"; // now get all parameter types for (int i=function.params.num-1; i>=0; i--) if (!is_bound(bindings,function.params.names[i],dummy)) { if (is_function_defined(function.params.names[i],dummy2)) { if (dummy2.params.num==0) { fun_error(cout << "parameter-name " << function.params.names[i] << " is overloaded by function-definition.\n",function) } } tarray.empty(); get_type_with_bindings(function.params.roots[i],bindings,tarray); var param(function.params.names[i],tarray); if (parameter_verbose) cout << "Parameter " << function.params.num-i << ": " << param << endl; if (!tarray.is_simple()) if (raise_error) fun_error(cout << "unzulaessiger Parameter " << param << endl,function) else { cout << "Funktion " << function.name << " nicht synthetisierbar; wird uebergangen!\n"; return ret; // ret is dummy value! } else { ret.parameters.push_back(param); module.new_inputparameter(param); // test, if function has to be connected to TOP-Level module connect_outside *connect_out=is_connect_outside_function(function.name+"x"+str_bindings); if (connect_out!=NULL) { if (connect_out->first) // this is the low-level function to be connected outside { connect_out->parameterstring+="\n"+module.new_outside_inputparameter(param,true,connect_out->original_functionname); } } } } // and the return type string return_wire; tarray.empty(); get_type_with_bindings(function.return_type,bindings,tarray); if (parameter_verbose) cout << "return type " << tarray << endl; if (!tarray.is_simple()) if (raise_error) fun_error(cout << "unzulaessiger Rueckgabetyp\n",function) else { cout << "Funktion " << function.name << " nicht synthetisierbar; wird uebergangen!\n"; return ret; } else { ret.return_type=tarray; return_wire=module.new_outputparameter(tarray); // falls die Funktion wires hat, die nach außen verbunden werden sollen, so wird das jetzt getan // test, if function has to be connected to TOP-Level module connect_outside *connect_out=is_connect_outside_function(function.name+"x"+str_bindings); if (connect_out!=NULL) { if (connect_out->first) // this is the low-level function to be connected outside { connect_out->parameterstring+=module.new_outside_outputparameter(tarray,true,connect_out->original_functionname); } } } synthesized_functions.push_back(ret); predefined_function pred_fun; if (is_function_in_lookup_table(function.name+str_bindings,pred_fun)) { if (parameter_verbose) cout << "function " << function.name << " synthesized from lookup table\n"; // test, if function has to be connected to TOP-Level module connect_outside *connect_out=is_connect_outside_function(function.name+"x"+str_bindings); if (connect_out!=NULL) { while (connect_out!=NULL) { connect_out->functionname=parentname; connect_out->feedthrough_functions.push_back(parentname); if (connect_out->first) { connect_out->function=function; connect_out->bindings=str_bindings; connect_out->first=false; } else { // create additional parameters and assigns synthesized_function synth_func; if (is_function_synthesized(connect_out->function.name,connect_out->bindings,synth_func)) { module.reset_outside_parameteranzahl(); list::const_iterator i=synth_func.parameters.begin(); while (i!=synth_func.parameters.end()) { module.new_outside_inputparameter(*i,false,connect_out->original_functionname); i++; } } else { cout << "Error: Connect_outside_function not synthesized." << endl; exit(1); } } // falls es weitere einträge gibt, auch diese benutzen connect_out=next_connect_outside_function(function.name+"x"+str_bindings,connect_out->original_functionname); } } else { // generate module_call module.new_moduleaufruf(pred_fun.module_name,module.parameter_str); } ostr << module; } else if (!function.root) { if (function.params.num==0) // constant? { list dclist; for (int i=0; i return_expr=synthesize_record_expression(copy,tarray,module,ret.parameters,""); if (tarray!=ret.return_type) fun_error(cout << "return type doesn't match,\n\tfound " << tarray << "\n\texpected " << ret.return_type << "\n",function); module.new_assign(return_wire,return_expr,tarray); knoten_speicherfreigeben(copy); // test, if function has to be connected to TOP-Level module connect_outside *connect_out=is_connect_outside_function(function.name+"x"+str_bindings); if (connect_out!=NULL) { while (connect_out!=NULL) { connect_out->functionname=parentname; connect_out->feedthrough_functions.push_back(parentname); if (connect_out->first) { connect_out->function=function; connect_out->bindings=str_bindings; connect_out->first=false; } else { // create additional parameters and assigns // input-parameter synthesized_function synth_func; if (is_function_synthesized(connect_out->function.name,connect_out->bindings,synth_func)) { module.reset_outside_parameteranzahl(); list::const_iterator i=synth_func.parameters.begin(); while (i!=synth_func.parameters.end()) { module.new_outside_inputparameter(*i,false,connect_out->original_functionname); i++; } // output-parameter module.new_outside_outputparameter(synth_func.return_type,false,connect_out->original_functionname); } else { cout << "Error: Connect_outside_function not synthesized." << endl; exit(1); } } // falls es weitere einträge gibt, auch diese benutzen connect_out=next_connect_outside_function(function.name+"x"+str_bindings,connect_out->original_functionname); } } ostr << module; } } return ret; } int compute_nat_function(const struct knoten* root, const char* name, int *is_nat_function) { defined_function function; type_array tarray; list bindings; list parameters; knoten *copy; int ret_value=0; *is_nat_function=0; // get the function root node if (is_function_defined(name,function)) { // not just a name? if (root->subtyp != 159) // then fill in all the constant bindings get_function_call_bindings(root,function,bindings,parameters); // not a nat function if it contains non-nat parameters // or is just called with 'expr->name' while parameters are expected if (parameters.empty() && !(root->subtyp == 159 && function.params.num)) { // get return type get_type_with_bindings(function.return_type,bindings,tarray); // check for nat return type if (tarray.name[0].empty() && (tarray.type[0]==bounded_nat || tarray.type[0]==unbounded_nat)) { copy=simplify_tree(function.root,bindings); if (!is_constant(copy)) knot_error(cout << "nat function doesn't evaluate to constant expression", root); ret_value=get_constant_value(copy); knoten_speicherfreigeben(copy); *is_nat_function=1; } } } return ret_value; } void synthesize_root_functions(const char *filename, const char *register_name) { list empty_list; char zeit[80]; time_t dt; dt=time(NULL); strftime((char *)&zeit, 79, "%d/%m/%Y %T", localtime(&dt)); cout << "pass 2: trying to synthesize " << root_functions.size() << " root function(s)...\n"; if (register_name) { defined_type register_type; if (!is_type_defined(register_name,register_type)) raise_error(cout << "register type " << register_name << " not defined!\n"); get_type_with_bindings(register_type.root,empty_list,register_tarray); if (parameter_verbose) cout << "register type: " << register_tarray << endl; cout << "register type " << register_name << " contains " << register_tarray.bit_count() << " bits!\n"; } ostr.open(filename); // write a default header to the file ostr << "///////////////////////////////////////////////////////////////\n"; ostr << "// verilog source code generated by pvs2hdl translator //\n"; ostr << "// written by Dirk Leinenbach and Sven Beyer at //\n"; ostr << "// Saarland University, Computer Science Department, Germany //\n"; ostr << "// comments, suggestions & bug reports to //\n"; ostr << "// {dirkl,sbeyer}@cs.uni-sb.de //\n"; ostr << "///////////////////////////////////////////////////////////////\n\n"; ostr << "// This file was generated at "; ostr << zeit; ostr << "\n\n"; ostr << endl; ostr << "// Source infos\n"; ostr << pvs_fileinfo << endl << endl; list::const_iterator i=root_functions.begin(); while (i!=root_functions.end()) { if (parameter_verbose) cout << *i; else cout << "synthesizing " << i->name << endl; synthesize_function(*i++,empty_list,i->name,false); } }