这篇文章的目的不是要从HEX文件中拿出明亮的C代码,而是要建立关于该主题的扎实知识。我知道编译器在执行其工作时可能会使我自己的工作更加困难,但是为了使CPU能够执行代码,需要遵循某种结构(也许是原始结构)。
因此,我坐在办公桌上并编写了一个Python小工具以帮助我进行此过程。它加载了HEX文件,并且我可以交互地向其中添加信息。这是到目前为止我得到的:
HEX文件的第一行说:
: 02 0000 04 0000 FA
该工具可以执行以下操作:
: --> MARK
02 --> RECORD LENGTH
0000 --> LOAD OFFSET
04 --> RECORD TYPE (EXTENDED LINEAR ADDRESS RECORD)
0000 --> DATA
FA --> CHECKSUM
这行似乎是建议告诉代码应放置的初始地址为
0x0000
的提议。其次,下一行显示:
: 20 0000 00 34C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50C07EEE7EB9 51
该工具将其解码为:
: --> MARK
20 --> LENGHT OF THE RECORD
0000 --> OFFSET
00 --> RECORD TYPE (00 -> DATA RECORD) 34C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50C07EEE7EB9 (ACTUAL DATA)
51 --> CHECKSUM
在这里有趣,问题开始了。
我在任何地方都找不到ATTiny45的内存映射。我认为它应该在数据表或说明手册中的某处。据我所知,在
0x0000
处存在中断向量(数据表第49页),第一个是复位向量。因此,AVR为低位字节序,指令为16位宽,因此我可以解码出复位向量包含值0xC034
。使用指令集,我发现0xC034
是:rjump 0x034
这是正确的吗?
继续这种思路,前面指出的同一行表明某些中断向量的值
0xFFFF
,这使我感到惊讶,但似乎没有问题,因为可能会禁用它们。具有工作值的唯一其他向量是USI_OVF_ISR
,它等于0xC050
。因此,根据之前提出的想法,这表示USI_OVF_ISR
具有以下说明:rjump 0x050
这是否还正确?
如果复位向量指向
0x034
,则表示程序将从0x034
开始运行。下一行: 20 0020 00 7FE77FB9B89A089570EE7EB95FB9B89A08957EEE7EB9B898089570EE7EB9B898 22
显示
0x034
是0xB898
,这是将要执行的第一条指令。这是正确的吗?
#1 楼
似乎几乎是正确的,因为数据手册在第8.1章“复位AVR”中进行了说明: –相对
跳转–复位处理例程的指令
然而,第202页-指令集摘要-像这样解释
RJMP
: br /> 这暗示着地址
RJMP
处的PC=0
与k=0x34
跳到了地址0x35
。,数据表似乎没有操作码表来确认
C0
是确实是一个RJMP
。第5.1章还说
ATtiny25 / 45/85包含2/4 / 8K字节片内输入-System可重编程闪存,用于存储程序。由于所有AVR指令的宽度均为16或32位,因此Flash的格式为1024/2048/4096 x16。
,第9章显示了表格(第48页)其中包含
RJMP
指令的示例,这些指令虽然需要2个字节,但每个都打包到一个地址中。从偏移量0开始,并使用15个复位矢量(每个复位矢量均为16位宽),程序从地址0x0F
开始。因此,地址空间似乎每个地址分为16位块,而不是8位字节,这意味着您必须将地址加倍才能在十六进制数组中获得适当的字节索引。对我来说似乎不正确,因为PC是
0D
(在十六进制字节中偏移1A
)和r=50
,所以RJMP
应该跳到0D+50+1
= 5E
或在十六进制字节中偏移BC
(2*0x5E
)。该地址表示16位字,然后从操作码选项卡中添加+1
,您可能应该查看0x35*2=0x6A
以查找要执行的第一条指令。