from pprint import pprint
from ply import lex, yacc
import astor
+from copy import deepcopy
from soc.decoder.power_decoder import create_pdecode
from soc.decoder.pseudo.lexer import IndentLexer
# Helper function
-def Assign(autoassign, left, right, iea_mode):
+def Assign(autoassign, assignname, left, right, iea_mode):
names = []
- print("Assign", left, right)
+ print("Assign", assignname, left, right)
if isinstance(left, ast.Name):
# Single assignment on left
# XXX when doing IntClass, which will have an "eq" function,
ass_list = [ast.AssName(name, 'OP_ASSIGN') for name in names]
return ast.Assign([ast.AssTuple(ass_list)], right)
elif isinstance(left, ast.Subscript):
- res = ast.Assign([left], right)
ls = left.slice
+ if (isinstance(ls, ast.Slice) and isinstance(right, ast.Name) and
+ right.id == 'undefined'):
+ # undefined needs to be copied the exact same slice
+ right = ast.Subscript(right, ls, ast.Load())
+ return ast.Assign([left], right)
+ res = ast.Assign([left], right)
if autoassign and isinstance(ls, ast.Slice):
- # hack to create a variable pre-declared
+ # hack to create a variable pre-declared based on a slice.
+ # dividend[0:32] = (RA)[0:32] will create
+ # dividend = [0] * 32
+ # dividend[0:32] = (RA)[0:32]
+ # the declaration makes the slice-assignment "work"
lower, upper, step = ls.lower, ls.upper, ls.step
- print ("lower, upper, step", repr(lower), repr(upper), step)
+ print("lower, upper, step", repr(lower), repr(upper), step)
if not isinstance(lower, ast.Constant) or \
not isinstance(upper, ast.Constant):
return res
- right = ast.BinOp(ast.List([ast.Num(0)]),
- ast.Mult(), ast.Num(upper.value-lower.value))
- declare = ast.Assign([left], right)
+ qty = ast.Num(upper.value-lower.value)
+ keywords = [ast.keyword(arg='repeat', value=qty)]
+ l = [ast.Num(0)]
+ right = ast.Call(ast.Name("concat", ast.Load()), l, keywords)
+ declare = ast.Assign([ast.Name(assignname, ast.Store())], right)
return [declare, res]
return res
# XXX HMMM probably not needed...
idx = subs[0]
else:
idx = ast.Slice(subs[0], subs[1], None)
+ # if isinstance(atom, ast.Name) and atom.id == 'CR':
+ # atom.id = 'CR' # bad hack
+ #print ("apply_trailer Subscript", atom.id, idx)
return ast.Subscript(atom, idx, ast.Load())
########## Parser (tokens -> AST) ######
("left", "INVERT"),
)
- def __init__(self, form):
+ def __init__(self, form, include_carry_in_write=False):
+ self.include_ca_in_write = include_carry_in_write
self.gprs = {}
form = self.sd.sigforms[form]
print(form)
self.declared_vars = set()
for rname in ['RA', 'RB', 'RC', 'RT', 'RS']:
self.gprs[rname] = None
+ self.declared_vars.add(rname)
self.available_op_fields = set()
for k in formkeys:
if k not in self.gprs:
self.read_regs = OrderedSet()
self.uninit_regs = OrderedSet()
self.write_regs = OrderedSet()
- self.special_regs = OrderedSet() # see p_atom_name
+ self.special_regs = OrderedSet() # see p_atom_name
# The grammar comments come from Python's Grammar/Grammar file
if name in self.gprs:
# add to list of uninitialised
self.uninit_regs.add(name)
- autoassign = name not in self.declared_vars
+ autoassign = (name not in self.declared_vars and
+ name not in self.special_regs)
elif isinstance(p[1], ast.Call) and p[1].func.id in ['GPR', 'SPR']:
print(astor.dump_tree(p[1]))
# replace GPR(x) with GPR[x]
print("expr assign", name, p[1])
if name and name in self.gprs:
self.write_regs.add(name) # add to list of regs to write
- p[0] = Assign(autoassign, p[1], p[3], iea_mode)
+ p[0] = Assign(autoassign, name, p[1], p[3], iea_mode)
if name:
self.declared_vars.add(name)
"""for_stmt : FOR atom EQ test TO test COLON suite
| DO atom EQ test TO test COLON suite
"""
- # auto-add-one (sigh) due to python range
start = p[4]
- end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
- it = ast.Call(ast.Name("range", ast.Load()), [start, end], [])
+ end = p[6]
+ if start.value > end.value: # start greater than end, must go -ve
+ # auto-subtract-one (sigh) due to python range
+ end = ast.BinOp(p[6], ast.Add(), ast.Constant(-1))
+ arange = [start, end, ast.Constant(-1)]
+ else:
+ # auto-add-one (sigh) due to python range
+ end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
+ arange = [start, end]
+ it = ast.Call(ast.Name("range", ast.Load()), arange, [])
p[0] = ast.For(p[2], it, p[8], [])
def p_while_stmt(self, p):
elif p[2] == '||':
l = check_concat(p[1]) + check_concat(p[3])
p[0] = ast.Call(ast.Name("concat", ast.Load()), l, [])
+ elif p[2] in ['/', '%']:
+ # bad hack: if % or / used anywhere other than div/mod ops,
+ # do % or /. however if the argument names are "dividend"
+ # we must call the special trunc_divs and trunc_rems functions
+ l, r = p[1], p[3]
+ # actual call will be "dividend / divisor" - just check
+ # LHS name
+ # XXX DISABLE BAD HACK (False)
+ if False and isinstance(l, ast.Name) and l.id == 'dividend':
+ if p[2] == '/':
+ fn = 'trunc_divs'
+ else:
+ fn = 'trunc_rems'
+ # return "function trunc_xxx(l, r)"
+ p[0] = ast.Call(ast.Name(fn, ast.Load()), (l, r), [])
+ else:
+ # return "l {binop} r"
+ p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3])
elif p[2] in ['<', '>', '=', '<=', '>=', '!=']:
p[0] = binary_ops[p[2]]((p[1], p[3]))
elif identify_sint_mul_pattern(p):
print("power dump trailerlist")
print(astor.dump_tree(p[2]))
p[0] = apply_trailer(p[1], p[2])
+ if isinstance(p[1], ast.Name):
+ name = p[1].id
+ if name in ['RA', 'RS', 'RB', 'RC']:
+ self.read_regs.add(name)
def p_atom_name(self, p):
"""atom : NAME"""
name = p[1]
if name in self.available_op_fields:
self.op_fields.add(name)
- if name in ['CA', 'CA32']:
+ if name == 'overflow':
self.write_regs.add(name)
+ if self.include_ca_in_write:
+ if name in ['CA', 'CA32']:
+ self.write_regs.add(name)
if name in ['CR', 'LR', 'CTR', 'TAR', 'FPSCR', 'MSR']:
self.special_regs.add(name)
- self.write_regs.add(name) # and add to list to write
+ self.write_regs.add(name) # and add to list to write
p[0] = ast.Name(id=name, ctx=ast.Load())
def p_atom_number(self, p):
class GardenSnakeParser(PowerParser):
- def __init__(self, lexer=None, debug=False, form=None):
+ def __init__(self, lexer=None, debug=False, form=None, incl_carry=False):
self.sd = create_pdecode()
- PowerParser.__init__(self, form)
+ PowerParser.__init__(self, form, incl_carry)
self.debug = debug
if lexer is None:
lexer = IndentLexer(debug=0)
#from compiler import misc, syntax, pycodegen
+_CACHED_PARSERS = {}
+_CACHE_PARSERS = True
+
+
class GardenSnakeCompiler(object):
- def __init__(self, debug=False, form=None):
- self.parser = GardenSnakeParser(debug=debug, form=form)
+ def __init__(self, debug=False, form=None, incl_carry=False):
+ if _CACHE_PARSERS:
+ try:
+ parser = _CACHED_PARSERS[debug, form, incl_carry]
+ except KeyError:
+ parser = GardenSnakeParser(debug=debug, form=form,
+ incl_carry=incl_carry)
+ _CACHED_PARSERS[debug, form, incl_carry] = parser
+
+ self.parser = deepcopy(parser)
+ else:
+ self.parser = GardenSnakeParser(debug=debug, form=form,
+ incl_carry=incl_carry)
def compile(self, code, mode="exec", filename="<string>"):
tree = self.parser.parse(code)