3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-08 15:13:24 +00:00

Merge pull request #4976 from Logikable/main

Support array ranges for identifiers in the Liberty parser.
This commit is contained in:
Emil J 2025-04-09 22:49:52 +02:00 committed by GitHub
commit a5e8f52ce5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 156 additions and 144 deletions

View file

@ -890,6 +890,7 @@ SH_TEST_DIRS += tests/rpc
SH_TEST_DIRS += tests/memfile SH_TEST_DIRS += tests/memfile
SH_TEST_DIRS += tests/fmt SH_TEST_DIRS += tests/fmt
SH_TEST_DIRS += tests/cxxrtl SH_TEST_DIRS += tests/cxxrtl
SH_TEST_DIRS += tests/liberty
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1) ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
SH_TEST_DIRS += tests/functional SH_TEST_DIRS += tests/functional
endif endif

View file

@ -417,24 +417,8 @@ int LibertyParser::lexer(std::string &str)
return c; return c;
} }
LibertyAst *LibertyParser::parse() void LibertyParser::report_unexpected_token(int tok)
{ {
std::string str;
int tok = lexer(str);
// there are liberty files in the wild that
// have superfluous ';' at the end of
// a { ... }. We simply ignore a ';' here.
// and get to the next statement.
while ((tok == 'n') || (tok == ';'))
tok = lexer(str);
if (tok == '}' || tok < 0)
return NULL;
if (tok != 'v') {
std::string eReport; std::string eReport;
switch(tok) switch(tok)
{ {
@ -453,60 +437,16 @@ LibertyAst *LibertyParser::parse()
error(eReport); error(eReport);
break; break;
default: default:
error(); eReport = "Unexpected token: ";
} eReport += static_cast<char>(tok);
error(eReport);
} }
}
LibertyAst *ast = new LibertyAst; // FIXME: the AST needs to be extended to store
ast->id = str; // these vector ranges.
void LibertyParser::parse_vector_range(int tok)
while (1) {
{
tok = lexer(str);
// allow both ';' and new lines to
// terminate a statement.
if ((tok == ';') || (tok == 'n'))
break;
if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value);
if (tok == 'v') {
tok = lexer(str);
}
while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') {
ast->value += tok;
tok = lexer(str);
if (tok != 'v')
error();
ast->value += str;
tok = lexer(str);
}
// 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();
continue;
}
if (tok == '(') {
while (1) {
std::string arg;
tok = lexer(arg);
if (tok == ',')
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] // parse vector range [A] or [A:B]
std::string arg; std::string arg;
tok = lexer(arg); tok = lexer(arg);
@ -542,28 +482,88 @@ LibertyAst *LibertyParser::parse()
{ {
error("Expected ']' on array range."); error("Expected ']' on array range.");
} }
continue; }
}
LibertyAst *LibertyParser::parse()
{
std::string str;
int tok = lexer(str);
// there are liberty files in the wild that
// have superfluous ';' at the end of
// a { ... }. We simply ignore a ';' here.
// and get to the next statement.
while ((tok == 'n') || (tok == ';'))
tok = lexer(str);
if (tok == '}' || tok < 0)
return NULL;
if (tok != 'v') { if (tok != 'v') {
std::string eReport; report_unexpected_token(tok);
switch(tok)
{
case 'n':
continue;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
default:
error();
} }
LibertyAst *ast = new LibertyAst;
ast->id = str;
while (1)
{
tok = lexer(str);
// allow both ';' and new lines to
// terminate a statement.
if ((tok == ';') || (tok == 'n'))
break;
if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value);
if (tok == 'v') {
tok = lexer(str);
if (tok == '[') {
parse_vector_range(tok);
tok = lexer(str);
}
}
while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') {
ast->value += tok;
tok = lexer(str);
if (tok != 'v')
error();
ast->value += str;
tok = lexer(str);
}
// 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();
continue;
}
if (tok == '(') {
while (1) {
std::string arg;
tok = lexer(arg);
if (tok == ',')
continue;
if (tok == ')')
break;
if (tok == '[')
{
parse_vector_range(tok);
continue;
}
if (tok == 'n')
continue;
if (tok != 'v') {
report_unexpected_token(tok);
} }
ast->args.push_back(arg); ast->args.push_back(arg);
} }
@ -580,7 +580,7 @@ LibertyAst *LibertyParser::parse()
break; break;
} }
error(); report_unexpected_token(tok);
} }
return ast; return ast;

View file

@ -163,6 +163,8 @@ namespace Yosys
*/ */
int lexer(std::string &str); int lexer(std::string &str);
void report_unexpected_token(int tok);
void parse_vector_range(int tok);
LibertyAst *parse(); LibertyAst *parse();
void error() const; void error() const;
void error(const std::string &str) const; void error(const std::string &str) const;

View file

@ -9,7 +9,7 @@ library(ls05_stdcells) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : !(B&!A|!B&A) ; function : "!(B&!A|!B&A)" ;
} }
} }
} }

View file

@ -2,5 +2,5 @@ module XNOR2X1 (B, A, Y);
input B; input B;
input A; input A;
output Y; output Y;
assign Y = !(B&!A|!B&A); // !(B&!A|!B&A) assign Y = !(B&!A|!B&A); // "!(B&!A|!B&A)"
endmodule endmodule

View file

@ -0,0 +1,6 @@
library("foobar") {
pin("foo") {
bar : baz[0] ;
}
}

View file

@ -0,0 +1,2 @@
library("foobar") {
}

View file

View file

@ -6,7 +6,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : A' ; function : "A'" ;
} }
} }
cell(tri_inv) { cell(tri_inv) {
@ -19,7 +19,7 @@ library(supergate) {
} }
pin(Z) { pin(Z) {
direction : output ; direction : output ;
function : A' ; function : "A'" ;
} }
} }
cell(buffer) { cell(buffer) {
@ -29,7 +29,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : A ; function : "A" ;
} }
} }
cell(nand2) { cell(nand2) {
@ -42,7 +42,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : (A * B)' ; function : "(A * B)'" ;
} }
} }
cell(nor2) { cell(nor2) {
@ -55,7 +55,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : (A + B)' ; function : "(A + B)'" ;
} }
} }
cell(xor2) { cell(xor2) {
@ -68,7 +68,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : (A *B') + (A' * B) ; function : "(A *B') + (A' * B)" ;
} }
} }
cell(imux2) { cell(imux2) {
@ -84,16 +84,16 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : ( (A * S) + (B * S') )' ; function : "( (A * S) + (B * S') )'" ;
} }
} }
cell(dff) { cell(dff) {
area : 6 ; area : 6 ;
ff(IQ, IQN) { ff("IQ", "IQN") {
next_state : D ; next_state : "D" ;
clocked_on : CLK ; clocked_on : "CLK" ;
clear : RESET ; clear : "RESET" ;
preset : PRESET ; preset : "PRESET" ;
clear_preset_var1 : L ; clear_preset_var1 : L ;
clear_preset_var2 : L ; clear_preset_var2 : L ;
} }
@ -111,18 +111,18 @@ library(supergate) {
} }
pin(Q) { pin(Q) {
direction : output ; direction : output ;
function : IQ ; function : "IQ" ;
} }
pin(QN) { pin(QN) {
direction : output ; direction : output ;
function : IQN ; function : "IQN" ;
} }
} }
cell(latch) { cell(latch) {
area : 5 ; area : 5 ;
latch(IQ, IQN) { latch("IQ", "IQN") {
enable : G ; enable : "G" ;
data_in : D ; data_in : "D" ;
} }
pin(D) { pin(D) {
direction : input ; direction : input ;
@ -132,11 +132,11 @@ library(supergate) {
} }
pin(Q) { pin(Q) {
direction : output ; direction : output ;
function : IQ ; function : "IQ" ;
} }
pin(QN) { pin(QN) {
direction : output ; direction : output ;
function : IQN ; function : "IQN" ;
} }
} }
cell(aoi211) { cell(aoi211) {
@ -152,7 +152,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : ((A * B) + C)' ; function : "((A * B) + C)'" ;
} }
} }
cell(oai211) { cell(oai211) {
@ -168,7 +168,7 @@ library(supergate) {
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : ((A + B) * C)' ; function : "((A + B) * C)'" ;
} }
} }
cell(halfadder) { cell(halfadder) {
@ -181,11 +181,11 @@ library(supergate) {
} }
pin(C) { pin(C) {
direction : output ; direction : output ;
function : (A * B) ; function : "(A * B)" ;
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : (A *B') + (A' * B) ; function : "(A *B') + (A' * B)" ;
} }
} }
cell(fulladder) { cell(fulladder) {
@ -201,11 +201,11 @@ library(supergate) {
} }
pin(CO) { pin(CO) {
direction : output ; direction : output ;
function : (((A * B)+(B * CI))+(CI * A)) ; function : "(((A * B)+(B * CI))+(CI * A))" ;
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : ((A^B)^CI) ; function : "((A^B)^CI)" ;
} }
} }
} }

View file

@ -1,86 +1,86 @@
module inv (A, Y); module inv (A, Y);
input A; input A;
output Y; output Y;
assign Y = ~A; // A' assign Y = ~A; // "A'"
endmodule endmodule
module tri_inv (A, S, Z); module tri_inv (A, S, Z);
input A; input A;
input S; input S;
output Z; output Z;
assign Z = ~A; // A' assign Z = ~A; // "A'"
endmodule endmodule
module buffer (A, Y); module buffer (A, Y);
input A; input A;
output Y; output Y;
assign Y = A; // A assign Y = A; // "A"
endmodule endmodule
module nand2 (A, B, Y); module nand2 (A, B, Y);
input A; input A;
input B; input B;
output Y; output Y;
assign Y = ~(A&B); // (A * B)' assign Y = ~(A&B); // "(A * B)'"
endmodule endmodule
module nor2 (A, B, Y); module nor2 (A, B, Y);
input A; input A;
input B; input B;
output Y; output Y;
assign Y = ~(A|B); // (A + B)' assign Y = ~(A|B); // "(A + B)'"
endmodule endmodule
module xor2 (A, B, Y); module xor2 (A, B, Y);
input A; input A;
input B; input B;
output Y; output Y;
assign Y = (A&~B)|(~A&B); // (A *B') + (A' * B) assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)"
endmodule endmodule
module imux2 (A, B, S, Y); module imux2 (A, B, S, Y);
input A; input A;
input B; input B;
input S; input S;
output Y; output Y;
assign Y = ~(&(A&S)|(B&~S)&); // ( (A * S) + (B * S') )' assign Y = ~(&(A&S)|(B&~S)&); // "( (A * S) + (B * S') )'"
endmodule endmodule
module dff (D, CLK, RESET, PRESET, Q, QN); module dff (D, CLK, RESET, PRESET, Q, QN);
reg IQ, IQN; reg "IQ", "IQN";
input D; input D;
input CLK; input CLK;
input RESET; input RESET;
input PRESET; input PRESET;
output Q; output Q;
assign Q = IQ; // IQ assign Q = IQ; // "IQ"
output QN; output QN;
assign QN = IQN; // IQN assign QN = IQN; // "IQN"
always @(posedge CLK, posedge RESET, posedge PRESET) begin always @(posedge CLK, posedge RESET, posedge PRESET) begin
if ((RESET) && (PRESET)) begin if ((RESET) && (PRESET)) begin
IQ <= 0; "IQ" <= 0;
IQN <= 0; "IQN" <= 0;
end end
else if (RESET) begin else if (RESET) begin
IQ <= 0; "IQ" <= 0;
IQN <= 1; "IQN" <= 1;
end end
else if (PRESET) begin else if (PRESET) begin
IQ <= 1; "IQ" <= 1;
IQN <= 0; "IQN" <= 0;
end end
else begin else begin
// D // "D"
IQ <= D; "IQ" <= D;
IQN <= ~(D); "IQN" <= ~(D);
end end
end end
endmodule endmodule
module latch (D, G, Q, QN); module latch (D, G, Q, QN);
reg IQ, IQN; reg "IQ", "IQN";
input D; input D;
input G; input G;
output Q; output Q;
assign Q = IQ; // IQ assign Q = IQ; // "IQ"
output QN; output QN;
assign QN = IQN; // IQN assign QN = IQN; // "IQN"
always @* begin always @* begin
if (G) begin if (G) begin
IQ <= D; "IQ" <= D;
IQN <= ~(D); "IQN" <= ~(D);
end end
end end
endmodule endmodule
@ -89,29 +89,29 @@ module aoi211 (A, B, C, Y);
input B; input B;
input C; input C;
output Y; output Y;
assign Y = ~((A&B)|C); // ((A * B) + C)' assign Y = ~((A&B)|C); // "((A * B) + C)'"
endmodule endmodule
module oai211 (A, B, C, Y); module oai211 (A, B, C, Y);
input A; input A;
input B; input B;
input C; input C;
output Y; output Y;
assign Y = ~((A|B)&C); // ((A + B) * C)' assign Y = ~((A|B)&C); // "((A + B) * C)'"
endmodule endmodule
module halfadder (A, B, C, Y); module halfadder (A, B, C, Y);
input A; input A;
input B; input B;
output C; output C;
assign C = (A&B); // (A * B) assign C = (A&B); // "(A * B)"
output Y; output Y;
assign Y = (A&~B)|(~A&B); // (A *B') + (A' * B) assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)"
endmodule endmodule
module fulladder (A, B, CI, CO, Y); module fulladder (A, B, CI, CO, Y);
input A; input A;
input B; input B;
input CI; input CI;
output CO; output CO;
assign CO = (((A&B)|(B&CI))|(CI&A)); // (((A * B)+(B * CI))+(CI * A)) assign CO = (((A&B)|(B&CI))|(CI&A)); // "(((A * B)+(B * CI))+(CI * A))"
output Y; output Y;
assign Y = ((A^B)^CI); // ((A^B)^CI) assign Y = ((A^B)^CI); // "((A^B)^CI)"
endmodule endmodule

View file

@ -7,9 +7,10 @@ for x in *.lib; do
../../yosys-filterlib - $x 2>/dev/null > $x.filtered ../../yosys-filterlib - $x 2>/dev/null > $x.filtered
../../yosys-filterlib -verilogsim $x > $x.verilogsim ../../yosys-filterlib -verilogsim $x > $x.verilogsim
diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok
done done || exit 1
for x in *.ys; do for x in *.ys; do
echo "Running $x.." echo "Running $x.."
../../yosys -q -s $x -l ${x%.ys}.log ../../yosys -q -s $x -l ${x%.ys}.log
done done || exit 1

View file

@ -10,8 +10,8 @@ library(supergate) {
clock : true ; clock : true ;
} }
ff(IQ, IQN) { ff(IQ, IQN) {
clocked_on : CK ; clocked_on : "CK" ;
next_state : D ; next_state : "D" ;
} }
pin(Q) { pin(Q) {
direction : output ; direction : output ;

View file

@ -4,7 +4,7 @@ module DFF (D, CK, Q);
input CK; input CK;
output Q; output Q;
always @(posedge CK) begin always @(posedge CK) begin
// D // "D"
IQ <= D; IQ <= D;
IQN <= ~(D); IQN <= ~(D);
end end

View file

@ -12,11 +12,11 @@ library(supergate) {
} }
pin(CO) { pin(CO) {
direction : output ; direction : output ;
function : (((A * B)+(B * CI))+(CI * A)) ; function : "(((A * B)+(B * CI))+(CI * A))" ;
} }
pin(Y) { pin(Y) {
direction : output ; direction : output ;
function : ((A^B)^CI) ; function : "((A^B)^CI)" ;
} }
} }
} }

View file

@ -3,7 +3,7 @@ module fulladder (A, B, CI, CO, Y);
input B; input B;
input CI; input CI;
output CO; output CO;
assign CO = (((A&B)|(B&CI))|(CI&A)); // (((A * B)+(B * CI))+(CI * A)) assign CO = (((A&B)|(B&CI))|(CI&A)); // "(((A * B)+(B * CI))+(CI * A))"
output Y; output Y;
assign Y = ((A^B)^CI); // ((A^B)^CI) assign Y = ((A^B)^CI); // "((A^B)^CI)"
endmodule endmodule