VIS
|
00001 00023 #include "synthInt.h" 00024 00025 static char rcsid[] UNUSED = "$Id: synthSynth.c,v 1.47 2005/04/23 14:37:51 jinh Exp $"; 00026 00027 00028 /*---------------------------------------------------------------------------*/ 00029 /* Constant declarations */ 00030 /*---------------------------------------------------------------------------*/ 00031 00032 00033 /*---------------------------------------------------------------------------*/ 00034 /* Type declarations */ 00035 /*---------------------------------------------------------------------------*/ 00036 00037 00038 /*---------------------------------------------------------------------------*/ 00039 /* Structure declarations */ 00040 /*---------------------------------------------------------------------------*/ 00041 00042 00043 /*---------------------------------------------------------------------------*/ 00044 /* Variable declarations */ 00045 /*---------------------------------------------------------------------------*/ 00046 00047 00048 /*---------------------------------------------------------------------------*/ 00049 /* Macro declarations */ 00050 /*---------------------------------------------------------------------------*/ 00051 00052 00055 /*---------------------------------------------------------------------------*/ 00056 /* Static function prototypes */ 00057 /*---------------------------------------------------------------------------*/ 00058 00059 static int synthesizeNetwork(Ntk_Network_t *network, graph_t *partition, Fsm_Fsm_t *fsm, st_table *careBddTable, Synth_InfoData_t *synthInfo, int verbosity); 00060 static int IsPartitionValid(Ntk_Network_t *network, graph_t *partition); 00061 static array_t * GetCombOutputNameArray(Ntk_Network_t *network); 00062 static array_t * GetCombInputIdArray(Ntk_Network_t *network); 00063 static bdd_node ** GetBddArray(Mvf_Function_t *combMvfs); 00064 00068 /*---------------------------------------------------------------------------*/ 00069 /* Definition of exported functions */ 00070 /*---------------------------------------------------------------------------*/ 00071 00084 Synth_InfoData_t * 00085 Synth_InitializeInfo(int factoring, 00086 int divisor, 00087 int unreachDC, 00088 int reordering, 00089 int trySharing, 00090 int realign, 00091 char *filehead, 00092 char *prefix, 00093 boolean eqn) 00094 { 00095 00096 Synth_InfoData_t *synthInfo; 00097 00098 synthInfo = ALLOC(Synth_InfoData_t, 1); 00099 if (!synthInfo) { 00100 (void) fprintf(vis_stderr, 00101 "** synth error: Could not initialize info structure.\n"); 00102 return NIL(Synth_InfoData_t); 00103 } 00104 synthInfo->factoring = factoring; 00105 synthInfo->divisor = divisor; 00106 synthInfo->unreachDC = unreachDC; 00107 synthInfo->reordering = reordering; 00108 synthInfo->trySharing = trySharing; 00109 synthInfo->realign = realign; 00110 synthInfo->filehead = filehead; 00111 synthInfo->prefix = prefix; 00112 synthInfo->eqn = eqn; 00113 return synthInfo; 00114 } 00115 00127 void 00128 Synth_FreeInfo(Synth_InfoData_t *synthInfo) 00129 { 00130 FREE(synthInfo); 00131 } 00132 00148 int 00149 Synth_SynthesizeNetwork(Ntk_Network_t *network, 00150 graph_t *partition, 00151 st_table *careTable, 00152 Synth_InfoData_t *synthInfo, 00153 int verbosity) 00154 { 00155 graph_t *newPartition = NIL(graph_t); 00156 Fsm_Fsm_t *fsm = NIL(Fsm_Fsm_t); 00157 st_table *careBddTable; 00158 int status; 00159 int createdPart = 0; 00160 int createdFsm = 0; 00161 int ntkIsSeq = 1; 00162 00163 if (bdd_get_package_name() != CUDD) { 00164 (void) fprintf(vis_stderr, 00165 "** synth error: The synthesis package can be used only with CUDD package\n"); 00166 (void) fprintf(vis_stderr, 00167 "** synth error: Please link with the CUDD package\n"); 00168 return 0; 00169 } 00170 if (partition == NIL(graph_t)) { 00171 newPartition = (graph_t *) Ntk_NetworkReadApplInfo(network, 00172 PART_NETWORK_APPL_KEY); 00173 createdPart = 0; /* Using partition of the network. */ 00174 if (newPartition == NIL(graph_t) || 00175 (!IsPartitionValid(network,newPartition))) { 00176 newPartition = Part_NetworkCreatePartition(network, 00177 NIL(Hrc_Node_t), 00178 "dummy", (lsList) 0, 00179 (lsList) 0, NIL(mdd_t), 00180 Part_InOut_c, 00181 (lsList) 0, 00182 FALSE, FALSE, TRUE); 00183 if (newPartition == NIL(graph_t)) { 00184 (void) fprintf(vis_stderr,"** synth error: Could not create an InOut"); 00185 (void) fprintf(vis_stderr,"partition.\n"); 00186 return 0; 00187 } 00188 createdPart = 1; /* Using new partition */ 00189 } 00190 } else { 00191 if (IsPartitionValid(network,partition)) { 00192 newPartition = partition; 00193 createdPart = 2; /* Using the partition provided. */ 00194 } else { 00195 newPartition = Part_NetworkCreatePartition(network, 00196 NIL(Hrc_Node_t), 00197 "dummy", (lsList) 0, 00198 (lsList) 0, NIL(mdd_t), 00199 Part_InOut_c, 00200 (lsList) 0, 00201 FALSE, FALSE, TRUE); 00202 if (newPartition == NIL(graph_t)) { 00203 (void) fprintf(vis_stderr,"** synth error: Could not create an InOut"); 00204 (void) fprintf(vis_stderr,"partition.\n"); 00205 return 0; 00206 } 00207 createdPart = 1; 00208 } 00209 } 00210 00211 00212 if(!Ntk_NetworkReadNumLatches(network)) { 00213 (void) fprintf(vis_stdout, "** synth info: No latches present in the "); 00214 (void) fprintf(vis_stdout, "current network.\n"); 00215 (void) fprintf(vis_stdout, 00216 "** synth info: Proceeding with combinational synthesis.\n"); 00217 ntkIsSeq = 0; 00218 } 00219 00220 if (ntkIsSeq) { 00221 switch (createdPart) { 00222 case 0: 00223 /* Check if there is already an Fsm attached to 00224 * the network. 00225 */ 00226 fsm = (Fsm_Fsm_t *) Ntk_NetworkReadApplInfo(network, 00227 FSM_NETWORK_APPL_KEY); 00228 if (fsm == NIL(Fsm_Fsm_t)) { 00229 fsm = Fsm_FsmCreateFromNetworkWithPartition(network, 00230 NIL(graph_t)); 00231 if (fsm == NIL(Fsm_Fsm_t)) { 00232 (void) fprintf(vis_stderr,"** synth error: Could not create "); 00233 (void) fprintf(vis_stderr,"an Fsm\n"); 00234 goto endgame; 00235 } 00236 createdFsm = 1; 00237 } else { 00238 createdFsm = 0; 00239 } 00240 break; 00241 case 1: 00242 case 2: 00243 fsm = Fsm_FsmCreateFromNetworkWithPartition(network, 00244 Part_PartitionDuplicate(newPartition)); 00245 00246 if (fsm == NIL(Fsm_Fsm_t)) { 00247 (void) fprintf(vis_stderr,"** synth error: Could not create "); 00248 (void) fprintf(vis_stderr,"an Fsm\n"); 00249 goto endgame; 00250 } 00251 createdFsm = 1; 00252 break; 00253 } 00254 } 00255 00256 careBddTable = NIL(st_table); 00257 if (careTable != NIL(st_table)) { 00258 mdd_t *mddTemp; 00259 bdd_node *ddNode; 00260 char *name; 00261 st_generator *stGen; 00262 00263 careBddTable = st_init_table(strcmp, st_strhash); 00264 st_foreach_item(careTable,stGen,&name,&mddTemp) { 00265 ddNode = bdd_extract_node_as_is(mddTemp); 00266 st_insert(careBddTable,name,(char *)ddNode); 00267 } 00268 } 00269 if (fsm) 00270 status = synthesizeNetwork(network, newPartition, 00271 fsm, careBddTable, synthInfo, 00272 verbosity); 00273 else 00274 status = synthesizeNetwork(network,newPartition, 00275 NIL(Fsm_Fsm_t), careBddTable, 00276 synthInfo, verbosity); 00277 00278 if (careBddTable) 00279 st_free_table(careBddTable); 00280 if (createdPart == 1) 00281 Part_PartitionFree(newPartition); 00282 if (createdFsm == 1) 00283 Fsm_FsmFree(fsm); 00284 00285 return status; 00286 00287 endgame: 00288 if (createdPart == 1) 00289 Part_PartitionFree(newPartition); 00290 if (createdFsm == 1) 00291 Fsm_FsmFree(fsm); 00292 00293 return 0; 00294 00295 } 00296 00310 int 00311 Synth_SynthesizeFsm(Fsm_Fsm_t *fsm, 00312 st_table *careTable, 00313 Synth_InfoData_t *synthInfo, 00314 int verbosity) 00315 { 00316 Ntk_Network_t *network; 00317 graph_t *partition; 00318 st_table *careBddTable; 00319 int status; 00320 00321 network = Fsm_FsmReadNetwork(fsm); 00322 partition = Fsm_FsmReadPartition(fsm); 00323 00324 careBddTable = NIL(st_table); 00325 if (careTable != NIL(st_table)) { 00326 mdd_t *mddTemp; 00327 bdd_node *ddNode; 00328 char *name; 00329 st_generator *stGen; 00330 00331 careBddTable = st_init_table(strcmp, st_strhash); 00332 st_foreach_item(careTable,stGen,&name,&mddTemp) { 00333 ddNode = bdd_extract_node_as_is(mddTemp); 00334 st_insert(careBddTable,name,(char *)ddNode); 00335 } 00336 } 00337 00338 status = synthesizeNetwork(network,partition,fsm,careBddTable,synthInfo, 00339 verbosity); 00340 if (careBddTable) 00341 st_free_table(careBddTable); 00342 00343 return status; 00344 } 00345 00346 /*---------------------------------------------------------------------------*/ 00347 /* Definition of internal functions */ 00348 /*---------------------------------------------------------------------------*/ 00349 00350 00351 /*---------------------------------------------------------------------------*/ 00352 /* Definition of static functions */ 00353 /*---------------------------------------------------------------------------*/ 00354 00367 static int 00368 synthesizeNetwork(Ntk_Network_t *network, 00369 graph_t *partition, 00370 Fsm_Fsm_t *fsm, 00371 st_table *careBddTable, 00372 Synth_InfoData_t *synthInfo, 00373 int verbosity) 00374 { 00375 bdd_manager *ddManager = (bdd_manager *) Ntk_NetworkReadMddManager(network); 00376 int i, numOut; 00377 int *initStates = NIL(int); 00378 Mvf_Function_t *combMvfs; 00379 array_t *inputIds, *combOutNamesArray; 00380 bdd_node **combOutBdds, *ddTemp; 00381 bdd_node *unReachable = NIL(bdd_node), *reachable = NIL(bdd_node); 00382 bdd_node **combUpperBdds; 00383 bdd_node *initBdd = NIL(bdd_node), *temp; 00384 char **combOutNames; 00385 char *str; 00386 int realign_bdd, realign_zdd; 00387 Fsm_RchType_t reachMethod; 00388 00389 /* Save current values of realignment flags. */ 00390 realign_zdd = bdd_zdd_realignment_enabled(ddManager); 00391 realign_bdd = bdd_realignment_enabled(ddManager); 00392 00393 if (synthInfo->reordering == 1) { 00394 if (synthInfo->realign) 00395 bdd_zdd_realign_enable(ddManager); 00396 else 00397 bdd_zdd_realign_disable(ddManager); 00398 bdd_realign_disable(ddManager); 00399 } else if (synthInfo->reordering == 2) { 00400 bdd_zdd_realign_disable(ddManager); 00401 if (synthInfo->realign) 00402 bdd_realign_enable(ddManager); 00403 else 00404 bdd_realign_disable(ddManager); 00405 } else { 00406 bdd_zdd_realign_disable(ddManager); 00407 bdd_realign_disable(ddManager); 00408 } 00409 00410 /* Get the names of the combinational outputs, i.e, next state functions 00411 * as well as primary outputs. In VIS even latch initial inputs are 00412 * considered combinational outputs. Since, we support only blif files, 00413 * latch initial inputs are not present in combOutNamesArray. 00414 */ 00415 combOutNamesArray = GetCombOutputNameArray(network); 00416 if (combOutNamesArray == NIL(array_t)) { 00417 if (realign_zdd == 1) 00418 bdd_zdd_realign_enable(ddManager); 00419 else 00420 bdd_zdd_realign_disable(ddManager); 00421 if (realign_bdd == 1) 00422 bdd_realign_enable(ddManager); 00423 else 00424 bdd_realign_disable(ddManager); 00425 return 0; 00426 } 00427 /* Get the array of combinational inputs, i.e., primary inputs, 00428 * present state variables. 00429 */ 00430 inputIds = GetCombInputIdArray(network); 00431 if (inputIds == NIL(array_t)) { 00432 array_free(combOutNamesArray); 00433 /* Restore values of realignment flags. */ 00434 if (realign_zdd == 1) 00435 bdd_zdd_realign_enable(ddManager); 00436 else 00437 bdd_zdd_realign_disable(ddManager); 00438 if (realign_bdd == 1) 00439 bdd_realign_enable(ddManager); 00440 else 00441 bdd_realign_disable(ddManager); 00442 return 0; 00443 } 00444 /* Compute the Bdds */ 00445 combMvfs = Part_PartitionBuildFunctions(partition,combOutNamesArray, 00446 inputIds,NIL(mdd_t)); 00447 combOutBdds = (bdd_node **) GetBddArray(combMvfs); 00448 if (combOutBdds == NIL(bdd_node *)) { 00449 array_free(combOutNamesArray); 00450 array_free(inputIds); 00451 Mvf_FunctionArrayFree(combMvfs); 00452 if (realign_zdd == 1) 00453 bdd_zdd_realign_enable(ddManager); 00454 else 00455 bdd_zdd_realign_disable(ddManager); 00456 if (realign_bdd == 1) 00457 bdd_realign_enable(ddManager); 00458 else 00459 bdd_realign_disable(ddManager); 00460 return 0; 00461 } 00462 Mvf_FunctionArrayFree(combMvfs); 00463 00464 numOut = array_n(combOutNamesArray); 00465 combOutNames = ALLOC(char *, numOut); 00466 if (combOutNames == NIL(char *)) { 00467 (void) fprintf(vis_stderr,"** synth error: Could not allocate memory\n"); 00468 array_free(combOutNamesArray); 00469 array_free(inputIds); 00470 00471 for (i = 0; i < numOut; i++) { 00472 bdd_recursive_deref(ddManager,combOutBdds[i]); 00473 } 00474 FREE(combOutBdds); 00475 if (realign_zdd == 1) 00476 bdd_zdd_realign_enable(ddManager); 00477 else 00478 bdd_zdd_realign_disable(ddManager); 00479 if (realign_bdd == 1) 00480 bdd_realign_enable(ddManager); 00481 else 00482 bdd_realign_disable(ddManager); 00483 return 0; 00484 } 00485 arrayForEachItem(char *, combOutNamesArray, i, str) { 00486 combOutNames[i] = str; 00487 } 00488 array_free(combOutNamesArray); 00489 00490 00491 combUpperBdds = ALLOC(bdd_node *,numOut); 00492 /* Initialize the upper bound to be the lower bound */ 00493 for (i = 0; i < numOut; i++) { 00494 bdd_ref(combUpperBdds[i] = combOutBdds[i]); 00495 } 00496 00497 if (fsm) { 00498 mdd_t *initMdd; 00499 /* Duplicate copy of initial States is returned */ 00500 initMdd = Fsm_FsmComputeInitialStates(fsm); 00501 initBdd = (bdd_node *)bdd_extract_node_as_is(initMdd); 00502 bdd_ref(initBdd); 00503 mdd_free(initMdd); 00504 00505 if (synthInfo->unreachDC) { 00506 mdd_t *reachStates; 00507 00508 (void) fprintf(vis_stdout, 00509 "** synth info: Using unreachable states as dont cares\n"); 00510 if (synthInfo->unreachDC == 1) { 00511 reachMethod = Fsm_Rch_Bfs_c; 00512 } else if (synthInfo->unreachDC == 2) { 00513 reachMethod = Fsm_Rch_Hd_c; 00514 } else if (synthInfo->unreachDC == 3) { 00515 reachMethod = Fsm_Rch_Oa_c; 00516 } else { 00517 reachMethod = Fsm_Rch_Default_c; 00518 } 00519 reachStates = Fsm_FsmComputeReachableStates(fsm,0,0,0,0, 00520 0,0,1000,reachMethod, 00521 0,0,NIL(array_t), FALSE, 00522 NIL(array_t)); 00523 reachable = (bdd_node *)bdd_extract_node_as_is(reachStates); 00524 bdd_ref(reachable); 00525 unReachable = bdd_not_bdd_node(reachable); 00526 bdd_ref(unReachable); 00527 mdd_free(reachStates); 00528 } 00529 } 00530 00531 if (careBddTable == NIL(st_table)) { 00532 if (fsm && synthInfo->unreachDC) { 00533 /* Upper bound = LowerBould + DC */ 00534 for (i = 0; i < numOut; i++) { 00535 bdd_recursive_deref(ddManager,combUpperBdds[i]); 00536 combUpperBdds[i] = bdd_bdd_or(ddManager,combOutBdds[i], 00537 unReachable); 00538 bdd_ref(combUpperBdds[i]); 00539 } 00540 00541 /* LowerBound = OutputFuns . Care */ 00542 bdd_recursive_deref(ddManager,unReachable); 00543 for (i = 0; i < numOut; i++) { 00544 bdd_node *temp; 00545 temp = bdd_bdd_and(ddManager,combOutBdds[i],reachable); 00546 bdd_ref(temp); 00547 bdd_recursive_deref(ddManager,combOutBdds[i]); 00548 combOutBdds[i] = temp; 00549 } 00550 bdd_recursive_deref(ddManager,reachable); 00551 } 00552 } else { /* Use the cares supplied. */ 00553 if (fsm && synthInfo->unreachDC) { 00554 bdd_recursive_deref(ddManager,unReachable); 00555 } 00556 for (i = 0; i < numOut; i++) { 00557 bdd_node *dontCare,*care; 00558 00559 if (st_lookup(careBddTable,combOutNames[i],&ddTemp) == 1) { 00560 if (fsm && synthInfo->unreachDC) { 00561 bdd_ref(care = bdd_bdd_or(ddManager,ddTemp,reachable)); 00562 } else { 00563 bdd_ref(care = ddTemp); 00564 } 00565 bdd_ref(dontCare = bdd_not_bdd_node(care)); 00566 00567 /* Update the upper bound for each combinational output */ 00568 bdd_recursive_deref(ddManager,combUpperBdds[i]); 00569 combUpperBdds[i] = bdd_bdd_or(ddManager,combOutBdds[i],dontCare); 00570 bdd_ref(combUpperBdds[i]); 00571 bdd_recursive_deref(ddManager,dontCare); 00572 00573 /* Update the lower bound */ 00574 bdd_ref(temp = bdd_bdd_and(ddManager,combOutBdds[i],care)); 00575 bdd_recursive_deref(ddManager,combOutBdds[i]); 00576 bdd_recursive_deref(ddManager,care); 00577 combOutBdds[i]=temp; 00578 } 00579 } 00580 } 00581 00582 if (fsm) { 00583 bdd_t *bddVar, *bddTInit, *bddTtemp; 00584 int id, i = 0; 00585 lsGen gen; 00586 Ntk_Node_t *node; 00587 bdd_node *logicZero = bdd_read_logic_zero(ddManager); 00588 00589 bddTInit = bdd_construct_bdd_t(ddManager,initBdd); 00590 initStates = ALLOC(int, Ntk_NetworkReadNumLatches(network)); 00591 Ntk_NetworkForEachLatch(network,gen,node) { 00592 id = Ntk_NodeReadMddId(node); 00593 bddVar = bdd_get_variable(ddManager,id); 00594 bddTtemp = bdd_cofactor(bddTInit, bddVar); 00595 if (bdd_extract_node_as_is(bddTtemp) == logicZero) 00596 initStates[i] = 0; 00597 else 00598 initStates[i] = 1; 00599 i++; 00600 bdd_free(bddVar); 00601 bdd_free(bddTtemp); 00602 } 00603 /* This will free initBdd too. So, no need to deref it again. */ 00604 bdd_free(bddTInit); 00605 } 00606 00607 SynthMultiLevelOptimize(network,combOutBdds,combUpperBdds, 00608 combOutNames, initStates,synthInfo, 00609 verbosity); 00610 00611 /* Clean up. */ 00612 if (fsm) { 00613 FREE(initStates); 00614 } 00615 for (i = 0; i < numOut; i++) { 00616 bdd_recursive_deref(ddManager,combUpperBdds[i]); 00617 bdd_recursive_deref(ddManager,combOutBdds[i]); 00618 } 00619 FREE(combOutNames); 00620 FREE(combOutBdds); 00621 FREE(combUpperBdds); 00622 array_free(inputIds); 00623 if (realign_zdd == 1) 00624 bdd_zdd_realign_enable(ddManager); 00625 else 00626 bdd_zdd_realign_disable(ddManager); 00627 if (realign_bdd == 1) 00628 bdd_realign_enable(ddManager); 00629 else 00630 bdd_realign_disable(ddManager); 00631 return(1); 00632 } 00633 00648 static int 00649 IsPartitionValid(Ntk_Network_t *network, 00650 graph_t *partition) 00651 { 00652 Ntk_Node_t *node; 00653 lsGen gen; 00654 char *name; 00655 00656 Ntk_NetworkForEachCombOutput(network, gen, node) { 00657 name = Ntk_NodeReadName(node); 00658 if(Part_PartitionFindVertexByName(partition, name) == NIL(vertex_t)) { 00659 return(0); 00660 } 00661 } 00662 Ntk_NetworkForEachCombInput(network, gen, node) { 00663 name = Ntk_NodeReadName(node); 00664 if(Part_PartitionFindVertexByName(partition, name) == NIL(vertex_t)) { 00665 return(0); 00666 } 00667 } 00668 00669 return 1; 00670 } 00671 00672 00684 static array_t * 00685 GetCombOutputNameArray(Ntk_Network_t *network) 00686 { 00687 array_t *outputFunNames; 00688 lsGen gen; 00689 Ntk_Node_t *node; 00690 00691 outputFunNames = array_alloc(char *, 0); 00692 if (outputFunNames == NIL(array_t)) { 00693 (void) fprintf(vis_stderr,"** synth error: Could not allocate space "); 00694 (void) fprintf(vis_stderr,"for the names of combinational outputs\n"); 00695 return NIL(array_t); 00696 } 00697 Ntk_NetworkForEachCombOutput(network, gen, node){ 00698 if (Ntk_NodeTestIsLatchInitialInput(node)) 00699 continue; 00700 array_insert_last(char *, outputFunNames, 00701 Ntk_NodeReadName(node)); 00702 } 00703 return outputFunNames; 00704 } 00705 00717 static array_t * 00718 GetCombInputIdArray(Ntk_Network_t *network) 00719 { 00720 array_t *inputIds; 00721 lsGen gen; 00722 Ntk_Node_t *node; 00723 00724 inputIds = array_alloc(int, 0); 00725 if (inputIds == NIL(array_t)) { 00726 (void) fprintf(vis_stderr,"** synth error: Could not allocate space "); 00727 (void) fprintf(vis_stderr,"for an array of ids of comb. inputs\n"); 00728 return NIL(array_t); 00729 } 00730 Ntk_NetworkForEachCombInput(network, gen, node){ 00731 array_insert_last(int, inputIds, Ntk_NodeReadMddId(node)); 00732 } 00733 return inputIds; 00734 } 00735 00736 00748 static bdd_node ** 00749 GetBddArray(Mvf_Function_t *combMvfs) 00750 { 00751 bdd_node **bddArray; 00752 Mvf_Function_t *mvf; 00753 int i; 00754 00755 bddArray = ALLOC(bdd_node *,array_n(combMvfs)); 00756 if (bddArray == NIL(bdd_node *)) { 00757 (void) fprintf(vis_stderr,"** synth error: Could not allocate space "); 00758 (void) fprintf(vis_stderr,"for an array of Bdd nodes.\n"); 00759 return NIL(bdd_node *); 00760 } 00761 arrayForEachItem(Mvf_Function_t *, combMvfs, i, mvf) { 00762 mdd_t *mddTemp; 00763 00764 mddTemp = array_fetch(mdd_t *, mvf, 1); 00765 bddArray[i] = (bdd_node *) bdd_extract_node_as_is(mddTemp); 00766 bdd_ref(bddArray[i]); 00767 } 00768 return bddArray; 00769 } 00770