#![cfg(test)]
use simple_logger::SimpleLogger;
use crate::{
DefaultCtx,
ast::{AttriValues, SimpleDefined},
common::f64_eq,
};
use super::*;
fn parse_cmp(text: &str, want: &str) -> Library<DefaultCtx> {
match Library::parse_lib(text, None) {
Ok(mut library) => {
library.comments_this_entry().or_insert("test".into());
let s = library.to_string();
println!("{s}");
dev_utils::text_diff(&s, want);
library
}
Err(e) => panic!("{e}"),
}
}
fn fmt_cmp(library: &Library<DefaultCtx>, want: &str) {
let s = library.to_string();
println!("{s}");
dev_utils::text_diff(&s, want);
}
#[test]
fn define() {
let library = parse_cmp(
r#"
library(define) {
define(my_define_float, library, float);
define(my_define_bool, library, boolean);
define(my_define_str, library, string);
define(my_define_integer, cell, integer);
my_define_float: 1;
my_define_float: 2;
my_define_float: 3;
my_define_float: 4;
my_define_float: abc;
my_define_bool: true;
my_define_bool: abc;
my_define_bool: false;
my_define_str: "abc";
cell (test1) {
my_define_integer: 1;
my_define_integer: 2;
my_define_integer: 3;
my_define_integer: 4;
}
}"#,
r#"** test
library (define) {
| define (my_define_bool, library, boolean);
| define (my_define_float, library, float);
| define (my_define_integer, cell, integer);
| define (my_define_str, library, string);
| delay_model : table_lookup;
| time_unit : 1ns;
| voltage_unit : 1V;
| slew_upper_threshold_pct_rise : 80.0;
| slew_lower_threshold_pct_rise : 20.0;
| slew_derate_from_library : 1.0;
| slew_lower_threshold_pct_fall : 20.0;
| slew_upper_threshold_pct_fall : 80.0;
| input_threshold_pct_fall : 50.0;
| input_threshold_pct_rise : 50.0;
| output_threshold_pct_rise : 50.0;
| output_threshold_pct_fall : 50.0;
| my_define_bool : true; /* user defined attribute */
| my_define_bool : abc; /* user defined attribute */
| my_define_bool : false; /* user defined attribute */
| my_define_float : 1.0; /* user defined attribute */
| my_define_float : 2.0; /* user defined attribute */
| my_define_float : 3.0; /* user defined attribute */
| my_define_float : 4.0; /* user defined attribute */
| my_define_float : abc; /* user defined attribute */
| my_define_str : abc; /* user defined attribute */
| cell (test1) {
| | my_define_integer : 1; /* user defined attribute */
| | my_define_integer : 2; /* user defined attribute */
| | my_define_integer : 3; /* user defined attribute */
| | my_define_integer : 4; /* user defined attribute */
| }
}
"#,
);
let cell_test1 = library.cell.get("test1").unwrap();
println!("{:?}", library.attributes);
println!("{:?}", cell_test1.attributes);
assert_eq!(
&library.attributes["my_define_float"],
&AttriValues::Simple(SimpleDefined::Float(vec![
Ok(1.0),
Ok(2.0),
Ok(3.0),
Ok(4.0),
Err("abc".into()),
]))
);
assert_eq!(
&library.attributes["my_define_bool"],
&AttriValues::Simple(SimpleDefined::Boolean(vec![
Ok(true),
Err("abc".into()),
Ok(false),
]))
);
assert_eq!(
&library.attributes["my_define_str"],
&AttriValues::Simple(SimpleDefined::String(vec!["abc".into()]))
);
assert_eq!(
&cell_test1.attributes["my_define_integer"],
&AttriValues::Simple(SimpleDefined::Integer(vec![Ok(1), Ok(2), Ok(3), Ok(4),]))
);
}
#[test]
fn comment() {
let mut library = Library::default();
library.comments_this_entry().or_insert("comment1".into());
library
.comments_this_entry()
.and_modify(|comment| comment.push_str("\ncomment2\ncomment3"));
library.technology = Some(Technology::CMOS);
library.comments_technology_entry().or_insert("comment1".into());
library
.comments_technology_entry()
.and_modify(|comment| comment.push_str("\ncomment2\ncomment3"));
library
.comments_time_unit_entry()
.or_insert("one line comment".into());
let mut cell_test1 = Cell::default();
cell_test1.name = "test1".into();
cell_test1.comments_this_entry().or_insert("comment1".into());
cell_test1
.comments_this_entry()
.and_modify(|comment| comment.push_str("\ncomment2\ncomment3"));
library.cell.insert(cell_test1);
library.cell = library.cell.into_iter().collect();
fmt_cmp(
&library,
r#"/** comment1
*** comment2
*** comment3 */
library (undefined) {
| /* comment1
| ** comment2
| ** comment3 */
| technology (cmos);
| delay_model : table_lookup;
| * one line comment
| time_unit : 1ns;
| voltage_unit : 1V;
| slew_upper_threshold_pct_rise : 80.0;
| slew_lower_threshold_pct_rise : 20.0;
| slew_derate_from_library : 1.0;
| slew_lower_threshold_pct_fall : 20.0;
| slew_upper_threshold_pct_fall : 80.0;
| input_threshold_pct_fall : 50.0;
| input_threshold_pct_rise : 50.0;
| output_threshold_pct_rise : 50.0;
| output_threshold_pct_fall : 50.0;
| /* comment1
| ** comment2
| ** comment3 */
| cell (test1) {
| }
}
"#,
);
}
#[test]
fn serde() {
let text = r#"library (undefined) {
delay_model : table_lookup;
time_unit : 1ns;
voltage_unit : 1V;
slew_upper_threshold_pct_rise : 80.0;
slew_lower_threshold_pct_rise : 20.0;
slew_derate_from_library : 1.0;
slew_lower_threshold_pct_fall : 20.0;
slew_upper_threshold_pct_fall : 80.0;
input_threshold_pct_fall : 50.0;
input_threshold_pct_rise : 50.0;
output_threshold_pct_rise : 50.0;
output_threshold_pct_fall : 50.0;
cell (CELL1) {
area : 0.0;
}
cell (CELL2) {
area : 1.0;
}
}
"#;
let want = r#"** test
library (undefined) {
| delay_model : table_lookup;
| time_unit : 1ns;
| voltage_unit : 1V;
| slew_upper_threshold_pct_rise : 80.0;
| slew_lower_threshold_pct_rise : 20.0;
| slew_derate_from_library : 1.0;
| slew_lower_threshold_pct_fall : 20.0;
| slew_upper_threshold_pct_fall : 80.0;
| input_threshold_pct_fall : 50.0;
| input_threshold_pct_rise : 50.0;
| output_threshold_pct_rise : 50.0;
| output_threshold_pct_fall : 50.0;
| cell (CELL1) {
| | area : 0.0;
| }
| cell (CELL2) {
| | area : 1.0;
| }
}
"#;
let library = parse_cmp(text, want);
let config = bincode::config::standard()
.with_little_endian()
.with_fixed_int_encoding();
let serialized = bincode::serde::encode_to_vec(library, config).unwrap();
fmt_cmp(&bincode::serde::decode_from_slice(&serialized, config).unwrap().0, want);
}
#[test]
fn formula() {
let text = r#"library (test) {
voltage_map(VDD, 0.8);
voltage_map(TVDD, 0.8);
voltage_map(VDDDST, 0.8);
voltage_map(VDDGR, 0.8);
voltage_map(VDDSRC, 0.8);
voltage_map(VSS, 0);
input_voltage(cmos) {
vil : 0.3 * VDD + VSS;
vih : 0.7 * VDD + VSS;
vimin : -0.5 + VSS;
vimax : VDD + 0.5 + VSS;
}
}
"#;
let want = r#"** test
library (test) {
| delay_model : table_lookup;
| time_unit : 1ns;
| voltage_unit : 1V;
| voltage_map (TVDD, 0.8);
| voltage_map (VDD, 0.8);
| voltage_map (VDDDST, 0.8);
| voltage_map (VDDGR, 0.8);
| voltage_map (VDDSRC, 0.8);
| voltage_map (VSS, 0.0);
| slew_upper_threshold_pct_rise : 80.0;
| slew_lower_threshold_pct_rise : 20.0;
| slew_derate_from_library : 1.0;
| slew_lower_threshold_pct_fall : 20.0;
| slew_upper_threshold_pct_fall : 80.0;
| input_threshold_pct_fall : 50.0;
| input_threshold_pct_rise : 50.0;
| output_threshold_pct_rise : 50.0;
| output_threshold_pct_fall : 50.0;
| input_voltage (cmos) {
| | vil : 0.3 * VDD + VSS;
| | vih : 0.7 * VDD + VSS;
| | vimin : -0.5 + VSS;
| | vimax : VDD + 0.5 + VSS;
| }
}
"#;
dev_utils::init_logger();
let library = parse_cmp(text, want);
let cmos_input_voltage = library.input_voltage.get("cmos").unwrap();
assert!(f64_eq(cmos_input_voltage.vil.value.unwrap(), 0.24));
assert!(f64_eq(cmos_input_voltage.vimin.value.unwrap(), -0.5));
assert!(f64_eq(cmos_input_voltage.vimax.value.unwrap(), 1.3));
}
#[test]
fn included() {
let sense = crate::ast::test_parse_fmt_included::<Sensitization<DefaultCtx>>(
r#"pin_names ( IN1, IN2, OUT1 );
vector ( 1, "0 0 1" );
vector ( 2, "0 X 1" );
vector ( 3, "Z 0 1" );
vector ( 4, "1 1 0" );
"#,
r#"
liberty_db::library::items::Sensitization ("") {
| pin_names (IN1, IN2, OUT1);
| vector (1, "0 0 1");
| vector (2, "0 X 1");
| vector (3, "Z 0 1");
| vector (4, "1 1 0");
}"#,
);
}
#[test]
fn bus_type() {
let text = r#"library (test) {
type (BUS4) {
base_type : array ;
bit_from : 0 ;
bit_to : 3 ;
bit_width : 4 ;
data_type : bit ;
downto : false ;
}
cell (AND) {
bus (A) {
bus_type : BUS4 ;
}
}
}
"#;
let want = r#"** test
library (test) {
| delay_model : table_lookup;
| time_unit : 1ns;
| voltage_unit : 1V;
| slew_upper_threshold_pct_rise : 80.0;
| slew_lower_threshold_pct_rise : 20.0;
| slew_derate_from_library : 1.0;
| slew_lower_threshold_pct_fall : 20.0;
| slew_upper_threshold_pct_fall : 80.0;
| input_threshold_pct_fall : 50.0;
| input_threshold_pct_rise : 50.0;
| output_threshold_pct_rise : 50.0;
| output_threshold_pct_fall : 50.0;
| type (BUS4) {
| | base_type : array;
| | bit_from : 0;
| | bit_to : 3;
| | bit_width : 4;
| | data_type : bit;
| | downto : false;
| }
| cell (AND) {
| | bus (A) {
| | | bus_type : BUS4;
| | | scan_pin_inverted : false;
| | }
| }
}
"#;
dev_utils::init_logger();
let library = parse_cmp(text, want);
let cell = library.cell.get("AND").unwrap();
let bus = cell.bus.get("A").unwrap();
let bus_type = &bus.bus_type;
assert_eq!(bus_type.name, "BUS4");
let bus_type_ctx = bus_type.ctx.as_ref().unwrap();
assert_eq!(bus_type_ctx.bit_from, 0);
assert_eq!(bus_type_ctx.bit_to, 3);
assert_eq!(bus_type_ctx.bit_width, 4);
}