在指令集翻译器/仿真器中解码线程

我写了一个完整的RISC风格处理器系统模拟器/仿真器(以及所有的外设)。 目前,它使用间接线程仿真循环。 即所有的指令页脚都是这样的:

pc += 4;
inst = loadWord(mem, pc);
instp = decodeTable[opcode(inst)];
goto *instp

这表现相当好,在启动Linux时,我在现代机器上获得了大约70-80 MIPS,这非常好。

不过,我正在考虑转向直接预解码的线程解释器模型,这看起来如下所示:

tPC += 1;
instp = predecodeMem[tPC].operation;
goto *instp;

预解码本身并不是什么大问题,它只是替换现有的解码器和添加一些影子存储器。 我的主要问题与自修改代码(或半自修改代码)有关。

在简单的情况下,我们可以在页面被访问之前懒惰地分配预解码页面,这些页面之前没有被执行过。 然后从所有条目中清除软件TLB,以确保我们在下一次写入该页面时通过内存模拟系统,因此写入可执行页面将不得不更新解码信息以及性能上的成本,但是因为这样很少见,我们应该没有问题(也可以通过添加在运行时计算的子页面可执行位来加快速度)。

这里的问题是关于一个长期的代码发现,当页面被仿真器内运行的操作系统重用时。 例如,内存页面可以由Linux内核分配,分配为一个进程的代码。 下一次创建进程时,页面可能会被分配为数据,但是在刚描述的方案中,这会导致问题,因为现在纯数据页面在每次写入字节时都必须经过很慢的预解码。

一些目前的想法,但不是这些我觉得特别好,即它们都有明显的缺点:

  • 执行页面时使用mprotect(),并用信号处理程序拦截保护错误。 这会降低写入速度,并使多线程多核仿真变得非常痛苦。
  • 在编写代码时,我们不是更新预解码信息,而是刷新与代码执行相关的软TLB转换,并翻转一些关于脏页面的信息。 这会减慢该页面上的代码执行速度,但至少读取和写入速度很快。 问题当然是,下次页面被重用为可执行文件而不是数据时,我们会遇到同样的问题。
  • 移动到一个较小的预解码缓存,其中保留了具有预解码信息的有限数量的页面。 这些网页的年龄并根据LRU策略或类似的内容被驱逐。 这种方法惩罚具有固定内存布局的应用程序(即许多嵌入式应用程序)。
  • 我发现文献严重缺乏关于这个话题的讨论。 什么样的通用方法可以在页面不再使用时使页面老化,以便我们例如清除与页面相关的执行位和预解码内存?

    链接地址: http://www.djcxy.com/p/50563.html

    上一篇: decoded threading in instruction set translator / emulator

    下一篇: Simplest possible architecture that can be virtualized and run the Linux kernel