Commits

David Boddie committed 11e6189

Removed the unused Syntax.Expected class hierarchy. The definitions
module contains classes used to represent operands.
Changed the Opcode's parsing algorithm to create a template that
describes where operands are inserted into generated opcodes.
Introduced a look-up dictionary in the Instruction class that is
used to hold definitions of the arguments when parsed.
Added a generate method to the Instruction class to perform
operand substitution into the opcode template for each instance.
Fixed the definition of the PUSH opcode.

Comments (0)

Files changed (1)

ATmega/instructions.py

+"""
+instructions.py - Instruction definitions for the ATmega package.
+"""
+
 from definitions import *
 
+class ParseError(Exception):
+    pass
+
 class Opcode:
 
     def __init__(self, text):
     
         self.text = text
-        self.pieces = self.parse_opcode(text)
+        self.parse_opcode(text)
     
     def __repr__(self):
         return "<Opcode '"+self.text+"'>"
     
         s = len(text)
         pieces = []
+        sizes = {}
         current_type = ""
         current = ""
         
+        # Create a template that can be used to insert arguments into the
+        # generated opcode.
+        
         for c in text:
             if c not in current_type:
                 if current:
-                    pieces.append((s, current))
+                    pieces.append((current_type, s, current))
                     current = ""
                 if c == "1" or c == "0":
                     current_type = "10"
                     current_type = c
             
             s -= 1
+            sizes[current_type] = sizes.get(current_type, 0) + 1
             current += c
         
         if current:
-            pieces.append((s, current))
+            pieces.append((current_type, s, current))
         
-        return pieces
+        self.template = []
+        
+        for data_type, shift, digits in pieces:
+        
+            # Calculate the amount these digits need to be shifted.
+            remaining = sizes[data_type] - len(digits)
+            # Create a mask that isolates these digits from the original value.
+            mask = ((1 << len(digits)) - 1) << remaining
+            # Record the remaining number of digits so that any more digits
+            # for this type can be masked and shifted correctly.
+            sizes[data_type] = remaining
+            
+            # Record the type, mask and number of places needed to shift a
+            # value into place when constructing an opcode value.
+            
+            if data_type == "10":
+                value = 0
+                for digit in digits:
+                    value = value << 1
+                    if digit == "1":
+                        value = value | 1
+                
+                self.template.append((value, mask, shift - remaining))
+            else:
+                self.template.append((data_type, mask, shift - remaining))
 
 class Syntax:
 
-    class Expected:
-        pass
-    
-    class Register(Expected):
-        def __init__(self, name):
-            self.name = name
-        def __repr__(self):
-            return "<Register '"+self.name+"'>"
-    
-    class Constant(Expected):
-        def __init__(self, name):
-            self.name = name
-        def __repr__(self):
-            return "<Constant '"+self.name+"'>"
-    
-    class Address(Expected):
-        def __init__(self, name):
-            self.name = name
-        def __repr__(self):
-            return "<Address '"+self.name+"'>"
-    
     def __init__(self, text):
     
         self.text = text
                 pieces += register0 + [":"] + register1
             else:
                 if piece[0] == "R":
-                    pieces.append(Syntax.Register(piece[1:]))
+                    pieces.append(Register(piece[1:]))
                 else:
                     for c in piece:
                         if c in "-+":
                             pieces.append(c)
                         elif c in "XYZ":
-                            pieces.append(Syntax.Register(c))
+                            pieces.append(Register(c))
                         elif c in "Kq":
-                            pieces.append(Syntax.Constant(c))
+                            pieces.append(Constant(c))
                         elif c in "Ak":
-                            pieces.append(Syntax.Address(c))
+                            pieces.append(Address(c))
                         else:
                             pieces.append(c)
             
 
     def __init__(self, *args):
     
-        self.arguments = self.match_arguments(args)
+        self.match_arguments(args)
     
     def __repr__(self):
         return "<"+self.text+" "+self.arguments_string+">"
     
         arguments = []
         arguments_string = ""
+        values = {}
         
         i = 0
         for piece in self.syntax.parameters:
-            if isinstance(piece, Syntax.Expected):
+        
+            if isinstance(piece, Operand):
                 try:
-                    arguments.append(args[i])
+                    valid = piece.validate(args[i])
                 except IndexError:
                     raise ParseError, "Insuffient arguments to %s: %s" % (self.text, args)
                 
+                if not valid:
+                    raise ParseError, "Invalid value for %s operand: %s" % (self.text, args[i])
+                
                 arguments_string += str(args[i])
+                values[piece.name] = args[i]
                 i += 1
             else:
                 arguments_string += piece
         if i < len(args):
             raise ParseError, "Too many arguments specified to %s: %s" % (self.text, args)
         
+        self.arguments = arguments
+        self.values = values
         self.arguments_string = arguments_string
+    
+    def generate(self):
+    
+        opcode = 0
+        for data_type, mask, shift in self.opcode.template:
+        
+            if type(data_type) == int:
+                value = data_type
+            else:
+                value = self.values[data_type]
+            
+            opcode = opcode | ((value & mask) << shift)
+        
+        return opcode
 
 class ADC(Instruction):
 
 class PUSH(Instruction):
 
     text = "PUSH"
-    opcode = Opcode("1001001ddddd1111")
+    opcode = Opcode("1001001rrrrr1111")
     flags = ()
     syntax = Syntax("Rr")