CHIP8模拟器的python3实现-3-指令实现
- class Chip8CPU(object):
- def __init__(self, screen):
- self.registers = {
- 'v': [],
- 'index': 0,
- 'pc': 0,
- 'sp': 0,
- 'rpl': []
- }
- self.timers = {
- 'delay': 0,
- 'sound': 0,
- }
- self.operation_lookup = {
- 0x0: self.screen_return,
- 0x1: self.jump_to_address,
- 0x2: self.jump_to_subroutine,
- 0x3: self.skip_if_reg_equal_val,
- 0x4: self.skip_if_reg_not_equal_val,
- 0x5: self.skip_if_reg_equal_reg,
- 0x6: self.move_value_to_reg,
- 0x7: self.add_value_to_reg,
- 0x8: self.execute_logical_instruction,
- 0x9: self.skip_if_reg_not_equal_reg,
- 0xA: self.load_index_reg_with_value,
- 0xB: self.jump_to_index_plus_value,
- 0xC: self.generate_random_number_to_reg,
- 0xD: self.draw_sprite,
- 0xE: self.keyboard_routines,
- 0xF: self.misc_routines,
- }
- self.logical_operation_lookup = {
- 0x0: self.move_reg_into_reg,
- 0x1: self.logical_or,
- 0x2: self.logical_and,
- 0x3: self.exclusive_or,
- 0x4: self.add_reg_to_reg,
- 0x5: self.subtract_reg_from_reg,
- 0x6: self.right_shift_reg,
- 0x7: self.substract_reg_from_reg1,
- 0xE: self.left_shift_reg,
- }
- self.misc_routine_lookup = {
- 0x07: self.move_delay_timer_into_reg,
- 0x0A: self.wait_for_keypress,
- 0x15: self.move_reg_into_delay_timer,
- 0x18: self.move_reg_into_sound_timer,
- 0x1E: self.add_reg_into_index,
- 0x29: self.load_index_with_reg_sprite,
- 0x30: self.load_index_with_extended_reg_sprite,
- 0x33: self.store_bcd_in_memory,
- 0x55: self.store_regs_in_memory,
- 0x65: self.read_regs_from_memory,
- 0x75: self.store_regs_in_rpl,
- 0x85: self.read_regs_from_rpl
- }
- self.operand = 0
- self.mode = MODE_NORMAL
- self.screen = screen
- self.memory = bytearray(MAX_MEMORY)
- self.reset()
- self.running = True
- def execute_instruction(self, operand=None):
- if operand:
- self.operand = operand
- else:
- self.operand = int(self.memory[self.registers['pc']])
- self.operand = self.operand << 8
- self.operand += int(self.memory[self.registers['pc'] + 1])
- self.registers['pc'] += 2
- operation = (self.operand & 0xF000) >> 12
- self.operation_lookup[operation]()
- return self.operand
- def screen_return(self):
- operation = self.operand & 0x00FF
- sub_operation = operation & 0x00F0
- if sub_operation == 0x00C0:
- num_lines = self.operand & 0x000F
- self.screen.scroll_down(num_lines)
- elif operation == 0x00E0:
- self.screen.clear_screen()
- elif operation == 0x00EE:
- self.return_from_subroutine()
- elif operation == 0x00FB:
- self.screen.scroll_right()
- elif operation == 0x00FC:
- self.screen.scroll_left()
- elif operation == 0x00FD:
- self.running = False
- elif operation == 0x00FE:
- self.disable_extended_mode()
- elif operation == 0x00FF:
- self.enable_extended_mode()
- def return_from_subroutine(self):
- self.registers['sp'] -= 1
- self.registers['pc'] = self.memory[self.registers['sp']] << 8
- self.registers['sp'] -= 1
- self.registers['pc'] += self.memory[self.registers['sp']]
- def enable_extended_mode(self):
- self.screen.set_extended()
- self.mode = MODE_EXTENDED
- def disable_extended_mode(self):
- self.screen.set_normal()
- self.mode = MODE_NORMAL
- def jump_to_address(self):
- self.registers['pc'] = self.operand & 0x0FFF
- def jump_to_subroutine(self):
- self.memory[self.registers['sp']] = self.registers['pc'] & 0x00FF
- self.registers['sp'] += 1
- self.memory[self.registers['sp']] = (self.registers['pc'] & 0xFF00) >> 8
- self.registers['sp'] += 1
- self.registers['pc'] = self.operand & 0x0FFF
- def skip_if_reg_equal_val(self):
- source = (self.operand & 0x0F00) >> 8
- if self.registers['v'][source] == (self.operand & 0x00FF):
- self.registers['pc'] += 2
- def skip_if_reg_not_equal_val(self):
- source = (self.operand & 0x0F00) >> 8
- if self.registers['v'][source] != (self.operand & 0x00FF):
- self.registers['pc'] += 2
- def skip_if_reg_equal_reg(self):
- source = (self.operand & 0x0F00) >> 8
- target = (self.operand & 0x00F0) >> 4
- if self.registers['v'][source] == self.registers['v'][target]:
- self.registers['pc'] += 2
- def move_value_to_reg(self):
- target = (self.operand & 0x0F00) >> 8
- self.registers['v'][target] = self.operand & 0x00FF
- def add_value_to_reg(self):
- target = (self.operand & 0x0F00) >> 8
- temp = self.registers['v'][target] + (self.operand & 0x00FF)
- self.registers['v'][target] = temp if temp < 256 else temp - 256
- def skip_if_reg_not_equal_reg(self):
- source = (self.operand & 0x0F00) >> 8
- target = (self.operand & 0x00F0) >> 4
- if self.registers['v'][source] != self.registers['v'][target]:
- self.registers['pc'] += 2
- def load_index_reg_with_value(self):
- self.registers['index'] = self.operand & 0x0FFF
- def jump_to_index_plus_value(self):
- self.registers['pc'] = self.registers['index'] + (self.operand & 0x0FFF)
- def generate_random_number_to_reg(self):
- value = self.operand & 0x00FF
- target = (self.operand & 0x0F00) >> 8
- self.registers['v'][target] = value & randint(0, 255)
- def draw_sprite(self):
- x_source = (self.operand & 0x0F00) >> 8
- y_source = (self.operand & 0x00F0) >> 4
- x_pos = self.registers['v'][x_source]
- y_pos = self.registers['v'][y_source]
- num_bytes = self.operand & 0x000F
- self.registers['v'][0xF] = 0
- if self.mode == MODE_EXTENDED and num_bytes == 0:
- self.draw_extended(x_pos, y_pos, 16)
- else:
- self.draw_normal(x_pos, y_pos, num_bytes)
- def draw_normal(self, x_pos, y_pos, num_bytes):
- for y_index in range(num_bytes):
- color_byte = bin(self.memory[self.registers['index'] + y_index])
- color_byte = color_byte[2:].zfill(8)
- y_coord = y_pos + y_index
- y_coord = y_coord % self.screen.get_height()
- for x_index in range(8):
- x_coord = x_pos + x_index
- x_coord = x_coord % self.screen.get_width()
- color = int(color_byte[x_index])
- current_color = self.screen.get_pixel(x_coord, y_coord)
- if color == 1 and current_color == 1:
- self.registers['v'][0xF] = 1
- color = 0
- elif color == 0 and current_color == 1:
- color = 1
- self.screen.draw_pixel(x_coord, y_coord, color)
- self.screen.update()
- def draw_extended(self, x_pos, y_pos, num_bytes):
- for y_index in range(num_bytes):
- for x_byte in range(2):
- color_byte = bin(self.memory[self.registers['index'] + (y_index * 2) + x_byte])
- color_byte = color_byte[2:].zfill(8)
- y_coord = y_pos + y_index
- y_coord = y_coord % self.screen.height
- for x_index in range(8):
- x_coord = x_pos + x_index + (x_byte * 8)
- x_coord = x_coord % self.screen.width
- color = int(color_byte[x_index])
- current_color = self.screen.get_pixel(x_coord, y_coord)
- if color == 1 and current_color == 1:
- self.registers['v'][0xF] = 1
- color = 0
- elif color == 0 and current_color == 1:
- color = 1
- self.screen.draw_pixel(x_coord, y_coord, color)
- self.screen.update()
- def keyboard_routines(self):
- operation = self.operand & 0x00FF
- source = (self.operand & 0x0F00) >> 8
- key_to_check = self.registers['v'][source]
- keys_pressed = key.get_pressed()
- if operation == 0x9E:
- if keys_pressed[KEY_MAPPINGS[key_to_check]]:
- self.registers['pc'] += 2
- elif operation == 0xA1:
- if not keys_pressed[KEY_MAPPINGS[key_to_check]]:
- self.registers['pc'] += 2
- def execute_logical_instruction(self):
- operation = self.operand & 0x000F
- self.logical_operation_lookup[operation]()
- def move_reg_into_reg(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- self.registers['v'][target] = self.registers['v'][source]
- def logical_or(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- self.registers['v'][target] |= self.registers['v'][source]
- def logical_and(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- self.registers['v'][target] &= self.registers['v'][source]
- def exclusive_or(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- self.registers['v'][target] ^= self.registers['v'][source]
- def add_reg_to_reg(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- temp = self.registers['v'][target] + self.registers['v'][source]
- if temp > 255:
- self.registers['v'][target] = temp - 256
- self.registers['v'][0xF] = 1
- else:
- self.registers['v'][target] = temp
- self.registers['v'][0xF] = 0
- def subtract_reg_from_reg(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- source_reg = self.registers['v'][source]
- target_reg = self.registers['v'][target]
- if target_reg > source_reg:
- target_reg -= source_reg
- self.registers['v'][0xF] = 1
- else:
- target_reg = 256 + target_reg - source_reg
- self.registers['v'][0xF] = 0
- self.registers['v'][target] = target_reg
- def right_shift_reg(self):
- source = (self.operand & 0x0F00) >> 8
- target = (self.operand & 0x00F0) >> 4
- bit_zero = self.registers['v'][source] & 0x1
- self.registers['v'][target] = self.registers['v'][source] >> 1
- self.registers['v'][0xF] = bit_zero
- def substract_reg_from_reg1(self):
- target = (self.operand & 0x0F00) >> 8
- source = (self.operand & 0x00F0) >> 4
- source_reg = self.registers['v'][source]
- target_reg = self.registers['v'][target]
- if source_reg > target_reg:
- target_reg = source_reg - target_reg
- self.registers['v'][0xF] = 1
- else:
- target_reg = 256 + source_reg - target_reg
- self.registers['v'][0xF] = 0
- self.registers['v'][target] = target_reg
- def left_shift_reg(self):
- source = (self.operand & 0x0F00) >> 8
- target = (self.operand & 0x00F0) >> 4
- bit_seven = (self.registers['v'][source] & 0x80) >> 8
- self.registers['v'][target] = self.registers['v'][source] << 1
- self.registers['v'][0xF] = bit_seven
- def misc_routines(self):
- operation = self.operand & 0x00FF
- self.misc_routine_lookup[operation]()
- def move_delay_timer_into_reg(self):
- target = (self.operand & 0x0F00) >> 8
- self.registers['v'][target] = self.timers['delay']
- def wait_for_keypress(self):
- target = (self.operand & 0x0F00) >> 8
- key_pressed = False
- while not key_pressed:
- event = pygame.event.wait()
- if event.type == pygame.KEYDOWN:
- keys_pressed = key.get_pressed()
- for keyval, lookup_key in KEY_MAPPINGS.items():
- if keys_pressed[lookup_key]:
- self.registers['v'][target] = keyval
- key_pressed = True
- break
- def move_reg_into_delay_timer(self):
- source = (self.operand & 0x0F00) >> 8
- self.timers['delay'] = self.registers['v'][source]
- def move_reg_into_sound_timer(self):
- source = (self.operand & 0x0F00) >> 8
- self.timers['sound'] = self.registers['v'][source]
- def load_index_with_reg_sprite(self):
- source = (self.operand & 0x0F00) >> 8
- self.registers['index'] = self.registers['v'][source] * 5
- def load_index_with_extended_reg_sprite(self):
- source = (self.operand & 0x0F00) >> 8
- self.registers['index'] = self.registers['v'][source] * 10
- def add_reg_into_index(self):
- source = (self.operand & 0x0F00) >> 8
- self.registers['index'] += self.registers['v'][source]
- def store_bcd_in_memory(self):
- source = (self.operand & 0x0F00) >> 8
- bcd_value = '{:03d}'.format(self.registers['v'][source])
- self.memory[self.registers['index']] = int(bcd_value[0])
- self.memory[self.registers['index'] + 1] = int(bcd_value[1])
- self.memory[self.registers['index'] + 2] = int(bcd_value[2])
- def store_regs_in_memory(self):
- source = (self.operand & 0x0F00) >> 8
- for counter in range(source + 1):
- self.memory[self.registers['index'] + counter] = \
- self.registers['v'][counter]
- def read_regs_from_memory(self):
- source = (self.operand & 0x0F00) >> 8
- for counter in range(source + 1):
- self.registers['v'][counter] = \
- self.memory[self.registers['index'] + counter]
- def store_regs_in_rpl(self):
- source = (self.operand & 0x0F00) >> 8
- for counter in range(source + 1):
- self.registers['rpl'][counter] = self.registers['v'][counter]
- def read_regs_from_rpl(self):
- source = (self.operand & 0x0F00) >> 8
- for counter in range(source + 1):
- self.registers['v'][counter] = self.registers['rpl'][counter]
- def reset(self):
- self.registers['v'] = [0] * NUM_REGISTERS
- self.registers['pc'] = PROGRAM_COUNTER_START
- self.registers['sp'] = STACK_POINTER_START
- self.registers['index'] = 0
- self.registers['rpl'] = [0] * NUM_REGISTERS
- self.timers['delay'] = 0
- self.timers['sound'] = 0
- def load_rom(self, filename, offset=PROGRAM_COUNTER_START):
- rom_data = open(filename, 'rb').read()
- for index, val in enumerate(rom_data):
- self.memory[offset + index] = val
- def decrement_timers(self):
- if self.timers['delay'] != 0:
- self.timers['delay'] -= 1
- if self.timers['sound'] != 0:
- self.timers['delay'] -= 1
CHIP8模拟器的python3实现-3-指令实现的更多相关文章
- chip8模拟器的python3实现-1-CHIP8简介
打算编写一个NES模拟器,先从简单的chip8模拟器入手 1.CHIP-8简介 CHIP-8是一个解释型语言,由Joseph Weisbecker开发.最初CHIP-8在上个世纪70年代被使用在COS ...
- chip8模拟器的python3实现-2-指令介绍
CHIP指令表 CHIP-8有35个指令,都为两字节长,以大端方式存储.指令表的指令格式规定如下: NNN:地址 NN:8位常量 N:4位常量 V:寄存器 X和Y:4位,标识寄存器 PC:程序计数器 ...
- QEMU模拟器Windows版本模拟ARMX86CPU指令
http://qemu.weilnetz.de/ QEMU Binaries for Windows
- Python3执行top指令
import subprocess top_info = subprocess.Popen(["], stdout=subprocess.PIPE) out, err = top_info. ...
- C++版 Chip8游戏模拟器
很早就想写个FC模拟器,但真是一件艰难的事情.. 所以先写个Chip8模拟器,日后再继续研究FC模拟器. Chip8只有35条指令,属于RISC指令集,4k内存,2k显存,16个寄存器(其中15个通用 ...
- 如何实现模拟器(CHIP-8 interpreter) 绝佳杰作.
转自 http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/ How to write an ...
- CS:APP2e Y86处理器模拟器∗指南
CS:APP2e Y86处理器模拟器∗指南 Randal E.Bryant David R. O'Hallaron 2013年7月29日 本文档描述了处理器模拟器,伴随的表示在第4章Y86处理器架构的 ...
- Appium+python自动化19-iOS模拟器(iOS Simulator)安装自家APP
前言 做过iOS上app测试的小伙伴应该都知道,普通用户安装app都是从appstore下载安装,安装测试版本的app,一般就是开发给的二维码扫码安装, 或者开发给个.ipa的安装包文件,通过itoo ...
- Appium+python自动化19-iOS模拟器(iOS Simulator)安装自家APP【转载】
前言 做过iOS上app测试的小伙伴应该都知道,普通用户安装app都是从appstore下载安装,安装测试版本的app,一般就是开发给的二维码扫码安装, 或者开发给个.ipa的安装包文件,通过itoo ...
随机推荐
- 被公司的垃圾XG人事系统吓尿了
OA要尝试设置单点登录,拿现有的HR系统尝试,结果不知道HR系统的加密方式和验证地址,于是乎找HR厂商——厦门XG软件实施人员.结果那个技术人员支支吾吾不肯给我,搞得非常的烦. 真奇怪了,不开源的软件 ...
- SourceInsight教程
概述: Source Insight是一个面向项目开发的程序编辑器和代码浏览器,它拥有内置的对C/C++, C#和Java等程序的分析.Source Insight能分析你的源代码并在你工作的同时动态 ...
- 关于MySQL的一些骚操作——提升正确性,抠点性能
概要 回顾以前写的项目,发现在规范的时候,还是可以做点骚操作的. 假使以后还有新的项目用到了MySQL,那么肯定是要实践一番的. 为了准备,创建测试数据表(建表语句中默认使用utf8mb4以及utf8 ...
- [20190531]ORA-600 kokasgi1故障模拟与恢复(后续).txt
[20190531]ORA-600 kokasgi1故障模拟与恢复(后续).txt --//http://blog.itpub.net/267265/viewspace-2646340/=>[2 ...
- 使用ML.NET进行自定义机器学习
ML.NET是Microsoft最近发布的用于机器学习的开源,跨平台,代码优先的框架.尽管对我们来说是一个新的框架,但该框架的根源是Microsoft Research,并且在过去十年中已被许多内部团 ...
- 基于mkv31芯片ADC差分应用
一.单端.全差分.伪差分 此部分转载https://www.cnblogs.com/alifpga/p/7976531.html 单端信号: 单端信号(single-end)是相对于差分信号而言的,单 ...
- selenium python 脚本不支持中文问题
在 python shell 中执行以下脚本: ...... dr.find_element_by_xpath("//a[test()='查看']") ...... 点击 Run ...
- 读取本地文件转化成MultipartFile
介绍 现在有个上传文件功能,需要将文件上传到oss上,但是文件有点多,于是使用接口进行上传.但是需要上传文件转换为MultipartFile类型文件进行上传. 主要代码 添加pom文件 <dep ...
- 《Vue 进阶系列之响应式原理及实现》
https://www.bilibili.com/video/av51444410/?p=5 https://github.com/amandakelake/blog/issues/63 https: ...
- html各种弹出框和提示框
控制台输出 console.log() console.info() confirm() alert() promt() 提示对话框