routing_matrix.cpp 14.7 KB
Newer Older
1 2 3
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
4 5 6 7 8
 * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
 * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
 *
 * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

28
/**
29 30
 * @file routing_matrix.cpp
 * @brief Functions to create autorouting maps
31
 */
32

33 34 35 36 37
#include <fctsys.h>
#include <common.h>

#include <pcbnew.h>
#include <cell.h>
38
#include <autorout.h>
39 40 41 42 43 44 45

#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_edge_mod.h>
#include <class_pcb_text.h>
46

dickelbeck's avatar
dickelbeck committed
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
{
    m_BoardSide[0]   = m_BoardSide[1] = NULL;
    m_DistSide[0]    = m_DistSide[1] = NULL;
    m_DirSide[0]     = m_DirSide[1] = NULL;
    m_InitMatrixDone = false;
    m_Nrows   = m_Ncols = 0;
    m_MemSize = 0;
    m_RoutingLayersCount = 1;
}


MATRIX_ROUTING_HEAD::~MATRIX_ROUTING_HEAD()
{
}


65
bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
66
{
67
    aPcb->ComputeBoundingBox( aUseBoardEdgesOnly );
dickelbeck's avatar
dickelbeck committed
68

Dick Hollenbeck's avatar
Dick Hollenbeck committed
69 70
    // The boundary box must have its start point on routing grid:
    m_BrdBox = aPcb->GetBoundingBox();
71

72 73
    m_BrdBox.SetX( m_BrdBox.GetX() - ( m_BrdBox.GetX() % m_GridRouting ) );
    m_BrdBox.SetY( m_BrdBox.GetY() - ( m_BrdBox.GetY() % m_GridRouting ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
74 75

    // The boundary box must have its end point on routing grid:
76
    wxPoint end = m_BrdBox.GetEnd();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
77

78 79
    end.x -= end.x % m_GridRouting;
    end.x += m_GridRouting;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
80

81 82
    end.y -= end.y % m_GridRouting;
    end.y += m_GridRouting;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
83

84
    m_BrdBox.SetEnd( end );
85

Dick Hollenbeck's avatar
Dick Hollenbeck committed
86 87
    aPcb->SetBoundingBox( m_BrdBox );

88 89
    m_Nrows = m_BrdBox.GetHeight() / m_GridRouting;
    m_Ncols = m_BrdBox.GetWidth() / m_GridRouting;
90

91 92 93
    // gives a small margin
    m_Ncols += 1;
    m_Nrows += 1;
dickelbeck's avatar
dickelbeck committed
94

95
    return true;
96 97 98
}


dickelbeck's avatar
dickelbeck committed
99

100
int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
101
{
102
    if( m_Nrows <= 0 || m_Ncols <= 0 )
dickelbeck's avatar
dickelbeck committed
103
        return 0;
104

105
    m_InitMatrixDone = true;     // we have been called
106

107
    // give a small margin for memory allocation:
108
    int ii = (RoutingMatrix.m_Nrows + 1) * (RoutingMatrix.m_Ncols + 1);
109

110 111
    int side = BOTTOM;
    for( int jj = 0; jj < m_RoutingLayersCount; jj++ )  // m_RoutingLayersCount = 1 or 2
dickelbeck's avatar
dickelbeck committed
112
    {
113 114 115
        m_BoardSide[side] = NULL;
        m_DistSide[side]  = NULL;
        m_DirSide[side]   = NULL;
116

Dick Hollenbeck's avatar
Dick Hollenbeck committed
117
        // allocate matrix & initialize everything to empty
118 119
        m_BoardSide[side] = (MATRIX_CELL*) operator new( ii * sizeof(MATRIX_CELL) );
        memset( m_BoardSide[side], 0, ii * sizeof(MATRIX_CELL) );
120

121
        if( m_BoardSide[side] == NULL )
dickelbeck's avatar
dickelbeck committed
122
            return -1;
123

124
        // allocate Distances
125 126
        m_DistSide[side] = (DIST_CELL*) operator new( ii * sizeof(DIST_CELL) );
        memset( m_DistSide[side], 0, ii * sizeof(DIST_CELL) );
127

128
        if( m_DistSide[side] == NULL )
dickelbeck's avatar
dickelbeck committed
129
            return -1;
130

131
        // allocate Dir (chars)
132 133
        m_DirSide[side] = (char*) operator new( ii );
        memset( m_DirSide[side], 0, ii );
134

135
        if( m_DirSide[side] == NULL )
dickelbeck's avatar
dickelbeck committed
136
            return -1;
137 138

        side = TOP;
dickelbeck's avatar
dickelbeck committed
139
    }
140

141 142
    m_MemSize = m_RouteCount * ii * ( sizeof(MATRIX_CELL)
                + sizeof(DIST_CELL) + sizeof(char) );
143

dickelbeck's avatar
dickelbeck committed
144
    return m_MemSize;
145 146
}

dickelbeck's avatar
dickelbeck committed
147

148
void MATRIX_ROUTING_HEAD::UnInitRoutingMatrix()
149
{
dickelbeck's avatar
dickelbeck committed
150 151
    int ii;

152
    m_InitMatrixDone = false;
dickelbeck's avatar
dickelbeck committed
153

154
    for( ii = 0; ii < MAX_ROUTING_LAYERS_COUNT; ii++ )
dickelbeck's avatar
dickelbeck committed
155
    {
156
        // de-allocate Dir matrix
dickelbeck's avatar
dickelbeck committed
157 158
        if( m_DirSide[ii] )
        {
159
            delete m_DirSide[ii];
160
            m_DirSide[ii] = NULL;
dickelbeck's avatar
dickelbeck committed
161 162
        }

163
        // de-allocate Distances matrix
dickelbeck's avatar
dickelbeck committed
164 165
        if( m_DistSide[ii] )
        {
166
            delete m_DistSide[ii];
167
            m_DistSide[ii] = NULL;
dickelbeck's avatar
dickelbeck committed
168 169
        }

170
        // de-allocate cells matrix
dickelbeck's avatar
dickelbeck committed
171 172
        if( m_BoardSide[ii] )
        {
173
            delete m_BoardSide[ii];
174
            m_BoardSide[ii] = NULL;
dickelbeck's avatar
dickelbeck committed
175 176 177 178
        }
    }

    m_Nrows = m_Ncols = 0;
179 180 181
}


182 183
/**
 * Function PlaceCells
184 185 186 187 188 189 190
 * Initialize the matrix routing by setting obstacles for each occupied cell
 * a cell set to HOLE is an obstacle for tracks and vias
 * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only.
 * a cell set to CELL_is_EDGE is a frontier.
 * Tracks and vias having the same net code as net_code are skipped
 * (htey do not are obstacles)
 *
stambaughw's avatar
stambaughw committed
191
 * For single-sided Routing 1:
192
 * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
193
 *
194
 * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
dickelbeck's avatar
dickelbeck committed
195
 */
stambaughw's avatar
stambaughw committed
196
void PlaceCells( BOARD* aPcb, int net_code, int flag )
197
{
Dick Hollenbeck's avatar
Dick Hollenbeck committed
198 199 200
    int     ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
    int     marge, via_marge;
    LSET    layerMask;
dickelbeck's avatar
dickelbeck committed
201

202
    // use the default NETCLASS?
203
    NETCLASSPTR nc = aPcb->GetDesignSettings().GetDefault();
204

Dick Hollenbeck's avatar
Dick Hollenbeck committed
205 206 207
    int     trackWidth = nc->GetTrackWidth();
    int     clearance  = nc->GetClearance();
    int     viaSize    = nc->GetViaDiameter();
208 209 210

    marge     = clearance + (trackWidth / 2);
    via_marge = clearance + (viaSize / 2);
dickelbeck's avatar
dickelbeck committed
211

212
    // Place PADS on matrix routing:
213
    for( unsigned i = 0; i < aPcb->GetPadCount(); ++i )
dickelbeck's avatar
dickelbeck committed
214
    {
215
        D_PAD* pad = aPcb->GetPad( i );
216

217
        if( net_code != pad->GetNetCode() || (flag & FORCE_PADS) )
dickelbeck's avatar
dickelbeck committed
218
        {
219
            ::PlacePad( pad, HOLE, marge, WRITE_CELL );
dickelbeck's avatar
dickelbeck committed
220
        }
221

222
        ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
dickelbeck's avatar
dickelbeck committed
223 224
    }

225 226
    // Place outlines of modules on matrix routing, if they are on a copper layer
    // or on the edge layer
227

228
    for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
dickelbeck's avatar
dickelbeck committed
229
    {
230
        for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() )
dickelbeck's avatar
dickelbeck committed
231
        {
232
            switch( item->Type() )
dickelbeck's avatar
dickelbeck committed
233
            {
234
            case PCB_MODULE_EDGE_T:
235 236
            {
                EDGE_MODULE* edge = (EDGE_MODULE*) item;
237
                EDGE_MODULE tmpEdge( *edge );
238

Dick Hollenbeck's avatar
Dick Hollenbeck committed
239
                if( tmpEdge.GetLayer() == Edge_Cuts )
240
                    tmpEdge.SetLayer( UNDEFINED_LAYER );
241

242 243
                TraceSegmentPcb( &tmpEdge, HOLE, marge, WRITE_CELL );
                TraceSegmentPcb( &tmpEdge, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
244 245
            }
            break;
dickelbeck's avatar
dickelbeck committed
246 247 248 249 250 251 252

            default:
                break;
            }
        }
    }

253
    // Place board outlines and texts on copper layers:
stambaughw's avatar
stambaughw committed
254
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
dickelbeck's avatar
dickelbeck committed
255
    {
256
        switch( item->Type() )
dickelbeck's avatar
dickelbeck committed
257
        {
258
        case PCB_LINE_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
259 260
            {
                DRAWSEGMENT* DrawSegm;
261

Dick Hollenbeck's avatar
Dick Hollenbeck committed
262 263 264
                int          type_cell = HOLE;
                DrawSegm = (DRAWSEGMENT*) item;
                DRAWSEGMENT tmpSegm( DrawSegm );
265

Dick Hollenbeck's avatar
Dick Hollenbeck committed
266 267 268 269 270
                if( DrawSegm->GetLayer() == Edge_Cuts )
                {
                    tmpSegm.SetLayer( UNDEFINED_LAYER );
                    type_cell |= CELL_is_EDGE;
                }
271

Dick Hollenbeck's avatar
Dick Hollenbeck committed
272 273 274
                TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
            }
            break;
dickelbeck's avatar
dickelbeck committed
275

276
        case PCB_TEXT_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
277 278
            {
                TEXTE_PCB* PtText = (TEXTE_PCB*) item;
279

Dick Hollenbeck's avatar
Dick Hollenbeck committed
280 281
                if( PtText->GetText().Length() == 0 )
                    break;
282

Dick Hollenbeck's avatar
Dick Hollenbeck committed
283 284 285 286 287
                EDA_RECT textbox = PtText->GetTextBox( -1 );
                ux0 = textbox.GetX();
                uy0 = textbox.GetY();
                dx  = textbox.GetWidth();
                dy  = textbox.GetHeight();
dickelbeck's avatar
dickelbeck committed
288

Dick Hollenbeck's avatar
Dick Hollenbeck committed
289 290 291
                // Put bounding box (rectangle) on matrix
                dx /= 2;
                dy /= 2;
292

Dick Hollenbeck's avatar
Dick Hollenbeck committed
293 294
                ux1 = ux0 + dx;
                uy1 = uy0 + dy;
295

Dick Hollenbeck's avatar
Dick Hollenbeck committed
296 297
                ux0 -= dx;
                uy0 -= dy;
dickelbeck's avatar
dickelbeck committed
298

Dick Hollenbeck's avatar
Dick Hollenbeck committed
299
                layerMask = LSET( PtText->GetLayer() );
dickelbeck's avatar
dickelbeck committed
300

Dick Hollenbeck's avatar
Dick Hollenbeck committed
301 302 303
                TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
                                      uy1 + marge, PtText->GetOrientation(),
                                      layerMask, HOLE, WRITE_CELL );
304

Dick Hollenbeck's avatar
Dick Hollenbeck committed
305 306 307 308 309 310
                TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
                                      ux1 + via_marge, uy1 + via_marge,
                                      PtText->GetOrientation(),
                                      layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
            }
            break;
dickelbeck's avatar
dickelbeck committed
311 312 313 314 315 316

        default:
            break;
        }
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
317
    // Put tracks and vias on matrix
318
    for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
dickelbeck's avatar
dickelbeck committed
319
    {
320
        if( net_code == track->GetNetCode() )
dickelbeck's avatar
dickelbeck committed
321
            continue;
322

323 324
        TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
        TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
dickelbeck's avatar
dickelbeck committed
325
    }
326 327
}

dickelbeck's avatar
dickelbeck committed
328

329
int Build_Work( BOARD* Pcb )
330
{
Dick Hollenbeck's avatar
Dick Hollenbeck committed
331 332 333 334
    RATSNEST_ITEM*  pt_rats;
    D_PAD*          pt_pad;
    int             r1, r2, c1, c2, current_net_code;
    RATSNEST_ITEM*  pt_ch;
335
    int             demi_pas = RoutingMatrix.m_GridRouting / 2;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
336 337
    wxString        msg;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
338
    InitWork(); // clear work list
339
    int cellCount = 0;
340

faa's avatar
faa committed
341
    for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
dickelbeck's avatar
dickelbeck committed
342
    {
343
        pt_rats = &Pcb->m_FullRatsnest[ii];
344

345
        /* We consider here only ratsnest that are active ( obviously not yet routed)
charras's avatar
charras committed
346 347
         * and routables (that are not yet attempt to be routed and fail
         */
348
        if( (pt_rats->m_Status & CH_ACTIF) == 0 )
dickelbeck's avatar
dickelbeck committed
349
            continue;
350

351
        if( pt_rats->m_Status & CH_UNROUTABLE )
dickelbeck's avatar
dickelbeck committed
352
            continue;
353

354
        if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
dickelbeck's avatar
dickelbeck committed
355
            continue;
356

357
        pt_pad = pt_rats->m_PadStart;
dickelbeck's avatar
dickelbeck committed
358

359
        current_net_code = pt_pad->GetNetCode();
dickelbeck's avatar
dickelbeck committed
360 361
        pt_ch = pt_rats;

362 363
        r1 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY() + demi_pas )
            / RoutingMatrix.m_GridRouting;
364

365
        if( r1 < 0 || r1 >= RoutingMatrix.m_Nrows )
dickelbeck's avatar
dickelbeck committed
366
        {
stambaughw's avatar
stambaughw committed
367
            msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
368
                        pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
369
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
370 371
            return 0;
        }
372

373
        c1 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas ) / RoutingMatrix.m_GridRouting;
374

375
        if( c1 < 0 || c1 >= RoutingMatrix.m_Ncols )
dickelbeck's avatar
dickelbeck committed
376
        {
stambaughw's avatar
stambaughw committed
377
            msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
378
                        pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
379
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
380 381 382
            return 0;
        }

383
        pt_pad = pt_rats->m_PadEnd;
dickelbeck's avatar
dickelbeck committed
384

385
        r2 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY()
386
               + demi_pas ) / RoutingMatrix.m_GridRouting;
387

388
        if( r2 < 0 || r2 >= RoutingMatrix.m_Nrows )
dickelbeck's avatar
dickelbeck committed
389
        {
stambaughw's avatar
stambaughw committed
390
            msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
391
                        pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
392
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
393 394
            return 0;
        }
395

396 397
        c2 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas )
             / RoutingMatrix.m_GridRouting;
398

399
        if( c2 < 0 || c2 >= RoutingMatrix.m_Ncols )
dickelbeck's avatar
dickelbeck committed
400
        {
stambaughw's avatar
stambaughw committed
401
            msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
402
                        pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
403
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
404 405 406
            return 0;
        }

faa's avatar
faa committed
407
        SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
408
        cellCount++;
dickelbeck's avatar
dickelbeck committed
409 410 411
    }

    SortWork();
412 413 414
    return cellCount;
}

415
// Initialize m_opWriteCell member to make the aLogicOp
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
void MATRIX_ROUTING_HEAD::SetCellOperation( int aLogicOp )
{
    switch( aLogicOp )
    {
    default:
    case WRITE_CELL:
        m_opWriteCell = &MATRIX_ROUTING_HEAD::SetCell;
        break;

    case WRITE_OR_CELL:
        m_opWriteCell = &MATRIX_ROUTING_HEAD::OrCell;
        break;

    case WRITE_XOR_CELL:
        m_opWriteCell = &MATRIX_ROUTING_HEAD::XorCell;
        break;

    case WRITE_AND_CELL:
        m_opWriteCell = &MATRIX_ROUTING_HEAD::AndCell;
        break;

    case WRITE_ADD_CELL:
        m_opWriteCell = &MATRIX_ROUTING_HEAD::AddCell;
        break;
    }
441 442 443
}


444
/* return the value stored in a cell
445
 */
446
MATRIX_CELL MATRIX_ROUTING_HEAD::GetCell( int aRow, int aCol, int aSide )
447
{
448
    MATRIX_CELL* p;
449

450
    p = RoutingMatrix.m_BoardSide[aSide];
451
    return p[aRow * m_Ncols + aCol];
452 453 454
}


455
/* basic cell operation : WRITE operation
456
 */
457
void MATRIX_ROUTING_HEAD::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
458
{
459
    MATRIX_CELL* p;
460

461
    p = RoutingMatrix.m_BoardSide[aSide];
462
    p[aRow * m_Ncols + aCol] = x;
463 464 465
}


466
/* basic cell operation : OR operation
467
 */
468
void MATRIX_ROUTING_HEAD::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
469
{
470
    MATRIX_CELL* p;
471

472
    p = RoutingMatrix.m_BoardSide[aSide];
473
    p[aRow * m_Ncols + aCol] |= x;
474 475 476
}


477
/* basic cell operation : XOR operation
478
 */
479
void MATRIX_ROUTING_HEAD::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
480
{
481
    MATRIX_CELL* p;
482

483
    p = RoutingMatrix.m_BoardSide[aSide];
484
    p[aRow * m_Ncols + aCol] ^= x;
485 486 487
}


488
/* basic cell operation : AND operation
489
 */
490
void MATRIX_ROUTING_HEAD::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
491
{
492
    MATRIX_CELL* p;
493

494
    p = RoutingMatrix.m_BoardSide[aSide];
495
    p[aRow * m_Ncols + aCol] &= x;
496 497 498
}


499
/* basic cell operation : ADD operation
500
 */
501
void MATRIX_ROUTING_HEAD::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
502
{
503
    MATRIX_CELL* p;
504

505
    p = RoutingMatrix.m_BoardSide[aSide];
506
    p[aRow * m_Ncols + aCol] += x;
507 508 509
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
510 511
// fetch distance cell
DIST_CELL MATRIX_ROUTING_HEAD::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
512
{
513
    DIST_CELL* p;
514

515
    p = RoutingMatrix.m_DistSide[aSide];
516
    return p[aRow * m_Ncols + aCol];
517 518 519
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
520
// store distance cell
521
void MATRIX_ROUTING_HEAD::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
522
{
523
    DIST_CELL* p;
524

525
    p = RoutingMatrix.m_DistSide[aSide];
526
    p[aRow * m_Ncols + aCol] = x;
527 528 529
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
530
// fetch direction cell
531
int MATRIX_ROUTING_HEAD::GetDir( int aRow, int aCol, int aSide )
532
{
533
    DIR_CELL* p;
534

535
    p = RoutingMatrix.m_DirSide[aSide];
536
    return (int) (p[aRow * m_Ncols + aCol]);
537 538 539
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
540
// store direction cell
541
void MATRIX_ROUTING_HEAD::SetDir( int aRow, int aCol, int aSide, int x )
542
{
543
    DIR_CELL* p;
544

545
    p = RoutingMatrix.m_DirSide[aSide];
546
    p[aRow * m_Ncols + aCol] = (char) x;
547
}