1 class Chip8CPU(object): 2 def __init__(self, screen): 3 self.registers = { 4 'v': [], 5 'index': 0, 6 'pc': 0, 7 'sp': 0, 8 'rpl': [] 9 } 10 self.timers = { 11 'delay': 0, 12 'sound': 0, 13 } 14 15 self.operation_lookup = { 16 0x0: self.screen_return, 17 0x1: self.jump_to_address, 18 0x2: self.jump_to_subroutine, 19 0x3: self.skip_if_reg_equal_val, 20 0x4: self.skip_if_reg_not_equal_val, 21 0x5: self.skip_if_reg_equal_reg, 22 0x6: self.move_value_to_reg, 23 0x7: self.add_value_to_reg, 24 0x8: self.execute_logical_instruction, 25 0x9: self.skip_if_reg_not_equal_reg, 26 0xA: self.load_index_reg_with_value, 27 0xB: self.jump_to_index_plus_value, 28 0xC: self.generate_random_number_to_reg, 29 0xD: self.draw_sprite, 30 0xE: self.keyboard_routines, 31 0xF: self.misc_routines, 32 33 } 34 35 self.logical_operation_lookup = { 36 0x0: self.move_reg_into_reg, 37 0x1: self.logical_or, 38 0x2: self.logical_and, 39 0x3: self.exclusive_or, 40 0x4: self.add_reg_to_reg, 41 0x5: self.subtract_reg_from_reg, 42 0x6: self.right_shift_reg, 43 0x7: self.substract_reg_from_reg1, 44 0xE: self.left_shift_reg, 45 } 46 47 self.misc_routine_lookup = { 48 0x07: self.move_delay_timer_into_reg, 49 0x0A: self.wait_for_keypress, 50 0x15: self.move_reg_into_delay_timer, 51 0x18: self.move_reg_into_sound_timer, 52 0x1E: self.add_reg_into_index, 53 0x29: self.load_index_with_reg_sprite, 54 0x30: self.load_index_with_extended_reg_sprite, 55 0x33: self.store_bcd_in_memory, 56 0x55: self.store_regs_in_memory, 57 0x65: self.read_regs_from_memory, 58 0x75: self.store_regs_in_rpl, 59 0x85: self.read_regs_from_rpl 60 } 61 62 self.operand = 0 63 self.mode = MODE_NORMAL 64 self.screen = screen 65 66 self.memory = bytearray(MAX_MEMORY) 67 self.reset() 68 self.running = True 69 70 def execute_instruction(self, operand=None): 71 if operand: 72 self.operand = operand 73 else: 74 self.operand = int(self.memory[self.registers['pc']]) 75 self.operand = self.operand << 8 76 self.operand += int(self.memory[self.registers['pc'] + 1]) 77 self.registers['pc'] += 2 78 operation = (self.operand & 0xF000) >> 12 79 self.operation_lookup[operation]() 80 return self.operand 81 82 def screen_return(self): 83 operation = self.operand & 0x00FF 84 sub_operation = operation & 0x00F0 85 if sub_operation == 0x00C0: 86 num_lines = self.operand & 0x000F 87 self.screen.scroll_down(num_lines) 88 elif operation == 0x00E0: 89 self.screen.clear_screen() 90 elif operation == 0x00EE: 91 self.return_from_subroutine() 92 elif operation == 0x00FB: 93 self.screen.scroll_right() 94 elif operation == 0x00FC: 95 self.screen.scroll_left() 96 elif operation == 0x00FD: 97 self.running = False 98 elif operation == 0x00FE: 99 self.disable_extended_mode() 100 elif operation == 0x00FF: 101 self.enable_extended_mode() 102 103 def return_from_subroutine(self): 104 self.registers['sp'] -= 1 105 self.registers['pc'] = self.memory[self.registers['sp']] << 8 106 self.registers['sp'] -= 1 107 self.registers['pc'] += self.memory[self.registers['sp']] 108 109 def enable_extended_mode(self): 110 self.screen.set_extended() 111 self.mode = MODE_EXTENDED 112 113 def disable_extended_mode(self): 114 self.screen.set_normal() 115 self.mode = MODE_NORMAL 116 117 def jump_to_address(self): 118 self.registers['pc'] = self.operand & 0x0FFF 119 120 def jump_to_subroutine(self): 121 self.memory[self.registers['sp']] = self.registers['pc'] & 0x00FF 122 self.registers['sp'] += 1 123 self.memory[self.registers['sp']] = (self.registers['pc'] & 0xFF00) >> 8 124 self.registers['sp'] += 1 125 self.registers['pc'] = self.operand & 0x0FFF 126 127 def skip_if_reg_equal_val(self): 128 source = (self.operand & 0x0F00) >> 8 129 if self.registers['v'][source] == (self.operand & 0x00FF): 130 self.registers['pc'] += 2 131 132 def skip_if_reg_not_equal_val(self): 133 source = (self.operand & 0x0F00) >> 8 134 if self.registers['v'][source] != (self.operand & 0x00FF): 135 self.registers['pc'] += 2 136 137 def skip_if_reg_equal_reg(self): 138 source = (self.operand & 0x0F00) >> 8 139 target = (self.operand & 0x00F0) >> 4 140 if self.registers['v'][source] == self.registers['v'][target]: 141 self.registers['pc'] += 2 142 143 def move_value_to_reg(self): 144 target = (self.operand & 0x0F00) >> 8 145 self.registers['v'][target] = self.operand & 0x00FF 146 147 def add_value_to_reg(self): 148 target = (self.operand & 0x0F00) >> 8 149 temp = self.registers['v'][target] + (self.operand & 0x00FF) 150 self.registers['v'][target] = temp if temp < 256 else temp - 256 151 152 def skip_if_reg_not_equal_reg(self): 153 source = (self.operand & 0x0F00) >> 8 154 target = (self.operand & 0x00F0) >> 4 155 if self.registers['v'][source] != self.registers['v'][target]: 156 self.registers['pc'] += 2 157 158 def load_index_reg_with_value(self): 159 self.registers['index'] = self.operand & 0x0FFF 160 161 def jump_to_index_plus_value(self): 162 self.registers['pc'] = self.registers['index'] + (self.operand & 0x0FFF) 163 164 def generate_random_number_to_reg(self): 165 value = self.operand & 0x00FF 166 target = (self.operand & 0x0F00) >> 8 167 self.registers['v'][target] = value & randint(0, 255) 168 169 def draw_sprite(self): 170 x_source = (self.operand & 0x0F00) >> 8 171 y_source = (self.operand & 0x00F0) >> 4 172 x_pos = self.registers['v'][x_source] 173 y_pos = self.registers['v'][y_source] 174 num_bytes = self.operand & 0x000F 175 self.registers['v'][0xF] = 0 176 177 if self.mode == MODE_EXTENDED and num_bytes == 0: 178 self.draw_extended(x_pos, y_pos, 16) 179 else: 180 self.draw_normal(x_pos, y_pos, num_bytes) 181 182 def draw_normal(self, x_pos, y_pos, num_bytes): 183 for y_index in range(num_bytes): 184 color_byte = bin(self.memory[self.registers['index'] + y_index]) 185 color_byte = color_byte[2:].zfill(8) 186 y_coord = y_pos + y_index 187 y_coord = y_coord % self.screen.get_height() 188 189 for x_index in range(8): 190 x_coord = x_pos + x_index 191 x_coord = x_coord % self.screen.get_width() 192 193 color = int(color_byte[x_index]) 194 current_color = self.screen.get_pixel(x_coord, y_coord) 195 196 if color == 1 and current_color == 1: 197 self.registers['v'][0xF] = 1 198 color = 0 199 elif color == 0 and current_color == 1: 200 color = 1 201 202 self.screen.draw_pixel(x_coord, y_coord, color) 203 204 self.screen.update() 205 206 def draw_extended(self, x_pos, y_pos, num_bytes): 207 for y_index in range(num_bytes): 208 for x_byte in range(2): 209 color_byte = bin(self.memory[self.registers['index'] + (y_index * 2) + x_byte]) 210 color_byte = color_byte[2:].zfill(8) 211 y_coord = y_pos + y_index 212 y_coord = y_coord % self.screen.height 213 214 for x_index in range(8): 215 x_coord = x_pos + x_index + (x_byte * 8) 216 x_coord = x_coord % self.screen.width 217 color = int(color_byte[x_index]) 218 current_color = self.screen.get_pixel(x_coord, y_coord) 219 220 if color == 1 and current_color == 1: 221 self.registers['v'][0xF] = 1 222 color = 0 223 224 elif color == 0 and current_color == 1: 225 color = 1 226 227 self.screen.draw_pixel(x_coord, y_coord, color) 228 229 self.screen.update() 230 231 def keyboard_routines(self): 232 operation = self.operand & 0x00FF 233 source = (self.operand & 0x0F00) >> 8 234 235 key_to_check = self.registers['v'][source] 236 keys_pressed = key.get_pressed() 237 if operation == 0x9E: 238 if keys_pressed[KEY_MAPPINGS[key_to_check]]: 239 self.registers['pc'] += 2 240 elif operation == 0xA1: 241 if not keys_pressed[KEY_MAPPINGS[key_to_check]]: 242 self.registers['pc'] += 2 243 244 def execute_logical_instruction(self): 245 operation = self.operand & 0x000F 246 self.logical_operation_lookup[operation]() 247 248 def move_reg_into_reg(self): 249 target = (self.operand & 0x0F00) >> 8 250 source = (self.operand & 0x00F0) >> 4 251 self.registers['v'][target] = self.registers['v'][source] 252 253 def logical_or(self): 254 target = (self.operand & 0x0F00) >> 8 255 source = (self.operand & 0x00F0) >> 4 256 self.registers['v'][target] |= self.registers['v'][source] 257 258 def logical_and(self): 259 target = (self.operand & 0x0F00) >> 8 260 source = (self.operand & 0x00F0) >> 4 261 self.registers['v'][target] &= self.registers['v'][source] 262 263 def exclusive_or(self): 264 target = (self.operand & 0x0F00) >> 8 265 source = (self.operand & 0x00F0) >> 4 266 self.registers['v'][target] ^= self.registers['v'][source] 267 268 def add_reg_to_reg(self): 269 target = (self.operand & 0x0F00) >> 8 270 source = (self.operand & 0x00F0) >> 4 271 temp = self.registers['v'][target] + self.registers['v'][source] 272 if temp > 255: 273 self.registers['v'][target] = temp - 256 274 self.registers['v'][0xF] = 1 275 else: 276 self.registers['v'][target] = temp 277 self.registers['v'][0xF] = 0 278 279 def subtract_reg_from_reg(self): 280 target = (self.operand & 0x0F00) >> 8 281 source = (self.operand & 0x00F0) >> 4 282 source_reg = self.registers['v'][source] 283 target_reg = self.registers['v'][target] 284 if target_reg > source_reg: 285 target_reg -= source_reg 286 self.registers['v'][0xF] = 1 287 else: 288 target_reg = 256 + target_reg - source_reg 289 self.registers['v'][0xF] = 0 290 self.registers['v'][target] = target_reg 291 292 def right_shift_reg(self): 293 source = (self.operand & 0x0F00) >> 8 294 target = (self.operand & 0x00F0) >> 4 295 bit_zero = self.registers['v'][source] & 0x1 296 self.registers['v'][target] = self.registers['v'][source] >> 1 297 self.registers['v'][0xF] = bit_zero 298 299 def substract_reg_from_reg1(self): 300 target = (self.operand & 0x0F00) >> 8 301 source = (self.operand & 0x00F0) >> 4 302 source_reg = self.registers['v'][source] 303 target_reg = self.registers['v'][target] 304 if source_reg > target_reg: 305 target_reg = source_reg - target_reg 306 self.registers['v'][0xF] = 1 307 else: 308 target_reg = 256 + source_reg - target_reg 309 self.registers['v'][0xF] = 0 310 self.registers['v'][target] = target_reg 311 312 def left_shift_reg(self): 313 source = (self.operand & 0x0F00) >> 8 314 target = (self.operand & 0x00F0) >> 4 315 bit_seven = (self.registers['v'][source] & 0x80) >> 8 316 self.registers['v'][target] = self.registers['v'][source] << 1 317 self.registers['v'][0xF] = bit_seven 318 319 def misc_routines(self): 320 operation = self.operand & 0x00FF 321 self.misc_routine_lookup[operation]() 322 323 def move_delay_timer_into_reg(self): 324 target = (self.operand & 0x0F00) >> 8 325 self.registers['v'][target] = self.timers['delay'] 326 327 def wait_for_keypress(self): 328 target = (self.operand & 0x0F00) >> 8 329 key_pressed = False 330 while not key_pressed: 331 event = pygame.event.wait() 332 if event.type == pygame.KEYDOWN: 333 keys_pressed = key.get_pressed() 334 for keyval, lookup_key in KEY_MAPPINGS.items(): 335 if keys_pressed[lookup_key]: 336 self.registers['v'][target] = keyval 337 key_pressed = True 338 break 339 340 def move_reg_into_delay_timer(self): 341 source = (self.operand & 0x0F00) >> 8 342 self.timers['delay'] = self.registers['v'][source] 343 344 def move_reg_into_sound_timer(self): 345 source = (self.operand & 0x0F00) >> 8 346 self.timers['sound'] = self.registers['v'][source] 347 348 def load_index_with_reg_sprite(self): 349 source = (self.operand & 0x0F00) >> 8 350 self.registers['index'] = self.registers['v'][source] * 5 351 352 def load_index_with_extended_reg_sprite(self): 353 source = (self.operand & 0x0F00) >> 8 354 self.registers['index'] = self.registers['v'][source] * 10 355 356 def add_reg_into_index(self): 357 source = (self.operand & 0x0F00) >> 8 358 self.registers['index'] += self.registers['v'][source] 359 360 def store_bcd_in_memory(self): 361 source = (self.operand & 0x0F00) >> 8 362 bcd_value = '{:03d}'.format(self.registers['v'][source]) 363 self.memory[self.registers['index']] = int(bcd_value[0]) 364 self.memory[self.registers['index'] + 1] = int(bcd_value[1]) 365 self.memory[self.registers['index'] + 2] = int(bcd_value[2]) 366 367 def store_regs_in_memory(self): 368 source = (self.operand & 0x0F00) >> 8 369 for counter in range(source + 1): 370 self.memory[self.registers['index'] + counter] = \ 371 self.registers['v'][counter] 372 373 def read_regs_from_memory(self): 374 source = (self.operand & 0x0F00) >> 8 375 for counter in range(source + 1): 376 self.registers['v'][counter] = \ 377 self.memory[self.registers['index'] + counter] 378 379 def store_regs_in_rpl(self): 380 source = (self.operand & 0x0F00) >> 8 381 for counter in range(source + 1): 382 self.registers['rpl'][counter] = self.registers['v'][counter] 383 384 def read_regs_from_rpl(self): 385 source = (self.operand & 0x0F00) >> 8 386 for counter in range(source + 1): 387 self.registers['v'][counter] = self.registers['rpl'][counter] 388 389 def reset(self): 390 self.registers['v'] = [0] * NUM_REGISTERS 391 self.registers['pc'] = PROGRAM_COUNTER_START 392 self.registers['sp'] = STACK_POINTER_START 393 self.registers['index'] = 0 394 self.registers['rpl'] = [0] * NUM_REGISTERS 395 self.timers['delay'] = 0 396 self.timers['sound'] = 0 397 398 def load_rom(self, filename, offset=PROGRAM_COUNTER_START): 399 rom_data = open(filename, 'rb').read() 400 for index, val in enumerate(rom_data): 401 self.memory[offset + index] = val 402 403 def decrement_timers(self): 404 if self.timers['delay'] != 0: 405 self.timers['delay'] -= 1 406 407 if self.timers['sound'] != 0: 408 self.timers['delay'] -= 1
CHIP8模拟器的python3实现-3-指令实现
猜你喜欢
转载自www.cnblogs.com/hwnzy/p/10949601.html
今日推荐
周排行