Getting Started¶
This is a step-by-step instruction for getting started with developing a VeriTrans backend and using it within the Verilog translator environment. The term backend refers to a component that traverses an abstract syntax tree (AST) of the Verilog description and processes it in some way (e.g., constructs the internal representation and/or converts the description into some other language). The document is illustrated by the example of VerilogPrinter
(see the package ru.ispras.verilog.parser.sample
).
Developing a Backend¶
Technically, a backend is a Java object that implements the VerilogBackend
interface (the method start
). Here is an example:
package ru.ispras.verilog.parser.sample;
import ru.ispras.verilog.parser.VerilogBackend;
import ru.ispras.verilog.parser.model.*; // AST nodes (Module, Activity, etc.)
import ru.ispras.verilog.parser.model.basis.*; // Objects used in AST nodes (Expression, Range, etc.)
...
/**
* This class illustrates development of a Verilog backend.
*/
public final class VerilogPrinter extends VerilogBackend
{
/**
* Processes the abstract syntax tree (AST).
*
* @param root the AST's root.
*/
public void start(final VerilogNode root)
{
...
}
}
To ease development of a backend, one can use VerilogTreeWalker
, a VeriTrans class that implements AST traversal. The VerilogTreeWalker
's constructor takes two parameters: (1) a reference to the tree's root and (2) a visitor to be applied to the tree nodes:
...
import ru.ispras.verilog.parser.walker.*; // Walker and visitor (VerilogTreeWalker and VerilogNodeVisitor)
public void start(final VerilogNode root)
{
// Create the AST traverser.
VerilogTreeWalker walker = new VerilogTreeWalker(root, new VerilogNodePrinter());
walker.start();
}
The most substantial part of backend development concerns creation of the AST nodes’ visitor, a subclass of the abstract class VerilogNodeVisitor
. The visitor should implement two methods for each of the node types:
// Pre-visitor: it is invoked before the child nodes are visited.
public void on<NodeType>Begin (final <NodeType> node);
// Post-visitor: it is invoked after the child nodes are visited.
public void on<NodeType>End (final <NodeType> node);
Supported node types include (see the package ru.ispras.verilog.parser.model
):
Activity | process (always or initial ) |
AssignBegin | continuous assignment (assign ) |
AssignStatement | assignment statement (= , <= , assign , deassign , force or release ) |
Assignment | assignment |
Attribute | attribute |
BlockGenerate | generate block |
BlockStatement | block statement (begin or fork ) |
CaseGenerate | generate case selection |
CaseGenerateItem | generate case item |
CaseStatement | case statement (case , casex or casez ) |
CaseStatementItem | case statement item |
Code | source code |
Declaration | declaration (input , output , inout , event , parameter , specparam , localparam , defparam , genvar or variable) |
DelayedStatement | delayed statement |
DisableStatement | disable statement |
Generate | generate construct |
IfGenerate | conditional generate construct |
IfGenerateBranch | if generate branch (then or else ) |
IfStatement | conditional statement |
IfStatementBranch | if statement branch (then or else ) |
Instantiation | instantiation construct |
LoopGenerate | generate loop |
LoopStatement | loop statement (forever , repeat , while or for ) |
Module | module declaration |
NullStatement | null statement |
PathDeclaration | path declaration |
Port | port declaration |
PortConnection | port connection |
Procedure | procedure declaration (function or task ) |
PulseStyle | pulse style specification |
ShowCancelled | show-cancelled construct |
Specify | specify construct |
Table | UDP (user-defined primitive) table |
TableEntry | UDP table entry |
TaskStatement | task statement |
TriggerStatement | trigger statement |
WaitStatement | wait statement |
A visitor example is given below.
package ru.ispras.verilog.parser.sample;
import ru.ispras.verilog.parser.model.*;
import ru.ispras.verilog.parser.model.basis.*;
import ru.ispras.verilog.parser.walker.*;
...
/**
* This class illustrates development of a Verilog node visitor.
*/
public final class VerilogNodePrinter extends VerilogNodeVisitor
{
@Override
public void onActivityBegin(final Activity node)
{
indent();
switch(node.getType())
{
case INITIAL:
text("initial");
break;
case ALWAYS:
text("always");
break;
}
endl();
begin();
}
@Override
public void onActivityEnd(final Activity node)
{
end();
}
...
}
Registering a Backend¶
A backend is registered by calling the add
method of the VerilogTranslator
object. An example is given below:
/**
* Launches the Verilog translator with the Verilog printer as a backend.
*
* @param args the command line parameters.
*/
public static void main(String[] args)
{
VerilogTranslator translator = new VerilogTranslator();
translator.add(new VerilogPrinter());
translator.start(args);
}
Updated by Alexander Kamkin over 10 years ago · 11 revisions