Updated the liberty parser to accept [A:B] ranges (AST has not been updated). Liberty parser now also accepts key : value pair lines that do not end in ';'.

This commit is contained in:
Niels Moseley 2019-03-24 22:54:18 +01:00
parent ccfa2fe01c
commit 3b3b77291a
8 changed files with 631 additions and 7 deletions

View 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) \

View 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);
};
}

2
tests/liberty/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
test.ys

81
tests/liberty/busdef.lib Normal file
View File

@ -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 */

360
tests/liberty/normal.lib Normal file
View File

@ -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 */

10
tests/liberty/run-test.sh Executable file
View File

@ -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

View File

@ -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 */

16
tests/liberty/small.v Normal file
View File

@ -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