Updated the liberty parser to accept [A:B] ranges (AST has not been updated). Liberty...
authorNiels Moseley <n.a.moseley@moseleyinstruments.com>
Sun, 24 Mar 2019 21:54:18 +0000 (22:54 +0100)
committerNiels Moseley <n.a.moseley@moseleyinstruments.com>
Sun, 24 Mar 2019 21:54:18 +0000 (22:54 +0100)
passes/techmap/libparse.cc
passes/techmap/libparse.h
tests/liberty/.gitignore [new file with mode: 0644]
tests/liberty/busdef.lib [new file with mode: 0644]
tests/liberty/normal.lib [new file with mode: 0644]
tests/liberty/run-test.sh [new file with mode: 0755]
tests/liberty/semicolmissing.lib [new file with mode: 0644]
tests/liberty/small.v [new file with mode: 0644]

index 3927a657b3229654cb9a3208138376eb523c924d..878ca31605b65517217dd4f2f08eaf21a99298ac 100644 (file)
@@ -24,6 +24,7 @@
 #include <istream>
 #include <fstream>
 #include <iostream>
+#include <sstream>
 
 #ifndef FILTERLIB
 #include "kernel/log.h"
@@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
 {
        int c;
 
+    // eat whitespace
        do {
                c = f.get();
        } while (c == ' ' || c == '\t' || c == '\r');
 
-       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
+    // search for identifiers, numbers, plus or minus.
+       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
                str = c;
                while (1) {
                        c = f.get();
-                       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
+                       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
                                str += c;
                        else
                                break;
@@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
                }
        }
 
+    // if it wasn't an identifer, number of array range,
+    // maybe it's a string?
        if (c == '"') {
                str = "";
                while (1) {
@@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
                return 'v';
        }
 
+    // if it wasn't a string, perhaps it's a comment or a forward slash?
        if (c == '/') {
                c = f.get();
-               if (c == '*') {
+               if (c == '*') {         // start of '/*' block comment
                        int last_c = 0;
                        while (c > 0 && (last_c != '*' || c != '/')) {
                                last_c = c;
@@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
                                        line++;
                        }
                        return lexer(str);
-               } else if (c == '/') {
+               } else if (c == '/') {  // start of '//' line comment
                        while (c > 0 && c != '\n')
                                c = f.get();
                        line++;
@@ -144,9 +150,10 @@ int LibertyParser::lexer(std::string &str)
                }
                f.unget();
                // fprintf(stderr, "LEX: char >>/<<\n");
-               return '/';
+               return '/';             // a single '/' charater.
        }
 
+    // check for a backslash
        if (c == '\\') {
                c = f.get();
                if (c == '\r')
@@ -157,11 +164,15 @@ int LibertyParser::lexer(std::string &str)
                return '\\';
        }
 
+    // check for a new line
        if (c == '\n') {
                line++;
                return 'n';
        }
 
+    // anything else, such as ';' will get passed
+    // through as literal items.
+
        // if (c >= 32 && c < 255)
        //      fprintf(stderr, "LEX: char >>%c<<\n", c);
        // else
@@ -210,7 +221,12 @@ LibertyAst *LibertyParser::parse()
                                ast->value += str;
                                tok = lexer(str);
                        }
-                       if (tok == ';')
+            
+            // In a liberty file, all key : value pairs should end in ';'
+            // However, there are some liberty files in the wild that
+            // just have a newline. We'll be kind and accept a newline
+            // instead of the ';' too..
+                       if ((tok == ';') || (tok == 'n'))
                                break;
                        else
                                error();
@@ -225,6 +241,48 @@ LibertyAst *LibertyParser::parse()
                                        continue;
                                if (tok == ')')
                                        break;
+                
+                // FIXME: the AST needs to be extended to store
+                //        these vector ranges.
+                if (tok == '[')
+                {
+                    // parse vector range [A] or [A:B]
+                    std::string arg;
+                    tok = lexer(arg);
+                    if (tok != 'v')
+                    {
+                        // expected a vector array index
+                        error("Expected a number.");
+                    }
+                    else
+                    {
+                        // fixme: check for number A
+                    }
+                    tok = lexer(arg);
+                    // optionally check for : in case of [A:B]
+                    // if it isn't we just expect ']'
+                    // as we have [A]
+                    if (tok == ':')
+                    {
+                        tok = lexer(arg);
+                        if (tok != 'v')
+                        {
+                            // expected a vector array index
+                            error("Expected a number.");
+                        }
+                        else
+                        {
+                            // fixme: check for number B
+                            tok = lexer(arg);                            
+                        }
+                    }
+                    // expect a closing bracket of array range
+                    if (tok != ']')
+                    {
+                        error("Expected ']' on array range.");
+                    }
+                    continue;           
+                }
                                if (tok != 'v')
                                        error();
                                ast->args.push_back(arg);
@@ -255,6 +313,14 @@ void LibertyParser::error()
        log_error("Syntax error in liberty file on line %d.\n", line);
 }
 
+void LibertyParser::error(const std::string &str)
+{
+    std::stringstream ss;
+    ss << "Syntax error in liberty file on line " << line << ".\n";
+    ss << "  " << str << "\n";
+    log_error("%s", ss.str().c_str());
+}
+
 #else
 
 void LibertyParser::error()
@@ -263,6 +329,15 @@ void LibertyParser::error()
        exit(1);
 }
 
+void LibertyParser::error(const std::string &str)
+{
+    std::stringstream ss;
+    ss << "Syntax error in liberty file on line " << line << ".\n";
+    ss << "  " << str << "\n";
+    printf("%s", ss.str().c_str());
+    exit(1);
+}
+
 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
 
 #define CHECK_NV(result, check)                                      \
index cf632557081d1f4e71ddb2f326310694221c534e..c9ebd06c58e2e1b7223d8da5d7afcf8350d21e51 100644 (file)
@@ -46,9 +46,17 @@ namespace Yosys
                LibertyAst *ast;
                LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
                ~LibertyParser() { if (ast) delete ast; }
+        
+        /* lexer return values:
+           'v': identifier, string, array range [...] -> str holds the token string
+           'n': newline
+           anything else is a single character.
+        */
                int lexer(std::string &str);
-               LibertyAst *parse();
+               
+        LibertyAst *parse();
                void error();
+        void error(const std::string &str);
        };
 }
 
diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore
new file mode 100644 (file)
index 0000000..e6ec49c
--- /dev/null
@@ -0,0 +1,2 @@
+*.log
+test.ys
diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib
new file mode 100644 (file)
index 0000000..b5e3d50
--- /dev/null
@@ -0,0 +1,81 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 02-11-2018                      */
+/* Version: 1.0                             */
+/*                                          */
+/********************************************/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+    type( IO_bus_3_to_0 ) {
+        base_type : array ;
+        data_type : bit ;
+        bit_width : 4;
+        bit_from : 3 ;
+        bit_to : 0 ;
+        downto : true ;
+    }
+
+    cell (SRAM) {
+        area : 1 ;
+        memory() {
+            type : ram;
+            address_width : 4;
+            word_width : 4;
+        }
+        pin(CE1) {
+            direction : input;
+            capacitance : 0.021;
+            max_transition : 1.024;
+            switch_pin : true;
+        }
+        bus(I1)  {
+            bus_type : IO_bus_3_to_0 ;
+            direction : input;
+            pin (I1[3:0]) {
+                timing() {
+                    related_pin :   "CE1" ;
+                    timing_type : setup_rising ;
+                    rise_constraint (scalar) {
+                        values("0.0507786");
+                    }
+                    fall_constraint (scalar) {
+                        values("0.0507786");
+                    }
+                }
+            }
+        }
+    }
+
+} /* end */
diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib
new file mode 100644 (file)
index 0000000..1474e2b
--- /dev/null
@@ -0,0 +1,360 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 02-11-2018                      */
+/* Version: 1.0                             */
+/*                                          */
+/********************************************/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+  /* Inverter */
+  cell (inv) {
+    area : 1;
+    pin(A) {
+      direction : input;
+    }
+    
+    pin(Y) {
+      direction : output;
+      function : "A'";
+    }
+  }
+  
+  /* tri-state inverter */
+  cell (tri_inv) {
+    area : 4;
+    pin(A) {
+      direction : input;    
+    }
+    pin(S) {
+      direction : input;
+    }
+    pin(Z) {
+      direction : output;
+      function  : "A'";
+      three_State : "S'";
+    }
+  }
+  
+  cell (buffer) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(Y) {
+      direction : output;
+      function : "A";
+    }
+  }  
+  
+  /* 2-input NAND gate */
+  cell (nand2) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A * B)'";
+    }
+  }
+  
+  /* 2-input NOR gate */
+  cell (nor2) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A + B)'";
+    }
+  }
+  
+  /* 2-input XOR */
+  cell (xor2) {
+    area : 6;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A *B') + (A' * B)";
+    }
+  }
+  
+  /* 2-input inverting MUX */
+  cell (imux2) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(S) {
+      direction : input;
+    } 
+    pin(Y) {
+      direction: output;
+      function : "( (A * S) + (B * S') )'";
+    }
+  }
+  
+  /* D-type flip-flop with asynchronous reset and preset */
+  cell (dff) 
+  {
+    area : 6;
+    ff("IQ", "IQN") {
+      next_state : "D";
+      clocked_on : "CLK";
+      clear      : "RESET";
+      preset     : "PRESET";
+      clear_preset_var1 : L;
+      clear_preset_var2 : L;
+    } 
+    pin(D) {
+      direction : input;
+    }
+    pin(CLK) {
+      direction : input;
+    }
+    pin(RESET) {
+      direction : input;
+    }
+    pin(PRESET) {
+      direction : input;
+    }
+    pin(Q) {
+      direction: output;
+      function : "IQ";
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0; 
+        related_pin : "CLK";
+      }
+      timing () {
+        timing_type : clear;
+        timing_sense : positive_unate;
+        intrinsic_fall : 75;
+        related_pin : "RESET";
+      }
+      timing () {
+        timing_type : preset;
+        timing_sense : negative_unate;
+        intrinsic_rise : 75;
+        related_pin : "PRESET";
+      }      
+    }
+    pin(QN) {
+      direction: output;
+      function : "IQN";
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0; 
+        related_pin : "CLK";
+      }
+      timing () {
+        timing_type : preset;
+        timing_sense : negative_unate;
+        intrinsic_rise : 75;
+        related_pin : "RESET";
+      }
+      timing () {
+        timing_type : clear;
+        timing_sense : positive_unate;
+        intrinsic_fall : 75;
+        related_pin : "PRESET";
+      }      
+    } 
+  }
+
+  /* Latch */
+  cell(latch) {
+    area : 5;
+    latch ("IQ","IQN") {
+      enable : "G";
+      data_in : "D";
+    }
+
+    pin(D) {
+      direction : input;
+    }
+    pin(G) {
+      direction : input;
+    }
+    pin(Q) {
+      direction : output;
+      function : "IQ";
+      internal_node : "Q";
+      
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "G";
+      }
+      
+      timing() {
+        timing_sense : positive_unate;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "D";
+      }
+    }
+    
+    pin(QN) {
+      direction : output;
+      function : "IQN";
+      internal_node : "QN";
+      
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "G";
+      }
+      
+      timing() {
+        timing_sense : negative_unate;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "D";
+      }
+    }
+  }
+
+  /* 3 input AND-OR-INVERT gate */
+  cell (aoi211) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : input;
+    }    
+    pin(Y) {
+      direction: output;
+      function : "((A * B) + C)'";
+    }
+  }
+
+
+  /* 3 input OR-AND-INVERT gate */
+  cell (oai211) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : input;
+    }    
+    pin(Y) {
+      direction: output;
+      function : "((A + B) * C)'";
+    }
+  }
+
+  /* half adder */
+  cell (halfadder) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : output;
+      function  : "(A * B)";
+    }    
+    pin(Y) {
+      direction: output;
+      function : "(A *B') + (A' * B)";
+    }    
+  }
+
+  /* full adder */
+  cell (fulladder) {
+    area : 8;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(CI) {
+      direction : input;
+    }    
+    pin(CO) {
+      direction : output;
+      function : "(((A * B)+(B * CI))+(CI * A))";
+    }
+    pin(Y) {
+      direction: output;
+      function : "((A^B)^CI)";
+    }    
+  }
+
+} /* end */
diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh
new file mode 100755 (executable)
index 0000000..7e2ed23
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+
+for x in *.lib; do
+       echo "Running $x.."
+    echo "read_verilog small.v" > test.ys
+    echo "synth -top small" >> test.ys
+    echo "dfflibmap -liberty ${x}" >> test.ys
+       ../../yosys -ql ${x%.lib}.log -s test.ys
+done
diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib
new file mode 100644 (file)
index 0000000..f7c2075
--- /dev/null
@@ -0,0 +1,72 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 24-03-2019                      */
+/* Version: 1.0                             */
+/* Version: 1.1 - Removed semicolons in     */
+/*                full adder                */
+/*                                          */
+/********************************************/
+
+/* 
+    semi colon is missing in full-adder specification
+    some TSMC liberty files are formatted this way..
+*/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+  /* full adder */
+  cell (fulladder) {
+    area : 8
+    pin(A) {
+      direction : input
+    }
+    pin(B) {
+      direction : input
+    }
+    pin(CI) {
+      direction : input
+    }    
+    pin(CO) {
+      direction : output
+      function : "(((A * B)+(B * CI))+(CI * A))"
+    }
+    pin(Y) {
+      direction: output
+      function : "((A^B)^CI)"
+    }    
+  }
+
+} /* end */
+
+
diff --git a/tests/liberty/small.v b/tests/liberty/small.v
new file mode 100644 (file)
index 0000000..bd94be4
--- /dev/null
@@ -0,0 +1,16 @@
+/** small, meaningless design to test loading of liberty files */
+
+module small
+(
+    input clk,
+    output reg[7:0] count
+);
+
+initial count = 0;
+
+always @ (posedge clk) 
+begin
+    count <= count + 1'b1;
+end
+
+endmodule