/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: GlobalRouterV3.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.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Vector; import java.util.concurrent.CyclicBarrier; import com.sun.electric.tool.routing.RoutingFrame.RoutingSegment; import com.sun.electric.tool.routing.experimentalLeeMoore2.RoutingFrameLeeMoore.Coordinate; public class GlobalRouterV3 { /** Threads */ int num_threads; /** barrier to synchronize stages */ CyclicBarrier barrier; /** minimum tile size of detailed router */ double tileSize; /** maximum detour */ int max_detour = 6; /** cost for crossing a tile from horizontal to vertical or vice versa */ double via_cost = 0.2; /** Global routing output. This represents a view on a whole route. */ public class RouteToStitch{ public int id = -1; public List<SegPart> coarse_route = null; public ArrayList<Vector2i> region_positions; public RoutingSegment seg_head_tail = null; public int start_layer = Integer.MIN_VALUE; public int finish_layer = Integer.MIN_VALUE; public RouteToStitch(RoutingSegment routing_seg){ seg_head_tail = routing_seg; start_layer = routing_seg.getStartLayers().get(0).getMetalNumber(); finish_layer = routing_seg.getFinishLayers().get(0).getMetalNumber(); } public ArrayList<RegionToRoute> SelectPassedRegionsFrom(RegionToRoute[] all_regions){ ArrayList<RegionToRoute> ret = new ArrayList<RegionToRoute>(); Iterator<Vector2i> it = region_positions.iterator(); while(it.hasNext()){ Vector2i pos = it.next(); ret.add(all_regions[pos.y * regions_x + pos.x]); } return ret; } } public HashMap<Integer, RouteToStitch> output_coarse_routes; /** Adds a whole route to output data */ public synchronized void OfferCoarseRoute(List<SegPart> route, int seg_id, ArrayList<Vector2i> passed_regions){ RouteToStitch rts = new RouteToStitch(electric_segments.get(seg_id)); rts.coarse_route = route; rts.id = seg_id; rts.region_positions = passed_regions; output_coarse_routes.put(new Integer(rts.id), rts); } /** Output data for further processing in a detailed router. */ public class RegionToRoute{ Rectangle2D bounds; List<SegPart> segments_to_route; public RegionToRoute(Rectangle2D b){ bounds = b; segments_to_route = new ArrayList<SegPart>(); } } public RegionToRoute[] output_regions; /** Adds a route patch to a output region representation */ public synchronized void AddRouteToOutReg(Vector2i reg_pos, SegPart segment){ RegionToRoute region = OutputRegionAt(reg_pos.x, reg_pos.y); region.segments_to_route.add(segment); } /** Access to output */ public RegionToRoute OutputRegionAt(int x, int y){ return output_regions[y * regions_x + x]; } public RegionToRoute OutputRegionAt(int x, int y, RegionDirection dir){ switch(dir){ case rd_left: --x; break; case rd_right: ++x; break; case rd_down: --y; break; case rd_up: ++y; break; case rd_undefined: break; } if(IsCoordinateValid(x, y)){ return OutputRegionAt(x, y); }else{ return null; } } /** Information for a GlobalRouter worker to do his job */ class SegmentInfo{ public boolean is_initialized = false; public boolean was_part_of_bt = false; public boolean is_on_min_path = false; /** for each direction you can reach the source with several * length-minimum pairs */ private ArrayList<WeightLengthPair> left_back_scores = new ArrayList<WeightLengthPair>(); private ArrayList<WeightLengthPair> right_back_scores = new ArrayList<WeightLengthPair>(); private ArrayList<WeightLengthPair> up_back_scores = new ArrayList<WeightLengthPair>(); private ArrayList<WeightLengthPair> down_back_scores = new ArrayList<WeightLengthPair>(); public ArrayList<WeightLengthPair> GetScores(RegionDirection dir){ ArrayList<WeightLengthPair> ret = null; switch(dir){ case rd_left: ret = left_back_scores; break; case rd_right: ret = right_back_scores; break; case rd_up: ret = up_back_scores; break; case rd_down: ret = down_back_scores; break; case rd_undefined: ret = null; break; } return ret; } /** checks if segment is possibly part of the best backtrace and refreshes data */ public boolean RefreshSegment(int length, double weight, RegionDirection min_dir){ // first check if detour limit is reached if(max_detour < length){ return false; }else if(!is_initialized){ is_initialized = true; } if(min_dir != RegionDirection.rd_undefined){ // drop this path if there is another path with lower cost AND lower length ArrayList<WeightLengthPair> scores = GetScores(min_dir); for(WeightLengthPair wlp : scores){ if(wlp.length <= length && wlp.weight <= weight){ return false; } } // if not returned false, insert weight-length pair GetScores(min_dir).add(new WeightLengthPair(weight, length)); }else{ // broadcast weight-length pair to all directions (needed for source segment) for(RegionDirection dir : RegionDirection.values()){ if(dir == RegionDirection.rd_undefined){ continue; } ArrayList<WeightLengthPair> scores = GetScores(dir); scores.add(new WeightLengthPair(weight, length)); } } return true; } /** Information for backtracking to find its way back to the start point */ public BacktraceState GetMin(int max_path_length){ if(!is_initialized){ return null; } BacktraceState min = null; for(RegionDirection dir : RegionDirection.values()){ if(dir == RegionDirection.rd_undefined){ continue; } ArrayList<WeightLengthPair> scores = GetScores(dir); for(WeightLengthPair cur_wlp : scores){ if(cur_wlp.length > max_path_length){ continue; } if(min == null){ min = new BacktraceState(cur_wlp.weight, dir, cur_wlp.length); }else if(cur_wlp.weight < min.weight){ min.weight = cur_wlp.weight; min.dir = dir; min.path_length = cur_wlp.length; } } } return min; } } /** This represents a sub-region, passed by routes */ class RegionRepresentation{ public double weight; public SegmentInfo[] segment_infos; public RegionBorder left_border; public RegionBorder right_border; public RegionBorder lower_border; public RegionBorder upper_border; public RegionRepresentation(double weight, int num_segs){ this.weight = weight; segment_infos = new SegmentInfo[num_segs]; } public double getCongestionWeight(){ double congestion = 0; if(left_border != null && left_border.GetWeight() != Double.MAX_VALUE) congestion += left_border.GetWeight(); else congestion += 10; if(right_border != null && right_border.GetWeight() != Double.MAX_VALUE) congestion += right_border.GetWeight(); else congestion += 10; if(lower_border != null && lower_border.GetWeight() != Double.MAX_VALUE) congestion += lower_border.GetWeight(); else congestion += 10; if(upper_border != null && upper_border.GetWeight() != Double.MAX_VALUE) congestion += upper_border.GetWeight(); else congestion += 10; return congestion; } public RegionBorder GetRegionBorder(RegionDirection dir){ switch(dir){ case rd_left: return left_border; case rd_right: return right_border; case rd_down: return lower_border; case rd_up: return upper_border; default: return null; } } } RegionRepresentation[] regions; int regions_x, regions_y; double region_width, region_height; double offset_x, offset_y; /** Access to regions */ public RegionRepresentation RegionAt(int x, int y){ return regions[y * regions_x + x]; } public RegionRepresentation RegionAt(int x, int y, RegionDirection dir){ switch(dir){ case rd_left: --x; break; case rd_right: ++x; break; case rd_down: --y; break; case rd_up: ++y; break; case rd_undefined: break; } if(IsCoordinateValid(x, y)){ return RegionAt(x, y); }else{ return null; } } /** Representation of a border between two regions */ class RegionBorder{ private int demand; private int supply; private int min_supply = 4; private Vector<Integer> priv_soft_passes; private ArrayList<Integer> soft_passes = new ArrayList<Integer>(); private Vector<Integer> hard_passes = new Vector<Integer>(); public RegionBorder(int demand, int supply, int passes){ this.demand = demand; this.supply = supply; priv_soft_passes = new Vector<Integer>(); for(int i = 0; i < passes; ++i){ priv_soft_passes.add(null); hard_passes.add(null); } } boolean IsBlocked(){ synchronized(this){ return supply <= this.min_supply; } } public int GetDemand(){ return demand; } public void IncDemand(){ ++ demand; } public boolean DecDemand(){ if(demand > 0){ --demand; return true; }else{ return false; } } public int GetSupply(){ return supply; } public int GetHardPos(int seg_id){ return hard_passes.indexOf(new Integer(seg_id)); } /** see: "Global Wiring on a Wire Routing Machine" Ravi Nair et al. */ public double GetWeight(){ double estd = (double)(demand + 1) / 16.0d; double weight = Double.MAX_VALUE; if(estd <= supply - min_supply){ weight = estd * 8 / Math.pow(2, ((double)supply - min_supply - estd)/2); }else if(estd > supply - min_supply && supply - min_supply >= 3){ weight = estd * 8 * 2 / Math.pow(2, (double)supply - min_supply / 2); }else if(estd > supply - min_supply && supply - min_supply == 2){ weight = estd * 8 * 3; }else if(estd > supply - min_supply && supply - min_supply == 1){ weight = estd * 8 * 9; }else if(supply - min_supply == 0){ weight = Double.MAX_VALUE; } return weight; } /** Route passes border temporarily */ public boolean SoftPassBorder(int seg_id){ synchronized(this){ if(supply > this.min_supply){ --supply; soft_passes.add(seg_id); return true; }else{ return false; } } } /** Set a privileged position in this border */ public boolean FromSoftToPriv(int seg_id, int priv_pos){ synchronized(this){ if(soft_passes.contains(seg_id)){ soft_passes.remove(soft_passes.indexOf(seg_id)); int delta = 1; int length = priv_soft_passes.size(); int lower = priv_pos - delta; int higher = priv_pos + delta; while(((lower >= 0) && (lower < length)) || ((higher >= 0) && (higher < length))){ if(((lower >= 0) && (lower < length)) && priv_soft_passes.get(lower) == null){ priv_soft_passes.set(lower, seg_id); return true; }else if(((higher >= 0) && (higher < length)) && priv_soft_passes.get(higher) == null){ priv_soft_passes.set(higher, seg_id); return true; } ++delta; lower = priv_pos - delta; higher = priv_pos + delta; } // nothing free (should not happen) soft_passes.add(seg_id); return false; }else{ return false; } } } public boolean SoftPassBorder(int seg_id, int priv_pos){ synchronized(this){ if(supply > this.min_supply){ --supply; if(priv_soft_passes.get(priv_pos) == null){ priv_soft_passes.set(priv_pos, seg_id); return true; }else{ int delta = 1; int length = priv_soft_passes.size(); int lower = priv_pos - delta; int higher = priv_pos + delta; while(((lower >= 0) && (lower < length)) || ((higher >= 0) && (higher < length))){ if(((lower >= 0) && (lower < length)) && priv_soft_passes.get(lower) == null){ priv_soft_passes.set(lower, seg_id); return true; }else if(((higher >= 0) && (higher < length)) && priv_soft_passes.get(higher) == null){ priv_soft_passes.set(higher, seg_id); return true; } ++delta; lower = priv_pos - delta; higher = priv_pos + delta; } // nothing free (should not happen) soft_passes.add(seg_id); return true; } }else{ return false; } } } /** Remove a route, which passed this border earlier */ public boolean RevertSoftPass(int seg_id){ synchronized(this){ if(soft_passes.contains(seg_id)){ ++supply; soft_passes.remove(soft_passes.indexOf(seg_id)); return true; }else if(priv_soft_passes.contains(seg_id)){ ++supply; int index = priv_soft_passes.indexOf(seg_id); priv_soft_passes.set(index, null); return true; }else{ return false; } } } /** Pay attention using these two functions because of concurrency. * Reverting a pass, set in this function will only be done, if * detailed will not be able to route this wire. */ public Vector<Integer> HardPassBorderV2(){ HardPassBorder(); return new Vector<Integer>(hard_passes); } public Vector<Integer> HardPassBorderV2(Vector<Integer> passes){ for(int i = 0; i < passes.size(); ++i){ Integer id = passes.get(i); if(id != null && soft_passes.contains(id)){ FromSoftToPriv(id, i); } } HardPassBorder(); return new Vector<Integer>(hard_passes); } public void HardPassBorder(){ synchronized(this){ /** first sort passes */ Collections.sort(soft_passes); /** insert previliged passes */ for(int priv_i = 0; priv_i < priv_soft_passes.size(); ++priv_i){ if(priv_soft_passes.get(priv_i) == null){ continue; } int id = priv_soft_passes.get(priv_i); if(hard_passes.get(priv_i) == null){ hard_passes.set(priv_i, id); }else{ int delta = 1; int length = hard_passes.size(); int lower = priv_i - delta; int higher = priv_i + delta; while(((lower >= 0) && (lower < length)) || ((higher >= 0) && (higher < length))){ if(((lower >= 0) && (lower < length)) && hard_passes.get(lower) == null){ hard_passes.set(lower, id); break; }else if(((higher >= 0) && (higher < length)) && hard_passes.get(higher) == null){ hard_passes.set(higher, id); break; } ++delta; lower = priv_i - delta; higher = priv_i + delta; } } } /** then insert soft passes to hard passes */ int hi = this.min_supply / 2; for(int si = 0; si < soft_passes.size(); ++ si){ for(; hi < hard_passes.size() && hard_passes.get(hi) != null && hard_passes.get(hi) >= 0; ++hi){ }; if(hi < hard_passes.size()){ hard_passes.set(hi, soft_passes.get(si)); }else{ hard_passes.add(soft_passes.get(si)); } hi++; } /** and at the end reset soft_passes */ soft_passes = new ArrayList<Integer>(); int passes = priv_soft_passes.size(); priv_soft_passes = new Vector<Integer>(); for(int i = 0; i < passes; ++i){ priv_soft_passes.add(null); } } } /** Reverts a pass through this border, if the detailed router could * not route the segment. */ public boolean RevertHardPass(int seg_id){ synchronized(this){ int index = hard_passes.indexOf(new Integer(seg_id)); if(index >= 0){ ++supply; hard_passes.set(index, null); return true; }else{ return false; } } } /** Removes segments failed to route in the global router. */ public void CleanBorder(){ synchronized(this){ for(Integer i : not_routed){ if(soft_passes.contains(i)){ soft_passes.remove(soft_passes.indexOf(i)); } if(priv_soft_passes.contains(i)){ priv_soft_passes.set(priv_soft_passes.indexOf(i), null); } } } } } int max_supply_vertical, max_supply_horizontal; /** Checks and s to assure a correct coordinate access */ public boolean IsCoordinateValid(int x, int y){ return 0 <= x && x < regions_x && 0 <= y && y < regions_y; } public int ConvertX(double x){ return (int)(x / region_width); } public int ConvertY(double y){ return (int)(y / region_height); } public RegionDirection DirFromTo(Vector2i from, Vector2i to){ int x = to.x - from.x; int y = to.y - from.y; RegionDirection dir; if(x == 1 && y == 0){ dir = RegionDirection.rd_right; }else if(x == -1 && y == 0){ dir = RegionDirection.rd_left; }else if(x == 0 && y == 1){ dir = RegionDirection.rd_up; }else if(x == 0 && y == -1){ dir = RegionDirection.rd_down; }else{ dir = RegionDirection.rd_undefined; } return dir; } public int GetNeighborX(int x, RegionDirection dir){ switch(dir){ case rd_left: --x; break; case rd_right: ++x; break; } return x; } public int GetNeighborY(int y, RegionDirection dir){ switch(dir){ case rd_down: --y; break; case rd_up: ++y; break; } return y; } public Vector2i GetNeighborPos(int x, int y, RegionDirection dir){ switch(dir){ case rd_left: --x; break; case rd_right: ++x; break; case rd_down: --y; break; case rd_up: ++y; break; case rd_undefined: break; } return new Vector2i(x, y); } public Vector2i GetNeighborPos(Vector2i curr_pos, RegionDirection dir){ return GetNeighborPos(curr_pos.x, curr_pos.y, dir); } static public RegionDirection GetOppositeDir(RegionDirection dir){ switch(dir){ case rd_left: return RegionDirection.rd_right; case rd_right: return RegionDirection.rd_left; case rd_down: return RegionDirection.rd_up; case rd_up: return RegionDirection.rd_down; default: return RegionDirection.rd_undefined; } } /** Structure to implement job-stealing. This queue offers not yet routed segments. */ private ArrayList<JobMessage> segment_jobs; public synchronized JobMessage PollSegmentJob(){ if(segment_jobs.isEmpty()){ return null; }else{ JobMessage job = segment_jobs.get(0); segment_jobs.remove(0); return job; } } /** Interface between data from electric and global router */ class SegmentRepresentation{ public Vector2i start; public Vector2i end; public double d_start_x; public double d_start_y; public double d_end_x; public double d_end_y; SegmentRepresentation(Vector2i start, Vector2i end){ this.start = new Vector2i(start.x, start.y); this.end = new Vector2i(end.x, end.y); } } SegmentRepresentation[] segments; ArrayList<RoutingSegment> electric_segments; /** job stealing for demand estimation */ Integer demand_seg_index; public synchronized SegmentRepresentation PollDemandEstimationJob(){ SegmentRepresentation ret = null; if(to_reroute.isEmpty()){ if(demand_seg_index < segments.length){ ret = segments[demand_seg_index]; ++demand_seg_index; } }else{ if(demand_seg_index < to_reroute.size()){ ret = segments[to_reroute.get(demand_seg_index)]; ++demand_seg_index; } } return ret; } /** job stealing for removing failed segments */ Integer remove_failed_index; public synchronized int PollFailedId(){ if(remove_failed_index < to_reroute.size()){ int ret = to_reroute.get(remove_failed_index); ++remove_failed_index; return ret; }else{ return -1; } } public synchronized void ResetOutputRoutes(){ this.output_coarse_routes = new HashMap<Integer, RouteToStitch>(); } /** backtraces from global router workers */ class SegBtPair{ public int seg_id; public Vector<RegionDirection> backtrace; } ArrayList<SegBtPair> seg_backtraces; public synchronized void OfferBacktrace(Vector<RegionDirection> bt, int seg_id){ SegBtPair pair = new SegBtPair(); pair.backtrace = bt; pair.seg_id = seg_id; seg_backtraces.add(pair); } public synchronized SegBtPair PollBacktrace(){ SegBtPair ret; if(seg_backtraces.isEmpty()){ ret = new SegBtPair(); ret.seg_id = -1; ret.backtrace = null; }else{ ret = seg_backtraces.get(0); seg_backtraces.remove(0); } return ret; } /** routes which could not be routed */ public ArrayList<Integer> not_routed; public synchronized void OfferUnrouted(ArrayList<Integer> list){ not_routed.addAll(list); } /** synchronization of second phase */ Integer regions_in_work; public synchronized RegionRepresentation PollNextRegionToSort(){ RegionRepresentation ret = null; if(regions_in_work < regions_x * regions_y){ ret = regions[regions_in_work]; ++regions_in_work; } return ret; } /** list with id's of segments which need to be rerouted (feedback from detailed)*/ ArrayList<Integer> to_reroute; /** Transforms Coordinates back after the whole routing process is finished. */ public void Retransform(List<Coordinate> list){ Coordinate co; for (Iterator<Coordinate> i = list.iterator(); i.hasNext();) { co = i.next(); co.x += offset_x; co.y += offset_y; } } public GlobalRouterV3(Rectangle2D rect, int num_regions, List<RoutingSegment> segmentsToRoute, int num_threads, double tileSize){ this.tileSize = tileSize; this.num_threads = num_threads; barrier = new CyclicBarrier(num_threads); /* calculate region width and height */ double w = rect.getWidth() / num_regions; double h = rect.getHeight() / num_regions; int num_tiles_w_in_region = (int)Math.ceil(w / this.tileSize); int num_tiles_h_in_region = (int)Math.ceil(h / this.tileSize); this.region_width = num_tiles_w_in_region * this.tileSize; this.region_height = num_tiles_h_in_region * this.tileSize; this.regions_x = num_regions; this.regions_y = num_regions; this.offset_x = rect.getMinX() - Math.signum(rect.getMinX()) * Math.abs(rect.getMinX()) % 0.01; this.offset_y = rect.getMinY() - Math.signum(rect.getMinY()) * Math.abs(rect.getMinY()) % 0.01; regions = new RegionRepresentation[regions_x * regions_y]; electric_segments = new ArrayList<RoutingSegment>(segmentsToRoute); this.segments = new SegmentRepresentation[segmentsToRoute.size()]; Iterator<RoutingSegment> it = segmentsToRoute.iterator(); for(int i = 0; i < segments.length; ++i){ RoutingSegment r_seg = it.next(); double start_x = r_seg.getStartEnd().getLocation().getX() - offset_x; double start_y = r_seg.getStartEnd().getLocation().getY() - offset_y; double end_x = r_seg.getFinishEnd().getLocation().getX() - offset_x; double end_y = r_seg.getFinishEnd().getLocation().getY() - offset_y; Vector2i i_start = new Vector2i((int)(start_x / this.region_width), (int)(start_y / this.region_height)); Vector2i i_end = new Vector2i((int)(end_x / this.region_width), (int)(end_y / this.region_height)); if(i_start.x < 0){ i_start.x = 0; } if(i_start.x >= regions_x){ i_start.x = regions_x - 1; } if(i_start.y < 0){ i_start.y = 0; } if(i_start.y >= regions_y){ i_start.y = regions_y - 1; } if(i_end.x < 0){ i_end.x = 0; } if(i_end.x >= regions_x){ i_end.x = regions_x - 1; } if(i_end.y < 0){ i_end.y = 0; } if(i_end.y >= regions_y){ i_end.y = regions_y - 1; } this.segments[i] = new SegmentRepresentation(i_start, i_end); this.segments[i].d_start_x = start_x; this.segments[i].d_start_y = start_y; this.segments[i].d_end_x = end_x; this.segments[i].d_end_y = end_y; } /** setup RegionRepresentations */ for(int i = 0; i < this.regions_x * this.regions_y; ++i){ regions[i] = new RegionRepresentation(0d, segments.length); } /** create borders */ this.max_supply_horizontal = (int)(region_width / tileSize) - 1; int supply_x = this.max_supply_horizontal; this.max_supply_vertical = (int)(region_height / tileSize) - 1; int supply_y = this.max_supply_vertical; for(int x = 0; x < this.regions_x; ++x){ for(int y = 0; y < this.regions_y; ++y){ if(x > 0){ RegionAt(x, y).left_border = new RegionBorder(0, supply_y, max_supply_vertical); } if(y > 0){ RegionAt(x, y).lower_border = new RegionBorder(0, supply_x, max_supply_horizontal); } } } /** set upper and right border */ for(int x = 0; x < this.regions_x; ++x){ for(int y = 0; y < this.regions_y; ++y){ if(x < this.regions_x - 1){ RegionAt(x, y).right_border = RegionAt(x, y, RegionDirection.rd_right).left_border; } if(y < this.regions_y - 1){ RegionAt(x, y).upper_border = RegionAt(x, y, RegionDirection.rd_up).lower_border; } } } /** initialize for first run of global router */ to_reroute = new ArrayList<Integer>(); segment_jobs = new ArrayList<JobMessage>(); demand_seg_index = 0; regions_in_work = 0; not_routed = new ArrayList<Integer>(); remove_failed_index = 0; this.seg_backtraces = new ArrayList<SegBtPair>(); for(int i = 0; i < segments.length; ++i){ JobMessage job = new JobMessage(i, segments[i].start, 0, 0.0d, RegionDirection.rd_undefined); segment_jobs.add(job); } this.output_coarse_routes = new HashMap<Integer, RouteToStitch>(); this.output_regions = new RegionToRoute[regions_x * regions_y]; for(int x = 0; x < regions_x; ++x){ for(int y = 0; y < regions_y; ++y){ Rectangle2D rec = new Rectangle2D.Double(); rec.setFrameFromDiagonal(x * this.region_width, y * this.region_height, (x + 1) * this.region_width, (y + 1) * this.region_height); output_regions[y * regions_x + x] = new RegionToRoute(rec); } } } /** List of routes, which could be completed by the detailed router */ List<Integer> wiried_routes = new LinkedList<Integer>(); public void Reinitialize(List<Integer> failed_to_route){ to_reroute = new ArrayList<Integer>(failed_to_route); if(max_detour < Math.max(regions_x, regions_y)) { max_detour += 2; } //mark rest of output_coarse_routes that are not in failed_to_route as wiried for(RouteToStitch rts : output_coarse_routes.values()){ if(!failed_to_route.contains(rts.id)){ wiried_routes.add(rts.id); } } to_reroute.addAll(not_routed); not_routed = new ArrayList<Integer>(); segment_jobs = new ArrayList<JobMessage>(); demand_seg_index = 0; regions_in_work = 0; remove_failed_index = 0; this.seg_backtraces = new ArrayList<SegBtPair>(); for(int i = 0; i < to_reroute.size(); ++i){ int seg_id = to_reroute.get(i); JobMessage job = new JobMessage(seg_id, segments[seg_id].start, 0, 0.0d, RegionDirection.rd_undefined); segment_jobs.add(job); } this.output_regions = new RegionToRoute[regions_x * regions_y]; for(int x = 0; x < regions_x; ++x){ for(int y = 0; y < regions_y; ++y){ Rectangle2D rec = new Rectangle2D.Double(); rec.setFrameFromDiagonal(x * this.region_width, y * this.region_height, (x + 1) * this.region_width, (y + 1) * this.region_height); output_regions[y * regions_x + x] = new RegionToRoute(rec); } } /** reset demand estimate */ for(int x = 0; x < this.regions_x; ++x){ for(int y = 0; y < this.regions_y; ++y){ if(x > 0){ RegionAt(x, y).left_border.demand = 0; } if(y > 0){ RegionAt(x, y).lower_border.demand = 0; } } } } public void StartGlobalRouting(){ Thread[] slave_threads; GlobalRouterThreadV3[] slaves; slave_threads = new Thread[num_threads - 1]; slaves = new GlobalRouterThreadV3[num_threads]; /** start parallel global routing */ for(int i = 0; i < num_threads - 1; ++i){ slaves[i] = new GlobalRouterThreadV3(this, i); slave_threads[i] = new Thread(slaves[i]); slave_threads[i].setName("GlobalRouterSlave_" + i); slave_threads[i].start(); } slaves[num_threads - 1] = new GlobalRouterThreadV3(this, num_threads - 1); slaves[num_threads - 1].run(); } } /** routing segments representation declarations */ /** Position in coordinate system of global router */ class Vector2i{ public int x; public int y; public Vector2i(int x, int y){ this.x = x; this.y = y; } public Vector2i(Vector2i p){ this.x = p.x; this.y = p.y; } public boolean equals(Vector2i v){ return (v.x == x && v.y == y); } } /** region declaration */ enum RegionDirection{ rd_left, rd_right, rd_up, rd_down, rd_undefined } /** job queues declaration */ class JobMessage{ public int seg_id = Integer.MIN_VALUE; public Vector2i position = null; public int step_num = Integer.MIN_VALUE; public double weight = Double.MIN_VALUE; public RegionDirection min_dir = RegionDirection.rd_undefined; public JobMessage(int seg_id, Vector2i pos, int min_length, double weight, RegionDirection min_dir){ position = new Vector2i(pos.x, pos.y); this.seg_id = seg_id; this.step_num = min_length; this.weight = weight; this.min_dir = min_dir; } public JobMessage(int seg_id, Vector2i pos, int step_num){ position = new Vector2i(pos.x, pos.y); this.seg_id = seg_id; this.step_num = step_num; } public JobMessage(int seg_id, Vector2i pos, double weight, int step_num){ position = new Vector2i(pos.x, pos.y); this.seg_id = seg_id; this.weight = weight; this.step_num = step_num; } } /** SegmentInfoHelper classes */ class WeightLengthPair{ public double weight; public int length; public WeightLengthPair(double w, int l){ weight = w; length = l; } } /** Structure holding information for backtracing procedure */ class BacktraceState{ public double weight; public RegionDirection dir; public int path_length; public BacktraceState(double w, RegionDirection d, int l){ weight = w; dir = d; path_length = l; } } /** A segment patch, inside of a region. */ class SegPart{ public List<Coordinate> segment_part; public int id; }