#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "maze.h"
#include "grid.h"
#include "parser.h"
#include "cmumovie.h"
extern long long cells_expanded;
extern int nets_routed;
extern int max_queue_size;
extern int dir_cost,via_cost,bend_cost;
extern int global_num_cells_frame;
extern int dir_cost_array[4][6];
extern float RUBIN_CONST;
extern int global_cmuview_file;
extern char global_cmuview_filename[256];
int global_movie=0;
int global_movie_expand=0; // whether to show mazeroute expansion or not
//vector<list<cell> > net_paths;
vector<list<wire_segment> > net_paths_segment;
vector<int> net_partial;
int violations_wirelen(grid &g, int &violations, int &wirelen,
vector<int> &layer_wirelen)
{
violations=wirelen=0;
cell c;
for (c.l=0; c.l<4; c.l++) {
for (c.y=0; c.y<g.height; c.y++) {
for (c.x=0; c.x<g.width; c.x++) {
if (g.countNets(c)>1) {
violations++;
}
if (g.countNets(c)>0) {
if (!(g.isPin(c))) {
layer_wirelen[(int)c.l]++;
wirelen++;
}
}
}
}
}
return 0;
}
int net_violations_wirelen_bends(grid &g, int n, int &violations, int &wirelen,
int &vias, int &bends, vector<int> &layer_wirelen)
{
violations=wirelen=vias=bends=0;
list<cell>::iterator lci;
list<cell> lc;
segment_to_path(net_paths_segment[n],lc);
lci=lc.begin();
int old_layer=lci->l;
int old_dir=0,dir=0,first=1;
wire_segment ws;
ws.x1=lci->x; ws.y1=lci->y; ws.z1=lci->l;
for (;lci!=lc.end();++lci) {
ws.x2=lci->x; ws.y2=lci->y; ws.z2=lci->l;
if (g.countNets(*lci)>1) {
violations++;
//fprintf(stderr,"violation at net=%i (%i,%i,%i)\n",
// n,lci->x,lci->y,lci->l);
}
wirelen++;
layer_wirelen[lci->l]++;
// try to determine if this is a non-contiguous cell
dir=get_seg_dir(ws);
if (dir>=0) {
if (lci->l != old_layer) vias++;
if (dir!=old_dir && !first) bends++;
first=0;
} else {
first=1;
}
old_layer=lci->l;
old_dir=dir;
ws.x1=ws.x2; ws.y1=ws.y2; ws.z1=ws.z2;
}
return 0;
}
int route_all_nets(grid &g, vector<net> &vn)
{
// pick some random ordering of the nets... for now we'll
// just do them in the order given to us
int i,j,partial;
for (i=0;i<vn.size();i++) {
fprintf(stderr,"route_all_nets: routing net %i/%i\r",i,vn.size());
fflush(stderr);
int id=vn[i].id;
// check to see if this net has already been routed
if (net_paths_segment[id].size()>0) {
// we need to rip up this path
list<cell> lc;
segment_to_path(net_paths_segment[id],lc);
g.removeNetFromPath(lc,id);
net_paths_segment[id].clear();
}
// now we need to route it again using the current
// path costs as stored in the grid element
list<pin> lp;
for (j=0;j<vn[i].pins.size();j++)
lp.push_back(vn[i].pins[j]);
list<cell> lc;
lc=net_maze_route(g,id,lp,partial);
net_paths_segment[id]=path_to_segment(lc);
net_partial[id]=partial;
// now we should add this new path into the grid
g.addNetToPath(lc,id);
}
return 0;
}
int tot_wirelen,tot_bends,tot_vias,tot_violations, max_violations;
vector<int> vi_violations, vi_bends, vi_wirelen, vi_vias;
vector<int> vi_layer_wirelen;
vector<net> vn;
int route_one_pass(grid &g, int max_id, int pass)
{
int i;
int netcost,mincost,badcost;
// guess at a way to change net costs... needs to be more complicated
// the violations subtraction should probably be something exponential
// i.e. approach the minimum only as violations gets very large
netcost=4*pass;
if (pass>=5) netcost+=(int) (2.0*pow(pass-3,3.5));
mincost=netcost/2;
// number of violations should probably also be relative to number of
// pins... nets with large number of pins will tend to have big numbers
// of violations by default
for (i=0;i<max_id;i++) {
if (max_violations==0) badcost=0;
else badcost=vi_violations[i]*(netcost-mincost)/max_violations;
badcost=vi_violations[i];
g.net_costs[i]=max(netcost-badcost,mincost);
}
g.quantizeCosts();
route_all_nets(g,vn);
tot_wirelen=tot_bends=tot_vias=tot_violations=0;
vi_violations.clear();
vi_bends.clear();
vi_wirelen.clear();
vi_vias.clear();
vi_layer_wirelen.resize(4); vi_layer_wirelen.clear();
max_violations=0;
for (i=0;i<vn.size();i++) {
int violations,bends,wirelen,vias;
net_violations_wirelen_bends(g, vn[i].id, violations, wirelen,
vias,bends,vi_layer_wirelen);
vi_violations[vn[i].id]=violations;
tot_violations+=violations;
if (violations>max_violations) max_violations=violations;
vi_bends[vn[i].id]=bends;
tot_bends+=bends;
vi_wirelen[vn[i].id]=wirelen;
tot_wirelen+=wirelen;
vi_vias[vn[i].id]=vias;
tot_vias+=vias;
}
vi_layer_wirelen.resize(4); vi_layer_wirelen.clear();
violations_wirelen(g,tot_violations,tot_wirelen,vi_layer_wirelen);
fprintf(stderr, "\nPASS:%i \t",pass);
fprintf(stderr, "Wirelen: %i Vias: %i Bends: %i Violations: %i\n",
tot_wirelen,tot_vias,tot_bends,tot_violations);
if (global_movie) {
if (cmumovie_newframe()<0) exit(1);
// draw the routed nets
cmumovie_drawnets(net_paths_segment,vi_violations);
}
}
int ripup_reroute(char *fname)
{
vector<pin> vp;
int width,height;
int ret,i,y,j;
ret=parse_placement(fname,vn,vp,width,height);
if (ret<0) {
printf("parsing failed!\n");
return 0;
}
if (global_movie) {
if (cmumovie_config(width,height)<0) exit(1);
}
int max_id=0;
for (i=0;i<vn.size();i++) if (vn[i].id>max_id) max_id=vn[i].id;
// net_paths.resize(max_id+1);
net_paths_segment.resize(max_id+1);
net_partial.resize(max_id+1);
grid g;
g.makeGrid(vp,width,height,max_id);
vi_violations.resize(max_id+1); vi_violations.clear();
vi_bends.resize(max_id+1);
vi_wirelen.resize(max_id+1);
vi_vias.resize(max_id+1);
float ratio,old_ratio;
route_one_pass(g,max_id,0);
for (i=1;i<=6 || ratio>1.5 || old_ratio>1.5;i++) {
old_ratio=ratio;
ratio=tot_violations;
route_one_pass(g,max_id,i);
ratio=ratio/(float) tot_violations;
if (tot_violations==0) ratio=0;
}
if (tot_violations==0) return 0;
for (i=2;i<=5 || ratio>1.3 || old_ratio>1.3;i++) {
old_ratio=ratio;
ratio=tot_violations;
route_one_pass(g,max_id,i);
ratio=ratio/(float)(tot_violations);
if (tot_violations==0) ratio=0;
}
if (tot_violations==0) return 0;
route_one_pass(g,max_id,100);
return 0;
}
int display_net(list<wire_segment> lws, int net_id, int violations, int partial)
{
printf("n %i\n",net_id);
if (partial) {
printf("p\n");
/*
} else if (lws.size()==0 &&
vn[net_id].pins.size()>1) {
printf("x\n");
*/
} else {
printf("r\n");
}
printf("%i\n",violations);
list<wire_segment>::iterator lwsi;
for (lwsi=lws.begin();lwsi!=lws.end();++lwsi) {
if (lwsi->z1!=lwsi->z2) {
printf("v %i %i %i %i\n",lwsi->z1+1, lwsi->z2+1, lwsi->x1, lwsi->y1);
} else {
printf("w %i %i %i %i %i\n",lwsi->z1+1, lwsi->x1, lwsi->y1, lwsi->x2, lwsi->y2);
}
}
}
int display_results()
{
int i;
printf("%i\n",tot_wirelen);
printf("%i\n",tot_bends);
printf("%i\n",tot_vias);
printf("%i %i %i %i\n",vi_layer_wirelen[0],vi_layer_wirelen[1],
vi_layer_wirelen[2],vi_layer_wirelen[3]);
for (i=0;i<vn.size();i++) {
//list<wire_segment> lws=path_to_segment(net_paths[vn[i].id]);
display_net(net_paths_segment[vn[i].id],vn[i].id,
vi_violations[vn[i].id],net_partial[vn[i].id]);
}
printf("e\n");
fprintf(stderr, "\ncells_expanded: %lld nets_routed: %i ave: %lld\n",
cells_expanded, nets_routed, cells_expanded/nets_routed);
return 0;
}
void init_dir_cost()
{
int l,dir;
for (l=0;l<4;l++) {
for (dir=0;dir<6;dir++) dir_cost_array[l][dir]=0;
}
dir_cost_array[0][0]=dir_cost;
dir_cost_array[0][2]=dir_cost;
dir_cost_array[2][0]=dir_cost;
dir_cost_array[2][2]=dir_cost;
dir_cost_array[1][1]=dir_cost;
dir_cost_array[1][3]=dir_cost;
dir_cost_array[3][1]=dir_cost;
dir_cost_array[3][3]=dir_cost;
}
void usage()
{
printf("Usage: route [OPTION]... [PLACEMENT FILE]...\n");
printf("Performs ripup/reroute routing on the given placement file.\n");
printf("Final routed design is written to standard output, intermediate\n");
printf("status information is written to standard error\n");
printf(" -m Open cmuview and display results after each pass\n");
printf(" -e Ditto, but display cell expansion during mazerouting\n");
printf(" -n Number of expanded cells to show each frame\n");
printf(" -d Frame delay for cmumovie, default is 500ms\n");
printf(" -f Write cmuview output to given file\n");
printf(" -v Via cost, default is %i\n",via_cost);
printf(" -w Wrong direction cost, default is %i\n",dir_cost);
printf(" -b Bend cost, default is %i\n",bend_cost);
printf(" -R Rubin cost estimator fudge factor, default is %f\n",RUBIN_CONST);
printf(" -h Display this help and exit\n");
printf("\n(c) 2002 Josh Pieper & Ricky Raedalli-Sanchez\n");
exit(0);
}
int main(int argc, char **argv)
{
char *short_opt="mew:v:d:hn:b:R:f:";
int c;
int movie_delay=500;
init_dir_cost();
while ((c=getopt(argc, argv, short_opt))!=-1) {
switch (c) {
case 'f':
strncpy(global_cmuview_filename,optarg,255);
global_cmuview_file=1;
break;
case 'm': // movie playing on
global_movie=1;
break;
case 'e':
global_movie_expand=1;
global_movie=1;
break;
case 'w': // wrong direction cost
dir_cost=atoi(optarg);
init_dir_cost();
break;
case 'd': // movie delay
movie_delay=atoi(optarg);
break;
case 'v':
via_cost=atoi(optarg);
break;
case 'b':
bend_cost=atoi(optarg);
break;
case 'n':
global_num_cells_frame=atoi(optarg);
break;
case 'R':
RUBIN_CONST=atof(optarg);
break;
case 'h':
usage();
break;
default:
printf("unrecognized option!\n");
usage();
}
}
if (optind>=argc) {
printf("not enough args\n");
usage();
}
if (global_movie) {
if (cmumovie_open(movie_delay)<0) {
fprintf(stderr,"cmumovie_open failed!\n");
exit(1);
}
}
ripup_reroute(argv[optind]);
display_results();
fflush(stdout);
fflush(stderr);
if (global_movie && ! global_cmuview_file) {
// somehow wait for window to close
while (1) sleep(1);
cmumovie_close();
}
return 0;
}