blob: 084c113a47a422731294709ca427ca3a6f31796b [file] [log] [blame]
# -------------------------------------------------------------------------------
# transition.py
#
# Splitting a tree into state part and transition condition part
#
# 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.dataflow.dataflow import *
import pyverilog.utils.util as util
import pyverilog.utils.signaltype as signaltype
import pyverilog.utils.inference as inference
def walkCondlist(condlist, termname, termwidth=32):
node = None
if len(condlist) == 0:
maxvalue = util.maxValue(termwidth)
return StateNode(maxvalue=maxvalue, isany=True)
for cond in condlist:
rslt = walkCond(cond, termname, termwidth)
if node and rslt:
node = andStateNodeList(node, rslt)
elif rslt:
node = rslt
return node
def walkCond(cond, termname, termwidth=32):
if isinstance(cond, DFOperator):
if len(cond.nextnodes) == 1:
return _walkCond_DFOperator_unary(cond, termname, termwidth)
if len(cond.nextnodes) == 2:
return _walkCond_DFOperator_dual(cond, termname, termwidth)
if isinstance(cond, DFTerminal):
comp_cond = DFOperator((cond, DFEvalValue(0)), 'GreaterThan')
return _walkCond_DFOperator_dual(comp_cond, termname, termwidth)
maxvalue = util.maxValue(termwidth)
return StateNode(transcond=cond, maxvalue=maxvalue, isany=True)
def _walkCond_DFOperator_unary(cond, termname, termwidth=32):
node = walkCond(cond.nextnodes[0], termname, termwidth)
if signaltype.isNot(cond.operator):
node = notStateNodeList(node)
return node
def _walkCond_DFOperator_dual(cond, termname, termwidth=32):
maxvalue = util.maxValue(termwidth)
if signaltype.isNonConditionOp(cond.operator):
return StateNode(transcond=cond, maxvalue=maxvalue, isany=True)
if not signaltype.isCompare(cond.operator) and signaltype.isOr(cond.operator):
lnode = walkCond(cond.nextnodes[0], termname, termwidth)
rnode = walkCond(cond.nextnodes[1], termname, termwidth)
ret = orStateNodeList(lnode, rnode)
if ret:
return ret
if not signaltype.isCompare(cond.operator) and signaltype.isAnd(cond.operator):
lnode = walkCond(cond.nextnodes[0], termname, termwidth)
rnode = walkCond(cond.nextnodes[1], termname, termwidth)
ret = andStateNodeList(lnode, rnode)
if ret:
return ret
l = cond.nextnodes[0]
r = cond.nextnodes[1]
if isinstance(l, DFTerminal) and l.name == termname:
infval = inference.infer(cond.operator, r)
return createStateNode(infval, termwidth)
if isinstance(r, DFTerminal) and r.name == termname:
new_op = re.sub('Greater', 'TMP', cond.operator)
new_op = re.sub('Less', 'Greater', new_op)
new_op = re.sub('TMP', 'Less', new_op)
infval = inference.infer(new_op, l)
return createStateNode(infval, termwidth)
maxvalue = util.maxValue(termwidth)
return StateNode(transcond=cond, maxvalue=maxvalue, isany=True)
def notStateNodeList(node):
if isStateNode(node):
return notStateNode(node)
if isStateNodeList(node):
new_nodes = []
for n in node.nodelist:
new_nodes.append(notStateNode(n))
ret_node = None
for n in new_nodes:
if ret_node is None:
ret_node = n
else:
ret_node = andStateNodeList(ret_node, n)
return ret_node
return None
def orStateNodeList(lnode, rnode):
if isStateNode(lnode) and isStateNode(rnode):
return StateNodeList((lnode, rnode))
if isStateNodeList(lnode) and isStateNodeList(rnode):
new_list = []
new_list.extend(lnode.nodelist)
new_list.extend(rnode.nodelist)
return StateNodeList(tuple(new_list))
if isStateNodeList(lnode) and isStateNode(rnode):
new_list = []
new_list.extend(lnode.nodelist)
new_list.append(rnode)
return StateNodeList(tuple(new_list))
if isStateNode(lnode) and isStateNodeList(rnode):
new_list = []
new_list.append(lnode)
new_list.extend(rnode.nodelist)
return StateNodeList(tuple(new_list))
return None
def andStateNodeList(lnode, rnode):
if lnode is None and rnode is None:
return None
if lnode is None:
return rnode
if rnode is None:
return lnode
if isStateNode(lnode) and isStateNode(rnode):
return andStateNode(lnode, rnode)
if isStateNodeList(lnode) and isStateNodeList(rnode):
new_list = []
for l in lnode.nodelist:
for r in rnode.nodelist:
val = andStateNode(l, r)
if val:
new_list.append(val)
if len(new_list) == 0:
return None
return StateNodeList(tuple(new_list))
if isStateNodeList(lnode) and isStateNode(rnode):
new_list = []
for l in lnode.nodelist:
val = andStateNode(l, rnode)
if val:
new_list.append(val)
if len(new_list) == 0:
return None
return StateNodeList(tuple(new_list))
if isStateNode(lnode) and isStateNodeList(rnode):
new_list = []
for r in rnode.nodelist:
val = andStateNode(lnode, r)
if val:
new_list.append(val)
if len(new_list) == 0:
return None
return StateNodeList(tuple(new_list))
return None
def notStateNode(node):
if node.isany:
new_transcond = _not_transcond(node.transcond)
return StateNode(transcond=new_transcond, maxvalue=node.maxvalue, isany=True)
new_range_pairs = _not_range_pairs(node)
a = StateNode(range_pairs=new_range_pairs, maxvalue=node.maxvalue)
if node.transcond is None:
return a
new_transcond = _not_transcond(node.transcond)
b = StateNode(range_pairs=node.range_pairs, transcond=new_transcond, maxvalue=node.maxvalue)
return StateNodeList((a, b))
def andStateNode(sna, snb):
if sna is None and snb is None:
return None
if sna is None:
return snb
if snb is None:
return sna
isany = False
range_pairs = []
if sna.isany and snb.isany:
isany = True
elif sna.isany:
range_pairs = snb.range_pairs
elif snb.isany:
range_pairs = sna.range_pairs
elif len(sna.range_pairs) > 0 and len(snb.range_pairs) > 0:
range_pairs = _and_range_pairs(sna, snb)
if (not isany) and len(range_pairs) == 0:
return None
transcond = None
if isinstance(sna.transcond, DFNode) and isinstance(snb.transcond, DFNode):
transcond = DFOperator((sna.transcond, snb.transcond), 'Land')
elif isinstance(sna.transcond, DFNode):
transcond = sna.transcond
elif isinstance(snb.transcond, DFNode):
transcond = snb.transcond
maxvalue = max(sna.maxvalue, snb.maxvalue)
return StateNode(tuple(range_pairs), maxvalue=maxvalue, transcond=transcond, isany=isany)
def _and_range_pairs(sna, snb):
range_pairs = []
a_ptr = 0
b_ptr = 0
sorted_sna = sorted(sna.range_pairs, key=lambda x: x[0])
sorted_snb = sorted(snb.range_pairs, key=lambda x: x[0])
amin, amax = sorted_sna[a_ptr]
bmin, bmax = sorted_snb[b_ptr]
last_a_ptr = -1
last_b_ptr = -1
while True:
next_min = max(amin, bmin)
next_max = min(amax, bmax)
if bmax < amin or bmin > amax:
pass
else:
range_pairs.append((next_min, next_max))
if amax >= bmax and b_ptr < len(sorted_snb) - 1:
b_ptr += 1
bmin, bmax = sorted_snb[b_ptr]
elif amax <= bmax and a_ptr < len(sorted_sna) - 1:
a_ptr += 1
amin, amax = sorted_sna[a_ptr]
if a_ptr == last_a_ptr and b_ptr == last_b_ptr:
break
last_a_ptr = a_ptr
last_b_ptr = b_ptr
ret_set = set(range_pairs)
ret_list = list(ret_set)
return ret_list
def _not_range_pairs(node):
new_range_pairs = []
cur_min = node.minvalue
for rmin, rmax in sorted(node.range_pairs, key=lambda x: x[0]):
if rmin - 1 >= cur_min:
new_range_pairs.append((cur_min, rmin - 1))
cur_min = max(rmax + 1, cur_min)
if cur_min <= node.maxvalue:
new_range_pairs.append((cur_min, node.maxvalue))
return new_range_pairs
def _not_transcond(transcond):
if transcond is None:
return None
elif isinstance(transcond, DFOperator) and transcond.operator == 'Ulnot':
return transcond.nextnodes[0]
elif isinstance(transcond, DFOperator) and transcond.operator == 'Unot':
return transcond.nextnodes[0]
return DFOperator((transcond,), 'Ulnot')
def createStateNode(infval, width):
statelabels = []
minval = infval.minval
maxval = infval.maxval
if minval is None:
minval = 0
if maxval is None:
maxval = util.maxValue(width)
ret = StateNode(((minval, maxval),), 0, util.maxValue(width), None)
if infval.inv:
ret = notStateNodeList(ret)
return ret
def isStateNode(node):
return isinstance(node, StateNode)
def isStateNodeList(node):
return isinstance(node, StateNodeList)
class StateNode(object):
def __init__(self, range_pairs=(), minvalue=0, maxvalue=0, transcond=None, isany=False):
self.range_pairs = range_pairs
self.minvalue = minvalue
self.maxvalue = maxvalue
self.transcond = transcond
self.isany = isany
def __repr__(self):
ret = 'state:'
for r in self.range_pairs:
ret += str(r) + ' '
if self.isany:
ret += 'any '
ret = ret[:-1]
ret += ', cond:'
if isinstance(self.transcond, DFNode):
ret += self.transcond.tocode()
else:
ret += str(self.transcond)
return ret
class StateNodeList(object):
def __init__(self, nodelist=()):
self.nodelist = nodelist
def __repr__(self):
ret = '('
for n in self.nodelist:
ret += n.__repr__() + ' '
return ret[:-1] + ')'