kicad/pcbnew/board.cpp

506 lines
13 KiB
C++
Raw Normal View History

/**
* @file board.cpp
* @brief Functions for autorouting
*/
#include "fctsys.h"
#include "common.h"
#include "pcbcommon.h"
#include "pcbnew.h"
#include "cell.h"
#include "ar_protos.h"
#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"
2007-08-21 14:34:54 +00:00
/*
* Calculates nrows and ncols, dimensions of the matrix representation of BOARD
* for routing and automatic calculation of area.
2007-08-21 14:34:54 +00:00
*/
bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb )
{
2011-03-09 14:30:39 +00:00
aPcb->ComputeBoundingBox();
2007-08-21 14:34:54 +00:00
/* The boundary box must have its start point on routing grid: */
aPcb->m_BoundaryBox.m_Pos.x -= aPcb->m_BoundaryBox.m_Pos.x % m_GridRouting;
aPcb->m_BoundaryBox.m_Pos.y -= aPcb->m_BoundaryBox.m_Pos.y % m_GridRouting;
m_BrdBox = aPcb->m_BoundaryBox;
2007-08-21 14:34:54 +00:00
/* The boundary box must have its end point on routing grid: */
wxPoint end = m_BrdBox.GetEnd();
end.x -= end.x % m_GridRouting;
end.x += m_GridRouting;
end.y -= end.y % m_GridRouting;
end.y += m_GridRouting;
2011-03-09 14:30:39 +00:00
aPcb->m_BoundaryBox.SetEnd( end );
m_BrdBox.SetEnd(end);
m_Nrows = Nrows = m_BrdBox.m_Size.y / m_GridRouting;
m_Ncols = Ncols = m_BrdBox.m_Size.x / m_GridRouting;
2011-03-09 14:30:39 +00:00
2007-08-21 14:34:54 +00:00
/* get a small margin for memory allocation: */
Ncols += 1; Nrows += 1;
2007-08-21 14:34:54 +00:00
2011-03-09 14:30:39 +00:00
return true;
}
2011-03-09 14:30:39 +00:00
/* class MATRIX_ROUTING_HEAD
*/
2011-03-09 14:30:39 +00:00
MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
{
2007-08-21 14:34:54 +00:00
m_BoardSide[0] = m_BoardSide[1] = NULL;
m_DistSide[0] = m_DistSide[1] = NULL;
m_DirSide[0] = m_DirSide[1] = NULL;
m_InitBoardDone = false;
2011-03-09 14:30:39 +00:00
m_Layers = MAX_SIDES_COUNT;
2007-08-21 14:34:54 +00:00
m_Nrows = m_Ncols = 0;
m_MemSize = 0;
}
2007-08-21 14:34:54 +00:00
2011-03-09 14:30:39 +00:00
MATRIX_ROUTING_HEAD::~MATRIX_ROUTING_HEAD()
{
}
2007-08-21 14:34:54 +00:00
/* initialize the data structures
* returns the RAM size used, or -1 if default
2007-08-21 14:34:54 +00:00
*/
2011-03-09 14:30:39 +00:00
int MATRIX_ROUTING_HEAD::InitBoard()
{
2007-08-21 14:34:54 +00:00
int ii, kk;
2007-08-21 14:34:54 +00:00
if( Nrows <= 0 || Ncols <= 0 )
return 0;
m_Nrows = Nrows;
m_Ncols = Ncols;
2011-03-09 14:30:39 +00:00
m_InitBoardDone = true; /* we have been called */
2007-08-21 14:34:54 +00:00
ii = (Nrows + 1) * (Ncols + 1);
2007-08-21 14:34:54 +00:00
for( kk = 0; kk < m_Layers; kk++ )
{
m_BoardSide[kk] = NULL;
m_DistSide[kk] = NULL;
m_DirSide[kk] = NULL;
2007-08-21 14:34:54 +00:00
/* allocate Board & initialize everything to empty */
2011-03-09 14:30:39 +00:00
m_BoardSide[kk] = (MATRIX_CELL*) MyZMalloc( ii * sizeof(MATRIX_CELL) );
2007-08-21 14:34:54 +00:00
if( m_BoardSide[kk] == NULL )
return -1;
2007-08-21 14:34:54 +00:00
/***** allocate Distances *****/
2011-03-09 14:30:39 +00:00
m_DistSide[kk] = (DIST_CELL*) MyZMalloc( ii * sizeof(DIST_CELL) );
2007-08-21 14:34:54 +00:00
if( m_DistSide[kk] == NULL )
return -1;
2007-08-21 14:34:54 +00:00
/***** allocate Dir (chars) *****/
m_DirSide[kk] = (char*) MyZMalloc( ii );
2007-08-21 14:34:54 +00:00
if( m_DirSide[kk] == NULL )
return -1;
}
2011-03-09 14:30:39 +00:00
m_MemSize = m_Layers * ii * ( sizeof(MATRIX_CELL) + sizeof(DIST_CELL) + sizeof(char) );
2007-08-21 14:34:54 +00:00
return m_MemSize;
}
2007-08-21 14:34:54 +00:00
2011-03-09 14:30:39 +00:00
void MATRIX_ROUTING_HEAD::UnInitBoard()
{
2007-08-21 14:34:54 +00:00
int ii;
m_InitBoardDone = false;
2007-08-21 14:34:54 +00:00
for( ii = 0; ii < MAX_SIDES_COUNT; ii++ )
2007-08-21 14:34:54 +00:00
{
/***** de-allocate Dir matrix *****/
2007-08-21 14:34:54 +00:00
if( m_DirSide[ii] )
{
MyFree( m_DirSide[ii] );
m_DirSide[ii] = NULL;
2007-08-21 14:34:54 +00:00
}
/***** de-allocate Distances matrix *****/
2007-08-21 14:34:54 +00:00
if( m_DistSide[ii] )
{
MyFree( m_DistSide[ii] );
m_DistSide[ii] = NULL;
2007-08-21 14:34:54 +00:00
}
/**** de-allocate cells matrix *****/
2007-08-21 14:34:54 +00:00
if( m_BoardSide[ii] )
{
MyFree( m_BoardSide[ii] );
m_BoardSide[ii] = NULL;
2007-08-21 14:34:54 +00:00
}
}
m_Nrows = m_Ncols = 0;
}
/* Initialize the cell board is set and VIA_IMPOSSIBLE HOLE according to
* the setbacks
* The elements of net_code = net_code will not be occupied as places
* but only VIA_IMPOSSIBLE
* For single-sided Routing 1:
* BOTTOM side is used and Route_Layer_BOTTOM = Route_Layer_TOP
*
* According to the bits = 1 parameter flag:
* If FORCE_PADS: all pads will be placed even those same net_code.
2007-08-21 14:34:54 +00:00
*/
void PlaceCells( BOARD* aPcb, int net_code, int flag )
{
int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
int marge, via_marge;
int layerMask;
2007-08-21 14:34:54 +00:00
2009-09-10 15:22:26 +00:00
// use the default NETCLASS?
NETCLASS* nc = aPcb->m_NetClasses.GetDefault();
2009-09-10 15:22:26 +00:00
int trackWidth = nc->GetTrackWidth();
int clearance = nc->GetClearance();
int viaSize = nc->GetViaDiameter();
2009-09-10 15:22:26 +00:00
marge = clearance + (trackWidth / 2);
via_marge = clearance + (viaSize / 2);
2007-08-21 14:34:54 +00:00
// Place PADS on matrix routing:
for( unsigned i = 0; i < aPcb->GetPadsCount(); ++i )
2007-08-21 14:34:54 +00:00
{
D_PAD* pad = aPcb->m_NetInfo->GetPad( i );
if( net_code != pad->GetNet() || (flag & FORCE_PADS) )
2007-08-21 14:34:54 +00:00
{
::PlacePad( aPcb, pad, HOLE, marge, WRITE_CELL );
2007-08-21 14:34:54 +00:00
}
::PlacePad( aPcb, pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
2007-08-21 14:34:54 +00:00
}
// 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.
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
2007-08-21 14:34:54 +00:00
{
for( BOARD_ITEM* item = module->m_Drawings; item; item = item->Next() )
2007-08-21 14:34:54 +00:00
{
switch( item->Type() )
2007-08-21 14:34:54 +00:00
{
case TYPE_EDGE_MODULE:
{
EDGE_MODULE* edge = (EDGE_MODULE*) item;
tmpSegm.SetLayer( edge->GetLayer() );
if( tmpSegm.GetLayer() == EDGE_N )
tmpSegm.SetLayer( -1 );
tmpSegm.m_Start = edge->m_Start;
tmpSegm.m_End = edge->m_End;
tmpSegm.m_Shape = edge->m_Shape;
tmpSegm.m_Width = edge->m_Width;
tmpSegm.m_Param = edge->m_Angle;
tmpSegm.SetNet( -1 );
TraceSegmentPcb( aPcb, &tmpSegm, HOLE, marge, WRITE_CELL );
TraceSegmentPcb( aPcb, &tmpSegm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
}
break;
2007-08-21 14:34:54 +00:00
default:
break;
}
}
}
// Place board outlines and texts on copper layers:
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
2007-08-21 14:34:54 +00:00
{
switch( item->Type() )
2007-08-21 14:34:54 +00:00
{
case TYPE_DRAWSEGMENT:
{
DRAWSEGMENT* DrawSegm;
int type_cell = HOLE;
DrawSegm = (DRAWSEGMENT*) item;
tmpSegm.SetLayer( DrawSegm->GetLayer() );
if( DrawSegm->GetLayer() == EDGE_N )
2007-08-21 14:34:54 +00:00
{
tmpSegm.SetLayer( -1 );
type_cell |= CELL_is_EDGE;
}
tmpSegm.m_Start = DrawSegm->m_Start;
tmpSegm.m_End = DrawSegm->m_End;
tmpSegm.m_Shape = DrawSegm->m_Shape;
tmpSegm.m_Width = DrawSegm->m_Width;
tmpSegm.m_Param = DrawSegm->m_Angle;
tmpSegm.SetNet( -1 );
TraceSegmentPcb( aPcb, &tmpSegm, type_cell, marge, WRITE_CELL );
}
break;
2007-08-21 14:34:54 +00:00
case TYPE_TEXTE:
2009-09-10 15:22:26 +00:00
{
TEXTE_PCB* PtText;
PtText = (TEXTE_PCB*) item;
2007-08-21 14:34:54 +00:00
if( PtText->GetLength() == 0 )
break;
2009-06-06 18:08:49 +00:00
EDA_RECT textbox = PtText->GetTextBox( -1 );
ux0 = textbox.GetX();
uy0 = textbox.GetY();
dx = textbox.GetWidth();
dy = textbox.GetHeight();
2007-08-21 14:34:54 +00:00
/* Put bounding box (rectangle) on matrix */
dx /= 2;
dy /= 2;
ux1 = ux0 + dx;
uy1 = uy0 + dy;
ux0 -= dx;
uy0 -= dy;
2007-08-21 14:34:54 +00:00
layerMask = g_TabOneLayerMask[PtText->GetLayer()];
2007-08-21 14:34:54 +00:00
TraceFilledRectangle( aPcb, ux0 - marge, uy0 - marge, ux1 + marge,
uy1 + marge, (int) (PtText->m_Orient),
layerMask, HOLE, WRITE_CELL );
TraceFilledRectangle( aPcb, ux0 - via_marge, uy0 - via_marge,
2007-08-21 14:34:54 +00:00
ux1 + via_marge, uy1 + via_marge,
(int) (PtText->m_Orient),
layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
2009-09-10 15:22:26 +00:00
}
break;
2007-08-21 14:34:54 +00:00
default:
break;
}
}
/* Put tracks and vias on matrix */
for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
2007-08-21 14:34:54 +00:00
{
if( net_code == track->GetNet() )
2007-08-21 14:34:54 +00:00
continue;
TraceSegmentPcb( aPcb, track, HOLE, marge, WRITE_CELL );
TraceSegmentPcb( aPcb, track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
2007-08-21 14:34:54 +00:00
}
}
2007-08-21 14:34:54 +00:00
int Build_Work( BOARD* Pcb )
{
RATSNEST_ITEM* pt_rats;
D_PAD* pt_pad;
int r1, r2, c1, c2, current_net_code;
RATSNEST_ITEM* pt_ch;
int demi_pas = Board.m_GridRouting / 2;
wxString msg;
2007-08-21 14:34:54 +00:00
InitWork(); /* clear work list */
Ntotal = 0;
2009-06-03 17:18:39 +00:00
for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
2007-08-21 14:34:54 +00:00
{
pt_rats = &Pcb->m_FullRatsnest[ii];
/* We consider her only ratsnest that are active ( obviously not yet routed)
2009-11-15 14:12:53 +00:00
* and routables (that are not yet attempt to be routed and fail
*/
if( (pt_rats->m_Status & CH_ACTIF) == 0 )
2007-08-21 14:34:54 +00:00
continue;
if( pt_rats->m_Status & CH_UNROUTABLE )
2007-08-21 14:34:54 +00:00
continue;
if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
2007-08-21 14:34:54 +00:00
continue;
pt_pad = pt_rats->m_PadStart;
2007-08-21 14:34:54 +00:00
2007-10-13 06:18:44 +00:00
current_net_code = pt_pad->GetNet();
2007-08-21 14:34:54 +00:00
pt_ch = pt_rats;
r1 = ( pt_pad->GetPosition().y - Pcb->m_BoundaryBox.m_Pos.y
+ demi_pas ) / Board.m_GridRouting;
2007-08-21 14:34:54 +00:00
if( r1 < 0 || r1 >= Nrows )
{
msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
2007-12-01 03:42:52 +00:00
pt_pad->GetPosition().y, Pcb->m_BoundaryBox.m_Pos.y );
2011-03-09 14:30:39 +00:00
wxMessageBox( msg );
2007-08-21 14:34:54 +00:00
return 0;
}
c1 = ( pt_pad->GetPosition().x - Pcb->m_BoundaryBox.m_Pos.x
+ demi_pas ) / Board.m_GridRouting;
2007-08-21 14:34:54 +00:00
if( c1 < 0 || c1 >= Ncols )
{
msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
2007-12-01 03:42:52 +00:00
pt_pad->GetPosition().x, Pcb->m_BoundaryBox.m_Pos.x );
2011-03-09 14:30:39 +00:00
wxMessageBox( msg );
2007-08-21 14:34:54 +00:00
return 0;
}
pt_pad = pt_rats->m_PadEnd;
2007-08-21 14:34:54 +00:00
r2 = ( pt_pad->GetPosition().y - Pcb->m_BoundaryBox.m_Pos.y
+ demi_pas ) / Board.m_GridRouting;
2007-08-21 14:34:54 +00:00
if( r2 < 0 || r2 >= Nrows )
{
msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
2007-12-01 03:42:52 +00:00
pt_pad->GetPosition().y, Pcb->m_BoundaryBox.m_Pos.y );
2011-03-09 14:30:39 +00:00
wxMessageBox( msg );
2007-08-21 14:34:54 +00:00
return 0;
}
c2 = ( pt_pad->GetPosition().x - Pcb->m_BoundaryBox.m_Pos.x
+ demi_pas ) / Board.m_GridRouting;
2007-08-21 14:34:54 +00:00
if( c2 < 0 || c2 >= Ncols )
{
msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
2007-12-01 03:42:52 +00:00
pt_pad->GetPosition().x, Pcb->m_BoundaryBox.m_Pos.x );
2011-03-09 14:30:39 +00:00
wxMessageBox( msg );
2007-08-21 14:34:54 +00:00
return 0;
}
2009-06-03 17:18:39 +00:00
SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
Ntotal++;
2007-08-21 14:34:54 +00:00
}
SortWork();
return Ntotal;
}
2011-03-09 14:30:39 +00:00
/* return the value stored in a cell
*/
2011-03-09 14:30:39 +00:00
MATRIX_CELL GetCell( int aRow, int aCol, int aSide )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
return p[aRow * Ncols + aCol];
}
2011-03-09 14:30:39 +00:00
/* basic cell operation : WRITE operation
*/
2011-03-09 14:30:39 +00:00
void SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
p[aRow * Ncols + aCol] = x;
}
2011-03-09 14:30:39 +00:00
/* basic cell operation : OR operation
*/
2011-03-09 14:30:39 +00:00
void OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
p[aRow * Ncols + aCol] |= x;
}
2011-03-09 14:30:39 +00:00
/* basic cell operation : XOR operation
*/
2011-03-09 14:30:39 +00:00
void XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
p[aRow * Ncols + aCol] ^= x;
}
2011-03-09 14:30:39 +00:00
/* basic cell operation : AND operation
*/
2011-03-09 14:30:39 +00:00
void AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
p[aRow * Ncols + aCol] &= x;
}
2011-03-09 14:30:39 +00:00
/* basic cell operation : ADD operation
*/
2011-03-09 14:30:39 +00:00
void AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
{
2011-03-09 14:30:39 +00:00
MATRIX_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_BoardSide[aSide];
p[aRow * Ncols + aCol] += x;
}
/* fetch distance cell */
2011-03-09 14:30:39 +00:00
DIST_CELL GetDist( int aRow, int aCol, int aSide ) /* fetch distance cell */
{
2011-03-09 14:30:39 +00:00
DIST_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_DistSide[aSide];
return p[aRow * Ncols + aCol];
}
/* store distance cell */
2011-03-09 14:30:39 +00:00
void SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
{
2011-03-09 14:30:39 +00:00
DIST_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_DistSide[aSide];
p[aRow * Ncols + aCol] = x;
}
/* fetch direction cell */
2011-03-09 14:30:39 +00:00
int GetDir( int aRow, int aCol, int aSide )
{
2011-03-09 14:30:39 +00:00
DIR_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_DirSide[aSide];
return (int) (p[aRow * Ncols + aCol]);
}
/* store direction cell */
2011-03-09 14:30:39 +00:00
void SetDir( int aRow, int aCol, int aSide, int x )
{
2011-03-09 14:30:39 +00:00
DIR_CELL* p;
2011-03-09 14:30:39 +00:00
p = Board.m_DirSide[aSide];
p[aRow * Ncols + aCol] = (char) x;
}