mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2024-11-24 22:05:02 +00:00
0d2371c9c3
Lot of things can be const which makes the interface a bit more legible and safe to use - lots of things are accessing pointers that if they changed, would have wierd and unpredicatable effects. Probably of minor concern in practice, but a lot of strings and vectors are being copied when they don't have to be. Very crude profiling indicates this could save 30-50% of the time in KIBIS::KIBIS after ParseFile, but this is incidental to clarifying the API of the classes. Report is const as it doesn't change the logical state of the IBIS_ANY object (if m_reporter were a ref, it'd be mutable). If a T* isn't null-checked inside a function, pass as ref to show that the function expects and requires non-nullity.
473 lines
16 KiB
C++
473 lines
16 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2022 Fabien Corona f.corona<at>laposte.net
|
|
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#ifndef KIBIS_H
|
|
#define KIBIS_H
|
|
|
|
#include "ibis_parser.h"
|
|
|
|
class KIBIS_PIN;
|
|
class KIBIS_FILE;
|
|
class KIBIS_MODEL;
|
|
class KIBIS_COMPONENT;
|
|
class KIBIS;
|
|
|
|
class KIBIS_ANY : public IBIS_ANY
|
|
{
|
|
protected:
|
|
KIBIS_ANY( KIBIS* aTopLevel );
|
|
|
|
/**
|
|
* Ctor for when a reporter is not available in the top level object
|
|
* (e.g. when the top level object itself is under construction)
|
|
*/
|
|
KIBIS_ANY( KIBIS* aTopLevel, REPORTER* aReporter );
|
|
|
|
public:
|
|
KIBIS* m_topLevel;
|
|
bool m_valid;
|
|
};
|
|
|
|
enum class KIBIS_WAVEFORM_TYPE
|
|
{
|
|
NONE = 0, // Used for three state
|
|
PRBS,
|
|
RECTANGULAR,
|
|
STUCK_HIGH,
|
|
STUCK_LOW,
|
|
HIGH_Z
|
|
};
|
|
|
|
|
|
class KIBIS_WAVEFORM : public KIBIS_ANY
|
|
{
|
|
public:
|
|
KIBIS_WAVEFORM( KIBIS& aTopLevel ) : KIBIS_ANY{ &aTopLevel } { m_valid = true; };
|
|
KIBIS_WAVEFORM_TYPE GetType() const { return m_type; };
|
|
virtual double GetDuration() const { return 1; };
|
|
bool inverted = false; // Used for differential drivers
|
|
virtual ~KIBIS_WAVEFORM() {};
|
|
|
|
virtual std::vector<std::pair<int, double>> GenerateBitSequence() const
|
|
{
|
|
std::vector<std::pair<int, double>> bits;
|
|
return bits;
|
|
};
|
|
|
|
// Check function if using waveform data
|
|
virtual bool Check( const IbisWaveform* aRisingWf, const IbisWaveform* aFallingWf ) const
|
|
{
|
|
return true;
|
|
};
|
|
// Check function if using ramp data
|
|
virtual bool Check( const dvdtTypMinMax& aRisingRp, const dvdtTypMinMax& aFallingRp ) const
|
|
{
|
|
return true;
|
|
};
|
|
|
|
protected:
|
|
KIBIS_WAVEFORM_TYPE m_type = KIBIS_WAVEFORM_TYPE::NONE;
|
|
};
|
|
|
|
class KIBIS_WAVEFORM_RECTANGULAR : public KIBIS_WAVEFORM
|
|
{
|
|
public:
|
|
KIBIS_WAVEFORM_RECTANGULAR( KIBIS& aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
|
|
{
|
|
m_type = KIBIS_WAVEFORM_TYPE::RECTANGULAR;
|
|
};
|
|
double m_ton = 100e-9;
|
|
double m_toff = 100e-9;
|
|
double m_delay = 0;
|
|
int m_cycles = 1;
|
|
|
|
|
|
std::vector<std::pair<int, double>> GenerateBitSequence() const override;
|
|
bool Check( const IbisWaveform* aRisingWf, const IbisWaveform* aFallingWf ) const override;
|
|
bool Check( const dvdtTypMinMax& aRisingRp, const dvdtTypMinMax& aFallingRp ) const override;
|
|
|
|
double GetDuration() const 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& aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
|
|
{
|
|
m_type = KIBIS_WAVEFORM_TYPE::PRBS;
|
|
};
|
|
double m_bitrate = 10e6;
|
|
double m_delay = 0;
|
|
int m_bits = 10;
|
|
|
|
std::vector<std::pair<int, double>> GenerateBitSequence() const override;
|
|
bool Check( const IbisWaveform* aRisingWf, const IbisWaveform* aFallingWf ) const override;
|
|
bool Check( const dvdtTypMinMax& aRisingRp, const dvdtTypMinMax& aFallingRp ) const override;
|
|
|
|
void SetBits( int aBits ) { m_bits = std::abs( aBits ); };
|
|
|
|
double GetDuration() const override { return m_bits / m_bitrate; };
|
|
};
|
|
|
|
class KIBIS_WAVEFORM_STUCK_HIGH : public KIBIS_WAVEFORM
|
|
{
|
|
public:
|
|
KIBIS_WAVEFORM_STUCK_HIGH( KIBIS& aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
|
|
{
|
|
m_type = KIBIS_WAVEFORM_TYPE::STUCK_HIGH;
|
|
};
|
|
std::vector<std::pair<int, double>> GenerateBitSequence() const override;
|
|
};
|
|
|
|
class KIBIS_WAVEFORM_STUCK_LOW : public KIBIS_WAVEFORM
|
|
{
|
|
public:
|
|
KIBIS_WAVEFORM_STUCK_LOW( KIBIS& aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
|
|
{
|
|
m_type = KIBIS_WAVEFORM_TYPE::STUCK_LOW;
|
|
};
|
|
std::vector<std::pair<int, double>> GenerateBitSequence() const override;
|
|
};
|
|
|
|
class KIBIS_WAVEFORM_HIGH_Z : public KIBIS_WAVEFORM
|
|
{
|
|
public:
|
|
KIBIS_WAVEFORM_HIGH_Z( KIBIS& aTopLevel ) : KIBIS_WAVEFORM( aTopLevel )
|
|
{
|
|
m_type = KIBIS_WAVEFORM_TYPE::HIGH_Z;
|
|
};
|
|
std::vector<std::pair<int, double>> GenerateBitSequence() const override;
|
|
};
|
|
|
|
/** Accuracy level.
|
|
*
|
|
* Level 0 is faster, but not as accurate
|
|
*
|
|
* Level 0 :
|
|
* - Driver: Don't use waveform
|
|
* - Driver: Don't use _DUT info
|
|
* Level 1 :
|
|
* _ Driver: Use up to one waveform
|
|
* _ Driver: Don't use _DUT info
|
|
* Level 2 :
|
|
* _ Driver: Use up to two waveforms
|
|
* _ Driver: Don't use _DUT info
|
|
*
|
|
* Level 3 : ( not implemented, fallback to level 2 )
|
|
* _ Driver: Use up to two waveforms
|
|
* _ Driver: Use _DUT info if at least one waveform
|
|
*/
|
|
enum class KIBIS_ACCURACY
|
|
{
|
|
LEVEL_0,
|
|
LEVEL_1,
|
|
LEVEL_2,
|
|
LEVEL_3,
|
|
};
|
|
|
|
class KIBIS_PARAMETER
|
|
{
|
|
public:
|
|
IBIS_CORNER m_Rpin = IBIS_CORNER::TYP;
|
|
IBIS_CORNER m_Lpin = IBIS_CORNER::TYP;
|
|
IBIS_CORNER m_Cpin = IBIS_CORNER::TYP;
|
|
IBIS_CORNER m_Ccomp = IBIS_CORNER::TYP;
|
|
IBIS_CORNER m_supply = IBIS_CORNER::TYP;
|
|
KIBIS_WAVEFORM* m_waveform = nullptr;
|
|
KIBIS_ACCURACY m_accuracy = KIBIS_ACCURACY::LEVEL_2;
|
|
|
|
void SetCornerFromString( IBIS_CORNER& aCorner, const std::string& aString );
|
|
};
|
|
|
|
|
|
class KIBIS_FILE : KIBIS_ANY
|
|
{
|
|
public:
|
|
KIBIS_FILE( KIBIS& aTopLevel );
|
|
|
|
std::string m_fileName;
|
|
double m_fileRev;
|
|
double m_ibisVersion;
|
|
std::string m_date;
|
|
std::string m_source;
|
|
std::string m_notes;
|
|
std::string m_disclaimer;
|
|
std::string m_copyright;
|
|
|
|
bool Init( const IbisParser& aParser );
|
|
};
|
|
|
|
class KIBIS_MODEL : public KIBIS_ANY
|
|
{
|
|
public:
|
|
KIBIS_MODEL( KIBIS& aTopLevel, const IbisModel& aSource, IbisParser& aParser );
|
|
|
|
std::string m_name;
|
|
std::string m_description;
|
|
IBIS_MODEL_TYPE m_type = IBIS_MODEL_TYPE::UNDEFINED;
|
|
/* The Polarity, Enable, Vinl, Vinh, Vmeas, Cref, Rref, and Vref subparameters are optional. */
|
|
/* the default values of Vinl = 0.8 V and Vinh = 2.0 V are assumed. */
|
|
double m_vinl = 0.8;
|
|
double m_vinh = 2;
|
|
double m_vref = 0;
|
|
double m_rref = 0;
|
|
double m_cref = 0;
|
|
double m_vmeas = 0;
|
|
IBIS_MODEL_ENABLE m_enable = IBIS_MODEL_ENABLE::UNDEFINED;
|
|
IBIS_MODEL_POLARITY m_polarity = IBIS_MODEL_POLARITY::UNDEFINED;
|
|
// End of optional subparameters
|
|
|
|
TypMinMaxValue m_C_comp;
|
|
TypMinMaxValue m_voltageRange;
|
|
TypMinMaxValue m_temperatureRange;
|
|
TypMinMaxValue m_pullupReference;
|
|
TypMinMaxValue m_pulldownReference;
|
|
TypMinMaxValue m_GNDClampReference;
|
|
TypMinMaxValue m_POWERClampReference;
|
|
TypMinMaxValue m_Rgnd;
|
|
TypMinMaxValue m_Rpower;
|
|
TypMinMaxValue m_Rac;
|
|
TypMinMaxValue m_Cac;
|
|
IVtable m_GNDClamp;
|
|
IVtable m_POWERClamp;
|
|
IVtable m_pullup;
|
|
IVtable m_pulldown;
|
|
std::vector<IbisWaveform*> m_risingWaveforms;
|
|
std::vector<IbisWaveform*> m_fallingWaveforms;
|
|
IbisRamp m_ramp;
|
|
|
|
/** @brief Return true if the model has a pulldown transistor */
|
|
bool HasPulldown() const;
|
|
/** @brief Return true if the model has a pullup transistor */
|
|
bool HasPullup() const;
|
|
/** @brief Return true if the model has a clamp diode to the gnd net */
|
|
bool HasGNDClamp() const;
|
|
/** @brief Return true if the model has a clamp diode to the power net */
|
|
bool HasPOWERClamp() const;
|
|
|
|
/** @brief Generate the spice directive to simulate the die
|
|
*
|
|
* @param aParam Parameters
|
|
* @param aIndex Index used to offset spice nodes / directives
|
|
* @return A multiline string with spice directives
|
|
*/
|
|
std::string SpiceDie( const KIBIS_PARAMETER& aParam, int aIndex ) const;
|
|
|
|
/** @brief Create waveform pairs
|
|
*
|
|
* For maximum accuracy, we need a waveform pair.
|
|
* This function creates the pairs based on the fixture.
|
|
* The first element is the rising edge, the second is the falling edge.
|
|
*
|
|
* @return a vector of waveform pairs
|
|
*/
|
|
std::vector<std::pair<IbisWaveform*, IbisWaveform*>> waveformPairs();
|
|
|
|
|
|
/** @brief Generate a square waveform
|
|
*
|
|
* For maximum accuracy, we need a waveform pair.
|
|
* This function creates the pairs based on the fixture.
|
|
*
|
|
* @param aNode1 node where the voltage is applied
|
|
* @param aNode2 Reference node
|
|
* @param aBits The first member is the bit value ( 1 or 0 ).
|
|
* The second member is the time of the transition edge.
|
|
* @param aPair @see waveformPairs()
|
|
* @param aParam Parameters
|
|
* @return A multiline string with spice directives
|
|
*/
|
|
std::string generateSquareWave( const std::string& aNode1, const std::string& aNode2,
|
|
const std::vector<std::pair<int, double>>& aBits,
|
|
const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
|
|
const KIBIS_PARAMETER& aParam );
|
|
|
|
|
|
/** @brief Copy a waveform, and substract the first value to all samples
|
|
*
|
|
*
|
|
* @param aIn Input waveform
|
|
* @return Output waveform
|
|
*/
|
|
IbisWaveform TrimWaveform( const IbisWaveform& aIn ) const;
|
|
};
|
|
|
|
class KIBIS_PIN : public KIBIS_ANY
|
|
{
|
|
public:
|
|
KIBIS_PIN( KIBIS& aTopLevel, const IbisComponentPin& aPin, const IbisComponentPackage& aPackage,
|
|
IbisParser& aParser, KIBIS_COMPONENT* aParent, std::vector<KIBIS_MODEL>& aModels );
|
|
/** @brief Name of the pin
|
|
* Examples : "VCC", "GPIOA", "CLK", etc...
|
|
*/
|
|
std::string m_signalName;
|
|
/** @brief Pin Number
|
|
* Examples : 1, 2, 3 ( or for BGA ), A1, A2, A3, etc...
|
|
*/
|
|
std::string m_pinNumber;
|
|
|
|
/** @brief Resistance from die to pin */
|
|
TypMinMaxValue m_Rpin;
|
|
/** @brief Inductance from die to pin */
|
|
TypMinMaxValue m_Lpin;
|
|
/** @brief Capacitance from pin to GND */
|
|
TypMinMaxValue m_Cpin;
|
|
|
|
KIBIS_COMPONENT* m_parent;
|
|
|
|
std::vector<double> m_t, m_Ku, m_Kd;
|
|
|
|
std::vector<KIBIS_MODEL*> m_models;
|
|
|
|
bool writeSpiceDriver( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
|
|
const KIBIS_PARAMETER& aParam );
|
|
bool writeSpiceDiffDriver( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
|
|
const KIBIS_PARAMETER& aParam );
|
|
bool writeSpiceDevice( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
|
|
const KIBIS_PARAMETER& aParam );
|
|
bool writeSpiceDiffDevice( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
|
|
const KIBIS_PARAMETER& aParam );
|
|
|
|
/** @brief Update m_Ku, m_Kd using no falling / rising waveform inputs ( low accuracy )
|
|
* @param aModel Model to be used
|
|
* @param aParam Parameters
|
|
*/
|
|
void getKuKdNoWaveform( KIBIS_MODEL& aModel, const KIBIS_PARAMETER& aParam );
|
|
|
|
/** @brief Update m_Ku, m_Kd using with a single waveform input
|
|
* @param aModel Model to be used
|
|
* @param aPair @see waveformPairs()
|
|
* @param aParam Parameters
|
|
*/
|
|
void getKuKdOneWaveform( KIBIS_MODEL& aModel,
|
|
const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
|
|
const KIBIS_PARAMETER& aParam );
|
|
|
|
/** @brief Update m_Ku, m_Kd using with two waveform inputs
|
|
*
|
|
* The order of aPair1 and aPair2 is not important.
|
|
* @param aModel Model to be used
|
|
* @param aPair1 @see waveformPairs()
|
|
* @param aPair2 @see waveformPairs()
|
|
* @param aParam Parameters
|
|
* @param aIndex Index for numbering spice .SUBCKT
|
|
*/
|
|
void getKuKdTwoWaveforms( KIBIS_MODEL& aModel,
|
|
const std::pair<IbisWaveform*, IbisWaveform*>& aPair1,
|
|
const std::pair<IbisWaveform*, IbisWaveform*>& aPair2,
|
|
const KIBIS_PARAMETER& aParam );
|
|
|
|
/** @brief Update m_Ku, m_Kd using with two waveform inputs
|
|
*
|
|
* The order of aPair1 and aPair2 is not important.
|
|
* @param aModel Model to be used
|
|
* @param aPair @see waveformPairs()
|
|
* @param aParam Parameters
|
|
* @param aIndex Index for numbering spice .SUBCKT
|
|
*
|
|
* @return A multiline string with spice directives
|
|
*/
|
|
std::string KuKdDriver( KIBIS_MODEL& aModel,
|
|
const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
|
|
const KIBIS_PARAMETER& aParam, int aIndex );
|
|
|
|
/** @brief Generate the spice directive to simulate the die for Ku/Kd estimation
|
|
*
|
|
* DO NOT use it in order to generate a model.
|
|
* It sole purpose is to run the internal simulation to get Ku/Kd
|
|
*
|
|
* @param aModel Model to be used
|
|
* @param aParam Parameters
|
|
* @param aIndex Index for numbering ports
|
|
* @return A multiline string with spice directives
|
|
*/
|
|
std::string addDie( KIBIS_MODEL& aModel, const KIBIS_PARAMETER& aParam, int aIndex );
|
|
|
|
|
|
/** @brief Update m_Ku, m_Kd using with two waveform inputs
|
|
*
|
|
* Runs a simulation. The simulation creates a specific file with Ku/Kd values
|
|
* This function then reads the output file and updates m_Ku / m_Kd.
|
|
* This function probably needs a rewrite.
|
|
*
|
|
* @param aSimul The simulation to run, multiline spice directives
|
|
*/
|
|
void getKuKdFromFile( const std::string& aSimul );
|
|
|
|
KIBIS_PIN* m_complementaryPin = nullptr;
|
|
|
|
bool isDiffPin() const { return m_complementaryPin != nullptr; };
|
|
};
|
|
|
|
class KIBIS_COMPONENT : public KIBIS_ANY
|
|
{
|
|
public:
|
|
KIBIS_COMPONENT( KIBIS& aToplevel, const IbisComponent& aSource, IbisParser& aParser );
|
|
/** @brief Name of the component */
|
|
std::string m_name;
|
|
/** @brief Name of the manufacturer */
|
|
std::string m_manufacturer;
|
|
|
|
std::vector<KIBIS_PIN> m_pins;
|
|
|
|
/** @brief Get a pin by its number ( 1, 2, A1, A2, ... )
|
|
*
|
|
* @param aPinNumber pin number
|
|
* @return pointer to a KIBIS_PIN, or nullptr if there is no matching pin
|
|
*/
|
|
KIBIS_PIN* GetPin( const std::string& aPinNumber );
|
|
};
|
|
|
|
class KIBIS : public KIBIS_ANY
|
|
{
|
|
public:
|
|
/** @brief Constructor for unitialized KIBIS members */
|
|
KIBIS() : KIBIS_ANY( this, nullptr ), m_file( *this ) {};
|
|
|
|
KIBIS( const std::string& aFileName, REPORTER* aReporter = nullptr );
|
|
|
|
std::vector<KIBIS_COMPONENT> m_components;
|
|
std::vector<KIBIS_MODEL> m_models;
|
|
KIBIS_FILE m_file;
|
|
|
|
/** @brief Absolute path of the directory that will be used for caching. */
|
|
std::string m_cacheDir = "";
|
|
|
|
/** @brief Return the model with name aName . Nullptr if not found */
|
|
KIBIS_MODEL* GetModel( const std::string& aName );
|
|
/** @brief Return the component with name aName . Nullptr if not found */
|
|
KIBIS_COMPONENT* GetComponent( const std::string& aName );
|
|
};
|
|
|
|
#endif
|