Ibis: correctly load QA files up to v2.1

This commit is contained in:
Fabien Corona 2022-11-20 19:10:46 +00:00 committed by Mikolaj Wielgus
parent 2919490e92
commit 8498630876
9 changed files with 386 additions and 199 deletions

View File

@ -710,6 +710,7 @@ bool IbisParser::ParseFile( std::string& aFileName )
ss << ibisFile.rdbuf(); ss << ibisFile.rdbuf();
const std::string& s = ss.str(); const std::string& s = ss.str();
m_buffer = std::vector<char>( s.begin(), s.end() ); m_buffer = std::vector<char>( s.begin(), s.end() );
m_buffer.push_back( 0 );
long size = m_buffer.size(); long size = m_buffer.size();
@ -764,7 +765,7 @@ bool IbisParser::checkEndofLine()
if( m_lineIndex < m_lineLength ) if( m_lineIndex < m_lineLength )
{ {
Report( _( "A line did not end properly.." ), RPT_SEVERITY_ERROR ); Report( _( "A line did not end properly." ), RPT_SEVERITY_ERROR );
return false; return false;
} }
return true; return true;
@ -787,6 +788,14 @@ bool IbisParser::readDvdt( std::string& aString, dvdt& aDest )
{ {
bool status = true; bool status = true;
if( aString == "NA" )
{
aDest.m_dv = nan( NAN_NA );
aDest.m_dt = nan( NAN_NA );
return status;
}
int i = 0; int i = 0;
for( i = 1; i < (int)aString.length(); i++ ) for( i = 1; i < (int)aString.length(); i++ )
@ -800,7 +809,7 @@ bool IbisParser::readDvdt( std::string& aString, dvdt& aDest )
if( aString.at( i ) == '/' ) if( aString.at( i ) == '/' )
{ {
std::string str1 = aString.substr( 0, i ); std::string str1 = aString.substr( 0, i );
std::string str2 = aString.substr( i + 2, aString.size() ); std::string str2 = aString.substr( i + 1, aString.size() - i - 1 );
if( !parseDouble( aDest.m_dv, str1, true ) || !parseDouble( aDest.m_dt, str2, true ) ) if( !parseDouble( aDest.m_dv, str1, true ) || !parseDouble( aDest.m_dt, str2, true ) )
{ {
@ -808,16 +817,6 @@ bool IbisParser::readDvdt( std::string& aString, dvdt& aDest )
} }
} }
else if( aString == "NA" )
{
aDest.m_dv = nan( NAN_NA );
aDest.m_dt = nan( NAN_NA );
}
else
{
status = false;
}
return status; return status;
} }
@ -836,18 +835,19 @@ bool IbisParser::parseDouble( double& aDest, std::string& aStr, bool aAllowModif
double result; double result;
size_t size = 0; size_t size = 0;
try
if( str == "NA" )
{ {
result = std::stod( str, &size ); result = nan( NAN_NA );
converted = true;
} }
catch( ... ) else
{ {
if( str == "NA" ) try
{ {
result = nan( NAN_NA ); result = std::stod( str, &size );
converted = true;
} }
else catch( ... )
{ {
result = nan( NAN_INVALID ); result = nan( NAN_INVALID );
status = false; status = false;
@ -887,6 +887,9 @@ bool IbisParser::getNextLine()
m_lineOffset = m_bufferIndex; m_lineOffset = m_bufferIndex;
if( m_bufferIndex >= m_buffer.size() )
return false;
char c = m_buffer[m_bufferIndex++]; char c = m_buffer[m_bufferIndex++];
int i = 1; int i = 1;
@ -1047,15 +1050,17 @@ bool IbisParser::readString( std::string& aDest )
bool IbisParser::storeString( std::string& aDest, bool aMultiline ) bool IbisParser::storeString( std::string& aDest, bool aMultiline )
{ {
bool status = true;
skipWhitespaces(); skipWhitespaces();
readString( aDest ); status &= readString( aDest );
m_continue = aMultiline ? IBIS_PARSER_CONTINUE::STRING : IBIS_PARSER_CONTINUE::NONE; m_continue = aMultiline ? IBIS_PARSER_CONTINUE::STRING : IBIS_PARSER_CONTINUE::NONE;
m_continuingString = &aDest; m_continuingString = &aDest;
return checkEndofLine(); status &= checkEndofLine();
return status;
} }
@ -1063,10 +1068,10 @@ bool IbisParser::changeCommentChar()
{ {
skipWhitespaces(); skipWhitespaces();
std::string strChar; std::string strChar = "";
// We cannot stop at m_lineLength here, because lineLength could stop before |_char // We cannot stop at m_lineLength here, because lineLength could stop before |_char
// if the char is remains the same // if the char remains the same
char c = m_buffer[m_lineOffset + m_lineIndex++]; char c = m_buffer[m_lineOffset + m_lineIndex++];
char d = c; char d = c;
@ -1087,7 +1092,7 @@ bool IbisParser::changeCommentChar()
c = m_buffer[m_lineOffset + m_lineIndex++]; c = m_buffer[m_lineOffset + m_lineIndex++];
} }
if( !strcmp( strChar.c_str(), "_char" ) ) if( strChar != "_char" )
{ {
Report( _( "Invalid syntax. Should be |_char or &_char, etc..." ), RPT_SEVERITY_ERROR ); Report( _( "Invalid syntax. Should be |_char or &_char, etc..." ), RPT_SEVERITY_ERROR );
return false; return false;
@ -1175,13 +1180,13 @@ bool IbisParser::changeContext( std::string& aKeyword )
{ {
m_ibisFile.m_components.push_back( IbisComponent( m_reporter ) ); m_ibisFile.m_components.push_back( IbisComponent( m_reporter ) );
m_currentComponent = &( m_ibisFile.m_components.back() ); m_currentComponent = &( m_ibisFile.m_components.back() );
storeString( m_currentComponent->m_name, false ); status &= storeString( m_currentComponent->m_name, false );
m_context = IBIS_PARSER_CONTEXT::COMPONENT; m_context = IBIS_PARSER_CONTEXT::COMPONENT;
} }
else if( compareIbisWord( aKeyword.c_str(), "Model_Selector" ) ) else if( compareIbisWord( aKeyword.c_str(), "Model_Selector" ) )
{ {
IbisModelSelector MS( m_reporter ); IbisModelSelector MS( m_reporter );
storeString( MS.m_name, false ); status &= storeString( MS.m_name, false );
m_ibisFile.m_modelSelectors.push_back( MS ); m_ibisFile.m_modelSelectors.push_back( MS );
m_currentModelSelector = &( m_ibisFile.m_modelSelectors.back() ); m_currentModelSelector = &( m_ibisFile.m_modelSelectors.back() );
m_context = IBIS_PARSER_CONTEXT::MODELSELECTOR; m_context = IBIS_PARSER_CONTEXT::MODELSELECTOR;
@ -1193,7 +1198,7 @@ bool IbisParser::changeContext( std::string& aKeyword )
model.m_temperatureRange.value[IBIS_CORNER::MIN] = 0; model.m_temperatureRange.value[IBIS_CORNER::MIN] = 0;
model.m_temperatureRange.value[IBIS_CORNER::TYP] = 50; model.m_temperatureRange.value[IBIS_CORNER::TYP] = 50;
model.m_temperatureRange.value[IBIS_CORNER::MAX] = 100; model.m_temperatureRange.value[IBIS_CORNER::MAX] = 100;
storeString( model.m_name, false ); status &= storeString( model.m_name, false );
m_ibisFile.m_models.push_back( model ); m_ibisFile.m_models.push_back( model );
m_currentModel = &( m_ibisFile.m_models.back() ); m_currentModel = &( m_ibisFile.m_models.back() );
m_context = IBIS_PARSER_CONTEXT::MODEL; m_context = IBIS_PARSER_CONTEXT::MODEL;
@ -1214,7 +1219,7 @@ bool IbisParser::changeContext( std::string& aKeyword )
PM.m_capacitanceMatrix->m_dim = -1; PM.m_capacitanceMatrix->m_dim = -1;
PM.m_inductanceMatrix->m_dim = -1; PM.m_inductanceMatrix->m_dim = -1;
storeString( PM.m_name, false ); status &= storeString( PM.m_name, false );
m_ibisFile.m_packageModels.push_back( PM ); m_ibisFile.m_packageModels.push_back( PM );
m_currentPackageModel = &( m_ibisFile.m_packageModels.back() ); m_currentPackageModel = &( m_ibisFile.m_packageModels.back() );
@ -1302,9 +1307,7 @@ bool IbisParser::readRamp()
m_continue = IBIS_PARSER_CONTINUE::RAMP; m_continue = IBIS_PARSER_CONTINUE::RAMP;
std::string keyword = std::string( "R_load " ); if( !readNumericSubparam( std::string( "R_load" ), m_currentModel->m_ramp.m_Rload ) )
if( !readNumericSubparam( std::string( "R_load " ), m_currentModel->m_ramp.m_Rload ) )
{ {
std::string str; std::string str;
@ -1312,11 +1315,11 @@ bool IbisParser::readRamp()
{ {
if( !strcmp( str.c_str(), "dV/dt_r" ) ) if( !strcmp( str.c_str(), "dV/dt_r" ) )
{ {
readRampdvdt( m_currentModel->m_ramp.m_rising ); status &= readRampdvdt( m_currentModel->m_ramp.m_rising );
} }
else if( !strcmp( str.c_str(), "dV/dt_f" ) ) else if( !strcmp( str.c_str(), "dV/dt_f" ) )
{ {
readRampdvdt( m_currentModel->m_ramp.m_falling ); status &= readRampdvdt( m_currentModel->m_ramp.m_falling );
} }
else else
{ {
@ -1703,18 +1706,12 @@ bool IbisParser::readModelSelector()
IbisModelSelectorEntry model; IbisModelSelectorEntry model;
if( readWord( model.m_modelName ) ) if( !readWord( model.m_modelName ) )
{ return false;
if( !readString( model.m_modelDescription ) )
{ status &= readString( model.m_modelDescription );
status &= false; m_currentModelSelector->m_models.push_back( model );
}
m_currentModelSelector->m_models.push_back( model );
}
else
{
status = false;
}
return status; return status;
} }
@ -1966,11 +1963,11 @@ bool IbisParser::parseHeader( std::string& aKeyword )
} }
else if( compareIbisWord( aKeyword.c_str(), "Comment_char" ) ) else if( compareIbisWord( aKeyword.c_str(), "Comment_char" ) )
{ {
changeCommentChar(); status &= changeCommentChar();
} }
else if( compareIbisWord( aKeyword.c_str(), "File_Name" ) ) else if( compareIbisWord( aKeyword.c_str(), "File_Name" ) )
{ {
storeString( m_ibisFile.m_header.m_fileName, false ); status &= storeString( m_ibisFile.m_header.m_fileName, false );
} }
else if( compareIbisWord( aKeyword.c_str(), "File_Rev" ) ) else if( compareIbisWord( aKeyword.c_str(), "File_Rev" ) )
{ {
@ -1978,23 +1975,23 @@ bool IbisParser::parseHeader( std::string& aKeyword )
} }
else if( compareIbisWord( aKeyword.c_str(), "Source" ) ) else if( compareIbisWord( aKeyword.c_str(), "Source" ) )
{ {
storeString( m_ibisFile.m_header.m_source, true ); status &= storeString( m_ibisFile.m_header.m_source, true );
} }
else if( compareIbisWord( aKeyword.c_str(), "Notes" ) ) else if( compareIbisWord( aKeyword.c_str(), "Notes" ) )
{ {
storeString( m_ibisFile.m_header.m_notes, true ); status &= storeString( m_ibisFile.m_header.m_notes, true );
} }
else if( compareIbisWord( aKeyword.c_str(), "Disclaimer" ) ) else if( compareIbisWord( aKeyword.c_str(), "Disclaimer" ) )
{ {
storeString( m_ibisFile.m_header.m_disclaimer, true ); status &= storeString( m_ibisFile.m_header.m_disclaimer, true );
} }
else if( compareIbisWord( aKeyword.c_str(), "Copyright" ) ) else if( compareIbisWord( aKeyword.c_str(), "Copyright" ) )
{ {
storeString( m_ibisFile.m_header.m_copyright, true ); status &= storeString( m_ibisFile.m_header.m_copyright, true );
} }
else if( compareIbisWord( aKeyword.c_str(), "Date" ) ) else if( compareIbisWord( aKeyword.c_str(), "Date" ) )
{ {
storeString( m_ibisFile.m_header.m_date, false ); status &= storeString( m_ibisFile.m_header.m_date, false );
} }
else else
{ {
@ -2092,36 +2089,23 @@ bool IbisParser::readPackage()
if( (int)fields.size() == ( 4 + extraArg ) ) if( (int)fields.size() == ( 4 + extraArg ) )
{ {
TypMinMaxValue* cValue;
if( fields.at( 0 ) == "R_pkg" ) if( fields.at( 0 ) == "R_pkg" )
{ cValue = R;
if( parseDouble( R->value[IBIS_CORNER::TYP], fields.at( 1 ), true ) )
{
status = false;
}
parseDouble( R->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
parseDouble( R->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
}
else if( fields.at( 0 ) == "L_pkg" ) else if( fields.at( 0 ) == "L_pkg" )
{ cValue = L;
if( parseDouble( L->value[IBIS_CORNER::TYP], fields.at( 1 ), true ) )
{
status = false;
}
parseDouble( L->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
parseDouble( L->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
}
else if( fields.at( 0 ) == "C_pkg" ) else if( fields.at( 0 ) == "C_pkg" )
cValue = C;
else
{ {
if( parseDouble( C->value[IBIS_CORNER::TYP], fields.at( 1 ), true ) ) Report( "Invalid field in [Package]" );
{ return false;
status = false;
}
parseDouble( C->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
parseDouble( C->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
} }
status &= parseDouble( cValue->value[IBIS_CORNER::TYP], fields.at( 1 ), true );
// Min / max values are optional, so don't update the status
parseDouble( cValue->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
parseDouble( cValue->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
} }
else else
{ {
@ -2133,7 +2117,7 @@ bool IbisParser::readPackage()
} }
m_continue = IBIS_PARSER_CONTINUE::COMPONENT_PACKAGE; m_continue = IBIS_PARSER_CONTINUE::COMPONENT_PACKAGE;
return true; return status;
} }
@ -2475,7 +2459,7 @@ bool IbisParser::onNewLine()
case IBIS_PARSER_CONTINUE::STRING: case IBIS_PARSER_CONTINUE::STRING:
skipWhitespaces(); skipWhitespaces();
*m_continuingString += '\n'; *m_continuingString += '\n';
readString( *m_continuingString ); status &= readString( *m_continuingString );
break; break;
case IBIS_PARSER_CONTINUE::COMPONENT_PACKAGE: status &= readPackage(); break; case IBIS_PARSER_CONTINUE::COMPONENT_PACKAGE: status &= readPackage(); break;
case IBIS_PARSER_CONTINUE::COMPONENT_PIN: status &= readPin(); break; case IBIS_PARSER_CONTINUE::COMPONENT_PIN: status &= readPin(); break;

View File

@ -45,6 +45,23 @@
#define _( x ) x #define _( x ) x
#endif #endif
std::vector<std::pair<int, double>> SimplifyBitSequence( std::vector<std::pair<int, double>> bits )
{
std::vector<std::pair<int, double>> result;
int prevbit = -1;
for( std::pair<int, double> bit : bits )
{
if( prevbit != bit.first )
result.push_back( bit );
prevbit = bit.first;
}
return result;
}
KIBIS_ANY::KIBIS_ANY( KIBIS* aTopLevel ) : IBIS_ANY( aTopLevel->m_reporter ) KIBIS_ANY::KIBIS_ANY( KIBIS* aTopLevel ) : IBIS_ANY( aTopLevel->m_reporter )
{ {
m_topLevel = aTopLevel; m_topLevel = aTopLevel;
@ -407,14 +424,14 @@ std::string KIBIS_MODEL::SpiceDie( KIBIS_PARAMETER& aParam, int aIndex )
{ {
result += m_pulldown.Spice( aIndex * 4 + 3, DIEBUFF, PD_GND, PD, supply ); result += m_pulldown.Spice( aIndex * 4 + 3, DIEBUFF, PD_GND, PD, supply );
result += "VmeasPD GND " + PD_GND + " 0\n"; result += "VmeasPD GND " + PD_GND + " 0\n";
result += "BKD GND " + DIE + " i=( -i(VmeasPU) * v(KU) )\n"; result += "BKD GND " + DIE + " i=( i(VmeasPD) * v(KD) )\n";
} }
if( HasPullup() ) if( HasPullup() )
{ {
result += m_pullup.Spice( aIndex * 4 + 4, PU_PWR, DIEBUFF, PU, supply ); result += m_pullup.Spice( aIndex * 4 + 4, PU_PWR, DIEBUFF, PU, supply );
result += "VmeasPU POWER " + PU_PWR + " 0\n"; result += "VmeasPU POWER " + PU_PWR + " 0\n";
result += "BKU POWER " + DIE + " i=( i(VmeasPD) * v(KD) )\n"; result += "BKU POWER " + DIE + " i=( -i(VmeasPU) * v(KU) )\n";
} }
result += "BDIEBUFF " + DIEBUFF + " GND v=v(" + DIE + ")\n"; result += "BDIEBUFF " + DIEBUFF + " GND v=v(" + DIE + ")\n";
@ -781,31 +798,11 @@ std::string KIBIS_PIN::KuKdDriver( KIBIS_MODEL& aMode
switch( wave->GetType() ) switch( wave->GetType() )
{ {
case KIBIS_WAVEFORM_TYPE::RECTANGULAR: case KIBIS_WAVEFORM_TYPE::RECTANGULAR:
{
KIBIS_WAVEFORM_RECTANGULAR* rectWave = dynamic_cast<KIBIS_WAVEFORM_RECTANGULAR*>( wave );
if( !rectWave )
{
break;
}
if( rectWave->m_ton < risingWF->m_table.m_entries.back().t )
{
Report( _( "Rising edge is longer than on time." ), RPT_SEVERITY_WARNING );
}
if( rectWave->m_toff < fallingWF->m_table.m_entries.back().t )
{
Report( _( "Falling edge is longer than off time." ), RPT_SEVERITY_WARNING );
}
std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence();
simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam );
break;
}
case KIBIS_WAVEFORM_TYPE::PRBS: case KIBIS_WAVEFORM_TYPE::PRBS:
{ {
wave->Check( risingWF, fallingWF );
std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence(); std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence();
bits = SimplifyBitSequence( bits );
simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam ); simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam );
break; break;
} }
@ -959,26 +956,24 @@ void KIBIS_PIN::getKuKdNoWaveform( KIBIS_MODEL& aModel, KIBIS_PARAMETER& aParam
switch( wave->GetType() ) switch( wave->GetType() )
{ {
case KIBIS_WAVEFORM_TYPE::RECTANGULAR: case KIBIS_WAVEFORM_TYPE::RECTANGULAR:
case KIBIS_WAVEFORM_TYPE::PRBS:
{ {
KIBIS_WAVEFORM_RECTANGULAR* rectWave = static_cast<KIBIS_WAVEFORM_RECTANGULAR*>( wave ); wave->Check( aModel.m_ramp.m_rising, aModel.m_ramp.m_falling );
std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence();
bits = SimplifyBitSequence( bits );
for( int i = 0; i < rectWave->m_cycles; i++ ) for( std::pair<int, double> bit : bits )
{ {
ku.push_back( 0 ); ku.push_back( bit.first ? 0 : 1 );
kd.push_back( 1 ); kd.push_back( bit.first ? 1 : 0 );
t.push_back( ( rectWave->m_ton + rectWave->m_toff ) * i ); t.push_back( bit.second );
ku.push_back( 1 ); ku.push_back( bit.first ? 1 : 0 );
kd.push_back( 0 ); kd.push_back( bit.first ? 0 : 1 );
t.push_back( ( rectWave->m_ton + rectWave->m_toff ) * i t.push_back( bit.second
+ aModel.m_ramp.m_rising.value[supply].m_dt + ( bit.first ? +aModel.m_ramp.m_rising.value[supply].m_dt
/ 0.6 ); // 0.6 because ibis only gives 20%-80% time : aModel.m_ramp.m_falling.value[supply].m_dt )
ku.push_back( 1 ); / 0.6 );
kd.push_back( 0 ); // 0.6 because ibis only gives 20%-80% time
t.push_back( ( rectWave->m_ton + rectWave->m_toff ) * i + rectWave->m_toff );
ku.push_back( 0 );
kd.push_back( 1 );
t.push_back( ( rectWave->m_ton + rectWave->m_toff ) * i + rectWave->m_toff
+ aModel.m_ramp.m_falling.value[supply].m_dt / 0.6 );
} }
break; break;
} }
@ -1530,3 +1525,149 @@ std::vector<std::pair<int, double>> KIBIS_WAVEFORM_PRBS::GenerateBitSequence()
return bitSequence; return bitSequence;
} }
bool KIBIS_WAVEFORM_RECTANGULAR::Check( IbisWaveform* aRisingWf, IbisWaveform* aFallingWf )
{
bool status = true;
if( m_cycles < 1 )
{
status = false;
Report( _( "Number of cycles should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_ton <= 0 )
{
status = false;
Report( _( "ON time should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_toff <= 0 )
{
status = false;
Report( _( "OFF time should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( aRisingWf )
{
if( m_ton < aRisingWf->m_table.m_entries.back().t )
{
status = false;
Report( _( "Rising edge is longer than on time." ), RPT_SEVERITY_WARNING );
}
}
if( aFallingWf )
{
if( m_toff < aFallingWf->m_table.m_entries.back().t )
{
status = false;
Report( _( "Falling edge is longer than off time." ), RPT_SEVERITY_WARNING );
}
}
status &= aRisingWf && aFallingWf;
return status;
}
bool KIBIS_WAVEFORM_RECTANGULAR::Check( dvdtTypMinMax aRisingRp, dvdtTypMinMax aFallingRp )
{
bool status = true;
if( m_cycles < 1 )
{
status = false;
Report( _( "Number of cycles should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_ton <= 0 )
{
status = false;
Report( _( "ON time should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_toff <= 0 )
{
status = false;
Report( _( "OFF time should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( ( m_ton < aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 )
|| ( m_ton < aRisingRp.value[IBIS_CORNER::MIN].m_dt / 0.6 )
|| ( m_ton < aRisingRp.value[IBIS_CORNER::MAX].m_dt / 0.6 ) )
{
status = false;
Report( _( "Rising edge is longer than ON time." ), RPT_SEVERITY_ERROR );
}
if( ( m_toff < aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 )
|| ( m_toff < aFallingRp.value[IBIS_CORNER::MIN].m_dt / 0.6 )
|| ( m_toff < aFallingRp.value[IBIS_CORNER::MAX].m_dt / 0.6 ) )
{
status = false;
Report( _( "Falling edge is longer than OFF time." ), RPT_SEVERITY_ERROR );
}
return status;
}
bool KIBIS_WAVEFORM_PRBS::Check( dvdtTypMinMax aRisingRp, dvdtTypMinMax aFallingRp )
{
bool status = true;
if( m_bitrate <= 0 )
{
status = false;
Report( _( "Bitrate should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_bits <= 0 )
{
status = false;
Report( _( "Number of bits should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_bitrate
&& ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
+ aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) )
&& ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
+ aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) )
&& ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
+ aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) ) )
{
status = false;
Report( _( "Bitrate is too high for rising / falling edges" ), RPT_SEVERITY_ERROR );
}
return status;
}
bool KIBIS_WAVEFORM_PRBS::Check( IbisWaveform* aRisingWf, IbisWaveform* aFallingWf )
{
bool status = true;
if( m_bitrate <= 0 )
{
status = false;
Report( _( "Bitrate should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_bits <= 0 )
{
status = false;
Report( _( "Number of bits should be greater than 0." ), RPT_SEVERITY_ERROR );
}
if( m_bitrate && aRisingWf && aFallingWf
&& ( ( 1 / m_bitrate ) < ( aRisingWf->m_table.m_entries.back().t
+ aFallingWf->m_table.m_entries.back().t ) ) )
{
status = false;
Report( _( "Bitrate could be too high for rising / falling edges" ), RPT_SEVERITY_WARNING );
}
return status;
}

View File

@ -59,10 +59,10 @@ enum KIBIS_WAVEFORM_TYPE
}; };
class KIBIS_WAVEFORM class KIBIS_WAVEFORM : public KIBIS_ANY
{ {
public: public:
KIBIS_WAVEFORM(){}; KIBIS_WAVEFORM( KIBIS* aTopLevel ) : KIBIS_ANY{ aTopLevel } { m_valid = true; };
KIBIS_WAVEFORM_TYPE GetType() { return m_type; }; KIBIS_WAVEFORM_TYPE GetType() { return m_type; };
virtual double GetDuration() { return 1; }; virtual double GetDuration() { return 1; };
bool inverted = false; // Used for differential drivers bool inverted = false; // Used for differential drivers
@ -74,6 +74,11 @@ public:
return bits; return bits;
}; };
// Check fuction if using waveform data
virtual bool Check( IbisWaveform* aRisingWf, IbisWaveform* aFallingWf ) { return true; };
// Check fuction if using ramp data
virtual bool Check( dvdtTypMinMax aRisingRp, dvdtTypMinMax aFallingRp ) { return true; };
protected: protected:
KIBIS_WAVEFORM_TYPE m_type = KIBIS_WAVEFORM_TYPE::NONE; KIBIS_WAVEFORM_TYPE m_type = KIBIS_WAVEFORM_TYPE::NONE;
}; };
@ -81,13 +86,20 @@ protected:
class KIBIS_WAVEFORM_RECTANGULAR : public KIBIS_WAVEFORM class KIBIS_WAVEFORM_RECTANGULAR : public KIBIS_WAVEFORM
{ {
public: public:
KIBIS_WAVEFORM_RECTANGULAR() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::RECTANGULAR; }; KIBIS_WAVEFORM_RECTANGULAR( KIBIS* aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
{
m_type = KIBIS_WAVEFORM_TYPE::RECTANGULAR;
};
double m_ton = 100e-9; double m_ton = 100e-9;
double m_toff = 100e-9; double m_toff = 100e-9;
int m_cycles = 1; int m_cycles = 1;
double m_delay = 0; double m_delay = 0;
std::vector<std::pair<int, double>> GenerateBitSequence() override; std::vector<std::pair<int, double>> GenerateBitSequence() override;
bool Check( IbisWaveform* aRisingWf, IbisWaveform* aFallingWf ) override;
bool Check( dvdtTypMinMax aRisingRp, dvdtTypMinMax aFallingRp ) override;
double GetDuration() override { return ( m_ton + m_toff ) * m_cycles; }; double GetDuration() override { return ( m_ton + m_toff ) * m_cycles; };
}; };
@ -95,33 +107,48 @@ public:
class KIBIS_WAVEFORM_PRBS : public KIBIS_WAVEFORM class KIBIS_WAVEFORM_PRBS : public KIBIS_WAVEFORM
{ {
public: public:
KIBIS_WAVEFORM_PRBS() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::PRBS; }; KIBIS_WAVEFORM_PRBS( KIBIS* aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
{
m_type = KIBIS_WAVEFORM_TYPE::PRBS;
};
double m_bitrate = 10e6; double m_bitrate = 10e6;
double m_delay = 0; double m_delay = 0;
double m_bits = 10; double m_bits = 10;
std::vector<std::pair<int, double>> GenerateBitSequence() override; std::vector<std::pair<int, double>> GenerateBitSequence() override;
bool Check( IbisWaveform* aRisingWf, IbisWaveform* aFallingWf ) override;
bool Check( dvdtTypMinMax aRisingRp, dvdtTypMinMax aFallingRp ) override;
double GetDuration() override { return m_bits / m_bitrate ; }; double GetDuration() override { return m_bits / m_bitrate ; };
}; };
class KIBIS_WAVEFORM_STUCK_HIGH : public KIBIS_WAVEFORM class KIBIS_WAVEFORM_STUCK_HIGH : public KIBIS_WAVEFORM
{ {
public: public:
KIBIS_WAVEFORM_STUCK_HIGH() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::STUCK_HIGH; }; KIBIS_WAVEFORM_STUCK_HIGH( KIBIS* aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
{
m_type = KIBIS_WAVEFORM_TYPE::STUCK_HIGH;
};
std::vector<std::pair<int, double>> GenerateBitSequence() override; std::vector<std::pair<int, double>> GenerateBitSequence() override;
}; };
class KIBIS_WAVEFORM_STUCK_LOW : public KIBIS_WAVEFORM class KIBIS_WAVEFORM_STUCK_LOW : public KIBIS_WAVEFORM
{ {
public: public:
KIBIS_WAVEFORM_STUCK_LOW() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::STUCK_LOW; }; KIBIS_WAVEFORM_STUCK_LOW( KIBIS* aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
{
m_type = KIBIS_WAVEFORM_TYPE::STUCK_LOW;
};
std::vector<std::pair<int, double>> GenerateBitSequence() override; std::vector<std::pair<int, double>> GenerateBitSequence() override;
}; };
class KIBIS_WAVEFORM_HIGH_Z : public KIBIS_WAVEFORM class KIBIS_WAVEFORM_HIGH_Z : public KIBIS_WAVEFORM
{ {
public: public:
KIBIS_WAVEFORM_HIGH_Z() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::HIGH_Z; }; KIBIS_WAVEFORM_HIGH_Z( KIBIS* aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
{
m_type = KIBIS_WAVEFORM_TYPE::HIGH_Z;
};
std::vector<std::pair<int, double>> GenerateBitSequence() override; std::vector<std::pair<int, double>> GenerateBitSequence() override;
}; };

View File

@ -143,17 +143,17 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const st
if( paramValue == "hi-Z" ) if( paramValue == "hi-Z" )
{ {
kparams.m_waveform = kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_HIGH_Z() ); static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_HIGH_Z( &kibis ) );
} }
else if( paramValue == "low" ) else if( paramValue == "low" )
{ {
kparams.m_waveform = kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_LOW() ); static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_LOW( &kibis ) );
} }
else if( paramValue == "high" ) else if( paramValue == "high" )
{ {
kparams.m_waveform = kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_HIGH() ); static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_HIGH( &kibis ) );
} }
if( diffMode ) if( diffMode )
@ -165,7 +165,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const st
case SIM_MODEL::TYPE::KIBIS_DRIVER_RECT: case SIM_MODEL::TYPE::KIBIS_DRIVER_RECT:
{ {
KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR(); KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR( &kibis );
if ( m_model.FindParam( "ton" ) ) if ( m_model.FindParam( "ton" ) )
waveform->m_ton = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "ton" )->value ).Get().value_or( 1 ); waveform->m_ton = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "ton" )->value ).Get().value_or( 1 );
@ -177,7 +177,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const st
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 ); waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 );
if ( m_model.FindParam( "cycles" ) ) if ( m_model.FindParam( "cycles" ) )
waveform->m_cycles = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "cycles" )->value ).Get().value_or( 0 ); waveform->m_cycles = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "cycles" )->value ).Get().value_or( 1 );
kparams.m_waveform = waveform; kparams.m_waveform = waveform;
@ -190,7 +190,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const st
case SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS: case SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS:
{ {
KIBIS_WAVEFORM_PRBS* waveform = new KIBIS_WAVEFORM_PRBS(); KIBIS_WAVEFORM_PRBS* waveform = new KIBIS_WAVEFORM_PRBS( &kibis );
if ( m_model.FindParam( "f0" ) ) if ( m_model.FindParam( "f0" ) )
waveform->m_bitrate = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "f0" )->value ).Get().value_or( 0 ); waveform->m_bitrate = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "f0" )->value ).Get().value_or( 0 );

View File

@ -7,42 +7,21 @@
source for the files source for the files
[Notes] We can have some [Notes] We can have some
Notes Notes
[Disclaimer]
/* [Disclaimer] This is NOT a valid component.
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
[Component] Virtual [Component] Virtual
[Manufacturer] KiCad [Manufacturer] KiCad
[Package] [Package]
R_pkg 1m 0.8m NA R_pkg 50m 40m 60m
L_pkg 1m NA NA L_pkg 2n NA NA
C_pkg 1m NA NA C_pkg 10p NA NA
[Pin] signal_name model_name R_pin L_pin C_pin [Pin] signal_name model_name R_pin L_pin C_pin
1 VCC POWER 1m 0.8m NA 1 VCC POWER 5mm 2n NA
2 GND GND 1m NA 2m 2 GND GND 55m NA NA
3 X Input 1m NA NA 3 X Input 55m NA 0.2p
4 Y Ouput 1m 0.8m 2m 4 Y Output 55m 2n 0.2p
[Model] Input [Model] Input
Model_type Input Model_type Input
@ -50,22 +29,10 @@ Polarity Non-Inverting
Enable Active-High Enable Active-High
Vinl = 0.8V Vinl = 0.8V
Vinh = 2.0V Vinh = 2.0V
C_comp 10.0pF 8.0pF 15.0pF C_comp 1.0pF 0.5pF 2.0pF
[Voltage range] 5.0V 4.5V 5.5V [Voltage range] 5.0V 4.5V 5.5V
[Pulldown]
# Voltage I(typ) I(min) I(max)
#
-5.0V -50.0m -40.0m -60.0m
0.0V 0 0 0
5.0V 50.0m 40.0m 60.0m
[Pullup]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V 50.0m 40.0m 60.0m
0.0V 0 0 0
5.0V -50.0m -40.0m -60.0m
[GND_clamp] [GND_clamp]
# #
# Voltage I(typ) I(min) I(max) # Voltage I(typ) I(min) I(max)
@ -81,9 +48,46 @@ C_comp 10.0pF 8.0pF 15.0pF
0.0V 0 NA NA 0.0V 0 NA NA
5.0V 0 NA NA 5.0V 0 NA NA
[Ramp] [Model] Output
# variable typ min max Model_type Output
dV/dt_r 3.0/2n 2.8/3n NA Polarity Non-Inverting
dV/dt_f 3.0/2n 2.8/3n 3.2/1n Enable Active-High
C_comp 10.0pF 8.0pF 15.0pF
[END] [Voltage range] 5.0V 4.5V 5.5V
[Pulldown]
# Voltage I(typ) I(min) I(max)
#
-5.0V -50.0m -40.0m -60.0m
0.0V 0 0 0
5.0V 500.0m 400.0m 600.0m
10.0V 550.0m 440.0m 660.0m
[Pullup]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V 50.0m 40.0m 60.0m
0.0V 0 0 0
5.0V -500.0m -400.0m -600.0m
10.0V -550.0m -440.0m -660.0m
[GND_clamp]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V -500.0m NA NA
-0.7V 0 NA NA
5.0V 0 NA NA
[POWER_clamp]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V 500.0m NA NA
-0.7V 0 NA NA
5.0V 0 NA NA
[Ramp]
# variable typ min max
dV/dt_r 3.0/30n 2.8/30n NA
dV/dt_f 3.0/20n 2.8/20n 3.2/20n
[END]

View File

@ -7,8 +7,7 @@
source for the files source for the files
[Notes] We can have some [Notes] We can have some
Notes Notes
[Copyright] [Copyright] /*
/*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
@ -42,10 +41,10 @@ C_pkg 1m 0.8m 2m
1 VCC POWER 1m 0.8m 2m 1 VCC POWER 1m 0.8m 2m
2 GND GND 1m 0.8m 2m 2 GND GND 1m 0.8m 2m
3 X Input 1m 0.8m 2m 3 X Input 1m 0.8m 2m
4 Y Ouput 1m 0.8m 2m 4 Y Output 1m 0.8m 2m
5 YN Ouput 1m 0.8m 2m 5 YN Output 1m 0.8m 2m
6 Y Ouput 1m 0.8m 2m 6 Y Output 1m 0.8m 2m
7 YN Ouput 1m 0.8m 2m 7 YN Output 1m 0.8m 2m
[Package Model] QS-SMT-cer-8-pin-pkgs [Package Model] QS-SMT-cer-8-pin-pkgs
[Pin Mapping] pulldown_ref pullup_ref gnd_clamp_ref power_clamp_ref [Pin Mapping] pulldown_ref pullup_ref gnd_clamp_ref power_clamp_ref
@ -116,6 +115,41 @@ C_comp 10.0pF 8.0pF 15.0pF
[Rac] 30Ohm NA NA [Rac] 30Ohm NA NA
[Cac] 50pF NA NA [Cac] 50pF NA NA
[Model] Output
Model_type Output
Polarity Non-Inverting
Enable Active-High
C_comp 10.0pF 8.0pF 15.0pF
[Voltage range] 5.0V 4.5V 5.5V
[Pulldown]
# Voltage I(typ) I(min) I(max)
#
-5.0V -50.0m -40.0m -60.0m
0.0V 0 0 0
5.0V 50.0m 40.0m 60.0m
[Pullup]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V 50.0m 40.0m 60.0m
0.0V 0 0 0
5.0V -50.0m -40.0m -60.0m
[GND_clamp]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V -50.0m NA NA
0.0V 0 NA NA
5.0V 0 NA NA
[POWER_clamp]
#
# Voltage I(typ) I(min) I(max)
#
-5.0V 50.0m NA NA
0.0V 0 NA NA
5.0V 0 NA NA
[Ramp] [Ramp]
# variable typ min max # variable typ min max

View File

@ -7,8 +7,7 @@
source for the files source for the files
[Notes] We can have some [Notes] We can have some
Notes Notes
[Copyright] [Copyright] /*
/*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.

View File

@ -7,8 +7,7 @@
source for the files source for the files
[Notes] We can have some [Notes] We can have some
Notes Notes
[Copyright] [Copyright] /*
/*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
@ -42,10 +41,10 @@ C_pkg 1m 0.8m 2m
1 VCC POWER 1m 0.8m 2m 1 VCC POWER 1m 0.8m 2m
2 GND GND 1m 0.8m 2m 2 GND GND 1m 0.8m 2m
3 X Input 1m 0.8m 2m 3 X Input 1m 0.8m 2m
4 Y Ouput 1m 0.8m 2m 4 Y Output 1m 0.8m 2m
5 YN Ouput 1m 0.8m 2m 5 YN Output 1m 0.8m 2m
6 Y Ouput 1m 0.8m 2m 6 Y Output 1m 0.8m 2m
7 YN Ouput 1m 0.8m 2m 7 YN Output 1m 0.8m 2m
[Package Model] QS-SMT-cer-8-pin-pkgs [Package Model] QS-SMT-cer-8-pin-pkgs
[Pin Mapping] pulldown_ref pullup_ref gnd_clamp_ref power_clamp_ref [Pin Mapping] pulldown_ref pullup_ref gnd_clamp_ref power_clamp_ref
@ -377,7 +376,7 @@ Off_delay 5n 6n 4n | Time from rising edge
0.000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000e+00 0.000e+00 0.000e+00
5.000 0.000e+00 0.000e+00 0.000e+00 5.000 0.000e+00 0.000e+00 0.000e+00
| |
[POWER Pulse Table] | POWER Clamp offset table | [POWER Pulse Table] | POWER Clamp offset table|
| Time V(typ) V(min) V(max) | Time V(typ) V(min) V(max)
| |
0 0 0 0 0 0 0 0

View File

@ -7,8 +7,7 @@
source for the files source for the files
[Notes] We can have some [Notes] We can have some
Notes Notes
[Copyright] [Copyright] /*
/*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.