我正在用68000 汇编实现排序算法,并决定使用堆栈将参数传递给交换数组中两个元素的子例程。我想确保正确高效地处理堆栈。
具体来说,在调用SWAP_SUB
子程序之前,我使用 将两个元素的地址推送到堆栈pea.l
,然后使用 的偏移量在子程序内部检索它们A7
。
完整代码如下:
ORG $8000
START:
moveq.l #len-1,d7
OUTER_LOOP:
lea.l array,a0
moveq.l #len-2,d6
INNER_LOOP:
move.b (a0)+,d2
cmp.b (a0),d2
blt.s DO_SWAP
NO_SWAP:
subq.l #1,d6
bge.s INNER_LOOP
subq.l #1,d7
bge.s OUTER_LOOP
SIMHALT
DO_SWAP:
pea.l (a0)
pea.l -1(a0)
bsr.s SWAP_SUB
addq.l #8,a7
bra.s NO_SWAP
SWAP_SUB:
movem.l d3-d4,-(a7) ;new line
move.l 4(a7),a0
move.l 8(a7),a1
move.b (a0),d3
move.b (a1),d4
lsl.w #8,d3
or.w d4,d3
rol.w #8,d3
move.w d3,d5
lsr.w #8,d5
move.b d5,(a0)
andi.w #$00FF,d3
move.b d3,(a1)
movem.l (a7)+,d3-d4 ;new line
rts
array DC.B 5,3,8,1,7
len EQU 5
END START
问题:
- 我是否正确使用堆栈传递参数?我的方法是否存在任何潜在问题?
- 向子程序传递参数时,是否有设置堆栈的通用方法?
- 这段代码能以任何方式简化吗?
堆栈方面很好。清理工作已到位。而且您真的可以随心所欲地传递参数。无论是在寄存器中,还是按您喜欢的顺序推送到堆栈上,寄存器和堆栈的混合,或者甚至通过传递单个地址将调用方引导到包含实际参数的内存块(Atari 上的 GEM 就是这样做的)。选择权在您手中。
有人可能会大叫:你开玩笑呢!
为什么要为这么简单的任务使用那么多指令(并破坏那么多寄存器)?
为什么你一直使用一个离开循环然后必须无条件
BRA
返回的结构?只需为你的写相反的条件blt.s DO_SWAP
:迭代次数过多
你为什么在这里使用
BGE
?D7 设置为 4(5-1)。外循环遍历 4、3、2、1 和 0,共 5 次,但在仅包含 5 个元素的数组中正确进行 5 次比较根本不可能!解决方案是坚持使用值得信赖的BNE
。或者,使用我刚才在回答你之前的一个问题DBNE
时详细解释的指令。(这可能无法解决冒泡排序中的所有问题)。
[编辑]
您在问题后面添加的内容试图将“寄存器保存”添加到子程序中。它不起作用,因为该指令在推送那些 D3 和 D4 寄存器的同时,还更改了 A7。因此,加载 A0 和 A1 的指令需要通过指定一个大于8 的
movem
偏移量来解决这个问题:如果您的意图是按照 Eric Eidt 的建议保留寄存器,那么列表中仍然缺少 D5。由于列表中有 3 个长字寄存器,因此原始偏移量需要增加12:
但由于子程序只改变 D3、D4 和 D5 的低位字,因此最好使用它
movem.w
来加快执行速度并减少堆栈内存消耗。那么原始偏移量只需要增加6个: