blob: e2d5251e979952889babd9feac7a2bb9fd422c72 [file] [log] [blame]
# -------------------------------------------------------------------------------
# signalvisitor.py
#
# Signal definition visitor
#
# Copyright (C) 2013, Shinya Takamaeda-Yamazaki
# License: Apache 2.0
# -------------------------------------------------------------------------------
from __future__ import absolute_import
from __future__ import print_function
import sys
import os
from pyverilog.vparser.ast import *
import pyverilog.utils.util as util
import pyverilog.utils.verror as verror
from pyverilog.utils.scope import ScopeLabel, ScopeChain
from pyverilog.dataflow.dataflow import *
from pyverilog.dataflow.visit import *
from pyverilog.dataflow.optimizer import VerilogOptimizer
import pyverilog.dataflow.reorder as reorder
class SignalVisitor(NodeVisitor):
def __init__(self, moduleinfotable, top):
self.moduleinfotable = moduleinfotable
self.top = top
self.frames = FrameTable()
self.labels = Labels()
self.optimizer = VerilogOptimizer({}, {})
# set the top frame of top module
self.stackInstanceFrame(top, top)
def getFrameTable(self):
return self.frames
def start_visit(self):
return self.visit(self.moduleinfotable.getDefinition(self.top))
def visit_Input(self, node):
self.frames.addSignal(node)
def visit_Output(self, node):
self.frames.addSignal(node)
def visit_Inout(self, node):
self.frames.addSignal(node)
def visit_Reg(self, node):
self.frames.addSignal(node)
def visit_Wire(self, node):
self.frames.addSignal(node)
def visit_Supply(self, node):
self.frames.addSignal(node)
def visit_Tri(self, node):
self.frames.addSignal(node)
def visit_Integer(self, node):
self.frames.addSignal(node)
def visit_Parameter(self, node):
self.frames.addConst(node)
name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
if not self.hasConstant(name):
value = self.optimize(self.getTree(node.value, self.frames.getCurrent()))
self.setConstant(name, value)
def visit_Localparam(self, node):
self.frames.addConst(node)
name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
if not self.hasConstant(name):
value = self.optimize(self.getTree(node.value, self.frames.getCurrent()))
self.setConstant(name, value)
def visit_Genvar(self, node):
self.frames.addConst(node)
name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
if not self.hasConstant(name):
value = DFEvalValue(0)
self.setConstant(name, value)
def visit_Function(self, node):
self.frames.addFunction(node)
self.frames.setFunctionDef()
self.generic_visit(node)
self.frames.unsetFunctionDef()
def visit_Task(self, node):
self.frames.addTask(node)
self.frames.setTaskDef()
self.generic_visit(node)
self.frames.unsetTaskDef()
def visit_Initial(self, node):
pass
#label = self.labels.get( self.frames.getLabelKey('initial') )
# current = self.frames.addFrame(ScopeLabel(label, 'initial'),
# generate=self.frames.isGenerate(),
# initial=True)
# self.generic_visit(node)
# self.frames.setCurrent(current)
def visit_InstanceList(self, node):
for i in node.instances:
self.visit(i)
def visit_Instance(self, node):
if node.array:
return self._visit_Instance_array(node)
nodename = node.name
return self._visit_Instance_body(node, nodename)
def _visit_Instance_array(self, node):
if node.name == '':
raise verror.FormatError("Module %s requires an instance name" % node.module)
current = self.frames.getCurrent()
msb = self.optimize(self.getTree(node.array.msb, current)).value
lsb = self.optimize(self.getTree(node.array.lsb, current)).value
for i in range(lsb, msb + 1):
nodename = node.name + '_' + str(i)
self._visit_Instance_body(node, nodename)
def _visit_Instance_body(self, node, nodename):
if node.module in primitives:
return self._visit_Instance_primitive(node)
if nodename == '':
raise verror.FormatError("Module %s requires an instance name" % node.module)
current = self.stackInstanceFrame(nodename, node.module)
self.setInstanceSimpleConstantTerms()
scope = self.frames.getCurrent()
paramnames = self.moduleinfotable.getParamNames(node.module)
for paramnames_i, param in enumerate(node.parameterlist):
paramname = paramnames[paramnames_i] if param.paramname is None else param.paramname
if paramname not in paramnames:
raise verror.FormatError("No such parameter: %s in %s" %
(paramname, nodename))
value = self.optimize(self.getTree(param.argname, current))
name, definition = self.searchConstantDefinition(scope, paramname)
self.setConstant(name, value)
self.setInstanceConstants()
self.setInstanceConstantTerms()
self.visit(self.moduleinfotable.getDefinition(node.module))
self.frames.setCurrent(current)
def _visit_Instance_primitive(self, node):
pass
def visit_Always(self, node):
label = self.labels.get(self.frames.getLabelKey('always'))
current = self.frames.addFrame(ScopeLabel(label, 'always'),
generate=self.frames.isGenerate(),
always=True)
self.generic_visit(node)
self.frames.setCurrent(current)
def visit_IfStatement(self, node):
if (self.frames.isGenerate()
and not self.frames.isAlways() and not self.frames.isInitial()
and not self.frames.isFunctioncall() and not self.frames.isTaskcall()
and not self.frames.isFunctiondef() and not self.frames.isTaskdef()):
# generate-if statement
current = self.frames.getCurrent()
tree = self.getTree(node.cond, current)
rslt = self.optimize(tree)
if not isinstance(rslt, DFEvalValue):
raise verror.FormatError("Can not resolve generate-if condition")
if rslt.value > 0:
label = self._if_true(node)
else:
label = self.labels.get(self.frames.getLabelKey('if'))
self._if_false(node, label)
return
label = self._if_true(node)
self._if_false(node, label)
def _toELSE(self, label):
return label + '_ELSE'
def _if_true(self, node):
if node.true_statement is None:
return None
label = self.labels.get(self.frames.getLabelKey('if'))
current = self.frames.addFrame(ScopeLabel(label, 'if'),
frametype='ifthen',
condition=node.cond,
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial())
self.visit(node.true_statement)
self.frames.setCurrent(current)
return label
def _if_false(self, node, label):
if node.false_statement is None:
return
label = self._toELSE(label)
current = self.frames.addFrame(ScopeLabel(label, 'if'),
frametype='ifelse',
condition=node.cond,
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial())
self.visit(node.false_statement)
self.frames.setCurrent(current)
return label
def visit_CaseStatement(self, node):
start_frame = self.frames.getCurrent()
self._case(node.comp, node.caselist)
self.frames.setCurrent(start_frame)
def visit_CasexStatement(self, node):
return self.visit_CaseStatement(node)
def _case(self, comp, caselist):
if len(caselist) == 0:
return
case = caselist[0]
cond = IntConst('1')
if case.cond is not None:
if len(case.cond) > 1:
cond = Eq(comp, case.cond[0])
for c in case.cond[1:]:
cond = Lor(cond, Eq(comp, c))
else:
cond = Eq(comp, case.cond[0])
label = self.labels.get(self.frames.getLabelKey('if'))
current = self.frames.addFrame(ScopeLabel(label, 'if'),
frametype='ifthen',
condition=cond,
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial())
if case.statement is not None:
self.visit(case.statement)
self.frames.setCurrent(current)
if len(caselist) == 1:
return
label = self._toELSE(label)
current = self.frames.addFrame(ScopeLabel(label, 'if'),
frametype='ifelse',
condition=cond,
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial())
self._case(comp, caselist[1:])
def visit_ForStatement(self, node):
# pre-statement
current = self.frames.getCurrent()
pre_right = self.getTree(node.pre.right, current)
pre_right_value = self.optimize(pre_right)
loop = pre_right_value.value
self.frames.setForPre()
self.visit(node.pre)
self.frames.unsetForPre()
label = self.labels.get(self.frames.getLabelKey('for'))
#loop = 0
while True:
# cond-statement
current = self.frames.getCurrent()
tree = self.getTree(node.cond, current)
rslt = self.optimize(tree)
if not isinstance(rslt, DFEvalValue):
raise verror.FormatError(("Can not process the for-statement. "
"for-condition should be evaluated statically."))
# loop termination
if rslt.value <= 0:
break
# main-statement
current = self.frames.addFrame(ScopeLabel(label, 'for', loop),
frametype='for',
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial(),
loop=loop, loop_iter=self.frames.getForIter())
self.visit(node.statement)
self.frames.setCurrent(current)
# post-statement
current = self.frames.getCurrent()
post_right = self.getTree(node.post.right, current)
post_right_value = self.optimize(post_right)
loop = post_right_value.value
self.frames.setForPost()
self.visit(node.post)
self.frames.unsetForPost()
#loop += 1
def visit_WhileStatement(self, node):
pass
def visit_GenerateStatement(self, node):
label = self.labels.get(self.frames.getLabelKey('generate'))
current = self.frames.addFrame(ScopeLabel(label, 'generate'),
generate=True)
self.generic_visit(node)
self.frames.setCurrent(current)
def visit_Block(self, node):
label = None
if node.scope is not None:
label = node.scope
else:
label = self.labels.get(self.frames.getLabelKey('block'))
current = self.frames.addFrame(ScopeLabel(label, 'block'),
frametype='block',
functioncall=self.frames.isFunctioncall(),
taskcall=self.frames.isTaskcall(),
generate=self.frames.isGenerate(),
always=self.frames.isAlways(),
initial=self.frames.isInitial())
self.generic_visit(node)
self.frames.setCurrent(current)
def visit_Assign(self, node):
pass
def visit_BlockingSubstitution(self, node):
if self.frames.isForpre() or self.frames.isForpost():
current = self.frames.getCurrent()
name, definition = self.searchConstantDefinition(current,
node.left.var.name)
value = self.optimize(self.getTree(node.right.var, current))
self.setConstant(name, value)
self.frames.setForIter(name)
def visit_NonblockingSubstitution(self, node):
pass
def optimize(self, node):
return self.optimizer.optimize(node)
def stackInstanceFrame(self, instname, modulename):
current = self.frames.addFrame(ScopeLabel(instname, 'module'), module=True,
modulename=modulename)
self.frames.updateSignal(self.moduleinfotable.getSignals(modulename))
self.frames.updateConst(self.moduleinfotable.getConsts(modulename))
return current
def setInstanceSimpleConstantTerms(self):
current = self.frames.getCurrent()
for name, definitions in self.frames.getConsts(current).items():
if len(definitions) > 1:
raise verror.FormatError("Multiple definitions for Constant")
for definition in definitions:
simple_definition = copy.deepcopy(definition)
if simple_definition.width is not None:
simple_definition.width.msb = None
simple_definition.width.lsb = None
term = self.makeConstantTerm(name, simple_definition, current)
self.setConstantTerm(name, term)
def setInstanceConstantTerms(self):
current = self.frames.getCurrent()
for name, definitions in self.frames.getConsts(current).items():
if len(definitions) > 1:
raise verror.FormatError("Multiple definitions for Constant")
for definition in definitions:
term = self.makeConstantTerm(name, definition, current)
self.setConstantTerm(name, term)
def setInstanceConstants(self):
current = self.frames.getCurrent()
all_passed = False
while not all_passed:
all_passed = True
for name, definitions in self.frames.getConsts(current).items():
if len(definitions) > 1:
raise verror.FormatError("Multiple definitions for Constant")
if self.hasConstant(name):
continue
for definition in definitions:
if isinstance(definition, Genvar):
continue
value = self.optimize(self.getTree(definition.value, current))
if not isinstance(value, DFEvalValue):
all_passed = False
continue
self.setConstant(name, value)
def setConstant(self, name, value):
self.optimizer.setConstant(name, value)
def getConstant(self, name):
return self.optimizer.getConstant(name)
def hasConstant(self, name):
return self.optimizer.hasConstant(name)
def setConstantTerm(self, name, term):
self.optimizer.setTerm(name, term)
def hasConstantTerm(self, name):
self.optimizer.hasTerm(name)
def toScopeChain(self, blocklabel):
scopelist = []
for b in blocklabel.labellist:
if b.loop is not None:
loop = self.optimize(b.loop)
if not isinstance(loop, DFEvalValue):
raise verror.FormatError('Loop iterator should be constant')
scopelist.append(ScopeLabel(b.name, 'for', loop))
scopelist.append(ScopeLabel(b.name, 'any'))
return ScopeChain(scopelist)
def searchScopeConstantValue(self, blocklabel, name):
currentmodule = self.frames.getCurrentModuleScopeChain()
localchain = currentmodule[-1:] + self.toScopeChain(blocklabel)
matchedchain = self.frames.searchMatchedScopeChain(currentmodule, localchain)
varname = currentmodule[:-1] + matchedchain + ScopeLabel(name, 'signal')
const = self.getConstant(varname)
return const
# def searchScopeConstantDefinition(self, blocklabel, name):
# currentmodule = self.frames.getCurrentModuleScopeChain()
# localchain = currentmodule[-1:] + self.toScopeChain(blocklabel)
# matchedchain = self.frames.searchMatchedScopeChain(currentmodule, localchain)
# constdef = self.frames.getConstantDefinition(matchedchain, name)
# return constdef
def searchConstantDefinition(self, key, name):
foundkey, founddef = self.frames.searchConstantDefinition(key, name)
if foundkey is not None:
return foundkey + ScopeLabel(name, 'signal'), founddef
foundkey, founddef = self.frames.searchSignalDefinition(key, name)
if foundkey is not None:
return foundkey + ScopeLabel(name, 'signal'), founddef
if foundkey is None:
raise verror.DefinitionError('constant value not found: %s' % name)
def searchConstantValue(self, key, name):
foundkey, founddef = self.searchConstantDefinition(key, name)
const = self.getConstant(foundkey)
return const
def makeConstantTerm(self, name, node, scope):
termtype = node.__class__.__name__
termtypes = set([termtype])
msb = DFIntConst('31') if node.width is None else self.makeDFTree(node.width.msb, scope)
lsb = DFIntConst('0') if node.width is None else self.makeDFTree(node.width.lsb, scope)
return Term(name, termtypes, msb, lsb)
def getTree(self, node, scope):
expr = node.var if isinstance(node, Rvalue) else node
return self.makeDFTree(expr, scope)
def makeDFTree(self, node, scope):
if isinstance(node, str):
return self.searchConstantValue(scope, node)
if isinstance(node, Identifier):
if node.scope is not None:
const = self.searchScopeConstantValue(node.scope, node.name)
return const
return self.searchConstantValue(scope, node.name)
if isinstance(node, IntConst):
return DFIntConst(node.value)
if isinstance(node, FloatConst):
return DFFloatConst(node.value)
if isinstance(node, StringConst):
return DFStringConst(node.value)
if isinstance(node, Cond):
true_df = self.makeDFTree(node.true_value, scope)
false_df = self.makeDFTree(node.false_value, scope)
cond_df = self.makeDFTree(node.cond, scope)
if isinstance(cond_df, DFBranch):
return reorder.insertCond(cond_df, true_df, false_df)
return DFBranch(cond_df, true_df, false_df)
if isinstance(node, UnaryOperator):
right_df = self.makeDFTree(node.right, scope)
if isinstance(right_df, DFBranch):
return reorder.insertUnaryOp(right_df, node.__class__.__name__)
return DFOperator((right_df,), node.__class__.__name__)
if isinstance(node, Operator):
left_df = self.makeDFTree(node.left, scope)
right_df = self.makeDFTree(node.right, scope)
if isinstance(left_df, DFBranch) or isinstance(right_df, DFBranch):
return reorder.insertOp(left_df, right_df, node.__class__.__name__)
return DFOperator((left_df, right_df,), node.__class__.__name__)
if isinstance(node, Partselect):
var_df = self.makeDFTree(node.var, scope)
msb_df = self.makeDFTree(node.msb, scope)
lsb_df = self.makeDFTree(node.lsb, scope)
if isinstance(var_df, DFBranch):
return reorder.insertPartselect(var_df, msb_df, lsb_df)
return DFPartselect(var_df, msb_df, lsb_df)
if isinstance(node, Pointer):
var_df = self.makeDFTree(node.var, scope)
ptr_df = self.makeDFTree(node.ptr, scope)
return DFPointer(var_df, ptr_df)
if isinstance(node, Concat):
nextnodes = []
for n in node.list:
nextnodes.append(self.makeDFTree(n, scope))
for n in nextnodes:
if isinstance(n, DFBranch):
return reorder.insertConcat(tuple(nextnodes))
return DFConcat(tuple(nextnodes))
if isinstance(node, Repeat):
nextnodes = []
times = self.optimize(self.getTree(node.times, scope)).value
value = self.makeDFTree(node.value, scope)
for i in range(int(times)):
nextnodes.append(copy.deepcopy(value))
return DFConcat(tuple(nextnodes))
if isinstance(node, SystemCall):
if node.syscall == 'unsigned':
return self.makeDFTree(node.args[0])
if node.syscall == 'signed':
return self.makeDFTree(node.args[0])
return DFIntConst('0')
raise verror.FormatError("unsupported AST node type: %s %s" %
(str(type(node)), str(node)))