Example #1
0
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)
{

/* This routine controls the overall placement and routing of a circuit. */
    char msg[BUFSIZE];
    int width_fac, inet, i;
    boolean success, Fc_clipped;
    float **net_delay, **net_slack;
    struct s_linked_vptr *net_delay_chunk_list_head;
    t_ivec **clb_opins_used_locally;	/* [0..num_blocks-1][0..num_class-1] */
    t_mst_edge **mst = NULL;	/* Make sure mst is never undefined */
    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, &mst);
	    print_place(place_file, net_file, arch_file);
		end = clock();
#ifdef CLOCKS_PER_SEC
		printf("Placement took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC);
#else
		printf("Placement took %g seconds\n", (float)(end - begin) / CLK_PER_SEC);
#endif
	}
	begin = clock();
    post_place_sync(num_blocks, block);


    fflush(stdout);

	/* reset mst */
	if(mst)
	{
	    for(inet = 0; inet < num_nets; inet++)
		{
			if(mst[inet]) {
				free(mst[inet]);
			}
		}
	    free(mst);
	}
	mst = NULL;

	if(!router_opts.doRouting)
	return;

    mst = (t_mst_edge **) my_malloc(sizeof(t_mst_edge *) * num_nets);
    for(inet = 0; inet < num_nets; inet++)
	{
	    mst[inet] = get_mst_of_net(inet);
	}

    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)
	{
	    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, mst, models);
	}
    else
	{
	    if(det_routing_arch.directionality == UNI_DIRECTIONAL)
		{
		    if(width_fac % 2 != 0)
			{
			    printf
				("Error: 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();

	    if(timing_inf.timing_analysis_enabled)
		{
		    net_slack =
			alloc_and_load_timing_graph(timing_inf);
		    net_delay = alloc_net_delay(&net_delay_chunk_list_head, clb_net, num_nets);
		}
	    else
		{
		    net_delay = NULL;	/* Defensive coding. */
		    net_slack = NULL;
		}

	    success =
		try_route(width_fac, router_opts, det_routing_arch,
			  segment_inf, timing_inf, net_slack, net_delay,
			  chan_width_dist, clb_opins_used_locally, mst,
			  &Fc_clipped);

	    if(Fc_clipped)
		{
		    printf
			("Warning: Fc_output was too high and was clipped to full (maximum) connectivity.\n");
		}

	    if(success == FALSE)
		{
		    printf
			("Circuit is unrouteable with a channel width factor of %d\n\n",
			 width_fac);
		    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();

		    printf
			("Circuit successfully routed with a channel width factor of %d.\n\n",
			 width_fac);

			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_slack, net_delay);

		    print_route(route_file);

#ifdef CREATE_ECHO_FILES
		    /*print_sink_delays("routing_sink_delays.echo"); */
#endif /* CREATE_ECHO_FILES */

		    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(net_slack);
			#ifdef CREATE_ECHO_FILES
				print_timing_graph_as_blif("post_flow_timing_graph.blif", models);
			#endif

		    free_timing_graph(net_slack);

		    assert(net_delay);
		    free_net_delay(net_delay, &net_delay_chunk_list_head);
		}

	    free_route_structs(clb_opins_used_locally);
	    fflush(stdout);
	}
	end = clock();
	#ifdef CLOCKS_PER_SEC
		printf("Routing took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC);
	#else
		printf("Routing took %g seconds\n", (float)(end - begin) / CLK_PER_SEC);
	#endif

    /*WMF: cleaning up memory usage */
    if(mst)
	{
	    for(inet = 0; inet < num_nets; inet++)
		{
			if(!mst[inet]) {
				printf("no mst for net %s #%d\n", clb_net[inet].name, inet);
			}
		    assert(mst[inet]);
		    free(mst[inet]);
		}
	    free(mst);
	    mst = NULL;
	}
}
Example #2
0
boolean
try_directed_search_route(struct s_router_opts router_opts,
			  t_ivec ** fb_opins_used_locally,
			  int width_fac,
			  t_mst_edge ** mst)
{

/* Iterated maze router ala Pathfinder Negotiated Congestion algorithm,  *
 * (FPGA 95 p. 111).  Returns TRUE if it can route this FPGA, FALSE if   *
 * it can't.                                                             */

    float pres_fac;
    boolean success, is_routable, rip_up_local_opins;
    int itry, inet;

    /* char msg[100]; */

    /* mst not built as good as it should, ideally, just have it after placement once only
	 however, rr_node numbers changed when the channel width changes so forced to do it here */
    if(mst)
	{
	    for(inet = 0; inet < num_nets; inet++)
		{
		    free(mst[inet]);
		    mst[inet] = get_mst_of_net(inet);
		}
	}

/* Usually the first iteration uses a very small (or 0) pres_fac to find  *
 * the shortest path and get a congestion map.  For fast compiles, I set  *
 * pres_fac high even for the first iteration.                            */

    pres_fac = router_opts.first_iter_pres_fac;

    for(itry = 1; itry <= router_opts.max_router_iterations; itry++)
	{

	    for(inet = 0; inet < num_nets; inet++)
		{
		    if(net[inet].is_global == FALSE)
			{	/* Skip global nets. */

			    is_routable =
				directed_search_route_net(inet, pres_fac,
							  router_opts.
							  astar_fac,
							  router_opts.
							  bend_cost, mst);

			    /* Impossible to route? (disconnected rr_graph) */

			    if(!is_routable)
				{
				    printf("Routing failed.\n");
				    return (FALSE);
				}

			}
		}

	    /* Make sure any FB OPINs used up by subblocks being hooked directly     *
	     * to them are reserved for that purpose.                                 */

	    if(itry == 1)
		rip_up_local_opins = FALSE;
	    else
		rip_up_local_opins = TRUE;

	    reserve_locally_used_opins(pres_fac, rip_up_local_opins,
				       fb_opins_used_locally);

	    success = feasible_routing();
	    if(success)
		{
		    printf
			("Successfully routed after %d routing iterations by Directed Search.\n",
			 itry);
		    return (TRUE);
		}
#if 0
	    else
		{
		    sprintf(msg,
			    "After iteration %d routing failed (A*) with a channel width factor of %d and Fc_int of %d, Fs_int of %d.",
			    itry, width_fac, Fc_int, Fs_int);
		    init_draw_coords(pins_per_clb);
		    update_screen(MAJOR, msg, ROUTING, FALSE);
		}
#endif


	    if(itry == 1)
		{
		    pres_fac = router_opts.initial_pres_fac;
		    pathfinder_update_cost(pres_fac, 0.);	/* Acc_fac=0 for first iter. */
		}
	    else
		{
		    pres_fac *= router_opts.pres_fac_mult;
		    pathfinder_update_cost(pres_fac, router_opts.acc_fac);
		}

	}

    printf("Routing failed.\n");

    return (FALSE);
}
boolean
try_directed_search_route(struct s_router_opts router_opts,
			  t_ivec ** clb_opins_used_locally,
			  int width_fac,
			  t_mst_edge ** mst)
{

/* Iterated maze router ala Pathfinder Negotiated Congestion algorithm,  *
 * (FPGA 95 p. 111).  Returns TRUE if it can route this FPGA, FALSE if   *
 * it can't.                                                             */

    float pres_fac;
    boolean success, is_routable, rip_up_local_opins;
    int itry, inet, i;
	clock_t begin, end;

    int bends;
    int wirelength, total_wirelength, available_wirelength;
    int segments;

	float *sinks;
	int *net_index;

	sinks = my_malloc(sizeof(float) * num_nets);
	net_index = my_malloc(sizeof(int) * num_nets);
	for(i = 0; i < num_nets; i++) {
		sinks[i] = clb_net[i].num_sinks;
		net_index[i] = i;
	}
	heapsort(net_index, sinks, num_nets, 1);

    /* char msg[100]; */

	begin = clock();

    /* mst not built as good as it should, ideally, just have it after placement once only
	 however, rr_node numbers changed when the channel width changes so forced to do it here */
    if(mst)
	{
	    for(inet = 0; inet < num_nets; inet++)
		{
			free(mst[inet]);
		    mst[inet] = get_mst_of_net(inet);
		}
	}

	end = clock();
	#ifdef CLOCKS_PER_SEC
		printf("mst took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC);
	#else
		printf("mst took %g seconds\n", (float)(end - begin) / CLK_PER_SEC);
	#endif


/* Usually the first iteration uses a very small (or 0) pres_fac to find  *
 * the shortest path and get a congestion map.  For fast compiles, I set  *
 * pres_fac high even for the first iteration.                            */

    pres_fac = router_opts.first_iter_pres_fac;

    for(itry = 1; itry <= router_opts.max_router_iterations; itry++)
	{
					begin = clock();

		printf("routing iteration %d\n", itry);
		for(i = 0; i < num_nets; i++)
		{
			inet = net_index[i];
	    	if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
			{	/* Skip global nets and empty nets (empty nets are already reserved using reserve_locally_used_opins). */
			    is_routable =
				directed_search_route_net(inet, pres_fac,
							  router_opts.
							  astar_fac,
							  router_opts.
							  bend_cost, mst);

			    /* Impossible to route? (disconnected rr_graph) */

			    if(!is_routable)
				{
				    printf("Routing failed.\n");
					free(net_index);
					free(sinks);
				    return (FALSE);
				}

			}
		}
		end = clock();
		#ifdef CLOCKS_PER_SEC
			printf("routing iteration took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC);
		#else
			printf("routing iteration took %g seconds\n", (float)(end - begin) / CLK_PER_SEC);
		#endif
		fflush(stdout);

		if(itry == 1) {
			/* Early exit code for cases where it is obvious that a successful route will not be found 
			   Heuristic: If total wirelength used in first routing iteration is X% of total available wirelength, exit
			*/
			total_wirelength = 0;
			available_wirelength = 0;

			for(i = 0; i < num_rr_nodes; i++) {
				if(rr_node[i].type == CHANX || rr_node[i].type == CHANY)
				{
					available_wirelength += 1 + rr_node[i].xhigh - rr_node[i].xlow +
					rr_node[i].yhigh - rr_node[i].ylow;
				}
			}

			for(inet = 0; inet < num_nets; inet++)
			{
				if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
				{		/* Globals don't count. */
					get_num_bends_and_length(inet, &bends, &wirelength,
								 &segments);

					total_wirelength += wirelength;
				}
			}
			printf("wirelength after first iteration %d, total available wirelength %d, ratio %g\n", total_wirelength, available_wirelength, (float)(total_wirelength)/(float)(available_wirelength));
			if((float)(total_wirelength)/(float)(available_wirelength) > FIRST_ITER_WIRELENTH_LIMIT) {
				printf("Wirelength usage ratio exceeds limit of %g, fail routing\n", FIRST_ITER_WIRELENTH_LIMIT);
				free(net_index);
				free(sinks);
				return FALSE;
			}
		}


	    /* Make sure any CLB OPINs used up by subblocks being hooked directly     *
	     * to them are reserved for that purpose.                                 */

	    if(itry == 1)
		rip_up_local_opins = FALSE;
	    else
		rip_up_local_opins = TRUE;

	    reserve_locally_used_opins(pres_fac, rip_up_local_opins,
				       clb_opins_used_locally);

	    success = feasible_routing();
	    if(success)
		{
		    printf
			("Successfully routed after %d routing iterations by Directed Search.\n",
			 itry);
			free(net_index);
			free(sinks);
		    return (TRUE);
		}
#if 0
	    else
		{
		    sprintf(msg,
			    "After iteration %d routing failed (A*) with a channel width factor of %d and Fc_int of %d, Fs_int of %d.",
			    itry, width_fac, Fc_int, Fs_int);
		    init_draw_coords(pins_per_clb);
		    update_screen(MAJOR, msg, ROUTING, FALSE);
		}
#endif


	    if(itry == 1)
		{
		    pres_fac = router_opts.initial_pres_fac;
		    pathfinder_update_cost(pres_fac, 0.);	/* Acc_fac=0 for first iter. */
		}
	    else
		{
		    pres_fac *= router_opts.pres_fac_mult;
		    pathfinder_update_cost(pres_fac, router_opts.acc_fac);
		}

	}

    printf("Routing failed.\n");
	free(sinks);
	free(net_index);

    return (FALSE);
}
Example #4
0
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);*/
}