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-指令实现的更多相关文章

  1. chip8模拟器的python3实现-1-CHIP8简介

    打算编写一个NES模拟器,先从简单的chip8模拟器入手 1.CHIP-8简介 CHIP-8是一个解释型语言,由Joseph Weisbecker开发.最初CHIP-8在上个世纪70年代被使用在COS ...

  2. chip8模拟器的python3实现-2-指令介绍

    CHIP指令表 CHIP-8有35个指令,都为两字节长,以大端方式存储.指令表的指令格式规定如下: NNN:地址 NN:8位常量 N:4位常量 V:寄存器 X和Y:4位,标识寄存器 PC:程序计数器 ...

  3. QEMU模拟器Windows版本模拟ARMX86CPU指令

    http://qemu.weilnetz.de/ QEMU Binaries for Windows

  4. Python3执行top指令

    import subprocess top_info = subprocess.Popen(["], stdout=subprocess.PIPE) out, err = top_info. ...

  5. C++版 Chip8游戏模拟器

    很早就想写个FC模拟器,但真是一件艰难的事情.. 所以先写个Chip8模拟器,日后再继续研究FC模拟器. Chip8只有35条指令,属于RISC指令集,4k内存,2k显存,16个寄存器(其中15个通用 ...

  6. 如何实现模拟器(CHIP-8 interpreter) 绝佳杰作.

    转自 http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/ How to write an ...

  7. CS:APP2e Y86处理器模拟器∗指南

    CS:APP2e Y86处理器模拟器∗指南 Randal E.Bryant David R. O'Hallaron 2013年7月29日 本文档描述了处理器模拟器,伴随的表示在第4章Y86处理器架构的 ...

  8. Appium+python自动化19-iOS模拟器(iOS Simulator)安装自家APP

    前言 做过iOS上app测试的小伙伴应该都知道,普通用户安装app都是从appstore下载安装,安装测试版本的app,一般就是开发给的二维码扫码安装, 或者开发给个.ipa的安装包文件,通过itoo ...

  9. Appium+python自动化19-iOS模拟器(iOS Simulator)安装自家APP【转载】

    前言 做过iOS上app测试的小伙伴应该都知道,普通用户安装app都是从appstore下载安装,安装测试版本的app,一般就是开发给的二维码扫码安装, 或者开发给个.ipa的安装包文件,通过itoo ...

随机推荐

  1. 被公司的垃圾XG人事系统吓尿了

    OA要尝试设置单点登录,拿现有的HR系统尝试,结果不知道HR系统的加密方式和验证地址,于是乎找HR厂商——厦门XG软件实施人员.结果那个技术人员支支吾吾不肯给我,搞得非常的烦. 真奇怪了,不开源的软件 ...

  2. SourceInsight教程

    概述: Source Insight是一个面向项目开发的程序编辑器和代码浏览器,它拥有内置的对C/C++, C#和Java等程序的分析.Source Insight能分析你的源代码并在你工作的同时动态 ...

  3. 关于MySQL的一些骚操作——提升正确性,抠点性能

    概要 回顾以前写的项目,发现在规范的时候,还是可以做点骚操作的. 假使以后还有新的项目用到了MySQL,那么肯定是要实践一番的. 为了准备,创建测试数据表(建表语句中默认使用utf8mb4以及utf8 ...

  4. [20190531]ORA-600 kokasgi1故障模拟与恢复(后续).txt

    [20190531]ORA-600 kokasgi1故障模拟与恢复(后续).txt --//http://blog.itpub.net/267265/viewspace-2646340/=>[2 ...

  5. 使用ML.NET进行自定义机器学习

    ML.NET是Microsoft最近发布的用于机器学习的开源,跨平台,代码优先的框架.尽管对我们来说是一个新的框架,但该框架的根源是Microsoft Research,并且在过去十年中已被许多内部团 ...

  6. 基于mkv31芯片ADC差分应用

    一.单端.全差分.伪差分 此部分转载https://www.cnblogs.com/alifpga/p/7976531.html 单端信号: 单端信号(single-end)是相对于差分信号而言的,单 ...

  7. selenium python 脚本不支持中文问题

    在 python shell 中执行以下脚本: ...... dr.find_element_by_xpath("//a[test()='查看']") ...... 点击 Run ...

  8. 读取本地文件转化成MultipartFile

    介绍 现在有个上传文件功能,需要将文件上传到oss上,但是文件有点多,于是使用接口进行上传.但是需要上传文件转换为MultipartFile类型文件进行上传. 主要代码 添加pom文件 <dep ...

  9. 《Vue 进阶系列之响应式原理及实现》

    https://www.bilibili.com/video/av51444410/?p=5 https://github.com/amandakelake/blog/issues/63 https: ...

  10. html各种弹出框和提示框

    控制台输出 console.log() console.info() confirm() alert() promt()   提示对话框