static void check_source(int inode, int inet) { /* Checks that the node passed in is a valid source for this net. */ t_rr_type rr_type; t_type_ptr type; int i, j, ptc_num, bnum, node_block_pin, iclass; rr_type = rr_node[inode].type; if (rr_type != SOURCE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_source: net %d begins with a node of type %d.\n", inet, rr_type); exit(1); } i = rr_node[inode].xlow; j = rr_node[inode].ylow; ptc_num = rr_node[inode].ptc_num; /* for sinks and sources, ptc_num is class */ bnum = clb_net[inet].node_block[0]; /* First node_block for net is the source */ type = grid[i][j].type; if (block[bnum].x != i || block[bnum].y != j) { vpr_printf(TIO_MESSAGE_ERROR, "in check_source: net SOURCE is in wrong location (%d,%d).\n", i, j); exit(1); } node_block_pin = clb_net[inet].node_block_pin[0]; iclass = type->pin_class[node_block_pin]; if (ptc_num != iclass) { vpr_printf(TIO_MESSAGE_ERROR, "in check_source: net SOURCE is of wrong class (%d).\n", ptc_num); exit(1); } }
static void check_switch(struct s_trace *tptr, int num_switch) { /* Checks that the switch leading from this traceback element to the next * * one is a legal switch type. */ int inode; short switch_type; inode = tptr->index; switch_type = tptr->iswitch; if (rr_node[inode].type != SINK) { if (switch_type < 0 || switch_type >= num_switch) { vpr_printf(TIO_MESSAGE_ERROR, "in check_switch: rr_node %d left via switch type %d.\n", inode, switch_type); vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n"); exit(1); } } else { /* Is a SINK */ /* Without feedthroughs, there should be no switch. If feedthroughs are * * allowed, change to treat a SINK like any other node (as above). */ if (switch_type != OPEN) { vpr_printf(TIO_MESSAGE_ERROR, "in check_switch: rr_node %d is a SINK, but attempts to use a switch of type %d.\n", inode, switch_type); exit(1); } } }
static void CheckGrid() { int i, j; /* Check grid is valid */ for (i = 0; i <= (nx + 1); ++i) { for (j = 0; j <= (ny + 1); ++j) { if (NULL == grid[i][j].type) { vpr_printf(TIO_MESSAGE_ERROR, "grid[%d][%d] has no type.\n", i, j); exit(1); } if (grid[i][j].usage != 0) { vpr_printf(TIO_MESSAGE_ERROR, "grid[%d][%d] has non-zero usage (%d) before netlist load.\n", i, j, grid[i][j].usage); exit(1); } if ((grid[i][j].offset < 0) || (grid[i][j].offset >= grid[i][j].type->height)) { vpr_printf(TIO_MESSAGE_ERROR, "grid[%d][%d] has invalid offset (%d).\n", i, j, grid[i][j].offset); exit(1); } if ((NULL == grid[i][j].blocks) && (grid[i][j].type->capacity > 0)) { vpr_printf(TIO_MESSAGE_ERROR, "grid[%d][%d] has no block list allocated.\n", i, j); exit(1); } } } }
static void compute_delta_arrays(struct s_router_opts router_opts, struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf, t_timing_inf timing_inf, int longest_length) { vpr_printf(TIO_MESSAGE_INFO, "Computing delta_io_to_io lookup matrix, may take a few seconds, please wait...\n"); compute_delta_io_to_io(router_opts, det_routing_arch, segment_inf, timing_inf); vpr_printf(TIO_MESSAGE_INFO, "Computing delta_io_to_clb lookup matrix, may take a few seconds, please wait...\n"); compute_delta_io_to_clb(router_opts, det_routing_arch, segment_inf, timing_inf); vpr_printf(TIO_MESSAGE_INFO, "Computing delta_clb_to_io lookup matrix, may take a few seconds, please wait...\n"); compute_delta_clb_to_io(router_opts, det_routing_arch, segment_inf, timing_inf); vpr_printf(TIO_MESSAGE_INFO, "Computing delta_clb_to_clb lookup matrix, may take a few seconds, please wait...\n"); compute_delta_clb_to_clb(router_opts, det_routing_arch, segment_inf, timing_inf, longest_length); #ifdef PRINT_ARRAYS lookup_dump = my_fopen(DUMPFILE, "w", 0); fprintf(lookup_dump, "\n\nprinting delta_clb_to_clb\n"); print_array(delta_clb_to_clb, 0, nx - 1, 0, ny - 1); fprintf(lookup_dump, "\n\nprinting delta_io_to_clb\n"); print_array(delta_io_to_clb, 0, nx, 0, ny); fprintf(lookup_dump, "\n\nprinting delta_clb_to_io\n"); print_array(delta_clb_to_io, 0, nx, 0, ny); fprintf(lookup_dump, "\n\nprinting delta_io_to_io\n"); print_array(delta_io_to_io, 0, nx + 1, 0, ny + 1); fclose(lookup_dump); #endif }
void vpr_pack(INP t_vpr_setup vpr_setup, INP t_arch arch) { clock_t begin, end; float inter_cluster_delay = UNDEFINED, Tdel_opin_switch, Tdel_wire_switch, Tdel_wtoi_switch, R_opin_switch, R_wire_switch, R_wtoi_switch, Cout_opin_switch, Cout_wire_switch, Cout_wtoi_switch, opin_switch_del, wire_switch_del, wtoi_switch_del, Rmetal, Cmetal, first_wire_seg_delay, second_wire_seg_delay; begin = clock(); vpr_printf(TIO_MESSAGE_INFO, "Initialize packing.\n"); /* If needed, estimate inter-cluster delay. Assume the average routing hop goes out of a block through an opin switch to a length-4 wire, then through a wire switch to another length-4 wire, then through a wire-to-ipin-switch into another block. */ if (vpr_setup.PackerOpts.timing_driven && vpr_setup.PackerOpts.auto_compute_inter_cluster_net_delay) { opin_switch_del = get_switch_info(arch.Segments[0].opin_switch, Tdel_opin_switch, R_opin_switch, Cout_opin_switch); wire_switch_del = get_switch_info(arch.Segments[0].wire_switch, Tdel_wire_switch, R_wire_switch, Cout_wire_switch); wtoi_switch_del = get_switch_info( vpr_setup.RoutingArch.wire_to_ipin_switch, Tdel_wtoi_switch, R_wtoi_switch, Cout_wtoi_switch); /* wire-to-ipin switch */ Rmetal = arch.Segments[0].Rmetal; Cmetal = arch.Segments[0].Cmetal; /* The delay of a wire with its driving switch is the switch delay plus the product of the equivalent resistance and capacitance experienced by the wire. */ #define WIRE_SEGMENT_LENGTH 4 first_wire_seg_delay = opin_switch_del + (R_opin_switch + Rmetal * WIRE_SEGMENT_LENGTH / 2) * (Cout_opin_switch + Cmetal * WIRE_SEGMENT_LENGTH); second_wire_seg_delay = wire_switch_del + (R_wire_switch + Rmetal * WIRE_SEGMENT_LENGTH / 2) * (Cout_wire_switch + Cmetal * WIRE_SEGMENT_LENGTH); inter_cluster_delay = 4 * (first_wire_seg_delay + second_wire_seg_delay + wtoi_switch_del); /* multiply by 4 to get a more conservative estimate */ } try_pack(&vpr_setup.PackerOpts, &arch, vpr_setup.user_models, vpr_setup.library_models, vpr_setup.Timing, inter_cluster_delay); end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "Packing took %g seconds.\n", (float) (end - begin) / CLOCKS_PER_SEC); vpr_printf(TIO_MESSAGE_INFO, "Packing completed.\n"); #else vpr_printf(TIO_MESSAGE_INFO, "Packing took %g seconds.\n", (float)(end - begin) / CLK_PER_SEC); #endif fflush(stdout); }
/** * VPR program * Generate FPGA architecture given architecture description * Pack, place, and route circuit into FPGA architecture * Electrical timing analysis on results * * Overall steps * 1. Initialization * 2. Pack * 3. Place-and-route and timing analysis * 4. Clean up */ int main(int argc, char **argv) { t_options Options; t_arch Arch; t_vpr_setup vpr_setup; clock_t entire_flow_begin,entire_flow_end,end,begin; entire_flow_begin = clock(); //end = clock(); //begin = clock(); /* Read options, architecture, and circuit netlist */ vpr_init(argc, argv, &Options, &vpr_setup, &Arch); /* If the user requests packing, do packing */ if (vpr_setup.PackerOpts.doPacking) { vpr_pack(vpr_setup, Arch); } if (vpr_setup.PlacerOpts.doPlacement || vpr_setup.RouterOpts.doRouting) { vpr_init_pre_place_and_route(vpr_setup, Arch); vpr_place_and_route(vpr_setup, Arch, Options); #if 0 if(vpr_setup.RouterOpts.doRouting) { vpr_resync_post_route_netlist_to_TI_CLAY_v1_architecture(&Arch); } #endif } end = clock(); #ifdef CLOCKS_PER_SEC printf("Packing took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); #else printf("Packing took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); #endif if (vpr_setup.PowerOpts.do_power) { vpr_power_estimation(vpr_setup, Arch); } entire_flow_end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "The entire flow of VPR took %g seconds.\n", (float)(entire_flow_end - entire_flow_begin) / CLOCKS_PER_SEC); #else vpr_printf(TIO_MESSAGE_INFO, "The entire flow of VPR took %g seconds.\n", (float)(entire_flow_end - entire_flow_begin) / CLK_PER_SEC); #endif /* free data structures */ vpr_free_all(Arch, Options, vpr_setup); /* Return 0 to single success to scripts */ return 0; }
/* count up pin classes of the same number for the given cluster */ static void sum_pin_class(INOUTP t_pb_graph_node *pb_graph_node) { int i, j; /* This is a primitive, for each pin in primitive, sum appropriate pin class */ for (i = 0; i < pb_graph_node->num_input_ports; i++) { for (j = 0; j < pb_graph_node->num_input_pins[i]; j++) { assert( pb_graph_node->input_pins[i][j].pin_class < pb_graph_node->num_input_pin_class); if (pb_graph_node->input_pins[i][j].pin_class == OPEN) { vpr_printf(TIO_MESSAGE_WARNING, "%s[%d].%s[%d] unconnected pin in architecture.\n", pb_graph_node->pb_type->name, pb_graph_node->placement_index, pb_graph_node->input_pins[i][j].port->name, pb_graph_node->input_pins[i][j].pin_number); continue; } pb_graph_node->input_pin_class_size[pb_graph_node->input_pins[i][j].pin_class]++; } } for (i = 0; i < pb_graph_node->num_output_ports; i++) { for (j = 0; j < pb_graph_node->num_output_pins[i]; j++) { assert( pb_graph_node->output_pins[i][j].pin_class < pb_graph_node->num_output_pin_class); if (pb_graph_node->output_pins[i][j].pin_class == OPEN) { vpr_printf(TIO_MESSAGE_WARNING, "%s[%d].%s[%d] unconnected pin in architecture.\n", pb_graph_node->pb_type->name, pb_graph_node->placement_index, pb_graph_node->output_pins[i][j].port->name, pb_graph_node->output_pins[i][j].pin_number); continue; } pb_graph_node->output_pin_class_size[pb_graph_node->output_pins[i][j].pin_class]++; } } for (i = 0; i < pb_graph_node->num_clock_ports; i++) { for (j = 0; j < pb_graph_node->num_clock_pins[i]; j++) { assert( pb_graph_node->clock_pins[i][j].pin_class < pb_graph_node->num_input_pin_class); if (pb_graph_node->clock_pins[i][j].pin_class == OPEN) { vpr_printf(TIO_MESSAGE_WARNING, "%s[%d].%s[%d] unconnected pin in architecture.\n", pb_graph_node->pb_type->name, pb_graph_node->placement_index, pb_graph_node->clock_pins[i][j].port->name, pb_graph_node->clock_pins[i][j].pin_number); continue; } pb_graph_node->input_pin_class_size[pb_graph_node->clock_pins[i][j].pin_class]++; } } }
static void ShowOperation(INP enum e_operation Operation) { vpr_printf(TIO_MESSAGE_INFO, "Operation: "); switch (Operation) { case RUN_FLOW: vpr_printf(TIO_MESSAGE_INFO, "RUN_FLOW\n"); break; case TIMING_ANALYSIS_ONLY: vpr_printf(TIO_MESSAGE_INFO, "TIMING_ANALYSIS_ONLY\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown VPR operation\n"); } vpr_printf(TIO_MESSAGE_INFO, "\n"); }
void ShowSetup(INP t_options options, INP t_vpr_setup vpr_setup) { vpr_printf(TIO_MESSAGE_INFO, "Timing analysis: %s\n", (vpr_setup.TimingEnabled? "ON" : "OFF")); vpr_printf(TIO_MESSAGE_INFO, "Circuit netlist file: %s\n", vpr_setup.FileNameOpts.NetFile); vpr_printf(TIO_MESSAGE_INFO, "Circuit placement file: %s\n", vpr_setup.FileNameOpts.PlaceFile); vpr_printf(TIO_MESSAGE_INFO, "Circuit routing file: %s\n", vpr_setup.FileNameOpts.RouteFile); vpr_printf(TIO_MESSAGE_INFO, "Circuit SDC file: %s\n", vpr_setup.Timing.SDCFile); ShowOperation(vpr_setup.Operation); vpr_printf(TIO_MESSAGE_INFO, "Packer: %s\n", (vpr_setup.PackerOpts.doPacking ? "ENABLED" : "DISABLED")); vpr_printf(TIO_MESSAGE_INFO, "Placer: %s\n", (vpr_setup.PlacerOpts.doPlacement ? "ENABLED" : "DISABLED")); vpr_printf(TIO_MESSAGE_INFO, "Router: %s\n", (vpr_setup.RouterOpts.doRouting ? "ENABLED" : "DISABLED")); if (vpr_setup.PackerOpts.doPacking) { ShowPackerOpts(vpr_setup.PackerOpts); } if (vpr_setup.PlacerOpts.doPlacement) { ShowPlacerOpts(options, vpr_setup.PlacerOpts, vpr_setup.AnnealSched); } if (vpr_setup.RouterOpts.doRouting) { ShowRouterOpts(vpr_setup.RouterOpts); } if (DETAILED == vpr_setup.RouterOpts.route_type) ShowRoutingArch(vpr_setup.RoutingArch); }
static void check_sink(int inode, int inet, boolean * pin_done) { /* Checks that this SINK node is one of the terminals of inet, and marks * * the appropriate pin as being reached. */ int i, j, ipin, ifound, ptc_num, bnum, iclass, node_block_pin, iblk; t_type_ptr type; assert(rr_node[inode].type == SINK); i = rr_node[inode].xlow; j = rr_node[inode].ylow; type = grid[i][j].type; ptc_num = rr_node[inode].ptc_num; /* For sinks, ptc_num is the class */ ifound = 0; for (iblk = 0; iblk < type->capacity; iblk++) { bnum = grid[i][j].blocks[iblk]; /* Hardcoded to one block */ for (ipin = 1; ipin < (clb_net[inet].num_sinks + 1); ipin++) { /* All net SINKs */ if (clb_net[inet].node_block[ipin] == bnum) { node_block_pin = clb_net[inet].node_block_pin[ipin]; iclass = type->pin_class[node_block_pin]; if (iclass == ptc_num) { /* Could connect to same pin class on the same clb more than once. Only * * update pin_done for a pin that hasn't been reached yet. */ if (pin_done[ipin] == FALSE) { ifound++; pin_done[ipin] = TRUE; } } } } } if (ifound > 1 && type == IO_TYPE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_sink: found %d terminals of net %d of pad %d at location (%d, %d).\n", ifound, inet, ptc_num, i, j); exit(1); } if (ifound < 1) { vpr_printf(TIO_MESSAGE_ERROR, "in check_sink: node %d does not connect to any terminal of net %s #%d.\n" "This error is usually caused by incorrectly specified logical equivalence in your architecture file.\n" "You should try to respecify what pins are equivalent or turn logical equivalence off.\n", inode, clb_net[inet].name, inet); exit(1); } }
/* Display general VPR information */ void vpr_print_title(void) { vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "VPR FPGA Placement and Routing.\n"); vpr_printf(TIO_MESSAGE_INFO, "Version: Version " VPR_VERSION "\n"); vpr_printf(TIO_MESSAGE_INFO, "Compiled: " __DATE__ ".\n"); vpr_printf(TIO_MESSAGE_INFO, "University of Toronto\n"); vpr_printf(TIO_MESSAGE_INFO, "[email protected]\n"); vpr_printf(TIO_MESSAGE_INFO, "This is free open source code under MIT license.\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void check_locally_used_clb_opins(t_ivec ** clb_opins_used_locally, enum e_route_type route_type) { /* Checks that enough OPINs on CLBs have been set aside (used up) to make a * * legal routing if subblocks connect to OPINs directly. */ int iclass, iblk, num_local_opins, inode, ipin; t_rr_type rr_type; for (iblk = 0; iblk < num_blocks; iblk++) { for (iclass = 0; iclass < block[iblk].type->num_class; iclass++) { num_local_opins = clb_opins_used_locally[iblk][iclass].nelem; /* Always 0 for pads and for SINK classes */ for (ipin = 0; ipin < num_local_opins; ipin++) { inode = clb_opins_used_locally[iblk][iclass].list[ipin]; check_node_and_range(inode, route_type); /* Node makes sense? */ /* Now check that node is an OPIN of the right type. */ rr_type = rr_node[inode].type; if (rr_type != OPIN) { vpr_printf(TIO_MESSAGE_ERROR, "in check_locally_used_opins: block #%d (%s)\n", iblk, block[iblk].name); vpr_printf(TIO_MESSAGE_ERROR, "\tClass %d local OPIN is wrong rr_type -- rr_node #%d of type %d.\n", iclass, inode, rr_type); exit(1); } ipin = rr_node[inode].ptc_num; if (block[iblk].type->pin_class[ipin] != iclass) { vpr_printf(TIO_MESSAGE_ERROR, "in check_locally_used_opins: block #%d (%s):\n", iblk, block[iblk].name); vpr_printf(TIO_MESSAGE_ERROR, "\tExpected class %d local OPIN has class %d -- rr_node #: %d.\n", iclass, block[iblk].type->pin_class[ipin], inode); exit(1); } } } } }
static void check_node_and_range(int inode, enum e_route_type route_type) { /* Checks that inode is within the legal range, then calls check_node to * * check that everything else about the node is OK. */ if (inode < 0 || inode >= num_rr_nodes) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node_and_range: rr_node #%d is out of legal, range (0 to %d).\n", inode, num_rr_nodes - 1); exit(1); } check_node(inode, route_type); }
void printClusteredNetlistStats() { int i, j, L_num_p_inputs, L_num_p_outputs; int *num_blocks_type; num_blocks_type = (int*) my_calloc(num_types, sizeof(int)); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Netlist num_nets: %d\n", num_nets); vpr_printf(TIO_MESSAGE_INFO, "Netlist num_blocks: %d\n", num_blocks); for (i = 0; i < num_types; i++) { num_blocks_type[i] = 0; } /* Count I/O input and output pads */ L_num_p_inputs = 0; L_num_p_outputs = 0; for (i = 0; i < num_blocks; i++) { num_blocks_type[block[i].type->index]++; if (block[i].type == IO_TYPE) { for (j = 0; j < IO_TYPE->num_pins; j++) { if (block[i].nets[j] != OPEN) { if (IO_TYPE->class_inf[IO_TYPE->pin_class[j]].type == DRIVER) { L_num_p_inputs++; } else { assert( IO_TYPE-> class_inf[IO_TYPE-> pin_class[j]]. type == RECEIVER); L_num_p_outputs++; } } } } } for (i = 0; i < num_types; i++) { if (IO_TYPE != &type_descriptors[i]) { vpr_printf(TIO_MESSAGE_INFO, "Netlist %s blocks: %d.\n", type_descriptors[i].name, num_blocks_type[i]); } } /* Print out each block separately instead */ vpr_printf(TIO_MESSAGE_INFO, "Netlist inputs pins: %d\n", L_num_p_inputs); vpr_printf(TIO_MESSAGE_INFO, "Netlist output pins: %d\n", L_num_p_outputs); vpr_printf(TIO_MESSAGE_INFO, "\n"); free(num_blocks_type); }
static void ShowAnnealSched(INP struct s_annealing_sched AnnealSched) { vpr_printf(TIO_MESSAGE_INFO, "AnnealSched.type: "); switch (AnnealSched.type) { case AUTO_SCHED: vpr_printf(TIO_MESSAGE_INFO, "AUTO_SCHED\n"); break; case USER_SCHED: vpr_printf(TIO_MESSAGE_INFO, "USER_SCHED\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown annealing schedule\n"); } vpr_printf(TIO_MESSAGE_INFO, "AnnealSched.inner_num: %f\n", AnnealSched.inner_num); if (USER_SCHED == AnnealSched.type) { vpr_printf(TIO_MESSAGE_INFO, "AnnealSched.init_t: %f\n", AnnealSched.init_t); vpr_printf(TIO_MESSAGE_INFO, "AnnealSched.alpha_t: %f\n", AnnealSched.alpha_t); vpr_printf(TIO_MESSAGE_INFO, "AnnealSched.exit_t: %f\n", AnnealSched.exit_t); } }
static void print_string(const char *str_ptr, int *column, FILE * fpout) { /* Prints string without making any lines longer than LINELENGTH. Column * * points to the column in which the next character will go (both used and * * updated), and fpout points to the output file. */ int len; len = strlen(str_ptr); if (len + 3 > LINELENGTH) { vpr_printf(TIO_MESSAGE_ERROR, "in print_string: String %s is too long for desired maximum line length.\n", str_ptr); exit(1); } if (*column + len + 2 > LINELENGTH) { fprintf(fpout, "\\ \n"); *column = TABLENGTH; } fprintf(fpout, "%s ", str_ptr); *column += len + 1; }
static boolean check_adjacent(int from_node, int to_node) { /* This routine checks if the rr_node to_node is reachable from from_node. * * It returns TRUE if is reachable and FALSE if it is not. Check_node has * * already been used to verify that both nodes are valid rr_nodes, so only * * adjacency is checked here. * Special case: direct OPIN to IPIN connections need not be adjacent. These * represent specially-crafted connections such as carry-chains or more advanced * blocks where adjacency is overridden by the architect */ int from_xlow, from_ylow, to_xlow, to_ylow, from_ptc, to_ptc, iclass; int num_adj, to_xhigh, to_yhigh, from_xhigh, from_yhigh, iconn; boolean reached; t_rr_type from_type, to_type; t_type_ptr from_grid_type, to_grid_type; reached = FALSE; for (iconn = 0; iconn < rr_node[from_node].num_edges; iconn++) { if (rr_node[from_node].edges[iconn] == to_node) { reached = TRUE; break; } } if (!reached) return (FALSE); /* Now we know the rr graph says these two nodes are adjacent. Double * * check that this makes sense, to verify the rr graph. */ num_adj = 0; from_type = rr_node[from_node].type; from_xlow = rr_node[from_node].xlow; from_ylow = rr_node[from_node].ylow; from_xhigh = rr_node[from_node].xhigh; from_yhigh = rr_node[from_node].yhigh; from_ptc = rr_node[from_node].ptc_num; to_type = rr_node[to_node].type; to_xlow = rr_node[to_node].xlow; to_ylow = rr_node[to_node].ylow; to_xhigh = rr_node[to_node].xhigh; to_yhigh = rr_node[to_node].yhigh; to_ptc = rr_node[to_node].ptc_num; switch (from_type) { case SOURCE: assert(to_type == OPIN); if (from_xlow == to_xlow && from_ylow == to_ylow && from_xhigh == to_xhigh && from_yhigh == to_yhigh) { from_grid_type = grid[from_xlow][from_ylow].type; to_grid_type = grid[to_xlow][to_ylow].type; assert(from_grid_type == to_grid_type); iclass = to_grid_type->pin_class[to_ptc]; if (iclass == from_ptc) num_adj++; } break; case SINK: /* SINKS are adjacent to not connected */ break; case OPIN: if(to_type == CHANX || to_type == CHANY) { num_adj += pin_and_chan_adjacent(from_node, to_node); } else { assert(to_type == IPIN); /* direct OPIN to IPIN connections not necessarily adjacent */ return TRUE; /* Special case, direct OPIN to IPIN connections need not be adjacent */ } break; case IPIN: assert(to_type == SINK); if (from_xlow == to_xlow && from_ylow == to_ylow && from_xhigh == to_xhigh && from_yhigh == to_yhigh) { from_grid_type = grid[from_xlow][from_ylow].type; to_grid_type = grid[to_xlow][to_ylow].type; assert(from_grid_type == to_grid_type); iclass = from_grid_type->pin_class[from_ptc]; if (iclass == to_ptc) num_adj++; } break; case CHANX: if (to_type == IPIN) { num_adj += pin_and_chan_adjacent(to_node, from_node); } else if (to_type == CHANX) { from_xhigh = rr_node[from_node].xhigh; to_xhigh = rr_node[to_node].xhigh; if (from_ylow == to_ylow) { /* UDSD Modification by WMF Begin */ /*For Fs > 3, can connect to overlapping wire segment */ if (to_xhigh == from_xlow - 1 || from_xhigh == to_xlow - 1) { num_adj++; } /* Overlapping */ else { int i; for (i = from_xlow; i <= from_xhigh; i++) { if (i >= to_xlow && i <= to_xhigh) { num_adj++; break; } } } /* UDSD Modification by WMF End */ } } else if (to_type == CHANY) { num_adj += chanx_chany_adjacent(from_node, to_node); } else { assert(0); } break; case CHANY: if (to_type == IPIN) { num_adj += pin_and_chan_adjacent(to_node, from_node); } else if (to_type == CHANY) { from_yhigh = rr_node[from_node].yhigh; to_yhigh = rr_node[to_node].yhigh; if (from_xlow == to_xlow) { /* UDSD Modification by WMF Begin */ if (to_yhigh == from_ylow - 1 || from_yhigh == to_ylow - 1) { num_adj++; } /* Overlapping */ else { int j; for (j = from_ylow; j <= from_yhigh; j++) { if (j >= to_ylow && j <= to_yhigh) { num_adj++; break; } } } /* UDSD Modification by WMF End */ } } else if (to_type == CHANX) { num_adj += chanx_chany_adjacent(to_node, from_node); } else { assert(0); } break; default: break; } if (num_adj == 1) return (TRUE); else if (num_adj == 0) return (FALSE); vpr_printf(TIO_MESSAGE_ERROR, "in check_adjacent: num_adj = %d. Expected 0 or 1.\n", num_adj); exit(1); }
void check_route(enum e_route_type route_type, int num_switch, t_ivec ** clb_opins_used_locally) { /* This routine checks that a routing: (1) Describes a properly * * connected path for each net, (2) this path connects all the * * pins spanned by that net, and (3) that no routing resources are * * oversubscribed (the occupancy of everything is recomputed from * * scratch). */ int inet, ipin, max_pins, inode, prev_node; boolean valid, connects; boolean * connected_to_route; /* [0 .. num_rr_nodes-1] */ struct s_trace *tptr; boolean * pin_done; vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Checking to ensure routing is legal...\n"); /* Recompute the occupancy from scratch and check for overuse of routing * * resources. This was already checked in order to determine that this * * is a successful routing, but I want to double check it here. */ recompute_occupancy_from_scratch(clb_opins_used_locally); valid = feasible_routing(); if (valid == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "Error in check_route -- routing resources are overused.\n"); exit(1); } check_locally_used_clb_opins(clb_opins_used_locally, route_type); connected_to_route = (boolean *) my_calloc(num_rr_nodes, sizeof(boolean)); max_pins = 0; for (inet = 0; inet < num_nets; inet++) max_pins = std::max(max_pins, (clb_net[inet].num_sinks + 1)); pin_done = (boolean *) my_malloc(max_pins * sizeof(boolean)); /* Now check that all nets are indeed connected. */ for (inet = 0; inet < num_nets; inet++) { if (clb_net[inet].is_global || clb_net[inet].num_sinks == 0) /* Skip global nets. */ continue; for (ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) pin_done[ipin] = FALSE; /* Check the SOURCE of the net. */ tptr = trace_head[inet]; if (tptr == NULL) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d has no routing.\n", inet); exit(1); } inode = tptr->index; check_node_and_range(inode, route_type); check_switch(tptr, num_switch); connected_to_route[inode] = TRUE; /* Mark as in path. */ check_source(inode, inet); pin_done[0] = TRUE; prev_node = inode; tptr = tptr->next; /* Check the rest of the net */ while (tptr != NULL) { inode = tptr->index; check_node_and_range(inode, route_type); check_switch(tptr, num_switch); if (rr_node[prev_node].type == SINK) { if (connected_to_route[inode] == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: node %d does not link into existing routing for net %d.\n", inode, inet); exit(1); } } else { connects = check_adjacent(prev_node, inode); if (!connects) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: found non-adjacent segments in traceback while checking net %d.\n", inet); exit(1); } if (connected_to_route[inode] && rr_node[inode].type != SINK) { /* Note: Can get multiple connections to the same logically-equivalent * * SINK in some logic blocks. */ vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d routing is not a tree.\n", inet); exit(1); } connected_to_route[inode] = TRUE; /* Mark as in path. */ if (rr_node[inode].type == SINK) check_sink(inode, inet, pin_done); } /* End of prev_node type != SINK */ prev_node = inode; tptr = tptr->next; } /* End while */ if (rr_node[prev_node].type != SINK) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d does not end with a SINK.\n", inet); exit(1); } for (ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) { if (pin_done[ipin] == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d does not connect to pin %d.\n", inet, ipin); exit(1); } } reset_flags(inet, connected_to_route); } /* End for each net */ free(pin_done); free(connected_to_route); vpr_printf(TIO_MESSAGE_INFO, "Completed routing consistency check successfully.\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void ShowRouterOpts(INP struct s_router_opts RouterOpts) { vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.route_type: "); switch (RouterOpts.route_type) { case GLOBAL: vpr_printf(TIO_MESSAGE_INFO, "GLOBAL\n"); break; case DETAILED: vpr_printf(TIO_MESSAGE_INFO, "DETAILED\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown router opt\n"); } if (DETAILED == RouterOpts.route_type) { vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.router_algorithm: "); switch (RouterOpts.router_algorithm) { case BREADTH_FIRST: vpr_printf(TIO_MESSAGE_INFO, "BREADTH_FIRST\n"); break; case TIMING_DRIVEN: vpr_printf(TIO_MESSAGE_INFO, "TIMING_DRIVEN\n"); break; case NO_TIMING: vpr_printf(TIO_MESSAGE_INFO, "NO_TIMING\n"); break; default: vpr_printf(TIO_MESSAGE_INFO, "<Unknown>\n"); exit(1); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.base_cost_type: "); switch (RouterOpts.base_cost_type) { case INTRINSIC_DELAY: vpr_printf(TIO_MESSAGE_INFO, "INTRINSIC_DELAY\n"); break; case DELAY_NORMALIZED: vpr_printf(TIO_MESSAGE_INFO, "DELAY_NORMALIZED\n"); break; case DEMAND_ONLY: vpr_printf(TIO_MESSAGE_INFO, "DEMAND_ONLY\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown base_cost_type\n"); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.fixed_channel_width: "); if (NO_FIXED_CHANNEL_WIDTH == RouterOpts.fixed_channel_width) { vpr_printf(TIO_MESSAGE_INFO, "NO_FIXED_CHANNEL_WIDTH\n"); } else { vpr_printf(TIO_MESSAGE_INFO, "%d\n", RouterOpts.fixed_channel_width); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.acc_fac: %f\n", RouterOpts.acc_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.bb_factor: %d\n", RouterOpts.bb_factor); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.bend_cost: %f\n", RouterOpts.bend_cost); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.first_iter_pres_fac: %f\n", RouterOpts.first_iter_pres_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.initial_pres_fac: %f\n", RouterOpts.initial_pres_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.pres_fac_mult: %f\n", RouterOpts.pres_fac_mult); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.max_router_iterations: %d\n", RouterOpts.max_router_iterations); if (TIMING_DRIVEN == RouterOpts.router_algorithm) { vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.astar_fac: %f\n", RouterOpts.astar_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.criticality_exp: %f\n", RouterOpts.criticality_exp); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.max_criticality: %f\n", RouterOpts.max_criticality); } } else { assert(GLOBAL == RouterOpts.route_type); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.router_algorithm: "); switch (RouterOpts.router_algorithm) { case BREADTH_FIRST: vpr_printf(TIO_MESSAGE_INFO, "BREADTH_FIRST\n"); break; case TIMING_DRIVEN: vpr_printf(TIO_MESSAGE_INFO, "TIMING_DRIVEN\n"); break; case NO_TIMING: vpr_printf(TIO_MESSAGE_INFO, "NO_TIMING\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown router algorithm\n"); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.base_cost_type: "); switch (RouterOpts.base_cost_type) { case INTRINSIC_DELAY: vpr_printf(TIO_MESSAGE_INFO, "INTRINSIC_DELAY\n"); break; case DELAY_NORMALIZED: vpr_printf(TIO_MESSAGE_INFO, "DELAY_NORMALIZED\n"); break; case DEMAND_ONLY: vpr_printf(TIO_MESSAGE_INFO, "DEMAND_ONLY\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown router base cost type\n"); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.fixed_channel_width: "); if (NO_FIXED_CHANNEL_WIDTH == RouterOpts.fixed_channel_width) { vpr_printf(TIO_MESSAGE_INFO, "NO_FIXED_CHANNEL_WIDTH\n"); } else { vpr_printf(TIO_MESSAGE_INFO, "%d\n", RouterOpts.fixed_channel_width); } vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.acc_fac: %f\n", RouterOpts.acc_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.bb_factor: %d\n", RouterOpts.bb_factor); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.bend_cost: %f\n", RouterOpts.bend_cost); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.first_iter_pres_fac: %f\n", RouterOpts.first_iter_pres_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.initial_pres_fac: %f\n", RouterOpts.initial_pres_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.pres_fac_mult: %f\n", RouterOpts.pres_fac_mult); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.max_router_iterations: %d\n", RouterOpts.max_router_iterations); if (TIMING_DRIVEN == RouterOpts.router_algorithm) { vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.astar_fac: %f\n", RouterOpts.astar_fac); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.criticality_exp: %f\n", RouterOpts.criticality_exp); vpr_printf(TIO_MESSAGE_INFO, "RouterOpts.max_criticality: %f\n", RouterOpts.max_criticality); } } vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void ShowPlacerOpts(INP t_options Options, INP struct s_placer_opts PlacerOpts, INP struct s_annealing_sched AnnealSched) { vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.place_freq: "); switch (PlacerOpts.place_freq) { case PLACE_ONCE: vpr_printf(TIO_MESSAGE_INFO, "PLACE_ONCE\n"); break; case PLACE_ALWAYS: vpr_printf(TIO_MESSAGE_INFO, "PLACE_ALWAYS\n"); break; case PLACE_NEVER: vpr_printf(TIO_MESSAGE_INFO, "PLACE_NEVER\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown Place Freq\n"); } if ((PLACE_ONCE == PlacerOpts.place_freq) || (PLACE_ALWAYS == PlacerOpts.place_freq)) { vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.place_algorithm: "); switch (PlacerOpts.place_algorithm) { case BOUNDING_BOX_PLACE: vpr_printf(TIO_MESSAGE_INFO, "BOUNDING_BOX_PLACE\n"); break; case NET_TIMING_DRIVEN_PLACE: vpr_printf(TIO_MESSAGE_INFO, "NET_TIMING_DRIVEN_PLACE\n"); break; case PATH_TIMING_DRIVEN_PLACE: vpr_printf(TIO_MESSAGE_INFO, "PATH_TIMING_DRIVEN_PLACE\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "Unknown placement algorithm\n"); } vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.pad_loc_type: "); switch (PlacerOpts.pad_loc_type) { case FREE: vpr_printf(TIO_MESSAGE_INFO, "FREE\n"); break; case RANDOM: vpr_printf(TIO_MESSAGE_INFO, "RANDOM\n"); break; case USER: vpr_printf(TIO_MESSAGE_INFO, "USER '%s'\n", PlacerOpts.pad_loc_file); break; default: vpr_printf(TIO_MESSAGE_INFO, "Unknown I/O pad location type\n"); exit(1); } vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.place_cost_exp: %f\n", PlacerOpts.place_cost_exp); if (Options.Count[OT_PLACE_CHAN_WIDTH]) { vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.place_chan_width: %d\n", PlacerOpts.place_chan_width); } if ((NET_TIMING_DRIVEN_PLACE == PlacerOpts.place_algorithm) || (PATH_TIMING_DRIVEN_PLACE == PlacerOpts.place_algorithm)) { vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.inner_loop_recompute_divider: %d\n", PlacerOpts.inner_loop_recompute_divider); vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.recompute_crit_iter: %d\n", PlacerOpts.recompute_crit_iter); vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.timing_tradeoff: %f\n", PlacerOpts.timing_tradeoff); vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.td_place_exp_first: %f\n", PlacerOpts.td_place_exp_first); vpr_printf(TIO_MESSAGE_INFO, "PlacerOpts.td_place_exp_last: %f\n", PlacerOpts.td_place_exp_last); } vpr_printf(TIO_MESSAGE_INFO, "PlaceOpts.seed: %d\n", PlacerOpts.seed); ShowAnnealSched(AnnealSched); } vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void ShowPackerOpts(INP struct s_packer_opts PackerOpts) { vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.allow_early_exit: %s", (PackerOpts.allow_early_exit ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.allow_unrelated_clustering: %s", (PackerOpts.allow_unrelated_clustering ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.alpha_clustering: %f\n", PackerOpts.alpha); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.aspect: %f\n", PackerOpts.aspect); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.beta_clustering: %f\n", PackerOpts.beta); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.block_delay: %f\n", PackerOpts.block_delay); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.cluster_seed_type: "); switch (PackerOpts.cluster_seed_type) { case VPACK_TIMING: vpr_printf(TIO_MESSAGE_INFO, "TIMING\n"); break; case VPACK_MAX_INPUTS: vpr_printf(TIO_MESSAGE_INFO, "MAX_INPUTS\n"); break; default: vpr_printf(TIO_MESSAGE_INFO, "Unknown packer cluster_seed_type\n"); exit(1); } vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.connection_driven: %s", (PackerOpts.connection_driven ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.global_clocks: %s", (PackerOpts.global_clocks ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.hill_climbing_flag: %s", (PackerOpts.hill_climbing_flag ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.inter_cluster_net_delay: %f\n", PackerOpts.inter_cluster_net_delay); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.intra_cluster_net_delay: %f\n", PackerOpts.intra_cluster_net_delay); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.recompute_timing_after: %d\n", PackerOpts.recompute_timing_after); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.sweep_hanging_nets_and_inputs: %s", (PackerOpts.sweep_hanging_nets_and_inputs ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "PackerOpts.timing_driven: %s", (PackerOpts.timing_driven ? "TRUE\n" : "FALSE\n")); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static int find_fanin_rr_node(t_pb *cur_pb, enum PORTS type, int rr_node_index) { /* finds first fanin rr_node */ t_pb *parent, *sibling, *child; int net_num, irr_node; int i, j, k, ichild_type, ichild_inst; int hack_empty_route_through; t_pb_graph_node *hack_empty_pb_graph_node; hack_empty_route_through = OPEN; net_num = rr_node[rr_node_index].net_num; parent = cur_pb->parent_pb; if (net_num == OPEN) { return OPEN; } if (type == IN_PORT) { /* check parent inputs for valid connection */ for (i = 0; i < parent->pb_graph_node->num_input_ports; i++) { for (j = 0; j < parent->pb_graph_node->num_input_pins[i]; j++) { irr_node = parent->pb_graph_node->input_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { if (cur_pb->pb_graph_node->pb_type->model && strcmp( cur_pb->pb_graph_node->pb_type->model->name, MODEL_LATCH) == 0) { /* HACK: latches are special becuase LUTs can be set to route-through mode for them I will assume that the input to a LATCH can always come from a parent input pin this only works for hierarchical soft logic structures that follow LUT -> LATCH design must do it better later */ return irr_node; } hack_empty_route_through = irr_node; for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } } } } /* check parent clocks for valid connection */ for (i = 0; i < parent->pb_graph_node->num_clock_ports; i++) { for (j = 0; j < parent->pb_graph_node->num_clock_pins[i]; j++) { irr_node = parent->pb_graph_node->clock_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } } } } /* check siblings for connection */ if (parent) { for (ichild_type = 0; ichild_type < parent->pb_graph_node->pb_type->modes[parent->mode].num_pb_type_children; ichild_type++) { for (ichild_inst = 0; ichild_inst < parent->pb_graph_node->pb_type->modes[parent->mode].pb_type_children[ichild_type].num_pb; ichild_inst++) { if (parent->child_pbs[ichild_type] && parent->child_pbs[ichild_type][ichild_inst].name != NULL) { sibling = &parent->child_pbs[ichild_type][ichild_inst]; for (i = 0; i < sibling->pb_graph_node->num_output_ports; i++) { for (j = 0; j < sibling->pb_graph_node->num_output_pins[i]; j++) { irr_node = sibling->pb_graph_node->output_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } } } } } else { /* hack just in case routing is down through an empty cluster */ hack_empty_pb_graph_node = &parent->pb_graph_node->child_pb_graph_nodes[ichild_type][0][ichild_inst]; for (i = 0; i < hack_empty_pb_graph_node->num_output_ports; i++) { for (j = 0; j < hack_empty_pb_graph_node->num_output_pins[i]; j++) { irr_node = hack_empty_pb_graph_node->output_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } } } } } } } } } else { assert(type == OUT_PORT); /* check children for connection */ for (ichild_type = 0; ichild_type < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].num_pb_type_children; ichild_type++) { for (ichild_inst = 0; ichild_inst < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].pb_type_children[ichild_type].num_pb; ichild_inst++) { if (cur_pb->child_pbs[ichild_type] && cur_pb->child_pbs[ichild_type][ichild_inst].name != NULL) { child = &cur_pb->child_pbs[ichild_type][ichild_inst]; for (i = 0; i < child->pb_graph_node->num_output_ports; i++) { for (j = 0; j < child->pb_graph_node->num_output_pins[i]; j++) { irr_node = child->pb_graph_node->output_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } hack_empty_route_through = irr_node; } } } } } } /* If not in children, check current pb inputs for valid connection */ for (i = 0; i < cur_pb->pb_graph_node->num_input_ports; i++) { for (j = 0; j < cur_pb->pb_graph_node->num_input_pins[i]; j++) { irr_node = cur_pb->pb_graph_node->input_pins[i][j].pin_count_in_cluster; if (rr_node[irr_node].net_num == net_num) { hack_empty_route_through = irr_node; for (k = 0; k < rr_node[irr_node].num_edges; k++) { if (rr_node[irr_node].edges[k] == rr_node_index) { return irr_node; } } } } } } /* TODO: Once I find a way to output routing in empty blocks then code should never reach here, for now, return OPEN */ vpr_printf(TIO_MESSAGE_INFO, "Use hack in blif dumper (do properly later): connecting net %s #%d for pb %s type %s\n", vpack_net[net_num].name, net_num, cur_pb->name, cur_pb->pb_graph_node->pb_type->name); assert(hack_empty_route_through != OPEN); return hack_empty_route_through; }
static void ShowRoutingArch(INP struct s_det_routing_arch RoutingArch) { vpr_printf(TIO_MESSAGE_INFO, "RoutingArch.directionality: "); switch (RoutingArch.directionality) { case BI_DIRECTIONAL: vpr_printf(TIO_MESSAGE_INFO, "BI_DIRECTIONAL\n"); break; case UNI_DIRECTIONAL: vpr_printf(TIO_MESSAGE_INFO, "UNI_DIRECTIONAL\n"); break; default: vpr_printf(TIO_MESSAGE_INFO, "<Unknown>\n"); exit(1); } vpr_printf(TIO_MESSAGE_INFO, "RoutingArch.switch_block_type: "); switch (RoutingArch.switch_block_type) { case SUBSET: vpr_printf(TIO_MESSAGE_INFO, "SUBSET\n"); break; case WILTON: vpr_printf(TIO_MESSAGE_INFO, "WILTON\n"); break; case UNIVERSAL: vpr_printf(TIO_MESSAGE_INFO, "UNIVERSAL\n"); break; case FULL: vpr_printf(TIO_MESSAGE_INFO, "FULL\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR, "switch block type\n"); } vpr_printf(TIO_MESSAGE_INFO, "RoutingArch.Fs: %d\n", RoutingArch.Fs); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
/* * Sets globals: nx, ny * Allocs globals: chan_width_x, chan_width_y, grid * Depends on num_clbs, pins_per_clb */ void vpr_init_pre_place_and_route(INP t_vpr_setup vpr_setup, INP t_arch Arch) { int *num_instances_type, *num_blocks_type; int i; int current, high, low; boolean fit; /* Read in netlist file for placement and routing */ if (vpr_setup.FileNameOpts.NetFile) { read_netlist(vpr_setup.FileNameOpts.NetFile, &Arch, &num_blocks, &block, &num_nets, &clb_net); /* This is done so that all blocks have subblocks and can be treated the same */ check_netlist(); } /* Output the current settings to console. */ printClusteredNetlistStats(); if (vpr_setup.Operation == TIMING_ANALYSIS_ONLY) { do_constant_net_delay_timing_analysis(vpr_setup.Timing, vpr_setup.constant_net_delay); } else { current = nint((float)sqrt((float)num_blocks)); /* current is the value of the smaller side of the FPGA */ low = 1; high = -1; num_instances_type = (int*) my_calloc(num_types, sizeof(int)); num_blocks_type = (int*) my_calloc(num_types, sizeof(int)); for (i = 0; i < num_blocks; i++) { num_blocks_type[block[i].type->index]++; } if (Arch.clb_grid.IsAuto) { /* Auto-size FPGA, perform a binary search */ while (high == -1 || low < high) { /* Generate grid */ if (Arch.clb_grid.Aspect >= 1.0) { ny = current; nx = nint(current * Arch.clb_grid.Aspect); } else { nx = current; ny = nint(current / Arch.clb_grid.Aspect); } #if DEBUG vpr_printf(TIO_MESSAGE_INFO, "Auto-sizing FPGA at x = %d y = %d\n", nx, ny); #endif alloc_and_load_grid(num_instances_type, &Arch); freeGrid(); /* Test if netlist fits in grid */ fit = TRUE; for (i = 0; i < num_types; i++) { if (num_blocks_type[i] > num_instances_type[i]) { fit = FALSE; break; } } /* get next value */ if (!fit) { /* increase size of max */ if (high == -1) { current = current * 2; if (current > MAX_SHORT) { vpr_printf(TIO_MESSAGE_ERROR, "FPGA required is too large for current architecture settings.\n"); exit(1); } } else { if (low == current) current++; low = current; current = low + ((high - low) / 2); } } else { high = current; current = low + ((high - low) / 2); } } /* Generate grid */ if (Arch.clb_grid.Aspect >= 1.0) { ny = current; nx = nint(current * Arch.clb_grid.Aspect); } else { nx = current; ny = nint(current / Arch.clb_grid.Aspect); } alloc_and_load_grid(num_instances_type, &Arch); vpr_printf(TIO_MESSAGE_INFO, "FPGA auto-sized to x = %d y = %d\n", nx, ny); } else { nx = Arch.clb_grid.W; ny = Arch.clb_grid.H; alloc_and_load_grid(num_instances_type, &Arch); } vpr_printf(TIO_MESSAGE_INFO, "The circuit will be mapped into a %d x %d array of clbs.\n", nx, ny); /* Test if netlist fits in grid */ fit = TRUE; for (i = 0; i < num_types; i++) { if (num_blocks_type[i] > num_instances_type[i]) { fit = FALSE; break; } } if (!fit) { vpr_printf(TIO_MESSAGE_ERROR, "Not enough physical locations for type %s, number of blocks is %d but number of locations is %d.\n", type_descriptors[i].name, num_blocks_type[i], num_instances_type[i]); exit(1); } vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Resource usage...\n"); for (i = 0; i < num_types; i++) { vpr_printf(TIO_MESSAGE_INFO, "\tNetlist %d\tblocks of type: %s\n", num_blocks_type[i], type_descriptors[i].name); vpr_printf(TIO_MESSAGE_INFO, "\tArchitecture %d\tblocks of type: %s\n", num_instances_type[i], type_descriptors[i].name); } vpr_printf(TIO_MESSAGE_INFO, "\n"); chan_width_x = (int *) my_malloc((ny + 1) * sizeof(int)); chan_width_y = (int *) my_malloc((nx + 1) * sizeof(int)); free(num_blocks_type); free(num_instances_type); } }
/* This function performs power estimation, and must be called * after packing, placement AND routing. Currently, this * will not work when running a partial flow (ex. only routing). */ void vpr_power_estimation(t_vpr_setup vpr_setup, t_arch Arch) { e_power_ret_code power_ret_code; boolean power_error; /* Ensure we are only using 1 clock */ assert(count_netlist_clocks() == 1); /* Get the critical path of this clock */ g_solution_inf.T_crit = get_critical_path_delay() / 1e9; assert(g_solution_inf.T_crit > 0.); vpr_printf(TIO_MESSAGE_INFO, "\n\nPower Estimation:\n"); vpr_printf(TIO_MESSAGE_INFO, "-----------------\n"); vpr_printf(TIO_MESSAGE_INFO, "Initializing power module\n"); /* Initialize the power module */ power_error = power_init(vpr_setup.FileNameOpts.PowerFile, vpr_setup.FileNameOpts.CmosTechFile, &Arch, &vpr_setup.RoutingArch); if (power_error) { vpr_printf(TIO_MESSAGE_ERROR, "Power initialization failed.\n"); } if (!power_error) { float power_runtime_s; vpr_printf(TIO_MESSAGE_INFO, "Running power estimation\n"); /* Run power estimation */ power_ret_code = power_total(&power_runtime_s, vpr_setup, &Arch, &vpr_setup.RoutingArch); /* Check for errors/warnings */ if (power_ret_code == POWER_RET_CODE_ERRORS) { vpr_printf(TIO_MESSAGE_ERROR, "Power estimation failed. See power output for error details.\n"); } else if (power_ret_code == POWER_RET_CODE_WARNINGS) { vpr_printf(TIO_MESSAGE_WARNING, "Power estimation completed with warnings. See power output for more details.\n"); } else if (power_ret_code == POWER_RET_CODE_SUCCESS) { } vpr_printf(TIO_MESSAGE_INFO, "Power estimation took %g seconds\n", power_runtime_s); } /* Uninitialize power module */ if (!power_error) { vpr_printf(TIO_MESSAGE_INFO, "Uninitializing power module\n"); power_error = power_uninit(); if (power_error) { vpr_printf(TIO_MESSAGE_ERROR, "Power uninitialization failed.\n"); } else { } } vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void clay_logical_equivalence_handling(const t_arch *arch) { t_trace **saved_ext_rr_trace_head, **saved_ext_rr_trace_tail; t_rr_node *saved_ext_rr_node; int num_ext_rr_node, num_ext_nets; int i, j; for (i = 0; i < num_blocks; i++) { clay_reload_ble_locations(i); } /* Resolve logically equivalent inputs */ saved_ext_rr_trace_head = trace_head; saved_ext_rr_trace_tail = trace_tail; saved_ext_rr_node = rr_node; num_ext_rr_node = num_rr_nodes; num_ext_nets = num_nets; num_rr_nodes = 0; rr_node = NULL; trace_head = NULL; trace_tail = NULL; free_rr_graph(); /* free all data structures associated with rr_graph */ alloc_and_load_cluster_legality_checker(); for (i = 0; i < num_blocks; i++) { /* Regenerate rr_graph (note, can be more runtime efficient but this allows for more code reuse) */ rr_node = block[i].pb->rr_graph; num_rr_nodes = block[i].pb->pb_graph_node->total_pb_pins; free_legalizer_for_cluster(&block[i], TRUE); alloc_and_load_legalizer_for_cluster(&block[i], i, arch); reload_intra_cluster_nets(block[i].pb); reload_ext_net_rr_terminal_cluster(); force_post_place_route_cb_input_pins(i); #ifdef HACK_LUT_PIN_SWAPPING /* Resolve rebalancing of LUT inputs */ clay_lut_input_rebalancing(i, block[i].pb); #endif /* reset rr_graph */ for (j = 0; j < num_rr_nodes; j++) { rr_node[j].occ = 0; rr_node[j].prev_edge = OPEN; rr_node[j].prev_node = OPEN; } if (try_breadth_first_route_cluster() == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "Failed to resync post routed solution with clustered netlist.\n"); vpr_printf(TIO_MESSAGE_ERROR, "Cannot recover from error.\n"); exit(1); } save_cluster_solution(); reset_legalizer_for_cluster(&block[i]); free_legalizer_for_cluster(&block[i], FALSE); } free_cluster_legality_checker(); trace_head = saved_ext_rr_trace_head; trace_tail = saved_ext_rr_trace_tail; rr_node = saved_ext_rr_node; num_rr_nodes = num_ext_rr_node; num_nets = num_ext_nets; }
void print_relative_pos_distr(void) { /* Prints out the probability distribution of the relative locations of * * input pins on a net -- i.e. simulates 2-point net distance probability * * distribution. */ #ifdef PRINT_REL_POS_DISTR FILE *out_bin_file; relapos_rec_t rp_rec; #endif /* PRINT_REL_POS_DISTR */ int inet, len, rp, src_x, src_y, dst_x, dst_y, del_x, del_y, min_del, sink_pin, sum; int *total_conn; int **relapos; double **relapos_distr; total_conn = (int *)my_malloc((nx + ny + 1) * sizeof(int)); relapos = (int **)my_malloc((nx + ny + 1) * sizeof(int *)); relapos_distr = (double **)my_malloc((nx + ny + 1) * sizeof(double *)); for (len = 0; len <= nx + ny; len++) { relapos[len] = (int *)my_calloc(len / 2 + 1, sizeof(int)); relapos_distr[len] = (double *)my_calloc((len / 2 + 1), sizeof(double)); } for (inet = 0; inet < num_nets; inet++) { if (clb_net[inet].is_global == FALSE) { src_x = block[clb_net[inet].node_block[0]].x; src_y = block[clb_net[inet].node_block[0]].y; for (sink_pin = 1; sink_pin <= clb_net[inet].num_sinks; sink_pin++) { dst_x = block[clb_net[inet].node_block[sink_pin]].x; dst_y = block[clb_net[inet].node_block[sink_pin]].y; del_x = ABS_DIFF(dst_x, src_x); del_y = ABS_DIFF(dst_y, src_y); len = del_x + del_y; min_del = (del_x < del_y) ? del_x : del_y; if (!(min_del <= (len / 2))) { vpr_printf(TIO_MESSAGE_ERROR, "Error calculating relative location min_del = %d, len = %d\n", min_del, len); exit(1); } else { relapos[len][min_del]++; } } } } #ifdef PRINT_REL_POS_DISTR out_bin_file = fopen("/jayar/b/b5/fang/vpr_test/wirelength/relapos2.bin", "rb+"); #endif /* PRINT_REL_POS_DISTR */ for (len = 0; len <= nx + ny; len++) { sum = 0; for (rp = 0; rp <= len / 2; rp++) { sum += relapos[len][rp]; } if (sum != 0) { #ifdef PRINT_REL_POS_DISTR fseek(out_bin_file, sizeof(relapos_rec_t) * len, SEEK_SET); fread(&rp_rec, sizeof(relapos_rec_t), 1, out_bin_file); #endif /* PRINT_REL_POS_DISTR */ for (rp = 0; rp <= len / 2; rp++) { relapos_distr[len][rp] = (double)relapos[len][rp] / (double)sum; /* updating the binary record at "len" */ #ifdef PRINT_REL_POS_DISTR vpr_printf(TIO_MESSAGE_ERROR, "old %d increased by %d\n", rp_rec.num_rp[rp], relapos[len][rp]); rp_rec.num_rp[rp] += relapos[len][rp]; vpr_printf(TIO_MESSAGE_ERROR, "becomes %d\n", rp_rec.num_rp[rp]); #endif /* PRINT_REL_POS_DISTR */ } #ifdef PRINT_REL_POS_DISTR /* write back the updated record at "len" */ fseek(out_bin_file, sizeof(relapos_rec_t) * len, SEEK_SET); fwrite(&rp_rec, sizeof(relapos_rec_t), 1, out_bin_file); #endif /* PRINT_REL_POS_DISTR */ } total_conn[len] = sum; } fprintf(stdout, "Source to sink relative positions:\n"); for (len = 1; len <= nx + ny; len++) { if (total_conn[len] != 0) { fprintf(stdout, "Of 2-pin distance %d exists %d\n\n", len, total_conn[len]); for (rp = 0; rp <= len / 2; rp++) { fprintf(stdout, "\trp%d\t%d\t\t(%.5f)\n", rp, relapos[len][rp], relapos_distr[len][rp]); } fprintf(stdout, "----------------\n"); } } free((void *)total_conn); for (len = 0; len <= nx + ny; len++) { free((void *)relapos[len]); free((void *)relapos_distr[len]); } free((void *)relapos); free((void *)relapos_distr); #ifdef PRINT_REL_POS_DISTR fclose(out_bin_file); #endif /* PRINT_REL_POS_DISTR */ }
/* Display help screen */ void vpr_print_usage(void) { vpr_printf(TIO_MESSAGE_INFO, "Usage: vpr fpga_architecture.xml circuit_name [Options ...]\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "General Options: [--nodisp] [--auto <int>] [--pack]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--place] [--route] [--timing_analyze_only_with_net_delay <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--fast] [--full_stats] [--timing_analysis on | off] [--outfile_prefix <string>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--blif_file <string>][--net_file <string>][--place_file <string>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--route_file <string>][--sdc_file <string>][--echo_file on | off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Packer Options:\n"); /* vpr_printf(TIO_MESSAGE_INFO, "\t[-global_clocks on|off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[-hill_climbing on|off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[-sweep_hanging_nets_and_inputs on|off]\n"); */ vpr_printf(TIO_MESSAGE_INFO, "\t[--timing_driven_clustering on|off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--cluster_seed_type timing|max_inputs] [--alpha_clustering <float>] [--beta_clustering <float>]\n"); /* vpr_printf(TIO_MESSAGE_INFO, "\t[-recompute_timing_after <int>] [-cluster_block_delay <float>]\n"); */ vpr_printf(TIO_MESSAGE_INFO, "\t[--allow_unrelated_clustering on|off]\n"); /* vpr_printf(TIO_MESSAGE_INFO, "\t[-allow_early_exit on|off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[-intra_cluster_net_delay <float>] \n"); vpr_printf(TIO_MESSAGE_INFO, "\t[-inter_cluster_net_delay <float>] \n"); */ vpr_printf(TIO_MESSAGE_INFO, "\t[--connection_driven_clustering on|off] \n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Placer Options:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--place_algorithm bounding_box | net_timing_driven | path_timing_driven]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--init_t <float>] [--exit_t <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--alpha_t <float>] [--inner_num <float>] [--seed <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--place_cost_exp <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--place_chan_width <int>] \n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--fix_pins random | <file.pads>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--enable_timing_computations on | off]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--block_dist <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Placement Options Valid Only for Timing-Driven Placement:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--timing_tradeoff <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--recompute_crit_iter <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inner_loop_recompute_divider <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--td_place_exp_first <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--td_place_exp_last <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Router Options: [-max_router_iterations <int>] [-bb_factor <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--initial_pres_fac <float>] [--pres_fac_mult <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--acc_fac <float>] [--first_iter_pres_fac <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--bend_cost <float>] [--route_type global | detailed]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--verify_binary_search] [--route_chan_width <int>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--router_algorithm breadth_first | timing_driven]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--router_algorithm breadth_first | timing_driven | Read_Route]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--base_cost_type intrinsic_delay | delay_normalized | demand_only]\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Routing options valid only for timing-driven routing:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--astar_fac <float>] [--max_criticality <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "\t[--criticality_exp <float>]\n"); vpr_printf(TIO_MESSAGE_INFO, "OVERLAY NETWORK options:"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inc_instrument_type overlay]"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inc_router_algorithm breadth_first | timing_driven | directed_search | read_route]"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inc_route_file <file>.route]"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inc_match_file <file>.match]"); vpr_printf(TIO_MESSAGE_INFO, "\t[--inc_le_symmetry on|off] [--inc_best_effort on|off] [--inc_dump_all_nets]"); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
static void print_complete_net_trace(t_trace* trace, const char *file_name) { FILE *fp; int iblock, inode, iprev_block; t_trace *current; t_rr_node *local_rr_graph; const char *name_type[] = { "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE" }; int i; fp = my_fopen(file_name, "w", 0); for (i = 0; i < num_logical_nets; i++) { current = &trace[i]; iprev_block = OPEN; fprintf(fp, "Net %s (%d)\n\n", vpack_net[i].name, i); while (current != NULL) { iblock = current->iblock; inode = current->index; if (iblock != OPEN) { if (iprev_block != iblock) { iprev_block = iblock; fprintf(fp, "Block %s (%d) (%d, %d, %d):\n", block[iblock].name, iblock, block[iblock].x, block[iblock].y, block[iblock].z); } local_rr_graph = block[iblock].pb->rr_graph; fprintf(fp, "\tNode:\t%d\t%s[%d].%s[%d]", inode, local_rr_graph[inode].pb_graph_pin->parent_node->pb_type->name, local_rr_graph[inode].pb_graph_pin->parent_node->placement_index, local_rr_graph[inode].pb_graph_pin->port->name, local_rr_graph[inode].pb_graph_pin->pin_number); } else { fprintf(fp, "Node:\t%d\t%6s (%d,%d) ", inode, name_type[(int) rr_node[inode].type], rr_node[inode].xlow, rr_node[inode].ylow); if ((rr_node[inode].xlow != rr_node[inode].xhigh) || (rr_node[inode].ylow != rr_node[inode].yhigh)) fprintf(fp, "to (%d,%d) ", rr_node[inode].xhigh, rr_node[inode].yhigh); switch (rr_node[inode].type) { case IPIN: case OPIN: if (grid[rr_node[inode].xlow][rr_node[inode].ylow].type == IO_TYPE) { fprintf(fp, " Pad: "); } else { /* IO Pad. */ fprintf(fp, " Pin: "); } break; case CHANX: case CHANY: fprintf(fp, " Track: "); break; case SOURCE: case SINK: if (grid[rr_node[inode].xlow][rr_node[inode].ylow].type == IO_TYPE) { fprintf(fp, " Pad: "); } else { /* IO Pad. */ fprintf(fp, " Class: "); } break; default: vpr_printf(TIO_MESSAGE_ERROR, "in print_route: Unexpected traceback element type: %d (%s).\n", rr_node[inode].type, name_type[rr_node[inode].type]); exit(1); break; } fprintf(fp, "%d ", rr_node[inode].ptc_num); /* Uncomment line below if you're debugging and want to see the switch types * * used in the routing. */ /* fprintf (fp, "Switch: %d", tptr->iswitch); */ fprintf(fp, "\n"); } current = current->next; } fprintf(fp, "\n"); } fclose(fp); }
static void print_primitive(FILE *fpout, int iblk) { t_pb *pb; int clb_index; int i, j, node_index; int in_port_index, out_port_index, clock_port_index; struct s_linked_vptr *truth_table; const t_pb_type *pb_type; pb = logical_block[iblk].pb; pb_type = pb->pb_graph_node->pb_type; clb_index = logical_block[iblk].clb_index; if (logical_block[iblk].type == VPACK_INPAD || logical_block[iblk].type == VPACK_OUTPAD) { /* do nothing */ } else if (logical_block[iblk].type == VPACK_LATCH) { fprintf(fpout, ".latch "); in_port_index = 0; out_port_index = 0; clock_port_index = 0; for (i = 0; i < pb_type->num_ports; i++) { if (pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == FALSE) { assert(pb_type->ports[i].num_pins == 1); assert(logical_block[iblk].input_nets[i][0] != OPEN); node_index = pb->pb_graph_node->input_pins[in_port_index][0].pin_count_in_cluster; fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index)); in_port_index++; } } for (i = 0; i < pb_type->num_ports; i++) { if (pb_type->ports[i].type == OUT_PORT) { assert(pb_type->ports[i].num_pins == 1 && out_port_index == 0); node_index = pb->pb_graph_node->output_pins[out_port_index][0].pin_count_in_cluster; fprintf(fpout, "clb_%d_rr_node_%d re ", clb_index, node_index); out_port_index++; } } for (i = 0; i < pb_type->num_ports; i++) { if (pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == TRUE) { assert(logical_block[iblk].clock_net != OPEN); node_index = pb->pb_graph_node->clock_pins[clock_port_index][0].pin_count_in_cluster; fprintf(fpout, "clb_%d_rr_node_%d 2", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index)); clock_port_index++; } } fprintf(fpout, "\n"); } else if (logical_block[iblk].type == VPACK_COMB) { if (strcmp(logical_block[iblk].model->name, "names") == 0) { fprintf(fpout, ".names "); in_port_index = 0; out_port_index = 0; for (i = 0; i < pb_type->num_ports; i++) { if (pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == FALSE) { for (j = 0; j < pb_type->ports[i].num_pins; j++) { if (logical_block[iblk].input_nets[in_port_index][j] != OPEN) { node_index = pb->pb_graph_node->input_pins[in_port_index][j].pin_count_in_cluster; fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index)); } } in_port_index++; } } for (i = 0; i < pb_type->num_ports; i++) { if (pb_type->ports[i].type == OUT_PORT) { for (j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb->pb_graph_node->output_pins[out_port_index][j].pin_count_in_cluster; fprintf(fpout, "clb_%d_rr_node_%d\n", clb_index, node_index); } out_port_index++; } } truth_table = logical_block[iblk].truth_table; while (truth_table) { fprintf(fpout, "%s\n", (char *) truth_table->data_vptr); truth_table = truth_table->next; } } else { vpr_printf(TIO_MESSAGE_WARNING, "TODO: Implement blif dumper for subckt %s model %s", logical_block[iblk].name, logical_block[iblk].model->name); } } }