如何在SuperH汇编中多次分支?

huangapple go评论40阅读模式
英文:

How to branch multiple times in SuperH assembly?

问题

我编写了一个SuperH汇编子例程,用于将像素绘制到屏幕:

r3: x坐标

r4: y坐标

r5: 像素颜色

draw_pixel:
mov.l frame_buffer_address, r0
mov.l screen_width, r6
mul.l r6, r4
sts macl, r4
add r4, r3
add r3, r0

mov r5, r1
mov.b r1, @r0

rts
nop


然后,我可以从我的程序中分支到这个子例程:

mov #20, r3
mov #50, r4
mov #10, r5
bsr draw_pixel
nop


这完全正常运行,我可以多次使用不同的参数执行它,一切正常。

当我尝试从另一个子例程中分支到draw_pixel时,出现了问题(我想要绘制一个矩形,但现在只是绘制一个像素,直到它正确运行)。

draw_rect:
mov #50, r3
mov #20, r4
mov #4, r5
bsr draw_pixel
nop

rts
nop


然后,我尝试从我的程序中使用以下方式调用它:

bsr draw_rect
nop


这不起作用。我怀疑这与从draw_rect分支到draw_pixel有关,因为代码与之前可行的代码相同,唯一改变的是混合中的附加子例程/分支。

我觉得在进行嵌套分支时需要考虑额外的事情,但不确定具体是什么。或者可能我在这里犯了不同的错误。

另请注意,我只是为了测试而使用立即值,一旦它正常工作,我将使用变量。

编辑:

解决方法是在分支到draw_pixel之前保存pr:

sts pr, r9


然后,在从draw_rect返回之前恢复pr:

lds r9, pr

英文:

I wrote a SuperH assembly subroutine that draws a pixel to the screen:

# r3: x coord
# r4: y coord
# r5: pixel color
draw_pixel:
  mov.l frame_buffer_address, r0
  mov.l screen_width, r6
  mul.l r6, r4
  sts macl, r4
  add r4, r3
  add r3, r0

  mov r5, r1
  mov.b r1, @r0 

  rts 
  nop 

I can then branch from my program with:

  mov #20, r3
  mov #50, r4
  mov #10, r5
  bsr draw_pixel
  nop 

This works perfectly, and I can do it multiple times with different parameters, it all works.

I start to run into trouble when I try to branch to draw_pixel from another subroutine. (I want to draw a rectangle but for now I am just drawing a single pixel until it works correctly)

draw_rect:
  mov #50, r3
  mov #20, r4
  mov #4, r5
  bsr draw_pixel
  nop

  rts
  nop

Which I try to call from my program with:

  bsr draw_rect
  nop

This does not work. I suspect it has something to do with branching to draw_rect to draw_pixel, since the code is identical as the code that worked, the only thing that has changed is just an additional subroutine / branch in the mix.

I feel like there is something extra I need to consider when doing nested branching, but not exactly sure what that would be. Or perhaps there is a different sort of mistake I'm making here.

Also please note I'm using immediate values just for testing, I'll use variables once I get it working.

Edit:

The solution is to save pr before branching to draw_pixel:

sts pr, r9

and then restore pr before returning from draw_rect:

lds r9, pr

答案1

得分: 3

根据手册bsr 指令执行以下操作:

> 延迟分支,PC + 4 → PR,
disp × 2 + PC + 4 → PC

换句话说,它首先将返回地址保存在过程寄存器(PR)中,然后将程序计数器(PC)设置为过程的地址。

等效地,rts 指令执行:

> 延迟分支,PR → PC

也就是说,它恢复了之前由 bsr 保存的程序计数器的值。

问题在于:第一次使用 bsr 指令(bsr draw_rect)时,处理器将下一条指令的地址保存在 PR 中,以便知道如何从过程返回。然后再次使用 bsrbsr draw_pixel)时,它会再次保存。因此,您实际上丢失了原始的 PR 值。

draw_pixel 返回时,它将返回到 bsr draw_pixel 后的 nop,如预期的那样。然而,当 draw_rect 返回时,它也将返回到相同的位置,因为那是 PR 指向的地方。

为了解决这个问题,您需要将 PR 值保存在其他地方(另一个寄存器或堆栈中),然后在返回之前恢复它。

英文:

According to the manual the bsr instruction performs the following operations:

> Delayed branch, PC + 4 → PR,
disp × 2 + PC + 4 → PC

In other words, it first saves the return address in the procedure register (PR), then sets the program counter (PC) to the address of the procedure.

Equivalently, the rts instruction does:

> Delayed branch, PR → PC

That is, it restores the program counter value that was previously saved by bsr.

Here's the problem: the first time you use the bsr instruction (bsr draw_rect), the processor saves the address of the next instruction in PR, so it knows how to return from the procedure. Then you use bsr again (bsr draw_pixel) and it does that again. So you're effectively losing the original value of PR.

When draw_pixel returns, it will return to the nop after bsr draw_pixel, as expected. However, when draw_rect returns, it will also return to the same place, since that's where PR points to.

To solve that, you need to save PR somewhere else (another register or the stack), then restore it before returning.

huangapple
  • 本文由 发表于 2023年2月16日 06:19:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465960.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定