#include <stdio.h> #include <stdlib.h> #include <stl.h> #include <hash_set> #include "maze.h" #include "grid.h" #include "cmumovie.h" float RUBIN_CONST=1.1; extern int global_movie_expand; extern vector<list<wire_segment> > net_paths_segment; extern vector<int> vi_violations; long long cells_expanded=0; int nets_routed=0; int dir_cost=10; int via_cost=10; int bend_cost=1; int global_num_cells_frame=10; int dir_cost_array[4][6]; list<cell> maze_route(grid &g, list<cell> &source, int net_dest, list<pin> &remaining); bool operator<(const active_cell &ac, const active_cell &ac2) { return (ac.total_cost>ac2.total_cost); } static int estimated_pathcost(cell c, cube r) { int dx=0,dy=0,dz=0; if (c.x < r.x1) { dx=r.x1-c.x; } else if (c.x > r.x2) { dx=c.x - r.x2; } if (c.y < r.y1) { dy=r.y1-c.y; } else if (c.y > r.y2) { dy=c.y-r.y2; } if (c.l < r.z1) { dz=r.z1 - c.l; } else if (c.l > r.z2) { dz=c.l-r.z2; } return dx+dy+dz*(via_cost); } // estimated path cost for a destination pin // to a source cube -- how to deal with levels static int estimated_pathcost(pin p, cube r) { int dx=0,dy=0,dz=0; if (p.x < r.x1) { dx=r.x1-p.x; } else if (p.x > r.x2) { dx=p.x - r.x2; } if (p.y < r.y1) { dy=r.y1-p.y; } else if (p.y > r.y2) { dy=p.y-r.y2; } // pins have no level information /* if (p.l < r.z1) { dz=r.z1 - p.l; } else if (p.l > r.z2) { dz=p.l-r.z2; } */ // return dx+dy+dz*(via_cost+1); return dx+dy; } static cube get_bounding_cube(list<pin> &vp) { int i,count=0; int vp_size=vp.size(); cube r; r.x1=vp.front().x; r.x2=vp.front().x; r.y1=vp.front().y-1; r.y2=vp.front().y+1; list<pin>::iterator lpi; lpi=vp.begin(); ++lpi; for (;lpi!=vp.end();++lpi,++count) { if (lpi->x<r.x1) r.x1=lpi->x; if ((lpi->x)>r.x2) r.x2=(lpi->x); if ((lpi->y-1)<r.y1) r.y1=(lpi->y-1); if ((lpi->y+2)>r.y2) r.y2=(lpi->y+1); } r.z1=0; r.z2=1; return r; } // cells from pin cannot be in lc to begin with static void add_cells_from_pin(list<cell> &lc, pin p) { int y; int l=-1,h=1; if (p.pad) { l=0;h=0; } cell c; for (y=l;y<=h;y++) { c.x=p.x; c.y=p.y+y; c.l=1; c.l2=-1; lc.push_back(c); c.l=0; lc.push_back(c); } } int get_seg_dir(wire_segment ws) { if (ws.x1==ws.x2 && ws.y1==ws.y2) { if ((ws.z1-ws.z2)==1) return 0; if ((ws.z2-ws.z1)==1) return 1; return -2; // up/down } if (ws.x1==ws.x2 && ws.z1==ws.z2) { if ((ws.y1-ws.y2)==1) return 2; if ((ws.y2-ws.y1)==1) return 3; return -2; // north/south } if (ws.y1==ws.y2 && ws.z1==ws.z2) { if ((ws.x1-ws.x2)==1) return 4; if ((ws.x2-ws.x1)==1) return 5; return -2; // east/west } return -2; } void segment_to_path(list<wire_segment> &path, list<cell> &ret) { cell c; list<wire_segment>::iterator lwsi; for (lwsi=path.begin();lwsi!=path.end();++lwsi) { if (lwsi->z1==lwsi->z2) { // not a via if (lwsi->x1 != lwsi->x2) { // x dir c.y=lwsi->y1; c.l=lwsi->z1; for (c.x=min(lwsi->x1,lwsi->x2); c.x<=(max(lwsi->x1,lwsi->x2));c.x++) ret.push_back(c); } else { // y dir c.x=lwsi->x1; c.l=lwsi->z1; for (c.y=min(lwsi->y1,lwsi->y2); c.y<=(max(lwsi->y1,lwsi->y2));c.y++) ret.push_back(c); } } } } list<wire_segment> path_to_segment(list<cell> &path) { list<wire_segment> ret; wire_segment cur_seg,tseg; int dir=-1; cur_seg.x1=-1; cur_seg.x2=-1; list<cell>::iterator lci; for (lci=path.begin();lci!=path.end();++lci) { if (lci->l2>=0) { // we have a via if (cur_seg.x2>=0) { // current segment is valid, so push it onto return list ret.push_back(cur_seg); } cur_seg.x1=lci->x; cur_seg.y1=lci->y; cur_seg.z1=lci->l; cur_seg.x2=lci->x; cur_seg.y2=lci->y; cur_seg.z2=lci->l2; ret.push_back(cur_seg); cur_seg.x1=-1; cur_seg.x2=-1; } else { if (cur_seg.x1==-1) { //we have no current segment, //new one will be just this cell cur_seg.x1=lci->x; cur_seg.y1=lci->y; cur_seg.z1=lci->l; cur_seg.x2=lci->x; cur_seg.y2=lci->y; cur_seg.z2=lci->l; dir=-1; } else { tseg.x1=cur_seg.x2; tseg.y1=cur_seg.y2; tseg.z1=cur_seg.z2; tseg.x2=lci->x; tseg.y2=lci->y; tseg.z2=lci->l; if (get_seg_dir(tseg)==-2) { //cells are not adjacent ret.push_back(cur_seg); cur_seg.x1=lci->x; cur_seg.y1=lci->y; cur_seg.z1=lci->l; cur_seg.x2=lci->x; cur_seg.y2=lci->y; cur_seg.z2=lci->l; dir=-1; } else { if (dir==-1 || dir==get_seg_dir(tseg)) { cur_seg.x2=lci->x; cur_seg.y2=lci->y; cur_seg.z2=lci->l; dir=get_seg_dir(tseg); } else { ret.push_back(cur_seg); cur_seg=tseg; dir=get_seg_dir(tseg); } } } } } if (cur_seg.x1!=-1) { ret.push_back(cur_seg); } return ret; } list<pin> find_pin_to_route(list<pin> &remaining_pins, list<pin> &used_pins) { list<pin>::iterator lpi,best; int pin_to_route_cost=1<<30;; list<pin> pin_to_route; cube source_cube = get_bounding_cube(used_pins); for (lpi=remaining_pins.begin();lpi!=remaining_pins.end();++lpi) { if (estimated_pathcost(*lpi,source_cube)<pin_to_route_cost) { pin_to_route_cost = estimated_pathcost(*lpi,source_cube); best = lpi; } } pin_to_route.push_front(*best); return pin_to_route; } list<cell> net_maze_route(grid &g, int net, list<pin> &pins, int &partial) { // we have to route each of the pins in turn until all the pins are // connected int pins_size=pins.size(); // for now we'll just do the pins in order list<cell> source; list<pin> remaining_pins=pins,used_pins; list<cell> actual_paths; int remaining_pins_size=remaining_pins.size(); list<pin> pin_to_route; add_cells_from_pin(source,remaining_pins.front()); used_pins.push_back(remaining_pins.front()); remaining_pins.pop_front(); remaining_pins_size=remaining_pins.size(); while(!remaining_pins.empty()) { list<pin>::iterator lpi,start_pin; list<cell>::iterator lci; pin_to_route = find_pin_to_route(remaining_pins,used_pins); list<cell> path=maze_route(g,source,net,pin_to_route); if (path.empty()) { // printf("ERROR, no route to cell!\n"); partial=1; return actual_paths; } for (lpi=remaining_pins.begin();lpi!=remaining_pins.end();++lpi) { if (lpi->x==path.back().x && (path.back().y>=(lpi->y-1) && path.back().y<=(lpi->y+1))) { break; } } if (lpi==remaining_pins.end()) { printf("ERROR in net_maze_route... path doesn't end on\n"); printf("one of the remaining pins!\n"); printf("it ends at (%i,%i,%i)\n",path.back().x,path.back().y, path.back().l); printf("remaining pins are: "); for (lpi=remaining_pins.begin();lpi!=remaining_pins.end();++lpi) { printf("(%i,%i,%i)\n",lpi->x,lpi->y,0); } printf("\n\nSource list is:\n"); for (lci=source.begin();lci!=source.end();++lci) { printf("(%i,%i,%i)\n",lci->x,lci->y,lci->l); } printf("\n\nBad path is:\n"); for (lci=path.begin();lci!=path.end();++lci) { printf("(%i,%i,%i)\n",lci->x,lci->y,lci->l); } exit(1); } add_cells_from_pin(source,*lpi); used_pins.push_back(*lpi); remaining_pins.erase(lpi); // copy path to actual path for (lci=path.begin();lci!=path.end();++lci) actual_paths.push_back(*lci); path.pop_front(); path.pop_back(); for (lci=path.begin();lci!=path.end();++lci) { source.push_back(*lci); } //fprintf(stderr,"net_maze_route %i/%i\r",used_pins.size(), // remaining_pins.size()); //fflush(stderr); } partial=0; return actual_paths; } void expand_cell(grid &g, priority_queue<active_cell> &pqa, cell &new_cell, active_cell &ac, cube &dest_cube, char dir, int dest) { cells_expanded++; active_cell nac; nac.pathcost=ac.pathcost+1; if (dest==0) nac.pathcost+=g.cellCost(new_cell); // now we will check for bends int old_dir=g.getPrevDir(ac.pos); if (old_dir<4 && dir<4 && old_dir!=dir) nac.pathcost+=bend_cost; // now we will check for vias if (new_cell.l != ac.pos.l) nac.pathcost+=via_cost; // let's penalize for the wrong direction: // odd layers: north-south, even layers: east-west if (new_cell.l&1) { // horizontal if (dir==1 || dir==3) { nac.pathcost+=dir_cost; } } else { // vertical if (dir==0 || dir==2) { nac.pathcost+=dir_cost; } } // trying to add the heuristic fudge factor to // make things go faster... turns out k=2 ended up being 10% // faster than k=1, but much worse results nac.total_cost=nac.pathcost+ (estimated_pathcost(new_cell,dest_cube))*RUBIN_CONST; nac.pos=new_cell; nac.dir=dir; pqa.push(nac); //fprintf(stderr,"reached cell (%i,%i,%i) path_cost=%.2f total_cost=%.2f\n", // nac.pos.x,nac.pos.y,nac.pos.l,nac.pathcost, // nac.total_cost); } struct hash_cell_struct { size_t operator() (const cell &c) const { return c.x+c.y+c.l; } }; struct eqcell { size_t operator() (const cell &a, const cell &b) const { return (a.x==b.x && a.y==b.y && a.l==b.l); } }; hash_set<cell, hash_cell_struct, eqcell> get_destinations_from_pins(list<pin> &pins) { hash_set<cell, hash_cell_struct, eqcell> ret; list<pin>::iterator lpi; for (lpi=pins.begin();lpi!=pins.end();++lpi) { cell c; c.x=lpi->x; for (c.l=0;c.l<2;c.l++) { for (c.y=(lpi->y-1);c.y<=(lpi->y+1);c.y++) { ret.insert(c); } } } return ret; } list<cell> maze_route(grid &g, list<cell> &source, int net_dest, list<pin> &remaining_pins) { int i; int count=0; list<cell> vc; list<cell> expanded_cells; priority_queue<active_cell> pqa; cube dest_cube; g.clearVisitedAndPrev(); cell zero; zero.x=-1; zero.y=-1; zero.l=0; list<cell>::iterator lci; // calc dest rectangle somehow dest_cube = get_bounding_cube(remaining_pins); hash_set<cell, hash_cell_struct, eqcell> destinations= get_destinations_from_pins(remaining_pins); for (lci=source.begin();lci!=source.end();++lci) { if (lci->l2 >= 0) continue; active_cell ac; ac.pathcost=0; ac.total_cost=estimated_pathcost(*lci,dest_cube)*RUBIN_CONST; ac.pos=*lci; ac.dir=7; pqa.push(ac); } if (global_movie_expand) { cmumovie_newframe(); cmumovie_drawnets(net_paths_segment,vi_violations); cmumovie_drawsourcedest(source,remaining_pins); } while (!pqa.empty()) { count++; if (global_movie_expand && (count%global_num_cells_frame)==0) { // draw an expanded cell movie frame cmumovie_newframe_short(); //cmumovie_drawnets(net_paths_segment,vi_violations); cmumovie_drawexpansion(expanded_cells); expanded_cells.clear(); } active_cell ac=pqa.top(); pqa.pop(); if (g.getVisited(ac.pos)) continue; // don't expand a cell twice g.setVisited(ac.pos); g.setPrev(ac.pos,ac.pos,ac.dir); if (global_movie_expand) expanded_cells.push_back(ac.pos); //fprintf(stderr,"expanding cell (%i,%i,%i) path_cost=%.2f total_cost=%.2f\n", // ac.pos.x,ac.pos.y,ac.pos.l,ac.pathcost,ac.total_cost); // expanding cell ac int done2=(destinations.find(ac.pos)!=destinations.end()); if (done2) { // we have hit the target // printf("We hit the target, backtracing\n"); cell c=ac.pos; unsigned char d; do { c.l2=-1; vc.push_front(c); d=g.getPrevDir(c); if ((d==4) || (d==5)) { if (d==4) c.l2=c.l-1; if (d==5) c.l2=c.l+1; vc.push_front(c); } } while ((c=g.getPrev(c)).x!=-1); nets_routed++; return vc; } int dir; for (dir=0;dir<6;dir++) { // printf("checking dir=%i\n",dir); cell new_cell; if (g.getNeighbor(ac.pos,dir,new_cell) && !g.getVisited(new_cell)) { int dest; if (destinations.find(new_cell)!=destinations.end()) dest=1; else dest=0; expand_cell(g,pqa,new_cell,ac, dest_cube,dir,dest); //} } } } return vc; // no path found, return empty }