/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: GlobalRouterThreadV3.java * Written by: Alexander Herzog (Team 4) * * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.routing.experimentalLeeMoore2; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; import java.util.concurrent.BrokenBarrierException; import com.sun.electric.tool.routing.experimentalLeeMoore2.GlobalRouterV3.*; import com.sun.electric.tool.routing.experimentalLeeMoore2.RoutingFrameLeeMoore.Coordinate; import com.sun.electric.tool.routing.experimentalLeeMoore2.RoutingFrameLeeMoore.ManhattenAlignment; public class GlobalRouterThreadV3 implements Runnable { ArrayList<Integer> non_routable = new ArrayList<Integer>(); /** Id of this worker */ int slave_id; /** internal job queues */ ArrayList<JobMessage> internal_fwd_jobs = new ArrayList<JobMessage>(); ArrayList<JobMessage> internal_bckwd_jobs = new ArrayList<JobMessage>(); /** temporary result of backtracing */ Vector<RegionDirection> backtrace; /** master */ GlobalRouterV3 rm; public GlobalRouterThreadV3(GlobalRouterV3 gr, int slave_id){ this.rm = gr; this.slave_id = slave_id; } /** if sink was found, offers backward job to queue and returns true */ private JobMessage DoForwardJob(JobMessage entry){ /** do job */ RegionRepresentation region = rm.RegionAt(entry.position.x, entry.position.y); SegmentInfo seg_info = region.segment_infos[entry.seg_id]; JobMessage ret = null; // check if region has to be considered and refresh data if(seg_info.RefreshSegment(entry.step_num, entry.weight, entry.min_dir)){ /** check if sink was reached */ Vector2i end_point = rm.segments[entry.seg_id].end; if(entry.position.x == end_point.x && entry.position.y == end_point.y){ JobMessage bwd_job = new JobMessage(entry.seg_id, entry.position, entry.weight, rm.max_detour); ret = bwd_job; } /** offer neighbor jobs to queue */ for(RegionDirection dir : RegionDirection.values()){ if(dir == RegionDirection.rd_undefined){ continue; } if(!rm.IsCoordinateValid(rm.GetNeighborX( entry.position.x, dir), rm.GetNeighborY( entry.position.y, dir))){ continue; } /** create job */ double weight = entry.weight; boolean from_hor = entry.min_dir == RegionDirection.rd_left || entry.min_dir == RegionDirection.rd_right; boolean from_vert = entry.min_dir == RegionDirection.rd_up || entry.min_dir == RegionDirection.rd_down; boolean to_hor = dir == RegionDirection.rd_left || dir == RegionDirection.rd_right; boolean to_vert = dir == RegionDirection.rd_up || dir == RegionDirection.rd_down; if((from_hor && to_vert) || (from_vert && to_hor)){ weight += rm.via_cost; } RegionBorder border = region.GetRegionBorder(dir); // double bw = border.GetWeight(); double congestion_w = rm.RegionAt(rm.GetNeighborX( entry.position.x, dir), rm.GetNeighborY( entry.position.y, dir)).getCongestionWeight(); // if weight is equal to Double.Max there is a blockage if(border.IsBlocked()){ continue; } // weight += bw; // weight = bw; weight = congestion_w; weight = Math.max(entry.weight, weight); SegmentInfo neighbor_info = rm.RegionAt(entry.position.x, entry.position.y, dir).segment_infos[entry.seg_id]; int detour_inc = seg_info.is_on_min_path && neighbor_info.is_on_min_path ? 0 : 1; JobMessage job_to_send = new JobMessage(entry.seg_id, rm.GetNeighborPos(entry.position, dir), entry.step_num + detour_inc, weight, GlobalRouterV3.GetOppositeDir(dir)); /** send job to region */ internal_fwd_jobs.add(job_to_send); } } return ret; } /** returns false, if could not continue because of blockage */ private boolean DoBackwardJob(JobMessage entry){ RegionRepresentation region = rm.RegionAt(entry.position.x, entry.position.y); SegmentInfo seg_info = region.segment_infos[entry.seg_id]; /** mark region as part of backtrace */ seg_info.was_part_of_bt = true; /** check if source was reached */ Vector2i start_point = rm.segments[entry.seg_id].start; if(entry.position.x == start_point.x && entry.position.y == start_point.y){ /** source reached */ return true; }else{ /** search for minimum */ BacktraceState min = seg_info.GetMin(entry.step_num); /** try to pass border, but if blockage occurred return false */ RegionBorder passed_border = rm.RegionAt(entry.position.x, entry.position.y).GetRegionBorder(min.dir); if(!passed_border.SoftPassBorder(entry.seg_id)){ return false; } /** set backtrace */ RegionDirection dir_to_get_here = GlobalRouterV3.GetOppositeDir(min.dir); backtrace.add(0, dir_to_get_here); /** delegate new job to neighbor */ JobMessage job_to_send = new JobMessage(entry.seg_id, rm.GetNeighborPos(entry.position, min.dir), min.path_length); /** send job to region */ internal_bckwd_jobs.add(job_to_send); return true; } } /** if backward propagation had to be canceled, last position visited is returned */ private Vector2i BackwardPropagation(){ while(!internal_bckwd_jobs.isEmpty()){ JobMessage internal_bwd_job = internal_bckwd_jobs.get(0); internal_bckwd_jobs.remove(0); if(!DoBackwardJob(internal_bwd_job)){ return internal_bwd_job.position; } } return null; } /** Try to put shortest path and create forward jobs. */ private JobMessage PutShortestPath(List<RegionDirection> dirs, Vector2i start, int seg_id){ Vector2i pos = new Vector2i(start); Iterator<RegionDirection> it = dirs.iterator(); double w = 0.0d; // set start point RegionRepresentation region = rm.RegionAt(pos.x, pos.y); SegmentInfo seg_info = region.segment_infos[seg_id]; seg_info.is_on_min_path = true; if(!it.hasNext()){ // send jobs to neighbors for(RegionDirection rd : RegionDirection.values()){ if(rd == RegionDirection.rd_undefined){ continue; } if(!rm.IsCoordinateValid(rm.GetNeighborX( pos.x, rd), rm.GetNeighborY(pos.y, rd))){ continue; } RegionBorder b = region.GetRegionBorder(rd); double next_w = b.GetWeight(); if(b.IsBlocked()){ //skip this direction continue; }else{ //send job to this direction next_w += w; JobMessage job_to_send = new JobMessage(seg_id, rm.GetNeighborPos(pos, rd), 1, next_w, GlobalRouterV3.GetOppositeDir(rd)); /** send job to region */ internal_fwd_jobs.add(job_to_send); } } } while(it.hasNext()){ // send jobs to neighbors for(RegionDirection rd : RegionDirection.values()){ if(rd == RegionDirection.rd_undefined){ continue; } if(!rm.IsCoordinateValid(rm.GetNeighborX( pos.x, rd), rm.GetNeighborY(pos.y, rd))){ continue; } RegionBorder b = region.GetRegionBorder(rd); double next_w = b.GetWeight(); if(b.IsBlocked()){ //skip this direction continue; }else{ //send job to this direction next_w += w; JobMessage job_to_send = new JobMessage(seg_id, rm.GetNeighborPos(pos, rd), 1, next_w, GlobalRouterV3.GetOppositeDir(rd)); /** send job to region */ internal_fwd_jobs.add(job_to_send); } } //get direction and border to next region RegionDirection cur_dir = it.next(); RegionBorder border = region.GetRegionBorder(cur_dir); //calculate new weight double bw = border.GetWeight(); // blockages could have been occurred meanwhile if(border.IsBlocked()){ //cancel computation, because of blockage return null; } w += bw; // fetch next region and seg_info pos = rm.GetNeighborPos(pos, cur_dir); region = rm.RegionAt(pos.x, pos.y); seg_info = region.segment_infos[seg_id]; // set new weight seg_info.is_on_min_path = true; } return new JobMessage(seg_id, pos, w, rm.max_detour); } /** Polls jobs from master and tries to route them */ private void FindRoutes(){ /** put source to internal job queue */ JobMessage job = rm.PollSegmentJob(); while(job != null){ /** first re-initialize segment_infos */ for(int i = 0; i < rm.regions_x * rm.regions_y; ++i){ rm.regions[i].segment_infos[job.seg_id] = rm.new SegmentInfo(); } Vector2i source = new Vector2i(rm.segments[job.seg_id].start); Vector2i sink = new Vector2i(rm.segments[job.seg_id].end); /** create shortest path */ GlobalRouterPathFinder path_finder = new GlobalRouterPathFinder(rm); // XXX [fschmidt] router could not find shortest path on small designs List<RegionDirection> rd_path = path_finder.FindShortestPath(job.seg_id); JobMessage best_job = null; if(rd_path != null){ //could find shortest path best_job = PutShortestPath(rd_path, source, job.seg_id); } if(rd_path == null || best_job == null){ // could not find shortest path so drop this segment /** remove demand estimate */ DemandTemplateHandler dth = new DemandTemplateHandler(this); dth.DecrementDemandEstimate(source, sink); /** put segment id to non_routable */ non_routable.add(job.seg_id); /** continue with next segment */ }else{ //min_path found and set /** do internal jobs */ while(!internal_fwd_jobs.isEmpty()){ JobMessage internal_job = internal_fwd_jobs.get(0); internal_fwd_jobs.remove(0); int seg_id = internal_job.seg_id; JobMessage bwd_job = DoForwardJob(internal_job); if(bwd_job != null){ if(bwd_job.weight < best_job.weight){ best_job = bwd_job; } } if(internal_job.step_num > rm.max_detour || internal_fwd_jobs.isEmpty()){ internal_bckwd_jobs.add(best_job); backtrace = new Vector<RegionDirection>(); Vector2i error_pos = BackwardPropagation(); if(error_pos != null){ // could not complete backtrace, because blockage occurred meanwhile // need to revert changes Vector2i it = new Vector2i(error_pos); for(int i = 0; i < backtrace.size(); ++i){ RegionDirection curr_dir = backtrace.get(i); it = rm.GetNeighborPos(it, curr_dir); } // add id to non_routables non_routable.add(job.seg_id); }else{ /** backtrace was valid, so offer it to master */ //but first reset start and end passes if(backtrace.size() > 0){ RegionDirection start_dir = backtrace.get(0); Vector2i start = rm.segments[seg_id].start; if(start_dir == RegionDirection.rd_left || start_dir == RegionDirection.rd_right){ double y = rm.segments[seg_id].d_start_y % rm.region_height; int sy_pos = (int)Math.floor((y - (rm.tileSize / 2d)) / rm.tileSize); rm.RegionAt(start.x, start.y).GetRegionBorder(start_dir).FromSoftToPriv(seg_id, sy_pos); }else if(start_dir == RegionDirection.rd_up || start_dir == RegionDirection.rd_down){ double x = rm.segments[seg_id].d_start_x % rm.region_width; int sx_pos = (int)Math.floor((x - (rm.tileSize / 2d)) / rm.tileSize); rm.RegionAt(start.x, start.y).GetRegionBorder(start_dir).FromSoftToPriv(seg_id, sx_pos); } start_dir = null; start = null; RegionDirection end_dir = GlobalRouterV3.GetOppositeDir(backtrace.get(backtrace.size() - 1)); Vector2i end = rm.segments[seg_id].end; if(end_dir == RegionDirection.rd_left || end_dir == RegionDirection.rd_right){ double y = rm.segments[seg_id].d_end_y % rm.region_height; int ey_pos = (int)Math.floor((y - (rm.tileSize / 2d)) / rm.tileSize); rm.RegionAt(end.x, end.y).GetRegionBorder(end_dir).FromSoftToPriv(seg_id, ey_pos); }else if(end_dir == RegionDirection.rd_up || end_dir == RegionDirection.rd_down){ double x = rm.segments[seg_id].d_end_x % rm.region_width; int ex_pos = (int)Math.floor((x - (rm.tileSize / 2d)) / rm.tileSize); rm.RegionAt(end.x, end.y).GetRegionBorder(end_dir).FromSoftToPriv(seg_id, ex_pos); } } // finally offer backtrace to master rm.OfferBacktrace(backtrace, seg_id); } /** in any case remove estimated demand and continue with next job */ DemandTemplateHandler dth = new DemandTemplateHandler(this); dth.DecrementDemandEstimate(source, sink); break; } } } internal_fwd_jobs.clear(); job = rm.PollSegmentJob(); } } private void SortPassesV2(){ for(int y = slave_id; y < rm.regions_y; y += rm.num_threads){ Vector<Integer> passes = rm.RegionAt(0, y).GetRegionBorder(RegionDirection.rd_right).HardPassBorderV2(); for(int x = 1; x < rm.regions_x - 1; ++x){ passes = rm.RegionAt(x, y).GetRegionBorder(RegionDirection.rd_right).HardPassBorderV2(passes); } } for(int x = slave_id; x < rm.regions_x; x += rm.num_threads){ Vector<Integer> passes = rm.RegionAt(x, 0).GetRegionBorder(RegionDirection.rd_up).HardPassBorderV2(); for(int y = 1; y < rm.regions_y - 1; ++y){ passes = rm.RegionAt(x, y).GetRegionBorder(RegionDirection.rd_up).HardPassBorderV2(passes); } } } int debug_bt_skips = 0; private void CreateOutput(){ /** poll backtraces */ SegBtPair sbtp = rm.PollBacktrace(); Vector<RegionDirection> bt = sbtp.backtrace; int seg_id = sbtp.seg_id; while(bt != null){ if(!rm.not_routed.contains(new Integer(sbtp.seg_id))){ Vector2i current_region_pos = new Vector2i(rm.segments[seg_id].start); Vector2i next_region_pos; int start_layer = rm.electric_segments.get(seg_id).getStartLayers().get(0).getMetalNumber(); int finish_layer = rm.electric_segments.get(seg_id).getFinishLayers().get(0).getMetalNumber(); List<SegPart> coarse_route = new ArrayList<SegPart>(); ArrayList<Vector2i> visited_routes = new ArrayList<Vector2i>(); visited_routes.add(new Vector2i(rm.segments[seg_id].start)); /** set startpoint */ Coordinate last_coordinate = new Coordinate(rm.segments[seg_id].d_start_x, rm.segments[seg_id].d_start_y, start_layer); Coordinate cur_coordinate; /** iterate through trace */ Iterator<RegionDirection> it = bt.iterator(); while(it.hasNext()){ RegionDirection direction = it.next(); next_region_pos = rm.GetNeighborPos(current_region_pos, direction); visited_routes.add(new Vector2i(next_region_pos)); RegionBorder border = rm.RegionAt(current_region_pos.x, current_region_pos.y).GetRegionBorder(direction); /** calculate position in border */ int pos_in_list = border.GetHardPos(seg_id); int pos_in_vertical_border = pos_in_list; int pos_in_horizontal_border = pos_in_list; double offset_hor = (double) pos_in_horizontal_border * rm.tileSize + rm.tileSize; double offset_vert = (double) pos_in_vertical_border * rm.tileSize + rm.tileSize; double cur_seg_pos_x = current_region_pos.x * rm.region_width; double cur_seg_pos_y = current_region_pos.y * rm.region_height; ManhattenAlignment cur_seg_pos_align = ManhattenAlignment.ma_undefined; switch(direction){ case rd_left: cur_seg_pos_x += 0.0d; cur_seg_pos_y += offset_vert; cur_seg_pos_align = ManhattenAlignment.ma_horizontal; break; case rd_right: cur_seg_pos_x += rm.region_width; cur_seg_pos_y += offset_vert; cur_seg_pos_align = ManhattenAlignment.ma_horizontal; break; case rd_up: cur_seg_pos_x += offset_hor; cur_seg_pos_y += rm.region_height; cur_seg_pos_align = ManhattenAlignment.ma_vertical; break; case rd_down: cur_seg_pos_x += offset_hor; cur_seg_pos_y += 0.0d; cur_seg_pos_align = ManhattenAlignment.ma_vertical; break; } /** enlarge route */ cur_coordinate = new Coordinate(cur_seg_pos_x, cur_seg_pos_y, start_layer, cur_seg_pos_align); SegPart sub_r_wrapper = new SegPart(); ArrayList<Coordinate> sub_r = new ArrayList<Coordinate>(); sub_r.add(last_coordinate); sub_r.add(cur_coordinate); sub_r_wrapper.segment_part = sub_r; sub_r_wrapper.id = seg_id; coarse_route.add(sub_r_wrapper); /** set routing segment to region */ rm.AddRouteToOutReg(current_region_pos, sub_r_wrapper); /** refresh variables for next iteration */ current_region_pos = next_region_pos; last_coordinate = cur_coordinate;//new Coordinate(cur_coordinate.x, cur_coordinate.y, cur_coordinate.layer); } /** set endpoint */ cur_coordinate = new Coordinate(rm.segments[seg_id].d_end_x, rm.segments[seg_id].d_end_y, finish_layer); SegPart sub_r_wrapper = new SegPart(); ArrayList<Coordinate> sub_r = new ArrayList<Coordinate>(); sub_r.add(last_coordinate); sub_r.add(cur_coordinate); sub_r_wrapper.segment_part = sub_r; sub_r_wrapper.id = seg_id; coarse_route.add(sub_r_wrapper); /** set routing segment to region */ rm.AddRouteToOutReg(current_region_pos, sub_r_wrapper); /** offer calculated route to rm */ rm.OfferCoarseRoute(coarse_route, seg_id, visited_routes); }else{ ++debug_bt_skips; } /** poll next backtrace */ sbtp = rm.PollBacktrace(); bt = sbtp.backtrace; seg_id = sbtp.seg_id; } } private void EstimateDemand(){ SegmentRepresentation seg_rep = rm.PollDemandEstimationJob(); while(seg_rep != null){ /** Create Demand Template and add it to RegionBorders */ DemandTemplateHandler dth = new DemandTemplateHandler(this); dth.AddDemandEstimate(seg_rep.start, seg_rep.end); /** poll new job */ seg_rep = rm.PollDemandEstimationJob(); } } private void RemoveFailedSegments(){ int seg_id = rm.PollFailedId(); while(seg_id >= 0){ /** get route */ RouteToStitch rts = null; rts = rm.output_coarse_routes.get(seg_id); if(rts == null){ seg_id = rm.PollFailedId(); continue; } ArrayList<Vector2i> route = rts.region_positions; Iterator<Vector2i> it = route.iterator(); if(it.hasNext()){ Vector2i cur = it.next(); Vector2i next = it.hasNext() ? it.next() : null; while(next != null){ RegionDirection dir = rm.DirFromTo(cur, next); if(dir != RegionDirection.rd_undefined){ RegionBorder b = rm.RegionAt(cur.x, cur.y).GetRegionBorder(dir); b.RevertHardPass(seg_id); } cur = next; next = it.hasNext() ? it.next() : null; } } seg_id = rm.PollFailedId(); }; } public void run(){ /** Remove Failed Segments from last run */ RemoveFailedSegments(); /** join threads */ try { rm.barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } /** reset output_routes */ if(slave_id == 0){ rm.ResetOutputRoutes(); } /** calculate demand estimate */ EstimateDemand(); /** join threads */ try { rm.barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } /** do frontwave and backtraces for all segments */ FindRoutes(); rm.OfferUnrouted(non_routable); /** join threads */ try { rm.barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } SortPassesV2(); /** join threads */ try { rm.barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } CreateOutput(); /** join threads */ try { rm.barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } } }