解码和匹配Chip 8操作码在C / C ++ [英] Decoding and matching Chip 8 opcodes in C/C++

查看:203
本文介绍了解码和匹配Chip 8操作码在C / C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写一个Chip 8模拟器作为模拟的介绍,我有点失落。基本上,我读了一个芯片8 ROM,并将其存储在一个char数组在内存中。然后,按照指南,我使用以下代码在当前程序计数器(pc)检索操作码:

I'm writing a Chip 8 emulator as an introduction to emulation and I'm kind of lost. Basically, I've read a Chip 8 ROM and stored it in a char array in memory. Then, following a guide, I use the following code to retrieve the opcode at the current program counter (pc):

// Fetch opcode
opcode = memory[pc] << 8 | memory[pc + 1];

芯片8操作码各为2字节。这是从一个指南,我模糊地理解为添加8额外的位空间到存储器[pc](使用<<8),然后合并内存[pc + 1]与它(使用|),并将结果存储在操作码变量。

Chip 8 opcodes are 2 bytes each. This is code from a guide which I vaguely understand as adding 8 extra bit spaces to memory[pc] (using << 8) and then merging memory[pc + 1] with it (using |) and storing the result in the opcode variable.

现在我已经分离了操作码,但是我真的不知道该怎么做。我使用操作码表,我基本上失去了匹配我读取的十六进制操作码到该表中的操作码标识符。另外,我意识到,我正在阅读的许多操作码也包含操作数(我假设后一个字节?),这可能使我的情况进一步复杂。

Now that I have the opcode isolated however, I don't really know what to do with it. I'm using this opcode table and I'm basically lost in regards to matching the hex opcodes I read to the opcode identifiers in that table. Also, I realize that many of the opcodes I'm reading also contain operands (I'm assuming the latter byte?), and that is probably further complicating my situation.

帮助?

推荐答案

在github.com搜索thumbulator或mspulator。我有几个非常简单的指令集模拟器,可能或可能没有帮助。

At github.com search for thumbulator or mspulator. I have a couple of very simple instruction set simulators that may or may not be helpful.

基本上,一旦你有了你需要解码的指令。例如从您的操作码表:

Basically once you have the instruction you need to decode it. For example from your opcode table:

if ((inst&0xF000)==0x1000)
{
  write_register(pc,(inst&0x0FFF)<<1);
}

猜测由于每个指令访问rom两个字节,可能一个(16位)字地址不是一个字节地址,所以我把它移到左边一个(你需要研究这些指令是如何编码的,你提供的操作码表是不够的,没有必要做假设)。

And guessing that since you are accessing rom two bytes per instruction, the address is probably a (16 bit) word address not a byte address so I shifted it left one (you need to study how those instructions are encoded, the opcode table you provided is inadequate for that, well without having to make assumptions).

还有很多事情要发生,我不知道是否在我的github示例中写了任何内容。我建议您创建一个抓取功能,用于在地址,读存储器功能,写存储器功能,读寄存器功能,写寄存器功能中获取指令。我建议您的解码和执行功能解码,并且一次只执行一个指令。正常执行只是在一个循环中调用它,它提供了做中断和类似的东西,没有很多额外的工作的能力。它还模块化您的解决方案。通过创建fetch()read_mem_byte()read_mem_word()等函数。你模块化你的代码(性能的微小成本),使调试更容易,因为你有一个单一的地方,你可以观看寄存器或内存访问,弄清楚是什么或不在。

There is a lot more that has to happen and I dont know if I wrote anything about it in my github samples. I recommend you create a fetch function for fetching instructions at an address, a read memory function, a write memory function a read register function, write register function. I recommend your decode and execute function decodes and executes only one instruction at a time. Normal execution is to just call it in a loop, it provides the ability to do interrupts and things like that without a lot of extra work. It also modularizes your solution. By creating the fetch() read_mem_byte() read_mem_word() etc functions. You modularize your code (at a slight cost of performance), makes debugging much easier as you have a single place where you can watch registers or memory accesses and figure out what is or isnt going on.

根据你的问题,以及你在这个过程中,我认为在写一个模拟器之前你需要做的第一件事就是写一个反汇编器。作为一个固定的指令长度指令集(16位),使它更容易。你可以从rom的一些有趣的地方开始,或者如果你喜欢,在开始的时候,解码你看到的一切。例如:

Based on your question, and where you are in this process, I think the first thing you need to do before writing an emulator is to write a disassembler. Being a fixed instruction length instruction set (16 bits) that makes it much much easier. You can start at some interesting point in the rom, or at the beginning if you like, and decode everything you see. For example:

if ((inst&0xF000)==0x1000)
{
  printf("jmp 0x%04X\n",(inst&0x0FFF)<<1);
}

只有35条指令不应该在一个下午,是你第一次解码指令(我假设根据你的问题)。反汇编器成为您的仿真器的核心解码器。用仿真替换printf(),更好的做法是留下printfs,只需添加代码来模拟指令执行,这样就可以执行。 (相同的交易有一个反汇编单个指令函数,为每个指令调用它,这成为你的仿真器的基础)。

With only 35 instructions that shouldnt take but an afternoon, maybe a whole saturday, being your first time decoding instructions (I assume that based on your question). The disassembler becomes the core decoder for your emulator. Replace the printf()s with emulation, even better leave the printfs and just add code to emulate the instruction execution, this way you can follow the execution. (same deal have a disassemble a single instruction function, call it for each instruction, this becomes the foundation for your emulator).

你的理解需要超过模糊到获取代码行所做的事情,为了完成这个任务,你必须对位操作有很强的理解。

Your understanding needs to be more than vague as to what that fetch line of code is doing, in order to pull off this task you are going to have to have a strong understanding of bit manipulation.

这行代码你提供buggy或至少冒险。如果memory []是一个字节数组,编译器可能很好地执行左移位使用字节大小的数学,导致一个零,然后零第二个字节导致只有第二个字节。

Also I would call that line of code you provided buggy or at least risky. If memory[] is an array of bytes, the compiler might very well perform the left shift using byte sized math, resulting in a zero, then zero orred with the second byte results in only the second byte.

基本上一个编译器是在它的权限,以改变这一点:

Basically a compiler is within its rights to turn this:

opcode = memory[pc] << 8) | memory[pc + 1];

进入:

opcode = memory[pc + 1];

这不会为你工作,一个很快的修复:

Which wont work for you at all, a very quick fix:

opcode = memory[pc + 0];
opcode <<= 8;
opcode |= memory[pc + 1];

会为您节省一些头痛。最小优化将保存编译器从存储中间结果到每个操作导致相同(期望的)输出/性能的中间结果。

Will save you some headaches. Minimal optimization will save the compiler from storing the intermediate results to ram for each operation resulting in the same (desired) output/performance.

指令集模拟器我写和提到以上不是为了性能,而是可读性,可见性,并希望教育。我将从类似的东西开始,然后如果性能的例子是你感兴趣,你必须重写它。这个芯片8模拟器,一旦经历过,将从头开始一个下午的任务,所以一旦你通过这第一次,你可以重写一个周末可能三或四次,而不是一个巨大的任务(必须重写)。 (指点器给我一个周末,大部分时间,msp430一个可能更像一个晚上或两个值得工作。让溢出标志一劳永逸是最大的任务,后来)。无论如何,点是,看看类似的游戏源,大多数如果不是所有的那些指令集模拟器被设计为执行速度,许多是勉强可读没有相当多的研究。通常大量的表驱动,有时大量的C编程技巧等。从一些易于管理,让它正常运行,然后担心改进它的速度或大小或可移植性或任何。这个chip8的东西看起来是基于图形的,所以你也要处理很多线描和其他位操作位图/屏幕/无处不在。或者你可以调用api或操作系统函数。基本上这个chip8东西不是你的传统指令集的寄存器和寻址模式和alu操作的清单。

The instruction set simulators I wrote and mentioned above are not intended for performance but instead readability, visibility, and hopefully educational. I would start with something like that then if performance for example is of interest you will have to re-write it. This chip8 emulator, once experienced, would be an afternoon task from scratch, so once you get through this the first time you could re-write it maybe three or four times in a weekend, not a monumental task (to have to re-write). (the thumbulator one took me a weekend, for the bulk of it. The msp430 one was probably more like an evening or two worth of work. Getting the overflow flag right, once and for all, was the biggest task, and that came later). Anyway, point being, look at things like the mame sources, most if not all of those instruction set simulators are designed for execution speed, many are barely readable without a fair amount of study. Often heavily table driven, sometimes lots of C programming tricks, etc. Start with something manageable, get it functioning properly, then worry about improving it for speed or size or portability or whatever. This chip8 thing looks to be graphics based so you are going to also have to deal with a lot of line drawing and other bit manipulation on a bitmap/screen/wherever. Or you could just call api or operating system functions. Basically this chip8 thing is not your traditional instruction set with registers and a laundry list of addressing modes and alu operations.

这篇关于解码和匹配Chip 8操作码在C / C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆