# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl Parse-Liberty.t'
#########################
use Test::More tests => 95;
BEGIN { use_ok('Parse::Liberty') };
#########################
use strict;
# check if $expr true for every element in @list
sub forall (&@) {
my $expr = shift;
my @list = @_;
foreach (@list) { return 0 if !&{$expr} }
return 1;
}
# check if ->isa($str) true for every element in @list
sub isa_all {
my $str = shift;
my @list = @_;
return forall {$_->isa($str)} @list;
}
my $indent = 4;
my $file = "test.lib";
my ($attr, $def, $g, @vals, $val);
#### Liberty.pm tests ##########################################################
my $parser = new Parse::Liberty (verbose=>0, indent=>$indent, file=>$file);
isa_ok($parser, 'Parse::Liberty');
can_ok($parser, 'new', 'methods', 'library');
### properties
ok($parser->{file} eq "test.lib",
"Parser 'file' property");
ok($parser->{indent} == 4,
"Parser 'indent' property");
ok($parser->{verbose} == 0,
"Parser 'verbose' property");
### common methods
ok($parser->methods eq "library\nwrite_library\n",
"Parser methods");
#### Group.pm tests ############################################################
my $library = $parser->library;
isa_ok($library, 'Parse::Liberty::Group');
can_ok($library, 'new', 'methods', 'lineno', 'comment', 'remove',
'type', 'get_names', 'set_names', 'get_attributes', 'get_defines', 'get_groups', 'extract');
### properties
ok($library->{object_type} eq 'group',
"Library 'object_type' property");
isa_ok($library->{parser}, 'Parse::Liberty');
isa_ok($library->{parent}, 'Parse::Liberty');
isa_ok($library->{si2_object}, 'liberty::si2ObjectIdT');
ok($library->{depth} == 0,
"Library 'depth' property");
### common methods
ok($library->methods eq "lineno\ncomment\nremove\ntype\nget_names\nset_names\nget_attributes\nget_defines\nget_groups\nextract\n",
"Library methods");
ok($library->lineno == 1,
"Library lineno");
ok(!defined $library->comment,
"Library comment");
### methods
ok($library->type eq 'library',
"Library type");
ok($library->get_names eq 'test1',
"Library name");
ok($library->set_names('testlib') == 1,
"Library set new name");
ok($library->get_names eq 'testlib',
"Library get new name");
my @attrs;
@attrs = $library->get_attributes;
ok($#attrs == 8 && isa_all('Parse::Liberty::Attribute', @attrs),
"Library get all attributes");
@attrs = $library->get_attributes('delay_model', 'FANOUT');
ok($#attrs == 1 && isa_all('Parse::Liberty::Attribute', @attrs),
"Library get two attributes");
@attrs = $library->get_attributes('FAN.*T', '.*_unit');
ok($#attrs == 4 && isa_all('Parse::Liberty::Attribute', @attrs),
"Library get attributes by regex");
$attr = $library->get_attributes('technology');
ok($attr->isa('Parse::Liberty::Attribute'),
"Library get one attribute");
my @defs;
@defs = $library->get_defines;
ok($#defs == 3 && isa_all('Parse::Liberty::Define', @defs),
"Library get all defines");
@defs = $library->get_defines('sec_acore_internal_power', 'sec_acore_when');
ok($#defs == 1 && isa_all('Parse::Liberty::Define', @defs),
"Library get two defines");
@defs = $library->get_defines('.*when.*', '.*l_power');
ok($#defs == 2 && isa_all('Parse::Liberty::Define', @defs),
"Library get defines by regex");
$def = $library->get_defines('sec_acore_rise_power');
ok($def->isa('Parse::Liberty::Define'),
"Library get one define");
my @gps;
@gps = $library->get_groups;
ok($#gps == 5 && isa_all('Parse::Liberty::Group', @gps),
"Library get all groups");
@gps = $library->get_groups('cell');
ok($#gps == 4 && isa_all('Parse::Liberty::Group', @gps),
"Library get all groups by type");
@gps = $library->get_groups('cell', 'cell5', 'cell2');
ok($#gps == 1 && isa_all('Parse::Liberty::Group', @gps),
"Library get two groups by type and name");
@gps = $library->get_groups('cell', 'c.*5', '.*[1-3]');
ok($#gps == 3 && isa_all('Parse::Liberty::Group', @gps),
"Library get groups by type and regex");
$g = $library->get_groups('lu_table_template', 'dti_delay_drivex1_5x7');
ok($g->isa('Parse::Liberty::Group'),
"Library get one group by type and name");
#### Attribute.pm tests ########################################################
$attr = $library->get_attributes('nom_temperature'); # first, get simple attribute
isa_ok($attr, 'Parse::Liberty::Attribute');
can_ok($attr, 'new', 'methods', 'lineno', 'comment', 'remove',
'type', 'name', 'is_var', 'get_values', 'set_values', 'extract');
### properties
ok($attr->{object_type} eq 'attribute',
"Attribute 'object_type' property");
isa_ok($attr->{parser}, 'Parse::Liberty');
isa_ok($attr->{parent}, 'Parse::Liberty::Group');
isa_ok($attr->{si2_object}, 'liberty::si2ObjectIdT');
ok($attr->{depth} == 1,
"Attribute 'depth' property");
### common methods
ok($attr->methods eq "lineno\ncomment\nremove\ntype\nname\nis_var\nget_values\nset_values\nextract\n",
"Attribute methods");
ok($attr->lineno == 10,
"Attribute lineno");
ok($attr->comment eq '0',
"Attribute comment");
### methods
ok($attr->type eq 'simple', # strange, but this still works after $attr->remove
"Attribute type");
ok($attr->name eq 'nom_temperature', # but this not
"Attribute name");
## simple
ok($attr->is_var == 0,
"Simple attribute is not a variable declaration");
@vals = $attr->get_values;
ok($#vals == 0 && $vals[0]->type eq 'integer' && $vals[0]->value == 25,
"Simple attribute get all values");
$val = $attr->get_values;
ok($val->type eq 'integer' && $val->value == 25,
"Simple attribute get first value");
ok($attr->set_values('boolean', 0, 'string', "abc", 'float', 1.23) == 1, # boolean value must be set as integer >=0
"Simple attribute set new values (always first value only)");
@vals = $attr->get_values;
ok($#vals == 0 # but 'get' on boolean value give 'false' or 'true' as in .lib
&& $vals[0]->type eq 'boolean' && $vals[0]->value eq 'false',
"Simple attribute get new value");
ok($attr->extract eq "/*0*/\n".' 'x$indent."nom_temperature : false ;\n",
"Simple attribute extract");
## complex
$attr = $library->get_attributes('capacitive_load_unit'); # get complex attribute
ok($attr->is_var == 0,
"Complex attribute cannot be a variable declaration");
@vals = $attr->get_values;
ok($#vals == 1
&& $vals[0]->type eq 'integer' && $vals[0]->value == 1
&& $vals[1]->type eq 'string' && $vals[1]->value eq "pf",
"Complex attribute get all values");
$val = $attr->get_values;
ok($val->type eq 'integer' && $val->value == 1,
"Complex attribute get first value");
ok($attr->set_values('boolean', 0, 'string', "abc", 'float', 1.23) == 1,
"Complex attribute set new values");
@vals = $attr->get_values;
ok($#vals == 2
&& $vals[0]->type eq 'boolean' && $vals[0]->value eq 'false'
&& $vals[1]->type eq 'string' && $vals[1]->value eq "abc"
&& $vals[2]->type eq 'float' && $vals[2]->value == 1.23,
"Complex attribute get new values");
ok($attr->extract eq ' 'x$indent."capacitive_load_unit (false, abc, 1.23) ;\n",
"Complex attribute extract");
## variable declaration
$attr = $library->get_attributes('FANOUT');
ok($attr->is_var == 1,
"Simple variable attribute is variable declaration");
@vals = $attr->get_values;
ok($#vals == 0
&& $vals[0]->type eq 'integer' && $vals[0]->value == 5,
"Simple variable attribute get all values");
$val = $attr->get_values;
ok($val->type eq 'integer' && $val->value == 5,
"Simple variable attribute get first value");
ok($attr->set_values('boolean', 0, 'string', "abc", 'float', 1.23) == 1,
"Simple variable attribute set new values (always first value only)");
@vals = $attr->get_values;
ok($#vals == 0
&& $vals[0]->type eq 'boolean' && $vals[0]->value eq 'false',
"Simple variable attribute get new value");
ok($attr->extract eq ' 'x$indent."FANOUT = false ;\n",
"Simple variable attribute extract");
ok($attr->remove == 1 && !defined $library->get_attributes('FANOUT'),
"Attribute remove");
#### Define.pm tests ###########################################################
$def = $library->get_defines('sec_acore_rise_power');
isa_ok($def, 'Parse::Liberty::Define');
can_ok($def, 'new', 'methods', 'lineno', 'comment', 'remove',
'type', 'name', 'allowed_group_name', 'extract');
### properties
ok($def->{object_type} eq 'define',
"Define 'object_type' property");
isa_ok($def->{parser}, 'Parse::Liberty');
isa_ok($def->{parent}, 'Parse::Liberty::Group');
isa_ok($def->{si2_object}, 'liberty::si2ObjectIdT');
ok($def->{depth} == 1,
"Define 'depth' property");
### common methods
ok($def->methods eq "lineno\ncomment\nremove\ntype\nname\nallowed_group_name\nextract\n",
"Define methods");
ok($def->lineno == 15,
"Define lineno");
ok(!defined $def->comment,
"Define comment");
### methods
ok($def->type eq 'float',
"Define type");
ok($def->name eq 'sec_acore_rise_power',
"Define name");
ok($def->allowed_group_name eq 'sec_acore_internal_power',
"Define allowed group name");
ok($def->extract eq ' 'x$indent."define (sec_acore_rise_power, sec_acore_internal_power, float) ;\n",
"Define extract");
ok($def->remove == 1 && !defined $library->get_defines('sec_acore_rise_power'),
"Define remove");
#### Value.pm tests ############################################################
$attr = $library->get_attributes('default_max_transition'); # first, get simple attribute
$val = $attr->get_values;
isa_ok($val, 'Parse::Liberty::Value');
can_ok($val, 'new', 'methods', 'type', 'value');
### properties
ok($val->{object_type} eq 'value',
"Value 'object_type' property");
isa_ok($val->{parser}, 'Parse::Liberty');
isa_ok($val->{parent}, 'Parse::Liberty::Attribute');
### simple attribute value properties
ok(!defined $val->{si2_object},
"Simple attribute value 'si2_object' property (always undefined)");
### simple attribute value methods
ok($val->type eq 'float',
"Simple attribute value type");
ok($val->value == 2.4,
"Simple attribute value value");
### complex attribute value properties
$attr = $library->get_attributes('technology'); # get complex attribute
$val = $attr->get_values;
isa_ok($val->{si2_object}, '_p_si2drAttrComplexValIdT');
## complex attribute value methods
ok($val->type eq 'string',
"Complex attribute value type");
ok($val->value eq "cmos",
"Complex attribute value value");
### common methods
ok($val->methods eq "type\nvalue\n",
"Value methods");
#### Group extract, remove and liberty extract #################################
my $cell = $library->get_groups('cell', 'cell2');
ok($cell->extract eq "/* cell */\n".' 'x$indent."cell (cell2) {\n".' 'x 2 x$indent."area : 777.88 ;\n".' 'x$indent."}\n",
"Group extract");
ok($cell->remove == 1,
"Group remove");
ok($library->extract eq join('', <DATA>),
"Extract full library ");
__DATA__
library (testlib) {
technology (cmos) ;
/* 0 */
delay_model : table_lookup ;
time_unit : 1ns ;
voltage_unit : 1V ;
current_unit : 1uA ;
/*0*/
nom_temperature : false ;
capacitive_load_unit (false, abc, 1.23) ;
define_group (sec_acore_internal_power, pin) ;
define (sec_acore_fall_power, sec_acore_internal_power, float) ;
define (sec_acore_when, sec_acore_internal_power, string) ;
/* declaration */
default_max_transition : 2.4 ;
lu_table_template (dti_delay_drivex1_5x7) {
variable_1 : input_net_transition ;
variable_2 : total_output_net_capacitance ;
index_1 ("0.0020, 0.0100, 0.0300, 0.0650, 0.1400") ;
index_2 ("0.0003, 0.0030, 0.0100, 0.0300, 0.0950, 0.1700, 0.3000") ;
}
cell (cell1) {
area : 456 ;
ff (NET0108_5, NET078_4) {
next_state : "((SE SI) + (!SE D))" ;
clocked_on : "CK" ;
clear : "(!RN)" ;
}
statetable ("CLK E SE", enl) {
table : "H L L : - : L ,\
H L H : - : H ,\
H H L : - : H ,\
H H H : - : H ,\
L - - : - : N " ;
}
pin (TST) {
direction : input ;
capacitance : 0.1 ;
sec_acore_internal_power (TST) {
sec_acore_rise_power : 1000 ;
sec_acore_fall_power : 0 ;
sec_acore_when : "CNT' " ;
}
sec_acore_internal_power (TST) {
sec_acore_rise_power : 1000 ;
sec_acore_fall_power : 0 ;
sec_acore_when : "CNT " ;
}
}
pin (TST2) {
direction : inout ;
capacitance : 0.2 ;
sec_acore_internal_power (TST) {
sec_acore_rise_power : 1000 ;
sec_acore_fall_power : 0 ;
sec_acore_when : "CNT' " ;
}
sec_acore_internal_power (TST1) {
sec_acore_rise_power : 1000 ;
sec_acore_fall_power : 0 ;
sec_acore_when : CNT ;
}
}
pin (TST3) {
direction : output ;
function : "TST" ;
capacitance : 0.3 ;
max_fanout : FANOUT * 2 ;
/* usage, here max_fanout : 10 */
sec_acore_internal_power (TST) {
sec_acore_rise_power : 1000 ;
}
timing () {
related_pin : TST ;
timing_sense : positive_unate ;
cell_rise (dti_delay_drivex1_5x7) {
values ( \
"0.0111, 0.0164, 0.0277, 0.0587, 0.1607, 0.2785, 0.4858", \
"0.0131, 0.0185, 0.0297, 0.0608, 0.1627, 0.2813, 0.4814", \
"0.0163, 0.0219, 0.0330, 0.0641, 0.1663, 0.2839, 0.4950", \
"0.0196, 0.0255, 0.0371, 0.0683, 0.1701, 0.2885, 0.4904", \
"0.0351, 0.0458, 0.0652, 0.1059, 0.2140, 0.3333, 0.5357" \
) ;
}
rise_transition (dti_delay_drivex1_5x7) {
values ( \
"1.0111, 1.0164, 1.0277, 1.0587, 1.1607, 1.2785, 1.4858", \
"1.0131, 1.0185, 1.0297, 1.0608, 1.1627, 1.2813, 1.4814", \
"1.0163, 1.0219, 1.0330, 1.0641, 1.1663, 1.2839, 1.4950", \
"1.0196, 1.0255, 1.0371, 1.0683, 1.1701, 1.2885, 1.4904", \
"1.0351, 1.0458, 1.0652, 1.1059, 1.2140, 1.3333, 1.5357" \
) ;
}
}
}
}
cell (cell3) {
define (cell3_define, sec_acore_internal_power, string) ;
}
cell (cell4) {
pin (A) {
}
}
cell (cell5) {
}
}