如果我想在 8051 程序集中创建一个有限状态机,我需要一个有效的 C switch()
表达式等价物。
[对于这个问题,让我们忽略掉线行为,保留和丢弃它都是可以接受的]。
在 8051 汇编中有几种方法可以实现这一点,但每种方法都有其缺点。用于5-10个案例的简短切换的操作足够简单,也足够清楚,但是如果我希望切换> 128,甚至> 256个案例,事情就会变得复杂。
第一个很简单,一串 CJNE
将操作数与值进行比较,如果不相等则跳转到下一个案例;相当于 if(){...}else if(){....} else if(){...}
。优点是简单,缺点是明显的:在长时间切换的情况下,这将产生很长的选择串。
这可以通过构建二叉树来减少,对控制变量的连续位使用 JB
。这仍然不是很有效,很难维护并且使得稀疏键集难以实现(`case 1:...; case 5:...; case 23:...; case 118:...)
下一个方法是相乘,然后跳转偏移。将控制变量乘以 2,将结果加载到 DPTR,加载带有偏移量的累加器,然后在预加载了大量 JMP @A+DPTR
的区域中执行 AJMP
。 (或乘以 3 并跳转到预加载了大量 LJMP
的区域。)。
我做过一次。将跳转指令的位置调整为字节是一个我不想重复的难题,而且跳转表不必要地大(每个字节重复 ajmp
)。也许我不知道一些能让事情变得简单的技巧......
还有一种方法是从专用表中提取地址,预加载堆栈并执行 RET
。这听起来很简洁,除了需要使用可怕的 MOVC A, @A+DPTR
或 MOV A, @A+PC
从专用表中提取地址之外,这些寻址模式让我很难受,我从未尝试过实现它。如果您知道这样做的巧妙方法,请将其发布为答案。
一般来说,我想知道是否有一种更优雅、更有效的方式来执行 switch() 风格的跳转——一种不会产生太多开销,不会浪费太多内存,并且可以自由跳转至少 AJMP
距离,数字的case
数以百计。
最佳答案
我的第二个答案是另一个你可能不喜欢的答案。
不要在汇编中写这种东西!你希望达到什么目标?老年?
状态机(可能用于 lexical analysis ?)正是 generated code 的用途。生成的代码几乎没有错误,而且更容易维护。有很好的免费 tools available 。代码生成器的输出通常是漂亮、方便的 C。您将 C 提供给编译器。猜猜看,编译器知道您问题的答案。一个好的编译器会知道如何制作最有效的 switch 语句,它会继续执行它,而不会浪费你数周的时间来调试它。
另一件很棒的事情是,有一天,当您认为 8051 对您来说不够强大时,您可以轻松地迁移到更强大的架构,而无需从头开始完全重写和调试整个状态机!另外,您的余生都不会是 stuck working with 8051s。
添加:
由于这不是词法分析,我建议您使用状态机编译器,例如 Ragel 。您只需向它提供状态机的描述,它就会生成您的状态机 C 代码。
或者,尝试 logic grid 方法。
关于assembly - 如何在 8051 程序集中编写高效的 switch()?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24128915/