/* Returns a trace array [0..num_logical_nets-1] with the final routing of the circuit from the logical_block netlist, index of the trace array corresponds to the index of a vpack_net */ t_trace* vpr_resync_post_route_netlist_to_TI_CLAY_v1_architecture( INP const t_arch *arch) { t_trace *trace; /* Map post-routed traces to clb_nets and block */ resync_post_route_netlist(); /* Resolve logically equivalent inputs */ clay_logical_equivalence_handling(arch); /* Finalize traceback */ trace = alloc_and_load_final_routing_trace(); if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_COMPLETE_NET_TRACE)) { print_complete_net_trace(trace, getEchoFileName(E_ECHO_COMPLETE_NET_TRACE)); } return trace; }
/** * Pre-pack atoms in netlist to molecules * 1. Single atoms are by definition a molecule. * 2. Forced pack molecules are groupings of atoms that matches a t_pack_pattern definition. * 3. Chained molecules are molecules that follow a carry-chain style pattern: ie. a single linear chain that can be split across multiple complex blocks */ t_pack_molecule *alloc_and_load_pack_molecules( INP t_pack_patterns *list_of_pack_patterns, INP int num_packing_patterns, OUTP int *num_pack_molecule) { int i, j; t_pack_molecule *list_of_molecules_head; t_pack_molecule *cur_molecule; int L_num_blocks; struct s_linked_vptr* logical_block_molecule; cur_molecule = list_of_molecules_head = NULL; /* Find forced pack patterns */ /* TODO: Need to properly empirically investigate the right base cost function values (gain variable) and do some normalization */ for (i = 0; i < num_packing_patterns; i++) { for (j = 0; j < num_logical_blocks; j++) { cur_molecule = try_create_molecule(list_of_pack_patterns, i, j); if (cur_molecule != NULL) { cur_molecule->next = list_of_molecules_head; /* In the event of multiple molecules with the same logical block pattern, bias to use the molecule with less costly physical resources first */ /* TODO: Need to normalize magical number 100 */ cur_molecule->base_gain = cur_molecule->num_blocks - (cur_molecule->pack_pattern->base_cost / 100); list_of_molecules_head = cur_molecule; } } } /* jedit TODO: Find chain patterns */ /* List all logical blocks as a molecule for blocks that do not belong to any molecules. This allows the packer to be consistent as it now packs molecules only instead of atoms and molecules If a block belongs to a molecule, then carrying the single atoms around can make the packing problem more difficult because now it needs to consider splitting molecules. TODO: Need to handle following corner case, if I have a LUT -> FF -> multiplier, LUT + FF is one molecule and FF + multiplier is another, need to ensure that this is packable. Solution is probably to allow for single atom molecules until something a particular packing forces another molecule to get broken */ for (i = 0; i < num_logical_blocks; i++) { logical_block[i].expected_lowest_cost_primitive = get_expected_lowest_cost_primitive_for_logical_block(i); if (logical_block[i].packed_molecules == NULL) { cur_molecule = (t_pack_molecule*) my_calloc(1, sizeof(t_pack_molecule)); cur_molecule->valid = TRUE; cur_molecule->type = MOLECULE_SINGLE_ATOM; cur_molecule->num_blocks = 1; cur_molecule->root = 0; cur_molecule->num_ext_inputs = logical_block[i].used_input_pins; cur_molecule->chain_pattern = NULL; cur_molecule->pack_pattern = NULL; cur_molecule->logical_block_ptrs = (t_logical_block**) my_malloc( 1 * sizeof(t_logical_block*)); cur_molecule->logical_block_ptrs[0] = &logical_block[i]; cur_molecule->next = list_of_molecules_head; cur_molecule->base_gain = 1; list_of_molecules_head = cur_molecule; logical_block[i].packed_molecules = (struct s_linked_vptr*) my_calloc(1, sizeof(struct s_linked_vptr)); logical_block[i].packed_molecules->data_vptr = (void*) cur_molecule; } } /* Reduce incentive to use logical blocks as standalone blocks when molecules already exist */ for (i = 0; i < num_logical_blocks; i++) { logical_block_molecule = logical_block[i].packed_molecules; L_num_blocks = 1; while (logical_block_molecule != NULL) { cur_molecule = (t_pack_molecule*)logical_block_molecule->data_vptr; if (cur_molecule->num_blocks > L_num_blocks) { L_num_blocks = cur_molecule->num_blocks; break; } logical_block_molecule = logical_block_molecule->next; } if (L_num_blocks > 1) { logical_block_molecule = logical_block[i].packed_molecules; while (logical_block_molecule != NULL) { cur_molecule = (t_pack_molecule*)logical_block_molecule->data_vptr; if (cur_molecule->num_blocks == 1) { cur_molecule->base_gain /= L_num_blocks; } logical_block_molecule = logical_block_molecule->next; } } } if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_PRE_PACKING_MOLECULES_AND_PATTERNS)) { print_pack_molecules(getEchoFileName(E_ECHO_PRE_PACKING_MOLECULES_AND_PATTERNS), list_of_pack_patterns, num_packing_patterns, list_of_molecules_head); } return list_of_molecules_head; }
void place_and_route(enum e_operation operation, struct s_placer_opts placer_opts, char *place_file, char *net_file, char *arch_file, char *route_file, struct s_annealing_sched annealing_sched, struct s_router_opts router_opts, struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf, t_timing_inf timing_inf, t_chan_width_dist chan_width_dist, struct s_model *models, t_direct_inf *directs, int num_directs) { /* This routine controls the overall placement and routing of a circuit. */ char msg[BUFSIZE]; int width_fac, i; boolean success, Fc_clipped; float **net_delay = NULL; t_slack * slacks = NULL; t_chunk net_delay_ch = {NULL, 0, NULL}; /*struct s_linked_vptr *net_delay_chunk_list_head;*/ t_ivec **clb_opins_used_locally = NULL; /* [0..num_blocks-1][0..num_class-1] */ int max_pins_per_clb; clock_t begin, end; Fc_clipped = FALSE; max_pins_per_clb = 0; for (i = 0; i < num_types; i++) { if (type_descriptors[i].num_pins > max_pins_per_clb) { max_pins_per_clb = type_descriptors[i].num_pins; } } if (placer_opts.place_freq == PLACE_NEVER) { /* Read the placement from a file */ read_place(place_file, net_file, arch_file, nx, ny, num_blocks, block); sync_grid_to_blocks(num_blocks, block, nx, ny, grid); } else { assert( (PLACE_ONCE == placer_opts.place_freq) || (PLACE_ALWAYS == placer_opts.place_freq)); begin = clock(); try_place(placer_opts, annealing_sched, chan_width_dist, router_opts, det_routing_arch, segment_inf, timing_inf, directs, num_directs); print_place(place_file, net_file, arch_file); end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "Placement took %g seconds.\n", (float)(end - begin) / CLOCKS_PER_SEC); #else vpr_printf(TIO_MESSAGE_INFO, "Placement took %g seconds.\n", (float)(end - begin) / CLK_PER_SEC); #endif } begin = clock(); post_place_sync(num_blocks, block); fflush(stdout); if (!router_opts.doRouting) return; width_fac = router_opts.fixed_channel_width; /* If channel width not fixed, use binary search to find min W */ if (NO_FIXED_CHANNEL_WIDTH == width_fac) { g_solution_inf.channel_width = binary_search_place_and_route(placer_opts, place_file, net_file, arch_file, route_file, router_opts.full_stats, router_opts.verify_binary_search, annealing_sched, router_opts, det_routing_arch, segment_inf, timing_inf, chan_width_dist, models, directs, num_directs); } else { g_solution_inf.channel_width = width_fac; if (det_routing_arch.directionality == UNI_DIRECTIONAL) { if (width_fac % 2 != 0) { vpr_printf(TIO_MESSAGE_ERROR, "in pack_place_and_route.c: Given odd chan width (%d) for udsd architecture.\n", width_fac); exit(1); } } /* Other constraints can be left to rr_graph to check since this is one pass routing */ /* Allocate the major routing structures. */ clb_opins_used_locally = alloc_route_structs(); slacks = alloc_and_load_timing_graph(timing_inf); net_delay = alloc_net_delay(&net_delay_ch, clb_net, num_nets); success = try_route(width_fac, router_opts, det_routing_arch, segment_inf, timing_inf, net_delay, slacks, chan_width_dist, clb_opins_used_locally, &Fc_clipped, directs, num_directs); if (Fc_clipped) { vpr_printf(TIO_MESSAGE_WARNING, "Fc_output was too high and was clipped to full (maximum) connectivity.\n"); } if (success == FALSE) { vpr_printf(TIO_MESSAGE_INFO, "Circuit is unrouteable with a channel width factor of %d.\n", width_fac); vpr_printf(TIO_MESSAGE_INFO, "\n"); sprintf(msg, "Routing failed with a channel width factor of %d. ILLEGAL routing shown.", width_fac); } else { check_route(router_opts.route_type, det_routing_arch.num_switch, clb_opins_used_locally); get_serial_num(); vpr_printf(TIO_MESSAGE_INFO, "Circuit successfully routed with a channel width factor of %d.\n", width_fac); vpr_printf(TIO_MESSAGE_INFO, "\n"); routing_stats(router_opts.full_stats, router_opts.route_type, det_routing_arch.num_switch, segment_inf, det_routing_arch.num_segment, det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos, det_routing_arch.directionality, timing_inf.timing_analysis_enabled, net_delay, slacks); print_route(route_file); if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_ROUTING_SINK_DELAYS)) { print_sink_delays(getEchoFileName(E_ECHO_ROUTING_SINK_DELAYS)); } sprintf(msg, "Routing succeeded with a channel width factor of %d.\n\n", width_fac); } init_draw_coords(max_pins_per_clb); update_screen(MAJOR, msg, ROUTING, timing_inf.timing_analysis_enabled); if (timing_inf.timing_analysis_enabled) { assert(slacks->slack); if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_POST_FLOW_TIMING_GRAPH)) { print_timing_graph_as_blif (getEchoFileName(E_ECHO_POST_FLOW_TIMING_GRAPH), models); } free_timing_graph(slacks); assert(net_delay); free_net_delay(net_delay, &net_delay_ch); } fflush(stdout); } if (clb_opins_used_locally != NULL) { for (i = 0; i < num_blocks; i++) { free_ivec_vector(clb_opins_used_locally[i], 0, block[i].type->num_class - 1); } free(clb_opins_used_locally); clb_opins_used_locally = NULL; } if(GetPostSynthesisOption()) { verilog_writer(); } end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "Routing took %g seconds.\n", (float) (end - begin) / CLOCKS_PER_SEC); #else vpr_printf(TIO_MESSAGE_INFO, "Routing took %g seconds.\n", (float)(end - begin) / CLK_PER_SEC); #endif /*WMF: cleaning up memory usage */ /* if (g_heap_free_head) free(g_heap_free_head); if (g_trace_free_head) free(g_trace_free_head); if (g_linked_f_pointer_free_head) free(g_linked_f_pointer_free_head);*/ }