/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: CompileVHDL.java
* Compile VHDL to a netlist
* Written by Andrew R. Kostiuk, Queen's University.
* Translated to Java by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2005 Sun Microsystems and Static Free Software
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.user;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.tool.sc.SilComp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
/**
* This is the VHDL Compiler.
*/
public class CompileVHDL
{
/********** Token Definitions ******************************************/
/********** Delimiters **********/
private static final int TOKEN_AMPERSAND = 0;
private static final int TOKEN_APOSTROPHE = 1;
private static final int TOKEN_LEFTBRACKET = 2;
private static final int TOKEN_RIGHTBRACKET = 3;
private static final int TOKEN_STAR = 4;
private static final int TOKEN_PLUS = 5;
private static final int TOKEN_COMMA = 6;
private static final int TOKEN_MINUS = 7;
private static final int TOKEN_PERIOD = 8;
private static final int TOKEN_SLASH = 9;
private static final int TOKEN_COLON = 10;
private static final int TOKEN_SEMICOLON = 11;
private static final int TOKEN_LT = 12;
private static final int TOKEN_EQ = 13;
private static final int TOKEN_GT = 14;
private static final int TOKEN_VERTICALBAR = 15;
/********** Compound Delimiters **********/
private static final int TOKEN_ARROW = 16;
private static final int TOKEN_DOUBLEDOT = 17;
private static final int TOKEN_DOUBLESTAR = 18;
private static final int TOKEN_VARASSIGN = 19;
private static final int TOKEN_NE = 20;
private static final int TOKEN_GE = 21;
private static final int TOKEN_LE = 22;
private static final int TOKEN_BOX = 23;
/********** Other Token **********/
private static final int TOKEN_UNKNOWN = 24;
private static final int TOKEN_IDENTIFIER = 25; /* alphanumeric (first char alpha) */
private static final int TOKEN_KEYWORD = 26; /* reserved keyword of the language */
private static final int TOKEN_DECIMAL = 27; /* decimal literal */
private static final int TOKEN_BASED = 28; /* based literal */
private static final int TOKEN_CHAR = 29; /* character literal */
private static final int TOKEN_STRING = 30; /* string enclosed in double quotes */
private static final int TOKEN_BIT_STRING = 31; /* bit string */
/********** Keyword Constants ******************************************/
private static final int KEY_ABS = 0;
private static final int KEY_AFTER = 1;
private static final int KEY_ALIAS = 2;
private static final int KEY_AND = 3;
private static final int KEY_ARCHITECTURE = 4;
private static final int KEY_ARRAY = 5;
private static final int KEY_ASSERTION = 6;
private static final int KEY_ATTRIBUTE = 7;
private static final int KEY_BEHAVIORAL = 8;
private static final int KEY_BEGIN = 9;
private static final int KEY_BODY = 10;
private static final int KEY_CASE = 11;
private static final int KEY_COMPONENT = 12;
private static final int KEY_CONNECT = 13;
private static final int KEY_CONSTANT = 14;
private static final int KEY_CONVERT = 15;
private static final int KEY_DOT = 16;
private static final int KEY_DOWNTO = 17;
private static final int KEY_ELSE = 18;
private static final int KEY_ELSIF = 19;
private static final int KEY_END = 20;
private static final int KEY_ENTITY = 21;
private static final int KEY_EXIT = 22;
private static final int KEY_FOR = 23;
private static final int KEY_FUNCTION = 24;
private static final int KEY_GENERATE = 25;
private static final int KEY_GENERIC = 26;
private static final int KEY_IF = 27;
private static final int KEY_IN = 28;
private static final int KEY_INOUT = 29;
private static final int KEY_IS = 30;
private static final int KEY_LINKAGE = 31;
private static final int KEY_LOOP = 32;
private static final int KEY_MOD = 33;
private static final int KEY_NAND = 34;
private static final int KEY_NEXT = 35;
private static final int KEY_NOR = 36;
private static final int KEY_NOT = 37;
private static final int KEY_NULL = 38;
private static final int KEY_OF = 39;
private static final int KEY_OR = 40;
private static final int KEY_OTHERS = 41;
private static final int KEY_OUT = 42;
private static final int KEY_PACKAGE = 43;
private static final int KEY_PORT = 44;
private static final int KEY_RANGE = 45;
private static final int KEY_RECORD = 46;
private static final int KEY_REM = 47;
private static final int KEY_REPORT = 48;
private static final int KEY_RESOLVE = 49;
private static final int KEY_RETURN = 50;
private static final int KEY_SEVERITY = 51;
private static final int KEY_SIGNAL = 52;
private static final int KEY_STANDARD = 53;
private static final int KEY_STATIC = 54;
private static final int KEY_SUBTYPE = 55;
private static final int KEY_THEN = 56;
private static final int KEY_TO = 57;
private static final int KEY_TYPE = 58;
private static final int KEY_UNITS = 59;
private static final int KEY_USE = 60;
private static final int KEY_VARIABLE = 61;
private static final int KEY_WHEN = 62;
private static final int KEY_WHILE = 63;
private static final int KEY_WITH = 64;
private static final int KEY_XOR = 65;
private static final int KEY_OPEN = 66;
private static final int KEY_MAP = 67;
private static final int KEY_ALL = 68;
private static final int KEY_LIBRARY = 69;
/********** Miscellaneous Constants *********************************/
/** enternal entities flag */ private static final boolean EXTERNALENTITIES = true;
/** warning flag, TRUE warn */ private static final boolean WARNFLAG = false;
/** flag the entity as called */ private static final int TOP_ENTITY_FLAG = 0x0001;
/** flag the entity as written */ private static final int ENTITY_WRITTEN = 0x0002;
/********** Keyword Structures *****************************************/
private static class VKeyword
{
/** string defining keyword */ String name;
/** number of keyword */ int num;
VKeyword(String name, int num) { this.name = name; this.num = num; }
};
/********** Token Structures *****************************************/
private class TokenList
{
/** token number */ int token;
/** NULL if delimiter,
* pointer to global name space if identifier,
* pointer to keyword table if keyword,
* pointer to string if decimal literal,
* pointer to string if based literal,
* value of character if character literal,
* pointer to string if string literal,
* pointer to string if bit string literal */ Object pointer;
/** TRUE if space before next token */ boolean space;
/** line number token occurred */ int lineNum;
/** next in list */ TokenList next;
/** previous in list */ TokenList last;
TokenList(int token, Object pointer, int lineNum, boolean space)
{
this.token = token;
this.pointer = pointer;
this.lineNum = lineNum;
this.space = true;
this.next = null;
this.last = tListEnd;
if (tListEnd == null)
{
tListStart = tListEnd = this;
} else
{
tListEnd.space = space;
tListEnd.next = this;
tListEnd = this;
}
}
};
/********** Symbol Trees **********************************************/
private static final int SYMBOL_ENTITY = 1;
private static final int SYMBOL_BODY = 2;
private static final int SYMBOL_TYPE = 3;
private static final int SYMBOL_FPORT = 4;
private static final int SYMBOL_COMPONENT = 5;
private static final int SYMBOL_SIGNAL = 6;
private static final int SYMBOL_INSTANCE = 7;
private static final int SYMBOL_VARIABLE = 8;
private static final int SYMBOL_LABEL = 9;
private static final int SYMBOL_PACKAGE = 10;
private static final int SYMBOL_CONSTANT = 11;
private static class SymbolTree
{
/** identifier */ String value;
/** type of item */ int type;
/** pointer to item */ Object pointer;
/** flag for deallocation */ int seen;
};
private static class SymbolList
{
/** the symbol table map */ HashMap<String,SymbolTree> sym;
/** previous in stack */ SymbolList last;
/** next in list */ SymbolList next;
};
/********** Unresolved Reference List **********************************/
private static class UnResList
{
/** name of reference */ String interfacef;
/** number of references */ int numRef;
/** next in list */ UnResList next;
};
/***********************************************************************/
private static class DBUnits
{
/** list of interfaces */ DBInterface interfaces;
/** list of bodies */ DBBody bodies;
};
private static class DBPackage
{
/** name of package */ String name;
/** root of symbol tree */ SymbolList root;
};
private static class DBInterface
{
/** name of interface */ String name;
/** list of ports */ DBPortList ports;
/** interface declarations */ Object interfacef;
/** for later code gen */ int flags;
/** associated bodies */ DBBody bodies;
/** local symbols */ SymbolList symbols;
/** next interface */ DBInterface next;
};
private static final int DBMODE_IN = 1;
private static final int DBMODE_OUT = 2;
// private static final int DBMODE_DOTOUT = 3;
// private static final int DBMODE_INOUT = 4;
// private static final int DBMODE_LINKAGE = 5;
private static class DBPortList
{
/** name of port */ String name;
/** mode of port */ int mode;
/** type of port */ DBLType type;
/** general flags */ int flags;
/** next in port list */ DBPortList next;
};
private static final int DBTYPE_SINGLE = 1;
private static final int DBTYPE_ARRAY = 2;
private static class DBLType
{
/** name of type */ String name;
/** type of type */ int type;
/** pointer to info */ Object pointer;
/** possible subtype */ DBLType subType;
};
/********** Bodies *****************************************************/
private static class DBBody
{
/** name of body: identifier */ String name;
/** parent entity of body */ String entity;
/** declarations */ DBBodyDelcare declare;
/** statements in body */ DBStatements statements;
/** pointer to parent */ DBInterface parent;
/** bodies of same parent */ DBBody sameParent;
/** next body */ DBBody next;
};
private static class DBBodyDelcare
{
/** components */ DBComponents components;
/** signals */ DBSignals bodySignals;
};
private static class DBComponents
{
/** name of component */ String name;
/** list of ports */ DBPortList ports;
/** next component */ DBComponents next;
};
private static class DBSignals
{
/** name of signal */ String name;
/** type of signal */ DBLType type;
/** next signal */ DBSignals next;
};
/********** Architectural Statements ***********************************/
private static class DBStatements
{
DBInstance instances;
};
private static class DBInstance
{
/** identifier */ String name;
/** component */ DBComponents compo;
/** ports on instance */ DBAPortList ports;
/** next instance in list */ DBInstance next;
};
private static class DBAPortList
{
/** name of port */ DBName name;
/** pointer to port on comp */ DBPortList port;
/** flags for processing */ int flags;
/** next in list */ DBAPortList next;
};
/********** Names ******************************************************/
private static final int DBNAME_IDENTIFIER = 1;
private static final int DBNAME_INDEXED = 2;
private static final int DBNAME_CONCATENATED = 3;
private static class DBName
{
/** name of name */ String name;
/** type of name */ int type;
/** null if identifier
* DBExprList if indexed
* DBNameList if concatenated */Object pointer;
/** pointer to type */ DBLType dbType;
};
private static class DBExprList
{
/** value */ int value;
/** next in list */ DBExprList next;
};
private static class DBDiscreteRange
{
/** start of range */ int start;
/** end of range */ int end;
};
private static class DBIndexRange
{
/** discrete range */ DBDiscreteRange dRange;
/** next in list */ DBIndexRange next;
};
private static class DBNameList
{
/** name in list */ DBName name;
/** next in list */ DBNameList next;
};
/******** Parser Constants and Structures ******************************/
private static final int NOUNIT = 0;
private static final int UNIT_INTERFACE = 1;
private static final int UNIT_FUNCTION = 2;
private static final int UNIT_PACKAGE = 3;
private static final int UNIT_BODY = 4;
private static final int UNIT_USE = 6;
private static class PTree
{
/** type of entity */ int type;
/** pointer to design unit */ Object pointer;
/** pointer to next */ PTree next;
};
/********** Packages ***************************************************/
private static class Package
{
/** package name */ TokenList name;
/** package declare part */ PackagedPart declare;
/** package declare items */ List packagedParts;
};
private static class PackagedPart
{
/** package declare item */ BasicDeclare item;
/** pointer to next */ PackagedPart next;
};
private static class Use
{
/** unit */ TokenList unit;
/** next in list */ Use next;
};
/********** Interfaces *************************************************/
private static class VInterface
{
/** name of entity */ TokenList name;
/** list of ports */ FPortList ports;
/** interface declarations */ Object interfacef;
};
private static final int MODE_IN = 1;
private static final int MODE_OUT = 2;
private static final int MODE_DOTOUT = 3;
private static final int MODE_INOUT = 4;
private static final int MODE_LINKAGE = 5;
private static class FPortList
{
/** names of port */ IdentList names;
/** mode of port */ int mode;
/** type of port */ VName type;
/** next in port list */ FPortList next;
};
private static class IdentList
{
/** identifier */ TokenList identifier;
/** next in list */ IdentList next;
};
/********** Bodies *****************************************************/
// private static final int BODY_BEHAVIORAL = 1;
// private static final int BODY_ARCHITECTURAL = 2;
private static class Body
{
/** name of body: identifier */ TokenList name;
/** parent entity of body */ SimpleName entity;
/** body declarations */ BodyDeclare bodyDeclare;
/** statements in body */ Statements statements;
};
private static final int BODYDECLARE_BASIC = 1;
private static final int BODYDECLARE_COMPONENT = 2;
private static final int BODYDECLARE_RESOLUTION = 3;
private static final int BODYDECLARE_LOCAL = 4;
private static class BodyDeclare
{
/** type of declaration */ int type;
/** pointer to part tree */ Object pointer;
/** next in list */ BodyDeclare next;
};
/********** Basic Declarations *****************************************/
private static final int NOBASICDECLARE = 0;
private static final int BASICDECLARE_OBJECT = 1;
private static final int BASICDECLARE_TYPE = 2;
private static final int BASICDECLARE_SUBTYPE = 3;
private static final int BASICDECLARE_CONVERSION = 4;
private static final int BASICDECLARE_ATTRIBUTE = 5;
private static final int BASICDECLARE_ATT_SPEC = 6;
private static class BasicDeclare
{
/** type of basic declare */ int type;
/** pointer to parse tree */ Object pointer;
};
private static final int NOOBJECTDECLARE = 0;
private static final int OBJECTDECLARE_CONSTANT = 1;
private static final int OBJECTDECLARE_SIGNAL = 2;
private static final int OBJECTDECLARE_VARIABLE = 3;
private static final int OBJECTDECLARE_ALIAS = 4;
private static class ObjectDeclare
{
/** type of object declare */ int type;
/** pointer to parse tree */ Object pointer;
};
private static class SignalDeclare
{
/** list of identifiers */ IdentList names;
/** subtype indicator */ SubTypeInd subType;
};
private static class VComponent
{
/** name of component */ TokenList name;
/** ports of component */ FPortList ports;
};
private static class ConstantDeclare
{
/** name of constant */ TokenList identifier;
/** subtype indicator */ SubTypeInd subType;
/** expression */ Expression expression;
};
/********** Types ******************************************************/
private static class SubTypeInd
{
/** type of subtype */ VName type;
};
private static final int TYPE_SCALAR = 1;
private static final int TYPE_COMPOSITE = 2;
private static class Type
{
/** name of type */ TokenList identifier;
/** type definition */ int type;
/** pointer to type */ Object pointer;
};
private static final int COMPOSITE_ARRAY = 1;
private static final int COMPOSITE_RECORD = 2;
private static class Composite
{
/** type of composite */ int type;
/** pointer to composite */ Object pointer;
};
private static final int ARRAY_UNCONSTRAINED = 1;
private static final int ARRAY_CONSTRAINED = 2;
private static class Array
{
/** (un)constrained array */ int type;
/** pointer to array */ Object pointer;
};
private static class Constrained
{
/** index constraint */ IndexConstraint constraint;
/** subtype indication */ SubTypeInd subType;
};
private static class IndexConstraint
{
/** discrete range */ DiscreteRange discrete;
/** possible more */ IndexConstraint next;
};
/********** Architectural Statements ***********************************/
private static final int NOARCHSTATE = 0;
private static final int ARCHSTATE_GENERATE = 1;
private static final int ARCHSTATE_SIG_ASSIGN = 2;
private static final int ARCHSTATE_IF = 3;
private static final int ARCHSTATE_CASE = 4;
private static final int ARCHSTATE_INSTANCE = 5;
private static final int ARCHSTATE_NULL = 6;
private static class Statements
{
/** type of statement */ int type;
/** pointer to parse tree */ Object pointer;
/** pointer to next */ Statements next;
};
private static class VInstance
{
/** optional identifier */ TokenList name;
/** entity of instance */ SimpleName entity;
/** ports on instance */ APortList ports;
};
private static final int APORTLIST_NAME = 1;
// private static final int APORTLIST_TYPE_NAME = 2;
// private static final int APORTLIST_EXPRESSION = 3;
private static class APortList
{
/** type of actual port */ int type;
/** pointer to parse tree */ Object pointer;
/** next in list */ APortList next;
};
private static class Generate
{
/** optional label */ TokenList label;
/** generate scheme */ GenScheme genScheme;
/** statements */ Statements statements;
};
private static final int GENSCHEME_FOR = 0;
private static final int GENSCHEME_IF = 1;
private static class GenScheme
{
/** scheme (for or if) */ int scheme;
/** if FOR scheme */ TokenList identifier;
/** if FOR scheme */ DiscreteRange range;
/** if IF scheme */ Expression condition;
};
/********** Names ******************************************************/
private static final int NONAME = 0;
private static final int NAME_SINGLE = 1;
private static final int NAME_CONCATENATE = 2;
private static final int NAME_ATTRIBUTE = 3;
private static class VName
{
/** type of name */ int type;
/** pointer to parse tree */ Object pointer;
};
private static final int NOSINGLENAME = 0;
private static final int SINGLENAME_SIMPLE = 1;
private static final int SINGLENAME_SELECTED = 2;
private static final int SINGLENAME_INDEXED = 3;
private static final int SINGLENAME_SLICE = 4;
private static class SingleName
{
/** type of simple name */ int type;
/** pointer to parse tree */ Object pointer;
};
private static class SimpleName
{
/** identifier */ TokenList identifier;
};
private static final int PREFIX_NAME = 1;
private static final int PREFIX_FUNCTION_CALL = 2;
private static class Prefix
{
/** type of prefix */ int type;
/** pointer to parse tree */ Object pointer;
};
private static class IndexedName
{
/** prefix */ Prefix prefix;
/** expression list */ ExprList exprList;
};
private static class ExprList
{
/** expression */ Expression expression;
/** next in list */ ExprList next;
};
private static final int DISCRETERANGE_SUBTYPE = 1;
private static final int DISCRETERANGE_RANGE = 2;
private static class DiscreteRange
{
/** type of discrete range */ int type;
/** pointer to parse tree */ Object pointer;
};
private static final int RANGE_ATTRIBUTE = 1;
private static final int RANGE_SIMPLE_EXPR = 2;
private static class Range
{
/** type of range */ int type;
/** pointer to parse tree */ Object pointer;
};
private static class RangeSimple
{
/** start of range */ SimpleExpr start;
/** end of range */ SimpleExpr end;
};
private static class ConcatenatedName
{
/** single name */ SingleName name;
/** next in list */ ConcatenatedName next;
};
/********** Expressions ************************************************/
private static final int NOLOGOP = 0;
private static final int LOGOP_AND = 1;
private static final int LOGOP_OR = 2;
private static final int LOGOP_NAND = 3;
private static final int LOGOP_NOR = 4;
private static final int LOGOP_XOR = 5;
private static class Expression
{
/** first relation */ Relation relation;
/** more relations */ MRelations next;
};
private static final int NORELOP = 0;
private static final int RELOP_EQ = 1;
private static final int RELOP_NE = 2;
private static final int RELOP_LT = 3;
private static final int RELOP_LE = 4;
private static final int RELOP_GT = 5;
private static final int RELOP_GE = 6;
private static class Relation
{
/** simple expression */ SimpleExpr simpleExpr;
/** possible operator */ int relOperator;
/** possible expression */ SimpleExpr simpleExpr2;
};
private static class MRelations
{
/** logical operator */ int logOperator;
/** relation */ Relation relation;
/** more relations */ MRelations next;
};
private static final int NOADDOP = 0;
private static final int ADDOP_ADD = 1;
private static final int ADDOP_SUBTRACT = 2;
private static class SimpleExpr
{
/** sign (1 or -1) */ int sign;
/** first term */ Term term;
/** additional terms */ MTerms next;
};
private static final int NOMULOP = 0;
private static final int MULOP_MULTIPLY = 1;
private static final int MULOP_DIVIDE = 2;
private static final int MULOP_MOD = 3;
private static final int MULOP_REM = 4;
private static class Term
{
/** first factor */ Factor factor;
/** additional factors */ MFactors next;
};
private static class MTerms
{
/** add operator */ int addOperator;
/** next term */ Term term;
/** any more terms */ MTerms next;
};
private static final int NOMISCOP = 0;
private static final int MISCOP_POWER = 1;
private static final int MISCOP_ABS = 2;
private static final int MISCOP_NOT = 3;
private static class Factor
{
/** first primary */ Primary primary;
/** possible operator */ int miscOperator;
/** possible primary */ Primary primary2;
};
private static class MFactors
{
/** operator */ int mulOperator;
/** next factor */ Factor factor;
/** possible more factors */ MFactors next;
};
private static final int NOPRIMARY = 0;
private static final int PRIMARY_NAME = 1;
private static final int PRIMARY_LITERAL = 2;
private static final int PRIMARY_AGGREGATE = 3;
private static final int PRIMARY_CONCATENATION = 4;
private static final int PRIMARY_FUNCTION_CALL = 5;
private static final int PRIMARY_TYPE_CONVERSION = 6;
private static final int PRIMARY_QUALIFIED_EXPR = 7;
private static final int PRIMARY_EXPRESSION = 8;
private static class Primary
{
/** type of primary */ int type;
/** pointer to primary */ Object pointer;
};
private static final int NOLITERAL = 0;
private static final int LITERAL_NUMERIC = 1;
private static final int LITERAL_ENUMERATION = 2;
private static final int LITERAL_STRING = 3;
private static final int LITERAL_BIT_STRING = 4;
private static class Literal
{
/** type of literal */ int type;
/** pointer to parse tree */ Object pointer;
};
/* special codes during VHDL generation */
// /** ordinary block */ private static final int BLOCKNORMAL = 0;
// /** a MOS transistor */ private static final int BLOCKMOSTRAN = 1;
// /** a buffer */ private static final int BLOCKBUFFER = 2;
// /** an and, or, xor */ private static final int BLOCKPOSLOGIC = 3;
// /** an inverter */ private static final int BLOCKINVERTER = 4;
// /** a nand */ private static final int BLOCKNAND = 5;
// /** a nor */ private static final int BLOCKNOR = 6;
// /** an xnor */ private static final int BLOCKXNOR = 7;
// /** a settable D flip-flop */ private static final int BLOCKFLOPDS = 8;
// /** a resettable D flip-flop */ private static final int BLOCKFLOPDR = 9;
// /** a settable T flip-flop */ private static final int BLOCKFLOPTS = 10;
// /** a resettable T flip-flop */ private static final int BLOCKFLOPTR = 11;
// /** a general flip-flop */ private static final int BLOCKFLOP = 12;
private static String delimiterStr = "&'()*+,-./:;<=>|";
private static String doubleDelimiterStr = "=>..**:=/=>=<=<>";
private static VKeyword [] theKeywords =
{
new VKeyword("abs", KEY_ABS),
new VKeyword("after", KEY_AFTER),
new VKeyword("alias", KEY_ALIAS),
new VKeyword("all", KEY_ALL),
new VKeyword("and", KEY_AND),
new VKeyword("architecture", KEY_ARCHITECTURE),
new VKeyword("array", KEY_ARRAY),
new VKeyword("assertion", KEY_ASSERTION),
new VKeyword("attribute", KEY_ATTRIBUTE),
new VKeyword("begin", KEY_BEGIN),
new VKeyword("behavioral", KEY_BEHAVIORAL),
new VKeyword("body", KEY_BODY),
new VKeyword("case", KEY_CASE),
new VKeyword("component", KEY_COMPONENT),
new VKeyword("connect", KEY_CONNECT),
new VKeyword("constant", KEY_CONSTANT),
new VKeyword("convert", KEY_CONVERT),
new VKeyword("dot", KEY_DOT),
new VKeyword("downto", KEY_DOWNTO),
new VKeyword("else", KEY_ELSE),
new VKeyword("elsif", KEY_ELSIF),
new VKeyword("end", KEY_END),
new VKeyword("entity", KEY_ENTITY),
new VKeyword("exit", KEY_EXIT),
new VKeyword("for", KEY_FOR),
new VKeyword("function", KEY_FUNCTION),
new VKeyword("generate", KEY_GENERATE),
new VKeyword("generic", KEY_GENERIC),
new VKeyword("if", KEY_IF),
new VKeyword("in", KEY_IN),
new VKeyword("inout", KEY_INOUT),
new VKeyword("is", KEY_IS),
new VKeyword("library", KEY_LIBRARY),
new VKeyword("linkage", KEY_LINKAGE),
new VKeyword("loop", KEY_LOOP),
new VKeyword("map", KEY_MAP),
new VKeyword("mod", KEY_MOD),
new VKeyword("nand", KEY_NAND),
new VKeyword("next", KEY_NEXT),
new VKeyword("nor", KEY_NOR),
new VKeyword("not", KEY_NOT),
new VKeyword("null", KEY_NULL),
new VKeyword("of", KEY_OF),
new VKeyword("open", KEY_OPEN),
new VKeyword("or", KEY_OR),
new VKeyword("others", KEY_OTHERS),
new VKeyword("out", KEY_OUT),
new VKeyword("package", KEY_PACKAGE),
new VKeyword("port", KEY_PORT),
new VKeyword("range", KEY_RANGE),
new VKeyword("record", KEY_RECORD),
new VKeyword("rem", KEY_REM),
new VKeyword("report", KEY_REPORT),
new VKeyword("resolve", KEY_RESOLVE),
new VKeyword("return", KEY_RETURN),
new VKeyword("severity", KEY_SEVERITY),
new VKeyword("signal", KEY_SIGNAL),
new VKeyword("standard", KEY_STANDARD),
new VKeyword("static", KEY_STATIC),
new VKeyword("subtype", KEY_SUBTYPE),
new VKeyword("then", KEY_THEN),
new VKeyword("to", KEY_TO),
new VKeyword("type", KEY_TYPE),
new VKeyword("units", KEY_UNITS),
new VKeyword("use", KEY_USE),
new VKeyword("variable", KEY_VARIABLE),
new VKeyword("when", KEY_WHEN),
new VKeyword("while", KEY_WHILE),
new VKeyword("with", KEY_WITH),
new VKeyword("xor", KEY_XOR)
};
private Cell vhdlCell;
private HashSet<String> identTable;
private TokenList tListStart;
private TokenList tListEnd;
private int errorCount;
private boolean hasErrors;
private UnResList unResolvedList;
/**
* The constructor compiles the VHDL and produces a netlist.
*/
public CompileVHDL(Cell vhdlCell)
{
this.vhdlCell = vhdlCell;
hasErrors = true;
String [] strings = vhdlCell.getTextViewContents();
if (strings == null)
{
System.out.println("Cell " + vhdlCell.describe(true) + " has no text in it");
return;
}
// initialize
unResolvedList = null;
// build and clear identTable
identTable = new HashSet<String>();
errorCount = 0;
doScanner(strings);
if (doParser(tListStart)) return;
if (doSemantic()) return;
hasErrors = false;
}
/**
* Method to report whether the VHDL compile was successful.
* @return true if there were errors.
*/
public boolean hasErrors() { return hasErrors; };
/**
* Method to generate a QUISC (silicon compiler) netlist.
* @param destLib destination library.
* @return a List of strings with the netlist.
*/
public List<String> getQUISCNetlist(Library destLib)
{
// now produce the netlist
if (hasErrors) return null;
List<String> netlistStrings = genQuisc(destLib);
return netlistStrings;
}
/**
* Method to generate an ALS (simulation) netlist.
* @param destLib destination library.
* @return a List of strings with the netlist.
*/
public List<String> getALSNetlist(Library destLib)
{
// now produce the netlist
if (hasErrors) return null;
Library behaveLib = null;
List<String> netlistStrings = genALS(destLib, behaveLib);
return netlistStrings;
}
/******************************** THE VHDL SCANNER ********************************/
/**
* Method to do lexical scanning of input VHDL and create token list.
*/
private void doScanner(String [] strings)
{
String buf = "";
int bufPos = 0;
int lineNum = 0;
boolean space = false;
for(;;)
{
if (bufPos >= buf.length())
{
if (lineNum >= strings.length) return;
buf = strings[lineNum++];
bufPos = 0;
space = true;
} else
{
if (Character.isWhitespace(buf.charAt(bufPos))) space = true; else
space = false;
}
while (bufPos < buf.length() && Character.isWhitespace(buf.charAt(bufPos))) bufPos++;
if (bufPos >= buf.length()) continue;
char c = buf.charAt(bufPos);
if (Character.isLetter(c))
{
// could be identifier (keyword) or bit string literal
int end = bufPos;
for(; end < buf.length(); end++)
{
char eChar = buf.charAt(end);
if (!Character.isLetterOrDigit(eChar) && eChar != '_') break;
}
// got alphanumeric from c to end - 1
VKeyword key = isKeyword(buf.substring(bufPos, end));
if (key != null)
{
new TokenList(TOKEN_KEYWORD, key, lineNum, space);
} else
{
String ident = buf.substring(bufPos, end);
identTable.add(ident);
new TokenList(TOKEN_IDENTIFIER, ident, lineNum, space);
}
bufPos = end;
} else if (TextUtils.isDigit(c))
{
// could be decimal or based literal
int end = bufPos+1;
for(; end < buf.length(); end++)
{
char eChar = buf.charAt(end);
if (!TextUtils.isDigit(eChar) && eChar != '_') break;
}
// got numeric from c to end - 1
new TokenList(TOKEN_DECIMAL, buf.substring(bufPos, end), lineNum, space);
bufPos = end;
} else
{
switch (c)
{
case '"':
// got a start of a string
int end = bufPos + 1;
while (end < buf.length() && buf.charAt(end) != '\n')
{
if (buf.charAt(end) == '"')
{
if (end+1 < buf.length() && buf.charAt(end+1) == '"') end++; else
break;
}
end++;
}
// string from c + 1 to end - 1
String newString = buf.substring(bufPos + 1, end);
newString.replaceAll("\"\"", "\"");
new TokenList(TOKEN_STRING, newString, lineNum, space);
if (buf.charAt(end) == '"') end++;
bufPos = end;
break;
case '&':
new TokenList(TOKEN_AMPERSAND, null, lineNum, space);
bufPos++;
break;
case '\'':
// character literal
if (bufPos+2 < buf.length() && buf.charAt(bufPos+2) == '\'')
{
new TokenList(TOKEN_CHAR, new Character(buf.charAt(bufPos+1)), lineNum, space);
bufPos += 3;
} else
bufPos++;
break;
case '(':
new TokenList(TOKEN_LEFTBRACKET, null, lineNum, space);
bufPos++;
break;
case ')':
new TokenList(TOKEN_RIGHTBRACKET, null, lineNum, space);
bufPos++;
break;
case '*':
// could be STAR or DOUBLESTAR
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '*')
{
new TokenList(TOKEN_DOUBLESTAR, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_STAR, null, lineNum, space);
bufPos++;
}
break;
case '+':
new TokenList(TOKEN_PLUS, null, lineNum, space);
bufPos++;
break;
case ',':
new TokenList(TOKEN_COMMA, null, lineNum, space);
bufPos++;
break;
case '-':
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '-')
{
// got a comment, throw away rest of line
bufPos = buf.length();
} else
{
// got a minus sign
new TokenList(TOKEN_MINUS, null, lineNum, space);
bufPos++;
}
break;
case '.':
// could be PERIOD or DOUBLEDOT
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '.')
{
new TokenList(TOKEN_DOUBLEDOT, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_PERIOD, null, lineNum, space);
bufPos++;
}
break;
case '/':
// could be SLASH or NE
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '=')
{
new TokenList(TOKEN_NE, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_SLASH, null, lineNum, space);
bufPos++;
}
break;
case ':':
// could be COLON or VARASSIGN
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '=')
{
new TokenList(TOKEN_VARASSIGN, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_COLON, null, lineNum, space);
bufPos++;
}
break;
case ';':
new TokenList(TOKEN_SEMICOLON, null, lineNum, space);
bufPos++;
break;
case '<':
// could be LT or LE or BOX
if (bufPos+1 < buf.length())
{
if (buf.charAt(bufPos+1) == '=')
{
new TokenList(TOKEN_LE, null, lineNum, space);
bufPos += 2;
break;
}
if (buf.charAt(bufPos+1) == '>')
{
new TokenList(TOKEN_BOX, null, lineNum, space);
bufPos += 2;
break;
}
}
new TokenList(TOKEN_LT, null, lineNum, space);
bufPos++;
break;
case '=':
// could be EQUAL or double delimiter ARROW
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '>')
{
new TokenList(TOKEN_ARROW, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_EQ, null, lineNum, space);
bufPos++;
}
break;
case '>':
// could be GT or GE
if (bufPos+1 < buf.length() && buf.charAt(bufPos+1) == '=')
{
new TokenList(TOKEN_GE, null, lineNum, space);
bufPos += 2;
} else
{
new TokenList(TOKEN_GT, null, lineNum, space);
bufPos++;
}
break;
case '|':
new TokenList(TOKEN_VERTICALBAR, null, lineNum, space);
bufPos++;
break;
default:
new TokenList(TOKEN_UNKNOWN, null, lineNum, space);
bufPos++;
break;
}
}
}
}
/**
* Method to get address in the keyword table.
* @param tString string to lookup.
* @return entry in keywords table if keyword, else null.
*/
public static VKeyword isKeyword(String tString)
{
int base = 0;
int num = theKeywords.length;
int aIndex = num >> 1;
while (num != 0)
{
int check = tString.compareTo(theKeywords[base + aIndex].name);
if (check == 0) return theKeywords[base + aIndex];
if (check < 0)
{
num = aIndex;
aIndex = num >> 1;
} else
{
base += aIndex + 1;
num -= aIndex + 1;
aIndex = num >> 1;
}
}
return null;
}
/******************************** THE VHDL PARSER ********************************/
private boolean hasError;
private TokenList nextToken;
private PTree pTree;
private class ParseException extends Exception {}
/**
* Method to parse the passed token list using the parse tables.
* Reports on any syntax errors and create the required syntax trees.
* @param tlist list of tokens.
*/
private boolean doParser(TokenList tList)
{
hasError = false;
pTree = null;
PTree endunit = null;
nextToken = tList;
try
{
while (nextToken != null)
{
if (nextToken.token == TOKEN_KEYWORD)
{
int type = NOUNIT;
VKeyword vk = (VKeyword)nextToken.pointer;
Object pointer = null;
switch (vk.num)
{
case KEY_LIBRARY:
parseToSemicolon();
break;
case KEY_ENTITY:
type = UNIT_INTERFACE;
pointer = parseInterface();
break;
case KEY_ARCHITECTURE:
type = UNIT_BODY;
pointer = parseBody();
break;
case KEY_PACKAGE:
type = UNIT_PACKAGE;
pointer = parsePackage();
break;
case KEY_USE:
type = UNIT_USE;
pointer = parseUse();
break;
default:
reportErrorMsg(nextToken, "No entry keyword - entity, architectural, behavioral");
nextToken = nextToken.next;
break;
}
if (type != NOUNIT)
{
PTree newUnit = new PTree();
newUnit.type = type;
newUnit.pointer = pointer;
newUnit.next = null;
if (endunit == null)
{
pTree = endunit = newUnit;
} else
{
endunit.next = newUnit;
endunit = newUnit;
}
}
} else
{
reportErrorMsg(nextToken, "No entry keyword - entity, architectural, behavioral");
nextToken = nextToken.next;
}
}
} catch (ParseException e)
{
}
return hasError;
}
/**
* Method to parse an interface description of the form:
* ENTITY identifier IS PORT (formal_port_list);
* END [identifier] ;
*/
private VInterface parseInterface()
throws ParseException
{
getNextToken();
// check for entity IDENTIFIER
TokenList name = null;
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
} else
{
name = nextToken;
}
// check for keyword IS
getNextToken();
if (!isKeySame(nextToken, KEY_IS))
{
reportErrorMsg(nextToken, "Expecting keyword IS");
}
// check for keyword PORT
getNextToken();
if (!isKeySame(nextToken, KEY_PORT))
{
reportErrorMsg(nextToken, "Expecting keyword PORT");
}
// check for opening bracket of FORMAL_PORT_LIST
getNextToken();
if (nextToken.token != TOKEN_LEFTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a left bracket");
}
// gather FORMAL_PORT_LIST
getNextToken();
FPortList ports = parseFormalPortList();
if (ports == null)
{
reportErrorMsg(nextToken, "Interface must have ports");
}
// check for closing bracket of FORMAL_PORT_LIST
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
}
getNextToken();
// check for SEMICOLON
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
else getNextToken();
// check for keyword END
if (!isKeySame(nextToken, KEY_END))
{
reportErrorMsg(nextToken, "Expecting keyword END");
}
// check for optional entity IDENTIFIER
getNextToken();
if (nextToken.token == TOKEN_IDENTIFIER)
{
if (!nextToken.pointer.equals(name.pointer))
{
reportErrorMsg(nextToken, "Unmatched entity identifier names");
}
getNextToken();
}
// check for closing SEMICOLON
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
nextToken = nextToken.next;
// allocate an entity parse tree
VInterface interfacef = new VInterface();
interfacef.name = name;
interfacef.ports = ports;
interfacef.interfacef = null;
return interfacef;
}
/**
* Method to parse a body. The syntax is of the form:
* ARCHITECTURE identifier OF simple_name IS
* body_declaration_part
* BEGIN
* set_of_statements
* END [identifier] ;
* @return the created body structure.
*/
private Body parseBody()
throws ParseException
{
getNextToken();
// next is bodyName (identifier)
TokenList bodyName = null;
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
} else
{
bodyName = nextToken;
}
getNextToken();
// check for keyword OF
if (!isKeySame(nextToken, KEY_OF))
{
reportErrorMsg(nextToken, "Expecting keyword OF");
}
getNextToken();
// next is design entity reference for this body (simple_name)
SimpleName entityName = parseSimpleName();
// check for keyword IS
if (!isKeySame(nextToken, KEY_IS))
{
reportErrorMsg(nextToken, "Expecting keyword IS");
}
getNextToken();
// body declaration part
BodyDeclare bodyDeclare = parseBodyDeclare();
// should be at keyword BEGIN
if (!isKeySame(nextToken, KEY_BEGIN))
{
reportErrorMsg(nextToken, "Expecting keyword BEGIN");
}
getNextToken();
// statements of body
Statements statements = parseSetOfStatements();
// should be at keyword END
if (!isKeySame(nextToken, KEY_END))
{
reportErrorMsg(nextToken, "Expecting keyword END");
}
getNextToken();
// optional body name
if (nextToken.token == TOKEN_IDENTIFIER)
{
if (!nextToken.pointer.equals(bodyName.pointer))
{
reportErrorMsg(nextToken, "Body name mismatch");
}
getNextToken();
}
// should be at final semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
nextToken = nextToken.next;
// create body parse tree
Body body = new Body();
body.name = bodyName;
body.entity = entityName;
body.bodyDeclare = bodyDeclare;
body.statements = statements;
return body;
}
/**
* Method to parse a package declaration.
* It has the form:
* package_declaration ::= PACKAGE identifier IS
* package_declarative_part
* END [simple_name] ;
* @return the package declaration.
*/
private Package parsePackage()
throws ParseException
{
Package vPackage = null;
// should be at keyword package
if (!isKeySame(nextToken, KEY_PACKAGE))
{
reportErrorMsg(nextToken, "Expecting keyword PACKAGE");
getNextToken();
return vPackage;
}
getNextToken();
// should be package identifier
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return vPackage;
}
TokenList identifier = nextToken;
getNextToken();
// should be at keyword IS
if (!isKeySame(nextToken, KEY_IS))
{
reportErrorMsg(nextToken, "Expecting keyword IS");
getNextToken();
return vPackage;
}
getNextToken();
// package declarative part
PackagedPart declarePart = parsePackageDeclarePart();
// should be at keyword END
if (!isKeySame(nextToken, KEY_END))
{
reportErrorMsg(nextToken, "Expecting keyword END");
getNextToken();
return vPackage;
}
getNextToken();
// check for optional end identifier
if (nextToken.token == TOKEN_IDENTIFIER)
{
if (!nextToken.pointer.equals(identifier.pointer))
{
reportErrorMsg(nextToken, "Name mismatch");
getNextToken();
return vPackage;
}
getNextToken();
}
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
getNextToken();
return vPackage;
}
getNextToken();
// create package structure
vPackage = new Package();
vPackage.name = identifier;
vPackage.declare = declarePart;
return vPackage;
}
/**
* Method to parse a use clause.
* It has the form:
* use_clause ::= USE unit {,unit} ;
* unit ::= package_name.ALL
* @return the use clause structure.
*/
private Use parseUse()
throws ParseException
{
Use use = null;
// should be at keyword USE
if (!isKeySame(nextToken, KEY_USE))
{
reportErrorMsg(nextToken, "Expecting keyword USE");
getNextToken();
return use;
}
getNextToken();
// must be at least one unit
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Bad unit name for use clause");
getNextToken();
return use;
}
use = new Use();
use.unit = nextToken;
use.next = null;
Use endUse = use;
getNextToken();
// IEEE version uses form unit.ALL only
for(;;)
{
if (nextToken.token != TOKEN_PERIOD)
{
reportErrorMsg(nextToken, "Expecting period");
break;
}
getNextToken();
if (isKeySame(nextToken, KEY_ALL))
{
getNextToken();
break;
}
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Bad unit name for use clause");
break;
}
getNextToken();
}
while (nextToken.token == TOKEN_COMMA)
{
getNextToken();
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Bad unit name for use clause");
getNextToken();
return use;
}
Use newUse = new Use();
newUse.unit = nextToken;
newUse.next = null;
endUse.next = newUse;
endUse = newUse;
getNextToken();
// IEEE version uses form unit.ALL only
if (nextToken.token == TOKEN_PERIOD)
getNextToken();
else reportErrorMsg(nextToken, "Expecting period");
if (isKeySame(nextToken, KEY_ALL))
getNextToken();
else reportErrorMsg(nextToken, "Expecting keyword ALL");
}
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
return use;
}
/**
* Method to parse a package declarative part.
* It has the form:
* package_declarative_part ::= package_declarative_item {package_declarative_item}
* package_declarative_item ::= basic_declaration | function_declaration
* Note: Currently only support basic declarations.
* @return the package declarative part.
*/
private PackagedPart parsePackageDeclarePart()
throws ParseException
{
PackagedPart dPart = null;
// should be at least one
if (isKeySame(nextToken, KEY_END))
{
reportErrorMsg(nextToken, "No Package declarative part");
return dPart;
}
BasicDeclare dItem = parseBasicDeclare();
dPart = new PackagedPart();
dPart.item = dItem;
dPart.next = null;
PackagedPart endPart = dPart;
while (!isKeySame(nextToken, KEY_END))
{
dItem = parseBasicDeclare();
PackagedPart newpart = new PackagedPart();
newpart.item = dItem;
newpart.next = null;
endPart.next = newpart;
endPart = newpart;
}
return dPart;
}
/**
* Method to parse the body statements and return pointer to the parse tree.
* The form of body statements are:
* set_of_statements :== architectural_statement {architectural_statement}
* architectural_statement :== generate_statement | signal_assignment_statement | architectural_if_statement | architectural_case_statement | component_instantiation_statement | null_statement
* @return the statements parse tree.
*/
private Statements parseSetOfStatements()
throws ParseException
{
Statements statements = null;
Statements endState = null;
while (!isKeySame(nextToken, KEY_END))
{
int type = NOARCHSTATE;
Object pointer = null;
// check for case statement
if (isKeySame(nextToken, KEY_CASE))
{
// EMPTY
}
// check for null statement
else if (isKeySame(nextToken, KEY_NULL))
{
type = ARCHSTATE_NULL;
pointer = null;
getNextToken();
// should be a semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
}
// check for label
else if (nextToken.token == TOKEN_IDENTIFIER && nextToken.next != null &&
nextToken.next.token == TOKEN_COLON)
{
TokenList label = nextToken;
getNextToken();
getNextToken();
// check for generate statement
if (isKeySame(nextToken, KEY_IF))
{
type = ARCHSTATE_GENERATE;
pointer = parseGenerate(label, GENSCHEME_IF);
}
else if (isKeySame(nextToken, KEY_FOR))
{
type = ARCHSTATE_GENERATE;
pointer = parseGenerate(label, GENSCHEME_FOR);
}
// should be component_instantiation_declaration
else
{
nextToken = label;
type = ARCHSTATE_INSTANCE;
pointer = parseInstance();
}
}
// add statement if found
if (type != NOARCHSTATE)
{
Statements newState = new Statements();
newState.type = type;
newState.pointer = pointer;
newState.next = null;
if (endState == null)
{
statements = endState = newState;
} else
{
endState.next = newState;
endState = newState;
}
} else
{
reportErrorMsg(nextToken, "Invalid ARCHITECTURAL statement");
nextToken = nextToken.next;
break;
}
}
return statements;
}
/**
* Method to parse a component instantiation statement.
* It has the form:
* component_instantiation_statement :== label : simple_name PORT MAP(actual_port_list);
* @return the instance parse tree.
*/
private VInstance parseInstance()
throws ParseException
{
VInstance inst = null;
// check for identifier
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return inst;
}
TokenList name = nextToken;
getNextToken();
// if colon, previous token was the label
if (nextToken.token == TOKEN_COLON)
{
getNextToken();
} else
{
nextToken = name;
name = null;
}
// should be at component reference
SimpleName entity = parseSimpleName();
// Require PORT MAP
if (isKeySame(nextToken, KEY_PORT))
getNextToken();
else reportErrorMsg(nextToken, "Expecting keyword PORT");
if (isKeySame(nextToken, KEY_MAP))
getNextToken();
else reportErrorMsg(nextToken, "Expecting keyword MAP");
// should be at left bracket
if (nextToken.token != TOKEN_LEFTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a left bracket");
}
getNextToken();
APortList ports = parseActualPortList();
// should be at right bracket
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
}
getNextToken();
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
inst = new VInstance();
inst.name = name;
inst.entity = entity;
inst.ports = ports;
return inst;
}
/**
* Method to parse an actual port list.
* It has the form:
* actual_port_list ::= port_association {, port_association}
* port_association ::= name | OPEN
* @return the actual port list structure.
*/
private APortList parseActualPortList()
throws ParseException
{
APortList lastPort = null;
// should be at least one port association
APortList apList = new APortList();
apList.type = APORTLIST_NAME;
if (nextToken.token != TOKEN_COMMA && nextToken.token != TOKEN_RIGHTBRACKET)
{
if (isKeySame(nextToken, KEY_OPEN))
{
apList.pointer = null;
getNextToken();
} else
{
apList.pointer = parseName();
if (nextToken.token == TOKEN_ARROW)
{
getNextToken();
apList.pointer = parseName();
}
}
}
else reportErrorMsg(nextToken, "No identifier in port list");
apList.next = null;
lastPort = apList;
while (nextToken.token == TOKEN_COMMA)
{
getNextToken();
APortList newPort = new APortList();
newPort.type = APORTLIST_NAME;
if (nextToken.token != TOKEN_COMMA && nextToken.token != TOKEN_RIGHTBRACKET)
{
if (isKeySame(nextToken, KEY_OPEN))
{
newPort.pointer = null;
getNextToken();
} else
{
newPort.pointer = parseName();
if (nextToken.token == TOKEN_ARROW)
{
getNextToken();
newPort.pointer = parseName();
}
}
}
else reportErrorMsg(nextToken, "No identifier in port list");
newPort.next = null;
lastPort.next = newPort;
lastPort = newPort;
}
return apList;
}
/**
* Method to parse a generate statement.
* It has the form:
* generate_statement ::= label: generate_scheme GENERATE set_of_statements END GENERATE [label];
* generate_scheme ::= FOR generate_parameter_specification | IF condition
* generate_parameter_specification ::= identifier IN discrete_range
* @param label pointer to optional label.
* @param gScheme generate scheme (FOR or IF).
* @return generate statement structure.
*/
private Generate parseGenerate(TokenList label, int gScheme)
throws ParseException
{
Generate gen = null;
if (gScheme == GENSCHEME_FOR)
{
// should be past label and at keyword FOR
if (!isKeySame(nextToken, KEY_FOR))
{
reportErrorMsg(nextToken, "Expecting keyword FOR");
}
} else
{
// should be past label and at keyword IF
if (!isKeySame(nextToken, KEY_IF))
{
reportErrorMsg(nextToken, "Expecting keyword IF");
}
}
GenScheme scheme = new GenScheme();
if (gScheme == GENSCHEME_FOR)
{
scheme.scheme = GENSCHEME_FOR;
} else
{
scheme.scheme = GENSCHEME_IF;
}
scheme.identifier = null;
scheme.range = null;
scheme.condition = null; // for IF scheme only
getNextToken();
if (gScheme == GENSCHEME_FOR)
{
// should be generate parameter specification
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
} else
{
scheme.identifier = nextToken;
}
getNextToken();
// should be keyword IN
if (!isKeySame(nextToken, KEY_IN))
{
reportErrorMsg(nextToken, "Expecting keyword IN");
}
getNextToken();
// should be discrete range
scheme.range = parseDiscreteRange();
} else
{
scheme.condition = parseExpression();
}
// should be keyword GENERATE
if (!isKeySame(nextToken, KEY_GENERATE))
{
reportErrorMsg(nextToken, "Expecting keyword GENERATE");
}
getNextToken();
// set of statements
Statements states = parseSetOfStatements();
// should be at keyword END
if (!isKeySame(nextToken, KEY_END))
{
reportErrorMsg(nextToken, "Expecting keyword END");
}
getNextToken();
// should be at keyword GENERATE
if (!isKeySame(nextToken, KEY_GENERATE))
{
reportErrorMsg(nextToken, "Expecting keyword GENERATE");
}
getNextToken();
// check if label should be present
if (label != null)
{
/* For correct IEEE syntax, label is always true, but trailing
* label is optional.
*/
if (nextToken.token == TOKEN_IDENTIFIER)
{
if (!label.pointer.equals(nextToken.pointer))
reportErrorMsg(nextToken, "Label mismatch");
getNextToken();
}
}
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
// create generate statement structure
gen = new Generate();
gen.label = label;
gen.genScheme = scheme;
gen.statements = states;
return gen;
}
/**
* Method to parse the body declaration and return pointer to the parse tree.
* The format is:
* body_declaration_part :== {body_declaration_item}
* body_delaration_item :== basic_declaration | component_declaration | resolution_mechanism_declaration | local_function_declaration
* @return the parse tree, null if parsing error encountered.
*/
private BodyDeclare parseBodyDeclare()
throws ParseException
{
BodyDeclare body =null;
BodyDeclare endBody = null;
Object pointer = null;
int type = 0;
while (!isKeySame(nextToken, KEY_BEGIN))
{
// check for component declaration
if (isKeySame(nextToken, KEY_COMPONENT))
{
type = BODYDECLARE_COMPONENT;
pointer = parseComponent();
}
// check for resolution declaration
else if (isKeySame(nextToken, KEY_RESOLVE))
{
type = BODYDECLARE_RESOLUTION;
pointer = null;
getNextToken();
}
// check for local function declaration
else if (isKeySame(nextToken, KEY_FUNCTION))
{
type = BODYDECLARE_LOCAL;
pointer = null;
getNextToken();
}
// should be basic declaration
else
{
type = BODYDECLARE_BASIC;
pointer = parseBasicDeclare();
}
BodyDeclare newBody = new BodyDeclare();
newBody.type = type;
newBody.pointer = pointer;
newBody.next = null;
if (endBody == null)
{
body = endBody = newBody;
} else
{
endBody.next = newBody;
endBody = newBody;
}
}
return body;
}
/**
* Method to parse a basic declaration and return a pointer to the parse tree.
* The form of a basic declaration is:
* basic_declaration :== object_declaration | type_declaration | subtype_declaration | conversion_declaration | attribute_declaration | attribute_specification
* @return pointer to basic_declaration parse tree, null if unrecoverable parsing error.
*/
private BasicDeclare parseBasicDeclare()
throws ParseException
{
BasicDeclare basic = null;
int type = NOBASICDECLARE;
Object pointer = null;
if (isKeySame(nextToken, KEY_TYPE))
{
type = BASICDECLARE_TYPE;
pointer = parseType();
} else
{
type = BASICDECLARE_OBJECT;
pointer = parseObjectDeclare();
}
if (type != NOBASICDECLARE)
{
basic = new BasicDeclare();
basic.type = type;
basic.pointer = pointer;
} else getNextToken(); // Bug fix , D.J.Yurach, June, 1988
return basic;
}
/**
* Method to parse a type declaration.
* It has the form: type_declaration ::= TYPE identifier IS type_definition ;
* @return the type declaration structure.
*/
private Type parseType()
throws ParseException
{
Type type = null;
// should be at keyword TYPE
if (!isKeySame(nextToken, KEY_TYPE))
{
reportErrorMsg(nextToken, "Expecting keyword TYPE");
getNextToken();
return type;
}
getNextToken();
// should be at type identifier
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return type;
}
TokenList ident = nextToken;
getNextToken();
// should be keyword IS
if (!isKeySame(nextToken, KEY_IS))
{
reportErrorMsg(nextToken, "Expecting keyword IS");
getNextToken();
return type;
}
getNextToken();
// parse type definition
Object pointer = null;
int typeDefine = 0;
if (isKeySame(nextToken, KEY_ARRAY))
{
typeDefine = TYPE_COMPOSITE;
pointer = parseCompositeType();
} else if (isKeySame(nextToken, KEY_RECORD))
{
typeDefine = TYPE_COMPOSITE;
pointer = parseCompositeType();
} else if (isKeySame(nextToken, KEY_RANGE))
{
typeDefine = TYPE_SCALAR;
pointer = null;
} else if (nextToken.token == TOKEN_LEFTBRACKET)
{
typeDefine = TYPE_SCALAR;
pointer = null;
} else
{
reportErrorMsg(nextToken, "Invalid type definition");
getNextToken();
return type;
}
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
getNextToken();
return type;
}
getNextToken();
type = new Type();
type.identifier = ident;
type.type = typeDefine;
type.pointer = pointer;
return type;
}
/**
* Method to parse a composite type definition.
* It has the form:
* composite_type_definition ::= array_type_definition | record_type_definition
*/
private Composite parseCompositeType()
throws ParseException
{
Composite compo = null;
// should be ARRAY or RECORD keyword
Object pointer = null;
int type = 0;
if (isKeySame(nextToken, KEY_ARRAY))
{
type = COMPOSITE_ARRAY;
pointer = parseArrayType();
} else if (isKeySame(nextToken, KEY_RECORD))
{
type = COMPOSITE_RECORD;
pointer = null;
} else
{
reportErrorMsg(nextToken, "Invalid composite type");
getNextToken();
return compo;
}
compo = new Composite();
compo.type = type;
compo.pointer = pointer;
return compo;
}
/**
* Method to parse an array type definition.
* It has the form:
* array_type_definition ::= unconstrained_array_definition | constrained_array_definition
* unconstrained_array_definition ::= ARRAY (index_subtype_definition {, index_subtype_definition}) OF subtype_indication
* constrained_array_definition ::= ARRAY index_constraint OF subtype_indication
* index_constraint ::= (discrete_range {, discrete_range})
* NOTE: Only currently supporting constrained array definitions.
* @return the array type definition.
*/
private Array parseArrayType()
throws ParseException
{
Array array = null;
// should be keyword ARRAY
if (!isKeySame(nextToken, KEY_ARRAY))
{
reportErrorMsg(nextToken, "Expecting keyword ARRAY");
getNextToken();
return array;
}
getNextToken();
// index_constraint
// should be left bracket
if (nextToken.token != TOKEN_LEFTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a left bracket");
getNextToken();
return array;
}
getNextToken();
// should at least one discrete range
IndexConstraint iConstraint = new IndexConstraint();
iConstraint.discrete = parseDiscreteRange();
iConstraint.next = null;
IndexConstraint endconstraint = iConstraint;
// continue while comma
while (nextToken.token == TOKEN_COMMA)
{
getNextToken();
IndexConstraint newConstraint = new IndexConstraint();
newConstraint.discrete = parseDiscreteRange();
newConstraint.next = null;
endconstraint.next = newConstraint;
endconstraint = newConstraint;
}
// should be at right bracket
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
getNextToken();
return array;
}
getNextToken();
// should be at keyword OF
if (!isKeySame(nextToken, KEY_OF))
{
reportErrorMsg(nextToken, "Expecting keyword OF");
getNextToken();
return array;
}
getNextToken();
// subtype_indication
SubTypeInd subType = parseSubtypeIndication();
// create array type definition
array = new Array();
array.type = ARRAY_CONSTRAINED;
Constrained constr = new Constrained();
array.pointer = constr;
constr.constraint = iConstraint;
constr.subType = subType;
return array;
}
/**
* Method to parse a discrete range.
* The range has the form: discrete_range ::= subtype_indication | range
* @return the discrete range structure.
*/
private DiscreteRange parseDiscreteRange()
throws ParseException
{
DiscreteRange dRange = new DiscreteRange();
// currently only support range option
dRange.type = DISCRETERANGE_RANGE;
dRange.pointer = parseRange();
return dRange;
}
/**
* Method to parse a range.
* The range has the form:
* range :== simple_expression direction simple_expression
* direction ::= TO | DOWNTO
* @return the range structure.
*/
private Range parseRange()
throws ParseException
{
Range range = new Range();
// currently support only simple expression range option
range.type = RANGE_SIMPLE_EXPR;
range.pointer = parseRangeSimple();
return range;
}
/**
* Method to parse a simple expression range.
* The range has the form: simple_expression .. simple_expression
* @return the simple expression range.
*/
private RangeSimple parseRangeSimple()
throws ParseException
{
RangeSimple sRange = new RangeSimple();
sRange.start = parseSimpleExpression();
// Need keyword TO or DOWNTO
if (isKeySame(nextToken, KEY_TO) || isKeySame(nextToken, KEY_DOWNTO))
getNextToken();
else
{
reportErrorMsg(nextToken, "Expecting keyword TO or DOWNTO");
getNextToken(); // absorb the token anyway (probably "..")
}
sRange.end = parseSimpleExpression();
return sRange;
}
/**
* Method to parse an object declaration and return the pointer to its parse tree.
* An object declaration has the form:
* object_declaration :== constant_declaration | signal_declaration | variable_declaration | alias_declaration
* @return the object declaration parse tree.
*/
private ObjectDeclare parseObjectDeclare()
throws ParseException
{
ObjectDeclare object = null;
int type = NOOBJECTDECLARE;
Object pointer = null;
if (isKeySame(nextToken, KEY_CONSTANT))
{
type = OBJECTDECLARE_CONSTANT;
pointer = parseConstantDeclare();
} else if (isKeySame(nextToken, KEY_SIGNAL))
{
type = OBJECTDECLARE_SIGNAL;
pointer = parseSignalDeclare();
} else if (isKeySame(nextToken, KEY_VARIABLE))
{
// EMPTY
} else if (isKeySame(nextToken, KEY_ALIAS))
{
// EMPTY
} else
{
reportErrorMsg(nextToken, "Invalid object declaration");
}
if (type != NOOBJECTDECLARE)
{
object = new ObjectDeclare();
object.type = type;
object.pointer = pointer;
} else
{
getNextToken();
}
return object;
}
/**
* Method to parse a constant declaration and return the pointer to the parse tree.
* The form of a constant declaration is:
* constant_declaration :== CONSTANT identifier : subtype_indication := expression ;
* @return the constant declaration parse tree.
*/
private ConstantDeclare parseConstantDeclare()
throws ParseException
{
ConstantDeclare constant = null;
getNextToken();
// parse identifier
// Note that the standard allows identifier_list here, but we don't support it!
TokenList ident = null;
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
} else
{
ident = nextToken;
}
getNextToken();
// should be at colon
if (nextToken.token != TOKEN_COLON)
{
reportErrorMsg(nextToken, "Expecting a colon");
}
getNextToken();
// parse subtype indication
SubTypeInd ind = parseSubtypeIndication();
// should be at assignment symbol
if (nextToken.token != TOKEN_VARASSIGN)
{
reportErrorMsg(nextToken, "Expecting variable assignment symbol");
}
getNextToken();
// should be at expression
Expression expr = parseExpression();
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
constant = new ConstantDeclare();
constant.identifier = ident;
constant.subType = ind;
constant.expression = expr;
return constant;
}
/**
* Method to parse a signal declaration and return the pointer to the parse tree.
* The form of a signal declaration is:
* signal_declaration :== SIGNAL identifier_list : subtype_indication;
* @return the signal declaration parse tree.
*/
private SignalDeclare parseSignalDeclare()
throws ParseException
{
getNextToken();
// parse identifier list
IdentList signalList = parseIdentList();
// should be at colon
if (nextToken.token != TOKEN_COLON)
{
reportErrorMsg(nextToken, "Expecting a colon");
}
getNextToken();
// parse subtype indication
SubTypeInd ind = parseSubtypeIndication();
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
SignalDeclare signal = new SignalDeclare();
signal.names = signalList;
signal.subType = ind;
return signal;
}
/**
* Method to parse a subtype indicatio.
* It has the form: subtype_indication :== type_mark [constraint]
* @return subtype indication parse tree.
*/
private SubTypeInd parseSubtypeIndication()
throws ParseException
{
VName type = parseName();
SubTypeInd ind = new SubTypeInd();
ind.type = type;
return ind;
}
/**
* Method to parse a component declaration and return a pointer to the parse tree.
* The format of a component declaration is:
* component_declaration :== COMPONENT identifier PORT (local_port_list);
* END COMPONENT ;
* Note: Treat local_port_list as a formal_port_list.
* @return pointer to a component declaration, null if an error occurs.
*/
private VComponent parseComponent()
throws ParseException
{
VComponent compo = null;
getNextToken();
// should be component identifier
TokenList entity = null;
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
} else
{
entity = nextToken;
}
getNextToken();
// Need keyword PORT
if (!isKeySame(nextToken,KEY_PORT))
reportErrorMsg(nextToken, "Expecting keyword PORT");
else getNextToken();
// should be left bracket, start of port list
if (nextToken.token != TOKEN_LEFTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a left bracket");
}
getNextToken();
// go through port list
FPortList ports = parseFormalPortList();
// should be pointing to RIGHTBRACKET
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
}
getNextToken();
// should be at semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
// Need "END COMPONENT"
if (!isKeySame(nextToken, KEY_END))
reportErrorMsg(nextToken, "Expecting keyword END");
getNextToken();
if (!isKeySame(nextToken, KEY_COMPONENT))
reportErrorMsg(nextToken, "Expecting keyword COMPONENT");
getNextToken();
// should be at terminating semicolon
if (nextToken.token != TOKEN_SEMICOLON)
{
reportErrorMsg(nextToken, "Expecting a semicolon");
}
getNextToken();
compo = new VComponent();
compo.name = entity;
compo.ports = ports;
return compo;
}
/**
* Method to parse a formal port list.
* A formal port list has the form:
* formal_port_list ::= port_declaration {; port_declaration}
* port_declaration ::= identifier_list : port_mode type_mark
* identifier_list ::= identifier {, identifier}
* port_mode ::= [in] | [dot] out | inout | linkage
* type_mark ::= name
* @return the formal port list parse tree (null on error).
*/
private FPortList parseFormalPortList()
throws ParseException
{
// must be at least one port declaration
IdentList iList = parseIdentList();
if (iList == null) return null;
// should be at colon
if (nextToken.token != TOKEN_COLON)
{
reportErrorMsg(nextToken, "Expecting a colon");
return null;
}
getNextToken();
// Get port mode
int mode = parsePortMode();
// should be at type_mark
VName type = parseName();
// create port declaration
FPortList ports = new FPortList();
ports.names = iList;
ports.mode = mode;
ports.type = type;
ports.next = null;
FPortList endPort = ports;
while (nextToken.token == TOKEN_SEMICOLON)
{
getNextToken();
iList = parseIdentList();
if (iList == null) return null;
// should be at colon
if (nextToken.token != TOKEN_COLON)
{
reportErrorMsg(nextToken, "Expecting a colon");
return null;
}
getNextToken();
// Get port mode
mode = parsePortMode();
// should be at type_mark
type = parseName();
FPortList newPort = new FPortList();
newPort.names = iList;
newPort.mode = mode;
newPort.type = type;
newPort.next = null;
endPort.next = newPort;
endPort = newPort;
}
return ports;
}
/**
* Method to parse a port mode description.
* The description has the form:
* port_mode :== [in] | [ dot ] out | inout | linkage
* @return type of mode (default to in).
*/
private int parsePortMode()
throws ParseException
{
int mode = MODE_IN;
if (nextToken.token == TOKEN_KEYWORD)
{
switch (((VKeyword)(nextToken.pointer)).num)
{
case KEY_IN:
getNextToken();
break;
case KEY_OUT:
mode = MODE_OUT;
getNextToken();
break;
case KEY_INOUT:
mode = MODE_INOUT;
getNextToken();
break;
case KEY_LINKAGE:
mode = MODE_LINKAGE;
getNextToken();
break;
default:
break;
}
}
return mode;
}
/**
* Method to parse a name.
* The form of a name is:
* name :== single_name | concatenated_name | attribute_name
* @return the name parse tree.
*/
private VName parseName()
throws ParseException
{
int type = NONAME;
Object pointer = parseSingleName();
switch (nextToken.token)
{
case TOKEN_AMPERSAND:
type = NAME_CONCATENATE;
ConcatenatedName concat = new ConcatenatedName();
concat.name = (SingleName)pointer;
concat.next = null;
pointer = concat;
while (nextToken.token == TOKEN_AMPERSAND)
{
getNextToken();
SingleName pointer2 = parseSingleName();
ConcatenatedName concat2 = new ConcatenatedName();
concat.next = concat2;
concat2.name = pointer2;
concat2.next = null;
concat = concat2;
}
break;
case TOKEN_APOSTROPHE:
break;
default:
type = NAME_SINGLE;
break;
}
VName name = null;
if (type != NONAME)
{
name = new VName();
name.type = type;
name.pointer = pointer;
} else
{
getNextToken();
}
return name;
}
/**
* Method to parse a single name.
* Single names are of the form:
* single_name :== simple_name | selected_name | indexed_name | slice_name
* @return the single name structure.
*/
private SingleName parseSingleName()
throws ParseException
{
int type = NOSINGLENAME;
SingleName sName = null;
Object pointer = parseSimpleName();
if (nextToken.last.space)
{
type = SINGLENAME_SIMPLE;
} else
{
switch (nextToken.token)
{
case TOKEN_PERIOD:
break;
case TOKEN_LEFTBRACKET:
// could be a indexed_name or a slice_name
// but support only indexed names
getNextToken();
type = SINGLENAME_INDEXED;
VName nPtr = new VName();
nPtr.type = NAME_SINGLE;
SingleName sName2 = new SingleName();
nPtr.pointer = sName2;
sName2.type = SINGLENAME_SIMPLE;
sName2.pointer = pointer;
pointer = parseIndexedName(PREFIX_NAME, nPtr);
// should be at right bracket
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
}
getNextToken();
break;
default:
type = SINGLENAME_SIMPLE;
break;
}
}
if (type != NOSINGLENAME)
{
sName = new SingleName();
sName.type = type;
sName.pointer = pointer;
} else
{
getNextToken();
}
return sName;
}
/**
* Method to parse a simple name.
* The name has the form:
* simple_name ::= identifier
* @return pointer to simple name structure.
*/
private SimpleName parseSimpleName()
throws ParseException
{
SimpleName sName = null;
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return sName;
}
sName = new SimpleName();
sName.identifier = nextToken;
getNextToken();
return sName;
}
/**
* Method to parse an indexed name given its prefix and now at the index.
* The form of an indexed name is: indexed_name ::= prefix(expression{, expression})
* @param preType type of prefix (VName or FUNCTION CALL).
* @param prePtr pointer to prefix structure.
* @return pointer to indexed name.
*/
private IndexedName parseIndexedName(int preType, VName prePtr)
throws ParseException
{
Prefix prefix = new Prefix();
prefix.type = preType;
prefix.pointer = prePtr;
IndexedName ind = new IndexedName();
ind.prefix = prefix;
ind.exprList = new ExprList();
ind.exprList.expression = parseExpression();
ind.exprList.next = null;
ExprList eList = ind.exprList;
// continue while at a comma
while (nextToken.token == TOKEN_COMMA)
{
getNextToken();
ExprList newEList = new ExprList();
newEList.expression = parseExpression();
newEList.next = null;
eList.next = newEList;
eList = newEList;
}
return ind;
}
/**
* Method to parse an expression of the form:
* expression ::= relation {AND relation} | relation {OR relation} | relation {NAND relation} | relation {NOR relation} | relation {XOR relation}
* @return the expression structure.
*/
private Expression parseExpression()
throws ParseException
{
Expression exp = new Expression();
exp.relation = parseRelation();
exp.next = null;
// check for more terms
int key = 0;
int logOp = NOLOGOP;
if (nextToken.token == TOKEN_KEYWORD)
{
key = ((VKeyword)(nextToken.pointer)).num;
switch (key)
{
case KEY_AND:
logOp = LOGOP_AND;
break;
case KEY_OR:
logOp = LOGOP_OR;
break;
case KEY_NAND:
logOp = LOGOP_NAND;
break;
case KEY_NOR:
logOp = LOGOP_NOR;
break;
case KEY_XOR:
logOp = LOGOP_XOR;
break;
default:
break;
}
}
if (logOp != NOLOGOP)
{
exp.next = parseMoreRelations(key, logOp);
}
return exp;
}
/**
* Method to parse a relation.
* It has the form:
* relation ::= simple_expression [relational_operator simple_expression]
* relational_operator ::= = | /= | < | <= | > | >=
* @return the relation structure.
*/
private Relation parseRelation()
throws ParseException
{
int relOp = NORELOP;
Relation relation = new Relation();
relation.simpleExpr = parseSimpleExpression();
relation.relOperator = NORELOP;
relation.simpleExpr2 = null;
switch (nextToken.token)
{
case TOKEN_EQ: relOp = RELOP_EQ; break;
case TOKEN_NE: relOp = RELOP_NE; break;
case TOKEN_LT: relOp = RELOP_LT; break;
case TOKEN_LE: relOp = RELOP_LE; break;
case TOKEN_GT: relOp = RELOP_GT; break;
case TOKEN_GE: relOp = RELOP_GE; break;
}
if (relOp != NORELOP)
{
relation.relOperator = relOp;
getNextToken();
relation.simpleExpr2 = parseSimpleExpression();
}
return relation;
}
/**
* Method to parse more relations of an expression.
* They have the form: AND | OR | NAND | NOR | XOR relation
* Note: The logical operator must be the same throughout.
* @param key key of logical operator.
* @param logop logical operator.
* @return pointer to more relations, null if no more.
*/
private MRelations parseMoreRelations(int key, int logOp)
throws ParseException
{
MRelations more = null;
if (isKeySame(nextToken, key))
{
getNextToken();
more = new MRelations();
more.logOperator = logOp;
more.relation = parseRelation();
more.next = parseMoreRelations(key, logOp);
}
return more;
}
/**
* Method to parse a simple expression.
* It has the form: simple_expression ::= [sign] term {adding_operator term}
* @return the simple expression structure.
*/
private SimpleExpr parseSimpleExpression()
throws ParseException
{
SimpleExpr exp = new SimpleExpr();
// check for optional sign
if (nextToken.token == TOKEN_PLUS)
{
exp.sign = 1;
getNextToken();
} else if (nextToken.token == TOKEN_MINUS)
{
exp.sign = -1;
getNextToken();
} else
{
exp.sign = 1; // default sign
}
// next is a term
exp.term = parseTerm();
// check for more terms
exp.next = parseMoreTerms();
return exp;
}
/**
* Method to parse a term.
* It has the form: term ::= factor {multiplying_operator factor}
* @return the term structure.
*/
private Term parseTerm()
throws ParseException
{
Term term = new Term();
term.factor = parseFactor();
term.next = parseMoreFactors();
return term;
}
/**
* Method to parse more factors of a term.
* The factors have the form:
* multiplying_operator factor
* @return pointer to more factors, null if no more.
*/
private MFactors parseMoreFactors()
throws ParseException
{
MFactors more = null;
int mulOp = NOMULOP;
if (nextToken.token == TOKEN_STAR)
{
mulOp = MULOP_MULTIPLY;
} else if (nextToken.token == TOKEN_SLASH)
{
mulOp = MULOP_DIVIDE;
} else if (isKeySame(nextToken, KEY_MOD))
{
mulOp = MULOP_MOD;
} else if (isKeySame(nextToken, KEY_REM))
{
mulOp = MULOP_REM;
}
if (mulOp != NOMULOP)
{
getNextToken();
more = new MFactors();
more.mulOperator = mulOp;
more.factor = parseFactor();
more.next = parseMoreFactors();
}
return more;
}
/**
* Method to parse a factor of the form:
* factor :== primary [** primary] | ABS primary | NOT primary
* @return the factor structure.
*/
private Factor parseFactor()
throws ParseException
{
Factor factor = null;
Primary primary = null;
Primary primary2 = null;
int miscOp = NOMISCOP;
if (isKeySame(nextToken, KEY_ABS))
{
miscOp = MISCOP_ABS;
getNextToken();
primary = parsePrimary();
} else if (isKeySame(nextToken, KEY_NOT))
{
miscOp = MISCOP_NOT;
getNextToken();
primary = parsePrimary();
} else
{
primary = parsePrimary();
if (nextToken.token == TOKEN_DOUBLESTAR)
{
miscOp = MISCOP_POWER;
getNextToken();
primary2 = parsePrimary();
}
}
factor = new Factor();
factor.primary = primary;
factor.miscOperator = miscOp;
factor.primary2 = primary2;
return factor;
}
/**
* Method to parse a primary of the form:
* primary ::= name | literal | aggregate | concatenation | function_call | type_conversion | qualified_expression | (expression)
* @return the primary structure.
*/
private Primary parsePrimary()
throws ParseException
{
int type = NOPRIMARY;
Object pointer = null;
Primary primary = null;
switch (nextToken.token)
{
case TOKEN_DECIMAL:
case TOKEN_BASED:
case TOKEN_STRING:
case TOKEN_BIT_STRING:
type = PRIMARY_LITERAL;
pointer = parseLiteral();
break;
case TOKEN_IDENTIFIER:
type = PRIMARY_NAME;
pointer = parseName();
break;
case TOKEN_LEFTBRACKET:
// should be an expression in brackets
getNextToken();
type = PRIMARY_EXPRESSION;
pointer = parseExpression();
// should be at right bracket
if (nextToken.token != TOKEN_RIGHTBRACKET)
{
reportErrorMsg(nextToken, "Expecting a right bracket");
}
getNextToken();
break;
default:
break;
}
if (type != NOPRIMARY)
{
primary = new Primary();
primary.type = type;
primary.pointer = pointer;
}
return primary;
}
/**
* Method to parse a literal of the form:
* literal ::= numeric_literal | enumeration_literal | string_literal | bit_string_literal
* @return pointer to returned literal structure.
*/
private Literal parseLiteral()
throws ParseException
{
Literal literal = null;
Object pointer = null;
int type = NOLITERAL;
switch(nextToken.token)
{
case TOKEN_DECIMAL:
type = LITERAL_NUMERIC;
pointer = parseDecimal();
break;
case TOKEN_BASED:
// type = LITERAL_NUMERIC;
// pointer = parseBased();
break;
case TOKEN_STRING:
break;
case TOKEN_BIT_STRING:
break;
default:
break;
}
if (type != NOLITERAL)
{
literal = new Literal();
literal.type = type;
literal.pointer = pointer;
}
return literal;
}
/**
* Method to parse a decimal literal of the form:
* decimal_literal ::= integer [.integer] [exponent]
* integer ::= digit {[underline] digit}
* exponent ::= E [+] integer | E - integer
* Currently only integer supported.
* @return the value of decimal literal.
*/
private Integer parseDecimal()
throws ParseException
{
int value = TextUtils.atoi((String)nextToken.pointer);
getNextToken();
return new Integer(value);
}
/**
* Method to parse more terms of a simple expression.
* The terms have the form:
* adding_operator term
* @return pointer to more terms, null if no more.
*/
private MTerms parseMoreTerms()
throws ParseException
{
MTerms more = null;
int addOp = NOADDOP;
if (nextToken.token == TOKEN_PLUS)
{
addOp = ADDOP_ADD;
} else if (nextToken.token == TOKEN_MINUS)
{
addOp = ADDOP_SUBTRACT;
}
if (addOp != NOADDOP)
{
getNextToken();
more = new MTerms();
more.addOperator = addOp;
more.term = parseTerm();
more.next = parseMoreTerms();
}
return more;
}
/**
* Method to parse an identifier list and return its parse tree.
* The form of an identifier list is:
* identifier_list :== identifier {, identifier}
* @return a pointer to identifier list.
*/
private IdentList parseIdentList()
throws ParseException
{
// must be at least one identifier
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return null;
}
IdentList newIList = new IdentList();
newIList.identifier = nextToken;
newIList.next = null;
IdentList iList = newIList;
IdentList iListEnd = newIList;
// continue while a comma is next
getNextToken();
while (nextToken.token == TOKEN_COMMA)
{
getNextToken();
// should be another identifier
if (nextToken.token != TOKEN_IDENTIFIER)
{
reportErrorMsg(nextToken, "Expecting an identifier");
getNextToken();
return null;
}
newIList = new IdentList();
newIList.identifier = nextToken;
newIList.next = null;
iListEnd.next = newIList;
iListEnd = newIList;
getNextToken();
}
return iList;
}
/**
* Method to ignore up to the next semicolon.
*/
private void parseToSemicolon()
throws ParseException
{
for(;;)
{
getNextToken();
if (nextToken.token == TOKEN_SEMICOLON)
{
getNextToken();
break;
}
}
}
/**
* Method to get the next token if possible.
*/
private void getNextToken()
throws ParseException
{
if (nextToken.next == null)
{
reportErrorMsg(nextToken, "Unexpected termination within block");
throw new ParseException();
}
nextToken = nextToken.next;
}
/**
* Method to compare the two keywords, the first as part of a token.
* @param tokenPtr pointer to the token entity.
* @param key value of key to be compared.
* @return true if the same, false if not the same.
*/
private boolean isKeySame(TokenList tokenPtr, int key)
{
if (tokenPtr.token != TOKEN_KEYWORD) return false;
if (((VKeyword)(tokenPtr.pointer)).num == key) return true;
return false;
}
private void reportErrorMsg(TokenList tList, String errMsg)
{
hasError = true;
errorCount++;
if (errorCount == 30)
System.out.println("TOO MANY ERRORS...PRINTING NO MORE");
if (errorCount >= 30) return;
if (tList == null)
{
System.out.println("ERROR " + errMsg);
return;
}
System.out.println("ERROR on line " + tList.lineNum + ", " + errMsg + ":");
// back up to start of line
TokenList tStart;
for (tStart = tList; tStart.last != null; tStart = tStart.last)
{
if (tStart.last.lineNum != tList.lineNum) break;
}
// form line in buffer
int pointer = 0;
StringBuffer buffer = new StringBuffer();
for ( ; tStart != null && tStart.lineNum == tList.lineNum; tStart = tStart.next)
{
int i = buffer.length();
if (tStart == tList) pointer = i;
if (tStart.token < TOKEN_ARROW)
{
char chr = delimiterStr.charAt(tStart.token);
buffer.append(chr);
} else if (tStart.token < TOKEN_UNKNOWN)
{
int start = 2 * (tStart.token - TOKEN_ARROW);
buffer.append(doubleDelimiterStr.substring(start, start+2));
} else switch (tStart.token)
{
case TOKEN_STRING:
buffer.append("\"" + tStart.pointer + "\" ");
break;
case TOKEN_KEYWORD:
buffer.append(((VKeyword)tStart.pointer).name);
break;
case TOKEN_IDENTIFIER:
buffer.append(tStart.pointer);
break;
case TOKEN_CHAR:
buffer.append(((Character)tStart.pointer).charValue());
case TOKEN_DECIMAL:
buffer.append(tStart.pointer);
break;
default:
if (tStart.pointer != null)
buffer.append(tStart.pointer);
break;
}
if (tStart.space) buffer.append(" ");
}
// print out line
System.out.println(buffer.toString());
// print out pointer
buffer = new StringBuffer();
for (int i = 0; i < pointer; i++) buffer.append(" ");
System.out.println(buffer.toString() + "^");
}
/******************************** THE VHDL SEMANTICS ********************************/
private DBUnits theUnits;
private SymbolList localSymbols, globalSymbols;
private int forLoopLevel = 0;
private int [] forLoopTags = new int[10];
/**
* Method to start semantic analysis of the generated parse tree.
* @return the status of the analysis (errors).
*/
private boolean doSemantic()
{
hasError = false;
theUnits = new DBUnits();
theUnits.interfaces = null;
DBInterface endInterface = null;
theUnits.bodies = null;
DBBody endBody = null;
localSymbols = pushSymbols(null);
globalSymbols = pushSymbols(null);
// add defaults to symbol tree
createDefaultType(localSymbols);
SymbolList sSymbols = localSymbols;
localSymbols = pushSymbols(localSymbols);
for (PTree unit = pTree; unit != null; unit = unit.next)
{
switch (unit.type)
{
case UNIT_INTERFACE:
DBInterface interfacef = semInterface((VInterface)unit.pointer);
if (interfacef == null) break;
if (endInterface == null)
{
theUnits.interfaces = endInterface = interfacef;
} else
{
endInterface.next = interfacef;
endInterface = interfacef;
}
localSymbols = pushSymbols(sSymbols);
break;
case UNIT_BODY:
DBBody body = semBody((Body)unit.pointer);
if (endBody == null)
{
theUnits.bodies = endBody = body;
} else
{
endBody.next = body;
endBody = body;
}
localSymbols = pushSymbols(sSymbols);
break;
case UNIT_PACKAGE:
semPackage((Package)unit.pointer);
break;
case UNIT_USE:
semUse((Use)unit.pointer);
break;
case UNIT_FUNCTION:
default:
break;
}
}
return hasError;
}
/**
* Method to do semantic analysis of a use statement.
* Add package symbols to symbol list.
* @param use pointer to use parse structure.
*/
private void semUse(Use use)
{
for ( ; use != null; use = use.next)
{
/* Note this code was lifted with minor mods from semWith()
* which is not a distinct function in IEEE version.
* It seems a little redundant as written, but I don't
* really understand what Andy was doing here.....
*/
SymbolTree symbol = searchSymbol((String)use.unit.pointer, globalSymbols);
if (symbol == null)
{
continue;
}
if (symbol.type != SYMBOL_PACKAGE)
{
reportErrorMsg(use.unit, "Symbol is not a PACKAGE");
} else
{
addSymbol(symbol.value, SYMBOL_PACKAGE, symbol.pointer, localSymbols);
}
symbol = searchSymbol((String)use.unit.pointer, globalSymbols);
if (symbol == null)
{
reportErrorMsg(use.unit, "Symbol is undefined");
continue;
}
if (symbol.type != SYMBOL_PACKAGE)
{
reportErrorMsg(use.unit, "Symbol is not a PACKAGE");
} else
{
SymbolList newSymList = ((DBPackage)(symbol.pointer)).root;
newSymList.last = localSymbols;
localSymbols = newSymList;
}
}
}
/**
* Method to do semantic analysis of a package declaration.
* @param vPackage pointer to a package.
*/
private void semPackage(Package vPackage)
{
if (vPackage == null) return;
DBPackage dbPackage = null;
// search to see if package name is unique
if (searchSymbol((String)vPackage.name.pointer, globalSymbols) != null)
{
reportErrorMsg(vPackage.name, "Symbol previously defined");
} else
{
dbPackage = new DBPackage();
dbPackage.name = (String)vPackage.name.pointer;
dbPackage.root = null;
addSymbol(dbPackage.name, SYMBOL_PACKAGE, dbPackage, globalSymbols);
}
// check package parts
localSymbols = pushSymbols(localSymbols);
for (PackagedPart part = vPackage.declare; part != null; part = part.next)
{
semBasicDeclare(part.item);
}
if (dbPackage != null)
{
dbPackage.root = localSymbols;
}
localSymbols = popSymbols(localSymbols);
}
/**
* Method to do semantic analysis of an body declaration.
* @param body pointer to body parse structure.
* @return resultant database body.
*/
private DBBody semBody(Body body)
{
DBBody dbBody = null;
if (body == null) return dbBody;
if (searchSymbol((String)body.name.pointer, globalSymbols) != null)
{
reportErrorMsg(body.name, "Body previously defined");
return dbBody;
}
// create dbbody
dbBody = new DBBody();
dbBody.name = (String)body.name.pointer;
dbBody.entity = null;
dbBody.declare = null;
dbBody.statements = null;
dbBody.parent = null;
dbBody.sameParent = null;
dbBody.next = null;
addSymbol(dbBody.name, SYMBOL_BODY, dbBody, globalSymbols);
// check if interface declared
SymbolTree symbol = searchSymbol((String)body.entity.identifier.pointer, globalSymbols);
if (symbol == null)
{
reportErrorMsg(body.entity.identifier, "Reference to undefined entity");
return dbBody;
} else if (symbol.type != SYMBOL_ENTITY)
{
reportErrorMsg(body.entity.identifier, "Symbol is not an entity");
return dbBody;
} else
{
dbBody.entity = symbol.value;
dbBody.parent = (DBInterface)symbol.pointer;
if (symbol.pointer != null)
{
// add interfacef-body reference to list
dbBody.sameParent = ((DBInterface)(symbol.pointer)).bodies;
((DBInterface)(symbol.pointer)).bodies = dbBody;
}
}
// create new symbol tree
SymbolList tempSymbols = localSymbols;
SymbolList endSymbol = localSymbols;
if (symbol.pointer != null)
{
while (endSymbol.last != null)
{
endSymbol = endSymbol.last;
}
endSymbol.last = ((DBInterface)(symbol.pointer)).symbols;
}
localSymbols = pushSymbols(localSymbols);
// check body declaration
dbBody.declare = semBodyDeclare(body.bodyDeclare);
// check statements
dbBody.statements = semSetOfStatements(body.statements);
// delete current symbol table
localSymbols = tempSymbols;
endSymbol.last = null;
return dbBody;
}
/**
* Method to do semantic analysis of architectural set of statements in a body.
* @param state pointer to architectural statements.
* @return pointer to created statements.
*/
private DBStatements semSetOfStatements(Statements state)
{
if (state == null) return null;
DBStatements dbStates = new DBStatements();
dbStates.instances = null;
DBInstance endInstance = null;
for (; state != null; state = state.next)
{
switch (state.type)
{
case ARCHSTATE_INSTANCE:
DBInstance newInstance = semInstance((VInstance)state.pointer);
if (endInstance == null)
{
dbStates.instances = endInstance = newInstance;
} else
{
endInstance.next = newInstance;
endInstance = newInstance;
}
break;
case ARCHSTATE_GENERATE:
DBStatements newState = semGenerate((Generate)state.pointer);
if (newState != null)
{
for (newInstance = newState.instances; newInstance != null;
newInstance = newInstance.next)
{
if (endInstance == null)
{
dbStates.instances = endInstance = newInstance;
} else
{
endInstance.next = newInstance;
endInstance = newInstance;
}
}
}
break;
case ARCHSTATE_SIG_ASSIGN:
case ARCHSTATE_IF:
case ARCHSTATE_CASE:
default:
break;
}
}
return dbStates;
}
/**
* Method to do semantic analysis of generate statement.
* @param gen pointer to generate statement.
* @return pointer to generated statements.
*/
private DBStatements semGenerate(Generate gen)
{
DBStatements dbStates = null;
if (gen == null) return dbStates;
// check label
// For IEEE standard, check label only if not inside a for generate
// Not a perfect implementation, but label is not used for anything
// in this situation. This is easier to check in the parser...
if (gen.label != null && forLoopLevel == 0)
{
// check label for uniqueness
if (searchSymbol((String)gen.label.pointer, localSymbols) != null)
{
reportErrorMsg(gen.label, "Symbol previously defined");
} else
{
addSymbol((String)gen.label.pointer, SYMBOL_LABEL, null, localSymbols);
}
}
// check generation scheme
GenScheme scheme = gen.genScheme;
if (scheme == null) return dbStates;
switch (scheme.scheme)
{
case GENSCHEME_FOR:
// Increment forLoopLevel and clear tag
forLoopTags[++forLoopLevel] = 0;
// create new local symbol table
localSymbols = pushSymbols(localSymbols);
// add identifier as a variable symbol
SymbolTree symbol = addSymbol((String)scheme.identifier.pointer, SYMBOL_VARIABLE,
null, localSymbols);
// determine direction of discrete range (ascending or descending)
DBDiscreteRange dRange = semDiscreteRange(scheme.range);
if (dRange.start > dRange.end)
{
int temp = dRange.end;
dRange.end = dRange.start;
dRange.start = temp;
}
DBStatements oldStates = null;
DBInstance endInst = null;
for (int temp = dRange.start; temp <= dRange.end; temp++)
{
symbol.pointer = new Integer(temp);
dbStates = semSetOfStatements(gen.statements);
++forLoopTags[forLoopLevel];
if (dbStates != null)
{
if (oldStates == null)
{
oldStates = dbStates;
endInst = dbStates.instances;
if (endInst != null)
{
while (endInst.next != null)
{
endInst = endInst.next;
}
}
} else
{
for (DBInstance inst = dbStates.instances; inst != null; inst = inst.next)
{
if (endInst == null)
{
oldStates.instances = endInst = inst;
} else
{
endInst.next = inst;
endInst = inst;
}
}
}
}
}
dbStates = oldStates;
// restore old symbol table
localSymbols = popSymbols(localSymbols);
--forLoopLevel;
break;
case GENSCHEME_IF:
if (evalExpression(scheme.condition) != 0)
{
dbStates = semSetOfStatements(gen.statements);
}
default:
break;
}
return dbStates;
}
/**
* Method to do demantic analysis of instance for an architectural body.
* @param inst pointer to instance structure.
* @return pointer to created instance.
*/
private DBInstance semInstance(VInstance inst)
{
DBInstance dbInst = null;
if (inst == null) return dbInst;
// If inside a "for generate" make unique instance name
// from instance label and forLoopTags[]
String iKey = null;
if (forLoopLevel > 0)
{
if (inst.name == null) iKey = "no_name"; else
iKey = (String)inst.name.pointer;
for (int i=1; i<=forLoopLevel; ++i)
{
iKey += "_" + forLoopTags[i];
}
} else
{
iKey = (String)inst.name.pointer;
}
dbInst = new DBInstance();
dbInst.name = iKey;
dbInst.compo = null;
dbInst.ports = null;
DBAPortList endDBAPort = null;
dbInst.next = null;
if (searchSymbol(dbInst.name, localSymbols) != null)
{
reportErrorMsg(inst.name, "Instance name previously defined");
} else
{
addSymbol(dbInst.name, SYMBOL_INSTANCE, dbInst, localSymbols);
}
// check that instance entity is among component list
DBComponents compo = null;
SymbolTree symbol = searchSymbol((String)inst.entity.identifier.pointer, localSymbols);
if (symbol == null)
{
reportErrorMsg(inst.entity.identifier, "Instance references undefined component");
} else if (symbol.type != SYMBOL_COMPONENT)
{
reportErrorMsg(inst.entity.identifier, "Symbol is not a component reference");
} else
{
compo = (DBComponents)symbol.pointer;
dbInst.compo = compo;
// check that number of ports match
int iPortNum = 0;
for (APortList apList = inst.ports; apList != null; apList = apList.next)
{
iPortNum++;
}
int cPortNum = 0;
for (DBPortList pList = compo.ports; pList != null; pList = pList.next)
{
cPortNum++;
}
if (iPortNum != cPortNum)
{
reportErrorMsg(getNameToken((VName)inst.ports.pointer),
"Instance has different number of ports than component (instance has " + iPortNum + ", component has " + cPortNum + ")");
return null;
}
}
// check that ports of instance are either signals or entity port
// note 0 ports are allowed for position placement
DBPortList pList = null;
if (compo != null)
{
pList = compo.ports;
}
for (APortList apList = inst.ports; apList != null; apList = apList.next)
{
DBAPortList dbAPort = new DBAPortList();
dbAPort.name = null;
dbAPort.port = pList;
if (pList != null)
{
pList = pList.next;
}
dbAPort.flags = 0;
dbAPort.next = null;
if (endDBAPort == null)
{
dbInst.ports = endDBAPort = dbAPort;
} else
{
endDBAPort.next = dbAPort;
endDBAPort = dbAPort;
}
if (apList.pointer == null) continue;
dbAPort.name = semName((VName)apList.pointer);
// check that name is reference to a signal or formal port
semAPortCheck((VName)apList.pointer);
}
return dbInst;
}
/**
* Method to do semantic analysis of a name.
* @param name pointer to name structure.
* @return pointer to created db name.
*/
private DBName semName(VName name)
{
DBName dbName = null;
if (name == null) return dbName;
switch (name.type)
{
case NAME_SINGLE:
dbName = semSingleName((SingleName)name.pointer);
break;
case NAME_CONCATENATE:
dbName = semConcatenatedName((ConcatenatedName)name.pointer);
break;
case NAME_ATTRIBUTE:
default:
break;
}
return dbName;
}
/**
* Method to do semantic analysis of a concatenated name.
* @param name pointer to concatenated name structure.
* @return pointer to generated db name.
*/
private DBName semConcatenatedName(ConcatenatedName name)
{
DBName dbName = null;
if (name == null) return dbName;
dbName = new DBName();
dbName.name = null;
dbName.type = DBNAME_CONCATENATED;
dbName.pointer = null;
dbName.dbType = null;
DBNameList end = null;
for (ConcatenatedName cat = name; cat != null; cat = cat.next)
{
DBNameList newNL = new DBNameList();
newNL.name = semSingleName(cat.name);
newNL.next = null;
if (end != null)
{
end.next = newNL;
end = newNL;
} else
{
end = newNL;
dbName.pointer = newNL;
}
}
return dbName;
}
/**
* Method to do semantic analysis of a single name.
* @param name pointer to single name structure.
* @return pointer to generated db name.
*/
private DBName semSingleName(SingleName name)
{
DBName dbName = null;
if (name == null) return dbName;
switch (name.type)
{
case SINGLENAME_SIMPLE:
dbName = new DBName();
dbName.name = (String)((SimpleName)(name.pointer)).identifier.pointer;
dbName.type = DBNAME_IDENTIFIER;
dbName.pointer = null;
dbName.dbType = getType(dbName.name);
break;
case SINGLENAME_INDEXED:
dbName = semIndexedName((IndexedName)name.pointer);
break;
case SINGLENAME_SLICE:
case SINGLENAME_SELECTED:
default:
break;
}
return dbName;
}
/**
* Method to do semantic analysis of an indexed name.
* @param name pointer to indexed name structure.
* @return pointer to generated name.
*/
private DBName semIndexedName(IndexedName name)
{
DBName dbName = null;
if (name == null) return dbName;
// must be an array type
DBLType type = getType(getPrefixIdent(name.prefix));
if (type == null)
{
reportErrorMsg(getPrefixToken(name.prefix), "No type specified");
return dbName;
}
if (type.type != DBTYPE_ARRAY)
{
reportErrorMsg(getPrefixToken(name.prefix), "Must be of constrained array type");
return dbName;
}
dbName = new DBName();
dbName.name = getPrefixIdent(name.prefix);
dbName.type = DBNAME_INDEXED;
dbName.pointer = null;
dbName.dbType = type;
// evaluate any expressions
DBIndexRange indexR = (DBIndexRange)type.pointer;
DBExprList dbExpr = null, endExpr = null;
for (ExprList expr = name.exprList; expr != null && indexR != null; expr = expr.next)
{
int value = evalExpression(expr.expression);
if (!isInDiscreteRange(value, indexR.dRange))
{
reportErrorMsg(getPrefixToken(name.prefix), "Index is out of range");
return dbName;
}
DBExprList nExpr = new DBExprList();
nExpr.value = value;
nExpr.next = null;
if (endExpr == null)
{
dbExpr = endExpr = nExpr;
} else
{
endExpr.next = nExpr;
endExpr = nExpr;
}
indexR = indexR.next;
}
dbName.pointer = dbExpr;
return dbName;
}
/**
* Method to decide whether value is in discrete range.
* @param value value to be checked.
* @param discrete pointer to db discrete range structure.
* @return true if value in discrete range, else false.
*/
private boolean isInDiscreteRange(int value, DBDiscreteRange discrete)
{
boolean inRange = false;
if (discrete == null)
return inRange;
int start = discrete.start;
int end = discrete.end;
if (start > end)
{
int temp = end;
end = start;
start = temp;
}
if (value >= start && value <= end)
inRange = true;
return inRange;
}
/**
* Method to get the type of an identifier.
* @param ident pointer to identifier.
* @return type, null if no type.
*/
private DBLType getType(String ident)
{
DBLType type = null;
if (ident != null)
{
SymbolTree symbol = searchSymbol(ident, localSymbols);
if (symbol != null)
{
type = getSymbolType(symbol);
}
}
return type;
}
/**
* Method to get a pointer to the type of a symbol.
* @param symbol pointer to symbol.
* @return pointer to returned type, null if no type exists.
*/
private DBLType getSymbolType(SymbolTree symbol)
{
DBLType type = null;
if (symbol == null) return type;
switch (symbol.type)
{
case SYMBOL_FPORT:
DBPortList fPort = (DBPortList)symbol.pointer;
if (fPort == null) break;
type = fPort.type;
break;
case SYMBOL_SIGNAL:
DBSignals signal = (DBSignals)symbol.pointer;
if (signal == null) break;
type = signal.type;
break;
case SYMBOL_TYPE:
type = (DBLType)symbol.pointer;
break;
default:
break;
}
return type;
}
/**
* Method to check that the passed name which is a reference on an actual port
* list is a signal of formal port.
* @param name pointer to name parse structure.
*/
private void semAPortCheck(VName name)
{
switch (name.type)
{
case NAME_SINGLE:
semAPortCheckSingleName((SingleName)name.pointer);
break;
case NAME_CONCATENATE:
for (ConcatenatedName cat = (ConcatenatedName)name.pointer; cat != null; cat = cat.next)
{
semAPortCheckSingleName(cat.name);
}
break;
default:
break;
}
}
/**
* Method to check that the passed single name references a signal or formal port.
* @param sName pointer to single name structure.
*/
private void semAPortCheckSingleName(SingleName sName)
{
switch (sName.type)
{
case SINGLENAME_SIMPLE:
SimpleName simName = (SimpleName)sName.pointer;
String ident = (String)simName.identifier.pointer;
SymbolTree symbol = searchSymbol(ident, localSymbols);
if (symbol == null ||
(symbol.type != SYMBOL_FPORT && symbol.type != SYMBOL_SIGNAL))
{
reportErrorMsg(simName.identifier,
"Instance port has reference to unknown port");
}
break;
case SINGLENAME_INDEXED:
IndexedName iName = (IndexedName)sName.pointer;
ident = getPrefixIdent(iName.prefix);
symbol = searchSymbol(ident, localSymbols);
if (symbol == null)
{
symbol = searchSymbol(ident, localSymbols);
}
if (symbol == null ||
(symbol.type != SYMBOL_FPORT && symbol.type != SYMBOL_SIGNAL))
{
reportErrorMsg(getPrefixToken(iName.prefix),
"Instance port has reference to unknown port");
}
break;
default:
break;
}
}
/**
* Method to do semantic analysis of the body declaration portion of a body.
* @param ointer to body declare. pointer to body declare.
* @return pointer to generated body declare.
*/
private DBBodyDelcare semBodyDeclare(BodyDeclare declare)
{
DBBodyDelcare dbDeclare = null;
if (declare == null) return dbDeclare;
dbDeclare = new DBBodyDelcare();
dbDeclare.components = null;
DBComponents endComponent = null;
dbDeclare.bodySignals = null;
DBSignals endSignal = null;
for (; declare != null; declare = declare.next)
{
switch (declare.type)
{
case BODYDECLARE_BASIC:
DBSignals newSignals = semBasicDeclare((BasicDeclare)declare.pointer);
if (newSignals != null)
{
if (endSignal == null)
{
dbDeclare.bodySignals = endSignal = newSignals;
} else
{
endSignal.next = newSignals;
endSignal = newSignals;
}
while (endSignal.next != null)
{
endSignal = endSignal.next;
}
}
break;
case BODYDECLARE_COMPONENT:
DBComponents newComponent = semComponent((VComponent)declare.pointer);
if (newComponent != null)
{
if (endComponent == null)
{
dbDeclare.components = endComponent = newComponent;
} else
{
endComponent.next = newComponent;
endComponent = newComponent;
}
}
break;
case BODYDECLARE_RESOLUTION:
case BODYDECLARE_LOCAL:
default:
break;
}
}
return dbDeclare;
}
/**
* Method to do semantic analysis of body's component.
* @param compo pointer to component parse.
* @return pointer to created component.
*/
private DBComponents semComponent(VComponent compo)
{
DBComponents dbComp = null;
if (compo == null) return dbComp;
if (searchFSymbol((String)compo.name.pointer, localSymbols) != null)
{
reportErrorMsg(compo.name, "Identifier previously defined");
return dbComp;
}
dbComp = new DBComponents();
dbComp.name = (String)compo.name.pointer;
dbComp.ports = null;
dbComp.next = null;
addSymbol(dbComp.name, SYMBOL_COMPONENT, dbComp, localSymbols);
localSymbols = pushSymbols(localSymbols);
dbComp.ports = semFormalPortList(compo.ports);
localSymbols = popSymbols(localSymbols);
return dbComp;
}
/**
* Method to top off the top most symbol list and return next symbol list.
* @param oldSymList pointer to old symbol list.
* @return pointer to new symbol list.
*/
private SymbolList popSymbols(SymbolList oldSymList)
{
if (oldSymList == null)
{
System.out.println("ERROR - trying to pop nonexistant symbol list.");
return null;
}
SymbolList newSymList = oldSymList.last;
return newSymList;
}
/**
* Method to do semantic analysis of basic declaration.
* @param declare pointer to basic declaration structure.
* @return pointer to new signal, null if not.
*/
private DBSignals semBasicDeclare(BasicDeclare declare)
{
DBSignals dbSignal = null;
if (declare == null) return dbSignal;
switch (declare.type)
{
case BASICDECLARE_OBJECT:
dbSignal = semObjectDeclare((ObjectDeclare)declare.pointer);
break;
case BASICDECLARE_TYPE:
semTypeDeclare((Type)declare.pointer);
break;
case BASICDECLARE_SUBTYPE:
case BASICDECLARE_CONVERSION:
case BASICDECLARE_ATTRIBUTE:
case BASICDECLARE_ATT_SPEC:
default:
break;
}
return dbSignal;
}
/**
* Method to do semantic analysis of a type declaration.
* @param type pointer to type parse tree.
*/
private void semTypeDeclare(Type type)
{
DBLType dbType = null;
if (type == null) return;
// check that type name is distict
if (searchSymbol((String)type.identifier.pointer, localSymbols) != null)
{
reportErrorMsg(type.identifier, "Identifier previously defined");
return;
}
// check type definition
switch (type.type)
{
case TYPE_SCALAR:
break;
case TYPE_COMPOSITE:
dbType = semCompositeType((Composite)type.pointer);
break;
default:
break;
}
// add symbol to list
if (dbType != null)
{
dbType.name = (String)type.identifier.pointer;
addSymbol(dbType.name, SYMBOL_TYPE, dbType, localSymbols);
}
}
/**
* Method to do semantic analysis of a composite type definition.
* @param composite pointer to composite type structure.
* @return generated db type.
*/
private DBLType semCompositeType(Composite composite)
{
DBLType dbType = null;
if (composite == null) return dbType;
switch (composite.type)
{
case COMPOSITE_ARRAY:
dbType = semArrayType((Array)composite.pointer);
break;
case COMPOSITE_RECORD:
break;
default:
break;
}
return dbType;
}
/**
* Method to do semantic analysis of an array composite type definition.
* @param array pointer to composite array type structure.
* @return pointer to generated type.
*/
private DBLType semArrayType(Array array)
{
DBLType dbType = null;
if (array == null) return dbType;
switch (array.type)
{
case ARRAY_UNCONSTRAINED:
break;
case ARRAY_CONSTRAINED:
dbType = semConstrainedArray((Constrained)array.pointer);
break;
default:
break;
}
return dbType;
}
/**
* Method to do semantic analysis of a composite constrained array type definition.
* @param constr pointer to constrained array structure.
* @return pointer to generated type.
*/
private DBLType semConstrainedArray(Constrained constr)
{
DBLType dbType = null;
if (constr == null) return dbType;
dbType = new DBLType();
dbType.name = null;
dbType.type = DBTYPE_ARRAY;
DBIndexRange endRange = null;
dbType.pointer = null;
dbType.subType = null;
// check index constraint
for (IndexConstraint indexC = constr.constraint; indexC != null; indexC = indexC.next)
{
DBIndexRange newRange = new DBIndexRange();
newRange.dRange = semDiscreteRange(indexC.discrete);
newRange.next = null;
if (endRange == null)
{
endRange = newRange;
dbType.pointer = newRange;
} else
{
endRange.next = newRange;
endRange = newRange;
}
}
// check subtype indication
dbType.subType = semSubtypeIndication(constr.subType);
return dbType;
}
/**
* Method to do semantic analysis of a sybtype indication.
* @param subtype pointer to subtype indication.
* @return pointer to db type;
*/
private DBLType semSubtypeIndication(SubTypeInd subType)
{
DBLType dbType = null;
if (subType == null) return dbType;
dbType = semTypeMark(subType.type);
return dbType;
}
/**
* Method to do semantic type mark.
* @param name pointer to type name.
* @return pointer to db type.
*/
private DBLType semTypeMark(VName name)
{
DBLType dbType = null;
if (name == null) return dbType;
SymbolTree symbol = searchSymbol(getNameIdent(name), localSymbols);
if (symbol == null ||
symbol.type != SYMBOL_TYPE)
{
reportErrorMsg(getNameToken(name), "Bad type");
} else
{
dbType = (DBLType)symbol.pointer;
}
return dbType;
}
/**
* Method to do semantic analysis of a discrete range.
* @param discrete pointer to a discrete range structure.
* @return pointer to generated range.
*/
private DBDiscreteRange semDiscreteRange(DiscreteRange discrete)
{
DBDiscreteRange dbRange = null;
if (discrete == null) return dbRange;
switch (discrete.type)
{
case DISCRETERANGE_SUBTYPE:
break;
case DISCRETERANGE_RANGE:
dbRange = semRange((Range)discrete.pointer);
break;
default:
break;
}
return dbRange;
}
/**
* Method to do semantic analysis of a range.
* @param range pointer to a range structure.
* @return pointer to generated range.
*/
private DBDiscreteRange semRange(Range range)
{
DBDiscreteRange dbRange = null;
if (range == null) return dbRange;
switch (range.type)
{
case RANGE_ATTRIBUTE:
break;
case RANGE_SIMPLE_EXPR:
RangeSimple rSimp = (RangeSimple)range.pointer;
if (rSimp != null)
{
dbRange = new DBDiscreteRange();
dbRange.start = evalSimpleExpr(rSimp.start);
dbRange.end = evalSimpleExpr(rSimp.end);
}
break;
default:
break;
}
return dbRange;
}
/**
* Method to do semantic analysis of object declaration.
* @param primary pointer to object declaration structure.
* @return pointer to new signals, null if not.
*/
private DBSignals semObjectDeclare(ObjectDeclare declare)
{
DBSignals signals = null;
if (declare == null) return signals;
switch (declare.type)
{
case OBJECTDECLARE_SIGNAL:
signals = semSignalDeclare((SignalDeclare)declare.pointer);
break;
case OBJECTDECLARE_CONSTANT:
semConstantDeclare((ConstantDeclare)declare.pointer);
break;
case OBJECTDECLARE_VARIABLE:
case OBJECTDECLARE_ALIAS:
default:
break;
}
return signals;
}
/**
* Method to do semantic analysis of constant declaration.
* @param constant pointer to constant declare structure.
*/
private void semConstantDeclare(ConstantDeclare constant)
{
if (constant == null) return;
// check if name exists in top level of symbol tree
if (searchFSymbol((String)constant.identifier.pointer, localSymbols) != null)
{
reportErrorMsg(constant.identifier, "Symbol previously defined");
} else
{
int value = evalExpression(constant.expression);
addSymbol((String)constant.identifier.pointer, SYMBOL_CONSTANT,
new Integer(value), localSymbols);
}
}
/**
* Method to get the value of an expression.
* @param expr pointer to expression structure.
* @return value.
*/
private int evalExpression(Expression expr)
{
if (expr == null) return 0;
int value = evalRelation(expr.relation);
if (expr.next != null)
{
if (value != 0) value = 1;
}
for (MRelations more = expr.next; more != null; more = more.next)
{
int value2 = evalRelation(more.relation);
if (value2 != 0) value2 = 1;
switch (more.logOperator)
{
case LOGOP_AND:
value &= value2;
break;
case LOGOP_OR:
value |= value2;
break;
case LOGOP_NAND:
value = ~(value & value2);
break;
case LOGOP_NOR:
value = ~(value | value2);
break;
case LOGOP_XOR:
value ^= value2;
break;
default:
break;
}
}
return value;
}
/**
* Method to evaluate a relation.
* @param relation pointer to relation structure.
* @return evaluated value.
*/
private int evalRelation(Relation relation)
{
if (relation == null) return 0;
int value = evalSimpleExpr(relation.simpleExpr);
if (relation.relOperator != NORELOP)
{
int value2 = evalSimpleExpr(relation.simpleExpr2);
switch (relation.relOperator)
{
case RELOP_EQ:
if (value == value2) value = 1; else
value = 0;
break;
case RELOP_NE:
if (value != value2) value = 1; else
value = 0;
break;
case RELOP_LT:
if (value < value2) value = 1; else
value = 0;
break;
case RELOP_LE:
if (value <= value2) value = 1; else
value = 0;
break;
case RELOP_GT:
if (value > value2) value = 1; else
value = 0;
break;
case RELOP_GE:
if (value >= value2) value = 1; else
value = 0;
break;
default:
break;
}
}
return value;
}
/**
* Method to get the value of a simple expression.
* @param expr pointer to a simple expression.
* @return value.
*/
private int evalSimpleExpr(SimpleExpr expr)
{
if (expr == null) return 0;
int value = evalTerm(expr.term) * expr.sign;
for (MTerms more = expr.next; more != null; more = more.next)
{
int value2 = evalTerm(more.term);
switch (more.addOperator)
{
case ADDOP_ADD:
value += value2;
break;
case ADDOP_SUBTRACT:
value -= value2;
break;
default:
break;
}
}
return value;
}
/**
* Method to get the value of a term.
* @param term pointer to a term.
* @return value.
*/
private int evalTerm(Term term)
{
if (term == null) return 0;
int value = evalFactor(term.factor);
for (MFactors more = term.next; more != null; more = more.next)
{
int value2 = evalFactor(more.factor);
switch (more.mulOperator)
{
case MULOP_MULTIPLY:
value *= value2;
break;
case MULOP_DIVIDE:
value /= value2;
break;
case MULOP_MOD:
value %= value2;
break;
case MULOP_REM:
value -= (value / value2) * value2;
break;
default:
break;
}
}
return value;
}
/**
* Method to get the value of a factor.
* @param factor pointer to a factor.
* @return value.
*/
private int evalFactor(Factor factor)
{
if (factor == null) return 0;
int value = evalPrimary(factor.primary);
switch (factor.miscOperator)
{
case MISCOP_POWER:
int value2 = evalPrimary(factor.primary2);
while (value2-- != 0)
{
value += value;
}
break;
case MISCOP_ABS:
value = Math.abs(value);
break;
case MISCOP_NOT:
if (value != 0) value = 0; else
value = 1;
break;
default:
break;
}
return value;
}
/**
* Method to evaluate the value of a primary and return.
* @param primary pointer to primary structure.
* @return evaluated value.
*/
private int evalPrimary(Primary primary)
{
if (primary == null) return 0;
int value = 0;
switch (primary.type)
{
case PRIMARY_LITERAL:
Literal literal = (Literal)primary.pointer;
if (literal == null) break;
switch (literal.type)
{
case LITERAL_NUMERIC:
value = ((Integer)literal.pointer).intValue();
break;
case LITERAL_ENUMERATION:
case LITERAL_STRING:
case LITERAL_BIT_STRING:
default:
break;
}
break;
case PRIMARY_NAME:
value = evalName((VName)primary.pointer);
break;
case PRIMARY_EXPRESSION:
value = evalExpression((Expression)primary.pointer);
break;
case PRIMARY_AGGREGATE:
case PRIMARY_CONCATENATION:
case PRIMARY_FUNCTION_CALL:
case PRIMARY_TYPE_CONVERSION:
case PRIMARY_QUALIFIED_EXPR:
default:
break;
}
return value;
}
/**
* Method to evaluate and return the value of a name.
* @param name pointer to name.
* @return value, 0 if no value.
*/
private int evalName(VName name)
{
if (name == null) return 0;
int value = 0;
SymbolTree symbol = searchSymbol(getNameIdent(name), localSymbols);
if (symbol == null)
{
reportErrorMsg(getNameToken(name), "Symbol is undefined");
return value;
}
if (symbol.type == SYMBOL_VARIABLE)
{
if (symbol.pointer instanceof Integer) value = ((Integer)symbol.pointer).intValue();
} else if (symbol.type == SYMBOL_CONSTANT)
{
value = ((Integer)symbol.pointer).intValue();
} else
{
reportErrorMsg(getNameToken(name), "Cannot evaluate value of symbol");
return value;
}
return value;
}
/**
* Method to do semantic analysis of signal declaration.
* @param signal pointer to signal declaration.
* @return pointer to new signals.
*/
private DBSignals semSignalDeclare(SignalDeclare signal)
{
DBSignals signals = null;
if (signal == null) return signals;
// check for valid type
String type = getNameIdent(signal.subType.type);
SymbolTree symbol = searchSymbol(type, localSymbols);
if (symbol == null || symbol.type != SYMBOL_TYPE)
{
reportErrorMsg(getNameToken(signal.subType.type), "Bad type");
}
// check each signal in signal list for uniqueness
for (IdentList sig = signal.names; sig != null; sig = sig.next)
{
if (searchSymbol((String)sig.identifier.pointer, localSymbols) != null)
{
reportErrorMsg(sig.identifier, "Signal previously defined");
} else
{
DBSignals newSignal = new DBSignals();
newSignal.name = (String)sig.identifier.pointer;
if (symbol != null)
{
newSignal.type = (DBLType)symbol.pointer;
} else
{
newSignal.type = null;
}
newSignal.next = signals;
signals = newSignal;
addSymbol(newSignal.name, SYMBOL_SIGNAL, newSignal, localSymbols);
}
}
return signals;
}
/**
* Method to do semantic analysis of an interface declaration.
* @param interfacef pointer to interface parse structure.
* @return resultant database interface.
*/
private DBInterface semInterface(VInterface interfacef)
{
DBInterface dbInter = null;
if (interfacef == null) return dbInter;
if (searchSymbol((String)interfacef.name.pointer, globalSymbols) != null)
{
reportErrorMsg(interfacef.name, "Entity previously defined");
} else
{
dbInter = new DBInterface();
dbInter.name = (String)interfacef.name.pointer;
dbInter.ports = null;
dbInter.flags = 0;
dbInter.bodies = null;
dbInter.symbols = null;
dbInter.next = null;
addSymbol(dbInter.name, SYMBOL_ENTITY, dbInter, globalSymbols);
localSymbols = pushSymbols(localSymbols);
dbInter.ports = semFormalPortList(interfacef.ports);
// remove last symbol tree
SymbolList endSymbol = localSymbols;
while (endSymbol.last.last != null)
{
endSymbol = endSymbol.last;
}
endSymbol.last = null;
dbInter.symbols = localSymbols;
}
return dbInter;
}
/**
* Method to check the semantic of the passed formal port list.
* @param port pointer to start of formal port list.
* @return pointer to database port list.
*/
private DBPortList semFormalPortList(FPortList port)
{
DBPortList dbPorts = null;
DBPortList endPort = null;
for (; port != null; port = port.next)
{
// check the mode of the port
switch (port.mode)
{
case MODE_IN:
case MODE_DOTOUT:
case MODE_OUT:
case MODE_INOUT:
case MODE_LINKAGE:
break;
default:
reportErrorMsg(port.names.identifier, "Unknown port mode");
break;
}
// check the type
String symName = getNameIdent(port.type);
SymbolTree symbol = searchSymbol(symName, localSymbols);
if (symbol == null || symbol.type != SYMBOL_TYPE)
{
reportErrorMsg(getNameToken(port.type), "Unknown port name (" + symName + ")");
}
// check for uniqueness of port names
for (IdentList names = port.names; names != null; names = names.next)
{
if (searchFSymbol((String)names.identifier.pointer, localSymbols) != null)
{
reportErrorMsg(names.identifier, "Duplicate port name in port list");
} else
{
// add to port list
DBPortList newPort = new DBPortList();
newPort.name = (String)names.identifier.pointer;
newPort.mode = port.mode;
if (symbol != null)
{
newPort.type = (DBLType)symbol.pointer;
} else
{
newPort.type = null;
}
newPort.flags = 0;
newPort.next = null;
if (endPort == null)
{
dbPorts = endPort = newPort;
} else
{
endPort.next = newPort;
endPort = newPort;
}
addSymbol(newPort.name, SYMBOL_FPORT, newPort, localSymbols);
}
}
}
return dbPorts;
}
/**
* Method to find a reference to a token given a pointer to a name.
* @param name pointer to name structure.
* @return pointer to token, null if not found.
*/
private TokenList getNameToken(VName name)
{
TokenList token = null;
if (name == null) return token;
switch (name.type)
{
case NAME_SINGLE:
SingleName singl = (SingleName)(name.pointer);
switch (singl.type)
{
case SINGLENAME_SIMPLE:
token = ((SimpleName)singl.pointer).identifier;
break;
case SINGLENAME_SELECTED:
break;
case SINGLENAME_INDEXED:
token = getPrefixToken(((IndexedName)(singl.pointer)).prefix);
break;
case SINGLENAME_SLICE:
default:
break;
}
break;
case NAME_CONCATENATE:
case NAME_ATTRIBUTE:
default:
break;
}
return token;
}
/**
* Method to find a reference to a token given a pointer to a prefix.
* @param prefix pointer to prefix structure.
* @return pointer to token, null if not found.
*/
private TokenList getPrefixToken(Prefix prefix)
{
TokenList token = null;
if (prefix == null) return token;
switch (prefix.type)
{
case PREFIX_NAME:
token = getNameToken((VName)prefix.pointer);
break;
case PREFIX_FUNCTION_CALL:
default:
break;
}
return token;
}
/**
* Method to search the symbol list for a symbol of the passed value.
* Note that all symbol trees of the list are checked, from last to first.
* @param ident global name.
* @param symList pointer to last (current) symbol list.
* @return a pointer to the node, if not found, return null.
*/
private SymbolTree searchSymbol(String ident, SymbolList symList)
{
String lcIdent = TextUtils.canonicString(ident);
for ( ; symList != null; symList = symList.last)
{
SymbolTree node = symList.sym.get(lcIdent);
if (node != null) return node;
}
return null;
}
/**
* Method to search the symbol list for the first symbol of the passed value.
* Note that only the first symbol tree of the list is checked.
* @param ident global name.
* @param symList pointer to last (current) symbol list.
* @return a pointer to the node, if not found, return null.
*/
private SymbolTree searchFSymbol(String ident, SymbolList symList)
{
if (symList != null)
{
SymbolTree node = symList.sym.get(TextUtils.canonicString(ident));
if (node != null) return node;
}
return null;
}
/**
* Method to get a name given a pointer to a name.
* @param name pointer to name structure.
* @return global name.
*/
private String getNameIdent(VName name)
{
String iTable = null;
if (name == null) return iTable;
switch (name.type)
{
case NAME_SINGLE:
SingleName singl = (SingleName)name.pointer;
switch (singl.type)
{
case SINGLENAME_SIMPLE:
iTable = (String)((SimpleName)singl.pointer).identifier.pointer;
break;
case SINGLENAME_INDEXED:
iTable = getPrefixIdent(((IndexedName)(singl.pointer)).prefix);
break;
case SINGLENAME_SELECTED:
case SINGLENAME_SLICE:
default:
break;
}
break;
case NAME_CONCATENATE:
case NAME_ATTRIBUTE:
default:
break;
}
return iTable;
}
/**
* Method to get a name given a pointer to a prefix.
* @param prefix pointer to prefix structure.
* @return string identifier.
*/
private String getPrefixIdent(Prefix prefix)
{
String iTable = null;
if (prefix == null) return iTable;
switch (prefix.type)
{
case PREFIX_NAME:
iTable = getNameIdent((VName)prefix.pointer);
break;
case PREFIX_FUNCTION_CALL:
default:
break;
}
return iTable;
}
/**
* Method to create the default type symbol tree.
* @param symbols pointer to current symbol list.
*/
private void createDefaultType(SymbolList symbols)
{
// type BIT
identTable.add("BIT");
addSymbol("BIT", SYMBOL_TYPE, null, symbols);
// type "std_logic"
identTable.add("std_logic");
addSymbol("std_logic", SYMBOL_TYPE, null, symbols);
}
/**
* Method to add a symbol to the symbol tree at the current symbol list.
* @param value pointer to identifier in namespace.
* @param type type of symbol.
* @param pointer generic pointer to symbol.
* @param symList pointer to symbol list.
* @return pointer to created symbol.
*/
private SymbolTree addSymbol(String value, int type, Object pointer, SymbolList symList)
{
SymbolTree symbol = new SymbolTree();
symbol.value = value;
symbol.type = type;
symbol.pointer = pointer;
symList.sym.put(TextUtils.canonicString(value), symbol);
return symbol;
}
/**
* Method to add a new symbol tree to the symbol list.
* @param oldSymList pointer to old symbol list.
* @return the new symbol list.
*/
private SymbolList pushSymbols(SymbolList oldSymList)
{
SymbolList newSymList = new SymbolList();
newSymList.sym = new HashMap<String,SymbolTree>();
newSymList.last = oldSymList;
return newSymList;
}
/******************************** THE ALS NETLIST GENERATOR ********************************/
private static String [] power =
{
"gate power(p)",
"set p=H@3",
"t: delta=0"
};
private static String [] ground =
{
"gate ground(g)",
"set g=L@3",
"t: delta=0"
};
private static String [] pMOStran =
{
"function PMOStran(g, a1, a2)",
"i: g, a1, a2",
"o: a1, a2",
"t: delta=1e-8"
};
private static String [] pMOStranWeak =
{
"function pMOStranWeak(g, a1, a2)",
"i: g, a1, a2",
"o: a1, a2",
"t: delta=1e-8"
};
private static String [] nMOStran =
{
"function nMOStran(g, a1, a2)",
"i: g, a1, a2",
"o: a1, a2",
"t: delta=1e-8"
};
private static String [] nMOStranWeak =
{
"function nMOStranWeak(g, a1, a2)",
"i: g, a1, a2",
"o: a1, a2",
"t: delta=1e-8"
};
private static String [] inverter =
{
"gate inverter(a,z)",
"t: delta=1.33e-9", /* T3=1.33 */
"i: a=L o: z=H",
"t: delta=1.07e-9", /* T1=1.07 */
"i: a=H o: z=L",
"t: delta=0",
"i: a=X o: z=X",
"load: a=1.0"
};
private static String [] buffer =
{
"gate buffer(in,out)",
"t: delta=0.56e-9", /* T4*Cin=0.56 */
"i: in=H o: out=H",
"t: delta=0.41e-9", /* T2*Cin=0.41 */
"i: in=L o: out=L",
"t: delta=0",
"i: in=X o: out=X"
};
private static String [] xor2 =
{
/* input a,b cap = 0.xx pF, Tphl = T1 + T2*Cin, Tplh = T3 + T4*Cin */
"model xor2(a,b,z)",
"g1: xor2fun(a,b,out)",
"g2: xor2buf(out,z)",
"gate xor2fun(a,b,out)",
"t: delta=1.33e-9", /* T3=1.33 */
"i: a=L b=H o: out=H",
"i: a=H b=L o: out=H",
"t: delta=1.07e-9", /* T1=1.07 */
"i: a=L b=L o: out=L",
"i: a=H b=H o: out=L",
"t: delta=0",
"i: o: out=X",
"load: a=1.0 b=1.0",
"gate xor2buf(in,out)",
"t: delta=0.56e-9", /* T4*Cin=0.56 */
"i: in=H o: out=H",
"t: delta=0.41e-9", /* T2*Cin=0.41 */
"i: in=L o: out=L",
"t: delta=0",
"i: in=X o: out=X"
};
private static String [] JKFF =
{
"model jkff(j, k, clk, pr, clr, q, qbar)",
"n: JKFFLOP(clk, j, k, q, qbar)",
"function JKFFLOP(clk, j, k, q, qbar)",
"i: clk, j, k",
"o: q, qbar",
"t: delta=1e-8"
};
private static String [] DFF =
{
"model dsff(d, clk, pr, q)",
"n: DFFLOP(d, clk, q)",
"function DFFLOP(d, clk, q)",
"i: d, clk",
"o: q",
"t: delta=1e-8"
};
/**
* Method to generate ALS target output for the created parse tree.
* Assume parse tree is semantically correct.
* @param destLib destination library.
* @param behaveLib behaviour library.
* @return a list of strings that has the netlist.
*/
private List<String> genALS(Library destLib, Library behaveLib)
{
Cell basenp = vhdlCell;
// print file header
List<String> netlist = new ArrayList<String>();
netlist.add("#*************************************************");
netlist.add("# ALS Netlist file");
netlist.add("#");
if (User.isIncludeDateAndVersionInOutput())
netlist.add("# File Creation: " + TextUtils.formatDate(new Date()));
netlist.add("#-------------------------------------------------");
netlist.add("");
// determine top level cell
DBInterface topInterface = findTopInterface(theUnits);
if (topInterface == null)
System.out.println("ERROR - Cannot find interface to rename main."); else
{
// clear written flag on all entities
for (DBInterface interfacef = theUnits.interfaces; interfacef != null;
interfacef = interfacef.next) interfacef.flags &= ~ENTITY_WRITTEN;
genALSInterface(topInterface, basenp.getName(), netlist);
}
// print closing line of output file
netlist.add("#********* End of netlist *******************");
// scan unresolved references for reality inside of Electric
int total = 0;
for (UnResList uList = unResolvedList; uList != null; uList = uList.next)
{
total++;
String gate = uList.interfacef;
// first see if this is a reference to a cell in the destination library
if (addNetlist(destLib, gate, netlist))
{
uList.numRef = 0;
total--;
continue;
}
// next see if this is a reference to the behavior library
if (behaveLib != null && behaveLib != destLib)
{
if (addNetlist(behaveLib, gate, netlist))
{
uList.numRef = 0;
total--;
continue;
}
}
// now see if this is a reference to a function primitive
if (gate.equals("PMOStran"))
{
dumpFunction(gate, pMOStran, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("pMOStranWeak"))
{
dumpFunction(gate, pMOStranWeak, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("nMOStran"))
{
dumpFunction(gate, nMOStran, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("nMOStranWeak"))
{
dumpFunction(gate, nMOStranWeak, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("inverter"))
{
dumpFunction(gate, inverter, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("buffer"))
{
dumpFunction(gate, buffer, netlist);
uList.numRef = 0;
total--;
} else if (gate.startsWith("and") && TextUtils.isDigit(gate.charAt(3)))
{
genFunction("and", true, false, TextUtils.atoi(gate.substring(3)), netlist);
uList.numRef = 0;
total--;
} else if (gate.startsWith("nand") && TextUtils.isDigit(gate.charAt(4)))
{
genFunction("and", true, true, TextUtils.atoi(gate.substring(4)), netlist);
uList.numRef = 0;
total--;
} else if (gate.startsWith("or") && TextUtils.isDigit(gate.charAt(2)))
{
genFunction("or", false, false, TextUtils.atoi(gate.substring(2)), netlist);
uList.numRef = 0;
total--;
} else if (gate.startsWith("nor") && TextUtils.isDigit(gate.charAt(3)))
{
genFunction("or", false, true, TextUtils.atoi(gate.substring(3)), netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("xor2"))
{
dumpFunction(gate, xor2, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("power"))
{
dumpFunction(gate, power, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("ground"))
{
dumpFunction(gate, ground, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("jkff"))
{
dumpFunction(gate, JKFF, netlist);
uList.numRef = 0;
total--;
} else if (gate.equals("dsff"))
{
dumpFunction(gate, DFF, netlist);
uList.numRef = 0;
total--;
}
}
// print unresolved reference list if not empty
if (total > 0)
{
System.out.println("***** UNRESOLVED REFERENCES *****");
for (UnResList uList = unResolvedList; uList != null; uList = uList.next)
if (uList.numRef > 0)
System.out.println(uList.interfacef + ", " + uList.numRef + " time(s)");
}
return netlist;
}
/**
* Method to search library "lib" for a netlist that matches "name". If found,
* add it to the current output netlist and return nonzero. If not found, return false.
*/
private boolean addNetlist(Library lib, String name, List<String> netlist)
{
for(Iterator<Cell> it = lib.getCells(); it.hasNext(); )
{
Cell np = it.next();
if (np.getView() != View.NETLISTALS) continue;
StringBuffer infstr = new StringBuffer();
String cellName = np.getName();
for(int i=0; i<cellName.length(); i++)
{
char chr = cellName.charAt(i);
if (TextUtils.isLetterOrDigit(chr)) infstr.append(chr); else
infstr.append("_");
}
String key = infstr.toString();
if (!name.equalsIgnoreCase(key)) continue;
// add it to the netlist
Variable var = np.getVar(Cell.CELL_TEXT_KEY);
if (var == null) continue;
String [] strings = (String [])var.getObject();
netlist.add("");
for(int i=0; i<strings.length; i++) netlist.add(strings[i]);
return true;
}
return false;
}
/*
* inputs cap = 0.xx pF, Tphl = T1 + T2*Cin, Tplh = T3 + T4*Cin
*/
private void genFunction(String name, boolean isand, boolean isneg, int inputs, List<String> netlist)
{
// generate model name
String modelName = "";
if (isneg) modelName = "n";
if (isand) modelName += "and"; else modelName += "or";
modelName += inputs;
netlist.add("");
netlist.add("# Built-in model for " + modelName);
// write header line
StringBuffer infstr = new StringBuffer();
infstr.append("model " + modelName + "(");
for(int i=1; i<=inputs; i++)
{
if (i > 1) infstr.append(",");
infstr.append("a" + i);
}
infstr.append(",z)");
netlist.add(infstr.toString());
// write function line
infstr = new StringBuffer();
infstr.append("g1: " + modelName + "fun(");
for(int i=1; i<=inputs; i++)
{
if (i > 1) infstr.append(",");
infstr.append("a" + i);
}
if (!isneg) infstr.append(",out)"); else
infstr.append(",z)");
netlist.add(infstr.toString());
// write buffer line if not negated
if (!isneg)
netlist.add("g2: " + modelName + "buf(out,z)");
// write function header
infstr = new StringBuffer();
infstr.append("gate " + modelName + "fun(");
for(int i=1; i<=inputs; i++)
{
if (i > 1) infstr.append(",");
infstr.append("a" + i);
}
infstr.append(",z)");
netlist.add(infstr.toString());
netlist.add("t: delta=1.33e-9"); /* T3=1.33 */
for(int i=1; i<=inputs; i++)
{
infstr = new StringBuffer();
infstr.append("i: a" + i);
if (isand) infstr.append("=L o: z=H"); else
infstr.append("=H o: z=L");
netlist.add(infstr.toString());
}
netlist.add("t: delta=1.07e-9"); /* T1=1.07 */
infstr = new StringBuffer();
infstr.append("i:");
for(int i=1; i<=inputs; i++)
{
if (isand) infstr.append(" a" + i + "=H"); else
infstr.append(" a" + i + "=L");
}
if (isand) infstr.append(" o: z=L"); else
infstr.append(" o: z=H");
netlist.add(infstr.toString());
netlist.add("t: delta=0");
netlist.add("i: o: z=X");
infstr = new StringBuffer();
infstr.append("load:");
for(int i=1; i<=inputs; i++)
{
infstr.append(" a" + i + "=1.0");
}
netlist.add(infstr.toString());
// write buffer gate if not negated
if (!isneg)
{
netlist.add("gate " + modelName + "buf(in,out)");
netlist.add("t: delta=0.56e-9"); /* T4*Cin=0.56 */
netlist.add("i: in=H o: out=L");
netlist.add("t: delta=0.41e-9"); /* T2*Cin=0.41 */
netlist.add("i: in=L o: out=H");
netlist.add("t: delta=0");
netlist.add("i: in=X o: out=X");
}
}
private void dumpFunction(String name, String [] model, List<String> netlist)
{
netlist.add("");
netlist.add("# Built-in model for " + name);
for(int i=0; i < model.length; i++) netlist.add(model[i]);
}
/**
* Method to recursively generate the ALS description for the specified model.
* Works by first generating the lowest interface instantiation and working back to the top (i.e. bottom up).
* @param interfacef pointer to interface.
* @param netlist the List of strings to create.
*/
private void genALSInterface(DBInterface interfacef, String name, List<String> netlist)
{
// go through interface's architectural body and call generate interfaces
// for any interface called by an instance which has not been already generated
// check written flag
if ((interfacef.flags & ENTITY_WRITTEN) != 0) return;
// set written flag
interfacef.flags |= ENTITY_WRITTEN;
// check all instants of corresponding architectural body
// and write if non-primitive instances
if (interfacef.bodies != null && interfacef.bodies.statements != null)
{
for (DBInstance inst = interfacef.bodies.statements.instances; inst != null; inst = inst.next)
{
SymbolTree symbol = searchSymbol(inst.compo.name, globalSymbols);
if (symbol == null)
{
if (EXTERNALENTITIES)
{
if (WARNFLAG)
System.out.println("WARNING - interface " + inst.compo.name + " not found, assumed external.");
addToUnresolved(inst.compo.name);
} else
{
System.out.println("ERROR - interface " + inst.compo.name + " not found.");
}
continue;
} else if (symbol.pointer == null)
{
// Should have gate entity
// should be automatically added at end of .net file
} else
{
genALSInterface((DBInterface)symbol.pointer, inst.compo.name, netlist);
}
}
}
// write this interface
int generic = 0;
boolean power_flag = false, ground_flag = false;
StringBuffer infstr = new StringBuffer("model ");
for(int i=0; i<name.length(); i++)
{
char chr = name.charAt(i);
if (TextUtils.isLetterOrDigit(chr)) infstr.append(chr); else
infstr.append('_');
}
infstr.append("(");
// write port list of interface
boolean first = true;
for (DBPortList port = interfacef.ports; port != null; port = port.next)
{
if (port.type == null || port.type.type == DBTYPE_SINGLE)
{
if (!first) infstr.append(", ");
infstr.append(port.name);
first = false;
} else
{
DBIndexRange iRange = (DBIndexRange)port.type.pointer;
DBDiscreteRange dRange = iRange.dRange;
if (dRange.start > dRange.end)
{
for (int i = dRange.start; i >= dRange.end; i--)
{
if (!first) infstr.append(", ");
infstr.append(port.name + "[" + i + "]");
first = false;
}
} else
{
for (int i = dRange.start; i <= dRange.end; i++)
{
if (!first) infstr.append(", ");
infstr.append(port.name + "[" + i + "]");
first = false;
}
}
}
}
infstr.append(")");
netlist.add(infstr.toString());
// write all instances
if (interfacef.bodies != null && interfacef.bodies.statements != null)
{
for (DBInstance inst = interfacef.bodies.statements.instances; inst != null; inst = inst.next)
{
infstr = new StringBuffer();
infstr.append(inst.name);
infstr.append(": ");
infstr.append(inst.compo.name);
infstr.append("(");
// print instance port list
first = true;
for (DBAPortList aPort = inst.ports; aPort != null; aPort = aPort.next)
{
if (aPort.name != null)
{
if (aPort.name.type == DBNAME_CONCATENATED)
{
// concatenated name
for (DBNameList cat = (DBNameList)aPort.name.pointer; cat != null; cat = cat.next)
{
String ident = cat.name.name;
if (ident.equalsIgnoreCase("power")) power_flag = true; else
if (ident.equalsIgnoreCase("ground")) ground_flag = true;
first = genAPort(infstr, first, cat.name);
}
} else
{
String ident = aPort.name.name;
if (ident.equalsIgnoreCase("power")) power_flag = true; else
if (ident.equalsIgnoreCase("ground")) ground_flag = true;
first = genAPort(infstr, first, aPort.name);
}
} else
{
// check if formal port is of array type
if (aPort.port.type != null && aPort.port.type.type == DBTYPE_ARRAY)
{
DBIndexRange iRange = (DBIndexRange)aPort.port.type.pointer;
DBDiscreteRange dRange = iRange.dRange;
if (dRange.start > dRange.end)
{
for (int i = dRange.start; i >= dRange.end; i--)
{
if (!first) infstr.append(", ");
infstr.append("n" + (generic++));
first = false;
}
} else
{
for (int i = dRange.start; i <= dRange.end; i++)
{
if (!first) infstr.append(", ");
infstr.append("n" + (generic++));
first = false;
}
}
} else
{
if (!first) infstr.append(", ");
infstr.append("n" + (generic++));
first = false;
}
}
}
infstr.append(")");
netlist.add(infstr.toString());
}
}
// check for power and ground flags
if (power_flag) netlist.add("set power = H@3");
else if (ground_flag) netlist.add("set ground = L@3");
netlist.add("");
}
/**
* Method to add the actual port for a single name to the infinite string.
*/
private boolean genAPort(StringBuffer infstr, boolean first, DBName name)
{
if (name.type == DBNAME_INDEXED)
{
if (!first) infstr.append(", ");
infstr.append(name.name + ((DBExprList)(name.pointer)).value);
first = false;
} else
{
if (name.dbType != null && name.dbType.type == DBTYPE_ARRAY)
{
DBIndexRange iRange = (DBIndexRange)name.dbType.pointer;
DBDiscreteRange dRange = iRange.dRange;
if (dRange.start > dRange.end)
{
for (int i = dRange.start; i >= dRange.end; i--)
{
if (!first) infstr.append(", ");
infstr.append(name.name + "[" + i + "]");
first = false;
}
} else
{
for (int i = dRange.start; i <= dRange.end; i++)
{
if (!first) infstr.append(", ");
infstr.append(name.name + "[" + i + "]");
first = false;
}
}
} else
{
if (!first) infstr.append(", ");
infstr.append(name.name);
first = false;
}
}
return first;
}
/******************************** THE QUISC NETLIST GENERATOR ********************************/
private static final int QNODE_SNAME = 0;
private static final int QNODE_INAME = 1;
private static final int QNODE_EXPORT = 0x0001;
private static final int QNODE_POWER = 0x0002;
private static final int QNODE_GROUND = 0x0004;
private static class QNODE
{
String name;
int nameType; /* type of name - simple or indexed */
int start, end; /* range if array */
int size; /* size of array if indexed */
QPORT []table; /* array of pointers if indexed */
int flags; /* export flag */
int mode; /* port mode if exported */
QPORT ports; /* list of ports */
QNODE next; /* next in list of nodes */
};
private static class QPORT
{
String instName; /* name of instance */
String portName; /* name of port */
QPORT next; /* next in port list */
};
/**
* Method to generate QUISC target output for the created parse tree.
* Assume parse tree is semantically correct.
* @param destLib destination library.
* @return a list of strings that has the netlist.
*/
private List<String> genQuisc(Library destLib)
{
List<String> netlist = new ArrayList<String>();
// print file header
netlist.add("!*************************************************");
netlist.add("! QUISC Command file");
netlist.add("!");
if (User.isIncludeDateAndVersionInOutput())
netlist.add("! File Creation: " + TextUtils.formatDate(new Date()));
netlist.add("!-------------------------------------------------");
netlist.add("");
// determine top level cell
DBInterface topInterface = findTopInterface(theUnits);
if (topInterface == null)
System.out.println("ERROR - Cannot find top interface."); else
{
// clear written flag on all entities
for (DBInterface interfacef = theUnits.interfaces; interfacef != null;
interfacef = interfacef.next) interfacef.flags &= ~ENTITY_WRITTEN;
genQuiscInterface(topInterface, netlist);
}
// print closing line of output file
netlist.add("!********* End of command file *******************");
// scan unresolved references for reality inside of Electric
Library cellLib = Library.findLibrary(SilComp.SCLIBNAME);
int total = 0;
for (UnResList uList = unResolvedList; uList != null; uList = uList.next)
{
// see if this is a reference to a cell in the destination library
boolean found = false;
for(Iterator<Cell> it = destLib.getCells(); it.hasNext(); )
{
Cell np = it.next();
StringBuffer sb = new StringBuffer();
String name = np.getName();
for(int i=0; i<name.length(); i++)
{
char chr = name.charAt(i);
if (Character.isLetterOrDigit(chr)) sb.append(chr); else
sb.append('_');
}
if (uList.interfacef.equalsIgnoreCase(sb.toString())) { found = true; break; }
}
if (!found && cellLib != null)
{
for(Iterator<Cell> it = cellLib.getCells(); it.hasNext(); )
{
Cell np = it.next();
StringBuffer sb = new StringBuffer();
String name = np.getName();
for(int i=0; i<name.length(); i++)
{
char chr = name.charAt(i);
if (Character.isLetterOrDigit(chr)) sb.append(chr); else
sb.append('_');
}
if (uList.interfacef.equalsIgnoreCase(sb.toString())) { found = true; break; }
}
}
if (found)
{
uList.numRef = 0;
continue;
}
total++;
}
// print unresolved reference list
if (total > 0)
{
System.out.println("***** UNRESOLVED REFERENCES *****");
for (UnResList uList = unResolvedList; uList != null; uList = uList.next)
if (uList.numRef > 0)
System.out.println(uList.interfacef + ", " + uList.numRef + " time(s)");
}
return netlist;
}
/**
* Method to find the top interface in the database.
* The top interface is defined as the interface is called by no other architectural bodies.
* @param units pointer to database design units.
* @return pointer to top interface.
*/
private DBInterface findTopInterface(DBUnits units)
{
/* clear flags of all interfaces in database */
for (DBInterface interfacef = units.interfaces; interfacef != null; interfacef = interfacef.next)
interfacef.flags &= ~TOP_ENTITY_FLAG;
/* go through the list of bodies and flag any interfaces */
for (DBBody body = units.bodies; body != null; body = body.next)
{
/* go through component list */
if (body.declare == null) continue;
for (DBComponents compo = body.declare.components; compo != null; compo = compo.next)
{
SymbolTree symbol = searchSymbol(compo.name, globalSymbols);
if (symbol != null && symbol.pointer != null)
{
((DBInterface)(symbol.pointer)).flags |= TOP_ENTITY_FLAG;
}
}
}
/* find interface with the flag bit not set */
DBInterface interfacef;
for (interfacef = units.interfaces; interfacef != null; interfacef = interfacef.next)
{
if ((interfacef.flags & TOP_ENTITY_FLAG) == 0) break;
}
return interfacef;
}
/**
* Method to recursively generate the QUISC description for the specified model.
* Works by first generating the lowest interface instantiation and working back to the top (i.e. bottom up).
* @param interfacef pointer to interface.
* @param netlist the List of strings to create.
*/
private void genQuiscInterface(DBInterface interfacef, List<String> netlist)
{
// go through interface's architectural body and call generate interface
// for any interface called by an instance which has not been already
// generated
// check written flag
if ((interfacef.flags & ENTITY_WRITTEN) != 0) return;
// set written flag
interfacef.flags |= ENTITY_WRITTEN;
// check all instants of corresponding architectural body
// and write if non-primitive interfaces
if (interfacef.bodies != null && interfacef.bodies.statements != null)
{
for (DBInstance inst = interfacef.bodies.statements.instances; inst != null; inst = inst.next)
{
SymbolTree symbol = searchSymbol(inst.compo.name, globalSymbols);
if (symbol == null || symbol.pointer == null)
{
if (EXTERNALENTITIES)
{
if (WARNFLAG)
System.out.println("WARNING - interface " + inst.compo.name + " not found, assumed external.");
// add to unresolved list
addToUnresolved(inst.compo.name);
} else
System.out.println("ERROR - interface " + inst.compo.name + "not found.");
continue;
}
genQuiscInterface((DBInterface)symbol.pointer, netlist);
}
}
// write this entity
netlist.add("create cell " + interfacef.name);
// write out instances as components
if (interfacef.bodies != null && interfacef.bodies.statements != null)
{
for (DBInstance inst = interfacef.bodies.statements.instances; inst != null; inst = inst.next)
netlist.add("create instance " + inst.name + " " + inst.compo.name);
}
// create export list
QNODE qNodes = null;
QNODE lastNode = null;
for (DBPortList fPort = interfacef.ports; fPort != null; fPort = fPort.next)
{
if (fPort.type == null || fPort.type.type == DBTYPE_SINGLE)
{
QNODE newQNode = new QNODE();
newQNode.name = fPort.name;
newQNode.nameType = QNODE_SNAME;
newQNode.size = 0;
newQNode.start = 0;
newQNode.end = 0;
newQNode.table = null;
newQNode.flags = QNODE_EXPORT;
newQNode.mode = fPort.mode;
newQNode.ports = null;
newQNode.next = null;
if (lastNode == null) qNodes = lastNode = newQNode; else
{
lastNode.next = newQNode;
lastNode = newQNode;
}
} else
{
QNODE newQNode = new QNODE();
newQNode.name = fPort.name;
newQNode.nameType = QNODE_INAME;
newQNode.flags = QNODE_EXPORT;
newQNode.mode = fPort.mode;
newQNode.ports = null;
newQNode.next = null;
if (lastNode == null) qNodes = lastNode = newQNode; else
{
lastNode.next = newQNode;
lastNode = newQNode;
}
DBIndexRange iRange = (DBIndexRange)fPort.type.pointer;
DBDiscreteRange dRange = iRange.dRange;
newQNode.start = dRange.start;
newQNode.end = dRange.end;
int size = 1;
if (dRange.start > dRange.end)
{
size = dRange.start - dRange.end + 1;
} else if (dRange.start < dRange.end)
{
size = dRange.end - dRange.start + 1;
}
newQNode.size = size;
newQNode.table = new QPORT[size];
for (int i = 0; i < size; i++) newQNode.table[i] = null;
}
}
// add local signals
if (interfacef.bodies != null && interfacef.bodies.declare != null)
{
for (DBSignals signal = interfacef.bodies.declare.bodySignals; signal != null; signal = signal.next)
{
if (signal.type == null || signal.type.type == DBTYPE_SINGLE)
{
QNODE newQNode = new QNODE();
newQNode.name = signal.name;
newQNode.nameType = QNODE_SNAME;
newQNode.size = 0;
newQNode.start = 0;
newQNode.end = 0;
newQNode.table = null;
if (signal.name.equalsIgnoreCase("power"))
{
newQNode.flags = QNODE_POWER;
} else if (signal.name.equalsIgnoreCase("ground"))
{
newQNode.flags = QNODE_GROUND;
} else
{
newQNode.flags = 0;
}
newQNode.mode = 0;
newQNode.ports = null;
newQNode.next = null;
if (lastNode == null)
{
qNodes = lastNode = newQNode;
} else
{
lastNode.next = newQNode;
lastNode = newQNode;
}
} else
{
QNODE newQNode = new QNODE();
newQNode.name = signal.name;
newQNode.nameType = QNODE_INAME;
newQNode.flags = 0;
newQNode.mode = 0;
newQNode.ports = null;
newQNode.next = null;
if (lastNode == null)
{
qNodes = lastNode = newQNode;
} else
{
lastNode.next = newQNode;
lastNode = newQNode;
}
DBIndexRange iRange = (DBIndexRange)signal.type.pointer;
DBDiscreteRange dRange = iRange.dRange;
newQNode.start = dRange.start;
newQNode.end = dRange.end;
int size = 1;
if (dRange.start > dRange.end)
{
size = dRange.start - dRange.end + 1;
} else if (dRange.start < dRange.end)
{
size = dRange.end - dRange.start + 1;
}
newQNode.size = size;
newQNode.table = new QPORT[size];
for (int i = 0; i < size; i++) newQNode.table[i] = null;
}
}
}
// write out connects
if (interfacef.bodies != null && interfacef.bodies.statements != null)
{
for (DBInstance inst = interfacef.bodies.statements.instances; inst != null; inst = inst.next)
{
// check all instance ports for connections
for (DBAPortList aPort = inst.ports; aPort != null; aPort = aPort.next)
{
if (aPort.name == null) continue;
// get names of all members of actual port
switch (aPort.name.type)
{
case DBNAME_IDENTIFIER:
addIdentAPort(aPort.name, aPort.port, 0, inst, qNodes);
break;
case DBNAME_INDEXED:
addIndexedAPort(aPort.name, aPort.port, 0, inst, qNodes);
break;
case DBNAME_CONCATENATED:
int offset = 0;
for (DBNameList cat = (DBNameList)aPort.name.pointer; cat != null; cat = cat.next)
{
if (cat.name.type == DBNAME_IDENTIFIER)
{
addIdentAPort(cat.name, aPort.port, offset, inst, qNodes);
} else
{
addIndexedAPort(cat.name, aPort.port, offset, inst, qNodes);
}
offset += querySize(cat.name);
}
break;
default:
System.out.println("ERROR - unknown name type on actual port.");
break;
}
}
}
}
// print out connections
for (QNODE newQNode = qNodes; newQNode != null; newQNode = newQNode.next)
{
if (newQNode.nameType == QNODE_SNAME)
{
QPORT qPort = newQNode.ports;
if (qPort != null)
{
for (QPORT qPort2 = qPort.next; qPort2 != null; qPort2 = qPort2.next)
{
netlist.add("connect " + qPort.instName + " " + qPort.portName + " " + qPort2.instName + " " + qPort2.portName);
}
if ((newQNode.flags & QNODE_POWER) != 0)
{
netlist.add("connect " + qPort.instName + " " + qPort.portName + " power");
}
if ((newQNode.flags & QNODE_GROUND) != 0)
{
netlist.add("connect " + qPort.instName + " " + qPort.portName + " ground");
}
}
} else
{
for (int i = 0; i < newQNode.size; i++)
{
QPORT qPort = newQNode.table[i];
if (qPort != null)
{
for (QPORT qPort2 = qPort.next; qPort2 != null; qPort2 = qPort2.next)
{
netlist.add("connect " + qPort.instName + " " + qPort.portName + " " + qPort2.instName + " " + qPort2.portName);
}
}
}
}
}
// print out exports
for (QNODE newQNode = qNodes; newQNode != null; newQNode = newQNode.next)
{
if ((newQNode.flags & QNODE_EXPORT) != 0)
{
if (newQNode.nameType == QNODE_SNAME)
{
QPORT qPort = newQNode.ports;
if (qPort != null)
{
String inOut = "";
switch (newQNode.mode)
{
case DBMODE_IN: inOut = " input"; break;
case DBMODE_OUT: inOut = " output"; break;
}
netlist.add("export " + qPort.instName + " " + qPort.portName + " " + newQNode.name + inOut);
} else
{
System.out.println("ERROR - no export for " + newQNode.name);
}
} else
{
for (int i = 0; i < newQNode.size; i++)
{
int indexC = 0;
if (newQNode.start > newQNode.end)
{
indexC = newQNode.start - i;
} else
{
indexC = newQNode.start + i;
}
QPORT qPort = newQNode.table[i];
if (qPort != null)
{
String inOut = "";
switch (newQNode.mode)
{
case DBMODE_IN: inOut = " input"; break;
case DBMODE_OUT: inOut = " output"; break;
}
netlist.add("export " + qPort.instName + " " + qPort.portName + " " + newQNode.name + "[" + indexC + "]" + inOut);
} else
{
System.out.println("ERROR - no export for " + newQNode.name + "[" + indexC + "]");
}
}
}
}
}
// extract entity
netlist.add("extract");
// print out non-exported node name assignments
for (QNODE newQNode = qNodes; newQNode != null; newQNode = newQNode.next)
{
if ((newQNode.flags & QNODE_EXPORT) == 0)
{
if (newQNode.nameType == QNODE_SNAME)
{
QPORT qPort = newQNode.ports;
if (qPort != null)
{
netlist.add("set node-name " + qPort.instName + " " + qPort.portName + " " + newQNode.name);
}
} else
{
for (int i = 0; i < newQNode.size; i++)
{
int indexC = 0;
if (newQNode.start > newQNode.end)
{
indexC = newQNode.start - i;
} else
{
indexC = newQNode.start + i;
}
QPORT qPort = newQNode.table[i];
if (qPort != null)
{
netlist.add("set node-name " + qPort.instName + " " + qPort.portName + " " + newQNode.name + "[" + indexC + "]");
}
}
}
}
}
netlist.add("");
}
/**
* Method to get the size (in number of elements) of the passed name.
* @param name pointer to the name.
* @return number of elements, 0 default.
*/
private int querySize(DBName name)
{
int size = 0;
if (name != null)
{
switch (name.type)
{
case DBNAME_IDENTIFIER:
if (name.dbType != null)
{
switch (name.dbType.type)
{
case DBTYPE_SINGLE:
size = 1;
break;
case DBTYPE_ARRAY:
DBIndexRange iRange = (DBIndexRange)name.dbType.pointer;
if (iRange != null)
{
DBDiscreteRange dRange = iRange.dRange;
if (dRange != null)
{
if (dRange.start > dRange.end)
{
size = dRange.start - dRange.end;
} else
{
size = dRange.end - dRange.start;
}
size++;
}
}
break;
default:
break;
}
} else
{
size = 1;
}
break;
case DBNAME_INDEXED:
size = 1;
break;
default:
break;
}
}
return size;
}
/**
* Method to add the actual port of identifier name type to the node list.
* @param name pointer to name.
* @param port pointer to port on component.
* @param offset offset in bits if of array type.
* @param inst pointer to instance of component.
* @param qNodes address of start of node list.
*/
private void addIdentAPort(DBName name, DBPortList port, int offset, DBInstance inst, QNODE qNodes)
{
if (name.dbType != null && name.dbType.type == DBTYPE_ARRAY)
{
DBIndexRange iRange = (DBIndexRange)name.dbType.pointer;
if (iRange != null)
{
DBDiscreteRange dRange = iRange.dRange;
if (dRange != null)
{
int delta = 0;
if (dRange.start > dRange.end)
{
delta = -1;
} else if (dRange.start < dRange.end)
{
delta = 1;
}
int i = dRange.start - delta;
int offset2 = 0;
do
{
i += delta;
QPORT newPort = createQPort(inst.name, port, offset + offset2);
addQPortToQNode(newPort, name.name, QNODE_INAME, i, qNodes);
offset2++;
} while (i != dRange.end);
}
}
} else
{
QPORT newPort = createQPort(inst.name, port, offset);
addQPortToQNode(newPort, name.name, QNODE_SNAME, 0, qNodes);
}
}
/**
* Method to add the actual port of indexed name type to the node list.
* @param name pointer to name.
* @param port pointer to port on component.
* @param offset offset in bits if of array type.
* @param inst pointer to instance of component.
* @param qNodes address of start of node list.
*/
private void addIndexedAPort(DBName name, DBPortList port, int offset, DBInstance inst, QNODE qNodes)
{
QPORT newPort = createQPort(inst.name, port, offset);
int indexC = ((DBExprList)name.pointer).value;
addQPortToQNode(newPort, name.name, QNODE_INAME, indexC, qNodes);
}
/**
* Method to create a qport for the indicated port.
* @param iname name of instance.
* @param port pointer to port on component.
* @param offset offset if array.
* @return address of created QPORT.
*/
private QPORT createQPort(String iname, DBPortList port, int offset)
{
QPORT newPort = new QPORT();
newPort.instName = iname;
newPort.next = null;
if (port.type != null && port.type.type == DBTYPE_ARRAY)
{
newPort.portName = port.name + "[" + offset + "]";
} else
{
newPort.portName = port.name;
}
return newPort;
}
/**
* Method to add the port to the node list.
* @param port port to add.
* @param ident name of node to add to.
* @param type if simple or indexed.
* @param indexC index if arrayed.
* @param qNodes address of pointer to start of list.
*/
private void addQPortToQNode(QPORT port, String ident, int type, int indexC, QNODE qNodes)
{
for (QNODE node = qNodes; node != null; node = node.next)
{
if (node.name.equalsIgnoreCase(ident))
{
if (node.nameType == type)
{
if (type == QNODE_SNAME)
{
port.next = node.ports;
node.ports = port;
return;
}
int tindex;
if (node.start > node.end)
{
tindex = node.start - indexC;
} else
{
tindex = indexC - node.start;
}
if (tindex >= 0 && tindex < node.size)
{
port.next = node.table[tindex];
node.table[tindex] = port;
return;
}
}
}
}
System.out.println("WARNING node " + ident + " not found");
}
private void addToUnresolved(String name)
{
for (UnResList uList = unResolvedList; uList != null; uList = uList.next)
{
if (uList.interfacef.equals(name)) { uList.numRef++; return; }
}
UnResList uList = new UnResList();
uList.interfacef = name;
uList.numRef = 1;
uList.next = unResolvedList;
unResolvedList = uList;
}
}