【发布时间】:2010-09-25 00:47:42
【问题描述】:
我需要优化代码以便为一些新代码腾出空间。我没有空间进行所有更改。我不能使用代码库切换(80c31 和 64k)。
【问题讨论】:
标签: optimization assembly embedded intel 8051
我需要优化代码以便为一些新代码腾出空间。我没有空间进行所有更改。我不能使用代码库切换(80c31 和 64k)。
【问题讨论】:
标签: optimization assembly embedded intel 8051
您在这里并没有真正做太多事情,但是您可以考虑两个主要级别的优化:
微优化: 例如。 XOR A 而不是 MOV A,0 Adam 之前已经很好地介绍了其中的一些内容。
宏观优化: 查看程序的结构、使用的数据结构和算法、执行的任务,并认真思考如何重新排列甚至删除这些内容。是否存在实际上没有使用的整块代码?您的代码是否充满了用户从未见过的调试输出语句?是否有特定于单个客户的功能可以在一般版本中省略?
要很好地处理这个问题,您需要找出内存在哪里被用完。 Linker map 是一个很好的起点。宏观优化是大获全胜的地方。
顺便说一句,您可以 - 认真地 - 尝试使用优化的 C 编译器重写部分代码。您可能会惊讶于代码的紧凑程度。一个真正的汇编能手可能会改进它,但它很容易比大多数编码器更好。大约 20 年前,我使用了 IAR 一个,它让我大吃一惊。
【讨论】:
使用汇编语言,您必须手动进行优化。以下是一些技巧:
注意:IANA8051P(我不是 8501 程序员,但我在其他 8 位芯片上做了很多组装)。
通过代码寻找任何重复的位,无论多小,并使它们起作用。
了解一些比较不寻常的指令,看看是否可以使用它们进行优化,例如。一个不错的技巧是使用 XOR A 来清除累加器而不是 MOV A,0 - 它节省了一个字节。
另一个巧妙的技巧是,如果您在返回之前调用一个函数,只需跳转到它,例如,而不是:
CALL otherfunc
RET
只要做:
JMP otherfunc
始终确保尽可能进行相对跳转和分支,它们使用的内存比绝对跳转少。
这就是我暂时能想到的。
【讨论】:
PrImm: POP DPH / POP DPL / CALL PrintMsg / INC DPTR / PUSH DPL / PUSH DPH / RET 的内容可能很有用。每次调用 Primm 只需要 3 个字节加上要输出的实际字符。
对不起,我来晚了,但我曾经遇到过完全相同的问题,它变成了一个反复出现的问题,不断地回到我身边。就我而言,该项目是一部电话,在 8051 系列处理器上,我已经完全用尽了 ROM(代码)内存。它不断地回到我身边,因为管理层不断要求新功能,所以每个新功能都变成了一个两步过程。 1)优化旧东西腾出空间 2)实现新功能,用完我刚刚腾出的空间。
有两种优化方法。战术和战略。战术优化使用微优化思想一次节省几个字节。我认为您需要进行战略优化,包括对您的工作方式进行更彻底的重新思考。
我记得的一些东西对我有用,也可以为你工作;
看看你的代码必须做什么的本质,并尝试提炼出一些非常强大的灵活的原始操作。然后重建您的顶级代码,以便它除了调用原语之外根本不做任何低级代码。理想情况下使用基于表格的方法,您的表格包含以下内容;输入状态、事件、输出状态、原语……换句话说,当事件发生时,在表中查找当前状态下的该事件的单元格。该单元格告诉您要更改为(可选)什么新状态以及要执行什么原语(如果有)。对于不同的层/子系统,您可能需要多组状态/事件/表/基元。
这种方法的许多好处之一是您可以将其视为针对您的特定问题构建自定义语言,您可以通过修改表格非常有效地(即使用最少的额外代码)创建新功能。
抱歉,我迟到了几个月,你可能没有时间做这么激进的事情。据我所知,您已经在使用类似的方法!但我的回答可能有一天会帮助其他知道的人。
【讨论】:
在被淘汰的部门中,您还可以考虑压缩部分代码,只保留在任何特定时间点被积极使用的部分解压缩。我很难相信压缩/解压缩系统所需的代码将是 8051 微小内存的一部分,足以让这变得有价值,但在稍大的系统上创造了奇迹。
另一种方法是转向字节码格式或某些状态机工具输出的那种表驱动的代码——让机器了解您的应用正在做什么并生成一个完全难以理解的实现可能是一个很好的方法节省空间的方法:)
最后,如果代码确实是用 C 编译的,我建议使用一系列不同的选项进行编译,看看会发生什么。另外,I wrote a piece on compact C coding for the ESC back in 2001 that is still pretty current. 请参阅该文本以了解小型机器的其他技巧。
【讨论】:
1) 尽可能将变量保存在 Idata 而不是 xdata
2) 查看你的 Jmp 语句——利用 SJmp 和 AJmp
【讨论】:
我假设您知道它不适合,因为您编写/遵守并得到“内存不足”错误。 :) 看来答案非常准确地解决了您的问题;缺少代码示例。
不过,我会推荐一些额外的想法;
或者现在桌面上可能有硬件版本 2.0 的争论...... :)
问候
【讨论】:
除了已经提到的(或多或少)明显的优化之外,还有一个非常奇怪(几乎不可能实现)的优化:代码重用。对于代码重用,我并不是指正常的重用,而是a)将您的代码重用为数据或b)将您的代码重用为其他代码。也许您可以创建一个 lut(或任何静态数据),它可以由 asm 十六进制操作码表示(在这里您必须查看哈佛与冯诺依曼架构)。
当你处理不同的代码时,另一个会通过赋予代码不同的含义来重用代码。这里有一个例子来说明我的意思。如果代码的字节如下所示:地址 X 处的 AABCCCDDEEFFGGHH,其中每个字母代表一个操作码,假设您现在将跳转到 X+1。也许你会得到一个完全不同的功能,现在由空格分隔的字节形成新的操作码:ABC CCD DE EF GH。
但请注意:这不仅难以实现(也许不可能),而且难以维持。因此,如果您不是演示代码(或类似的外来代码),我建议您使用已经提到的其他方法来保存内存。
【讨论】: