3
Copyright (C) 1998 Stefan Westerfeld
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
#include "autorouter.h"
27
#include <arts/debug.h>
29
#ifndef HAVE_LIBPTHREAD
30
#define pthread_create(a,b,c,d) ;
31
#define pthread_join(a,b) ;
32
#define pthread_mutex_lock(a) ;
33
#define pthread_mutex_unlock(a) ;
34
#define pthread_mutex_init(a,b) ;
35
#define pthread_attr_init(a) ;
40
void *startroute(void *where)
42
((AutoRouter *)where)->thread_command_loop();
43
// just to prevent the compiler warning
47
AutoRouter::AutoRouter(int width, int height)
50
const int PRSIZE = 16; // size of the pseudo random table
52
// field = new Field[width][height]; anybody knows how to do this correct?
54
field = (Field **)malloc(sizeof(Field *)*width);
55
completefield = (Field **)malloc(sizeof(Field *)*width);
59
field[i] = (Field *)malloc(sizeof(Field)*height);
60
completefield[i] = (Field *)calloc(1,sizeof(Field)*height);
63
for(i=0;i<255;i++) directionmask[i] = 0xffff;
65
directionmask['d'] = ~(left | right);
66
directionmask['u'] = ~(left | right);
67
directionmask['l'] = ~(up | down);
68
directionmask['r'] = ~(up | down);
70
ownerindex['d'] = OWNER_UD;
71
ownerindex['u'] = OWNER_UD;
72
ownerindex['l'] = OWNER_LR;
73
ownerindex['r'] = OWNER_LR;
75
prstart = (long *)malloc((PRSIZE + 1) * sizeof(long));
84
for (j=0;j<4;j++) remaining[j] = j+1;
94
} while(!remaining[rnd]);
96
*prp++ = remaining[rnd];
98
arts_debug("%d ",remaining[rnd]);
108
this->height = height;
110
thread_terminate_now = false; // not yet
115
#ifdef HAVE_LIBPTHREAD
116
pthread_attr_t attrs;
118
pthread_attr_init(&attrs);
119
pthread_mutex_init(&mutex_sync,0);
120
pthread_mutex_init(&mutex_queue,0);
122
pthread_create(&route_thread,&attrs,startroute,this);
125
arts_debug("AR UP...");
128
AutoRouter::~AutoRouter()
131
pthread_mutex_lock(&mutex_queue);
132
thread_terminate_now = true;
133
pthread_mutex_unlock(&mutex_queue);
134
pthread_join(route_thread,&rc);
135
arts_debug("AR DOWN...");
138
void AutoRouter::queue(ARCommand *command)
140
#ifdef HAVE_LIBPTHREAD
141
// threaded execution
142
pthread_mutex_lock(&mutex_queue);
143
if(command->isDestructive())
145
// ok, then we can kill the whole list, since this will clear
146
// the whole results anyway
148
while(command_queue.size() > 0)
150
delete *command_queue.begin();
151
command_queue.pop_front();
154
command_queue.push_back(command);
155
pthread_mutex_unlock(&mutex_queue);
157
// immediate execution
158
command->execute(this);
163
void AutoRouter::thread_command_loop()
171
pthread_mutex_lock(&mutex_queue);
172
if(command_queue.size() > 0)
174
command = (*command_queue.begin());
175
command_queue.pop_front();
179
if(thread_terminate_now) return;
181
pthread_mutex_unlock(&mutex_queue);
185
command->execute(this);
192
void AutoRouter::sync()
194
queue(new ARSyncCommand());
197
void ARSyncCommand::execute(AutoRouter *router)
199
router->thread_sync();
202
void AutoRouter::thread_sync()
205
pthread_mutex_lock(&mutex_sync);
206
for(i=0;i<width;i++) memcpy(completefield[i],field[i],sizeof(Field)*height);
208
pthread_mutex_unlock(&mutex_sync);
211
bool AutoRouter::needRedraw()
215
pthread_mutex_lock(&mutex_sync);
216
result = _needRedraw;
219
if(result) arts_debug("NEED REDRAW NOW!");
221
pthread_mutex_unlock(&mutex_sync);
226
void AutoRouter::clear()
228
queue(new ARClearCommand());
231
bool ARCommand::isDestructive()
236
bool ARClearCommand::isDestructive()
241
void ARClearCommand::execute(AutoRouter *router)
243
router->thread_clear();
246
void AutoRouter::thread_clear()
250
// if there is lots of movement on the screen this usleep will prevent
251
// lots of calculations to be done; normally you shouldn't need it as
252
// the calculations will take place in a seperate thread and don't
257
for (x=0;x<width;x++)
258
for (y=0;y<height;y++)
260
field[x][y].data = none;
261
field[x][y].penalty = 0;
262
field[x][y].owner[0] = -1;
263
field[x][y].owner[1] = -1;
269
long AutoRouter::get(int x,int y)
271
assert(x >= 0 && x < width);
272
assert(y >= 0 && y < height);
274
pthread_mutex_lock(&mutex_sync);
275
long result = completefield[x][y].data;
276
pthread_mutex_unlock(&mutex_sync);
280
void AutoRouter::getowners(int x, int y, long& ud_owner, long& lr_owner)
282
assert(x >= 0 && x < width);
283
assert(y >= 0 && y < height);
285
pthread_mutex_lock(&mutex_sync);
286
ud_owner = completefield[x][y].owner[OWNER_UD];
287
lr_owner = completefield[x][y].owner[OWNER_LR];
288
pthread_mutex_unlock(&mutex_sync);
291
void AutoRouter::set(int x1,int y1, int x2, int y2, long lt)
293
queue(new ARSetCommand(x1,y1,x2,y2,lt));
296
ARSetCommand::ARSetCommand(int x1,int y1, int x2, int y2, long lt)
298
_x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2; _lt = lt;
301
void ARSetCommand::execute(AutoRouter *router)
303
router->thread_set(_x1,_y1,_x2,_y2,_lt);
306
void AutoRouter::thread_set(int x1,int y1, int x2, int y2, long lt)
309
for(x=x1; x <= x2; x++)
311
for(y=y1; y <= y2; y++)
313
assert(x >= 0 && x < width);
314
assert(y >= 0 && y < height);
319
field[x][y-1].penalty += 5;
322
field[x][y-2].penalty += 2;
325
field[x][y+1].penalty += 5;
328
field[x][y+2].penalty += 2;
330
field[x][y].data = lt;
331
field[x][y].owner[0] = 0;
332
field[x][y].owner[1] = 0; // don't pass
338
// gms = global min score: score of the best connection that was achieved
339
// new routing steps are only tried if their score does not exceed gms
343
long AutoRouter::connect(int x1, int y1, int x2, int y2, long owner)
345
if(owner == 0) owner = newowner++;
347
queue(new ARConnectCommand(x1,y1,x2,y2,owner));
352
ARConnectCommand::ARConnectCommand(int x1, int y1, int x2, int y2, long owner)
354
_x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2; _owner = owner;
357
void ARConnectCommand::execute(AutoRouter *router)
359
router->thread_connect(_x1,_y1,_x2,_y2,_owner);
362
void AutoRouter::thread_connect(int x1, int y1, int x2, int y2, long owner)
365
long dat_source, dat_dest;
367
currentowner = owner;
369
// clear data(source) & data(dest) first and restore later, since they
373
arts_debug("-field[x1][y1].owner[0..1] = %ld,%ld",field[x1][y1].owner[0],
374
field[x1][y1].owner[1]);
375
arts_debug("-field[x2][y2].owner[0..1] = %ld,%ld",field[x2][y2].owner[0],
376
field[x2][y2].owner[1]);
378
dat_source = field[x1][y1].data; field[x1][y1].data = none;
379
dat_dest = field[x2][y2].data; field[x2][y2].data = none;
381
for (x=0;x<width;x++)
382
for (y=0;y<height;y++)
383
field[x][y].minscore = 20000;
386
arts_debug("autorouter: trying to connect %d,%d with %d,%d (owner %ld)",
397
q_try_connect(x1,y1,x2,y2,0,0,history);
401
list<tryinfo>::iterator ti,minti;
404
while(!trylist[activelist].size()) activelist++;
405
list<tryinfo>& activetrylist = trylist[activelist];
407
minti = activetrylist.begin();
408
ti = activetrylist.begin();
409
while(ti != activetrylist.end())
411
if((*ti).score < mintry)
413
mintry = (*ti).score;
419
try_connect((*minti).x1, (*minti).y1,
420
(*minti).x2, (*minti).y2, (*minti).score, (*minti).depth, (*minti).history);
421
activetrylist.erase(minti);
424
//arts_debug("gmsd= %d",gmsd);
426
field[x1][y1].data = dat_source;
427
field[x2][y2].data = dat_dest;
431
//arts_debug("minhistory for this connection is %s",minhistory.data());
432
//arts_debug("minscore for that was %d",gms);
434
char *walk = (char*)minhistory.ascii();
441
field[x][y].owner[ownerindex[*walk]] = currentowner;
444
case 'd': field[x][y++].data |= down;
445
field[x][y].data |= up;
447
case 'u': field[x][y--].data |= up;
448
field[x][y].data |= down;
450
case 'l': field[x--][y].data |= left;
451
field[x][y].data |= right;
453
case 'r': field[x++][y].data |= right;
454
field[x][y].data |= left;
457
field[x][y].owner[ownerindex[*walk]] = currentowner;
464
arts_debug("!! sorry, this connection is impossible !!");
469
void AutoRouter::q_try_connect(int x1, int y1, int x2, int y2, int score, int depth, QString history)
477
newtry.score = score;
478
newtry.depth = depth;
479
newtry.history = history;
481
int targetlist = newtry.score/5;
482
if(targetlist > 1023) targetlist = 1023;
484
trylist[targetlist].push_back(newtry);
488
void AutoRouter::try_connect(int x1, int y1, int x2, int y2, int score, int depth, QString history)
490
char *walk = (char*)history.ascii();
492
// check if we can go here:
494
if(x1 < 0 || x1 >= width) return;
495
if(y1 < 0 || y1 >= width) return;
499
if(field[x1][y1].data != 0) score += 100;
500
// going over a field where already connections are is bad...
502
if(directionmask[walk[depth-1]] & field[x1][y1].data)
504
// someone already uses that field... we can continue
505
// only if the connection has the same sourceport
507
long fieldowner = field[x1][y1].owner[ownerindex[walk[depth-1]]];
509
if(fieldowner != -1) // used?
511
if(fieldowner != currentowner) return;
513
// ... or a good idea, if the connections are from the
520
score += abs(x1-x2) + abs(y1-y2);
521
score += field[x1][y1].penalty;
524
if(walk[depth-2] != walk[depth-1]) score += 100;
526
if(field[x1][y1].minscore <= score) return;
527
if(score > gms) { gmsd++; return; }
529
field[x1][y1].minscore = score;
531
// check if we are where we wanted to be:
533
if(x1 == x2 && y1 == y2) {
538
// best solution until now
539
minhistory = history;
545
// search next place to go; take some pseudo random direction order
546
// this method improves search speed ;)
558
case 1: q_try_connect(x1-1,y1,x2,y2,score,depth,history+"l");
560
case 2: q_try_connect(x1+1,y1,x2,y2,score,depth,history+"r");
562
case 3: q_try_connect(x1,y1-1,x2,y2,score,depth,history+"u");
564
case 4: q_try_connect(x1,y1+1,x2,y2,score,depth,history+"d");