blob: 99f5e78a85386ea15f69bc62bbf8a015d8b75b80 [file] [log] [blame] [edit]
//===========================================================================//
// Purpose : Method definitions for the TAS_ArchitectureSpec class.
//
// Public methods include:
// - TAS_ArchitectureSpec_c, ~TAS_ArchitectureSpec_c
// - operator=
// - operator==, operator!=
// - Print
// - PrintXML
// - InitDefaults
// - InitValidate
// - IsValid
//
// Private methods include:
// - InitDefaultsConfig_
// - InitDefaultsBlockHier_
// - InitDefaultsParentLinks_
// - InitDefaultsCellList_
// - InitValidateConfig_
// - InitValidatePhysicalBlockList_
// - InitValidatePhysicalBlock_
// - InitValidateModeList_
// - InitValidateMode_
// - InitValidatePinAssignList_
// - InitValidateGridAssignList_
// - InitValidateSegmentList_
// - InitValidateSegment_
// - InitValidateCellList_
// - InitValidateCell_
// - FindPhysicalBlockHier_
// - HasPhysicalBlockUsage_
//
//===========================================================================//
//---------------------------------------------------------------------------//
// 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 "TIO_PrintHandler.h"
#include "TAS_StringUtils.h"
#include "TAS_ArchitectureSpec.h"
//===========================================================================//
// Method : TAS_ArchitectureSpec_c
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
TAS_ArchitectureSpec_c::TAS_ArchitectureSpec_c(
void )
:
physicalBlockList( TAS_PHYSICAL_BLOCK_LIST_DEF_CAPACITY ),
modeList( TAS_MODE_LIST_DEF_CAPACITY ),
switchBoxList( TAS_SWITCH_BOX_LIST_DEF_CAPACITY ),
segmentList( TAS_SEGMENT_LIST_DEF_CAPACITY ),
carryChainList( TAS_CARRY_CHAIN_LIST_DEF_CAPACITY ),
cellList( TAS_CELL_LIST_DEF_CAPACITY )
{
this->sorted.physicalBlockList.SetCapacity( TAS_PHYSICAL_BLOCK_LIST_DEF_CAPACITY );
this->sorted.modeList.SetCapacity( TAS_MODE_LIST_DEF_CAPACITY );
this->sorted.switchBoxList.SetCapacity( TAS_SWITCH_BOX_LIST_DEF_CAPACITY );
}
//===========================================================================//
TAS_ArchitectureSpec_c::TAS_ArchitectureSpec_c(
const TAS_ArchitectureSpec_c& architectureSpec )
:
srName( architectureSpec.srName ),
config( architectureSpec.config ),
physicalBlockList( architectureSpec.physicalBlockList ),
modeList( architectureSpec.modeList ),
switchBoxList( architectureSpec.switchBoxList ),
segmentList( architectureSpec.segmentList ),
carryChainList( architectureSpec.carryChainList ),
cellList( architectureSpec.cellList )
{
this->sorted.physicalBlockList = architectureSpec.sorted.physicalBlockList;
this->sorted.modeList = architectureSpec.sorted.modeList;
this->sorted.switchBoxList = architectureSpec.sorted.switchBoxList;
}
//===========================================================================//
// Method : ~TAS_ArchitectureSpec_c
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
TAS_ArchitectureSpec_c::~TAS_ArchitectureSpec_c(
void )
{
}
//===========================================================================//
// Method : operator=
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
TAS_ArchitectureSpec_c& TAS_ArchitectureSpec_c::operator=(
const TAS_ArchitectureSpec_c& architectureSpec )
{
if( &architectureSpec != this )
{
this->srName = architectureSpec.srName;
this->config = architectureSpec.config;
this->physicalBlockList = architectureSpec.physicalBlockList;
this->modeList = architectureSpec.modeList;
this->switchBoxList = architectureSpec.switchBoxList;
this->segmentList = architectureSpec.segmentList;
this->carryChainList = architectureSpec.carryChainList;
this->cellList = architectureSpec.cellList;
this->sorted.physicalBlockList = architectureSpec.sorted.physicalBlockList;
this->sorted.modeList = architectureSpec.sorted.modeList;
this->sorted.switchBoxList = architectureSpec.sorted.switchBoxList;
}
return( *this );
}
//===========================================================================//
// Method : operator==
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::operator==(
const TAS_ArchitectureSpec_c& architectureSpec ) const
{
return(( this->srName == architectureSpec.srName ) &&
( this->config == architectureSpec.config ) &&
( this->physicalBlockList == architectureSpec.physicalBlockList ) &&
( this->modeList == architectureSpec.modeList ) &&
( this->switchBoxList == architectureSpec.switchBoxList ) &&
( this->segmentList == architectureSpec.segmentList ) &&
( this->carryChainList == architectureSpec.carryChainList ) &&
( this->cellList == architectureSpec.cellList ) ?
true : false );
}
//===========================================================================//
// Method : operator!=
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::operator!=(
const TAS_ArchitectureSpec_c& architectureSpec ) const
{
return( !this->operator==( architectureSpec ) ? true : false );
}
//===========================================================================//
// Method : Print
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
// 07/10/13 jeffr : Added support for processing carry chain list
//===========================================================================//
void TAS_ArchitectureSpec_c::Print(
FILE* pfile,
size_t spaceLen ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
printHandler.Write( pfile, spaceLen, "<architecture name=\"%s\">\n",
TIO_SR_STR( this->srName ));
spaceLen += 3;
printHandler.Write( pfile, spaceLen, "\n" );
this->config.Print( pfile, spaceLen );
if( this->physicalBlockList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "\n" );
TAS_ModeList_t modeList_;
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
if( this->physicalBlockList[i]->GetUsage( ) == TAS_USAGE_INPUT_OUTPUT )
{
this->physicalBlockList[i]->Print( pfile, spaceLen,
0, &modeList_ );
}
}
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
if( this->physicalBlockList[i]->GetUsage( ) == TAS_USAGE_PHYSICAL_BLOCK )
{
this->physicalBlockList[i]->Print( pfile, spaceLen,
0, &modeList_ );
}
}
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
if(( this->physicalBlockList[i]->GetUsage( ) != TAS_USAGE_INPUT_OUTPUT ) &&
( this->physicalBlockList[i]->GetUsage( ) != TAS_USAGE_PHYSICAL_BLOCK ))
{
this->physicalBlockList[i]->Print( pfile, spaceLen,
0, &modeList_ );
}
}
}
if( this->switchBoxList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "\n" );
this->switchBoxList.Print( pfile, spaceLen );
}
if( this->segmentList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "\n" );
this->segmentList.Print( pfile, spaceLen );
}
if( this->carryChainList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "\n" );
this->carryChainList.Print( pfile, spaceLen );
}
if( this->cellList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "\n" );
for( size_t i = 0; i < this->cellList.GetLength( ); ++i )
{
if( this->cellList[i]->GetSource( ) == TLO_CELL_SOURCE_STANDARD )
continue;
this->cellList[i]->Print( pfile, spaceLen );
}
}
spaceLen -= 3;
printHandler.Write( pfile, spaceLen, "</architecture>\n" );
}
//===========================================================================//
// Method : PrintXML
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
void TAS_ArchitectureSpec_c::PrintXML(
void ) const
{
FILE* pfile = 0;
size_t spaceLen = 0;
this->PrintXML( pfile, spaceLen );
}
//===========================================================================//
void TAS_ArchitectureSpec_c::PrintXML(
FILE* pfile,
size_t spaceLen ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
printHandler.Write( pfile, spaceLen, "<architecture>\n" );
spaceLen += 3;
if( this->config.IsValid( ))
{
this->config.PrintXML( pfile, spaceLen );
}
if( this->cellList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "<models>\n" );
for( size_t i = 0; i < this->cellList.GetLength( ); ++i )
{
if( this->cellList[i]->GetSource( ) == TLO_CELL_SOURCE_STANDARD )
continue;
this->cellList[i]->PrintXML( pfile, spaceLen + 3 );
}
printHandler.Write( pfile, spaceLen, "</models>\n" );
}
if( this->physicalBlockList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "<complexblocklist>\n" );
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
this->physicalBlockList[i]->PrintXML( pfile, spaceLen + 3 );
}
printHandler.Write( pfile, spaceLen, "</complexblocklist>\n" );
}
if( this->switchBoxList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "<switchlist>\n" );
for( size_t i = 0; i < this->switchBoxList.GetLength( ); ++i )
{
this->switchBoxList[i]->PrintXML( pfile, spaceLen + 3 );
}
printHandler.Write( pfile, spaceLen, "</switchlist>\n" );
}
if( this->segmentList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "<segmentlist>\n" );
for( size_t i = 0; i < this->segmentList.GetLength( ); ++i )
{
this->segmentList[i]->PrintXML( pfile, spaceLen + 3 );
}
printHandler.Write( pfile, spaceLen, "</segmentlist>\n" );
}
if( this->carryChainList.IsValid( ))
{
printHandler.Write( pfile, spaceLen, "<directlist>\n" );
for( size_t i = 0; i < this->carryChainList.GetLength( ); ++i )
{
this->carryChainList[i]->PrintXML( pfile, spaceLen + 3 );
}
printHandler.Write( pfile, spaceLen, "</directlist>\n" );
}
spaceLen -= 3;
printHandler.Write( pfile, spaceLen, "</architecture>\n" );
}
//===========================================================================//
// Method : InitDefaults
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitDefaults(
void )
{
bool ok = true;
// Set configuration defaults
this->InitDefaultsConfig_( &this->config );
// Initialize all physical block hierachical links, if needed (non-XML)
ok = this->InitDefaultsBlockHier_( );
if( ok )
{
// Initialize all physical block and mode parent pointers
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
this->InitDefaultsParentLinks_( this->physicalBlockList[i], 0, 0 );
}
// Add cell list defaults
this->InitDefaultsCellList_( &this->cellList );
}
return( ok );
}
//===========================================================================//
// Method : InitValidate
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidate(
void )
{
bool ok = true;
if( ok )
{
ok = this->InitValidateConfig_( );
}
if( ok )
{
this->sorted.physicalBlockList.SetCapacity( this->physicalBlockList.GetCapacity( ));
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
this->sorted.physicalBlockList.Add( *this->physicalBlockList[i] );
}
// Validate unique physical block list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = this->sorted.physicalBlockList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"pb_type list" );
}
if( ok )
{
ok = this->InitValidatePhysicalBlockList_( &this->physicalBlockList,
this->cellList, 0 );
}
if( ok )
{
this->sorted.modeList.SetCapacity( this->modeList.GetCapacity( ));
for( size_t i = 0; i < this->modeList.GetLength( ); ++i )
{
this->sorted.modeList.Add( *this->modeList[i] );
}
// Validate unique mode list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = this->sorted.modeList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"mode list" );
}
if( ok )
{
this->sorted.switchBoxList.SetCapacity( this->switchBoxList.GetCapacity( ));
for( size_t i = 0; i < this->switchBoxList.GetLength( ); ++i )
{
this->sorted.switchBoxList.Add( *this->switchBoxList[i] );
}
// Validate unique switch box list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = this->sorted.switchBoxList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"switch box list" );
}
if( ok )
{
ok = this->InitValidateSegmentList_( this->segmentList,
this->sorted.switchBoxList );
}
if( ok )
{
ok = this->InitValidateCellList_( this->cellList );
}
return( ok );
}
//===========================================================================//
// Method : IsValid
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::IsValid(
void ) const
{
return(( this->physicalBlockList.IsValid( )) ||
( this->modeList.IsValid( )) ||
( this->switchBoxList.IsValid( )) ||
( this->segmentList.IsValid( )) ||
( this->carryChainList.IsValid( )) ||
( this->cellList.IsValid( )) ?
true : false );
}
//===========================================================================//
// Method : InitDefaultsConfig_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
void TAS_ArchitectureSpec_c::InitDefaultsConfig_(
TAS_Config_c* pconfig ) const
{
// Set configuration defaults
// (ie. hard-coded switch box default parameters based on the VPR tool)
if( pconfig->device.switchBoxes.modelType == TAS_SWITCH_BOX_MODEL_UNDEFINED )
{
pconfig->device.switchBoxes.modelType = TAS_SWITCH_BOX_MODEL_WILTON;
}
if( pconfig->device.switchBoxes.fs == 0 )
{
pconfig->device.switchBoxes.fs = 3;
}
// Set channel distribution width defaults (for non-XML interface)
if( pconfig->device.channelWidth.io.usageMode == TAS_CHANNEL_USAGE_UNDEFINED )
{
pconfig->device.channelWidth.io.usageMode = TAS_CHANNEL_USAGE_IO;
pconfig->device.channelWidth.io.width = 1.0;
}
if( pconfig->device.channelWidth.x.usageMode == TAS_CHANNEL_USAGE_UNDEFINED )
{
pconfig->device.channelWidth.x.usageMode = TAS_CHANNEL_USAGE_X;
pconfig->device.channelWidth.x.distrMode = TAS_CHANNEL_DISTR_UNIFORM;
pconfig->device.channelWidth.x.peak = 1.0;
}
if( pconfig->device.channelWidth.y.usageMode == TAS_CHANNEL_USAGE_UNDEFINED )
{
pconfig->device.channelWidth.y.usageMode = TAS_CHANNEL_USAGE_Y;
pconfig->device.channelWidth.y.distrMode = TAS_CHANNEL_DISTR_UNIFORM;
pconfig->device.channelWidth.y.peak = 1.0;
}
// Set layour auto size aspect ratio (for non-XML interface)
if( pconfig->layout.sizeMode == TAS_ARRAY_SIZE_UNDEFINED )
{
pconfig->layout.sizeMode = TAS_ARRAY_SIZE_AUTO;
pconfig->layout.autoSize.aspectRatio = 1.0;
}
}
//===========================================================================//
// Method : InitDefaultsBlockHier_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 08/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitDefaultsBlockHier_(
void )
{
bool ok = true;
if( this->HasPhysicalBlockUsage_( ))
{
TAS_PhysicalBlockList_t physicalBlockList_ = this->physicalBlockList;
this->physicalBlockList.Clear( );
// Iterate local list as long as list has at least one more element
while( physicalBlockList_.IsValid( ))
{
// Get 1st (ie. next) physical block and delete from list
const TAS_PhysicalBlock_c& physicalBlock = *physicalBlockList_[0];
TAS_PhysicalBlock_c* pphysicalBlock = 0;
if( !this->FindPhysicalBlockHier_( this->physicalBlockList, physicalBlock ))
{
pphysicalBlock = this->physicalBlockList.Add( physicalBlock );
}
physicalBlockList_.Delete( 0 );
// Recursively iterate to add mode and physical block hierarchy
if( pphysicalBlock )
{
ok = this->InitDefaultsBlockHier_( &physicalBlockList_, pphysicalBlock );
if( !ok )
break;
}
}
}
return( ok );
}
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitDefaultsBlockHier_(
TAS_PhysicalBlockList_t* pphysicalBlockList,
TAS_PhysicalBlock_c* pphysicalBlock )
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
TAS_ModeNameList_t modeNameList = pphysicalBlock->modeNameList;
pphysicalBlock->modeNameList.Clear( );
for( size_t i = 0; i < modeNameList.GetLength( ); ++i )
{
const TC_Name_c& modeName = *modeNameList[i];
TAS_Mode_c mode;
if( this->modeList.Find( modeName.GetName( ), &mode ))
{
TAS_Mode_c* pmode_ = pphysicalBlock->modeList.Add( mode );
for( size_t j = 0; j < pmode_->physicalBlockList.GetLength( ); ++j )
{
TAS_PhysicalBlock_c* pphysicalBlock_ = pmode_->physicalBlockList[j];
TAS_PhysicalBlock_c physicalBlock;
if( pphysicalBlockList->Find( *pphysicalBlock_, &physicalBlock ))
{
pphysicalBlockList->Delete( physicalBlock );
pphysicalBlock_ = pmode_->physicalBlockList.Replace( physicalBlock );
ok = InitDefaultsBlockHier_( pphysicalBlockList, pphysicalBlock_ );
if( !ok )
break;
}
else
{
ok = printHandler.Error( "Invalid architecture specification!\n"
"%sMissing physical block \"%s\" for mode \"%s\"\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PSZ_STR( pphysicalBlock->GetName( )),
TIO_PSZ_STR( pmode_->GetName( )));
if( !ok )
break;
}
}
}
else
{
ok = printHandler.Error( "Invalid architecture specification!\n"
"%sMissing mode \"%s\" for physical block \"%s\"\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PSZ_STR( modeName.GetName( )),
TIO_PSZ_STR( pphysicalBlock->GetName( )));
if( !ok )
break;
}
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : InitDefaultsParentLinks_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
void TAS_ArchitectureSpec_c::InitDefaultsParentLinks_(
TAS_PhysicalBlock_c* pphysicalBlock,
const TAS_PhysicalBlock_c* pphysicalBlockParent,
const TAS_Mode_c* pmodeParent ) const
{
// Initialize links to parent (either physical block or mode)
pphysicalBlock->SetPhysicalBlockParent( pphysicalBlockParent );
pphysicalBlock->SetModeParent( pmodeParent );
// Apply recursion to initialize children to this physical block
for( size_t i = 0; i < pphysicalBlock->physicalBlockList.GetLength( ); ++i )
{
this->InitDefaultsParentLinks_( pphysicalBlock->physicalBlockList[i],
pphysicalBlock, 0 );
}
for( size_t i = 0; i < pphysicalBlock->modeList.GetLength( ); ++i )
{
this->InitDefaultsParentLinks_( pphysicalBlock->modeList[i],
pphysicalBlock );
}
}
//===========================================================================//
void TAS_ArchitectureSpec_c::InitDefaultsParentLinks_(
TAS_Mode_c* pmode,
const TAS_PhysicalBlock_c* pphysicalBlockParent ) const
{
// Initialize links to parent (either physical block or mode)
pmode->SetPhysicalBlockParent( pphysicalBlockParent );
// Apply recursion to initialize children to this physical block
for( size_t i = 0; i < pmode->physicalBlockList.GetLength( ); ++i )
{
this->InitDefaultsParentLinks_( pmode->physicalBlockList[i],
0, pmode );
}
}
//===========================================================================//
// Method : InitDefaultsCellList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
void TAS_ArchitectureSpec_c::InitDefaultsCellList_(
TAS_CellList_t* pcellList ) const
{
// Add cell list defaults
// (ie. hard-coded BLIF cells parameters based on the VPR tool)
TAS_Cell_c inputCell( "input", TLO_CELL_SOURCE_STANDARD );
inputCell.AddPort( "inpad", TC_TYPE_OUTPUT );
TAS_Cell_c outputCell( "output", TLO_CELL_SOURCE_STANDARD );
outputCell.AddPort( "outpad", TC_TYPE_INPUT );
TAS_Cell_c flipflopCell( "latch", TLO_CELL_SOURCE_STANDARD );
flipflopCell.AddPort( "D", TC_TYPE_INPUT );
flipflopCell.AddPort( "clk", TC_TYPE_CLOCK );
flipflopCell.AddPort( "Q", TC_TYPE_OUTPUT );
TAS_Cell_c lutCell( "names", TLO_CELL_SOURCE_STANDARD );
lutCell.AddPort( "in", TC_TYPE_INPUT );
lutCell.AddPort( "out", TC_TYPE_OUTPUT );
pcellList->Add( inputCell );
pcellList->Add( outputCell );
pcellList->Add( flipflopCell );
pcellList->Add( lutCell );
}
//===========================================================================//
// Method : InitValidateConfig_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateConfig_(
void )
{
TC_MinGrid_c& MinGrid = TC_MinGrid_c::GetInstance( );
unsigned int precision = MinGrid.GetPrecision( );
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
if( ok && this->IsValid( ))
{
if( TCTF_IsGT( this->config.layout.autoSize.aspectRatio, 0.0 ) &&
this->config.layout.manualSize.gridDims.IsValid( ))
{
ok = printHandler.Warning( "Ignoring conflicting layout auto=\"%0.*f\", width=\"%u\", and height=\"%u\" parameters.\n"
"%sValid parameters limited to either \"auto\" or \"width\" and \"height\" values.\n"
"%sDefaulting to auto=\"%0.*f\".\n",
precision, this->config.layout.autoSize.aspectRatio,
this->config.layout.manualSize.gridDims.dx,
this->config.layout.manualSize.gridDims.dy,
TIO_PREFIX_WARNING_SPACE,
TIO_PREFIX_WARNING_SPACE,
precision, this->config.layout.autoSize.aspectRatio );
this->config.layout.manualSize.gridDims.Reset( );
}
}
if( ok && this->IsValid( ))
{
if( TCTF_IsLT( this->config.layout.autoSize.aspectRatio, 0.0 ))
{
ok = printHandler.Warning( "Ignoring invalid layout auto=\"%0.*f\" parameter.\n"
"%sValid aspect ratio must be greater than zero.\n"
"%sUsing \"auto\" default.\n",
precision, this->config.layout.autoSize.aspectRatio,
TIO_PREFIX_WARNING_SPACE,
TIO_PREFIX_WARNING_SPACE );
this->config.layout.autoSize.aspectRatio = 0.0;
}
}
if( ok && this->IsValid( ))
{
if( !this->config.device.channelWidth.io.IsValid( ) ||
TCTF_IsEQ( this->config.device.channelWidth.io.width, 0.0 ))
{
ok = printHandler.Error( "Missing or invalid channel width distribution!\n"
"%sExpected <io width=\"...\"/>\n",
TIO_PREFIX_ERROR_SPACE );
}
}
if( ok && this->IsValid( ))
{
if( !this->config.device.channelWidth.x.IsValid( ) ||
this->config.device.channelWidth.x.distrMode == TAS_CHANNEL_DISTR_UNDEFINED )
{
ok = printHandler.Error( "Missing or invalid channel width distribution!\n"
"%sExpected <x distr=\"...\"/>\n",
TIO_PREFIX_ERROR_SPACE );
}
}
if( ok && this->IsValid( ))
{
if( !this->config.device.channelWidth.y.IsValid( ) ||
this->config.device.channelWidth.y.distrMode == TAS_CHANNEL_DISTR_UNDEFINED )
{
ok = printHandler.Error( "Missing or invalid channel width distribution!\n"
"%sExpected <y distr=\"...\"/>\n",
TIO_PREFIX_ERROR_SPACE );
}
}
return( ok );
}
//===========================================================================//
// Method : InitValidatePhysicalBlockList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidatePhysicalBlockList_(
TAS_PhysicalBlockList_t* pphysicalBlockList,
const TAS_CellList_t& cellList_,
size_t hierarchyLevel ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
// Validate each physical block (recursively)
bool ok = true;
for( size_t i = 0; i < pphysicalBlockList->GetLength( ); ++i )
{
ok = this->InitValidatePhysicalBlock_(( *pphysicalBlockList )[i],
cellList_,
hierarchyLevel + 1 );
if( !ok )
break;
}
if( ok && pphysicalBlockList->IsValid( ) && ( hierarchyLevel == 0 ))
{
if( !this->sorted.physicalBlockList.IsMember( "io" ))
{
ok = printHandler.Error( "Invalid physical block list!\n"
"%sNo \"io\" physical block defined\n",
TIO_PREFIX_ERROR_SPACE );
}
}
if( ok && pphysicalBlockList->IsValid( ) && ( hierarchyLevel == 0 ))
{
bool isGridFillDefined = false;
for( size_t i = 0; i < pphysicalBlockList->GetLength( ); ++i )
{
const TAS_PhysicalBlock_c& physicalBlock = *( *pphysicalBlockList )[i];
const TAS_GridAssignList_t& gridAssignList = physicalBlock.gridAssignList;
for( size_t j = 0; j < gridAssignList.GetLength( ); ++j )
{
const TAS_GridAssign_c& gridAssign = *gridAssignList[j];
if( gridAssign.distr == TAS_GRID_ASSIGN_DISTR_FILL )
{
isGridFillDefined = true;
}
}
}
if( !isGridFillDefined )
{
ok = printHandler.Error( "Invalid physical block list!\n"
"%sNo grid <loc type=\"fill\".../> detected\n",
TIO_PREFIX_ERROR_SPACE );
}
}
return( ok );
}
//===========================================================================//
// Method : InitValidatePhysicalBlock_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidatePhysicalBlock_(
TAS_PhysicalBlock_c* pphysicalBlock,
const TAS_CellList_t& cellList_,
size_t hierarchyLevel ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
if( ok )
{
// Validate physical block "custom" BLIF model defined in by circuit ".subckt" cell
if(( pphysicalBlock->modelType == TAS_PHYSICAL_BLOCK_MODEL_CUSTOM ) &&
( !cellList_.IsMember( pphysicalBlock->srModelName )))
{
ok = printHandler.Error( "Invalid physical BLIF model name detected!\n"
"%sModel name not found in circuit '.subckt' list\n"
"%sSee <pb_type name=\"%s\" blif_model=\".subckt %s\">\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( pphysicalBlock->srName ),
TIO_SR_STR( pphysicalBlock->srModelName ));
}
}
if( ok )
{
pphysicalBlock->sorted.modeList.SetCapacity( pphysicalBlock->modeList.GetCapacity( ));
for( size_t i = 0; i < pphysicalBlock->modeList.GetLength( ); ++i )
{
pphysicalBlock->sorted.modeList.Add( *pphysicalBlock->modeList[i] );
}
// Validate unique mode list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = pphysicalBlock->sorted.modeList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"mode list" );
}
if( ok )
{
pphysicalBlock->sorted.physicalBlockList.SetCapacity( pphysicalBlock->physicalBlockList.GetCapacity( ));
for( size_t i = 0; i < pphysicalBlock->physicalBlockList.GetLength( ); ++i )
{
pphysicalBlock->sorted.physicalBlockList.Add( *pphysicalBlock->physicalBlockList[i] );
}
// Validate unique physical block list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = pphysicalBlock->sorted.physicalBlockList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"pb_type list" );
}
if( ok )
{
// Validate each physical block (recursively)
ok = this->InitValidatePhysicalBlockList_( &pphysicalBlock->physicalBlockList,
cellList_,
hierarchyLevel );
}
if( ok )
{
// Validate unique mode list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = pphysicalBlock->sorted.modeList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"mode list" );
}
if( ok )
{
ok = this->InitValidateModeList_( &pphysicalBlock->modeList,
cellList_,
hierarchyLevel );
}
if( ok )
{
if(( pphysicalBlock->fcOut.type != pphysicalBlock->fcIn.type ) &&
( pphysicalBlock->fcOut.type != TAS_CONNECTION_BOX_FULL ))
{
string srFcInType, srFcOutType;
TAS_ExtractStringConnectionBoxType( pphysicalBlock->fcIn.type, &srFcInType );
TAS_ExtractStringConnectionBoxType( pphysicalBlock->fcOut.type, &srFcOutType );
ok = printHandler.Error( "Invalid physical block Fc_in and Fc_out types!\n"
"%sFc types must match unless FC_out is \"full\"\n"
"%sSee: <fc_in type=\"%s\">...</fc_in>\n"
"%sSee: <fc_out type=\"%s\">...</fc_out>\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( srFcInType ),
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( srFcOutType ));
}
}
if( ok )
{
ok = this->InitValidatePinAssignList_( pphysicalBlock->pinAssignList,
pphysicalBlock->height );
}
if( ok )
{
ok = this->InitValidateGridAssignList_( pphysicalBlock->gridAssignList );
}
// TBD - <delay_matrix type="max" in_port="string" out_port="string"/> matrix </delay>
// TBD - // Validate: matrix (input) #of rows assumed
// TBD - // Validate: matrix (input) #of rows == #of pins asso. with input port
// TBD - // Validate: matrix (input) #of columns == #of pins asso. with output port
return( ok );
}
//===========================================================================//
// Method : InitValidateModeList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateModeList_(
TAS_ModeList_t* pmodeList_,
const TAS_CellList_t& cellList_,
size_t hierarchyLevel ) const
{
bool ok = true;
for( size_t i = 0; i < pmodeList_->GetLength( ); ++i )
{
ok = this->InitValidateMode_(( *pmodeList_ )[i],
cellList_,
hierarchyLevel + 1 );
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : InitValidateMode_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateMode_(
TAS_Mode_c* pmode,
const TAS_CellList_t& cellList_,
size_t hierarchyLevel ) const
{
bool ok = true;
if( ok )
{
pmode->sorted.physicalBlockList.SetCapacity( pmode->physicalBlockList.GetCapacity( ));
for( size_t i = 0; i < pmode->physicalBlockList.GetLength( ); ++i )
{
pmode->sorted.physicalBlockList.Add( *pmode->physicalBlockList[i] );
}
// Validate unique physical block list names
bool uniquifyShowWarning = true;
bool uniquifyShowError = false;
ok = pmode->sorted.physicalBlockList.Uniquify( uniquifyShowWarning, uniquifyShowError,
"pb_type list" );
}
if( ok )
{
// Validate each physical block (recursively)
for( size_t i = 0; i < pmode->physicalBlockList.GetLength( ); ++i )
{
ok = this->InitValidatePhysicalBlock_( pmode->physicalBlockList[i],
cellList_,
hierarchyLevel );
if( !ok )
break;
}
}
return( ok );
}
//===========================================================================//
// Method : InitValidatePinAssignList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidatePinAssignList_(
const TAS_PinAssignList_t& pinAssignList,
unsigned int height ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
// Validate physical block pin assignment offset < height
if( height > 0 )
{
for( size_t j = 0; j < pinAssignList.GetLength( ); ++j )
{
const TAS_PinAssign_c& pinAssign = *pinAssignList[j];
if( pinAssign.pattern != TAS_PIN_ASSIGN_PATTERN_CUSTOM )
continue;
if( pinAssign.offset == 0 )
continue;
if( pinAssign.offset >= height )
{
ok = printHandler.Error( "Invalid physical block pin location \"custom\" pattern detected!\n"
"%sPin location offset (%u) >= height (%u)\n",
TIO_PREFIX_ERROR_SPACE,
pinAssign.offset,
height );
if( !ok )
break;
}
if( pinAssign.side == TC_SIDE_UPPER &&
pinAssign.offset != height - 1 )
{
ok = printHandler.Error( "Invalid physical block pin location \"custom\" pattern detected!\n"
"%sPin location side \"top\" offset (%u) != height - 1 (%u)\n",
TIO_PREFIX_ERROR_SPACE,
pinAssign.offset,
height - 1 );
if( !ok )
break;
}
if( pinAssign.side == TC_SIDE_LOWER )
{
ok = printHandler.Error( "Invalid physical block pin location \"custom\" pattern detected!\n"
"%sPin location side \"bottom\" offset (%u) != 0\n",
TIO_PREFIX_ERROR_SPACE,
pinAssign.offset );
if( !ok )
break;
}
}
}
return( ok );
}
//===========================================================================//
// Method : InitValidateGridAssignList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateGridAssignList_(
const TAS_GridAssignList_t& gridAssignList ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
size_t fillCount = 0;
size_t perimeterCount = 0;
for( size_t i = 0; i < gridAssignList.GetLength( ); ++i )
{
const TAS_GridAssign_c& gridAssign = *gridAssignList[i];
switch( gridAssign.distr )
{
case TAS_GRID_ASSIGN_DISTR_SINGLE:
if( gridAssign.singlePercent == 0 )
{
ok = printHandler.Error( "Missing physical block grid location property!\n"
"%sGrid location type \"rel\" must include a 'pos' value\n",
TIO_PREFIX_ERROR_SPACE );
}
break;
case TAS_GRID_ASSIGN_DISTR_MULTIPLE:
if( gridAssign.multipleStart == 0 )
{
ok = printHandler.Error( "Missing physical block grid location property!\n"
"%sGrid location type \"col\" must include a 'start' value\n",
TIO_PREFIX_ERROR_SPACE );
}
if( gridAssign.multipleRepeat == 0 )
{
ok = printHandler.Error( "Missing physical block grid location property!\n"
"%sGrid location type \"col\" must include a 'repeat' value\n",
TIO_PREFIX_ERROR_SPACE );
}
break;
case TAS_GRID_ASSIGN_DISTR_FILL:
++fillCount;
break;
case TAS_GRID_ASSIGN_DISTR_PERIMETER:
++perimeterCount;
break;
case TAS_GRID_ASSIGN_DISTR_UNDEFINED:
break;
}
if( !ok )
break;
}
if( ok && ( fillCount > 1 ))
{
ok = printHandler.Error( "Invalid physical block grid location type!\n"
"%sGrid location type \"fill\" defined more than once\n",
TIO_PREFIX_ERROR_SPACE );
}
if( ok && ( perimeterCount > 1 ))
{
ok = printHandler.Error( "Invalid physical block grid location type!\n"
"%sGrid location type \"perimeter\" defined more than once\n",
TIO_PREFIX_ERROR_SPACE );
}
return( ok );
}
//===========================================================================//
// Method : InitValidateSegmentList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateSegmentList_(
const TAS_SegmentList_t& segmentList_,
const TAS_SwitchBoxSortedList_t& switchBoxSortedList_ ) const
{
// Validate each segment
bool ok = true;
for( size_t i = 0; i < segmentList_.GetLength( ); ++i )
{
ok = this->InitValidateSegment_( *segmentList_[i],
switchBoxSortedList_ );
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : InitValidateSegment_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateSegment_(
const TAS_Segment_c& segment,
const TAS_SwitchBoxSortedList_t& switchBoxSortedList_ ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
if( ok )
{
// Validate segment mux name matches switch box based on multiplexor type
if(( segment.dirType == TAS_SEGMENT_DIR_UNIDIRECTIONAL ) &&
( !segment.srMuxSwitchName.length( )))
{
ok = printHandler.Error( "Missing segment mux switch name!\n"
"%sExpected <mux name=\"...\"/> when type=\"unidir\"\n",
TIO_PREFIX_ERROR_SPACE );
}
if(( segment.srMuxSwitchName.length( )) &&
( !switchBoxSortedList_.Find( segment.srMuxSwitchName )))
{
ok = printHandler.Error( "Invalid segment mux switch name detected!\n"
"%sNo matching name found in switch box list\n"
"%sSee: <mux name=\"%s\"/>\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( segment.srMuxSwitchName ));
}
}
if( ok )
{
// Validate segment wire switch name matches switch box based on buffer type
if(( segment.dirType == TAS_SEGMENT_DIR_BIDIRECTIONAL ) &&
( !segment.srWireSwitchName.length( )))
{
ok = printHandler.Error( "Missing segment wire switch name!\n"
"%sExpected <wire name=\"...\"/> when type=\"bidir\"\n",
TIO_PREFIX_ERROR_SPACE );
}
if(( segment.srWireSwitchName.length( )) &&
( !switchBoxSortedList_.Find( segment.srWireSwitchName )))
{
ok = printHandler.Error( "Invalid segment wire switch name detected!\n"
"%sNo matching name found in switch box list\n"
"%sSee: <wire_switch name=\"%s\"/>\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( segment.srWireSwitchName ));
}
}
if( ok )
{
// Validate segment output switch name matches switch box based on buffer type
if(( segment.dirType == TAS_SEGMENT_DIR_BIDIRECTIONAL ) &&
( !segment.srOutputSwitchName.length( )))
{
ok = printHandler.Error( "Missing segment output switch name!\n"
"%sExpected <opin name=\"...\"/> when type=\"bidir\"\n",
TIO_PREFIX_ERROR_SPACE );
}
if(( segment.srOutputSwitchName.length( )) &&
( !switchBoxSortedList_.Find( segment.srOutputSwitchName )))
{
ok = printHandler.Error( "Invalid segment output switch name detected!\n"
"%sNo matching name found in switch box list\n"
"%sSee: <opin_switch name=\"%s\"/>\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PREFIX_ERROR_SPACE,
TIO_SR_STR( segment.srOutputSwitchName ));
}
}
return( ok );
}
//===========================================================================//
// Method : InitValidateCellList_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateCellList_(
const TAS_CellList_t& cellList_ ) const
{
// Validate each cell
bool ok = true;
for( size_t i = 0; i < cellList_.GetLength( ); ++i )
{
if( cellList_[i]->GetSource( ) == TLO_CELL_SOURCE_STANDARD )
continue;
ok = this->InitValidateCell_( *cellList_[i] );
if( !ok )
break;
}
return( ok );
}
//===========================================================================//
// Method : InitValidateCell_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::InitValidateCell_(
const TAS_Cell_c& cell ) const
{
TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( );
bool ok = true;
size_t inputCount = 0;
size_t outputCount = 0;
const TLO_PortList_t& portList = cell.GetPortList( );
for( size_t i = 0; i < portList.GetLength( ); ++i )
{
const TLO_Port_c& port = *portList[i];
inputCount += (( port.GetType( ) == TC_TYPE_INPUT ) ? 1 : 0 );
outputCount += (( port.GetType( ) == TC_TYPE_OUTPUT ) ? 1 : 0 );
}
if( ok && !inputCount )
{
ok = printHandler.Error( "Invalid model cell detected!\n"
"%sNo input ports defined for model \"%s\"\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PSZ_STR( cell.GetName( )));
}
if( ok && !outputCount )
{
ok = printHandler.Error( "Invalid model cell detected!\n"
"%sNo output ports defined for model \"%s\"\n",
TIO_PREFIX_ERROR_SPACE,
TIO_PSZ_STR( cell.GetName( )));
}
return( ok );
}
//===========================================================================//
// Method : FindPhysicalBlockHier_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/24/13 jeffr : Original
//===========================================================================//
TAS_PhysicalBlock_c* TAS_ArchitectureSpec_c::FindPhysicalBlockHier_(
const TAS_PhysicalBlockList_t& physicalBlockList,
const TAS_PhysicalBlock_c& physicalBlock ) const
{
TAS_PhysicalBlock_c* pfoundBlock = 0;
for( size_t i = 0; i < physicalBlockList.GetLength( ); ++i )
{
TAS_PhysicalBlock_c* pphysicalBlock = physicalBlockList[i];
if( physicalBlock == *pphysicalBlock )
{
pfoundBlock = pphysicalBlock;
break;
}
else
{
for( size_t j = 0; j < pphysicalBlock->modeList.GetLength( ); ++j )
{
const TAS_Mode_c mode = *pphysicalBlock->modeList[j];
pfoundBlock = this->FindPhysicalBlockHier_( mode.physicalBlockList,
physicalBlock );
if( pfoundBlock )
break;
}
if( pfoundBlock )
break;
pfoundBlock = this->FindPhysicalBlockHier_( pphysicalBlock->physicalBlockList,
physicalBlock );
if( pfoundBlock )
break;
}
}
return( pfoundBlock );
}
//===========================================================================//
// Method : HasPhysicalBlockUsage_
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 08/15/12 jeffr : Original
//===========================================================================//
bool TAS_ArchitectureSpec_c::HasPhysicalBlockUsage_(
void ) const
{
bool hasUsage = false;
for( size_t i = 0; i < this->physicalBlockList.GetLength( ); ++i )
{
const TAS_PhysicalBlock_c& physicalBlock = *this->physicalBlockList[i];
if( physicalBlock.GetUsage( ) != TAS_USAGE_UNDEFINED )
{
hasUsage = true;
break;
}
}
return( hasUsage );
}