mirror of
https://github.com/verilator/verilator.git
synced 2025-02-01 11:14:03 +00:00
3795 lines
153 KiB
Plaintext
3795 lines
153 KiB
Plaintext
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: Bison grammer file
|
|
//
|
|
// Code available from: http://www.veripool.org/verilator
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
// Version 2.0.
|
|
//
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
//*************************************************************************
|
|
// Original code here by Paul Wasson and Duane Galbi
|
|
//*************************************************************************
|
|
|
|
%{
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstdarg>
|
|
#include <cstring>
|
|
|
|
#include "V3Ast.h"
|
|
#include "V3Global.h"
|
|
#include "V3Config.h"
|
|
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
|
|
|
#define YYERROR_VERBOSE 1
|
|
#define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH
|
|
#define YYMAXDEPTH 10000
|
|
|
|
// Pick up new lexer
|
|
#define yylex PARSEP->lexToBison
|
|
#define GATEUNSUP(fl,tok) { if (!v3Global.opt.bboxUnsup()) { (fl)->v3error("Unsupported: Verilog 1995 gate primitive: "<<(tok)); } }
|
|
|
|
extern void yyerror(const char* errmsg);
|
|
extern void yyerrorf(const char* format, ...);
|
|
|
|
//======================================================================
|
|
// Statics (for here only)
|
|
|
|
#define PARSEP V3ParseImp::parsep()
|
|
#define SYMP PARSEP->symp()
|
|
#define GRAMMARP V3ParseGrammar::singletonp()
|
|
|
|
class V3ParseGrammar {
|
|
public:
|
|
bool m_impliedDecl; // Allow implied wire declarations
|
|
AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc)
|
|
AstVarType m_varIO; // Type for next signal declaration (input/output/etc)
|
|
AstVar* m_varAttrp; // Current variable for attribute adding
|
|
AstCase* m_caseAttrp; // Current case statement for attribute adding
|
|
AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration
|
|
AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration
|
|
int m_pinNum; // Pin number currently parsing
|
|
string m_instModule; // Name of module referenced for instantiations
|
|
AstPin* m_instParamp; // Parameters for instantiations
|
|
AstNodeModule* m_modp; // Module
|
|
int m_modTypeImpNum; // Implicit type number, incremented each module
|
|
|
|
// CONSTRUCTORS
|
|
V3ParseGrammar() {
|
|
m_impliedDecl = false;
|
|
m_varDecl = AstVarType::UNKNOWN;
|
|
m_varIO = AstVarType::UNKNOWN;
|
|
m_varDTypep = NULL;
|
|
m_memDTypep = NULL;
|
|
m_pinNum = -1;
|
|
m_instModule = "";
|
|
m_instParamp = NULL;
|
|
m_modp = NULL;
|
|
m_modTypeImpNum = 0;
|
|
m_varAttrp = NULL;
|
|
m_caseAttrp = NULL;
|
|
}
|
|
static V3ParseGrammar* singletonp() {
|
|
static V3ParseGrammar singleton;
|
|
return &singleton;
|
|
}
|
|
|
|
// METHODS
|
|
void argWrapList(AstNodeFTaskRef* nodep);
|
|
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
|
|
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
|
|
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
|
AstText* createTextQuoted(FileLine* fileline, string text) {
|
|
string newtext = deQuote(fileline, text);
|
|
return new AstText(fileline, newtext);
|
|
}
|
|
AstDisplay* createDisplayError(FileLine* fileline) {
|
|
AstDisplay* nodep = new AstDisplay(fileline,AstDisplayType::DT_ERROR, "", NULL,NULL);
|
|
nodep->addNext(new AstStop(fileline));
|
|
return nodep;
|
|
}
|
|
void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); }
|
|
void endLabel(FileLine* fl, string name, string* endnamep) {
|
|
if (fl && endnamep && *endnamep != "" && name != *endnamep) {
|
|
fl->v3warn(ENDLABEL,"End label '"<<*endnamep<<"' does not match begin label '"<<name<<"'");
|
|
}
|
|
}
|
|
void setDType(AstNodeDType* dtypep) {
|
|
if (m_varDTypep) { m_varDTypep->deleteTree(); m_varDTypep=NULL; } // It was cloned, so this is safe.
|
|
m_varDTypep = dtypep;
|
|
}
|
|
AstPackage* unitPackage(FileLine* fl) {
|
|
// Find one made earlier?
|
|
AstPackage* pkgp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName())->nodep()->castPackage();
|
|
if (!pkgp) {
|
|
pkgp = PARSEP->rootp()->dollarUnitPkgAddp();
|
|
GRAMMARP->m_modp = pkgp; GRAMMARP->m_modTypeImpNum = 0;
|
|
SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global
|
|
}
|
|
return pkgp;
|
|
}
|
|
AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp, bool isPacked) {
|
|
// If dtypep isn't basic, don't use this, call createArray() instead
|
|
if (!rangesp) {
|
|
return dtypep;
|
|
} else {
|
|
// If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]"
|
|
// then [1:1] becomes the basicdtype range; everything else is arraying
|
|
// the final [5:5][4:4] will be passed in another call to createArray
|
|
AstRange* rangearraysp = NULL;
|
|
if (dtypep->isRanged()) {
|
|
rangearraysp = rangesp; // Already a range; everything is an array
|
|
} else {
|
|
AstRange* finalp = rangesp;
|
|
while (finalp->nextp()) finalp=finalp->nextp()->castRange();
|
|
if (finalp != rangesp) {
|
|
finalp->unlinkFrBack();
|
|
rangearraysp = rangesp;
|
|
}
|
|
if (dtypep->implicit()) {
|
|
// It's no longer implicit but a real logic type
|
|
AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC,
|
|
dtypep->numeric(), dtypep->width(), dtypep->widthMin());
|
|
dtypep->deleteTree(); dtypep=NULL;
|
|
dtypep = newp;
|
|
}
|
|
dtypep->rangep(finalp);
|
|
}
|
|
return createArray(dtypep, rangearraysp, isPacked);
|
|
}
|
|
}
|
|
string deQuote(FileLine* fileline, string text);
|
|
void checkDpiVer(FileLine* fileline, const string& str) {
|
|
if (str != "DPI-C" && !v3Global.opt.bboxSys()) {
|
|
fileline->v3error("Unsupported DPI type '"<<str<<"': Use 'DPI-C'");
|
|
}
|
|
}
|
|
};
|
|
|
|
const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC"
|
|
const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT;
|
|
|
|
//======================================================================
|
|
// Macro functions
|
|
|
|
#define CRELINE() (PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings
|
|
|
|
#define VARRESET_LIST(decl) { GRAMMARP->m_pinNum=1; VARRESET(); VARDECL(decl); } // Start of pinlist
|
|
#define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; VARRESET(); VARDECL(decl); } // Not in a pinlist
|
|
#define VARRESET() { VARDECL(UNKNOWN); VARIO(UNKNOWN); VARDTYPE(NULL); }
|
|
#define VARDECL(type) { GRAMMARP->m_varDecl = AstVarType::type; }
|
|
#define VARIO(type) { GRAMMARP->m_varIO = AstVarType::type; }
|
|
#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); }
|
|
|
|
#define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs))
|
|
#define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs))
|
|
#define PINNUMINC() (GRAMMARP->m_pinNum++)
|
|
|
|
#define INSTPREP(modname,paramsp) { GRAMMARP->m_impliedDecl = true; GRAMMARP->m_instModule = modname; GRAMMARP->m_instParamp = paramsp; }
|
|
|
|
#define DEL(nodep) { if (nodep) nodep->deleteTree(); }
|
|
|
|
static void ERRSVKWD(FileLine* fileline, const string& tokname) {
|
|
static int toldonce = 0;
|
|
fileline->v3error((string)"Unexpected \""+tokname+"\": \""+tokname+"\" is a SystemVerilog keyword misused as an identifier.");
|
|
if (!toldonce++) fileline->v3error("Modify the Verilog-2001 code to avoid SV keywords, or use `begin_keywords or --language.");
|
|
}
|
|
|
|
//======================================================================
|
|
|
|
class AstSenTree;
|
|
%}
|
|
|
|
// When writing Bison patterns we use yTOKEN instead of "token",
|
|
// so Bison will error out on unknown "token"s.
|
|
|
|
// Generic lexer tokens, for example a number
|
|
// IEEE: real_number
|
|
%token<cdouble> yaFLOATNUM "FLOATING-POINT NUMBER"
|
|
|
|
// IEEE: identifier, class_identifier, class_variable_identifier,
|
|
// covergroup_variable_identifier, dynamic_array_variable_identifier,
|
|
// enum_identifier, interface_identifier, interface_instance_identifier,
|
|
// package_identifier, type_identifier, variable_identifier,
|
|
%token<strp> yaID__ETC "IDENTIFIER"
|
|
%token<strp> yaID__LEX "IDENTIFIER-in-lex"
|
|
%token<strp> yaID__aPACKAGE "PACKAGE-IDENTIFIER"
|
|
%token<strp> yaID__aTYPE "TYPE-IDENTIFIER"
|
|
// Can't predecode aFUNCTION, can declare after use
|
|
// Can't predecode aINTERFACE, can declare after use
|
|
// Can't predecode aTASK, can declare after use
|
|
|
|
// IEEE: integral_number
|
|
%token<nump> yaINTNUM "INTEGER NUMBER"
|
|
// IEEE: time_literal + time_unit
|
|
%token<cdouble> yaTIMENUM "TIME NUMBER"
|
|
// IEEE: string_literal
|
|
%token<strp> yaSTRING "STRING"
|
|
%token<strp> yaSTRING__IGNORE "STRING-ignored" // Used when expr:string not allowed
|
|
|
|
%token<fl> yaTIMINGSPEC "TIMING SPEC ELEMENT"
|
|
|
|
%token<strp> yaTABLELINE "TABLE LINE"
|
|
|
|
%token<strp> yaSCHDR "`systemc_header BLOCK"
|
|
%token<strp> yaSCINT "`systemc_ctor BLOCK"
|
|
%token<strp> yaSCIMP "`systemc_dtor BLOCK"
|
|
%token<strp> yaSCIMPH "`systemc_interface BLOCK"
|
|
%token<strp> yaSCCTOR "`systemc_implementation BLOCK"
|
|
%token<strp> yaSCDTOR "`systemc_imp_header BLOCK"
|
|
|
|
%token<fl> yVLT_COVERAGE_OFF "coverage_off"
|
|
%token<fl> yVLT_LINT_OFF "lint_off"
|
|
%token<fl> yVLT_TRACING_OFF "tracing_off"
|
|
|
|
%token<fl> yVLT_D_FILE "--file"
|
|
%token<fl> yVLT_D_LINES "--lines"
|
|
%token<fl> yVLT_D_MSG "--msg"
|
|
|
|
%token<strp> yaD_IGNORE "${ignored-bbox-sys}"
|
|
%token<strp> yaD_DPI "${dpi-sys}"
|
|
|
|
// <fl> is the fileline, abbreviated to shorten "$<fl>1" references
|
|
%token<fl> '!'
|
|
%token<fl> '#'
|
|
%token<fl> '%'
|
|
%token<fl> '&'
|
|
%token<fl> '('
|
|
%token<fl> ')'
|
|
%token<fl> '*'
|
|
%token<fl> '+'
|
|
%token<fl> ','
|
|
%token<fl> '-'
|
|
%token<fl> '.'
|
|
%token<fl> '/'
|
|
%token<fl> ':'
|
|
%token<fl> ';'
|
|
%token<fl> '<'
|
|
%token<fl> '='
|
|
%token<fl> '>'
|
|
%token<fl> '?'
|
|
%token<fl> '@'
|
|
%token<fl> '['
|
|
%token<fl> ']'
|
|
%token<fl> '^'
|
|
%token<fl> '{'
|
|
%token<fl> '|'
|
|
%token<fl> '}'
|
|
%token<fl> '~'
|
|
|
|
// Specific keywords
|
|
// yKEYWORD means match "keyword"
|
|
// Other cases are yXX_KEYWORD where XX makes it unique,
|
|
// for example yP_ for punctuation based operators.
|
|
// Double underscores "yX__Y" means token X followed by Y,
|
|
// and "yX__ETC" means X folled by everything but Y(s).
|
|
%token<fl> yALWAYS "always"
|
|
%token<fl> yALWAYS_FF "always_ff"
|
|
%token<fl> yALWAYS_COMB "always_comb"
|
|
%token<fl> yALWAYS_LATCH "always_latch"
|
|
%token<fl> yAND "and"
|
|
%token<fl> yASSERT "assert"
|
|
%token<fl> yASSIGN "assign"
|
|
%token<fl> yAUTOMATIC "automatic"
|
|
%token<fl> yBEGIN "begin"
|
|
%token<fl> yBIND "bind"
|
|
%token<fl> yBIT "bit"
|
|
%token<fl> yBREAK "break"
|
|
%token<fl> yBUF "buf"
|
|
%token<fl> yBUFIF0 "bufif0"
|
|
%token<fl> yBUFIF1 "bufif1"
|
|
%token<fl> yBYTE "byte"
|
|
%token<fl> yCASE "case"
|
|
%token<fl> yCASEX "casex"
|
|
%token<fl> yCASEZ "casez"
|
|
%token<fl> yCHANDLE "chandle"
|
|
%token<fl> yCLOCKING "clocking"
|
|
%token<fl> yCONST__ETC "const"
|
|
%token<fl> yCONST__LEX "const-in-lex"
|
|
%token<fl> yCMOS "cmos"
|
|
%token<fl> yCONTEXT "context"
|
|
%token<fl> yCONTINUE "continue"
|
|
%token<fl> yCOVER "cover"
|
|
%token<fl> yDEFAULT "default"
|
|
%token<fl> yDEFPARAM "defparam"
|
|
%token<fl> yDISABLE "disable"
|
|
%token<fl> yDO "do"
|
|
%token<fl> yEDGE "edge"
|
|
%token<fl> yELSE "else"
|
|
%token<fl> yEND "end"
|
|
%token<fl> yENDCASE "endcase"
|
|
%token<fl> yENDCLOCKING "endclocking"
|
|
%token<fl> yENDFUNCTION "endfunction"
|
|
%token<fl> yENDGENERATE "endgenerate"
|
|
%token<fl> yENDINTERFACE "endinterface"
|
|
%token<fl> yENDMODULE "endmodule"
|
|
%token<fl> yENDPACKAGE "endpackage"
|
|
%token<fl> yENDPRIMITIVE "endprimitive"
|
|
%token<fl> yENDPROGRAM "endprogram"
|
|
%token<fl> yENDPROPERTY "endproperty"
|
|
%token<fl> yENDSPECIFY "endspecify"
|
|
%token<fl> yENDTABLE "endtable"
|
|
%token<fl> yENDTASK "endtask"
|
|
%token<fl> yENUM "enum"
|
|
%token<fl> yEXPORT "export"
|
|
%token<fl> yFINAL "final"
|
|
%token<fl> yFOR "for"
|
|
%token<fl> yFOREVER "forever"
|
|
%token<fl> yFUNCTION "function"
|
|
%token<fl> yGENERATE "generate"
|
|
%token<fl> yGENVAR "genvar"
|
|
%token<fl> yGLOBAL__CLOCKING "global-then-clocking"
|
|
%token<fl> yGLOBAL__LEX "global-in-lex"
|
|
%token<fl> yIF "if"
|
|
%token<fl> yIFF "iff"
|
|
%token<fl> yIMPORT "import"
|
|
%token<fl> yINITIAL "initial"
|
|
%token<fl> yINOUT "inout"
|
|
%token<fl> yINPUT "input"
|
|
%token<fl> yINSIDE "inside"
|
|
%token<fl> yINT "int"
|
|
%token<fl> yINTEGER "integer"
|
|
%token<fl> yINTERFACE "interface"
|
|
%token<fl> yLOCALPARAM "localparam"
|
|
%token<fl> yLOGIC "logic"
|
|
%token<fl> yLONGINT "longint"
|
|
%token<fl> yMODPORT "modport"
|
|
%token<fl> yMODULE "module"
|
|
%token<fl> yNAND "nand"
|
|
%token<fl> yNEGEDGE "negedge"
|
|
%token<fl> yNMOS "nmos"
|
|
%token<fl> yNOR "nor"
|
|
%token<fl> yNOT "not"
|
|
%token<fl> yNOTIF0 "notif0"
|
|
%token<fl> yNOTIF1 "notif1"
|
|
%token<fl> yOR "or"
|
|
%token<fl> yOUTPUT "output"
|
|
%token<fl> yPACKAGE "package"
|
|
%token<fl> yPACKED "packed"
|
|
%token<fl> yPARAMETER "parameter"
|
|
%token<fl> yPMOS "pmos"
|
|
%token<fl> yPOSEDGE "posedge"
|
|
%token<fl> yPRIMITIVE "primitive"
|
|
%token<fl> yPRIORITY "priority"
|
|
%token<fl> yPROGRAM "program"
|
|
%token<fl> yPROPERTY "property"
|
|
%token<fl> yPULLDOWN "pulldown"
|
|
%token<fl> yPULLUP "pullup"
|
|
%token<fl> yPURE "pure"
|
|
%token<fl> yRAND "rand"
|
|
%token<fl> yRANDC "randc"
|
|
%token<fl> yRCMOS "rcmos"
|
|
%token<fl> yREAL "real"
|
|
%token<fl> yREALTIME "realtime"
|
|
%token<fl> yREG "reg"
|
|
%token<fl> yREPEAT "repeat"
|
|
%token<fl> yRETURN "return"
|
|
%token<fl> yRNMOS "rnmos"
|
|
%token<fl> yRPMOS "rpmos"
|
|
%token<fl> yRTRAN "rtran"
|
|
%token<fl> yRTRANIF0 "rtranif0"
|
|
%token<fl> yRTRANIF1 "rtranif1"
|
|
%token<fl> ySCALARED "scalared"
|
|
%token<fl> ySHORTINT "shortint"
|
|
%token<fl> ySIGNED "signed"
|
|
%token<fl> ySPECIFY "specify"
|
|
%token<fl> ySPECPARAM "specparam"
|
|
%token<fl> ySTATIC "static"
|
|
%token<fl> ySTRING "string"
|
|
%token<fl> ySTRUCT "struct"
|
|
%token<fl> ySUPPLY0 "supply0"
|
|
%token<fl> ySUPPLY1 "supply1"
|
|
%token<fl> yTABLE "table"
|
|
%token<fl> yTASK "task"
|
|
%token<fl> yTIME "time"
|
|
%token<fl> yTIMEPRECISION "timeprecision"
|
|
%token<fl> yTIMEUNIT "timeunit"
|
|
%token<fl> yTRAN "tran"
|
|
%token<fl> yTRANIF0 "tranif0"
|
|
%token<fl> yTRANIF1 "tranif1"
|
|
%token<fl> yTRI "tri"
|
|
%token<fl> yTRI0 "tri0"
|
|
%token<fl> yTRI1 "tri1"
|
|
%token<fl> yTRUE "true"
|
|
%token<fl> yTYPEDEF "typedef"
|
|
%token<fl> yUNION "union"
|
|
%token<fl> yUNIQUE "unique"
|
|
%token<fl> yUNIQUE0 "unique0"
|
|
%token<fl> yUNSIGNED "unsigned"
|
|
%token<fl> yVAR "var"
|
|
%token<fl> yVECTORED "vectored"
|
|
%token<fl> yVOID "void"
|
|
%token<fl> yWHILE "while"
|
|
%token<fl> yWIRE "wire"
|
|
%token<fl> yWREAL "wreal"
|
|
%token<fl> yXNOR "xnor"
|
|
%token<fl> yXOR "xor"
|
|
|
|
%token<fl> yD_BITS "$bits"
|
|
%token<fl> yD_BITSTOREAL "$bitstoreal"
|
|
%token<fl> yD_C "$c"
|
|
%token<fl> yD_CEIL "$ceil"
|
|
%token<fl> yD_CLOG2 "$clog2"
|
|
%token<fl> yD_COUNTONES "$countones"
|
|
%token<fl> yD_DIMENSIONS "$dimensions"
|
|
%token<fl> yD_DISPLAY "$display"
|
|
%token<fl> yD_ERROR "$error"
|
|
%token<fl> yD_EXP "$exp"
|
|
%token<fl> yD_FATAL "$fatal"
|
|
%token<fl> yD_FCLOSE "$fclose"
|
|
%token<fl> yD_FDISPLAY "$fdisplay"
|
|
%token<fl> yD_FEOF "$feof"
|
|
%token<fl> yD_FFLUSH "$fflush"
|
|
%token<fl> yD_FGETC "$fgetc"
|
|
%token<fl> yD_FGETS "$fgets"
|
|
%token<fl> yD_FINISH "$finish"
|
|
%token<fl> yD_FLOOR "$floor"
|
|
%token<fl> yD_FOPEN "$fopen"
|
|
%token<fl> yD_FSCANF "$fscanf"
|
|
%token<fl> yD_FWRITE "$fwrite"
|
|
%token<fl> yD_HIGH "$high"
|
|
%token<fl> yD_INCREMENT "$increment"
|
|
%token<fl> yD_INFO "$info"
|
|
%token<fl> yD_ISUNKNOWN "$isunknown"
|
|
%token<fl> yD_ITOR "$itor"
|
|
%token<fl> yD_LEFT "$left"
|
|
%token<fl> yD_LN "$ln"
|
|
%token<fl> yD_LOG10 "$log10"
|
|
%token<fl> yD_LOW "$low"
|
|
%token<fl> yD_ONEHOT "$onehot"
|
|
%token<fl> yD_ONEHOT0 "$onehot0"
|
|
%token<fl> yD_POW "$pow"
|
|
%token<fl> yD_RANDOM "$random"
|
|
%token<fl> yD_READMEMB "$readmemb"
|
|
%token<fl> yD_READMEMH "$readmemh"
|
|
%token<fl> yD_REALTIME "$realtime"
|
|
%token<fl> yD_REALTOBITS "$realtobits"
|
|
%token<fl> yD_RIGHT "$right"
|
|
%token<fl> yD_RTOI "$rtoi"
|
|
%token<fl> yD_SFORMAT "$sformat"
|
|
%token<fl> yD_SIGNED "$signed"
|
|
%token<fl> yD_SIZE "$size"
|
|
%token<fl> yD_SQRT "$sqrt"
|
|
%token<fl> yD_SSCANF "$sscanf"
|
|
%token<fl> yD_STIME "$stime"
|
|
%token<fl> yD_STOP "$stop"
|
|
%token<fl> yD_SWRITE "$swrite"
|
|
%token<fl> yD_SYSTEM "$system"
|
|
%token<fl> yD_TESTPLUSARGS "$test$plusargs"
|
|
%token<fl> yD_TIME "$time"
|
|
%token<fl> yD_UNIT "$unit"
|
|
%token<fl> yD_UNPACKED_DIMENSIONS "$unpacked_dimensions"
|
|
%token<fl> yD_UNSIGNED "$unsigned"
|
|
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
|
|
%token<fl> yD_WARNING "$warning"
|
|
%token<fl> yD_WRITE "$write"
|
|
|
|
%token<fl> yPSL "psl"
|
|
%token<fl> yPSL_ASSERT "PSL assert"
|
|
%token<fl> yPSL_CLOCK "PSL clock"
|
|
%token<fl> yPSL_COVER "PSL cover"
|
|
%token<fl> yPSL_REPORT "PSL report"
|
|
|
|
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
|
%token<fl> yVL_CLOCK_ENABLE "/*verilator clock_enable*/"
|
|
%token<fl> yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/"
|
|
%token<fl> yVL_FULL_CASE "/*verilator full_case*/"
|
|
%token<fl> yVL_INLINE_MODULE "/*verilator inline_module*/"
|
|
%token<fl> yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/"
|
|
%token<fl> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/"
|
|
%token<fl> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/"
|
|
%token<fl> yVL_SC_BV "/*verilator sc_bv*/"
|
|
%token<fl> yVL_SFORMAT "/*verilator sformat*/"
|
|
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
|
%token<fl> yVL_PUBLIC "/*verilator public*/"
|
|
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
|
|
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
|
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
|
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
|
|
|
%token<fl> yP_TICK "'"
|
|
%token<fl> yP_TICKBRA "'{"
|
|
%token<fl> yP_OROR "||"
|
|
%token<fl> yP_ANDAND "&&"
|
|
%token<fl> yP_NOR "~|"
|
|
%token<fl> yP_XNOR "^~"
|
|
%token<fl> yP_NAND "~&"
|
|
%token<fl> yP_EQUAL "=="
|
|
%token<fl> yP_NOTEQUAL "!="
|
|
%token<fl> yP_CASEEQUAL "==="
|
|
%token<fl> yP_CASENOTEQUAL "!=="
|
|
%token<fl> yP_WILDEQUAL "==?"
|
|
%token<fl> yP_WILDNOTEQUAL "!=?"
|
|
%token<fl> yP_GTE ">="
|
|
%token<fl> yP_LTE "<="
|
|
%token<fl> yP_LTE__IGNORE "<=-ignored" // Used when expr:<= means assignment
|
|
%token<fl> yP_SLEFT "<<"
|
|
%token<fl> yP_SRIGHT ">>"
|
|
%token<fl> yP_SSRIGHT ">>>"
|
|
%token<fl> yP_POW "**"
|
|
|
|
%token<fl> yP_PLUSCOLON "+:"
|
|
%token<fl> yP_MINUSCOLON "-:"
|
|
%token<fl> yP_MINUSGT "->"
|
|
%token<fl> yP_MINUSGTGT "->>"
|
|
%token<fl> yP_EQGT "=>"
|
|
%token<fl> yP_ASTGT "*>"
|
|
%token<fl> yP_ANDANDAND "&&&"
|
|
%token<fl> yP_POUNDPOUND "##"
|
|
%token<fl> yP_DOTSTAR ".*"
|
|
|
|
%token<fl> yP_ATAT "@@"
|
|
%token<fl> yP_COLONCOLON "::"
|
|
%token<fl> yP_COLONEQ ":="
|
|
%token<fl> yP_COLONDIV ":/"
|
|
%token<fl> yP_ORMINUSGT "|->"
|
|
%token<fl> yP_OREQGT "|=>"
|
|
%token<fl> yP_BRASTAR "[*"
|
|
%token<fl> yP_BRAEQ "[="
|
|
%token<fl> yP_BRAMINUSGT "[->"
|
|
|
|
%token<fl> yP_PLUSPLUS "++"
|
|
%token<fl> yP_MINUSMINUS "--"
|
|
%token<fl> yP_PLUSEQ "+="
|
|
%token<fl> yP_MINUSEQ "-="
|
|
%token<fl> yP_TIMESEQ "*="
|
|
%token<fl> yP_DIVEQ "/="
|
|
%token<fl> yP_MODEQ "%="
|
|
%token<fl> yP_ANDEQ "&="
|
|
%token<fl> yP_OREQ "|="
|
|
%token<fl> yP_XOREQ "^="
|
|
%token<fl> yP_SLEFTEQ "<<="
|
|
%token<fl> yP_SRIGHTEQ ">>="
|
|
%token<fl> yP_SSRIGHTEQ ">>>="
|
|
|
|
%token<fl> yPSL_BRA "{"
|
|
%token<fl> yPSL_KET "}"
|
|
%token<fl> yP_LOGIFF
|
|
|
|
// [* is not a operator, as "[ * ]" is legal
|
|
// [= and [-> could be repitition operators, but to match [* we don't add them.
|
|
// '( is not a operator, as "' (" is legal
|
|
|
|
//********************
|
|
// PSL op precedence
|
|
%right yP_MINUSGT yP_LOGIFF
|
|
%right yP_ORMINUSGT yP_OREQGT
|
|
%left<fl> prPSLCLK
|
|
|
|
// Verilog op precedence
|
|
%right '?' ':'
|
|
%left yP_OROR
|
|
%left yP_ANDAND
|
|
%left '|' yP_NOR
|
|
%left '^' yP_XNOR
|
|
%left '&' yP_NAND
|
|
%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL
|
|
%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE
|
|
%left yP_SLEFT yP_SRIGHT yP_SSRIGHT
|
|
%left '+' '-'
|
|
%left '*' '/' '%'
|
|
%left yP_POW
|
|
%left prUNARYARITH yP_MINUSMINUS yP_PLUSPLUS prREDUCTION prNEGATION
|
|
%left '.'
|
|
// Not in IEEE, but need to avoid conflicts; TICK should bind tightly just lower than COLONCOLON
|
|
%left yP_TICK
|
|
//%left '(' ')' '[' ']' yP_COLONCOLON '.'
|
|
|
|
%nonassoc prLOWER_THAN_ELSE
|
|
%nonassoc yELSE
|
|
|
|
//BISONPRE_TYPES
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
// Blank lines for type insertion
|
|
|
|
%start source_text
|
|
|
|
%%
|
|
//**********************************************************************
|
|
// Feedback to the Lexer
|
|
// Note we read a parenthesis ahead, so this may not change the lexer at the right point.
|
|
|
|
stateExitPsl: // For PSL lexing, return from PSL state
|
|
/* empty */ { PARSEP->stateExitPsl(); }
|
|
;
|
|
statePushVlg: // For PSL lexing, escape current state into Verilog state
|
|
/* empty */ { PARSEP->statePushVlg(); }
|
|
;
|
|
statePop: // Return to previous lexing state
|
|
/* empty */ { PARSEP->statePop(); }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// Files
|
|
|
|
source_text: // ==IEEE: source_text
|
|
/* empty */ { }
|
|
// // timeunits_declaration moved into description:package_item
|
|
| descriptionList { }
|
|
;
|
|
|
|
descriptionList: // IEEE: part of source_text
|
|
description { }
|
|
| descriptionList description { }
|
|
;
|
|
|
|
description: // ==IEEE: description
|
|
module_declaration { }
|
|
// // udp_declaration moved into module_declaration
|
|
| interface_declaration { }
|
|
| program_declaration { }
|
|
| package_declaration { }
|
|
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
|
|
| bind_directive { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
|
|
// unsupported // IEEE: config_declaration
|
|
// // Verilator only
|
|
| vltItem { }
|
|
| error { }
|
|
;
|
|
|
|
timeunits_declaration<nodep>: // ==IEEE: timeunits_declaration
|
|
yTIMEUNIT yaTIMENUM ';' { $$ = NULL; }
|
|
| yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' { $$ = NULL; }
|
|
| yTIMEPRECISION yaTIMENUM ';' { $$ = NULL; }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// Packages
|
|
|
|
package_declaration: // ==IEEE: package_declaration
|
|
packageFront package_itemListE yENDPACKAGE endLabelE
|
|
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
|
if ($2) $1->addStmtp($2);
|
|
SYMP->popScope($1);
|
|
GRAMMARP->endLabel($<fl>4,$1,$4); }
|
|
;
|
|
|
|
packageFront<modulep>:
|
|
yPACKAGE idAny ';'
|
|
{ $$ = new AstPackage($1,*$2);
|
|
$$->inLibrary(true); // packages are always libraries; don't want to make them a "top"
|
|
$$->modTrace(v3Global.opt.trace());
|
|
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
|
|
PARSEP->rootp()->addModulep($$);
|
|
SYMP->pushNew($$); }
|
|
;
|
|
|
|
package_itemListE<nodep>: // IEEE: [{ package_item }]
|
|
/* empty */ { $$ = NULL; }
|
|
| package_itemList { $$ = $1; }
|
|
;
|
|
|
|
package_itemList<nodep>: // IEEE: { package_item }
|
|
package_item { $$ = $1; }
|
|
| package_itemList package_item { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
package_item<nodep>: // ==IEEE: package_item
|
|
package_or_generate_item_declaration { $$ = $1; }
|
|
//UNSUP anonymous_program { $$ = $1; }
|
|
//UNSUP package_export_declaration { $$ = $1; }
|
|
| timeunits_declaration { $$ = $1; }
|
|
;
|
|
|
|
package_or_generate_item_declaration<nodep>: // ==IEEE: package_or_generate_item_declaration
|
|
net_declaration { $$ = $1; }
|
|
| data_declaration { $$ = $1; }
|
|
| task_declaration { $$ = $1; }
|
|
| function_declaration { $$ = $1; }
|
|
//UNSUP checker_declaration { $$ = $1; }
|
|
| dpi_import_export { $$ = $1; }
|
|
//UNSUP extern_constraint_declaration { $$ = $1; }
|
|
//UNSUP class_declaration { $$ = $1; }
|
|
// // class_constructor_declaration is part of function_declaration
|
|
| local_parameter_declaration ';' { $$ = $1; }
|
|
| parameter_declaration ';' { $$ = $1; }
|
|
//UNSUP covergroup_declaration { $$ = $1; }
|
|
//UNSUP overload_declaration { $$ = $1; }
|
|
//UNSUP assertion_item_declaration { $$ = $1; }
|
|
| ';' { $$ = NULL; }
|
|
;
|
|
|
|
package_import_declaration<nodep>: // ==IEEE: package_import_declaration
|
|
yIMPORT package_import_itemList ';' { $$ = $2; }
|
|
;
|
|
|
|
package_import_itemList<nodep>:
|
|
package_import_item { $$ = $1; }
|
|
| package_import_itemList ',' package_import_item { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
package_import_item<nodep>: // ==IEEE: package_import_item
|
|
yaID__aPACKAGE yP_COLONCOLON package_import_itemObj
|
|
{ $$ = new AstPackageImport($<fl>1, $<scp>1->castPackage(), *$3);
|
|
SYMP->import($<scp>1,*$3); }
|
|
;
|
|
|
|
package_import_itemObj<strp>: // IEEE: part of package_import_item
|
|
idAny { $<fl>$=$<fl>1; $$=$1; }
|
|
| '*' { $<fl>$=$<fl>1; static string star="*"; $$=☆ }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// Module headers
|
|
|
|
module_declaration: // ==IEEE: module_declaration
|
|
// // timeunits_declaration instead in module_item
|
|
// // IEEE: module_nonansi_header + module_ansi_header
|
|
modFront parameter_port_listE portsStarE ';'
|
|
module_itemListE yENDMODULE endLabelE
|
|
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
|
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
|
if ($5) $1->addStmtp($5);
|
|
SYMP->popScope($1);
|
|
GRAMMARP->endLabel($<fl>7,$1,$7); }
|
|
| udpFront parameter_port_listE portsStarE ';'
|
|
module_itemListE yENDPRIMITIVE endLabelE
|
|
{ $1->modTrace(false); // Stash for implicit wires, etc
|
|
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
|
if ($5) $1->addStmtp($5);
|
|
SYMP->popScope($1);
|
|
GRAMMARP->endLabel($<fl>7,$1,$7); }
|
|
//
|
|
//UNSUP yEXTERN modFront parameter_port_listE portsStarE ';'
|
|
//UNSUP { UNSUP }
|
|
;
|
|
|
|
modFront<modulep>:
|
|
// // General note: all *Front functions must call symPushNew before
|
|
// // any formal arguments, as the arguments must land in the new scope.
|
|
yMODULE lifetimeE idAny
|
|
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
|
|
$$->modTrace(v3Global.opt.trace());
|
|
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
|
|
PARSEP->rootp()->addModulep($$);
|
|
SYMP->pushNew($$); }
|
|
;
|
|
|
|
udpFront<modulep>:
|
|
yPRIMITIVE lifetimeE idAny
|
|
{ $$ = new AstPrimitive($1,*$3); $$->inLibrary(true);
|
|
$$->modTrace(false);
|
|
$$->addStmtp(new AstPragma($1,AstPragmaType::INLINE_MODULE));
|
|
PARSEP->fileline()->tracingOn(false);
|
|
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
|
|
PARSEP->rootp()->addModulep($$);
|
|
SYMP->pushNew($$); }
|
|
;
|
|
|
|
parameter_value_assignmentE<pinp>: // IEEE: [ parameter_value_assignment ]
|
|
/* empty */ { $$ = NULL; }
|
|
| '#' '(' cellpinList ')' { $$ = $3; }
|
|
// // Parentheses are optional around a single parameter
|
|
| '#' yaINTNUM { $$ = new AstPin($1,1,"",new AstConst($1,*$2)); }
|
|
| '#' yaFLOATNUM { $$ = new AstPin($1,1,"",new AstConst($1,AstConst::Unsized32(),(int)(($2<0)?($2-0.5):($2+0.5)))); }
|
|
| '#' idClassSel { $$ = new AstPin($1,1,"",$2); }
|
|
// // Not needed in Verilator:
|
|
// // Side effect of combining *_instantiations
|
|
// // '#' delay_value { UNSUP }
|
|
;
|
|
|
|
parameter_port_listE<nodep>: // IEEE: parameter_port_list + empty == parameter_value_assignment
|
|
/* empty */ { $$ = NULL; }
|
|
| '#' '(' ')' { $$ = NULL; }
|
|
// // IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')'
|
|
// // IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')'
|
|
// // Can't just do that as "," conflicts with between vars and between stmts, so
|
|
// // split into pre-comma and post-comma parts
|
|
| '#' '(' {VARRESET_LIST(GPARAM);} paramPortDeclOrArgList ')' { $$ = $4; VARRESET_NONLIST(UNKNOWN); }
|
|
// // Note legal to start with "a=b" with no parameter statement
|
|
;
|
|
|
|
paramPortDeclOrArgList<nodep>: // IEEE: list_of_param_assignments + { parameter_port_declaration }
|
|
paramPortDeclOrArg { $$ = $1; }
|
|
| paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
paramPortDeclOrArg<nodep>: // IEEE: param_assignment + parameter_port_declaration
|
|
// // We combine the two as we can't tell which follows a comma
|
|
param_assignment { $$ = $1; }
|
|
| parameter_port_declarationFront param_assignment { $$ = $2; }
|
|
;
|
|
|
|
portsStarE<nodep>: // IEEE: .* + list_of_ports + list_of_port_declarations + empty
|
|
/* empty */ { $$ = NULL; }
|
|
| '(' ')' { $$ = NULL; }
|
|
// // .* expanded from module_declaration
|
|
//UNSUP '(' yP_DOTSTAR ')' { UNSUP }
|
|
| '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); }
|
|
;
|
|
|
|
list_of_ports<nodep>: // IEEE: list_of_ports + list_of_port_declarations
|
|
port { $$ = $1; }
|
|
| list_of_ports ',' port { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
port<nodep>: // ==IEEE: port
|
|
// // Though not type for interfaces, we factor out the port direction and type
|
|
// // so we can simply handle it in one place
|
|
//
|
|
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
|
|
// // Expanded interface_port_header
|
|
// // We use instantCb here because the non-port form looks just like a module instantiation
|
|
portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE
|
|
{ $$ = $3; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN);
|
|
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2));
|
|
$$->addNextNull(VARDONEP($$,$4,$5)); }
|
|
| portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig rangeListE sigAttrListE
|
|
{ $$ = $5; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN);
|
|
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2,*$4));
|
|
$$->addNextNull(VARDONEP($$,$6,$7)); }
|
|
| portDirNetE yINTERFACE portSig rangeListE sigAttrListE
|
|
{ $<fl>2->v3error("Unsupported: virtual interfaces"); $$=NULL; }
|
|
| portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE
|
|
{ $<fl>2->v3error("Unsupported: virtual interfaces"); $$=NULL; }
|
|
//
|
|
// // IEEE: ansi_port_declaration, with [port_direction] removed
|
|
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
|
|
// // IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')'
|
|
// // IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ]
|
|
// // Substitute net_port_header = [ port_direction ] net_port_type
|
|
// // Substitute variable_port_header = [ port_direction ] variable_port_type
|
|
// // Substitute net_port_type = [ net_type ] data_type_or_implicit
|
|
// // Substitute variable_port_type = var_data_type
|
|
// // Substitute var_data_type = data_type | yVAR data_type_or_implicit
|
|
// // [ [ port_direction ] net_port_type | interface_port_header ] port_identifier { unpacked_dimension }
|
|
// // [ [ port_direction ] var_data_type ] port_identifier variable_dimensionListE [ '=' constant_expression ]
|
|
// // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')'
|
|
//
|
|
// // Remove optional '[...] id' is in portAssignment
|
|
// // Remove optional '[port_direction]' is in port
|
|
// // net_port_type | interface_port_header port_identifier { unpacked_dimension }
|
|
// // net_port_type | interface_port_header port_identifier { unpacked_dimension }
|
|
// // var_data_type port_identifier variable_dimensionListE [ '=' constExpr ]
|
|
// // net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')'
|
|
// // Expand implicit_type
|
|
//
|
|
// // variable_dimensionListE instead of rangeListE to avoid conflicts
|
|
//
|
|
// // Note implicit rules looks just line declaring additional followon port
|
|
// // No VARDECL("port") for implicit, as we don't want to declare variables for them
|
|
//UNSUP portDirNetE data_type '.' portSig '(' portAssignExprE ')' sigAttrListE
|
|
//UNSUP { UNSUP }
|
|
//UNSUP portDirNetE yVAR data_type '.' portSig '(' portAssignExprE ')' sigAttrListE
|
|
//UNSUP { UNSUP }
|
|
//UNSUP portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE
|
|
//UNSUP { UNSUP }
|
|
//UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE
|
|
//UNSUP { UNSUP }
|
|
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE
|
|
//UNSUP { UNSUP }
|
|
//
|
|
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
|
|
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
|
|
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
|
|
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
|
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
|
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
|
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
|
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
|
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
|
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
|
|
//
|
|
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
{ $$=$3; VARDTYPE($2); AstVar* vp=VARDONEP($$,$4,$5); $$->addNextNull(vp); vp->valuep($7); }
|
|
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
{ $$=$4; VARDTYPE($3); AstVar* vp=VARDONEP($$,$5,$6); $$->addNextNull(vp); vp->valuep($8); }
|
|
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
{ $$=$4; VARDTYPE($3); AstVar* vp=VARDONEP($$,$5,$6); $$->addNextNull(vp); vp->valuep($8); }
|
|
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
{ $$=$2; /*VARDTYPE-same*/ AstVar* vp=VARDONEP($$,$3,$4); $$->addNextNull(vp); vp->valuep($6); }
|
|
;
|
|
|
|
portDirNetE: // IEEE: part of port, optional net type and/or direction
|
|
/* empty */ { }
|
|
// // Per spec, if direction given default the nettype.
|
|
// // The higher level rule may override this VARDTYPE with one later in the parse.
|
|
| port_direction { VARDECL(PORT); VARDTYPE(NULL/*default_nettype*/); }
|
|
| port_direction { VARDECL(PORT); } net_type { VARDTYPE(NULL/*default_nettype*/); } // net_type calls VARNET
|
|
| net_type { } // net_type calls VARNET
|
|
;
|
|
|
|
port_declNetE: // IEEE: part of port_declaration, optional net type
|
|
/* empty */ { }
|
|
| net_type { } // net_type calls VARNET
|
|
;
|
|
|
|
portSig<nodep>:
|
|
id/*port*/ { $$ = new AstPort($<fl>1,PINNUMINC(),*$1); }
|
|
| idSVKwd { $$ = new AstPort($<fl>1,PINNUMINC(),*$1); }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// Interface headers
|
|
|
|
interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
|
|
// // timeunits_delcarationE is instead in interface_item
|
|
intFront parameter_port_listE portsStarE ';'
|
|
interface_itemListE yENDINTERFACE endLabelE
|
|
{ if ($2) $1->addStmtp($2);
|
|
if ($3) $1->addStmtp($3);
|
|
if ($5) $1->addStmtp($5);
|
|
SYMP->popScope($1); }
|
|
//UNSUP yEXTERN intFront parameter_port_listE portsStarE ';' { }
|
|
;
|
|
|
|
intFront<modulep>:
|
|
yINTERFACE lifetimeE idAny/*new_interface*/
|
|
{ $$ = new AstIface($1,*$3);
|
|
$$->inLibrary(true);
|
|
PARSEP->rootp()->addModulep($$);
|
|
SYMP->pushNew($$); }
|
|
;
|
|
|
|
interface_itemListE<nodep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| interface_itemList { $$ = $1; }
|
|
;
|
|
|
|
interface_itemList<nodep>:
|
|
interface_item { $$ = $1; }
|
|
| interface_itemList interface_item { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
|
|
port_declaration ';' { $$ = $1; }
|
|
// // IEEE: non_port_interface_item
|
|
//UNSUP generate_region { $$ = $1; }
|
|
| interface_or_generate_item { $$ = $1; }
|
|
//UNSUP program_declaration { $$ = $1; }
|
|
//UNSUP interface_declaration { $$ = $1; }
|
|
| timeunits_declaration { $$ = $1; }
|
|
// // See note in interface_or_generate item
|
|
| module_common_item { $$ = $1; }
|
|
;
|
|
|
|
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
|
|
// // module_common_item in interface_item, as otherwise duplicated
|
|
// // with module_or_generate_item's module_common_item
|
|
modport_declaration { $$ = $1; }
|
|
//UNSUP extern_tf_declaration { $$ = $1; }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// Program headers
|
|
|
|
program_declaration: // IEEE: program_declaration + program_nonansi_header + program_ansi_header:
|
|
// // timeunits_delcarationE is instead in program_item
|
|
pgmFront parameter_port_listE portsStarE ';'
|
|
program_itemListE yENDPROGRAM endLabelE
|
|
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
|
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
|
if ($5) $1->addStmtp($5);
|
|
SYMP->popScope($1);
|
|
GRAMMARP->endLabel($<fl>7,$1,$7); }
|
|
//UNSUP yEXTERN pgmFront parameter_port_listE portsStarE ';'
|
|
//UNSUP { PARSEP->symPopScope(VAstType::PROGRAM); }
|
|
;
|
|
|
|
pgmFront<modulep>:
|
|
yPROGRAM lifetimeE idAny/*new_program*/
|
|
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
|
|
$$->modTrace(v3Global.opt.trace());
|
|
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
|
|
PARSEP->rootp()->addModulep($$);
|
|
SYMP->pushNew($$); }
|
|
;
|
|
|
|
program_itemListE<nodep>: // ==IEEE: [{ program_item }]
|
|
/* empty */ { $$ = NULL; }
|
|
| program_itemList { $$ = $1; }
|
|
;
|
|
|
|
program_itemList<nodep>: // ==IEEE: { program_item }
|
|
program_item { $$ = $1; }
|
|
| program_itemList program_item { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
program_item<nodep>: // ==IEEE: program_item
|
|
port_declaration ';' { $$ = $1; }
|
|
| non_port_program_item { $$ = $1; }
|
|
;
|
|
|
|
non_port_program_item<nodep>: // ==IEEE: non_port_program_item
|
|
continuous_assign { $$ = $1; }
|
|
| module_or_generate_item_declaration { $$ = $1; }
|
|
| initial_construct { $$ = $1; }
|
|
| final_construct { $$ = $1; }
|
|
| concurrent_assertion_item { $$ = $1; }
|
|
| timeunits_declaration { $$ = $1; }
|
|
| program_generate_item { $$ = $1; }
|
|
;
|
|
|
|
program_generate_item<nodep>: // ==IEEE: program_generate_item
|
|
loop_generate_construct { $$ = $1; }
|
|
| conditional_generate_construct { $$ = $1; }
|
|
| generate_region { $$ = $1; }
|
|
//UNSUP elaboration_system_task { $$ = $1; }
|
|
;
|
|
|
|
modport_declaration<nodep>: // ==IEEE: modport_declaration
|
|
yMODPORT modport_itemList ';' { $$ = $2; }
|
|
;
|
|
|
|
modport_itemList<nodep>: // IEEE: part of modport_declaration
|
|
modport_item { $$ = $1; }
|
|
| modport_itemList ',' modport_item { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
modport_item<nodep>: // ==IEEE: modport_item
|
|
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
|
|
;
|
|
|
|
modportPortsDeclList<nodep>:
|
|
modportPortsDecl { $$ = $1; }
|
|
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
|
|
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
|
|
// We've expanded the lists each take to instead just have standalone ID ports.
|
|
// We track the type as with the V2k series of defines, then create as each ID is seen.
|
|
modportPortsDecl<nodep>:
|
|
// // IEEE: modport_simple_ports_declaration
|
|
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
|
|
// // IEEE: modport_clocking_declaration
|
|
| yCLOCKING idAny/*clocking_identifier*/ { $1->v3error("Unsupported: Modport clocking"); }
|
|
// // IEEE: yIMPORT modport_tf_port
|
|
// // IEEE: yEXPORT modport_tf_port
|
|
// // modport_tf_port expanded here
|
|
| yIMPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($<fl>1,*$2,false); }
|
|
| yEXPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($<fl>1,*$2,true); }
|
|
| yIMPORT method_prototype { $1->v3error("Unsupported: Modport import with prototype"); }
|
|
| yEXPORT method_prototype { $1->v3error("Unsupported: Modport export with prototype"); }
|
|
// Continuations of above after a comma.
|
|
// // IEEE: modport_simple_ports_declaration
|
|
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
|
|
;
|
|
|
|
modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
|
|
id { $$ = $1; }
|
|
//UNSUP '.' idAny '(' ')' { }
|
|
//UNSUP '.' idAny '(' expr ')' { }
|
|
;
|
|
|
|
//************************************************
|
|
// Variable Declarations
|
|
|
|
genvar_declaration<nodep>: // ==IEEE: genvar_declaration
|
|
yGENVAR list_of_genvar_identifiers ';' { $$ = $2; }
|
|
;
|
|
|
|
list_of_genvar_identifiers<nodep>: // IEEE: list_of_genvar_identifiers (for declaration)
|
|
genvar_identifierDecl { $$ = $1; }
|
|
| list_of_genvar_identifiers ',' genvar_identifierDecl { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
genvar_identifierDecl<varp>: // IEEE: genvar_identifier (for declaration)
|
|
id/*new-genvar_identifier*/ sigAttrListE
|
|
{ VARRESET_NONLIST(GENVAR); VARDTYPE(new AstBasicDType($<fl>1,AstBasicDTypeKwd::INTEGER));
|
|
$$ = VARDONEA($<fl>1, *$1, NULL, $2); }
|
|
;
|
|
|
|
local_parameter_declaration<nodep>: // IEEE: local_parameter_declaration
|
|
// // See notes in parameter_declaration
|
|
local_parameter_declarationFront list_of_param_assignments { $$ = $2; }
|
|
;
|
|
|
|
parameter_declaration<nodep>: // IEEE: parameter_declaration
|
|
// // IEEE: yPARAMETER yTYPE list_of_type_assignments ';'
|
|
// // Instead of list_of_type_assignments
|
|
// // we use list_of_param_assignments because for port handling
|
|
// // it already must accept types, so simpler to have code only one place
|
|
parameter_declarationFront list_of_param_assignments { $$ = $2; }
|
|
;
|
|
|
|
local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment
|
|
varLParamReset implicit_typeE { /*VARRESET-in-varLParam*/ VARDTYPE($2); }
|
|
| varLParamReset data_type { /*VARRESET-in-varLParam*/ VARDTYPE($2); }
|
|
//UNSUP varLParamReset yTYPE { /*VARRESET-in-varLParam*/ VARDTYPE($2); }
|
|
;
|
|
|
|
parameter_declarationFront: // IEEE: parameter_declaration w/o assignment
|
|
varGParamReset implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
|
|
| varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
|
|
//UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
|
|
;
|
|
|
|
parameter_port_declarationFront: // IEEE: parameter_port_declaration w/o assignment
|
|
// // IEEE: parameter_declaration (minus assignment)
|
|
parameter_declarationFront { }
|
|
//
|
|
//UNSUP data_type { VARDTYPE($1); }
|
|
//UNSUP yTYPE { VARDTYPE($1); }
|
|
;
|
|
|
|
net_declaration<nodep>: // IEEE: net_declaration - excluding implict
|
|
net_declarationFront netSigList ';' { $$ = $2; }
|
|
;
|
|
|
|
net_declarationFront: // IEEE: beginning of net_declaration
|
|
net_declRESET net_type strengthSpecE net_scalaredE net_dataType { VARDTYPE($5); }
|
|
;
|
|
|
|
net_declRESET:
|
|
/* empty */ { VARRESET_NONLIST(UNKNOWN); }
|
|
;
|
|
|
|
net_scalaredE:
|
|
/* empty */ { }
|
|
//UNSUP: ySCALARED/yVECTORED ignored
|
|
| ySCALARED { }
|
|
| yVECTORED { }
|
|
;
|
|
|
|
net_dataType<dtypep>:
|
|
// // If there's a SV data type there shouldn't be a delay on this wire
|
|
// // Otherwise #(...) can't be determined to be a delay or parameters
|
|
// // Submit this as a footnote to the committee
|
|
var_data_type { $$ = $1; }
|
|
| signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); } // not implicit
|
|
| signing { $$ = new AstBasicDType($<fl>1, LOGIC, $1); } // not implicit
|
|
| /*implicit*/ delayE { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
|
|
;
|
|
|
|
net_type: // ==IEEE: net_type
|
|
ySUPPLY0 { VARDECL(SUPPLY0); }
|
|
| ySUPPLY1 { VARDECL(SUPPLY1); }
|
|
| yTRI { VARDECL(TRIWIRE); }
|
|
| yTRI0 { VARDECL(TRI0); }
|
|
| yTRI1 { VARDECL(TRI1); }
|
|
//UNSUP yTRIAND { VARDECL(TRIAND); }
|
|
//UNSUP yTRIOR { VARDECL(TRIOR); }
|
|
//UNSUP yTRIREG { VARDECL(TRIREG); }
|
|
//UNSUP yWAND { VARDECL(WAND); }
|
|
| yWIRE { VARDECL(WIRE); }
|
|
//UNSUP yWOR { VARDECL(WOR); }
|
|
;
|
|
|
|
varGParamReset:
|
|
yPARAMETER { VARRESET_NONLIST(GPARAM); }
|
|
;
|
|
|
|
varLParamReset:
|
|
yLOCALPARAM { VARRESET_NONLIST(LPARAM); }
|
|
;
|
|
|
|
port_direction: // ==IEEE: port_direction + tf_port_direction
|
|
// // IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here
|
|
yINPUT { VARIO(INPUT); }
|
|
| yOUTPUT { VARIO(OUTPUT); }
|
|
| yINOUT { VARIO(INOUT); }
|
|
//UNSUP yREF { VARIO(REF); }
|
|
//UNSUP yCONST__REF yREF { VARIO(CONSTREF); }
|
|
;
|
|
|
|
port_directionReset: // IEEE: port_direction that starts a port_declaraiton
|
|
// // Used only for declarations outside the port list
|
|
yINPUT { VARRESET_NONLIST(UNKNOWN); VARIO(INPUT); }
|
|
| yOUTPUT { VARRESET_NONLIST(UNKNOWN); VARIO(OUTPUT); }
|
|
| yINOUT { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); }
|
|
//UNSUP yREF { VARRESET_NONLIST(UNKNOWN); VARIO(REF); }
|
|
//UNSUP yCONST__REF yREF { VARRESET_NONLIST(UNKNOWN); VARIO(CONSTREF); }
|
|
;
|
|
|
|
port_declaration<nodep>: // ==IEEE: port_declaration
|
|
// // Used inside block; followed by ';'
|
|
// // SIMILAR to tf_port_declaration
|
|
//
|
|
// // IEEE: inout_declaration
|
|
// // IEEE: input_declaration
|
|
// // IEEE: output_declaration
|
|
// // IEEE: ref_declaration
|
|
port_directionReset port_declNetE data_type { VARDTYPE($3); }
|
|
list_of_variable_decl_assignments { $$ = $5; }
|
|
| port_directionReset port_declNetE yVAR data_type { VARDTYPE($4); }
|
|
list_of_variable_decl_assignments { $$ = $6; }
|
|
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
|
|
list_of_variable_decl_assignments { $$ = $6; }
|
|
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4,true)); }
|
|
list_of_variable_decl_assignments { $$ = $6; }
|
|
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
|
|
list_of_variable_decl_assignments { $$ = $5; }
|
|
| port_directionReset port_declNetE /*implicit*/ { VARDTYPE(NULL);/*default_nettype*/}
|
|
list_of_variable_decl_assignments { $$ = $4; }
|
|
;
|
|
|
|
tf_port_declaration<nodep>: // ==IEEE: tf_port_declaration
|
|
// // Used inside function; followed by ';'
|
|
// // SIMILAR to port_declaration
|
|
//
|
|
port_directionReset data_type { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; }
|
|
| port_directionReset implicit_typeE { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; }
|
|
| port_directionReset yVAR data_type { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; }
|
|
| port_directionReset yVAR implicit_typeE { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; }
|
|
;
|
|
|
|
integer_atom_type<bdtypep>: // ==IEEE: integer_atom_type
|
|
yBYTE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BYTE); }
|
|
| ySHORTINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::SHORTINT); }
|
|
| yINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INT); }
|
|
| yLONGINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LONGINT); }
|
|
| yINTEGER { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INTEGER); }
|
|
| yTIME { $$ = new AstBasicDType($1,AstBasicDTypeKwd::TIME); }
|
|
;
|
|
|
|
integer_vector_type<bdtypep>: // ==IEEE: integer_atom_type
|
|
yBIT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); }
|
|
| yLOGIC { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); }
|
|
| yREG { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); } // logic==reg
|
|
;
|
|
|
|
non_integer_type<bdtypep>: // ==IEEE: non_integer_type
|
|
yREAL { $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
|
|
| yREALTIME { $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
|
|
//UNSUP ySHORTREAL { $$ = new AstBasicDType($1,AstBasicDTypeKwd::FLOAT); }
|
|
// // VAMS - somewhat hackish
|
|
| yWREAL { $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); VARDECL(WIRE); }
|
|
;
|
|
|
|
signingE<signstate>: // IEEE: signing - plus empty
|
|
/*empty*/ { $$ = signedst_NOSIGN; }
|
|
| signing { $$ = $1; }
|
|
;
|
|
|
|
signing<signstate>: // ==IEEE: signing
|
|
ySIGNED { $<fl>$ = $<fl>1; $$ = signedst_SIGNED; }
|
|
| yUNSIGNED { $<fl>$ = $<fl>1; $$ = signedst_UNSIGNED; }
|
|
;
|
|
|
|
//************************************************
|
|
// Data Types
|
|
|
|
casting_type<dtypep>: // IEEE: casting_type
|
|
simple_type { $$ = $1; }
|
|
// // IEEE: constant_primary
|
|
// // In expr:cast this is expanded to just "expr"
|
|
//
|
|
// // IEEE: signing
|
|
//See where casting_type used
|
|
//^^ ySIGNED { $$ = new AstSigned($1,$3); }
|
|
//^^ yUNSIGNED { $$ = new AstUnsigned($1,$3); }
|
|
//UNSUP ySTRING { $$ = $1; }
|
|
//UNSUP yCONST__ETC/*then `*/ { $$ = $1; }
|
|
;
|
|
|
|
simple_type<dtypep>: // ==IEEE: simple_type
|
|
// // IEEE: integer_type
|
|
integer_atom_type { $$ = $1; }
|
|
| integer_vector_type { $$ = $1; }
|
|
| non_integer_type { $$ = $1; }
|
|
// // IEEE: ps_type_identifier
|
|
// // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE)
|
|
| ps_type { $$ = $1; }
|
|
// // { generate_block_identifer ... } '.'
|
|
// // Need to determine if generate_block_identifier can be lex-detected
|
|
;
|
|
|
|
data_type<dtypep>: // ==IEEE: data_type
|
|
// // This expansion also replicated elsewhere, IE data_type__AndID
|
|
data_typeNoRef { $$ = $1; }
|
|
// // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension }
|
|
| ps_type packed_dimensionListE { $$ = GRAMMARP->createArray($1,$2,true); }
|
|
//UNSUP class_scope_type packed_dimensionListE { UNSUP }
|
|
// // IEEE: class_type
|
|
//UNSUP class_typeWithoutId { $$ = $1; }
|
|
// // IEEE: ps_covergroup_identifier
|
|
// // we put covergroups under ps_type, so can ignore this
|
|
;
|
|
|
|
data_typeBasic<dtypep>: // IEEE: part of data_type
|
|
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
|
|
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
|
| non_integer_type { $$ = $1; }
|
|
;
|
|
|
|
data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc references
|
|
data_typeBasic { $$ = $1; }
|
|
| struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
|
|
GRAMMARP->m_modp,VFlagChildDType(),$1),$2,true); }
|
|
| enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
|
|
GRAMMARP->m_modp,VFlagChildDType(),$1); }
|
|
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
|
|
| yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
|
|
//UNSUP yEVENT { UNSUP }
|
|
//UNSUP yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ { UNSUP }
|
|
//UNSUP yVIRTUAL__anyID id/*interface*/ { UNSUP }
|
|
//UNSUP type_reference { UNSUP }
|
|
// // IEEE: class_scope: see data_type above
|
|
// // IEEE: class_type: see data_type above
|
|
// // IEEE: ps_covergroup: see data_type above
|
|
;
|
|
|
|
data_type_or_void<dtypep>: // ==IEEE: data_type_or_void
|
|
data_type { $$ = $1; }
|
|
//UNSUP yVOID { UNSUP } // No yTAGGED structures
|
|
;
|
|
|
|
var_data_type<dtypep>: // ==IEEE: var_data_type
|
|
data_type { $$ = $1; }
|
|
| yVAR data_type { $$ = $2; }
|
|
| yVAR implicit_typeE { $$ = $2; }
|
|
;
|
|
|
|
struct_unionDecl<classp>: // IEEE: part of data_type
|
|
// // packedSigningE is NOP for unpacked
|
|
ySTRUCT packedSigningE '{' { $<classp>$ = new AstStructDType($1, $2); SYMP->pushNew($<classp>$); }
|
|
/*cont*/ struct_union_memberList '}'
|
|
{ $$=$<classp>4; $$->addMembersp($5); SYMP->popScope($$); }
|
|
| yUNION taggedE packedSigningE '{' { $<classp>$ = new AstUnionDType($1, $3); SYMP->pushNew($<classp>$); }
|
|
/*cont*/ struct_union_memberList '}'
|
|
{ $$=$<classp>5; $$->addMembersp($6); SYMP->popScope($$); }
|
|
;
|
|
|
|
struct_union_memberList<nodep>: // IEEE: { struct_union_member }
|
|
struct_union_member { $$ = $1; }
|
|
| struct_union_memberList struct_union_member { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
struct_union_member<nodep>: // ==IEEE: struct_union_member
|
|
random_qualifierE data_type_or_void
|
|
{ GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member.
|
|
/*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = NULL; }
|
|
;
|
|
|
|
list_of_member_decl_assignments<nodep>: // Derived from IEEE: list_of_variable_decl_assignments
|
|
member_decl_assignment { $$ = $1; }
|
|
| list_of_member_decl_assignments ',' member_decl_assignment { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
member_decl_assignment<memberp>: // Derived from IEEE: variable_decl_assignment
|
|
// // At present we allow only packed structures/unions. So this is different from variable_decl_assignment
|
|
id variable_dimensionListE
|
|
{ if ($2) $2->v3error("Unsupported: Unpacked array in packed struct/union");
|
|
$$ = new AstMemberDType($<fl>1, *$1, VFlagChildDType(), GRAMMARP->m_memDTypep->cloneTree(true)); }
|
|
| id variable_dimensionListE '=' variable_declExpr
|
|
{ $4->v3error("Unsupported: Initial values in struct/union members."); }
|
|
| idSVKwd { $$ = NULL; }
|
|
//
|
|
// // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
|
|
// // Matches above with variable_dimensionE = "[]"
|
|
// // IEEE: "class_variable_identifier [ '=' class_new ]"
|
|
// // variable_dimensionE must be empty
|
|
// // Pushed into variable_declExpr:dynamic_array_new
|
|
//
|
|
// // IEEE: "[ covergroup_variable_identifier ] '=' class_new
|
|
// // Pushed into variable_declExpr:class_new
|
|
//UNSUP '=' class_new { UNSUP }
|
|
;
|
|
|
|
list_of_variable_decl_assignments<nodep>: // ==IEEE: list_of_variable_decl_assignments
|
|
variable_decl_assignment { $$ = $1; }
|
|
| list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
variable_decl_assignment<varp>: // ==IEEE: variable_decl_assignment
|
|
id variable_dimensionListE sigAttrListE
|
|
{ $$ = VARDONEA($<fl>1,*$1,$2,$3); }
|
|
| id variable_dimensionListE sigAttrListE '=' variable_declExpr
|
|
{ $$ = VARDONEA($<fl>1,*$1,$2,$3); $$->valuep($5); }
|
|
| idSVKwd { $$ = NULL; }
|
|
//
|
|
// // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
|
|
// // Matches above with variable_dimensionE = "[]"
|
|
// // IEEE: "class_variable_identifier [ '=' class_new ]"
|
|
// // variable_dimensionE must be empty
|
|
// // Pushed into variable_declExpr:dynamic_array_new
|
|
//
|
|
// // IEEE: "[ covergroup_variable_identifier ] '=' class_new
|
|
// // Pushed into variable_declExpr:class_new
|
|
//UNSUP '=' class_new { UNSUP }
|
|
;
|
|
|
|
list_of_tf_variable_identifiers<nodep>: // ==IEEE: list_of_tf_variable_identifiers
|
|
tf_variable_identifier { $$ = $1; }
|
|
| list_of_tf_variable_identifiers ',' tf_variable_identifier { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
tf_variable_identifier<varp>: // IEEE: part of list_of_tf_variable_identifiers
|
|
id variable_dimensionListE sigAttrListE
|
|
{ $$ = VARDONEA($<fl>1,*$1, $2, $3); }
|
|
| id variable_dimensionListE sigAttrListE '=' expr
|
|
{ $$ = VARDONEA($<fl>1,*$1, $2, $3);
|
|
$$->addNext(new AstAssign($4, new AstVarRef($4, *$1, true), $5)); }
|
|
;
|
|
|
|
variable_declExpr<nodep>: // IEEE: part of variable_decl_assignment - rhs of expr
|
|
expr { $$ = $1; }
|
|
//UNSUP dynamic_array_new { $$ = $1; }
|
|
//UNSUP class_new { $$ = $1; }
|
|
;
|
|
|
|
variable_dimensionListE<rangep>: // IEEE: variable_dimension + empty
|
|
/*empty*/ { $$ = NULL; }
|
|
| variable_dimensionList { $$ = $1; }
|
|
;
|
|
|
|
variable_dimensionList<rangep>: // IEEE: variable_dimension + empty
|
|
variable_dimension { $$ = $1; }
|
|
| variable_dimensionList variable_dimension { $$ = $1->addNext($2)->castRange(); }
|
|
;
|
|
|
|
variable_dimension<rangep>: // ==IEEE: variable_dimension
|
|
// // IEEE: unsized_dimension
|
|
//UNSUP '[' ']' { UNSUP }
|
|
// // IEEE: unpacked_dimension
|
|
anyrange { $$ = $1; }
|
|
| '[' constExpr ']' { $$ = new AstRange($1,new AstSub($1,$2, new AstConst($1,1)), new AstConst($1,0)); }
|
|
// // IEEE: associative_dimension
|
|
//UNSUP '[' data_type ']' { UNSUP }
|
|
//UNSUP yP_BRASTAR ']' { UNSUP }
|
|
//UNSUP '[' '*' ']' { UNSUP }
|
|
// // IEEE: queue_dimension
|
|
// // '[' '$' ']' -- $ is part of expr
|
|
// // '[' '$' ':' expr ']' -- anyrange:expr:$
|
|
;
|
|
|
|
random_qualifierE: // IEEE: random_qualifier + empty
|
|
/*empty*/ { }
|
|
| random_qualifier { }
|
|
;
|
|
|
|
random_qualifier: // ==IEEE: random_qualifier
|
|
yRAND { } // Ignored until we support randomize()
|
|
| yRANDC { } // Ignored until we support randomize()
|
|
;
|
|
|
|
taggedE:
|
|
/*empty*/ { }
|
|
//UNSUP yTAGGED { UNSUP }
|
|
;
|
|
|
|
packedSigningE<signstate>:
|
|
// // AstNumeric::NOSIGN overloaded to indicate not packed
|
|
/*empty*/ { $$ = signedst_NOSIGN; }
|
|
| yPACKED signingE { $$ = $2; if ($$ == signedst_NOSIGN) $$ = signedst_UNSIGNED; }
|
|
;
|
|
|
|
//************************************************
|
|
// enum
|
|
|
|
// IEEE: part of data_type
|
|
enumDecl<dtypep>:
|
|
yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,VFlagChildDType(),$2,$4); }
|
|
;
|
|
|
|
enum_base_typeE<dtypep>: // IEEE: enum_base_type
|
|
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
|
|
// // Not in spec, but obviously "enum [1:0]" should work
|
|
// // implicit_type expanded, without empty
|
|
// // Note enum base types are always packed data types
|
|
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
|
|
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
|
//
|
|
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
|
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
|
|
// // below can be idAny or yaID__aTYPE
|
|
// // IEEE requires a type, though no shift conflict if idAny
|
|
| idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, true); }
|
|
;
|
|
|
|
enum_nameList<nodep>:
|
|
enum_name_declaration { $$ = $1; }
|
|
| enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
enum_name_declaration<nodep>: // ==IEEE: enum_name_declaration
|
|
idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($<fl>1, *$1, $2, $3); }
|
|
;
|
|
|
|
enumNameRangeE<nodep>: // IEEE: second part of enum_name_declaration
|
|
/* empty */ { $$ = NULL; }
|
|
| '[' intnumAsConst ']' { $$ = new AstRange($1,new AstConst($1,0), $2); }
|
|
| '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); }
|
|
;
|
|
|
|
enumNameStartE<nodep>: // IEEE: third part of enum_name_declaration
|
|
/* empty */ { $$ = NULL; }
|
|
| '=' constExpr { $$ = $2; }
|
|
;
|
|
|
|
intnumAsConst<nodep>:
|
|
yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
|
|
;
|
|
|
|
//************************************************
|
|
// Typedef
|
|
|
|
data_declaration<nodep>: // ==IEEE: data_declaration
|
|
// // VARRESET can't be called here - conflicts
|
|
data_declarationVar { $$ = $1; }
|
|
| type_declaration { $$ = $1; }
|
|
| package_import_declaration { $$ = $1; }
|
|
// // IEEE: virtual_interface_declaration
|
|
// // "yVIRTUAL yID yID" looks just like a data_declaration
|
|
// // Therefore the virtual_interface_declaration term isn't used
|
|
;
|
|
|
|
data_declarationVar<nodep>: // IEEE: part of data_declaration
|
|
// // The first declaration has complications between assuming what's the type vs ID declaring
|
|
data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; }
|
|
;
|
|
|
|
data_declarationVarFront: // IEEE: part of data_declaration
|
|
// // Expanded: "constE yVAR lifetimeE data_type"
|
|
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
|
|
/**/ yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); }
|
|
| /**/ yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
|
|
| /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,true)); }
|
|
//
|
|
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
|
|
| yCONST__ETC yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), $4)); }
|
|
| yCONST__ETC yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), new AstBasicDType($<fl>2, LOGIC_IMPLICIT))); }
|
|
| yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,true))); }
|
|
//
|
|
// // Expanded: "constE lifetimeE data_type"
|
|
| /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); }
|
|
| /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARDTYPE($2); }
|
|
| yCONST__ETC lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), $3)); }
|
|
// // = class_new is in variable_decl_assignment
|
|
;
|
|
|
|
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
|
// // Also expanded in data_declaration
|
|
/* empty */ { $$ = NULL; }
|
|
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
|
|
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
|
;
|
|
|
|
type_declaration<nodep>: // ==IEEE: type_declaration
|
|
// // Use idAny, as we can redeclare a typedef on an existing typedef
|
|
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
|
|
SYMP->reinsert($$); }
|
|
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
|
|
// // Combines into above "data_type id" rule
|
|
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
|
| yTYPEDEF id ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$2); SYMP->reinsert($$); }
|
|
| yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
|
| yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
|
| yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
|
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
|
;
|
|
|
|
//************************************************
|
|
// Module Items
|
|
|
|
module_itemListE<nodep>: // IEEE: Part of module_declaration
|
|
/* empty */ { $$ = NULL; }
|
|
| module_itemList { $$ = $1; }
|
|
;
|
|
|
|
module_itemList<nodep>: // IEEE: Part of module_declaration
|
|
module_item { $$ = $1; }
|
|
| module_itemList module_item { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
module_item<nodep>: // ==IEEE: module_item
|
|
port_declaration ';' { $$ = $1; }
|
|
| non_port_module_item { $$ = $1; }
|
|
;
|
|
|
|
non_port_module_item<nodep>: // ==IEEE: non_port_module_item
|
|
generate_region { $$ = $1; }
|
|
| module_or_generate_item { $$ = $1; }
|
|
| specify_block { $$ = $1; }
|
|
| specparam_declaration { $$ = $1; }
|
|
//UNSUP program_declaration { $$ = $1; }
|
|
//UNSUP module_declaration { $$ = $1; }
|
|
//UNSUP interface_declaration { $$ = $1; }
|
|
| timeunits_declaration { $$ = $1; }
|
|
// // Verilator specific
|
|
| yaSCHDR { $$ = new AstScHdr($<fl>1,*$1); }
|
|
| yaSCINT { $$ = new AstScInt($<fl>1,*$1); }
|
|
| yaSCIMP { $$ = new AstScImp($<fl>1,*$1); }
|
|
| yaSCIMPH { $$ = new AstScImpHdr($<fl>1,*$1); }
|
|
| yaSCCTOR { $$ = new AstScCtor($<fl>1,*$1); }
|
|
| yaSCDTOR { $$ = new AstScDtor($<fl>1,*$1); }
|
|
| yVL_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::INLINE_MODULE); }
|
|
| yVL_NO_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_MODULE); }
|
|
| yVL_PUBLIC_MODULE { $$ = new AstPragma($1,AstPragmaType::PUBLIC_MODULE); v3Global.dpi(true); }
|
|
;
|
|
|
|
module_or_generate_item<nodep>: // ==IEEE: module_or_generate_item
|
|
// // IEEE: parameter_override
|
|
yDEFPARAM list_of_defparam_assignments ';' { $$ = $2; }
|
|
// // IEEE: gate_instantiation + udp_instantiation + module_instantiation
|
|
// // not here, see etcInst in module_common_item
|
|
// // We joined udp & module definitions, so this goes here
|
|
| combinational_body { $$ = $1; }
|
|
// // This module_common_item shared with interface_or_generate_item:module_common_item
|
|
| module_common_item { $$ = $1; }
|
|
;
|
|
|
|
module_common_item<nodep>: // ==IEEE: module_common_item
|
|
module_or_generate_item_declaration { $$ = $1; }
|
|
// // IEEE: interface_instantiation
|
|
// // + IEEE: program_instantiation
|
|
// // + module_instantiation from module_or_generate_item
|
|
| etcInst { $$ = $1; }
|
|
| concurrent_assertion_item { $$ = $1; }
|
|
| bind_directive { $$ = $1; }
|
|
| continuous_assign { $$ = $1; }
|
|
// // IEEE: net_alias
|
|
//UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP }
|
|
| initial_construct { $$ = $1; }
|
|
| final_construct { $$ = $1; }
|
|
// // IEEE: always_construct
|
|
// // Verilator only - event_control attached to always
|
|
| yALWAYS event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, $2,$3); }
|
|
| yALWAYS_FF event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, $2,$3); }
|
|
| yALWAYS_COMB event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, $2,$3); }
|
|
| yALWAYS_LATCH event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); }
|
|
| loop_generate_construct { $$ = $1; }
|
|
| conditional_generate_construct { $$ = $1; }
|
|
// // Verilator only
|
|
| pslStmt { $$ = $1; }
|
|
//
|
|
| error ';' { $$ = NULL; }
|
|
;
|
|
|
|
continuous_assign<nodep>: // IEEE: continuous_assign
|
|
yASSIGN delayE assignList ';' { $$ = $3; }
|
|
//UNSUP: strengthSpecE not in above assign
|
|
;
|
|
|
|
initial_construct<nodep>: // IEEE: initial_construct
|
|
yINITIAL stmtBlock { $$ = new AstInitial($1,$2); }
|
|
;
|
|
|
|
final_construct<nodep>: // IEEE: final_construct
|
|
yFINAL stmtBlock { $$ = new AstFinal($1,$2); }
|
|
;
|
|
|
|
module_or_generate_item_declaration<nodep>: // ==IEEE: module_or_generate_item_declaration
|
|
package_or_generate_item_declaration { $$ = $1; }
|
|
| genvar_declaration { $$ = $1; }
|
|
| clocking_declaration { $$ = $1; }
|
|
//UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; }
|
|
;
|
|
|
|
bind_directive<nodep>: // ==IEEE: bind_directive + bind_target_scope
|
|
// // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation
|
|
// // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier
|
|
yBIND bind_target_instance bind_instantiation { $$ = new AstBind($<fl>1,*$2,$3); }
|
|
| yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation { $$=NULL; $1->v3error("Unsupported: Bind with instance list"); }
|
|
;
|
|
|
|
bind_target_instance_list: // ==IEEE: bind_target_instance_list
|
|
bind_target_instance { }
|
|
| bind_target_instance_list ',' bind_target_instance { }
|
|
;
|
|
|
|
bind_target_instance<strp>: // ==IEEE: bind_target_instance
|
|
//UNSUP hierarchical_identifierBit { }
|
|
idAny { $$ = $1; }
|
|
;
|
|
|
|
bind_instantiation<nodep>: // ==IEEE: bind_instantiation
|
|
// // IEEE: program_instantiation
|
|
// // IEEE: + module_instantiation
|
|
// // IEEE: + interface_instantiation
|
|
// // Need to get an AstBind instead of AstCell, so have special rules
|
|
instDecl { $$ = $1; }
|
|
;
|
|
|
|
//************************************************
|
|
// Generates
|
|
//
|
|
// Way down in generate_item is speced a difference between module,
|
|
// interface and checker generates. modules and interfaces are almost
|
|
// identical (minus DEFPARAMs) so we overlap them. Checkers are too
|
|
// different, so we copy all rules for checkers.
|
|
|
|
generate_region<nodep>: // ==IEEE: generate_region
|
|
yGENERATE genItemList yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
|
| yGENERATE yENDGENERATE { $$ = NULL; }
|
|
;
|
|
|
|
generate_block_or_null<nodep>: // IEEE: generate_block_or_null
|
|
// ';' // is included in
|
|
// // IEEE: generate_block
|
|
// // Must always return a BEGIN node, or NULL - see GenFor construction
|
|
generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"genblk",$1,true)) : NULL; }
|
|
| genItemBegin { $$ = $1; }
|
|
;
|
|
|
|
genItemBegin<nodep>: // IEEE: part of generate_block
|
|
yBEGIN genItemList yEND { $$ = new AstBegin($1,"genblk",$2,true); }
|
|
| yBEGIN yEND { $$ = NULL; }
|
|
| id ':' yBEGIN genItemList yEND endLabelE { $$ = new AstBegin($2,*$1,$4,true); GRAMMARP->endLabel($<fl>6,*$1,$6); }
|
|
| id ':' yBEGIN yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($<fl>5,*$1,$5); }
|
|
| yBEGIN ':' idAny genItemList yEND endLabelE { $$ = new AstBegin($2,*$3,$4,true); GRAMMARP->endLabel($<fl>6,*$3,$6); }
|
|
| yBEGIN ':' idAny yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($<fl>5,*$3,$5); }
|
|
;
|
|
|
|
genItemOrBegin<nodep>: // Not in IEEE, but our begin isn't under generate_item
|
|
~c~generate_item { $$ = $1; }
|
|
| ~c~genItemBegin { $$ = $1; }
|
|
;
|
|
|
|
genItemList<nodep>:
|
|
~c~genItemOrBegin { $$ = $1; }
|
|
| ~c~genItemList ~c~genItemOrBegin { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
generate_item<nodep>: // IEEE: module_or_interface_or_generate_item
|
|
// // Only legal when in a generate under a module (or interface under a module)
|
|
module_or_generate_item { $$ = $1; }
|
|
// // Only legal when in a generate under an interface
|
|
//UNSUP interface_or_generate_item { $$ = $1; }
|
|
// // IEEE: checker_or_generate_item
|
|
// // Only legal when in a generate under a checker
|
|
// // so below in c_generate_item
|
|
;
|
|
|
|
conditional_generate_construct<nodep>: // ==IEEE: conditional_generate_construct
|
|
yCASE '(' expr ')' ~c~case_generate_itemListE yENDCASE { $$ = new AstGenCase($1,$3,$5); }
|
|
| yIF '(' expr ')' generate_block_or_null %prec prLOWER_THAN_ELSE { $$ = new AstGenIf($1,$3,$5,NULL); }
|
|
| yIF '(' expr ')' generate_block_or_null yELSE generate_block_or_null { $$ = new AstGenIf($1,$3,$5,$7); }
|
|
;
|
|
|
|
loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct
|
|
yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null
|
|
{ // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar
|
|
AstBegin* lowerBegp = $9->castBegin();
|
|
if ($9 && !lowerBegp) $9->v3fatalSrc("Child of GENFOR should have been begin");
|
|
if (!lowerBegp) lowerBegp = new AstBegin($1,"genblk",NULL,true); // Empty body
|
|
AstNode* lowerNoBegp = lowerBegp->stmtsp();
|
|
if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext();
|
|
//
|
|
AstBegin* blkp = new AstBegin($1,lowerBegp->name(),NULL,true);
|
|
// V3LinkDot detects BEGIN(GENFOR(...)) as a special case
|
|
AstNode* initp = $3; AstNode* varp = $3;
|
|
if (varp->castVar()) { // Genvar
|
|
initp = varp->nextp();
|
|
initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init
|
|
blkp->addStmtsp(varp);
|
|
}
|
|
// Statements are under 'genforp' as cells under this
|
|
// for loop won't get an extra layer of hierarchy tacked on
|
|
blkp->addGenforp(new AstGenFor($1,initp,$5,$7,lowerNoBegp));
|
|
$$ = blkp;
|
|
lowerBegp->deleteTree(); lowerBegp=NULL;
|
|
}
|
|
;
|
|
|
|
genvar_initialization<nodep>: // ==IEEE: genvar_initalization
|
|
varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); }
|
|
| yGENVAR genvar_identifierDecl '=' constExpr { $$ = $2; $2->addNext(new AstAssign($3,new AstVarRef($3,$2,true), $4)); }
|
|
;
|
|
|
|
genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
|
varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); }
|
|
| varRefBase yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
|
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
|
// // inc_or_dec_operator
|
|
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstMathStmt?
|
|
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
|
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
|
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
|
| varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
|
;
|
|
|
|
case_generate_itemListE<nodep>: // IEEE: [{ case_generate_itemList }]
|
|
/* empty */ { $$ = NULL; }
|
|
| case_generate_itemList { $$ = $1; }
|
|
;
|
|
|
|
case_generate_itemList<nodep>: // IEEE: { case_generate_itemList }
|
|
~c~case_generate_item { $$=$1; }
|
|
| ~c~case_generate_itemList ~c~case_generate_item { $$=$1; $1->addNext($2); }
|
|
;
|
|
|
|
case_generate_item<nodep>: // ==IEEE: case_generate_item
|
|
caseCondList ':' generate_block_or_null { $$ = new AstCaseItem($2,$1,$3); }
|
|
| yDEFAULT ':' generate_block_or_null { $$ = new AstCaseItem($2,NULL,$3); }
|
|
| yDEFAULT generate_block_or_null { $$ = new AstCaseItem($1,NULL,$2); }
|
|
;
|
|
|
|
//************************************************
|
|
// Assignments and register declarations
|
|
|
|
assignList<nodep>:
|
|
assignOne { $$ = $1; }
|
|
| assignList ',' assignOne { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
assignOne<nodep>:
|
|
variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); }
|
|
;
|
|
|
|
delayE:
|
|
/* empty */ { }
|
|
| delay_control { $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); } /* ignored */
|
|
;
|
|
|
|
delay_control<fl>: //== IEEE: delay_control
|
|
'#' delay_value { $$ = $1; } /* ignored */
|
|
| '#' '(' minTypMax ')' { $$ = $1; } /* ignored */
|
|
| '#' '(' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */
|
|
| '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */
|
|
;
|
|
|
|
delay_value: // ==IEEE:delay_value
|
|
// // IEEE: ps_identifier
|
|
ps_id_etc { }
|
|
| yaINTNUM { }
|
|
| yaFLOATNUM { }
|
|
| yaTIMENUM { }
|
|
;
|
|
|
|
delayExpr:
|
|
expr { DEL($1); }
|
|
// // Verilator doesn't support yaTIMENUM, so not in expr
|
|
| yaTIMENUM { }
|
|
;
|
|
|
|
minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression
|
|
delayExpr { }
|
|
| delayExpr ':' delayExpr ':' delayExpr { }
|
|
;
|
|
|
|
netSigList<varp>: // IEEE: list_of_port_identifiers
|
|
netSig { $$ = $1; }
|
|
| netSigList ',' netSig { $$ = $1; $1->addNext($3); }
|
|
;
|
|
|
|
netSig<varp>: // IEEE: net_decl_assignment - one element from list_of_port_identifiers
|
|
netId sigAttrListE { $$ = VARDONEA($<fl>1,*$1, NULL, $2); }
|
|
| netId sigAttrListE '=' expr { $$ = VARDONEA($<fl>1,*$1, NULL, $2); $$->addNext(new AstAssignW($3,new AstVarRef($3,$$->name(),true),$4)); }
|
|
| netId variable_dimensionList sigAttrListE { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
|
|
;
|
|
|
|
netId<strp>:
|
|
id/*new-net*/ { $$ = $1; $<fl>$=$<fl>1; }
|
|
| idSVKwd { $$ = $1; $<fl>$=$<fl>1; }
|
|
;
|
|
|
|
sigAttrListE<nodep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| sigAttrList { $$ = $1; }
|
|
;
|
|
|
|
sigAttrList<nodep>:
|
|
sigAttr { $$ = $1; }
|
|
| sigAttrList sigAttr { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
sigAttr<nodep>:
|
|
yVL_CLOCK { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK); }
|
|
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
|
|
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); v3Global.dpi(true); }
|
|
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); }
|
|
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); }
|
|
| yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); }
|
|
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true);
|
|
$$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
|
|
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
|
| yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
|
|
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
|
;
|
|
|
|
rangeListE<rangep>: // IEEE: [{packed_dimension}]
|
|
/* empty */ { $$ = NULL; }
|
|
| rangeList { $$ = $1; }
|
|
;
|
|
|
|
rangeList<rangep>: // IEEE: {packed_dimension}
|
|
anyrange { $$ = $1; }
|
|
| rangeList anyrange { $$ = $1; $1->addNext($2); }
|
|
;
|
|
|
|
// IEEE: select
|
|
// Merged into more general idArray
|
|
|
|
anyrange<rangep>:
|
|
'[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); }
|
|
;
|
|
|
|
packed_dimensionListE<rangep>: // IEEE: [{ packed_dimension }]
|
|
/* empty */ { $$ = NULL; }
|
|
| packed_dimensionList { $$ = $1; }
|
|
;
|
|
|
|
packed_dimensionList<rangep>: // IEEE: { packed_dimension }
|
|
packed_dimension { $$ = $1; }
|
|
| packed_dimensionList packed_dimension { $$ = $1->addNext($2)->castRange(); }
|
|
;
|
|
|
|
packed_dimension<rangep>: // ==IEEE: packed_dimension
|
|
anyrange { $$ = $1; }
|
|
//UNSUP '[' ']' { UNSUP }
|
|
;
|
|
|
|
//************************************************
|
|
// Parameters
|
|
|
|
param_assignment<varp>: // ==IEEE: param_assignment
|
|
// // IEEE: constant_param_expression
|
|
// // constant_param_expression: '$' is in expr
|
|
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' expr
|
|
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
|
//UNSUP: exprOrDataType instead of expr
|
|
;
|
|
|
|
list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
|
|
param_assignment { $$ = $1; }
|
|
| list_of_param_assignments ',' param_assignment { $$ = $1; $1->addNext($3); }
|
|
;
|
|
|
|
list_of_defparam_assignments<nodep>: //== IEEE: list_of_defparam_assignments
|
|
defparam_assignment { $$ = $1; }
|
|
| list_of_defparam_assignments ',' defparam_assignment { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
defparam_assignment<nodep>: // ==IEEE: defparam_assignment
|
|
id '.' id '=' expr { $$ = new AstDefParam($4,*$1,*$3,$5); }
|
|
//UNSUP More general dotted identifiers
|
|
;
|
|
|
|
//************************************************
|
|
// Instances
|
|
// We don't know identifier types, so this matches all module,udp,etc instantiation
|
|
// module_id [#(params)] name (pins) [, name ...] ; // module_instantiation
|
|
// gate (strong0) [#(delay)] [name] (pins) [, (pins)...] ; // gate_instantiation
|
|
// program_id [#(params}] name ; // program_instantiation
|
|
// interface_id [#(params}] name ; // interface_instantiation
|
|
// checker_id name (pins) ; // checker_instantiation
|
|
|
|
etcInst<nodep>: // IEEE: module_instantiation + gate_instantiation + udp_instantiation
|
|
instDecl { $$ = $1; }
|
|
| gateDecl { $$ = $1; }
|
|
;
|
|
|
|
instDecl<nodep>:
|
|
id parameter_value_assignmentE {INSTPREP(*$1,$2);} instnameList ';'
|
|
{ $$ = $4; GRAMMARP->m_impliedDecl=false;}
|
|
//UNSUP: strengthSpecE for udp_instantiations
|
|
;
|
|
|
|
instnameList<nodep>:
|
|
instnameParen { $$ = $1; }
|
|
| instnameList ',' instnameParen { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
instnameParen<nodep>:
|
|
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2); }
|
|
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2); }
|
|
//UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP
|
|
// // Adding above and switching to the Verilog-Perl syntax
|
|
// // causes a shift conflict due to use of idClassSel inside exprScope.
|
|
// // It also breaks allowing "id foo;" instantiation syntax.
|
|
;
|
|
|
|
instRangeE<rangep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| '[' constExpr ']' { $$ = new AstRange($1,$2,$2->cloneTree(true)); }
|
|
| '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); }
|
|
;
|
|
|
|
cellpinList<pinp>:
|
|
{VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); }
|
|
;
|
|
|
|
cellpinItList<pinp>: // IEEE: list_of_port_connections + list_of_parameter_assignmente
|
|
cellpinItemE { $$ = $1; }
|
|
| cellpinItList ',' cellpinItemE { $$ = $1->addNextNull($3)->castPin(); }
|
|
;
|
|
|
|
cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment + empty
|
|
// Note empty can match either () or (,); V3LinkCells cleans up ()
|
|
/* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(),PINNUMINC(),"",NULL); }
|
|
| yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",NULL); }
|
|
| '.' idSVKwd { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
|
|
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
|
|
| '.' idAny '(' ')' { $$ = new AstPin($1,PINNUMINC(),*$2,NULL); }
|
|
// // mintypmax is expanded here, as it might be a UDP or gate primitive
|
|
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
|
|
//UNSUP '.' idAny '(' expr ':' expr ')' { }
|
|
//UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { }
|
|
// // For parameters
|
|
//UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); }
|
|
// // For parameters
|
|
//UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); }
|
|
//
|
|
| expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
|
|
//UNSUP expr ':' expr { }
|
|
//UNSUP expr ':' expr ':' expr { }
|
|
;
|
|
|
|
//************************************************
|
|
// EventControl lists
|
|
|
|
attr_event_control<sentreep>: // ==IEEE: event_control
|
|
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
|
|
| '@' '(' '*' ')' { $$ = NULL; }
|
|
| '@' '*' { $$ = NULL; }
|
|
;
|
|
|
|
event_controlE<sentreep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| event_control { $$ = $1; }
|
|
;
|
|
|
|
event_control<sentreep>: // ==IEEE: event_control
|
|
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
|
|
| '@' '(' '*' ')' { $$ = NULL; }
|
|
| '@' '*' { $$ = NULL; }
|
|
// // IEEE: hierarchical_event_identifier
|
|
| '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */
|
|
// // IEEE: sequence_instance
|
|
// // sequence_instance without parens matches idClassSel above.
|
|
// // Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr
|
|
// // For now we avoid this, as it's very unlikely someone would mix
|
|
// // 1995 delay with a sequence with parameters.
|
|
// // Alternatively split this out of event_control, and delay_or_event_controlE
|
|
// // and anywhere delay_or_event_controlE is called allow two expressions
|
|
//| '@' idClassSel '(' list_of_argumentsE ')' { }
|
|
;
|
|
|
|
event_expression<senitemp>: // IEEE: event_expression - split over several
|
|
senitem { $$ = $1; }
|
|
| event_expression yOR senitem { $$ = $1->addNextNull($3)->castNodeSenItem(); }
|
|
| event_expression ',' senitem { $$ = $1->addNextNull($3)->castNodeSenItem(); } /* Verilog 2001 */
|
|
;
|
|
|
|
senitem<senitemp>: // IEEE: part of event_expression, non-'OR' ',' terms
|
|
senitemEdge { $$ = $1; }
|
|
| senitemVar { $$ = $1; }
|
|
| '(' senitemVar ')' { $$ = $2; }
|
|
//UNSUP expr { UNSUP }
|
|
//UNSUP expr yIFF expr { UNSUP }
|
|
// Since expr is unsupported we allow and ignore constants (removed in V3Const)
|
|
| yaINTNUM { $$ = NULL; }
|
|
| yaFLOATNUM { $$ = NULL; }
|
|
| '(' yaINTNUM ')' { $$ = NULL; }
|
|
| '(' yaFLOATNUM ')' { $$ = NULL; }
|
|
;
|
|
|
|
senitemVar<senitemp>:
|
|
idClassSel { $$ = new AstSenItem($1->fileline(),AstEdgeType::ET_ANYEDGE,$1); }
|
|
;
|
|
|
|
senitemEdge<senitemp>: // IEEE: part of event_expression
|
|
yPOSEDGE idClassSel { $$ = new AstSenItem($1,AstEdgeType::ET_POSEDGE,$2); }
|
|
| yNEGEDGE idClassSel { $$ = new AstSenItem($1,AstEdgeType::ET_NEGEDGE,$2); }
|
|
| yEDGE idClassSel { $$ = new AstSenItem($1,AstEdgeType::ET_BOTHEDGE,$2); }
|
|
| yPOSEDGE '(' idClassSel ')' { $$ = new AstSenItem($1,AstEdgeType::ET_POSEDGE,$3); }
|
|
| yNEGEDGE '(' idClassSel ')' { $$ = new AstSenItem($1,AstEdgeType::ET_NEGEDGE,$3); }
|
|
| yEDGE '(' idClassSel ')' { $$ = new AstSenItem($1,AstEdgeType::ET_BOTHEDGE,$3); }
|
|
//UNSUP yIFF...
|
|
;
|
|
|
|
//************************************************
|
|
// Statements
|
|
|
|
stmtBlock<nodep>: // IEEE: statement + seq_block + par_block
|
|
stmt { $$ = $1; }
|
|
;
|
|
|
|
seq_block<nodep>: // ==IEEE: seq_block
|
|
// // IEEE doesn't allow declarations in unnamed blocks, but several simulators do.
|
|
// // So need AstBegin's even if unnamed to scope variables down
|
|
seq_blockFront blockDeclStmtList yEND endLabelE { $$=$1; $1->addStmtsp($2); SYMP->popScope($1); GRAMMARP->endLabel($<fl>4,$1,$4); }
|
|
| seq_blockFront /**/ yEND endLabelE { $$=$1; SYMP->popScope($1); GRAMMARP->endLabel($<fl>3,$1,$3); }
|
|
;
|
|
|
|
seq_blockFront<beginp>: // IEEE: part of par_block
|
|
yBEGIN { $$ = new AstBegin($1,"",NULL); SYMP->pushNew($$); }
|
|
| yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($1,*$3,NULL); SYMP->pushNew($$); }
|
|
;
|
|
|
|
blockDeclStmtList<nodep>: // IEEE: { block_item_declaration } { statement or null }
|
|
// // The spec seems to suggest a empty declaration isn't ok, but most simulators take it
|
|
block_item_declarationList { $$ = $1; }
|
|
| block_item_declarationList stmtList { $$ = $1->addNextNull($2); }
|
|
| stmtList { $$ = $1; }
|
|
;
|
|
|
|
block_item_declarationList<nodep>: // IEEE: [ block_item_declaration ]
|
|
block_item_declaration { $$ = $1; }
|
|
| block_item_declarationList block_item_declaration { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
block_item_declaration<nodep>: // ==IEEE: block_item_declaration
|
|
data_declaration { $$ = $1; }
|
|
| local_parameter_declaration ';' { $$ = $1; }
|
|
| parameter_declaration ';' { $$ = $1; }
|
|
//UNSUP overload_declaration { $$ = $1; }
|
|
//UNSUP let_declaration { $$ = $1; }
|
|
;
|
|
|
|
stmtList<nodep>:
|
|
stmtBlock { $$ = $1; }
|
|
| stmtList stmtBlock { $$ = ($2==NULL)?($1):($1->addNext($2)); }
|
|
;
|
|
|
|
stmt<nodep>: // IEEE: statement_or_null == function_statement_or_null
|
|
statement_item { }
|
|
//UNSUP: Labeling any statement
|
|
| labeledStmt { $$ = $1; }
|
|
| id ':' labeledStmt { $$ = new AstBegin($2, *$1, $3); } /*S05 block creation rule*/
|
|
// // from _or_null
|
|
| ';' { $$ = NULL; }
|
|
;
|
|
|
|
statement_item<nodep>: // IEEE: statement_item
|
|
// // IEEE: operator_assignment
|
|
foperator_assignment ';' { $$ = $1; }
|
|
//
|
|
// // IEEE: blocking_assignment
|
|
// // 1800-2009 restricts LHS of assignment to new to not have a range
|
|
// // This is ignored to avoid conflicts
|
|
//UNSUP fexprLvalue '=' class_new ';' { UNSUP }
|
|
//UNSUP fexprLvalue '=' dynamic_array_new ';' { UNSUP }
|
|
//
|
|
// // IEEE: nonblocking_assignment
|
|
| fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); }
|
|
//UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP }
|
|
//
|
|
// // IEEE: procedural_continuous_assignment
|
|
| yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); }
|
|
//UNSUP: delay_or_event_controlE above
|
|
//UNSUP yDEASSIGN variable_lvalue ';' { UNSUP }
|
|
//UNSUP yFORCE expr '=' expr ';' { UNSUP }
|
|
//UNSUP yRELEASE variable_lvalue ';' { UNSUP }
|
|
//
|
|
// // IEEE: case_statement
|
|
| unique_priorityE caseStart caseAttrE case_itemListE yENDCASE { $$ = $2; if ($4) $2->addItemsp($4);
|
|
if ($1 == uniq_UNIQUE) $2->uniquePragma(true);
|
|
if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true);
|
|
if ($1 == uniq_PRIORITY) $2->priorityPragma(true); }
|
|
//UNSUP caseStart caseAttrE yMATCHES case_patternListE yENDCASE { }
|
|
| unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE { $$ = $2; if ($5) $2->addItemsp($5);
|
|
if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez");
|
|
$2->caseInsideSet();
|
|
if ($1 == uniq_UNIQUE) $2->uniquePragma(true);
|
|
if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true);
|
|
if ($1 == uniq_PRIORITY) $2->priorityPragma(true); }
|
|
//
|
|
// // IEEE: conditional_statement
|
|
| unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE
|
|
{ $$ = new AstIf($2,$4,$6,NULL);
|
|
if ($1 == uniq_UNIQUE) $$->castIf()->uniquePragma(true);
|
|
if ($1 == uniq_UNIQUE0) $$->castIf()->unique0Pragma(true);
|
|
if ($1 == uniq_PRIORITY) $$->castIf()->priorityPragma(true); }
|
|
| unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock
|
|
{ $$ = new AstIf($2,$4,$6,$8);
|
|
if ($1 == uniq_UNIQUE) $$->castIf()->uniquePragma(true);
|
|
if ($1 == uniq_UNIQUE0) $$->castIf()->unique0Pragma(true);
|
|
if ($1 == uniq_PRIORITY) $$->castIf()->priorityPragma(true); }
|
|
//
|
|
| finc_or_dec_expression ';' { $$ = $1; }
|
|
// // IEEE: inc_or_dec_expression
|
|
// // Below under expr
|
|
//
|
|
// // IEEE: subroutine_call_statement
|
|
//UNSUP yVOID yP_TICK '(' function_subroutine_callNoMethod ')' ';' { }
|
|
//UNSUP yVOID yP_TICK '(' expr '.' function_subroutine_callNoMethod ')' ';' { }
|
|
// // Expr included here to resolve our not knowing what is a method call
|
|
// // Expr here must result in a subroutine_call
|
|
| task_subroutine_callNoMethod ';' { $$ = $1; }
|
|
//UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP }
|
|
| fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($<fl>2,$1,$3); }
|
|
//UNSUP fexprScope ';' { UNSUP }
|
|
// // Not here in IEEE; from class_constructor_declaration
|
|
// // Because we've joined class_constructor_declaration into generic functions
|
|
// // Way over-permissive;
|
|
// // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ]
|
|
//UNSUP fexpr '.' class_new ';' { }
|
|
//
|
|
| statementVerilatorPragmas { $$ = $1; }
|
|
//
|
|
// // IEEE: disable_statement
|
|
| yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); }
|
|
//UNSUP yDISABLE yFORK ';' { UNSUP }
|
|
// // IEEE: event_trigger
|
|
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
|
//UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP }
|
|
// // IEEE: loop_statement
|
|
| yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,AstConst::LogicTrue()),$2); }
|
|
| yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);}
|
|
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
|
// // for's first ';' is in for_initalization
|
|
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
|
{ $$ = new AstBegin($1,"",$3); $3->addNext(new AstWhile($1, $4,$8,$6)); }
|
|
| yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));}
|
|
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
|
|
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
|
|
//
|
|
// // IEEE: jump_statement
|
|
| yRETURN ';' { $$ = new AstReturn($1); }
|
|
| yRETURN expr ';' { $$ = new AstReturn($1,$2); }
|
|
| yBREAK ';' { $$ = new AstBreak($1); }
|
|
| yCONTINUE ';' { $$ = new AstContinue($1); }
|
|
//
|
|
//UNSUP par_block { $$ = $1; }
|
|
// // IEEE: procedural_timing_control_statement + procedural_timing_control
|
|
| delay_control stmtBlock { $$ = $2; $1->v3warn(STMTDLY,"Unsupported: Ignoring delay on this delayed statement."); }
|
|
//UNSUP event_control stmtBlock { UNSUP }
|
|
//UNSUP cycle_delay stmtBlock { UNSUP }
|
|
//
|
|
| seq_block { $$ = $1; }
|
|
//
|
|
// // IEEE: wait_statement
|
|
//UNSUP yWAIT '(' expr ')' stmtBlock { UNSUP }
|
|
//UNSUP yWAIT yFORK ';' { UNSUP }
|
|
//UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP }
|
|
//
|
|
// // IEEE: procedural_assertion_statement
|
|
// // Verilator: Label included instead
|
|
| concurrent_assertion_item { $$ = $1; }
|
|
// // concurrent_assertion_statement { $$ = $1; }
|
|
// // Verilator: Part of labeledStmt instead
|
|
// // immediate_assert_statement { UNSUP }
|
|
//
|
|
// // IEEE: clocking_drive ';'
|
|
// // Pattern w/o cycle_delay handled by nonblocking_assign above
|
|
// // clockvar_expression made to fexprLvalue to prevent reduce conflict
|
|
// // Note LTE in this context is highest precedence, so first on left wins
|
|
//UNSUP cycle_delay fexprLvalue yP_LTE ';' { UNSUP }
|
|
//UNSUP fexprLvalue yP_LTE cycle_delay expr ';' { UNSUP }
|
|
//
|
|
//UNSUP randsequence_statement { $$ = $1; }
|
|
//
|
|
// // IEEE: randcase_statement
|
|
//UNSUP yRANDCASE case_itemList yENDCASE { UNSUP }
|
|
//
|
|
//UNSUP expect_property_statement { $$ = $1; }
|
|
//
|
|
| error ';' { $$ = NULL; }
|
|
;
|
|
|
|
statementVerilatorPragmas<nodep>:
|
|
yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); }
|
|
;
|
|
|
|
foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression)
|
|
fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); }
|
|
| fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = NULL; $3->v3error("Unsupported: $fopen with multichannel descriptor. Add ,\"w\" as second argument to open a file descriptor."); }
|
|
| fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); }
|
|
//
|
|
//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
|
|
//UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP }
|
|
| fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
|
| fexprLvalue yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
|
;
|
|
|
|
finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
|
|
//UNSUP: Generic scopes in incrementes
|
|
fexprLvalue yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
|
| fexprLvalue yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
|
| yP_PLUSPLUS fexprLvalue { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
|
| yP_MINUSMINUS fexprLvalue { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
|
;
|
|
|
|
//************************************************
|
|
// Case/If
|
|
|
|
unique_priorityE<uniqstate>: // IEEE: unique_priority + empty
|
|
/*empty*/ { $$ = uniq_NONE; }
|
|
| yPRIORITY { $$ = uniq_PRIORITY; }
|
|
| yUNIQUE { $$ = uniq_UNIQUE; }
|
|
| yUNIQUE0 { $$ = uniq_UNIQUE0; }
|
|
;
|
|
|
|
caseStart<casep>: // IEEE: part of case_statement
|
|
yCASE '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASE,$3,NULL); }
|
|
| yCASEX '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEX,$3,NULL); }
|
|
| yCASEZ '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEZ,$3,NULL); }
|
|
;
|
|
|
|
caseAttrE:
|
|
/*empty*/ { }
|
|
| caseAttrE yVL_FULL_CASE { GRAMMARP->m_caseAttrp->fullPragma(true); }
|
|
| caseAttrE yVL_PARALLEL_CASE { GRAMMARP->m_caseAttrp->parallelPragma(true); }
|
|
;
|
|
|
|
case_itemListE<caseitemp>: // IEEE: [ { case_item } ]
|
|
/* empty */ { $$ = NULL; }
|
|
| case_itemList { $$ = $1; }
|
|
;
|
|
|
|
case_insideListE<caseitemp>: // IEEE: [ { case_inside_item } ]
|
|
/* empty */ { $$ = NULL; }
|
|
| case_inside_itemList { $$ = $1; }
|
|
;
|
|
|
|
case_itemList<caseitemp>: // IEEE: { case_item + ... }
|
|
caseCondList ':' stmtBlock { $$ = new AstCaseItem($2,$1,$3); }
|
|
| yDEFAULT ':' stmtBlock { $$ = new AstCaseItem($2,NULL,$3); }
|
|
| yDEFAULT stmtBlock { $$ = new AstCaseItem($1,NULL,$2); }
|
|
| case_itemList caseCondList ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
|
|
| case_itemList yDEFAULT stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); }
|
|
| case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); }
|
|
;
|
|
|
|
case_inside_itemList<caseitemp>: // IEEE: { case_inside_item + open_range_list ... }
|
|
open_range_list ':' stmtBlock { $$ = new AstCaseItem($2,$1,$3); }
|
|
| yDEFAULT ':' stmtBlock { $$ = new AstCaseItem($2,NULL,$3); }
|
|
| yDEFAULT stmtBlock { $$ = new AstCaseItem($1,NULL,$2); }
|
|
| case_inside_itemList open_range_list ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
|
|
| case_inside_itemList yDEFAULT stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); }
|
|
| case_inside_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); }
|
|
;
|
|
|
|
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
|
|
open_value_range { $$ = $1; }
|
|
| open_range_list ',' open_value_range { $$ = $1;$1->addNext($3); }
|
|
;
|
|
|
|
open_value_range<nodep>: // ==IEEE: open_value_range
|
|
value_range { $$ = $1; }
|
|
;
|
|
|
|
value_range<nodep>: // ==IEEE: value_range
|
|
expr { $$ = $1; }
|
|
| '[' expr ':' expr ']' { $$ = new AstInsideRange($3,$2,$4); }
|
|
;
|
|
|
|
caseCondList<nodep>: // IEEE: part of case_item
|
|
expr { $$ = $1; }
|
|
| caseCondList ',' expr { $$ = $1;$1->addNext($3); }
|
|
;
|
|
|
|
patternNoExpr<nodep>: // IEEE: pattern **Excluding Expr*
|
|
'.' id/*variable*/ { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
|
|
| yP_DOTSTAR { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
|
|
// // IEEE: "expr" excluded; expand in callers
|
|
// // "yTAGGED id [expr]" Already part of expr
|
|
//UNSUP yTAGGED id/*member_identifier*/ patternNoExpr { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
|
|
// // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern
|
|
;
|
|
|
|
patternList<nodep>: // IEEE: part of pattern
|
|
patternOne { $$ = $1; }
|
|
| patternList ',' patternOne { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
patternOne<nodep>: // IEEE: part of pattern
|
|
expr { $$ = new AstPatMember($1->fileline(),$1,NULL,NULL); }
|
|
| expr '{' argsExprList '}' { $$ = new AstPatMember($2,$3,NULL,$1); }
|
|
| patternNoExpr { $$ = $1; }
|
|
;
|
|
|
|
patternMemberList<nodep>: // IEEE: part of pattern and assignment_pattern
|
|
patternMemberOne { $$ = $1; }
|
|
| patternMemberList ',' patternMemberOne { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
patternMemberOne<patmemberp>: // IEEE: part of pattern and assignment_pattern
|
|
patternKey ':' expr { $$ = new AstPatMember($2,$3,$1,NULL); }
|
|
| patternKey ':' patternNoExpr { $2->v3error("Unsupported: '{} .* patterns"); $$=NULL; }
|
|
// // From assignment_pattern_key
|
|
| yDEFAULT ':' expr { $$ = new AstPatMember($2,$3,NULL,NULL); $$->isDefault(true); }
|
|
| yDEFAULT ':' patternNoExpr { $2->v3error("Unsupported: '{} .* patterns"); $$=NULL; }
|
|
;
|
|
|
|
patternKey<nodep>: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key
|
|
// // IEEE: structure_pattern_key
|
|
// // id/*member*/ is part of constExpr below
|
|
//UNSUP constExpr { $$ = $1; }
|
|
// // IEEE: assignment_pattern_key
|
|
//UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$=$1; }
|
|
// // simple_type reference looks like constExpr
|
|
// // Verilator:
|
|
// // The above expressions cause problems because "foo" may be a constant identifier
|
|
// // (if array) or a reference to the "foo"member (if structure)
|
|
// // So for now we only allow a true constant number, or a identifier which we treat as a structure member name
|
|
yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
|
|
| yaFLOATNUM { $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
|
|
| yaID__ETC { $$ = new AstText($<fl>1,*$1); }
|
|
;
|
|
|
|
assignment_pattern<patternp>: // ==IEEE: assignment_pattern
|
|
// This doesn't match the text of the spec. I think a : is missing, or example code needed
|
|
// yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; }
|
|
// // "'{ const_expression }" is same as patternList with one entry
|
|
// // From patternNoExpr
|
|
// // also IEEE: "''{' expression { ',' expression } '}'"
|
|
// // matches since patternList includes expr
|
|
yP_TICKBRA patternList '}' { $$ = new AstPattern($1,$2); }
|
|
// // From patternNoExpr
|
|
// // also IEEE "''{' structure_pattern_key ':' ...
|
|
// // also IEEE "''{' array_pattern_key ':' ...
|
|
| yP_TICKBRA patternMemberList '}' { $$ = new AstPattern($1,$2); }
|
|
// // IEEE: Not in grammar, but in VMM
|
|
| yP_TICKBRA '}' { $1->v3error("Unsupported: Empty '{}"); $$=NULL; }
|
|
;
|
|
|
|
// "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal
|
|
for_initialization<nodep>: // ==IEEE: for_initialization + for_variable_declaration + extra terminating ";"
|
|
// // IEEE: for_variable_declaration
|
|
data_type idAny/*new*/ '=' expr ';'
|
|
{ VARRESET_NONLIST(VAR); VARDTYPE($1);
|
|
$$ = VARDONEA($<fl>2,*$2,NULL,NULL);
|
|
$$->addNext(new AstAssign($3,new AstVarRef($3,*$2,true),$4));}
|
|
| varRefBase '=' expr ';' { $$ = new AstAssign($2,$1,$3); }
|
|
//UNSUP: List of initializations
|
|
;
|
|
|
|
for_stepE<nodep>: // IEEE: for_step + empty
|
|
/* empty */ { $$ = NULL; }
|
|
| for_step { $$ = $1; }
|
|
;
|
|
|
|
for_step<nodep>: // IEEE: for_step
|
|
//UNSUP: List of steps, instead we keep it simple
|
|
genvar_iteration { $$ = $1; }
|
|
;
|
|
|
|
//************************************************
|
|
// Functions/tasks
|
|
|
|
taskRef<nodep>: // IEEE: part of tf_call
|
|
id { $$ = new AstTaskRef($<fl>1,*$1,NULL); }
|
|
| id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($<fl>1,*$1,$3); }
|
|
| package_scopeIdFollows id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($<fl>2, $1, new AstTaskRef($<fl>2,*$2,$4)); }
|
|
;
|
|
|
|
funcRef<nodep>: // IEEE: part of tf_call
|
|
// // package_scope/hierarchical_... is part of expr, so just need ID
|
|
// // making-a id-is-a
|
|
// // ----------------- ------------------
|
|
// // tf_call tf_identifier expr (list_of_arguments)
|
|
// // method_call(post .) function_identifier expr (list_of_arguments)
|
|
// // property_instance property_identifier property_actual_arg
|
|
// // sequence_instance sequence_identifier sequence_actual_arg
|
|
// // let_expression let_identifier let_actual_arg
|
|
//
|
|
id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2, *$1, $3); }
|
|
| package_scopeIdFollows id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($<fl>2, $1, new AstFuncRef($<fl>2,*$2,$4)); }
|
|
//UNSUP: idDotted is really just id to allow dotted method calls
|
|
;
|
|
|
|
task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as task)
|
|
// // IEEE: tf_call
|
|
taskRef { $$ = $1; }
|
|
| system_t_call { $$ = $1; }
|
|
// // IEEE: method_call requires a "." so is in expr
|
|
//UNSUP randomize_call { $$ = $1; }
|
|
;
|
|
|
|
function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_call (as function)
|
|
// // IEEE: tf_call
|
|
funcRef { $$ = $1; }
|
|
| system_f_call { $$ = $1; }
|
|
// // IEEE: method_call requires a "." so is in expr
|
|
//UNSUP randomize_call { $$ = $1; }
|
|
;
|
|
|
|
system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|
//
|
|
yaD_IGNORE parenE { $$ = new AstSysIgnore($<fl>1,NULL); }
|
|
| yaD_IGNORE '(' exprList ')' { $$ = new AstSysIgnore($<fl>1,$3); }
|
|
//
|
|
| yaD_DPI parenE { $$ = new AstTaskRef($<fl>1,*$1,NULL); }
|
|
| yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($2,*$1,$3); GRAMMARP->argWrapList($$->castTaskRef()); }
|
|
//
|
|
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
|
|
| yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); }
|
|
| yD_FFLUSH parenE { $1->v3error("Unsupported: $fflush of all handles does not map to C++."); }
|
|
| yD_FFLUSH '(' idClassSel ')' { $$ = new AstFFlush($1, $3); }
|
|
| yD_FINISH parenE { $$ = new AstFinish($1); }
|
|
| yD_FINISH '(' expr ')' { $$ = new AstFinish($1); DEL($3); }
|
|
| yD_STOP parenE { $$ = new AstStop($1); }
|
|
| yD_STOP '(' expr ')' { $$ = new AstStop($1); DEL($3); }
|
|
//
|
|
| yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
|
| yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
|
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1,$3); }
|
|
//
|
|
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,"", NULL,NULL); }
|
|
| yD_DISPLAY '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,*$3,NULL,$4); }
|
|
| yD_WRITE parenE { $$ = NULL; } // NOP
|
|
| yD_WRITE '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, *$3,NULL,$4); }
|
|
| yD_FDISPLAY '(' idClassSel ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,"",$3,NULL); }
|
|
| yD_FDISPLAY '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,*$5,$3,$6); }
|
|
| yD_FWRITE '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, *$5,$3,$6); }
|
|
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, "", NULL,NULL); }
|
|
| yD_INFO '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, *$3,NULL,$4); }
|
|
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::DT_WARNING,"", NULL,NULL); }
|
|
| yD_WARNING '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WARNING,*$3,NULL,$4); }
|
|
| yD_ERROR parenE { $$ = GRAMMARP->createDisplayError($1); }
|
|
| yD_ERROR '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
|
|
| yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
|
|
| yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); DEL($3); }
|
|
| yD_FATAL '(' expr ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); DEL($3); }
|
|
//
|
|
| yD_READMEMB '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
|
| yD_READMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
|
| yD_READMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
|
| yD_READMEMH '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
|
| yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
|
| yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
|
;
|
|
|
|
system_f_call<nodep>: // IEEE: system_tf_call (as func)
|
|
yaD_IGNORE parenE { $$ = new AstConst($<fl>1,V3Number($<fl>1,"'b0")); } // Unsized 0
|
|
| yaD_IGNORE '(' exprList ')' { $$ = new AstConst($2,V3Number($2,"'b0")); } // Unsized 0
|
|
//
|
|
| yaD_DPI parenE { $$ = new AstFuncRef($<fl>1,*$1,NULL); }
|
|
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); GRAMMARP->argWrapList($$->castFuncRef()); }
|
|
//
|
|
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
|
|
| yD_BITS '(' data_type ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
|
|
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
|
|
| yD_BITS '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
|
|
| yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); }
|
|
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
|
|
| yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); }
|
|
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
|
|
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
|
|
| yD_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); }
|
|
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
|
|
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
|
|
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
|
|
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
|
|
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
|
|
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
|
|
| yD_HIGH '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
|
|
| yD_HIGH '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,$5); }
|
|
| yD_INCREMENT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,NULL); }
|
|
| yD_INCREMENT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,$5); }
|
|
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
|
|
| yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); }
|
|
| yD_LEFT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,NULL); }
|
|
| yD_LEFT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,$5); }
|
|
| yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); }
|
|
| yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); }
|
|
| yD_LOW '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,NULL); }
|
|
| yD_LOW '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,$5); }
|
|
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
|
|
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
|
|
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); }
|
|
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); }
|
|
| yD_RANDOM parenE { $$ = new AstRand($1); }
|
|
| yD_REALTIME parenE { $$ = new AstTimeD($1); }
|
|
| yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); }
|
|
| yD_RIGHT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,NULL); }
|
|
| yD_RIGHT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,$5); }
|
|
| yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); }
|
|
//| yD_SFORMATF '(' str commaEListE ')' { $$ = new AstSFormatF($1,*$3,false,$4); } // Have AST, just need testing and debug
|
|
| yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); }
|
|
| yD_SIZE '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,NULL); }
|
|
| yD_SIZE '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,$5); }
|
|
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
|
|
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
|
|
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
|
|
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
|
|
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
|
|
| yD_TIME parenE { $$ = new AstTime($1); }
|
|
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
|
|
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }
|
|
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
|
|
;
|
|
|
|
list_of_argumentsE<nodep>: // IEEE: [list_of_arguments]
|
|
argsDottedList { $$ = $1; }
|
|
| argsExprListE { if ($1->castArg() && $1->castArg()->emptyConnectNoNext()) { $1->deleteTree(); $$ = NULL; } // Mis-created when have 'func()'
|
|
/*cont*/ else $$ = $1; }
|
|
| argsExprListE ',' argsDottedList { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
task_declaration<ftaskp>: // ==IEEE: task_declaration
|
|
yTASK lifetimeE taskId tfGuts yENDTASK endLabelE
|
|
{ $$ = $3; $$->addStmtsp($4); SYMP->popScope($$);
|
|
GRAMMARP->endLabel($<fl>6,$$,$6); }
|
|
;
|
|
|
|
task_prototype<ftaskp>: // ==IEEE: task_prototype
|
|
yTASK taskId '(' tf_port_listE ')' { $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
|
|
;
|
|
|
|
function_declaration<ftaskp>: // IEEE: function_declaration + function_body_declaration
|
|
yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE
|
|
{ $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5);
|
|
SYMP->popScope($$);
|
|
GRAMMARP->endLabel($<fl>7,$$,$7); }
|
|
;
|
|
|
|
function_prototype<ftaskp>: // IEEE: function_prototype
|
|
yFUNCTION funcId '(' tf_port_listE ')' { $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
|
|
;
|
|
|
|
funcIsolateE<cint>:
|
|
/* empty */ { $$ = 0; }
|
|
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
|
|
;
|
|
|
|
method_prototype:
|
|
task_prototype { }
|
|
| function_prototype { }
|
|
;
|
|
|
|
lifetimeE: // IEEE: [lifetime]
|
|
/* empty */ { }
|
|
| lifetime { }
|
|
;
|
|
|
|
lifetime: // ==IEEE: lifetime
|
|
// // Note lifetime used by members is instead under memberQual
|
|
ySTATIC { $1->v3error("Unsupported: Static in this context"); }
|
|
| yAUTOMATIC { }
|
|
;
|
|
|
|
taskId<ftaskp>:
|
|
tfIdScoped
|
|
{ $$ = new AstTask($<fl>1, *$<strp>1, NULL);
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
;
|
|
|
|
funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_body_declaration
|
|
// // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict
|
|
// // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID
|
|
/**/ tfIdScoped
|
|
{ $$ = new AstFunc ($<fl>1,*$<strp>1,NULL,
|
|
new AstBasicDType($<fl>1, LOGIC_IMPLICIT));
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
| signingE rangeList tfIdScoped
|
|
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,
|
|
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,true));
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
| signing tfIdScoped
|
|
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
|
|
new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $1));
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
| data_type tfIdScoped
|
|
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,$1);
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
// // To verilator tasks are the same as void functions (we separately detect time passing)
|
|
| yVOID tfIdScoped
|
|
{ $$ = new AstTask ($<fl>2,*$<strp>2,NULL);
|
|
SYMP->pushNewUnder($$, NULL); }
|
|
;
|
|
|
|
tfIdScoped<strp>: // IEEE: part of function_body_declaration/task_body_declaration
|
|
// // IEEE: [ interface_identifier '.' | class_scope ] function_identifier
|
|
id { $<fl>$=$<fl>1; $<strp>$ = $1; }
|
|
//UNSUP id/*interface_identifier*/ '.' id { UNSUP }
|
|
//UNSUP class_scope_id { UNSUP }
|
|
;
|
|
|
|
tfGuts<nodep>:
|
|
'(' tf_port_listE ')' ';' tfBodyE { $$ = $2->addNextNull($5); }
|
|
| ';' tfBodyE { $$ = $2; }
|
|
;
|
|
|
|
tfBodyE<nodep>: // IEEE: part of function_body_declaration/task_body_declaration
|
|
/* empty */ { $$ = NULL; }
|
|
| tf_item_declarationList { $$ = $1; }
|
|
| tf_item_declarationList stmtList { $$ = $1->addNextNull($2); }
|
|
| stmtList { $$ = $1; }
|
|
;
|
|
|
|
tf_item_declarationList<nodep>:
|
|
tf_item_declaration { $$ = $1; }
|
|
| tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); }
|
|
;
|
|
|
|
tf_item_declaration<nodep>: // ==IEEE: tf_item_declaration
|
|
block_item_declaration { $$ = $1; }
|
|
| tf_port_declaration { $$ = $1; }
|
|
| tf_item_declarationVerilator { $$ = $1; }
|
|
;
|
|
|
|
tf_item_declarationVerilator<nodep>: // Verilator extensions
|
|
yVL_PUBLIC { $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); v3Global.dpi(true); }
|
|
| yVL_NO_INLINE_TASK { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); }
|
|
;
|
|
|
|
tf_port_listE<nodep>: // IEEE: tf_port_list + empty
|
|
// // Empty covered by tf_port_item
|
|
{VARRESET_LIST(UNKNOWN); VARIO(INPUT); }
|
|
tf_port_listList { $$ = $2; VARRESET_NONLIST(UNKNOWN); }
|
|
;
|
|
|
|
tf_port_listList<nodep>: // IEEE: part of tf_port_list
|
|
tf_port_item { $$ = $1; }
|
|
| tf_port_listList ',' tf_port_item { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
tf_port_item<nodep>: // ==IEEE: tf_port_item
|
|
// // We split tf_port_item into the type and assignment as don't know what follows a comma
|
|
/* empty */ { $$ = NULL; PINNUMINC(); } // For example a ",," port
|
|
| tf_port_itemFront tf_port_itemAssignment { $$ = $2; }
|
|
| tf_port_itemAssignment { $$ = $1; }
|
|
;
|
|
|
|
tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type
|
|
data_type { VARDTYPE($1); }
|
|
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, true)); }
|
|
| signing { VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
|
|
| yVAR data_type { VARDTYPE($2); }
|
|
| yVAR implicit_typeE { VARDTYPE($2); }
|
|
//
|
|
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
|
|
| tf_port_itemDir data_type { VARDTYPE($2); }
|
|
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,true)); }
|
|
| tf_port_itemDir signing { VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
|
|
| tf_port_itemDir yVAR data_type { VARDTYPE($3); }
|
|
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
|
|
;
|
|
|
|
tf_port_itemDir: // IEEE: part of tf_port_item, direction
|
|
port_direction { } // port_direction sets VARIO
|
|
;
|
|
|
|
tf_port_itemAssignment<varp>: // IEEE: part of tf_port_item, which has assignment
|
|
id variable_dimensionListE sigAttrListE
|
|
{ $$ = VARDONEA($<fl>1, *$1, $2, $3); }
|
|
| id variable_dimensionListE sigAttrListE '=' expr
|
|
{ $$ = VARDONEA($<fl>1, *$1, $2, $3); $$->valuep($5); }
|
|
;
|
|
|
|
parenE:
|
|
/* empty */ { }
|
|
| '(' ')' { }
|
|
;
|
|
|
|
// method_call: // ==IEEE: method_call + method_call_body
|
|
// // IEEE: method_call_root '.' method_identifier [ '(' list_of_arguments ')' ]
|
|
// // "method_call_root '.' method_identifier" looks just like "expr '.' id"
|
|
// // "method_call_root '.' method_identifier (...)" looks just like "expr '.' tf_call"
|
|
// // IEEE: built_in_method_call
|
|
// // method_call_root not needed, part of expr resolution
|
|
// // What's left is below array_methodNoRoot
|
|
|
|
dpi_import_export<nodep>: // ==IEEE: dpi_import_export
|
|
yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';'
|
|
{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
|
$5->dpiImport(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
|
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName()); // For $SysTF overriding
|
|
SYMP->reinsert($$); }
|
|
| yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';'
|
|
{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
|
$5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
|
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName()); // For $SysTF overriding
|
|
SYMP->reinsert($$); }
|
|
| yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';' { $$ = new AstDpiExport($1,*$5,*$3);
|
|
GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
|
| yEXPORT yaSTRING dpi_importLabelE yTASK idAny ';' { $$ = new AstDpiExport($1,*$5,*$3);
|
|
GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
|
;
|
|
|
|
dpi_importLabelE<strp>: // IEEE: part of dpi_import_export
|
|
/* empty */ { static string s = ""; $$ = &s; }
|
|
| idAny/*c_identifier*/ '=' { $$ = $1; $<fl>$=$<fl>1; }
|
|
;
|
|
|
|
dpi_tf_import_propertyE<iprop>: // IEEE: [ dpi_function_import_property + dpi_task_import_property ]
|
|
/* empty */ { $$ = iprop_NONE; }
|
|
| yCONTEXT { $$ = iprop_CONTEXT; }
|
|
| yPURE { $$ = iprop_PURE; }
|
|
;
|
|
|
|
//************************************************
|
|
// Expressions
|
|
//
|
|
// ~l~ means this is the (l)eft hand side of any operator
|
|
// it will get replaced by "", "f" or "s"equence
|
|
// ~r~ means this is a (r)ight hand later expansion in the same statement,
|
|
// not under parenthesis for <= disambiguation
|
|
// it will get replaced by "", or "f"
|
|
// ~p~ means this is a (p)arenthetized expression
|
|
// it will get replaced by "", or "s"equence
|
|
|
|
constExpr<nodep>:
|
|
expr { $$ = $1; }
|
|
;
|
|
|
|
expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
|
// *SEE BELOW* // IEEE: primary/constant_primary
|
|
//
|
|
// // IEEE: unary_operator primary
|
|
'+' ~r~expr %prec prUNARYARITH { $$ = $2; }
|
|
| '-' ~r~expr %prec prUNARYARITH { $$ = new AstNegate ($1,$2); }
|
|
| '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); }
|
|
| '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); }
|
|
| '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); }
|
|
| '|' ~r~expr %prec prREDUCTION { $$ = new AstRedOr ($1,$2); }
|
|
| '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); }
|
|
| yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedAnd($1,$2)); }
|
|
| yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedOr ($1,$2)); }
|
|
| yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstRedXnor ($1,$2); }
|
|
//
|
|
// // IEEE: inc_or_dec_expression
|
|
//UNSUP ~l~inc_or_dec_expression { UNSUP }
|
|
//
|
|
// // IEEE: '(' operator_assignment ')'
|
|
// // Need exprScope of variable_lvalue to prevent conflict
|
|
//UNSUP '(' ~p~exprScope '=' expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_PLUSEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_MINUSEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_TIMESEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_DIVEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_MODEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_ANDEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_OREQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_XOREQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_SLEFTEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_SRIGHTEQ expr ')' { UNSUP }
|
|
//UNSUP '(' ~p~exprScope yP_SSRIGHTEQ expr ')' { UNSUP }
|
|
//
|
|
// // IEEE: expression binary_operator expression
|
|
| ~l~expr '+' ~r~expr { $$ = new AstAdd ($2,$1,$3); }
|
|
| ~l~expr '-' ~r~expr { $$ = new AstSub ($2,$1,$3); }
|
|
| ~l~expr '*' ~r~expr { $$ = new AstMul ($2,$1,$3); }
|
|
| ~l~expr '/' ~r~expr { $$ = new AstDiv ($2,$1,$3); }
|
|
| ~l~expr '%' ~r~expr { $$ = new AstModDiv ($2,$1,$3); }
|
|
| ~l~expr yP_EQUAL ~r~expr { $$ = new AstEq ($2,$1,$3); }
|
|
| ~l~expr yP_NOTEQUAL ~r~expr { $$ = new AstNeq ($2,$1,$3); }
|
|
| ~l~expr yP_CASEEQUAL ~r~expr { $$ = new AstEqCase ($2,$1,$3); }
|
|
| ~l~expr yP_CASENOTEQUAL ~r~expr { $$ = new AstNeqCase ($2,$1,$3); }
|
|
| ~l~expr yP_WILDEQUAL ~r~expr { $$ = new AstEqWild ($2,$1,$3); }
|
|
| ~l~expr yP_WILDNOTEQUAL ~r~expr { $$ = new AstNeqWild ($2,$1,$3); }
|
|
| ~l~expr yP_ANDAND ~r~expr { $$ = new AstLogAnd ($2,$1,$3); }
|
|
| ~l~expr yP_OROR ~r~expr { $$ = new AstLogOr ($2,$1,$3); }
|
|
| ~l~expr yP_POW ~r~expr { $$ = new AstPow ($2,$1,$3); }
|
|
| ~l~expr '<' ~r~expr { $$ = new AstLt ($2,$1,$3); }
|
|
| ~l~expr '>' ~r~expr { $$ = new AstGt ($2,$1,$3); }
|
|
| ~l~expr yP_GTE ~r~expr { $$ = new AstGte ($2,$1,$3); }
|
|
| ~l~expr '&' ~r~expr { $$ = new AstAnd ($2,$1,$3); }
|
|
| ~l~expr '|' ~r~expr { $$ = new AstOr ($2,$1,$3); }
|
|
| ~l~expr '^' ~r~expr { $$ = new AstXor ($2,$1,$3); }
|
|
| ~l~expr yP_XNOR ~r~expr { $$ = new AstXnor ($2,$1,$3); }
|
|
| ~l~expr yP_NOR ~r~expr { $$ = new AstNot($2,new AstOr ($2,$1,$3)); }
|
|
| ~l~expr yP_NAND ~r~expr { $$ = new AstNot($2,new AstAnd ($2,$1,$3)); }
|
|
| ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); }
|
|
| ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); }
|
|
| ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$3); }
|
|
// // <= is special, as we need to disambiguate it with <= assignment
|
|
// // We copy all of expr to fexpr and rename this token to a fake one.
|
|
| ~l~expr yP_LTE~f__IGNORE~ ~r~expr { $$ = new AstLte ($2,$1,$3); }
|
|
//
|
|
// // IEEE: conditional_expression
|
|
| ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); }
|
|
//
|
|
// // IEEE: inside_expression
|
|
| ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); }
|
|
//
|
|
// // IEEE: tagged_union_expression
|
|
//UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP }
|
|
//UNSUP yTAGGED id/*member*/ %prec prTAGGED expr { UNSUP }
|
|
//
|
|
//======================// PSL expressions
|
|
//
|
|
| ~l~expr yP_MINUSGT ~r~expr { $$ = new AstLogIf ($2,$1,$3); }
|
|
| ~l~expr yP_LOGIFF ~r~expr { $$ = new AstLogIff ($2,$1,$3); }
|
|
//
|
|
//======================// IEEE: primary/constant_primary
|
|
//
|
|
// // IEEE: primary_literal (minus string, which is handled specially)
|
|
| yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
|
|
| yaFLOATNUM { $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
|
|
//UNSUP yaTIMENUM { UNSUP }
|
|
| strAsInt~noStr__IGNORE~ { $$ = $1; }
|
|
//
|
|
// // IEEE: "... hierarchical_identifier select" see below
|
|
//
|
|
// // IEEE: empty_queue
|
|
//UNSUP '{' '}'
|
|
//
|
|
// // IEEE: concatenation/constant_concatenation
|
|
// // Part of exprOkLvalue below
|
|
//
|
|
// // IEEE: multiple_concatenation/constant_multiple_concatenation
|
|
| '{' constExpr '{' cateList '}' '}' { $$ = new AstReplicate($1,$4,$2); }
|
|
//
|
|
| function_subroutine_callNoMethod { $$ = $1; }
|
|
// // method_call
|
|
| ~l~expr '.' function_subroutine_callNoMethod { $$ = new AstDot($2,$1,$3); }
|
|
// // method_call:array_method requires a '.'
|
|
//UNSUP ~l~expr '.' array_methodNoRoot { UNSUP }
|
|
//
|
|
// // IEEE: let_expression
|
|
// // see funcRef
|
|
//
|
|
// // IEEE: '(' mintypmax_expression ')'
|
|
| ~noPar__IGNORE~'(' expr ')' { $$ = $2; }
|
|
//UNSUP ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' { $$ = $4; }
|
|
// // PSL rule
|
|
| '_' '(' statePushVlg expr statePop ')' { $$ = $4; } // Arbitrary Verilog inside PSL
|
|
//
|
|
// // IEEE: cast/constant_cast
|
|
| casting_type yP_TICK '(' expr ')' { $$ = new AstCast($2,$4,$1); }
|
|
// // expanded from casting_type
|
|
| ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned($1,$4); }
|
|
| yUNSIGNED yP_TICK '(' expr ')' { $$ = new AstUnsigned($1,$4); }
|
|
// // Spec only allows primary with addition of a type reference
|
|
// // We'll be more general, and later assert LHS was a type.
|
|
//UNSUP ~l~expr yP_TICK '(' expr ')' { UNSUP }
|
|
| yaINTNUM yP_TICK '(' expr ')' { $$ = new AstCastSize($2,$4,new AstConst($1->fileline(),*$1)); }
|
|
//
|
|
// // IEEE: assignment_pattern_expression
|
|
// // IEEE: streaming_concatenation
|
|
// // See exprOkLvalue
|
|
//
|
|
// // IEEE: sequence_method_call
|
|
// // Indistinguishable from function_subroutine_call:method_call
|
|
//
|
|
//UNSUP '$' { UNSUP }
|
|
//UNSUP yNULL { UNSUP }
|
|
// // IEEE: yTHIS
|
|
// // See exprScope
|
|
//
|
|
//----------------------
|
|
//
|
|
// // Part of expr that may also be used as lvalue
|
|
| ~l~exprOkLvalue { $$ = $1; }
|
|
//
|
|
//----------------------
|
|
//
|
|
// // IEEE: cond_predicate - here to avoid reduce problems
|
|
// // Note expr includes cond_pattern
|
|
//UNSUP ~l~expr yP_ANDANDAND ~r~expr { UNSUP }
|
|
//
|
|
// // IEEE: cond_pattern - here to avoid reduce problems
|
|
// // "expr yMATCHES pattern"
|
|
// // IEEE: pattern - expanded here to avoid conflicts
|
|
//UNSUP ~l~expr yMATCHES patternNoExpr { UNSUP }
|
|
//UNSUP ~l~expr yMATCHES ~r~expr { UNSUP }
|
|
//
|
|
// // IEEE: expression_or_dist - here to avoid reduce problems
|
|
// // "expr yDIST '{' dist_list '}'"
|
|
//UNSUP ~l~expr yDIST '{' dist_list '}' { UNSUP }
|
|
;
|
|
|
|
fexpr<nodep>: // For use as first part of statement (disambiguates <=)
|
|
BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied}
|
|
;
|
|
|
|
exprNoStr<nodep>: // expression with string removed
|
|
BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied}
|
|
;
|
|
|
|
exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
|
|
~l~exprScope { $$ = $1; }
|
|
// // IEEE: concatenation/constant_concatenation
|
|
| '{' cateList '}' { $$ = $2; }
|
|
// // IEEE: assignment_pattern_expression
|
|
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
|
|
// // We allow more here than the spec requires
|
|
//UNSUP ~l~exprScope assignment_pattern { UNSUP }
|
|
| data_type assignment_pattern { $$ = $2; $2->childDTypep($1); }
|
|
| assignment_pattern { $$ = $1; }
|
|
//
|
|
//UNSUP streaming_concatenation { UNSUP }
|
|
;
|
|
|
|
fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statement (disambiguates <=)
|
|
BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied}
|
|
;
|
|
|
|
fexprLvalue<nodep>: // For use as first part of statement (disambiguates <=)
|
|
fexprOkLvalue { $<fl>$=$<fl>1; $$ = $1; }
|
|
;
|
|
|
|
exprScope<nodep>: // scope and variable for use to inside an expression
|
|
// // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope
|
|
// // from the object being called and let expr's "." deal with resolving it.
|
|
// // (note method_call_root was simplified to require a primary in 1800-2009)
|
|
//
|
|
// // IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select
|
|
// // Or method_call_body without parenthesis
|
|
// // See also varRefClassBit, which is the non-expr version of most of this
|
|
//UNSUP yTHIS { UNSUP }
|
|
idArrayed { $$ = $1; }
|
|
| package_scopeIdFollows idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); }
|
|
//UNSUP class_scopeIdFollows idArrayed { UNSUP }
|
|
| ~l~expr '.' idArrayed { $$ = new AstDot($<fl>2,$1,$3); }
|
|
// // expr below must be a "yTHIS"
|
|
//UNSUP ~l~expr '.' ySUPER { UNSUP }
|
|
// // Part of implicit_class_handle
|
|
//UNSUP ySUPER { UNSUP }
|
|
;
|
|
|
|
fexprScope<nodep>: // exprScope, For use as first part of statement (disambiguates <=)
|
|
BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied}
|
|
;
|
|
|
|
// Psl excludes {}'s by lexer converting to different token
|
|
exprPsl<nodep>:
|
|
expr { $$ = $1; }
|
|
;
|
|
|
|
// PLI calls exclude "" as integers, they're strings
|
|
// For $c("foo","bar") we want "bar" as a string, not a Verilog integer.
|
|
exprStrText<nodep>:
|
|
exprNoStr { $$ = $1; }
|
|
| strAsText { $$ = $1; }
|
|
;
|
|
|
|
cStrList<nodep>:
|
|
exprStrText { $$ = $1; }
|
|
| exprStrText ',' cStrList { $$ = $1;$1->addNext($3); }
|
|
;
|
|
|
|
cateList<nodep>:
|
|
// // Not just 'expr' to prevent conflict via stream_concOrExprOrType
|
|
stream_expression { $$ = $1; }
|
|
| cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); }
|
|
;
|
|
|
|
exprList<nodep>:
|
|
expr { $$ = $1; }
|
|
| exprList ',' expr { $$ = $1;$1->addNext($3); }
|
|
;
|
|
|
|
commaEListE<nodep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| ',' exprList { $$ = $2; }
|
|
;
|
|
|
|
vrdList<nodep>:
|
|
idClassSel { $$ = $1; }
|
|
| vrdList ',' idClassSel { $$ = $1;$1->addNext($3); }
|
|
;
|
|
|
|
commaVRDListE<nodep>:
|
|
/* empty */ { $$ = NULL; }
|
|
| ',' vrdList { $$ = $2; }
|
|
;
|
|
|
|
argsExprList<nodep>: // IEEE: part of list_of_arguments (used where ,, isn't legal)
|
|
expr { $$ = $1; }
|
|
| argsExprList ',' expr { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
argsExprListE<nodep>: // IEEE: part of list_of_arguments
|
|
argsExprOneE { $$ = $1; }
|
|
| argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
argsExprOneE<nodep>: // IEEE: part of list_of_arguments
|
|
/*empty*/ { $$ = new AstArg(CRELINE(),"",NULL); }
|
|
| expr { $$ = new AstArg(CRELINE(),"",$1); }
|
|
;
|
|
|
|
argsDottedList<nodep>: // IEEE: part of list_of_arguments
|
|
argsDotted { $$ = $1; }
|
|
| argsDottedList ',' argsDotted { $$ = $1->addNextNull($3); }
|
|
;
|
|
|
|
argsDotted<nodep>: // IEEE: part of list_of_arguments
|
|
'.' idAny '(' ')' { $$ = new AstArg($1,*$2,NULL); }
|
|
| '.' idAny '(' expr ')' { $$ = new AstArg($1,*$2,$4); }
|
|
;
|
|
|
|
stream_expression<nodep>: // ==IEEE: stream_expression
|
|
// // IEEE: array_range_expression expanded below
|
|
expr { $$ = $1; }
|
|
//UNSUP expr yWITH__BRA '[' expr ']' { UNSUP }
|
|
//UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP }
|
|
//UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP }
|
|
//UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP }
|
|
;
|
|
|
|
//************************************************
|
|
// Gate declarations
|
|
|
|
gateDecl<nodep>:
|
|
yBUF delayE gateBufList ';' { $$ = $3; }
|
|
| yBUFIF0 delayE gateBufif0List ';' { $$ = $3; }
|
|
| yBUFIF1 delayE gateBufif1List ';' { $$ = $3; }
|
|
| yNOT delayE gateNotList ';' { $$ = $3; }
|
|
| yNOTIF0 delayE gateNotif0List ';' { $$ = $3; }
|
|
| yNOTIF1 delayE gateNotif1List ';' { $$ = $3; }
|
|
| yAND delayE gateAndList ';' { $$ = $3; }
|
|
| yNAND delayE gateNandList ';' { $$ = $3; }
|
|
| yOR delayE gateOrList ';' { $$ = $3; }
|
|
| yNOR delayE gateNorList ';' { $$ = $3; }
|
|
| yXOR delayE gateXorList ';' { $$ = $3; }
|
|
| yXNOR delayE gateXnorList ';' { $$ = $3; }
|
|
| yPULLUP delayE gatePullupList ';' { $$ = $3; }
|
|
| yPULLDOWN delayE gatePulldownList ';' { $$ = $3; }
|
|
| yNMOS delayE gateBufif1List ';' { $$ = $3; } // ~=bufif1, as don't have strengths yet
|
|
| yPMOS delayE gateBufif0List ';' { $$ = $3; } // ~=bufif0, as don't have strengths yet
|
|
//
|
|
| yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported
|
|
| yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported
|
|
| yCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported
|
|
| yRNMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported
|
|
| yRPMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported
|
|
| yRTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported
|
|
| yRTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported
|
|
| yRTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported
|
|
| yTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported
|
|
| yTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported
|
|
;
|
|
|
|
gateBufList<nodep>:
|
|
gateBuf { $$ = $1; }
|
|
| gateBufList ',' gateBuf { $$ = $1->addNext($3); }
|
|
;
|
|
gateBufif0List<nodep>:
|
|
gateBufif0 { $$ = $1; }
|
|
| gateBufif0List ',' gateBufif0 { $$ = $1->addNext($3); }
|
|
;
|
|
gateBufif1List<nodep>:
|
|
gateBufif1 { $$ = $1; }
|
|
| gateBufif1List ',' gateBufif1 { $$ = $1->addNext($3); }
|
|
;
|
|
gateNotList<nodep>:
|
|
gateNot { $$ = $1; }
|
|
| gateNotList ',' gateNot { $$ = $1->addNext($3); }
|
|
;
|
|
gateNotif0List<nodep>:
|
|
gateNotif0 { $$ = $1; }
|
|
| gateNotif0List ',' gateNotif0 { $$ = $1->addNext($3); }
|
|
;
|
|
gateNotif1List<nodep>:
|
|
gateNotif1 { $$ = $1; }
|
|
| gateNotif1List ',' gateNotif1 { $$ = $1->addNext($3); }
|
|
;
|
|
gateAndList<nodep>:
|
|
gateAnd { $$ = $1; }
|
|
| gateAndList ',' gateAnd { $$ = $1->addNext($3); }
|
|
;
|
|
gateNandList<nodep>:
|
|
gateNand { $$ = $1; }
|
|
| gateNandList ',' gateNand { $$ = $1->addNext($3); }
|
|
;
|
|
gateOrList<nodep>:
|
|
gateOr { $$ = $1; }
|
|
| gateOrList ',' gateOr { $$ = $1->addNext($3); }
|
|
;
|
|
gateNorList<nodep>:
|
|
gateNor { $$ = $1; }
|
|
| gateNorList ',' gateNor { $$ = $1->addNext($3); }
|
|
;
|
|
gateXorList<nodep>:
|
|
gateXor { $$ = $1; }
|
|
| gateXorList ',' gateXor { $$ = $1->addNext($3); }
|
|
;
|
|
gateXnorList<nodep>:
|
|
gateXnor { $$ = $1; }
|
|
| gateXnorList ',' gateXnor { $$ = $1->addNext($3); }
|
|
;
|
|
gatePullupList<nodep>:
|
|
gatePullup { $$ = $1; }
|
|
| gatePullupList ',' gatePullup { $$ = $1->addNext($3); }
|
|
;
|
|
gatePulldownList<nodep>:
|
|
gatePulldown { $$ = $1; }
|
|
| gatePulldownList ',' gatePulldown { $$ = $1->addNext($3); }
|
|
;
|
|
gateUnsupList<nodep>:
|
|
gateUnsup { $$ = $1; }
|
|
| gateUnsupList ',' gateUnsup { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
gateBuf<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
|
|
;
|
|
gateBufif0<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8),$6)); DEL($2); }
|
|
;
|
|
gateBufif1<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8,$6)); DEL($2); }
|
|
;
|
|
gateNot<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
|
|
;
|
|
gateNotif0<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8), new AstNot($3, $6))); DEL($2); }
|
|
;
|
|
gateNotif1<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8, new AstNot($3,$6))); DEL($2); }
|
|
;
|
|
gateAnd<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
|
|
;
|
|
gateNand<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
|
|
;
|
|
gateOr<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
|
|
;
|
|
gateNor<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
|
|
;
|
|
gateXor<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
|
|
;
|
|
gateXnor<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
|
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
|
|
;
|
|
gatePullup<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); DEL($2); }
|
|
;
|
|
gatePulldown<nodep>:
|
|
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); DEL($2); }
|
|
;
|
|
gateUnsup<nodep>:
|
|
gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); DEL($2); }
|
|
;
|
|
|
|
gateIdE:
|
|
/*empty*/ {}
|
|
| id {}
|
|
;
|
|
|
|
gateAndPinList<nodep>:
|
|
expr { $$ = $1; }
|
|
| gateAndPinList ',' expr { $$ = new AstAnd($2,$1,$3); }
|
|
;
|
|
gateOrPinList<nodep>:
|
|
expr { $$ = $1; }
|
|
| gateOrPinList ',' expr { $$ = new AstOr($2,$1,$3); }
|
|
;
|
|
gateXorPinList<nodep>:
|
|
expr { $$ = $1; }
|
|
| gateXorPinList ',' expr { $$ = new AstXor($2,$1,$3); }
|
|
;
|
|
gateUnsupPinList<nodep>:
|
|
expr { $$ = $1; }
|
|
| gateUnsupPinList ',' expr { $$ = $1->addNext($3); }
|
|
;
|
|
|
|
strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
|
|
/* empty */ { }
|
|
//UNSUP strengthSpec { }
|
|
;
|
|
|
|
//************************************************
|
|
// Tables
|
|
|
|
combinational_body<nodep>: // IEEE: combinational_body + sequential_body
|
|
yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable($1,$2); }
|
|
;
|
|
|
|
tableEntryList<nodep>: // IEEE: { combinational_entry | sequential_entry }
|
|
tableEntry { $$ = $1; }
|
|
| tableEntryList tableEntry { $$ = $1->addNext($2); }
|
|
;
|
|
|
|
tableEntry<nodep>: // IEEE: combinational_entry + sequential_entry
|
|
yaTABLELINE { $$ = new AstUdpTableLine($<fl>1,*$1); }
|
|
| error { $$ = NULL; }
|
|
;
|
|
|
|
//************************************************
|
|
// Specify
|
|
|
|
specify_block<nodep>: // ==IEEE: specify_block
|
|
ySPECIFY specifyJunkList yENDSPECIFY { $$ = NULL; }
|
|
| ySPECIFY yENDSPECIFY { $$ = NULL; }
|
|
;
|
|
|
|
specifyJunkList:
|
|
specifyJunk { } /* ignored */
|
|
| specifyJunkList specifyJunk { } /* ignored */
|
|
;
|
|
|
|
specifyJunk:
|
|
BISONPRE_NOT(ySPECIFY,yENDSPECIFY) { }
|
|
| ySPECIFY specifyJunk yENDSPECIFY { }
|
|
| error {}
|
|
;
|
|
|
|
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
|
ySPECPARAM junkToSemiList ';' { $$ = NULL; }
|
|
;
|
|
|
|
junkToSemiList:
|
|
junkToSemi { } /* ignored */
|
|
| junkToSemiList junkToSemi { } /* ignored */
|
|
;
|
|
|
|
junkToSemi:
|
|
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
|
|
| error {}
|
|
;
|
|
|
|
//************************************************
|
|
// IDs
|
|
|
|
id<strp>:
|
|
yaID__ETC { $$ = $1; $<fl>$=$<fl>1; }
|
|
;
|
|
|
|
idAny<strp>: // Any kind of identifier
|
|
//UNSUP yaID__aCLASS { $$ = $1; $<fl>$=$<fl>1; }
|
|
//UNSUP yaID__aCOVERGROUP { $$ = $1; $<fl>$=$<fl>1; }
|
|
yaID__aPACKAGE { $$ = $1; $<fl>$=$<fl>1; }
|
|
| yaID__aTYPE { $$ = $1; $<fl>$=$<fl>1; }
|
|
| yaID__ETC { $$ = $1; $<fl>$=$<fl>1; }
|
|
;
|
|
|
|
idSVKwd<strp>: // Warn about non-forward compatible Verilog 2001 code
|
|
// // yBIT, yBYTE won't work here as causes conflicts
|
|
yDO { static string s = "do" ; $$ = &s; ERRSVKWD($1,*$$); $<fl>$=$<fl>1; }
|
|
| yFINAL { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $<fl>$=$<fl>1; }
|
|
;
|
|
|
|
variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue
|
|
// // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist
|
|
idClassSel { $$ = $1; }
|
|
| '{' variable_lvalueConcList '}' { $$ = $2; }
|
|
// // IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue
|
|
// // We allow more assignment_pattern_expression_types then strictly required
|
|
//UNSUP data_type yP_TICKBRA variable_lvalueList '}' { UNSUP }
|
|
//UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP }
|
|
//UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP }
|
|
//UNSUP streaming_concatenation { UNSUP }
|
|
;
|
|
|
|
variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}'
|
|
variable_lvalue { $$ = $1; }
|
|
| variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); }
|
|
;
|
|
|
|
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable
|
|
idClassSel<nodep>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
|
|
idDotted { $$ = $1; }
|
|
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
|
|
//UNSUP yTHIS '.' idDotted { UNSUP }
|
|
//UNSUP ySUPER '.' idDotted { UNSUP }
|
|
//UNSUP yTHIS '.' ySUPER '.' idDotted { UNSUP }
|
|
// // Expanded: package_scope idDotted
|
|
//UNSUP class_scopeIdFollows idDotted { UNSUP }
|
|
//UNSUP package_scopeIdFollows idDotted { UNSUP }
|
|
;
|
|
|
|
idDotted<nodep>:
|
|
//UNSUP yD_ROOT '.' idDottedMore { UNSUP }
|
|
idDottedMore { $$ = $1; }
|
|
;
|
|
|
|
idDottedMore<nodep>:
|
|
idArrayed { $$ = $1; }
|
|
| idDottedMore '.' idArrayed { $$ = new AstDot($2,$1,$3); }
|
|
;
|
|
|
|
// Single component of dotted path, maybe [#].
|
|
// Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part),
|
|
// we'll assume so and cleanup later.
|
|
// id below includes:
|
|
// enum_identifier
|
|
idArrayed<nodep>: // IEEE: id + select
|
|
id { $$ = new AstParseRef($<fl>1,AstParseRefExp::PX_TEXT,*$1,NULL,NULL); }
|
|
// // IEEE: id + part_select_range/constant_part_select_range
|
|
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
|
|
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); }
|
|
// // IEEE: id + indexed_range/constant_indexed_range
|
|
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); }
|
|
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); }
|
|
;
|
|
|
|
// VarRef without any dots or vectorizaion
|
|
varRefBase<varrefp>:
|
|
id { $$ = new AstVarRef($<fl>1,*$1,false);}
|
|
;
|
|
|
|
// yaSTRING shouldn't be used directly, instead via an abstraction below
|
|
str<strp>: // yaSTRING but with \{escapes} need decoded
|
|
yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($<fl>1,*$1)); }
|
|
;
|
|
|
|
strAsInt<nodep>:
|
|
yaSTRING { $$ = new AstConst($<fl>1,V3Number(V3Number::VerilogString(),$<fl>1,GRAMMARP->deQuote($<fl>1,*$1)));}
|
|
;
|
|
|
|
strAsIntIgnore<nodep>: // strAsInt, but never matches for when expr shouldn't parse strings
|
|
yaSTRING__IGNORE { $$ = NULL; yyerror("Impossible token"); }
|
|
;
|
|
|
|
strAsText<nodep>:
|
|
yaSTRING { $$ = GRAMMARP->createTextQuoted($<fl>1,*$1);}
|
|
;
|
|
|
|
endLabelE<strp>:
|
|
/* empty */ { $$ = NULL; $<fl>$=NULL; }
|
|
| ':' idAny { $$ = $2; $<fl>$=$<fl>2; }
|
|
//UNSUP ':' yNEW__ETC { $$ = $2; $<fl>$=$<fl>2; }
|
|
;
|
|
|
|
//************************************************
|
|
// Clocking
|
|
|
|
clocking_declaration<nodep>: // IEEE: clocking_declaration (INCOMPLETE)
|
|
yDEFAULT yCLOCKING '@' '(' senitemEdge ')' ';' yENDCLOCKING
|
|
{ $$ = new AstClocking($1, $5, NULL); }
|
|
//UNSUP: Vastly simplified grammar
|
|
;
|
|
|
|
//************************************************
|
|
// Asserts
|
|
|
|
labeledStmt<nodep>:
|
|
immediate_assert_statement { $$ = $1; }
|
|
;
|
|
|
|
concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item
|
|
concurrent_assertion_statement { $$ = $1; }
|
|
| id/*block_identifier*/ ':' concurrent_assertion_statement { $$ = new AstBegin($2,*$1,$3); }
|
|
// // IEEE: checker_instantiation
|
|
// // identical to module_instantiation; see etcInst
|
|
;
|
|
|
|
concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statement
|
|
//UNSUP: assert/assume
|
|
// // IEEE: cover_property_statement
|
|
yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstPslCover($1,$4,$6); }
|
|
;
|
|
|
|
property_spec<nodep>: // IEEE: property_spec
|
|
//UNSUP: This rule has been super-specialized to what is supported now
|
|
'@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' expr
|
|
{ $$ = new AstPslClocked($1,$3,$8,$10); }
|
|
| '@' '(' senitemEdge ')' expr { $$ = new AstPslClocked($1,$3,NULL,$5); }
|
|
| yDISABLE yIFF '(' expr ')' expr { $$ = new AstPslClocked($4->fileline(),NULL,$4,$6); }
|
|
| expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); }
|
|
;
|
|
|
|
immediate_assert_statement<nodep>: // ==IEEE: immediate_assert_statement
|
|
// // action_block expanded here, for compatibility with AstVAssert
|
|
yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, GRAMMARP->createDisplayError($1)); }
|
|
| yASSERT '(' expr ')' yELSE stmtBlock { $$ = new AstVAssert($1,$3,NULL,$6); }
|
|
| yASSERT '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstVAssert($1,$3,$5,$7); }
|
|
;
|
|
|
|
//************************************************
|
|
// Covergroup
|
|
|
|
//**********************************************************************
|
|
// Randsequence
|
|
|
|
//**********************************************************************
|
|
// Class
|
|
|
|
//=========
|
|
// Package scoping - to traverse the symbol table properly, the final identifer
|
|
// must be included in the rules below.
|
|
// Each of these must end with {symsPackageDone | symsClassDone}
|
|
|
|
ps_id_etc: // package_scope + general id
|
|
package_scopeIdFollowsE id { }
|
|
;
|
|
|
|
ps_type<dtypep>: // IEEE: ps_parameter_identifier | ps_type_identifier
|
|
// Even though we looked up the type and have a AstNode* to it,
|
|
// we can't fully resolve it because it may have been just a forward definition.
|
|
package_scopeIdFollowsE yaID__aTYPE { $$ = new AstRefDType($<fl>2, *$2); $$->castRefDType()->packagep($1); }
|
|
// // Simplify typing - from ps_covergroup_identifier
|
|
//UNSUP package_scopeIdFollowsE yaID__aCOVERGROUP { $<fl>$=$<fl>1; $$=$1+$2; }
|
|
;
|
|
|
|
//=== Below rules assume special scoping per above
|
|
|
|
package_scopeIdFollowsE<packagep>: // IEEE: [package_scope]
|
|
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
|
// // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' class_scope ]
|
|
/* empty */ { $$ = NULL; }
|
|
| package_scopeIdFollows { $$ = $1; }
|
|
;
|
|
|
|
package_scopeIdFollows<packagep>: // IEEE: package_scope
|
|
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
|
// //vv mid rule action needed otherwise we might not have NextId in time to parse the id token
|
|
yD_UNIT { SYMP->nextId(PARSEP->rootp()); }
|
|
/*cont*/ yP_COLONCOLON { $$ = GRAMMARP->unitPackage($<fl>1); }
|
|
| yaID__aPACKAGE { SYMP->nextId($<scp>1); }
|
|
/*cont*/ yP_COLONCOLON { $$ = $<scp>1->castPackage(); }
|
|
//UNSUP yLOCAL__COLONCOLON { PARSEP->symTableNextId($<scp>1); }
|
|
//UNSUP /*cont*/ yP_COLONCOLON { UNSUP }
|
|
;
|
|
|
|
//************************************************
|
|
// PSL Statements
|
|
|
|
pslStmt<nodep>:
|
|
yPSL pslDir stateExitPsl { $$ = $2; }
|
|
| yPSL pslDecl stateExitPsl { $$ = $2; }
|
|
;
|
|
|
|
pslDir<nodep>:
|
|
id ':' pslDirOne { $$ = $3; }
|
|
| pslDirOne { $$ = $1; }
|
|
;
|
|
|
|
pslDirOne<nodep>:
|
|
yPSL_ASSERT pslProp ';' { $$ = new AstPslAssert($1,$2); }
|
|
| yPSL_ASSERT pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslAssert($1,$2,*$4); }
|
|
| yPSL_COVER pslProp ';' { $$ = new AstPslCover($1,$2,NULL); }
|
|
| yPSL_COVER pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslCover($1,$2,NULL,*$4); }
|
|
;
|
|
|
|
pslDecl<nodep>:
|
|
yDEFAULT yPSL_CLOCK '=' senitemEdge ';' { $$ = new AstPslDefClock($3, $4); }
|
|
| yDEFAULT yPSL_CLOCK '=' '(' senitemEdge ')' ';' { $$ = new AstPslDefClock($3, $5); }
|
|
;
|
|
|
|
//************************************************
|
|
// PSL Properties, Sequences and SEREs
|
|
// Don't use '{' or '}'; in PSL they're yPSL_BRA and yPSL_KET to avoid expr concatenates
|
|
|
|
pslProp<nodep>:
|
|
pslSequence { $$ = $1; }
|
|
| pslSequence '@' %prec prPSLCLK '(' senitemEdge ')' { $$ = new AstPslClocked($2,$4,NULL,$1); } // or pslSequence @ ...?
|
|
;
|
|
|
|
pslSequence<nodep>:
|
|
yPSL_BRA pslSere yPSL_KET { $$ = $2; }
|
|
;
|
|
|
|
pslSere<nodep>:
|
|
pslExpr { $$ = $1; }
|
|
| pslSequence { $$ = $1; } // Sequence containing sequence
|
|
;
|
|
|
|
// Undocumented PSL rule is that {} is always a SERE; concatenation is not allowed.
|
|
// This can be bypassed with the _(...) embedding of any arbitrary expression.
|
|
pslExpr<nodep>:
|
|
exprPsl { $$ = new AstPslBool($1->fileline(), $1); }
|
|
| yTRUE { $$ = new AstPslBool($1, new AstConst($1, AstConst::LogicTrue())); }
|
|
;
|
|
|
|
//**********************************************************************
|
|
// VLT Files
|
|
|
|
vltItem:
|
|
vltOffFront { V3Config::addIgnore($1,"*",0,0); }
|
|
| vltOffFront yVLT_D_FILE yaSTRING { V3Config::addIgnore($1,*$3,0,0); }
|
|
| vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM { V3Config::addIgnore($1,*$3,$5->toUInt(),$5->toUInt()+1); }
|
|
| vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM { V3Config::addIgnore($1,*$3,$5->toUInt(),$7->toUInt()+1); }
|
|
;
|
|
|
|
vltOffFront<errcodeen>:
|
|
yVLT_COVERAGE_OFF { $$ = V3ErrorCode::I_COVERAGE; }
|
|
| yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; }
|
|
| yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; }
|
|
| yVLT_LINT_OFF yVLT_D_MSG yaID__ETC
|
|
{ $$ = V3ErrorCode((*$3).c_str());
|
|
if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<<endl); } }
|
|
;
|
|
|
|
//**********************************************************************
|
|
%%
|
|
|
|
int V3ParseImp::bisonParse() {
|
|
if (PARSEP->debugBison()>=9) yydebug = 1;
|
|
return yyparse();
|
|
}
|
|
|
|
const char* V3ParseImp::tokenName(int token) {
|
|
#if YYDEBUG || YYERROR_VERBOSE
|
|
if (token >= 255)
|
|
return yytname[token-255];
|
|
else {
|
|
static char ch[2]; ch[0]=token; ch[1]='\0';
|
|
return ch;
|
|
}
|
|
#else
|
|
return "";
|
|
#endif
|
|
}
|
|
|
|
void V3ParseImp::parserClear() {
|
|
// Clear up any dynamic memory V3Parser required
|
|
VARDTYPE(NULL);
|
|
}
|
|
|
|
void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
|
|
// Convert list of expressions to list of arguments
|
|
AstNode* outp = NULL;
|
|
while (nodep->pinsp()) {
|
|
AstNode* exprp = nodep->pinsp()->unlinkFrBack();
|
|
outp = outp->addNext(new AstArg(exprp->fileline(), "", exprp));
|
|
}
|
|
if (outp) nodep->addPinsp(outp);
|
|
}
|
|
|
|
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int value) {
|
|
FileLine* newfl = new FileLine (fileline);
|
|
newfl->warnOff(V3ErrorCode::WIDTH, true);
|
|
AstNode* nodep = new AstConst(newfl, V3Number(newfl));
|
|
// Adding a NOT is less work than figuring out how wide to make it
|
|
if (value) nodep = new AstNot(newfl, nodep);
|
|
nodep = new AstAssignW(newfl, new AstVarRef(fileline, name, true),
|
|
nodep);
|
|
return nodep;
|
|
}
|
|
|
|
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked) {
|
|
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
|
AstNodeDType* arrayp = basep;
|
|
if (rangep) { // Maybe no range - return unmodified base type
|
|
while (rangep->nextp()) rangep = rangep->nextp()->castRange();
|
|
while (rangep) {
|
|
AstRange* prevp = rangep->backp()->castRange();
|
|
if (prevp) rangep->unlinkFrBack();
|
|
if (isPacked) {
|
|
arrayp = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
|
} else {
|
|
arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
|
}
|
|
rangep = prevp;
|
|
}
|
|
}
|
|
return arrayp;
|
|
}
|
|
|
|
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp) {
|
|
AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
|
|
UINFO(5," creVar "<<name<<" decl="<<GRAMMARP->m_varDecl<<" io="<<GRAMMARP->m_varIO<<" dt="<<(dtypep?"set":"")<<endl);
|
|
if (GRAMMARP->m_varIO == AstVarType::UNKNOWN
|
|
&& GRAMMARP->m_varDecl == AstVarType::PORT) {
|
|
// Just a port list with variable name (not v2k format); AstPort already created
|
|
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
|
|
return NULL;
|
|
}
|
|
AstVarType type = GRAMMARP->m_varIO;
|
|
if (dtypep->castIfaceRefDType()) {
|
|
if (arrayp) { fileline->v3error("Unsupported: Arrayed interfaces"); arrayp=NULL; }
|
|
}
|
|
if (!dtypep) { // Created implicitly
|
|
dtypep = new AstBasicDType(fileline, LOGIC_IMPLICIT);
|
|
} else { // May make new variables with same type, so clone
|
|
dtypep = dtypep->cloneTree(false);
|
|
}
|
|
//UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
|
if (type == AstVarType::UNKNOWN
|
|
|| (type == AstVarType::PORT && GRAMMARP->m_varDecl != AstVarType::UNKNOWN))
|
|
type = GRAMMARP->m_varDecl;
|
|
if (type == AstVarType::UNKNOWN) fileline->v3fatalSrc("Unknown signal type declared");
|
|
if (type == AstVarType::GENVAR) {
|
|
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
|
|
}
|
|
|
|
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
|
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp,false);
|
|
|
|
AstVar* nodep = new AstVar(fileline, type, name, VFlagChildDType(), arrayDTypep);
|
|
nodep->addAttrsp(attrsp);
|
|
if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
|
|
if (GRAMMARP->m_varIO != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varIO);
|
|
|
|
if (GRAMMARP->m_varDecl == AstVarType::SUPPLY0) {
|
|
nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0));
|
|
}
|
|
if (GRAMMARP->m_varDecl == AstVarType::SUPPLY1) {
|
|
nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1));
|
|
}
|
|
// Don't set dtypep in the ranging;
|
|
// We need to autosize parameters and integers separately
|
|
//
|
|
// Propagate from current module tracing state
|
|
if (nodep->isGenVar()) nodep->trace(false);
|
|
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
|
|
else nodep->trace(v3Global.opt.trace() && nodep->fileline()->tracingOn());
|
|
|
|
// Remember the last variable created, so we can attach attributes to it in later parsing
|
|
GRAMMARP->m_varAttrp = nodep;
|
|
return nodep;
|
|
}
|
|
|
|
string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
|
|
// Fix up the quoted strings the user put in, for example "\"" becomes "
|
|
// Reverse is AstNode::quoteName(...)
|
|
bool quoted = false;
|
|
string newtext;
|
|
unsigned char octal_val = 0;
|
|
int octal_digits = 0;
|
|
for (const char* cp=text.c_str(); *cp; ++cp) {
|
|
if (quoted) {
|
|
if (isdigit(*cp)) {
|
|
octal_val = octal_val*8 + (*cp-'0');
|
|
if (++octal_digits == 3) {
|
|
octal_digits = 0;
|
|
quoted = false;
|
|
newtext += octal_val;
|
|
}
|
|
} else {
|
|
if (octal_digits) {
|
|
// Spec allows 1-3 digits
|
|
octal_digits = 0;
|
|
quoted = false;
|
|
newtext += octal_val;
|
|
--cp; // Backup to reprocess terminating character as non-escaped
|
|
continue;
|
|
}
|
|
quoted = false;
|
|
if (*cp == 'n') newtext += '\n';
|
|
else if (*cp == 'a') newtext += '\a'; // SystemVerilog 3.1
|
|
else if (*cp == 'f') newtext += '\f'; // SystemVerilog 3.1
|
|
else if (*cp == 'r') newtext += '\r';
|
|
else if (*cp == 't') newtext += '\t';
|
|
else if (*cp == 'v') newtext += '\v'; // SystemVerilog 3.1
|
|
else if (*cp == 'x' && isxdigit(cp[1]) && isxdigit(cp[2])) { // SystemVerilog 3.1
|
|
#define vl_decodexdigit(c) ((isdigit(c)?((c)-'0'):(tolower((c))-'a'+10)))
|
|
newtext += (char)(16*vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
|
|
cp += 2;
|
|
}
|
|
else if (isalnum(*cp)) {
|
|
fileline->v3error("Unknown escape sequence: \\"<<*cp);
|
|
break;
|
|
}
|
|
else newtext += *cp;
|
|
}
|
|
}
|
|
else if (*cp == '\\') {
|
|
quoted = true;
|
|
octal_digits = 0;
|
|
}
|
|
else if (*cp != '"') {
|
|
newtext += *cp;
|
|
}
|
|
}
|
|
return newtext;
|
|
}
|
|
|
|
//YACC = /kits/sources/bison-2.4.1/src/bison --report=lookahead
|
|
// --report=lookahead
|
|
// --report=itemset
|
|
// --graph
|