#include <stdio.h>
#include <stdlib.h>
#include "grid.h"
int grid::makeGrid(vector<pin> &vp, int _width, int _height, int max_net)
{
int i,j;
width=_width;
height=_height;
ge=(grid_element ***) malloc(sizeof(grid_element **)*4);
if (!ge) return -1;
gpv=(grid_prev_visited ***) malloc(sizeof(grid_element **)*4);
if (!gpv) return -1;
gc=(grid_cost ***) malloc(sizeof(grid_cost **)*4);
if (!gc) return -1;
for (i=0;i<4;i++) {
ge[i]=(grid_element **) malloc(sizeof(grid_element*)*(height));
if (!ge[i]) return -1;
gpv[i]=(grid_prev_visited **) malloc(sizeof(grid_element *)*height);
if (!gpv[i]) return -1;
gc[i]=(grid_cost **) malloc(sizeof(grid_cost *)*height);
if (!gc[i]) return -1;
for (j=0;j<height;j++) {
ge[i][j]=(grid_element *) calloc(sizeof(grid_element)*(width),1);
if (!ge[i][j]) return -1;
gpv[i][j]=(grid_prev_visited *)
calloc(sizeof(grid_prev_visited)*(width+1)/2,1);
if (!gpv[i][j]) return -1;
gc[i][j]=(grid_cost *)
calloc(sizeof(grid_cost)*(width+1)/2,1);
if (!gc[i][j]) return -1;
}
}
cell c;
for (i=0;i<vp.size();i++) {
c.x=vp[i].x;
c.y=vp[i].y-1;
c.l=0;
addCellToPath(c,-1);
c.l=1;
addCellToPath(c,-1);
c.y++;
addCellToPath(c,-1);
c.l=0;
addCellToPath(c,-1);
c.y++;
addCellToPath(c,-1);
c.l=1;
addCellToPath(c,-1);
}
net_costs.resize(max_net+1);
for (i=0;i<=max_net;i++) net_costs[i]=0;
return 0;
}
int grid::clearVisitedAndPrev()
{
unsigned int x,y,l;
for (l=0;l<4;l++) {
for (y=0;y<height;y++) {
memset(gpv[l][y],0,sizeof(grid_prev_visited)*(width+1)/2);
}
}
return 0;
}
/*
void grid::setVisited(cell c)
{
if (c.x&0x01) {
gpv[c.l][c.y][c.x/2].stuff|=0x08;
} else {
gpv[c.l][c.y][c.x/2].stuff|=0x80;
}
}
*/
int grid::cellCostAccurate(cell c)
{
routed_net *rn;
int cost=0;
for (rn=ge[c.l][c.y][c.x].rn;rn;rn=rn->next) {
if (rn->net_id==-1) return 1<<30;
cost+=net_costs[rn->net_id];
}
return cost;
}
/*
int grid::setPrev(cell c, cell nc, int dir)
{
if (c.x&0x01) {
gpv[c.l][c.y][c.x/2].stuff&=0xF8;
gpv[c.l][c.y][c.x/2].stuff|=dir;
} else {
gpv[c.l][c.y][c.x/2].stuff&=0x8F;
gpv[c.l][c.y][c.x/2].stuff|=(dir<<4);
}
return 0;
}
*/
cell grid::getPrev(cell c)
{
cell ret;
int dir;
if (c.x&0x01) {
dir=gpv[c.l][c.y][c.x/2].stuff&0x07;
} else {
dir=(gpv[c.l][c.y][c.x/2].stuff&0x70)>>4;
}
if (dir==7) {
ret.x=-1;
ret.y=-1;
ret.l=0;
return ret;
}
// now we just need to work backwards from the direction
switch (dir) {
case 0:
dir=2;
break;
case 1:
dir=3;
break;
case 2:
dir=0;
break;
case 3:
dir=1;
break;
case 4:
dir=5;
break;
case 5:
dir=4;
break;
}
if (!getNeighbor(c,dir,ret)) {
fprintf(stderr,"getPrev failed bigtime!\n");
fprintf(stderr,"c=(%i,%i,%i) dir=%i\n",
c.x,c.y,c.l,dir);
exit(1);
}
return ret;
}
void grid::resetCost(cell c)
{
int t=cellCostAccurate(c);
if (t<(1<<30)) {
t=min((int)((float)t/cost_quantizer),14);
} else t=15;
if (c.x&0x01) {
gc[c.l][c.y][c.x/2].cost&=0xF0;
gc[c.l][c.y][c.x/2].cost|=t;
} else {
gc[c.l][c.y][c.x/2].cost&=0x0F;
gc[c.l][c.y][c.x/2].cost|=(t<<4);
}
}
void grid::addCellToPath(cell &c, int net)
{
routed_net *rn;
// first check to see if this net is already here
for (rn=ge[c.l][c.y][c.x].rn;rn && rn->net_id!=net;rn=rn->next);
if (rn) return; // this net already exists
rn=new routed_net;
if (!rn) {
fprintf(stderr,"addNetToPath: Out of Memory!\n");
exit(1);
}
rn->net_id=net;
rn->next=ge[c.l][c.y][c.x].rn;
ge[c.l][c.y][c.x].rn=rn;
resetCost(c);
}
int grid::addNetToPath(list<cell> &lc, int net)
{
list<cell>::iterator lci;
for (lci=lc.begin();lci!=lc.end();++lci) {
addCellToPath(*lci,net);
}
return 0;
}
int grid::removeNetFromPath(list<cell> &lc, int net)
{
list<cell>::iterator lci;
for (lci=lc.begin();lci!=lc.end();++lci) {
routed_net *rn,**parent;
parent=&ge[lci->l][lci->y][lci->x].rn;
for (rn=*parent;rn && rn->net_id!=net;parent=&rn->next,rn=rn->next);
if (!rn) {
//fprintf(stderr,"removeNetFromPath: net %i not found"
// "at cell (%i,%i,%i)\n", net,lci->x,lci->y,lci->l);
} else {
*parent=rn->next;
delete rn;
resetCost(*lci);
}
}
return 0;
}
int grid::countNets(cell c)
{
int count=0;
routed_net *rn;
for (rn=ge[c.l][c.y][c.x].rn;rn;rn=rn->next,count++) if (rn->net_id==-1) count--;
return count;
}
int grid::isPin(cell c)
{
routed_net *rn;
for (rn=ge[c.l][c.y][c.x].rn;rn;rn=rn->next) if (rn->net_id==-1) return 1;
return 0;
}
/*
int grid::cellCost(cell c)
{
int l;
if (c.x&0x1) {
l=gc[c.l][c.y][c.x/2].cost&0x0f;
} else {
l=(gc[c.l][c.y][c.x/2].cost&0xf0)>>4;
}
return quantized_costs[l];
}
*/
// take the costs in the net_costs vector, and finds a good set of
// 16 different costs to use with them, then insert those into the
// quantize_costs array, go through every cell, and see what cost
// should be used for it
int grid::quantizeCosts()
{
// to find a good set of quantized costs, lets look through
// all the cells quick like and find the max cost, then we
// will just make even divisions around it
int t;
cell c;
int max_cost=0;
for (c.l=0;c.l<4;c.l++) {
for (c.y=0;c.y<height;c.y++) {
for (c.x=0;c.x<width;c.x++) {
t=cellCostAccurate(c);
if (t<(1<<30) && t>max_cost) max_cost=t;
}
}
}
// now that we have the max_cost, divide it by 16 and set
// up the schedule
fprintf(stderr,"quantizeCosts max_cost=%i\n",max_cost);
if (max_cost<14) max_cost=14; // don't want a degenerate case
cost_quantizer=((float)max_cost/14.0);
for (t=0;t<15;t++) {
quantized_costs[t]=(int)(((float)t)*cost_quantizer);
//fprintf(stderr,"quantized_costs[%i]=%i\n",t,quantized_costs[t]);
}
quantized_costs[15]=1<<30;
// now we need to go through every cell, and assign a shortcut
// cost for it
for (c.l=0;c.l<4;c.l++) {
for (c.y=0;c.y<height;c.y++) {
for (c.x=0;c.x<width;c.x++) {
resetCost(c);
//if (t>0) fprintf(stdout,"(%i,%i,%i) cost(t)=%i"
// " stuff=%i\n",
// c.x,c.y,c.l,t,
// gc[c.l][c.y][c.x].cost);
}
}
}
return 0;
}