KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ibis_parser.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 "ibis_parser.h"
34
35#include <sstream>
36#include <cstring> //for memcmp
37#include <iterator>
38#include <locale_io.h> // KiCad header
39#include <wx/log.h>
40
41// _() is used here to mark translatable strings in IBIS_REPORTER::Report()
42// However, currently non ASCII7 chars are nor correctly handled when printing messages
43// So we disable translations
44#if 0
45#include <wx/intl.h> // for _() macro and wxGetTranslation()
46#else
47#undef _
48#define _( x ) x
49#endif
50
51
52bool IbisParser::compareIbisWord( const std::string& stra, const std::string& strb )
53{
54 return std::equal( stra.begin(), stra.end(),
55 strb.begin(), strb.end(),
56 [](char a, char b)
57 {
58 return std::tolower(a) == std::tolower(b);
59 });
60}
61
62
64{
65 if( ( m_rows < 1 ) || ( m_cols < 1 ) )
66 {
67 Report( _( "Dimension of matrices should be >= 1." ), RPT_SEVERITY_ERROR );
68 return false;
69 }
70
71 for( size_t i = 0; i < m_data.size(); i++ )
72 {
73 if( std::isnan( m_data[i] ) )
74 {
75 Report( _( "There are NaN elements in a matrix." ), RPT_SEVERITY_ERROR );
76 return false;
77 }
78 }
79
80 return true;
81}
82
83
84bool isNumberNA( double aNumber )
85{
86 double NA = nan( NAN_NA );
87 return std::memcmp( &aNumber, &NA, sizeof NA ) == 0;
88}
89
90
92{
94}
95
96
98{
99 bool status = true;
100
101 if( std::isnan( value[IBIS_CORNER::TYP] ) && !isNumberNA( value[IBIS_CORNER::TYP] ) )
102 status = false;
103
104 if( std::isnan( value[IBIS_CORNER::MIN] ) && !isNumberNA( value[IBIS_CORNER::MIN] ) )
105 status = false;
106
107 if( std::isnan( value[IBIS_CORNER::MAX] ) && !isNumberNA( value[IBIS_CORNER::MAX] ) )
108 status = false;
109
110 return status;
111}
112
113
115{
116 if( !aValue.isNA() )
117 {
121 else
125 else
127 }
128}
129
130
132{
133 bool status = true;
134
135 if( !m_Rpkg.Check() || m_Rpkg.isNA() )
136 {
137 Report( _( "Missing or invalid R_pkg value." ), RPT_SEVERITY_ERROR );
138 status = false;
139 }
140
141 if( !m_Lpkg.Check() || m_Lpkg.isNA() )
142 {
143 Report( _( "Missing or invalid L_pkg value." ), RPT_SEVERITY_ERROR );
144 status = false;
145 }
146
147 if( !m_Cpkg.Check() || m_Cpkg.isNA() )
148 {
149 Report( _( "Missing or invalid C_pkg value." ), RPT_SEVERITY_ERROR );
150 status = false;
151 }
152
153 return status;
154}
155
156
158{
159 bool status = true;
160
161 if( !m_dummy )
162 {
163 std::stringstream message;
164 message << _( "Checking pin " ) << m_pinName;
165
166 if( m_pinName.empty() )
167 {
168 if( status )
169 Report( message.str(), RPT_SEVERITY_ACTION );
170
171 Report( _( "Pin name cannot be empty." ), RPT_SEVERITY_ERROR );
172 status = false;
173 }
174
175 if( m_signalName.empty() )
176 {
177 if( status )
178 Report( message.str(), RPT_SEVERITY_ACTION );
179
180 Report( _( "Signal name cannot be empty." ), RPT_SEVERITY_ERROR );
181 status = false;
182 }
183
184 if( m_modelName.empty() )
185 {
186 if( status )
187 Report( message.str(), RPT_SEVERITY_ACTION );
188
189 Report( _( "Model name cannot be empty." ), RPT_SEVERITY_ERROR );
190 status = false;
191 }
192
193 if( std::isnan( m_Rpin ) && !isNumberNA( m_Rpin ) )
194 {
195 if( status )
196 Report( message.str(), RPT_SEVERITY_ACTION );
197
198 Report( _( "Rpin is not valid." ), RPT_SEVERITY_ERROR );
199 status = false;
200 }
201
202 if( std::isnan( m_Lpin )&& !isNumberNA( m_Lpin ) )
203 {
204 if( status )
205 Report( message.str(), RPT_SEVERITY_ACTION );
206
207 Report( _( "Lpin is not valid." ), RPT_SEVERITY_ERROR );
208 status = false;
209 }
210
211 if( std::isnan( m_Cpin )&& !isNumberNA( m_Cpin ) )
212 {
213 if( status )
214 Report( message.str(), RPT_SEVERITY_ACTION );
215
216 Report( _( "Cpin is not valid." ), RPT_SEVERITY_ERROR );
217 status = false;
218 }
219 }
220
221 return status;
222}
223
224
226{
227 bool status = true;
228
229 std::stringstream message;
230 message << _( "Checking component " ) << m_name;
231
232 if( m_name.empty() )
233 {
234 if( status )
235 Report( message.str(), RPT_SEVERITY_ACTION );
236
237 Report( _( "Component: name cannot be empty." ), RPT_SEVERITY_ERROR );
238 status = false;
239 }
240
241 if( m_manufacturer.empty() )
242 {
243 if( status )
244 Report( message.str(), RPT_SEVERITY_ACTION );
245
246 Report( _( "Component: manufacturer cannot be empty." ), RPT_SEVERITY_ERROR );
247 status = false;
248 }
249
250 if( !m_package.Check() )
251 {
252 if( status )
253 Report( message.str(), RPT_SEVERITY_ACTION );
254
255 Report( _( "Component: invalid package." ), RPT_SEVERITY_ERROR );
256 status = false;
257 }
258
259 if( m_pins.size() < 1 )
260 {
261 if( status )
262 Report( message.str(), RPT_SEVERITY_ACTION );
263
264 Report( _( "Component: no pin" ), RPT_SEVERITY_ERROR );
265 status = false;
266 }
267
268 for( IbisComponentPin& pin : m_pins )
269 status &= pin.Check();
270
271 return status;
272}
273
274
276{
277 return true;
278}
279
280
281std::string IBIS_BASE::doubleToString( double aNumber )
282{
283 std::ostringstream ss;
284 ss.setf( std::ios_base::scientific, std::ios_base::floatfield );
285 ss << aNumber;
286 return ss.str();
287}
288
289
290std::string IVtable::Spice( int aN, const std::string& aPort1, const std::string& aPort2, bool aNegateI,
291 const std::string& aModelName, IBIS_CORNER aCorner ) const
292{
293 std::string result = "";
294
295 if( m_entries.size() > 0 )
296 {
297 result += "a";
298 result += std::to_string( aN );
299 result += " %vd(";
300 result += aPort1;
301 result += " ";
302 result += aPort2;
303 result += ") %id(";
304 result += aNegateI ? aPort2 : aPort1;
305 result += " ";
306 result += aNegateI ? aPort1 : aPort2;
307 result += ") ";
308 result += aModelName;
309 result += "\n";
310 result += "\n";
311 result += ".model ";
312 result += aModelName;
313 result += " pwl(\n+ x_array=[";
314
315 for( const IVtableEntry& entry : m_entries )
316 {
317 if( !isNumberNA( entry.I.value[aCorner] ) )
318 {
319 result += doubleToString( entry.V );
320 result += "\n+";
321 }
322 }
323
324 result += "]\n+ y_array=[";
325
326 for( const IVtableEntry& entry : m_entries )
327 {
328 if( !isNumberNA( entry.I.value[aCorner] ) )
329 {
330 result += doubleToString( entry.I.value[aCorner] );
331 result += "\n+";
332 }
333 }
334
335 result += "]\n+ input_domain=0.05 fraction=TRUE)\n\n";
336 }
337 return result;
338}
339
340double IVtable::InterpolatedI( double aV, IBIS_CORNER aCorner ) const
341{
342 // @TODO change this algorithm
343
344 if( m_entries.back().V > m_entries.at( 0 ).V )
345 {
346 if( aV >= m_entries.back().V )
347 return m_entries.back().I.value[aCorner];
348
349 if( aV <= m_entries.at( 0 ).V )
350 return m_entries.at( 0 ).I.value[aCorner];
351
352 for( size_t i = 1; i < m_entries.size(); i++ )
353 {
354 if( m_entries.at( i ).V > aV )
355 {
356 return m_entries.at( i - 1 ).I.value[aCorner]
357 + ( m_entries.at( i ).I.value[aCorner]
358 - m_entries.at( i - 1 ).I.value[aCorner] )
359 / ( m_entries.at( i ).V - m_entries.at( i - 1 ).V )
360 * ( aV - m_entries.at( i - 1 ).V );
361 }
362 }
363
364 Report( _( "Cannot interpolate the current based on this IV table." ), RPT_SEVERITY_ERROR );
365 return nan( "" );
366 }
367 else
368 {
369 // exiting the function here would mean the IV table is reversed.
370 return nan( "" );
371 }
372 // @TODO prefer another method such as a dichotomy
373}
374
376{
377 bool status = true;
378
379 for( IVtableEntry& entry : m_entries )
380 {
381 if( std::isnan( entry.V ) )
382 {
383 Report( _( "There is an invalid voltage in an IV table" ), RPT_SEVERITY_ERROR );
384 status = false;
385 break;
386 }
387
388 if( !entry.I.Check() )
389 {
390 Report( _( "There is an invalid current in an IV table" ), RPT_SEVERITY_ERROR );
391 status = false;
392 break;
393 }
394 }
395
396 // TODO: Check if the IV table is monotonic :
397 // IBIS standard defines 8 criteria for an IV table to be monotonic
398 // Issue a warning, not an error
399
400 return status;
401}
402
403
405{
406 bool status = true;
407
408 if( std::isnan( value[IBIS_CORNER::TYP].m_dv ) )
409 status = false;
410
411 if( std::isnan( value[IBIS_CORNER::TYP].m_dt ) )
412 status = false;
413
414 if( std::isnan( value[IBIS_CORNER::MIN].m_dv ) && !isNumberNA( value[IBIS_CORNER::MIN].m_dv ) )
415 status = false;
416
417 if( std::isnan( value[IBIS_CORNER::MIN].m_dt ) && !isNumberNA( value[IBIS_CORNER::MIN].m_dt ) )
418 status = false;
419
420 if( std::isnan( value[IBIS_CORNER::MIN].m_dv ) && !isNumberNA( value[IBIS_CORNER::MIN].m_dv ) )
421 status = false;
422
423 if( std::isnan( value[IBIS_CORNER::MIN].m_dt ) && !isNumberNA( value[IBIS_CORNER::MIN].m_dt ) )
424 status = false;
425
426 return status;
427}
428
430{
431 bool status = true;
432
433 if( std::isnan( m_Rload ) )
434 {
435 status = false;
436 Report( _( "Invalid R_load." ), RPT_SEVERITY_ERROR );
437 }
438
439 if( !m_falling.Check() )
440 {
441 Report( _( "Invalid falling dV/dt." ), RPT_SEVERITY_ERROR );
442 status = false;
443 }
444
445 if( !m_rising.Check() )
446 {
447 Report( _( "Invalid rising dV/dt." ), RPT_SEVERITY_ERROR );
448 status = false;
449 }
450
451 return status;
452}
453
454
455
457{
458 return !m_Rseries.isNA() || !m_Lseries.isNA() || !m_Cseries.isNA()
459 || !m_RlSeries.isNA() || !m_RcSeries.isNA() || !m_LcSeries.isNA()
460 || !m_seriesCurrent.m_entries.empty() || !m_seriesMosfet.empty();
461}
462
463
465{
466 bool status = true;
467
468 if( m_name.empty() )
469 {
470 Report( _( "Model name cannot be empty" ), RPT_SEVERITY_ERROR );
471 status = false;
472 }
473
474 std::stringstream message;
475 message << _( "Checking model " ) << m_name;
476
478 {
479 if( status )
480 Report( message.str(), RPT_SEVERITY_ACTION );
481
482 Report( _( "Undefined model type." ), RPT_SEVERITY_ERROR );
483 status = false;
484 }
485
486 if( std::isnan( m_vinh ) && !isNumberNA( m_vinh ) )
487 {
488 if( status )
489 Report( message.str(), RPT_SEVERITY_ACTION );
490
491 Report( _( "Invalid Vinh value." ), RPT_SEVERITY_ERROR );
492 status = false;
493 }
494
495 if( std::isnan( m_vinl ) && !isNumberNA( m_vinl ) )
496 {
497 if( status )
498 Report( message.str(), RPT_SEVERITY_ACTION );
499
500 Report( _( "Invalid Vinl value." ), RPT_SEVERITY_ERROR );
501 status = false;
502 }
503
504 if( std::isnan( m_rref ) && !isNumberNA( m_rref ) )
505 {
506 if( status )
507 Report( message.str(), RPT_SEVERITY_ACTION );
508
509 Report( _( "Invalid R_ref value." ), RPT_SEVERITY_ERROR );
510 status = false;
511 }
512
513 if( std::isnan( m_cref ) && !isNumberNA( m_cref ) )
514 {
515 if( status )
516 Report( message.str(), RPT_SEVERITY_ACTION );
517
518 Report( _( "Invalid C_ref value." ), RPT_SEVERITY_ERROR );
519 status = false;
520 }
521
522 if( std::isnan( m_vref ) && !isNumberNA( m_vref ) )
523 {
524 if( status )
525 Report( message.str(), RPT_SEVERITY_ACTION );
526
527 Report( _( "Invalid V_ref value." ), RPT_SEVERITY_ERROR );
528 status = false;
529 }
530
531 if( std::isnan( m_vmeas ) && !isNumberNA( m_vmeas ) )
532 {
533 if( status )
534 Report( message.str(), RPT_SEVERITY_ACTION );
535
536 Report( _( "Invalid V_meas value." ), RPT_SEVERITY_ERROR );
537 status = false;
538 }
539
540 if( !m_C_comp.Check() )
541 {
542 if( status )
543 Report( message.str(), RPT_SEVERITY_ACTION );
544
545 Report( _( "Missing or invalid C_comp value." ), RPT_SEVERITY_ERROR );
546 status = false;
547 }
548
549 if( !m_C_comp_gnd_clamp.Check() )
550 {
551 if( status )
552 Report( message.str(), RPT_SEVERITY_ACTION );
553
554 Report( _( "Missing or invalid C_comp_gnd_clamp value." ), RPT_SEVERITY_ERROR );
555 status = false;
556 }
557
558 if( !m_C_comp_power_clamp.Check() )
559 {
560 if( status )
561 Report( message.str(), RPT_SEVERITY_ACTION );
562
563 Report( _( "Missing or invalid C_comp_power_clamp value." ), RPT_SEVERITY_ERROR );
564 status = false;
565 }
566
567 if( !m_C_comp_pullup.Check() )
568 {
569 if( status )
570 Report( message.str(), RPT_SEVERITY_ACTION );
571
572 Report( _( "Missing or invalid C_comp_pullup value." ), RPT_SEVERITY_ERROR );
573 status = false;
574 }
575
576 if( !m_C_comp_pulldown.Check() )
577 {
578 if( status )
579 Report( message.str(), RPT_SEVERITY_ACTION );
580
581 Report( _( "Missing or invalid C_comp_pulldown value." ), RPT_SEVERITY_ERROR );
582 status = false;
583 }
584
585 if( m_C_comp.isNA() && m_C_comp_gnd_clamp.isNA() && m_C_comp_power_clamp.isNA()
586 && m_C_comp_pullup.isNA() && m_C_comp_pulldown.isNA() )
587 {
588 if( status )
589 Report( message.str(), RPT_SEVERITY_ACTION );
590
591 Report( _( "No C_comp values are available." ), RPT_SEVERITY_ERROR );
592 status = false;
593 }
594
595 if( !m_temperatureRange.Check() || m_temperatureRange.isNA() )
596 {
597 if( status )
598 Report( message.str(), RPT_SEVERITY_ACTION );
599
600 Report( _( "Missing or invalid Temperature Range value." ), RPT_SEVERITY_ERROR );
601 status = false;
602 }
603
604 if( !m_voltageRange.Check() )
605 {
606 if( status )
607 Report( message.str(), RPT_SEVERITY_ACTION );
608
609 Report( _( "Missing or invalid Voltage Range value." ), RPT_SEVERITY_ERROR );
610 status = false;
611 }
612
613 if( !m_pullupReference.Check() )
614 {
615 if( status )
616 Report( message.str(), RPT_SEVERITY_ACTION );
617
618 Report( _( "Missing or invalid Pullup Reference value." ), RPT_SEVERITY_ERROR );
619 status = false;
620 }
621
622 if( !m_pulldownReference.Check() )
623 {
624 if( status )
625 Report( message.str(), RPT_SEVERITY_ACTION );
626
627 Report( _( "Missing or invalid Pulldown Reference value." ), RPT_SEVERITY_ERROR );
628 status = false;
629 }
630
631 if( !m_GNDClampReference.Check() )
632 {
633 if( status )
634 Report( message.str(), RPT_SEVERITY_ACTION );
635
636 Report( _( "Missing or invalid GND Clamp Reference value." ), RPT_SEVERITY_ERROR );
637 status = false;
638 }
639
640 if( !m_POWERClampReference.Check() )
641 {
642 if( status )
643 Report( message.str(), RPT_SEVERITY_ACTION );
644
645 Report( _( "Missing or invalid POWER Clamp Reference value." ), RPT_SEVERITY_ERROR );
646 status = false;
647 }
648
649 if ( m_voltageRange.isNA() && ( m_pullupReference.isNA() || m_pulldownReference.isNA()
650 || m_GNDClampReference.isNA() || m_POWERClampReference.isNA() ) )
651 {
652 if( status )
653 Report( message.str(), RPT_SEVERITY_ACTION );
654
655 Report( _( "Voltage Range or Reference is missing." ), RPT_SEVERITY_ERROR );
656 status = false;
657 }
658
659 if( !m_pulldown.Check() )
660 {
661 Report( _( "Invalid Pulldown table." ), RPT_SEVERITY_ERROR );
662 status = false;
663 }
664
665 if( !m_pullup.Check() )
666 {
667 Report( _( "Invalid Pullup table." ), RPT_SEVERITY_ERROR );
668 status = false;
669 }
670
671 if( !m_ISSO_PD.Check() )
672 {
673 Report( _( "Invalid ISSO_PD table." ), RPT_SEVERITY_ERROR );
674 status = false;
675 }
676
677 if( !m_ISSO_PU.Check() )
678 {
679 Report( _( "Invalid ISSO_PU table." ), RPT_SEVERITY_ERROR );
680 status = false;
681 }
682
683 if( !m_compositeCurrent.Check() )
684 {
685 Report( _( "Invalid Composite Current table." ), RPT_SEVERITY_ERROR );
686 status = false;
687 }
688
689 const bool isSeries = ( m_type == IBIS_MODEL_TYPE::SERIES );
690 const bool isSeriesSwitch = ( m_type == IBIS_MODEL_TYPE::SERIES_SWITCH );
691
692 auto checkSeriesData = [&]( IbisSeriesData& aData, const wxString& aLabel )
693 {
694 auto report = [&]( const wxString& aMsg )
695 {
696 Report( wxString::Format( aMsg, aLabel ).ToStdString(), RPT_SEVERITY_ERROR );
697 status = false;
698 };
699
700 if( !aData.m_seriesCurrent.Check() )
701 report( _( "Invalid Series Current table in %s." ) );
702
704 {
705 if( !mosfet.m_table.Check() )
706 report( _( "Invalid Series MOSFET table in %s." ) );
707
708 if( isNumberNA( mosfet.m_Vds ) || mosfet.m_Vds <= 0.0 )
709 report( _( "Series MOSFET Vds must be > 0 in %s." ) );
710 }
711
712 if( !aData.m_RlSeries.isNA() && aData.m_Lseries.isNA() )
713 report( _( "Rl Series requires L Series in %s." ) );
714
715 if( ( !aData.m_RcSeries.isNA() || !aData.m_LcSeries.isNA() ) && aData.m_Cseries.isNA() )
716 report( _( "Rc/Lc Series requires C Series in %s." ) );
717 };
718
719 if( isSeries )
720 {
721 checkSeriesData( m_series, wxT( "[Model]" ) );
722
723 if( m_seriesOn.m_seen || m_seriesOff.m_seen )
724 {
725 Report( _( "[On] and [Off] are only allowed in Series_switch models." ),
727 status = false;
728 }
729
730 if( !m_series.isPopulated() )
731 {
732 Report( _( "Series model has no series elements." ), RPT_SEVERITY_ERROR );
733 status = false;
734 }
735 }
736 else if( isSeriesSwitch )
737 {
738 checkSeriesData( m_seriesOn, wxT( "[On]" ) );
739 checkSeriesData( m_seriesOff, wxT( "[Off]" ) );
740
741 if( !m_seriesOn.m_seen )
742 {
743 Report( _( "Series_switch model is missing the [On] block." ), RPT_SEVERITY_ERROR );
744 status = false;
745 }
746
747 if( !m_seriesOff.m_seen )
748 {
749 Report( _( "Series_switch model is missing the [Off] block." ), RPT_SEVERITY_ERROR );
750 status = false;
751 }
752
753 if( m_series.isPopulated() )
754 {
755 Report( _( "Series_switch model has series elements outside [On]/[Off]." ),
757 status = false;
758 }
759 }
760
761 if( !m_POWERClamp.Check() )
762 {
763 Report( _( "Invalid POWER Clamp table." ), RPT_SEVERITY_ERROR );
764 status = false;
765 }
766
767 if( !m_GNDClamp.Check() )
768 {
769 Report( _( "Invalid GND Clamp table." ), RPT_SEVERITY_ERROR );
770 status = false;
771 }
772
776 {
777 if( !m_ramp.Check() )
778 Report( _( "Invalid Ramp specification." ), RPT_SEVERITY_ERROR );
779 }
780
781 return status;
782}
783
784
786{
787 bool status = true;
788
789 if( m_name.empty() )
790 {
791 Report( _( "Submodel name cannot be empty." ), RPT_SEVERITY_ERROR );
792 status = false;
793 }
794
795 std::stringstream message;
796 message << _( "Checking submodel " ) << m_name;
797
799 {
800 if( status )
801 Report( message.str(), RPT_SEVERITY_ACTION );
802
803 Report( _( "The submodel has no type." ), RPT_SEVERITY_ERROR );
804 status = false;
805 }
806
807 if( !m_VtriggerR.Check() )
808 {
809 if( status )
810 Report( message.str(), RPT_SEVERITY_ACTION );
811
812 Report( _( "Missing or invalid V_trigger_r value." ), RPT_SEVERITY_ERROR );
813 status = false;
814 }
815 if( !m_VtriggerF.Check() )
816 {
817 if( status )
818 Report( message.str(), RPT_SEVERITY_ACTION );
819
820 Report( _( "Missing or invalid V_trigger_f value." ), RPT_SEVERITY_ERROR );
821 status = false;
822 }
823 if( !m_offDelay.Check() )
824 {
825 if( status )
826 Report( message.str(), RPT_SEVERITY_ACTION );
827
828 Report( _( "Missing or invalid Off_delay value." ), RPT_SEVERITY_ERROR );
829 status = false;
830 }
831 if( !m_pullup.Check() )
832 {
833 Report( _( "Invalid Pullup table." ), RPT_SEVERITY_ERROR );
834 status = false;
835 }
836 if( !m_pulldown.Check() )
837 {
838 Report( _( "Invalid Pulldown table." ), RPT_SEVERITY_ERROR );
839 status = false;
840 }
841 if( !m_GNDClamp.Check() )
842 {
843 Report( _( "Invalid GND Clamp table." ), RPT_SEVERITY_ERROR );
844 status = false;
845 }
846 if( !m_POWERClamp.Check() )
847 {
848 Report( _( "Invalid POWER Clamp table." ), RPT_SEVERITY_ERROR );
849 status = false;
850 }
851 if( !m_GNDPulse.Check() )
852 {
853 Report( _( "Invalid GND Pulse table." ), RPT_SEVERITY_ERROR );
854 status = false;
855 }
856 if( !m_POWERPulse.Check() )
857 {
858 Report( _( "Invalid POWER Pulse table." ), RPT_SEVERITY_ERROR );
859 status = false;
860 }
861 if( !m_ramp.Check() )
862 {
863 Report( _( "Invalid Ramp specification." ), RPT_SEVERITY_ERROR );
864 status = false;
865 }
867 {
868 std::stringstream err_msg;
869 switch( m_type )
870 {
871 case IBIS_SUBMODEL_TYPE::BUS_HOLD: err_msg << "Bus Hold"; break;
872 case IBIS_SUBMODEL_TYPE::FALL_BACK: err_msg << "Fall Back"; break;
873 default: wxLogMessage( "Invalid submodel type: %i", (int) m_type ); return false;
874 }
875 err_msg << _( " submodels are not yet supported." );
876 Report( err_msg.str(), RPT_SEVERITY_ERROR );
877 status = false;
878 }
879 else if( !m_VtriggerR.isNA() || !m_VtriggerF.isNA() )
880 {
881 Report( _( "Triggered mode dynamic clamp submodels are not yet supported." ), RPT_SEVERITY_ERROR );
882 status = false;
883 }
884 return status;
885}
886
887
889{
890 bool status = true;
891
892 std::stringstream message;
893 message << _( "Checking Header..." );
894
895 if( m_ibisVersion == -1 )
896 {
897 if( status )
898 Report( message.str(), RPT_SEVERITY_ACTION );
899
900 Report( _( "Missing [IBIS Ver]" ), RPT_SEVERITY_ERROR );
901 status = false;
902 }
903
905 {
906 if( status )
907 Report( message.str(), RPT_SEVERITY_ACTION );
908
909 Report( _( "The parser does not handle this IBIS version" ), RPT_SEVERITY_ERROR );
910 status = false;
911 }
912
913 if( m_fileRevision == -1 )
914 {
915 if( status )
916 Report( message.str(), RPT_SEVERITY_ACTION );
917
918 Report( _( "Missing [File Rev]" ), RPT_SEVERITY_ERROR );
919 status = false;
920 }
921
922 if( m_fileName.empty() )
923 {
924 if( status )
925 Report( message.str(), RPT_SEVERITY_ACTION );
926
927 Report( _( "Missing [File Name]" ), RPT_SEVERITY_ERROR );
928 status = false;
929 }
930
931 std::string ext = m_fileName.substr( m_fileName.length() - 4 );
932
933 if( !( !strcmp( ext.c_str(), ".ibs" ) || !strcmp( ext.c_str(), ".pkg" )
934 || !strcmp( ext.c_str(), ".ebd" ) || !strcmp( ext.c_str(), ".ims" ) ) )
935 {
936 if( status )
937 Report( message.str(), RPT_SEVERITY_ACTION );
938
939 Report( "Invalid file extension in [File Name]", RPT_SEVERITY_ERROR );
940 status = false;
941 }
942
943 return status;
944}
945
947{
948 bool status = true;
949
950 if( m_name.empty() )
951 {
952 Report( _( "Package model name cannot be empty." ), RPT_SEVERITY_ERROR );
953 status = false;
954 }
955
956 std::stringstream message;
957 message << _( "Checking package model " ) << m_name;
958
959 if( m_manufacturer.empty() )
960 {
961 if( status )
962 Report( message.str(), RPT_SEVERITY_ACTION );
963
964 Report( _( "Manufacturer cannot be empty." ), RPT_SEVERITY_ERROR );
965 status = false;
966 }
967
968 if( m_OEM.empty() )
969 {
970 if( status )
971 Report( message.str(), RPT_SEVERITY_ACTION );
972
973 Report( _( "OEM cannot be empty." ), RPT_SEVERITY_ERROR );
974 status = false;
975 }
976
977 if( m_numberOfPins < 0 )
978 {
979 if( status )
980 Report( message.str(), RPT_SEVERITY_ACTION );
981
982 Report( _( "Negative number of pins." ), RPT_SEVERITY_ERROR );
983 status = false;
984 }
985
986 if( (int)m_pins.size() != m_numberOfPins )
987 {
988 if( status )
989 Report( message.str(), RPT_SEVERITY_ACTION );
990
991 Report( "Number of pins does not match [Pin Numbers] size.", RPT_SEVERITY_ERROR );
992 status = false;
993 }
994
995 // resistance matrix is not required
996
997 if( !( m_resistanceMatrix )->Check() )
998 {
999 if( status )
1000 Report( message.str(), RPT_SEVERITY_ACTION );
1001
1002 Report( _( "Resistance matrix is incorrect." ), RPT_SEVERITY_ERROR );
1003 status = false;
1004 }
1005
1006 if( m_capacitanceMatrix != nullptr )
1007 {
1009 {
1010 if( status )
1011 Report( message.str(), RPT_SEVERITY_ACTION );
1012
1013 Report( _( "Capacitance matrix is undefined." ), RPT_SEVERITY_ERROR );
1014 status = false;
1015 }
1016
1017 if( !m_capacitanceMatrix->Check() )
1018 {
1019 if( status )
1020 Report( message.str(), RPT_SEVERITY_ACTION );
1021
1022 Report( _( "Capacitance matrix is incorrect." ), RPT_SEVERITY_ERROR );
1023 status = false;
1024 }
1025 }
1026 else
1027 {
1028 if( status )
1029 Report( message.str(), RPT_SEVERITY_ACTION );
1030
1031 Report( _( "Capacitance matrix is nullptr." ), RPT_SEVERITY_ERROR );
1032 status = false;
1033 }
1034
1035 if( m_inductanceMatrix != nullptr )
1036 {
1038 {
1039 if( status )
1040 Report( message.str(), RPT_SEVERITY_ACTION );
1041
1042 Report( _( "Inductance matrix is undefined." ), RPT_SEVERITY_ERROR );
1043 status = false;
1044 }
1045
1046 if( !m_inductanceMatrix->Check() )
1047 {
1048 if( status )
1049 Report( message.str(), RPT_SEVERITY_ACTION );
1050
1051 Report( _( "Inductance matrix is incorrect." ), RPT_SEVERITY_ERROR );
1052 status = false;
1053 }
1054 }
1055 else
1056 {
1057 if( status )
1058 Report( message.str(), RPT_SEVERITY_ACTION );
1059
1060 Report( _( "Inductance matrix is nullptr." ), RPT_SEVERITY_ERROR );
1061 status = false;
1062 }
1063 return status;
1064}
1065
1066
1067bool IbisParser::ParseFile( const std::string& aFileName )
1068{
1069 std::stringstream err_msg;
1070
1071 std::ifstream ibisFile;
1072 ibisFile.open( aFileName );
1073
1074 if( !ibisFile.is_open() )
1075 {
1076 err_msg << _( "Cannot open file " ) << aFileName;
1077 Report( err_msg.str(), RPT_SEVERITY_ERROR );
1078 return false;
1079 }
1080
1081 std::ostringstream ss;
1082 ss << ibisFile.rdbuf();
1083 const std::string& s = ss.str();
1084 m_buffer = std::vector<char>( s.begin(), s.end() );
1085 m_buffer.push_back( 0 );
1086
1087 long size = m_buffer.size();
1088
1089 m_lineCounter = 0;
1090 m_bufferIndex = 0;
1091
1092 bool status = true;
1093
1094 LOCALE_IO toggle; // Temporary switch the locale to standard C to r/w floats
1095
1096 while( ( m_bufferIndex < size ) && status )
1097 {
1098 if( !getNextLine() )
1099 {
1100 Report( _( "Unexpected end of file. Missing [END] ?" ), RPT_SEVERITY_ERROR );
1101 status = false;
1102 }
1103
1104 if( status && m_parrot )
1105 printLine();
1106
1107 if( status && !onNewLine() )
1108 {
1109 err_msg.clear();
1110 err_msg << _( "Error on line " ) << std::to_string( m_lineCounter );
1111 Report( err_msg.str(), RPT_SEVERITY_ERROR );
1112 status = false;
1113 }
1114
1116 break;
1117 }
1118
1119 if( status )
1120 {
1121 for( const IbisModel& model : m_ibisFile.m_models )
1122 {
1123 for( const IbisSubmodelMode& submodel : model.m_submodels )
1124 {
1125 if( m_ibisFile.m_submodels.count( submodel.m_name ) == 0 )
1126 {
1127 err_msg.clear();
1128 err_msg << submodel.m_name << _( " submodel not found." );
1129 Report( err_msg.str(), RPT_SEVERITY_ERROR );
1130 status = false;
1131 goto done;
1132 }
1133 }
1134 }
1135 }
1136
1137done:
1138 m_buffer.clear();
1139 return status;
1140}
1141
1143{
1144 while( isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
1145 m_lineIndex++;
1146}
1147
1148
1150{
1152
1154 {
1155 Report( _( "A line did not end properly." ), RPT_SEVERITY_ERROR );
1156 return false;
1157 }
1158
1159 return true;
1160}
1161
1162
1164{
1165 int cursor = m_lineIndex;
1166
1167 while( isspace( m_buffer[m_lineOffset + cursor] ) && cursor < m_lineLength )
1168 cursor++;
1169
1170 return ( cursor >= m_lineLength );
1171}
1172
1173
1174bool IbisParser::parseDvdt( dvdt& aDest, std::string& aString )
1175{
1176 bool status = true;
1177
1178 if( aString == "NA" )
1179 {
1180 aDest.m_dv = nan( NAN_NA );
1181 aDest.m_dt = nan( NAN_NA );
1182
1183 return status;
1184 }
1185
1186 int i = 0;
1187
1188 for( i = 1; i < (int)aString.length(); i++ )
1189 {
1190 if( aString.at( i ) == '/' )
1191 break;
1192 }
1193
1194 if( aString.at( i ) == '/' )
1195 {
1196 std::string str1 = aString.substr( 0, i );
1197 std::string str2 = aString.substr( i + 1, aString.size() - i - 1 );
1198
1199 if( !parseDouble( aDest.m_dv, str1, true ) || !parseDouble( aDest.m_dt, str2, true ) )
1200 status = false;
1201 }
1202
1203 return status;
1204}
1205
1206
1208{
1209 bool status = true;
1210 std::string str;
1211
1212 if( readWord( str ) )
1213 {
1214 if( !parseDvdt( aDest, str ) )
1215 {
1216 std::stringstream message;
1217 message << str << _( " is not a valid dV/dt value." );
1218 Report( message.str(), RPT_SEVERITY_WARNING );
1219 status = false;
1220 }
1221 }
1222 else
1223 {
1224 Report( _( "A dV/dt value is missing." ), RPT_SEVERITY_WARNING );
1225 status = false;
1226 }
1227
1228 return status;
1229}
1230
1231
1232bool IbisParser::parseDouble( double& aDest, std::string& aStr, bool aAllowModifiers )
1233{
1234 // " an entry of the C matrix could be given as 1.23e-12 or as 1.23p or 1.23pF."
1235 // Kibis: This implementation will also allow 1.23e-3n
1236
1238 bool status = true;
1239 bool converted = false;
1240
1241 std::string str = aStr;
1242
1243 double result;
1244 size_t size = 0;
1245
1246
1247 if( str == "NA" )
1248 {
1249 result = nan( NAN_NA );
1250 }
1251 else
1252 {
1253 try
1254 {
1255 result = std::stod( str, &size );
1256 converted = true;
1257 }
1258 catch( ... )
1259 {
1260 result = nan( NAN_INVALID );
1261 status = false;
1262 }
1263 }
1264
1265 if( converted && ( size < str.length() ) )
1266 {
1267 switch( static_cast<char>( str.at( size ) ) )
1268 {
1269 case 'T': result *= 1e12; break;
1270 case 'G': result *= 1e9; break;
1271 case 'M': result *= 1e6; break;
1272 case 'k': result *= 1e3; break;
1273 case 'm': result *= 1e-3; break;
1274 case 'u': result *= 1e-6; break;
1275 case 'n': result *= 1e-9; break;
1276 case 'p': result *= 1e-12; break;
1277 case 'f': result *= 1e-15; break;
1278 default:
1279 break;
1280 // In some files, "vinh = 3.0V", therefore we can't return false in the default case
1281 }
1282 }
1283
1284 aDest = result;
1285
1286 return status;
1287}
1288
1289
1291{
1292 m_lineCounter++;
1293
1294 long tmpIndex = m_bufferIndex;
1295
1297
1298 if( m_bufferIndex >= (int)m_buffer.size() )
1299 return false;
1300
1301 char c = m_buffer[m_bufferIndex++];
1302
1303 int i = 1;
1304
1305 while( c != m_commentChar && c != 0 && c != '\n' && i < IBIS_MAX_LINE_LENGTH )
1306 {
1307 c = m_buffer[m_bufferIndex++];
1308 i++;
1309 }
1310
1311 if( i == IBIS_MAX_LINE_LENGTH )
1312 {
1313 Report( _( "Line exceeds maximum length." ), RPT_SEVERITY_ERROR );
1314 return false;
1315 }
1316
1317 m_lineLength = m_bufferIndex - tmpIndex - 1; // Don't add the end of line condition
1318 m_lineIndex = 0;
1319
1320 if( c == m_commentChar )
1321 {
1322 while( c != 0 && c != '\n' )
1323 c = m_buffer[m_bufferIndex++];
1324 }
1325
1326 if( i == IBIS_MAX_LINE_LENGTH )
1327 {
1328 Report( _( "Line exceeds maximum length." ), RPT_SEVERITY_ERROR );
1329 return false;
1330 }
1331
1332 return true;
1333}
1334
1335
1337{
1338 for( int i = 0; i < m_lineLength; i++ )
1339 std::cout << m_buffer[m_lineOffset + i];
1340
1341 std::cout << std::endl;
1342}
1343
1344bool IbisParser::readDouble( double& aDest )
1345{
1346 bool status = true;
1347 std::string str;
1348
1349 if( readWord( str ) )
1350 {
1351 if( !parseDouble( aDest, str, true ) )
1352 {
1353 Report( _( "Failed to read a double." ), RPT_SEVERITY_WARNING );
1354 status = false;
1355 }
1356 }
1357 else
1358 {
1359 Report( _( "Failed to read a word." ), RPT_SEVERITY_WARNING );
1360 status = false;
1361 }
1362
1363 return status;
1364}
1365
1366bool IbisParser::readInt( int& aDest )
1367{
1368 bool status = true;
1369 std::string str;
1370
1371 if( readWord( str ) )
1372 {
1373 double result;
1374 size_t size = 0;
1375
1376 try
1377 {
1378 result = std::stoi( str, &size );
1379 }
1380 catch( ... )
1381 {
1382 if( str == "NA" )
1383 {
1384 result = nan( NAN_NA );
1385 }
1386 else
1387 {
1388 result = nan( NAN_INVALID );
1389 status = false;
1390 }
1391 }
1392
1393 if( size != str.size() )
1394 {
1395 status = false;
1396 Report( _( "Number is not an integer" ), RPT_SEVERITY_WARNING );
1397 }
1398
1399 aDest = result;
1400 }
1401 else
1402 {
1403 Report( _( "Failed to read a word." ), RPT_SEVERITY_WARNING );
1404 status = false;
1405 }
1406
1407 return status;
1408}
1409
1410bool IbisParser::readWord( std::string& aDest )
1411{
1413
1414 int startIndex = m_lineIndex;
1415
1416 while( !isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
1417 m_lineIndex++;
1418
1419 std::vector<char>::iterator start = std::next( m_buffer.begin(), m_lineOffset + startIndex );
1420 std::vector<char>::iterator end = std::next( m_buffer.begin(), m_lineOffset + m_lineIndex );
1421 aDest = std::string( start, end );
1422
1423 return ( aDest.size() > 0 );
1424}
1425
1426bool IbisParser::readString( std::string& aDest )
1427{
1428 while( m_lineIndex < m_lineLength )
1429 aDest += m_buffer[m_lineOffset + m_lineIndex++];
1430
1431 // Remove extra whitespace characters
1432 int len = aDest.length();
1433
1434 if( len < 1 )
1435 return true; // The data is likely on the next line. Skip.
1436
1437 char c = aDest[len - 1];
1438 int i = 0;
1439
1440 while( isspace( c ) && ( i < len ) )
1441 {
1442 c = aDest[len - 1 - i];
1443 i++;
1444 }
1445
1446 aDest = aDest.substr( 0, len - i + 1 );
1447
1448 return true;
1449}
1450
1451bool IbisParser::storeString( std::string& aDest, bool aMultiline )
1452{
1453 bool status = true;
1454
1456
1457 status &= readString( aDest );
1458
1460 m_continuingString = &aDest;
1461
1462 status &= checkEndofLine();
1463 return status;
1464}
1465
1466
1468{
1470
1471 std::string strChar = "";
1472
1473 // We cannot stop at m_lineLength here, because lineLength could stop before |_char
1474 // if the char remains the same
1475
1476 char c = m_buffer[m_lineOffset + m_lineIndex++];
1477 char d = c;
1478
1479 if( !( c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\''
1480 || c == '(' || c == ')' || c == '*' || c == ',' || c == ':' || c == ';' || c == '<'
1481 || c == '>' || c == '?' || c == '@' || c == '\\' || c == '^' || c == '`' || c == '{'
1482 || c == '|' || c == '}' || c == '~' || c == ')' ) )
1483 {
1484 Report( _( "New comment character is invalid." ), RPT_SEVERITY_ERROR );
1485 }
1486
1488
1489 while( ( !isspace( c ) ) && c != 0 && c != '\n' )
1490 {
1491 strChar += c;
1493 }
1494
1495 if( strChar != "_char" )
1496 {
1497 Report( _( "Invalid syntax. Should be |_char or &_char, etc..." ), RPT_SEVERITY_ERROR );
1498 return false;
1499 }
1500
1501 while( isspace( c ) && c != 0 && c != '\n' && c != d )
1503
1504 if( ( !isspace( c ) ) && c != d )
1505 {
1506 Report( _( "No extra argument was expected" ), RPT_SEVERITY_ERROR );
1507 return false;
1508 }
1509
1510 m_commentChar = d;
1511
1513
1514 return true;
1515}
1516
1518{
1519 std::string keyword = "";
1520 //"Keywords must be enclosed in square brackets, “[]”, and must start in column 1 of the line."
1521 //"No space or tab is allowed immediately after the opening bracket “[” or immediately"
1522 // "before the closing bracket “]"
1523
1524 if( m_buffer[m_lineOffset + m_lineIndex] != '[' )
1525 {
1526 // We return an empty keyword, this should stop the parser.
1527 return "";
1528 }
1529
1530 m_lineIndex++;
1531
1532 char c;
1534
1535 while( ( c != ']' )
1536 && ( m_lineIndex
1537 < m_lineLength ) ) // We know the maximum keyword length, we could add a condition.
1538 {
1539 // "Underscores and spaces are equivalent in keywords"
1540 if( c == ' ' )
1541 c = '_';
1542
1543 keyword += c;
1545 }
1546
1547 return keyword;
1548}
1549
1550bool IbisParser::changeContext( std::string& aKeyword )
1551{
1552 bool status = true;
1553
1554 if( status )
1555 {
1556 switch( m_context )
1557 {
1558 case IBIS_PARSER_CONTEXT::HEADER: status &= m_ibisFile.m_header.Check(); break;
1559 case IBIS_PARSER_CONTEXT::COMPONENT: status &= m_currentComponent->Check(); break;
1560 case IBIS_PARSER_CONTEXT::MODEL: status &= m_currentModel->Check(); break;
1561 case IBIS_PARSER_CONTEXT::SUBMODEL: status &= m_currentSubmodel->Check(); break;
1562 case IBIS_PARSER_CONTEXT::MODELSELECTOR: status &= m_currentModelSelector->Check(); break;
1563 case IBIS_PARSER_CONTEXT::PACKAGEMODEL: status &= m_currentPackageModel->Check(); break;
1565 Report( "Cannot change context after [END]" );
1566 status = false;
1567 break;
1568 default:
1569 Report( "Changing context from an undefined context" );
1570 }
1571 }
1572
1573 if( !compareIbisWord( aKeyword.c_str(), "End" ) && status )
1574 {
1575 //New context
1576 if( compareIbisWord( aKeyword.c_str(), "Component" ) )
1577 {
1578 m_ibisFile.m_components.push_back( IbisComponent( m_Reporter ) );
1579 m_currentComponent = &( m_ibisFile.m_components.back() );
1580 status &= storeString( m_currentComponent->m_name, false );
1582 }
1583 else if( compareIbisWord( aKeyword.c_str(), "Model_Selector" ) )
1584 {
1586 status &= storeString( MS.m_name, false );
1587 m_ibisFile.m_modelSelectors.push_back( MS );
1588 m_currentModelSelector = &( m_ibisFile.m_modelSelectors.back() );
1591 }
1592 else if( compareIbisWord( aKeyword.c_str(), "Model" ) )
1593 {
1595 model.m_temperatureRange.value[IBIS_CORNER::MIN] = 0;
1596 model.m_temperatureRange.value[IBIS_CORNER::TYP] = 50;
1597 model.m_temperatureRange.value[IBIS_CORNER::MAX] = 100;
1598 status &= storeString( model.m_name, false );
1599 m_ibisFile.m_models.push_back( model );
1600 m_currentModel = &( m_ibisFile.m_models.back() );
1601 m_currentSeriesData = nullptr;
1602 m_currentMosfetEntry = nullptr;
1605 }
1606 else if( compareIbisWord( aKeyword.c_str(), "Submodel" ) )
1607 {
1609 status &= storeString( model.m_name, false );
1610 auto [it, success] = m_ibisFile.m_submodels.emplace( model.m_name, model );
1611
1612 if( !success )
1613 {
1614 std::stringstream message;
1615 message << _( "Submodel name is not unique: " ) << model.m_name;
1616 Report( message.str(), RPT_SEVERITY_ERROR );
1617 status = false;
1618 }
1619
1620 m_currentSubmodel = &( it->second );
1623 }
1624 else if( compareIbisWord( aKeyword.c_str(), "Define_Package_Model" ) )
1625 {
1627 PM.m_resistanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1628 PM.m_capacitanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1629 PM.m_inductanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1630
1631 status &= storeString( PM.m_name, false );
1632
1633 m_ibisFile.m_packageModels.push_back( PM );
1634 m_currentPackageModel = &( m_ibisFile.m_packageModels.back() );
1636 }
1637 else if( compareIbisWord( aKeyword.c_str(), "End_Package_Model" ) )
1638 {
1639 if( m_currentComponent != nullptr )
1640 {
1643 }
1644 else // .pkg file, we just go back to header, to get the [END] keyword
1645 { // This will cause the header to be checked twice.
1648 }
1649 }
1650 else
1651 {
1652 status = false;
1653 std::string context_string;
1654
1655 switch( m_context )
1656 {
1657 case IBIS_PARSER_CONTEXT::HEADER: context_string += "HEADER"; break;
1658 case IBIS_PARSER_CONTEXT::COMPONENT: context_string += "COMPONENT"; break;
1659 case IBIS_PARSER_CONTEXT::MODELSELECTOR: context_string += "MODEL_SELECTOR"; break;
1660 case IBIS_PARSER_CONTEXT::MODEL: context_string += "MODEL"; break;
1661 case IBIS_PARSER_CONTEXT::PACKAGEMODEL: context_string += "PACKAGE_MODEL"; break;
1662 case IBIS_PARSER_CONTEXT::PACKAGEMODEL_MODELDATA: context_string += "PACKAGE_MODEL_MODEL_DATA"; break;
1663 default: context_string += "???"; break;
1664 }
1665
1666 std::stringstream message;
1667 message << _( "Unknown keyword in " ) << context_string << _( " context: " ) << aKeyword;
1668 Report( message.str(), RPT_SEVERITY_ERROR );
1669 }
1670 }
1671 else
1672 {
1674 }
1675
1676 return status;
1677}
1678
1679
1680bool IbisParser::parseModelSelector( std::string& aKeyword )
1681{
1682 bool status = true;
1683
1684 if( !changeContext( aKeyword ) )
1685 status = false;
1686
1687 return status;
1688}
1689
1690
1692{
1693 bool status = true;
1694
1695 status &= readDvdt( aDest.value[IBIS_CORNER::TYP] );
1696 status &= readDvdt( aDest.value[IBIS_CORNER::MIN] );
1697 status &= readDvdt( aDest.value[IBIS_CORNER::MAX] );
1698
1699 return status;
1700}
1701
1703{
1704 bool status = true;
1706
1707 IbisRamp* ramp = nullptr;
1708 switch( m_context )
1709 {
1711 ramp = &m_currentModel->m_ramp;
1712 break;
1714 ramp = &m_currentSubmodel->m_ramp;
1715 break;
1716 default:
1717 wxLogMessage( "Invalid context for ramp: %i.", (int) m_context );
1718 return false;
1719 }
1720
1721 if( !readNumericSubparam( std::string( "R_load" ), ramp->m_Rload ) )
1722 {
1723 std::string str;
1724
1725 if( readWord( str ) )
1726 {
1727 if( !strcmp( str.c_str(), "dV/dt_r" ) )
1728 {
1729 status &= readRampdvdt( ramp->m_rising );
1730 }
1731 else if( !strcmp( str.c_str(), "dV/dt_f" ) )
1732 {
1733 status &= readRampdvdt( ramp->m_falling );
1734 }
1735 else
1736 {
1737 Report( _( "Invalid ramp data" ), RPT_SEVERITY_ERROR );
1738 status = false;
1739 }
1740 }
1741 }
1742
1743 return status;
1744}
1745
1746
1748{
1749 bool status = true;
1750
1752 {
1754
1755 if( !data )
1756 {
1757 Report( _( "[Series MOSFET] outside of [Model] context." ), RPT_SEVERITY_ERROR );
1758 return false;
1759 }
1760
1761 data->m_seriesMosfet.emplace_back( m_Reporter );
1762 m_currentMosfetEntry = &data->m_seriesMosfet.back();
1765 return true;
1766 }
1767
1769 {
1770 Report( _( "Internal error: no current [Series MOSFET] entry." ), RPT_SEVERITY_ERROR );
1771 return false;
1772 }
1773
1774 if( !readNumericSubparam( std::string( "Vds" ), m_currentMosfetEntry->m_Vds ) )
1775 status = readIVtableEntry( m_currentMosfetEntry->m_table );
1776
1778 return status;
1779}
1780
1781
1783{
1784 bool status = true;
1785
1787
1788 // TODO
1789 // readTypMinMaxValueSubparam( std::string( "Vmeas" ), m_currentModel->... )
1790 // ...
1791
1792 return status;
1793}
1794
1795
1797{
1798 bool status = true;
1799
1801
1802 // TODO
1803 // readTypMinMaxValueSubparam( std::string( "Vth" ), m_currentModel->... )
1804 // ...
1805
1806 return status;
1807}
1808
1809
1811{
1812 bool status = true;
1813
1814 // TODO: ???
1815
1816 return status;
1817}
1818
1819
1820bool IbisParser::parseAlgorithmicModel( std::string& aKeyword )
1821{
1822 bool status = true;
1823
1824 if( compareIbisWord( aKeyword.c_str(), "End_Algorithmic_Model" ) )
1825 {
1828 }
1829 else
1830 {
1831 status = changeContext( aKeyword );
1832 }
1833 return status;
1834}
1835
1836
1838{
1839 bool status = true;
1840
1842
1844
1846 {
1847 std::string name;
1848 if( !readWord( name ) )
1849 {
1850 Report( _( "The submodel name is missing." ) );
1851 return false;
1852 }
1853
1854 std::string str;
1855 if( !readWord( str ) )
1856 {
1857 Report( _( "The submodel mode is missing." ) );
1858 return false;
1859 }
1860
1862 if( !strcmp( str.c_str(), "All" ) )
1863 {
1865 }
1866 else if( !strcmp( str.c_str(), "Driving" ) )
1867 {
1869 }
1870 else if( !strcmp( str.c_str(), "Non-Driving" ) )
1871 {
1873 }
1874 else
1875 {
1876 std::stringstream message;
1877 message << str << _( " is not a recognised submodel mode." );
1878 Report( message.str(), RPT_SEVERITY_WARNING );
1879 return false;
1880 }
1881
1882 m_currentModel->m_submodels.push_back( IbisSubmodelMode( name, mode ) );
1883 }
1884
1885 return status;
1886}
1887
1888
1889bool IbisParser::parseModel( std::string& aKeyword )
1890{
1891 bool status = false;
1892
1893 if( compareIbisWord( aKeyword.c_str(), "Voltage_Range" ) )
1894 status = readTypMinMaxValue( m_currentModel->m_voltageRange );
1895 else if( compareIbisWord( aKeyword.c_str(), "Temperature_Range" ) )
1896 status = readTypMinMaxValue( m_currentModel->m_temperatureRange );
1897 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp" ) )
1898 status = readIVtableEntry( m_currentModel->m_GNDClamp );
1899 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp" ) )
1900 status = readIVtableEntry( m_currentModel->m_POWERClamp );
1901 else if( compareIbisWord( aKeyword.c_str(), "Pulldown" ) )
1902 status = readIVtableEntry( m_currentModel->m_pulldown );
1903 else if( compareIbisWord( aKeyword.c_str(), "Pullup" ) )
1904 status = readIVtableEntry( m_currentModel->m_pullup );
1905 else if( compareIbisWord( aKeyword.c_str(), "ISSO_PD" ) )
1906 status = readIVtableEntry( m_currentModel->m_ISSO_PD );
1907 else if( compareIbisWord( aKeyword.c_str(), "ISSO_PU" ) )
1908 status = readIVtableEntry( m_currentModel->m_ISSO_PU );
1909 else if( compareIbisWord( aKeyword.c_str(), "Composite_Current" ) )
1910 status = readIVtableEntry( m_currentModel->m_compositeCurrent );
1911 else if( compareIbisWord( aKeyword.c_str(), "Rising_Waveform" ) )
1912 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::RISING );
1913 else if( compareIbisWord( aKeyword.c_str(), "Falling_Waveform" ) )
1914 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::FALLING );
1915 else if( compareIbisWord( aKeyword.c_str(), "Ramp" ) )
1916 status = readRamp();
1917 else if( compareIbisWord( aKeyword.c_str(), "Model_Spec" ) )
1918 status = readModelSpec();
1919 else if( compareIbisWord( aKeyword.c_str(), "Receiver_Thresholds" ) )
1920 status = readReceiverThresholds();
1921 else if( compareIbisWord( aKeyword.c_str(), "Pullup_Reference" ) )
1922 status = readTypMinMaxValue( m_currentModel->m_pullupReference );
1923 else if( compareIbisWord( aKeyword.c_str(), "Pulldown_Reference" ) )
1924 status = readTypMinMaxValue( m_currentModel->m_pulldownReference );
1925 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp_Reference" ) )
1926 status = readTypMinMaxValue( m_currentModel->m_POWERClampReference );
1927 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp_Reference" ) )
1928 status = readTypMinMaxValue( m_currentModel->m_GNDClampReference );
1929 else if( compareIbisWord( aKeyword.c_str(), "Rac" ) )
1930 status = readTypMinMaxValue( m_currentModel->m_Rac );
1931 else if( compareIbisWord( aKeyword.c_str(), "Cac" ) )
1932 status = readTypMinMaxValue( m_currentModel->m_Cac );
1933 else if( compareIbisWord( aKeyword.c_str(), "Rpower" ) )
1934 status = readTypMinMaxValue( m_currentModel->m_Rpower );
1935 else if( compareIbisWord( aKeyword.c_str(), "Rgnd" ) )
1936 status = readTypMinMaxValue( m_currentModel->m_Rgnd );
1937 else if( compareIbisWord( aKeyword.c_str(), "On" ) )
1938 {
1939 m_currentSeriesData = &m_currentModel->m_seriesOn;
1940 m_currentSeriesData->m_seen = true;
1941 m_currentMosfetEntry = nullptr;
1942 status = true;
1943 }
1944 else if( compareIbisWord( aKeyword.c_str(), "Off" ) )
1945 {
1946 m_currentSeriesData = &m_currentModel->m_seriesOff;
1947 m_currentSeriesData->m_seen = true;
1948 m_currentMosfetEntry = nullptr;
1949 status = true;
1950 }
1951 else if( compareIbisWord( aKeyword.c_str(), "R_Series" ) )
1952 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_Rseries );
1953 else if( compareIbisWord( aKeyword.c_str(), "L_Series" ) )
1954 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_Lseries );
1955 else if( compareIbisWord( aKeyword.c_str(), "C_Series" ) )
1956 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_Cseries );
1957 else if( compareIbisWord( aKeyword.c_str(), "Rl_Series" ) )
1958 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_RlSeries );
1959 else if( compareIbisWord( aKeyword.c_str(), "Lc_Series" ) )
1960 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_LcSeries );
1961 else if( compareIbisWord( aKeyword.c_str(), "Rc_Series" ) )
1962 status = currentSeriesData() && readTypMinMaxValue( currentSeriesData()->m_RcSeries );
1963 else if( compareIbisWord( aKeyword.c_str(), "Series_Current" ) )
1964 status = currentSeriesData() && readIVtableEntry( currentSeriesData()->m_seriesCurrent );
1965 else if( compareIbisWord( aKeyword.c_str(), "Series_MOSFET" ) )
1966 status = readSeriesMosfet();
1967 else if( compareIbisWord( aKeyword.c_str(), "Algorithmic_Model" ) )
1968 {
1971 status = true;
1972 }
1973 else if( compareIbisWord( aKeyword.c_str(), "Add_Submodel" ) )
1974 status = readAddSubmodel();
1975 else
1976 {
1977 status = changeContext( aKeyword );
1978 }
1979 return status;
1980}
1981
1982
1984{
1985 bool status = true;
1986
1988
1990
1991 std::string subparam;
1992 if( readWord( subparam ) )
1993 {
1994 if( !strcmp( subparam.c_str(), "Off_delay" ) )
1995 status = readTypMinMaxValue( m_currentSubmodel->m_offDelay );
1996 else if( !strcmp( subparam.c_str(), "V_trigger_r" ) )
1997 status = readTypMinMaxValue( m_currentSubmodel->m_VtriggerR );
1998 else if( !strcmp( subparam.c_str(), "V_trigger_f" ) )
1999 status = readTypMinMaxValue( m_currentSubmodel->m_VtriggerF );
2000 else
2001 {
2002 std::stringstream message;
2003 message << subparam << _( " is not a recognised Submodel Spec subparameter." );
2004 Report( message.str(), RPT_SEVERITY_ERROR );
2005 status = false;
2006 }
2007 }
2008
2009 return status;
2010}
2011
2012
2013bool IbisParser::parseSubmodel( std::string& aKeyword )
2014{
2015 bool status = false;
2016
2017 if( compareIbisWord( aKeyword.c_str(), "Submodel_Spec" ) )
2018 status = readSubmodelSpec();
2019 else if( compareIbisWord( aKeyword.c_str(), "Pullup" ) )
2020 status = readIVtableEntry( m_currentSubmodel->m_pullup );
2021 else if( compareIbisWord( aKeyword.c_str(), "Pulldown" ) )
2022 status = readIVtableEntry( m_currentSubmodel->m_pulldown );
2023 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp" ) )
2024 status = readIVtableEntry( m_currentSubmodel->m_GNDClamp );
2025 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp" ) )
2026 status = readIVtableEntry( m_currentSubmodel->m_POWERClamp );
2027 else if( compareIbisWord( aKeyword.c_str(), "GND_Pulse" ) )
2028 status = readIVtableEntry( m_currentSubmodel->m_GNDPulse );
2029 else if( compareIbisWord( aKeyword.c_str(), "POWER_Pulse" ) )
2030 status = readIVtableEntry( m_currentSubmodel->m_POWERPulse );
2031 else if( compareIbisWord( aKeyword.c_str(), "Rising_Waveform" ) )
2032 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::RISING );
2033 else if( compareIbisWord( aKeyword.c_str(), "Falling_Waveform" ) )
2034 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::FALLING );
2035 else if( compareIbisWord( aKeyword.c_str(), "Ramp" ) )
2036 status = readRamp();
2037 else
2038 status = changeContext( aKeyword );
2039
2040 return status;
2041}
2042
2043
2045{
2047 std::string str;
2048
2049 if( readWord( str ) )
2050 m_currentPackageModel->m_pins[str] = m_currentPackageModel->m_pins.size();
2051
2052 return true;
2053}
2054
2056{
2057 aDest = 0;
2058
2059 std::string str;
2060 if( !readWord( str ) )
2061 {
2062 Report( _( "Missing pin name/number for matrix row." ) );
2063 return false;
2064 }
2065 auto pin = m_currentPackageModel->m_pins.find( str );
2066 if( pin == m_currentPackageModel->m_pins.end() )
2067 {
2068 Report( _( "Invalid pin name/number in matrix row." ) );
2069 return false;
2070 }
2071 aDest = pin->second;
2072 return true;
2073}
2074
2075
2076bool IbisParser::readMatrixType( std::shared_ptr<IBIS_MATRIX>& aDest )
2077{
2078 m_currentMatrix = aDest;
2080 m_currentMatrix->m_rows = -1;
2081 m_currentMatrix->m_cols = -1;
2082 m_currentMatrixRow = -1;
2083 m_currentMatrixCol = -1;
2085
2086 std::string str;
2087 if( !readWord( str ) )
2088 {
2089 Report( _( "The matrix type is missing." ), RPT_SEVERITY_ERROR );
2090 return false;
2091 }
2092 if( compareIbisWord( str.c_str(), "Banded_matrix" ) )
2093 {
2095 }
2096 else if( compareIbisWord( str.c_str(), "Full_matrix" ) )
2097 {
2099 }
2100 else if( compareIbisWord( str.c_str(), "Sparse_matrix" ) )
2101 {
2103 }
2104 else
2105 {
2106 std::stringstream message;
2107 message << str << _( " is not a recognised matrix type." );
2109 return false;
2110 }
2111
2113 {
2114 int numPins = m_currentPackageModel->m_numberOfPins;
2115 m_currentMatrix->m_rows = numPins;
2116 m_currentMatrix->m_cols = numPins;
2117 m_currentMatrix->m_data.resize( numPins * numPins );
2118 }
2119 return true;
2120}
2121
2122
2124{
2125 if( ( m_currentMatrix == nullptr )
2127 || ( m_currentMatrix->m_cols > 0 ) )
2128 {
2129 Report( _( "Unexpected [Bandwidth] keyword." ), RPT_SEVERITY_ERROR );
2130 return false;
2131 }
2132
2133 int bandwidth;
2134 bool status = readInt( bandwidth );
2135 if( status )
2136 {
2137 if( bandwidth < 0 )
2138 {
2139 Report( _( "Matrix bandwidth must be >= 0." ), RPT_SEVERITY_ERROR );
2140 return false;
2141 }
2142 int numPins = m_currentPackageModel->m_numberOfPins;
2143 m_currentMatrix->m_rows = numPins;
2144 m_currentMatrix->m_cols = 1 + bandwidth;
2145 m_currentMatrix->m_data.resize( numPins * ( 1 + bandwidth ) );
2146 }
2147 return status;
2148}
2149
2151{
2152 if( ( m_currentMatrix == nullptr ) || ( m_currentMatrix->m_rows < 0 ) )
2153 {
2154 Report( _( "Unexpected [Row] keyword." ), RPT_SEVERITY_ERROR );
2155 return false;
2156 }
2157 int index;
2158 bool status = readMatrixPinIndex( index );
2159 if( status )
2160 {
2163 {
2165 }
2166 else
2167 {
2169 }
2171 }
2172 return status;
2173}
2174
2176{
2177 std::vector<std::string> values;
2178 bool status = readTableLine( values );
2179
2180 for( size_t i = 0; i < values.size(); i++ )
2181 {
2182 if( m_currentMatrixCol >= m_currentMatrix->m_cols )
2183 {
2184 Report( _( "Too much data for this matrix row." ), RPT_SEVERITY_ERROR );
2185 return false;
2186 }
2188 if( ( index < 0 ) || ( index >= (int)m_currentMatrix->m_data.size() ) )
2189 {
2190 Report( _( "Element location is outside the matrix." ), RPT_SEVERITY_ERROR );
2191 return false;
2192 }
2193 if( !parseDouble( m_currentMatrix->m_data[index], values.at( i ), true ) )
2194 {
2195 Report( _( "Failed to read a matrix element." ), RPT_SEVERITY_ERROR );
2196 return false;
2197 }
2199 }
2200 return status;
2201}
2202
2204{
2205 int index;
2206 if( !readMatrixPinIndex( index ) )
2207 {
2208 Report( _( "Failed to read a matrix pin name." ), RPT_SEVERITY_ERROR );
2209 return false;
2210 }
2211 double value;
2212 if( !readDouble( value ) )
2213 {
2214 Report( _( "Failed to read a matrix element." ), RPT_SEVERITY_ERROR );
2215 return false;
2216 }
2218 if( ( index < 0 ) || (index >= (int)m_currentMatrix->m_data.size() ) )
2219 {
2220 Report( _( "Element location is outside the matrix." ), RPT_SEVERITY_ERROR );
2221 return false;
2222 }
2223 m_currentMatrix->m_data[index] = value;
2224 return true;
2225}
2226
2228{
2229 int status = false;
2230 if( m_currentMatrix != nullptr )
2231 {
2232 switch( m_currentMatrix->m_type )
2233 {
2236 status = readMatrixBandedOrFull();
2237 break;
2239 status = readMatrixSparse();
2240 break;
2242 default:
2243 wxLogMessage( "Invalid matrix type: %i", (int) m_currentMatrix->m_type );
2244 break;
2245 }
2246 }
2247 else
2248 {
2249 wxLogMessage( "Matrix pointer is null" );
2250 }
2251 return status;
2252}
2253
2254bool IbisParser::parsePackageModelModelData( std::string& aKeyword )
2255{
2256 bool status = true;
2257
2258 if( compareIbisWord( aKeyword.c_str(), "Resistance_Matrix" ) )
2259 {
2260 status = readMatrixType( m_currentPackageModel->m_resistanceMatrix );
2261 }
2262 else if( compareIbisWord( aKeyword.c_str(), "Capacitance_Matrix" ) )
2263 {
2264 status = readMatrixType( m_currentPackageModel->m_capacitanceMatrix );
2265 }
2266 else if( compareIbisWord( aKeyword.c_str(), "Inductance_Matrix" ) )
2267 {
2268 status = readMatrixType( m_currentPackageModel->m_inductanceMatrix );
2269 }
2270 else if( compareIbisWord( aKeyword.c_str(), "Bandwidth" ) )
2271 {
2272 status = readMatrixBandwidth();
2273 }
2274 else if( compareIbisWord( aKeyword.c_str(), "Row" ) )
2275 {
2276 status = readMatrixRow();
2277 }
2278 else if( compareIbisWord( aKeyword.c_str(), "End_Model_Data" ) )
2279 {
2282 }
2283 else if( !changeContext( aKeyword ) )
2284 {
2285 status = false;
2286 }
2287
2288 return status;
2289}
2290
2291bool IbisParser::parsePackageModel( std::string& aKeyword )
2292{
2293 bool status = true;
2294
2295 if( compareIbisWord( aKeyword.c_str(), "Manufacturer" ) )
2296 status &= storeString( m_currentPackageModel->m_manufacturer, false );
2297 else if( compareIbisWord( aKeyword.c_str(), "OEM" ) )
2298 status &= storeString( m_currentPackageModel->m_OEM, false );
2299 else if( compareIbisWord( aKeyword.c_str(), "Description" ) )
2300 status &= storeString( m_currentPackageModel->m_description, false );
2301 else if( compareIbisWord( aKeyword.c_str(), "Number_of_Pins" ) )
2302 status &= readInt( m_currentPackageModel->m_numberOfPins );
2303 else if( compareIbisWord( aKeyword.c_str(), "Pin_Numbers" ) )
2304 status &= readPackageModelPins();
2305 else if( compareIbisWord( aKeyword.c_str(), "Model_Data" ) )
2306 {
2309 }
2310 else if( !changeContext( aKeyword ) )
2311 {
2312 status = false;
2313 }
2314
2315 return status;
2316}
2317
2319{
2320 bool status = true;
2321
2323
2324 if( !readWord( model.m_modelName ) )
2325 return false;
2326
2327 status &= readString( model.m_modelDescription );
2328 m_currentModelSelector->m_models.push_back( model );
2329
2330 return status;
2331}
2332
2333bool IbisParser::readNumericSubparam( const std::string& aSubparam, double& aDest )
2334{
2335 std::string paramName;
2336 bool status = true;
2337
2338 if( aSubparam.size() >= (size_t)m_lineLength )
2339 {
2340 // Continuing would result in an overflow
2341 return false;
2342 }
2343
2344 int old_index = m_lineIndex;
2345 m_lineIndex = 0;
2346
2347 for( size_t i = 0; i < aSubparam.size(); i++ )
2348 paramName += m_buffer[m_lineOffset + m_lineIndex++];
2349
2350 if( strcmp( paramName.c_str(), aSubparam.c_str() ) )
2351 {
2352 m_lineIndex = old_index;
2353 return false;
2354 }
2355
2357
2358 status &= m_buffer[m_lineOffset + m_lineIndex++] == '=';
2359
2360 if( status )
2361 {
2363 status &= readDouble( aDest );
2364 }
2365
2366 if( !status )
2367 m_lineIndex = old_index;
2368
2369 return status;
2370}
2371
2372
2374{
2375 bool status = true;
2376
2378
2379 std::string strValue;
2380
2381 if( !readDouble( aDest.value[IBIS_CORNER::TYP] ) )
2382 {
2383 Report( _( "Typ-Min-Max Values requires at least Typ." ), RPT_SEVERITY_ERROR );
2384 return false;
2385 }
2386
2389
2390 return status;
2391}
2392
2393bool IbisParser::readTypMinMaxValueSubparam( const std::string& aSubparam, TypMinMaxValue& aDest )
2394{
2395 std::string paramName;
2396 bool status = true;
2397
2398 m_lineIndex = 0; // rewind
2399
2400 if( aSubparam.size() < (size_t)m_lineLength )
2401 {
2402 for( size_t i = 0; i < aSubparam.size(); i++ )
2403 paramName += m_buffer[m_lineOffset + m_lineIndex++];
2404
2405 if( ( m_buffer[m_lineOffset + m_lineIndex] == ' ' ) && !strcmp( paramName.c_str(), aSubparam.c_str() ) )
2406 readTypMinMaxValue( aDest );
2407 else
2408 status = false;
2409 }
2410 else
2411 {
2412 status = false;
2413 }
2414
2415 return status;
2416}
2417
2419{
2420 bool status = true;
2421 std::string subparam;
2422
2423 if( readWord( subparam ) )
2424 {
2425 switch( m_continue )
2426 {
2428
2429 if( !strcmp( subparam.substr( 0, 10 ).c_str(), "Model_type" ) )
2430 {
2431 if( readWord( subparam ) )
2432 {
2433 if( compareIbisWord( subparam.c_str(), "Input" ) )
2435 else if( compareIbisWord( subparam.c_str(), "Output" ) )
2437 else if( compareIbisWord( subparam.c_str(), "I/O" ) )
2439 else if( compareIbisWord( subparam.c_str(), "3-state" ) )
2441 else if( compareIbisWord( subparam.c_str(), "Open_drain" ) )
2443 else if( compareIbisWord( subparam.c_str(), "I/O_Open_drain" ) )
2445 else if( compareIbisWord( subparam.c_str(), "Open_sink" ) )
2447 else if( compareIbisWord( subparam.c_str(), "I/O_open_sink" ) )
2449 else if( compareIbisWord( subparam.c_str(), "Open_source" ) )
2451 else if( compareIbisWord( subparam.c_str(), "I/O_open_source" ) )
2453 else if( compareIbisWord( subparam.c_str(), "Input_ECL" ) )
2455 else if( compareIbisWord( subparam.c_str(), "Output_ECL" ) )
2457 else if( compareIbisWord( subparam.c_str(), "I/O_ECL" ) )
2459 else if( compareIbisWord( subparam.c_str(), "3-state_ECL" ) )
2461 else if( compareIbisWord( subparam.c_str(), "Terminator" ) )
2463 else if( compareIbisWord( subparam.c_str(), "Series" ) )
2465 else if( compareIbisWord( subparam.c_str(), "Series_switch" ) )
2467 else
2468 {
2469 std::stringstream message;
2470 message << _( "Unknown Model_type " ) << subparam;
2471 Report( message.str(), RPT_SEVERITY_ERROR );
2472 status = false;
2473 }
2474 }
2475 else
2476 {
2477 Report( _( "Internal Error while reading model_type" ), RPT_SEVERITY_ERROR );
2478 status = false;
2479 }
2480 }
2481 else if( !strcmp( subparam.substr( 0, 7 ).c_str(), "Enable" ) )
2482 {
2483 if( readWord( subparam ) )
2484 {
2485 if( !strcmp( subparam.c_str(), "Active-High" ) )
2487 else if( !strcmp( subparam.c_str(), "Active-Low" ) )
2489 else
2490 {
2491 std::stringstream message;
2492 message << _( "Unknown Enable: " ) << subparam;
2493 Report( message.str(), RPT_SEVERITY_ERROR );
2494 status = false;
2495 }
2496 }
2497 else
2498 {
2499 Report( _( "Internal Error while reading Enable" ), RPT_SEVERITY_ERROR );
2500 status = false;
2501 }
2502 }
2503 else if( subparam.substr( 0, 9 ) == "Polarity" )
2504 {
2505 if( readWord( subparam ) )
2506 {
2507 if( subparam == "Inverting" )
2509 else if( subparam == "Non-Inverting" )
2511 else
2512 {
2513 std::stringstream message;
2514 message << _( "Unknown polarity " ) << subparam;
2515 Report( message.str(), RPT_SEVERITY_ERROR );
2516 status = false;
2517 }
2518 }
2519 else
2520 {
2521 Report( _( "Internal Error while reading Enable" ), RPT_SEVERITY_ERROR );
2522 status = false;
2523 }
2524 }
2525 else if( readNumericSubparam( std::string( "Vinl" ), m_currentModel->m_vinl ) )
2526 ;
2527 else if( readNumericSubparam( std::string( "Vinh" ), m_currentModel->m_vinh ) )
2528 ;
2529 else if( readNumericSubparam( std::string( "Vref" ), m_currentModel->m_vref ) )
2530 ;
2531 else if( readNumericSubparam( std::string( "Rref" ), m_currentModel->m_rref ) )
2532 ;
2533 else if( readNumericSubparam( std::string( "Cref" ), m_currentModel->m_cref ) )
2534 ;
2535 else if( readNumericSubparam( std::string( "Vmeas" ), m_currentModel->m_vmeas ) )
2536 ;
2537 else if( readTypMinMaxValueSubparam( std::string( "C_comp" ), m_currentModel->m_C_comp ) )
2538 ;
2539 else if( readTypMinMaxValueSubparam( std::string( "C_comp_gnd_clamp" ),
2540 m_currentModel->m_C_comp_gnd_clamp ) )
2541 ;
2542 else if( readTypMinMaxValueSubparam( std::string( "C_comp_power_clamp" ),
2543 m_currentModel->m_C_comp_power_clamp ) )
2544 ;
2545 else if( readTypMinMaxValueSubparam( std::string( "C_comp_pullup" ),
2546 m_currentModel->m_C_comp_pullup ) )
2547 ;
2548 else if( readTypMinMaxValueSubparam( std::string( "C_comp_pulldown" ),
2549 m_currentModel->m_C_comp_pulldown ) )
2550 ;
2551 else
2552 status = false;
2553
2555
2556 break;
2557
2558 default:
2559 status = false;
2560 Report( _( "Continued reading a model that did not begin. ( internal error )" ),
2562 }
2563 }
2564
2565 return status;
2566}
2567
2568
2570{
2571 bool status = true;
2572
2573 std::string subparam;
2574 if( readWord( subparam ) )
2575 {
2576 if( !strcmp( subparam.c_str(), "Submodel_type" ) )
2577 {
2578 if( readWord( subparam ) )
2579 {
2580 if( !strcmp( subparam.c_str(), "Dynamic_clamp" ) )
2582 else if( !strcmp( subparam.c_str(), "Bus_hold" ) )
2584 else if( !strcmp( subparam.c_str(), "Fall_back" ) )
2586 else
2587 {
2588 std::stringstream message;
2589 message << subparam << _( " is not a recognised submodel type." );
2590 Report( message.str(), RPT_SEVERITY_ERROR );
2591 status = false;
2592 }
2593 }
2594 else
2595 {
2596 Report( _( "The Submodel_type value is missing." ), RPT_SEVERITY_ERROR );
2597 status = false;
2598 }
2599 }
2600 else
2601 {
2602 std::stringstream message;
2603 message << subparam << _( " is not a recognised Submodel subparameter." );
2604 Report( message.str(), RPT_SEVERITY_ERROR );
2605 status = false;
2606 }
2607 }
2608
2609 return status;
2610}
2611
2612
2613bool IbisParser::parseHeader( std::string& aKeyword )
2614{
2615 bool status = true;
2616
2617 if( compareIbisWord( aKeyword.c_str(), "IBIS_Ver" ) )
2618 {
2619 status &= readDouble( m_ibisFile.m_header.m_ibisVersion );
2620 }
2621 else if( compareIbisWord( aKeyword.c_str(), "Comment_char" ) )
2622 {
2623 status &= changeCommentChar();
2624 }
2625 else if( compareIbisWord( aKeyword.c_str(), "File_Name" ) )
2626 {
2627 status &= storeString( m_ibisFile.m_header.m_fileName, false );
2628 }
2629 else if( compareIbisWord( aKeyword.c_str(), "File_Rev" ) )
2630 {
2631 status &= readDouble( m_ibisFile.m_header.m_fileRevision );
2632 }
2633 else if( compareIbisWord( aKeyword.c_str(), "Source" ) )
2634 {
2635 status &= storeString( m_ibisFile.m_header.m_source, true );
2636 }
2637 else if( compareIbisWord( aKeyword.c_str(), "Notes" ) )
2638 {
2639 status &= storeString( m_ibisFile.m_header.m_notes, true );
2640 }
2641 else if( compareIbisWord( aKeyword.c_str(), "Disclaimer" ) )
2642 {
2643 status &= storeString( m_ibisFile.m_header.m_disclaimer, true );
2644 }
2645 else if( compareIbisWord( aKeyword.c_str(), "Copyright" ) )
2646 {
2647 status &= storeString( m_ibisFile.m_header.m_copyright, true );
2648 }
2649 else if( compareIbisWord( aKeyword.c_str(), "Date" ) )
2650 {
2651 status &= storeString( m_ibisFile.m_header.m_date, false );
2652 }
2653 else if( !changeContext( aKeyword ) )
2654 {
2655 status = false;
2656 }
2657
2658 return status;
2659}
2660
2661
2662bool IbisParser::parseComponent( std::string& aKeyword )
2663{
2664 bool status = true;
2665
2666 if( compareIbisWord( aKeyword.c_str(), "Manufacturer" ) )
2667 {
2668 status &= storeString( m_currentComponent->m_manufacturer, true );
2669 }
2670 else if( compareIbisWord( aKeyword.c_str(), "Package" ) )
2671 {
2672 status &= readPackage();
2673 }
2674 else if( compareIbisWord( aKeyword.c_str(), "Pin" ) )
2675 {
2676 status &= readPin();
2677 }
2678 else if( compareIbisWord( aKeyword.c_str(), "Pin_Mapping" ) )
2679 {
2680 status &= readPinMapping();
2681 }
2682 else if( compareIbisWord( aKeyword.c_str(), "Diff_Pin" ) )
2683 {
2684 status &= readDiffPin();
2685 }
2686 else if( compareIbisWord( aKeyword.c_str(), "Series_Pin_Mapping" ) )
2687 {
2688 status &= readSeriesPinMapping();
2689 }
2690 /*
2691 // Not supported yet
2692 else if( aKeyword == "Die_Supply_Pads" )
2693 {
2694 status &= ReadDieSupplyPads();
2695 }*/
2696 else if( compareIbisWord( aKeyword.c_str(), "Package_Model" ) )
2697 {
2698 status &= storeString( m_currentComponent->m_packageModel, true );
2699 }
2700 else if( !changeContext( aKeyword ) )
2701 {
2702 status = false;
2703 }
2704
2705 return status;
2706}
2707
2708bool IbisParser::readTableLine( std::vector<std::string>& aDest )
2709{
2710 aDest.clear();
2711
2712 while( m_lineIndex < m_lineLength )
2713 {
2714 std::string str;
2715
2716 while( !isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
2717 str += m_buffer[m_lineOffset + m_lineIndex++];
2718
2719 if( str.size() > 0 )
2720 aDest.push_back( str );
2721
2722 while( isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
2723 m_lineIndex++;
2724 }
2725
2726 return true;
2727}
2728
2730{
2731 bool status = true;
2732
2733 std::vector<std::string> fields;
2734
2735 TypMinMaxValue* R = &( m_currentComponent->m_package.m_Rpkg );
2736 TypMinMaxValue* L = &( m_currentComponent->m_package.m_Lpkg );
2737 TypMinMaxValue* C = &( m_currentComponent->m_package.m_Cpkg );
2738
2739 readTableLine( fields );
2740
2741 int extraArg = ( m_continue == IBIS_PARSER_CONTINUE::NONE ) ? 1 : 0;
2742
2743 if( (int)fields.size() == ( 4 + extraArg ) )
2744 {
2745 TypMinMaxValue* cValue;
2746
2747 if( fields.at( 0 ) == "R_pkg" )
2748 cValue = R;
2749 else if( fields.at( 0 ) == "L_pkg" )
2750 cValue = L;
2751 else if( fields.at( 0 ) == "C_pkg" )
2752 cValue = C;
2753 else
2754 {
2755 Report( "Invalid field in [Package]" );
2756 return false;
2757 }
2758 status &= parseDouble( cValue->value[IBIS_CORNER::TYP], fields.at( 1 ), true );
2759 // Min / max values are optional, so don't update the status
2760 parseDouble( cValue->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
2761 parseDouble( cValue->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
2762 }
2763 else
2764 {
2765 if( fields.size() != 0 )
2766 {
2767 Report( _( "A [Package] line requires exactly 4 elements." ), RPT_SEVERITY_ERROR );
2768 status = false;
2769 }
2770 }
2771
2773
2774 return status;
2775}
2776
2777
2779{
2780 bool status = true;
2781
2782 std::vector<std::string> fields;
2783
2784 m_lineIndex = 0;
2785 status &= readTableLine( fields );
2786
2788
2789 if( ( fields.size() == 3 ) )
2790 {
2791 if( m_continue == IBIS_PARSER_CONTINUE::COMPONENT_PIN ) // No info on first line
2792 {
2793 pin.m_pinName = fields.at( 0 );
2794 pin.m_signalName = fields.at( 1 );
2795 pin.m_modelName = fields.at( 2 );
2796 pin.m_Rcol = m_currentComponent->m_pins.back().m_Rcol;
2797 pin.m_Lcol = m_currentComponent->m_pins.back().m_Lcol;
2798 pin.m_Ccol = m_currentComponent->m_pins.back().m_Ccol;
2799 }
2800 else
2801 {
2802 pin.m_dummy = true;
2803 }
2804 }
2805 else
2806 {
2807 if( m_continue == IBIS_PARSER_CONTINUE::COMPONENT_PIN ) // Not on the first line
2808 {
2809 pin.m_pinName = fields.at( 0 );
2810 pin.m_signalName = fields.at( 1 );
2811 pin.m_modelName = fields.at( 2 );
2812
2813 pin.m_Rcol = m_currentComponent->m_pins.back().m_Rcol;
2814 pin.m_Lcol = m_currentComponent->m_pins.back().m_Lcol;
2815 pin.m_Ccol = m_currentComponent->m_pins.back().m_Ccol;
2816
2817 if( pin.m_Rcol == 0 || pin.m_Lcol == 0 || pin.m_Ccol == 0 )
2818 {
2819 Report( _( "Invalid pin entry: 6 values from a table with only 3." ),
2821 status = false; // Did we just try to go from a 3 column table to a 6 ?
2822 }
2823 else
2824 {
2825 if( !parseDouble( pin.m_Rpin, fields.at( pin.m_Rcol ), true )
2826 || !parseDouble( pin.m_Lpin, fields.at( pin.m_Lcol ), true )
2827 || !parseDouble( pin.m_Cpin, fields.at( pin.m_Ccol ), true ) )
2828 {
2829 Report( _( "Can't read a R, L or C value for a pin." ), RPT_SEVERITY_ERROR );
2830 status = false;
2831 }
2832 }
2833 }
2834 else
2835 {
2836 for( int i = 3; i < 6; i++ )
2837 {
2838 if( fields.at( i ) == "R_pin" )
2839 {
2840 pin.m_Rcol = i;
2841 }
2842 else if( fields.at( i ) == "L_pin" )
2843 {
2844 pin.m_Lcol = i;
2845 }
2846 else if( fields.at( i ) == "C_pin" )
2847 {
2848 pin.m_Ccol = i;
2849 }
2850 else
2851 {
2852 Report( _( "Invalid field name in [Pin]" ), RPT_SEVERITY_ERROR );
2853 status = false;
2854 }
2855 }
2856
2857 if( pin.m_Rcol == 0 || pin.m_Lcol == 0 || pin.m_Ccol == 0 )
2858 {
2859 Report( _( "Missing argument in [Pin]" ), RPT_SEVERITY_ERROR );
2860 status = false;
2861 }
2862
2863 pin.m_dummy = true;
2864 }
2865 }
2866
2867 m_currentComponent->m_pins.push_back( pin );
2869
2870
2871 return status;
2872}
2873
2874
2876{
2877 bool status = true;
2878
2879 std::vector<std::string> fields;
2880
2881 status &= readTableLine( fields );
2882
2883 IbisComponentPinMapping pinMapping( m_Reporter );
2884
2885 if( m_continue == IBIS_PARSER_CONTINUE::NONE ) // No info on first line
2886 {
2888 }
2889 else
2890 {
2891 if( fields.size() != 0 )
2892 {
2893 if( fields.size() > 6 || fields.size() < 3 )
2894 {
2895 Report( _( "Wrong number of columns for pin mapping." ), RPT_SEVERITY_ERROR );
2896 status = false;
2897 }
2898 else
2899 {
2900 pinMapping.m_pinName = fields.at( 0 );
2901 pinMapping.m_PDref = fields.at( 1 );
2902 pinMapping.m_PUref = fields.at( 2 );
2903
2904 if( fields.size() > 3 )
2905 pinMapping.m_GNDClampRef = fields.at( 3 );
2906
2907 if( fields.size() > 4 )
2908 pinMapping.m_POWERClampRef = fields.at( 4 );
2909
2910 if( fields.size() > 5 )
2911 pinMapping.m_extRef = fields.at( 5 );
2912 }
2913 m_currentComponent->m_pinMappings.push_back( pinMapping );
2914 }
2915 }
2916
2917 return status;
2918}
2919
2920
2922{
2923 bool status = true;
2924
2925 m_lineIndex = 0; // rewind
2927
2928 if( m_continue == IBIS_PARSER_CONTINUE::NONE ) // No info on first line
2929 {
2931 }
2932 else
2933 {
2934 if( !readWord( entry.pinA ) )
2935 {
2936 Report( _( "Incorrect diff pin name" ), RPT_SEVERITY_ERROR );
2937 status = false;
2938 }
2939
2940 if( !readWord( entry.pinB ) )
2941 {
2942 Report( _( "Incorrect inv_pin name" ), RPT_SEVERITY_ERROR );
2943 status = false;
2944 }
2945
2946 if( status )
2947 m_currentComponent->m_diffPin.m_entries.push_back( entry );
2948 }
2949
2950 return status;
2951}
2952
2953
2955{
2956 // IBIS 4.1+ [Series Pin Mapping] row: pin_1 pin_2 model_name [function_table_group].
2957 // Rows with fewer than three columns are tolerated with a warning so that an
2958 // unusual layout does not abort parsing of the whole file.
2959
2960 bool status = true;
2961
2962 std::vector<std::string> fields;
2963 status &= readTableLine( fields );
2964
2966 {
2968 }
2969 else if( !fields.empty() )
2970 {
2972
2973 if( fields.size() >= 3 )
2974 {
2975 mapping.m_pin1 = fields.at( 0 );
2976 mapping.m_pin2 = fields.at( 1 );
2977 mapping.m_modelName = fields.at( 2 );
2978
2979 if( fields.size() > 3 )
2980 mapping.m_functionTableGroup = fields.at( 3 );
2981
2982 m_currentComponent->m_seriesPinMappings.push_back( mapping );
2983 }
2984 else
2985 {
2986 Report( _( "Wrong number of columns for series pin mapping." ), RPT_SEVERITY_WARNING );
2987 }
2988 }
2989
2990 return status;
2991}
2992
2993
2995{
2996 bool status = true;
2997
2999
3000 IVtableEntry entry( m_Reporter );
3001
3003 {
3004 std::string str;
3005
3006 status &= readDouble( entry.V );
3007
3008 if( status && readTypMinMaxValue( entry.I ) )
3009 aDest.m_entries.push_back( entry );
3010 }
3011
3013 m_currentIVtable = &aDest;
3014
3015 return status;
3016}
3017
3019{
3020 bool status = true;
3022
3023 VTtableEntry entry( m_Reporter );
3024
3026 {
3027 std::string str;
3028 status &= readDouble( entry.t );
3029 status &= readTypMinMaxValue( entry.V );
3030 }
3031
3033 m_currentVTtable = &aDest;
3034
3035 if( status )
3036 aDest.m_entries.push_back( entry );
3037
3038 return status;
3039}
3040
3042{
3043 bool status = true;
3044
3045 IbisWaveform* wf;
3046
3048 {
3049 wf = new IbisWaveform( m_Reporter );
3050 wf->m_type = aType;
3051
3052 switch( m_context )
3053 {
3055 switch( aType )
3056 {
3058 m_currentModel->m_fallingWaveforms.push_back( wf );
3059 break;
3061 m_currentModel->m_risingWaveforms.push_back( wf );
3062 break;
3063 default:
3064 wxLogMessage( "Invalid waveform type: %i", (int) aType );
3065 status = false;
3066 }
3067 break;
3069 switch( aType )
3070 {
3072 m_currentSubmodel->m_fallingWaveforms.push_back( wf );
3073 break;
3075 m_currentSubmodel->m_risingWaveforms.push_back( wf );
3076 break;
3077 default:
3078 wxLogMessage( "Invalid waveform type: %i", (int) aType );
3079 status = false;
3080 }
3081 break;
3082 default:
3083 wxLogMessage( "Invalid context for waveform: %i", (int) m_context );
3084 return false;
3085 }
3086 }
3087 else
3088 {
3089 if( aDest != nullptr )
3090 {
3091 wf = aDest;
3092 }
3093 else
3094 {
3095 Report( _( "Internal error detected, a waveform should exist" ), RPT_SEVERITY_ERROR );
3096 return false;
3097 }
3098 }
3099
3100
3101 if( status & !isLineEmptyFromCursor() )
3102 {
3103 // readNumericSubparam() returns true if it could read the subparameter and store it
3104 // Testing all subparameters
3105 if( readNumericSubparam( std::string( "R_fixture" ), wf->m_R_fixture ) )
3106 ;
3107 else if( readNumericSubparam( std::string( "L_fixture" ), wf->m_L_fixture ) )
3108 ;
3109 else if( readNumericSubparam( std::string( "C_fixture" ), wf->m_C_fixture ) )
3110 ;
3111 else if( readNumericSubparam( std::string( "V_fixture" ), wf->m_V_fixture ) )
3112 ;
3113 else if( readNumericSubparam( std::string( "V_fixture_min" ), wf->m_V_fixture_min ) )
3114 ;
3115 else if( readNumericSubparam( std::string( "V_fixture_max" ), wf->m_V_fixture_max ) )
3116 ;
3117 else if( readNumericSubparam( std::string( "R_dut" ), wf->m_R_fixture ) )
3118 ;
3119 else if( readNumericSubparam( std::string( "L_dut" ), wf->m_L_fixture ) )
3120 ;
3121 else if( readNumericSubparam( std::string( "C_dut" ), wf->m_C_fixture ) )
3122 ;
3123 // The line is not a subparameter, then let's try to read a VT table entry
3124 else if( !readVTtableEntry( m_currentWaveform->m_table ) )
3125 status = false;
3126 }
3127
3128 m_currentWaveform = wf;
3130 return status;
3131}
3132
3134{
3135 bool status = true;
3136 char c;
3137 std::string keyword = getKeyword();
3138
3139 if( keyword.size() > 0 ) // New keyword
3140 {
3143
3144 switch( m_context )
3145 {
3147 status &= parseHeader( keyword );
3148 break;
3150 status &= parseComponent( keyword );
3151 break;
3153 status &= parseModelSelector( keyword );
3154 break;
3156 status &= parseModel( keyword );
3157 break;
3159 status &= parseSubmodel( keyword );
3160 break;
3162 status &= parsePackageModel( keyword );
3163 break;
3165 status &= parsePackageModelModelData( keyword );
3166 break;
3168 status &= parseAlgorithmicModel( keyword );
3169 break;
3170 default:
3171 status = false;
3172 Report( _( "Internal error: Bad parser context." ), RPT_SEVERITY_ERROR );
3173 }
3174 }
3175 else
3176 {
3178 if( m_lineIndex == m_lineLength )
3179 {
3180 // That was an empty line
3181 return true;
3182 }
3183
3184 // No new keyword ? Then it is the continuation of the previous one !
3185 switch( m_continue )
3186 {
3189 *m_continuingString += '\n';
3190 status &= readString( *m_continuingString );
3191 break;
3193 status &= readPackage();
3194 break;
3196 status &= readPin();
3197 break;
3199 status &= readPinMapping();
3200 break;
3202 status &= readDiffPin();
3203 break;
3205 status &= readSeriesPinMapping();
3206 break;
3208 status &= readModelSelector();
3209 break;
3211 status &= readModel();
3212 break;
3214 status &= readSubmodel();
3215 break;
3217 status &= readIVtableEntry( *m_currentIVtable );
3218 break;
3220 status &= readVTtableEntry( *m_currentVTtable );
3221 break;
3223 status &= readWaveform( m_currentWaveform, m_currentWaveform->m_type );
3224 break;
3226 status &= readRamp();
3227 break;
3229 status &= readSeriesMosfet();
3230 break;
3232 status &= readModelSpec();
3233 break;
3235 status &= readReceiverThresholds();
3236 break;
3238 status &= readAlgorithmicModel();
3239 break;
3241 status &= readAddSubmodel();
3242 break;
3244 status &= readSubmodelSpec();
3245 break;
3247 status &= readPackageModelPins();
3248 break;
3250 status &= readMatrixData();
3251 break;
3253 default:
3254 Report( _( "Missing keyword." ), RPT_SEVERITY_ERROR );
3255 return false;
3256 break;
3257 }
3258 }
3259
3261
3262 while( ( c != '\n' ) && ( c != 0 ) ) // Go to the end of line
3264
3265 return status;
3266}
int index
const char * name
void Report(const std::string &aMsg, SEVERITY aSeverity=RPT_SEVERITY_INFO) const
Print a message.
Definition ibis_parser.h:70
REPORTER * m_Reporter
Definition ibis_parser.h:77
static std::string doubleToString(double aNumber)
Convert a double to string using scientific notation.
std::vector< double > m_data
bool Check() override
Check if the data held by the object is valid.
TypMinMaxValue I
bool Check() override
Check if the data held by the object is valid.
double InterpolatedI(double aV, IBIS_CORNER aCorner) const
Interpolate the IV table.
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
bool Check() override
Check if the data held by the object is valid.
TypMinMaxValue m_Cpkg
TypMinMaxValue m_Lpkg
TypMinMaxValue m_Rpkg
std::string m_POWERClampRef
bool Check() override
Check if the data held by the object is valid.
std::string m_signalName
std::string m_pinName
std::string m_modelName
One row of a [Series Pin Mapping] table (IBIS 4.1+).
std::string m_manufacturer
IbisComponentPackage m_package
bool Check() override
Check if the data held by the object is valid.
std::string m_name
std::vector< IbisComponentPin > m_pins
std::string pinB
std::string pinA
bool Check() override
Check if the data held by the object is valid.
std::string m_fileName
double m_ibisVersion
double m_fileRevision
bool Check() override
Check if the data held by the object is valid.
TypMinMaxValue m_C_comp_pullup
TypMinMaxValue m_C_comp_power_clamp
IBIS_MODEL_TYPE m_type
double m_cref
IVtable m_pullup
IbisSeriesData m_seriesOff
IVtable m_ISSO_PU
TypMinMaxValue m_pullupReference
TypMinMaxValue m_C_comp_pulldown
TypMinMaxValue m_C_comp_gnd_clamp
double m_vmeas
IVtable m_pulldown
bool Check() override
Check if the data held by the object is valid.
IVtable m_POWERClamp
TypMinMaxValue m_POWERClampReference
IbisSeriesData m_series
IVtable m_GNDClamp
IbisRamp m_ramp
IbisSeriesData m_seriesOn
IVtable m_ISSO_PD
IVtable m_compositeCurrent
TypMinMaxValue m_C_comp
double m_rref
TypMinMaxValue m_temperatureRange
TypMinMaxValue m_pulldownReference
double m_vref
TypMinMaxValue m_GNDClampReference
double m_vinh
double m_vinl
TypMinMaxValue m_voltageRange
std::string m_name
std::map< std::string, int > m_pins
std::shared_ptr< IBIS_MATRIX > m_resistanceMatrix
std::string m_OEM
std::shared_ptr< IBIS_MATRIX > m_inductanceMatrix
bool Check() override
Check if the data held by the object is valid.
std::string m_name
std::shared_ptr< IBIS_MATRIX > m_capacitanceMatrix
std::string m_manufacturer
bool parseSubmodel(std::string &aKeyword)
Parse a single keyword in the submodel context.
std::vector< char > m_buffer
char m_commentChar
long m_lineCounter
bool readAlgorithmicModel()
bool readMatrixBandedOrFull()
IBIS_PARSER_CONTINUE m_continue
bool readSubmodelSpec()
bool readModelSpec()
bool changeCommentChar()
Ibis can change the character used for comments.
bool getNextLine()
Load the next line.
bool parseComponent(std::string &aKeyword)
Parse a single keyword in the component context.
bool parseModel(std::string &aKeyword)
Parse a single keyword in the model context.
VTtable * m_currentVTtable
bool readMatrixBandwidth()
bool readMatrixRow()
bool parsePackageModelModelData(std::string &aKeyword)
Parse a single keyword in the package model model data context.
bool isLineEmptyFromCursor()
void printLine()
Print the current line.
bool readModelSelector()
bool changeContext(std::string &aKeyword)
std::string getKeyword()
int m_currentMatrixCol
bool parseDouble(double &aDest, std::string &aStr, bool aAllowModifiers=false)
Parse a double according to the ibis standard.
bool onNewLine()
Parse the current line.
bool readWord(std::string &aDest)
bool readTypMinMaxValue(TypMinMaxValue &aDest)
bool compareIbisWord(const std::string &a, const std::string &b)
compare two strings without being case sensitive
bool readDvdt(dvdt &aDest)
int m_currentMatrixRow
IbisComponent * m_currentComponent
std::shared_ptr< IBIS_MATRIX > m_currentMatrix
IbisSubmodel * m_currentSubmodel
bool readMatrixSparse()
bool ParseFile(const std::string &aFileName)
Parse a file.
bool readMatrixType(std::shared_ptr< IBIS_MATRIX > &aDest)
std::string * m_continuingString
IbisModel * m_currentModel
bool readSeriesPinMapping()
bool parseDvdt(dvdt &aDest, std::string &aStr)
Parse a dV/dt value according to the ibis standard.
IbisPackageModel * m_currentPackageModel
IbisSeriesData * currentSeriesData()
Active series data: [On]/[Off] sub-block when set, else m_series.
bool readDouble(double &aDest)
bool readSubmodel()
IbisModelSelector * m_currentModelSelector
bool checkEndofLine()
bool parsePackageModel(std::string &aKeyword)
Parse a single keyword in the package model context.
bool readSeriesMosfet()
Read one [Series MOSFET] line (Vds subparam or IV row).
bool readString(std::string &aDest)
bool readPinMapping()
bool readTypMinMaxValueSubparam(const std::string &aSubparam, TypMinMaxValue &aDest)
bool parseAlgorithmicModel(std::string &aKeyword)
Parse a single keyword in the algorithmic model context.
bool readNumericSubparam(const std::string &aSubparam, double &aDest)
bool readMatrixPinIndex(int &aDest)
bool readInt(int &aDest)
bool readPackage()
int m_bufferIndex
IBIS_PARSER_CONTEXT m_context
IbisFile m_ibisFile
IVtable * m_currentIVtable
bool readIVtableEntry(IVtable &aTable)
IbisSeriesData * m_currentSeriesData
bool readVTtableEntry(VTtable &aTable)
bool parseModelSelector(std::string &aKeyword)
Parse a single keyword in the model selector context.
bool readDiffPin()
bool readReceiverThresholds()
bool readAddSubmodel()
void skipWhitespaces()
bool storeString(std::string &aDest, bool aMultiline)
bool readPackageModelPins()
IbisMosfetEntry * m_currentMosfetEntry
bool readRampdvdt(dvdtTypMinMax &aDest)
bool readTableLine(std::vector< std::string > &aDest)
bool readMatrixData()
bool parseHeader(std::string &aKeyword)
Parse a single keyword in the header context.
bool readWaveform(IbisWaveform *aDest, IBIS_WAVEFORM_TYPE aType)
IbisWaveform * m_currentWaveform
dvdtTypMinMax m_rising
bool Check() override
Check if the data held by the object is valid.
double m_Rload
dvdtTypMinMax m_falling
TypMinMaxValue m_Lseries
TypMinMaxValue m_RlSeries
TypMinMaxValue m_LcSeries
TypMinMaxValue m_Cseries
std::vector< IbisMosfetEntry > m_seriesMosfet
bool isPopulated() const
TypMinMaxValue m_RcSeries
TypMinMaxValue m_Rseries
IVtable m_seriesCurrent
std::string m_name
IVtable m_POWERPulse
IVtable m_pulldown
TypMinMaxValue m_VtriggerR
IVtable m_POWERClamp
bool Check() override
Check if the data held by the object is valid.
IBIS_SUBMODEL_TYPE m_type
IVtable m_GNDClamp
IVtable m_GNDPulse
std::string m_name
IVtable m_pullup
TypMinMaxValue m_offDelay
IbisRamp m_ramp
TypMinMaxValue m_VtriggerF
double m_L_fixture
double m_V_fixture
double m_V_fixture_min
IBIS_WAVEFORM_TYPE m_type
double m_V_fixture_max
double m_R_fixture
double m_C_fixture
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
TypMinMaxValue(REPORTER *aReporter)
bool Check() override
Check if the data held by the object is valid.
double value[3]
bool isNA() const
void Add(const TypMinMaxValue &aValue)
TypMinMaxValue V
std::vector< VTtableEntry > m_entries
bool Check() override
Check if the data held by the object is valid.
double m_dv
double m_dt
#define _(s)
bool isNumberNA(double aNumber)
#define NAN_NA
Definition ibis_parser.h:36
IBIS_CORNER
@ TYP
@ MIN
@ MAX
#define IBIS_MAX_VERSION
Definition ibis_parser.h:39
IBIS_SUBMODEL_MODE
#define NAN_INVALID
Definition ibis_parser.h:37
#define IBIS_MAX_LINE_LENGTH
Definition ibis_parser.h:40
IBIS_WAVEFORM_TYPE
#define I(x, y, z)
Definition md5_hash.cpp:18
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
static std::string strValue(double aValue)
KIBIS_MODEL * model
const IbisMosfetEntry & mosfet
KIBIS_PIN * pin
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.