Пример #1
0
class TestMemoryClass(unittest.TestCase):
    def setUp(self):
        self.u8 = UInt8()
        self.u8.toggle(0)
        self.u8.bit(6, True)
        self.mem = MemoryMap(0x2000)
        self.mem.write(65)
        self.mem.write16(1024)
        self.mem[0x100] = 65
        self.mem.ptr = 0x0
        self.mc = MemoryController()
        self.mc.add_map(0x0, self.mem)
        self.mc.write(65)
        self.mc.write16(1024)
        self.mc[0x100] = 65
        self.mc.ptr = 0x0

    def test_uint8(self):
        self.assertEqual(self.u8.value, 65)
        self.assertEqual(self.u8.b, 65)
        self.assertEqual(self.u8.c, 'A')
        self.assertEqual(self.u8.bit(0), True)
        self.assertEqual(self.u8.bit(1), False)
        self.assertEqual(self.u8.bit(2), False)
        self.assertEqual(self.u8.bit(3), False)
        self.assertEqual(self.u8.bit(4), False)
        self.assertEqual(self.u8.bit(5), False)
        self.assertEqual(self.u8.bit(6), True)
        self.assertEqual(self.u8.bit(7), False)

    def test_memorymap(self):
        self.mem.write_protect()
        self.assertEqual(len(self.mem), 0x2000)
        self.assertEqual(self.mem.ptr, 0x0)
        self.assertEqual(self.mem.read(), 65)
        self.assertEqual(self.mem.read16(), 1024)
        self.assertEqual(self.mem.ptr, 0x3)
        self.assertEqual(self.mem[0x100], 65)
        self.assertEqual(self.mem.ptr, 0x3)
        self.assertRaises(MemoryProtectionError, self.mem.write, [0x30, 70])
        self.mem.read_protect()
        self.assertRaises(MemoryProtectionError, self.mem.read)

    def test_memorycontroller(self):
        self.assertEqual(len(self.mc), 0xFFFF)
        self.assertEqual(self.mc.ptr, 0x0)
        self.assertEqual(self.mc.fetch(), 65)
        self.assertEqual(self.mc.fetch16(), 1024)
        self.assertEqual(self.mc.ptr, 0x3)
        self.assertEqual(self.mc[0x100], 65)
        self.assertEqual(self.mc.ptr, 0x3)
Пример #2
0
class TestMemoryClass(unittest.TestCase):
    def setUp(self):
        self.u8 = UInt8()
        self.u8.toggle(0)
        self.u8.bit(6, True)
        self.mem = MemoryMap(0x2000)
        self.mem.write(65)
        self.mem.write16(1024)
        self.mem[0x100] = 65
        self.mem.ptr = 0x0
        self.mc = MemoryController()
        self.mc.add_map(0x0, self.mem)
        self.mc.write(65)
        self.mc.write16(1024)
        self.mc[0x100] = 65
        self.mc.ptr = 0x0
    def test_uint8(self):
        self.assertEqual(self.u8.value, 65)
        self.assertEqual(self.u8.b, 65)
        self.assertEqual(self.u8.c, 'A')
        self.assertEqual(self.u8.bit(0), True)
        self.assertEqual(self.u8.bit(1), False)
        self.assertEqual(self.u8.bit(2), False)
        self.assertEqual(self.u8.bit(3), False)
        self.assertEqual(self.u8.bit(4), False)
        self.assertEqual(self.u8.bit(5), False)
        self.assertEqual(self.u8.bit(6), True)
        self.assertEqual(self.u8.bit(7), False)
    def test_memorymap(self):
        self.mem.write_protect()
        self.assertEqual(len(self.mem), 0x2000)
        self.assertEqual(self.mem.ptr, 0x0)
        self.assertEqual(self.mem.read(), 65)
        self.assertEqual(self.mem.read16(), 1024)
        self.assertEqual(self.mem.ptr, 0x3)
        self.assertEqual(self.mem[0x100], 65)
        self.assertEqual(self.mem.ptr, 0x3)
        self.assertRaises(MemoryProtectionError, self.mem.write, [0x30, 70])
        self.mem.read_protect()
        self.assertRaises(MemoryProtectionError, self.mem.read)
    def test_memorycontroller(self):
        self.assertEqual(len(self.mc), 0xFFFF)
        self.assertEqual(self.mc.ptr, 0x0)
        self.assertEqual(self.mc.fetch(), 65)
        self.assertEqual(self.mc.fetch16(), 1024)
        self.assertEqual(self.mc.ptr, 0x3)
        self.assertEqual(self.mc[0x100], 65)
        self.assertEqual(self.mc.ptr, 0x3)
Пример #3
0
class CPU(object):
    """
    This class is the core CPU/Virtual Machine class.  It has most of the runtime that should be platform independent.
    This class does not contain any code that can touch the host operating environment, so it cannot load or save data.
    Depending on how or where you want the binary data/memory to be located in the host environment, let it be on disk, or in a database,
    you will need to subclass this and enable your specific environment's functionality.
    The other class below this CPU, should work on most operating systems to access standard disk and memory.
    """
    def __init__(self):
        self.regs = CPURegisters()
        self.flags = UInt8()
        self.mem = MemoryController()
        self.iomap = IOMap()
        self.mem.add_map(0x0, MemoryMap(0x2000))
        self.mem.add_map(0xa, self.iomap)
        self.cpu_hooks = {}
        self.devices = []
        self.__opcodes = {}
        for name in dir(self.__class__):
            if name[:7] == 'opcode_':
                self.__opcodes.update({int(name[7:], 16): getattr(self, name)})

    @property
    def var_map(self):
        return self.regs.registers

    def __getattr__(self, name):
        if name in self.regs.registers:
            return getattr(self.regs, name)
        raise AttributeError("%s isn't here." % name)

    def add_device(self, klass):
        hook = klass(self)
        self.devices.append(hook)
        for port in hook.ports:
            self.cpu_hooks.update({port: hook})
        if hasattr(hook, 'io_address'):
            self.iomap.add_map(hook.io_address, hook)

    def clear_registers(self, persistent=[]):
        for reg in self.regs.registers:
            if reg not in persistent:
                getattr(self.regs, reg).value = 0

    def push_registers(self, regs=None):
        if regs is None:
            regs = self.regs.pushable
        for reg in regs:
            self.mem.write16(self.ss + self.sp, getattr(self.regs, reg).b)
            self.sp.value += 2

    def pop_registers(self, regs=None):
        if regs is None:
            regs = self.regs.pushable.reverse()
        for reg in regs:
            self.sp.value -= 2
            getattr(self.regs, reg).value = self.mem.read16(self.ss + self.sp)

    def push_value(self, value):
        try:
            value = int(value)
            self.mem.write16(self.ss + self.sp, value)
            self.sp.value += 2
        except:
            self.mem.ptr = self.ds
            self.mem.write(value + chr(0))
            self.mem[self.ss + self.sp] = 0
            self.sp.value += 2

    def pop_value(self):
        if self.sp.value > 0:
            self.sp.value -= 2
            return self.mem.read16(self.ss + self.sp)
        raise CPUException('Stack out of range.')

    def resolve(self, typ, value):
        if typ == 0:
            value = value.b
        elif typ == 4:
            value = self.mem.read(value)
        elif typ == 5:
            value = self.mem.read16(value)
        return value

    def get_value(self, resolve=True):
        b = self.fetch()
        typ = b >> 4
        b = b & 0xf
        if typ == 0:
            value = getattr(self, self.var_map[b])
        elif typ == 1:
            value = b
        elif typ in (
                2,
                4,
        ):
            value = b | self.fetch() << 4
        elif typ in (
                3,
                5,
        ):
            value = b | self.fetch16() << 4
        if resolve:
            return typ, self.resolve(typ, value)
        return typ, value

    def set_value(self, dst, src, valid=None):
        if valid is not None and dst[0] not in valid:
            raise CPUException(
                'Attempted to place data in invalid location for specific operation.'
            )
        typ, dst = dst
        if typ == 0:
            dst.value = src
        elif typ in (
                4,
                5,
        ):
            if src < 256:
                self.mem[self.ds + dst] = src
            else:
                self.mem.write16(self.ds + dst, src)
        else:
            raise CPUException('Attempted to move data into immediate value.')

    def device_command(self, cmd):
        for device in self.devices:
            handler = getattr(device, cmd, None)
            if handler:
                handler()

    def start_devices(self):
        self.device_command('start')

    def stop_devices(self):
        self.device_command('stop')

    def device_cycle(self):
        self.device_command('cycle')

    def fetch(self):
        return self.mem.fetch()

    def fetch16(self):
        return self.mem.fetch16()

    def process(self):
        """ Processes a single bytecode. """
        self.mem.ptr = self.cs + self.ip
        op = self.fetch()
        if self.__opcodes.has_key(op):
            if not self.__opcodes[op]():
                self.ip.value = self.mem.ptr - self.cs.b
        else:
            raise CPUException('Invalid OpCode detected: %s' % op)

    def opcode_0x0(self):
        pass  # NOP

    def opcode_0x1(self):
        """ INT """
        i = self.get_value()[1]
        self.ip.value = self.mem.ptr - self.cs
        self.push_registers(['cs', 'ip'])
        jmp = self.mem[i * 2 + self.int_table:i * 2 + self.int_table + 2]
        self.regs.cs.value = jmp
        self.ip.value = 0
        return True

    def opcode_0x2(self):
        """ MOV """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, src)

    def opcode_0x3(self):
        """ IN """
        src = self.get_value()[1]
        dst = self.get_value(False)
        if self.cpu_hooks.has_key(src):
            self.set_value(dst, self.cpu_hooks[src].input(src))

    def opcode_0x4(self):
        """ OUT """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        if self.cpu_hooks.has_key(dst):
            self.cpu_hooks[dst].output(dst, src)

    def opcode_0x5(self):
        """ HLT """
        self.running = False

    def opcode_0x6(self):
        """ JMP """
        self.mem.ptr = self.cs.b + self.get_value()[1]

    def opcode_0x7(self):
        """ PUSH """
        typ, src = self.get_value()
        if typ == 0:
            self.push_value(src)
        else:
            raise CPUException('Attempt to PUSH a non-register.')

    def opcode_0x8(self):
        """ POP """
        dst = self.get_value(False)
        self.set_value(dst, self.pop_value(), [0])

    def opcode_0x9(self):
        """ CALL """
        jmp = self.cs.b + self.get_value()[1]
        self.ip.value = self.mem.ptr - self.cs.b
        self.push_registers(['cs', 'ip'])
        self.mem.ptr = jmp

    def opcode_0xa(self):
        """ INC """
        typ, src = self.get_value(False)
        if typ == 0:
            src.value += 1
        else:
            raise CPUException('Attempt to increment a non-register.')

    def opcode_0xb(self):
        """ DEC """
        typ, src = self.get_value(False)
        if typ == 0:
            src.value -= 1
        else:
            raise CPUException('Attempt to decrement a non-register.')

    def opcode_0xc(self):
        """ ADD """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, src + dst[1].b)

    def opcode_0xd(self):
        """ SUB """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b - src)

    def opcode_0xe(self):
        """ TEST """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        self.flags.bit(0, src == dst)

    def opcode_0xf(self):
        """ JE """
        jmp = self.get_value()[1]
        if self.flags.bit(0):
            self.mem.ptr = self.cs.b + jmp

    def opcode_0x10(self):
        """ JNE """
        jmp = self.get_value()[1]
        if not self.flags.bit(0):
            self.mem.ptr = self.cs.b + jmp

    def opcode_0x11(self):
        """ CMP """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        result = src - dst
        self.flags.bit(0, True if result == 0 else False)

    def opcode_0x12(self):
        """ MUL """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b * src)

    def opcode_0x13(self):
        """ DIV """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b / src)

    def opcode_0x14(self):
        """ PUSHF """
        self.push_value(self.flags.b)

    def opcode_0x15(self):
        """ POPF """
        self.flags.value = self.pop_value()

    def opcode_0x16(self):
        """ AND """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v & src, [0])

    def opcode_0x17(self):
        """ OR """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v | src, [0])

    def opcode_0x18(self):
        """ XOR """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v ^ src, [0])

    def opcode_0x19(self):
        """ NOT """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v & ~src, [0])

    def opcode_0x1a(self):
        """ RET """
        self.pop_registers(['ip', 'cs'])
        return True

    def run(self, cs=0, persistent=[]):
        self.clear_registers(persistent)
        self.cs.value = cs
        self.mem.ptr = 0
        self.int_table = len(self.mem) - 512
        del persistent
        del cs
        self.running = True
        while self.running:
            if 'bp' in self.__dict__ and self.bp == self.mem.ptr: break
            self.device_cycle()
            self.process()
        self.stop_devices()
        return 0

    def loadbin(self, filename, dest, compressed=False):
        if not compressed:
            bindata = open(filename, 'rb').read()
        else:
            bindata = zlib.decompress(open(filename, 'rb').read())
        self.mem.writeblock(dest, bindata)
        self.mem.ptr = 0

    def savebin(self, filename, src, size, compress=False):
        if not compress:
            open(filename, 'wb').write(self.mem.readblock(src, size))
        else:
            open(filename,
                 'wb').write(zlib.compress(self.mem.readblock(src, size)))
Пример #4
0
class CPU(object):
    """
    This class is the core CPU/Virtual Machine class.  It has most of the runtime that should be platform independent.
    This class does not contain any code that can touch the host operating environment, so it cannot load or save data.
    Depending on how or where you want the binary data/memory to be located in the host environment, let it be on disk, or in a database,
    you will need to subclass this and enable your specific environment's functionality.
    The other class below this CPU, should work on most operating systems to access standard disk and memory.
    """
    def __init__(self):
        self.regs = CPURegisters()
        self.flags = UInt8()
        self.mem = MemoryController()
        self.iomap = IOMap()
        self.mem.add_map(0x0, MemoryMap(0x2000))
        self.mem.add_map(0xa, self.iomap)
        self.cpu_hooks = {}
        self.devices = []
        self.__opcodes = {}
        for name in dir(self.__class__):
            if name[:7] == 'opcode_':
                self.__opcodes.update({int(name[7:], 16):getattr(self, name)})
    @property
    def var_map(self):
        return self.regs.registers
    def __getattr__(self, name):
        if name in self.regs.registers:
            return getattr(self.regs, name)
        raise AttributeError("%s isn't here." % name)
    def add_device(self, klass):
        hook = klass(self)
        self.devices.append(hook)
        for port in hook.ports:
            self.cpu_hooks.update({port: hook})
        if hasattr(hook, 'io_address'):
            self.iomap.add_map(hook.io_address, hook)
    def clear_registers(self, persistent=[]):
        for reg in self.regs.registers:
            if reg not in persistent:
                getattr(self.regs, reg).value = 0
    def push_registers(self, regs=None):
        if regs is None:
            regs = self.regs.pushable
        for reg in regs:
            self.mem.write16(self.ss+self.sp, getattr(self.regs, reg).b)
            self.sp.value += 2
    def pop_registers(self, regs=None):
        if regs is None:
            regs = self.regs.pushable.reverse()
        for reg in regs:
            self.sp.value -= 2
            getattr(self.regs, reg).value = self.mem.read16(self.ss+self.sp)
    def push_value(self, value):
        try:
            value = int(value)
            self.mem.write16(self.ss+self.sp,value)
            self.sp.value += 2
        except:
            self.mem.ptr = self.ds
            self.mem.write(value+chr(0))
            self.mem[self.ss+self.sp] = 0
            self.sp.value += 2
    def pop_value(self):
        if self.sp.value > 0:
            self.sp.value -= 2
            return self.mem.read16(self.ss+self.sp)
        raise CPUException('Stack out of range.')
    def resolve(self, typ, value):
        if typ == 0:
            value = value.b
        elif typ == 4:
            value = self.mem.read(value)
        elif typ == 5:
            value = self.mem.read16(value)
        return value
    def get_value(self, resolve=True):
        b = self.fetch()
        typ = b>>4
        b = b&0xf
        if typ == 0:
            value = getattr(self, self.var_map[b])
        elif typ == 1:
            value = b
        elif typ in (2,4,):
            value = b|self.fetch()<<4
        elif typ in (3,5,):
            value = b|self.fetch16()<<4
        if resolve:
            return typ, self.resolve(typ, value)
        return typ, value
    def set_value(self, dst, src, valid=None):
        if valid is not None and dst[0] not in valid:
            raise CPUException('Attempted to place data in invalid location for specific operation.')
        typ, dst = dst
        if typ == 0:
            dst.value = src
        elif typ in (4,5,):
            if src < 256:
                self.mem[self.ds+dst] = src
            else:
                self.mem.write16(self.ds+dst, src)
        else:
            raise CPUException('Attempted to move data into immediate value.')
    def device_command(self, cmd):
        for device in self.devices:
            handler = getattr(device, cmd, None)
            if handler:
                handler()
    def start_devices(self):
        self.device_command('start')
    def stop_devices(self):
        self.device_command('stop')
    def device_cycle(self):
        self.device_command('cycle')
    def fetch(self):
        return self.mem.fetch()
    def fetch16(self):
        return self.mem.fetch16()
    def process(self):
        """ Processes a single bytecode. """
        self.mem.ptr = self.cs+self.ip
        op = self.fetch()
        if self.__opcodes.has_key(op):
            if not self.__opcodes[op]():
                self.ip.value = self.mem.ptr-self.cs.b
        else:
            raise CPUException('Invalid OpCode detected: %s' % op)
    def opcode_0x0(self):
        pass # NOP
    def opcode_0x1(self):
        """ INT """
        i = self.get_value()[1]
        self.ip.value = self.mem.ptr-self.cs
        self.push_registers(['cs', 'ip'])
        jmp = self.mem[i*2+self.int_table:i*2+self.int_table+2]
        self.regs.cs.value = jmp
        self.ip.value = 0
        return True
    def opcode_0x2(self):
        """ MOV """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, src)
    def opcode_0x3(self):
        """ IN """
        src = self.get_value()[1]
        dst = self.get_value(False)
        if self.cpu_hooks.has_key(src):
            self.set_value(dst, self.cpu_hooks[src].input(src))
    def opcode_0x4(self):
        """ OUT """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        if self.cpu_hooks.has_key(dst):
            self.cpu_hooks[dst].output(dst, src)
    def opcode_0x5(self):
        """ HLT """
        self.running = False
    def opcode_0x6(self):
        """ JMP """
        self.mem.ptr = self.cs.b+self.get_value()[1]
    def opcode_0x7(self):
        """ PUSH """
        typ, src = self.get_value()
        if typ == 0:
            self.push_value(src)
        else:
            raise CPUException('Attempt to PUSH a non-register.')
    def opcode_0x8(self):
        """ POP """
        dst = self.get_value(False)
        self.set_value(dst, self.pop_value(), [0])
    def opcode_0x9(self):
        """ CALL """
        jmp = self.cs.b+self.get_value()[1]
        self.ip.value = self.mem.ptr-self.cs.b
        self.push_registers(['cs', 'ip'])
        self.mem.ptr = jmp
    def opcode_0xa(self):
        """ INC """
        typ, src = self.get_value(False)
        if typ == 0:
            src.value +=1
        else:
            raise CPUException('Attempt to increment a non-register.')
    def opcode_0xb(self):
        """ DEC """
        typ, src = self.get_value(False)
        if typ == 0:
            src.value -=1
        else:
            raise CPUException('Attempt to decrement a non-register.')
    def opcode_0xc(self):
        """ ADD """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, src+dst[1].b)
    def opcode_0xd(self):
        """ SUB """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b-src)
    def opcode_0xe(self):
        """ TEST """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        self.flags.bit(0, src == dst)
    def opcode_0xf(self):
        """ JE """
        jmp = self.get_value()[1]
        if self.flags.bit(0):
            self.mem.ptr = self.cs.b+jmp
    def opcode_0x10(self):
        """ JNE """
        jmp = self.get_value()[1]
        if not self.flags.bit(0):
            self.mem.ptr = self.cs.b+jmp
    def opcode_0x11(self):
        """ CMP """
        src = self.get_value()[1]
        dst = self.get_value()[1]
        result = src - dst
        self.flags.bit(0, True if result == 0 else False)
    def opcode_0x12(self):
        """ MUL """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b*src)
    def opcode_0x13(self):
        """ DIV """
        src = self.get_value()[1]
        dst = self.get_value(False)
        self.set_value(dst, dst[1].b/src)
    def opcode_0x14(self):
        """ PUSHF """
        self.push_value(self.flags.b)
    def opcode_0x15(self):
        """ POPF """
        self.flags.value = self.pop_value()
    def opcode_0x16(self):
        """ AND """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v & src, [0])
    def opcode_0x17(self):
        """ OR """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v | src, [0])
    def opcode_0x18(self):
        """ XOR """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v ^ src, [0])
    def opcode_0x19(self):
        """ NOT """
        src = self.get_value()[1]
        dst = self.get_value(False)
        v = self.resolve(*dst)
        self.set_value(dst, v & ~src, [0])
    def opcode_0x1a(self):
        """ RET """
        self.pop_registers(['ip', 'cs'])
        return True
    def run(self, cs=0, persistent=[]):
        self.clear_registers(persistent)
        self.cs.value = cs
        self.mem.ptr = 0
        self.int_table = len(self.mem)-512
        del persistent
        del cs
        self.running = True
        while self.running:
            if 'bp' in self.__dict__ and self.bp == self.mem.ptr: break
            self.device_cycle()
            self.process()
        self.stop_devices()
        return 0
    def loadbin(self, filename, dest, compressed=False):
        if not compressed:
            bindata = open(filename, 'rb').read()
        else:
            bindata = zlib.decompress(open(filename, 'rb').read())
        self.mem.writeblock(dest, bindata)
        self.mem.ptr = 0
    def savebin(self, filename, src, size, compress=False):
        if not compress:
            open(filename, 'wb').write(self.mem.readblock(src, size))
        else:
            open(filename, 'wb').write(zlib.compress(self.mem.readblock(src, size)))