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 bool status = true;
459
460 if( m_name.empty() )
461 {
462 Report( _( "Model name cannot be empty" ), RPT_SEVERITY_ERROR );
463 status = false;
464 }
465
466 std::stringstream message;
467 message << _( "Checking model " ) << m_name;
468
470 {
471 if( status )
472 Report( message.str(), RPT_SEVERITY_ACTION );
473
474 Report( _( "Undefined model type." ), RPT_SEVERITY_ERROR );
475 status = false;
476 }
477
478 if( std::isnan( m_vinh ) && !isNumberNA( m_vinh ) )
479 {
480 if( status )
481 Report( message.str(), RPT_SEVERITY_ACTION );
482
483 Report( _( "Invalid Vinh value." ), RPT_SEVERITY_ERROR );
484 status = false;
485 }
486
487 if( std::isnan( m_vinl ) && !isNumberNA( m_vinl ) )
488 {
489 if( status )
490 Report( message.str(), RPT_SEVERITY_ACTION );
491
492 Report( _( "Invalid Vinl value." ), RPT_SEVERITY_ERROR );
493 status = false;
494 }
495
496 if( std::isnan( m_rref ) && !isNumberNA( m_rref ) )
497 {
498 if( status )
499 Report( message.str(), RPT_SEVERITY_ACTION );
500
501 Report( _( "Invalid R_ref value." ), RPT_SEVERITY_ERROR );
502 status = false;
503 }
504
505 if( std::isnan( m_cref ) && !isNumberNA( m_cref ) )
506 {
507 if( status )
508 Report( message.str(), RPT_SEVERITY_ACTION );
509
510 Report( _( "Invalid C_ref value." ), RPT_SEVERITY_ERROR );
511 status = false;
512 }
513
514 if( std::isnan( m_vref ) && !isNumberNA( m_vref ) )
515 {
516 if( status )
517 Report( message.str(), RPT_SEVERITY_ACTION );
518
519 Report( _( "Invalid V_ref value." ), RPT_SEVERITY_ERROR );
520 status = false;
521 }
522
523 if( std::isnan( m_vmeas ) && !isNumberNA( m_vmeas ) )
524 {
525 if( status )
526 Report( message.str(), RPT_SEVERITY_ACTION );
527
528 Report( _( "Invalid V_meas value." ), RPT_SEVERITY_ERROR );
529 status = false;
530 }
531
532 if( !m_C_comp.Check() )
533 {
534 if( status )
535 Report( message.str(), RPT_SEVERITY_ACTION );
536
537 Report( _( "Missing or invalid C_comp value." ), RPT_SEVERITY_ERROR );
538 status = false;
539 }
540
541 if( !m_C_comp_gnd_clamp.Check() )
542 {
543 if( status )
544 Report( message.str(), RPT_SEVERITY_ACTION );
545
546 Report( _( "Missing or invalid C_comp_gnd_clamp value." ), RPT_SEVERITY_ERROR );
547 status = false;
548 }
549
550 if( !m_C_comp_power_clamp.Check() )
551 {
552 if( status )
553 Report( message.str(), RPT_SEVERITY_ACTION );
554
555 Report( _( "Missing or invalid C_comp_power_clamp value." ), RPT_SEVERITY_ERROR );
556 status = false;
557 }
558
559 if( !m_C_comp_pullup.Check() )
560 {
561 if( status )
562 Report( message.str(), RPT_SEVERITY_ACTION );
563
564 Report( _( "Missing or invalid C_comp_pullup value." ), RPT_SEVERITY_ERROR );
565 status = false;
566 }
567
568 if( !m_C_comp_pulldown.Check() )
569 {
570 if( status )
571 Report( message.str(), RPT_SEVERITY_ACTION );
572
573 Report( _( "Missing or invalid C_comp_pulldown value." ), RPT_SEVERITY_ERROR );
574 status = false;
575 }
576
577 if( m_C_comp.isNA() && m_C_comp_gnd_clamp.isNA() && m_C_comp_power_clamp.isNA()
578 && m_C_comp_pullup.isNA() && m_C_comp_pulldown.isNA() )
579 {
580 if( status )
581 Report( message.str(), RPT_SEVERITY_ACTION );
582
583 Report( _( "No C_comp values are available." ), RPT_SEVERITY_ERROR );
584 status = false;
585 }
586
587 if( !m_temperatureRange.Check() || m_temperatureRange.isNA() )
588 {
589 if( status )
590 Report( message.str(), RPT_SEVERITY_ACTION );
591
592 Report( _( "Missing or invalid Temperature Range value." ), RPT_SEVERITY_ERROR );
593 status = false;
594 }
595
596 if( !m_voltageRange.Check() )
597 {
598 if( status )
599 Report( message.str(), RPT_SEVERITY_ACTION );
600
601 Report( _( "Missing or invalid Voltage Range value." ), RPT_SEVERITY_ERROR );
602 status = false;
603 }
604
605 if( !m_pullupReference.Check() )
606 {
607 if( status )
608 Report( message.str(), RPT_SEVERITY_ACTION );
609
610 Report( _( "Missing or invalid Pullup Reference value." ), RPT_SEVERITY_ERROR );
611 status = false;
612 }
613
614 if( !m_pulldownReference.Check() )
615 {
616 if( status )
617 Report( message.str(), RPT_SEVERITY_ACTION );
618
619 Report( _( "Missing or invalid Pulldown Reference value." ), RPT_SEVERITY_ERROR );
620 status = false;
621 }
622
623 if( !m_GNDClampReference.Check() )
624 {
625 if( status )
626 Report( message.str(), RPT_SEVERITY_ACTION );
627
628 Report( _( "Missing or invalid GND Clamp Reference value." ), RPT_SEVERITY_ERROR );
629 status = false;
630 }
631
632 if( !m_POWERClampReference.Check() )
633 {
634 if( status )
635 Report( message.str(), RPT_SEVERITY_ACTION );
636
637 Report( _( "Missing or invalid POWER Clamp Reference value." ), RPT_SEVERITY_ERROR );
638 status = false;
639 }
640
641 if ( m_voltageRange.isNA() && ( m_pullupReference.isNA() || m_pulldownReference.isNA()
642 || m_GNDClampReference.isNA() || m_POWERClampReference.isNA() ) )
643 {
644 if( status )
645 Report( message.str(), RPT_SEVERITY_ACTION );
646
647 Report( _( "Voltage Range or Reference is missing." ), RPT_SEVERITY_ERROR );
648 status = false;
649 }
650
651 if( !m_pulldown.Check() )
652 {
653 Report( _( "Invalid Pulldown table." ), RPT_SEVERITY_ERROR );
654 status = false;
655 }
656
657 if( !m_pullup.Check() )
658 {
659 Report( _( "Invalid Pullup table." ), RPT_SEVERITY_ERROR );
660 status = false;
661 }
662
663 if( !m_ISSO_PD.Check() )
664 {
665 Report( _( "Invalid ISSO_PD table." ), RPT_SEVERITY_ERROR );
666 status = false;
667 }
668
669 if( !m_ISSO_PU.Check() )
670 {
671 Report( _( "Invalid ISSO_PU table." ), RPT_SEVERITY_ERROR );
672 status = false;
673 }
674
675 if( !m_compositeCurrent.Check() )
676 {
677 Report( _( "Invalid Composite Current table." ), RPT_SEVERITY_ERROR );
678 status = false;
679 }
680
681 if( !m_POWERClamp.Check() )
682 {
683 Report( _( "Invalid POWER Clamp table." ), RPT_SEVERITY_ERROR );
684 status = false;
685 }
686
687 if( !m_GNDClamp.Check() )
688 {
689 Report( _( "Invalid GND Clamp table." ), RPT_SEVERITY_ERROR );
690 status = false;
691 }
692
696 {
697 if( !m_ramp.Check() )
698 Report( _( "Invalid Ramp specification." ), RPT_SEVERITY_ERROR );
699 }
700
701 return status;
702}
703
704
706{
707 bool status = true;
708
709 if( m_name.empty() )
710 {
711 Report( _( "Submodel name cannot be empty." ), RPT_SEVERITY_ERROR );
712 status = false;
713 }
714
715 std::stringstream message;
716 message << _( "Checking submodel " ) << m_name;
717
719 {
720 if( status )
721 Report( message.str(), RPT_SEVERITY_ACTION );
722
723 Report( _( "The submodel has no type." ), RPT_SEVERITY_ERROR );
724 status = false;
725 }
726
727 if( !m_VtriggerR.Check() )
728 {
729 if( status )
730 Report( message.str(), RPT_SEVERITY_ACTION );
731
732 Report( _( "Missing or invalid V_trigger_r value." ), RPT_SEVERITY_ERROR );
733 status = false;
734 }
735 if( !m_VtriggerF.Check() )
736 {
737 if( status )
738 Report( message.str(), RPT_SEVERITY_ACTION );
739
740 Report( _( "Missing or invalid V_trigger_f value." ), RPT_SEVERITY_ERROR );
741 status = false;
742 }
743 if( !m_offDelay.Check() )
744 {
745 if( status )
746 Report( message.str(), RPT_SEVERITY_ACTION );
747
748 Report( _( "Missing or invalid Off_delay value." ), RPT_SEVERITY_ERROR );
749 status = false;
750 }
751 if( !m_pullup.Check() )
752 {
753 Report( _( "Invalid Pullup table." ), RPT_SEVERITY_ERROR );
754 status = false;
755 }
756 if( !m_pulldown.Check() )
757 {
758 Report( _( "Invalid Pulldown table." ), RPT_SEVERITY_ERROR );
759 status = false;
760 }
761 if( !m_GNDClamp.Check() )
762 {
763 Report( _( "Invalid GND Clamp table." ), RPT_SEVERITY_ERROR );
764 status = false;
765 }
766 if( !m_POWERClamp.Check() )
767 {
768 Report( _( "Invalid POWER Clamp table." ), RPT_SEVERITY_ERROR );
769 status = false;
770 }
771 if( !m_GNDPulse.Check() )
772 {
773 Report( _( "Invalid GND Pulse table." ), RPT_SEVERITY_ERROR );
774 status = false;
775 }
776 if( !m_POWERPulse.Check() )
777 {
778 Report( _( "Invalid POWER Pulse table." ), RPT_SEVERITY_ERROR );
779 status = false;
780 }
781 if( !m_ramp.Check() )
782 {
783 Report( _( "Invalid Ramp specification." ), RPT_SEVERITY_ERROR );
784 status = false;
785 }
787 {
788 std::stringstream err_msg;
789 switch( m_type )
790 {
791 case IBIS_SUBMODEL_TYPE::BUS_HOLD: err_msg << "Bus Hold"; break;
792 case IBIS_SUBMODEL_TYPE::FALL_BACK: err_msg << "Fall Back"; break;
793 default: wxLogMessage( "Invalid submodel type: %i", (int) m_type ); return false;
794 }
795 err_msg << _( " submodels are not yet supported." );
796 Report( err_msg.str(), RPT_SEVERITY_ERROR );
797 status = false;
798 }
799 else if( !m_VtriggerR.isNA() || !m_VtriggerF.isNA() )
800 {
801 Report( _( "Triggered mode dynamic clamp submodels are not yet supported." ), RPT_SEVERITY_ERROR );
802 status = false;
803 }
804 return status;
805}
806
807
809{
810 bool status = true;
811
812 std::stringstream message;
813 message << _( "Checking Header..." );
814
815 if( m_ibisVersion == -1 )
816 {
817 if( status )
818 Report( message.str(), RPT_SEVERITY_ACTION );
819
820 Report( _( "Missing [IBIS Ver]" ), RPT_SEVERITY_ERROR );
821 status = false;
822 }
823
825 {
826 if( status )
827 Report( message.str(), RPT_SEVERITY_ACTION );
828
829 Report( _( "The parser does not handle this IBIS version" ), RPT_SEVERITY_ERROR );
830 status = false;
831 }
832
833 if( m_fileRevision == -1 )
834 {
835 if( status )
836 Report( message.str(), RPT_SEVERITY_ACTION );
837
838 Report( _( "Missing [File Rev]" ), RPT_SEVERITY_ERROR );
839 status = false;
840 }
841
842 if( m_fileName.empty() )
843 {
844 if( status )
845 Report( message.str(), RPT_SEVERITY_ACTION );
846
847 Report( _( "Missing [File Name]" ), RPT_SEVERITY_ERROR );
848 status = false;
849 }
850
851 std::string ext = m_fileName.substr( m_fileName.length() - 4 );
852
853 if( !( !strcmp( ext.c_str(), ".ibs" ) || !strcmp( ext.c_str(), ".pkg" )
854 || !strcmp( ext.c_str(), ".ebd" ) || !strcmp( ext.c_str(), ".ims" ) ) )
855 {
856 if( status )
857 Report( message.str(), RPT_SEVERITY_ACTION );
858
859 Report( "Invalid file extension in [File Name]", RPT_SEVERITY_ERROR );
860 status = false;
861 }
862
863 return status;
864}
865
867{
868 bool status = true;
869
870 if( m_name.empty() )
871 {
872 Report( _( "Package model name cannot be empty." ), RPT_SEVERITY_ERROR );
873 status = false;
874 }
875
876 std::stringstream message;
877 message << _( "Checking package model " ) << m_name;
878
879 if( m_manufacturer.empty() )
880 {
881 if( status )
882 Report( message.str(), RPT_SEVERITY_ACTION );
883
884 Report( _( "Manufacturer cannot be empty." ), RPT_SEVERITY_ERROR );
885 status = false;
886 }
887
888 if( m_OEM.empty() )
889 {
890 if( status )
891 Report( message.str(), RPT_SEVERITY_ACTION );
892
893 Report( _( "OEM cannot be empty." ), RPT_SEVERITY_ERROR );
894 status = false;
895 }
896
897 if( m_numberOfPins < 0 )
898 {
899 if( status )
900 Report( message.str(), RPT_SEVERITY_ACTION );
901
902 Report( _( "Negative number of pins." ), RPT_SEVERITY_ERROR );
903 status = false;
904 }
905
906 if( (int)m_pins.size() != m_numberOfPins )
907 {
908 if( status )
909 Report( message.str(), RPT_SEVERITY_ACTION );
910
911 Report( "Number of pins does not match [Pin Numbers] size.", RPT_SEVERITY_ERROR );
912 status = false;
913 }
914
915 // resistance matrix is not required
916
917 if( !( m_resistanceMatrix )->Check() )
918 {
919 if( status )
920 Report( message.str(), RPT_SEVERITY_ACTION );
921
922 Report( _( "Resistance matrix is incorrect." ), RPT_SEVERITY_ERROR );
923 status = false;
924 }
925
926 if( m_capacitanceMatrix != nullptr )
927 {
929 {
930 if( status )
931 Report( message.str(), RPT_SEVERITY_ACTION );
932
933 Report( _( "Capacitance matrix is undefined." ), RPT_SEVERITY_ERROR );
934 status = false;
935 }
936
937 if( !m_capacitanceMatrix->Check() )
938 {
939 if( status )
940 Report( message.str(), RPT_SEVERITY_ACTION );
941
942 Report( _( "Capacitance matrix is incorrect." ), RPT_SEVERITY_ERROR );
943 status = false;
944 }
945 }
946 else
947 {
948 if( status )
949 Report( message.str(), RPT_SEVERITY_ACTION );
950
951 Report( _( "Capacitance matrix is nullptr." ), RPT_SEVERITY_ERROR );
952 status = false;
953 }
954
955 if( m_inductanceMatrix != nullptr )
956 {
958 {
959 if( status )
960 Report( message.str(), RPT_SEVERITY_ACTION );
961
962 Report( _( "Inductance matrix is undefined." ), RPT_SEVERITY_ERROR );
963 status = false;
964 }
965
966 if( !m_inductanceMatrix->Check() )
967 {
968 if( status )
969 Report( message.str(), RPT_SEVERITY_ACTION );
970
971 Report( _( "Inductance matrix is incorrect." ), RPT_SEVERITY_ERROR );
972 status = false;
973 }
974 }
975 else
976 {
977 if( status )
978 Report( message.str(), RPT_SEVERITY_ACTION );
979
980 Report( _( "Inductance matrix is nullptr." ), RPT_SEVERITY_ERROR );
981 status = false;
982 }
983 return status;
984}
985
986
987bool IbisParser::ParseFile( const std::string& aFileName )
988{
989 std::stringstream err_msg;
990
991 std::ifstream ibisFile;
992 ibisFile.open( aFileName );
993
994 if( !ibisFile.is_open() )
995 {
996 err_msg << _( "Cannot open file " ) << aFileName;
997 Report( err_msg.str(), RPT_SEVERITY_ERROR );
998 return false;
999 }
1000
1001 std::ostringstream ss;
1002 ss << ibisFile.rdbuf();
1003 const std::string& s = ss.str();
1004 m_buffer = std::vector<char>( s.begin(), s.end() );
1005 m_buffer.push_back( 0 );
1006
1007 long size = m_buffer.size();
1008
1009 m_lineCounter = 0;
1010 m_bufferIndex = 0;
1011
1012 bool status = true;
1013
1014 LOCALE_IO toggle; // Temporary switch the locale to standard C to r/w floats
1015
1016 while( ( m_bufferIndex < size ) && status )
1017 {
1018 if( !getNextLine() )
1019 {
1020 Report( _( "Unexpected end of file. Missing [END] ?" ), RPT_SEVERITY_ERROR );
1021 status = false;
1022 }
1023
1024 if( status && m_parrot )
1025 printLine();
1026
1027 if( status && !onNewLine() )
1028 {
1029 err_msg.clear();
1030 err_msg << _( "Error on line " ) << std::to_string( m_lineCounter );
1031 Report( err_msg.str(), RPT_SEVERITY_ERROR );
1032 status = false;
1033 }
1034
1036 break;
1037 }
1038
1039 if( status )
1040 {
1041 for( const IbisModel& model : m_ibisFile.m_models )
1042 {
1043 for( const IbisSubmodelMode& submodel : model.m_submodels )
1044 {
1045 if( m_ibisFile.m_submodels.count( submodel.m_name ) == 0 )
1046 {
1047 err_msg.clear();
1048 err_msg << submodel.m_name << _( " submodel not found." );
1049 Report( err_msg.str(), RPT_SEVERITY_ERROR );
1050 status = false;
1051 goto done;
1052 }
1053 }
1054 }
1055 }
1056
1057done:
1058 m_buffer.clear();
1059 return status;
1060}
1061
1063{
1064 while( isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
1065 m_lineIndex++;
1066}
1067
1068
1070{
1072
1074 {
1075 Report( _( "A line did not end properly." ), RPT_SEVERITY_ERROR );
1076 return false;
1077 }
1078
1079 return true;
1080}
1081
1082
1084{
1085 int cursor = m_lineIndex;
1086
1087 while( isspace( m_buffer[m_lineOffset + cursor] ) && cursor < m_lineLength )
1088 cursor++;
1089
1090 return ( cursor >= m_lineLength );
1091}
1092
1093
1094bool IbisParser::parseDvdt( dvdt& aDest, std::string& aString )
1095{
1096 bool status = true;
1097
1098 if( aString == "NA" )
1099 {
1100 aDest.m_dv = nan( NAN_NA );
1101 aDest.m_dt = nan( NAN_NA );
1102
1103 return status;
1104 }
1105
1106 int i = 0;
1107
1108 for( i = 1; i < (int)aString.length(); i++ )
1109 {
1110 if( aString.at( i ) == '/' )
1111 break;
1112 }
1113
1114 if( aString.at( i ) == '/' )
1115 {
1116 std::string str1 = aString.substr( 0, i );
1117 std::string str2 = aString.substr( i + 1, aString.size() - i - 1 );
1118
1119 if( !parseDouble( aDest.m_dv, str1, true ) || !parseDouble( aDest.m_dt, str2, true ) )
1120 status = false;
1121 }
1122
1123 return status;
1124}
1125
1126
1128{
1129 bool status = true;
1130 std::string str;
1131
1132 if( readWord( str ) )
1133 {
1134 if( !parseDvdt( aDest, str ) )
1135 {
1136 std::stringstream message;
1137 message << str << _( " is not a valid dV/dt value." );
1138 Report( message.str(), RPT_SEVERITY_WARNING );
1139 status = false;
1140 }
1141 }
1142 else
1143 {
1144 Report( _( "A dV/dt value is missing." ), RPT_SEVERITY_WARNING );
1145 status = false;
1146 }
1147
1148 return status;
1149}
1150
1151
1152bool IbisParser::parseDouble( double& aDest, std::string& aStr, bool aAllowModifiers )
1153{
1154 // " an entry of the C matrix could be given as 1.23e-12 or as 1.23p or 1.23pF."
1155 // Kibis: This implementation will also allow 1.23e-3n
1156
1158 bool status = true;
1159 bool converted = false;
1160
1161 std::string str = aStr;
1162
1163 double result;
1164 size_t size = 0;
1165
1166
1167 if( str == "NA" )
1168 {
1169 result = nan( NAN_NA );
1170 }
1171 else
1172 {
1173 try
1174 {
1175 result = std::stod( str, &size );
1176 converted = true;
1177 }
1178 catch( ... )
1179 {
1180 result = nan( NAN_INVALID );
1181 status = false;
1182 }
1183 }
1184
1185 if( converted && ( size < str.length() ) )
1186 {
1187 switch( static_cast<char>( str.at( size ) ) )
1188 {
1189 case 'T': result *= 1e12; break;
1190 case 'G': result *= 1e9; break;
1191 case 'M': result *= 1e6; break;
1192 case 'k': result *= 1e3; break;
1193 case 'm': result *= 1e-3; break;
1194 case 'u': result *= 1e-6; break;
1195 case 'n': result *= 1e-9; break;
1196 case 'p': result *= 1e-12; break;
1197 case 'f': result *= 1e-15; break;
1198 default:
1199 break;
1200 // In some files, "vinh = 3.0V", therefore we can't return false in the default case
1201 }
1202 }
1203
1204 aDest = result;
1205
1206 return status;
1207}
1208
1209
1211{
1212 m_lineCounter++;
1213
1214 long tmpIndex = m_bufferIndex;
1215
1217
1218 if( m_bufferIndex >= (int)m_buffer.size() )
1219 return false;
1220
1221 char c = m_buffer[m_bufferIndex++];
1222
1223 int i = 1;
1224
1225 while( c != m_commentChar && c != 0 && c != '\n' && i < IBIS_MAX_LINE_LENGTH )
1226 {
1227 c = m_buffer[m_bufferIndex++];
1228 i++;
1229 }
1230
1231 if( i == IBIS_MAX_LINE_LENGTH )
1232 {
1233 Report( _( "Line exceeds maximum length." ), RPT_SEVERITY_ERROR );
1234 return false;
1235 }
1236
1237 m_lineLength = m_bufferIndex - tmpIndex - 1; // Don't add the end of line condition
1238 m_lineIndex = 0;
1239
1240 if( c == m_commentChar )
1241 {
1242 while( c != 0 && c != '\n' )
1243 c = m_buffer[m_bufferIndex++];
1244 }
1245
1246 if( i == IBIS_MAX_LINE_LENGTH )
1247 {
1248 Report( _( "Line exceeds maximum length." ), RPT_SEVERITY_ERROR );
1249 return false;
1250 }
1251
1252 return true;
1253}
1254
1255
1257{
1258 for( int i = 0; i < m_lineLength; i++ )
1259 std::cout << m_buffer[m_lineOffset + i];
1260
1261 std::cout << std::endl;
1262}
1263
1264bool IbisParser::readDouble( double& aDest )
1265{
1266 bool status = true;
1267 std::string str;
1268
1269 if( readWord( str ) )
1270 {
1271 if( !parseDouble( aDest, str, true ) )
1272 {
1273 Report( _( "Failed to read a double." ), RPT_SEVERITY_WARNING );
1274 status = false;
1275 }
1276 }
1277 else
1278 {
1279 Report( _( "Failed to read a word." ), RPT_SEVERITY_WARNING );
1280 status = false;
1281 }
1282
1283 return status;
1284}
1285
1286bool IbisParser::readInt( int& aDest )
1287{
1288 bool status = true;
1289 std::string str;
1290
1291 if( readWord( str ) )
1292 {
1293 double result;
1294 size_t size = 0;
1295
1296 try
1297 {
1298 result = std::stoi( str, &size );
1299 }
1300 catch( ... )
1301 {
1302 if( str == "NA" )
1303 {
1304 result = nan( NAN_NA );
1305 }
1306 else
1307 {
1308 result = nan( NAN_INVALID );
1309 status = false;
1310 }
1311 }
1312
1313 if( size != str.size() )
1314 {
1315 status = false;
1316 Report( _( "Number is not an integer" ), RPT_SEVERITY_WARNING );
1317 }
1318
1319 aDest = result;
1320 }
1321 else
1322 {
1323 Report( _( "Failed to read a word." ), RPT_SEVERITY_WARNING );
1324 status = false;
1325 }
1326
1327 return status;
1328}
1329
1330bool IbisParser::readWord( std::string& aDest )
1331{
1333
1334 int startIndex = m_lineIndex;
1335
1336 while( !isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
1337 m_lineIndex++;
1338
1339 std::vector<char>::iterator start = std::next( m_buffer.begin(), m_lineOffset + startIndex );
1340 std::vector<char>::iterator end = std::next( m_buffer.begin(), m_lineOffset + m_lineIndex );
1341 aDest = std::string( start, end );
1342
1343 return ( aDest.size() > 0 );
1344}
1345
1346bool IbisParser::readString( std::string& aDest )
1347{
1348 while( m_lineIndex < m_lineLength )
1349 aDest += m_buffer[m_lineOffset + m_lineIndex++];
1350
1351 // Remove extra whitespace characters
1352 int len = aDest.length();
1353
1354 if( len < 1 )
1355 return true; // The data is likely on the next line. Skip.
1356
1357 char c = aDest[len - 1];
1358 int i = 0;
1359
1360 while( isspace( c ) && ( i < len ) )
1361 {
1362 c = aDest[len - 1 - i];
1363 i++;
1364 }
1365
1366 aDest = aDest.substr( 0, len - i + 1 );
1367
1368 return true;
1369}
1370
1371bool IbisParser::storeString( std::string& aDest, bool aMultiline )
1372{
1373 bool status = true;
1374
1376
1377 status &= readString( aDest );
1378
1380 m_continuingString = &aDest;
1381
1382 status &= checkEndofLine();
1383 return status;
1384}
1385
1386
1388{
1390
1391 std::string strChar = "";
1392
1393 // We cannot stop at m_lineLength here, because lineLength could stop before |_char
1394 // if the char remains the same
1395
1396 char c = m_buffer[m_lineOffset + m_lineIndex++];
1397 char d = c;
1398
1399 if( !( c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\''
1400 || c == '(' || c == ')' || c == '*' || c == ',' || c == ':' || c == ';' || c == '<'
1401 || c == '>' || c == '?' || c == '@' || c == '\\' || c == '^' || c == '`' || c == '{'
1402 || c == '|' || c == '}' || c == '~' || c == ')' ) )
1403 {
1404 Report( _( "New comment character is invalid." ), RPT_SEVERITY_ERROR );
1405 }
1406
1408
1409 while( ( !isspace( c ) ) && c != 0 && c != '\n' )
1410 {
1411 strChar += c;
1413 }
1414
1415 if( strChar != "_char" )
1416 {
1417 Report( _( "Invalid syntax. Should be |_char or &_char, etc..." ), RPT_SEVERITY_ERROR );
1418 return false;
1419 }
1420
1421 while( isspace( c ) && c != 0 && c != '\n' && c != d )
1423
1424 if( ( !isspace( c ) ) && c != d )
1425 {
1426 Report( _( "No extra argument was expected" ), RPT_SEVERITY_ERROR );
1427 return false;
1428 }
1429
1430 m_commentChar = d;
1431
1433
1434 return true;
1435}
1436
1438{
1439 std::string keyword = "";
1440 //"Keywords must be enclosed in square brackets, “[]”, and must start in column 1 of the line."
1441 //"No space or tab is allowed immediately after the opening bracket “[” or immediately"
1442 // "before the closing bracket “]"
1443
1444 if( m_buffer[m_lineOffset + m_lineIndex] != '[' )
1445 {
1446 // We return an empty keyword, this should stop the parser.
1447 return "";
1448 }
1449
1450 m_lineIndex++;
1451
1452 char c;
1454
1455 while( ( c != ']' )
1456 && ( m_lineIndex
1457 < m_lineLength ) ) // We know the maximum keyword length, we could add a condition.
1458 {
1459 // "Underscores and spaces are equivalent in keywords"
1460 if( c == ' ' )
1461 c = '_';
1462
1463 keyword += c;
1465 }
1466
1467 return keyword;
1468}
1469
1470bool IbisParser::changeContext( std::string& aKeyword )
1471{
1472 bool status = true;
1473
1474 if( status )
1475 {
1476 switch( m_context )
1477 {
1478 case IBIS_PARSER_CONTEXT::HEADER: status &= m_ibisFile.m_header.Check(); break;
1479 case IBIS_PARSER_CONTEXT::COMPONENT: status &= m_currentComponent->Check(); break;
1480 case IBIS_PARSER_CONTEXT::MODEL: status &= m_currentModel->Check(); break;
1481 case IBIS_PARSER_CONTEXT::SUBMODEL: status &= m_currentSubmodel->Check(); break;
1482 case IBIS_PARSER_CONTEXT::MODELSELECTOR: status &= m_currentModelSelector->Check(); break;
1483 case IBIS_PARSER_CONTEXT::PACKAGEMODEL: status &= m_currentPackageModel->Check(); break;
1485 Report( "Cannot change context after [END]" );
1486 status = false;
1487 break;
1488 default:
1489 Report( "Changing context from an undefined context" );
1490 }
1491 }
1492
1493 if( !compareIbisWord( aKeyword.c_str(), "End" ) && status )
1494 {
1495 //New context
1496 if( compareIbisWord( aKeyword.c_str(), "Component" ) )
1497 {
1498 m_ibisFile.m_components.push_back( IbisComponent( m_Reporter ) );
1499 m_currentComponent = &( m_ibisFile.m_components.back() );
1500 status &= storeString( m_currentComponent->m_name, false );
1502 }
1503 else if( compareIbisWord( aKeyword.c_str(), "Model_Selector" ) )
1504 {
1506 status &= storeString( MS.m_name, false );
1507 m_ibisFile.m_modelSelectors.push_back( MS );
1508 m_currentModelSelector = &( m_ibisFile.m_modelSelectors.back() );
1511 }
1512 else if( compareIbisWord( aKeyword.c_str(), "Model" ) )
1513 {
1515 model.m_temperatureRange.value[IBIS_CORNER::MIN] = 0;
1516 model.m_temperatureRange.value[IBIS_CORNER::TYP] = 50;
1517 model.m_temperatureRange.value[IBIS_CORNER::MAX] = 100;
1518 status &= storeString( model.m_name, false );
1519 m_ibisFile.m_models.push_back( model );
1520 m_currentModel = &( m_ibisFile.m_models.back() );
1523 }
1524 else if( compareIbisWord( aKeyword.c_str(), "Submodel" ) )
1525 {
1527 status &= storeString( model.m_name, false );
1528 auto [it, success] = m_ibisFile.m_submodels.emplace( model.m_name, model );
1529
1530 if( !success )
1531 {
1532 std::stringstream message;
1533 message << _( "Submodel name is not unique: " ) << model.m_name;
1534 Report( message.str(), RPT_SEVERITY_ERROR );
1535 status = false;
1536 }
1537
1538 m_currentSubmodel = &( it->second );
1541 }
1542 else if( compareIbisWord( aKeyword.c_str(), "Define_Package_Model" ) )
1543 {
1545 PM.m_resistanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1546 PM.m_capacitanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1547 PM.m_inductanceMatrix = std::unique_ptr<IBIS_MATRIX>( new IBIS_MATRIX( m_Reporter ) );
1548
1549 status &= storeString( PM.m_name, false );
1550
1551 m_ibisFile.m_packageModels.push_back( PM );
1552 m_currentPackageModel = &( m_ibisFile.m_packageModels.back() );
1554 }
1555 else if( compareIbisWord( aKeyword.c_str(), "End_Package_Model" ) )
1556 {
1557 if( m_currentComponent != nullptr )
1558 {
1561 }
1562 else // .pkg file, we just go back to header, to get the [END] keyword
1563 { // This will cause the header to be checked twice.
1566 }
1567 }
1568 else
1569 {
1570 status = false;
1571 std::string context_string;
1572
1573 switch( m_context )
1574 {
1575 case IBIS_PARSER_CONTEXT::HEADER: context_string += "HEADER"; break;
1576 case IBIS_PARSER_CONTEXT::COMPONENT: context_string += "COMPONENT"; break;
1577 case IBIS_PARSER_CONTEXT::MODELSELECTOR: context_string += "MODEL_SELECTOR"; break;
1578 case IBIS_PARSER_CONTEXT::MODEL: context_string += "MODEL"; break;
1579 case IBIS_PARSER_CONTEXT::PACKAGEMODEL: context_string += "PACKAGE_MODEL"; break;
1580 case IBIS_PARSER_CONTEXT::PACKAGEMODEL_MODELDATA: context_string += "PACKAGE_MODEL_MODEL_DATA"; break;
1581 default: context_string += "???"; break;
1582 }
1583
1584 std::stringstream message;
1585 message << _( "Unknown keyword in " ) << context_string << _( " context: " ) << aKeyword;
1586 Report( message.str(), RPT_SEVERITY_ERROR );
1587 }
1588 }
1589 else
1590 {
1592 }
1593
1594 return status;
1595}
1596
1597
1598bool IbisParser::parseModelSelector( std::string& aKeyword )
1599{
1600 bool status = true;
1601
1602 if( !changeContext( aKeyword ) )
1603 status = false;
1604
1605 return status;
1606}
1607
1608
1610{
1611 bool status = true;
1612
1613 status &= readDvdt( aDest.value[IBIS_CORNER::TYP] );
1614 status &= readDvdt( aDest.value[IBIS_CORNER::MIN] );
1615 status &= readDvdt( aDest.value[IBIS_CORNER::MAX] );
1616
1617 return status;
1618}
1619
1621{
1622 bool status = true;
1624
1625 IbisRamp* ramp = nullptr;
1626 switch( m_context )
1627 {
1629 ramp = &m_currentModel->m_ramp;
1630 break;
1632 ramp = &m_currentSubmodel->m_ramp;
1633 break;
1634 default:
1635 wxLogMessage( "Invalid context for ramp: %i.", (int) m_context );
1636 return false;
1637 }
1638
1639 if( !readNumericSubparam( std::string( "R_load" ), ramp->m_Rload ) )
1640 {
1641 std::string str;
1642
1643 if( readWord( str ) )
1644 {
1645 if( !strcmp( str.c_str(), "dV/dt_r" ) )
1646 {
1647 status &= readRampdvdt( ramp->m_rising );
1648 }
1649 else if( !strcmp( str.c_str(), "dV/dt_f" ) )
1650 {
1651 status &= readRampdvdt( ramp->m_falling );
1652 }
1653 else
1654 {
1655 Report( _( "Invalid ramp data" ), RPT_SEVERITY_ERROR );
1656 status = false;
1657 }
1658 }
1659 }
1660
1661 return status;
1662}
1663
1664
1666{
1667 bool status = true;
1668
1670
1671 // TODO
1672 // readTypMinMaxValueSubparam( std::string( "Vmeas" ), m_currentModel->... )
1673 // ...
1674
1675 return status;
1676}
1677
1678
1680{
1681 bool status = true;
1682
1684
1685 // TODO
1686 // readTypMinMaxValueSubparam( std::string( "Vth" ), m_currentModel->... )
1687 // ...
1688
1689 return status;
1690}
1691
1692
1694{
1695 bool status = true;
1696
1697 // TODO: ???
1698
1699 return status;
1700}
1701
1702
1703bool IbisParser::parseAlgorithmicModel( std::string& aKeyword )
1704{
1705 bool status = true;
1706
1707 if( compareIbisWord( aKeyword.c_str(), "End_Algorithmic_Model" ) )
1708 {
1711 }
1712 else
1713 {
1714 status = changeContext( aKeyword );
1715 }
1716 return status;
1717}
1718
1719
1721{
1722 bool status = true;
1723
1725
1727
1729 {
1730 std::string name;
1731 if( !readWord( name ) )
1732 {
1733 Report( _( "The submodel name is missing." ) );
1734 return false;
1735 }
1736
1737 std::string str;
1738 if( !readWord( str ) )
1739 {
1740 Report( _( "The submodel mode is missing." ) );
1741 return false;
1742 }
1743
1745 if( !strcmp( str.c_str(), "All" ) )
1746 {
1748 }
1749 else if( !strcmp( str.c_str(), "Driving" ) )
1750 {
1752 }
1753 else if( !strcmp( str.c_str(), "Non-Driving" ) )
1754 {
1756 }
1757 else
1758 {
1759 std::stringstream message;
1760 message << str << _( " is not a recognised submodel mode." );
1761 Report( message.str(), RPT_SEVERITY_WARNING );
1762 return false;
1763 }
1764
1765 m_currentModel->m_submodels.push_back( IbisSubmodelMode( name, mode ) );
1766 }
1767
1768 return status;
1769}
1770
1771
1772bool IbisParser::parseModel( std::string& aKeyword )
1773{
1774 bool status = false;
1775
1776 if( compareIbisWord( aKeyword.c_str(), "Voltage_Range" ) )
1777 status = readTypMinMaxValue( m_currentModel->m_voltageRange );
1778 else if( compareIbisWord( aKeyword.c_str(), "Temperature_Range" ) )
1779 status = readTypMinMaxValue( m_currentModel->m_temperatureRange );
1780 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp" ) )
1781 status = readIVtableEntry( m_currentModel->m_GNDClamp );
1782 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp" ) )
1783 status = readIVtableEntry( m_currentModel->m_POWERClamp );
1784 else if( compareIbisWord( aKeyword.c_str(), "Pulldown" ) )
1785 status = readIVtableEntry( m_currentModel->m_pulldown );
1786 else if( compareIbisWord( aKeyword.c_str(), "Pullup" ) )
1787 status = readIVtableEntry( m_currentModel->m_pullup );
1788 else if( compareIbisWord( aKeyword.c_str(), "ISSO_PD" ) )
1789 status = readIVtableEntry( m_currentModel->m_ISSO_PD );
1790 else if( compareIbisWord( aKeyword.c_str(), "ISSO_PU" ) )
1791 status = readIVtableEntry( m_currentModel->m_ISSO_PU );
1792 else if( compareIbisWord( aKeyword.c_str(), "Composite_Current" ) )
1793 status = readIVtableEntry( m_currentModel->m_compositeCurrent );
1794 else if( compareIbisWord( aKeyword.c_str(), "Rising_Waveform" ) )
1795 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::RISING );
1796 else if( compareIbisWord( aKeyword.c_str(), "Falling_Waveform" ) )
1797 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::FALLING );
1798 else if( compareIbisWord( aKeyword.c_str(), "Ramp" ) )
1799 status = readRamp();
1800 else if( compareIbisWord( aKeyword.c_str(), "Model_Spec" ) )
1801 status = readModelSpec();
1802 else if( compareIbisWord( aKeyword.c_str(), "Receiver_Thresholds" ) )
1803 status = readReceiverThresholds();
1804 else if( compareIbisWord( aKeyword.c_str(), "Pullup_Reference" ) )
1805 status = readTypMinMaxValue( m_currentModel->m_pullupReference );
1806 else if( compareIbisWord( aKeyword.c_str(), "Pulldown_Reference" ) )
1807 status = readTypMinMaxValue( m_currentModel->m_pulldownReference );
1808 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp_Reference" ) )
1809 status = readTypMinMaxValue( m_currentModel->m_POWERClampReference );
1810 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp_Reference" ) )
1811 status = readTypMinMaxValue( m_currentModel->m_GNDClampReference );
1812 else if( compareIbisWord( aKeyword.c_str(), "Rac" ) )
1813 status = readTypMinMaxValue( m_currentModel->m_Rac );
1814 else if( compareIbisWord( aKeyword.c_str(), "Cac" ) )
1815 status = readTypMinMaxValue( m_currentModel->m_Cac );
1816 else if( compareIbisWord( aKeyword.c_str(), "Rpower" ) )
1817 status = readTypMinMaxValue( m_currentModel->m_Rpower );
1818 else if( compareIbisWord( aKeyword.c_str(), "Rgnd" ) )
1819 status = readTypMinMaxValue( m_currentModel->m_Rgnd );
1820 else if( compareIbisWord( aKeyword.c_str(), "Algorithmic_Model" ) )
1821 {
1824 status = true;
1825 }
1826 else if( compareIbisWord( aKeyword.c_str(), "Add_Submodel" ) )
1827 status = readAddSubmodel();
1828 else
1829 {
1830 status = changeContext( aKeyword );
1831 }
1832 return status;
1833}
1834
1835
1837{
1838 bool status = true;
1839
1841
1843
1844 std::string subparam;
1845 if( readWord( subparam ) )
1846 {
1847 if( !strcmp( subparam.c_str(), "Off_delay" ) )
1848 status = readTypMinMaxValue( m_currentSubmodel->m_offDelay );
1849 else if( !strcmp( subparam.c_str(), "V_trigger_r" ) )
1850 status = readTypMinMaxValue( m_currentSubmodel->m_VtriggerR );
1851 else if( !strcmp( subparam.c_str(), "V_trigger_f" ) )
1852 status = readTypMinMaxValue( m_currentSubmodel->m_VtriggerF );
1853 else
1854 {
1855 std::stringstream message;
1856 message << subparam << _( " is not a recognised Submodel Spec subparameter." );
1857 Report( message.str(), RPT_SEVERITY_ERROR );
1858 status = false;
1859 }
1860 }
1861
1862 return status;
1863}
1864
1865
1866bool IbisParser::parseSubmodel( std::string& aKeyword )
1867{
1868 bool status = false;
1869
1870 if( compareIbisWord( aKeyword.c_str(), "Submodel_Spec" ) )
1871 status = readSubmodelSpec();
1872 else if( compareIbisWord( aKeyword.c_str(), "Pullup" ) )
1873 status = readIVtableEntry( m_currentSubmodel->m_pullup );
1874 else if( compareIbisWord( aKeyword.c_str(), "Pulldown" ) )
1875 status = readIVtableEntry( m_currentSubmodel->m_pulldown );
1876 else if( compareIbisWord( aKeyword.c_str(), "GND_Clamp" ) )
1877 status = readIVtableEntry( m_currentSubmodel->m_GNDClamp );
1878 else if( compareIbisWord( aKeyword.c_str(), "POWER_Clamp" ) )
1879 status = readIVtableEntry( m_currentSubmodel->m_POWERClamp );
1880 else if( compareIbisWord( aKeyword.c_str(), "GND_Pulse" ) )
1881 status = readIVtableEntry( m_currentSubmodel->m_GNDPulse );
1882 else if( compareIbisWord( aKeyword.c_str(), "POWER_Pulse" ) )
1883 status = readIVtableEntry( m_currentSubmodel->m_POWERPulse );
1884 else if( compareIbisWord( aKeyword.c_str(), "Rising_Waveform" ) )
1885 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::RISING );
1886 else if( compareIbisWord( aKeyword.c_str(), "Falling_Waveform" ) )
1887 status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::FALLING );
1888 else if( compareIbisWord( aKeyword.c_str(), "Ramp" ) )
1889 status = readRamp();
1890 else
1891 status = changeContext( aKeyword );
1892
1893 return status;
1894}
1895
1896
1898{
1900 std::string str;
1901
1902 if( readWord( str ) )
1903 m_currentPackageModel->m_pins[str] = m_currentPackageModel->m_pins.size();
1904
1905 return true;
1906}
1907
1909{
1910 aDest = 0;
1911
1912 std::string str;
1913 if( !readWord( str ) )
1914 {
1915 Report( _( "Missing pin name/number for matrix row." ) );
1916 return false;
1917 }
1918 auto pin = m_currentPackageModel->m_pins.find( str );
1919 if( pin == m_currentPackageModel->m_pins.end() )
1920 {
1921 Report( _( "Invalid pin name/number in matrix row." ) );
1922 return false;
1923 }
1924 aDest = pin->second;
1925 return true;
1926}
1927
1928
1929bool IbisParser::readMatrixType( std::shared_ptr<IBIS_MATRIX>& aDest )
1930{
1931 m_currentMatrix = aDest;
1933 m_currentMatrix->m_rows = -1;
1934 m_currentMatrix->m_cols = -1;
1935 m_currentMatrixRow = -1;
1936 m_currentMatrixCol = -1;
1938
1939 std::string str;
1940 if( !readWord( str ) )
1941 {
1942 Report( _( "The matrix type is missing." ), RPT_SEVERITY_ERROR );
1943 return false;
1944 }
1945 if( compareIbisWord( str.c_str(), "Banded_matrix" ) )
1946 {
1948 }
1949 else if( compareIbisWord( str.c_str(), "Full_matrix" ) )
1950 {
1952 }
1953 else if( compareIbisWord( str.c_str(), "Sparse_matrix" ) )
1954 {
1956 }
1957 else
1958 {
1959 std::stringstream message;
1960 message << str << _( " is not a recognised matrix type." );
1962 return false;
1963 }
1964
1966 {
1967 int numPins = m_currentPackageModel->m_numberOfPins;
1968 m_currentMatrix->m_rows = numPins;
1969 m_currentMatrix->m_cols = numPins;
1970 m_currentMatrix->m_data.resize( numPins * numPins );
1971 }
1972 return true;
1973}
1974
1975
1977{
1978 if( ( m_currentMatrix == nullptr )
1980 || ( m_currentMatrix->m_cols > 0 ) )
1981 {
1982 Report( _( "Unexpected [Bandwidth] keyword." ), RPT_SEVERITY_ERROR );
1983 return false;
1984 }
1985
1986 int bandwidth;
1987 bool status = readInt( bandwidth );
1988 if( status )
1989 {
1990 if( bandwidth < 0 )
1991 {
1992 Report( _( "Matrix bandwidth must be >= 0." ), RPT_SEVERITY_ERROR );
1993 return false;
1994 }
1995 int numPins = m_currentPackageModel->m_numberOfPins;
1996 m_currentMatrix->m_rows = numPins;
1997 m_currentMatrix->m_cols = 1 + bandwidth;
1998 m_currentMatrix->m_data.resize( numPins * ( 1 + bandwidth ) );
1999 }
2000 return status;
2001}
2002
2004{
2005 if( ( m_currentMatrix == nullptr ) || ( m_currentMatrix->m_rows < 0 ) )
2006 {
2007 Report( _( "Unexpected [Row] keyword." ), RPT_SEVERITY_ERROR );
2008 return false;
2009 }
2010 int index;
2011 bool status = readMatrixPinIndex( index );
2012 if( status )
2013 {
2016 {
2018 }
2019 else
2020 {
2022 }
2024 }
2025 return status;
2026}
2027
2029{
2030 std::vector<std::string> values;
2031 bool status = readTableLine( values );
2032
2033 for( size_t i = 0; i < values.size(); i++ )
2034 {
2035 if( m_currentMatrixCol >= m_currentMatrix->m_cols )
2036 {
2037 Report( _( "Too much data for this matrix row." ), RPT_SEVERITY_ERROR );
2038 return false;
2039 }
2041 if( ( index < 0 ) || ( index >= (int)m_currentMatrix->m_data.size() ) )
2042 {
2043 Report( _( "Element location is outside the matrix." ), RPT_SEVERITY_ERROR );
2044 return false;
2045 }
2046 if( !parseDouble( m_currentMatrix->m_data[index], values.at( i ), true ) )
2047 {
2048 Report( _( "Failed to read a matrix element." ), RPT_SEVERITY_ERROR );
2049 return false;
2050 }
2052 }
2053 return status;
2054}
2055
2057{
2058 int index;
2059 if( !readMatrixPinIndex( index ) )
2060 {
2061 Report( _( "Failed to read a matrix pin name." ), RPT_SEVERITY_ERROR );
2062 return false;
2063 }
2064 double value;
2065 if( !readDouble( value ) )
2066 {
2067 Report( _( "Failed to read a matrix element." ), RPT_SEVERITY_ERROR );
2068 return false;
2069 }
2071 if( ( index < 0 ) || (index >= (int)m_currentMatrix->m_data.size() ) )
2072 {
2073 Report( _( "Element location is outside the matrix." ), RPT_SEVERITY_ERROR );
2074 return false;
2075 }
2076 m_currentMatrix->m_data[index] = value;
2077 return true;
2078}
2079
2081{
2082 int status = false;
2083 if( m_currentMatrix != nullptr )
2084 {
2085 switch( m_currentMatrix->m_type )
2086 {
2089 status = readMatrixBandedOrFull();
2090 break;
2092 status = readMatrixSparse();
2093 break;
2095 default:
2096 wxLogMessage( "Invalid matrix type: %i", (int) m_currentMatrix->m_type );
2097 break;
2098 }
2099 }
2100 else
2101 {
2102 wxLogMessage( "Matrix pointer is null" );
2103 }
2104 return status;
2105}
2106
2107bool IbisParser::parsePackageModelModelData( std::string& aKeyword )
2108{
2109 bool status = true;
2110
2111 if( compareIbisWord( aKeyword.c_str(), "Resistance_Matrix" ) )
2112 {
2113 status = readMatrixType( m_currentPackageModel->m_resistanceMatrix );
2114 }
2115 else if( compareIbisWord( aKeyword.c_str(), "Capacitance_Matrix" ) )
2116 {
2117 status = readMatrixType( m_currentPackageModel->m_capacitanceMatrix );
2118 }
2119 else if( compareIbisWord( aKeyword.c_str(), "Inductance_Matrix" ) )
2120 {
2121 status = readMatrixType( m_currentPackageModel->m_inductanceMatrix );
2122 }
2123 else if( compareIbisWord( aKeyword.c_str(), "Bandwidth" ) )
2124 {
2125 status = readMatrixBandwidth();
2126 }
2127 else if( compareIbisWord( aKeyword.c_str(), "Row" ) )
2128 {
2129 status = readMatrixRow();
2130 }
2131 else if( compareIbisWord( aKeyword.c_str(), "End_Model_Data" ) )
2132 {
2135 }
2136 else if( !changeContext( aKeyword ) )
2137 {
2138 status = false;
2139 }
2140
2141 return status;
2142}
2143
2144bool IbisParser::parsePackageModel( std::string& aKeyword )
2145{
2146 bool status = true;
2147
2148 if( compareIbisWord( aKeyword.c_str(), "Manufacturer" ) )
2149 status &= storeString( m_currentPackageModel->m_manufacturer, false );
2150 else if( compareIbisWord( aKeyword.c_str(), "OEM" ) )
2151 status &= storeString( m_currentPackageModel->m_OEM, false );
2152 else if( compareIbisWord( aKeyword.c_str(), "Description" ) )
2153 status &= storeString( m_currentPackageModel->m_description, false );
2154 else if( compareIbisWord( aKeyword.c_str(), "Number_of_Pins" ) )
2155 status &= readInt( m_currentPackageModel->m_numberOfPins );
2156 else if( compareIbisWord( aKeyword.c_str(), "Pin_Numbers" ) )
2157 status &= readPackageModelPins();
2158 else if( compareIbisWord( aKeyword.c_str(), "Model_Data" ) )
2159 {
2162 }
2163 else if( !changeContext( aKeyword ) )
2164 {
2165 status = false;
2166 }
2167
2168 return status;
2169}
2170
2172{
2173 bool status = true;
2174
2176
2177 if( !readWord( model.m_modelName ) )
2178 return false;
2179
2180 status &= readString( model.m_modelDescription );
2181 m_currentModelSelector->m_models.push_back( model );
2182
2183 return status;
2184}
2185
2186bool IbisParser::readNumericSubparam( const std::string& aSubparam, double& aDest )
2187{
2188 std::string paramName;
2189 bool status = true;
2190
2191 if( aSubparam.size() >= (size_t)m_lineLength )
2192 {
2193 // Continuing would result in an overflow
2194 return false;
2195 }
2196
2197 int old_index = m_lineIndex;
2198 m_lineIndex = 0;
2199
2200 for( size_t i = 0; i < aSubparam.size(); i++ )
2201 paramName += m_buffer[m_lineOffset + m_lineIndex++];
2202
2203 if( strcmp( paramName.c_str(), aSubparam.c_str() ) )
2204 {
2205 m_lineIndex = old_index;
2206 return false;
2207 }
2208
2210
2211 status &= m_buffer[m_lineOffset + m_lineIndex++] == '=';
2212
2213 if( status )
2214 {
2216 status &= readDouble( aDest );
2217 }
2218
2219 if( !status )
2220 m_lineIndex = old_index;
2221
2222 return status;
2223}
2224
2225
2227{
2228 bool status = true;
2229
2231
2232 std::string strValue;
2233
2234 if( !readDouble( aDest.value[IBIS_CORNER::TYP] ) )
2235 {
2236 Report( _( "Typ-Min-Max Values requires at least Typ." ), RPT_SEVERITY_ERROR );
2237 return false;
2238 }
2239
2242
2243 return status;
2244}
2245
2246bool IbisParser::readTypMinMaxValueSubparam( const std::string& aSubparam, TypMinMaxValue& aDest )
2247{
2248 std::string paramName;
2249 bool status = true;
2250
2251 m_lineIndex = 0; // rewind
2252
2253 if( aSubparam.size() < (size_t)m_lineLength )
2254 {
2255 for( size_t i = 0; i < aSubparam.size(); i++ )
2256 paramName += m_buffer[m_lineOffset + m_lineIndex++];
2257
2258 if( ( m_buffer[m_lineOffset + m_lineIndex] == ' ' ) && !strcmp( paramName.c_str(), aSubparam.c_str() ) )
2259 readTypMinMaxValue( aDest );
2260 else
2261 status = false;
2262 }
2263 else
2264 {
2265 status = false;
2266 }
2267
2268 return status;
2269}
2270
2272{
2273 bool status = true;
2274 std::string subparam;
2275
2276 if( readWord( subparam ) )
2277 {
2278 switch( m_continue )
2279 {
2281
2282 if( !strcmp( subparam.substr( 0, 10 ).c_str(), "Model_type" ) )
2283 {
2284 if( readWord( subparam ) )
2285 {
2286 if( compareIbisWord( subparam.c_str(), "Input" ) )
2288 else if( compareIbisWord( subparam.c_str(), "Output" ) )
2290 else if( compareIbisWord( subparam.c_str(), "I/O" ) )
2292 else if( compareIbisWord( subparam.c_str(), "3-state" ) )
2294 else if( compareIbisWord( subparam.c_str(), "Open_drain" ) )
2296 else if( compareIbisWord( subparam.c_str(), "I/O_Open_drain" ) )
2298 else if( compareIbisWord( subparam.c_str(), "Open_sink" ) )
2300 else if( compareIbisWord( subparam.c_str(), "I/O_open_sink" ) )
2302 else if( compareIbisWord( subparam.c_str(), "Open_source" ) )
2304 else if( compareIbisWord( subparam.c_str(), "I/O_open_source" ) )
2306 else if( compareIbisWord( subparam.c_str(), "Input_ECL" ) )
2308 else if( compareIbisWord( subparam.c_str(), "Output_ECL" ) )
2310 else if( compareIbisWord( subparam.c_str(), "I/O_ECL" ) )
2312 else if( compareIbisWord( subparam.c_str(), "3-state_ECL" ) )
2314 else if( compareIbisWord( subparam.c_str(), "Terminator" ) )
2316 else if( compareIbisWord( subparam.c_str(), "Series" ) )
2318 else if( compareIbisWord( subparam.c_str(), "Series_switch" ) )
2320 else
2321 {
2322 std::stringstream message;
2323 message << _( "Unknown Model_type " ) << subparam;
2324 Report( message.str(), RPT_SEVERITY_ERROR );
2325 status = false;
2326 }
2327 }
2328 else
2329 {
2330 Report( _( "Internal Error while reading model_type" ), RPT_SEVERITY_ERROR );
2331 status = false;
2332 }
2333 }
2334 else if( !strcmp( subparam.substr( 0, 7 ).c_str(), "Enable" ) )
2335 {
2336 if( readWord( subparam ) )
2337 {
2338 if( !strcmp( subparam.c_str(), "Active-High" ) )
2340 else if( !strcmp( subparam.c_str(), "Active-Low" ) )
2342 else
2343 {
2344 std::stringstream message;
2345 message << _( "Unknown Enable: " ) << subparam;
2346 Report( message.str(), RPT_SEVERITY_ERROR );
2347 status = false;
2348 }
2349 }
2350 else
2351 {
2352 Report( _( "Internal Error while reading Enable" ), RPT_SEVERITY_ERROR );
2353 status = false;
2354 }
2355 }
2356 else if( subparam.substr( 0, 9 ) == "Polarity" )
2357 {
2358 if( readWord( subparam ) )
2359 {
2360 if( subparam == "Inverting" )
2362 else if( subparam == "Non-Inverting" )
2364 else
2365 {
2366 std::stringstream message;
2367 message << _( "Unknown polarity " ) << subparam;
2368 Report( message.str(), RPT_SEVERITY_ERROR );
2369 status = false;
2370 }
2371 }
2372 else
2373 {
2374 Report( _( "Internal Error while reading Enable" ), RPT_SEVERITY_ERROR );
2375 status = false;
2376 }
2377 }
2378 else if( readNumericSubparam( std::string( "Vinl" ), m_currentModel->m_vinl ) )
2379 ;
2380 else if( readNumericSubparam( std::string( "Vinh" ), m_currentModel->m_vinh ) )
2381 ;
2382 else if( readNumericSubparam( std::string( "Vref" ), m_currentModel->m_vref ) )
2383 ;
2384 else if( readNumericSubparam( std::string( "Rref" ), m_currentModel->m_rref ) )
2385 ;
2386 else if( readNumericSubparam( std::string( "Cref" ), m_currentModel->m_cref ) )
2387 ;
2388 else if( readNumericSubparam( std::string( "Vmeas" ), m_currentModel->m_vmeas ) )
2389 ;
2390 else if( readTypMinMaxValueSubparam( std::string( "C_comp" ), m_currentModel->m_C_comp ) )
2391 ;
2392 else if( readTypMinMaxValueSubparam( std::string( "C_comp_gnd_clamp" ),
2393 m_currentModel->m_C_comp_gnd_clamp ) )
2394 ;
2395 else if( readTypMinMaxValueSubparam( std::string( "C_comp_power_clamp" ),
2396 m_currentModel->m_C_comp_power_clamp ) )
2397 ;
2398 else if( readTypMinMaxValueSubparam( std::string( "C_comp_pullup" ),
2399 m_currentModel->m_C_comp_pullup ) )
2400 ;
2401 else if( readTypMinMaxValueSubparam( std::string( "C_comp_pulldown" ),
2402 m_currentModel->m_C_comp_pulldown ) )
2403 ;
2404 else
2405 status = false;
2406
2408
2409 break;
2410
2411 default:
2412 status = false;
2413 Report( _( "Continued reading a model that did not begin. ( internal error )" ),
2415 }
2416 }
2417
2418 return status;
2419}
2420
2421
2423{
2424 bool status = true;
2425
2426 std::string subparam;
2427 if( readWord( subparam ) )
2428 {
2429 if( !strcmp( subparam.c_str(), "Submodel_type" ) )
2430 {
2431 if( readWord( subparam ) )
2432 {
2433 if( !strcmp( subparam.c_str(), "Dynamic_clamp" ) )
2435 else if( !strcmp( subparam.c_str(), "Bus_hold" ) )
2437 else if( !strcmp( subparam.c_str(), "Fall_back" ) )
2439 else
2440 {
2441 std::stringstream message;
2442 message << subparam << _( " is not a recognised submodel type." );
2443 Report( message.str(), RPT_SEVERITY_ERROR );
2444 status = false;
2445 }
2446 }
2447 else
2448 {
2449 Report( _( "The Submodel_type value is missing." ), RPT_SEVERITY_ERROR );
2450 status = false;
2451 }
2452 }
2453 else
2454 {
2455 std::stringstream message;
2456 message << subparam << _( " is not a recognised Submodel subparameter." );
2457 Report( message.str(), RPT_SEVERITY_ERROR );
2458 status = false;
2459 }
2460 }
2461
2462 return status;
2463}
2464
2465
2466bool IbisParser::parseHeader( std::string& aKeyword )
2467{
2468 bool status = true;
2469
2470 if( compareIbisWord( aKeyword.c_str(), "IBIS_Ver" ) )
2471 {
2472 status &= readDouble( m_ibisFile.m_header.m_ibisVersion );
2473 }
2474 else if( compareIbisWord( aKeyword.c_str(), "Comment_char" ) )
2475 {
2476 status &= changeCommentChar();
2477 }
2478 else if( compareIbisWord( aKeyword.c_str(), "File_Name" ) )
2479 {
2480 status &= storeString( m_ibisFile.m_header.m_fileName, false );
2481 }
2482 else if( compareIbisWord( aKeyword.c_str(), "File_Rev" ) )
2483 {
2484 status &= readDouble( m_ibisFile.m_header.m_fileRevision );
2485 }
2486 else if( compareIbisWord( aKeyword.c_str(), "Source" ) )
2487 {
2488 status &= storeString( m_ibisFile.m_header.m_source, true );
2489 }
2490 else if( compareIbisWord( aKeyword.c_str(), "Notes" ) )
2491 {
2492 status &= storeString( m_ibisFile.m_header.m_notes, true );
2493 }
2494 else if( compareIbisWord( aKeyword.c_str(), "Disclaimer" ) )
2495 {
2496 status &= storeString( m_ibisFile.m_header.m_disclaimer, true );
2497 }
2498 else if( compareIbisWord( aKeyword.c_str(), "Copyright" ) )
2499 {
2500 status &= storeString( m_ibisFile.m_header.m_copyright, true );
2501 }
2502 else if( compareIbisWord( aKeyword.c_str(), "Date" ) )
2503 {
2504 status &= storeString( m_ibisFile.m_header.m_date, false );
2505 }
2506 else if( !changeContext( aKeyword ) )
2507 {
2508 status = false;
2509 }
2510
2511 return status;
2512}
2513
2514
2515bool IbisParser::parseComponent( std::string& aKeyword )
2516{
2517 bool status = true;
2518
2519 if( compareIbisWord( aKeyword.c_str(), "Manufacturer" ) )
2520 {
2521 status &= storeString( m_currentComponent->m_manufacturer, true );
2522 }
2523 else if( compareIbisWord( aKeyword.c_str(), "Package" ) )
2524 {
2525 status &= readPackage();
2526 }
2527 else if( compareIbisWord( aKeyword.c_str(), "Pin" ) )
2528 {
2529 status &= readPin();
2530 }
2531 else if( compareIbisWord( aKeyword.c_str(), "Pin_Mapping" ) )
2532 {
2533 status &= readPinMapping();
2534 }
2535 else if( compareIbisWord( aKeyword.c_str(), "Diff_Pin" ) )
2536 {
2537 status &= readDiffPin();
2538 }
2539 /*
2540 // Not supported yet
2541 else if( aKeyword == "Die_Supply_Pads" )
2542 {
2543 status &= ReadDieSupplyPads();
2544 }*/
2545 else if( compareIbisWord( aKeyword.c_str(), "Package_Model" ) )
2546 {
2547 status &= storeString( m_currentComponent->m_packageModel, true );
2548 }
2549 else if( !changeContext( aKeyword ) )
2550 {
2551 status = false;
2552 }
2553
2554 return status;
2555}
2556
2557bool IbisParser::readTableLine( std::vector<std::string>& aDest )
2558{
2559 aDest.clear();
2560
2561 while( m_lineIndex < m_lineLength )
2562 {
2563 std::string str;
2564
2565 while( !isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
2566 str += m_buffer[m_lineOffset + m_lineIndex++];
2567
2568 if( str.size() > 0 )
2569 aDest.push_back( str );
2570
2571 while( isspace( m_buffer[m_lineOffset + m_lineIndex] ) && m_lineIndex < m_lineLength )
2572 m_lineIndex++;
2573 }
2574
2575 return true;
2576}
2577
2579{
2580 bool status = true;
2581
2582 std::vector<std::string> fields;
2583
2584 TypMinMaxValue* R = &( m_currentComponent->m_package.m_Rpkg );
2585 TypMinMaxValue* L = &( m_currentComponent->m_package.m_Lpkg );
2586 TypMinMaxValue* C = &( m_currentComponent->m_package.m_Cpkg );
2587
2588 readTableLine( fields );
2589
2590 int extraArg = ( m_continue == IBIS_PARSER_CONTINUE::NONE ) ? 1 : 0;
2591
2592 if( (int)fields.size() == ( 4 + extraArg ) )
2593 {
2594 TypMinMaxValue* cValue;
2595
2596 if( fields.at( 0 ) == "R_pkg" )
2597 cValue = R;
2598 else if( fields.at( 0 ) == "L_pkg" )
2599 cValue = L;
2600 else if( fields.at( 0 ) == "C_pkg" )
2601 cValue = C;
2602 else
2603 {
2604 Report( "Invalid field in [Package]" );
2605 return false;
2606 }
2607 status &= parseDouble( cValue->value[IBIS_CORNER::TYP], fields.at( 1 ), true );
2608 // Min / max values are optional, so don't update the status
2609 parseDouble( cValue->value[IBIS_CORNER::MIN], fields.at( 2 ), true );
2610 parseDouble( cValue->value[IBIS_CORNER::MAX], fields.at( 3 ), true );
2611 }
2612 else
2613 {
2614 if( fields.size() != 0 )
2615 {
2616 Report( _( "A [Package] line requires exactly 4 elements." ), RPT_SEVERITY_ERROR );
2617 status = false;
2618 }
2619 }
2620
2622
2623 return status;
2624}
2625
2626
2628{
2629 bool status = true;
2630
2631 std::vector<std::string> fields;
2632
2633 m_lineIndex = 0;
2634 status &= readTableLine( fields );
2635
2637
2638 if( ( fields.size() == 3 ) )
2639 {
2640 if( m_continue == IBIS_PARSER_CONTINUE::COMPONENT_PIN ) // No info on first line
2641 {
2642 pin.m_pinName = fields.at( 0 );
2643 pin.m_signalName = fields.at( 1 );
2644 pin.m_modelName = fields.at( 2 );
2645 pin.m_Rcol = m_currentComponent->m_pins.back().m_Rcol;
2646 pin.m_Lcol = m_currentComponent->m_pins.back().m_Lcol;
2647 pin.m_Ccol = m_currentComponent->m_pins.back().m_Ccol;
2648 }
2649 else
2650 {
2651 pin.m_dummy = true;
2652 }
2653 }
2654 else
2655 {
2656 if( m_continue == IBIS_PARSER_CONTINUE::COMPONENT_PIN ) // Not on the first line
2657 {
2658 pin.m_pinName = fields.at( 0 );
2659 pin.m_signalName = fields.at( 1 );
2660 pin.m_modelName = fields.at( 2 );
2661
2662 pin.m_Rcol = m_currentComponent->m_pins.back().m_Rcol;
2663 pin.m_Lcol = m_currentComponent->m_pins.back().m_Lcol;
2664 pin.m_Ccol = m_currentComponent->m_pins.back().m_Ccol;
2665
2666 if( pin.m_Rcol == 0 || pin.m_Lcol == 0 || pin.m_Ccol == 0 )
2667 {
2668 Report( _( "Invalid pin entry: 6 values from a table with only 3." ),
2670 status = false; // Did we just try to go from a 3 column table to a 6 ?
2671 }
2672 else
2673 {
2674 if( !parseDouble( pin.m_Rpin, fields.at( pin.m_Rcol ), true )
2675 || !parseDouble( pin.m_Lpin, fields.at( pin.m_Lcol ), true )
2676 || !parseDouble( pin.m_Cpin, fields.at( pin.m_Ccol ), true ) )
2677 {
2678 Report( _( "Can't read a R, L or C value for a pin." ), RPT_SEVERITY_ERROR );
2679 status = false;
2680 }
2681 }
2682 }
2683 else
2684 {
2685 for( int i = 3; i < 6; i++ )
2686 {
2687 if( fields.at( i ) == "R_pin" )
2688 {
2689 pin.m_Rcol = i;
2690 }
2691 else if( fields.at( i ) == "L_pin" )
2692 {
2693 pin.m_Lcol = i;
2694 }
2695 else if( fields.at( i ) == "C_pin" )
2696 {
2697 pin.m_Ccol = i;
2698 }
2699 else
2700 {
2701 Report( _( "Invalid field name in [Pin]" ), RPT_SEVERITY_ERROR );
2702 status = false;
2703 }
2704 }
2705
2706 if( pin.m_Rcol == 0 || pin.m_Lcol == 0 || pin.m_Ccol == 0 )
2707 {
2708 Report( _( "Missing argument in [Pin]" ), RPT_SEVERITY_ERROR );
2709 status = false;
2710 }
2711
2712 pin.m_dummy = true;
2713 }
2714 }
2715
2716 m_currentComponent->m_pins.push_back( pin );
2718
2719
2720 return status;
2721}
2722
2723
2725{
2726 bool status = true;
2727
2728 std::vector<std::string> fields;
2729
2730 status &= readTableLine( fields );
2731
2732 IbisComponentPinMapping pinMapping( m_Reporter );
2733
2734 if( m_continue == IBIS_PARSER_CONTINUE::NONE ) // No info on first line
2735 {
2737 }
2738 else
2739 {
2740 if( fields.size() != 0 )
2741 {
2742 if( fields.size() > 6 || fields.size() < 3 )
2743 {
2744 Report( _( "Wrong number of columns for pin mapping." ), RPT_SEVERITY_ERROR );
2745 status = false;
2746 }
2747 else
2748 {
2749 pinMapping.m_pinName = fields.at( 0 );
2750 pinMapping.m_PDref = fields.at( 1 );
2751 pinMapping.m_PUref = fields.at( 2 );
2752
2753 if( fields.size() > 3 )
2754 pinMapping.m_GNDClampRef = fields.at( 3 );
2755
2756 if( fields.size() > 4 )
2757 pinMapping.m_POWERClampRef = fields.at( 4 );
2758
2759 if( fields.size() > 5 )
2760 pinMapping.m_extRef = fields.at( 5 );
2761 }
2762 m_currentComponent->m_pinMappings.push_back( pinMapping );
2763 }
2764 }
2765
2766 return status;
2767}
2768
2769
2771{
2772 bool status = true;
2773
2774 m_lineIndex = 0; // rewind
2776
2777 if( m_continue == IBIS_PARSER_CONTINUE::NONE ) // No info on first line
2778 {
2780 }
2781 else
2782 {
2783 if( !readWord( entry.pinA ) )
2784 {
2785 Report( _( "Incorrect diff pin name" ), RPT_SEVERITY_ERROR );
2786 status = false;
2787 }
2788
2789 if( !readWord( entry.pinB ) )
2790 {
2791 Report( _( "Incorrect inv_pin name" ), RPT_SEVERITY_ERROR );
2792 status = false;
2793 }
2794
2795 if( status )
2796 m_currentComponent->m_diffPin.m_entries.push_back( entry );
2797 }
2798
2799 return status;
2800}
2801
2802
2804{
2805 bool status = true;
2806
2808
2809 IVtableEntry entry( m_Reporter );
2810
2812 {
2813 std::string str;
2814
2815 status &= readDouble( entry.V );
2816
2817 if( status && readTypMinMaxValue( entry.I ) )
2818 aDest.m_entries.push_back( entry );
2819 }
2820
2822 m_currentIVtable = &aDest;
2823
2824 return status;
2825}
2826
2828{
2829 bool status = true;
2831
2832 VTtableEntry entry( m_Reporter );
2833
2835 {
2836 std::string str;
2837 status &= readDouble( entry.t );
2838 status &= readTypMinMaxValue( entry.V );
2839 }
2840
2842 m_currentVTtable = &aDest;
2843
2844 if( status )
2845 aDest.m_entries.push_back( entry );
2846
2847 return status;
2848}
2849
2851{
2852 bool status = true;
2853
2854 IbisWaveform* wf;
2855
2857 {
2858 wf = new IbisWaveform( m_Reporter );
2859 wf->m_type = aType;
2860
2861 switch( m_context )
2862 {
2864 switch( aType )
2865 {
2867 m_currentModel->m_fallingWaveforms.push_back( wf );
2868 break;
2870 m_currentModel->m_risingWaveforms.push_back( wf );
2871 break;
2872 default:
2873 wxLogMessage( "Invalid waveform type: %i", (int) aType );
2874 status = false;
2875 }
2876 break;
2878 switch( aType )
2879 {
2881 m_currentSubmodel->m_fallingWaveforms.push_back( wf );
2882 break;
2884 m_currentSubmodel->m_risingWaveforms.push_back( wf );
2885 break;
2886 default:
2887 wxLogMessage( "Invalid waveform type: %i", (int) aType );
2888 status = false;
2889 }
2890 break;
2891 default:
2892 wxLogMessage( "Invalid context for waveform: %i", (int) m_context );
2893 return false;
2894 }
2895 }
2896 else
2897 {
2898 if( aDest != nullptr )
2899 {
2900 wf = aDest;
2901 }
2902 else
2903 {
2904 Report( _( "Internal error detected, a waveform should exist" ), RPT_SEVERITY_ERROR );
2905 return false;
2906 }
2907 }
2908
2909
2910 if( status & !isLineEmptyFromCursor() )
2911 {
2912 // readNumericSubparam() returns true if it could read the subparameter and store it
2913 // Testing all subparameters
2914 if( readNumericSubparam( std::string( "R_fixture" ), wf->m_R_fixture ) )
2915 ;
2916 else if( readNumericSubparam( std::string( "L_fixture" ), wf->m_L_fixture ) )
2917 ;
2918 else if( readNumericSubparam( std::string( "C_fixture" ), wf->m_C_fixture ) )
2919 ;
2920 else if( readNumericSubparam( std::string( "V_fixture" ), wf->m_V_fixture ) )
2921 ;
2922 else if( readNumericSubparam( std::string( "V_fixture_min" ), wf->m_V_fixture_min ) )
2923 ;
2924 else if( readNumericSubparam( std::string( "V_fixture_max" ), wf->m_V_fixture_max ) )
2925 ;
2926 else if( readNumericSubparam( std::string( "R_dut" ), wf->m_R_fixture ) )
2927 ;
2928 else if( readNumericSubparam( std::string( "L_dut" ), wf->m_L_fixture ) )
2929 ;
2930 else if( readNumericSubparam( std::string( "C_dut" ), wf->m_C_fixture ) )
2931 ;
2932 // The line is not a subparameter, then let's try to read a VT table entry
2933 else if( !readVTtableEntry( m_currentWaveform->m_table ) )
2934 status = false;
2935 }
2936
2937 m_currentWaveform = wf;
2939 return status;
2940}
2941
2943{
2944 bool status = true;
2945 char c;
2946 std::string keyword = getKeyword();
2947
2948 if( keyword.size() > 0 ) // New keyword
2949 {
2952
2953 switch( m_context )
2954 {
2956 status &= parseHeader( keyword );
2957 break;
2959 status &= parseComponent( keyword );
2960 break;
2962 status &= parseModelSelector( keyword );
2963 break;
2965 status &= parseModel( keyword );
2966 break;
2968 status &= parseSubmodel( keyword );
2969 break;
2971 status &= parsePackageModel( keyword );
2972 break;
2974 status &= parsePackageModelModelData( keyword );
2975 break;
2977 status &= parseAlgorithmicModel( keyword );
2978 break;
2979 default:
2980 status = false;
2981 Report( _( "Internal error: Bad parser context." ), RPT_SEVERITY_ERROR );
2982 }
2983 }
2984 else
2985 {
2987 if( m_lineIndex == m_lineLength )
2988 {
2989 // That was an empty line
2990 return true;
2991 }
2992
2993 // No new keyword ? Then it is the continuation of the previous one !
2994 switch( m_continue )
2995 {
2998 *m_continuingString += '\n';
2999 status &= readString( *m_continuingString );
3000 break;
3002 status &= readPackage();
3003 break;
3005 status &= readPin();
3006 break;
3008 status &= readPinMapping();
3009 break;
3011 status &= readDiffPin();
3012 break;
3014 status &= readModelSelector();
3015 break;
3017 status &= readModel();
3018 break;
3020 status &= readSubmodel();
3021 break;
3023 status &= readIVtableEntry( *m_currentIVtable );
3024 break;
3026 status &= readVTtableEntry( *m_currentVTtable );
3027 break;
3029 status &= readWaveform( m_currentWaveform, m_currentWaveform->m_type );
3030 break;
3032 status &= readRamp();
3033 break;
3035 status &= readModelSpec();
3036 break;
3038 status &= readReceiverThresholds();
3039 break;
3041 status &= readAlgorithmicModel();
3042 break;
3044 status &= readAddSubmodel();
3045 break;
3047 status &= readSubmodelSpec();
3048 break;
3050 status &= readPackageModelPins();
3051 break;
3053 status &= readMatrixData();
3054 break;
3056 default:
3057 Report( _( "Missing keyword." ), RPT_SEVERITY_ERROR );
3058 return false;
3059 break;
3060 }
3061 }
3062
3064
3065 while( ( c != '\n' ) && ( c != 0 ) ) // Go to the end of line
3067
3068 return status;
3069}
int index
const char * name
void Report(const std::string &aMsg, SEVERITY aSeverity=RPT_SEVERITY_INFO) const
Print a message.
Definition ibis_parser.h:68
REPORTER * m_Reporter
Definition ibis_parser.h:75
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
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
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
IVtable m_GNDClamp
IbisRamp m_ramp
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 parseDvdt(dvdt &aDest, std::string &aStr)
Parse a dV/dt value according to the ibis standard.
IbisPackageModel * m_currentPackageModel
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 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)
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()
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
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
KIBIS_PIN * pin
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.