指令集仿真器指南

4

我对编写像Gameboy和其他掌上游戏机一样的模拟器很感兴趣,但我读到第一步是模拟指令集。我在这里找到了一个链接,说是初学者可以模拟Commodore 64 8位微处理器,问题是我对模拟指令集一无所知。我了解MIPS指令集,所以我认为我可以理解其他指令集,但问题是什么是模拟指令集?

注意:如果有人能为我提供针对初学者的逐步指南,让我了解指令集模拟,我将非常感激。

注意2:我计划使用C语言编写。

注意3:这是我第一次尝试学习整个模拟器的东西。

谢谢。

编辑:我发现了这个站点,它是一个详细的、逐步指南,介绍如何编写模拟器,看起来很有前途。我会开始阅读它,并希望它能帮助其他想要编写模拟器的人。

模拟器101


1
如果你想开始模拟器编程,我建议你先从一些更简单的项目入手,比如Chip-8。 - alex
我认为这是一个好主意,因为6502有许多指令可供使用。 - hakuna matata
是的,Chip-8也只有一种寻址模式。 - alex
1个回答

7
一种指令集仿真器是一种软件程序,它从软件设备中读取二进制数据,并像物理微处理器访问物理数据一样执行其中包含的指令。
Commodore 64使用了6502微处理器。我曾经为这个处理器编写过一个仿真器。首先,您需要阅读处理器的数据手册并学习其行为。它有哪些操作码?内存寻址方式如何?IO方法是什么?它有哪些寄存器?它如何开始执行?这些都是您需要回答的问题,然后才能编写仿真器。
下面是用C语言实现的大致概述(不完全准确):
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!

    }
}

根据这个参考,6502处理器实际上有8个操作码,这意味着您将在switch语句中拥有8个不同的ADC,每个ADC用于不同的操作码和内存寻址方案。您将不得不处理字节序和字节顺序,当然还有指针。如果您还没有对C中的指针和类型转换有牢固的理解,我建议您先了解一下。要操作标志寄存器,您必须对C中的位运算有牢固的理解。如果您聪明的话,可以利用C宏甚至函数指针来节省一些工作,就像上面的CARRY_FLAG示例一样。
每次执行指令时,必须将程序计数器按该指令的大小推进,每个操作码的大小都不同。某些操作码不需要任何参数,因此它们的大小只是1个字节,而其他操作码则像我的MOV示例一样使用16位整数。所有这些都应该有很好的文档记录。
分支指令(JMP,JE,JNE等)很简单:如果标志寄存器中设置了某个标志,则将PC加载到指定的地址。这就是微处理器中“决策”的方式,模拟它们只需要改变PC,就像真实的微处理器所做的那样。
编写指令集模拟器最困难的部分是调试。你如何知道一切是否按预期工作?有许多资源可以帮助你。人们编写了测试代码,可以帮助您调试每个指令。您可以逐个执行它们,并比较参考输出。如果有什么不同,您就知道有bug,可以修复它。
这应该足以让您开始了解。重要的是,您必须A)对要模拟的指令集有牢固的理解,B)对C语言中的低级数据操作具有牢固的理解,包括类型转换、指针、位运算、字节顺序等。

非常感谢您的帮助。我将开始阅读数据表。 - hakuna matata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接