4

我有兴趣为 gameboy 和其他手持控制台编写模拟器,但我读到的第一步是模拟指令集。我在这里找到了一个链接,上面说初学者可以模拟 Commodore 64 8 位微处理器,问题是我对模拟指令集一无所知。我知道 mips 指令集,所以我想我可以理解其他指令集,但问题是模拟它们意味着什么?

注意:如果有人可以为我提供初学者指令集仿真的分步指南,我将不胜感激。

注意 #2:我打算用 C 语言编写。

注意#3:这是我第一次尝试学习整个仿真。

谢谢

编辑:我发现这个网站是一个详细的分步指南来编写一个看起来很有希望的模拟器。我将开始阅读它,并希望它对其他正在研究编写模拟器的人有所帮助。

模拟器 101

4

1 回答 1

7

指令集仿真器是一种软件程序,它从软件设备读取二进制数据并执行数据包含的指令,就好像它是访问物理数据的物理微处理器一样。

Commodore 64 使用了 6502 微处理器。我曾经为这个处理器写过一个模拟器。您需要做的第一件事是阅读处理器上的数据表并了解其行为。它有什么样的操作码,内存寻址怎么样,IO的方法。它的寄存器是什么?它是如何开始执行的?这些都是您在编写模拟器之前需要回答的所有问题。

以下是它在 C 中的外观的一般概述(不是 100% 准确):

uint8_t RAM[65536]; //Declare a memory buffer for emulated RAM (64k)
uint16_t A; //Declare Accumulator
uint16_t X; //Declare X register
uint16_t Y; //Declare Y register
uint16_t PC = 0; //Declare Program counter, start executing at address 0
uint16_t FLAGS = 0 //Start with all flags cleared;

//Return 1 if the carry flag is set 0 otherwise, in this example, the 3rd bit is
//the carry flag (not true for actual 6502)
#define CARRY_FLAG(flags)  ((0x4 & flags) >> 2)

#define ADC 0x69
#define LDA 0xA9

while (executing) {
    switch(RAM[PC]) {  //Grab the opcode at the program counter
        case ADC: //Add with carry
            A = X + RAM[PC+1] + CARRY_FLAG(FLAGS);
            UpdateFlags(A);
            PC += ADC_SIZE;
            break;
        case LDA: //Load accumulator
            A = RAM[PC+1]; 
            UpdateFlags(X);
            PC += MOV_SIZE;
            break;
        default:
            //Invalid opcode!

    }
}

根据这个参考ADC 实际上在 6502 处理器中有 8 个操作码,这意味着您的 switch 语句中将有 8 个不同的 ADC,每个 ADC 用于不同的操作码和内存寻址方案。您将不得不处理字节序和字节顺序,当然还有指针。如果您还没有 C 中的指针和类型转换,我将有一个深入的了解。要操作标志寄存器,您必须对 C 中的按位运算有深入的了解。如果您很聪明,可以使用 C 宏甚至函数指针来节省一些工作,如上面的 CARRY_FLAG 示例。

每次执行指令时,都必须将程序计数器推进该指令的大小,每个操作码的大小都不同。一些操作码不带任何参数,因此它们的大小只有 1 个字节,而其他操作码采用 16 位整数,如我上面的 MOV 示例。所有这些都应该有很好的记录。

分支指令(JMP、JE、JNE 等)很简单:如果在标志寄存器中设置了某个标志,则将 PC 加载到指定的地址。这就是微处理器如何做出“决定”,而模拟它们只是改变 PC 的问题,就像真正的微处理器会做的那样。

编写指令集模拟器最困难的部分是调试。你怎么知道一切是否正常?有很多资源可以帮助您。人们已经编写了测试代码,可以帮助您调试每条指令。您可以一次执行一条指令并比较参考输出。如果有什么不同,你知道你在某个地方有一个错误并且可以修复它。

这应该足以让你开始。重要的是你有 A) 对要模拟的指令集有很好的深入理解 B) 对 C 中的低级数据操作有充分的理解,包括类型转换、指针、按位操作、字节顺序等。

于 2012-11-17T19:23:20.730 回答