搜索
bottom↓
回复: 17

探究 51 模拟器指令解码的效率问题

[复制链接]

出280入168汤圆

发表于 2021-4-6 15:44:40 | 显示全部楼层 |阅读模式
在做完了初期的模拟器之后, 检测的效果不是太好.

在 STM32F429 上, 经过强优化的代码也只能将主频勉强维持在 300 KHz 左右,

这离预计的目标 1.2MHz 相距甚远.

按照兄弟们的提示, 在实际上 168MHz 的 STM32 上, 执行比大约是 560:1 ,  效率太低了 ...

所以今天在彻底优化之前检查一下指令解码器部分的效率.

从 C 编译器给出的 arm 汇编指令文件来看, 基本上能知道效率低的原因了:

对 255 条 51 指令, switch 展开后使用了查表法, 所以基本上能直达解析段代码,

但紧跟着的 SFR 寄存器访问就不行了, 一长溜的 cmp 指令命中率极低,

而且对模拟 51 的寄存器操作是一大堆寄存器互相绕来绕去交换数据和运算,

所以才造成执行效率超低.

  1. 8002130:        f7fe bc6f         b.w        8000a12 <alu_instruction_decode+0x322>
  2. 8002134:        28e0              cmp        r0, #224        ; 0xe0
  3. 8002136:        f43f ae5f         beq.w        8001df8 <alu_instruction_decode+0x1708>
  4. 800213a:        28f0              cmp        r0, #240        ; 0xf0
  5. 800213c:        f041 8332         bne.w        80037a4 <alu_instruction_decode+0x30b4>
  6. 8002140:        4b56              ldr        r3, [pc, #344]        ; (800229c <alu_instruction_decode+0x1bac>)
  7. 8002142:        4a55              ldr        r2, [pc, #340]        ; (8002298 <alu_instruction_decode+0x1ba8>)
  8. 8002144:        7818              ldrb        r0, [r3, #0]
  9. 8002146:        4e52              ldr        r6, [pc, #328]        ; (8002290 <alu_instruction_decode+0x1ba0>)
  10. 8002148:        4b52              ldr        r3, [pc, #328]        ; (8002294 <alu_instruction_decode+0x1ba4>)
  11. 800214a:        7010              strb        r0, [r2, #0]
  12. 800214c:        7018              strb        r0, [r3, #0]
  13. 800214e:        f996 3000         ldrsb.w        r3, [r6]
  14. 8002152:        f7fe bc5e         b.w        8000a12 <alu_instruction_decode+0x322>
  15. 8002156:        28d0              cmp        r0, #208        ; 0xd0
  16. 8002158:        f001 8666         beq.w        8003e28 <alu_instruction_decode+0x3738>
  17. 800215c:        d83d              bhi.n        80021da <alu_instruction_decode+0x1aea>
  18. 800215e:        2882              cmp        r0, #130        ; 0x82
  19. 8002160:        f001 8656         beq.w        8003e10 <alu_instruction_decode+0x3720>
  20. 8002164:        2883              cmp        r0, #131        ; 0x83
  21. 8002166:        d12a              bne.n        80021be <alu_instruction_decode+0x1ace>
  22. 8002168:        4a48              ldr        r2, [pc, #288]        ; (800228c <alu_instruction_decode+0x1b9c>)
  23. 800216a:        4b4a              ldr        r3, [pc, #296]        ; (8002294 <alu_instruction_decode+0x1ba4>)
  24. 800216c:        6811              ldr        r1, [r2, #0]
  25. 800216e:        781a              ldrb        r2, [r3, #0]
  26. 8002170:        7808              ldrb        r0, [r1, #0]
  27. 8002172:        4e47              ldr        r6, [pc, #284]        ; (8002290 <alu_instruction_decode+0x1ba0>)
  28. 8002174:        4050              eors        r0, r2
  29. 8002176:        7018              strb        r0, [r3, #0]
  30. 8002178:        f996 3000         ldrsb.w        r3, [r6]
  31. 800217c:        f7fe bc49         b.w        8000a12 <alu_instruction_decode+0x322>
  32. 8002180:        2881              cmp        r0, #129        ; 0x81
  33. 8002182:        f041 8334         bne.w        80037ee <alu_instruction_decode+0x30fe>
  34. 8002186:        4b43              ldr        r3, [pc, #268]        ; (8002294 <alu_instruction_decode+0x1ba4>)
  35. 8002188:        4a3f              ldr        r2, [pc, #252]        ; (8002288 <alu_instruction_decode+0x1b98>)
  36. 800218a:        7818              ldrb        r0, [r3, #0]
  37. 800218c:        7812              ldrb        r2, [r2, #0]
  38. 800218e:        4e40              ldr        r6, [pc, #256]        ; (8002290 <alu_instruction_decode+0x1ba0>)
  39. 8002190:        4310              orrs        r0, r2
  40. 8002192:        7018              strb        r0, [r3, #0]
  41. 8002194:        f996 3000         ldrsb.w        r3, [r6]
  42. 8002198:        f7fe bc3b         b.w        8000a12 <alu_instruction_decode+0x322>
复制代码


现在定下的优化目标是:

对 51 SFR 寄存器的访问也使用查表法, 实在用 C 不行就直接使用内嵌的 asm.

现在要解决 switch 的展开问题, 难道要建一个 64K 的巨表来避免 arm 编译器的强行展开吗?

我先写一个脚本, 展开 51 的巨集指令表试试.

出615入1076汤圆

发表于 2021-4-6 17:01:56 | 显示全部楼层
10 年前,實際使用 STC 51 MCU 外接的是 12MHz 晶體,所以,爲了仿真更貼近真實,1.2M 不夠,應該要支持 12M 才行,加油。。。

出0入20汤圆

发表于 2021-4-6 17:23:16 | 显示全部楼层
把51全部的SFR写成结构体,位和字节用联合实现,然后...位域访问?

目测这里有cmp的原因还是因为深入到了指令内部,在根据寄存器地址做寻址,而51真正的精华不就是那一堆变态的寻址方式,直接用指令代表寻址方式然后立即数就是干

啥也不懂,乱说的哈~

出280入168汤圆

 楼主| 发表于 2021-4-6 17:38:18 | 显示全部楼层
Error.Dan 发表于 2021-4-6 17:23
把51全部的SFR写成结构体,位和字节用联合实现,然后...位域访问?

目测这里有cmp的原因还是因为深入到了指令 ...


兄弟没说错, 问题的原因就在于寄存器组的定义比较混乱.

我现在正在调整访问方式, 全部放在一个数组内, 强行用指针和下标访问,

免得编译器使用中间寄存器互相交换数据, 那种方式效率太低了.

出280入168汤圆

 楼主| 发表于 2021-4-6 17:41:25 | 显示全部楼层
dukelec 发表于 2021-4-6 17:01
10 年前,實際使用 STC 51 MCU 外接的是 12MHz 晶體,所以,爲了仿真更貼近真實,1.2M 不夠,應該要支持 12 ...

MCU Flash 的访问不是 0 等待, 所以难度很大啊 ...

测试过从一个中断响应回来, 要耽误很久的重刷指令数据时间.

出140入158汤圆

发表于 2021-4-6 17:45:43 | 显示全部楼层
兄弟可否参考一下FC模拟器,参考一下它的架构,那玩意,72M的M3也能全速模拟1.8M的6502。我没仔细研究过,乱说一通的。

出140入158汤圆

发表于 2021-4-6 17:48:24 | 显示全部楼层
兄弟该不会用switch来判断指令吧??我看很多模拟器都是用函数指针数组来解析。

出0入0汤圆

发表于 2021-4-6 17:51:23 | 显示全部楼层
不懂,做这个是用来干什么的

出280入168汤圆

 楼主| 发表于 2021-4-6 18:06:10 | 显示全部楼层
amigenius 发表于 2021-4-6 17:48
兄弟该不会用switch来判断指令吧??我看很多模拟器都是用函数指针数组来解析。 ...

没错, 就是用它的. 但没想到 switch 的效率太低了.

刚开始时感觉对函数的调用在进出时开销有点大,  

所以想用 switch 直接整成一个大通铺, 省去调用的开销,

现在看起来不是那么回事 ...

函数指针是现在准备做的事情, 不过还是在想办法绕过调用环节的开销,

如果是 6502 就简单多了, 就那几个固定的寄存器, 不像 51 这么麻烦.

出280入168汤圆

 楼主| 发表于 2021-4-6 18:07:08 | 显示全部楼层
honeybear 发表于 2021-4-6 17:51
不懂,做这个是用来干什么的

一个硬件形式的 debuger, 模拟 8051 的运行.

出140入158汤圆

发表于 2021-4-6 19:44:14 | 显示全部楼层
chunjiu 发表于 2021-4-6 18:06
没错, 就是用它的. 但没想到 switch 的效率太低了.

刚开始时感觉对函数的调用在进出时开销有点大,  

刚好相反,大量的条件判断,switch效率太低,开销太大。而使用用函数指针,您每个指令解析函数里面,不要使用局部变量,就不会带来额外的出入栈开销,总体开销很小的,而且开销也比较确定。

出280入168汤圆

 楼主| 发表于 2021-4-6 20:48:56 | 显示全部楼层
amigenius 发表于 2021-4-6 19:44
刚好相反,大量的条件判断,switch效率太低,开销太大。而使用用函数指针,您每个指令解析函数里面,不要 ...

当时已经考虑到局部变量的开销问题了. 使用的全是全局变量.

但今天检查了全局变量的汇编代码后也不行, 它还是用几个寄存器来回倒腾地址和数据.

所以, 我后面的代码已经开始用全局数组保存模拟的寄存器组.

计划是固定用一个 arm 寄存器做数组的指针, 然后用下标来指定模拟的 51 寄存器内容,

反正就是禁止编译器自己折腾那些数据, 这样处理起来应该会效率比较高了.

出140入158汤圆

发表于 2021-4-6 22:21:30 | 显示全部楼层
chunjiu 发表于 2021-4-6 20:48
当时已经考虑到局部变量的开销问题了. 使用的全是全局变量.

但今天检查了全局变量的汇编代码后也不行,  ...

为了避免编译器开优化后把全局变量倒腾在寄存器,并且频繁出入栈,您可以试试把51的寄存器定义在CCM里,并且指定地址存放,并加volatile修饰。

出0入0汤圆

发表于 2021-4-6 22:55:28 | 显示全部楼层
楼主精力可嘉啊,楼主搞这个是只是为了学习?

出280入168汤圆

 楼主| 发表于 2021-4-6 23:18:06 来自手机 | 显示全部楼层
amigenius 发表于 2021-4-6 22:21
为了避免编译器开优化后把全局变量倒腾在寄存器,并且频繁出入栈,您可以试试把51的寄存器定义在CCM里, ...

CCM 的缺点就是太小了,我正在看它的相关资料,研究一下将哪部分塞进去最合适。

中断必须要放进去的,因为之前的代码用定时器后,发现速度下降的厉害,估计是flash响应的时间太长。

还有几个很大的数据表,用来避免连环 if 的,不知道能不能塞的下。

看样子还要花不少脑筋的……

出280入168汤圆

 楼主| 发表于 2021-4-6 23:19:10 来自手机 | 显示全部楼层
arm_m0 发表于 2021-4-6 22:55
楼主精力可嘉啊,楼主搞这个是只是为了学习?

差不多是为了学习,准备开始用国产51了。

出0入4汤圆

发表于 2021-6-16 16:16:22 | 显示全部楼层
这个用STM32芯片运行的仿真器如何导入51的HEX 文件?

出280入168汤圆

 楼主| 发表于 2021-6-16 16:21:50 | 显示全部楼层
PICTURE 发表于 2021-6-16 16:16
这个用STM32芯片运行的仿真器如何导入51的HEX 文件?

之前是直接读入 RAM 的(通过串口或 SPI),然后解析并执行。

现在手上有其它工作,等工作忙完了再重新折腾它。

还要进行重大的架构调整,否则无法在 STM32 上做到高速仿真运行。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-18 17:39

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表