#
# A class which represents the CPU itself, the brain of the virtual
# machine. It ties all the systems together and runs the story.
#
# For the license of this file, please consult the LICENSE file in the
# root directory of this distribution.
#

class ZCpuError(Exception):
    "General exception for Zcpu class"

class ZCpuIllegalInstruction(ZCpuError):
    "Illegal instruction encountered"

class ZCpu(object):

    _opcodes = {}

    def __init__(self, zmem, zopdecoder):
        self._memory = zmem
        self._opdecoder = zopdecoder

        print self._opcodes

    def _get_handler(self, opcode):
        try:
            return getattr(self, self._opcodes[opcode])
        except KeyError:
            raise ZCpuIllegalInstruction

    def run(self):
        while True:
            (type, opcode, operands) = self._opdecoder.get_next_instruction()
            self._get_handler(opcode)(*operands)


    # This is the "automagic" opcode handler registration system.
    # After each function that is an opcode handler, we assign the
    # function object an _opcode attribute, giving the numeric opcode
    # the function implements.
    #
    # Then, the following code iterates back over all items in the
    # class, and registers all objects with that attribute in the
    # _opcodes dictionary.
    #
    # Then, at runtime, the _get_handler method can be invoked to
    # retrieve the function implementing a given opcode.  Pretty cool
    # voodoo if you ask me.
    for k,v in vars().items():
        if hasattr(v, "_opcode"):
            _opcodes[v._opcode] = k

@@ -242,16 +242,51 @@
 ion.%0A#%0A%0A
+from zopdecoder import ZOpDecoder%0A%0A
 class ZC
@@ -345,16 +345,90 @@
 class%22%0A%0A
+class ZCpuOpcodeOverlap(ZCpuError):%0A    %22Overlapping opcodes registered%22%0A%0A
 class ZC
@@ -491,32 +491,259 @@
 n encountered%22%0A%0A
+def declare_opcode(func, optype, opcode, version=(1,2,3,4,5)):%0A    %22%22%22Helper function used for declaring functions implementing%0A    opcodes.%22%22%22%0A    func._optype = optype%0A    func._opcode = opcode%0A    func._opversion = version%0A%0A
 class ZCpu(objec
@@ -929,16 +929,24 @@
 er(self,
+ optype,
  opcode)
@@ -976,76 +976,298 @@
     
-return getattr(self, self._opcodes%5Bopcode%5D)%0A        except KeyError:
+print %22Opcode key:%22, (optype, opcode, self._memory.version)%0A            return getattr(self, self._opcodes%5B(optype, opcode,%0A                                                self._memory.version)%5D)%0A        except KeyError:%0A            print %22Unknown instruction (%25s, 0x%25X)%22 %25 (optype, opcode)
 %0A   
@@ -1357,16 +1357,18 @@
        (
+op
 type, op
@@ -1454,16 +1454,24 @@
 handler(
+optype, 
 opcode)(
@@ -1482,16 +1482,145 @@
 rands)%0A%0A
+    def op_add(a, b):%0A        %22%22%2216-bit signed addition%22%22%22%0A        print a,'+',b,'=',a+b%0A    declare_opcode(op_add, %222OP%22, 0x14)%0A
 %0A    # T
@@ -2243,46 +2243,226 @@
 %22_op
-code%22):%0A            _opcodes%5Bv._opcode
+type%22):%0A            for ver in v._opversion:%0A                opkey = (v._optype, v._opcode, ver)%0A%0A                if opkey in _opcodes.keys():%0A                    raise ZCpuOpcodeOverlap%0A%0A                _opcodes%5Bopkey
 %5D = 

Add versionning support for opcodes.