6

我需要优化代码为一些新代码腾出空间。我没有空间进行所有更改。我不能使用代码库切换(80c31 和 64k)。

4

7 回答 7

10

您在这里并没有真正做太多事情,但是您可以考虑两个主要级别的优化:

微优化: 例如。XOR A 而不是 MOV A,0 Adam 之前已经很好地介绍了其中的一些。

宏观优化: 查看程序的结构、使用的数据结构和算法、执行的任务,并认真思考如何重新安排甚至删除这些。是否存在实际上没有使用的整块代码?您的代码是否充满了用户从未见过的调试输出语句?是否有特定于单个客户的功能可以在一般版本中省略?

为了很好地处理这个问题,你需要弄清楚你的内存在哪里被用完。Linker map 是一个很好的起点。宏观优化是大获全胜的地方。

顺便说一句,您可以 - 认真地 - 尝试使用一个良好的优化 C 编译器重写部分代码。您可能会惊讶于代码的紧凑程度。一个真正的汇编能手可能会改进它,但它很容易比大多数编码器更好。大约 20 年前,我使用了IAR ,它让我大吃一惊。

于 2008-12-02T22:02:54.703 回答
7

使用汇编语言,您必须手动进行优化。这里有一些技巧:

注意:IANA8051P(我不是 8501 程序员,但我在其他 8 位芯片上做了很多组装)。

通过代码寻找任何重复的位,无论多么小,并使它们起作用。

学习一些更不寻常的指令,看看你是否可以使用它们来优化,例如。一个很好的技巧是使用 XOR A 来清除累加器而不是 MOV A,0 - 它节省了一个字节。

另一个巧妙的技巧是,如果您在返回之前调用一个函数,只需跳转到它,例如,而不是:

CALL otherfunc
RET

做就是了:

JMP otherfunc

始终确保尽可能进行相对跳转和分支,它们比绝对跳转使用更少的内存。

这就是我暂时能想到的。

于 2008-12-02T21:50:04.683 回答
7

对不起,我来晚了,但我曾经遇到过完全相同的问题,它变成了一个反复出现的问题,不断地回到我身边。就我而言,该项目是一部电话,在 8051 系列处理器上,我已经完全用尽了 ROM(代码)内存。它不断地回到我身边,因为管理层不断要求新功能,所以每个新功能都变成了一个两步过程。1)优化旧东西腾出空间 2)实现新功能,用完我刚刚腾出的房间。

有两种优化方法。战术和战略。战术优化使用微优化思想一次节省几个字节。我认为您需要进行战略优化,这涉及对您的做事方式进行更彻底的重新思考。

我记得的东西对我有用,也可以为你工作;

看看你的代码必须做什么的本质,并尝试提炼出一些非常强大的灵活的原始操作。然后重建您的顶级代码,以便它除了调用原语之外根本不做任何低级代码。理想情况下使用基于表格的方法,您的表格包含以下内容;输入状态、事件、输出状态、原语.... 换句话说,当事件发生时,在表中查找当前状态下该事件的单元格。该单元格告诉您要更改为(可选)什么新状态以及要执行什么原语(如果有)。对于不同的层/子系统,您可能需要多组状态/事件/表/基元。

这种方法的许多好处之一是您可以将其视为为您的特定问题构建自定义语言,您可以通过修改表非常有效地(即使用最少的额外代码)创建新功能。

对不起,我迟到了几个月,你可能没有时间做这么激进的事情。据我所知,您已经在使用类似的方法!但我的回答有一天可能会帮助其他知道的人。

于 2009-02-27T22:00:05.847 回答
4

在被淘汰的部门中,您还可以考虑压缩部分代码,只保留在任何特定时间点被积极使用的部分解压缩。我很难相信压缩/解压缩系统所需的代码在 8051 的微小内存中足够小,足以让这变得有价值,但在稍大的系统上却创造了奇迹。

另一种方法是转向字节码格式或某些状态机工具输出的表格驱动代码——让机器了解您的应用程序正在做什么并生成一个完全难以理解的实现可能是一种很好的保存方式房间 :)

最后,如果代码确实是用 C 编译的,我建议使用一系列不同的选项进行编译,看看会发生什么。此外,我在 2001 年为 ESC 写了一篇关于紧凑型 C 编码的文章,该文章仍然很流行。有关小型机器的其他技巧,请参阅该文本。

于 2008-12-09T19:32:42.177 回答
2

1) 尽可能将变量保存在 Idata 而不是 xdata
2) 查看您的 Jmp 语句 – 使用 SJmp 和 AJmp

于 2008-12-02T22:03:49.053 回答
2

我假设您知道它不适合,因为您编写/遵守并得到“内存不足”错误。:) 看来答案非常准确地解决了您的问题;缺少代码示例。

然而,我会推荐一些额外的想法;

  1. 确保所有代码都真正 被使用——代码覆盖测试?一个未使用的子是一个巨大的胜利——这是一个艰难的步骤——如果你是原作者,它可能更容易——(嗯,也许):)
  2. 确保“验证”和初始化的水平——有时我们倾向于过分热心地确保我们已经初始化了变量/内存,而且确实如此,我们被它咬了多少次。不是说不要初始化(duh),但是如果我们正在执行内存移动,则不需要首先将目标归零——这与

    1 --

  3. 评估新功能——是否可以增强现有的子功能以涵盖这两个功能或替换现有功能?
  4. 如果一段大代码可以节省创建新的小代码,则分解大代码。

或者现在桌面上可能存在硬件版本 2.0 的争论...... :)

问候

于 2008-12-03T19:33:00.433 回答
2

除了已经提到的(或多或少)明显的优化之外,还有一个非常奇怪(几乎不可能实现)的优化:代码重用。对于代码重用,我并不是指正常的重用,而是a)将您的代码重用为数据或b)将您的代码重用为其他代码。也许您可以创建一个 lut(或任何静态数据),它可以由 asm 十六进制操作码表示(在这里您必须查看哈佛与冯诺依曼架构)。

另一个将通过在您处理不同的代码时赋予代码不同的含义来重用代码。这里有一个例子来说明我的意思。如果代码的字节如下所示:地址 X 处的 AABCCCDDEEFFGGHH,其中每个字母代表一个操作码,假设您现在将跳转到 X+1。也许你会得到一个完全不同的功能,现在由空格分隔的字节形成新的操作码:ABC CCD DE EF GH。

但请注意:这不仅难以实现(也许不可能),而且难以维持。因此,如果您不是演示代码(或类似的外来代码),我建议您使用已经提到的其他方法来保存 mem。

于 2008-12-04T05:56:51.533 回答