【发布时间】:2012-05-16 07:41:20
【问题描述】:
这是我在 Stack Overflow 上的第一篇文章,所以我希望我做得正确。 ;-)
我正在尝试开发 TriCore 仿真器,但无法决定何时为指令加载操作数的策略。 TriCore 可能是一种相当不起眼的微控制器,所以让我稍微解释一下架构。
有两种类型的指令,16 位和 32 位。是16位还是32位,由最后一个字节的位0决定;由于字节顺序是小端,它始终是内存中的第一个字节。没问题。
这两种指令类型有几种操作码格式,14 种用于 16 位指令,25 种用于 32 位指令。操作码分为两个独立的操作码字段,尽管大多数 16 位操作码只有一个操作码字段。第一个操作码字段在低 8 位;它直接描述了 16 位指令的指令,对于许多 32 位指令,它描述了操作数编码,而第二个字段描述了实际指令(当然也有例外)。
我的计划是始终提取所有操作码字段(这有点烦人,因为所有指令格式的第二个字段的位置都不相同)并将它们组合成一个 16 位值,该值将用于函数指针表。
根据这个值,我想提取操作数。例如,在 32 位指令中,当第一个操作码是 0x8B 时,操作数是两个数据寄存器和一个 9 位常量。但是,也有一些非常乏味的例外情况:
ADD.A 和 ADDSC.A 指令都有操作码 1 == 0x01。但是ADD.A 使用三个地址寄存器,而ADDSC.A 使用两个地址寄存器,一个数据寄存器和一个索引,编码到指令中。
最后我的问题是:在执行指令之前在这样的架构中加载操作数是否可行?还是先调用指令函数并在那里提取操作数会更好?
任何有兴趣的人,指令集手册在这里:http://www.infineon.com/dgdl/tc_v131_instructionset_v138.pdf?folderId=db3a304412b407950112b409b6cd0351&fileId=db3a304412b407950112b409b6dd0352
感谢任何提示!
顺便说一句:选择的语言是 C 或 C++。
(应要求,我将我的想法插入到我最初的问题中。)
好吧,我对我拥有的不同选择进行了广泛的思考,我想我会解决以下问题。
我将整个过程分为两部分:
- 程序分析和操作数提取
- 执行
在第一步中,每条指令都被加载并对齐到 32 位。然后将加载的指令与一组位掩码进行比较,以确定正确的操作码,它不仅告诉我最终必须执行什么,还告诉我如何加载操作数。在特定于地址模式的函数中,操作数被加载到指针中;指令立即数根据需要存储。
这归结为一个类似这样的结构:
struct instruction_t {
int32_t **operands;
int32_t *immediates;
};
这基本上是为每条指令分配的(最大的缺点:内存消耗。我为这种结构计算了大约 40 字节作为最坏情况(使用 64 位指针),这意味着通常为 4 兆字节的程序仅包含 16位指令最终会占用大约 80 兆内存。另一方面,我认为执行速度可以相当快)。
通过这种方法,我可以只实现每条指令一次,因为我的操作数如何加载并不重要——另外,使用相同的操作数集执行相同的指令就像在真机上一样。代码的执行只意味着通过选择正确的结构并相应地调用指令函数来加载正确的操作数集。
我知道还有其他方法 - 我特别喜欢动态重新编译。但是这个系统相当复杂,具有不同的片上组件和 I/O 映射寄存器,无论如何都会添加大量样板代码。
我真的很感谢我的方法中的一些 cmets。也许您知道更好的方法?
谢谢!
【问题讨论】:
标签: c++ emulation instruction-set