KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kibis.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2022 Fabien Corona f.corona<at>laposte.net
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
18 * to endorse or promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33#include "kibis.h"
34#include "ibis_parser.h"
35#include <sstream>
36#include <sim/spice_simulator.h>
37
38
39// _() is used here to mark translatable strings in IBIS_REPORTER::Report()
40// However, currently non ASCII7 chars are nor correctly handled when printing messages
41// So we disable translations
42#if 0
43#include <wx/intl.h> // for _() macro and wxGetTranslation()
44#else
45#undef _
46#define _( x ) x
47#endif
48
49
50std::vector<std::pair<int, double>>
51SimplifyBitSequence( const std::vector<std::pair<int, double>>& bits )
52{
53 std::vector<std::pair<int, double>> result;
54 int prevbit = -1;
55
56 for( const std::pair<int, double>& bit : bits )
57 {
58 if( prevbit != bit.first )
59 result.push_back( bit );
60
61 prevbit = bit.first;
62 }
63
64 return result;
65}
66
67
69 KIBIS_BASE( aTopLevel, aTopLevel->m_Reporter )
70{
71}
72
73
74KIBIS_BASE::KIBIS_BASE( KIBIS* aTopLevel, REPORTER* aReporter ) :
75 IBIS_BASE( aReporter ),
76 m_topLevel( aTopLevel ),
77 m_valid( false )
78{
79}
80
81
83{
85
86 if( aIn == IBIS_CORNER::MIN )
87 out = IBIS_CORNER::MAX;
88 else if( aIn == IBIS_CORNER::MAX )
89 out = IBIS_CORNER::MIN;
90
91 return out;
92}
93
94KIBIS::KIBIS( const std::string& aFileName, REPORTER* aReporter ) :
95 KIBIS_BASE( this, aReporter ),
96 m_file( *this )
97{
98 IbisParser parser( m_Reporter );
99 bool status = true;
100
101 parser.m_parrot = false;
102 status &= parser.ParseFile( aFileName );
103
104 status &= m_file.Init( parser );
105
106 for( const IbisModel& iModel : parser.m_ibisFile.m_models )
107 {
108 KIBIS_MODEL& kModel = m_models.emplace_back( *this, iModel, parser );
109 status &= kModel.m_valid;
110 }
111
112 for( const IbisComponent& iComponent : parser.m_ibisFile.m_components )
113 {
114 KIBIS_COMPONENT& kComponent = m_components.emplace_back( *this, iComponent, parser );
115 status &= kComponent.m_valid;
116
117 for( KIBIS_PIN& pin : kComponent.m_pins )
118 pin.m_parent = &kComponent;
119
120 for( const IbisDiffPinEntry& dpEntry : iComponent.m_diffPin.m_entries )
121 {
122 KIBIS_PIN* pinA = kComponent.GetPin( dpEntry.pinA );
123 KIBIS_PIN* pinB = kComponent.GetPin( dpEntry.pinB );
124
125 if( pinA && pinB )
126 {
127 pinA->m_complementaryPin = pinB;
128 pinB->m_complementaryPin = pinA;
129 }
130 }
131 }
132
133 m_valid = status;
134}
135
136
138 KIBIS_BASE( &aTopLevel )
139{
140 m_fileRev = -1;
141 m_ibisVersion = -1;
142}
143
144
145bool KIBIS_FILE::Init( const IbisParser& aParser )
146{
147 bool status = true;
155
156 m_valid = status;
157
158 return status;
159}
160
161
163 const IbisComponentPackage& aPackage, IbisParser& aParser,
164 KIBIS_COMPONENT* aParent, std::vector<KIBIS_MODEL>& aModels ) :
165 KIBIS_BASE( &aTopLevel ),
166 m_Rpin( aTopLevel.m_Reporter ),
167 m_Lpin( aTopLevel.m_Reporter ),
168 m_Cpin( aTopLevel.m_Reporter )
169{
171 m_pinNumber = aPin.m_pinName;
172 m_parent = aParent;
173
174 m_Rpin = aPackage.m_Rpkg;
175 m_Lpin = aPackage.m_Lpkg;
176 m_Cpin = aPackage.m_Cpkg;
177
178 // The values listed in the [Pin] description section override the default
179 // values defined in [Package]
180
181 // @TODO : Reading the IBIS standard, I can't figure out if we are supposed
182 // to replace typ, min, and max, or just the typ ?
183
184 if( !std::isnan( aPin.m_Rpin ) )
185 {
186 m_Rpin.value[IBIS_CORNER::TYP] = aPin.m_Rpin;
187 m_Rpin.value[IBIS_CORNER::MIN] = aPin.m_Rpin;
188 m_Rpin.value[IBIS_CORNER::MAX] = aPin.m_Rpin;
189 }
190
191 if( !std::isnan( aPin.m_Lpin ) )
192 {
193 m_Lpin.value[IBIS_CORNER::TYP] = aPin.m_Lpin;
194 m_Lpin.value[IBIS_CORNER::MIN] = aPin.m_Lpin;
195 m_Lpin.value[IBIS_CORNER::MAX] = aPin.m_Lpin;
196 }
197
198 if( !std::isnan( aPin.m_Cpin ) )
199 {
200 m_Cpin.value[IBIS_CORNER::TYP] = aPin.m_Cpin;
201 m_Cpin.value[IBIS_CORNER::MIN] = aPin.m_Cpin;
202 m_Cpin.value[IBIS_CORNER::MAX] = aPin.m_Cpin;
203 }
204
205 bool modelSelected = false;
206 std::vector<std::string> listOfModels;
207
208 for( const IbisModelSelector& modelSelector : aParser.m_ibisFile.m_modelSelectors )
209 {
210 if( !strcmp( modelSelector.m_name.c_str(), aPin.m_modelName.c_str() ) )
211 {
212 for( const IbisModelSelectorEntry& model : modelSelector.m_models )
213 listOfModels.push_back( model.m_modelName );
214
215 modelSelected = true;
216 break;
217 }
218 }
219
220 if( !modelSelected )
221 listOfModels.push_back( aPin.m_modelName );
222
223 for( const std::string& modelName : listOfModels )
224 {
225 for( KIBIS_MODEL& model : aModels )
226 {
227 if( !strcmp( model.m_name.c_str(), modelName.c_str() ) )
228 m_models.push_back( &model );
229 }
230 }
231
232 m_valid = true;
233}
234
235
237 KIBIS_BASE( &aTopLevel ),
238 m_GNDClamp( aTopLevel.m_Reporter ),
239 m_POWERClamp( aTopLevel.m_Reporter )
240{
241 m_name = aSource.m_name;
242 m_type = aSource.m_type;
243 m_mode = aMode;
244
245 m_GNDClamp = aSource.m_GNDClamp;
246 m_POWERClamp = aSource.m_POWERClamp;
247
248 m_valid = true;
249}
250
252{
253 return m_GNDClamp.m_entries.size() > 0;
254}
255
256
258{
259 return m_POWERClamp.m_entries.size() > 0;
260}
261
262
263KIBIS_MODEL::KIBIS_MODEL( KIBIS& aTopLevel, const IbisModel& aSource, IbisParser& aParser ) :
264 KIBIS_BASE( &aTopLevel ),
265 m_C_comp( aTopLevel.m_Reporter ),
266 m_voltageRange( aTopLevel.m_Reporter ),
267 m_temperatureRange( aTopLevel.m_Reporter ),
268 m_pullupReference( aTopLevel.m_Reporter ),
269 m_pulldownReference( aTopLevel.m_Reporter ),
270 m_GNDClampReference( aTopLevel.m_Reporter ),
272 m_Rgnd( aTopLevel.m_Reporter ),
273 m_Rpower( aTopLevel.m_Reporter ),
274 m_Rac( aTopLevel.m_Reporter ),
275 m_Cac( aTopLevel.m_Reporter ),
276 m_GNDClamp( aTopLevel.m_Reporter ),
277 m_POWERClamp( aTopLevel.m_Reporter ),
278 m_pullup( aTopLevel.m_Reporter ),
279 m_pulldown( aTopLevel.m_Reporter ),
280 m_ramp( aTopLevel.m_Reporter ),
281 m_series( aTopLevel.m_Reporter ),
282 m_seriesOn( aTopLevel.m_Reporter ),
283 m_seriesOff( aTopLevel.m_Reporter )
284{
285 bool status = true;
286
287 m_name = aSource.m_name;
288 m_type = aSource.m_type;
289
290 m_description = std::string( "No description available." );
291
292 for( const IbisModelSelector& modelSelector : aParser.m_ibisFile.m_modelSelectors )
293 {
294 for( const IbisModelSelectorEntry& entry : modelSelector.m_models )
295 {
296 if( !strcmp( entry.m_modelName.c_str(), m_name.c_str() ) )
298 }
299 }
300
301 m_vinh = aSource.m_vinh;
302 m_vinl = aSource.m_vinl;
303 m_vref = aSource.m_vref;
304 m_rref = aSource.m_rref;
305 m_cref = aSource.m_cref;
306 m_vmeas = aSource.m_vmeas;
307
308 m_enable = aSource.m_enable;
309 m_polarity = aSource.m_polarity;
310
311 m_ramp = aSource.m_ramp;
314 m_GNDClamp = aSource.m_GNDClamp;
316 m_POWERClamp = aSource.m_POWERClamp;
318
319 if( aSource.m_C_comp.isNA() )
320 {
321 m_C_comp.value[IBIS_CORNER::TYP] = 0.0;
322 m_C_comp.value[IBIS_CORNER::MIN] = 0.0;
323 m_C_comp.value[IBIS_CORNER::MAX] = 0.0;
324 m_C_comp.Add( aSource.m_C_comp_pullup );
325 m_C_comp.Add( aSource.m_C_comp_pulldown );
326 m_C_comp.Add( aSource.m_C_comp_gnd_clamp );
327 m_C_comp.Add( aSource.m_C_comp_power_clamp );
328 }
329 else
330 {
331 m_C_comp = aSource.m_C_comp;
332 }
337
338 m_Rgnd = aSource.m_Rgnd;
339 m_Rpower = aSource.m_Rpower;
340 m_Rac = aSource.m_Rac;
341 m_Cac = aSource.m_Cac;
342 m_pullup = aSource.m_pullup;
343 m_pulldown = aSource.m_pulldown;
344
345 m_series = aSource.m_series;
346 m_seriesOn = aSource.m_seriesOn;
347 m_seriesOff = aSource.m_seriesOff;
348
349 for( const IbisSubmodelMode& submodel : aSource.m_submodels )
350 {
351 auto it = aParser.m_ibisFile.m_submodels.find( submodel.m_name );
352
353 if( it != aParser.m_ibisFile.m_submodels.end() )
354 {
355 const IbisSubmodel& submodelSource = it->second;
356
357 // For now, we only support static mode dynamic clamp submodels.
358 if( submodelSource.m_type != IBIS_SUBMODEL_TYPE::DYNAMIC_CLAMP
359 || !submodelSource.m_VtriggerR.isNA()
360 || !submodelSource.m_VtriggerF.isNA() )
361 {
362 break;
363 }
364
365 m_submodels.emplace_back( aTopLevel, submodelSource, submodel.m_mode );
366 }
367 }
368
369 m_valid = status;
370}
371
372
374 IbisParser& aParser ) :
375 KIBIS_BASE( &aTopLevel )
376{
377 bool status = true;
378
379 m_name = aSource.m_name;
381
382 for( const IbisComponentPin& iPin : aSource.m_pins )
383 {
384 if( iPin.m_dummy )
385 continue;
386
387 KIBIS_PIN kPin( aTopLevel, iPin, aSource.m_package, aParser, nullptr,
388 m_topLevel->m_models );
389 status &= kPin.m_valid;
390 m_pins.push_back( kPin );
391 }
392
393 for( const IbisComponentSeriesPinMapping& iPair : aSource.m_seriesPinMappings )
394 {
395 m_seriesPinMappings.push_back( { iPair.m_pin1, iPair.m_pin2, iPair.m_modelName,
396 iPair.m_functionTableGroup } );
397 }
398
399 m_valid = status;
400}
401
402
403KIBIS_PIN* KIBIS_PIN::SeriesPartner( std::string* aModelName, std::string* aGroupName ) const
404{
405 if( !m_parent )
406 return nullptr;
407
408 for( const KIBIS_SERIES_PAIR& pair : m_parent->m_seriesPinMappings )
409 {
410 const std::string* other = nullptr;
411
412 if( pair.m_pin1 == m_pinNumber )
413 other = &pair.m_pin2;
414 else if( pair.m_pin2 == m_pinNumber )
415 other = &pair.m_pin1;
416 else
417 continue;
418
419 if( aModelName )
420 *aModelName = pair.m_modelName;
421
422 if( aGroupName )
423 *aGroupName = pair.m_groupName;
424
425 return m_parent->GetPin( *other );
426 }
427
428 return nullptr;
429}
430
431
432KIBIS_PIN* KIBIS_COMPONENT::GetPin( const std::string& aPinNumber )
433{
434 for( KIBIS_PIN& pin : m_pins )
435 {
436 if( pin.m_pinNumber == aPinNumber )
437 return &pin;
438 }
439
440 return nullptr;
441}
442
443std::vector<std::pair<IbisWaveform*, IbisWaveform*>> KIBIS_MODEL::waveformPairs()
444{
445 std::vector<std::pair<IbisWaveform*, IbisWaveform*>> pairs;
446 IbisWaveform* wf1;
447 IbisWaveform* wf2;
448
449 for( size_t i = 0; i < m_risingWaveforms.size(); i++ )
450 {
451 for( size_t j = 0; j < m_fallingWaveforms.size(); j++ )
452 {
453 wf1 = m_risingWaveforms.at( i );
454 wf2 = m_fallingWaveforms.at( j );
455
456 if( wf1->m_R_fixture == wf2->m_R_fixture && wf1->m_L_fixture == wf2->m_L_fixture
457 && wf1->m_C_fixture == wf2->m_C_fixture && wf1->m_V_fixture == wf2->m_V_fixture
458 && wf1->m_V_fixture_min == wf2->m_V_fixture_min
459 && wf1->m_V_fixture_max == wf2->m_V_fixture_max )
460 {
461 pairs.emplace_back( wf1, wf2 );
462 }
463 }
464 }
465
466 return pairs;
467}
468
469
470std::string KIBIS_MODEL::SpiceDie( const KIBIS_PARAMETER& aParam, int aIndex, bool aDriver ) const
471{
472 std::string result;
473
474 std::string GC_GND = "GC_GND";
475 std::string PC_PWR = "PC_PWR";
476 std::string PU_PWR = "PU_PWR";
477 std::string PD_GND = "PD_GND";
478 std::string DIE = "DIE";
479 std::string DIEBUFF = "DIEBUFF";
480
481 IBIS_CORNER supply = aParam.m_supply;
482 IBIS_CORNER ccomp = aParam.m_Ccomp;
483
484 GC_GND += std::to_string( aIndex );
485 PC_PWR += std::to_string( aIndex );
486 PU_PWR += std::to_string( aIndex );
487 PD_GND += std::to_string( aIndex );
488 DIE += std::to_string( aIndex );
489 DIEBUFF += std::to_string( aIndex );
490
491
492 std::string GC = "GC";
493 std::string PC = "PC";
494 std::string PU = "PU";
495 std::string PD = "PD";
496
497 GC += std::to_string( aIndex );
498 PC += std::to_string( aIndex );
499 PU += std::to_string( aIndex );
500 PD += std::to_string( aIndex );
501
502 result = "\n";
503 result += "VPWR POWER GND ";
504 result += doubleToString( m_voltageRange.value[supply] );
505 result += "\n";
506 result += "CCPOMP " + DIE + " GND ";
507 result += doubleToString( m_C_comp.value[ccomp] );
508 result += "\n";
509
510 if( HasGNDClamp() )
511 {
512 result += m_GNDClamp.Spice( aIndex * 4 + 1, DIE, GC_GND, false, GC, supply );
513 result += "Vmeas" + GC + " GND " + GC_GND + " 0\n";
514 }
515
516 if( HasPOWERClamp() )
517 {
518 result += m_POWERClamp.Spice( aIndex * 4 + 2, PC_PWR, DIE, true, PC, supply );
519 result += "Vmeas" + PC + " POWER " + PC_PWR + " 0\n";
520 }
521
522 if( aDriver && HasPulldown() )
523 {
524 result += m_pulldown.Spice( aIndex * 4 + 3, DIEBUFF, PD_GND, false, PD, supply );
525 result += "VmeasPD GND " + PD_GND + " 0\n";
526 result += "BKD GND " + DIE + " i=( i(VmeasPD) * v(KD) )\n";
527 }
528
529 if( aDriver && HasPullup() )
530 {
531 result += m_pullup.Spice( aIndex * 4 + 4, PU_PWR, DIEBUFF, false, PU, supply );
532 result += "VmeasPU POWER " + PU_PWR + " 0\n";
533 result += "BKU POWER " + DIE + " i=( -i(VmeasPU) * v(KU) )\n";
534 }
535
536 if( aDriver && ( HasPullup() || HasPulldown() ) )
537 result += "BDIEBUFF " + DIEBUFF + " GND v=v(" + DIE + ")\n";
538
539 for( const KIBIS_SUBMODEL& submodel : m_submodels )
540 {
541 if( aDriver && ( submodel.m_mode == IBIS_SUBMODEL_MODE::NON_DRIVING ) )
542 continue;
543
544 if( !aDriver && ( submodel.m_mode == IBIS_SUBMODEL_MODE::DRIVING ) )
545 continue;
546
547 aIndex++;
548
549 GC_GND = "GC_GND" + std::to_string( aIndex );
550 PC_PWR = "PC_PWR" + std::to_string( aIndex );
551
552 GC = "GC" + std::to_string( aIndex );
553 PC = "PC" + std::to_string( aIndex );
554
555 if( submodel.HasGNDClamp() )
556 {
557 result += submodel.m_GNDClamp.Spice( aIndex * 4 + 1, DIE, GC_GND, false, GC, supply );
558 result += "Vmeas" + GC + " GND " + GC_GND + " 0\n";
559 }
560
561 if( submodel.HasPOWERClamp() )
562 {
563 result += submodel.m_POWERClamp.Spice( aIndex * 4 + 2, PC_PWR, DIE, true, PC, supply );
564 result += "Vmeas" + PC + " POWER " + PC_PWR + " 0\n";
565 }
566 }
567
568 return result;
569}
570
571
572std::string KIBIS_MODEL::SpiceSeriesDie( const KIBIS_PARAMETER& aParam, int aIndex,
573 const std::string& aPort1, const std::string& aPort2,
574 const IbisSeriesData& aData,
575 const std::string& aGate ) const
576{
577 std::string result;
578 IBIS_CORNER corner = aParam.m_supply;
579 std::string idx = std::to_string( aIndex );
580
581 // Gated arms terminate at ARM_OUT; a parametric resistor bridges it to
582 // aPort2 with ~mΩ when aGate ~= 1 and ~TΩ when ~= 0.
583 const bool gated = !aGate.empty();
584 std::string p2 = gated ? ( "ARM_OUT" + idx ) : aPort2;
585
586 if( !aData.m_Rseries.isNA() )
587 {
588 result += "R_S" + idx + " " + aPort1 + " " + p2 + " ";
589 result += doubleToString( aData.m_Rseries.value[corner] );
590 result += "\n";
591 }
592
593 if( !aData.m_Lseries.isNA() )
594 {
595 std::string nL = "n_L" + idx;
596 result += "L_S" + idx + " " + aPort1 + " " + nL + " ";
597 result += doubleToString( aData.m_Lseries.value[corner] );
598 result += "\n";
599
600 double rl = aData.m_RlSeries.isNA() ? 0.0 : aData.m_RlSeries.value[corner];
601 result += "R_Sl" + idx + " " + nL + " " + p2 + " ";
602 result += doubleToString( rl );
603 result += "\n";
604 }
605
606 if( !aData.m_Cseries.isNA() )
607 {
608 std::string node1 = aPort1;
609 int subnode = 0;
610
611 if( !aData.m_RcSeries.isNA() )
612 {
613 std::string n = "n_Cr" + idx + "_" + std::to_string( subnode++ );
614 result += "R_Sc" + idx + " " + node1 + " " + n + " ";
615 result += doubleToString( aData.m_RcSeries.value[corner] );
616 result += "\n";
617 node1 = n;
618 }
619
620 if( !aData.m_LcSeries.isNA() )
621 {
622 std::string n = "n_Cl" + idx + "_" + std::to_string( subnode++ );
623 result += "L_Sc" + idx + " " + node1 + " " + n + " ";
624 result += doubleToString( aData.m_LcSeries.value[corner] );
625 result += "\n";
626 node1 = n;
627 }
628
629 result += "C_S" + idx + " " + node1 + " " + p2 + " ";
630 result += doubleToString( aData.m_Cseries.value[corner] );
631 result += "\n";
632 }
633
634 // Use B-source pwl() instead of IVtable::Spice's xspice 'a' device:
635 // XSPICE code models (pwl.cm) aren't always loaded in embedded ngspice.
636 if( !aData.m_seriesCurrent.m_entries.empty() )
637 {
638 std::string expr = "pwl(v(" + aPort1 + "," + p2 + ")";
639
640 for( const IVtableEntry& e : aData.m_seriesCurrent.m_entries )
641 {
642 if( std::isnan( e.I.value[corner] ) )
643 continue;
644
645 expr += "," + doubleToString( e.V ) + "," + doubleToString( e.I.value[corner] );
646 }
647
648 expr += ")";
649 result += "B_SC" + idx + " " + aPort1 + " " + p2 + " i = " + expr + "\n";
650 }
651
652 // BIRD 41.8 §5: ids = Ids(Vgs, Vds_fixed) × vds / Vds_fixed.
653 // Vgs = m_voltageRange[supply] − min(V(P1), V(P2)).
654 int mIdx = 0;
655 const double vcc = m_voltageRange.value[corner];
656
657 for( const IbisMosfetEntry& mosfet : aData.m_seriesMosfet )
658 {
659 if( mosfet.m_table.m_entries.empty() || std::isnan( mosfet.m_Vds ) || mosfet.m_Vds <= 0.0 )
660 continue;
661
662 std::string suffix = idx + "_" + std::to_string( mIdx++ );
663 std::string tableExpr = "pwl(" + doubleToString( vcc ) + "-min(v(" + aPort1 + "),v("
664 + aPort2 + "))";
665
666 for( const IVtableEntry& e : mosfet.m_table.m_entries )
667 {
668 if( std::isnan( e.I.value[corner] ) )
669 continue;
670
671 tableExpr += "," + doubleToString( e.V ) + "," + doubleToString( e.I.value[corner] );
672 }
673
674 tableExpr += ")";
675
676 result += "B_M" + suffix + " " + aPort1 + " " + p2 + " i = ";
677 result += "(" + tableExpr + ") * (v(" + aPort1 + "," + p2 + ") / "
678 + doubleToString( mosfet.m_Vds ) + ")";
679 result += "\n";
680 }
681
682 if( gated )
683 {
684 result += "R_G" + idx + " " + p2 + " " + aPort2 + " R='0.001 / ((" + aGate + ") + 1e-12)'";
685 result += "\n";
686 }
687
688 return result;
689}
690
691
693{
694 IbisWaveform out( aIn.m_Reporter );
695
696 const int nbPoints = aIn.m_table.m_entries.size();
697
698 if( nbPoints < 2 )
699 {
700 Report( _( "waveform has less than two points" ), RPT_SEVERITY_ERROR );
701 return out;
702 }
703
704 const double DCtyp = aIn.m_table.m_entries[0].V.value[IBIS_CORNER::TYP];
705 const double DCmin = aIn.m_table.m_entries[0].V.value[IBIS_CORNER::MIN];
706 const double DCmax = aIn.m_table.m_entries[0].V.value[IBIS_CORNER::MAX];
707
708 if( nbPoints == 2 )
709 return out;
710
711 out.m_table.m_entries.clear();
712
713 for( int i = 0; i < nbPoints; i++ )
714 {
715 const VTtableEntry& inEntry = aIn.m_table.m_entries.at( i );
716 VTtableEntry& outEntry = out.m_table.m_entries.emplace_back( out.m_Reporter );
717
718 outEntry.t = inEntry.t;
719 outEntry.V.value[IBIS_CORNER::TYP] = inEntry.V.value[IBIS_CORNER::TYP] - DCtyp;
720 outEntry.V.value[IBIS_CORNER::MIN] = inEntry.V.value[IBIS_CORNER::MIN] - DCmin;
721 outEntry.V.value[IBIS_CORNER::MAX] = inEntry.V.value[IBIS_CORNER::MAX] - DCmax;
722 }
723
724 return out;
725}
726
727
729{
730 return m_pulldown.m_entries.size() > 0;
731}
732
733
735{
736 return m_pullup.m_entries.size() > 0;
737}
738
739
741{
742 return m_GNDClamp.m_entries.size() > 0;
743}
744
745
747{
748 return m_POWERClamp.m_entries.size() > 0;
749}
750
751
752std::string KIBIS_MODEL::generateSquareWave( const std::string& aNode1, const std::string& aNode2,
753 const std::vector<std::pair<int, double>>& aBits,
754 const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
755 const KIBIS_PARAMETER& aParam )
756{
757 const IBIS_CORNER supply = aParam.m_supply;
758 std::string simul;
759 std::vector<int> stimuliIndex;
760
761 IbisWaveform risingWF = TrimWaveform( *( aPair.first ) );
762 IbisWaveform fallingWF = TrimWaveform( *( aPair.second ) );
763
764 double deltaR = risingWF.m_table.m_entries.back().V.value[supply]
765 - risingWF.m_table.m_entries.at( 0 ).V.value[supply];
766 double deltaF = fallingWF.m_table.m_entries.back().V.value[supply]
767 - fallingWF.m_table.m_entries.at( 0 ).V.value[supply];
768
769 // Ideally, delta should be equal to zero.
770 // It can be different from zero if the falling waveform does not start were the rising one ended.
771 double delta = deltaR + deltaF;
772
773 int i = 0;
774
775 int prevBit = 2;
776
777 for( const std::pair<int, double>& bit : aBits )
778 {
780 double timing = bit.second;
781
782
783 if ( bit.first != prevBit )
784 {
785 if( bit.first == 1 )
786 WF = &risingWF;
787 else
788 WF = &fallingWF;
789
790 stimuliIndex.push_back( i );
791
792 simul += "Vstimuli";
793 simul += std::to_string( i );
794 simul += " stimuli";
795 simul += std::to_string( i );
796 simul += " ";
797 simul += aNode2;
798 simul += " pwl ( \n+";
799
800 if( i != 0 )
801 {
802 simul += "0 0 ";
803 VTtableEntry entry0 = WF->m_table.m_entries.at( 0 );
804 VTtableEntry entry1 = WF->m_table.m_entries.at( 1 );
805 double deltaT = entry1.t - entry0.t;
806
807 simul += doubleToString( entry0.t + timing - deltaT );
808 simul += " ";
809 simul += "0";
810 simul += "\n+";
811 }
812
813 for( const VTtableEntry& entry : WF->m_table.m_entries )
814 {
815 simul += doubleToString( entry.t + timing );
816 simul += " ";
817 simul += doubleToString( entry.V.value[supply] - delta );
818 simul += "\n+";
819 }
820
821 simul += ")\n";
822 }
823
824 i++;
825 prevBit = bit.first;
826 }
827
828 simul += "bin ";
829 simul += aNode1;
830 simul += " ";
831 simul += aNode2;
832 simul += " v=(";
833
834 for( int ii: stimuliIndex )
835 {
836 simul += " v( stimuli";
837 simul += std::to_string( ii );
838 simul += " ) +\n+";
839 }
840
841 // Depending on the first bit, we add a different DC value
842 // The DC value we add is the first value of the first bit.
843 if( ( aBits.size() > 0 ) && ( aBits[0].first == 0 ) )
844 simul += doubleToString( aPair.second->m_table.m_entries.at( 0 ).V.value[supply] );
845 else
846 simul += doubleToString( aPair.first->m_table.m_entries.at( 0 ).V.value[supply] );
847
848 simul += ")\n";
849 return simul;
850}
851
852
853std::string KIBIS_PIN::addDie( KIBIS_MODEL& aModel, const KIBIS_PARAMETER& aParam, int aIndex )
854{
855 const IBIS_CORNER supply = aParam.m_supply;
856 std::string simul;
857
858 std::string GC_GND = "GC_GND";
859 std::string PC_PWR = "PC_PWR";
860 std::string PU_PWR = "PU_PWR";
861 std::string PD_GND = "PD_GND";
862 std::string DIE = "DIE";
863
864 GC_GND += std::to_string( aIndex );
865 PC_PWR += std::to_string( aIndex );
866 PU_PWR += std::to_string( aIndex );
867 PD_GND += std::to_string( aIndex );
868 DIE += std::to_string( aIndex );
869
870
871 std::string GC = "GC";
872 std::string PC = "PC";
873 std::string PU = "PU";
874 std::string PD = "PD";
875
876 GC += std::to_string( aIndex );
877 PC += std::to_string( aIndex );
878 PU += std::to_string( aIndex );
879 PD += std::to_string( aIndex );
880
881 if( aModel.HasGNDClamp() )
882 simul += aModel.m_GNDClamp.Spice( aIndex * 4 + 1, DIE, GC_GND, false, GC, supply );
883
884 if( aModel.HasPOWERClamp() )
885 simul += aModel.m_POWERClamp.Spice( aIndex * 4 + 2, PC_PWR, DIE, true, PC, supply );
886
887 if( aModel.HasPulldown() )
888 simul += aModel.m_pulldown.Spice( aIndex * 4 + 3, DIE, PD_GND, false, PD, supply );
889
890 if( aModel.HasPullup() )
891 simul += aModel.m_pullup.Spice( aIndex * 4 + 4, PU_PWR, DIE, false, PU, supply );
892
893 return simul;
894}
895
896
897void KIBIS_PIN::getKuKdFromFile( const std::string& aSimul )
898{
899 const std::string outputFileName = m_topLevel->m_cacheDir + "temp_output.spice";
900
901 if( std::remove( outputFileName.c_str() ) )
902 Report( _( "Cannot remove temporary output file" ), RPT_SEVERITY_WARNING );
903
904 std::shared_ptr<SPICE_SIMULATOR> ng = SIMULATOR::CreateInstance( "ng-kibis" );
905
906 if( !ng )
907 throw std::runtime_error( "Could not create simulator instance" );
908
909 ng->Init();
910 ng->LoadNetlist( aSimul );
911
912 std::ifstream KuKdfile;
913 KuKdfile.open( outputFileName );
914
915 std::vector<double> ku, kd, t;
916
917 if( KuKdfile )
918 {
919 std::string line;
920 bool valuesTagFound = false;
921
922 while( std::getline( KuKdfile, line ) ) // skip ngspice output header
923 {
924 if( line.find( "Values:" ) != std::string::npos )
925 {
926 valuesTagFound = true;
927 break;
928 }
929 }
930
931 if( !valuesTagFound )
932 {
933 Report( _( "Missing 'Values:' tag in temporary file" ), RPT_SEVERITY_ERROR );
934 }
935
936 int i = 0;
937 double t_v, ku_v, kd_v;
938
939 try
940 {
941 while( KuKdfile )
942 {
943 std::getline( KuKdfile, line );
944
945 if( line.empty() )
946 continue;
947
948 switch( i )
949 {
950 case 0:
951 line = line.substr( line.find_first_of( "\t" ) + 1 );
952 t_v = std::stod( line );
953 break;
954 case 1: ku_v = std::stod( line ); break;
955 case 2:
956 kd_v = std::stod( line );
957 ku.push_back( ku_v );
958 kd.push_back( kd_v );
959 t.push_back( t_v );
960 break;
961 default: Report( _( "Error while reading temporary file" ), RPT_SEVERITY_ERROR );
962 }
963
964 i = ( i + 1 ) % 3;
965 }
966 }
967 catch( const std::exception& )
968 {
969 Report( _( "Error while reading temporary file" ), RPT_SEVERITY_ERROR );
970 }
971
972 std::getline( KuKdfile, line );
973 }
974 else
975 {
976 Report( _( "Error while creating temporary output file" ), RPT_SEVERITY_ERROR );
977 }
978
979 if( std::remove( outputFileName.c_str() ) )
980 {
981 Report( _( "Cannot remove temporary output file" ), RPT_SEVERITY_WARNING );
982 }
983
984 m_Ku = std::move( ku );
985 m_Kd = std::move( kd );
986 m_t = std::move( t );
987}
988
989
991 const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
992 const KIBIS_PARAMETER& aParam, int aIndex )
993{
994 IBIS_CORNER supply = aParam.m_supply;
995 IBIS_CORNER ccomp = aParam.m_Ccomp;
996 KIBIS_WAVEFORM* wave = aParam.m_waveform;
997
998 std::string simul = "";
999
1000 simul += "*THIS IS NOT A VALID SPICE MODEL.\n";
1001 simul += "*This part is intended to be executed by Kibis internally.\n";
1002 simul += "*You should not be able to read this.\n\n";
1003
1004 simul += ".SUBCKT DRIVER";
1005 simul += std::to_string( aIndex );
1006 simul += " POWER GND PIN \n"; // 1: POWER, 2:GND, 3:PIN
1007
1008 simul += "Vdummy 2 PIN 0\n";
1009
1010 if( ( aPair.first->m_R_dut != 0 ) || ( aPair.first->m_L_dut != 0 )
1011 || ( aPair.first->m_C_dut != 0 ) )
1012 {
1013 Report( _( "Kibis does not support DUT values yet. "
1014 "https://ibis.org/summits/nov16a/chen.pdf" ),
1016 }
1017
1018 simul += "\n";
1019 simul += "CCPOMP 2 GND ";
1020 simul += doubleToString( aModel.m_C_comp.value[ccomp] ); //@TODO: Check the corner ?
1021 simul += "\n";
1022
1023 const IbisWaveform* risingWF = aPair.first;
1024 const IbisWaveform* fallingWF = aPair.second;
1025
1026 switch( wave->GetType() )
1027 {
1030 {
1031 wave->Check( risingWF, fallingWF );
1032 std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence();
1033 bits = SimplifyBitSequence( bits );
1034 simul += aModel.generateSquareWave( "DIE0", "GND", bits, aPair, aParam );
1035 break;
1036 }
1038 {
1039 const IbisWaveform* waveform = wave->inverted ? risingWF : fallingWF;
1040 simul += "Vsig DIE0 GND ";
1041 simul += doubleToString( waveform->m_table.m_entries.at( 0 ).V.value[supply] );
1042 simul += "\n";
1043 break;
1044 }
1046 {
1047 const IbisWaveform* waveform = wave->inverted ? fallingWF : risingWF;
1048 simul += "Vsig DIE0 GND ";
1049 simul += doubleToString( waveform->m_table.m_entries.at( 0 ).V.value[supply] );
1050 simul += "\n";
1051 break;
1052 }
1055 default:
1056 break;
1057 }
1058
1059 simul += addDie( aModel, aParam, 0 );
1060
1061 simul += "\n.ENDS DRIVER\n\n";
1062 return simul;
1063}
1064
1065
1067 const std::pair<IbisWaveform*, IbisWaveform*>& aPair,
1068 const KIBIS_PARAMETER& aParam )
1069{
1070 IBIS_CORNER supply = aParam.m_supply;
1071 const KIBIS_WAVEFORM* wave = aParam.m_waveform;
1072
1073 std::string simul = "";
1074
1075 if( !wave )
1076 return;
1077
1078 if( wave->GetType() == KIBIS_WAVEFORM_TYPE::NONE )
1079 {
1080 //@TODO , there could be some current flowing through pullup / pulldown transistors, even when off
1081 std::vector<double> ku, kd, t;
1082 ku.push_back( 0 );
1083 kd.push_back( 0 );
1084 t.push_back( 0 );
1085 m_Ku = std::move( ku );
1086 m_Kd = std::move( kd );
1087 m_t = std::move( t );
1088 }
1089 else
1090 {
1091 simul += KuKdDriver( aModel, aPair, aParam, 0 );
1092 simul += "\n x1 3 0 1 DRIVER0 \n";
1093
1094 simul += "VCC 3 0 ";
1095 simul += doubleToString( aModel.m_voltageRange.value[supply] );
1096 simul += "\n";
1097 //simul += "Vpin x1.DIE 0 1 \n"
1098 simul += "Lfixture 1 4 ";
1099 simul += doubleToString( aPair.first->m_L_fixture );
1100 simul += "\n";
1101 simul += "Rfixture 4 5 ";
1102 simul += doubleToString( aPair.first->m_R_fixture );
1103 simul += "\n";
1104 simul += "Cfixture 4 0 ";
1105 simul += doubleToString( aPair.first->m_C_fixture );
1106 simul += "\n";
1107 simul += "Vfixture 5 0 ";
1108 simul += doubleToString( aPair.first->m_V_fixture );
1109 simul += "\n";
1110 simul += "VmeasIout x1.DIE0 x1.2 0\n";
1111 simul += "VmeasPD 0 x1.PD_GND0 0\n";
1112 simul += "VmeasPU x1.PU_PWR0 3 0\n";
1113 simul += "VmeasPC x1.PC_PWR0 3 0\n";
1114 simul += "VmeasGC 0 x1.GC_GND0 0\n";
1115
1116 if( aModel.HasPullup() && aModel.HasPulldown() )
1117 {
1118 Report( _( "Model has only one waveform pair, reduced accuracy" ),
1120 simul += "Bku KU 0 v=( (i(VmeasIout)-i(VmeasPC)-i(VmeasGC)-i(VmeasPD) "
1121 ")/(i(VmeasPU)-i(VmeasPD)))\n";
1122 simul += "Bkd KD 0 v=(1-v(KU))\n";
1123 }
1124
1125 else if( !aModel.HasPullup() && aModel.HasPulldown() )
1126 {
1127 simul += "Bku KD 0 v=( ( i(VmeasIout)+i(VmeasPC)+i(VmeasGC) )/(i(VmeasPD)))\n";
1128 simul += "Bkd KU 0 v=0\n";
1129 }
1130
1131 else if( aModel.HasPullup() && !aModel.HasPulldown() )
1132 {
1133 simul += "Bku KU 0 v=( ( i(VmeasIout)+i(VmeasPC)+i(VmeasGC) )/(i(VmeasPU)))\n";
1134 simul += "Bkd KD 0 v=0\n";
1135 }
1136 else
1137 {
1138 Report( _( "Driver needs at least a pullup or a pulldown" ), RPT_SEVERITY_ERROR );
1139 }
1140
1141 switch( wave->GetType() )
1142 {
1145 {
1146 double duration = wave->GetDuration();
1147 simul += ".tran 0.1n ";
1148 simul += doubleToString( duration );
1149 simul += "\n";
1150 break;
1151 }
1155 default:
1156 simul += ".tran 0.5 1 \n"; //
1157 }
1158
1159 //simul += ".dc Vpin -5 5 0.1\n";
1160 simul += ".control run \n";
1161 simul += "set filetype=ascii\n";
1162 simul += "run \n";
1163 //simul += "plot v(x1.DIE0) i(VmeasIout) i(VmeasPD) i(VmeasPU) i(VmeasPC) i(VmeasGC)\n";
1164 //simul += "plot v(KU) v(KD)\n";
1165
1166 std::string outputFileName = m_topLevel->m_cacheDir + "temp_output.spice";
1167 simul += "write '" + outputFileName + "' v(KU) v(KD)\n";
1168 simul += "quit\n";
1169 simul += ".endc \n";
1170 simul += ".end \n";
1171
1172 getKuKdFromFile( simul );
1173 }
1174}
1175
1176
1178{
1179 std::vector<double> ku, kd, t;
1180 const KIBIS_WAVEFORM* wave = aParam.m_waveform;
1181 const IBIS_CORNER& supply = aParam.m_supply;
1182
1183 if( !wave )
1184 return;
1185
1186 switch( wave->GetType() )
1187 {
1190 {
1191 wave->Check( aModel.m_ramp.m_rising, aModel.m_ramp.m_falling );
1192 std::vector<std::pair<int, double>> bits = wave->GenerateBitSequence();
1193 bits = SimplifyBitSequence( bits );
1194
1195 for( const std::pair<int, double>& bit : bits )
1196 {
1197 ku.push_back( bit.first ? 0 : 1 );
1198 kd.push_back( bit.first ? 1 : 0 );
1199 t.push_back( bit.second );
1200 ku.push_back( bit.first ? 1 : 0 );
1201 kd.push_back( bit.first ? 0 : 1 );
1202 t.push_back( bit.second
1203 + ( bit.first ? +aModel.m_ramp.m_rising.value[supply].m_dt
1204 : aModel.m_ramp.m_falling.value[supply].m_dt )
1205 / 0.6 );
1206 // 0.6 because ibis only gives 20%-80% time
1207 }
1208 break;
1209 }
1211 {
1212 ku.push_back( wave->inverted ? 0 : 1 );
1213 kd.push_back( wave->inverted ? 1 : 0 );
1214 t.push_back( 0 );
1215 break;
1216 }
1218 {
1219 ku.push_back( wave->inverted ? 1 : 0 );
1220 kd.push_back( wave->inverted ? 0 : 1 );
1221 t.push_back( 0 );
1222 break;
1223 }
1226 default:
1227 ku.push_back( 0 );
1228 kd.push_back( 0 );
1229 t.push_back( 0 );
1230 }
1231
1232 m_Ku = std::move( ku );
1233 m_Kd = std::move( kd );
1234 m_t = std::move( t );
1235}
1236
1237
1239 const std::pair<IbisWaveform*, IbisWaveform*>& aPair1,
1240 const std::pair<IbisWaveform*, IbisWaveform*>& aPair2,
1241 const KIBIS_PARAMETER& aParam )
1242{
1243 std::string simul = "";
1244 const IBIS_CORNER supply = aParam.m_supply;
1245 const KIBIS_WAVEFORM* wave = aParam.m_waveform;
1246
1247 if( !wave )
1248 return;
1249
1250 if( wave->GetType() == KIBIS_WAVEFORM_TYPE::NONE )
1251 {
1252 //@TODO , there could be some current flowing through pullup / pulldown transistors, even when off
1253 std::vector<double> ku, kd, t;
1254 ku.push_back( 0 );
1255 kd.push_back( 0 );
1256 t.push_back( 0 );
1257 m_Ku = std::move( ku );
1258 m_Kd = std::move( kd );
1259 m_t = std::move( t );
1260 }
1261 else
1262 {
1263 simul += KuKdDriver( aModel, aPair1, aParam, 0 );
1264 simul += KuKdDriver( aModel, aPair2, aParam, 1 );
1265 simul += "\n x1 3 0 1 DRIVER0 \n";
1266
1267 simul += "VCC 3 0 ";
1268 simul += doubleToString( aModel.m_voltageRange.value[supply] );
1269 simul += "\n";
1270 //simul += "Vpin x1.DIE 0 1 \n"
1271 simul += "Lfixture0 1 4 ";
1272 simul += doubleToString( aPair1.first->m_L_fixture );
1273 simul += "\n";
1274 simul += "Rfixture0 4 5 ";
1275 simul += doubleToString( aPair1.first->m_R_fixture );
1276 simul += "\n";
1277 simul += "Cfixture0 4 0 ";
1278 simul += doubleToString( aPair1.first->m_C_fixture );
1279 simul += "\n";
1280 simul += "Vfixture0 5 0 ";
1281 simul += doubleToString( aPair1.first->m_V_fixture );
1282 simul += "\n";
1283 simul += "VmeasIout0 x1.2 x1.DIE0 0\n";
1284 simul += "VmeasPD0 0 x1.PD_GND0 0\n";
1285 simul += "VmeasPU0 x1.PU_PWR0 3 0\n";
1286 simul += "VmeasPC0 x1.PC_PWR0 3 0\n";
1287 simul += "VmeasGC0 0 x1.GC_GND0 0\n";
1288
1289
1290 simul += "\n x2 3 0 7 DRIVER1 \n";
1291 //simul += "Vpin x1.DIE 0 1 \n"
1292 simul += "Lfixture1 7 8 ";
1293 simul += doubleToString( aPair2.first->m_L_fixture );
1294 simul += "\n";
1295 simul += "Rfixture1 8 9 ";
1296 simul += doubleToString( aPair2.first->m_R_fixture );
1297 simul += "\n";
1298 simul += "Cfixture1 8 0 ";
1299 simul += doubleToString( aPair2.first->m_C_fixture );
1300 simul += "\n";
1301 simul += "Vfixture1 9 0 ";
1302 simul += doubleToString( aPair2.first->m_V_fixture );
1303 simul += "\n";
1304 simul += "VmeasIout1 x2.2 x2.DIE0 0\n";
1305 simul += "VmeasPD1 0 x2.PD_GND0 0\n";
1306 simul += "VmeasPU1 x2.PU_PWR0 3 0\n";
1307 simul += "VmeasPC1 x2.PC_PWR0 3 0\n";
1308 simul += "VmeasGC1 0 x2.GC_GND0 0\n";
1309
1310 if( aModel.HasPullup() && aModel.HasPulldown() )
1311 {
1312 simul +=
1313 "Bku KU 0 v=( ( i(VmeasPD1) * ( i(VmeasIout0) + i(VmeasPC0) + i(VmeasGC0) ) - "
1314 "i(VmeasPD0) * ( i(VmeasIout1) + i(VmeasPC1) + i(VmeasGC1) ) )/ ( i(VmeasPU1) "
1315 "* "
1316 "i(VmeasPD0) - i(VmeasPU0) * i(VmeasPD1) ) )\n";
1317 simul +=
1318 "Bkd KD 0 v=( ( i(VmeasPU1) * ( i(VmeasIout0) + i(VmeasPC0) + i(VmeasGC0) ) - "
1319 "i(VmeasPU0) * ( i(VmeasIout1) + i(VmeasPC1) + i(VmeasGC1) ) )/ ( i(VmeasPD1) "
1320 "* "
1321 "i(VmeasPU0) - i(VmeasPD0) * i(VmeasPU1) ) )\n";
1322 //simul += "Bkd KD 0 v=(1-v(KU))\n";
1323 }
1324
1325 else if( !aModel.HasPullup() && aModel.HasPulldown() )
1326 {
1327 Report( _( "There are two waveform pairs, but only one transistor. More equations than "
1328 "unknowns." ),
1330 simul += "Bku KD 0 v=( ( i(VmeasIout0)+i(VmeasPC0)+i(VmeasGC0) )/(i(VmeasPD0)))\n";
1331 simul += "Bkd KU 0 v=0\n";
1332 }
1333
1334 else if( aModel.HasPullup() && !aModel.HasPulldown() )
1335 {
1336 Report( _( "There are two waveform pairs, but only one transistor. More equations than "
1337 "unknowns." ),
1339 simul += "Bku KU 0 v=( ( i(VmeasIout)+i(VmeasPC)+i(VmeasGC) )/(i(VmeasPU)))\n";
1340 simul += "Bkd KD 0 v=0\n";
1341 }
1342 else
1343 {
1344 Report( _( "Driver needs at least a pullup or a pulldown" ), RPT_SEVERITY_ERROR );
1345 }
1346
1347 switch( wave->GetType() )
1348 {
1351 {
1352 double duration = wave->GetDuration();
1353 simul += ".tran 0.1n ";
1354 simul += doubleToString( duration );
1355 simul += "\n";
1356 break;
1357 }
1361 default:
1362 simul += ".tran 0.5 1 \n"; //
1363 }
1364
1365 //simul += ".dc Vpin -5 5 0.1\n";
1366 simul += ".control run \n";
1367 simul += "set filetype=ascii\n";
1368 simul += "run \n";
1369 simul += "plot v(KU) v(KD)\n";
1370 //simul += "plot v(x1.DIE0) \n";
1371 std::string outputFileName = m_topLevel->m_cacheDir + "temp_output.spice";
1372 simul += "write '" + outputFileName + "' v(KU) v(KD)\n";
1373 simul += "quit\n";
1374 simul += ".endc \n";
1375 simul += ".end \n";
1376
1377 getKuKdFromFile( simul );
1378 }
1379}
1380
1381
1382bool KIBIS_PIN::writeSpiceDriver( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
1383 const KIBIS_PARAMETER& aParam )
1384{
1385 bool status = true;
1386
1387 switch( aModel.m_type )
1388 {
1401 {
1402 std::string result;
1403 std::string tmp;
1404
1405 result = "\n*Driver model generated by Kicad using Ibis data. ";
1406
1407 result += "\n*Pin number: ";
1409 result += "\n*Signal name: ";
1411 result += "\n*Model: ";
1412 result += aModel.m_name;
1413 result += "\n.SUBCKT ";
1414 result += aName;
1415 result += " GND PIN \n";
1416 result += "\n";
1417
1418 result += "RPIN 1 PIN ";
1419 result += doubleToString( m_Rpin.value[aParam.m_Rpin] );
1420 result += "\n";
1421 result += "LPIN DIE0 1 ";
1422 result += doubleToString( m_Lpin.value[aParam.m_Lpin] );
1423 result += "\n";
1424 result += "CPIN PIN GND ";
1425 result += doubleToString( m_Cpin.value[aParam.m_Cpin] );
1426 result += "\n";
1427
1428 std::vector<std::pair<IbisWaveform*, IbisWaveform*>> wfPairs = aModel.waveformPairs();
1430
1431 if( wfPairs.size() < 1 || accuracy <= KIBIS_ACCURACY::LEVEL_0 )
1432 {
1434 {
1435 Report( _( "Model has no waveform pair, using [Ramp] instead, poor accuracy" ),
1437 }
1438
1439 getKuKdNoWaveform( aModel, aParam );
1440 }
1441 else if( wfPairs.size() == 1 || accuracy <= KIBIS_ACCURACY::LEVEL_1 )
1442 {
1443 getKuKdOneWaveform( aModel, wfPairs.at( 0 ), aParam );
1444 }
1445 else
1446 {
1447 if( wfPairs.size() > 2 || accuracy <= KIBIS_ACCURACY::LEVEL_2 )
1448 {
1449 Report( _( "Model has more than 2 waveform pairs, using the first two." ),
1451 }
1452
1453 getKuKdTwoWaveforms( aModel, wfPairs.at( 0 ), wfPairs.at( 1 ), aParam );
1454 }
1455
1456 result += "Vku KU GND pwl ( ";
1457
1458 for( size_t i = 0; i < m_t.size(); i++ )
1459 {
1460 result += doubleToString( m_t.at( i ) );
1461 result += " ";
1462 result += doubleToString( m_Ku.at( i ) );
1463 result += " ";
1464 }
1465
1466 result += ") \n";
1467
1468
1469 result += "Vkd KD GND pwl ( ";
1470
1471 for( size_t i = 0; i < m_t.size(); i++ )
1472 {
1473 result += doubleToString( m_t.at( i ) );
1474 result += " ";
1475 result += doubleToString( m_Kd.at( i ) );
1476 result += " ";
1477 }
1478
1479 result += ") \n";
1480
1481 result += aModel.SpiceDie( aParam, 0, true );
1482
1483 result += "\n.ENDS DRIVER\n\n";
1484
1485 aDest += result;
1486 break;
1487 }
1488 default:
1489 if( aModel.m_type == IBIS_MODEL_TYPE::SERIES
1491 {
1492 Report( _( "Series and Series_switch models are passive devices, not drivers." ),
1494 }
1495 else
1496 {
1497 Report( _( "Invalid model type for a driver." ), RPT_SEVERITY_ERROR );
1498 }
1499
1500 status = false;
1501 }
1502
1503 return status;
1504}
1505
1506
1507bool KIBIS_PIN::writeSpiceDevice( std::string& aDest, const std::string& aName, KIBIS_MODEL& aModel,
1508 const KIBIS_PARAMETER& aParam )
1509{
1510 bool status = true;
1511
1512 switch( aModel.m_type )
1513 {
1520 {
1521 std::string result;
1522
1523 result += "\n";
1524 result = "*Device model generated by Kicad using Ibis data.";
1525 result += "\n.SUBCKT ";
1526 result += aName;
1527 result += " GND PIN\n";
1528 result += "\n";
1529 result += "\n";
1530 result += "RPIN 1 PIN ";
1531 result += doubleToString( m_Rpin.value[aParam.m_Rpin] );
1532 result += "\n";
1533 result += "LPIN DIE0 1 ";
1534 result += doubleToString( m_Lpin.value[aParam.m_Lpin] );
1535 result += "\n";
1536 result += "CPIN PIN GND ";
1537 result += doubleToString( m_Cpin.value[aParam.m_Cpin] );
1538 result += "\n";
1539
1540 result += aModel.SpiceDie( aParam, 0, false );
1541
1542 result += "\n.ENDS DEVICE\n\n";
1543
1544 aDest = std::move( result );
1545 break;
1546 }
1549 {
1551
1552 if( !partner )
1553 {
1554 Report( _( "Series model has no [Series Pin Mapping] partner pin." ),
1556 status = false;
1557 break;
1558 }
1559
1560 std::string result = "\n*Series device model generated by KiCad using IBIS data.\n";
1561
1562 // CPIN ties to ngspice's global 0 net so GND need not be a subckt port.
1563 result += ".SUBCKT ";
1564 result += aName;
1565 result += " PIN_A PIN_B\n";
1566
1568 result += ".param SW_STATE=1\n";
1569
1570 auto emitPinParasitics = [&]( const std::string& aSuffix, const KIBIS_PIN& aPin,
1571 const std::string& aPin_ext, const std::string& aDie )
1572 {
1573 std::string n1 = "n_pin" + aSuffix;
1574 result += "RPIN" + aSuffix + " " + n1 + " " + aPin_ext + " ";
1575 result += doubleToString( aPin.m_Rpin.value[aParam.m_Rpin] );
1576 result += "\n";
1577 result += "LPIN" + aSuffix + " " + aDie + " " + n1 + " ";
1578 result += doubleToString( aPin.m_Lpin.value[aParam.m_Lpin] );
1579 result += "\n";
1580 result += "CPIN" + aSuffix + " " + aPin_ext + " 0 ";
1581 result += doubleToString( aPin.m_Cpin.value[aParam.m_Cpin] );
1582 result += "\n";
1583 };
1584
1585 emitPinParasitics( "A", *this, "PIN_A", "DIE_A" );
1586 emitPinParasitics( "B", *partner, "PIN_B", "DIE_B" );
1587
1588 if( aModel.m_type == IBIS_MODEL_TYPE::SERIES )
1589 {
1590 result += aModel.SpiceSeriesDie( aParam, 0, "DIE_A", "DIE_B", aModel.m_series, "" );
1591 }
1592 else
1593 {
1594 result += aModel.SpiceSeriesDie( aParam, 1, "DIE_A", "DIE_B", aModel.m_seriesOn,
1595 "SW_STATE" );
1596 result += aModel.SpiceSeriesDie( aParam, 2, "DIE_A", "DIE_B", aModel.m_seriesOff,
1597 "(1 - SW_STATE)" );
1598 }
1599
1600 result += "\n.ENDS DEVICE\n\n";
1601
1602 aDest = std::move( result );
1603 break;
1604 }
1605 default:
1606 Report( _( "Invalid model type for a device" ), RPT_SEVERITY_ERROR );
1607 status = false;
1608 }
1609
1610 return status;
1611}
1612
1613
1614bool KIBIS_PIN::writeSpiceDiffDriver( std::string& aDest, const std::string& aName,
1615 KIBIS_MODEL& aModel, const KIBIS_PARAMETER& aParam )
1616{
1617 bool status = true;
1618 KIBIS_WAVEFORM* wave = aParam.m_waveform;
1619
1620 if( !wave )
1621 return false;
1622
1623 std::string result;
1624 result = "\n*Differential driver model generated by Kicad using Ibis data. ";
1625
1626 result += "\n.SUBCKT ";
1627 result += aName;
1628 result += " GND PIN_P PIN_N\n";
1629 result += "\n";
1630
1631 status &= writeSpiceDriver( result, aName + "_P", aModel, aParam );
1632 wave->inverted = !wave->inverted;
1633 status &= writeSpiceDriver( result, aName + "_N", aModel, aParam );
1634 wave->inverted = !wave->inverted;
1635
1636
1637 result += "\n";
1638 result += "x1 GND PIN_P " + aName + "_P \n";
1639 result += "x2 GND PIN_N " + aName + "_N \n";
1640 result += "\n";
1641
1642 result += "\n.ENDS " + aName + "\n\n";
1643
1644 if( status )
1645 aDest += result;
1646
1647 return status;
1648}
1649
1650
1651bool KIBIS_PIN::writeSpiceDiffDevice( std::string& aDest, const std::string& aName,
1652 KIBIS_MODEL& aModel, const KIBIS_PARAMETER& aParam )
1653{
1654 bool status = true;
1655
1656 std::string result;
1657 result = "\n*Differential device model generated by Kicad using Ibis data. ";
1658
1659 result += "\n.SUBCKT ";
1660 result += aName;
1661 result += " GND PIN_P PIN_N\n";
1662 result += "\n";
1663
1664 status &= writeSpiceDevice( result, aName + "_P", aModel, aParam );
1665 status &= writeSpiceDevice( result, aName + "_N", aModel, aParam );
1666
1667 result += "\n";
1668 result += "x1 GND PIN_P " + aName + "_P \n";
1669 result += "x2 GND PIN_N " + aName + "_N \n";
1670 result += "\n";
1671
1672 result += "\n.ENDS " + aName + "\n\n";
1673
1674 if( status )
1675 aDest += result;
1676
1677 return status;
1678}
1679
1680
1681KIBIS_MODEL* KIBIS::GetModel( const std::string& aName )
1682{
1683 for( KIBIS_MODEL& model : m_models )
1684 {
1685 if( model.m_name == aName )
1686 return &model;
1687 }
1688
1689 return nullptr;
1690}
1691
1692
1693KIBIS_COMPONENT* KIBIS::GetComponent( const std::string& aName )
1694{
1695 for( KIBIS_COMPONENT& cmp : m_components )
1696 {
1697 if( cmp.m_name == aName )
1698 return &cmp;
1699 }
1700
1701 return nullptr;
1702}
1703
1704
1705void KIBIS_PARAMETER::SetCornerFromString( IBIS_CORNER& aCorner, const std::string& aString )
1706{
1707 if( aString == "MIN" )
1708 aCorner = IBIS_CORNER::MIN;
1709 else if( aString == "MAX" )
1710 aCorner = IBIS_CORNER::MAX;
1711 else
1712 aCorner = IBIS_CORNER::TYP;
1713}
1714
1715
1716std::vector<std::pair<int, double>> KIBIS_WAVEFORM_STUCK_HIGH::GenerateBitSequence() const
1717{
1718 std::vector<std::pair<int, double>> bits;
1719 std::pair<int, double> bit;
1720 bit.first = inverted ? 1 : 0;
1721 bit.second = 0;
1722 return bits;
1723}
1724
1725
1726std::vector<std::pair<int, double>> KIBIS_WAVEFORM_STUCK_LOW::GenerateBitSequence() const
1727{
1728 std::vector<std::pair<int, double>> bits;
1729 std::pair<int, double> bit;
1730 bit.first = inverted ? 0 : 1;
1731 bit.second = 0;
1732 return bits;
1733}
1734
1735std::vector<std::pair<int, double>> KIBIS_WAVEFORM_HIGH_Z::GenerateBitSequence() const
1736{
1737 std::vector<std::pair<int, double>> bits;
1738 return bits;
1739}
1740
1741std::vector<std::pair<int, double>> KIBIS_WAVEFORM_RECTANGULAR::GenerateBitSequence() const
1742{
1743 std::vector<std::pair<int, double>> bits;
1744
1745 for( int i = 0; i < m_cycles; i++ )
1746 {
1747 std::pair<int, double> bit;
1748 bit.first = inverted ? 0 : 1;
1749 bit.second = ( m_ton + m_toff ) * i + m_delay;
1750 bits.push_back( bit );
1751
1752 bit.first = inverted ? 1 : 0;
1753 bit.second = ( m_ton + m_toff ) * i + m_delay + m_ton;
1754 bits.push_back( bit );
1755 }
1756
1757 return bits;
1758}
1759
1760
1761std::vector<std::pair<int, double>> KIBIS_WAVEFORM_PRBS::GenerateBitSequence() const
1762{
1763 std::vector<std::pair<int, double>> bitSequence;
1764 uint8_t polynomial = 0b1100000;
1765 //1100000 = x^7+x^6+1
1766 //10100 = x^5+x^3+1
1767 //110 = x^3+x^2+1
1768 uint8_t seed = 0x12; // Any non zero state
1769 uint8_t lfsr = seed;
1770
1771 if ( m_bitrate == 0 )
1772 return bitSequence;
1773
1774 double period = 1/m_bitrate;
1775 double t = 0;
1776
1777 wxASSERT( m_bits > 0 );
1778
1779 int bits = 0;
1780
1781 do
1782 {
1783 uint8_t lsb = lfsr & 0x01;
1784 bitSequence.emplace_back( ( static_cast<uint8_t>( inverted ) ^ lsb ? 1 : 0 ), t );
1785 lfsr = lfsr >> 1;
1786
1787 if ( lsb )
1788 lfsr ^= polynomial;
1789
1790 t += period;
1791
1792 } while ( ++bits < m_bits );
1793
1794 return bitSequence;
1795}
1796
1798 const IbisWaveform* aFallingWf ) const
1799{
1800 bool status = true;
1801
1802 if( m_cycles < 1 )
1803 {
1804 status = false;
1805 Report( _( "Number of cycles should be greater than 0." ), RPT_SEVERITY_ERROR );
1806 }
1807
1808 if( m_ton <= 0 )
1809 {
1810 status = false;
1811 Report( _( "ON time should be greater than 0." ), RPT_SEVERITY_ERROR );
1812 }
1813
1814 if( m_toff <= 0 )
1815 {
1816 status = false;
1817 Report( _( "OFF time should be greater than 0." ), RPT_SEVERITY_ERROR );
1818 }
1819
1820 if( aRisingWf )
1821 {
1822 if( m_ton < aRisingWf->m_table.m_entries.back().t )
1823 {
1824 status = false;
1825 Report( _( "Rising edge is longer than on time." ), RPT_SEVERITY_WARNING );
1826 }
1827 }
1828
1829 if( aFallingWf )
1830 {
1831 if( m_toff < aFallingWf->m_table.m_entries.back().t )
1832 {
1833 status = false;
1834 Report( _( "Falling edge is longer than off time." ), RPT_SEVERITY_WARNING );
1835 }
1836 }
1837
1838 status &= aRisingWf && aFallingWf;
1839
1840 return status;
1841}
1842
1843
1845 const dvdtTypMinMax& aFallingRp ) const
1846{
1847 bool status = true;
1848
1849 if( m_cycles < 1 )
1850 {
1851 status = false;
1852 Report( _( "Number of cycles should be greater than 0." ), RPT_SEVERITY_ERROR );
1853 }
1854
1855 if( m_ton <= 0 )
1856 {
1857 status = false;
1858 Report( _( "ON time should be greater than 0." ), RPT_SEVERITY_ERROR );
1859 }
1860
1861 if( m_toff <= 0 )
1862 {
1863 status = false;
1864 Report( _( "OFF time should be greater than 0." ), RPT_SEVERITY_ERROR );
1865 }
1866
1867 if( ( m_ton < aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 )
1868 || ( m_ton < aRisingRp.value[IBIS_CORNER::MIN].m_dt / 0.6 )
1869 || ( m_ton < aRisingRp.value[IBIS_CORNER::MAX].m_dt / 0.6 ) )
1870 {
1871 status = false;
1872 Report( _( "Rising edge is longer than ON time." ), RPT_SEVERITY_ERROR );
1873 }
1874
1875 if( ( m_toff < aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 )
1876 || ( m_toff < aFallingRp.value[IBIS_CORNER::MIN].m_dt / 0.6 )
1877 || ( m_toff < aFallingRp.value[IBIS_CORNER::MAX].m_dt / 0.6 ) )
1878 {
1879 status = false;
1880 Report( _( "Falling edge is longer than OFF time." ), RPT_SEVERITY_ERROR );
1881 }
1882
1883 return status;
1884}
1885
1886
1888 const dvdtTypMinMax& aFallingRp ) const
1889{
1890 bool status = true;
1891
1892 if( m_bitrate <= 0 )
1893 {
1894 status = false;
1895 Report( _( "Bitrate should be greater than 0." ), RPT_SEVERITY_ERROR );
1896 }
1897
1898 if( m_bits <= 0 )
1899 {
1900 status = false;
1901 Report( _( "Number of bits should be greater than 0." ), RPT_SEVERITY_ERROR );
1902 }
1903
1904 if( m_bitrate
1905 && ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
1906 + aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) )
1907 && ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
1908 + aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) )
1909 && ( ( 1 / m_bitrate ) < ( aRisingRp.value[IBIS_CORNER::TYP].m_dt / 0.6
1910 + aFallingRp.value[IBIS_CORNER::TYP].m_dt / 0.6 ) ) )
1911 {
1912 status = false;
1913 Report( _( "Bitrate is too high for rising / falling edges" ), RPT_SEVERITY_ERROR );
1914 }
1915
1916 return status;
1917}
1918
1920 const IbisWaveform* aFallingWf ) const
1921{
1922 bool status = true;
1923
1924 if( m_bitrate <= 0 )
1925 {
1926 status = false;
1927 Report( _( "Bitrate should be greater than 0." ), RPT_SEVERITY_ERROR );
1928 }
1929
1930 if( m_bits <= 0 )
1931 {
1932 status = false;
1933 Report( _( "Number of bits should be greater than 0." ), RPT_SEVERITY_ERROR );
1934 }
1935
1936 if( m_bitrate && aRisingWf && aFallingWf
1937 && ( ( 1 / m_bitrate ) < ( aRisingWf->m_table.m_entries.back().t
1938 + aFallingWf->m_table.m_entries.back().t ) ) )
1939 {
1940 status = false;
1941 Report( _( "Bitrate could be too high for rising / falling edges" ), RPT_SEVERITY_WARNING );
1942 }
1943
1944 return status;
1945}
void Report(const std::string &aMsg, SEVERITY aSeverity=RPT_SEVERITY_INFO) const
Print a message.
Definition ibis_parser.h:70
IBIS_BASE(REPORTER *aReporter)
Definition ibis_parser.h:56
REPORTER * m_Reporter
Definition ibis_parser.h:77
static std::string doubleToString(double aNumber)
Convert a double to string using scientific notation.
TypMinMaxValue I
std::string Spice(int aN, const std::string &aPort1, const std::string &aPort2, bool aNegateI, const std::string &aModelName, IBIS_CORNER aCorner) const
Interpolate the IV table.
std::vector< IVtableEntry > m_entries
TypMinMaxValue m_Cpkg
TypMinMaxValue m_Lpkg
TypMinMaxValue m_Rpkg
std::string m_signalName
std::string m_pinName
One row of a [Series Pin Mapping] table (IBIS 4.1+).
std::string m_manufacturer
IbisDiffPin m_diffPin
std::string m_name
std::vector< IbisComponentPin > m_pins
std::vector< IbisComponentSeriesPinMapping > m_seriesPinMappings
std::string pinB
std::string pinA
std::vector< IbisDiffPinEntry > m_entries
std::vector< IbisComponent > m_components
IbisHeader m_header
std::map< std::string, IbisSubmodel > m_submodels
std::vector< IbisModel > m_models
std::vector< IbisModelSelector > m_modelSelectors
std::string m_fileName
std::string m_copyright
std::string m_notes
double m_ibisVersion
std::string m_date
double m_fileRevision
std::string m_disclaimer
std::string m_modelDescription
std::vector< IbisModelSelectorEntry > m_models
TypMinMaxValue m_C_comp_pullup
TypMinMaxValue m_C_comp_power_clamp
IBIS_MODEL_TYPE m_type
double m_cref
IVtable m_pullup
TypMinMaxValue m_Cac
IbisSeriesData m_seriesOff
TypMinMaxValue m_pullupReference
TypMinMaxValue m_C_comp_pulldown
TypMinMaxValue m_C_comp_gnd_clamp
double m_vmeas
IVtable m_pulldown
TypMinMaxValue m_Rac
std::vector< IbisSubmodelMode > m_submodels
std::vector< IbisWaveform * > m_risingWaveforms
IVtable m_POWERClamp
TypMinMaxValue m_Rgnd
TypMinMaxValue m_POWERClampReference
IbisSeriesData m_series
IVtable m_GNDClamp
IbisRamp m_ramp
IbisSeriesData m_seriesOn
IBIS_MODEL_POLARITY m_polarity
TypMinMaxValue m_C_comp
double m_rref
IBIS_MODEL_ENABLE m_enable
TypMinMaxValue m_temperatureRange
std::vector< IbisWaveform * > m_fallingWaveforms
TypMinMaxValue m_pulldownReference
double m_vref
TypMinMaxValue m_GNDClampReference
double m_vinh
double m_vinl
TypMinMaxValue m_voltageRange
TypMinMaxValue m_Rpower
std::string m_name
bool ParseFile(const std::string &aFileName)
Parse a file.
IbisFile m_ibisFile
dvdtTypMinMax m_rising
dvdtTypMinMax m_falling
TypMinMaxValue m_Lseries
TypMinMaxValue m_RlSeries
TypMinMaxValue m_LcSeries
TypMinMaxValue m_Cseries
std::vector< IbisMosfetEntry > m_seriesMosfet
TypMinMaxValue m_RcSeries
TypMinMaxValue m_Rseries
IVtable m_seriesCurrent
IBIS_SUBMODEL_MODE m_mode
std::string m_name
TypMinMaxValue m_VtriggerR
IVtable m_POWERClamp
IBIS_SUBMODEL_TYPE m_type
IVtable m_GNDClamp
std::string m_name
TypMinMaxValue m_VtriggerF
double m_L_fixture
double m_V_fixture
VTtable m_table
double m_V_fixture_min
double m_V_fixture_max
double m_R_fixture
double m_C_fixture
bool m_valid
Definition kibis.h:57
KIBIS * m_topLevel
Definition kibis.h:56
KIBIS_BASE(KIBIS *aTopLevel)
Definition kibis.cpp:68
KIBIS_COMPONENT(KIBIS &aToplevel, const IbisComponent &aSource, IbisParser &aParser)
Definition kibis.cpp:373
std::vector< KIBIS_PIN > m_pins
Definition kibis.h:501
std::string m_manufacturer
Name of the manufacturer.
Definition kibis.h:499
std::string m_name
Name of the component.
Definition kibis.h:497
KIBIS_PIN * GetPin(const std::string &aPinNumber)
Get a pin by its number ( 1, 2, A1, A2, ... )
Definition kibis.cpp:432
KIBIS_FILE(KIBIS &aTopLevel)
Definition kibis.cpp:137
std::string m_notes
Definition kibis.h:238
double m_ibisVersion
Definition kibis.h:235
std::string m_date
Definition kibis.h:236
bool Init(const IbisParser &aParser)
Definition kibis.cpp:145
std::string m_fileName
Definition kibis.h:233
std::string m_copyright
Definition kibis.h:240
std::string m_disclaimer
Definition kibis.h:239
double m_fileRev
Definition kibis.h:234
std::vector< IbisWaveform * > m_fallingWaveforms
Definition kibis.h:300
IbisWaveform TrimWaveform(const IbisWaveform &aIn) const
Copy a waveform, and substract the first value to all samples.
Definition kibis.cpp:692
IBIS_MODEL_ENABLE m_enable
Definition kibis.h:280
double m_vref
Definition kibis.h:276
std::string m_name
Definition kibis.h:269
bool HasPOWERClamp() const
Return true if the model has a clamp diode to the power net.
Definition kibis.cpp:746
double m_vmeas
Definition kibis.h:279
std::vector< IbisWaveform * > m_risingWaveforms
Definition kibis.h:299
TypMinMaxValue m_Cac
Definition kibis.h:294
double m_vinh
Definition kibis.h:275
double m_rref
Definition kibis.h:277
bool HasPullup() const
Return true if the model has a pullup transistor.
Definition kibis.cpp:734
bool HasGNDClamp() const
Return true if the model has a clamp diode to the gnd net.
Definition kibis.cpp:740
std::string SpiceDie(const KIBIS_PARAMETER &aParam, int aIndex, bool aDriver) const
Generate the spice directive to simulate the die.
Definition kibis.cpp:470
IbisSeriesData m_seriesOn
Definition kibis.h:306
TypMinMaxValue m_pulldownReference
Definition kibis.h:288
TypMinMaxValue m_GNDClampReference
Definition kibis.h:289
TypMinMaxValue m_Rpower
Definition kibis.h:292
bool HasPulldown() const
Return true if the model has a pulldown transistor.
Definition kibis.cpp:728
IBIS_MODEL_TYPE m_type
Definition kibis.h:271
std::vector< KIBIS_SUBMODEL > m_submodels
Definition kibis.h:302
IbisRamp m_ramp
Definition kibis.h:301
IVtable m_pullup
Definition kibis.h:297
IBIS_MODEL_POLARITY m_polarity
Definition kibis.h:281
double m_cref
Definition kibis.h:278
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)
Generate a square waveform.
Definition kibis.cpp:752
IbisSeriesData m_series
Definition kibis.h:305
TypMinMaxValue m_Rac
Definition kibis.h:293
TypMinMaxValue m_temperatureRange
Definition kibis.h:286
TypMinMaxValue m_voltageRange
Definition kibis.h:285
IVtable m_GNDClamp
Definition kibis.h:295
TypMinMaxValue m_Rgnd
Definition kibis.h:291
std::string m_description
Definition kibis.h:270
KIBIS_MODEL(KIBIS &aTopLevel, const IbisModel &aSource, IbisParser &aParser)
Definition kibis.cpp:263
IVtable m_POWERClamp
Definition kibis.h:296
TypMinMaxValue m_pullupReference
Definition kibis.h:287
std::vector< std::pair< IbisWaveform *, IbisWaveform * > > waveformPairs()
Create waveform pairs.
Definition kibis.cpp:443
TypMinMaxValue m_POWERClampReference
Definition kibis.h:290
TypMinMaxValue m_C_comp
Definition kibis.h:284
std::string SpiceSeriesDie(const KIBIS_PARAMETER &aParam, int aIndex, const std::string &aPort1, const std::string &aPort2, const IbisSeriesData &aData, const std::string &aGate) const
Emit the two-port Series die.
Definition kibis.cpp:572
IVtable m_pulldown
Definition kibis.h:298
double m_vinl
Definition kibis.h:274
IbisSeriesData m_seriesOff
Definition kibis.h:307
IBIS_CORNER m_supply
Definition kibis.h:220
IBIS_CORNER m_Cpin
Definition kibis.h:218
KIBIS_ACCURACY m_accuracy
Definition kibis.h:222
IBIS_CORNER m_Ccomp
Definition kibis.h:219
IBIS_CORNER m_Lpin
Definition kibis.h:217
IBIS_CORNER m_Rpin
Definition kibis.h:216
void SetCornerFromString(IBIS_CORNER &aCorner, const std::string &aString)
Definition kibis.cpp:1705
KIBIS_WAVEFORM * m_waveform
Definition kibis.h:221
TypMinMaxValue m_Rpin
Resistance from die to pin.
Definition kibis.h:387
bool writeSpiceDiffDriver(std::string &aDest, const std::string &aName, KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam)
Definition kibis.cpp:1614
TypMinMaxValue m_Lpin
Inductance from die to pin.
Definition kibis.h:389
void getKuKdFromFile(const std::string &aSimul)
Update m_Ku, m_Kd using with two waveform inputs.
Definition kibis.cpp:897
KIBIS_COMPONENT * m_parent
Definition kibis.h:393
std::vector< double > m_Ku
Definition kibis.h:395
std::string m_pinNumber
Pin Number Examples : 1, 2, 3 ( or for BGA ), A1, A2, A3, etc...
Definition kibis.h:384
std::string addDie(KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam, int aIndex)
Generate the spice directive to simulate the die for Ku/Kd estimation.
Definition kibis.cpp:853
bool writeSpiceDevice(std::string &aDest, const std::string &aName, KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam)
Definition kibis.cpp:1507
std::vector< double > m_t
Definition kibis.h:395
TypMinMaxValue m_Cpin
Capacitance from pin to GND.
Definition kibis.h:391
std::string m_signalName
Name of the pin Examples : "VCC", "GPIOA", "CLK", etc...
Definition kibis.h:380
void getKuKdTwoWaveforms(KIBIS_MODEL &aModel, const std::pair< IbisWaveform *, IbisWaveform * > &aPair1, const std::pair< IbisWaveform *, IbisWaveform * > &aPair2, const KIBIS_PARAMETER &aParam)
Update m_Ku, m_Kd using with two waveform inputs.
Definition kibis.cpp:1238
void getKuKdOneWaveform(KIBIS_MODEL &aModel, const std::pair< IbisWaveform *, IbisWaveform * > &aPair, const KIBIS_PARAMETER &aParam)
Update m_Ku, m_Kd using with a single waveform input.
Definition kibis.cpp:1066
bool writeSpiceDiffDevice(std::string &aDest, const std::string &aName, KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam)
Definition kibis.cpp:1651
std::string KuKdDriver(KIBIS_MODEL &aModel, const std::pair< IbisWaveform *, IbisWaveform * > &aPair, const KIBIS_PARAMETER &aParam, int aIndex)
Update m_Ku, m_Kd using with two waveform inputs.
Definition kibis.cpp:990
KIBIS_PIN(KIBIS &aTopLevel, const IbisComponentPin &aPin, const IbisComponentPackage &aPackage, IbisParser &aParser, KIBIS_COMPONENT *aParent, std::vector< KIBIS_MODEL > &aModels)
Definition kibis.cpp:162
KIBIS_PIN * SeriesPartner(std::string *aModelName=nullptr, std::string *aGroupName=nullptr) const
Partner pin from [Series Pin Mapping], or nullptr.
Definition kibis.cpp:403
std::vector< double > m_Kd
Definition kibis.h:395
bool writeSpiceDriver(std::string &aDest, const std::string &aName, KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam)
Definition kibis.cpp:1382
KIBIS_PIN * m_complementaryPin
Definition kibis.h:474
void getKuKdNoWaveform(KIBIS_MODEL &aModel, const KIBIS_PARAMETER &aParam)
Update m_Ku, m_Kd using no falling / rising waveform inputs ( low accuracy )
Definition kibis.cpp:1177
KIBIS_SUBMODEL(KIBIS &aTopLevel, const IbisSubmodel &aSource, IBIS_SUBMODEL_MODE aMode)
Definition kibis.cpp:236
IVtable m_GNDClamp
Definition kibis.h:255
std::string m_name
Definition kibis.h:250
bool HasPOWERClamp() const
Return true if the model has a clamp diode to the power net.
Definition kibis.cpp:257
IBIS_SUBMODEL_MODE m_mode
Definition kibis.h:252
bool HasGNDClamp() const
Return true if the model has a clamp diode to the gnd net.
Definition kibis.cpp:251
IVtable m_POWERClamp
Definition kibis.h:256
IBIS_SUBMODEL_TYPE m_type
Definition kibis.h:251
std::vector< std::pair< int, double > > GenerateBitSequence() const override
Definition kibis.cpp:1735
bool Check(const IbisWaveform *aRisingWf, const IbisWaveform *aFallingWf) const override
Definition kibis.cpp:1919
std::vector< std::pair< int, double > > GenerateBitSequence() const override
Definition kibis.cpp:1761
bool Check(const IbisWaveform *aRisingWf, const IbisWaveform *aFallingWf) const override
Definition kibis.cpp:1797
std::vector< std::pair< int, double > > GenerateBitSequence() const override
Definition kibis.cpp:1741
std::vector< std::pair< int, double > > GenerateBitSequence() const override
Definition kibis.cpp:1716
std::vector< std::pair< int, double > > GenerateBitSequence() const override
Definition kibis.cpp:1726
virtual bool Check(const IbisWaveform *aRisingWf, const IbisWaveform *aFallingWf) const
Definition kibis.h:92
KIBIS_WAVEFORM_TYPE GetType() const
Definition kibis.h:80
bool inverted
Definition kibis.h:82
virtual double GetDuration() const
Definition kibis.h:81
virtual std::vector< std::pair< int, double > > GenerateBitSequence() const
Definition kibis.h:85
Definition kibis.h:513
std::vector< KIBIS_MODEL > m_models
Definition kibis.h:524
KIBIS()
Constructor for unitialized KIBIS members.
Definition kibis.h:516
std::vector< KIBIS_COMPONENT > m_components
Definition kibis.h:523
KIBIS_MODEL * GetModel(const std::string &aName)
Return the model with name aName .
Definition kibis.cpp:1681
KIBIS_COMPONENT * GetComponent(const std::string &aName)
Return the component with name aName .
Definition kibis.cpp:1693
KIBIS_FILE m_file
Definition kibis.h:525
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:75
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
double value[3]
bool isNA() const
TypMinMaxValue V
std::vector< VTtableEntry > m_entries
double m_dt
#define _(s)
IBIS_CORNER
@ TYP
@ MIN
@ MAX
IBIS_SUBMODEL_MODE
std::vector< std::pair< int, double > > SimplifyBitSequence(const std::vector< std::pair< int, double > > &bits)
Definition kibis.cpp:51
IBIS_CORNER ReverseLogic(IBIS_CORNER aIn)
Definition kibis.cpp:82
KIBIS_ACCURACY
Accuracy level.
Definition kibis.h:206
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
std::string m_pin1
Definition kibis.h:486
std::string m_groupName
Definition kibis.h:489
std::string m_pin2
Definition kibis.h:487
std::string m_modelName
Definition kibis.h:488
KIBIS_PIN * partner
KIBIS_MODEL * model
const IbisMosfetEntry & mosfet
KIBIS_PIN * pin
KIBIS_PIN * pinA
const uint32_t seed
const int accuracy
wxString result
Test unit parsing edge cases and error handling.
int delta
#define ku