搜索
bottom↓
回复: 73

用了半个月时间研究 STM32 的弱点,51 模拟器将继续优化

[复制链接]

出280入168汤圆

发表于 2021-4-22 16:02:27 | 显示全部楼层 |阅读模式
上次在 STM32F429 上移植了初版的 BigSam8052 模拟器,竭尽全力跑得成绩是 300KHz 左右的主频,还没有添加系统状态监控的代码部分。

这个成绩离实用状态还相距有点大,随后因肩周炎发作而暂停了更新代码。肩周炎疼的无法睡好觉,严重时鼠标都拿不起来。

所以兄弟们平时要注意锻炼哈,不然到年龄了啥毛病都来了,基本上就无法做事情了。

好了,回归正题,乘着养病期间,仔细研究了 STM32 的架构资料,查找效率低下的原因。

====================
一、超慢的 FLASH 存储器

最大访问速度是 30M。也就是说 :无论 CPU 内核有多快,都要等着 FLASH 慢吞吞的给你传递指令数据。

ST 的解决方案是加宽数据总线和使用 ART 策略,采用预取方式填充指令管道,

也就是每次取 4 ~8 条指令,然后利用执行这些指令的时间差再次预取下一批指令。

理论上能解决 FLASH 准备数据造成的等待问题并全速执行,但这是很理想的顺序执行情况下。

真实情况是,一个 jump 指令就能让这些准备工作全废 ... 因为跳转的地址不是指令管道所能预测并提前准备的。

在 160MHz 主频的情况下,取 FLASH 指令数据需要 5 个等待周期,在取得数据填充管道后译码并执行指令时,已经是第 9 个时钟周期了。

随后几条指令的确是全速执行的,但碰到一条 jump 指令后,这一切准备工作又要重头来过。

此时的 MCU 比 30MHz 主频的 MCU 也快不了多少 ...

所以,在我开了一个用来同步的定时中断后,模拟器性能直接下降了 17% 左右,就是因为跳转造成的 FLASH 取指令等待延时。

二、不是很理想的 SRAM

SRAM 可以 0 等待访问,不过此 0 等待是有条件的。如果用来跑代码的话,那的确比 FLASH 访问要快多了。

ARM 的指令总线和数据总线是分开的,所以在 FLASH 中取指令,往 RAM 中存数据是可以并行的,这才能号称单周期执行一条指令。

若在 RAM 中跑代码,两个总线会抢夺 RAM 的访问权,造成竞争并设置等待状态,所以一条指令做不到单周期。

打个比方,一条指令运算过后,结果要存回 RAM 中的变量地址内。

指令总线开始操作了,准备取下一条指令,但数据总线正在往 RAM 中存数据,指令总线只能暂停操作,等待数据写入完毕。

完成数据写入后,指令总线重新将指令地址送到 RAM 上,然后读取指令数据送入指令管道,再进行译码并执行 ...

可想而知,这期间经历了多少辛苦的事情。

===============================

在了解 STM32 的指令执行原理和架构后,终于理解了为啥模拟器跑不快的原因。

因为 51  的寻址方式太复杂了,需要大量的 if 来判断和最终定址,简直就是刀刀捅进 STM32 的心窝子 ...

现在要重新整理和设计模拟 51 的代码框架,尽量避免使用 if 来处理,减少牵连到 STM32 的短处。

但是不知道该架构最后的复杂程度是怎样的,先草拟一个框架看看吧。

出0入362汤圆

发表于 2021-4-22 16:17:06 | 显示全部楼层
STM32F4有CCM RAM啊,不和常规RAM抢总线, 试试?

出280入168汤圆

 楼主| 发表于 2021-4-22 16:26:03 | 显示全部楼层
tomzbj 发表于 2021-4-22 16:17
STM32F4有CCM RAM啊,不和常规RAM抢总线, 试试?

正在草拟新的代码框架,准备使用 CCM。因为 STM32F429 上的 CCM 不和指令总线挂钩,所以又重新买了两块板子:STM32H743 和一块双核的 STM32H745。

出280入168汤圆

 楼主| 发表于 2021-4-22 16:40:44 | 显示全部楼层
目前在对 51 的 SFR 寄存器进行访问权重统计,重新构建代码的访问方式。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入10汤圆

发表于 2021-4-22 16:47:28 | 显示全部楼层
这玩意儿做出来,能打断点?能单步调试么?

出280入168汤圆

 楼主| 发表于 2021-4-22 16:57:20 | 显示全部楼层
widesoft2 发表于 2021-4-22 16:47
这玩意儿做出来,能打断点?能单步调试么?

就是为这个目的做的 debuger,目前的性能太弱了,若后期加上系统信息的报告后,能跑到 10K+ 主频的模拟 51 就算不错了 ...

但我的目标是 1.2MHz 主频,所以还需要多多的努力,不然就没有太大的实用价值。

出0入0汤圆

发表于 2021-4-22 17:09:57 | 显示全部楼层
GD不是有零等待Flash么,那个肯定快。

出280入168汤圆

 楼主| 发表于 2021-4-22 17:16:55 来自手机 | 显示全部楼层
zhiwei 发表于 2021-4-22 17:09
GD不是有零等待Flash么,那个肯定快。

不可能的……

出0入0汤圆

发表于 2021-4-22 17:19:16 | 显示全部楼层
赶脚这个需求用FPGA去实现才是正招啊,做到全速模拟无压力。

出280入168汤圆

 楼主| 发表于 2021-4-22 17:30:15 来自手机 | 显示全部楼层
jathenal 发表于 2021-4-22 17:19
赶脚这个需求用FPGA去实现才是正招啊,做到全速模拟无压力。

主要是 debuger 需要模拟器运作时的实时信息数据,这在 fpga 上实现太艰难了,咋传送模拟系统中的用户指定的数据组呢?

若在 FPGA 中又要弄一个 CPU 来跑系统就多余了,所以才尽力想用 MCU 来实现。

出0入0汤圆

发表于 2021-4-22 17:41:24 | 显示全部楼层
chunjiu 发表于 2021-4-22 17:30
主要是 debuger 需要模拟器运作时的实时信息数据,这在 fpga 上实现太艰难了,咋传送模拟系统中的用户指 ...

如果只是访问内存区域(用户指定的数组或结构体最终会被debbuger转换为内存地址+长度),在FPGA中定义一个总线主设备就可以了;比如Altera(Intel)的FPGA,用Avalon-MM Master挂一个Uart,就可以通过串口(使用定义好的帧格式)访问任意地址的内存区块了。

出0入0汤圆

发表于 2021-4-22 17:49:09 | 显示全部楼层
外挂RAM,主程序在RAM执行

出280入168汤圆

 楼主| 发表于 2021-4-22 17:57:15 来自手机 | 显示全部楼层
jathenal 发表于 2021-4-22 17:41
如果只是访问内存区域(用户指定的数组或结构体最终会被debbuger转换为内存地址+长度),在FPGA中定义一个 ...

我在尝试用以太网或 USB 传输调试数据,尽量做到不产生大的延时,所以一个简单的接口实现不了这个愿望。它涉及到了 OS 和驱动程序,所以才使用高端的 MCU 来尝试。

出280入168汤圆

 楼主| 发表于 2021-4-22 17:57:56 来自手机 | 显示全部楼层
not_at_all 发表于 2021-4-22 17:49
外挂RAM,主程序在RAM执行

这样更慢……

出10入18汤圆

发表于 2021-4-22 18:09:48 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 17:57
这样更慢……

FPGA+STM32  

出280入168汤圆

 楼主| 发表于 2021-4-22 18:15:30 来自手机 | 显示全部楼层
qtechzdh 发表于 2021-4-22 18:09
FPGA+STM32

这是最后一步,表示的确无路可走了 ……

出0入4汤圆

发表于 2021-4-22 18:24:11 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 18:15
这是最后一步,表示的确无路可走了 ……

请参考伟福,希望你做出来再开源,那就赞一个

出0入8汤圆

发表于 2021-4-22 18:31:07 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 18:15
这是最后一步,表示的确无路可走了 ……

在这之前,你还可以尝试一下jit

出0入0汤圆

发表于 2021-4-22 18:33:55 | 显示全部楼层
zhanyanqiang 发表于 2021-4-22 18:24
请参考伟福,希望你做出来再开源,那就赞一个

也可以卖钱呀,程序里加个虚拟机,破解就困难多了

出280入168汤圆

 楼主| 发表于 2021-4-22 18:54:33 | 显示全部楼层
zhanyanqiang 发表于 2021-4-22 18:24
请参考伟福,希望你做出来再开源,那就赞一个

我一个人无法完成全部的工作量,所以若项目后期能延续下去的话肯定需要其他兄弟们的加入。

现在为避免集体走弯路白费力气,所以要先自己将所有的事情理顺了,验证架构上的设计没大问题才行。

如果证实了最终实现的性能不靠谱、或没有太大的实用价值也许就中途放弃了,免得浪费别人的时间和精力。


无条件开源是不太靠谱的,在目前的环境下不现实,起码这件事要等验证过了确实可行才会考虑后期的安排。

若真的有缘分和机会和大伙儿合作将是我的荣幸,我的处世哲学是希望参与进来贡献的兄弟们都不要白白出力气。

做事只有共赢才是上策,其它形式不用太多考虑。

出280入168汤圆

 楼主| 发表于 2021-4-22 18:56:32 | 显示全部楼层
canspider 发表于 2021-4-22 18:31
在这之前,你还可以尝试一下jit

考虑过,这是倒数第二的选择,在无路可走的情况下 ...

出280入168汤圆

 楼主| 发表于 2021-4-22 19:00:47 | 显示全部楼层
myxiaonia 发表于 2021-4-22 18:33
也可以卖钱呀,程序里加个虚拟机,破解就困难多了

不用卖钱,我考虑过如果能成功的话,也许需要一个共赢的商业模式来造福广大的学弟学妹们 ...

十几岁时在南京的三山街上,红着脸和柜台妹子赊一个 7805 被婉拒后的情形至今历历在目!

已经过去了三十多年了哈 ...

出10入18汤圆

发表于 2021-4-22 19:22:59 | 显示全部楼层
chunjiu 发表于 2021-4-22 19:00
不用卖钱,我考虑过如果能成功的话,也许需要一个共赢的商业模式来造福广大的学弟学妹们 ...

十几岁时 ...

当时妹子想的是:先要电话号码的话,免费给你都行。

出0入0汤圆

发表于 2021-4-22 19:25:25 | 显示全部楼层
51又不是买不到了,为什么要模拟51

出280入168汤圆

 楼主| 发表于 2021-4-22 19:29:24 | 显示全部楼层
本帖最后由 chunjiu 于 2021-4-22 19:30 编辑
qtechzdh 发表于 2021-4-22 19:22
当时妹子想的是:先要电话号码的话,免费给你都行。


不是吹牛,年轻时经常有妹子故意贴过来,在图书馆和书店、还有公车上都遇到过,只不过那年头太单纯,不解风情 ... 瞪人家妹子,害得妹子们红着脸跑掉 !

出280入168汤圆

 楼主| 发表于 2021-4-22 19:31:24 | 显示全部楼层
modbus 发表于 2021-4-22 19:25
51又不是买不到了,为什么要模拟51

为了验证很多构思是否可行,而 51 是最容易验证的。

出300入477汤圆

发表于 2021-4-22 19:34:26 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 18:56
考虑过,这是倒数第二的选择,在无路可走的情况下 ...

jit都很难做的,因为51指令集不是专门设计为方便jit的。
比如切换四组寄存器的操作你就不好模拟,然后它的SP啊PC啊都是有地址的,可以被隐含使用也可以当普通的SFR来操作。所以这些操作都很难被jit

出300入477汤圆

发表于 2021-4-22 19:37:28 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 19:31
为了验证很多构思是否可行,而 51 是最容易验证的。

51一点也不好验证。随便一个RISC的处理器都好验证的多。51的体系结构很混乱,cpu核心和那些SFR是强制绑在一起的。纯软的仿真还行,但高速的jit非常难,你非常难做到兼容所有的奇怪写法

出280入168汤圆

 楼主| 发表于 2021-4-22 19:40:01 | 显示全部楼层
redroof 发表于 2021-4-22 19:34
jit都很难做的,因为51指令集不是专门设计为方便jit的。
比如切换四组寄存器的操作你就不好模拟,然后它 ...

目前影响执行效率的也是同样的问题,正在想办法解决。

若单纯的只想从提高主机速度来实现不可能,因为目前的差距太大了,不是靠提升一点性能和优化优化就可以解决。

现在要重新构思整体的执行框架,看看能不能突破性的解决性能问题。

出280入168汤圆

 楼主| 发表于 2021-4-22 19:43:24 | 显示全部楼层
redroof 发表于 2021-4-22 19:37
51一点也不好验证。随便一个RISC的处理器都好验证的多。51的体系结构很混乱,cpu核心和那些SFR是强制绑在 ...

我说的好验证是指在结果上没有歧义,因为 51 的资料和开发工具都非常齐全。

其他的 CPU 就不太好凑齐这些东西了,整的结果上若有歧义,就无法验证结果是否完全正确。

出300入477汤圆

发表于 2021-4-22 19:52:18 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 19:40
目前影响执行效率的也是同样的问题,正在想办法解决。

若单纯的只想从提高主机速度来实现不可能,因为目 ...

估计你没什么好办法了,只能纯解释。看看解释器的代码还有什么好优化的吧,或者用arm汇编来写解释器的核心,这样可以用寄存器来当那些关键的解释器变量

出280入168汤圆

 楼主| 发表于 2021-4-22 19:57:13 | 显示全部楼层
redroof 发表于 2021-4-22 19:52
估计你没什么好办法了,只能纯解释。看看解释器的代码还有什么好优化的吧,或者用arm汇编来写解释器的核 ...

是的呀,目前正在统计 51 寄存器的访问频率,就是想找到瓶颈点,而 cortex-m 的寄存器也就那么几个,没办法可劲的使。

出300入477汤圆

发表于 2021-4-22 20:02:55 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 19:57
是的呀,目前正在统计 51 寄存器的访问频率,就是想找到瓶颈点,而 cortex-m 的寄存器也就那么几个,没办 ...

我说的是用寄存器当解释器内部的当前指令指针,堆栈指针,全局内存指针之类的。
被仿真的51里面的寄存器基本没法当你的寄存器变量,因为人家程序可以从SFR区来读写它,这种别名太多了不好处理。

出300入477汤圆

发表于 2021-4-22 20:08:51 来自手机 | 显示全部楼层
本帖最后由 redroof 于 2021-4-22 20:12 编辑
redroof 发表于 2021-4-22 20:02
我说的是用寄存器当解释器内部的当前指令指针,堆栈指针,全局内存指针之类的。
被仿真的51里面的寄存器 ...


或者你用两阶段解释,第一次解释得到中间代码,再执行上次得到的中间代码。
第一次解释主要处理那些坑人的寄存器别名,识别岀操作那些特殊寄存器的操作,然后普通操作都可以jit了。普通的算术逻辑和内存读写操作都非常容易直接对应到ARM的相同操作。

出280入168汤圆

 楼主| 发表于 2021-4-22 20:12:26 | 显示全部楼层
redroof 发表于 2021-4-22 20:02
我说的是用寄存器当解释器内部的当前指令指针,堆栈指针,全局内存指针之类的。
被仿真的51里面的寄存器 ...

我当前也是在研究这种复杂性。

例如在每个系统周期的开始时,要检查各个中断寄存器中的状态位的,

而我准备将这些状态位全部单独抽出来,集中到一个 cortex-m 寄存器中,

这样就可以避免多次访问不同的变量和跳转,在一个小循环内就能解决判定问题。

这种操作模式应该有利于 ART 架构,但是增加了编程的复杂性 ...

对 SFR 的操作就要将这些状态 bit 重新编码进行访问,很容易出 bug。

出300入477汤圆

发表于 2021-4-22 20:15:24 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 20:12
我当前也是在研究这种复杂性。

例如在每个系统周期的开始时,要检查各个中断寄存器中的状态位的,

用两遍式的解释就行了,第一遍识别岀需要特殊处理的sfr,第二遍就能简化很多操作

出280入168汤圆

 楼主| 发表于 2021-4-22 20:21:37 | 显示全部楼层
redroof 发表于 2021-4-22 20:15
用两遍式的解释就行了,第一遍识别岀需要特殊处理的sfr,第二遍就能简化很多操作 ...

那个方法和我目前构思中的一种实现形式很相似,不过不是为了 jit,而是为了减少 if 的使用量.

主要是想避免不明确的跳转,让代码尽量做到顺序化,就是针对 STM32 的 ART 特性做特殊处理。

出300入477汤圆

发表于 2021-4-22 21:15:27 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 20:21
那个方法和我目前构思中的一种实现形式很相似,不过不是为了 jit,而是为了减少 if 的使用量.

主要是想 ...

高性能的解释器都是解释中间代码的。先把原程序变成中间代码,再解释执行中间代码。这样用10倍主频来实时模拟还是有希望的。
每条中间代码可以比较长,比如32位甚至更长,这样可以包括足够多的信息。

出280入168汤圆

 楼主| 发表于 2021-4-22 21:27:13 来自手机 | 显示全部楼层
redroof 发表于 2021-4-22 21:15
高性能的解释器都是解释中间代码的。先把原程序变成中间代码,再解释执行中间代码。这样用10倍主频来实时 ...

模拟器还需要插入断点和提供用户实时编辑指令和数据的能力,用 jit 实现就不太好办,因为那需要额外的大量工作。

所以我才说,那是走投无路后的倒数第二号选择,毕竟比最后一步用 FPGA 实现起来还是简单不少。

出300入477汤圆

发表于 2021-4-22 21:29:50 来自手机 | 显示全部楼层
canspider 发表于 2021-4-22 18:31
在这之前,你还可以尝试一下jit

先把原来的51机器码转换为某种中间代码,再解释执行中间代码,也是个可行的方法。比jit简单一些,性能也低一些,但至少比直接解释51机器码可以快的多。这样比jit简单在于不用熟悉ARM的机器码和各种细节,可以是纯C程序

出300入477汤圆

发表于 2021-4-22 21:32:43 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 21:27
模拟器还需要插入断点和提供用户实时编辑指令和数据的能力,用 jit 实现就不太好办,因为那需要额外的大 ...

jit就彻底没法实时编辑指令了,但如果是解释中间代码,那么还是可以实时编辑的,并且可以双向对应。一条51指令一定对应一条中间代码就行

出280入168汤圆

 楼主| 发表于 2021-4-22 22:05:01 来自手机 | 显示全部楼层
redroof 发表于 2021-4-22 21:32
jit就彻底没法实时编辑指令了,但如果是解释中间代码,那么还是可以实时编辑的,并且可以双向对应。一条5 ...

这个构思可以借鉴到当前的框架构造中,的确会比强行解释执行要明确的多。它减少了不可预测性,优化代码就比较直观简单。

出300入477汤圆

发表于 2021-4-22 22:19:21 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-22 22:05
这个构思可以借鉴到当前的框架构造中,的确会比强行解释执行要明确的多。它减少了不可预测性,优化代码就 ...

我说了这就是高性能解释器的典型做法啊。大家都这么干。
连很多cpu内部都是这样的,最常见的例子就是x86

出280入168汤圆

 楼主| 发表于 2021-4-22 22:42:35 来自手机 | 显示全部楼层
redroof 发表于 2021-4-22 22:19
我说了这就是高性能解释器的典型做法啊。大家都这么干。
连很多cpu内部都是这样的,最常见的例子就是x86 ...

嗯,是个好办法!

出75入90汤圆

发表于 2021-4-22 22:43:42 | 显示全部楼层
chunjiu 发表于 2021-4-22 19:00
不用卖钱,我考虑过如果能成功的话,也许需要一个共赢的商业模式来造福广大的学弟学妹们 ...

十几岁时 ...

我十来岁去买pF级的瓷片电容,被两个站柜台的阿姨嘲笑说小孩子来批什么发。也是三十年过去,现在都还记得。

出280入168汤圆

 楼主| 发表于 2021-4-23 00:09:18 来自手机 | 显示全部楼层
本帖最后由 chunjiu 于 2021-4-23 00:12 编辑
redroof 发表于 2021-4-22 22:19
我说了这就是高性能解释器的典型做法啊。大家都这么干。
连很多cpu内部都是这样的,最常见的例子就是x86 ...


这个方法帮我理顺了思路,原先的想法是构思出一种使用链表来实现直接跳转,然后执行一个明确命令段的操作,那样就可以免除解释一条51指令所消耗的大量判断时间。

但初期毛估估出的链表体积太庞大了,如何做才是最合理的,并塞进有限的 RAM 中这些细节还没想好呢,实际操作起来难度挺大的。

若使用中间码来过渡,那就好处理多了。感谢兄弟的帮助。

出140入158汤圆

发表于 2021-4-23 01:01:17 来自手机 | 显示全部楼层
chunjiu 发表于 2021-4-23 00:09
这个方法帮我理顺了思路,原先的想法是构思出一种使用链表来实现直接跳转,然后执行一个明确命令段的操作 ...

哥,难道您还没用函数指针查表吗?

出0入34汤圆

发表于 2021-4-23 01:07:23 | 显示全部楼层
看这 chunjiu 兄这阵子玩得咋高兴的,怎不考虑再换颗效能更高些的芯片?我推荐就直接上 Cortex-A 系列吧!呵呵~

出280入168汤圆

 楼主| 发表于 2021-4-23 06:50:30 来自手机 | 显示全部楼层
amigenius 发表于 2021-4-23 01:01
哥,难道您还没用函数指针查表吗?

光一个函数表不行,真的全部拆分开有好多个表,太巨大了。而且51的 SFR 寻址机制太复杂,很难理清楚。

出280入168汤圆

 楼主| 发表于 2021-4-23 06:52:10 来自手机 | 显示全部楼层
xyz543 发表于 2021-4-23 01:07
看这 chunjiu 兄这阵子玩得咋高兴的,怎不考虑再换颗效能更高些的芯片?我推荐就直接上 Cortex-A 系列吧! ...

已经在计划中了,若 STM32 通通验证失败,那我的香橙派就要用上了。

出0入0汤圆

发表于 2021-4-23 08:43:41 | 显示全部楼层
chunjiu 发表于 2021-4-22 17:57
我在尝试用以太网或 USB 传输调试数据,尽量做到不产生大的延时,所以一个简单的接口实现不了这个愿望。 ...

看来确实是个大工程。综合上面的讨论,提供一个想法:既然调试过程无法离开PC,能否将模拟器直接在PC端实现、只是将I/O映射放在嵌入式端呢,这样就彻底消除了性能瓶颈,也无需考虑调试数据的传输问题了。

出0入4汤圆

发表于 2021-4-23 08:46:45 | 显示全部楼层
楼主加油, 我也做了好长时间的虚拟机和编译器, 不过, 我的虚拟机都是使用自家的指令, 所以就没有了51的那种条条框框.
我采用的是 AVR的寄存器方案+ARM的指令框架+x86的函数寻址方式.

出280入168汤圆

 楼主| 发表于 2021-4-23 09:01:13 | 显示全部楼层
jathenal 发表于 2021-4-23 08:43
看来确实是个大工程。综合上面的讨论,提供一个想法:既然调试过程无法离开PC,能否将模拟器直接在PC端实 ...

还需要有个加载后脱机运行的功能,所以目前仍然努力做各种 STM32 的尝试,最后在无可奈何的情况下还包括用树莓派或香橙派来做,但它们需要外拖电源,体积比较大,用起来不太方便。

出280入168汤圆

 楼主| 发表于 2021-4-23 09:03:35 | 显示全部楼层
aleyn 发表于 2021-4-23 08:46
楼主加油, 我也做了好长时间的虚拟机和编译器, 不过, 我的虚拟机都是使用自家的指令, 所以就没有了51的那种 ...

谢谢兄弟的鼓励,在这次尝试中又深入了很多过去未曾探究过的程度,所以收获良多,甚慰   

出140入158汤圆

发表于 2021-4-23 10:34:13 | 显示全部楼层
chunjiu 发表于 2021-4-23 06:50
光一个函数表不行,真的全部拆分开有好多个表,太巨大了。而且51的 SFR 寻址机制太复杂,很难理清楚。 ...

51的汇编俺2000年时研究过,也编写过不少程序,好像很简单吧,具体怎么样现在也忘记了。我写过最长的汇编是用中颖的4位机写全功能冷暖空调遥控器,项目时间只有两周,刚开始两天很恶心,后面架构建立起来后,慢慢得心应手。
俺觉得,模拟器对指令的解析应该用这种架构:
void (*instruction)[255](void)={
nop,
mov,
movx,
movxxxx,
jmp,
....
}

void nop(void){
.....
}

void mov(void){
.....
}

然后每个时钟节拍,先轮询判断IE那些什么的全局寄存器变量、外设寄存器。然后确定是否跳转中断,置响应的外设寄存器。然后再改写PC,SP,查指令表跳转对应指令函数。。。。。。
感觉上,51的模拟器应该很简单。H7对付起来毫无压力吧。。。。
当然我是乱说一通的,做起来肯定有很多细节是有一定难度的。。。。不过架构非常重要。。。

出300入477汤圆

发表于 2021-4-23 10:36:12 | 显示全部楼层
aleyn 发表于 2021-4-23 08:46
楼主加油, 我也做了好长时间的虚拟机和编译器, 不过, 我的虚拟机都是使用自家的指令, 所以就没有了51的那种 ...

是的,专门设计为方便解释的中间代码,就应该是RISC风格。这样执行起来效率才会高
51那样设计并不方便

出280入168汤圆

 楼主| 发表于 2021-4-23 10:44:51 | 显示全部楼层
本帖最后由 chunjiu 于 2021-4-23 10:49 编辑
amigenius 发表于 2021-4-23 10:34
51的汇编俺2000年时研究过,也编写过不少程序,好像很简单吧,具体怎么样现在也忘记了。我写过最长的汇编 ...


谢谢兄弟的探讨,之前的初版架构就是这么设计的。在 PC 机上实现没问题,因为 X86 现在够强悍,但 STM32 还不行,原因已经找到并在一楼上说明了。

STM32 的弱项是 FLASH 载入指令太慢,任何一个未命中的判断都会让 CPU 进入 30MHz 的主频状态,而不是标称的 168MHz,并且无法实现单指令周期,也就是说执行效率比 30MHz 还要差。

所以我现在的研究重点是如何减少判断。其他兄弟也提供了很多有用的信息,但不同的实现方式都有自己的优缺点,我需要很多尝试来融合它们,并找到平衡点。

出300入477汤圆

发表于 2021-4-23 10:58:33 | 显示全部楼层
本帖最后由 redroof 于 2021-4-23 11:02 编辑
chunjiu 发表于 2021-4-23 06:50
光一个函数表不行,真的全部拆分开有好多个表,太巨大了。而且51的 SFR 寻址机制太复杂,很难理清楚。 ...


其实你要是不在乎内存,SFR也好办,大不了就给SFR的位地址和字地址各建一个指令跳转表呗。反正也就128个地址,4种操作:读位,读字节,写位,写字节
这样就可以直接解释了,不用预编译了。
比如读PSW字节,不管你实际的标志位在哪里,反正这个仿真函数负责从各处搜集各种标志位变成所需的PSW寄存器返回
当然这个时候预编译还是有好处的,你可以看到某一条指令后面的指令有没有使用某些标志位,如果没使用就不需要生成该标志位。比如半进位标志,奇偶标志什么的,其实你在ARM上还不好生成它。即使是好生成的进位标志什么的,你在C里面也不好拿到ARM CPU自带的那一份。

出280入168汤圆

 楼主| 发表于 2021-4-23 11:04:02 | 显示全部楼层
redroof 发表于 2021-4-23 10:58
其实你要是不在乎内存,SFR也好办,大不了就给SFR的位地址和字地址各建一个指令跳转表呗。反正也就128个 ...

哈哈,就是之前在构思中的方案啊,但是表太大了,所以头疼怎么优化后塞进有限的 cache 或 TCM  内。

所以中间码可能是个很棒的方案,但还要考虑实时修改指令和数据的对策,正在构思中。

出280入168汤圆

 楼主| 发表于 2021-4-23 11:11:58 | 显示全部楼层
redroof 发表于 2021-4-23 10:58
其实你要是不在乎内存,SFR也好办,大不了就给SFR的位地址和字地址各建一个指令跳转表呗。反正也就128个 ...


因为 STM32 的 ART 架构适应顺序执行指令,但千万千万要避开非明确跳转(if 框架),

所以如何用计算方式快速的实现一个跳转表是突破性的关键。

出300入477汤圆

发表于 2021-4-23 11:18:06 | 显示全部楼层
本帖最后由 redroof 于 2021-4-23 11:23 编辑
chunjiu 发表于 2021-4-23 11:11
因为 STM32 的 ART 架构适应顺序执行指令,但千万千万要避开跳转(if 框架),

所以如何用计算方式快速 ...


除非JIT,否则无法避开跳转,因为解释器读取每条指令之后必须跳转到该指令的处理函数,不管是函数指针还是switch/case都一样
用函数比switch/case的开销要大一点,但是函数看起来更清晰。
其实节约仿真标志位倒是很重要的。
执行每条指令本身,大部分情况下就是一行C代码而已,但是更新各个标志位得好多行代码。所以如果后面的指令不需要用到标志位,前面就不用生成标志位了。

设计成用于优化解释执行的指令集都是这样,只有少数特定的指令(测试或者比较之类)会改变标志位,其它指令都不改变标志位。或者干脆没有标志位,比较指令的结果直接放到结果寄存器。
硬件执行每条指令都更新标志位是无代价的,软件这么做的代价就很高

出280入168汤圆

 楼主| 发表于 2021-4-23 11:36:50 | 显示全部楼层
redroof 发表于 2021-4-23 11:18
除非JIT,否则无法避开跳转,因为解释器读取每条指令之后必须跳转到该指令的处理函数,不管是函数指针还 ...

我先在统计各寄存器的标志位访问权重,为的就是在运行速度和编程难度上找平衡。

出0入115汤圆

发表于 2021-4-23 12:14:01 来自手机 | 显示全部楼层
还不如用fpga做软核

出280入168汤圆

 楼主| 发表于 2021-4-23 12:24:00 | 显示全部楼层
三年模拟 发表于 2021-4-23 12:14
还不如用fpga做软核

那要抛开其他的所有事情了,现状不允许啊

出0入0汤圆

发表于 2021-4-23 14:00:59 | 显示全部楼层
我之前也做过类似的,运行在51里面的51软核

出0入362汤圆

发表于 2021-4-23 19:25:56 | 显示全部楼层

怎么不可能,GD是用RAM给FLASH做了镜像。
试试GD,我把GD32F350和GD32FFPR超频到280M了。

出0入362汤圆

发表于 2021-4-23 19:27:38 | 显示全部楼层
chunjiu 发表于 2021-4-22 16:26
正在草拟新的代码框架,准备使用 CCM。因为 STM32F429 上的 CCM 不和指令总线挂钩,所以又重新买了两块板 ...

对了, 有不少用stm32模拟6502的项目,比如这个
https://github.com/BigEd/stm6502

参考参考?

出300入477汤圆

发表于 2021-4-23 20:18:22 | 显示全部楼层
tomzbj 发表于 2021-4-23 19:27
对了, 有不少用stm32模拟6502的项目,比如这个
https://github.com/BigEd/stm6502

6502的结构就比8051好仿真一些。没有那么多的跟核心寄存器混在一起的sfr

出105入79汤圆

发表于 2021-4-23 20:40:12 | 显示全部楼层
香橙派不够, 直接x86 电脑吧 , 还不用额外上电,方便. 所有内存都看得一清二楚

出280入168汤圆

 楼主| 发表于 2021-4-24 08:49:51 | 显示全部楼层
tomzbj 发表于 2021-4-23 19:25
怎么不可能,GD是用RAM给FLASH做了镜像。
试试GD,我把GD32F350和GD32FFPR超频到280M了。 ...

看了兄弟的测试,原来 GD32 有这种骚操作 ... 等我测完了 STM32H 再去试试 GD32。

另外 6502 就简单多了,仿真起来没那么难。

我是玩 6502 出身的,用它可以直接 jit 了,指令和寄存器都可以直接替代来跑 ...

即 100% 的 arm 原速,168MHz 的 6502。

出280入168汤圆

 楼主| 发表于 2021-4-24 08:52:37 | 显示全部楼层
qwe2231695 发表于 2021-4-23 20:40
香橙派不够, 直接x86 电脑吧 , 还不用额外上电,方便. 所有内存都看得一清二楚 ...

香橙派肯定够用了,如果这还不够快肯定是代码框架有问题。

现在的派都是 4 核的,只要跑多线程就不怕 SFR 的变态寻址了。

出0入91汤圆

发表于 2021-4-24 09:03:18 | 显示全部楼层
STM32 有64K 以上的RAM。   51就只要几K 的ram 和rom 就够了
为什么不把代码优化成  程序加载后 把所有数据都载入到ram 呢,这样整个系统跑起来就很欢快了呀

出280入168汤圆

 楼主| 发表于 2021-4-24 09:21:24 | 显示全部楼层
ackyee 发表于 2021-4-24 09:03
STM32 有64K 以上的RAM。   51就只要几K 的ram 和rom 就够了
为什么不把代码优化成  程序加载后 把所有数据 ...

cortex-m 体系结构不是想象的那么回事儿,如果深入了解就会理解了。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-5-5 07:30

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

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