routing_matrix.cpp 15.3 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 38
#include <fctsys.h>
#include <common.h>
#include <pcbcommon.h>

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

#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>
47

dickelbeck's avatar
dickelbeck committed
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
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()
{
}


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

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

73 74
    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
75 76

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

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

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

85
    m_BrdBox.SetEnd( end );
86

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

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

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

96
    return true;
97 98 99
}


dickelbeck's avatar
dickelbeck committed
100

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

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

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

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

118
        /* allocate matrix & initialize everything to empty */
119 120
        m_BoardSide[side] = (MATRIX_CELL*) operator new( ii * sizeof(MATRIX_CELL) );
        memset( m_BoardSide[side], 0, ii * sizeof(MATRIX_CELL) );
121

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

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

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

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

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

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

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

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

dickelbeck's avatar
dickelbeck committed
148

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

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

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

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

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

    m_Nrows = m_Ncols = 0;
180 181 182
}


183 184
/**
 * Function PlaceCells
185 186 187 188 189 190 191
 * 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
192
 * For single-sided Routing 1:
193
 * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
194
 *
195
 * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
dickelbeck's avatar
dickelbeck committed
196
 */
stambaughw's avatar
stambaughw committed
197
void PlaceCells( BOARD* aPcb, int net_code, int flag )
198
{
199 200
    int       ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
    int       marge, via_marge;
201
    LAYER_MSK layerMask;
dickelbeck's avatar
dickelbeck committed
202

203
    // use the default NETCLASS?
204
    NETCLASS* nc = aPcb->m_NetClasses.GetDefault();
205

206 207 208
    int       trackWidth = nc->GetTrackWidth();
    int       clearance  = nc->GetClearance();
    int       viaSize    = nc->GetViaDiameter();
209 210 211

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

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

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

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

226 227 228
    // Place outlines of modules on matrix routing, if they are on a copper layer
    // or on the edge layer
    TRACK tmpSegm( NULL );  // A dummy track used to create segments.
229

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

                tmpSegm.SetLayer( edge->GetLayer() );
241

242
                if( tmpSegm.GetLayer() == EDGE_N )
243
                    tmpSegm.SetLayer( UNDEFINED_LAYER );
244

Dick Hollenbeck's avatar
Dick Hollenbeck committed
245 246 247 248 249
                tmpSegm.SetStart( edge->GetStart() );
                tmpSegm.SetEnd(   edge->GetEnd() );
                tmpSegm.SetShape( edge->GetShape() );
                tmpSegm.SetWidth( edge->GetWidth() );
                tmpSegm.m_Param = edge->GetAngle();
250 251
                tmpSegm.SetNet( -1 );

252 253
                TraceSegmentPcb( &tmpSegm, HOLE, marge, WRITE_CELL );
                TraceSegmentPcb( &tmpSegm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
254 255
            }
            break;
dickelbeck's avatar
dickelbeck committed
256 257 258 259 260 261 262

            default:
                break;
            }
        }
    }

263
    // Place board outlines and texts on copper layers:
stambaughw's avatar
stambaughw committed
264
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
dickelbeck's avatar
dickelbeck committed
265
    {
266
        switch( item->Type() )
dickelbeck's avatar
dickelbeck committed
267
        {
268
        case PCB_LINE_T:
269 270 271 272 273 274
        {
            DRAWSEGMENT* DrawSegm;

            int          type_cell = HOLE;
            DrawSegm = (DRAWSEGMENT*) item;
            tmpSegm.SetLayer( DrawSegm->GetLayer() );
275

276
            if( DrawSegm->GetLayer() == EDGE_N )
dickelbeck's avatar
dickelbeck committed
277
            {
278
                tmpSegm.SetLayer( UNDEFINED_LAYER );
279
                type_cell |= CELL_is_EDGE;
280
            }
281

Dick Hollenbeck's avatar
Dick Hollenbeck committed
282 283 284 285 286
            tmpSegm.SetStart( DrawSegm->GetStart() );
            tmpSegm.SetEnd(   DrawSegm->GetEnd() );
            tmpSegm.SetShape( DrawSegm->GetShape() );
            tmpSegm.SetWidth( DrawSegm->GetWidth() );
            tmpSegm.m_Param = DrawSegm->GetAngle();
287 288
            tmpSegm.SetNet( -1 );

289
            TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
290 291
        }
        break;
dickelbeck's avatar
dickelbeck committed
292

293
        case PCB_TEXT_T:
294
        {
295
            TEXTE_PCB* PtText;
296 297
            PtText = (TEXTE_PCB*) item;

298
            if( PtText->GetText().Length() == 0 )
dickelbeck's avatar
dickelbeck committed
299
                break;
300

301
            EDA_RECT textbox = PtText->GetTextBox( -1 );
302 303
            ux0 = textbox.GetX();
            uy0 = textbox.GetY();
304 305
            dx  = textbox.GetWidth();
            dy  = textbox.GetHeight();
dickelbeck's avatar
dickelbeck committed
306

307
            /* Put bounding box (rectangle) on matrix */
308
            dx /= 2;
stambaughw's avatar
stambaughw committed
309
            dy /= 2;
310 311 312 313 314 315

            ux1 = ux0 + dx;
            uy1 = uy0 + dy;

            ux0 -= dx;
            uy0 -= dy;
dickelbeck's avatar
dickelbeck committed
316

317
            layerMask = GetLayerMask( PtText->GetLayer() );
dickelbeck's avatar
dickelbeck committed
318

319
            TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
320
                                  uy1 + marge, PtText->GetOrientation(),
321
                                  layerMask, HOLE, WRITE_CELL );
322

323
            TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
dickelbeck's avatar
dickelbeck committed
324
                                  ux1 + via_marge, uy1 + via_marge,
325
                                  PtText->GetOrientation(),
326
                                  layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
327
        }
328
        break;
dickelbeck's avatar
dickelbeck committed
329 330 331 332 333 334

        default:
            break;
        }
    }

335
    /* Put tracks and vias on matrix */
336
    for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
dickelbeck's avatar
dickelbeck committed
337
    {
338
        if( net_code == track->GetNet() )
dickelbeck's avatar
dickelbeck committed
339
            continue;
340

341 342
        TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
        TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
dickelbeck's avatar
dickelbeck committed
343
    }
344 345
}

dickelbeck's avatar
dickelbeck committed
346

347
int Build_Work( BOARD* Pcb )
348
{
Dick Hollenbeck's avatar
Dick Hollenbeck committed
349 350 351 352
    RATSNEST_ITEM*  pt_rats;
    D_PAD*          pt_pad;
    int             r1, r2, c1, c2, current_net_code;
    RATSNEST_ITEM*  pt_ch;
353
    int             demi_pas = RoutingMatrix.m_GridRouting / 2;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
354 355
    wxString        msg;

dickelbeck's avatar
dickelbeck committed
356
    InitWork(); /* clear work list */
357
    int cellCount = 0;
358

faa's avatar
faa committed
359
    for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
dickelbeck's avatar
dickelbeck committed
360
    {
361
        pt_rats = &Pcb->m_FullRatsnest[ii];
362

363
        /* We consider here only ratsnest that are active ( obviously not yet routed)
charras's avatar
charras committed
364 365
         * and routables (that are not yet attempt to be routed and fail
         */
366
        if( (pt_rats->m_Status & CH_ACTIF) == 0 )
dickelbeck's avatar
dickelbeck committed
367
            continue;
368

369
        if( pt_rats->m_Status & CH_UNROUTABLE )
dickelbeck's avatar
dickelbeck committed
370
            continue;
371

372
        if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
dickelbeck's avatar
dickelbeck committed
373
            continue;
374

375
        pt_pad = pt_rats->m_PadStart;
dickelbeck's avatar
dickelbeck committed
376

377
        current_net_code = pt_pad->GetNet();
dickelbeck's avatar
dickelbeck committed
378 379
        pt_ch = pt_rats;

380 381
        r1 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY() + demi_pas )
            / RoutingMatrix.m_GridRouting;
382

383
        if( r1 < 0 || r1 >= RoutingMatrix.m_Nrows )
dickelbeck's avatar
dickelbeck committed
384
        {
stambaughw's avatar
stambaughw committed
385
            msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
386
                        pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
387
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
388 389
            return 0;
        }
390

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

393
        if( c1 < 0 || c1 >= RoutingMatrix.m_Ncols )
dickelbeck's avatar
dickelbeck committed
394
        {
stambaughw's avatar
stambaughw committed
395
            msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
396
                        pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
397
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
398 399 400
            return 0;
        }

401
        pt_pad = pt_rats->m_PadEnd;
dickelbeck's avatar
dickelbeck committed
402

403
        r2 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY()
404
               + demi_pas ) / RoutingMatrix.m_GridRouting;
405

406
        if( r2 < 0 || r2 >= RoutingMatrix.m_Nrows )
dickelbeck's avatar
dickelbeck committed
407
        {
stambaughw's avatar
stambaughw committed
408
            msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
409
                        pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
410
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
411 412
            return 0;
        }
413

414 415
        c2 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas )
             / RoutingMatrix.m_GridRouting;
416

417
        if( c2 < 0 || c2 >= RoutingMatrix.m_Ncols )
dickelbeck's avatar
dickelbeck committed
418
        {
stambaughw's avatar
stambaughw committed
419
            msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
420
                        pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
421
            wxMessageBox( msg );
dickelbeck's avatar
dickelbeck committed
422 423 424
            return 0;
        }

faa's avatar
faa committed
425
        SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
426
        cellCount++;
dickelbeck's avatar
dickelbeck committed
427 428 429
    }

    SortWork();
430 431 432
    return cellCount;
}

433
// Initialize m_opWriteCell member to make the aLogicOp
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
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;
    }
459 460 461
}


462
/* return the value stored in a cell
463
 */
464
MATRIX_CELL MATRIX_ROUTING_HEAD::GetCell( int aRow, int aCol, int aSide )
465
{
466
    MATRIX_CELL* p;
467

468
    p = RoutingMatrix.m_BoardSide[aSide];
469
    return p[aRow * m_Ncols + aCol];
470 471 472
}


473
/* basic cell operation : WRITE operation
474
 */
475
void MATRIX_ROUTING_HEAD::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
476
{
477
    MATRIX_CELL* p;
478

479
    p = RoutingMatrix.m_BoardSide[aSide];
480
    p[aRow * m_Ncols + aCol] = x;
481 482 483
}


484
/* basic cell operation : OR operation
485
 */
486
void MATRIX_ROUTING_HEAD::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
487
{
488
    MATRIX_CELL* p;
489

490
    p = RoutingMatrix.m_BoardSide[aSide];
491
    p[aRow * m_Ncols + aCol] |= x;
492 493 494
}


495
/* basic cell operation : XOR operation
496
 */
497
void MATRIX_ROUTING_HEAD::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
498
{
499
    MATRIX_CELL* p;
500

501
    p = RoutingMatrix.m_BoardSide[aSide];
502
    p[aRow * m_Ncols + aCol] ^= x;
503 504 505
}


506
/* basic cell operation : AND operation
507
 */
508
void MATRIX_ROUTING_HEAD::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
509
{
510
    MATRIX_CELL* p;
511

512
    p = RoutingMatrix.m_BoardSide[aSide];
513
    p[aRow * m_Ncols + aCol] &= x;
514 515 516
}


517
/* basic cell operation : ADD operation
518
 */
519
void MATRIX_ROUTING_HEAD::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
520
{
521
    MATRIX_CELL* p;
522

523
    p = RoutingMatrix.m_BoardSide[aSide];
524
    p[aRow * m_Ncols + aCol] += x;
525 526 527 528
}


/* fetch distance cell */
529
DIST_CELL MATRIX_ROUTING_HEAD::GetDist( int aRow, int aCol, int aSide ) /* fetch distance cell */
530
{
531
    DIST_CELL* p;
532

533
    p = RoutingMatrix.m_DistSide[aSide];
534
    return p[aRow * m_Ncols + aCol];
535 536 537 538
}


/* store distance cell */
539
void MATRIX_ROUTING_HEAD::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
540
{
541
    DIST_CELL* p;
542

543
    p = RoutingMatrix.m_DistSide[aSide];
544
    p[aRow * m_Ncols + aCol] = x;
545 546 547 548
}


/* fetch direction cell */
549
int MATRIX_ROUTING_HEAD::GetDir( int aRow, int aCol, int aSide )
550
{
551
    DIR_CELL* p;
552

553
    p = RoutingMatrix.m_DirSide[aSide];
554
    return (int) (p[aRow * m_Ncols + aCol]);
555 556 557 558
}


/* store direction cell */
559
void MATRIX_ROUTING_HEAD::SetDir( int aRow, int aCol, int aSide, int x )
560
{
561
    DIR_CELL* p;
562

563
    p = RoutingMatrix.m_DirSide[aSide];
564
    p[aRow * m_Ncols + aCol] = (char) x;
565
}