blob: 782eb1ddc053331d0fd1d9f2cc820117e429427d [file] [log] [blame] [edit]
//===========================================================================//
// Purpose : Method definitions for the TVPR_CircuitDesign_c class.
//
// Public methods include:
// - TVPR_CircuitDesign_c, ~TVPR_CircuitDesign_c
// - Export
// - Import
//
// Private methods include:
// - InitStructures_
// - PokeStructures_
// - PokeInputOutputList_
// - PokeInputOutput_
// - PokeLogicList_
// - PokeLogic_
// - PokeLatchList_
// - PokeLatch_
// - PokeSubcktList_
// - PokeSubckt_
// - PokeBlockList_
// - UpdateStructures_
// - UpdateLogicalBlocks_
// - UpdateVpackNets_
// - UpdateGlobalNets_
// - UpdateAbsorbLogic_
// - UpdateCompressLists_
// - UpdatePrimaryCounts_
// - LoadModelLibrary_
// - PeekInputOutputList_
// - PeekInputOutput_
// - PeekPhysicalBlockList_
// - PeekPhysicalBlock_
// - PeekPackHierMapList_
// - PeekNetList_
// - ValidateModelList_
// - ValidateSubcktList_
// - ValidateInstList_
// - AddVpackNet_
// - AddLogicalBlockInputOutput_
// - AddLogicalBlockLogic_
// - AddLogicalBlockLatch_
// - FreeVpackNet_
// - FreeLogicalBlock_
// - ExtractNetList_
// - ExtractNetListInstPins_
// - ExtractNetListRoutes_
// - ExtractNetRoutes_
// - IsNetOpen_
// - MakeTraceNodeCountList_
// - UpdateTraceSiblingCount_
// - LoadTraceRoutes_
// - LoadTraceNodes_
// - FindModel_
// - FindModelPort_
// - FindModelPortCount_
// - FindGraphPin_
// - FindTraceListLength_
// - FindTraceListNode_
// - FindSwitchBoxCoord_
// - FindSwitchBoxSides_
//
//===========================================================================//
//---------------------------------------------------------------------------//
// Copyright (C) 2012-2013 Jeff Rudolph, Texas Instruments (jrudolph@ti.com) //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"),//
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included //
// in all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN //
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, //
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR //
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE //
// USE OR OTHER DEALINGS IN THE SOFTWARE. //
//---------------------------------------------------------------------------//
#include <string>
using namespace std;
#include "TC_Typedefs.h"
#include "TC_StringUtils.h"
#include "TC_MemoryUtils.h"
#include "TGS_ArrayGrid.h"
#include "TGO_Region.h"
#include "TVPR_CircuitDesign.h"
//===========================================================================//
// Method : TVPR_CircuitDesign_c
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/10/12 jeffr : Original
//===========================================================================//
TVPR_CircuitDesign_c::TVPR_CircuitDesign_c(
void )
{
}
//===========================================================================//
// Method : ~TVPR_CircuitDesign_c
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/10/12 jeffr : Original
//===========================================================================//
TVPR_CircuitDesign_c::~TVPR_CircuitDesign_c(
void )
{
}
//===========================================================================//
// Method : Export
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
// 08/09/13 jeffr : Added support for new VPR global net list (g_atoms_nlist)
//===========================================================================//
bool TVPR_CircuitDesign_c::Export(
const TCD_CircuitDesign_c& circuitDesign,
const t_model* pvpr_standardModels,
const t_model* pvpr_customModels,
t_net** pvpr_netArray,
int* pvpr_netCount,
t_netlist* pvpr_netList,
t_logical_block** pvpr_logicalBlockArray,
int* pvpr_logicalBlockCount,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount,
bool deleteInvalidData ) const
{
bool ok = true;
blif_circuit_name = TC_strdup( circuitDesign.srName ); // VPR global trickery...
TPO_InstList_t instList = circuitDesign.instList;
const TPO_NameList_t& instNameList = circuitDesign.instNameList;
const TPO_PortList_t& portList = circuitDesign.portList;
const TPO_NameList_t& portNameList = circuitDesign.portNameList;
const TLO_CellList_t& cellList = circuitDesign.cellList;
const TPO_InstList_t& blockList = circuitDesign.blockList;
const TNO_NetList_c& netList = circuitDesign.netList;
const TNO_NameList_t netNameList = circuitDesign.netNameList;
if( ok )
{
ok = this->ValidateModelList_( cellList,
pvpr_customModels );
}
if( ok )
{
ok = this->ValidateSubcktList_( instList, cellList );
}
if( ok )
{
ok = this->ValidateInstList_( &instList, cellList,
deleteInvalidData );
}
if( ok )
{
this->InitStructures_( instList, portList,
netList, netNameList,
pvpr_netArray, pvpr_netCount,
pvpr_logicalBlockArray, pvpr_logicalBlockCount );
ok = this->PokeStructures_( instList, instNameList,
portList, portNameList,
blockList, netList,
pvpr_standardModels, pvpr_customModels,
*pvpr_netArray,
*pvpr_logicalBlockArray, *pvpr_logicalBlockCount,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
}
if( ok )
{
ok = this->UpdateStructures_( pvpr_netArray, pvpr_netCount,
pvpr_netList,
pvpr_logicalBlockArray, pvpr_logicalBlockCount,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
}
return( ok );
}
//===========================================================================//
// Method : Import
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
// 07/23/13 jeffr : Added support for optional "tiClayResyncNets" parameter
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
void TVPR_CircuitDesign_c::Import(
const t_arch* vpr_architecture,
const t_netlist& vpr_netList,
const t_block* vpr_blockArray,
int vpr_blockCount,
const t_logical_block* vpr_logicalBlockArray,
const t_rr_node* vpr_rrNodeArray,
TCD_CircuitDesign_c* pcircuitDesign,
bool tiClayResyncNets ) const
{
TPO_InstList_t blockList( pcircuitDesign->blockList );
TPO_InstList_t* pblockList = &pcircuitDesign->blockList;
TNO_NetList_c* pnetList = &pcircuitDesign->netList;
pblockList->Clear( );
this->PeekNetList_( vpr_architecture,
vpr_netList,
vpr_blockArray, vpr_blockCount,
vpr_logicalBlockArray,
vpr_rrNodeArray,
pnetList,
tiClayResyncNets );
this->PeekInputOutputList_( vpr_blockArray, vpr_blockCount,
blockList, pblockList );
this->PeekPhysicalBlockList_( vpr_blockArray, vpr_blockCount,
vpr_logicalBlockArray,
blockList, pblockList );
}
//===========================================================================//
// Method : InitStructures_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::InitStructures_(
const TPO_InstList_t& instList,
const TPO_PortList_t& portList,
const TNO_NetList_c& netList,
const TNO_NameList_t& netNameList,
t_net** pvpr_netArray,
int* pvpr_netCount,
t_logical_block** pvpr_logicalBlockArray,
int* pvpr_logicalBlockCount ) const
{
*pvpr_netCount = static_cast< int >( netNameList.GetLength( ));
*pvpr_logicalBlockCount = static_cast< int >( instList.GetLength( ) + portList.GetLength( ));
*pvpr_netArray = static_cast< t_net* >( TC_calloc( *pvpr_netCount, sizeof( t_net )));
t_net* vpr_netArray = *pvpr_netArray;
for( int netIndex = 0; netIndex < *pvpr_netCount; ++netIndex )
{
const char* pszNetName = netNameList[netIndex]->GetName( );
int netIndex_ = static_cast< int >( netList.FindIndex( pszNetName ));
int count = static_cast< int >( netList[netIndex_]->FindInstPinCount( ));
vpr_netArray[netIndex].num_sinks = 0;
vpr_netArray[netIndex].name = TC_strdup( pszNetName );
vpr_netArray[netIndex].node_block = static_cast< int* >( TC_calloc( count, sizeof( int )));
vpr_netArray[netIndex].node_block_port = static_cast< int* >( TC_calloc( count, sizeof( int )));
vpr_netArray[netIndex].node_block_pin = static_cast< int* >( TC_calloc( count, sizeof( int )));
vpr_netArray[netIndex].is_global = static_cast< boolean >( false );
}
*pvpr_logicalBlockArray = static_cast< t_logical_block* >( TC_calloc( *pvpr_logicalBlockCount, sizeof( t_logical_block )));
t_logical_block* vpr_logicalBlockArray = *pvpr_logicalBlockArray;
for( int blockIndex = 0; blockIndex < *pvpr_logicalBlockCount; ++blockIndex )
{
vpr_logicalBlockArray[blockIndex].index = blockIndex;
}
}
//===========================================================================//
// Method : PokeStructures_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::PokeStructures_(
const TPO_InstList_t& instList,
const TPO_NameList_t& instNameList,
const TPO_PortList_t& portList,
const TPO_NameList_t& portNameList,
const TPO_InstList_t& blockList,
const TNO_NetList_c& netList,
const t_model* pvpr_standardModels,
const t_model* pvpr_customModels,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
bool ok = true;
// [VPR] Load default library models (inpad, outpad, logic, & latch)
t_model* pvpr_inputModel;
t_model* pvpr_outputModel;
t_model* pvpr_logicModel;
t_model* pvpr_latchModel;
ok = this->LoadModelLibrary_( pvpr_standardModels,
&pvpr_inputModel, &pvpr_outputModel,
&pvpr_logicModel, &pvpr_latchModel );
if( ok )
{
int vpr_blockIndex = 0;
// [VPR] First, write ".inputs" and ".outputs" data
this->PokeInputOutputList_( portList, portNameList, netList,
pvpr_inputModel, pvpr_outputModel,
vpr_netArray,
vpr_logicalBlockArray, &vpr_blockIndex,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
// [VPR] Then, write ".latch" flipflop data
this->PokeLatchList_( instList, instNameList, netList,
pvpr_latchModel,
vpr_netArray,
vpr_logicalBlockArray,
&vpr_blockIndex );
// [VPR] Next, write ".names" LUT data
this->PokeLogicList_( instList, instNameList, netList,
pvpr_logicModel,
vpr_netArray,
vpr_logicalBlockArray,
&vpr_blockIndex );
// [VPR] Next, write ".subckt" data, if any
this->PokeSubcktList_( instList, instNameList, netList,
pvpr_customModels,
vpr_netArray,
vpr_logicalBlockArray,
&vpr_blockIndex );
// Lastly, update VPR's block array based on optional placement regions
this->PokeBlockList_( blockList,
vpr_logicalBlockArray,
vpr_logicalBlockCount );
}
return( ok );
}
//===========================================================================//
// Method : PokeInputOutputList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeInputOutputList_(
const TPO_PortList_t& portList,
const TPO_NameList_t& portNameList,
const TNO_NetList_c& netList,
const t_model* pvpr_inputModel,
const t_model* pvpr_outputModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
for( size_t i = 0; i < portNameList.GetLength( ); ++i )
{
const TC_Name_c& portName = *portNameList[i];
const char* pszPortName = portName.GetName( );
const TPO_Port_t& port = *portList.Find( pszPortName );
this->PokeInputOutput_( port, netList,
pvpr_inputModel, pvpr_outputModel,
vpr_netArray,
vpr_logicalBlockArray, pvpr_blockIndex,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
}
}
//===========================================================================//
// Method : PokeInputOutput_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeInputOutput_(
const TPO_Port_t& port,
const TNO_NetList_c& netList,
const t_model* pvpr_inputModel,
const t_model* pvpr_outputModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
const char* pszPortName = port.GetName( );
int pinType = ( port.GetInputOutputType( ) == TC_TYPE_OUTPUT ? DRIVER : RECEIVER );
bool isGlobal = false;
int blockIndex = *pvpr_blockIndex;
int portIndex = 0;
int pinIndex = 0;
int netIndex = this->AddVpackNet_( pszPortName, pinType, isGlobal,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
this->AddLogicalBlockInputOutput_( pszPortName, pinType, netIndex,
pvpr_inputModel, pvpr_outputModel,
vpr_logicalBlockArray, blockIndex,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
++*pvpr_blockIndex;
}
//===========================================================================//
// Method : PokeLogicList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeLogicList_(
const TPO_InstList_t& instList,
const TPO_NameList_t& instNameList,
const TNO_NetList_c& netList,
const t_model* pvpr_logicModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
for( size_t i = 0; i < instNameList.GetLength( ); ++i )
{
const TC_Name_c& instName = *instNameList[i];
const char* pszInstName = instName.GetName( );
const TPO_Inst_c& inst = *instList.Find( pszInstName );
if( inst.GetSource( ) != TPO_INST_SOURCE_NAMES )
continue;
const TPO_Pin_t* poutputPin = inst.FindPin( TC_TYPE_OUTPUT );
if( poutputPin &&
strcmp( poutputPin->GetName( ), "unconn" ) == 0 )
{
continue;
}
this->PokeLogic_( inst, netList,
pvpr_logicModel, vpr_netArray,
vpr_logicalBlockArray, pvpr_blockIndex );
}
}
//===========================================================================//
// Method : PokeLogic_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeLogic_(
const TPO_Inst_c& inst,
const TNO_NetList_c& netList,
const t_model* pvpr_logicModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
// [VPR] Add a LUT (.names) as VPACK_COMB to vpack_net and logical_block array
int inputPinIndex = 0;
const TPO_PinList_t& pinList = inst.GetPinList( );
for( size_t i = 0; i < pinList.GetLength( ); ++i )
{
const TPO_Pin_t& pin = *pinList[i];
const char* pszPinName = pin.GetName( );
int pinType = ( pin.GetType( ) == TC_TYPE_OUTPUT ? DRIVER : RECEIVER );
bool isGlobal = false;
int blockIndex = *pvpr_blockIndex;
int portIndex = 0;
int pinIndex = 0;
if( pin.GetType( ) == TC_TYPE_INPUT )
{
pinIndex = inputPinIndex;
++inputPinIndex;
}
this->AddVpackNet_( pszPinName, pinType, isGlobal,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
}
const TPO_Pin_t* poutputPin = inst.FindPin( TC_TYPE_OUTPUT );
this->AddLogicalBlockLogic_( poutputPin->GetName( ), pinList,
netList, pvpr_logicModel,
vpr_logicalBlockArray, *pvpr_blockIndex );
const TPO_LogicBitsList_t& logicBitsList = inst.GetNamesLogicBitsList( );
for( size_t i = 0; i < logicBitsList.GetLength( ); ++i )
{
const TPO_LogicBits_t& logicBits = *logicBitsList[i];
string srLogicBits;
for( size_t j = 0; j < logicBits.GetLength( ); ++j )
{
string srLogicBit;
logicBits[j]->ExtractString( &srLogicBit );
srLogicBits += srLogicBit;
srLogicBits += ( j + 2 == logicBits.GetLength( ) ? " " : "" );
}
t_linked_vptr* ptruth_table = static_cast< t_linked_vptr* >( TC_calloc( 1, sizeof( t_linked_vptr )));
ptruth_table->next = vpr_logicalBlockArray[*pvpr_blockIndex].truth_table;
ptruth_table->data_vptr = TC_strdup( srLogicBits );
vpr_logicalBlockArray[*pvpr_blockIndex].truth_table = ptruth_table;
}
++*pvpr_blockIndex;
}
//===========================================================================//
// Method : PokeLatchList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeLatchList_(
const TPO_InstList_t& instList,
const TPO_NameList_t& instNameList,
const TNO_NetList_c& netList,
const t_model* pvpr_latchModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
for( size_t i = 0; i < instNameList.GetLength( ); ++i )
{
const TC_Name_c& instName = *instNameList[i];
const char* pszInstName = instName.GetName( );
const TPO_Inst_c& inst = *instList.Find( pszInstName );
if( inst.GetSource( ) != TPO_INST_SOURCE_LATCH )
continue;
this->PokeLatch_( inst, netList,
pvpr_latchModel, vpr_netArray,
vpr_logicalBlockArray, pvpr_blockIndex );
}
}
//===========================================================================//
// Method : PokeLatch_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeLatch_(
const TPO_Inst_c& inst,
const TNO_NetList_c& netList,
const t_model* pvpr_latchModel,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
const TPO_Pin_t* poutputPin = inst.FindPin( TC_TYPE_OUTPUT );
const TPO_Pin_t* pinputPin = inst.FindPin( TC_TYPE_INPUT );
const TPO_Pin_t* pclockPin = inst.FindPin( TC_TYPE_CLOCK );
if( pinputPin && poutputPin && pclockPin )
{
// [VPR] Add a flipflop (.latch) as VPACK_LATCH to the logical_block array
int blockIndex = *pvpr_blockIndex;
int portIndex = 0;
int pinIndex = 0;
this->AddVpackNet_( poutputPin->GetName( ), DRIVER, false,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
this->AddVpackNet_( pinputPin->GetName( ), RECEIVER, false,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
this->AddVpackNet_( pclockPin->GetName( ), RECEIVER, true,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
this->AddLogicalBlockLatch_( poutputPin->GetName( ),
pinputPin->GetName( ),
pclockPin->GetName( ),
netList, pvpr_latchModel,
vpr_logicalBlockArray, *pvpr_blockIndex );
++*pvpr_blockIndex;
}
}
//===========================================================================//
// Method : PokeSubcktList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeSubcktList_(
const TPO_InstList_t& instList,
const TPO_NameList_t& instNameList,
const TNO_NetList_c& netList,
const t_model* pvpr_customModels,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
for( size_t i = 0; i < instNameList.GetLength( ); ++i )
{
const TC_Name_c& instName = *instNameList[i];
const char* pszInstName = instName.GetName( );
const TPO_Inst_c& inst = *instList.Find( pszInstName );
if( inst.GetSource( ) != TPO_INST_SOURCE_SUBCKT )
continue;
this->PokeSubckt_( inst, netList,
pvpr_customModels, vpr_netArray,
vpr_logicalBlockArray, pvpr_blockIndex );
}
}
//===========================================================================//
// Method : PokeSubckt_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeSubckt_(
const TPO_Inst_c& inst,
const TNO_NetList_c& netList,
const t_model* pvpr_customModels,
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int* pvpr_blockIndex ) const
{
int blockIndex = *pvpr_blockIndex;
vpr_logicalBlockArray[blockIndex].type = VPACK_COMB;
// [VPR] Get and recode library model matching this subckt cell name
const char* pszCellName = inst.GetCellName( );
const t_model* pvpr_model = this->FindModel_( pvpr_customModels, pszCellName );
vpr_logicalBlockArray[blockIndex].model = const_cast< t_model* >( pvpr_model );
// [VPR] Allocate space for inputs and initialize all input nets to OPEN
int inputPortCount = this->FindModelPortCount_( pvpr_model, TC_TYPE_INPUT );
vpr_logicalBlockArray[blockIndex].input_nets = static_cast< int** >( TC_calloc( inputPortCount, sizeof( int* )));
for( const t_model_ports* pvpr_port = pvpr_model->inputs; pvpr_port; pvpr_port = pvpr_port->next )
{
if( pvpr_port->is_clock )
continue;
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
vpr_logicalBlockArray[blockIndex].input_nets[portIndex] = static_cast< int* >( TC_calloc( pinCount, sizeof( int )));
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex] = OPEN;
}
}
// [VPR] Allocate space for outputs and initialize all input nets to OPEN
int outputPortCount = this->FindModelPortCount_( pvpr_model, TC_TYPE_OUTPUT );
vpr_logicalBlockArray[blockIndex].output_nets = static_cast< int** >( TC_calloc( outputPortCount, sizeof( int* )));
for( const t_model_ports* pvpr_port = pvpr_model->outputs; pvpr_port; pvpr_port = pvpr_port->next )
{
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
vpr_logicalBlockArray[blockIndex].output_nets[portIndex] = static_cast< int* >( TC_calloc( pinCount, sizeof( int )));
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex] = OPEN;
}
}
// [VPR] Initialize clock data
vpr_logicalBlockArray[blockIndex].clock_net = OPEN;
vpr_logicalBlockArray[blockIndex].truth_table = 0;
// [VPR] Write output/input/clock based on pin-to-pin mappings
const TPO_PinMapList_t& pinMapList = inst.GetSubcktPinMapList( );
for( size_t i = 0; i < pinMapList.GetLength( ); ++i )
{
const TPO_PinMap_c& pinMap = *pinMapList[i];
const char* pszCellPinName = pinMap.GetCellPinName( );
const char* pszInstPinName = pinMap.GetInstPinName( );
size_t index;
TC_ParseStringNameIndex( pszCellPinName, 0, &index );
int cellPinIndex = static_cast< int >( index );
const t_model_ports* pvpr_port = 0;
pvpr_port = this->FindModelPort_( pvpr_model, pszCellPinName, TC_TYPE_OUTPUT );
if( pvpr_port )
{
int portIndex = pvpr_port->index;
int pinIndex = cellPinIndex;
int netIndex = this->AddVpackNet_( pszInstPinName, DRIVER, false,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex] = netIndex;
// [VPR] Record subckt block name based on first output pin processed
if( !vpr_logicalBlockArray[blockIndex].name )
{
vpr_logicalBlockArray[blockIndex].name = TC_strdup( pszInstPinName );
}
}
pvpr_port = this->FindModelPort_( pvpr_model, pszCellPinName, TC_TYPE_INPUT );
if( pvpr_port )
{
int portIndex = pvpr_port->index;
int pinIndex = cellPinIndex;
int netIndex = this->AddVpackNet_( pszInstPinName, RECEIVER, false,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex] = netIndex;
}
pvpr_port = this->FindModelPort_( pvpr_model, pszCellPinName, TC_TYPE_CLOCK );
if( pvpr_port )
{
int portIndex = pvpr_port->index;
int pinIndex = cellPinIndex;
int netIndex = this->AddVpackNet_( pszInstPinName, RECEIVER, true,
blockIndex, portIndex, pinIndex,
netList, vpr_netArray );
vpr_logicalBlockArray[blockIndex].clock_net = netIndex;
}
}
++*pvpr_blockIndex;
}
//===========================================================================//
// Method : PokeBlockList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PokeBlockList_(
const TPO_InstList_t& blockList,
t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount ) const
{
if( blockList.IsValid( ))
{
// Iterate for every logical block to update optional placement regions
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
const char* pszBlockName = vpr_logicalBlockArray[blockIndex].name;
const TPO_Inst_c* pblock = blockList.Find( pszBlockName );
if( !pblock )
continue;
const TGS_RegionList_t& placeRegionList = pblock->GetPlaceRegionList( );
for( size_t i = 0; i < placeRegionList.GetLength( ); ++i )
{
// For each optional placement region, snap to VPR's placement array grid
TGS_Region_c placeRegion = *placeRegionList[i];
TGS_ArrayGrid_c placeArrayGrid( 1.0, 1.0 );
placeArrayGrid.SnapToGrid( placeRegion, &placeRegion );
TGO_Region_c placementRegion( static_cast< int >( placeRegion.x1 ),
static_cast< int >( placeRegion.y1 ),
static_cast< int >( placeRegion.x2 ),
static_cast< int >( placeRegion.y2 ));
// Add optional placement region to VPR's logical block
// (so that VPR will subsequently write region to VPR's .net file)
// (so that VPR will subsequently read region into VPR's block array)
vpr_logicalBlockArray[blockIndex].placement_region_list.Add( placementRegion );
}
}
}
}
//===========================================================================//
// Method : UpdateStructures_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
// 08/09/13 jeffr : Added support for new VPR global net list (g_atoms_nlist)
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
bool TVPR_CircuitDesign_c::UpdateStructures_(
t_net** pvpr_netArray,
int* pvpr_netCount,
t_netlist* pvpr_netList,
t_logical_block** pvpr_logicalBlockArray,
int* pvpr_logicalBlockCount,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
bool ok = true;
// Apply post-processing on the logical block and vpack net lists
this->UpdateLogicalBlocks_( *pvpr_logicalBlockArray, *pvpr_logicalBlockCount );
ok = this->UpdateVpackNets_( *pvpr_netArray,
*pvpr_logicalBlockArray, *pvpr_logicalBlockCount );
// [VPR] Remove buffer LUTs (ie. single-input LUTs that are programmed to be a wire)
if( ok )
{
ok = this->UpdateAbsorbLogic_( *pvpr_netArray,
*pvpr_logicalBlockArray, *pvpr_logicalBlockCount );
}
// [VPR] Remove VPACK_EMPTY blocks and OPEN nets left post synthesis
if( ok )
{
ok = this->UpdateCompressLists_( pvpr_netArray, pvpr_netCount,
pvpr_logicalBlockArray, pvpr_logicalBlockCount );
}
if( ok )
{
this->UpdateGlobalNets_( *pvpr_netArray, *pvpr_netCount,
pvpr_netList );
}
if( ok )
{
this->UpdatePrimaryCounts_( *pvpr_logicalBlockArray, *pvpr_logicalBlockCount,
pvpr_primaryInputCount, pvpr_primaryOutputCount );
}
return( ok );
}
//===========================================================================//
// Method : UpdateLogicalBlocks_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::UpdateLogicalBlocks_(
t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount ) const
{
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( !vpr_logicalBlockArray[blockIndex].model )
continue;
int inputPinCount = 0;
for( t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->inputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
if( pvpr_port->is_clock )
continue;
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
if( vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex] == OPEN )
continue;
++inputPinCount;
}
}
vpr_logicalBlockArray[blockIndex].used_input_pins = inputPinCount;
}
}
//===========================================================================//
// Method : UpdateVpackNets_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::UpdateVpackNets_(
t_net* vpr_netArray,
const t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( !vpr_logicalBlockArray[blockIndex].model )
continue;
int inputPinCount = vpr_logicalBlockArray[blockIndex].used_input_pins;
for( t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->outputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
if( vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex] == OPEN )
continue;
int netIndex = vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex];
vpr_netArray[netIndex].is_const_gen = static_cast< boolean >( false );
if(( inputPinCount == 0 ) &&
( vpr_logicalBlockArray[blockIndex].type != VPACK_INPAD ) &&
( vpr_logicalBlockArray[blockIndex].type != VPACK_OUTPAD ) &&
( vpr_logicalBlockArray[blockIndex].clock_net == OPEN ))
{
vpr_netArray[netIndex].is_const_gen = static_cast< boolean >( true );
ok = printHandler.Warning( "Net \"%s\" is a constant generator.\n",
TIO_PSZ_STR( vpr_netArray[netIndex].name ));
}
if( !ok )
break;
}
if( !ok )
break;
}
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : UpdateGlobalNets_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 08/09/13 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::UpdateGlobalNets_(
t_net* vpr_netArray,
int vpr_netCount,
t_netlist* pvpr_netList ) const
{
// See VPR's netlist.c::load_global_net_from_array() function...
pvpr_netList->net.resize( vpr_netCount );
for( int i = 0; i < vpr_netCount; ++i )
{
pvpr_netList->net[i].name = TC_strdup( vpr_netArray[i].name );
pvpr_netList->net[i].is_routed = vpr_netArray[i].is_routed;
pvpr_netList->net[i].is_fixed = vpr_netArray[i].is_fixed;
pvpr_netList->net[i].is_global = vpr_netArray[i].is_global;
pvpr_netList->net[i].is_const_gen = vpr_netArray[i].is_const_gen;
pvpr_netList->net[i].pins.resize( vpr_netArray[i].num_sinks + 1 );
for( int j = 0; j <= vpr_netArray[i].num_sinks; ++j)
{
pvpr_netList->net[i].pins[j].block = vpr_netArray[i].node_block[j];
pvpr_netList->net[i].pins[j].block_pin = vpr_netArray[i].node_block_pin[j];
if( vpr_netArray[i].node_block_port )
{
pvpr_netList->net[i].pins[j].block_port = vpr_netArray[i].node_block_port[j];
}
}
}
}
//===========================================================================//
// Method : UpdateAbsorbLogic_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::UpdateAbsorbLogic_(
t_net* vpr_netArray,
t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
// [VPR] Delete any logical blocks (non-output) with 0 fanout ports
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( vpr_logicalBlockArray[blockIndex].type == VPACK_OUTPAD )
continue;
if( !vpr_logicalBlockArray[blockIndex].model )
continue;
int outputCount = 0;
for( const t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->outputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
for( int i = 0; i < pvpr_port->size; ++i )
{
if( vpr_logicalBlockArray[blockIndex].output_nets[pvpr_port->index][i] == OPEN )
continue;
++outputCount;
}
}
if( outputCount )
continue;
if( vpr_logicalBlockArray[blockIndex].type == VPACK_INPAD )
{
ok = printHandler.Warning( "Block \"%s\" has no fanout, deleting block.\n",
TIO_PSZ_STR( vpr_logicalBlockArray[blockIndex].name ));
vpr_logicalBlockArray[blockIndex].type = VPACK_EMPTY;
}
else
{
ok = printHandler.Warning( "Block \"%s\" has no fanout.\n",
TIO_PSZ_STR( vpr_logicalBlockArray[blockIndex].name ));
}
}
// [VPR] Delete any single-input LUTs that are programmed to be a wire
int deletedLogicCount = 0;
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( !vpr_logicalBlockArray[blockIndex].model )
continue;
if( strcmp( vpr_logicalBlockArray[blockIndex].model->name, "names") != 0 )
continue;
if( vpr_logicalBlockArray[blockIndex].truth_table &&
vpr_logicalBlockArray[blockIndex].truth_table->data_vptr )
{
const char* pszTruthTable = static_cast< const char* >( vpr_logicalBlockArray[blockIndex].truth_table->data_vptr );
if(( strcmp( pszTruthTable, "0 0" ) == 0 ) ||
( strcmp( pszTruthTable, "1 1" ) == 0 ))
{
int inputNetIndex = vpr_logicalBlockArray[blockIndex].input_nets[0][0]; // [VPR] Net driving this buffer
int outputNetIndex = vpr_logicalBlockArray[blockIndex].output_nets[0][0]; // [VPR] Net this buffer is driving
int outputBlockIndex = vpr_netArray[outputNetIndex].node_block[1];
if( vpr_netArray[outputNetIndex].num_sinks != 1 )
continue;
int inputPinIndex = 0;
for( inputPinIndex = 1; inputPinIndex <= vpr_netArray[inputNetIndex].num_sinks; inputPinIndex++)
{
if( vpr_netArray[inputNetIndex].node_block[inputPinIndex] == blockIndex )
break;
}
vpr_logicalBlockArray[blockIndex].type = VPACK_EMPTY; // [VPR] Mark logical_block that had LUT
blockIndex = vpr_netArray[outputNetIndex].node_block[1];
int portIndex = vpr_netArray[outputNetIndex].node_block_port[1];
int pinIndex = vpr_netArray[outputNetIndex].node_block_pin[1];
vpr_netArray[inputNetIndex].node_block[inputPinIndex] = blockIndex; // [VPR] New output
vpr_netArray[inputNetIndex].node_block_port[inputPinIndex] = portIndex;
vpr_netArray[inputNetIndex].node_block_pin[inputPinIndex] = pinIndex;
vpr_logicalBlockArray[outputBlockIndex].input_nets[portIndex][pinIndex] = inputNetIndex;
vpr_netArray[outputNetIndex].node_block[0] = OPEN; // [VPR] This vpack_net disappears; mark it
vpr_netArray[outputNetIndex].node_block_pin[0] = OPEN; // "
vpr_netArray[outputNetIndex].node_block_port[0] = OPEN; // "
vpr_netArray[outputNetIndex].num_sinks = 0; // "
++deletedLogicCount;
}
}
}
if( ok && deletedLogicCount )
{
ok = printHandler.Warning( "Deleted %d LUT buffers.\n",
deletedLogicCount );
}
return( ok );
}
//===========================================================================//
// Method : UpdateCompressLists_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::UpdateCompressLists_(
t_net** pvpr_netArray,
int* pvpr_netCount,
t_logical_block** pvpr_logicalBlockArray,
int* pvpr_logicalBlockCount ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
// [VPR] Delete any VPACK_EMPTY blocks and OPEN nets left behind post synthesis
// (insures all VPACK blocks in netlist are in a contiguous list with no unused spots)
t_net* vpr_netArray = *pvpr_netArray;
t_logical_block* vpr_logicalBlockArray = *pvpr_logicalBlockArray;
int* pmapNetIndexArray = static_cast< int* >( TC_calloc( *pvpr_netCount, sizeof( int )));
int* pmapBlockIndexArray = static_cast< int* >( TC_calloc( *pvpr_logicalBlockCount, sizeof( int )));
int vpr_netCount = *pvpr_netCount;
int new_netCount = 0;
for( int netIndex = 0; netIndex < vpr_netCount; ++netIndex )
{
if( vpr_netArray[netIndex].node_block[0] != OPEN )
{
pmapNetIndexArray[netIndex] = new_netCount;
++new_netCount;
}
else
{
pmapNetIndexArray[netIndex] = OPEN;
}
}
int vpr_logicalBlockCount = *pvpr_logicalBlockCount;
int new_logicalBlockCount = 0;
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( vpr_logicalBlockArray[blockIndex].type != VPACK_EMPTY )
{
pmapBlockIndexArray[blockIndex] = new_logicalBlockCount;
++new_logicalBlockCount;
}
else
{
pmapBlockIndexArray[blockIndex] = OPEN;
}
}
if(( new_netCount != vpr_netCount ) || ( new_logicalBlockCount != vpr_logicalBlockCount ))
{
for( int netIndex = 0; netIndex < vpr_netCount; ++netIndex )
{
if( vpr_netArray[netIndex].node_block[0] != OPEN )
{
int mapIndex = pmapNetIndexArray[netIndex];
vpr_netArray[mapIndex] = vpr_netArray[netIndex];
for( int pinIndex = 0; pinIndex <= vpr_netArray[mapIndex].num_sinks; ++pinIndex )
{
int blockIndex = vpr_netArray[mapIndex].node_block[pinIndex];
vpr_netArray[mapIndex].node_block[pinIndex] = pmapBlockIndexArray[blockIndex];
}
}
else
{
this->FreeVpackNet_( *pvpr_netArray, netIndex );
}
}
vpr_netCount = new_netCount;
*pvpr_netArray = static_cast< t_net* >( TC_realloc( *pvpr_netArray, vpr_netCount, sizeof( t_net )));
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( vpr_logicalBlockArray[blockIndex].type != VPACK_EMPTY )
{
int mapIndex = pmapBlockIndexArray[blockIndex];
if( mapIndex != blockIndex )
{
vpr_logicalBlockArray[mapIndex] = vpr_logicalBlockArray[blockIndex];
vpr_logicalBlockArray[mapIndex].index = mapIndex;
}
for( const t_model_ports* pvpr_port = vpr_logicalBlockArray[mapIndex].model->inputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
if( !pvpr_port->is_clock)
{
if( vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex] == OPEN)
continue;
mapIndex = vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex];
vpr_logicalBlockArray[blockIndex].input_nets[portIndex][pinIndex] = pmapNetIndexArray[mapIndex];
}
else
{
if( vpr_logicalBlockArray[blockIndex].clock_net == OPEN)
continue;
mapIndex = vpr_logicalBlockArray[blockIndex].clock_net;
vpr_logicalBlockArray[blockIndex].clock_net = pmapNetIndexArray[mapIndex];
}
}
}
for( const t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->outputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
int portIndex = pvpr_port->index;
int pinCount = pvpr_port->size;
for( int pinIndex = 0; pinIndex < pinCount; ++pinIndex )
{
if( vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex] == OPEN )
continue;
mapIndex = vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex];
vpr_logicalBlockArray[blockIndex].output_nets[portIndex][pinIndex] = pmapNetIndexArray[mapIndex];
}
}
}
else
{
this->FreeLogicalBlock_( *pvpr_logicalBlockArray, blockIndex );
}
}
vpr_logicalBlockCount = new_logicalBlockCount;
*pvpr_logicalBlockArray = static_cast< t_logical_block* >( TC_realloc( *pvpr_logicalBlockArray, vpr_logicalBlockCount, sizeof( t_logical_block )));
}
free( pmapNetIndexArray );
free( pmapBlockIndexArray );
if( *pvpr_netCount != vpr_netCount )
{
ok = printHandler.Warning( "Compressed net list, deleted %d open nets.\n",
*pvpr_netCount - vpr_netCount );
*pvpr_netCount = vpr_netCount;
}
if( *pvpr_logicalBlockCount != vpr_logicalBlockCount )
{
ok = printHandler.Warning( "Compressed block list, deleted %d empty blocks.\n",
*pvpr_logicalBlockCount - vpr_logicalBlockCount );
*pvpr_logicalBlockCount = vpr_logicalBlockCount;
}
return( ok );
}
//===========================================================================//
// Method : UpdatePrimiaryCounts_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::UpdatePrimaryCounts_(
t_logical_block* vpr_logicalBlockArray,
int vpr_logicalBlockCount,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
*pvpr_primaryInputCount = 0;
*pvpr_primaryOutputCount = 0;
for( int blockIndex = 0; blockIndex < vpr_logicalBlockCount; ++blockIndex )
{
if( vpr_logicalBlockArray[blockIndex].type == VPACK_INPAD )
{
++*pvpr_primaryInputCount;
}
else if( vpr_logicalBlockArray[blockIndex].type == VPACK_OUTPAD )
{
++*pvpr_primaryOutputCount;
}
}
}
//===========================================================================//
// Method : LoadModelLibrary_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::LoadModelLibrary_(
const t_model* pvpr_standardModels,
t_model** ppvpr_inputModel,
t_model** ppvpr_outputModel,
t_model** ppvpr_logicModel,
t_model** ppvpr_latchModel ) const
{
*ppvpr_inputModel = 0;
*ppvpr_outputModel = 0;
*ppvpr_logicModel = 0;
*ppvpr_latchModel = 0;
for( const t_model* pvpr_standardModel = pvpr_standardModels;
pvpr_standardModel;
pvpr_standardModel = pvpr_standardModel->next )
{
if(strcmp( pvpr_standardModel->name, MODEL_INPUT ) == 0 )
{
*ppvpr_inputModel = const_cast< t_model* >( pvpr_standardModel );
}
else if( strcmp( pvpr_standardModel->name, MODEL_OUTPUT ) == 0 )
{
*ppvpr_outputModel = const_cast< t_model* >( pvpr_standardModel );
}
else if( strcmp( pvpr_standardModel->name, MODEL_LOGIC ) == 0 )
{
*ppvpr_logicModel = const_cast< t_model* >( pvpr_standardModel );
}
else if( strcmp( pvpr_standardModel->name, MODEL_LATCH ) == 0 )
{
*ppvpr_latchModel = const_cast< t_model* >( pvpr_standardModel );
}
if( *ppvpr_inputModel && *ppvpr_outputModel && *ppvpr_logicModel && *ppvpr_latchModel )
break;
}
return( *ppvpr_inputModel && *ppvpr_outputModel && *ppvpr_logicModel && *ppvpr_latchModel ?
true : false );
}
//===========================================================================//
// Method : PeekInputOutputList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PeekInputOutputList_(
const t_block* vpr_blockArray,
int vpr_blockCount,
const TPO_InstList_t& inputOutputList,
TPO_InstList_t* pinputOutputList ) const
{
// Iterate VPR's global block list for IO_TYPE blocks
for( int blockIndex = 0; blockIndex < vpr_blockCount; ++blockIndex )
{
const t_block& vpr_block = vpr_blockArray[blockIndex];
if( vpr_block.type != IO_TYPE )
continue;
this->PeekInputOutput_( vpr_block,
inputOutputList, pinputOutputList );
}
}
//===========================================================================//
// Method : PeekInputOutput_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PeekInputOutput_(
const t_block& vpr_block,
const TPO_InstList_t& inputOutputList,
TPO_InstList_t* pinputOutputList ) const
{
const char* pszInstName = vpr_block.name;
const char* pszCellName = "";
if( vpr_block.pb &&
vpr_block.pb->pb_graph_node &&
vpr_block.pb->pb_graph_node->pb_type )
{
pszCellName = vpr_block.pb->pb_graph_node->pb_type->name;
}
string srPlaceFabricName;
if(( vpr_block.x >= 0 ) && ( vpr_block.y >= 0 ))
{
char szPlaceFabricName[TIO_FORMAT_STRING_LEN_DATA];
sprintf( szPlaceFabricName, "fabric[%d][%d].%d", vpr_block.x, vpr_block.y, vpr_block.z );
srPlaceFabricName = szPlaceFabricName;
}
TPO_StatusMode_t placeStatus = ( vpr_block.is_fixed ?
TPO_STATUS_FIXED : TPO_STATUS_PLACED );
TGO_Point_c placeOrigin( vpr_block.x, vpr_block.y, vpr_block.z );
TGS_RegionList_t placeRegionList;
if( vpr_block.placement_region_list.IsValid( ))
{
for( size_t i = 0; i < vpr_block.placement_region_list.GetLength( ); ++i )
{
const TGO_Region_c& placementRegion = *vpr_block.placement_region_list[i];
TGS_Region_c placeRegion( static_cast< double >( placementRegion.x1 ),
static_cast< double >( placementRegion.y1 ),
static_cast< double >( placementRegion.x2 ),
static_cast< double >( placementRegion.y2 ));
placeRegionList.Add( placeRegion );
}
}
TPO_PlaceRelativeList_t placeRelativeList;
if( inputOutputList.IsMember( pszInstName ))
{
const TPO_Inst_c& inputOutput = *inputOutputList.Find( pszInstName );
const TPO_PlaceRelativeList_t& placeRelativeList_ = inputOutput.GetPlaceRelativeList( );
for( size_t i = 0; i < placeRelativeList_.GetLength( ); ++i )
{
const TPO_PlaceRelative_c& placeRelative = *placeRelativeList_[i];
placeRelativeList.Add( placeRelative );
}
}
if( pszInstName && *pszInstName )
{
TPO_Inst_c inputOutput( pszInstName );
inputOutput.SetCellName( pszCellName );
inputOutput.SetPlaceFabricName( srPlaceFabricName );
inputOutput.SetPlaceStatus( placeStatus );
inputOutput.SetPlaceOrigin( placeOrigin );
inputOutput.SetPlaceRegionList( placeRegionList );
inputOutput.SetPlaceRelativeList( placeRelativeList );
pinputOutputList->Add( inputOutput );
}
}
//===========================================================================//
// Method : PeekPhysicalBlockList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PeekPhysicalBlockList_(
const t_block* vpr_blockArray,
int vpr_blockCount,
const t_logical_block* vpr_logicalBlockArray,
const TPO_InstList_t& physicalBlockList,
TPO_InstList_t* pphysicalBlockList ) const
{
// Iterate VPR's global block list for non-IO_TYPE blocks
for( int blockIndex = 0; blockIndex < vpr_blockCount; ++blockIndex )
{
const t_block& vpr_block = vpr_blockArray[blockIndex];
if( vpr_block.type == IO_TYPE )
continue;
this->PeekPhysicalBlock_( vpr_block, vpr_logicalBlockArray, blockIndex,
physicalBlockList, pphysicalBlockList );
}
}
//===========================================================================//
// Method : PeekPhysicalBlock_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PeekPhysicalBlock_(
const t_block& vpr_block,
const t_logical_block* vpr_logicalBlockArray,
int blockIndex,
const TPO_InstList_t& physicalBlockList,
TPO_InstList_t* pphysicalBlockList ) const
{
const char* pszInstName = vpr_block.name;
const char* pszCellName = "";
if( vpr_block.pb &&
vpr_block.pb->pb_graph_node &&
vpr_block.pb->pb_graph_node->pb_type )
{
pszCellName = vpr_block.pb->pb_graph_node->pb_type->name;
}
string srPlaceFabricName;
if(( vpr_block.x >= 0 ) && ( vpr_block.y >= 0 ))
{
char szPlaceFabricName[TIO_FORMAT_STRING_LEN_DATA];
sprintf( szPlaceFabricName, "fabric[%d][%d]", vpr_block.x, vpr_block.y );
srPlaceFabricName = szPlaceFabricName;
}
TPO_InstHierMapList_t packHierMapList;
if( vpr_block.pb )
{
this->PeekPackHierMapList_( *vpr_block.pb, vpr_logicalBlockArray,
blockIndex, &packHierMapList );
}
TPO_StatusMode_t placeStatus = ( vpr_block.is_fixed ?
TPO_STATUS_FIXED : TPO_STATUS_PLACED );
TGO_Point_c placeOrigin( vpr_block.x, vpr_block.y );
TGS_RegionList_t placeRegionList;
if( vpr_block.placement_region_list.IsValid( ))
{
for( size_t i = 0; i < vpr_block.placement_region_list.GetLength( ); ++i )
{
const TGO_Region_c& placementRegion = *vpr_block.placement_region_list[i];
TGS_Region_c placeRegion( static_cast< double >( placementRegion.x1 ),
static_cast< double >( placementRegion.y1 ),
static_cast< double >( placementRegion.x2 ),
static_cast< double >( placementRegion.y2 ));
placeRegionList.Add( placeRegion );
}
}
TPO_PlaceRelativeList_t placeRelativeList;
if( physicalBlockList.IsMember( pszInstName ))
{
const TPO_Inst_c& physicalBlock = *physicalBlockList.Find( pszInstName );
const TPO_PlaceRelativeList_t& placeRelativeList_ = physicalBlock.GetPlaceRelativeList( );
for( size_t i = 0; i < placeRelativeList_.GetLength( ); ++i )
{
const TPO_PlaceRelative_c& placeRelative = *placeRelativeList_[i];
placeRelativeList.Add( placeRelative );
}
}
if( pszInstName && *pszInstName )
{
TPO_Inst_c physicalBlock( pszInstName );
physicalBlock.SetCellName( pszCellName );
physicalBlock.SetPackInstHierMapList( packHierMapList );
physicalBlock.SetPlaceFabricName( srPlaceFabricName );
physicalBlock.SetPlaceStatus( placeStatus );
physicalBlock.SetPlaceOrigin( placeOrigin );
physicalBlock.SetPlaceRegionList( placeRegionList );
physicalBlock.SetPlaceRelativeList( placeRelativeList );
pphysicalBlockList->Add( physicalBlock );
}
}
//===========================================================================//
// Method : PeekPackHierMapList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::PeekPackHierMapList_(
const t_pb& vpr_pb,
const t_logical_block* vpr_logicalBlockArray,
int nodeIndex,
TPO_InstHierMapList_t* ppackHierMapList ) const
{
// Apply recursion to read physical block's hierarchical pack map list
TPO_NameList_t hierNameList;
this->PeekPackHierMapList_( vpr_pb, vpr_logicalBlockArray,
nodeIndex, &hierNameList, ppackHierMapList );
}
//===========================================================================//
void TVPR_CircuitDesign_c::PeekPackHierMapList_(
const t_pb& vpr_pb,
const t_logical_block* vpr_logicalBlockArray,
int nodeIndex,
TPO_NameList_t* phierNameList,
TPO_InstHierMapList_t* ppackHierMapList ) const
{
if( vpr_pb.name )
{
if( vpr_pb.child_pbs &&
vpr_pb.pb_graph_node &&
vpr_pb.pb_graph_node->pb_type )
{
char szHierName[TIO_FORMAT_STRING_LEN_DATA];
sprintf( szHierName, "%s[%d]", vpr_pb.pb_graph_node->pb_type->name, nodeIndex );
phierNameList->Add( szHierName );
int modeIndex = vpr_pb.mode;
const t_mode& vpr_mode = vpr_pb.pb_graph_node->pb_type->modes[modeIndex];
for( int typeIndex = 0; typeIndex < vpr_mode.num_pb_type_children; ++typeIndex )
{
for( int instIndex = 0; instIndex < vpr_mode.pb_type_children[typeIndex].num_pb; ++instIndex )
{
if( vpr_pb.child_pbs &&
vpr_pb.child_pbs[typeIndex] &&
vpr_pb.child_pbs[typeIndex][instIndex].name )
{
TPO_NameList_t hierNameList( *phierNameList );
const t_pb& child_pb = vpr_pb.child_pbs[typeIndex][instIndex];
this->PeekPackHierMapList_( child_pb, vpr_logicalBlockArray,
instIndex, &hierNameList, ppackHierMapList );
}
}
}
}
else if( vpr_pb.logical_block != OPEN )
{
int blockIndex = vpr_pb.logical_block;
const char* pszInstName = vpr_logicalBlockArray[blockIndex].name;
char szHierName[TIO_FORMAT_STRING_LEN_DATA];
sprintf( szHierName, "%s[%d]", vpr_pb.pb_graph_node->pb_type->name, 0 );
phierNameList->Add( szHierName );
TPO_InstHierMap_c packHierMap( pszInstName, *phierNameList );
ppackHierMapList->Add( packHierMap );
}
}
}
//===========================================================================//
// Method : PeekNetList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
void TVPR_CircuitDesign_c::PeekNetList_(
const t_arch* vpr_architecture,
const t_netlist& vpr_netList,
const t_block* vpr_blockArray,
int vpr_blockCount,
const t_logical_block* vpr_logicalBlockArray,
const t_rr_node* vpr_rrNodeArray,
TNO_NetList_c* pnetList,
bool tiClayResyncNets ) const
{
// Initialize net list based on all nets defined in given VPR net list
this->ExtractNetList_( vpr_netList,
pnetList );
// Update net list based on all net instance ports asso. with VPR nets
this->ExtractNetListInstPins_( vpr_netList,
vpr_logicalBlockArray,
pnetList );
// Update net list based on any available net global routes
// WIP - this->ExtractNetListGlobalRoutes_...
// Update net list based on any available net routes
this->ExtractNetListRoutes_( vpr_architecture,
vpr_netList,
vpr_blockArray, vpr_blockCount,
vpr_rrNodeArray,
pnetList,
tiClayResyncNets );
}
//===========================================================================//
// Method : ValidateModelList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::ValidateModelList_(
const TLO_CellList_t& cellList,
const t_model* pvpr_customModels ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
for( size_t i = 0; i < cellList.GetLength( ); ++i )
{
const TLO_Cell_c& cell = *cellList[i];
const char* pszCellName = cell.GetName( );
bool foundModel = false;
for( const t_model* pvpr_customModel = pvpr_customModels;
pvpr_customModel;
pvpr_customModel = pvpr_customModel->next )
{
if( strcmp( pvpr_customModel->name, pszCellName ) == 0 )
{
foundModel = true;
break;
}
}
if( !foundModel )
{
ok = printHandler.Error( "Invalid circuit .model \"%s\" detected!\n"
"%sModel not found in architecture's <model> list.\n",
TIO_PSZ_STR( pszCellName ),
TIO_PREFIX_ERROR_SPACE );
if( !ok )
break;
}
}
return( ok );
}
//===========================================================================//
// Method : ValidateSubcktList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::ValidateSubcktList_(
const TPO_InstList_t& instList,
const TLO_CellList_t& cellList ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
for( size_t i = 0; i < instList.GetLength( ); ++i )
{
const TPO_Inst_c& inst = *instList[i];
if( inst.GetSource( ) != TPO_INST_SOURCE_SUBCKT )
continue;
const char* pszCellName = inst.GetCellName( );
const TLO_Cell_c* pcell = cellList.Find( pszCellName );
if( pcell )
{
const TLO_PortList_t& portList = pcell->GetPortList( );
const TPO_PinMapList_t& pinMapList = inst.GetSubcktPinMapList( );
for( size_t j = 0; j < pinMapList.GetLength( ); ++j )
{
const TPO_PinMap_c& pinMap = *pinMapList[j];
const char* pszCellPinName = pinMap.GetCellPinName( );
if( !portList.Find( pszCellPinName ))
{
ok = printHandler.Error( "Invalid circuit .subckt model \"%s\" port \"%s\" detected!\n"
"%sPort not found in circuit's .model definition.\n",
TIO_PSZ_STR( pszCellName ),
TIO_PSZ_STR( pszCellPinName ),
TIO_PREFIX_ERROR_SPACE );
}
if( !ok )
break;
}
}
else
{
ok = printHandler.Error( "Invalid circuit .subckt model \"%s\" detected!\n"
"%sModel not found in circuit's .model list.\n",
TIO_PSZ_STR( pszCellName ),
TIO_PREFIX_ERROR_SPACE );
}
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : ValidateInstList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::ValidateInstList_(
TPO_InstList_t* pinstList,
const TLO_CellList_t& cellList,
bool deleteInvalidInsts ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
TPO_InstList_t instList( *pinstList );
pinstList->Clear( );
pinstList->SetCapacity( instList.GetLength( ));
size_t zeroOutputPinCount = 0;
for( size_t i = 0; i < instList.GetLength( ); ++i )
{
const TPO_Inst_c& inst = *instList[i];
if( inst.GetSource( ) == TPO_INST_SOURCE_SUBCKT )
{
// [VPR] Delete instance if 0 output pins (and is not an output pad)
size_t outputPinCount = inst.FindPinCount( TC_TYPE_OUTPUT, cellList );
if( outputPinCount == 0 )
{
ok = printHandler.Warning( "Invalid subckt block \"%s\" detected.\n"
"%sNo output pins founds.\n",
TIO_PSZ_STR( inst.GetName( )),
TIO_PREFIX_WARNING_SPACE );
if( !ok )
break;
if( deleteInvalidInsts )
{
++zeroOutputPinCount;
continue;
}
}
}
pinstList->Add( inst );
}
if( ok && zeroOutputPinCount )
{
ok = printHandler.Warning( "Deleted %d subckt blocks with zero outputs.\n",
zeroOutputPinCount );
}
return( ok );
}
//===========================================================================//
// Method : AddVpackNet_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
int TVPR_CircuitDesign_c::AddVpackNet_(
const char* pszNetName,
int pinType,
bool isGlobal,
int blockIndex,
int portIndex,
int pinIndex,
const TNO_NetList_c& netList,
t_net* vpr_netArray ) const
{
const TNO_Net_c* pnet = netList.Find( pszNetName );
size_t netIndex = ( pnet ? pnet->GetIndex( ) : SIZE_MAX );
if( netIndex != SIZE_MAX )
{
int nodeIndex = 0;
if( pinType == DRIVER )
{
// [VPR] Driver pin is always placed at position '0'
nodeIndex = 0;
}
else // if( pinType == RECEIVER )
{
++vpr_netArray[netIndex].num_sinks;
nodeIndex = vpr_netArray[netIndex].num_sinks;
}
vpr_netArray[netIndex].is_global = static_cast< boolean >( isGlobal );
vpr_netArray[netIndex].node_block[nodeIndex] = blockIndex;
vpr_netArray[netIndex].node_block_port[nodeIndex] = portIndex;
vpr_netArray[netIndex].node_block_pin[nodeIndex] = pinIndex;
}
else if( strcmp( pszNetName, "unconn") == 0)
{
netIndex = OPEN;
}
return( static_cast< int >( netIndex ));
}
//===========================================================================//
// Method : AddLogicalBlockInputOutput_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::AddLogicalBlockInputOutput_(
const char* pszPortName,
int pinType,
int netIndex,
const t_model* pvpr_inputModel,
const t_model* pvpr_outputModel,
t_logical_block* vpr_logicalBlockArray,
int vpr_blockIndex,
int* pvpr_primaryInputCount,
int* pvpr_primaryOutputCount ) const
{
int blockIndex = vpr_blockIndex;
vpr_logicalBlockArray[blockIndex].input_nets = 0;
vpr_logicalBlockArray[blockIndex].output_nets = 0;
vpr_logicalBlockArray[blockIndex].clock_net = OPEN;
vpr_logicalBlockArray[blockIndex].truth_table = 0;
if( pinType == DRIVER )
{
vpr_logicalBlockArray[blockIndex].name = TC_strdup( pszPortName );
vpr_logicalBlockArray[blockIndex].type = VPACK_INPAD;
vpr_logicalBlockArray[blockIndex].model = const_cast< t_model* >( pvpr_inputModel );
vpr_logicalBlockArray[blockIndex].output_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].output_nets[0] = static_cast< int* >( TC_calloc( 1, sizeof( int )));
vpr_logicalBlockArray[blockIndex].output_nets[0][0] = netIndex;
++*pvpr_primaryInputCount; // VPR trickery... see VPR's global num_p_inputs
}
else // if( pinType == RECEIVER )
{
// [VPR] Make output names unique from LUTs
string srPortName = "out:";
srPortName += pszPortName;
vpr_logicalBlockArray[blockIndex].name = TC_strdup( srPortName );
vpr_logicalBlockArray[blockIndex].type = VPACK_OUTPAD;
vpr_logicalBlockArray[blockIndex].model = const_cast< t_model* >( pvpr_outputModel );
vpr_logicalBlockArray[blockIndex].input_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].input_nets[0] = static_cast< int* >( TC_calloc( 1, sizeof( int )));
vpr_logicalBlockArray[blockIndex].input_nets[0][0] = netIndex;
++*pvpr_primaryOutputCount; // VPR trickery... see VPR's global num_p_outputs
}
}
//===========================================================================//
// Method : AddLogicalBlockLogic_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::AddLogicalBlockLogic_(
const char* pszOutputPinName,
const TPO_PinList_t& pinList,
const TNO_NetList_c& netList,
const t_model* pvpr_logicModel,
t_logical_block* vpr_logicalBlockArray,
int vpr_blockIndex ) const
{
int blockIndex = vpr_blockIndex;
vpr_logicalBlockArray[blockIndex].name = TC_strdup( pszOutputPinName );
vpr_logicalBlockArray[blockIndex].type = VPACK_COMB;
vpr_logicalBlockArray[blockIndex].model = const_cast< t_model* >( pvpr_logicModel );
vpr_logicalBlockArray[blockIndex].output_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].output_nets[0] = static_cast< int* >( TC_calloc( 1, sizeof( int )));
vpr_logicalBlockArray[blockIndex].input_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].input_nets[0] = static_cast< int* >( TC_calloc( pvpr_logicModel->inputs->size, sizeof( int )));
for( int i = 0; i < pvpr_logicModel->inputs->size; ++i )
{
vpr_logicalBlockArray[blockIndex].input_nets[0][i] = OPEN;
}
int inputPinIndex = 0;
for( size_t i = 0; i < pinList.GetLength( ); ++i )
{
const TPO_Pin_t& pin = *pinList[i];
const char* pszNetName = pin.GetName( );
const TNO_Net_c* pnet = netList.Find( pszNetName );
if( !pnet )
continue;
unsigned int netIndex = pnet->GetIndex( );
if( pin.GetType( ) == TC_TYPE_OUTPUT )
{
vpr_logicalBlockArray[blockIndex].output_nets[0][0] = netIndex;
}
else
{
vpr_logicalBlockArray[blockIndex].input_nets[0][inputPinIndex] = netIndex;
++inputPinIndex;
}
}
vpr_logicalBlockArray[blockIndex].clock_net = OPEN;
vpr_logicalBlockArray[blockIndex].truth_table = 0;
}
//===========================================================================//
// Method : AddLogicalBlockLatch_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::AddLogicalBlockLatch_(
const char* pszOutputPinName,
const char* pszInputPinName,
const char* pszClockPinName,
const TNO_NetList_c& netList,
const t_model* pvpr_latchModel,
t_logical_block* vpr_logicalBlockArray,
int vpr_blockIndex ) const
{
if( netList.IsMember( pszOutputPinName ) &&
netList.IsMember( pszInputPinName ) &&
netList.IsMember( pszClockPinName ))
{
int blockIndex = vpr_blockIndex;
const TNO_Net_c& outputNet = *netList.Find( pszOutputPinName );
const TNO_Net_c& inputNet = *netList.Find( pszInputPinName );
const TNO_Net_c& clockNet = *netList.Find( pszClockPinName );
unsigned int outputNetIndex = outputNet.GetIndex( );
unsigned int inputNetIndex = inputNet.GetIndex( );
unsigned int clockNetIndex = clockNet.GetIndex( );
vpr_logicalBlockArray[blockIndex].name = TC_strdup( pszOutputPinName );
vpr_logicalBlockArray[blockIndex].type = VPACK_LATCH;
vpr_logicalBlockArray[blockIndex].model = const_cast< t_model* >( pvpr_latchModel );
vpr_logicalBlockArray[blockIndex].output_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].output_nets[0] = static_cast< int* >( TC_calloc( 1, sizeof( int )));
vpr_logicalBlockArray[blockIndex].output_nets[0][0] = static_cast< int >( outputNetIndex );
vpr_logicalBlockArray[blockIndex].input_nets = static_cast< int** >( TC_calloc( 1, sizeof( int* )));
vpr_logicalBlockArray[blockIndex].input_nets[0] = static_cast< int* >( TC_calloc( 1, sizeof( int )));
vpr_logicalBlockArray[blockIndex].input_nets[0][0] = static_cast< int >( inputNetIndex );
vpr_logicalBlockArray[blockIndex].clock_net = static_cast< int >( clockNetIndex );
vpr_logicalBlockArray[blockIndex].truth_table = 0;
}
}
//===========================================================================//
// Method : FreeVpackNet_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::FreeVpackNet_(
t_net* vpr_netArray,
int netIndex ) const
{
free( vpr_netArray[netIndex].name );
free( vpr_netArray[netIndex].node_block );
free( vpr_netArray[netIndex].node_block_port );
free( vpr_netArray[netIndex].node_block_pin );
}
//===========================================================================//
// Method : FreeLogicalBlock_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::FreeLogicalBlock_(
t_logical_block* vpr_logicalBlockArray,
int blockIndex ) const
{
free( vpr_logicalBlockArray[blockIndex].name );
int i = 0;
for( const t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->inputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
if( pvpr_port->is_clock )
continue;
if( vpr_logicalBlockArray[blockIndex].input_nets &&
vpr_logicalBlockArray[blockIndex].input_nets[i] )
{
free( vpr_logicalBlockArray[blockIndex].input_nets[i] );
vpr_logicalBlockArray[blockIndex].input_nets[i] = 0;
}
++i;
}
if( vpr_logicalBlockArray[blockIndex].input_nets )
{
free( vpr_logicalBlockArray[blockIndex].input_nets );
}
i = 0;
for( const t_model_ports* pvpr_port = vpr_logicalBlockArray[blockIndex].model->outputs;
pvpr_port;
pvpr_port = pvpr_port->next )
{
if( vpr_logicalBlockArray[blockIndex].output_nets &&
vpr_logicalBlockArray[blockIndex].output_nets[i] )
{
free( vpr_logicalBlockArray[blockIndex].output_nets[i] );
vpr_logicalBlockArray[blockIndex].output_nets[i] = 0;
}
++i;
}
if( vpr_logicalBlockArray[blockIndex].output_nets)
{
free( vpr_logicalBlockArray[blockIndex].output_nets ) ;
}
t_linked_vptr *pvpr_linked_vptr = vpr_logicalBlockArray[blockIndex].truth_table;
while( pvpr_linked_vptr )
{
if( pvpr_linked_vptr->data_vptr )
{
free( pvpr_linked_vptr->data_vptr );
}
t_linked_vptr *pvpr_next_vptr = pvpr_linked_vptr->next;
free( pvpr_linked_vptr );
pvpr_linked_vptr = pvpr_next_vptr;
}
}
//===========================================================================//
// Method : ExtractNetList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
void TVPR_CircuitDesign_c::ExtractNetList_(
const t_netlist& vpr_netList,
TNO_NetList_c* pnetList ) const
{
// Iterate for every net in the existing VPR net list...
for( unsigned int netIndex = 0; netIndex < vpr_netList.net.size( ); ++netIndex )
{
const t_vnet& vpr_net = vpr_netList.net[netIndex];
const char* pszNetName = vpr_net.name;
if( pnetList->IsMember( pszNetName ))
continue;
// Define and add a new net node based on next VPR net
TC_TypeMode_t netType = ( vpr_net.is_global ? TC_TYPE_GLOBAL : TC_TYPE_SIGNAL );
TNO_Net_c net( pszNetName, netType );
pnetList->Add( net );
}
}
//===========================================================================//
// Method : ExtractNetListInstPins_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
void TVPR_CircuitDesign_c::ExtractNetListInstPins_(
const t_netlist& vpr_netList,
const t_logical_block* vpr_logicalBlockArray,
TNO_NetList_c* pnetList ) const
{
// Iterate for every net in the existing VPR net list...
for( unsigned int netIndex = 0; netIndex < vpr_netList.net.size( ); ++netIndex )
{
const t_vnet& vpr_net = vpr_netList.net[netIndex];
const char* pszNetName = vpr_net.name;
TNO_Net_c* pnet = pnetList->Find( pszNetName );
pnet->ClearInstPinList( );
// Iterate for every pin in the existing VPR net...
int pinCount = 1 + const_cast< t_vnet& >( vpr_net ).num_sinks( ); // [VPR] Assume [0] for output pin
for( int nodeIndex = 0; nodeIndex < pinCount; ++nodeIndex )
{
// Extract pin's instance (ie. block) name and port/pin name
int blockIndex = vpr_net.pins[nodeIndex].block;
const char* pszBlockName = vpr_logicalBlockArray[blockIndex].name;
const t_pb_graph_pin* pvpr_graphPin = 0;
pvpr_graphPin = this->FindGraphPin_( vpr_logicalBlockArray,
vpr_net, nodeIndex );
if( pvpr_graphPin )
{
const char* pszPortName = pvpr_graphPin->port->name;
TC_TypeMode_t ioType = TC_TYPE_OUTPUT;
ioType = ( nodeIndex > 0 ? TC_TYPE_INPUT : ioType );
ioType = ( pvpr_graphPin->port->is_clock ? TC_TYPE_CLOCK : ioType );
// Update new net's instance/pin list
TNO_InstPin_c instPin( pszBlockName, pszPortName, ioType );
pnet->AddInstPin( instPin );
}
}
}
}
//===========================================================================//
// Method : ExtractNetListRoutes_
// Reference: See Jason Luu's original vpr_resync_post_route_netlist()
// source code. This includes support for resolving logical
// equivalence on CLB pins.
//
// "Logical equivalence scrambles the packed netlist indices
// with the actual indices, need to resync then re-output
// clustered netlist. This code assumes we are dealing with
// a TI CLAY v1 architecture." -- Jason Luu
//
// "Returns a trace array [0..num_logical_nets-1] with the
// final routing of the circuit from the logical_block
// netlist, index of the trace array corresponds to the
// index of a vpack_net." -- Jason Luu
//
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
// 07/23/13 jeffr : Added support for optional "tiClayResyncNets" parameter
// 08/21/13 jeffr : Updated to handle "const t_netlist&" parameter instead of
// the obsolete "t_net*" and associated count parameters
//===========================================================================//
void TVPR_CircuitDesign_c::ExtractNetListRoutes_(
const t_arch* vpr_architecture,
const t_netlist& vpr_netList,
const t_block* vpr_blockArray,
int vpr_blockCount,
const t_rr_node* vpr_rrNodeArray,
TNO_NetList_c* pnetList,
bool tiClayResyncNets ) const
{
if( vpr_netList.net.size( ) && vpr_blockCount )
{
// Call VPR API's special TI-specific function to find all net trace lists
boolean applyLogicalEquivalence = static_cast< boolean >( tiClayResyncNets );
t_trace* pvpr_traceArray = 0;
pvpr_traceArray = vpr_resync_post_route_netlist_to_TI_CLAY_v1_architecture( applyLogicalEquivalence,
vpr_architecture );
if( pvpr_traceArray )
{
// Iterate for every net in the existing VPR net list...
for( unsigned int netIndex = 0; netIndex < vpr_netList.net.size( ); ++netIndex )
{
const t_vnet& vpr_net = vpr_netList.net[netIndex];
const char* pszNetName = vpr_net.name;
TNO_Net_c* pnet = pnetList->Find( pszNetName );
pnet->ClearRouteList( );
if( !vpr_blockArray || !vpr_rrNodeArray )
continue;
t_trace* pvpr_traceList = &pvpr_traceArray[netIndex];
if( this->IsNetOpen_( pvpr_traceList ))
continue;
TNO_RouteList_t routeList;
this->ExtractNetRoutes_( vpr_blockArray, vpr_rrNodeArray,
pvpr_traceList, &routeList );
TNO_StatusMode_t routeStatus = ( vpr_net.is_fixed ?
TNO_STATUS_FIXED : TNO_STATUS_ROUTED );
pnet->SetStatus( routeStatus );
pnet->AddRouteList( routeList );
}
}
free( pvpr_traceArray );
}
}
//===========================================================================//
// Method : ExtractNetRoutes_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::ExtractNetRoutes_(
const t_block* vpr_blockArray,
const t_rr_node* vpr_rrNodeArray,
t_trace* pvpr_traceList,
TNO_RouteList_t* prouteList ) const
{
// Generate a trace node count list based on current trace list
TVPR_IndexCountList_t traceCountList;
this->MakeTraceNodeCountList_( pvpr_traceList, &traceCountList );
// Update current trace list's sibling counts using node count list
this->UpdateTraceSiblingCount_( pvpr_traceList, traceCountList );
// Apply recursion to load list of route paths based on current trace list
const t_trace* pvpr_traceThis = pvpr_traceList;
const t_trace* pvpr_tracePrev = 0;
TNO_Route_t route;
this->LoadTraceRoutes_( vpr_blockArray, vpr_rrNodeArray,
pvpr_traceThis, pvpr_tracePrev,
&route, prouteList );
}
//===========================================================================//
// Method : IsNetOpen_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
bool TVPR_CircuitDesign_c::IsNetOpen_(
const t_trace* pvpr_traceList ) const
{
// Determine if net is open (or routed) based on current trace list
// (open impiles unique output/input block and no intra-CLB trace routing)
int blockIndex = OPEN;
bool hasSingleBlock = false;
bool hasRouteTrace = false;
for( const t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
if( pvpr_trace->iblock != OPEN )
{
if( blockIndex == OPEN )
{
blockIndex = pvpr_trace->iblock;
hasSingleBlock = true;
}
else if( blockIndex != pvpr_trace->iblock )
{
hasSingleBlock = false;
break;
}
}
else
{
hasRouteTrace = true;
break;
}
}
return( !hasSingleBlock && !hasRouteTrace ? true : false );
}
//===========================================================================//
// Method : MakeTraceNodeCountList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::MakeTraceNodeCountList_(
const t_trace* pvpr_traceList,
TVPR_IndexCountList_t* ptraceCountList ) const
{
// Allocate a node index/count list used to determine trace sibling counts
size_t len = this->FindTraceListLength_( pvpr_traceList );
ptraceCountList->SetCapacity( len );
// Load node index/count list based on trace sibling (ie. duplicate nodes)
for( const t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
TVPR_IndexCount_c indexCount( pvpr_trace->iblock, pvpr_trace->index );
if( !ptraceCountList->IsMember( indexCount ))
{
TVPR_IndexCount_c* pindexCount = ptraceCountList->Add( indexCount );
pindexCount->SetSiblingCount( 1 );
}
else
{
TVPR_IndexCount_c* pindexCount = ( *ptraceCountList )[ indexCount ];
pindexCount->SetSiblingCount( pindexCount->GetSiblingCount( ) + 1 );
}
}
}
//===========================================================================//
// Method : UpdateTraceSiblingCount_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::UpdateTraceSiblingCount_(
t_trace* pvpr_traceList,
const TVPR_IndexCountList_t& traceCountList ) const
{
// Update sibling count for all trace nodes baesd on node count list
for( t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
TVPR_IndexCount_c indexCount( pvpr_trace->iblock, pvpr_trace->index );
TVPR_IndexCount_c* pindexCount = traceCountList[ indexCount ];
pvpr_trace->num_siblings = static_cast< int >( pindexCount->GetSiblingCount( ));
}
for( t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
if( pvpr_trace->num_siblings == 1 )
{
if( !pvpr_trace->next )
{
pvpr_trace->num_siblings = 0;
}
}
if( pvpr_trace->num_siblings > 1 )
{
t_trace* pprev_trace = pvpr_trace;
while(( pprev_trace ) &&
( pprev_trace->next ))
{
if( pprev_trace->next->index == pvpr_trace->index )
break;
pprev_trace = pprev_trace->next;
}
if(( pprev_trace ) &&
( pprev_trace->iblock != OPEN ))
{
pprev_trace->num_siblings = 0;
}
}
}
}
//===========================================================================//
// Method : LoadTraceRoutes_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::LoadTraceRoutes_(
const t_block* vpr_blockArray,
const t_rr_node* vpr_rrNodeArray,
const t_trace* pvpr_traceThis,
const t_trace* pvpr_tracePrev,
TNO_Route_t* proute,
TNO_RouteList_t* prouteList ) const
{
// Load current track node (ie. 'instPin' or 'segment'+'switchBox')
this->LoadTraceNodes_( vpr_blockArray, vpr_rrNodeArray,
pvpr_traceThis, pvpr_tracePrev, proute );
if( pvpr_traceThis->num_siblings == 0 )
{
// Reached terminal for the current route path
// (add route to route list and start unwinding recursion)
prouteList->Add( *proute );
}
else if( pvpr_traceThis->num_siblings == 1 )
{
// Apply recursion to update route based on next trace node
pvpr_tracePrev = pvpr_traceThis;
pvpr_traceThis = pvpr_traceThis->next;
this->LoadTraceRoutes_( vpr_blockArray, vpr_rrNodeArray,
pvpr_traceThis, pvpr_tracePrev,
proute, prouteList );
}
else if( pvpr_traceThis->num_siblings > 1 )
{
// Hande multiple routes based on split at this trace node
int index = pvpr_traceThis->index;
int num_siblings = pvpr_traceThis->num_siblings;
for( int i = 0; i < num_siblings; ++i )
{
// Find next trace node with matching index (if any)
pvpr_traceThis = this->FindTraceListNode_( pvpr_traceThis, index );
if( !pvpr_traceThis )
break;
// Make local route to handle multiple routes from this split
TNO_Route_t route( *proute );
// Apply recursion to update route based on next trace node
pvpr_tracePrev = pvpr_traceThis;
pvpr_traceThis = pvpr_traceThis->next;
this->LoadTraceRoutes_( vpr_blockArray, vpr_rrNodeArray,
pvpr_traceThis, pvpr_tracePrev,
&route, prouteList );
}
}
}
//===========================================================================//
// Method : LoadTraceNodes_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::LoadTraceNodes_(
const t_block* vpr_blockArray,
const t_rr_node* vpr_rrNodeArray,
const t_trace* pvpr_traceThis,
const t_trace* pvpr_tracePrev,
TNO_Route_t* proute ) const
{
// Decide if we are adding 'instPin' or 'segment'+'switchBox' route nodes
if( pvpr_traceThis->iblock != OPEN )
{
// Adding an 'instpin' route node based in block and port name
int blockIndex = pvpr_traceThis->iblock;
int nodeIndex = pvpr_traceThis->index;
const char* pszBlockName = vpr_blockArray[blockIndex].name;
const t_rr_node* vpr_rrGraph = vpr_blockArray[blockIndex].pb->rr_graph;
const t_rr_node& vpr_rrNode = vpr_rrGraph[nodeIndex];
const t_pb_graph_pin& vpr_graphPin = *vpr_rrNode.pb_graph_pin;
const char* pszParentName = vpr_graphPin.parent_node->pb_type->name;
int parentIndex = vpr_graphPin.parent_node->placement_index;
const char* pszPortName = vpr_graphPin.port->name;
int portIndex = vpr_graphPin.pin_number;
// Check if this route node is a PAD (ie. has capacity) and
// if the next route node is an OPIN (ie. does not have block index) or
// if the previous route node was an IPIN (ie. does not have block index)
// (if so, need to update this node's parent and port indices)
if( vpr_blockArray[blockIndex].type &&
vpr_blockArray[blockIndex].type->capacity > 1 )
{
int numPins = vpr_blockArray[blockIndex].type->num_pins;
int capacity = vpr_blockArray[blockIndex].type->capacity;
if(( pvpr_traceThis->next ) &&
( pvpr_traceThis->next->iblock == OPEN ))
{
int nextIndex = pvpr_traceThis->next->index;
int ptcNum = vpr_rrNodeArray[nextIndex].ptc_num;
parentIndex = ptcNum / ( numPins / capacity );
portIndex = ptcNum % ( numPins / capacity );
pszPortName = vpr_blockArray[blockIndex].type->pb_type->ports[portIndex].name;
}
else if(( pvpr_tracePrev ) &&
( pvpr_tracePrev->iblock == OPEN ))
{
int prevIndex = pvpr_tracePrev->index;
int ptcNum = vpr_rrNodeArray[prevIndex].ptc_num;
parentIndex = ptcNum / ( numPins / capacity );
portIndex = ptcNum % ( numPins / capacity );
pszPortName = vpr_blockArray[blockIndex].type->pb_type->ports[portIndex].name;
}
}
if( vpr_rrNode.type != SOURCE )
{
TNO_InstPin_c instPin( pszBlockName,
pszParentName, parentIndex,
pszPortName, portIndex );
TNO_Node_c node( instPin );
proute->Add( node );
}
}
else
{
int nodeIndexThis = pvpr_traceThis->index;
const t_rr_node& vpr_rrNodeThis = vpr_rrNodeArray[nodeIndexThis];
// First, need to consider adding a 'switchBox' route node
// (if prev/this nodes are either OPIN->CHANX|Y or CHANX|Y->CHANX|Y)
if( pvpr_tracePrev )
{
int nodeIndexPrev = pvpr_tracePrev->index;
const t_rr_node& vpr_rrNodePrev = vpr_rrNodeArray[nodeIndexPrev];
if((( vpr_rrNodePrev.type == CHANX ) || ( vpr_rrNodePrev.type == CHANY )) &&
(( vpr_rrNodeThis.type == CHANX ) || ( vpr_rrNodeThis.type == CHANY )))
{
int x, y;
this->FindSwitchBoxCoord_( vpr_rrNodePrev, vpr_rrNodeThis, &x, &y );
char szName[TIO_FORMAT_STRING_LEN_DATA];
sprintf( szName, "sb[%d][%d]", x, y );
TC_SideMode_t sidePrev = TC_SIDE_UNDEFINED;
TC_SideMode_t sideThis = TC_SIDE_UNDEFINED;
this->FindSwitchBoxSides_( vpr_rrNodePrev, vpr_rrNodeThis, &sidePrev, &sideThis );
size_t trackPrev = vpr_rrNodePrev.ptc_num;
size_t trackThis = vpr_rrNodeThis.ptc_num;
TNO_SwitchBox_c switchBox( szName, sidePrev, trackPrev, sideThis, trackThis );
TNO_Node_c node( switchBox );
proute->Add( node );
}
}
// Next, need to consider adding a 'segment' route node
if(( vpr_rrNodeThis.type == CHANX ) || ( vpr_rrNodeThis.type == CHANY ))
{
char szName[TIO_FORMAT_STRING_LEN_DATA];
if( vpr_rrNodeThis.type == CHANX )
{
sprintf( szName, "sh[%d].%d", vpr_rrNodeThis.ylow, vpr_rrNodeThis.ptc_num );
}
else // if( vpr_rrNodeThis.type == CHANY ))
{
sprintf( szName, "sv[%d].%d", vpr_rrNodeThis.xlow, vpr_rrNodeThis.ptc_num );
}
TGS_OrientMode_t orient( vpr_rrNodeThis.type == CHANX ?
TGS_ORIENT_HORIZONTAL : TGS_ORIENT_VERTICAL );
TGS_Region_c channel( vpr_rrNodeThis.xlow, vpr_rrNodeThis.ylow,
vpr_rrNodeThis.xhigh, vpr_rrNodeThis.yhigh );
unsigned int track = vpr_rrNodeThis.ptc_num;
TNO_Segment_c segment( szName, orient, channel, track );
TNO_Node_c node( segment );
proute->Add( node );
}
else if(( vpr_rrNodeThis.type == IPIN ) || ( vpr_rrNodeThis.type == OPIN ))
{
// No action needed for these cases
}
}
}
//===========================================================================//
// Method : FindModel_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
const t_model* TVPR_CircuitDesign_c::FindModel_(
const t_model* pvpr_models,
const char* pszModelName ) const
{
const t_model* pvpr_model = pvpr_models;
while( pvpr_model )
{
if( strcmp( pszModelName, pvpr_model->name ) == 0 )
break;
pvpr_model = pvpr_model->next;
}
return( pvpr_model );
}
//===========================================================================//
// Method : FindModelPort_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
const t_model_ports* TVPR_CircuitDesign_c::FindModelPort_(
const t_model* pvpr_model,
const char* pszPortName,
TC_TypeMode_t portType ) const
{
const t_model_ports* pvpr_port = 0;
switch( portType )
{
case TC_TYPE_OUTPUT: pvpr_port = pvpr_model->outputs; break;
case TC_TYPE_INPUT: pvpr_port = pvpr_model->inputs; break;
case TC_TYPE_CLOCK: pvpr_port = pvpr_model->inputs; break;
default: break;
}
while( pvpr_port )
{
if( strcmp( pvpr_port->name, pszPortName ) == 0 )
{
if( portType == TC_TYPE_OUTPUT )
{
break;
}
else if( portType == TC_TYPE_INPUT && !pvpr_port->is_clock )
{
break;
}
else if( portType == TC_TYPE_CLOCK && pvpr_port->is_clock )
{
break;
}
}
pvpr_port = pvpr_port->next;
}
return( pvpr_port );
}
//===========================================================================//
// Method : FindModelPortCount_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/25/12 jeffr : Original
//===========================================================================//
int TVPR_CircuitDesign_c::FindModelPortCount_(
const t_model* pvpr_model,
TC_TypeMode_t portType ) const
{
int portCount = 0;
const t_model_ports* pvpr_port = 0;
switch( portType )
{
case TC_TYPE_INPUT: pvpr_port = pvpr_model->inputs; break;
case TC_TYPE_OUTPUT: pvpr_port = pvpr_model->outputs; break;
default: break;
}
while( pvpr_port )
{
if( !pvpr_port->is_clock )
{
++portCount;
}
pvpr_port = pvpr_port->next;
}
return( portCount );
}
//===========================================================================//
// Method : FindGraphPin_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
const t_pb_graph_pin* TVPR_CircuitDesign_c::FindGraphPin_(
const t_logical_block* vpr_logicalBlockArray,
const t_vnet& vpr_net,
int nodeIndex ) const
{
const t_pb_graph_pin* pvpr_graphPin = 0;
const t_model_ports* pvpr_port = 0;
int blockIndex = vpr_net.pins[nodeIndex].block;
if( vpr_logicalBlockArray[blockIndex].pb )
{
int portIndex = vpr_net.pins[nodeIndex].block_port;
// [VPR] This net has been packed, hence pb_graph_pin does exist
if( nodeIndex > 0 )
{
// [VPR] This is an input or clock pin
if( !vpr_net.is_global )
{
for( pvpr_port = vpr_logicalBlockArray[blockIndex].model->inputs;
pvpr_port; pvpr_port = pvpr_port->next )
{
if( pvpr_port->is_clock )
continue;
if( pvpr_port->index == portIndex )
break;
}
}
else
{
for( pvpr_port = vpr_logicalBlockArray[blockIndex].model->inputs;
pvpr_port; pvpr_port = pvpr_port->next )
{
if( !pvpr_port->is_clock )
continue;
if( pvpr_port->index == portIndex )
break;
}
}
}
else
{
// [VPR] This is an output pin
for( pvpr_port = vpr_logicalBlockArray[blockIndex].model->outputs;
pvpr_port; pvpr_port = pvpr_port->next )
{
if( pvpr_port->index == portIndex )
break;
}
}
}
if( pvpr_port )
{
int pinIndex = vpr_net.pins[nodeIndex].block_pin;
const t_pb_graph_node* pvpr_graphNode = 0;
pvpr_graphNode = vpr_logicalBlockArray[blockIndex].pb->pb_graph_node;
pvpr_graphPin = this->FindGraphPin_( *pvpr_graphNode, pvpr_port, pinIndex );
}
return( pvpr_graphPin );
}
//===========================================================================//
const t_pb_graph_pin* TVPR_CircuitDesign_c::FindGraphPin_(
const t_pb_graph_node& vpr_graphNode,
const t_model_ports* pvpr_port,
int pinIndex ) const
{
const t_pb_graph_pin* pvpr_graphPin = 0;
if( pvpr_port->dir == IN_PORT )
{
if( !pvpr_port->is_clock )
{
for( int portIndex = 0; portIndex < vpr_graphNode.num_input_ports; ++portIndex )
{
if(( vpr_graphNode.input_pins[portIndex][0].port->model_port == pvpr_port ) &&
( vpr_graphNode.num_input_pins[portIndex] > pinIndex ))
{
pvpr_graphPin = &vpr_graphNode.input_pins[portIndex][pinIndex];
break;
}
}
}
else
{
for( int portIndex = 0; portIndex < vpr_graphNode.num_clock_ports; ++portIndex )
{
if(( vpr_graphNode.clock_pins[portIndex][0].port->model_port == pvpr_port ) &&
( vpr_graphNode.num_clock_pins[portIndex] > pinIndex ))
{
pvpr_graphPin = &vpr_graphNode.clock_pins[portIndex][pinIndex];
break;
}
}
}
}
else
{
for( int portIndex = 0; portIndex < vpr_graphNode.num_output_ports; ++portIndex )
{
if(( vpr_graphNode.output_pins[portIndex][0].port->model_port == pvpr_port ) &&
( vpr_graphNode.num_output_pins[portIndex] > pinIndex ))
{
pvpr_graphPin = &vpr_graphNode.output_pins[portIndex][pinIndex];
break;
}
}
}
return( pvpr_graphPin );
}
//===========================================================================//
// Method : FindTraceListLength_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
size_t TVPR_CircuitDesign_c::FindTraceListLength_(
const t_trace* pvpr_traceList ) const
{
size_t len = 0;
for( const t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
++len;
}
return( len );
}
//===========================================================================//
// Method : FindTraceListNode_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
const t_trace* TVPR_CircuitDesign_c::FindTraceListNode_(
const t_trace* pvpr_traceList,
int index ) const
{
const t_trace* pvpr_trace_ = 0;
for( const t_trace* pvpr_trace = pvpr_traceList;
pvpr_trace; pvpr_trace = pvpr_trace->next )
{
if( pvpr_trace->index == index )
{
pvpr_trace_ = pvpr_trace;
break;
}
}
return( pvpr_trace_ );
}
//===========================================================================//
// Method : FindSwitchBoxCoord_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::FindSwitchBoxCoord_(
const t_rr_node& vpr_rrNode1,
const t_rr_node& vpr_rrNode2,
int* px,
int* py ) const
{
TGS_Region_c region1( vpr_rrNode1.xlow, vpr_rrNode1.ylow,
vpr_rrNode1.xhigh, vpr_rrNode1.yhigh );
TGS_Region_c region2( vpr_rrNode2.xlow, vpr_rrNode2.ylow,
vpr_rrNode2.xhigh, vpr_rrNode2.yhigh );
TGS_Point_c point1, point2;
region1.FindNearest( region2, &point2, &point1 );
TGS_Region_c region( point1, point2 );
TGS_Point_c center = region.FindCenter( );
*px = static_cast< int >( center.x );
*py = static_cast< int >( center.y );
}
//===========================================================================//
// Method : FindSwitchBoxSides_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 10/05/12 jeffr : Original
//===========================================================================//
void TVPR_CircuitDesign_c::FindSwitchBoxSides_(
const t_rr_node& vpr_rrNode1,
const t_rr_node& vpr_rrNode2,
TC_SideMode_t* pside1,
TC_SideMode_t* pside2 ) const
{
if( vpr_rrNode1.type == CHANX )
{
*pside1 = ( vpr_rrNode1.direction == INC_DIRECTION ?
TC_SIDE_LEFT : TC_SIDE_RIGHT );
if( vpr_rrNode2.type == CHANX )
{
*pside2 = ( vpr_rrNode1.direction == INC_DIRECTION ?
TC_SIDE_RIGHT : TC_SIDE_LEFT );
}
else if( vpr_rrNode2.type == CHANY )
{
*pside2 = ( vpr_rrNode2.direction == INC_DIRECTION ?
TC_SIDE_UPPER : TC_SIDE_LOWER );
}
}
else if( vpr_rrNode1.type == CHANY )
{
*pside1 = ( vpr_rrNode1.direction == INC_DIRECTION ?
TC_SIDE_LOWER : TC_SIDE_UPPER );
if( vpr_rrNode2.type == CHANY )
{
*pside2 = ( vpr_rrNode1.direction == INC_DIRECTION ?
TC_SIDE_UPPER : TC_SIDE_LOWER );
}
else if( vpr_rrNode2.type == CHANX )
{
*pside2 = ( vpr_rrNode2.direction == INC_DIRECTION ?
TC_SIDE_RIGHT : TC_SIDE_LEFT );
}
}
}