为字符串链表解释这个 AVR 宏

Explain this AVR macro for linked list of strings

您好,我正在使用微处理器 class 并尝试创建一个递归函数,该函数 returns 链表结构中某些字符串的长度。

我得到了这个宏可以使用,希望有人能帮助我理解它。特别是我想知道如何使用这个宏创建链表。

.set NEXT_STRING = 0x0000
.macro defstring 
    .set T = PC 
    .dw NEXT_STRING << 1 
    .set NEXT_STRING = T 
    .if strlen(@0) & 1 
    .db @0, 0
    .else 
    .db @0, 0, 0
    .endif    
.endmacro

使用方法如下:

defstring "somestring"
defstring "another"

然后假设创建了一个链表,这些字符串作为数据保存在每个节点上。

感谢任何帮助,谢谢!

下面的行声明了一个名为NEXT_STRING的汇编程序常量,其值为0。程序中任何出现NEXT_STRING的地方,都会被0替换。

.set NEXT_STRING = 0x0000

我认为 NEXT_STRING 这个名字可能会造成混淆。它实际上是指向您在程序集文件中声明的 last 字符串的指针。

此行将 T 设置为等于当前程序计数器 (PC)。这就是汇编程序正在写入的闪存中的当前位置。

.set T = PC 

下面的 .dw 指令将一个 16 位字写入闪存,并具有指定的值。这个词将存储指向列表中下一个节点的指针,所以我们将它设置为等于NEXT_STRING。位移部分可能是由于PC以字为单位计算,而AVR指针以字节为单位计算,因此在将PC值转换为指针时必须乘以2。这是实际向闪存写入任何内容的代码的第一部分。

.dw NEXT_STRING << 1

你生成的第一个指针将是一个空指针,因为NEXT_STRING是0。但是我们设置NEXT_STRING等于T,这样当你调用下一个宏时时,指针会指向flash中最后一个指针存放的地方。

.set NEXT_STRING = T 

至此,我想你可以看到正在形成一个链表。第一次调用 defstring 时,flash 中存储了一个空指针,有一天它会成为链表的末尾。然后你再次调用它,它会生成指向第一个的第二个指针。然后你再次调用它,它会生成指向第二个的第三个指针。

链接列表只有在其中有一些数据时才有用,因此宏接下来要做的是使用下面的代码添加字符串数据。写这篇文章的人决定他们希望始终以空字节结束字符串(这是 C 语言字符串的标准),并且他们还决定在字符串的长度为奇数时添加额外的填充字节,以确保 space 链表中某个节点所取的总是偶数。这称为 2-alignment 并且它可能使 AVR 更容易加载 2 字节指针。我不相信这种对齐是必要的,但如果是这样,我宁愿在宏的开头 and/or 末尾使用 .align 2 指令,而不是执行此 hack。

.if strlen(@0) & 1 
.db @0, 0
.else 
.db @0, 0, 0
.endif

旁白:这不是在 AVR 中存储字符串列表的唯一方法。您在 C 程序中看到的一种更标准的方法是将所有字符串放在一个地方,然后在另一个地方放一个指针数组。数组的长度要么是常量,要么数组可以由空指针终止。 Windows 注册表中的 REG_MULTI_SZ 数据使用的另一种选择是将字符串一个接一个地存储在内存中,没有指针,由空字节分隔,并以两个空字节结束。每种方法都为您提供了不同的 space/performance 权衡,最后一种方法不能存储空字符串。