caihong001 发表于 2012-6-20 10:04:12

AVR汇编跳转超范围的解决办法以及某些不明的地方求助

目前有一个AVR的汇编例程,BIN文件有8.5K,所用芯片型号是M88

程序编译后,出现诸多错误,超一百个了,但都是同一个问题,“realtive branch out of reach”即跳转超范围了。

查看了一下程序,大多出现在rcall指令上, 这个也是用的最多,函数间的调用。

在网上查,有人见意取消跳转超范围检测选项,不过这样做编译虽然不报错,但全出现在警告上,所以仍旧未解决本质上的问题。

因为手头上的例程还是比较多,我又查看了一个完整无误的例程,上面处理跳转超范围的方法是这样的:

比如:
L0001:   //0001
......
.             //00AB   
......
L00FF:   //00ff
......
L0CDF:    //0cdf
......
Lxxxx后的注解表示该语句所在的位置,说是地址也一样。那如果L0001中要调用L0CDF,假设两函数的地址已经超出跳转范围了,所以如果
直接在L0001中用rcallL0CDF的话,那编译肯定要出现“realtive branch out of reach”的报错了,解决的正解方法可以这样:
(假定调用L0CDF所在的位置是00AB)
原来语名句是:rcall   L0CDF   改成.dw0XDC33 或者 .dw0XCC33   就可解决
那么这个数是怎么算来的呢,细心的朋友可能已经猜测到,
其实就是    (目标位置-实际位置-1)+0xD000或0xC000      =》(0x0CDF-0x00AB-1)+0XD000或0xC000=0XDC33或0xCC33.
至于到底是加0XD000还是0XC000,这样看前面有没有重复的值,如果说有两个调用算得差值都一样,一个加0XD000,一个加0XC000,以错开。

于是我将程序报错的地方都这样修改过后,果然好了。 而且仿真时我尝试着修改0XD000和0XC000,发现其它值都不行,不能跳转到指定函数的位置。

所以我的疑问也出来了,虽然现在是乎知道怎么改,却不明白为什么这样。还望高人指点!!!

HYLG 发表于 2012-6-20 10:27:59

RCALL前面的R去掉不就行了。

caihong001 发表于 2012-6-20 14:17:47

HYLG 发表于 2012-6-20 10:27 static/image/common/back.gif
RCALL前面的R去掉不就行了。

谢谢你,不过按照你的方法改,仍旧会出点问题
将rcall改call后,编译通过,但在运行到call 处时,会弹出一对话框显示

黄点AVR Simualtor:Unsupported instruction 'call' at address0x000xxx

这是什么原因呢?

caihong001 发表于 2012-6-20 14:36:42

HYLG 发表于 2012-6-20 10:27 static/image/common/back.gif
RCALL前面的R去掉不就行了。

好像M88不支CALL这条指令

HYLG 发表于 2012-6-20 15:57:07

不好意思,没试过随口说的。一直以为M48不支持CALL,M88支持。
刚试了下CALL只能在M168下不报错。M48,M88都报不支持。

HYLG 发表于 2012-6-20 16:16:43

本帖最后由 HYLG 于 2012-6-20 16:27 编辑

看了下RCALL指令的介绍。
RCALL
相对调用PC - 2K + 1 到 PC + 2K (字)范围内的子程序。返回地址(RCALL后面那条指令的地址)保存到堆栈当中。 (相关参考:CALL). 在汇编程序中,标号作为相对调用的操作数。对于程序存储器不超过4K字(8K字节)的AVR芯片,这条指令可以寻址整个程序存储器空间。在调用RCALL指令时,堆栈指针是带后减量的(调用完成后减少)。

按这个介绍RCALL在M48可以在整个程序中正常使用,在M88只能在程序的最中间(4K字节)才能调用前面或后面的子程序,否则在1K的位置调用7K的子程序或者反之肯定有问题了。

还是头回碰到并且思考这个问题。
楼主的解决方法有点类似 ICALL指令。

caihong001 发表于 2012-6-20 18:25:26

HYLG 发表于 2012-6-20 16:16 static/image/common/back.gif
看了下RCALL指令的介绍。
RCALL
相对调用PC - 2K + 1 到 PC + 2K (字)范围内的子程序。返回地址(RCALL后面 ...

恩,现在虽然说那样可以解决,但一直不明白其中的道理,网上资料也甚少。

其实那样做还有个不好的地方,就是会将程序的语句全部固定死,假若要修改程序,增加或减少一条都会影响后面每条语句的地址,
编译时看不出什么问题,但程序在执行跳转时就会跳错位置

不知道前辈们是如何解决这些问题的

HYLG 发表于 2012-6-20 18:49:58

高手没出现之前给楼主的建议。
M48够用用48不够就用168。

eblc1388 发表于 2012-6-20 19:26:46

本帖最后由 eblc1388 于 2012-6-20 19:39 编辑

>> M88只能在程序的最中间(4K字节)才能调用前面或后面的子程序,否则在1K的位置调用7K的子程序或者反之肯定有问题了。

这样理解不对。

Mega88 有 4K字,而 RCALL 可在目前地址跳至 +2K字或 -2K字的地址,即能反跳超越地址0, 所以能在 4K 地址中跳到 4K 中的任何地址。

eblc1388 发表于 2012-6-20 20:44:26

>> 直接在L0001中用rcallL0CDF的话,那编译肯定要出现“realtive branch out of reach”的报错了

编译完全正常, 没有楼主的报错。

HYLG 发表于 2012-6-21 10:36:34

我又理解错了。谢谢楼上的讲解。

caihong001 发表于 2012-6-22 10:53:00

eblc1388 发表于 2012-6-20 20:44 static/image/common/back.gif
>> 直接在L0001中用rcallL0CDF的话,那编译肯定要出现“realtive branch out of reach”的报错了

编译完 ...

eble1388可是高人啊,样样都懂,但我这仍有疑问,因为这里我只是举了个简单的例子而已,
但在我实际的这个程序中函数的调用可不止一个啊!
我这一编译出现了一百多处跳转超范围的报错,那我这样修改不是很麻烦吗?

eblc1388 发表于 2012-6-22 14:43:17

>> 我这一编译出现了一百多处跳转超范围的报错,那我这样修改不是很麻烦吗?

我以上回复不是已给你清楚说明了 M88 内用 rcall根本不会出现跳转超范围的报错吗?

你采用 rcall 时报错一定是由不当编译设置引起的,AVRASM 是 2.1.42 或更新版本吗?

caihong001 发表于 2012-6-22 17:11:31

eblc1388 发表于 2012-6-22 14:43 static/image/common/back.gif
>> 我这一编译出现了一百多处跳转超范围的报错,那我这样修改不是很麻烦吗?

我以上回复不是已给你清楚说 ...

我现用的是AVR studio 2.1.12,难怪!!太感谢你了,我再下个最新的试试!

caihong001 发表于 2012-6-28 14:20:32

eblc1388 发表于 2012-6-20 19:26 static/image/common/back.gif
>> M88只能在程序的最中间(4K字节)才能调用前面或后面的子程序,否则在1K的位置调用7K的子程序或者反之肯 ...

这里得更正一下哦,M88是8K,我用2.1.42仍旧会提示超范围,后来用stuio 6就可以了

eblc1388 发表于 2012-6-28 15:49:41

◆ 这里得更正一下哦,M88是8K

M88 是 8K字节, 4K 字(每字 16bit), 为什么要更正? {:huffy:}

◆ 我用2.1.42仍旧会提示超范围

人品问题。你看看我在【10楼】用的 AVRASM 是什么。
页: [1]
查看完整版本: AVR汇编跳转超范围的解决办法以及某些不明的地方求助