CHIP8模拟器的python3实现-3-指令实现

  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

猜你喜欢

转载自www.cnblogs.com/hwnzy/p/10949601.html