mirror of
https://github.com/verilator/verilator.git
synced 2025-04-15 17:16:55 +00:00
3842 lines
166 KiB
C++
3842 lines
166 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: AstNode sub-types representing other constructs
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
// Version 2.0.
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// This files contains all 'AstNode' sub-types that relate to other constructs
|
|
// not covered by the more specific V3AstNode*.h files.
|
|
//
|
|
//*************************************************************************
|
|
|
|
#ifndef VERILATOR_V3ASTNODES_H_
|
|
#define VERILATOR_V3ASTNODES_H_
|
|
|
|
#ifndef VERILATOR_V3AST_H_
|
|
#error "Use V3Ast.h as the include"
|
|
#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h
|
|
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
|
|
#endif
|
|
|
|
// === Abstract base node types (AstNode*) =====================================
|
|
|
|
class AstNodeBlock VL_NOT_FINAL : public AstNode {
|
|
// A Begin/fork block
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
// Parents: statement
|
|
string m_name; // Name of block
|
|
bool m_unnamed; // Originally unnamed (name change does not affect this)
|
|
protected:
|
|
AstNodeBlock(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
|
: AstNode{t, fl}
|
|
, m_name{name} {
|
|
addStmtsp(stmtsp);
|
|
m_unnamed = (name == "");
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeBlock;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
|
void name(const string& name) override { m_name = name; }
|
|
bool unnamed() const { return m_unnamed; }
|
|
bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); }
|
|
};
|
|
class AstNodeFTask VL_NOT_FINAL : public AstNode {
|
|
// Output variable in functions, nullptr in tasks
|
|
// @astgen op1 := fvarp : Optional[AstNode]
|
|
// Class/package scope
|
|
// @astgen op2 := classOrPackagep : Optional[AstNode]
|
|
// Statements/Ports/Vars
|
|
// @astgen op3 := stmtsp : List[AstNode]
|
|
// Scope name
|
|
// @astgen op4 := scopeNamep : Optional[AstScopeName]
|
|
string m_name; // Name of task
|
|
string m_cname; // Name of task if DPI import
|
|
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
|
bool m_taskPublic : 1; // Public task
|
|
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
|
bool m_classMethod : 1; // Class method
|
|
bool m_externProto : 1; // Extern prototype
|
|
bool m_externDef : 1; // Extern definition
|
|
bool m_prototype : 1; // Just a prototype
|
|
bool m_dpiExport : 1; // DPI exported
|
|
bool m_dpiImport : 1; // DPI imported
|
|
bool m_dpiContext : 1; // DPI import context
|
|
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
|
|
bool m_dpiTask : 1; // DPI import task (vs. void function)
|
|
bool m_isConstructor : 1; // Class constructor
|
|
bool m_isHideLocal : 1; // Verilog local
|
|
bool m_isHideProtected : 1; // Verilog protected
|
|
bool m_dpiPure : 1; // DPI import pure (vs. virtual pure)
|
|
bool m_pureVirtual : 1; // Pure virtual
|
|
bool m_recursive : 1; // Recursive or part of recursion
|
|
bool m_static : 1; // Static method in class
|
|
bool m_underGenerate : 1; // Under generate (for warning)
|
|
bool m_virtual : 1; // Virtual method in class
|
|
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
|
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
|
VLifetime m_lifetime; // Default lifetime of local vars
|
|
VIsCached m_purity; // Pure state
|
|
|
|
protected:
|
|
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
|
: AstNode{t, fl}
|
|
, m_name{name}
|
|
, m_taskPublic{false}
|
|
, m_attrIsolateAssign{false}
|
|
, m_classMethod{false}
|
|
, m_externProto{false}
|
|
, m_externDef{false}
|
|
, m_prototype{false}
|
|
, m_dpiExport{false}
|
|
, m_dpiImport{false}
|
|
, m_dpiContext{false}
|
|
, m_dpiOpenChild{false}
|
|
, m_dpiTask{false}
|
|
, m_isConstructor{false}
|
|
, m_isHideLocal{false}
|
|
, m_isHideProtected{false}
|
|
, m_dpiPure{false}
|
|
, m_pureVirtual{false}
|
|
, m_recursive{false}
|
|
, m_static{false}
|
|
, m_underGenerate{false}
|
|
, m_virtual{false}
|
|
, m_needProcess{false} {
|
|
addStmtsp(stmtsp);
|
|
cname(name); // Might be overridden by dpi import/export
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeFTask;
|
|
virtual AstNodeFTask* cloneType(const string& name) = 0;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
|
bool maybePointedTo() const override { return true; }
|
|
bool isGateOptimizable() const override {
|
|
return !((m_dpiExport || m_dpiImport) && !m_dpiPure);
|
|
}
|
|
// {AstFunc only} op1 = Range output variable
|
|
void name(const string& name) override { m_name = name; }
|
|
string cname() const { return m_cname; }
|
|
void cname(const string& cname) { m_cname = cname; }
|
|
bool isFunction() const { return fvarp() != nullptr; }
|
|
// MORE ACCESSORS
|
|
void dpiOpenParentInc() { ++m_dpiOpenParent; }
|
|
void dpiOpenParentClear() { m_dpiOpenParent = 0; }
|
|
uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
|
|
bool taskPublic() const { return m_taskPublic; }
|
|
void taskPublic(bool flag) { m_taskPublic = flag; }
|
|
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
|
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
|
bool classMethod() const { return m_classMethod; }
|
|
void classMethod(bool flag) { m_classMethod = flag; }
|
|
bool isExternProto() const { return m_externProto; }
|
|
void isExternProto(bool flag) { m_externProto = flag; }
|
|
bool isExternDef() const { return m_externDef; }
|
|
void isExternDef(bool flag) { m_externDef = flag; }
|
|
bool prototype() const { return m_prototype; }
|
|
void prototype(bool flag) { m_prototype = flag; }
|
|
bool dpiExport() const { return m_dpiExport; }
|
|
void dpiExport(bool flag) { m_dpiExport = flag; }
|
|
bool dpiImport() const { return m_dpiImport; }
|
|
void dpiImport(bool flag) { m_dpiImport = flag; }
|
|
bool dpiContext() const { return m_dpiContext; }
|
|
void dpiContext(bool flag) { m_dpiContext = flag; }
|
|
bool dpiOpenChild() const { return m_dpiOpenChild; }
|
|
void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; }
|
|
bool dpiTask() const { return m_dpiTask; }
|
|
void dpiTask(bool flag) { m_dpiTask = flag; }
|
|
bool isConstructor() const { return m_isConstructor; }
|
|
void isConstructor(bool flag) { m_isConstructor = flag; }
|
|
bool isHideLocal() const { return m_isHideLocal; }
|
|
void isHideLocal(bool flag) { m_isHideLocal = flag; }
|
|
bool isHideProtected() const { return m_isHideProtected; }
|
|
void isHideProtected(bool flag) { m_isHideProtected = flag; }
|
|
bool dpiPure() const { return m_dpiPure; }
|
|
void dpiPure(bool flag) { m_dpiPure = flag; }
|
|
bool pureVirtual() const { return m_pureVirtual; }
|
|
void pureVirtual(bool flag) { m_pureVirtual = flag; }
|
|
bool recursive() const { return m_recursive; }
|
|
void recursive(bool flag) { m_recursive = flag; }
|
|
bool isStatic() const { return m_static; }
|
|
void isStatic(bool flag) { m_static = flag; }
|
|
bool underGenerate() const { return m_underGenerate; }
|
|
void underGenerate(bool flag) { m_underGenerate = flag; }
|
|
bool isVirtual() const { return m_virtual; }
|
|
void isVirtual(bool flag) { m_virtual = flag; }
|
|
bool needProcess() const { return m_needProcess; }
|
|
void setNeedProcess() { m_needProcess = true; }
|
|
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
|
|
VBaseOverride baseOverride() const { return m_baseOverride; }
|
|
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
|
VLifetime lifetime() const { return m_lifetime; }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
bool isPure() override;
|
|
const char* broken() const override;
|
|
void propagateAttrFrom(const AstNodeFTask* fromp) {
|
|
// Creating a wrapper with e.g. cloneType(); preserve some attributes
|
|
classMethod(fromp->classMethod());
|
|
isHideLocal(fromp->isHideLocal());
|
|
isHideProtected(fromp->isHideProtected());
|
|
isVirtual(fromp->isVirtual());
|
|
lifetime(fromp->lifetime());
|
|
underGenerate(fromp->underGenerate());
|
|
}
|
|
|
|
private:
|
|
bool getPurityRecurse() const;
|
|
};
|
|
class AstNodeFile VL_NOT_FINAL : public AstNode {
|
|
// Emitted Output file
|
|
// Parents: NETLIST
|
|
// @astgen op1 := tblockp : Optional[AstTextBlock]
|
|
string m_name; ///< Filename
|
|
public:
|
|
AstNodeFile(VNType t, FileLine* fl, const string& name)
|
|
: AstNode{t, fl}
|
|
, m_name{name} {}
|
|
ASTGEN_MEMBERS_AstNodeFile;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstNodeModule VL_NOT_FINAL : public AstNode {
|
|
// A module, package, program or interface declaration;
|
|
// something that can live directly under the TOP,
|
|
// excluding $unit package stuff
|
|
// @astgen op1 := inlinesp : List[AstNode]
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
// @astgen op3 := activesp : List[AstActive]
|
|
string m_name; // Name of the module
|
|
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
|
|
string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module.
|
|
// Used for user messages only.
|
|
int m_level = 0; // 1=top module, 2=cell off top module, ...
|
|
VLifetime m_lifetime; // Lifetime
|
|
VTimescale m_timeunit; // Global time unit
|
|
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
|
|
|
|
bool m_modPublic : 1; // Module has public references
|
|
bool m_modTrace : 1; // Tracing this module
|
|
bool m_inLibrary : 1; // From a library, no error if not used, never top level
|
|
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
|
|
bool m_hasGParam : 1; // Has global parameter (for link)
|
|
bool m_hasParameterList : 1; // Has #() for parameter declaration
|
|
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
|
|
bool m_internal : 1; // Internally created
|
|
bool m_recursive : 1; // Recursive module
|
|
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
|
|
protected:
|
|
AstNodeModule(VNType t, FileLine* fl, const string& name)
|
|
: AstNode{t, fl}
|
|
, m_name{name}
|
|
, m_origName{name}
|
|
, m_modPublic{false}
|
|
, m_modTrace{false}
|
|
, m_inLibrary{false}
|
|
, m_dead{false}
|
|
, m_hasGParam{false}
|
|
, m_hasParameterList{false}
|
|
, m_hierBlock{false}
|
|
, m_internal{false}
|
|
, m_recursive{false}
|
|
, m_recursiveClone{false} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeModule;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool maybePointedTo() const override { return true; }
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
virtual bool timescaleMatters() const = 0;
|
|
// ACCESSORS
|
|
void name(const string& name) override { m_name = name; }
|
|
string origName() const override { return m_origName; }
|
|
string someInstanceName() const VL_MT_SAFE { return m_someInstanceName; }
|
|
void someInstanceName(const string& name) { m_someInstanceName = name; }
|
|
bool inLibrary() const { return m_inLibrary; }
|
|
void inLibrary(bool flag) { m_inLibrary = flag; }
|
|
void level(int level) { m_level = level; }
|
|
int level() const VL_MT_SAFE { return m_level; }
|
|
bool isTop() const VL_MT_SAFE { return level() == 1; }
|
|
bool modPublic() const { return m_modPublic; }
|
|
void modPublic(bool flag) { m_modPublic = flag; }
|
|
bool modTrace() const { return m_modTrace; }
|
|
void modTrace(bool flag) { m_modTrace = flag; }
|
|
bool dead() const { return m_dead; }
|
|
void dead(bool flag) { m_dead = flag; }
|
|
bool hasGParam() const { return m_hasGParam; }
|
|
void hasGParam(bool flag) { m_hasGParam = flag; }
|
|
bool hasParameterList() const { return m_hasParameterList; }
|
|
void hasParameterList(bool flag) { m_hasParameterList = flag; }
|
|
bool hierBlock() const { return m_hierBlock; }
|
|
void hierBlock(bool flag) { m_hierBlock = flag; }
|
|
bool internal() const { return m_internal; }
|
|
void internal(bool flag) { m_internal = flag; }
|
|
bool recursive() const { return m_recursive; }
|
|
void recursive(bool flag) { m_recursive = flag; }
|
|
void recursiveClone(bool flag) { m_recursiveClone = flag; }
|
|
bool recursiveClone() const { return m_recursiveClone; }
|
|
VLifetime lifetime() const { return m_lifetime; }
|
|
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
|
|
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
|
|
};
|
|
class AstNodeProcedure VL_NOT_FINAL : public AstNode {
|
|
// IEEE procedure: initial, final, always
|
|
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
|
|
bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc.
|
|
bool m_needProcess : 1; // Uses VlProcess
|
|
protected:
|
|
AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp)
|
|
: AstNode{t, fl} {
|
|
m_needProcess = false;
|
|
m_suspendable = false;
|
|
addStmtsp(stmtsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeProcedure;
|
|
// METHODS
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
|
|
bool isSuspendable() const { return m_suspendable; }
|
|
void setSuspendable() { m_suspendable = true; }
|
|
bool needProcess() const { return m_needProcess; }
|
|
void setNeedProcess() { m_needProcess = true; }
|
|
};
|
|
class AstNodeRange VL_NOT_FINAL : public AstNode {
|
|
// A range, sized or unsized
|
|
protected:
|
|
AstNodeRange(VNType t, FileLine* fl)
|
|
: AstNode{t, fl} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeRange;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
};
|
|
class AstNodeStmt VL_NOT_FINAL : public AstNode {
|
|
// Procedural statement
|
|
protected:
|
|
AstNodeStmt(VNType t, FileLine* fl)
|
|
: AstNode{t, fl} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeStmt;
|
|
// METHODS
|
|
void addNextStmt(AstNode* newp,
|
|
AstNode* belowp) override; // Stop statement searchback here
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
};
|
|
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
|
|
// Iteration is in order, and we want rhsp to be visited first (which is the execution order)
|
|
// @astgen op1 := rhsp : AstNodeExpr
|
|
// @astgen op2 := lhsp : AstNodeExpr
|
|
// @astgen op3 := timingControlp : Optional[AstNode]
|
|
protected:
|
|
AstNodeAssign(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
|
AstNode* timingControlp = nullptr)
|
|
: AstNodeStmt{t, fl} {
|
|
this->rhsp(rhsp);
|
|
this->lhsp(lhsp);
|
|
this->timingControlp(timingControlp);
|
|
dtypeFrom(lhsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeAssign;
|
|
// Clone single node, just get same type back.
|
|
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
|
bool hasDType() const override { return true; }
|
|
virtual bool cleanRhs() const { return true; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
bool same(const AstNode*) const override { return true; }
|
|
string verilogKwd() const override { return "="; }
|
|
bool isTimingControl() const override { return timingControlp(); }
|
|
virtual bool brokeLhsMustBeLvalue() const = 0;
|
|
};
|
|
class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
|
|
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
|
|
// @astgen op2 := itemsp : List[AstCaseItem]
|
|
// @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's
|
|
protected:
|
|
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
|
: AstNodeStmt{t, fl} {
|
|
this->exprp(exprp);
|
|
this->addItemsp(itemsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeCase;
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
};
|
|
class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt {
|
|
// Cover or Assert
|
|
// Parents: {statement list}
|
|
// @astgen op1 := propp : AstNode
|
|
// @astgen op2 := sentreep : Optional[AstSenTree]
|
|
// op3 used by some sub-types only
|
|
// @astgen op4 := passsp: List[AstNode] // Statements when propp is passing/truthly
|
|
string m_name; // Name to report
|
|
const VAssertType m_type; // Assertion/cover type
|
|
const VAssertDirectiveType m_directive; // Assertion directive type
|
|
|
|
public:
|
|
AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, VAssertType type,
|
|
VAssertDirectiveType directive, const string& name = "")
|
|
: AstNodeStmt{t, fl}
|
|
, m_name{name}
|
|
, m_type{type}
|
|
, m_directive{directive} {
|
|
this->propp(propp);
|
|
this->addPasssp(passsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
|
bool same(const AstNode* samep) const override { return samep->name() == name(); }
|
|
void name(const string& name) override { m_name = name; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
VAssertType type() const { return m_type; }
|
|
VAssertDirectiveType directive() const { return m_directive; }
|
|
bool immediate() const {
|
|
return this->type().containsAny(VAssertType::SIMPLE_IMMEDIATE
|
|
| VAssertType::OBSERVED_DEFERRED_IMMEDIATE
|
|
| VAssertType::FINAL_DEFERRED_IMMEDIATE)
|
|
|| this->type() == VAssertType::INTERNAL;
|
|
}
|
|
};
|
|
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
|
|
// @astgen op1 := initsp : List[AstNode]
|
|
// @astgen op2 := condp : AstNodeExpr
|
|
// @astgen op3 := incsp : List[AstNode]
|
|
// @astgen op4 := stmtsp : List[AstNode]
|
|
protected:
|
|
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
|
|
AstNode* stmtsp)
|
|
: AstNodeStmt{t, fl} {
|
|
this->addInitsp(initsp);
|
|
this->condp(condp);
|
|
this->addIncsp(incsp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeFor;
|
|
bool isGateOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt {
|
|
// @astgen op1 := arrayp : AstNode
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
|
|
: AstNodeStmt(t, fl) {
|
|
this->arrayp(arrayp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstNodeForeach;
|
|
bool isGateOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
};
|
|
class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
|
|
// @astgen op1 := condp : AstNodeExpr
|
|
// @astgen op2 := thensp : List[AstNode]
|
|
// @astgen op3 := elsesp : List[AstNode]
|
|
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
|
|
bool m_isBoundsCheck; // True if this if node is for assertion/bounds checking
|
|
protected:
|
|
AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
|
|
: AstNodeStmt{t, fl} {
|
|
this->condp(condp);
|
|
this->addThensp(thensp);
|
|
this->addElsesp(elsesp);
|
|
isBoundsCheck(false);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeIf;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isGateDedupable() const override { return true; }
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void branchPred(VBranchPred flag) { m_branchPred = flag; }
|
|
VBranchPred branchPred() const { return m_branchPred; }
|
|
void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; }
|
|
bool isBoundsCheck() const { return m_isBoundsCheck; }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override {
|
|
return n == thensp() || n == elsesp();
|
|
}
|
|
};
|
|
class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt {
|
|
// @astgen op1 := filenamep : AstNodeExpr
|
|
// @astgen op2 := memp : AstNodeExpr
|
|
// @astgen op3 := lsbp : Optional[AstNodeExpr]
|
|
// @astgen op4 := msbp : Optional[AstNodeExpr]
|
|
|
|
const bool m_isHex; // readmemh, not readmemb
|
|
public:
|
|
AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNodeExpr* filenamep,
|
|
AstNodeExpr* memp, AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
|
: AstNodeStmt{t, fl}
|
|
, m_isHex(hex) {
|
|
this->filenamep(filenamep);
|
|
this->memp(memp);
|
|
this->lsbp(lsbp);
|
|
this->msbp(msbp);
|
|
}
|
|
ASTGEN_MEMBERS_AstNodeReadWriteMem;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* samep) const override {
|
|
return isHex() == VN_DBG_AS(samep, NodeReadWriteMem)->isHex();
|
|
}
|
|
bool isHex() const { return m_isHex; }
|
|
virtual const char* cFuncPrefixp() const = 0;
|
|
};
|
|
class AstNodeText VL_NOT_FINAL : public AstNode {
|
|
string m_text;
|
|
// METHODS
|
|
string shortText() const;
|
|
|
|
protected:
|
|
// Node that puts text into the output stream
|
|
AstNodeText(VNType t, FileLine* fl, const string& text)
|
|
: AstNode{t, fl}
|
|
, m_text{text} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeText;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
bool same(const AstNode* samep) const override {
|
|
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
|
|
return text() == asamep->text();
|
|
}
|
|
const string& text() const VL_MT_SAFE { return m_text; }
|
|
void text(const string& value) { m_text = value; }
|
|
};
|
|
class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText {
|
|
bool m_tracking; // When emit, it's ok to parse the string to do indentation
|
|
public:
|
|
AstNodeSimpleText(VNType t, FileLine* fl, const string& textp, bool tracking = false)
|
|
: AstNodeText{t, fl, textp}
|
|
, m_tracking{tracking} {}
|
|
ASTGEN_MEMBERS_AstNodeSimpleText;
|
|
void tracking(bool flag) { m_tracking = flag; }
|
|
bool tracking() const { return m_tracking; }
|
|
};
|
|
|
|
// === Concrete node types =====================================================
|
|
|
|
// === AstNode ===
|
|
class AstActive final : public AstNode {
|
|
// Block of code with sensitivity activation
|
|
// Parents: MODULE | CFUNC
|
|
// @astgen op1 := sensesStorep : Optional[AstSenTree] // Moved into m_sensesp in V3Active
|
|
// @astgen op2 := stmtsp : List[AstNode] // Logic
|
|
//
|
|
// @astgen ptr := m_sensesp : Optional[AstSenTree] // Sensitivity list for this process
|
|
string m_name;
|
|
|
|
public:
|
|
AstActive(FileLine* fl, const string& name, AstSenTree* sensesp)
|
|
: ASTGEN_SUPER_Active(fl)
|
|
, m_name{name}
|
|
, m_sensesp{sensesp} {
|
|
UASSERT(sensesp, "Sensesp required arg");
|
|
}
|
|
ASTGEN_MEMBERS_AstActive;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
// Statements are broken into pieces, as some must come before others.
|
|
void sensesp(AstSenTree* nodep) { m_sensesp = nodep; }
|
|
AstSenTree* sensesp() const { return m_sensesp; }
|
|
// METHODS
|
|
inline bool hasClocked() const;
|
|
inline bool hasCombo() const;
|
|
};
|
|
class AstBind final : public AstNode {
|
|
// Parents: MODULE
|
|
// Children: CELL
|
|
// @astgen op1 := cellsp : List[AstNode]
|
|
string m_name; // Binding to name
|
|
public:
|
|
AstBind(FileLine* fl, const string& name, AstNode* cellsp)
|
|
: ASTGEN_SUPER_Bind(fl)
|
|
, m_name{name} {
|
|
UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound");
|
|
this->addCellsp(cellsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstBind;
|
|
// ACCESSORS
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name
|
|
void name(const string& name) override { m_name = name; }
|
|
};
|
|
class AstCFunc final : public AstNode {
|
|
// C++ function
|
|
// Parents: MODULE/SCOPE
|
|
// If adding node accessors, see below emptyBody
|
|
// @astgen op1 := argsp : List[AstNode]
|
|
// @astgen op2 := initsp : List[AstNode]
|
|
// @astgen op3 := stmtsp : List[AstNode]
|
|
// @astgen op4 := finalsp : List[AstNode]
|
|
//
|
|
// @astgen ptr := m_scopep : Optional[AstScope] // Scope that function is under
|
|
string m_name;
|
|
string m_cname; // C name, for dpiExports
|
|
string m_rtnType; // void, bool, or other return type
|
|
string m_argTypes; // Argument types
|
|
string m_ifdef; // #ifdef symbol around this function
|
|
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
|
|
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
|
|
bool m_isTrace : 1; // Function is related to tracing
|
|
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
|
|
bool m_declPrivate : 1; // Declare it private
|
|
bool m_slow : 1; // Slow routine, called once or just at init time
|
|
bool m_funcPublic : 1; // From user public task/function
|
|
bool m_isConstructor : 1; // Is C class constructor
|
|
bool m_isDestructor : 1; // Is C class destructor
|
|
bool m_isMethod : 1; // Is inside a class definition
|
|
bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function
|
|
// with an explicitly passed 'self' pointer as the first argument
|
|
bool m_isInline : 1; // Inline function
|
|
bool m_isVirtual : 1; // Virtual function
|
|
bool m_entryPoint : 1; // User may call into this top level function
|
|
bool m_dpiPure : 1; // Pure DPI function
|
|
bool m_dpiContext : 1; // Declared as 'context' DPI import/export function
|
|
bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user)
|
|
bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup)
|
|
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
|
|
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
|
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
|
bool m_recursive : 1; // Recursive or part of recursion
|
|
public:
|
|
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
|
: ASTGEN_SUPER_CFunc(fl) {
|
|
m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed
|
|
m_scopep = scopep;
|
|
m_name = name;
|
|
m_rtnType = rtnType;
|
|
m_isStatic = false;
|
|
m_isTrace = false;
|
|
m_dontCombine = false;
|
|
m_declPrivate = false;
|
|
m_slow = false;
|
|
m_funcPublic = false;
|
|
m_isConstructor = false;
|
|
m_isDestructor = false;
|
|
m_isMethod = true;
|
|
m_isLoose = false;
|
|
m_isInline = false;
|
|
m_isVirtual = false;
|
|
m_needProcess = false;
|
|
m_entryPoint = false;
|
|
m_dpiPure = false;
|
|
m_dpiContext = false;
|
|
m_dpiExportDispatcher = false;
|
|
m_dpiExportImpl = false;
|
|
m_dpiImportPrototype = false;
|
|
m_dpiImportWrapper = false;
|
|
m_recursive = false;
|
|
}
|
|
ASTGEN_MEMBERS_AstCFunc;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool maybePointedTo() const override { return true; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
bool same(const AstNode* samep) const override {
|
|
const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc);
|
|
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
|
|
&& (argTypes() == asamep->argTypes()) && isLoose() == asamep->isLoose()
|
|
&& (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name()));
|
|
}
|
|
//
|
|
void name(const string& name) override { m_name = name; }
|
|
int instrCount() const override {
|
|
return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0;
|
|
}
|
|
VBoolOrUnknown isConst() const { return m_isConst; }
|
|
void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); }
|
|
void isConst(VBoolOrUnknown flag) { m_isConst = flag; }
|
|
bool isStatic() const { return m_isStatic; }
|
|
void isStatic(bool flag) { m_isStatic = flag; }
|
|
bool isTrace() const VL_MT_SAFE { return m_isTrace; }
|
|
void isTrace(bool flag) { m_isTrace = flag; }
|
|
void cname(const string& name) { m_cname = name; }
|
|
string cname() const { return m_cname; }
|
|
AstScope* scopep() const { return m_scopep; }
|
|
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
|
string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); }
|
|
void rtnType(const string& rtnType) { m_rtnType = rtnType; }
|
|
bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); }
|
|
void dontCombine(bool flag) { m_dontCombine = flag; }
|
|
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
|
|
bool declPrivate() const { return m_declPrivate; }
|
|
void declPrivate(bool flag) { m_declPrivate = flag; }
|
|
bool slow() const VL_MT_SAFE { return m_slow; }
|
|
void slow(bool flag) { m_slow = flag; }
|
|
bool funcPublic() const { return m_funcPublic; }
|
|
void funcPublic(bool flag) { m_funcPublic = flag; }
|
|
void argTypes(const string& str) { m_argTypes = str; }
|
|
string argTypes() const { return m_argTypes; }
|
|
void ifdef(const string& str) { m_ifdef = str; }
|
|
string ifdef() const { return m_ifdef; }
|
|
bool isConstructor() const { return m_isConstructor; }
|
|
void isConstructor(bool flag) { m_isConstructor = flag; }
|
|
bool isDestructor() const { return m_isDestructor; }
|
|
void isDestructor(bool flag) { m_isDestructor = flag; }
|
|
bool isMethod() const { return m_isMethod; }
|
|
void isMethod(bool flag) { m_isMethod = flag; }
|
|
bool isLoose() const { return m_isLoose; }
|
|
void isLoose(bool flag) { m_isLoose = flag; }
|
|
bool isProperMethod() const { return isMethod() && !isLoose(); }
|
|
bool isInline() const { return m_isInline; }
|
|
void isInline(bool flag) { m_isInline = flag; }
|
|
bool isVirtual() const { return m_isVirtual; }
|
|
void isVirtual(bool flag) { m_isVirtual = flag; }
|
|
bool needProcess() const { return m_needProcess; }
|
|
void setNeedProcess() { m_needProcess = true; }
|
|
bool entryPoint() const { return m_entryPoint; }
|
|
void entryPoint(bool flag) { m_entryPoint = flag; }
|
|
bool dpiPure() const { return m_dpiPure; }
|
|
void dpiPure(bool flag) { m_dpiPure = flag; }
|
|
bool dpiContext() const { return m_dpiContext; }
|
|
void dpiContext(bool flag) { m_dpiContext = flag; }
|
|
bool dpiExportDispatcher() const VL_MT_SAFE { return m_dpiExportDispatcher; }
|
|
void dpiExportDispatcher(bool flag) { m_dpiExportDispatcher = flag; }
|
|
bool dpiExportImpl() const { return m_dpiExportImpl; }
|
|
void dpiExportImpl(bool flag) { m_dpiExportImpl = flag; }
|
|
bool dpiImportPrototype() const VL_MT_SAFE { return m_dpiImportPrototype; }
|
|
void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; }
|
|
bool dpiImportWrapper() const { return m_dpiImportWrapper; }
|
|
void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; }
|
|
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
|
void recursive(bool flag) { m_recursive = flag; }
|
|
bool recursive() const { return m_recursive; }
|
|
// Special methods
|
|
bool emptyBody() const {
|
|
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
|
|
&& finalsp() == nullptr;
|
|
}
|
|
};
|
|
class AstCLocalScope final : public AstNode {
|
|
// Pack statements into an unnamed scope when generating C++
|
|
// @astgen op1 := stmtsp : List[AstNode]
|
|
public:
|
|
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_CLocalScope(fl) {
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCLocalScope;
|
|
};
|
|
class AstCUse final : public AstNode {
|
|
// C++ use of a class or #include; indicates need of forward declaration
|
|
// Parents: NODEMODULE
|
|
const string m_name;
|
|
const VUseType m_useType; // What sort of use this is
|
|
|
|
public:
|
|
AstCUse(FileLine* fl, VUseType useType, const string& name)
|
|
: ASTGEN_SUPER_CUse(fl)
|
|
, m_name{name}
|
|
, m_useType{useType} {}
|
|
ASTGEN_MEMBERS_AstCUse;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
VUseType useType() const { return m_useType; }
|
|
};
|
|
class AstCaseItem final : public AstNode {
|
|
// Single item of a case statement
|
|
// @astgen op1 := condsp : List[AstNodeExpr]
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_CaseItem(fl) {
|
|
this->addCondsp(condsp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCaseItem;
|
|
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
|
bool isDefault() const { return condsp() == nullptr; }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
};
|
|
class AstCell final : public AstNode {
|
|
// A instantiation cell or interface call (don't know which until link)
|
|
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
|
|
// @astgen op2 := paramsp : List[AstPin] // List of parameter assignments
|
|
// @astgen op3 := rangep : Optional[AstRange] // Range for arrayed instances
|
|
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references, for tracing
|
|
//
|
|
// @astgen ptr := m_modp : Optional[AstNodeModule] // [AfterLink] Pointer to module instanced
|
|
FileLine* m_modNameFileline; // Where module the cell instances token was
|
|
string m_name; // Cell name
|
|
string m_origName; // Original name before dot addition
|
|
string m_modName; // Module the cell instances
|
|
bool m_hasIfaceVar : 1; // True if a Var has been created for this cell
|
|
bool m_hasNoParens : 1; // Instantiation has no parenthesis
|
|
bool m_recursive : 1; // Self-recursive module
|
|
bool m_trace : 1; // Trace this cell
|
|
public:
|
|
AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName,
|
|
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
|
|
: ASTGEN_SUPER_Cell(fl)
|
|
, m_modNameFileline{mfl}
|
|
, m_name{instName}
|
|
, m_origName{instName}
|
|
, m_modName{modName}
|
|
, m_hasIfaceVar{false}
|
|
, m_hasNoParens{false}
|
|
, m_recursive{false}
|
|
, m_trace{true} {
|
|
this->addPinsp(pinsp);
|
|
this->addParamsp(paramsp);
|
|
this->rangep(rangep);
|
|
}
|
|
ASTGEN_MEMBERS_AstCell;
|
|
// No cloneRelink, we presume cloneee's want the same module linkages
|
|
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool maybePointedTo() const override { return true; }
|
|
// ACCESSORS
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
|
void name(const string& name) override { m_name = name; }
|
|
string origName() const override { return m_origName; } // * = Original name
|
|
void origName(const string& name) { m_origName = name; }
|
|
string modName() const { return m_modName; } // * = Instance name
|
|
void modName(const string& name) { m_modName = name; }
|
|
FileLine* modNameFileline() const { return m_modNameFileline; }
|
|
AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated
|
|
void modp(AstNodeModule* nodep) { m_modp = nodep; }
|
|
bool hasIfaceVar() const { return m_hasIfaceVar; }
|
|
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
|
|
bool hasNoParens() const { return m_hasNoParens; }
|
|
void hasNoParens(bool flag) { m_hasNoParens = flag; }
|
|
void trace(bool flag) { m_trace = flag; }
|
|
bool isTrace() const { return m_trace; }
|
|
void recursive(bool flag) { m_recursive = flag; }
|
|
bool recursive() const { return m_recursive; }
|
|
};
|
|
class AstCellInline final : public AstNode {
|
|
// A instantiation cell that was removed by inlining
|
|
// For communication between V3Inline and V3LinkDot,
|
|
// except for VPI runs where it exists until the end.
|
|
// It is augmented with the scope in V3Scope for VPI.
|
|
// Children: When 2 levels inlined, other CellInline under this
|
|
// @astgen ptr := m_scopep : Optional[AstScope] // The scope that the cell is inlined into
|
|
string m_name; // Cell name, possibly {a}__DOT__{b}...
|
|
const string m_origModName; // Original name of module, ignoring name() changes, for LinkDot
|
|
VTimescale m_timeunit; // Parent module time unit
|
|
public:
|
|
AstCellInline(FileLine* fl, const string& name, const string& origModName,
|
|
const VTimescale& timeunit)
|
|
: ASTGEN_SUPER_CellInline(fl)
|
|
, m_name{name}
|
|
, m_origModName{origModName}
|
|
, m_timeunit{timeunit} {}
|
|
ASTGEN_MEMBERS_AstCellInline;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
// ACCESSORS
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
|
bool maybePointedTo() const override { return true; }
|
|
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
|
void name(const string& name) override { m_name = name; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
|
|
class AstCellInlineScope final : public AstNode {
|
|
// A particular scoped usage of a Cell Inline
|
|
// Parents: Scope
|
|
// Children: none
|
|
//
|
|
// @astgen ptr := m_scopep : Optional[AstScope] // Scope variable is underneath
|
|
// @astgen ptr := m_cellp : Optional[AstCellInline] // Cell ref
|
|
const string m_origModName; // Original name of module, ignoring name() changes, for LinkDot
|
|
public:
|
|
AstCellInlineScope(FileLine* fl, AstScope* scopep, AstCellInline* cellp)
|
|
: ASTGEN_SUPER_CellInlineScope(fl)
|
|
, m_scopep{scopep}
|
|
, m_cellp{cellp} {
|
|
UASSERT_OBJ(scopep, fl, "Scope must be non-null");
|
|
UASSERT_OBJ(cellp, fl, "CellInline must be non-null");
|
|
}
|
|
ASTGEN_MEMBERS_AstCellInlineScope;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
// ACCESSORS
|
|
string name() const override VL_MT_STABLE { return m_cellp->name(); }
|
|
bool maybePointedTo() const override { return true; }
|
|
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
|
string origModName() const {
|
|
return m_cellp->origModName();
|
|
} // * = modp()->origName() before inlining
|
|
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
|
};
|
|
|
|
class AstClassExtends final : public AstNode {
|
|
// class extends class name, or class implements class name
|
|
// Children: List of AstParseRef for packages/classes
|
|
// during early parse, then moves to dtype
|
|
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
|
// @astgen op2 := classOrPkgsp : Optional[AstNode]
|
|
const bool m_isImplements = false; // class implements
|
|
bool m_parameterized = false; // has parameters in its statement
|
|
|
|
public:
|
|
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements)
|
|
: ASTGEN_SUPER_ClassExtends(fl)
|
|
, m_isImplements{isImplements} {
|
|
this->classOrPkgsp(classOrPkgsp); // Only for parser
|
|
}
|
|
ASTGEN_MEMBERS_AstClassExtends;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool hasDType() const override { return true; }
|
|
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
|
|
// Class being extended (after link and instantiation if needed)
|
|
AstClass* classOrNullp() const;
|
|
AstClass* classp() const; // Like above, but throws error if nulll
|
|
bool isImplements() const { return m_isImplements; }
|
|
void parameterized(bool flag) { m_parameterized = flag; }
|
|
bool parameterized() const { return m_parameterized; }
|
|
};
|
|
class AstClocking final : public AstNode {
|
|
// Parents: MODULE
|
|
// Children: SENITEM, CLOCKING ITEMs, VARs
|
|
// @astgen op1 := sensesp : AstSenItem
|
|
// @astgen op2 := itemsp : List[AstClockingItem]
|
|
// @astgen op3 := eventp : Optional[AstVar]
|
|
std::string m_name; // Clocking block name
|
|
const bool m_isDefault = false; // True if default clocking
|
|
const bool m_isGlobal = false; // True if global clocking
|
|
|
|
public:
|
|
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
|
|
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
|
|
: ASTGEN_SUPER_Clocking(fl)
|
|
, m_isDefault{isDefault}
|
|
, m_isGlobal{isGlobal} {
|
|
m_name = name;
|
|
this->sensesp(sensesp);
|
|
addItemsp(itemsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstClocking;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
std::string name() const override VL_MT_STABLE { return m_name; }
|
|
bool isDefault() const { return m_isDefault; }
|
|
bool isGlobal() const { return m_isGlobal; }
|
|
};
|
|
class AstClockingItem final : public AstNode {
|
|
// Parents: CLOCKING
|
|
// Children: EXPRs, ASSIGNs, VARs
|
|
// @astgen op1 := skewp : Optional[AstNodeExpr]
|
|
// @astgen op2 := exprp : Optional[AstNodeExpr]
|
|
// @astgen op3 := assignp : Optional[AstAssign]
|
|
// @astgen op4 := varp : Optional[AstVar]
|
|
// @astgen ptr := m_outputp : Optional[AstClockingItem]
|
|
VDirection m_direction;
|
|
|
|
public:
|
|
AstClockingItem(FileLine* fl, VDirection direction, AstNodeExpr* skewp, AstNode* clockingDeclp)
|
|
: ASTGEN_SUPER_ClockingItem(fl) {
|
|
m_direction = direction;
|
|
this->skewp(skewp);
|
|
if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) {
|
|
this->assignp(clkAssignp);
|
|
} else {
|
|
exprp(VN_AS(clockingDeclp, NodeExpr));
|
|
}
|
|
}
|
|
ASTGEN_MEMBERS_AstClockingItem;
|
|
VDirection direction() const { return m_direction; }
|
|
AstClockingItem* outputp() const { return m_outputp; }
|
|
void outputp(AstClockingItem* outputp) { m_outputp = outputp; }
|
|
bool maybePointedTo() const override { return true; }
|
|
};
|
|
class AstConstPool final : public AstNode {
|
|
// Container for const static data
|
|
// @astgen op1 := modulep : AstModule // m_modp below TODO: fix this mess
|
|
//
|
|
// @astgen ptr := m_modp : AstModule // The Module holding the Scope below ...
|
|
// @astgen ptr := m_scopep : AstScope // Scope holding the constant variables
|
|
std::unordered_multimap<uint32_t, AstVarScope*> m_tables; // Constant tables (unpacked arrays)
|
|
std::unordered_multimap<uint32_t, AstVarScope*> m_consts; // Constant tables (scalars)
|
|
|
|
AstVarScope* createNewEntry(const string& name, AstNodeExpr* initp);
|
|
|
|
public:
|
|
explicit AstConstPool(FileLine* fl);
|
|
ASTGEN_MEMBERS_AstConstPool;
|
|
bool maybePointedTo() const override { return true; }
|
|
void cloneRelink() override { V3ERROR_NA; }
|
|
AstModule* modp() const { return m_modp; }
|
|
|
|
// Find a table (unpacked array) within the constant pool which is initialized with the
|
|
// given value, or create one if one does not already exists. The returned VarScope *might*
|
|
// have a different dtype than the given initp->dtypep(), including a different element type,
|
|
// but it will always have the same size and element width. In contexts where this matters,
|
|
// the caller must handle the dtype difference as appropriate.
|
|
AstVarScope* findTable(AstInitArray* initp);
|
|
// Find a constant within the constant pool which is initialized with the given value, or
|
|
// create one if one does not already exists. If 'mergeDType' is true, then the returned
|
|
// VarScope *might* have a different type than the given initp->dtypep(). In contexts where
|
|
// this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is
|
|
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
|
|
AstVarScope* findConst(AstConst* initp, bool mergeDType);
|
|
};
|
|
class AstConstraint final : public AstNode {
|
|
// Constraint
|
|
// @astgen op1 := itemsp : List[AstNode]
|
|
string m_name; // Name of constraint
|
|
bool m_isStatic = false; // static constraint
|
|
public:
|
|
AstConstraint(FileLine* fl, const string& name, AstNode* itemsp)
|
|
: ASTGEN_SUPER_Constraint(fl)
|
|
, m_name(name) {
|
|
this->addItemsp(itemsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConstraint;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void isStatic(bool flag) { m_isStatic = flag; }
|
|
bool isStatic() const { return m_isStatic; }
|
|
};
|
|
class AstConstraintBefore final : public AstNode {
|
|
// Constraint solve before item
|
|
// @astgen op1 := lhssp : List[AstNodeExpr]
|
|
// @astgen op2 := rhssp : List[AstNodeExpr]
|
|
public:
|
|
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
|
|
: ASTGEN_SUPER_ConstraintBefore(fl) {
|
|
this->addLhssp(lhssp);
|
|
this->addRhssp(rhssp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConstraintBefore;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstDefParam final : public AstNode {
|
|
// A defparam assignment
|
|
// Parents: MODULE
|
|
// @astgen op1 := rhsp : AstNodeExpr
|
|
string m_name; // Name of variable getting set
|
|
string m_path; // Dotted cellname to set parameter of
|
|
public:
|
|
AstDefParam(FileLine* fl, const string& path, const string& name, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_DefParam(fl)
|
|
, m_name{name}
|
|
, m_path{path} {
|
|
this->rhsp(rhsp);
|
|
}
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
|
ASTGEN_MEMBERS_AstDefParam;
|
|
bool same(const AstNode*) const override { return true; }
|
|
string path() const { return m_path; }
|
|
};
|
|
class AstDpiExport final : public AstNode {
|
|
// We could put an AstNodeFTaskRef instead of the verilog function name,
|
|
// however we're not *calling* it, so that seems somehow wrong.
|
|
// (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef)
|
|
string m_name; // Name of function
|
|
string m_cname; // Name of function on c side
|
|
public:
|
|
AstDpiExport(FileLine* fl, const string& vname, const string& cname)
|
|
: ASTGEN_SUPER_DpiExport(fl)
|
|
, m_name{vname}
|
|
, m_cname{cname} {}
|
|
ASTGEN_MEMBERS_AstDpiExport;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
void name(const string& name) override { m_name = name; }
|
|
string cname() const { return m_cname; }
|
|
void cname(const string& cname) { m_cname = cname; }
|
|
};
|
|
class AstElabDisplay final : public AstNode {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := fmtp : List[AstSFormatF]
|
|
VDisplayType m_displayType;
|
|
|
|
public:
|
|
inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* exprsp);
|
|
ASTGEN_MEMBERS_AstElabDisplay;
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!fmtp());
|
|
return nullptr;
|
|
}
|
|
string verilogKwd() const override { return "$"s + string{displayType().ascii()}; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* samep) const override {
|
|
return displayType() == VN_DBG_AS(samep, ElabDisplay)->displayType();
|
|
}
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
VDisplayType displayType() const { return m_displayType; }
|
|
void displayType(VDisplayType type) { m_displayType = type; }
|
|
};
|
|
class AstEmpty final : public AstNode {
|
|
// Represents something missing, e.g. a missing argument in FOREACH
|
|
public:
|
|
explicit AstEmpty(FileLine* fl)
|
|
: ASTGEN_SUPER_Empty(fl) {}
|
|
ASTGEN_MEMBERS_AstEmpty;
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstExecGraph final : public AstNode {
|
|
// For parallel execution, this node contains a dependency graph. Each
|
|
// vertex in the graph is an ExecMTask, which contains a body for the
|
|
// mtask (an AstMTaskBody), which contains sequentially executed statements.
|
|
//
|
|
// The AstMTaskBody nodes are also children of this node, so we can visit
|
|
// them without traversing the graph.
|
|
//
|
|
// @astgen op1 := mTaskBodiesp : List[AstMTaskBody]
|
|
// In later phases, the statements that start the parallel execution
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
V3Graph* const m_depGraphp; // contains ExecMTask vertices
|
|
const string m_name; // Name of this AstExecGraph (for uniqueness at code generation)
|
|
|
|
public:
|
|
explicit AstExecGraph(FileLine* fl, const string& name) VL_MT_DISABLED;
|
|
~AstExecGraph() override;
|
|
ASTGEN_MEMBERS_AstExecGraph;
|
|
void cloneRelink() override { V3ERROR_NA; }
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!m_depGraphp);
|
|
return nullptr;
|
|
}
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
V3Graph* depGraphp() { return m_depGraphp; }
|
|
const V3Graph* depGraphp() const { return m_depGraphp; }
|
|
};
|
|
class AstImplicit final : public AstNode {
|
|
// Create implicit wires and do nothing else, for gates that are ignored
|
|
// Parents: MODULE
|
|
// @astgen op1 := exprsp : List[AstNode]
|
|
public:
|
|
AstImplicit(FileLine* fl, AstNode* exprsp)
|
|
: ASTGEN_SUPER_Implicit(fl) {
|
|
this->addExprsp(exprsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstImplicit;
|
|
};
|
|
class AstInitItem final : public AstNode {
|
|
// Container for a item in an init array
|
|
// This container is present so that the value underneath may get replaced with a new nodep
|
|
// and the upper AstInitArray's map will remain correct (pointing to this InitItem)
|
|
// @astgen op1 := valuep : AstNodeExpr
|
|
public:
|
|
// Parents: INITARRAY
|
|
AstInitItem(FileLine* fl, AstNodeExpr* valuep)
|
|
: ASTGEN_SUPER_InitItem(fl) {
|
|
this->valuep(valuep);
|
|
}
|
|
ASTGEN_MEMBERS_AstInitItem;
|
|
bool maybePointedTo() const override { return true; }
|
|
bool hasDType() const override { return false; } // See valuep()'s dtype instead
|
|
};
|
|
class AstIntfRef final : public AstNode {
|
|
// An interface reference
|
|
string m_name; // Name of the reference
|
|
public:
|
|
AstIntfRef(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_IntfRef(fl)
|
|
, m_name{name} {}
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
ASTGEN_MEMBERS_AstIntfRef;
|
|
};
|
|
class AstMTaskBody final : public AstNode {
|
|
// Hold statements for each MTask
|
|
// @astgen op1 := stmtsp : List[AstNode]
|
|
ExecMTask* m_execMTaskp = nullptr;
|
|
|
|
public:
|
|
explicit AstMTaskBody(FileLine* fl)
|
|
: ASTGEN_SUPER_MTaskBody(fl) {}
|
|
ASTGEN_MEMBERS_AstMTaskBody;
|
|
void cloneRelink() override { V3ERROR_NA; }
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!m_execMTaskp);
|
|
return nullptr;
|
|
}
|
|
void addStmtsFirstp(AstNode* nodep) {
|
|
if (stmtsp()) {
|
|
stmtsp()->addHereThisAsNext(nodep);
|
|
} else {
|
|
addStmtsp(nodep);
|
|
}
|
|
}
|
|
ExecMTask* execMTaskp() const { return m_execMTaskp; }
|
|
void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
};
|
|
class AstModport final : public AstNode {
|
|
// A modport in an interface
|
|
// @astgen op1 := varsp : List[AstNode]
|
|
string m_name; // Name of the modport
|
|
public:
|
|
AstModport(FileLine* fl, const string& name, AstNode* varsp)
|
|
: ASTGEN_SUPER_Modport(fl)
|
|
, m_name{name} {
|
|
this->addVarsp(varsp);
|
|
}
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool maybePointedTo() const override { return true; }
|
|
ASTGEN_MEMBERS_AstModport;
|
|
};
|
|
class AstModportFTaskRef final : public AstNode {
|
|
// An import/export referenced under a modport
|
|
// The storage for the function itself is inside the
|
|
// interface/instantiator, thus this is a reference
|
|
// PARENT: AstModport
|
|
//
|
|
// @astgen ptr := m_ftaskp : Optional[AstNodeFTask] // Link to the function
|
|
string m_name; // Name of the variable referenced
|
|
bool m_export; // Type of the function (import/export)
|
|
public:
|
|
AstModportFTaskRef(FileLine* fl, const string& name, bool isExport)
|
|
: ASTGEN_SUPER_ModportFTaskRef(fl)
|
|
, m_name{name}
|
|
, m_export{isExport} {}
|
|
ASTGEN_MEMBERS_AstModportFTaskRef;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool isImport() const { return !m_export; }
|
|
bool isExport() const { return m_export; }
|
|
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
|
|
void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp = ftaskp; }
|
|
};
|
|
class AstModportVarRef final : public AstNode {
|
|
// A input/output/etc variable referenced under a modport
|
|
// The storage for the variable itself is inside the interface, thus this is a reference
|
|
// PARENT: AstModport
|
|
//
|
|
// @astgen ptr := m_varp : Optional[AstVar] // Link to the actual Var
|
|
string m_name; // Name of the variable referenced
|
|
VDirection m_direction; // Direction of the variable (in/out)
|
|
public:
|
|
AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction)
|
|
: ASTGEN_SUPER_ModportVarRef(fl)
|
|
, m_name{name}
|
|
, m_direction{direction} {}
|
|
ASTGEN_MEMBERS_AstModportVarRef;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
void direction(const VDirection& flag) { m_direction = flag; }
|
|
VDirection direction() const { return m_direction; }
|
|
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
|
void varp(AstVar* varp) { m_varp = varp; }
|
|
};
|
|
class AstNetlist final : public AstNode {
|
|
// All modules are under this single top node.
|
|
// Parents: none
|
|
// Children: MODULEs & CFILEs
|
|
// @astgen op1 := modulesp : List[AstNodeModule]
|
|
// @astgen op2 := filesp : List[AstNodeFile]
|
|
// @astgen op3 := miscsp : List[AstNode]
|
|
//
|
|
// @astgen ptr := m_typeTablep : AstTypeTable // Reference to type table, for faster lookup
|
|
// @astgen ptr := m_constPoolp : AstConstPool // Reference to constant pool, for faster lookup
|
|
// @astgen ptr := m_dollarUnitPkgp : Optional[AstPackage] // $unit
|
|
// @astgen ptr := m_stdPackagep : Optional[AstPackage] // SystemVerilog std package
|
|
// @astgen ptr := m_evalp : Optional[AstCFunc] // The '_eval' function
|
|
// @astgen ptr := m_evalNbap : Optional[AstCFunc] // The '_eval__nba' function
|
|
// @astgen ptr := m_dpiExportTriggerp : Optional[AstVarScope] // DPI export trigger variable
|
|
// @astgen ptr := m_delaySchedulerp : Optional[AstVar] // Delay scheduler variable
|
|
// @astgen ptr := m_nbaEventp : Optional[AstVarScope] // NBA event variable
|
|
// @astgen ptr := m_nbaEventTriggerp : Optional[AstVarScope] // NBA event trigger
|
|
// @astgen ptr := m_topScopep : Optional[AstTopScope] // Singleton AstTopScope
|
|
VTimescale m_timeunit; // Global time unit
|
|
VTimescale m_timeprecision; // Global time precision
|
|
bool m_timescaleSpecified = false; // Input HDL specified timescale
|
|
public:
|
|
AstNetlist();
|
|
ASTGEN_MEMBERS_AstNetlist;
|
|
void cloneRelink() override { V3ERROR_NA; }
|
|
string name() const override VL_MT_STABLE { return "$root"; }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
|
|
return modulesp(); // First one in the list, for now
|
|
}
|
|
AstTypeTable* typeTablep() { return m_typeTablep; }
|
|
AstConstPool* constPoolp() { return m_constPoolp; }
|
|
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
|
|
AstPackage* dollarUnitPkgAddp();
|
|
AstCFunc* evalp() const { return m_evalp; }
|
|
void evalp(AstCFunc* funcp) { m_evalp = funcp; }
|
|
AstCFunc* evalNbap() const { return m_evalNbap; }
|
|
void evalNbap(AstCFunc* funcp) { m_evalNbap = funcp; }
|
|
AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; }
|
|
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
|
|
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
|
|
void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
|
|
AstVarScope* nbaEventp() const { return m_nbaEventp; }
|
|
void nbaEventp(AstVarScope* const varScopep) { m_nbaEventp = varScopep; }
|
|
AstVarScope* nbaEventTriggerp() const { return m_nbaEventTriggerp; }
|
|
void nbaEventTriggerp(AstVarScope* const varScopep) { m_nbaEventTriggerp = varScopep; }
|
|
void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
|
|
AstPackage* stdPackagep() const { return m_stdPackagep; }
|
|
AstTopScope* topScopep() const { return m_topScopep; }
|
|
void createTopScope(AstScope* scopep);
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
void timeunit(const VTimescale& value) { m_timeunit = value; }
|
|
VTimescale timeprecision() const { return m_timeprecision; }
|
|
void timeInit() {
|
|
m_timeunit = v3Global.opt.timeDefaultUnit();
|
|
m_timeprecision = v3Global.opt.timeDefaultPrec();
|
|
}
|
|
void timeprecisionMerge(FileLine*, const VTimescale& value);
|
|
void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; }
|
|
bool timescaleSpecified() const { return m_timescaleSpecified; }
|
|
};
|
|
class AstPackageExport final : public AstNode {
|
|
// A package export declaration
|
|
//
|
|
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
|
|
string m_name;
|
|
|
|
public:
|
|
AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name)
|
|
: ASTGEN_SUPER_PackageExport(fl)
|
|
, m_name{name}
|
|
, m_packagep{packagep} {}
|
|
ASTGEN_MEMBERS_AstPackageExport;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
AstPackage* packagep() const { return m_packagep; }
|
|
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
|
};
|
|
class AstPackageExportStarStar final : public AstNode {
|
|
// A package export *::* declaration
|
|
public:
|
|
// cppcheck-suppress noExplicitConstructor
|
|
AstPackageExportStarStar(FileLine* fl)
|
|
: ASTGEN_SUPER_PackageExportStarStar(fl) {}
|
|
ASTGEN_MEMBERS_AstPackageExportStarStar;
|
|
};
|
|
class AstPackageImport final : public AstNode {
|
|
// A package import declaration
|
|
//
|
|
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
|
|
string m_name;
|
|
|
|
public:
|
|
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
|
|
: ASTGEN_SUPER_PackageImport(fl)
|
|
, m_name{name}
|
|
, m_packagep{packagep} {}
|
|
ASTGEN_MEMBERS_AstPackageImport;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
AstPackage* packagep() const { return m_packagep; }
|
|
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
|
};
|
|
class AstPin final : public AstNode {
|
|
// A port or parameter assignment on an instantiation
|
|
// @astgen op1 := exprp : Optional[AstNode] // NodeExpr or NodeDType (nullptr if unconnected)
|
|
//
|
|
// @astgen ptr := m_modVarp : Optional[AstVar] // Input/output connects to on submodule
|
|
// @astgen ptr := m_modPTypep : Optional[AstParamTypeDType] // Param type connects to on sub
|
|
int m_pinNum; // Pin number
|
|
string m_name; // Pin name, or "" for number based interconnect
|
|
bool m_param = false; // Pin connects to parameter
|
|
bool m_svDotName = false; // Pin is SystemVerilog .name'ed
|
|
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed, allow implicit
|
|
public:
|
|
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
|
|
: ASTGEN_SUPER_Pin(fl)
|
|
, m_pinNum{pinNum}
|
|
, m_name{name} {
|
|
this->exprp(exprp);
|
|
}
|
|
inline AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp);
|
|
ASTGEN_MEMBERS_AstPin;
|
|
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
|
void name(const string& name) override { m_name = name; }
|
|
string prettyOperatorName() const override;
|
|
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
|
|
int pinNum() const { return m_pinNum; }
|
|
AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable
|
|
void modVarp(AstVar* nodep) { m_modVarp = nodep; }
|
|
// [After Link] Pointer to variable
|
|
AstParamTypeDType* modPTypep() const { return m_modPTypep; }
|
|
void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; }
|
|
bool param() const { return m_param; }
|
|
void param(bool flag) { m_param = flag; }
|
|
bool svDotName() const { return m_svDotName; }
|
|
void svDotName(bool flag) { m_svDotName = flag; }
|
|
bool svImplicit() const { return m_svImplicit; }
|
|
void svImplicit(bool flag) { m_svImplicit = flag; }
|
|
};
|
|
class AstPort final : public AstNode {
|
|
// A port (in/out/inout) on a module
|
|
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression connected to port
|
|
const int m_pinNum; // Pin number
|
|
const string m_name; // Name of pin
|
|
public:
|
|
AstPort(FileLine* fl, int pinnum, const string& name)
|
|
: ASTGEN_SUPER_Port(fl)
|
|
, m_pinNum{pinnum}
|
|
, m_name{name} {}
|
|
ASTGEN_MEMBERS_AstPort;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Port name
|
|
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
|
};
|
|
class AstPragma final : public AstNode {
|
|
const VPragmaType m_pragType; // Type of pragma
|
|
public:
|
|
// Pragmas don't result in any output code, they're just flags that affect
|
|
// other processing in verilator.
|
|
AstPragma(FileLine* fl, VPragmaType pragType)
|
|
: ASTGEN_SUPER_Pragma(fl)
|
|
, m_pragType{pragType} {}
|
|
ASTGEN_MEMBERS_AstPragma;
|
|
VPragmaType pragType() const { return m_pragType; } // *=type of the pragma
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* samep) const override {
|
|
return pragType() == VN_DBG_AS(samep, Pragma)->pragType();
|
|
}
|
|
};
|
|
class AstPropSpec final : public AstNode {
|
|
// A clocked property
|
|
// Parents: ASSERT|COVER (property)
|
|
// Children: SENITEM, Properties
|
|
// @astgen op1 := sensesp : Optional[AstSenItem]
|
|
// @astgen op2 := disablep : Optional[AstNodeExpr]
|
|
// @astgen op3 := propp : AstNode
|
|
public:
|
|
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* disablep, AstNode* propp)
|
|
: ASTGEN_SUPER_PropSpec(fl) {
|
|
this->sensesp(sensesp);
|
|
this->disablep(disablep);
|
|
this->propp(propp);
|
|
}
|
|
ASTGEN_MEMBERS_AstPropSpec;
|
|
bool hasDType() const override {
|
|
return true;
|
|
} // Used under Cover, which expects a bool child
|
|
};
|
|
class AstPull final : public AstNode {
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
|
|
const bool m_direction;
|
|
|
|
public:
|
|
AstPull(FileLine* fl, AstNodeExpr* lhsp, bool direction)
|
|
: ASTGEN_SUPER_Pull(fl)
|
|
, m_direction{direction} {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstPull;
|
|
bool same(const AstNode* samep) const override {
|
|
return direction() == VN_DBG_AS(samep, Pull)->direction();
|
|
}
|
|
uint32_t direction() const { return (uint32_t)m_direction; }
|
|
};
|
|
class AstScope final : public AstNode {
|
|
// A particular usage of a cell
|
|
// Parents: MODULE
|
|
// Children: NODEBLOCK
|
|
// @astgen op1 := varsp : List[AstVarScope]
|
|
// @astgen op2 := blocksp : List[AstNode] // Logic blocks/AstActive/AstCFunc
|
|
// @astgen op3 := inlinesp : List[AstCellInlineScope] // Cell Inlines
|
|
//
|
|
// Below scope and cell are nullptr if top scope
|
|
// @astgen ptr := m_aboveScopep : Optional[AstScope] // Scope above this one in the hierarchy
|
|
// @astgen ptr := m_aboveCellp : Optional[AstCell] // Cell above this in the hierarchy
|
|
// @astgen ptr := m_modp : AstNodeModule // Module scope corresponds to
|
|
|
|
// An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope
|
|
string m_name; // Name
|
|
public:
|
|
AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep,
|
|
AstCell* aboveCellp)
|
|
: ASTGEN_SUPER_Scope(fl)
|
|
, m_name{name}
|
|
, m_aboveScopep{aboveScopep}
|
|
, m_aboveCellp{aboveCellp}
|
|
, m_modp{modp} {}
|
|
ASTGEN_MEMBERS_AstScope;
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!m_modp);
|
|
return nullptr;
|
|
}
|
|
bool maybePointedTo() const override { return true; }
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
|
void name(const string& name) override { m_name = name; }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool same(const AstNode* samep) const override;
|
|
string nameDotless() const;
|
|
AstNodeModule* modp() const { return m_modp; }
|
|
//
|
|
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
|
|
AstCell* aboveCellp() const { return m_aboveCellp; }
|
|
bool isTop() const VL_MT_SAFE { return aboveScopep() == nullptr; } // At top of hierarchy
|
|
// Create new MODULETEMP variable under this scope
|
|
AstVarScope* createTemp(const string& name, unsigned width);
|
|
AstVarScope* createTemp(const string& name, AstNodeDType* dtypep);
|
|
AstVarScope* createTempLike(const string& name, AstVarScope* vscp);
|
|
};
|
|
class AstSenItem final : public AstNode {
|
|
// Parents: SENTREE
|
|
// @astgen op1 := sensp : Optional[AstNodeExpr] // Sensitivity expression
|
|
// @astgen op2 := condp : Optional[AstNodeExpr] // Sensitivity condition
|
|
VEdgeType m_edgeType; // Edge type
|
|
public:
|
|
class Combo {}; // for constructor type-overload selection
|
|
class Static {}; // for constructor type-overload selection
|
|
class Initial {}; // for constructor type-overload selection
|
|
class Final {}; // for constructor type-overload selection
|
|
class Never {}; // for constructor type-overload selection
|
|
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp, AstNodeExpr* condp = nullptr)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{edgeType} {
|
|
this->sensp(senp);
|
|
this->condp(condp);
|
|
}
|
|
AstSenItem(FileLine* fl, Combo)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{VEdgeType::ET_COMBO} {}
|
|
AstSenItem(FileLine* fl, Static)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{VEdgeType::ET_STATIC} {}
|
|
AstSenItem(FileLine* fl, Initial)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{VEdgeType::ET_INITIAL} {}
|
|
AstSenItem(FileLine* fl, Final)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{VEdgeType::ET_FINAL} {}
|
|
AstSenItem(FileLine* fl, Never)
|
|
: ASTGEN_SUPER_SenItem(fl)
|
|
, m_edgeType{VEdgeType::ET_NEVER} {}
|
|
ASTGEN_MEMBERS_AstSenItem;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool same(const AstNode* samep) const override {
|
|
return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType();
|
|
}
|
|
VEdgeType edgeType() const { return m_edgeType; }
|
|
void edgeType(VEdgeType type) {
|
|
m_edgeType = type;
|
|
editCountInc();
|
|
}
|
|
AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); }
|
|
//
|
|
bool isClocked() const { return edgeType().clockedStmt(); }
|
|
bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; }
|
|
bool isHybrid() const { return edgeType() == VEdgeType::ET_HYBRID; }
|
|
bool isStatic() const { return edgeType() == VEdgeType::ET_STATIC; }
|
|
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
|
|
bool isFinal() const { return edgeType() == VEdgeType::ET_FINAL; }
|
|
bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; }
|
|
};
|
|
class AstSenTree final : public AstNode {
|
|
// A sensitivity list
|
|
// @astgen op1 := sensesp : List[AstSenItem]
|
|
bool m_multi = false; // Created from combo logic by ORing multiple clock domains
|
|
public:
|
|
AstSenTree(FileLine* fl, AstSenItem* sensesp)
|
|
: ASTGEN_SUPER_SenTree(fl) {
|
|
this->addSensesp(sensesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSenTree;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool maybePointedTo() const override { return true; }
|
|
bool isMulti() const { return m_multi; }
|
|
void multi(bool flag) { m_multi = true; }
|
|
// METHODS
|
|
bool hasClocked() const; // Includes a clocked statement
|
|
bool hasStatic() const; // Includes a STATIC SenItem
|
|
bool hasInitial() const; // Includes a INITIAL SenItem
|
|
bool hasFinal() const; // Includes a FINAL SenItem
|
|
bool hasCombo() const; // Includes a COMBO SenItem
|
|
bool hasHybrid() const; // Includes a HYBRID SenItem
|
|
};
|
|
class AstSplitPlaceholder final : public AstNode {
|
|
public:
|
|
// Dummy node used within V3Split; never exists outside of V3Split.
|
|
explicit AstSplitPlaceholder(FileLine* fl)
|
|
: ASTGEN_SUPER_SplitPlaceholder(fl) {}
|
|
ASTGEN_MEMBERS_AstSplitPlaceholder;
|
|
};
|
|
class AstStrengthSpec final : public AstNode {
|
|
VStrength m_s0; // Drive 0 strength
|
|
VStrength m_s1; // Drive 1 strength
|
|
|
|
public:
|
|
AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1)
|
|
: ASTGEN_SUPER_StrengthSpec(fl)
|
|
, m_s0{s0}
|
|
, m_s1{s1} {}
|
|
|
|
ASTGEN_MEMBERS_AstStrengthSpec;
|
|
VStrength strength0() { return m_s0; }
|
|
VStrength strength1() { return m_s1; }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
};
|
|
class AstTopScope final : public AstNode {
|
|
// A singleton, held under the top level AstModule. Holds the top level
|
|
// AstScope, and after V3ActiveTop, the global list of AstSenTrees (list of
|
|
// unique sensitivity lists).
|
|
//
|
|
// @astgen op1 := senTreesp : List[AstSenTree] // Globally unique sensitivity lists
|
|
// @astgen op2 := scopep : AstScope // The AstScope of the top-leveL
|
|
|
|
friend class AstNetlist; // Only the AstNetlist can create one
|
|
AstTopScope(FileLine* fl, AstScope* ascopep)
|
|
: ASTGEN_SUPER_TopScope(fl) {
|
|
this->scopep(ascopep);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstTopScope;
|
|
bool maybePointedTo() const override { return true; }
|
|
};
|
|
class AstTypeTable final : public AstNode {
|
|
// Container for hash of standard data types
|
|
// @astgen op1 := typesp : List[AstNodeDType]
|
|
//
|
|
// @astgen ptr := m_constraintRefp : Optional[AstConstraintRefDType]
|
|
// @astgen ptr := m_emptyQueuep : Optional[AstEmptyQueueDType]
|
|
// @astgen ptr := m_queueIndexp : Optional[AstQueueDType]
|
|
// @astgen ptr := m_streamp : Optional[AstStreamDType]
|
|
// @astgen ptr := m_voidp : Optional[AstVoidDType]
|
|
AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{};
|
|
//
|
|
using DetailedMap = std::map<VBasicTypeKey, AstBasicDType*>;
|
|
DetailedMap m_detailedMap;
|
|
|
|
public:
|
|
explicit AstTypeTable(FileLine* fl);
|
|
ASTGEN_MEMBERS_AstTypeTable;
|
|
bool maybePointedTo() const override { return true; }
|
|
void cloneRelink() override { V3ERROR_NA; }
|
|
AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd);
|
|
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin,
|
|
VSigning numeric);
|
|
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range,
|
|
int widthMin, VSigning numeric);
|
|
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
|
AstConstraintRefDType* findConstraintRefDType(FileLine* fl);
|
|
AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl);
|
|
AstQueueDType* findQueueIndexDType(FileLine* fl);
|
|
AstStreamDType* findStreamDType(FileLine* fl);
|
|
AstVoidDType* findVoidDType(FileLine* fl);
|
|
void clearCache();
|
|
void repairCache();
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
};
|
|
class AstTypedef final : public AstNode {
|
|
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
|
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
|
|
|
|
string m_name;
|
|
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
|
bool m_attrPublic = false;
|
|
|
|
public:
|
|
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType,
|
|
AstNodeDType* dtp)
|
|
: ASTGEN_SUPER_Typedef(fl)
|
|
, m_name{name} {
|
|
childDTypep(dtp); // Only for parser
|
|
addAttrsp(attrsp);
|
|
dtypep(nullptr); // V3Width will resolve
|
|
}
|
|
ASTGEN_MEMBERS_AstTypedef;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
|
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
|
return dtypep() ? dtypep() : childDTypep();
|
|
}
|
|
// METHODS
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool maybePointedTo() const override { return true; }
|
|
bool hasDType() const override { return true; }
|
|
void name(const string& flag) override { m_name = flag; }
|
|
bool attrPublic() const { return m_attrPublic; }
|
|
void attrPublic(bool flag) { m_attrPublic = flag; }
|
|
void tag(const string& text) override { m_tag = text; }
|
|
string tag() const override { return m_tag; }
|
|
};
|
|
class AstTypedefFwd final : public AstNode {
|
|
// Forward declaration of a type; stripped after netlist parsing is complete
|
|
string m_name;
|
|
|
|
public:
|
|
AstTypedefFwd(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_TypedefFwd(fl)
|
|
, m_name{name} {}
|
|
ASTGEN_MEMBERS_AstTypedefFwd;
|
|
// METHODS
|
|
string name() const override VL_MT_STABLE { return m_name; }
|
|
bool maybePointedTo() const override { return true; }
|
|
};
|
|
class AstUdpTable final : public AstNode {
|
|
// @astgen op1 := linesp : List[AstUdpTableLine]
|
|
public:
|
|
AstUdpTable(FileLine* fl, AstUdpTableLine* linesp)
|
|
: ASTGEN_SUPER_UdpTable(fl) {
|
|
this->addLinesp(linesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstUdpTable;
|
|
};
|
|
class AstUdpTableLine final : public AstNode {
|
|
string m_text;
|
|
|
|
public:
|
|
AstUdpTableLine(FileLine* fl, const string& text)
|
|
: ASTGEN_SUPER_UdpTableLine(fl)
|
|
, m_text{text} {}
|
|
ASTGEN_MEMBERS_AstUdpTableLine;
|
|
string name() const override VL_MT_STABLE { return m_text; }
|
|
string text() const { return m_text; }
|
|
};
|
|
class AstVar final : public AstNode {
|
|
// A variable (in/out/wire/reg/param) inside a module
|
|
//
|
|
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
|
// @astgen op2 := delayp : Optional[AstDelay] // Net delay
|
|
// Initial value that never changes (static const), or constructor argument for
|
|
// MTASKSTATE variables
|
|
// @astgen op3 := valuep : Optional[AstNode] // May be a DType for type parameter defaults
|
|
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
|
|
// @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this
|
|
// var are sensitive
|
|
|
|
string m_name; // Name of variable
|
|
string m_origName; // Original name before dot addition
|
|
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
|
VVarType m_varType; // Type of variable
|
|
VDirection m_direction; // Direction input/output etc
|
|
VDirection m_declDirection; // Declared direction input/output etc
|
|
VLifetime m_lifetime; // Lifetime
|
|
VVarAttrClocker m_attrClocker;
|
|
VRandAttr m_rand; // Randomizability of this variable (rand, randc, etc)
|
|
int m_pinNum = 0; // For XML, if non-zero the connection pin number
|
|
bool m_ansi : 1; // Params or pins declared in the module header, rather than the body
|
|
bool m_declTyped : 1; // Declared as type (for dedup check)
|
|
bool m_tristate : 1; // Inout or triwire or trireg
|
|
bool m_primaryIO : 1; // In/out to top level (or directly assigned from same)
|
|
bool m_sc : 1; // SystemC variable
|
|
bool m_scClocked : 1; // SystemC sc_clk<> needed
|
|
bool m_scSensitive : 1; // SystemC sensitive() needed
|
|
bool m_sigPublic : 1; // User C code accesses this signal or is top signal
|
|
bool m_sigModPublic : 1; // User C code accesses this signal and module
|
|
bool m_sigUserRdPublic : 1; // User C code accesses this signal, read only
|
|
bool m_sigUserRWPublic : 1; // User C code accesses this signal, read-write
|
|
bool m_usedClock : 1; // Signal used as a clock
|
|
bool m_usedParam : 1; // Parameter is referenced (on link; later signals not setup)
|
|
bool m_usedLoopIdx : 1; // Variable subject of for unrolling
|
|
bool m_funcLocal : 1; // Local variable for a function
|
|
bool m_funcLocalSticky : 1; // As m_funcLocal but remains set if var is moved to a static
|
|
bool m_funcReturn : 1; // Return variable for a function
|
|
bool m_attrScBv : 1; // User force bit vector attribute
|
|
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
|
bool m_attrSFormat : 1; // User sformat attribute
|
|
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
|
bool m_fileDescr : 1; // File descriptor
|
|
bool m_isConst : 1; // Table contains constant data
|
|
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
|
|
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
|
|
bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic)
|
|
bool m_isPulldown : 1; // Tri0
|
|
bool m_isPullup : 1; // Tri1
|
|
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
|
|
bool m_isInternal : 1; // Internal state, don't add to method pinter
|
|
bool m_isDpiOpenArray : 1; // DPI import open array
|
|
bool m_isHideLocal : 1; // Verilog local
|
|
bool m_isHideProtected : 1; // Verilog protected
|
|
bool m_noReset : 1; // Do not do automated reset/randomization
|
|
bool m_noSubst : 1; // Do not substitute out references
|
|
bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam
|
|
bool m_trace : 1; // Trace this variable
|
|
bool m_isLatched : 1; // Not assigned in all control paths of combo always
|
|
bool m_isForceable : 1; // May be forced/released externally from user C code
|
|
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
|
|
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
|
|
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
|
|
|
|
void init() {
|
|
m_ansi = false;
|
|
m_declTyped = false;
|
|
m_tristate = false;
|
|
m_primaryIO = false;
|
|
m_sc = false;
|
|
m_scClocked = false;
|
|
m_scSensitive = false;
|
|
m_usedClock = false;
|
|
m_usedParam = false;
|
|
m_usedLoopIdx = false;
|
|
m_sigPublic = false;
|
|
m_sigModPublic = false;
|
|
m_sigUserRdPublic = false;
|
|
m_sigUserRWPublic = false;
|
|
m_funcLocal = false;
|
|
m_funcLocalSticky = false;
|
|
m_funcReturn = false;
|
|
m_attrScBv = false;
|
|
m_attrIsolateAssign = false;
|
|
m_attrSFormat = false;
|
|
m_attrSplitVar = false;
|
|
m_fileDescr = false;
|
|
m_isConst = false;
|
|
m_isContinuously = false;
|
|
m_hasStrengthAssignment = false;
|
|
m_isStatic = false;
|
|
m_isPulldown = false;
|
|
m_isPullup = false;
|
|
m_isIfaceParent = false;
|
|
m_isInternal = false;
|
|
m_isDpiOpenArray = false;
|
|
m_isHideLocal = false;
|
|
m_isHideProtected = false;
|
|
m_noReset = false;
|
|
m_noSubst = false;
|
|
m_overridenParam = false;
|
|
m_trace = false;
|
|
m_isLatched = false;
|
|
m_isForceable = false;
|
|
m_isForcedByCode = false;
|
|
m_isWrittenByDpi = false;
|
|
m_isWrittenBySuspendable = false;
|
|
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
|
|
}
|
|
|
|
public:
|
|
AstVar(FileLine* fl, VVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
|
: ASTGEN_SUPER_Var(fl)
|
|
, m_name{name}
|
|
, m_origName{name} {
|
|
init();
|
|
combineType(type);
|
|
childDTypep(dtp); // Only for parser
|
|
dtypep(nullptr); // V3Width will resolve
|
|
}
|
|
AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp)
|
|
: ASTGEN_SUPER_Var(fl)
|
|
, m_name{name}
|
|
, m_origName{name} {
|
|
init();
|
|
combineType(type);
|
|
UASSERT(dtp, "AstVar created with no dtype");
|
|
dtypep(dtp);
|
|
}
|
|
AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth)
|
|
: ASTGEN_SUPER_Var(fl)
|
|
, m_name{name}
|
|
, m_origName{name} {
|
|
init();
|
|
combineType(type);
|
|
dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED);
|
|
}
|
|
AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth)
|
|
: ASTGEN_SUPER_Var(fl)
|
|
, m_name{name}
|
|
, m_origName{name} {
|
|
init();
|
|
combineType(type);
|
|
dtypeSetBitSized(wantwidth, VSigning::UNSIGNED);
|
|
}
|
|
AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep)
|
|
: ASTGEN_SUPER_Var(fl)
|
|
, m_name{name}
|
|
, m_origName{name} {
|
|
init();
|
|
combineType(type);
|
|
if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true));
|
|
dtypeFrom(examplep);
|
|
}
|
|
ASTGEN_MEMBERS_AstVar;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool same(const AstNode* samep) const override;
|
|
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
|
|
bool hasDType() const override { return true; }
|
|
bool maybePointedTo() const override { return true; }
|
|
string origName() const override { return m_origName; } // * = Original name
|
|
void origName(const string& name) { m_origName = name; }
|
|
VVarType varType() const VL_MT_SAFE { return m_varType; } // * = Type of variable
|
|
void direction(const VDirection& flag) {
|
|
m_direction = flag;
|
|
if (m_direction == VDirection::INOUT) m_tristate = true;
|
|
}
|
|
VDirection direction() const VL_MT_SAFE { return m_direction; }
|
|
bool isIO() const VL_MT_SAFE { return m_direction != VDirection::NONE; }
|
|
void declDirection(const VDirection& flag) { m_declDirection = flag; }
|
|
VDirection declDirection() const { return m_declDirection; }
|
|
void varType(VVarType type) { m_varType = type; }
|
|
void varType2Out() {
|
|
m_tristate = false;
|
|
m_direction = VDirection::OUTPUT;
|
|
}
|
|
void varType2In() {
|
|
m_tristate = false;
|
|
m_direction = VDirection::INPUT;
|
|
}
|
|
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
|
// Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
|
string cPubArgType(bool named, bool forReturn) const;
|
|
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
|
string dpiTmpVarType(const string& varName) const;
|
|
// Return Verilator internal type for argument: CData, SData, IData, WData
|
|
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "",
|
|
bool asRef = false) const;
|
|
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
|
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
|
string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration
|
|
void combineType(VVarType type);
|
|
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
|
AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
|
// (Slow) recurse down to find basic data type (Note don't need virtual -
|
|
// AstVar isn't a NodeDType)
|
|
AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); }
|
|
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
|
return dtypep() ? dtypep() : childDTypep();
|
|
}
|
|
void ansi(bool flag) { m_ansi = flag; }
|
|
void declTyped(bool flag) { m_declTyped = flag; }
|
|
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
|
|
void attrClocker(VVarAttrClocker flag) { m_attrClocker = flag; }
|
|
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
|
void attrScClocked(bool flag) { m_scClocked = flag; }
|
|
void attrScBv(bool flag) { m_attrScBv = flag; }
|
|
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
|
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
|
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
|
|
void rand(const VRandAttr flag) { m_rand = flag; }
|
|
void usedClock(bool flag) { m_usedClock = flag; }
|
|
void usedParam(bool flag) { m_usedParam = flag; }
|
|
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
|
void sigPublic(bool flag) { m_sigPublic = flag; }
|
|
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
|
void sigUserRdPublic(bool flag) {
|
|
m_sigUserRdPublic = flag;
|
|
if (flag) sigPublic(true);
|
|
}
|
|
void sigUserRWPublic(bool flag) {
|
|
m_sigUserRWPublic = flag;
|
|
if (flag) sigUserRdPublic(true);
|
|
}
|
|
void sc(bool flag) { m_sc = flag; }
|
|
void scSensitive(bool flag) { m_scSensitive = flag; }
|
|
void primaryIO(bool flag) { m_primaryIO = flag; }
|
|
void isConst(bool flag) { m_isConst = flag; }
|
|
void isContinuously(bool flag) { m_isContinuously = flag; }
|
|
void isStatic(bool flag) { m_isStatic = flag; }
|
|
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
|
|
void isInternal(bool flag) { m_isInternal = flag; }
|
|
void funcLocal(bool flag) {
|
|
m_funcLocal = flag;
|
|
if (flag) m_funcLocalSticky = true;
|
|
}
|
|
void funcReturn(bool flag) { m_funcReturn = flag; }
|
|
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
|
|
bool hasStrengthAssignment() { return m_hasStrengthAssignment; }
|
|
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
|
|
bool isDpiOpenArray() const VL_MT_SAFE { return m_isDpiOpenArray; }
|
|
bool isHideLocal() const { return m_isHideLocal; }
|
|
void isHideLocal(bool flag) { m_isHideLocal = flag; }
|
|
bool isHideProtected() const { return m_isHideProtected; }
|
|
void isHideProtected(bool flag) { m_isHideProtected = flag; }
|
|
void noReset(bool flag) { m_noReset = flag; }
|
|
bool noReset() const { return m_noReset; }
|
|
void noSubst(bool flag) { m_noSubst = flag; }
|
|
bool noSubst() const { return m_noSubst; }
|
|
void overriddenParam(bool flag) { m_overridenParam = flag; }
|
|
bool overriddenParam() const { return m_overridenParam; }
|
|
void trace(bool flag) { m_trace = flag; }
|
|
void isLatched(bool flag) { m_isLatched = flag; }
|
|
bool isForceable() const { return m_isForceable; }
|
|
void setForceable() { m_isForceable = true; }
|
|
void setForcedByCode() { m_isForcedByCode = true; }
|
|
bool isForced() const { return m_isForceable || m_isForcedByCode; }
|
|
bool isWrittenByDpi() const { return m_isWrittenByDpi; }
|
|
void setWrittenByDpi() { m_isWrittenByDpi = true; }
|
|
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }
|
|
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
|
|
|
|
// METHODS
|
|
void name(const string& name) override { m_name = name; }
|
|
void tag(const string& text) override { m_tag = text; }
|
|
string tag() const override { return m_tag; }
|
|
bool isAnsi() const { return m_ansi; }
|
|
bool isContinuously() const { return m_isContinuously; }
|
|
bool isDeclTyped() const { return m_declTyped; }
|
|
bool isInoutish() const { return m_direction.isInoutish(); }
|
|
bool isInput() const { return m_direction.isInput(); }
|
|
bool isNonOutput() const { return m_direction.isNonOutput(); }
|
|
bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); }
|
|
bool isConstRef() const VL_MT_SAFE { return m_direction.isConstRef(); }
|
|
bool isRef() const VL_MT_SAFE { return m_direction.isRef(); }
|
|
bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); }
|
|
bool isTristate() const { return m_tristate; }
|
|
bool isPrimaryIO() const { return m_primaryIO; }
|
|
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
|
|
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
|
|
bool isIfaceParent() const { return m_isIfaceParent; }
|
|
bool isInternal() const { return m_isInternal; }
|
|
bool isSignal() const { return varType().isSignal(); }
|
|
bool isNet() const { return varType().isNet(); }
|
|
bool isTemp() const { return varType().isTemp(); }
|
|
bool isToggleCoverable() const {
|
|
return ((isIO() || isSignal())
|
|
&& (isIO() || isBitLogic())
|
|
// Wrapper would otherwise duplicate wrapped module's coverage
|
|
&& !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString());
|
|
}
|
|
bool isClassMember() const { return varType() == VVarType::MEMBER; }
|
|
bool isStatementTemp() const { return (varType() == VVarType::STMTTEMP); }
|
|
bool isXTemp() const { return (varType() == VVarType::XTEMP); }
|
|
bool isParam() const { return varType().isParam(); }
|
|
bool isGParam() const { return (varType() == VVarType::GPARAM); }
|
|
bool isGenVar() const { return (varType() == VVarType::GENVAR); }
|
|
bool isBitLogic() const {
|
|
AstBasicDType* bdtypep = basicp();
|
|
return bdtypep && bdtypep->isBitLogic();
|
|
}
|
|
bool isUsedClock() const { return m_usedClock; }
|
|
bool isUsedParam() const { return m_usedParam; }
|
|
bool isUsedLoopIdx() const { return m_usedLoopIdx; }
|
|
bool isSc() const VL_MT_SAFE { return m_sc; }
|
|
bool isScQuad() const;
|
|
bool isScBv() const;
|
|
bool isScUint() const;
|
|
bool isScUintBool() const;
|
|
bool isScBigUint() const;
|
|
bool isScSensitive() const { return m_scSensitive; }
|
|
bool isSigPublic() const;
|
|
bool isSigModPublic() const { return m_sigModPublic; }
|
|
bool isSigUserRdPublic() const { return m_sigUserRdPublic; }
|
|
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
|
bool isTrace() const { return m_trace; }
|
|
bool isRand() const { return m_rand.isRand(); }
|
|
bool isRandC() const { return m_rand.isRandC(); }
|
|
bool isConst() const VL_MT_SAFE { return m_isConst; }
|
|
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
|
|
bool isLatched() const { return m_isLatched; }
|
|
bool isFuncLocal() const { return m_funcLocal; }
|
|
bool isFuncLocalSticky() const { return m_funcLocalSticky; }
|
|
bool isFuncReturn() const { return m_funcReturn; }
|
|
bool isPullup() const { return m_isPullup; }
|
|
bool isPulldown() const { return m_isPulldown; }
|
|
bool attrScBv() const { return m_attrScBv; }
|
|
bool attrFileDescr() const { return m_fileDescr; }
|
|
bool attrScClocked() const { return m_scClocked; }
|
|
bool attrSFormat() const { return m_attrSFormat; }
|
|
bool attrSplitVar() const { return m_attrSplitVar; }
|
|
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
|
AstIface* sensIfacep() const { return m_sensIfacep; }
|
|
VVarAttrClocker attrClocker() const { return m_attrClocker; }
|
|
VRandAttr rand() const { return m_rand; }
|
|
string verilogKwd() const override;
|
|
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
|
VLifetime lifetime() const { return m_lifetime; }
|
|
void propagateAttrFrom(const AstVar* fromp) {
|
|
// This is getting connected to fromp; keep attributes
|
|
// Note the method below too
|
|
if (fromp->attrFileDescr()) attrFileDescr(true);
|
|
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
|
|
if (fromp->isContinuously()) isContinuously(true);
|
|
}
|
|
void propagateWrapAttrFrom(const AstVar* fromp) {
|
|
// Creating a function wrapper; keep attributes
|
|
propagateAttrFrom(fromp);
|
|
direction(fromp->direction());
|
|
declDirection(fromp->declDirection());
|
|
lifetime(fromp->lifetime());
|
|
}
|
|
void combineType(const AstVar* typevarp) {
|
|
// This is same as typevarp (for combining input & reg decls)
|
|
// "this" is the input var. typevarp is the reg var.
|
|
propagateAttrFrom(typevarp);
|
|
combineType(typevarp->varType());
|
|
if (typevarp->isSigPublic()) sigPublic(true);
|
|
if (typevarp->isSigModPublic()) sigModPublic(true);
|
|
if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
|
|
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
|
|
if (typevarp->attrScClocked()) attrScClocked(true);
|
|
}
|
|
void inlineAttrReset(const string& name) {
|
|
if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) {
|
|
m_varType = VVarType::TRIWIRE;
|
|
}
|
|
m_direction = VDirection::NONE;
|
|
m_name = name;
|
|
}
|
|
static AstVar* scVarRecurse(AstNode* nodep);
|
|
void pinNum(int id) { m_pinNum = id; }
|
|
int pinNum() const { return m_pinNum; }
|
|
};
|
|
class AstVarScope final : public AstNode {
|
|
// A particular scoped usage of a variable
|
|
// That is, as a module is used under multiple cells, we get a different
|
|
// varscope for each var in the module
|
|
// Parents: MODULE
|
|
// Children: none
|
|
//
|
|
// @astgen ptr := m_scopep : Optional[AstScope] // Scope variable is underneath
|
|
// @astgen ptr := m_varp : Optional[AstVar] // [AfterLink] Pointer to variable itself
|
|
bool m_trace : 1; // Tracing is turned on for this scope
|
|
public:
|
|
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
|
|
: ASTGEN_SUPER_VarScope(fl)
|
|
, m_scopep{scopep}
|
|
, m_varp{varp} {
|
|
UASSERT_OBJ(scopep, fl, "Scope must be non-null");
|
|
UASSERT_OBJ(varp, fl, "Var must be non-null");
|
|
m_trace = true;
|
|
dtypeFrom(varp);
|
|
}
|
|
ASTGEN_MEMBERS_AstVarScope;
|
|
void cloneRelink() override {
|
|
if (m_varp && m_varp->clonep()) {
|
|
UASSERT(m_scopep->clonep(), "No clone cross link: " << this);
|
|
}
|
|
cloneRelinkGen();
|
|
}
|
|
bool maybePointedTo() const override { return true; }
|
|
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool same(const AstNode* samep) const override;
|
|
bool hasDType() const override { return true; }
|
|
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
|
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
|
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
|
bool isTrace() const { return m_trace; }
|
|
void trace(bool flag) { m_trace = flag; }
|
|
};
|
|
|
|
// === AstNodeBlock ===
|
|
class AstBegin final : public AstNodeBlock {
|
|
// A Begin/end named block, only exists shortly after parsing until linking
|
|
// Parents: statement
|
|
// @astgen op1 := genforp : Optional[AstNode]
|
|
|
|
bool m_generate : 1; // Underneath a generate
|
|
bool m_needProcess : 1; // Uses VlProcess
|
|
const bool m_implied : 1; // Not inserted by user
|
|
public:
|
|
// Node that puts name into the output stream
|
|
AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false,
|
|
bool implied = false)
|
|
: ASTGEN_SUPER_Begin(fl, name, stmtsp)
|
|
, m_generate{generate}
|
|
, m_needProcess{false}
|
|
, m_implied{implied} {}
|
|
ASTGEN_MEMBERS_AstBegin;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool generate() const { return m_generate; }
|
|
void generate(bool flag) { m_generate = flag; }
|
|
void setNeedProcess() { m_needProcess = true; }
|
|
bool needProcess() const { return m_needProcess; }
|
|
bool implied() const { return m_implied; }
|
|
};
|
|
class AstFork final : public AstNodeBlock {
|
|
// A fork named block
|
|
// @astgen op1 := initsp : List[AstNode]
|
|
// Parents: statement
|
|
// Children: statements
|
|
VJoinType m_joinType; // Join keyword type
|
|
public:
|
|
// Node that puts name into the output stream
|
|
AstFork(FileLine* fl, const string& name, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Fork(fl, name, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstFork;
|
|
bool isTimingControl() const override { return !joinType().joinNone(); }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
VJoinType joinType() const { return m_joinType; }
|
|
void joinType(const VJoinType& flag) { m_joinType = flag; }
|
|
};
|
|
|
|
// === AstNodeFTask ===
|
|
class AstFunc final : public AstNodeFTask {
|
|
// A function inside a module
|
|
public:
|
|
AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarp)
|
|
: ASTGEN_SUPER_Func(fl, name, stmtp) {
|
|
this->fvarp(fvarp);
|
|
}
|
|
ASTGEN_MEMBERS_AstFunc;
|
|
bool hasDType() const override { return true; }
|
|
AstNodeFTask* cloneType(const string& name) override {
|
|
return new AstFunc{fileline(), name, nullptr, nullptr};
|
|
}
|
|
};
|
|
class AstLet final : public AstNodeFTask {
|
|
// Verilog "let" statement
|
|
// Parents: MODULE
|
|
// stmtp is always a StmtExpr as Let always returns AstNodeExpr
|
|
public:
|
|
AstLet(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Let(fl, name, nullptr) {}
|
|
ASTGEN_MEMBERS_AstLet;
|
|
bool hasDType() const override { return true; }
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr));
|
|
return nullptr;
|
|
}
|
|
AstNodeFTask* cloneType(const string& name) override { return new AstLet{fileline(), name}; }
|
|
};
|
|
class AstProperty final : public AstNodeFTask {
|
|
// A property inside a module
|
|
public:
|
|
AstProperty(FileLine* fl, const string& name, AstNode* stmtp)
|
|
: ASTGEN_SUPER_Property(fl, name, stmtp) {}
|
|
ASTGEN_MEMBERS_AstProperty;
|
|
bool hasDType() const override { return true; }
|
|
AstNodeFTask* cloneType(const string& name) override {
|
|
return new AstProperty{fileline(), name, nullptr};
|
|
}
|
|
};
|
|
class AstTask final : public AstNodeFTask {
|
|
// A task inside a module
|
|
public:
|
|
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
|
|
: ASTGEN_SUPER_Task(fl, name, stmtp) {}
|
|
ASTGEN_MEMBERS_AstTask;
|
|
AstNodeFTask* cloneType(const string& name) override {
|
|
return new AstTask{fileline(), name, nullptr};
|
|
}
|
|
};
|
|
|
|
// === AstNodeFile ===
|
|
class AstCFile final : public AstNodeFile {
|
|
// C++ output file
|
|
// Parents: NETLIST
|
|
bool m_slow : 1; ///< Compile w/o optimization
|
|
bool m_source : 1; ///< Source file (vs header file)
|
|
bool m_support : 1; ///< Support file (non systemc)
|
|
public:
|
|
AstCFile(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_CFile(fl, name)
|
|
, m_slow{false}
|
|
, m_source{false}
|
|
, m_support{false} {}
|
|
ASTGEN_MEMBERS_AstCFile;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
bool slow() const { return m_slow; }
|
|
void slow(bool flag) { m_slow = flag; }
|
|
bool source() const { return m_source; }
|
|
void source(bool flag) { m_source = flag; }
|
|
bool support() const { return m_support; }
|
|
void support(bool flag) VL_MT_SAFE { m_support = flag; }
|
|
};
|
|
class AstVFile final : public AstNodeFile {
|
|
// Verilog output file
|
|
// Parents: NETLIST
|
|
public:
|
|
AstVFile(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_VFile(fl, name) {}
|
|
ASTGEN_MEMBERS_AstVFile;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
};
|
|
|
|
// === AstNodeModule ===
|
|
class AstClass final : public AstNodeModule {
|
|
// @astgen op4 := extendsp : List[AstClassExtends]
|
|
// MEMBERS
|
|
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
|
|
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
|
bool m_extended = false; // Is extension or extended by other classes
|
|
bool m_interfaceClass = false; // Interface class
|
|
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
|
bool m_parameterized = false; // Parameterized class
|
|
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
|
|
bool m_virtual = false; // Virtual class
|
|
|
|
public:
|
|
AstClass(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Class(fl, name) {}
|
|
ASTGEN_MEMBERS_AstClass;
|
|
string verilogKwd() const override { return "class"; }
|
|
bool maybePointedTo() const override { return true; }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool timescaleMatters() const override { return false; }
|
|
AstClassPackage* classOrPackagep() const VL_MT_SAFE { return m_classOrPackagep; }
|
|
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
|
|
AstNode* membersp() const { return stmtsp(); }
|
|
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
|
|
bool isExtended() const { return m_extended; }
|
|
void isExtended(bool flag) { m_extended = flag; }
|
|
bool isInterfaceClass() const { return m_interfaceClass; }
|
|
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
|
|
bool isParameterized() const { return m_parameterized; }
|
|
void isParameterized(bool flag) { m_parameterized = flag; }
|
|
bool isVirtual() const { return m_virtual; }
|
|
void isVirtual(bool flag) { m_virtual = flag; }
|
|
bool needRNG() const { return m_needRNG; }
|
|
void needRNG(bool flag) { m_needRNG = flag; }
|
|
bool useVirtualPublic() const { return m_useVirtualPublic; }
|
|
void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; }
|
|
// Return true if this class is an extension of base class (SLOW)
|
|
// Accepts nullptrs
|
|
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
|
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
|
|
VBaseOverride baseOverride() const { return m_baseOverride; }
|
|
// Return the lowest class extended from, or this class
|
|
AstClass* baseMostClassp();
|
|
static bool isCacheableChild(const AstNode* nodep);
|
|
// Iterates top level members of the class, taking into account inheritance (starting from the
|
|
// root superclass). Note: after V3Scope, several children are moved under an AstScope and will
|
|
// not be found by this.
|
|
template <typename Callable>
|
|
void foreachMember(const Callable& f) {
|
|
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
|
static_assert(
|
|
vlstd::is_invocable<Callable, AstClass*, T_Node*>::value
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
"Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
|
if (AstClassExtends* const extendsp = this->extendsp()) {
|
|
extendsp->classp()->foreachMember(f);
|
|
}
|
|
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
if (AstNode::privateTypeTest<T_Node>(stmtp)) f(this, static_cast<T_Node*>(stmtp));
|
|
}
|
|
}
|
|
// Same as above, but stops after first match
|
|
template <typename Callable>
|
|
bool existsMember(const Callable& p) const {
|
|
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
|
static_assert(vlstd::is_invocable_r<bool, Callable, const AstClass*, const T_Node*>::value
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
|
|
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
|
|
if (AstClassExtends* const extendsp = this->extendsp()) {
|
|
if (extendsp->classp()->existsMember(p)) return true;
|
|
}
|
|
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
if (AstNode::privateTypeTest<T_Node>(stmtp)) {
|
|
if (p(this, static_cast<T_Node*>(stmtp))) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
class AstClassPackage final : public AstNodeModule {
|
|
// The static information portion of a class (treated similarly to a package)
|
|
//
|
|
// @astgen ptr := m_classp : Optional[AstClass] // Class package this is under
|
|
// // (weak pointer, hard link is other way)
|
|
public:
|
|
AstClassPackage(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_ClassPackage(fl, name) {}
|
|
ASTGEN_MEMBERS_AstClassPackage;
|
|
string verilogKwd() const override { return "classpackage"; }
|
|
bool timescaleMatters() const override { return false; }
|
|
AstClass* classp() const VL_MT_SAFE { return m_classp; }
|
|
void classp(AstClass* classp) { m_classp = classp; }
|
|
};
|
|
class AstIface final : public AstNodeModule {
|
|
// A module declaration
|
|
public:
|
|
AstIface(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Iface(fl, name) {}
|
|
ASTGEN_MEMBERS_AstIface;
|
|
// Interfaces have `timescale applicability but lots of code seems to
|
|
// get false warnings if we enable this
|
|
string verilogKwd() const override { return "interface"; }
|
|
bool timescaleMatters() const override { return false; }
|
|
};
|
|
class AstModule final : public AstNodeModule {
|
|
// A module declaration
|
|
const bool m_isProgram; // Module represents a program
|
|
public:
|
|
AstModule(FileLine* fl, const string& name, bool program = false)
|
|
: ASTGEN_SUPER_Module(fl, name)
|
|
, m_isProgram{program} {}
|
|
ASTGEN_MEMBERS_AstModule;
|
|
string verilogKwd() const override { return m_isProgram ? "program" : "module"; }
|
|
bool timescaleMatters() const override { return true; }
|
|
};
|
|
class AstNotFoundModule final : public AstNodeModule {
|
|
// A missing module declaration
|
|
public:
|
|
AstNotFoundModule(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_NotFoundModule(fl, name) {}
|
|
ASTGEN_MEMBERS_AstNotFoundModule;
|
|
string verilogKwd() const override { return "/*not-found-*/ module"; }
|
|
bool timescaleMatters() const override { return false; }
|
|
};
|
|
class AstPackage final : public AstNodeModule {
|
|
// A package declaration
|
|
public:
|
|
AstPackage(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Package(fl, name) {}
|
|
ASTGEN_MEMBERS_AstPackage;
|
|
string verilogKwd() const override { return "package"; }
|
|
bool timescaleMatters() const override { return !isDollarUnit(); }
|
|
static string dollarUnitName() { return AstNode::encodeName("$unit"); }
|
|
bool isDollarUnit() const { return name() == dollarUnitName(); }
|
|
};
|
|
class AstPrimitive final : public AstNodeModule {
|
|
// A primitive declaration
|
|
public:
|
|
AstPrimitive(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Primitive(fl, name) {}
|
|
ASTGEN_MEMBERS_AstPrimitive;
|
|
string verilogKwd() const override { return "primitive"; }
|
|
bool timescaleMatters() const override { return false; }
|
|
};
|
|
|
|
// === AstNodeProcedure ===
|
|
class AstAlways final : public AstNodeProcedure {
|
|
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked
|
|
const VAlwaysKwd m_keyword;
|
|
|
|
public:
|
|
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Always(fl, stmtsp)
|
|
, m_keyword{keyword} {
|
|
this->sensesp(sensesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAlways;
|
|
//
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
VAlwaysKwd keyword() const { return m_keyword; }
|
|
};
|
|
class AstAlwaysObserved final : public AstNodeProcedure {
|
|
// Like always but Observed scheduling region
|
|
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list, removed in V3Active
|
|
|
|
public:
|
|
AstAlwaysObserved(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
|
: ASTGEN_SUPER_AlwaysObserved(fl, bodysp) {
|
|
this->sensesp(sensesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAlwaysObserved;
|
|
};
|
|
class AstAlwaysPost final : public AstNodeProcedure {
|
|
// Like always but 'post' scheduled, e.g. for array NBA commits
|
|
|
|
public:
|
|
explicit AstAlwaysPost(FileLine* fl)
|
|
: ASTGEN_SUPER_AlwaysPost(fl, nullptr) {}
|
|
ASTGEN_MEMBERS_AstAlwaysPost;
|
|
};
|
|
class AstAlwaysPostponed final : public AstNodeProcedure {
|
|
// Like always but Postponed scheduling region
|
|
|
|
public:
|
|
AstAlwaysPostponed(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_AlwaysPostponed(fl, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstAlwaysPostponed;
|
|
};
|
|
class AstAlwaysReactive final : public AstNodeProcedure {
|
|
// Like always but Reactive scheduling region
|
|
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list, removed in V3Active
|
|
|
|
public:
|
|
AstAlwaysReactive(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
|
: ASTGEN_SUPER_AlwaysReactive(fl, bodysp) {
|
|
this->sensesp(sensesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAlwaysReactive;
|
|
};
|
|
class AstFinal final : public AstNodeProcedure {
|
|
public:
|
|
AstFinal(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Final(fl, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstFinal;
|
|
};
|
|
class AstInitial final : public AstNodeProcedure {
|
|
public:
|
|
AstInitial(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Initial(fl, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstInitial;
|
|
};
|
|
class AstInitialAutomatic final : public AstNodeProcedure {
|
|
// Automatic variable initialization
|
|
// That is, it runs every function start, or class construction
|
|
public:
|
|
AstInitialAutomatic(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_InitialAutomatic(fl, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstInitialAutomatic;
|
|
};
|
|
class AstInitialStatic final : public AstNodeProcedure {
|
|
// Static variable initialization
|
|
// That is, it runs at the beginning of simulation, before 'initial' blocks
|
|
public:
|
|
AstInitialStatic(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_InitialStatic(fl, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstInitialStatic;
|
|
};
|
|
|
|
// === AstNodeRange ===
|
|
class AstBracketRange final : public AstNodeRange {
|
|
// Parser only concept "[lhsp]", an AstUnknownRange, QueueRange or Range,
|
|
// unknown until lhsp type is determined
|
|
// @astgen op1 := elementsp : AstNode // Expr or DType
|
|
public:
|
|
AstBracketRange(FileLine* fl, AstNode* elementsp)
|
|
: ASTGEN_SUPER_BracketRange(fl) {
|
|
this->elementsp(elementsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstBracketRange;
|
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
|
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
// Will be removed in V3Width, which relies on this
|
|
// being a child not a dtype pointed node
|
|
bool maybePointedTo() const override { return false; }
|
|
};
|
|
class AstRange final : public AstNodeRange {
|
|
// Range specification, for use under variables and cells
|
|
// @astgen op1 := leftp : AstNodeExpr
|
|
// @astgen op2 := rightp : AstNodeExpr
|
|
public:
|
|
AstRange(FileLine* fl, AstNodeExpr* leftp, AstNodeExpr* rightp)
|
|
: ASTGEN_SUPER_Range(fl) {
|
|
this->leftp(leftp);
|
|
this->rightp(rightp);
|
|
}
|
|
inline AstRange(FileLine* fl, int left, int right);
|
|
inline AstRange(FileLine* fl, const VNumRange& range);
|
|
ASTGEN_MEMBERS_AstRange;
|
|
inline int leftConst() const VL_MT_STABLE;
|
|
inline int rightConst() const VL_MT_STABLE;
|
|
int hiConst() const VL_MT_STABLE {
|
|
const int l = leftConst();
|
|
const int r = rightConst();
|
|
return l > r ? l : r;
|
|
}
|
|
int loConst() const VL_MT_STABLE {
|
|
const int l = leftConst();
|
|
const int r = rightConst();
|
|
return l > r ? r : l;
|
|
}
|
|
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
|
|
bool ascending() const { return leftConst() < rightConst(); }
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstUnsizedRange final : public AstNodeRange {
|
|
// Unsized range specification, for open arrays
|
|
public:
|
|
explicit AstUnsizedRange(FileLine* fl)
|
|
: ASTGEN_SUPER_UnsizedRange(fl) {}
|
|
ASTGEN_MEMBERS_AstUnsizedRange;
|
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
|
virtual string emitVerilog() { return "[]"; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstWildcardRange final : public AstNodeRange {
|
|
// Wildcard range specification, for wildcard index type associative arrays
|
|
public:
|
|
explicit AstWildcardRange(FileLine* fl)
|
|
: ASTGEN_SUPER_WildcardRange(fl) {}
|
|
ASTGEN_MEMBERS_AstWildcardRange;
|
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
|
virtual string emitVerilog() { return "[*]"; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
|
|
// === AstNodeStmt ===
|
|
class AstAlwaysPublic final : public AstNodeStmt {
|
|
// "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/
|
|
// Body statements are just AstVarRefs to the public signals
|
|
// @astgen op1 := sensesp : List[AstSenTree]
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_AlwaysPublic(fl) {
|
|
addSensesp(sensesp);
|
|
addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAlwaysPublic;
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
// Special accessors
|
|
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
};
|
|
class AstAssertCtl final : public AstNodeStmt {
|
|
// @astgen op1 := controlTypep : AstNodeExpr
|
|
// @astgen op2 := assertTypesp : Optional[AstNodeExpr]
|
|
// @astgen op3 := directiveTypesp : Optional[AstNodeExpr]
|
|
// Type of assertcontrol task; either known from parser or from evaluated
|
|
// controlTypep expression.
|
|
VAssertCtlType m_ctlType; // $assert keyword type (control_type)
|
|
VAssertType m_assertTypes; // Types of assertions affected
|
|
VAssertDirectiveType m_directiveTypes; // Types of directives affected
|
|
|
|
public:
|
|
AstAssertCtl(FileLine* fl, VAssertCtlType ctlType, AstNodeExpr* levelp = nullptr,
|
|
AstNodeExpr* itemsp = nullptr);
|
|
AstAssertCtl(FileLine* fl, AstNodeExpr* controlTypep, AstNodeExpr* assertTypesp = nullptr,
|
|
AstNodeExpr* directiveTypep = nullptr, AstNodeExpr* levelp = nullptr,
|
|
AstNodeExpr* itemsp = nullptr);
|
|
ASTGEN_MEMBERS_AstAssertCtl;
|
|
string verilogKwd() const override { return m_ctlType.ascii(); }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
VAssertCtlType ctlType() const { return m_ctlType; }
|
|
void ctlType(int32_t type) { m_ctlType = VAssertCtlType{type}; }
|
|
VAssertType ctlAssertTypes() const { return m_assertTypes; }
|
|
void ctlAssertTypes(VAssertType types) { m_assertTypes = types; }
|
|
VAssertDirectiveType ctlDirectiveTypes() const { return m_directiveTypes; }
|
|
void ctlDirectiveTypes(VAssertDirectiveType types) { m_directiveTypes = types; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void dumpJson(std::ostream& str = std::cout) const override;
|
|
};
|
|
class AstBreak final : public AstNodeStmt {
|
|
public:
|
|
explicit AstBreak(FileLine* fl)
|
|
: ASTGEN_SUPER_Break(fl) {}
|
|
ASTGEN_MEMBERS_AstBreak;
|
|
string verilogKwd() const override { return "break"; }
|
|
bool isBrancher() const override {
|
|
return true; // SPECIAL: We don't process code after breaks
|
|
}
|
|
};
|
|
class AstCReset final : public AstNodeStmt {
|
|
// Reset variable at startup
|
|
// @astgen op1 := varrefp : AstVarRef
|
|
public:
|
|
AstCReset(FileLine* fl, AstVarRef* varrefp)
|
|
: ASTGEN_SUPER_CReset(fl) {
|
|
this->varrefp(varrefp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCReset;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstCReturn final : public AstNodeStmt {
|
|
// C++ return from a function
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
public:
|
|
AstCReturn(FileLine* fl, AstNodeExpr* lhsp)
|
|
: ASTGEN_SUPER_CReturn(fl) {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCReturn;
|
|
int instrCount() const override { return widthInstrs(); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstCStmt final : public AstNodeStmt {
|
|
// Emit C statement
|
|
// @astgen op1 := exprsp : List[AstNode]
|
|
public:
|
|
AstCStmt(FileLine* fl, AstNode* exprsp)
|
|
: ASTGEN_SUPER_CStmt(fl) {
|
|
this->addExprsp(exprsp);
|
|
}
|
|
inline AstCStmt(FileLine* fl, const string& textStmt);
|
|
ASTGEN_MEMBERS_AstCStmt;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstComment final : public AstNodeStmt {
|
|
// Some comment to put into the output stream
|
|
const string m_name; // Text of comment
|
|
const bool m_showAt; // Show "at <fileline>"
|
|
public:
|
|
AstComment(FileLine* fl, const string& name, bool showAt = false)
|
|
: ASTGEN_SUPER_Comment(fl)
|
|
, m_name{name}
|
|
, m_showAt{showAt} {}
|
|
ASTGEN_MEMBERS_AstComment;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Text
|
|
bool same(const AstNode* samep) const override { return true; } // Ignore name in comments
|
|
virtual bool showAt() const { return m_showAt; }
|
|
};
|
|
class AstConstraintExpr final : public AstNodeStmt {
|
|
// Constraint expression
|
|
// @astgen op1 := exprp : AstNodeExpr
|
|
bool m_isSoft = false; // Soft constraint expression
|
|
bool m_isDisableSoft = false; // Disable soft constraint expression
|
|
public:
|
|
AstConstraintExpr(FileLine* fl, AstNodeExpr* exprp)
|
|
: ASTGEN_SUPER_ConstraintExpr(fl) {
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConstraintExpr;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool isDisableSoft() const { return m_isDisableSoft; }
|
|
void isDisableSoft(bool flag) { m_isDisableSoft = flag; }
|
|
bool isSoft() const { return m_isSoft; }
|
|
void isSoft(bool flag) { m_isSoft = flag; }
|
|
};
|
|
class AstConstraintUnique final : public AstNodeStmt {
|
|
// Constraint unique statement
|
|
// @astgen op1 := rangesp : List[AstNode]
|
|
public:
|
|
AstConstraintUnique(FileLine* fl, AstNode* rangesp)
|
|
: ASTGEN_SUPER_ConstraintUnique(fl) {
|
|
this->addRangesp(rangesp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConstraintUnique;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstContinue final : public AstNodeStmt {
|
|
public:
|
|
explicit AstContinue(FileLine* fl)
|
|
: ASTGEN_SUPER_Continue(fl) {}
|
|
ASTGEN_MEMBERS_AstContinue;
|
|
string verilogKwd() const override { return "continue"; }
|
|
bool isBrancher() const override {
|
|
return true; // SPECIAL: We don't process code after breaks
|
|
}
|
|
};
|
|
class AstCoverDecl final : public AstNodeStmt {
|
|
// Coverage analysis point declaration
|
|
//
|
|
// [After V3CoverageJoin] Duplicate declaration to get data from instead
|
|
// @astgen ptr := m_dataDeclp : Optional[AstCoverDecl]
|
|
string m_page;
|
|
string m_text;
|
|
string m_hier;
|
|
string m_linescov;
|
|
int m_offset; // Offset column numbers to uniq-ify IFs
|
|
int m_binNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
|
public:
|
|
AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov,
|
|
int offset)
|
|
: ASTGEN_SUPER_CoverDecl(fl)
|
|
, m_page{page}
|
|
, m_text{comment}
|
|
, m_linescov{linescov}
|
|
, m_offset{offset} {}
|
|
ASTGEN_MEMBERS_AstCoverDecl;
|
|
const char* broken() const override {
|
|
if (m_dataDeclp
|
|
&& (m_dataDeclp == this || m_dataDeclp->m_dataDeclp)) { // Avoid O(n^2) accessing
|
|
v3fatalSrc("dataDeclp should point to real data, not be a list: " << cvtToHex(this));
|
|
}
|
|
return nullptr;
|
|
}
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
|
bool maybePointedTo() const override { return true; }
|
|
int binNum() const { return m_binNum; }
|
|
void binNum(int flag) { m_binNum = flag; }
|
|
int offset() const { return m_offset; }
|
|
const string& comment() const { return m_text; } // text to insert in code
|
|
const string& linescov() const { return m_linescov; }
|
|
const string& page() const { return m_page; }
|
|
const string& hier() const { return m_hier; }
|
|
void hier(const string& flag) { m_hier = flag; }
|
|
void comment(const string& flag) { m_text = flag; }
|
|
bool same(const AstNode* samep) const override {
|
|
const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl);
|
|
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
|
|
&& hier() == asamep->hier() && comment() == asamep->comment());
|
|
}
|
|
bool isPredictOptimizable() const override { return false; }
|
|
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
|
|
// dataDecl nullptr means "use this one", but often you want "this" to
|
|
// indicate to get data from here
|
|
AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; }
|
|
AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; }
|
|
};
|
|
class AstCoverInc final : public AstNodeStmt {
|
|
// Coverage analysis point; increment coverage count
|
|
//
|
|
// @astgen ptr := m_declp : AstCoverDecl // [After V3CoverageJoin] Declaration
|
|
public:
|
|
AstCoverInc(FileLine* fl, AstCoverDecl* declp)
|
|
: ASTGEN_SUPER_CoverInc(fl)
|
|
, m_declp{declp} {}
|
|
ASTGEN_MEMBERS_AstCoverInc;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
|
bool same(const AstNode* samep) const override {
|
|
return declp() == VN_DBG_AS(samep, CoverInc)->declp();
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isPure() override { return false; }
|
|
AstCoverDecl* declp() const { return m_declp; } // Where defined
|
|
};
|
|
class AstCoverToggle final : public AstNodeStmt {
|
|
// Toggle analysis of given signal
|
|
// Parents: MODULE
|
|
// @astgen op1 := incp : AstCoverInc
|
|
// @astgen op2 := origp : AstNodeExpr
|
|
// @astgen op3 := changep : AstNodeExpr
|
|
public:
|
|
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNodeExpr* origp, AstNodeExpr* changep)
|
|
: ASTGEN_SUPER_CoverToggle(fl) {
|
|
this->incp(incp);
|
|
this->origp(origp);
|
|
this->changep(changep);
|
|
}
|
|
ASTGEN_MEMBERS_AstCoverToggle;
|
|
int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return true; }
|
|
bool isOutputter() override {
|
|
return false; // Though the AstCoverInc under this is an outputter
|
|
}
|
|
// but isPure() true
|
|
};
|
|
class AstDelay final : public AstNodeStmt {
|
|
// Delay statement
|
|
// @astgen op1 := lhsp : AstNodeExpr // Delay value
|
|
// @astgen op2 := stmtsp : List[AstNode] // Statements under delay
|
|
VTimescale m_timeunit; // Delay's time unit
|
|
const bool m_isCycle; // True if it is a cycle delay
|
|
|
|
public:
|
|
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle)
|
|
: ASTGEN_SUPER_Delay(fl)
|
|
, m_isCycle{isCycle} {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstDelay;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
bool isTimingControl() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
bool isCycleDelay() const { return m_isCycle; }
|
|
};
|
|
class AstDisable final : public AstNodeStmt {
|
|
string m_name; // Name of block
|
|
public:
|
|
AstDisable(FileLine* fl, const string& name)
|
|
: ASTGEN_SUPER_Disable(fl)
|
|
, m_name{name} {}
|
|
ASTGEN_MEMBERS_AstDisable;
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
|
void name(const string& flag) override { m_name = flag; }
|
|
bool isBrancher() const override {
|
|
return true; // SPECIAL: We don't process code after breaks
|
|
}
|
|
};
|
|
class AstDisableFork final : public AstNodeStmt {
|
|
// A "disable fork" statement
|
|
public:
|
|
explicit AstDisableFork(FileLine* fl)
|
|
: ASTGEN_SUPER_DisableFork(fl) {}
|
|
ASTGEN_MEMBERS_AstDisableFork;
|
|
};
|
|
class AstDisplay final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := fmtp : AstSFormatF
|
|
// @astgen op2 := filep : Optional[AstNodeExpr] // file (must resolve to a VarRef)
|
|
VDisplayType m_displayType;
|
|
|
|
public:
|
|
AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNodeExpr* filep,
|
|
AstNodeExpr* exprsp, char missingArgChar = 'd')
|
|
: ASTGEN_SUPER_Display(fl)
|
|
, m_displayType{dispType} {
|
|
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
|
|
this->filep(filep);
|
|
}
|
|
AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp,
|
|
char missingArgChar = 'd')
|
|
: ASTGEN_SUPER_Display(fl)
|
|
, m_displayType{dispType} {
|
|
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
|
|
this->filep(filep);
|
|
}
|
|
ASTGEN_MEMBERS_AstDisplay;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!fmtp());
|
|
return nullptr;
|
|
}
|
|
string verilogKwd() const override {
|
|
return (filep() ? "$f"s + string{displayType().ascii()}
|
|
: "$"s + string{displayType().ascii()});
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* samep) const override {
|
|
return displayType() == VN_DBG_AS(samep, Display)->displayType();
|
|
}
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
VDisplayType displayType() const { return m_displayType; }
|
|
void displayType(VDisplayType type) { m_displayType = type; }
|
|
// * = Add a newline for $display
|
|
bool addNewline() const { return displayType().addNewline(); }
|
|
};
|
|
class AstDoWhile final : public AstNodeStmt {
|
|
// @astgen op1 := condp : AstNodeExpr
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr)
|
|
: ASTGEN_SUPER_DoWhile(fl) {
|
|
condp(conditionp);
|
|
addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstDoWhile;
|
|
bool isGateOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
// Stop statement searchback here
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
};
|
|
class AstDumpCtl final : public AstNodeStmt {
|
|
// $dumpon etc
|
|
// Parents: expr
|
|
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression based on type of statement
|
|
const VDumpCtlType m_ctlType; // Type of operation
|
|
public:
|
|
AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNodeExpr* exprp = nullptr)
|
|
: ASTGEN_SUPER_DumpCtl(fl)
|
|
, m_ctlType{ctlType} {
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstDumpCtl;
|
|
string verilogKwd() const override { return ctlType().ascii(); }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
virtual bool cleanOut() const { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
VDumpCtlType ctlType() const { return m_ctlType; }
|
|
};
|
|
class AstEventControl final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := sensesp : Optional[AstSenTree]
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_EventControl(fl) {
|
|
this->sensesp(sensesp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstEventControl;
|
|
string verilogKwd() const override { return "@(%l) %r"; }
|
|
bool isTimingControl() const override { return true; }
|
|
int instrCount() const override { return 0; }
|
|
};
|
|
class AstFClose final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := filep : AstNodeExpr // file (must be a VarRef)
|
|
public:
|
|
AstFClose(FileLine* fl, AstNodeExpr* filep)
|
|
: ASTGEN_SUPER_FClose(fl) {
|
|
this->filep(filep);
|
|
}
|
|
ASTGEN_MEMBERS_AstFClose;
|
|
string verilogKwd() const override { return "$fclose"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstFFlush final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := filep : Optional[AstNodeExpr] // file (must be a VarRef)
|
|
public:
|
|
AstFFlush(FileLine* fl, AstNodeExpr* filep)
|
|
: ASTGEN_SUPER_FFlush(fl) {
|
|
this->filep(filep);
|
|
}
|
|
ASTGEN_MEMBERS_AstFFlush;
|
|
string verilogKwd() const override { return "$fflush"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstFinish final : public AstNodeStmt {
|
|
public:
|
|
explicit AstFinish(FileLine* fl)
|
|
: ASTGEN_SUPER_Finish(fl) {}
|
|
ASTGEN_MEMBERS_AstFinish;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
|
bool isUnlikely() const override { return true; }
|
|
int instrCount() const override { return 0; } // Rarely executes
|
|
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
|
};
|
|
class AstFireEvent final : public AstNodeStmt {
|
|
// '-> _' and '->> _' event trigger statements
|
|
// @astgen op1 := operandp : AstNodeExpr
|
|
const bool m_delayed; // Delayed (->>) vs non-delayed (->)
|
|
public:
|
|
AstFireEvent(FileLine* fl, AstNodeExpr* operandp, bool delayed)
|
|
: ASTGEN_SUPER_FireEvent(fl)
|
|
, m_delayed{delayed} {
|
|
this->operandp(operandp);
|
|
}
|
|
ASTGEN_MEMBERS_AstFireEvent;
|
|
bool isDelayed() const { return m_delayed; }
|
|
};
|
|
class AstJumpBlock final : public AstNodeStmt {
|
|
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
|
|
// Parents: {statement list}
|
|
// Children: {statement list, with JumpGo and JumpLabel below}
|
|
// @astgen op1 := stmtsp : List[AstNode]
|
|
// @astgen op2 := endStmtsp : List[AstNode]
|
|
//
|
|
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
|
|
int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
|
VIsCached m_purity; // Pure state
|
|
public:
|
|
// After construction must call ->labelp to associate with appropriate label
|
|
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_JumpBlock(fl) {
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstJumpBlock;
|
|
const char* broken() const override;
|
|
int instrCount() const override { return 0; }
|
|
bool maybePointedTo() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
int labelNum() const { return m_labelNum; }
|
|
void labelNum(int flag) { m_labelNum = flag; }
|
|
AstJumpLabel* labelp() const { return m_labelp; }
|
|
void labelp(AstJumpLabel* labelp) { m_labelp = labelp; }
|
|
bool isPure() override;
|
|
|
|
private:
|
|
bool getPurityRecurse() const;
|
|
};
|
|
class AstJumpGo final : public AstNodeStmt {
|
|
// Jump point; branch down to a JumpLabel
|
|
// No support for backward jumps at present
|
|
// Parents: {statement list with JumpBlock above}
|
|
// Children: none
|
|
//
|
|
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
|
|
public:
|
|
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
|
: ASTGEN_SUPER_JumpGo(fl)
|
|
, m_labelp{labelp} {}
|
|
ASTGEN_MEMBERS_AstJumpGo;
|
|
const char* broken() const override;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* samep) const override {
|
|
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isBrancher() const override {
|
|
return true; // SPECIAL: We don't process code after breaks
|
|
}
|
|
AstJumpLabel* labelp() const { return m_labelp; }
|
|
};
|
|
class AstJumpLabel final : public AstNodeStmt {
|
|
// Jump point declaration
|
|
// Parents: {statement list with JumpBlock above}
|
|
// Children: none
|
|
// @astgen ptr := m_blockp : AstJumpBlock // [After V3Jump] Pointer to declaration
|
|
public:
|
|
AstJumpLabel(FileLine* fl, AstJumpBlock* blockp)
|
|
: ASTGEN_SUPER_JumpLabel(fl)
|
|
, m_blockp{blockp} {}
|
|
ASTGEN_MEMBERS_AstJumpLabel;
|
|
bool maybePointedTo() const override { return true; }
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!blockp()->brokeExistsAbove());
|
|
BROKEN_RTN(blockp()->labelp() != this);
|
|
return nullptr;
|
|
}
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return 0; }
|
|
bool same(const AstNode* samep) const override {
|
|
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
|
|
}
|
|
AstJumpBlock* blockp() const { return m_blockp; }
|
|
};
|
|
class AstMonitorOff final : public AstNodeStmt {
|
|
const bool m_off; // Monitor off. Using 0=on allows faster init and comparison
|
|
|
|
public:
|
|
AstMonitorOff(FileLine* fl, bool off)
|
|
: ASTGEN_SUPER_MonitorOff(fl)
|
|
, m_off{off} {}
|
|
ASTGEN_MEMBERS_AstMonitorOff;
|
|
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
|
|
bool isGateOptimizable() const override { return false; } // Though deleted before opt
|
|
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
|
|
bool isPure() override { return false; } // Though deleted before opt
|
|
bool isOutputter() override { return true; } // Though deleted before opt
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
bool same(const AstNode* samep) const override {
|
|
return m_off == VN_DBG_AS(samep, MonitorOff)->m_off;
|
|
}
|
|
bool off() const { return m_off; }
|
|
};
|
|
class AstPrintTimeScale final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
string m_name; // Parent module name
|
|
VTimescale m_timeunit; // Parent module time unit
|
|
public:
|
|
explicit AstPrintTimeScale(FileLine* fl)
|
|
: ASTGEN_SUPER_PrintTimeScale(fl) {}
|
|
ASTGEN_MEMBERS_AstPrintTimeScale;
|
|
void name(const string& name) override { m_name = name; }
|
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
string verilogKwd() const override { return "$printtimescale"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
class AstRandCase final : public AstNodeStmt {
|
|
// @astgen op2 := itemsp : List[AstCaseItem]
|
|
public:
|
|
AstRandCase(FileLine* fl, AstCaseItem* itemsp)
|
|
: ASTGEN_SUPER_RandCase(fl) {
|
|
addItemsp(itemsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstRandCase;
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
};
|
|
class AstRelease final : public AstNodeStmt {
|
|
// Procedural 'release' statement
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
public:
|
|
AstRelease(FileLine* fl, AstNodeExpr* lhsp)
|
|
: ASTGEN_SUPER_Release(fl) {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstRelease;
|
|
};
|
|
class AstRepeat final : public AstNodeStmt {
|
|
// @astgen op1 := countp : AstNodeExpr
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Repeat(fl) {
|
|
this->countp(countp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstRepeat;
|
|
bool isGateOptimizable() const override { return false; } // Not relevant - converted to FOR
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
};
|
|
class AstReturn final : public AstNodeStmt {
|
|
// @astgen op1 := lhsp : Optional[AstNodeExpr]
|
|
public:
|
|
explicit AstReturn(FileLine* fl, AstNodeExpr* lhsp = nullptr)
|
|
: ASTGEN_SUPER_Return(fl) {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstReturn;
|
|
string verilogKwd() const override { return "return"; }
|
|
bool isBrancher() const override {
|
|
return true; // SPECIAL: We don't process code after breaks
|
|
}
|
|
};
|
|
class AstSFormat final : public AstNodeStmt {
|
|
// Parents: statement container
|
|
// @astgen op1 := fmtp : AstSFormatF
|
|
// @astgen op2 := lhsp : AstNodeExpr
|
|
public:
|
|
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, const string& text, AstNodeExpr* exprsp,
|
|
char missingArgChar = 'd')
|
|
: ASTGEN_SUPER_SFormat(fl) {
|
|
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
|
|
this->lhsp(lhsp);
|
|
}
|
|
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd')
|
|
: ASTGEN_SUPER_SFormat(fl) {
|
|
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSFormat;
|
|
const char* broken() const override {
|
|
BROKEN_RTN(!fmtp());
|
|
return nullptr;
|
|
}
|
|
string verilogKwd() const override { return "$sformat"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return true; }
|
|
bool isPure() override { return true; }
|
|
bool isOutputter() override { return false; }
|
|
virtual bool cleanOut() const { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstStackTraceT final : public AstNodeStmt {
|
|
// $stacktrace used as task
|
|
public:
|
|
explicit AstStackTraceT(FileLine* fl)
|
|
: ASTGEN_SUPER_StackTraceT(fl) {}
|
|
ASTGEN_MEMBERS_AstStackTraceT;
|
|
string verilogKwd() const override { return "$stacktrace"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstStmtExpr final : public AstNodeStmt {
|
|
// Expression in statement position
|
|
// @astgen op1 := exprp : AstNodeExpr
|
|
public:
|
|
AstStmtExpr(FileLine* fl, AstNodeExpr* exprp)
|
|
: ASTGEN_SUPER_StmtExpr(fl) {
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstStmtExpr;
|
|
bool isPure() override { return exprp()->isPure(); }
|
|
};
|
|
class AstStop final : public AstNodeStmt {
|
|
public:
|
|
AstStop(FileLine* fl, bool maybe)
|
|
: ASTGEN_SUPER_Stop(fl) {}
|
|
ASTGEN_MEMBERS_AstStop;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
|
bool isUnlikely() const override { return true; }
|
|
int instrCount() const override { return 0; } // Rarely executes
|
|
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
|
};
|
|
class AstSysFuncAsTask final : public AstNodeStmt {
|
|
// TODO: This is superseded by AstStmtExpr, remove
|
|
// Call what is normally a system function (with a return) in a non-return context
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
public:
|
|
AstSysFuncAsTask(FileLine* fl, AstNodeExpr* lhsp)
|
|
: ASTGEN_SUPER_SysFuncAsTask(fl) {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSysFuncAsTask;
|
|
string verilogKwd() const override { return ""; }
|
|
bool isGateOptimizable() const override { return true; }
|
|
bool isPredictOptimizable() const override { return true; }
|
|
bool isPure() override { return true; }
|
|
bool isOutputter() override { return false; }
|
|
int instrCount() const override { return 0; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstSystemT final : public AstNodeStmt {
|
|
// $system used as task
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
public:
|
|
AstSystemT(FileLine* fl, AstNodeExpr* lhsp)
|
|
: ASTGEN_SUPER_SystemT(fl) {
|
|
this->lhsp(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSystemT;
|
|
string verilogKwd() const override { return "$system"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstTimeFormat final : public AstNodeStmt {
|
|
// Parents: stmtlist
|
|
// @astgen op1 := unitsp : AstNodeExpr
|
|
// @astgen op2 := precisionp : AstNodeExpr
|
|
// @astgen op3 := suffixp : AstNodeExpr
|
|
// @astgen op4 := widthp : AstNodeExpr
|
|
public:
|
|
AstTimeFormat(FileLine* fl, AstNodeExpr* unitsp, AstNodeExpr* precisionp, AstNodeExpr* suffixp,
|
|
AstNodeExpr* widthp)
|
|
: ASTGEN_SUPER_TimeFormat(fl) {
|
|
this->unitsp(unitsp);
|
|
this->precisionp(precisionp);
|
|
this->suffixp(suffixp);
|
|
this->widthp(widthp);
|
|
}
|
|
ASTGEN_MEMBERS_AstTimeFormat;
|
|
string verilogKwd() const override { return "$timeformat"; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
};
|
|
class AstTraceDecl final : public AstNodeStmt {
|
|
// Trace point declaration
|
|
// Separate from AstTraceInc; as a declaration can't be deleted
|
|
// Parents: {statement list}
|
|
// Expression being traced - Moved to AstTraceInc by V3Trace
|
|
// @astgen op1 := valuep : Optional[AstNodeExpr]
|
|
uint32_t m_code{0}; // Trace identifier code
|
|
uint32_t m_fidx{0}; // Trace function index
|
|
const string m_showname; // Name of variable
|
|
const VNumRange m_bitRange; // Property of var the trace details
|
|
const VNumRange m_arrayRange; // Property of var the trace details
|
|
const VVarType m_varType; // Type of variable (for localparam vs. param)
|
|
const VDirection m_declDirection; // Declared direction input/output etc
|
|
public:
|
|
AstTraceDecl(FileLine* fl, const string& showname,
|
|
AstVar* varp, // For input/output state etc
|
|
AstNodeExpr* valuep, const VNumRange& bitRange, const VNumRange& arrayRange)
|
|
: ASTGEN_SUPER_TraceDecl(fl)
|
|
, m_showname{showname}
|
|
, m_bitRange{bitRange}
|
|
, m_arrayRange{arrayRange}
|
|
, m_varType{varp->varType()}
|
|
, m_declDirection{varp->declDirection()} {
|
|
dtypeFrom(valuep);
|
|
this->valuep(valuep);
|
|
}
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return 100; } // Large...
|
|
ASTGEN_MEMBERS_AstTraceDecl;
|
|
string name() const override VL_MT_STABLE { return m_showname; }
|
|
bool maybePointedTo() const override { return true; }
|
|
bool hasDType() const override { return true; }
|
|
bool same(const AstNode* samep) const override { return false; }
|
|
string showname() const { return m_showname; } // * = Var name
|
|
// Details on what we're tracing
|
|
uint32_t code() const { return m_code; }
|
|
void code(uint32_t code) { m_code = code; }
|
|
uint32_t fidx() const { return m_fidx; }
|
|
void fidx(uint32_t fidx) { m_fidx = fidx; }
|
|
uint32_t codeInc() const {
|
|
return (m_arrayRange.ranged() ? m_arrayRange.elements() : 1)
|
|
* valuep()->dtypep()->widthWords()
|
|
* (VL_EDATASIZE / 32); // A code is always 32-bits
|
|
}
|
|
const VNumRange& bitRange() const { return m_bitRange; }
|
|
const VNumRange& arrayRange() const { return m_arrayRange; }
|
|
VVarType varType() const { return m_varType; }
|
|
VDirection declDirection() const { return m_declDirection; }
|
|
};
|
|
class AstTraceInc final : public AstNodeStmt {
|
|
// Trace point dump
|
|
// @astgen op1 := valuep : AstNodeExpr // Expression being traced (from decl)
|
|
//
|
|
// @astgen ptr := m_declp : AstTraceDecl // Pointer to declaration
|
|
const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc
|
|
const VTraceType m_traceType; // Is this a const/full/incremental dump
|
|
|
|
public:
|
|
AstTraceInc(FileLine* fl, AstTraceDecl* declp, VTraceType traceType, uint32_t baseCode = 0)
|
|
: ASTGEN_SUPER_TraceInc(fl)
|
|
, m_baseCode{baseCode}
|
|
, m_traceType{traceType}
|
|
, m_declp{declp} {
|
|
dtypeFrom(declp);
|
|
// Note: A clone is necessary (instead of using declp()->valuep()),
|
|
// for insertion of local temporaries in V3Premit
|
|
valuep(declp->valuep()->cloneTree(true));
|
|
}
|
|
ASTGEN_MEMBERS_AstTraceInc;
|
|
void dump(std::ostream& str) const override;
|
|
void dumpJson(std::ostream& str) const override;
|
|
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
|
|
bool hasDType() const override { return true; }
|
|
bool same(const AstNode* samep) const override {
|
|
return declp() == VN_DBG_AS(samep, TraceInc)->declp();
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool isPure() override { return false; }
|
|
AstTraceDecl* declp() const { return m_declp; }
|
|
VTraceType traceType() const { return m_traceType; }
|
|
uint32_t baseCode() const { return m_baseCode; }
|
|
};
|
|
class AstTracePopPrefix final : public AstNodeStmt {
|
|
public:
|
|
explicit AstTracePopPrefix(FileLine* fl)
|
|
: ASTGEN_SUPER_TracePopPrefix(fl) {}
|
|
ASTGEN_MEMBERS_AstTracePopPrefix;
|
|
bool same(const AstNode* samep) const override { return false; }
|
|
};
|
|
class AstTracePushPrefix final : public AstNodeStmt {
|
|
const string m_prefix; // Prefix to add to signal names
|
|
const VTracePrefixType m_prefixType; // Type of prefix being pushed
|
|
public:
|
|
AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType)
|
|
: ASTGEN_SUPER_TracePushPrefix(fl)
|
|
, m_prefix{prefix}
|
|
, m_prefixType{prefixType} {}
|
|
ASTGEN_MEMBERS_AstTracePushPrefix;
|
|
bool same(const AstNode* samep) const override { return false; }
|
|
string prefix() const { return m_prefix; }
|
|
VTracePrefixType prefixType() const { return m_prefixType; }
|
|
};
|
|
class AstUCStmt final : public AstNodeStmt {
|
|
// User $c statement
|
|
// @astgen op1 := exprsp : List[AstNode] // (some are AstText)
|
|
public:
|
|
AstUCStmt(FileLine* fl, AstNode* exprsp)
|
|
: ASTGEN_SUPER_UCStmt(fl) {
|
|
this->addExprsp(exprsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstUCStmt;
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() override { return false; }
|
|
bool isOutputter() override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstWait final : public AstNodeStmt {
|
|
// @astgen op1 := condp : AstNodeExpr
|
|
// @astgen op2 := stmtsp : List[AstNode]
|
|
public:
|
|
AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Wait(fl) {
|
|
this->condp(condp);
|
|
this->addStmtsp(stmtsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstWait;
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
bool isTimingControl() const override { return true; }
|
|
};
|
|
class AstWaitFork final : public AstNodeStmt {
|
|
// A "wait fork" statement
|
|
public:
|
|
explicit AstWaitFork(FileLine* fl)
|
|
: ASTGEN_SUPER_WaitFork(fl) {}
|
|
ASTGEN_MEMBERS_AstWaitFork;
|
|
bool isTimingControl() const override { return true; }
|
|
};
|
|
class AstWhile final : public AstNodeStmt {
|
|
// @astgen op1 := precondsp : List[AstNode]
|
|
// @astgen op2 := condp : AstNodeExpr
|
|
// @astgen op3 := stmtsp : List[AstNode]
|
|
// @astgen op4 := incsp : List[AstNode]
|
|
VOptionBool m_unrollFull; // Full, disable, or default unrolling
|
|
public:
|
|
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
|
|
: ASTGEN_SUPER_While(fl) {
|
|
this->condp(condp);
|
|
this->addStmtsp(stmtsp);
|
|
this->addIncsp(incsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstWhile;
|
|
void dump(std::ostream& str) const override;
|
|
bool isGateOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
// Stop statement searchback here
|
|
void addNextStmt(AstNode* newp, AstNode* belowp) override;
|
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
|
VOptionBool unrollFull() const { return m_unrollFull; }
|
|
void unrollFull(const VOptionBool flag) { m_unrollFull = flag; }
|
|
};
|
|
|
|
// === AstNodeAssign ===
|
|
class AstAssign final : public AstNodeAssign {
|
|
public:
|
|
AstAssign(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
|
AstNode* timingControlp = nullptr)
|
|
: ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) {
|
|
dtypeFrom(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAssign;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
|
return new AstAssign{fileline(), lhsp, rhsp, controlp};
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
};
|
|
class AstAssignAlias final : public AstNodeAssign {
|
|
// Like AstAssignW, but a true bidirect interconnection alias
|
|
// If both sides are wires, there's no LHS vs RHS,
|
|
public:
|
|
AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp)
|
|
: ASTGEN_SUPER_AssignAlias(fl, (AstNodeExpr*)lhsp, (AstNodeExpr*)rhsp) {}
|
|
ASTGEN_MEMBERS_AstAssignAlias;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
V3ERROR_NA_RETURN(nullptr);
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return false; }
|
|
};
|
|
class AstAssignDly final : public AstNodeAssign {
|
|
public:
|
|
AstAssignDly(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
|
AstNode* timingControlp = nullptr)
|
|
: ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {}
|
|
ASTGEN_MEMBERS_AstAssignDly;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
|
return new AstAssignDly{fileline(), lhsp, rhsp, controlp};
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
string verilogKwd() const override { return "<="; }
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
};
|
|
class AstAssignForce final : public AstNodeAssign {
|
|
// Procedural 'force' statement
|
|
public:
|
|
AstAssignForce(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {}
|
|
ASTGEN_MEMBERS_AstAssignForce;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAssignForce{fileline(), lhsp, rhsp};
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
};
|
|
class AstAssignPost final : public AstNodeAssign {
|
|
// Like Assign, but predelayed assignment requiring special order handling
|
|
public:
|
|
AstAssignPost(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {}
|
|
ASTGEN_MEMBERS_AstAssignPost;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAssignPost{fileline(), lhsp, rhsp};
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
};
|
|
class AstAssignPre final : public AstNodeAssign {
|
|
// Like Assign, but predelayed assignment requiring special order handling
|
|
public:
|
|
AstAssignPre(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {}
|
|
ASTGEN_MEMBERS_AstAssignPre;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAssignPre{fileline(), lhsp, rhsp};
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
};
|
|
class AstAssignVarScope final : public AstNodeAssign {
|
|
// Assign two VarScopes to each other
|
|
public:
|
|
AstAssignVarScope(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) {
|
|
dtypeFrom(rhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstAssignVarScope;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAssignVarScope{fileline(), lhsp, rhsp};
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return false; }
|
|
};
|
|
class AstAssignW final : public AstNodeAssign {
|
|
// Like assign, but wire/assign's in verilog, the only setting of the specified variable
|
|
// @astgen op4 := strengthSpecp : Optional[AstStrengthSpec]
|
|
public:
|
|
AstAssignW(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
|
AstNode* timingControlp = nullptr)
|
|
: ASTGEN_SUPER_AssignW(fl, lhsp, rhsp, timingControlp) {}
|
|
ASTGEN_MEMBERS_AstAssignW;
|
|
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
|
return new AstAssignW{fileline(), lhsp, rhsp, controlp};
|
|
}
|
|
bool isTimingControl() const override {
|
|
return timingControlp() || lhsp()->exists([](const AstNodeVarRef* refp) {
|
|
return refp->access().isWriteOrRW() && refp->varp()->delayp();
|
|
});
|
|
}
|
|
bool brokeLhsMustBeLvalue() const override { return true; }
|
|
AstAlways* convertToAlways();
|
|
};
|
|
|
|
// === AstNodeCase ===
|
|
class AstCase final : public AstNodeCase {
|
|
// Case statement
|
|
VCaseType m_casex; // 0=case, 1=casex, 2=casez
|
|
bool m_fullPragma = false; // Synthesis full_case
|
|
bool m_parallelPragma = false; // Synthesis parallel_case
|
|
bool m_uniquePragma = false; // unique case
|
|
bool m_unique0Pragma = false; // unique0 case
|
|
bool m_priorityPragma = false; // priority case
|
|
public:
|
|
AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
|
: ASTGEN_SUPER_Case(fl, exprp, itemsp)
|
|
, m_casex{casex} {}
|
|
ASTGEN_MEMBERS_AstCase;
|
|
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
|
|
bool same(const AstNode* samep) const override {
|
|
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
|
|
}
|
|
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
|
|
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
|
|
bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; }
|
|
bool caseSimple() const { return m_casex == VCaseType::CT_CASE; }
|
|
void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; }
|
|
bool fullPragma() const { return m_fullPragma; }
|
|
void fullPragma(bool flag) { m_fullPragma = flag; }
|
|
bool parallelPragma() const { return m_parallelPragma; }
|
|
void parallelPragma(bool flag) { m_parallelPragma = flag; }
|
|
bool uniquePragma() const { return m_uniquePragma; }
|
|
void uniquePragma(bool flag) { m_uniquePragma = flag; }
|
|
bool unique0Pragma() const { return m_unique0Pragma; }
|
|
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
|
|
bool priorityPragma() const { return m_priorityPragma; }
|
|
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
|
string pragmaString() const;
|
|
};
|
|
class AstGenCase final : public AstNodeCase {
|
|
// Generate Case statement
|
|
public:
|
|
AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
|
: ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {}
|
|
ASTGEN_MEMBERS_AstGenCase;
|
|
};
|
|
|
|
// === AstNodeCoverOrAssert ===
|
|
class AstAssert final : public AstNodeCoverOrAssert {
|
|
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstAssert;
|
|
AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, VAssertType type,
|
|
VAssertDirectiveType directive, const string& name = "")
|
|
: ASTGEN_SUPER_Assert(fl, propp, passsp, type, directive, name) {
|
|
this->addFailsp(failsp);
|
|
}
|
|
};
|
|
class AstAssertIntrinsic final : public AstNodeCoverOrAssert {
|
|
// A $cast or other compiler inserted assert, that must run even without --assert option
|
|
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
|
|
public:
|
|
ASTGEN_MEMBERS_AstAssertIntrinsic;
|
|
AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp,
|
|
const string& name = "")
|
|
// Intrinsic asserts are always enabled thus 'type' field is set to INTERNAL.
|
|
: ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, VAssertType::INTERNAL,
|
|
VAssertDirectiveType::INTRINSIC, name) {
|
|
this->addFailsp(failsp);
|
|
}
|
|
};
|
|
class AstCover final : public AstNodeCoverOrAssert {
|
|
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
|
public:
|
|
ASTGEN_MEMBERS_AstCover;
|
|
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
|
const string& name = "")
|
|
: ASTGEN_SUPER_Cover(fl, propp, stmtsp, type, VAssertDirectiveType::COVER, name) {}
|
|
};
|
|
class AstRestrict final : public AstNodeCoverOrAssert {
|
|
public:
|
|
ASTGEN_MEMBERS_AstRestrict;
|
|
AstRestrict(FileLine* fl, AstNode* propp)
|
|
// Intrinsic asserts are always ignored thus 'type' field is set to INTERNAL.
|
|
: ASTGEN_SUPER_Restrict(fl, propp, nullptr, VAssertType::INTERNAL,
|
|
VAssertDirectiveType::RESTRICT) {}
|
|
};
|
|
|
|
// === AstNodeFor ===
|
|
class AstGenFor final : public AstNodeFor {
|
|
public:
|
|
AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstGenFor;
|
|
};
|
|
|
|
// === AstNodeForeach ===
|
|
class AstConstraintForeach final : public AstNodeForeach {
|
|
// Constraint foreach statement
|
|
public:
|
|
AstConstraintForeach(FileLine* fl, AstNodeExpr* exprp, AstNode* bodysp)
|
|
: ASTGEN_SUPER_ConstraintForeach(fl, exprp, bodysp) {}
|
|
ASTGEN_MEMBERS_AstConstraintForeach;
|
|
};
|
|
class AstForeach final : public AstNodeForeach {
|
|
public:
|
|
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
|
|
: ASTGEN_SUPER_Foreach(fl, arrayp, stmtsp) {}
|
|
ASTGEN_MEMBERS_AstForeach;
|
|
};
|
|
|
|
// === AstNodeIf ===
|
|
class AstConstraintIf final : public AstNodeIf {
|
|
public:
|
|
AstConstraintIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
|
|
: ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {}
|
|
ASTGEN_MEMBERS_AstConstraintIf;
|
|
};
|
|
class AstGenIf final : public AstNodeIf {
|
|
public:
|
|
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
|
|
: ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {}
|
|
ASTGEN_MEMBERS_AstGenIf;
|
|
};
|
|
class AstIf final : public AstNodeIf {
|
|
bool m_uniquePragma = false; // unique case
|
|
bool m_unique0Pragma = false; // unique0 case
|
|
bool m_priorityPragma = false; // priority case
|
|
public:
|
|
AstIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp = nullptr, AstNode* elsesp = nullptr)
|
|
: ASTGEN_SUPER_If(fl, condp, thensp, elsesp) {}
|
|
ASTGEN_MEMBERS_AstIf;
|
|
bool uniquePragma() const { return m_uniquePragma; }
|
|
void uniquePragma(bool flag) { m_uniquePragma = flag; }
|
|
bool unique0Pragma() const { return m_unique0Pragma; }
|
|
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
|
|
bool priorityPragma() const { return m_priorityPragma; }
|
|
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
|
};
|
|
|
|
// === AstNodeReadWriteMem ===
|
|
class AstReadMem final : public AstNodeReadWriteMem {
|
|
public:
|
|
AstReadMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
|
|
AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
|
: ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {}
|
|
ASTGEN_MEMBERS_AstReadMem;
|
|
string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); }
|
|
const char* cFuncPrefixp() const override { return "VL_READMEM_"; }
|
|
};
|
|
class AstWriteMem final : public AstNodeReadWriteMem {
|
|
public:
|
|
AstWriteMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
|
|
AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
|
: ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {}
|
|
ASTGEN_MEMBERS_AstWriteMem;
|
|
string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); }
|
|
const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; }
|
|
};
|
|
|
|
// === AstNodeText ===
|
|
class AstScCtor final : public AstNodeText {
|
|
public:
|
|
AstScCtor(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScCtor(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScCtor;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
class AstScDtor final : public AstNodeText {
|
|
public:
|
|
AstScDtor(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScDtor(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScDtor;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
class AstScHdr final : public AstNodeText {
|
|
public:
|
|
AstScHdr(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScHdr(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScHdr;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
class AstScImp final : public AstNodeText {
|
|
public:
|
|
AstScImp(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScImp(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScImp;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
class AstScImpHdr final : public AstNodeText {
|
|
public:
|
|
AstScImpHdr(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScImpHdr(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScImpHdr;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
class AstScInt final : public AstNodeText {
|
|
public:
|
|
AstScInt(FileLine* fl, const string& textp)
|
|
: ASTGEN_SUPER_ScInt(fl, textp) {}
|
|
ASTGEN_MEMBERS_AstScInt;
|
|
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() override { return true; }
|
|
};
|
|
|
|
// === AstNodeSimpleText ===
|
|
class AstText final : public AstNodeSimpleText {
|
|
public:
|
|
AstText(FileLine* fl, const string& textp, bool tracking = false)
|
|
: ASTGEN_SUPER_Text(fl, textp, tracking) {}
|
|
ASTGEN_MEMBERS_AstText;
|
|
};
|
|
class AstTextBlock final : public AstNodeSimpleText {
|
|
// @astgen op1 := nodesp : List[AstNode]
|
|
bool m_commas; // Comma separate emitted children
|
|
public:
|
|
explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false,
|
|
bool commas = false)
|
|
: ASTGEN_SUPER_TextBlock(fl, textp, tracking)
|
|
, m_commas(commas) {}
|
|
ASTGEN_MEMBERS_AstTextBlock;
|
|
bool commas() const { return m_commas; }
|
|
void commas(bool flag) { m_commas = flag; }
|
|
void addText(FileLine* fl, const string& textp, bool tracking = false) {
|
|
addNodesp(new AstText{fl, textp, tracking});
|
|
}
|
|
};
|
|
|
|
#endif // Guard
|