├── games ├── Brick.ch8 ├── Cave.ch8 ├── Pong.ch8 ├── Airplane.ch8 ├── IBMLogo.ch8 ├── Tetris.ch8 ├── SpaceInvaders.ch8 └── Tic-Tac-Toe.ch8 ├── screenshots ├── Bricks.png ├── IBMLogo.png ├── Tetris.png └── SpaceInvader.png ├── LICENSE ├── README.md └── chip8.py /games/Brick.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Brick.ch8 -------------------------------------------------------------------------------- /games/Cave.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Cave.ch8 -------------------------------------------------------------------------------- /games/Pong.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Pong.ch8 -------------------------------------------------------------------------------- /games/Airplane.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Airplane.ch8 -------------------------------------------------------------------------------- /games/IBMLogo.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/IBMLogo.ch8 -------------------------------------------------------------------------------- /games/Tetris.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Tetris.ch8 -------------------------------------------------------------------------------- /games/SpaceInvaders.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/SpaceInvaders.ch8 -------------------------------------------------------------------------------- /games/Tic-Tac-Toe.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/games/Tic-Tac-Toe.ch8 -------------------------------------------------------------------------------- /screenshots/Bricks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/screenshots/Bricks.png -------------------------------------------------------------------------------- /screenshots/IBMLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/screenshots/IBMLogo.png -------------------------------------------------------------------------------- /screenshots/Tetris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/screenshots/Tetris.png -------------------------------------------------------------------------------- /screenshots/SpaceInvader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpacaMax/Python-CHIP8-Emulator/HEAD/screenshots/SpaceInvader.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 AlpacaMax 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CHIP-8 Emulator 2 | 3 | > **CHIP-8** is an interpreted programming language, developed by Joseph Weisbecker. It was initially used on the COSMAC VIP and Telmac 1800 8-bit microcomputers in the mid-1970s. CHIP-8 programs are run on a CHIP-8 virtual machine. It was made to allow video games to be more easily programmed for these computer 4 |
--[Wikipedia](https://en.wikipedia.org/wiki/Chip-8) 5 | 6 | ## Introduction 7 | 8 | This is a python version CHIP-8 Emulator. Although it was originally created as a virtual machine, CHIP-8 could be treated as a simple game console. As a result, implementing this emulator is a good way to get a brief understanding of how computer works. 9 | 10 | ## Usage 11 | 12 | ``` 13 | pip3 install pygame 14 | sudo apt install sox 15 | git clone git@github.com:AlpacaMax/Python-CHIP8-Emulator 16 | cd Python-CHIP8-Emulator 17 | python3 chip8.py games/ 18 | ``` 19 | 20 | ## Screenshots 21 | 22 | ![IBM Logo](screenshots/IBMLogo.png) 23 | 24 | ![Bricks](screenshots/Bricks.png) 25 | 26 | ![Tetris](screenshots/Tetris.png) 27 | 28 | ![Space Invader](screenshots/SpaceInvader.png) 29 | 30 | **Note:** If you don't like the color, you can go to `line 154` and `line 155` and change `self.zeroColor` and `self.oneColor`. 31 | 32 | ## More CHIP-8 ROMs(Games) 33 | 34 | Visit [The Old Computer](https://www.theoldcomputer.com/roms/index.php?folder=Chip-8/Chip-8/Games) for more CHIP-8 games -------------------------------------------------------------------------------- /chip8.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import time 3 | import sys 4 | import random 5 | import os 6 | 7 | class Register: 8 | def __init__(self, bits): 9 | self.value = 0 10 | self.bits = bits 11 | 12 | ''' 13 | def checkFlag(self): 14 | hexValue = hex(self.value)[2:] 15 | carryORborrow = False 16 | 17 | if self.value < 0: 18 | self.value = abs(self.value) 19 | carryORborrow = True 20 | 21 | if len(hexValue) > self.bits / 4: 22 | self.value = int(hexValue[-int(self.bits / 4):], 16) 23 | carryORborrow = True 24 | 25 | if carryORborrow: 26 | return 1 27 | return 0 28 | ''' 29 | 30 | def checkCarry(self): 31 | hexValue = hex(self.value)[2:] 32 | 33 | if len(hexValue) > self.bits / 4: 34 | self.value = int(hexValue[-int(self.bits / 4):], 16) 35 | return 1 36 | 37 | return 0 38 | 39 | def checkBorrow(self): 40 | if self.value < 0: 41 | self.value = abs(self.value) 42 | return 0 43 | 44 | return 1 45 | 46 | def readValue(self): 47 | return hex(self.value) 48 | 49 | def setValue(self, value): 50 | self.value = value 51 | 52 | class DelayTimer: 53 | def __init__(self): 54 | self.timer = 0 55 | 56 | def countDown(self): 57 | if self.timer > 0: 58 | self.timer -= 1 59 | 60 | def setTimer(self, value): 61 | self.timer = value 62 | 63 | def readTimer(self): 64 | return self.timer 65 | 66 | class SoundTimer(DelayTimer): 67 | def __init__(self): 68 | DelayTimer.__init__(self) 69 | 70 | def beep(self): 71 | if self.timer > 1: 72 | os.system('play --no-show-progress --null --channels 1 synth %s triangle %f' % (self.timer / 60, 440)) 73 | self.timer = 0 74 | 75 | class Stack: 76 | def __init__(self): 77 | self.stack = [] 78 | 79 | def push(self, value): 80 | self.stack.append(value) 81 | 82 | def pop(self): 83 | return self.stack.pop() 84 | 85 | class Emulator: 86 | def __init__(self): 87 | self.Memory = [] 88 | for i in range(0, 4096): 89 | self.Memory.append(0x0) 90 | 91 | fonts = [ 92 | 0xF0, 0x90, 0x90, 0x90, 0xF0, # 0 93 | 0x20, 0x60, 0x20, 0x20, 0x70, # 1 94 | 0xF0, 0x10, 0xF0, 0x80, 0xF0, # 2 95 | 0xF0, 0x10, 0xF0, 0x10, 0xF0, # 3 96 | 0x90, 0x90, 0xF0, 0x10, 0x10, # 4 97 | 0xF0, 0x80, 0xF0, 0x10, 0xF0, # 5 98 | 0xF0, 0x80, 0xF0, 0x90, 0xF0, # 6 99 | 0xF0, 0x10, 0x20, 0x40, 0x40, # 7 100 | 0xF0, 0x90, 0xF0, 0x90, 0xF0, # 8 101 | 0xF0, 0x90, 0xF0, 0x10, 0xF0, # 9 102 | 0xF0, 0x90, 0xF0, 0x90, 0x90, # A 103 | 0xE0, 0x90, 0xE0, 0x90, 0xE0, # B 104 | 0xF0, 0x80, 0x80, 0x80, 0xF0, # C 105 | 0xE0, 0x90, 0x90, 0x90, 0xE0, # D 106 | 0xF0, 0x80, 0xF0, 0x80, 0xF0, # E 107 | 0xF0, 0x80, 0xF0, 0x80, 0x80 # F 108 | ] 109 | for i in range(len(fonts)): 110 | self.Memory[i] = fonts[i] 111 | 112 | self.Registers = [] 113 | for i in range(16): 114 | self.Registers.append(Register(8)) 115 | 116 | self.IRegister = Register(16) 117 | self.ProgramCounter = 0x200 118 | 119 | self.stack = Stack() 120 | 121 | self.delayTimer = DelayTimer() 122 | self.soundTimer = SoundTimer() 123 | pygame.init() 124 | pygame.time.set_timer(pygame.USEREVENT+1, int(1000 / 60)) 125 | 126 | self.keys = [] 127 | for i in range(0, 16): 128 | self.keys.append(False) 129 | self.keyDict = { 130 | 49 : 1, 131 | 50 : 2, 132 | 51 : 3, 133 | 52 : 0xc, 134 | 113 : 4, 135 | 119 : 5, 136 | 101 : 6, 137 | 114 : 0xd, 138 | 97 : 7, 139 | 115 : 8, 140 | 100 : 9, 141 | 102 : 0xe, 142 | 122 : 0xa, 143 | 120 : 0, 144 | 99 : 0xb, 145 | 118 : 0xf 146 | } 147 | 148 | self.grid = [] 149 | for i in range(32): 150 | line = [] 151 | for j in range(64): 152 | line.append(0) 153 | self.grid.append(line) 154 | self.emptyGrid = self.grid[:] 155 | self.zeroColor = [0, 0, 50] 156 | self.oneColor = [255, 255, 255] 157 | 158 | self.size = 10 159 | width = 64 160 | height = 32 161 | self.screen = pygame.display.set_mode([width * self.size, height * self.size]) 162 | self.screen.fill(self.oneColor) 163 | pygame.display.flip() 164 | 165 | def execOpcode(self, opcode): 166 | #print(opcode) 167 | 168 | if opcode[0] == '0': 169 | 170 | if opcode[1] != '0': 171 | #0NNN 172 | 173 | print("ROM attempts to run RCA 1802 program at <0x" + opcode[1:] + '>') 174 | 175 | else: 176 | if opcode == '00e0': 177 | #00E0 178 | #disp_clear() 179 | 180 | self.clear() 181 | 182 | elif opcode == '00ee': 183 | #00EE 184 | #return; 185 | 186 | self.ProgramCounter = self.stack.pop() 187 | 188 | elif opcode[0] == '1': 189 | #1NNN 190 | #goto NNN; 191 | 192 | self.ProgramCounter = int(opcode[1:], 16) - 2 193 | 194 | elif opcode[0] == '2': 195 | #2NNN 196 | #*(0xNNN)() 197 | 198 | self.stack.push(self.ProgramCounter) 199 | self.ProgramCounter = int(opcode[1:], 16) - 2 200 | 201 | elif opcode[0] == '3': 202 | #3XNN 203 | #if(Vx==NN) 204 | 205 | vNum = int(opcode[1], 16) 206 | targetNum = int(opcode[2:], 16) 207 | 208 | if self.Registers[vNum].value == targetNum: 209 | self.ProgramCounter += 2 210 | 211 | elif opcode[0] == '4': 212 | #4XNN 213 | #if(Vx!=NN) 214 | 215 | vNum = int(opcode[1], 16) 216 | targetNum = int(opcode[2:], 16) 217 | 218 | if self.Registers[vNum].value != targetNum: 219 | self.ProgramCounter += 2 220 | 221 | elif opcode[0] == '5': 222 | #5XY0 223 | #if(Vx==Vy) 224 | 225 | v1 = int(opcode[1], 16) 226 | v2 = int(opcode[2], 16) 227 | 228 | if self.Registers[v1].value == self.Registers[v2].value: 229 | self.ProgramCounter += 2 230 | 231 | elif opcode[0] == '6': 232 | #6XNN 233 | #Vx = NN 234 | 235 | vNum = int(opcode[1], 16) 236 | targetNum = int(opcode[2:], 16) 237 | 238 | self.Registers[vNum].value = targetNum 239 | 240 | elif opcode[0] == '7': 241 | #7XNN 242 | #Vx += NN 243 | 244 | vNum = int(opcode[1], 16) 245 | targetNum = int(opcode[2:], 16) 246 | 247 | self.Registers[vNum].value += targetNum 248 | self.Registers[vNum].checkCarry() 249 | 250 | elif opcode[0] == '8': 251 | if opcode[3] == '0': 252 | #8XY0 253 | #Vx=Vy 254 | 255 | v1 = int(opcode[1], 16) 256 | v2 = int(opcode[2], 16) 257 | 258 | self.Registers[v1].value = self.Registers[v2].value 259 | 260 | elif opcode[3] == '1': 261 | #8XY1 262 | #Vx=Vx|Vy 263 | 264 | v1 = int(opcode[1], 16) 265 | v2 = int(opcode[2], 16) 266 | 267 | self.Registers[v1].value = self.Registers[v1].value | self.Registers[v2].value 268 | 269 | elif opcode[3] == '2': 270 | #8XY2 271 | #Vx=Vx&Vy 272 | 273 | v1 = int(opcode[1], 16) 274 | v2 = int(opcode[2], 16) 275 | 276 | self.Registers[v1].value = self.Registers[v1].value & self.Registers[v2].value 277 | 278 | elif opcode[3] == '3': 279 | #8XY3 280 | #Vx=Vx^Vy 281 | 282 | v1 = int(opcode[1], 16) 283 | v2 = int(opcode[2], 16) 284 | 285 | self.Registers[v1].value = self.Registers[v1].value ^ self.Registers[v2].value 286 | 287 | elif opcode[3] == '4': 288 | #8XY4 289 | #Vx += Vy 290 | 291 | v1 = int(opcode[1], 16) 292 | v2 = int(opcode[2], 16) 293 | 294 | self.Registers[v1].value += self.Registers[v2].value 295 | 296 | self.Registers[0xf].value = self.Registers[v1].checkCarry() 297 | 298 | elif opcode[3] == '5': 299 | #8XY5 300 | #Vx -= Vy 301 | 302 | v1 = int(opcode[1], 16) 303 | v2 = int(opcode[2], 16) 304 | 305 | self.Registers[v1].value -= self.Registers[v2].value 306 | 307 | self.Registers[0xf].value = self.Registers[v1].checkBorrow() 308 | 309 | elif opcode[3] == '6': 310 | #8XY6 311 | #Vx>>1 312 | 313 | v1 = int(opcode[1], 16) 314 | leastBit = int(bin(self.Registers[v1].value)[-1]) 315 | 316 | self.Registers[v1].value = self.Registers[v1].value >> 1 317 | self.Registers[0xf].value = leastBit 318 | 319 | elif opcode[3] == '7': 320 | #8XY7 321 | #Vx=Vy-Vx 322 | 323 | v1 = int(opcode[1], 16) 324 | v2 = int(opcode[2], 16) 325 | 326 | self.Registers[v1].value = self.Registers[v2].value - self.Registers[v1].value 327 | 328 | self.Registers[0xf].value = self.Registers[v1].checkBorrow() 329 | 330 | elif opcode[3] == 'e': 331 | #8XYE 332 | #Vx<<=1 333 | 334 | v1 = int(opcode[1], 16) 335 | mostBit = int(bin(self.Registers[v1].value)[2]) 336 | 337 | self.Registers[v1].value = self.Registers[v1].value << 1 338 | self.Registers[0xf].value = mostBit 339 | 340 | elif opcode[0] == '9': 341 | #9XY0 342 | #if(Vx!=Vy) 343 | 344 | v1 = int(opcode[1], 16) 345 | v2 = int(opcode[2], 16) 346 | 347 | if self.Registers[v1].value != self.Registers[v2].value: 348 | self.ProgramCounter += 2 349 | 350 | elif opcode[0] == 'a': 351 | #ANNN 352 | #I = NNN 353 | 354 | addr = int(opcode[1:], 16) 355 | 356 | self.IRegister.value = addr 357 | 358 | elif opcode[0] == 'b': 359 | #BNNN 360 | #PC=V0+NNN 361 | 362 | addr = int(opcode[1:], 16) 363 | 364 | self.ProgramCounter = self.Registers[0].value + addr - 2 365 | 366 | elif opcode[0] == 'c': 367 | #CXNN 368 | #Vx=rand()&NN 369 | 370 | vNum = int(opcode[1], 16) 371 | targetNum = int(opcode[2:], 16) 372 | 373 | rand = random.randint(0, 255) 374 | 375 | self.Registers[vNum].value = targetNum & rand 376 | 377 | elif opcode[0] == 'd': 378 | #DXYN 379 | #draw(Vx,Vy,N) 380 | 381 | Vx = int(opcode[1], 16) 382 | Vy = int(opcode[2], 16) 383 | N = int(opcode[3], 16) 384 | 385 | addr = self.IRegister.value 386 | sprite = self.Memory[addr: addr + N] 387 | 388 | for i in range(len(sprite)): 389 | if type(sprite[i]) == str: 390 | sprite[i] = int(sprite[i], 16) 391 | 392 | if self.draw(self.Registers[Vx].value, self.Registers[Vy].value, sprite): 393 | self.Registers[0xf].value = 1 394 | else: 395 | self.Registers[0xf].value = 0 396 | 397 | elif opcode[0] == 'e': 398 | if opcode[2:] == '9e': 399 | #EX9E 400 | #if(key()==Vx) 401 | 402 | Vx = int(opcode[1], 16) 403 | key = self.Registers[Vx].value 404 | if self.keys[key]: 405 | self.ProgramCounter += 2 406 | 407 | elif opcode[2:] == 'a1': 408 | #EXA1 409 | #if(key()!=Vx) 410 | 411 | Vx = int(opcode[1], 16) 412 | key = self.Registers[Vx].value 413 | if not self.keys[key]: 414 | self.ProgramCounter += 2 415 | 416 | elif opcode[0] == 'f': 417 | if opcode[2:] == '07': 418 | #FX07 419 | #delay_timer(Vx) 420 | 421 | Vx = int(opcode[1], 16) 422 | self.Registers[Vx].value = self.delayTimer.readTimer() 423 | 424 | elif opcode[2:] == '0a': 425 | #FX0A 426 | #Vx = get_key() 427 | 428 | Vx = int(opcode[1], 16) 429 | key = None 430 | 431 | while True: 432 | self.keyHandler() 433 | isKeyDown = False 434 | 435 | for i in range(len(self.keys)): 436 | if self.keys[i]: 437 | key = i 438 | isKeyDown = True 439 | 440 | if isKeyDown: 441 | break 442 | 443 | self.Registers[Vx].value = key 444 | 445 | elif opcode[2:] == '15': 446 | #FX15 447 | #delay_timer(Vx) 448 | 449 | Vx = int(opcode[1], 16) 450 | value = self.Registers[Vx].value 451 | 452 | self.delayTimer.setTimer(value) 453 | 454 | elif opcode[2:] == '18': 455 | #FX18 456 | #sound_timer(Vx) 457 | 458 | Vx = int(opcode[1], 16) 459 | value = self.Registers[Vx].value 460 | 461 | self.soundTimer.setTimer(value) 462 | 463 | elif opcode[2:] == '1e': 464 | #FX1E 465 | #I += Vx 466 | 467 | Vx = int(opcode[1], 16) 468 | self.IRegister.value += self.Registers[Vx].value 469 | 470 | elif opcode[2:] == '29': 471 | #FX29 472 | #I = sprite_addr[Vx] 473 | 474 | Vx = int(opcode[1], 16) 475 | value = self.Registers[Vx].value 476 | 477 | self.IRegister.value = value * 5 478 | 479 | elif opcode[2:] == '33': 480 | #FX33 481 | ''' 482 | set_BCD(Vx); 483 | *(I+0)=BCD(3); 484 | *(I+1)=BCD(2); 485 | *(I+2)=BCD(1); 486 | ''' 487 | 488 | Vx = int(opcode[1], 16) 489 | value = str(self.Registers[Vx].value) 490 | 491 | fillNum = 3 - len(value) 492 | value = '0' * fillNum + value 493 | 494 | for i in range(len(value)): 495 | self.Memory[self.IRegister.value + i] = int(value[i]) 496 | 497 | elif opcode[2:] == '55': 498 | #FX55 499 | #reg_dump(Vx, &I) 500 | 501 | Vx = int(opcode[1], 16) 502 | for i in range(0, Vx + 1): 503 | self.Memory[self.IRegister.value + i] = self.Registers[i].value 504 | 505 | elif opcode[2:] == '65': 506 | #FX65 507 | #reg_load(Vx, &I) 508 | 509 | Vx = int(opcode[1], 16) 510 | for i in range(0, Vx + 1): 511 | self.Registers[i].value = self.Memory[self.IRegister.value + i] 512 | 513 | self.ProgramCounter += 2 514 | 515 | def execution(self): 516 | index = self.ProgramCounter 517 | high = self.hexHandler(self.Memory[index]) 518 | low = self.hexHandler(self.Memory[index + 1]) 519 | 520 | opcode = high + low 521 | 522 | self.execOpcode(opcode) 523 | 524 | def draw(self, Vx, Vy, sprite): 525 | collision = False 526 | 527 | spriteBits = [] 528 | for i in sprite: 529 | binary = bin(i) 530 | line = list(binary[2:]) 531 | fillNum = 8 - len(line) 532 | line = ['0'] * fillNum + line 533 | 534 | spriteBits.append(line) 535 | 536 | ''' 537 | for i in spriteBits: 538 | print(i) 539 | ''' 540 | 541 | for i in range(len(spriteBits)): 542 | #line = '' 543 | for j in range(8): 544 | try: 545 | if self.grid[Vy + i][Vx + j] == 1 and int(spriteBits[i][j]) == 1: 546 | collision = True 547 | 548 | self.grid[Vy + i][Vx + j] = self.grid[Vy + i][Vx + j] ^ int(spriteBits[i][j]) 549 | #line += str(int(spriteBits[i][j])) 550 | except: 551 | continue 552 | 553 | #print(line) 554 | 555 | return collision 556 | 557 | def clear(self): 558 | for i in range(len(self.grid)): 559 | for j in range(len(self.grid[0])): 560 | self.grid[i][j] = 0 561 | 562 | def readProg(self, filename): 563 | rom = self.convertProg(filename) 564 | 565 | offset = int('0x200', 16) 566 | for i in rom: 567 | self.Memory[offset] = i 568 | offset += 1 569 | 570 | def convertProg(self, filename): 571 | rom = [] 572 | 573 | with open(filename, 'rb') as f: 574 | wholeProgram = f.read() 575 | 576 | for i in wholeProgram: 577 | opcode = i 578 | rom.append(opcode) 579 | 580 | return rom 581 | 582 | def hexHandler(self, Num): 583 | newHex = hex(Num)[2:] 584 | if len(newHex) == 1: 585 | newHex = '0' + newHex 586 | 587 | return newHex 588 | 589 | def keyHandler(self): 590 | ''' 591 | Chip8 My Keys 592 | --------- --------- 593 | 1 2 3 C 1 2 3 4 594 | 4 5 6 D q w e r 595 | 7 8 9 E a s d f 596 | A 0 B F z x c v 597 | ''' 598 | 599 | for event in pygame.event.get(): 600 | if event.type == pygame.QUIT: 601 | sys.exit() 602 | 603 | elif event.type == pygame.USEREVENT+1: 604 | self.delayTimer.countDown() 605 | 606 | elif event.type == pygame.KEYDOWN: 607 | try: 608 | targetKey = self.keyDict[event.key] 609 | self.keys[targetKey] = True 610 | 611 | except: pass 612 | 613 | elif event.type == pygame.KEYUP: 614 | try: 615 | targetKey = self.keyDict[event.key] 616 | self.keys[targetKey] = False 617 | 618 | except: pass 619 | 620 | def mainLoop(self): 621 | clock = pygame.time.Clock() 622 | 623 | while True: 624 | clock.tick(300) 625 | self.keyHandler() 626 | self.soundTimer.beep() 627 | self.execution() 628 | self.display() 629 | 630 | def display(self): 631 | for i in range(0, len(self.grid)): 632 | for j in range(0, len(self.grid[0])): 633 | cellColor = self.zeroColor 634 | 635 | if self.grid[i][j] == 1: 636 | cellColor = self.oneColor 637 | 638 | pygame.draw.rect(self.screen, cellColor, [j * self.size, i * self.size, self.size, self.size], 0) 639 | 640 | pygame.display.flip() 641 | 642 | chip8 = Emulator() 643 | chip8.readProg(sys.argv[1]) 644 | chip8.mainLoop() 645 | --------------------------------------------------------------------------------