コード例 #1
0
    def __init__(self, rom_file):
        signal.signal(signal.SIGINT, self.sigint_handler)

        self.commands = {
            "[di]sassemble": ("Disassemble: disassemble addr[, count=16]",
                              self.cmd_disassemble),
            "[r]egisters": ("Examine registers", self.cmd_registers),
            "[s]tep": ("One CPU step: step [count=1]", self.cmd_step),
            "[v]ideo": ("Examine video memory contents", self.cmd_video),
            "[du]mp": ("Dump memory: dump addr[, count=16]", self.cmd_dump),
            "[h]elp": ("This help", self.cmd_help),
            "[q]uit": ("Quit", self.cmd_quit),
        }

        self.video = Video()
        screen = pygame.display.set_mode(self.video.get_mode())
        #pygame.mouse.set_visible(0)
        pygame.display.update()

        surface = pygame.Surface(screen.get_size())
        surface = surface.convert()
        screen.blit(surface, (0, 0))
        self.video.set_surface(surface)

        pygame.display.flip()

        self.cpu = CPU(self.video)
        fd = open(rom_file, "rb")
        self.cpu.load(fd.read())
コード例 #2
0
ファイル: chip8.py プロジェクト: weibell/python-chip8-emu
    def __init__(self, scaling_factor: int, cycles_per_frame: int,
                 starting_address: int):
        pygame.init()
        self.screen = Screen(scaling_factor)
        self.keyboard = Keyboard()
        self.sound = Sound()
        self.cpu = CPU(self.screen, self.keyboard, starting_address)
        self.cycles_per_frame = cycles_per_frame

        sixty_hertz_ms = round(1000 / SIXTY_HERTZ)
        pygame.time.set_timer(SIXTY_HERTZ_CLOCK, sixty_hertz_ms)
        print(
            f"Target CPU speed: {cycles_per_frame * SIXTY_HERTZ} instructions per second"
        )
        print(f"Screen scaling factor: {scaling_factor}")
コード例 #3
0
ファイル: debugger.py プロジェクト: danaki/YaPyChip8
	def __init__(self, rom_file):
		signal.signal(signal.SIGINT, self.sigint_handler)

		self.commands = {
			"[di]sassemble": ("Disassemble: disassemble addr[, count=16]", self.cmd_disassemble),
			"[r]egisters": ("Examine registers", self.cmd_registers),
			"[s]tep": ("One CPU step: step [count=1]", self.cmd_step),
			"[v]ideo": ("Examine video memory contents", self.cmd_video),
			"[du]mp": ("Dump memory: dump addr[, count=16]", self.cmd_dump),
			"[h]elp": ("This help", self.cmd_help),
			"[q]uit": ("Quit", self.cmd_quit),
		}

		self.video = Video()
		screen = pygame.display.set_mode(self.video.get_mode())
		#pygame.mouse.set_visible(0)
		pygame.display.update()

		surface = pygame.Surface(screen.get_size())
		surface = surface.convert()
		screen.blit(surface, (0, 0))
		self.video.set_surface(surface)

		pygame.display.flip()

		self.cpu = CPU(self.video)
		fd = open(rom_file, "rb")
		self.cpu.load(fd.read())
コード例 #4
0
    def test_init(self):
        self.assertEqual(cpu.MEMORY_SIZE, len(self.cpu.memory))
        self.assertEqual(bytearray(cpu.font_sprites),
                         self.cpu.memory[0:len(cpu.font_sprites)])
        self.assertEqual([], self.cpu.stack)
        self.assertEqual(0x200, self.cpu.pc)
        self.assertEqual(0x600,
                         CPU(Screen(), Keyboard(), starting_address=0x600).pc)
        self.assertEqual([0x00] * 16, self.cpu.V)
        self.assertEqual(0x000, self.cpu.I)
        self.assertEqual(0x000, self.cpu.I)
        self.assertEqual(0x00, self.cpu.delay_timer)
        self.assertEqual(0x00, self.cpu.sound_timer)

        self.assertEqual(0x042,
                         CPU(Screen(), Keyboard(), starting_address=0x042).pc)
コード例 #5
0
ファイル: test_cpu.py プロジェクト: Broar/chip8
 def setUp(self):
     self.cpu = CPU()
コード例 #6
0
ファイル: test_cpu.py プロジェクト: Broar/chip8
class TestCPU(unittest.TestCase):
    """

    A class for testing the instructions of the CHIP-8 CPU

    """

    def setUp(self):
        self.cpu = CPU()

    def test_00E0(self):
        # Draw to every other pixel on the screen
        for i in range(len(self.cpu.gfx)):
            if i % 2 == 0:
                self.cpu.gfx[i] = 0x1

        # Clear the screen, then test it
        self.cpu._00E0()

        for i in range(len(self.cpu.gfx)):
            self.assertEqual(0x0, self.cpu.gfx[i])

    def test_00EE(self):
        # Enter a subroutine, then immediately exit
        # Check the values of the sp and pc
        self.cpu._2NNN(0x2300)
        self.cpu._00EE()
        self.assertEqual(0, self.cpu.sp)
        self.assertEqual(0x202, self.cpu.pc)

    def test_1NNN(self):
        self.cpu._1NNN(0x1100)
        self.assertEqual(0x100, self.cpu.pc)

    def test_2NNN(self):
        self.cpu._2NNN(0x2100)
        self.assertEqual(1, self.cpu.sp)

        # pc is initially located at 0x200, which is now stored on the stack
        self.assertEqual(0x200, self.cpu.stack[self.cpu.sp - 1])
        self.assertEqual(0x000, self.cpu.stack[self.cpu.sp])
        self.assertEqual(0x100, self.cpu.pc)

    def test_3XNN(self):
        # Test failure of v[x] == NN
        self.cpu._3XNN(0x3010)
        self.assertEqual(0x202, self.cpu.pc)

        # Test success of v[x] == NN
        self.cpu._6XNN(0x6010)
        self.cpu._3XNN(0x3010)

        # A successful skip moves the pc by 2 bytes
        # Since there were two instructions, pc is moved an additional 4 bytes
        # 0x202 + (3 * 0x2) = 0x208
        self.assertEqual(0x208, self.cpu.pc)

    def test_4XNN(self):
        # Test failure of v[x] != NN
        self.cpu._4XNN(0x4000)
        self.assertEqual(0x202, self.cpu.pc)

        # Test success of v[x] != NN
        self.cpu._6XNN(0x6010)
        self.cpu._4XNN(0x4000)

        # A successful skip moves the pc by 2 bytes
        # Since there were two instructions, pc is moved an additional 4 bytes
        # 0x202 + (3 * 0x2) = 0x208
        self.assertEqual(0x208, self.cpu.pc)

    def test_5XY0(self):
        # Test success of v[x] == v[y]
        # A successful skip moves the pc by 2 bytes
        # 0x200 + (2 * 0x2) = 0x204
        self.cpu._5XY0(0x5010)
        self.assertEqual(0x204, self.cpu.pc)

        # Test failure of v[x] == v[y]
        # Two instructions moves the pc by 4 bytes, so 0x204 + (2 * 0x2) = 0x208
        self.cpu._6XNN(0x6010)
        self.cpu._5XY0(0x5010)
        self.assertEqual(0x208, self.cpu.pc)

    def test_6XNN(self):
        self.cpu._6XNN(0x6010)
        self.assertEqual(0x10, self.cpu.v[0])
        self.assertEqual(0x202, self.cpu.pc)

    def test_7XNN(self):
        # Test without overflow
        self.cpu._7XNN(0x70FF)
        self.assertEqual(0xFF, self.cpu.v[0])
        self.assertEqual(0x202, self.cpu.pc)

        # Test with overflow
        self.cpu._7XNN(0x7001)
        self.assertEqual(0x00, self.cpu.v[0])
        self.assertEqual(0x204, self.cpu.pc)

    def test_8XY0(self):
        self.cpu._6XNN(0x61FF)
        self.cpu._8XY0(0, 1)
        self.assertEqual(0xFF, self.cpu.v[0])
        self.assertEqual(0x204, self.cpu.pc)

    def test_8XY1(self):
        # v[0] = 0xF0
        # v[1] = 0X0F
        self.cpu._6XNN(0x60F0)
        self.cpu._6XNN(0x610F)

        # v[0] | v[1] = 0XFF
        self.cpu._8XY1(0, 1)
        self.assertEqual(0xFF, self.cpu.v[0])
        self.assertEqual(0x206, self.cpu.pc)

    def test_8XY2(self):
        # v[0] = 0xF1
        # v[1] = 0x0F
        self.cpu._6XNN(0x60F1)
        self.cpu._6XNN(0x610F)

        # v[0] & v[1] = 0x01
        self.cpu._8XY2(0, 1)
        self.assertEqual(0x01, self.cpu.v[0])
        self.assertEqual(0x206, self.cpu.pc)

    def test_8XY3(self):
        # v[0] = 0x10
        # v[1] = 0x20
        self.cpu._6XNN(0x6010)
        self.cpu._6XNN(0x6120)

        # v[0] ^ v[1] = 0x01
        self.cpu._8XY3(0, 1)
        self.assertEqual(0x30, self.cpu.v[0])
        self.assertEqual(0x206, self.cpu.pc)

    def test_8XY4(self):
        # Test without carry
        self.cpu._6XNN(0x60F0)
        self.cpu._6XNN(0x610F)
        self.cpu._8XY4(0, 1)

        self.assertEqual(0xFF, self.cpu.v[0])
        self.assertEqual(0x00, self.cpu.v[0xF])
        self.assertEqual(0x206, self.cpu.pc)

        # Test with carry
        self.cpu._6XNN(0x6110)
        self.cpu._8XY4(0, 1)

        self.assertEqual(0x0F, self.cpu.v[0])
        self.assertEqual(0x01, self.cpu.v[0xF])
        self.assertEqual(0x20A, self.cpu.pc)

    def test_8XY5(self):
        # Test without borrow
        self.cpu._6XNN(0x60F0)
        self.cpu._6XNN(0x61E0)
        self.cpu._8XY5(0, 1)

        self.assertEqual(0x10, self.cpu.v[0])
        self.assertEqual(0x01, self.cpu.v[0xF])
        self.assertEqual(0x206, self.cpu.pc)

        # Test with borrow
        self.cpu._6XNN(0x61F0)
        self.cpu._8XY5(0, 1)

        self.assertEqual(0x20, self.cpu.v[0])
        self.assertEqual(0x00, self.cpu.v[0xF])
        self.assertEqual(0x20A, self.cpu.pc)

    def test_8XY6(self):
        # v[1] = 0x01
        self.cpu._6XNN(0x6101)
        self.cpu._8XY6(0, 1)
        self.assertEqual(0x01, self.cpu.v[0xF])
        self.assertEqual(0x2, self.cpu.v[1])
        self.assertEqual(0x2, self.cpu.v[0])
        self.assertEqual(0x204, self.cpu.pc)

    def test_8XY7(self):
        # Test without borrow
        self.cpu._6XNN(0x60E0)
        self.cpu._6XNN(0x61F0)
        self.cpu._8XY7(0, 1)

        self.assertEqual(0x10, self.cpu.v[0])
        self.assertEqual(0x01, self.cpu.v[0xF])
        self.assertEqual(0x206, self.cpu.pc)

        # Test with borrow
        self.cpu._6XNN(0x60F5)
        self.cpu._8XY7(0, 1)

        self.assertEqual(0xFB, self.cpu.v[0])
        self.assertEqual(0x00, self.cpu.v[0xF])
        self.assertEqual(0x20A, self.cpu.pc)

    def test_8XYE(self):
        # v[1] = 0x80
        self.cpu._6XNN(0x6180)
        self.cpu._8XYE(0, 1)
        self.assertEqual(0x01, self.cpu.v[0xF])
        self.assertEqual(0x40, self.cpu.v[1])
        self.assertEqual(0x40, self.cpu.v[0])
        self.assertEqual(0x204, self.cpu.pc)

    def test_9XY0(self):
        # Test failure of v[x] != v[y]
        self.cpu._9XY0(0x9010)
        self.assertEqual(0x202, self.cpu.pc)

        # Test success of v[x] != v[y]
        self.cpu._6XNN(0x6010)
        self.cpu._9XY0(0x9010)

        # A successful skip moves the pc by 2 bytes
        # Since there were two instructions, pc is moved an additional 4 bytes
        # 0x202 + (3 * 0x2) = 0x208
        self.assertEqual(0x208, self.cpu.pc)

    def test_ANNN(self):
        self.cpu._ANNN(0xAFFF)
        self.assertEqual(0xFFF, self.cpu.i)
        self.assertEqual(0x202, self.cpu.pc)

    def test_BNNN(self):
        self.cpu._6XNN(0x600F)
        self.cpu._BNNN(0xBFF0)
        self.assertEqual(0xFFF, self.cpu.pc)

    def test_CXNN(self):
        self.cpu._CXNN(0xC015)
        self.assertTrue(self.cpu.v[0] >= 0 and self.cpu.v[0] <= 255)
        self.assertEqual(0x202, self.cpu.pc)

    def test_EX9E(self):
        # Test failure of the key at v[x] being pressed
        self.cpu._EX9E(0)
        self.assertEqual(0x202, self.cpu.pc)

        # Test success of the key at v[x] being pressed
        # We will directly set the values of the cpu to simulate this case
        self.cpu.keys[0] = True
        self.cpu._EX9E(0)
        self.assertEqual(0x206, self.cpu.pc)

    def test_EXA1(self):
        # Test success of the key at v[x] not being pressed
        self.cpu._EXA1(0)
        self.assertEqual(0x204, self.cpu.pc)

        # Test failure of the key at v[x] not being pressed
        # We will directly set the values of the cpu to simulate this case
        self.cpu.keys[0] = True
        self.cpu._EXA1(0)
        self.assertEqual(0x206, self.cpu.pc)

    def test_FX07(self):
        # Set the delay timer directly
        self.cpu.delay = 1
        self.cpu._FX07(0)
        self.assertEqual(1, self.cpu.v[0])
        self.assertEqual(0x202, self.cpu.pc)

    def test_FX0A(self):
        pass

    def test_FX15(self):
        self.cpu._6XNN(0x6010)
        self.cpu._FX15(0)
        self.assertEqual(0x10, self.cpu.delay)
        self.assertEqual(0x204, self.cpu.pc)

    def test_FX18(self):
        self.cpu._6XNN(0x6010)
        self.cpu._FX18(0)
        self.assertEqual(0x10, self.cpu.sound)
        self.assertEqual(0x204, self.cpu.pc)

    def test_FX1E(self):
        self.cpu._6XNN(0x6010)
        self.cpu._ANNN(0xA100)
        self.cpu._FX1E(0)
        self.assertEqual(0x110, self.cpu.i)
        self.assertEqual(0x206, self.cpu.pc)

    def test_FX29(self):
        self.cpu._6XNN(0x6010)
        self.cpu._FX29(0)
        self.assertEqual(0x50, self.cpu.i)
        self.assertEqual(0x204, self.cpu.pc)

    def test_FX33(self):
        # Place 245 into V0. 
        self.cpu._6XNN(0x60F5)
        self.cpu._FX33(0)

        # We expect 2, 4, 5 to be located at i, i + 1, and i + 2, respectively
        self.assertEqual(2, self.cpu.memory[self.cpu.i])
        self.assertEqual(4, self.cpu.memory[self.cpu.i + 1])
        self.assertEqual(5, self.cpu.memory[self.cpu.i + 2])
        self.assertEqual(0x204, self.cpu.pc)

    def test_FX55(self):
        self.cpu._6XNN(0x6001)
        self.cpu._6XNN(0x6102)
        self.cpu._6XNN(0x6203)
        self.cpu._6XNN(0x6304)

        j = self.cpu.i
        self.cpu._FX55(3)

        self.assertEqual(1, self.cpu.memory[j])
        self.assertEqual(2, self.cpu.memory[j + 1])
        self.assertEqual(3, self.cpu.memory[j + 2])
        self.assertEqual(4, self.cpu.memory[j + 3])
        self.assertEqual(4, self.cpu.i)
        self.assertEqual(0x20A, self.cpu.pc)

    def test_FX65(self):
        for j in range(3):
            self.cpu.memory[self.cpu.i + j] = j

        self.cpu._FX65(2)

        self.assertEqual(0, self.cpu.v[0])
        self.assertEqual(1, self.cpu.v[1])
        self.assertEqual(2, self.cpu.v[2])
        self.assertEqual(0, self.cpu.v[3])
        self.assertEqual(3, self.cpu.i)
        self.assertEqual(0x202, self.cpu.pc)
コード例 #7
0
ファイル: debugger.py プロジェクト: danaki/YaPyChip8
class Debugger:
	def __init__(self, rom_file):
		signal.signal(signal.SIGINT, self.sigint_handler)

		self.commands = {
			"[di]sassemble": ("Disassemble: disassemble addr[, count=16]", self.cmd_disassemble),
			"[r]egisters": ("Examine registers", self.cmd_registers),
			"[s]tep": ("One CPU step: step [count=1]", self.cmd_step),
			"[v]ideo": ("Examine video memory contents", self.cmd_video),
			"[du]mp": ("Dump memory: dump addr[, count=16]", self.cmd_dump),
			"[h]elp": ("This help", self.cmd_help),
			"[q]uit": ("Quit", self.cmd_quit),
		}

		self.video = Video()
		screen = pygame.display.set_mode(self.video.get_mode())
		#pygame.mouse.set_visible(0)
		pygame.display.update()

		surface = pygame.Surface(screen.get_size())
		surface = surface.convert()
		screen.blit(surface, (0, 0))
		self.video.set_surface(surface)

		pygame.display.flip()

		self.cpu = CPU(self.video)
		fd = open(rom_file, "rb")
		self.cpu.load(fd.read())

	def run(self):
		last_command = None
		while True:
			try:
				prompt = "(debugger) "
				raw = raw_input(prompt)
				if (raw == '') and (not last_command is None):
					callback, callback_args = last_command
					callback(*callback_args)
				else:
					args = shlex.split(raw)

					callback = None
					for k, v in self.commands.items():
						m = re.search("^(.*)\[(.*)\](.*)$", k)
						short = m.group(2)
						long = m.group(1) + m.group(2) + m.group(3)

						if args[0] in [short, long]:
							callback = v[1]
							# we assume that command arguments are always numeric either in hex 0x... or decimal format
							callback_args = []
							for arg in args[1:]:
								try:
									arg = int(arg, 0)
								except (ValueError, TypeError):
									pass

								callback_args.append(arg)

							last_command = callback, callback_args
							callback(*callback_args)
							break
					else:
						raise CommandException("Unknown command %s" % args[0])

			except IndexError:
				continue

			except CommandException as e:
				print e

			except (EOFError, ExitException):
				return 0

			except SIGINTException:
				print >> sys.stderr, \
					"<SIGINT received, bye-bye>"
				return 1

	def sigint_handler(self, signum, frame):
		"""Handler for the SIGINT signal."""
		raise SIGINTException

	def print_addr(self, addr):
		instruction = self.cpu.get_instruction(addr)
		decoded = self.cpu.decode_instruction(instruction)

		print "0x%04X 0x%04X" % (addr, instruction),

		if decoded is None:
			print "*** Unknown instruction"
		else:
			(handler, args) = decoded
			syntax = re.split('\n', inspect.getdoc(handler))[0]
			fmt = syntax\
				.replace('Vx', 'V%d')\
				.replace('Vy', 'V%d')\
				.replace('addr', '0x%04X')\
				.replace('nibble', '%d')\
				.replace('byte', '0x%02X')\

			print fmt % tuple(args),
			if addr == self.cpu.IP:
				print " <<<",

			print

	def cmd_disassemble(self, *args):
		if (len(args) < 1) or (len(args) > 2):
			raise BadArgumentCountException

		addr = args[0]
		count = args[1] if len(args) == 2 else 16

		while (count > 0) and (addr < len(self.cpu.ram) - 2):
			self.print_addr(addr)

			count -= 1
			addr += 2

	def cmd_registers(self, *args):
		if len(args) > 0:
			raise BadArgumentsException

		for i in range(0, len(self.cpu.V)):
			print "V%d: 0x%02x" % (i, self.cpu.V[i])

		print "I: 0x%04X" % self.cpu.I
		print "DT: 0x%02X" % self.cpu.DT
		print "ST: 0x%02X" % self.cpu.ST
		print "(IP): 0x%04X" % self.cpu.IP
		print "(SP): 0x%02X" % self.cpu.SP

	def cmd_dump(self, *args):
		if (len(args) < 1) or (len(args) > 2):
			raise BadArgumentCountException

		addr = args[0]
		count = args[1] if len(args) == 2 else 16

		i = 0
		while (i < count) and (addr < len(self.cpu.ram) - 2):
			if ((i % 16) == 0) and (i > 0):
				print

			print "%02X" % self.cpu.ram[addr],

			i += 1
			addr += 2

		print

	def cmd_video(self, *args):
		if len(args) > 0:
			raise BadArgumentCountException

		for y in xrange(0, 32):
			for x in xrange(0, 64):
				print 'x' if self.video.get_pixel(x, y) else '.',

			print

		print

	def cmd_step(self, *args):
		if len(args) > 1:
			raise BadArgumentCountException

		if len(args) == 0:
			count = 1
		else:
			count = args[0]

		while count > 0:
			self.print_addr(self.cpu.IP)
			self.cpu.tick()
			count -= 1

	def cmd_help(self, *args):
		if len(args) > 0:
			raise NoArgumentsRequredException

		for k, v in self.commands.items():
			print k,
			print " " * (12 - len(k)),
			print v[0]

	def cmd_quit(self, *args):
		raise ExitException
コード例 #8
0
def main(rom_file):
	pygame.init()
	#screen = pygame.display.set_mode((64, 64))
	video = Video()
	screen = pygame.display.set_mode(video.get_mode())
	#pygame.mouse.set_visible(0)
	pygame.display.update()
	
	surface = pygame.Surface(screen.get_size())
	surface = surface.convert()
	screen.blit(surface, (0, 0))
	video.set_surface(surface)
	
	pygame.display.flip()

	keyboard = Keyboard()
	computer = CPU(video)
	fd = open(rom_file, "rb")
	computer.load(fd.read())
	
	CLOCK_HZ = 10000 # 4194304
	TIMER_HZ = 30
	CPU_CLOCK_EVENT = USEREVENT + 1
	TIMER_CLOCK_EVENT = CPU_CLOCK_EVENT + 1

	#pygame.time.set_timer(CPU_CLOCK_EVENT, 1000 / CLOCK_HZ)
	#pygame.time.set_timer(TIMER_CLOCK_EVENT, int(1000 / TIMER_HZ))
	pygame.time.set_timer(TIMER_CLOCK_EVENT, 100)
	
	i = 0
	while True:

		event = pygame.event.poll()
		
		if event.type == pygame.QUIT:
			sys.exit()
		#elif event.type == CPU_CLOCK_EVENT:
		#	computer.tick()
		elif event.type == TIMER_CLOCK_EVENT:
			computer.timer()
		elif event.type == pygame.KEYUP:
			key = keyboard.translate(event.key)
			if not key is None: 
				computer.key_up(key)
		elif event.type == pygame.KEYDOWN:
			key = keyboard.translate(event.key)
			if not key is None: 
				computer.key_down(key)
				
		i += 1
		#print "timer " + str(i)
		computer.timer()
		computer.tick()
		#pygame.time.wait(1000 / CLOCK_HZ)
		
		screen.blit(surface, (0, 0))
		if not video.dirty_rect is None: 
			pygame.display.update(video.dirty_rect)

		video.dirty_rect = None
コード例 #9
0
ファイル: test_cpu.py プロジェクト: danaki/YaPyChip8
 def setUp(self):
     self.cpu = CPU()
コード例 #10
0
ファイル: test_cpu.py プロジェクト: danaki/YaPyChip8
class CPUTest(unittest.TestCase):
    def setUp(self):
        self.cpu = CPU()

    def test_int2hex(self):
        self.assertEquals('0000', self.cpu.int2hex(0))
        self.assertEquals('0001', self.cpu.int2hex(1))
        self.assertEquals('00FF', self.cpu.int2hex(255))
        self.assertEquals('0100', self.cpu.int2hex(256))
        self.assertEquals('0FFF', self.cpu.int2hex(0x0FFF))
        self.assertEquals('FFFF', self.cpu.int2hex(0xFFFF))
        self.assertEquals('A123', self.cpu.int2hex(0xA123))

    def test_decode_instruction(self):
        self.assertEquals((self.cpu.CLS, []),
                          self.cpu.decode_instruction(0x00E0))  # CLS
        self.assertEquals((self.cpu.JP_addr, [564]),
                          self.cpu.decode_instruction(0x1234))  # JP 0x234
        self.assertEquals((self.cpu.LD_Vx_Vy, [1, 2]),
                          self.cpu.decode_instruction(0x8120))  # LD V1, V2
        self.assertEquals((self.cpu.RND_Vx_byte, [5, 255]),
                          self.cpu.decode_instruction(0xC5FF))  # RND V5, FF
        self.assertEquals((self.cpu.DRW_Vx_Vy_nibble, [4, 5, 7]),
                          self.cpu.decode_instruction(0xD457))  # DRW V4, V5, 7
        self.assertEquals((self.cpu.LD_I_Vx, [10]),
                          self.cpu.decode_instruction(0xFA55))  # LD [I], V10

    def load_example_program(self):
        program = '00E081201000'  # CLS; LD V1, V2; JP 0000
        data = bytearray(program.decode('hex'))
        self.cpu.load(data)

    def test_get_instruction(self):
        self.load_example_program()
        self.assertEquals(0x00E0, self.cpu.get_instruction(0))
        self.assertEquals(0x8120, self.cpu.get_instruction(2))
        self.assertEquals(0x1000, self.cpu.get_instruction(4))

    def test_load_and_decode_instruction(self):
        self.load_example_program()
コード例 #11
0
ファイル: chip8.py プロジェクト: weibell/python-chip8-emu
class Chip8:
    screen: Screen
    keyboard: Keyboard
    sound: Sound
    cpu: CPU
    cycles_per_frame: int

    def __init__(self, scaling_factor: int, cycles_per_frame: int,
                 starting_address: int):
        pygame.init()
        self.screen = Screen(scaling_factor)
        self.keyboard = Keyboard()
        self.sound = Sound()
        self.cpu = CPU(self.screen, self.keyboard, starting_address)
        self.cycles_per_frame = cycles_per_frame

        sixty_hertz_ms = round(1000 / SIXTY_HERTZ)
        pygame.time.set_timer(SIXTY_HERTZ_CLOCK, sixty_hertz_ms)
        print(
            f"Target CPU speed: {cycles_per_frame * SIXTY_HERTZ} instructions per second"
        )
        print(f"Screen scaling factor: {scaling_factor}")

    def load(self, rom: bytes):
        self.cpu.load(rom)

    def run(self):
        while True:
            self._handle_events()

    def _handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                self.keyboard.keydown(event)

            elif event.type == pygame.KEYUP:
                key = self.keyboard.keyup(event)
                if self.cpu.waiting_for_keypress and key is not None:
                    self.cpu.key_was_pressed(key)

            elif event.type == SIXTY_HERTZ_CLOCK:
                self.tick()

            elif event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

    def tick(self):
        if self.cpu.waiting_for_keypress:
            return

        has_screen_changed = False
        self.cpu.decrease_timers()
        for _ in range(self.cycles_per_frame):
            try:
                self.cpu.step()
            except UpdateScreen:
                has_screen_changed = True
            except WaitForKeypress:
                break
        self.sound.update(self.cpu.sound_timer)
        if has_screen_changed:
            self.screen.update()
コード例 #12
0
 def setUp(self):
     self.screen = Screen()
     self.keyboard = Keyboard()
     self.cpu = CPU(self.screen, self.keyboard)
コード例 #13
0
class TestCPU(unittest.TestCase):
    def setUp(self):
        self.screen = Screen()
        self.keyboard = Keyboard()
        self.cpu = CPU(self.screen, self.keyboard)

    def test_init(self):
        self.assertEqual(cpu.MEMORY_SIZE, len(self.cpu.memory))
        self.assertEqual(bytearray(cpu.font_sprites),
                         self.cpu.memory[0:len(cpu.font_sprites)])
        self.assertEqual([], self.cpu.stack)
        self.assertEqual(0x200, self.cpu.pc)
        self.assertEqual(0x600,
                         CPU(Screen(), Keyboard(), starting_address=0x600).pc)
        self.assertEqual([0x00] * 16, self.cpu.V)
        self.assertEqual(0x000, self.cpu.I)
        self.assertEqual(0x000, self.cpu.I)
        self.assertEqual(0x00, self.cpu.delay_timer)
        self.assertEqual(0x00, self.cpu.sound_timer)

        self.assertEqual(0x042,
                         CPU(Screen(), Keyboard(), starting_address=0x042).pc)

    def test_decrease_timers(self):
        self.cpu.delay_timer = 0x01
        self.cpu.sound_timer = 0x01
        self.cpu.decrease_timers()
        self.assertEqual(0x00, self.cpu.delay_timer)
        self.assertEqual(0x00, self.cpu.sound_timer)

        self.cpu.decrease_timers()
        self.assertEqual(0x00, self.cpu.delay_timer)
        self.assertEqual(0x00, self.cpu.sound_timer)

    def test_CLS(self):  # 00E0
        for row in self.screen.buffer:
            for x, _ in enumerate(row):
                row[x] = True
        self.cpu._CLS()
        for row in self.screen.buffer:
            self.assertTrue(not any(row))

    def test_RET(self):  # 00EE
        self.cpu.stack.append(0x42)
        self.cpu._RET()
        self.assertEqual(0x42, self.cpu.pc)
        self.assertEqual([], self.cpu.stack)

    def test_JP_nnn(self):  # 1nnn
        self.cpu.instruction = 0x1042
        self.cpu._JP_nnn()
        self.assertEqual(0x42, self.cpu.pc)

    def test_CALL_nnn(self):  # 2nnn
        self.cpu.instruction = 0x2042
        self.cpu.pc = 0x1234
        self.cpu._CALL_nnn()
        self.assertEqual(0x42, self.cpu.pc)
        self.assertEqual([0x1234], self.cpu.stack)

    def test_SE_Vx_nn(self):  # 3xnn
        addr = self.cpu.pc
        self.cpu.V[0x1] = 0x42

        self.cpu.instruction = 0x3042
        self.cpu._SE_Vx_nn()
        self.assertEqual(addr, self.cpu.pc)

        self.cpu.instruction = 0x3141
        self.cpu._SE_Vx_nn()
        self.assertEqual(addr, self.cpu.pc)

        self.cpu.instruction = 0x3142
        self.cpu._SE_Vx_nn()
        self.assertEqual(addr + 2, self.cpu.pc)

    def test_SNE_Vx_nn(self):  # 4xnn
        addr = self.cpu.pc
        self.cpu.V[0x1] = 0x42

        self.cpu.instruction = 0x4142
        self.cpu._SNE_Vx_nn()
        self.assertEqual(addr, self.cpu.pc)

        self.cpu.instruction = 0x4042
        self.cpu._SNE_Vx_nn()
        self.assertEqual(addr + 2, self.cpu.pc)

        self.cpu.instruction = 0x4141
        self.cpu._SNE_Vx_nn()
        self.assertEqual(addr + 4, self.cpu.pc)

    def test_SE_Vx_Vy(self):  # 5xy0
        self.cpu.instruction = 0x5120
        addr = self.cpu.pc

        self.cpu.V[0x1] = 0x41
        self.cpu.V[0x2] = 0x42
        self.cpu._SE_Vx_Vy()
        self.assertEqual(addr, self.cpu.pc)

        self.cpu.V[0x1] = 0x42
        self.cpu._SE_Vx_Vy()
        self.assertEqual(addr + 2, self.cpu.pc)

    def test_LD_Vx_nn(self):  # 6xnn
        self.cpu.instruction = 0x6142
        self.cpu._LD_Vx_nn()
        self.assertEqual(0x42, self.cpu.V[0x1])

        self.cpu._LD_Vx_nn()
        self.assertEqual(0x42, self.cpu.V[0x1])

    def test_ADD_Vx_nn(self):  # 7xnn
        self.cpu.instruction = 0x7101
        self.cpu.V[0x1] = 0xfe

        self.cpu._ADD_Vx_nn()
        self.assertEqual(0xff, self.cpu.V[0x1])
        self.assertEqual(0x00, self.cpu.V[0xf])

        self.cpu._ADD_Vx_nn()
        self.assertEqual(0x00, self.cpu.V[0x1])
        self.assertEqual(0x00, self.cpu.V[0xf])

    def test_LD_Vx_Vy(self):  # 8xy0
        self.cpu.instruction = 0x8010
        self.cpu.V[0x1] = 0x42
        self.cpu._LD_Vx_Vy()
        self.assertEqual(0x42, self.cpu.V[0x0])

    def test_OR_Vx_Vy(self):  # 8xy1
        self.cpu.instruction = 0x8121
        self.cpu.V[0x1] = 0b01010101
        self.cpu.V[0x2] = 0b00001111
        self.cpu._OR_Vx_Vy()
        self.assertEqual(0b01011111, self.cpu.V[0x1])

    def test_AND_Vx_Vy(self):  # 8xy2
        self.cpu.instruction = 0x8122
        self.cpu.V[0x1] = 0b01010101
        self.cpu.V[0x2] = 0b00001111
        self.cpu._AND_Vx_Vy()
        self.assertEqual(0b00000101, self.cpu.V[0x1])

    def test_XOR_Vx_Vy(self):  # 8xy3
        self.cpu.instruction = 0x8123
        self.cpu.V[0x1] = 0b01010101
        self.cpu.V[0x2] = 0b00001111
        self.cpu._XOR_Vx_Vy()
        self.assertEqual(0b01011010, self.cpu.V[0x1])

    def test_ADD_Vx_Vy(self):  # 8xy4
        self.cpu.instruction = 0x8124
        self.cpu.V[0x1] = 0xfe
        self.cpu.V[0x2] = 0x01

        self.cpu._ADD_Vx_Vy()
        self.assertEqual(0xff, self.cpu.V[0x1])
        self.assertEqual(0x00, self.cpu.V[0xf])

        self.cpu._ADD_Vx_Vy()
        self.assertEqual(0x00, self.cpu.V[0x1])
        self.assertEqual(0x01, self.cpu.V[0xf])

    def test_SUB_Vx_Vy(self):  # 8xy5
        self.cpu.instruction = 0x8125
        self.cpu.V[0x1] = 0x01
        self.cpu.V[0x2] = 0x01

        self.cpu._SUB_Vx_Vy()
        self.assertEqual(0x00, self.cpu.V[0x1])
        self.assertEqual(0x01, self.cpu.V[0xf])

        self.cpu._SUB_Vx_Vy()
        self.assertEqual(0xff, self.cpu.V[0x1])
        self.assertEqual(0x00, self.cpu.V[0xf])

    def test_SHR_Vx_Vy(self):  # 8xy6
        self.cpu.instruction = 0x8126
        self.cpu.V[0x2] = 0b11110000
        self.cpu._SHR_Vx_Vy()
        self.assertEqual(0b01111000, self.cpu.V[0x1])
        self.assertEqual(0b00000000, self.cpu.V[0xf])

        self.cpu.V[0x2] = 0b00001111
        self.cpu._SHR_Vx_Vy()
        self.assertEqual(0b00000111, self.cpu.V[0x1])
        self.assertEqual(0b00000001, self.cpu.V[0xf])

    def test_SUBN_Vx_Vy(self):  # 8xy7
        self.cpu.instruction = 0x8127
        self.cpu.V[0x1] = 0x01
        self.cpu.V[0x2] = 0x01

        self.cpu._SUBN_Vx_Vy()
        self.assertEqual(0x00, self.cpu.V[0x1])
        self.assertEqual(0x01, self.cpu.V[0xf])

        self.cpu.V[0x1] = 0x02
        self.cpu._SUBN_Vx_Vy()
        self.assertEqual(0xff, self.cpu.V[0x1])
        self.assertEqual(0x00, self.cpu.V[0xf])

    def test_SHL_Vx_Vy(self):  # 8xyE
        self.cpu.instruction = 0x812E
        self.cpu.V[0x2] = 0b11110000
        self.cpu._SHL_Vx_Vy()
        self.assertEqual(0b11100000, self.cpu.V[0x1])
        self.assertEqual(0b00000001, self.cpu.V[0xf])

        self.cpu.V[0x2] = 0b00001111
        self.cpu._SHL_Vx_Vy()
        self.assertEqual(0b00011110, self.cpu.V[0x1])
        self.assertEqual(0b00000000, self.cpu.V[0xf])

    def test_SNE_Vx_Vy(self):  # 9xy0
        self.cpu.instruction = 0x9120
        addr = self.cpu.pc

        self.cpu.V[0x1] = 0x42
        self.cpu.V[0x2] = 0x42
        self.cpu._SNE_Vx_Vy()
        self.assertEqual(addr, self.cpu.pc)

        self.cpu.V[0x1] = 0x41
        self.cpu._SNE_Vx_Vy()
        self.assertEqual(addr + 2, self.cpu.pc)

    def test_LD_I_nnn(self):  # Annn
        self.cpu.instruction = 0xA042
        self.cpu._LD_I_nnn()
        self.assertEqual(0x42, self.cpu.I)

    def test_JP_V0_nnn(self):  # Bnnn
        self.cpu.instruction = 0xB042
        self.cpu.V[0x0] = 0x42
        self.cpu._JP_V0_nnn()
        self.assertEqual(0x42 + 0x42, self.cpu.pc)

    def test_RND_Vx_nn(self):  # Cxnn
        numbers = set()
        for mask in range(0xff + 1):
            self.cpu.instruction = 0xC100 | mask
            self.cpu._RND_Vx_nn()
            rnd = self.cpu.V[0x1]
            self.assertEqual(rnd & mask, rnd)
            numbers.add(rnd)
        self.assertGreater(len(numbers), 50)

    def test_DRW_Vx_Vy_n(self):  # Dxyn
        to_int = lambda bool_list: sum(
            [val << (7 - pos) for pos, val in enumerate(bool_list)])
        x = 4
        y = 2
        digit = 7

        self.cpu.instruction = 0xD125
        self.cpu.I = digit * 5
        self.cpu.V[0x1] = x
        self.cpu.V[0x2] = y

        with self.assertRaises(UpdateScreen):
            self.cpu._DRW_Vx_Vy_n()
        for line in range(5):
            self.assertEqual(cpu.font_sprites[digit * 5 + line],
                             to_int(self.screen.buffer[y + line][x:x + 8]))
        self.assertEqual(0x00, self.cpu.V[0xf])

        with self.assertRaises(UpdateScreen):
            self.cpu._DRW_Vx_Vy_n()
        for line in range(5):
            self.assertEqual(0x00,
                             to_int(self.screen.buffer[y + line][x:x + 8]))
        self.assertEqual(0x01, self.cpu.V[0xf])

        self.cpu.V[0x1] = 62
        self.cpu.V[0x2] = 30
        with self.assertRaises(UpdateScreen):
            self.cpu._DRW_Vx_Vy_n()
        self.assertEqual([True, True], self.screen.buffer[30][62:64])
        self.assertEqual([False, False], self.screen.buffer[31][62:64])
        self.assertEqual([False, False], self.screen.buffer[0][62:64])
        self.assertEqual([False, True], self.screen.buffer[1][62:64])
        self.assertEqual([False, True], self.screen.buffer[2][62:64])

        self.assertEqual([True, True], self.screen.buffer[30][0:2])
        self.assertEqual([False, True], self.screen.buffer[31][0:2])
        self.assertEqual([True, False], self.screen.buffer[0][0:2])
        self.assertEqual([False, False], self.screen.buffer[1][0:2])
        self.assertEqual([False, False], self.screen.buffer[2][0:2])

    def test_SKP_Vx(self):  # Ex9E
        self.cpu.instruction = 0xE19E
        addr = self.cpu.pc

        self.cpu.V[0x1] = 0x1

        self.cpu._SKP_Vx()
        self.assertEqual(addr, self.cpu.pc)

        self.keyboard.pressed_keys.add(0x1)
        self.cpu._SKP_Vx()
        self.assertEqual(addr + 2, self.cpu.pc)

    def test_SKNP_Vx(self):  # ExA1
        self.cpu.instruction = 0xE1A1
        addr = self.cpu.pc

        self.cpu.V[0x1] = 0x1

        self.keyboard.pressed_keys.add(0x1)
        self.cpu._SKNP_Vx()
        self.assertEqual(addr, self.cpu.pc)

        self.keyboard.pressed_keys.remove(0x1)
        self.cpu._SKNP_Vx()
        self.assertEqual(addr + 2, self.cpu.pc)

    def test_LD_Vx_DT(self):  # Fx07
        self.cpu.instruction = 0xF107
        self.cpu.delay_timer = 0x42
        self.cpu._LD_Vx_DT()
        self.assertEqual(0x42, self.cpu.V[0x1])

    def test_LD_Vx_K(self):  # Fx0A
        self.cpu.instruction = 0xF10A
        with self.assertRaises(WaitForKeypress):
            self.cpu._LD_Vx_K()
        self.assertTrue(self.cpu.waiting_for_keypress)

        self.cpu.key_was_pressed(0x1)
        self.assertFalse(self.cpu.waiting_for_keypress)
        self.assertEqual(0x1, self.cpu.V[0x1])

    def test_LD_DT_Vx(self):  # Fx15
        self.cpu.instruction = 0xF115
        self.cpu.V[0x1] = 0x42
        self.cpu._LD_DT_Vx()
        self.assertEqual(0x42, self.cpu.delay_timer)

    def test_LD_ST_Vx(self):  # Fx18
        self.cpu.instruction = 0xF118
        self.cpu.V[0x1] = 0x42
        self.cpu._LD_ST_Vx()
        self.assertEqual(0x42, self.cpu.sound_timer)

    def test_ADD_I_Vx(self):  # Fx1E
        self.cpu.instruction = 0xF11E
        self.cpu.V[0x1] = 0x1
        self.cpu.I = 0xffe
        self.cpu._ADD_I_Vx()
        self.assertEqual(0xfff, self.cpu.I)

        self.cpu._ADD_I_Vx()
        self.assertEqual(0x000, self.cpu.I)

    def test_LD_F_Vx(self):  # Fx29
        self.cpu.instruction = 0xF129
        self.cpu.V[0x1] = 7
        self.cpu._LD_F_Vx()
        self.assertEqual(7 * 5, self.cpu.I)

    def test_LD_B_Vx(self):  # Fx33
        self.cpu.instruction = 0xF133
        self.cpu._LD_B_Vx()

    def test_LD_I_Vx(self):  # Fx55
        self.cpu.instruction = 0xF755
        self.cpu.I = 0x123
        for reg in range(0x7 + 1):
            self.cpu.V[reg] = reg * 2
        self.cpu._LD_I_Vx()
        for reg in range(0x7 + 1):
            self.assertEqual(reg * 2, self.cpu.memory[0x123 + reg])
        self.assertEqual(0x123 + 0x7 + 1, self.cpu.I)

    def test_LD_Vx_I(self):  # Fx65
        self.cpu.instruction = 0xF765
        self.cpu.I = 0x123
        for reg in range(0x7 + 1):
            self.cpu.memory[0x123 + reg] = reg * 2
        self.cpu._LD_Vx_I()
        for reg in range(0x7 + 1):
            self.assertEqual(reg * 2, self.cpu.V[reg])
        self.assertEqual(0x123 + 0x7 + 1, self.cpu.I)
コード例 #14
0
ファイル: test_cpu.py プロジェクト: danaki/YaPyChip8
class CPUTest(unittest.TestCase):
	def setUp(self):
		self.cpu = CPU()
		
	def test_int2hex(self):
		self.assertEquals('0000', self.cpu.int2hex(0))
		self.assertEquals('0001', self.cpu.int2hex(1))
		self.assertEquals('00FF', self.cpu.int2hex(255))
		self.assertEquals('0100', self.cpu.int2hex(256))
		self.assertEquals('0FFF', self.cpu.int2hex(0x0FFF))
		self.assertEquals('FFFF', self.cpu.int2hex(0xFFFF))
		self.assertEquals('A123', self.cpu.int2hex(0xA123))
		
	def test_decode_instruction(self):
		self.assertEquals((self.cpu.CLS, []), self.cpu.decode_instruction(0x00E0)) # CLS
		self.assertEquals((self.cpu.JP_addr, [564]), self.cpu.decode_instruction(0x1234)) # JP 0x234
		self.assertEquals((self.cpu.LD_Vx_Vy, [1, 2]), self.cpu.decode_instruction(0x8120)) # LD V1, V2
		self.assertEquals((self.cpu.RND_Vx_byte, [5, 255]), self.cpu.decode_instruction(0xC5FF)) # RND V5, FF
		self.assertEquals((self.cpu.DRW_Vx_Vy_nibble, [4, 5, 7]), self.cpu.decode_instruction(0xD457)) # DRW V4, V5, 7
		self.assertEquals((self.cpu.LD_I_Vx, [10]), self.cpu.decode_instruction(0xFA55)) # LD [I], V10

	def load_example_program(self):
		program = '00E081201000' # CLS; LD V1, V2; JP 0000
		data = bytearray(program.decode('hex'))
		self.cpu.load(data)

	def test_get_instruction(self):
		self.load_example_program()
		self.assertEquals(0x00E0, self.cpu.get_instruction(0))
		self.assertEquals(0x8120, self.cpu.get_instruction(2))
		self.assertEquals(0x1000, self.cpu.get_instruction(4))

	def test_load_and_decode_instruction(self):
		self.load_example_program()
コード例 #15
0
class Debugger:
    def __init__(self, rom_file):
        signal.signal(signal.SIGINT, self.sigint_handler)

        self.commands = {
            "[di]sassemble": ("Disassemble: disassemble addr[, count=16]",
                              self.cmd_disassemble),
            "[r]egisters": ("Examine registers", self.cmd_registers),
            "[s]tep": ("One CPU step: step [count=1]", self.cmd_step),
            "[v]ideo": ("Examine video memory contents", self.cmd_video),
            "[du]mp": ("Dump memory: dump addr[, count=16]", self.cmd_dump),
            "[h]elp": ("This help", self.cmd_help),
            "[q]uit": ("Quit", self.cmd_quit),
        }

        self.video = Video()
        screen = pygame.display.set_mode(self.video.get_mode())
        #pygame.mouse.set_visible(0)
        pygame.display.update()

        surface = pygame.Surface(screen.get_size())
        surface = surface.convert()
        screen.blit(surface, (0, 0))
        self.video.set_surface(surface)

        pygame.display.flip()

        self.cpu = CPU(self.video)
        fd = open(rom_file, "rb")
        self.cpu.load(fd.read())

    def run(self):
        last_command = None
        while True:
            try:
                prompt = "(debugger) "
                raw = raw_input(prompt)
                if (raw == '') and (not last_command is None):
                    callback, callback_args = last_command
                    callback(*callback_args)
                else:
                    args = shlex.split(raw)

                    callback = None
                    for k, v in self.commands.items():
                        m = re.search("^(.*)\[(.*)\](.*)$", k)
                        short = m.group(2)
                        long = m.group(1) + m.group(2) + m.group(3)

                        if args[0] in [short, long]:
                            callback = v[1]
                            # we assume that command arguments are always numeric either in hex 0x... or decimal format
                            callback_args = []
                            for arg in args[1:]:
                                try:
                                    arg = int(arg, 0)
                                except (ValueError, TypeError):
                                    pass

                                callback_args.append(arg)

                            last_command = callback, callback_args
                            callback(*callback_args)
                            break
                    else:
                        raise CommandException("Unknown command %s" % args[0])

            except IndexError:
                continue

            except CommandException as e:
                print e

            except (EOFError, ExitException):
                return 0

            except SIGINTException:
                print >> sys.stderr, \
                 "<SIGINT received, bye-bye>"
                return 1

    def sigint_handler(self, signum, frame):
        """Handler for the SIGINT signal."""
        raise SIGINTException

    def print_addr(self, addr):
        instruction = self.cpu.get_instruction(addr)
        decoded = self.cpu.decode_instruction(instruction)

        print "0x%04X 0x%04X" % (addr, instruction),

        if decoded is None:
            print "*** Unknown instruction"
        else:
            (handler, args) = decoded
            syntax = re.split('\n', inspect.getdoc(handler))[0]
            fmt = syntax\
             .replace('Vx', 'V%d')\
             .replace('Vy', 'V%d')\
             .replace('addr', '0x%04X')\
             .replace('nibble', '%d')\
             .replace('byte', '0x%02X')\

            print fmt % tuple(args),
            if addr == self.cpu.IP:
                print " <<<",

            print

    def cmd_disassemble(self, *args):
        if (len(args) < 1) or (len(args) > 2):
            raise BadArgumentCountException

        addr = args[0]
        count = args[1] if len(args) == 2 else 16

        while (count > 0) and (addr < len(self.cpu.ram) - 2):
            self.print_addr(addr)

            count -= 1
            addr += 2

    def cmd_registers(self, *args):
        if len(args) > 0:
            raise BadArgumentsException

        for i in range(0, len(self.cpu.V)):
            print "V%d: 0x%02x" % (i, self.cpu.V[i])

        print "I: 0x%04X" % self.cpu.I
        print "DT: 0x%02X" % self.cpu.DT
        print "ST: 0x%02X" % self.cpu.ST
        print "(IP): 0x%04X" % self.cpu.IP
        print "(SP): 0x%02X" % self.cpu.SP

    def cmd_dump(self, *args):
        if (len(args) < 1) or (len(args) > 2):
            raise BadArgumentCountException

        addr = args[0]
        count = args[1] if len(args) == 2 else 16

        i = 0
        while (i < count) and (addr < len(self.cpu.ram) - 2):
            if ((i % 16) == 0) and (i > 0):
                print

            print "%02X" % self.cpu.ram[addr],

            i += 1
            addr += 2

        print

    def cmd_video(self, *args):
        if len(args) > 0:
            raise BadArgumentCountException

        for y in xrange(0, 32):
            for x in xrange(0, 64):
                print 'x' if self.video.get_pixel(x, y) else '.',

            print

        print

    def cmd_step(self, *args):
        if len(args) > 1:
            raise BadArgumentCountException

        if len(args) == 0:
            count = 1
        else:
            count = args[0]

        while count > 0:
            self.print_addr(self.cpu.IP)
            self.cpu.tick()
            count -= 1

    def cmd_help(self, *args):
        if len(args) > 0:
            raise NoArgumentsRequredException

        for k, v in self.commands.items():
            print k,
            print " " * (12 - len(k)),
            print v[0]

    def cmd_quit(self, *args):
        raise ExitException