Ibis differential and PRBS models

This commit is contained in:
Fabien Corona 2022-09-29 08:35:01 +00:00 committed by Mikolaj Wielgus
parent 8ae48bb093
commit 7e486327d9
11 changed files with 302 additions and 78 deletions

View File

@ -524,7 +524,26 @@ void DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aFilePath )
try
{
m_library->ReadFile( std::string( absolutePath.ToUTF8() ) );
if( IsIbisLoaded() )
{
wxString ibisTypeString = SIM_MODEL::GetFieldValue( &m_fields, SIM_MODEL::TYPE_FIELD );
SIM_MODEL::TYPE ibisType = SIM_MODEL::TYPE::KIBIS_DEVICE;
if( ibisTypeString == "IBISDRIVER" )
ibisType = SIM_MODEL::TYPE::KIBIS_DRIVER;
else if( ibisTypeString == "IBISDIFFDRIVER" )
ibisType = SIM_MODEL::TYPE::KIBIS_DIFFDRIVER;
else if( ibisTypeString == "IBISDIFFDEVICE" )
ibisType = SIM_MODEL::TYPE::KIBIS_DIFFDEVICE;
std::dynamic_pointer_cast<SIM_LIBRARY_KIBIS>( m_library )
->ReadFile( std::string( absolutePath.ToUTF8() ), ibisType );
}
else
{
m_library->ReadFile( std::string( absolutePath.ToUTF8() ) );
}
}
catch( const IO_ERROR& e )
{
@ -1010,8 +1029,9 @@ void DIALOG_SIM_MODEL<T>::onTypeChoice( wxCommandEvent& aEvent )
&& typeDescription == SIM_MODEL::TypeInfo( type ).description )
{
if( IsIbisLoaded()
&& ( type == SIM_MODEL::TYPE::KIBIS_DEVICE
|| type == SIM_MODEL::TYPE::KIBIS_DRIVER ) )
&& ( type == SIM_MODEL::TYPE::KIBIS_DEVICE || type == SIM_MODEL::TYPE::KIBIS_DRIVER
|| type == SIM_MODEL::TYPE::KIBIS_DIFFDRIVER
|| type == SIM_MODEL::TYPE::KIBIS_DIFFDEVICE ) )
{
std::shared_ptr<SIM_MODEL_KIBIS> kibismodel =
std::dynamic_pointer_cast<SIM_MODEL_KIBIS>(

View File

@ -273,6 +273,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
switch( type )
{
case SIM_MODEL::TYPE::KIBIS_DIFFDEVICE:
case SIM_MODEL::TYPE::KIBIS_DIFFDRIVER:
case SIM_MODEL::TYPE::KIBIS_DEVICE:
case SIM_MODEL::TYPE::KIBIS_DRIVER: break;
default:
@ -329,6 +331,10 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
case SIM_MODEL::TYPE::KIBIS_DEVICE:
kpin->writeSpiceDevice( &modelData, modelName, *kmodel, kparams );
break;
case SIM_MODEL::TYPE::KIBIS_DIFFDEVICE:
kpin->writeSpiceDiffDevice( &modelData, modelName, *kmodel, kparams );
break;
case SIM_MODEL::TYPE::KIBIS_DIFFDRIVER:
case SIM_MODEL::TYPE::KIBIS_DRIVER:
{
mparam = spiceItem.model->FindParam( "wftype" );
@ -369,6 +375,39 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
->Get()
.value_or( 0 ) );
}
if( paramValue == "prbs" )
{
kparams.m_waveform = static_cast<KIBIS_WAVEFORM*>(
new KIBIS_WAVEFORM_PRBS() );
mparam = spiceItem.model->FindParam( "bitrate" );
if( mparam )
static_cast<KIBIS_WAVEFORM_PRBS*>( kparams.m_waveform )
->m_bitrate = static_cast<double>(
std::dynamic_pointer_cast<SIM_VALUE_FLOAT>( mparam->value )
->Get()
.value_or( 1 ) );
mparam = spiceItem.model->FindParam( "nbits" );
if( mparam )
static_cast<KIBIS_WAVEFORM_PRBS*>( kparams.m_waveform )
->m_bits = static_cast<double>(
std::dynamic_pointer_cast<SIM_VALUE_FLOAT>( mparam->value )
->Get()
.value_or( 1 ) );
mparam = spiceItem.model->FindParam( "delay" );
if( mparam )
static_cast<KIBIS_WAVEFORM_PRBS*>( kparams.m_waveform )
->m_delay = static_cast<double>(
std::dynamic_pointer_cast<SIM_VALUE_FLOAT>( mparam->value )
->Get()
.value_or( 0 ) );
}
else if( paramValue == "stuck high" )
{
kparams.m_waveform =
@ -385,7 +424,11 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_HIGH_Z() );
}
}
kpin->writeSpiceDriver( &modelData, modelName, *kmodel, kparams );
if( type == SIM_MODEL::TYPE::KIBIS_DIFFDRIVER )
kpin->writeSpiceDiffDriver( &modelData, modelName, *kmodel, kparams );
else
kpin->writeSpiceDriver( &modelData, modelName, *kmodel, kparams );
break;
}
default: continue;

View File

@ -30,7 +30,7 @@
#include <pegtl/contrib/parse_tree.hpp>
void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath )
void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, SIM_MODEL::TYPE aType )
{
SIM_LIBRARY::ReadFile( aFilePath );
m_kibis = KIBIS( std::string( aFilePath.c_str() ) );
@ -41,13 +41,20 @@ void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath )
return;
}
unsigned pinNumber = 2;
if( aType == SIM_MODEL::TYPE::KIBIS_DIFFDEVICE || aType == SIM_MODEL::TYPE::KIBIS_DIFFDEVICE )
pinNumber = 3;
for( KIBIS_COMPONENT& kcomp : m_kibis.m_components )
{
m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, 2 ) );
m_models.push_back( SIM_MODEL::Create( aType, pinNumber ) );
m_modelNames.emplace_back( kcomp.m_name );
SIM_MODEL_KIBIS* libcomp = dynamic_cast<SIM_MODEL_KIBIS*>( m_models.back().get() );
InitModel( *libcomp, kcomp.m_name );
if ( libcomp )
InitModel( *libcomp, kcomp.m_name );
}
}

View File

@ -37,7 +37,11 @@ public:
static constexpr auto MODEL_FIELD = "Ibis_Model";
// @copydoc SIM_LIBRARY::ReadFile()
void ReadFile( const std::string& aFilePath ) override;
void ReadFile( const std::string& aFilePath, SIM_MODEL::TYPE aType );
void ReadFile( const std::string& aFilePath ) override
{
ReadFile( aFilePath, SIM_MODEL::TYPE::KIBIS_DEVICE );
}
// @copydoc SIM_LIBRARY::WriteFile()
void WriteFile( const std::string& aFilePath ) override{};

View File

@ -229,8 +229,10 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
//case TYPE::I_RANDPOISSON: return { DEVICE_TYPE::I, "RANDPOISSON", "Random Poisson" };
case TYPE::I_BEHAVIORAL: return { DEVICE_TYPE_::I, "=", "Behavioral" };
case TYPE::KIBIS_DRIVER: return { DEVICE_TYPE_::KIBIS, "IBISDRIVER", "Driver" };
case TYPE::KIBIS_DEVICE: return { DEVICE_TYPE_::KIBIS, "IBISDEVICE", "Device" };
case TYPE::KIBIS_DRIVER: return { DEVICE_TYPE_::KIBIS, "IBISDRIVER", "Driver" };
case TYPE::KIBIS_DEVICE: return { DEVICE_TYPE_::KIBIS, "IBISDEVICE", "Device" };
case TYPE::KIBIS_DIFFDRIVER: return { DEVICE_TYPE_::KIBIS, "IBISDIFFDRIVER", "Differential driver" };
case TYPE::KIBIS_DIFFDEVICE: return { DEVICE_TYPE_::KIBIS, "IBISDIFFDEVICE", "Differential device" };
case TYPE::SUBCKT: return { DEVICE_TYPE_::SUBCKT, "", "" };
case TYPE::XSPICE: return { DEVICE_TYPE_::XSPICE, "", "" };
case TYPE::RAWSPICE: return { DEVICE_TYPE_::SPICE, "", "" };
@ -365,6 +367,9 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
case TYPE::KIBIS_DEVICE: return { "X" };
case TYPE::KIBIS_DRIVER: return { "X" };
case TYPE::KIBIS_DIFFDEVICE: return { "X" };
case TYPE::KIBIS_DIFFDRIVER: return { "X" };
case TYPE::NONE:
case TYPE::RAWSPICE:
return {};
@ -949,6 +954,8 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType )
case TYPE::KIBIS_DRIVER:
case TYPE::KIBIS_DEVICE:
case TYPE::KIBIS_DIFFDEVICE:
case TYPE::KIBIS_DIFFDRIVER:
return std::make_unique<SIM_MODEL_KIBIS>( aType );
case TYPE::RAWSPICE:

View File

@ -298,6 +298,8 @@ public:
KIBIS_DRIVER,
KIBIS_DEVICE,
KIBIS_DIFFDEVICE,
KIBIS_DIFFDRIVER,
SUBCKT,
XSPICE,
@ -502,7 +504,7 @@ public:
DEVICE_TYPE_ GetDeviceType() const { return GetTypeInfo().deviceType; }
TYPE GetType() const { return m_type; }
const SIM_MODEL* GetBaseModel() const { return m_baseModel; }
virtual const SIM_MODEL* GetBaseModel() const { return m_baseModel; }
virtual void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; }
int GetPinCount() const { return static_cast<int>( m_pins.size() ); }
@ -517,7 +519,7 @@ public:
int GetParamCount() const { return static_cast<int>( m_params.size() ); }
const PARAM& GetParam( unsigned aParamIndex ) const; // Return base parameter unless it's overridden.
virtual const PARAM& GetParam( unsigned aParamIndex ) const; // Return base parameter unless it's overridden.
const PARAM* FindParam( const std::string& aParamName ) const;
@ -571,6 +573,7 @@ protected:
bool aAllowParamValuePairs = true );
std::vector<PARAM> m_params;
bool m_requiresUIUpdate = false;
const SIM_MODEL* m_baseModel;
private:
static TYPE readTypeFromSpiceStrings( const std::string& aTypeString,
@ -599,7 +602,6 @@ private:
std::unique_ptr<SPICE_GENERATOR> m_spiceGenerator;
const SIM_MODEL* m_baseModel;
const TYPE m_type;
std::vector<PIN> m_pins;

View File

@ -59,16 +59,25 @@ SIM_MODEL_KIBIS::SIM_MODEL_KIBIS( TYPE aType, std::string aWfType ) :
{
SetParameters( aType, aWfType );
AddPin( { "GND", "1" } );
AddPin( { "IN/OUT", "2" } );
if( aType == SIM_MODEL::TYPE::KIBIS_DIFFDEVICE || aType == SIM_MODEL::TYPE::KIBIS_DIFFDRIVER )
{
AddPin( { "GND", "1" } );
AddPin( { "+", "2" } );
AddPin( { "-", "3" } );
}
else
{
AddPin( { "GND", "1" } );
AddPin( { "IN/OUT", "2" } );
}
}
SIM_MODEL_KIBIS::SIM_MODEL_KIBIS( TYPE aType, SIM_MODEL_KIBIS& aSource ) : SIM_MODEL_KIBIS( aType )
SIM_MODEL_KIBIS::SIM_MODEL_KIBIS( TYPE aType, const SIM_MODEL_KIBIS& aSource ) : SIM_MODEL_KIBIS( aType )
{
for( PARAM& param1 : m_params )
{
for( auto param2refwrap : aSource.GetParams() )
for( auto& param2refwrap : aSource.GetParams() )
{
const PARAM& param2 = param2refwrap.get();
@ -109,8 +118,10 @@ void SIM_MODEL_KIBIS::SetParameters( TYPE aType, std::string aWfType )
makeKibisParamInfos( SIM_MODEL::TYPE::KIBIS_DRIVER, SIM_MODEL_KIBIS::DRIVER_STUCKL );
static std::vector<PARAM::INFO> kibisparam_driver_highz =
makeKibisParamInfos( SIM_MODEL::TYPE::KIBIS_DRIVER, SIM_MODEL_KIBIS::DRIVER_HIGHZ );
static std::vector<PARAM::INFO> kibisparam_driver_prbs =
makeKibisParamInfos( SIM_MODEL::TYPE::KIBIS_DRIVER, SIM_MODEL_KIBIS::DRIVER_PRBS );
static std::vector<PARAM::INFO> kibisparam_driver_allParams =
makeKibisParamInfos( SIM_MODEL::TYPE::KIBIS_DRIVER, "NoInit" );
makeKibisParamInfos( SIM_MODEL::TYPE::KIBIS_DRIVER, SIM_MODEL_KIBIS::JOCKER );
m_requiresUIUpdate = true;
@ -118,7 +129,9 @@ void SIM_MODEL_KIBIS::SetParameters( TYPE aType, std::string aWfType )
switch( aType )
{
case SIM_MODEL::TYPE::KIBIS_DEVICE: params = &kibisparam_device; break;
case SIM_MODEL::TYPE::KIBIS_DEVICE:
case SIM_MODEL::TYPE::KIBIS_DIFFDEVICE: params = &kibisparam_device; break;
case SIM_MODEL::TYPE::KIBIS_DIFFDRIVER:
case SIM_MODEL::TYPE::KIBIS_DRIVER:
if( aWfType == SIM_MODEL_KIBIS::DRIVER_RECT )
@ -129,6 +142,8 @@ void SIM_MODEL_KIBIS::SetParameters( TYPE aType, std::string aWfType )
params = &kibisparam_driver_stuckl;
else if( aWfType == SIM_MODEL_KIBIS::DRIVER_HIGHZ )
params = &kibisparam_driver_highz;
else if( aWfType == SIM_MODEL_KIBIS::DRIVER_PRBS )
params = &kibisparam_driver_prbs;
else
params = &kibisparam_driver_allParams;
// All params allow for a newly created model to read any parameter
@ -137,6 +152,9 @@ void SIM_MODEL_KIBIS::SetParameters( TYPE aType, std::string aWfType )
default: wxFAIL; return;
}
m_params.clear();
/*
if( m_params.empty() )
{
for( const PARAM::INFO& paramInfo : *params )
@ -151,14 +169,10 @@ void SIM_MODEL_KIBIS::SetParameters( TYPE aType, std::string aWfType )
m_params.pop_back(); // waveform parameters are at the end of the vector
}
}
*/
for( const PARAM::INFO& paramInfo : *params )
{
if( paramInfo.category == PARAM::CATEGORY::WAVEFORM )
{
AddParam( paramInfo );
}
}
AddParam( paramInfo );
}
void SIM_MODEL_KIBIS::SetParameters( std::string aWfType )
@ -204,7 +218,7 @@ SIM_MODEL_KIBIS::makeKibisParamInfos( TYPE aType, std::string aWfType )
paramInfos.push_back( paramInfo );
paramInfo.name = "lpin";
paramInfo.type = SIM_VALUE::TYPE_STRING;
paramInfo.type = SIM_VALUE::TYPE_STRING;
paramInfo.unit = "";
paramInfo.category = PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "TYP";
@ -223,9 +237,26 @@ SIM_MODEL_KIBIS::makeKibisParamInfos( TYPE aType, std::string aWfType )
paramInfo.enumValues = { "TYP", "MIN", "MAX" };
paramInfos.push_back( paramInfo );
if ( aType == SIM_MODEL::TYPE::KIBIS_DEVICE )
if( aType == SIM_MODEL::TYPE::KIBIS_DEVICE || aType == SIM_MODEL::TYPE::KIBIS_DIFFDEVICE )
return paramInfos; // Devices have no waveform parameters
paramInfo.name = "wftype";
paramInfo.type = SIM_VALUE::TYPE_STRING;
paramInfo.unit = "";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = DRIVER_HIGHZ;
paramInfo.description = _( "Waveform" );
paramInfo.spiceModelName = "";
paramInfo.enumValues = { DRIVER_RECT, DRIVER_STUCKH, DRIVER_STUCKL, DRIVER_HIGHZ, DRIVER_PRBS };
paramInfos.push_back( paramInfo );
if( aWfType == DRIVER_STUCKH || aWfType == DRIVER_STUCKL || aWfType == DRIVER_HIGHZ )
{
return paramInfos;
}
paramInfo.name = "ac";
paramInfo.type = SIM_VALUE::TYPE_STRING;
paramInfo.unit = "";
@ -236,47 +267,58 @@ SIM_MODEL_KIBIS::makeKibisParamInfos( TYPE aType, std::string aWfType )
paramInfo.enumValues = { "low", "normal", "high" };
paramInfos.push_back( paramInfo );
paramInfo.name = "wftype";
paramInfo.type = SIM_VALUE::TYPE_STRING;
paramInfo.unit = "";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = DRIVER_HIGHZ;
paramInfo.description = _( "Waveform" );
paramInfo.spiceModelName = "";
paramInfo.enumValues = { DRIVER_RECT, DRIVER_STUCKH, DRIVER_STUCKL, DRIVER_HIGHZ };
paramInfos.push_back( paramInfo );
if ( aWfType == DRIVER_RECT || aWfType == JOCKER )
if( aWfType == DRIVER_STUCKH || aWfType == DRIVER_STUCKL || aWfType == DRIVER_HIGHZ )
{
return paramInfos;
paramInfo.name = "ton";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "ON time" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
paramInfo.name = "toff";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "OFF time" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
paramInfo.name = "delay";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "0";
paramInfo.description = _( "Delay" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
}
paramInfo.name = "ton";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "ON time" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
if ( ( aWfType == DRIVER_PRBS ) || ( aWfType == JOCKER ) )
paramInfo.name = "toff";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "OFF time" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
{
paramInfo.name = "f0";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "Hz";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "Bitrate" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
paramInfo.name = "delay";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "0";
paramInfo.description = _( "Delay" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
paramInfo.name = "bits";
paramInfo.type = SIM_VALUE::TYPE_FLOAT;
paramInfo.unit = "Hz";
paramInfo.category = PARAM::CATEGORY::WAVEFORM;
paramInfo.defaultValue = "";
paramInfo.description = _( "Number of bits" );
paramInfo.spiceModelName = "";
paramInfos.push_back( paramInfo );
}
return paramInfos;
}

View File

@ -50,13 +50,15 @@ class SIM_MODEL_KIBIS : public SIM_MODEL
static constexpr auto DRIVER_STUCKH = "stuck high";
static constexpr auto DRIVER_STUCKL = "stuck low";
static constexpr auto DRIVER_HIGHZ = "high Z";
static constexpr auto DRIVER_PRBS = "prbs";
static constexpr auto JOCKER = "kicadjocker"; // Gets all parameters
public:
SIM_MODEL_KIBIS( TYPE aType, std::string aWfType = "NoInit" );
// @brief Special copy constructor
// creates a a model with aType, but tries to match parameters from aSource.
SIM_MODEL_KIBIS( TYPE aType, SIM_MODEL_KIBIS& aSource );
SIM_MODEL_KIBIS( TYPE aType, const SIM_MODEL_KIBIS& aSource );
SIM_MODEL_KIBIS( TYPE aType, SIM_MODEL_KIBIS& aSource, const std::vector<LIB_FIELD>& aFields );
SIM_MODEL_KIBIS( TYPE aType, SIM_MODEL_KIBIS& aSource, const std::vector<SCH_FIELD>& aFields );
@ -80,6 +82,9 @@ public:
: m_componentName;
};
const PARAM& GetParam( unsigned aParamIndex ) const override { return m_params.at( aParamIndex ); };
/** @brief update the list of available models based on the pin number.
* */
bool ChangePin( SIM_LIBRARY_KIBIS& aLib, std::string aPinNumber );

View File

@ -481,6 +481,7 @@ std::string KIBIS_MODEL::generateSquareWave( std::string aNode1, std::string aNo
{
IBIS_CORNER supply = aParam.m_supply;
std::string simul;
std::vector<int>stimuliIndex;
IbisWaveform risingWF = TrimWaveform( *( aPair.first ) );
IbisWaveform fallingWF = TrimWaveform( *( aPair.second ) );
@ -495,16 +496,24 @@ std::string KIBIS_MODEL::generateSquareWave( std::string aNode1, std::string aNo
double delta = deltaR + deltaF;
int i = 0;
int prevBit = 2;
for( std::pair<int, double> bit : aBits )
{
IbisWaveform* WF;
double timing = bit.second;
if ( bit.first != prevBit )
{
if( bit.first == 1 )
WF = &risingWF;
else
WF = &fallingWF;
stimuliIndex.push_back( i );
simul += "Vstimuli";
simul += std::to_string( i );
simul += " stimuli";
@ -534,8 +543,10 @@ std::string KIBIS_MODEL::generateSquareWave( std::string aNode1, std::string aNo
simul += " ";
}
simul += ")\n";
}
i++;
prevBit = bit.first;
}
simul += "bin ";
@ -544,7 +555,7 @@ std::string KIBIS_MODEL::generateSquareWave( std::string aNode1, std::string aNo
simul += aNode2;
simul += " v=(";
for( size_t ii = 0; ii < aBits.size(); ii++ )
for( int ii: stimuliIndex )
{
simul += " v( stimuli";
simul += std::to_string( ii );
@ -797,6 +808,13 @@ std::string KIBIS_PIN::KuKdDriver( KIBIS_MODEL& aMode
simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam );
break;
}
case KIBIS_WAVEFORM_TYPE::PRBS:
{
KIBIS_WAVEFORM_PRBS* prbsWave = dynamic_cast<KIBIS_WAVEFORM_PRBS*>( wave );
std::vector<std::pair<int, double>> bits = prbsWave->GenerateBitSequence();
simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam );
break;
}
case KIBIS_WAVEFORM_TYPE::STUCK_HIGH:
{
IbisWaveform* waveform = wave->inverted ? risingWF : fallingWF;
@ -901,8 +919,15 @@ void KIBIS_PIN::getKuKdOneWaveform( KIBIS_MODEL& aMod
switch( wave->GetType() )
{
case KIBIS_WAVEFORM_TYPE::RECTANGULAR: simul += ".tran 0.1n 1000n \n"; break;
case KIBIS_WAVEFORM_TYPE::PRBS:
case KIBIS_WAVEFORM_TYPE::RECTANGULAR:
{
double duration = wave->GetDuration();
simul += ".tran 0.1n ";
simul += doubleToString( duration );
simul += "\n";
break;
}
case KIBIS_WAVEFORM_TYPE::HIGH_Z:
case KIBIS_WAVEFORM_TYPE::STUCK_LOW:
case KIBIS_WAVEFORM_TYPE::STUCK_HIGH:
@ -1097,15 +1122,30 @@ void KIBIS_PIN::getKuKdTwoWaveforms( KIBIS_MODEL& aMo
Report( _( "Driver needs at least a pullup or a pulldown" ), RPT_SEVERITY_ERROR );
}
simul += ".tran 0.1n 1000n \n";
switch( wave->GetType() )
{
case KIBIS_WAVEFORM_TYPE::RECTANGULAR:
case KIBIS_WAVEFORM_TYPE::PRBS:
{
double duration = wave->GetDuration();
simul += ".tran 0.1n ";
simul += doubleToString( duration );
simul += "\n";
break;
}
case KIBIS_WAVEFORM_TYPE::HIGH_Z:
case KIBIS_WAVEFORM_TYPE::STUCK_LOW:
case KIBIS_WAVEFORM_TYPE::STUCK_HIGH:
default: simul += ".tran 0.5 1 \n"; //
}
//simul += ".dc Vpin -5 5 0.1\n";
simul += ".control run \n";
simul += "set filetype=ascii\n";
simul += "run \n";
simul += "plot v(KU) v(KD)\n";
simul += "plot v(x1.DIE0) \n";
//simul += "plot v(x1.DIE0) \n";
simul += "write temp_output.spice v(KU) v(KD)\n"; // @TODO we might want to remove this...
//simul += "quit\n";
simul += "quit\n";
simul += ".endc \n";
simul += ".end \n";
@ -1142,13 +1182,13 @@ bool KIBIS_PIN::writeSpiceDriver( std::string* aDest, std::string aName, KIBIS_M
if( m_parent )
{
result += m_parent->m_name;
//result += m_parent->m_name;
}
result += "\n*Manufacturer: ";
if( m_parent )
{
result += m_parent->m_manufacturer;
//result += m_parent->m_manufacturer;
}
result += "\n*Pin number: ";
result += m_pinNumber;
@ -1303,13 +1343,13 @@ bool KIBIS_PIN::writeSpiceDiffDriver( std::string* aDest, std::string aName, KIB
if( m_parent )
{
result += m_parent->m_name;
//result += m_parent->m_name;
}
result += "\n*Manufacturer: ";
if( m_parent )
{
result += m_parent->m_manufacturer;
//result += m_parent->m_manufacturer;
}
result += "\n.SUBCKT ";
@ -1350,13 +1390,13 @@ bool KIBIS_PIN::writeSpiceDiffDevice( std::string* aDest, std::string aName, KIB
if( m_parent )
{
result += m_parent->m_name;
//result += m_parent->m_name;
}
result += "\n*Manufacturer: ";
if( m_parent )
{
result += m_parent->m_manufacturer;
//result += m_parent->m_manufacturer;
}
result += "\n.SUBCKT ";
@ -1414,3 +1454,38 @@ void KIBIS_PARAMETER::SetCornerFromString( IBIS_CORNER& aCorner, std::string aSt
else
aCorner = IBIS_CORNER::TYP;
}
std::vector<std::pair<int, double>> KIBIS_WAVEFORM_PRBS::GenerateBitSequence()
{
std::vector<std::pair<int, double>> bitSequence;
uint8_t polynomial = 0b1100000;
//1100000 = x^7+x^6+1
//10100 = x^5+x^3+1
//110 = x^3+x^2+1
uint8_t seed = 0x12; // Any non zero state
uint8_t lfsr = seed;
if ( m_bitrate == 0 )
return bitSequence;
double period = 1/m_bitrate;
double t = 0;
m_bits = abs( m_bits ); // Just to be sure.
int bits = 0;
do
{
uint8_t lsb = lfsr & 0x01;
bitSequence.emplace_back( ( inverted ^ lsb ? 1 : 0 ), t );
lfsr = lfsr >> 1;
if ( lsb )
lfsr ^= polynomial;
t += period;
} while ( ++bits < m_bits );
return bitSequence;
}

View File

@ -51,6 +51,7 @@ public:
enum KIBIS_WAVEFORM_TYPE
{
NONE = 0, // Used for three state
PRBS,
RECTANGULAR,
STUCK_HIGH,
STUCK_LOW,
@ -63,6 +64,7 @@ class KIBIS_WAVEFORM
public:
KIBIS_WAVEFORM(){};
KIBIS_WAVEFORM_TYPE GetType() { return m_type; };
virtual double GetDuration() { return 1; };
bool inverted = false; // Used for differential drivers
virtual ~KIBIS_WAVEFORM(){};
@ -76,8 +78,23 @@ public:
KIBIS_WAVEFORM_RECTANGULAR() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::RECTANGULAR; };
double m_ton = 100e-9;
double m_toff = 100e-9;
int m_cycles = 10;
int m_cycles = 1;
double m_delay = 0;
double GetDuration() override { return ( m_ton + m_toff ) * m_cycles; };
};
// For now, we only support PRBS7
class KIBIS_WAVEFORM_PRBS : public KIBIS_WAVEFORM
{
public:
KIBIS_WAVEFORM_PRBS() : KIBIS_WAVEFORM() { m_type = KIBIS_WAVEFORM_TYPE::PRBS; };
double m_bitrate = 10e6;
double m_delay = 0;
double m_bits = 10;
std::vector<std::pair<int, double>> GenerateBitSequence();
double GetDuration() override { return m_bits / m_bitrate ; };
};
class KIBIS_WAVEFORM_STUCK_HIGH : public KIBIS_WAVEFORM

View File

@ -43,6 +43,8 @@ int main( void )
KIBIS_PARAMETER params;
params.m_waveform = new KIBIS_WAVEFORM_RECTANGULAR();
pin2->writeSpiceDevice( tmp4, "device_typ", *( pin2->m_models.at( 0 ) ), params );
KIBIS_MODEL* model1 = pin1->m_models.at( 0 );