6

出于学习目的,我打算开始构建一个 8051 微控制器仿真器。我很擅长用 C/C++/C# 编程。这不是课堂项目等,而是我这边的学习计划。

我确实发现了很多讨论这个问题的问题。但是,我想更细化地打破它,以便在我真正开始编写代码之前知道我需要关注哪些领域。

我最初的要求是:

  1. 文本编辑器(可以使用编辑框控件),用户可以在其中编写汇编代码

  2. 验证语法是否正确

  3. 有一个小窗口,在运行时显示寄存器值。

  4. 当用户启动程序时,说明应逐步更新注册窗口。

除了 GUI 元素,我更想知道如何模拟微控制器。

我理解的方式可以进一步分解:

  1. 我需要查找表以获取指令或其他方式来存储可用指令并验证语法。任何指示如何实现这一点,请告诉我。

  2. 如何模拟 8051 的每条指令?

  3. 对于寄存器,我可以根据类型使用无符号整数并更新表。

  4. 由于微控制器的 RAM 内存有限,我如何检查代码长度或更确切地说是在内存中执行的代码,以避免和缓冲区溢出或其他问题。

如果有一些开源项目详细说明了如何构建模拟器,将不胜感激。

4

2 回答 2

7

我认为您对这个项目的范围有点不清楚,至少与标题相关。

模拟器执行二进制代码,仅此而已。模拟器不包括编辑器(即开发工具)或汇编器(同上)。进行语法检查和翻译是汇编程序的责任,这样模拟器就只有执行预先验证的合法代码的相对简单的工作。

听起来您想构建一个完整的 IDE。这将在编辑器、汇编器和仿真器周围包裹很多 GUI。我会把这一步作为最后一步。


至于您对模拟器本身的问题:

您可以使用最多(例如)64K 字节的数组作为模拟器的工作内存。您在程序中使用变量来模拟寄存器。我会用 anunsigned char *来模拟程序计数器,而ints 则用于大多数其他东西......

操作非常简单:在 0(或预先确定的引导位置)启动程序计数器,并启动一个循环,通过该指针获取指令,并将与指令相关的任何操作应用于寄存器和内存。一个简单的实现将围绕一个switch包含所有可能指令代码的巨大语句。

正如我所说,你的模拟器不应该担心非法指令,因为汇编器不应该产生任何指令。如果遇到非法操作,您可以让您的程序(即主循环)停止。

同样,您的仿真器不必担心范围、索引或大小溢出……这也是汇编器的问题,或者如果您有链接器的问题,也可能是链接器的问题。


更新: SO中的一些指针:

模拟器框架

于 2009-11-24T09:32:50.563 回答
6

最近我为AVR芯片组装了一个仿真器,它也是一个小型8位微控制器。源代码在 GitHub 上为ghewgill/emulino。最有趣的文件是cpu.c,它包含每个 CPU 指令的实现。关键线在cpu_run()(省略一些细节):

while (state == CPU_RUN) {
    u16 instr = Program[PC++];
    Instr[instr](instr);
}

这会从 PC 寄存器指向的程序存储器中加载一个 16 位字,然后将其用作指令跳转表的索引(这是一个 64k 函数指针数组 - 实际表是由脚本在编译时生成的)。该函数将是do_XXX()该源文件中的函数之一,并且可以在执行实际指令之前进行进一步的指令解码。例如,do_ADD()函数:

static void do_ADD(u16 instr)
{
    trace(__FUNCTION__);
    // ------rdddddrrrr
    u16 r = (instr & 0xf) | ((instr >> 5) & 0x10);
    u16 d = ((instr >> 4) & 0x1f);
    u8 x = Data.Reg[d] + Data.Reg[r];
    Data.SREG.H = (((Data.Reg[d] & Data.Reg[r]) | (Data.Reg[r] & ~x) | (~x & Data.Reg[d])) & 0x08) != 0;
    Data.SREG.V = (((Data.Reg[d] & Data.Reg[r] & ~x) | (~Data.Reg[d] & ~Data.Reg[r] & x)) & 0x80) != 0;
    Data.SREG.N = (x & 0x80) != 0;
    Data.SREG.S = Data.SREG.N ^ Data.SREG.V;
    Data.SREG.Z = x == 0;
    Data.SREG.C = (((Data.Reg[d] & Data.Reg[r]) | (Data.Reg[r] & ~x) | (~x & Data.Reg[d])) & 0x80) != 0;
    Data.Reg[d] = x;
    Cycle++;
}

这会执行实际的加法运算 ( Data.Reg[d] + Data.Reg[r]),然后根据结果设置所有各种条件标志。

于 2009-11-24T09:35:44.553 回答