attempting to add overflow setting in ISACaller
[soc.git] / src / soc / decoder / pseudo / parser.py
index 664cc2f738884c3cbcfaf4cd8c8b0de360c18252..ddd49fabeeb9c4fff5edb6623d37a4c664d0d965 100644 (file)
@@ -23,7 +23,7 @@ import ast
 # Helper function
 
 
-def Assign(left, right, iea_mode):
+def Assign(autoassign, assignname, left, right, iea_mode):
     names = []
     print("Assign", left, right)
     if isinstance(left, ast.Name):
@@ -43,7 +43,31 @@ def Assign(left, right, iea_mode):
         ass_list = [ast.AssName(name, 'OP_ASSIGN') for name in names]
         return ast.Assign([ast.AssTuple(ass_list)], right)
     elif isinstance(left, ast.Subscript):
-        return 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 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)
+            if not isinstance(lower, ast.Constant) or \
+               not isinstance(upper, ast.Constant):
+                return res
+            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...
         ls = left.slice
         if isinstance(ls, ast.Slice):
@@ -83,32 +107,32 @@ def Assign(left, right, iea_mode):
 
 def make_le_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.LtE()], [right])
+    return ast.Call(ast.Name("le", ast.Load()), (left, right), [])
 
 
 def make_ge_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.GtE()], [right])
+    return ast.Call(ast.Name("ge", ast.Load()), (left, right), [])
 
 
 def make_lt_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.Lt()], [right])
+    return ast.Call(ast.Name("lt", ast.Load()), (left, right), [])
 
 
 def make_gt_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.Gt()], [right])
+    return ast.Call(ast.Name("gt", ast.Load()), (left, right), [])
 
 
 def make_eq_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.Eq()], [right])
+    return ast.Call(ast.Name("eq", ast.Load()), (left, right), [])
 
 
 def make_ne_compare(arg):
     (left, right) = arg
-    return ast.Compare(left, [ast.NotEq()], [right])
+    return ast.Call(ast.Name("ne", ast.Load()), (left, right), [])
 
 
 binary_ops = {
@@ -118,7 +142,7 @@ binary_ops = {
     "+": ast.Add(),
     "-": ast.Sub(),
     "*": ast.Mult(),
-    "/": ast.Div(),
+    "/": ast.FloorDiv(),
     "%": ast.Mod(),
     "<=": make_le_compare,
     ">=": make_ge_compare,
@@ -227,13 +251,16 @@ class PowerParser:
         ("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)
         formkeys = form._asdict().keys()
+        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:
@@ -244,6 +271,7 @@ class PowerParser:
         self.read_regs = OrderedSet()
         self.uninit_regs = OrderedSet()
         self.write_regs = OrderedSet()
+        self.special_regs = OrderedSet() # see p_atom_name
 
     # The grammar comments come from Python's Grammar/Grammar file
 
@@ -321,6 +349,8 @@ class PowerParser:
                        | small_stmt"""
         if len(p) == 4:
             p[0] = p[1] + [p[3]]
+        elif isinstance(p[1], list):
+            p[0] = p[1]
         else:
             p[0] = [p[1]]
 
@@ -332,6 +362,11 @@ class PowerParser:
                       | expr_stmt"""
         if isinstance(p[1], ast.Call):
             p[0] = ast.Expr(p[1])
+        elif isinstance(p[1], ast.Name) and p[1].id == 'TRAP':
+            # TRAP needs to actually be a function
+            name = ast.Name("self", ast.Load())
+            name = ast.Attribute(name, "TRAP", ast.Load())
+            p[0] = ast.Call(name, [], [])
         else:
             p[0] = p[1]
 
@@ -351,6 +386,7 @@ class PowerParser:
         else:
             iea_mode = p[2] == '<-iea'
             name = None
+            autoassign = False
             if isinstance(p[1], ast.Name):
                 name = p[1].id
             elif isinstance(p[1], ast.Subscript):
@@ -359,6 +395,7 @@ class PowerParser:
                     if name in self.gprs:
                         # add to list of uninitialised
                         self.uninit_regs.add(name)
+                    autoassign = name not in self.declared_vars
             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]
@@ -379,7 +416,9 @@ class PowerParser:
             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(p[1], p[3], iea_mode)
+            p[0] = Assign(autoassign, name, p[1], p[3], iea_mode)
+            if name:
+                self.declared_vars.add(name)
 
     def p_flow_stmt(self, p):
         "flow_stmt : return_stmt"
@@ -569,6 +608,23 @@ class PowerParser:
             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_div and trunc_rem functions
+                l, r = p[1], p[3]
+                # actual call will be "dividend / divisor" - just check
+                # LHS name
+                if isinstance(l, ast.Name) and l.id == 'dividend':
+                    if p[2] == '/':
+                        fn = 'trunc_div'
+                    else:
+                        fn = 'trunc_rem'
+                    # 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):
@@ -605,6 +661,14 @@ class PowerParser:
         name = p[1]
         if name in self.available_op_fields:
             self.op_fields.add(name)
+        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
         p[0] = ast.Name(id=name, ctx=ast.Load())
 
     def p_atom_number(self, p):
@@ -764,9 +828,9 @@ class PowerParser:
 
 
 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)
@@ -786,8 +850,9 @@ class GardenSnakeParser(PowerParser):
 #from compiler import misc, syntax, pycodegen
 
 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):
+        self.parser = GardenSnakeParser(debug=debug, form=form,
+                                        incl_carry=incl_carry)
 
     def compile(self, code, mode="exec", filename="<string>"):
         tree = self.parser.parse(code)