在我的ATtiny 84 a AVR汇编程序中,我在一个寄存器中得到了一个0到7之间的位数,比如r16。现在我需要创建一个设置了该位数的掩码。为了使它更复杂,操作的时序必须相同,而不管设置了哪个位。
例如,如果r16 = 5,则结果掩码将为0x 20(第5位设置)。
到目前为止,我已经将一个位移位了LSL,并使用r16(位数)作为循环计数器,然后为了保持准确的时序(无论位数如何),执行了NOP8-r16次的虚拟循环。
汇编指令SBR根据掩码设置寄存器中的位,因此无法使用。汇编指令SBI根据位号设置I/O寄存器中的位,但它是常量,而不是寄存器(我可以将I/O寄存器用作临时寄存器)。
然后使用掩码清除存储器位置中的位,因此如果有另一种解决方案可以从寄存器中的位数执行此操作,那么也可以。
我有另一个解决方案来尝试(基于移位的进位),但我希望有人有一个比循环和移位更优雅的解决方案。
6条答案
按热度按时间bwitn5fc1#
我认为你的移位和进位的直觉是一个很好的解决方案,你基本上会递减索引寄存器,当递减量为零时设置进位,然后将进位移位到输出寄存器。
您可以使用
subtract
来执行递减,当索引命中0时,它将自动设置进位位。您可以使用rotate right 来代替shift,因为这可以让您向右移动位以匹配decement。
然后,您可以非常巧妙地在输出中使用一个sentinel位作为伪循环计数器,在8次循环迭代后终止。
比如说...
我数4字(8字节)的存储和24个周期,这对所有的AVR操作,所以我认为赢家的大小,令人惊讶的(甚至对我来说!)击败了强大的领域的查找表为基础的条目。
还具有对脱离键合条件的合理处理,除输入和输出外,没有其他寄存器发生变化。重复旋转还有助于防止ALU移位器门中的存款。
非常感谢@ReAI和@PeterCordes,他们的指导和灵感使这段代码成为可能!:)
vfh0ocws2#
9个字,9个周期
dgsult0t3#
由于你的输出只有8个变量,你可以使用一个查找表。它将做完全相同的操作,无论输入是什么,因此有完全相同的执行时间。
w1jd8yoj4#
8字节对齐的查找表可简化索引,适用于支持
lpm
-从程序存储器加载的AVR芯片。(根据@AterLux的答案优化)。将表对齐8意味着所有8个条目的地址的高位字节相同。低3位没有换行,因此我们可以使用ori
,而不必对subi
的地址取反。(adiw
仅适用于0..63,因此可能无法表示地址。)我展示的是最好的情况,首先你可以方便地在
r30
(Z的下半部分)中生成输入,否则你需要一个mov
。而且,这太短了,不值得调用一个函数,所以我没有展示ret
,只是一个代码片段。假设输入有效(在0..7内);如果需要忽略高位,请考虑@真实的's,或者只考虑
andi r30, 0x7
如果你可以很容易地重新加载Z,或者不需要保留它,这是很好的。如果重敲Z很糟糕,你可以考虑在初始启动时在RAM中建立表(用循环),这样你就可以使用X或Y作为指针,而不是
lpm
。或者如果你的AVR不支持lpm
。如果您可以在256字节对齐边界处找到该表,则可以删除
lo8(table)
= 0,这样您就可以删除ori
,而直接将r30
用作地址的低位字节。成本为
ori
版本,不包括重新加载Z
之后的内容,或者更糟糕的保存/恢复Z
。(如果Z在你需要的时候很宝贵,考虑一个不同的策略)。在的循环中,如果您需要相同的256 B程序内存块中的其他数据,则
ldi r31, hi8
只能提升/完成一次。如果你能将表对齐256,那么就节省了一个字的代码和一个周期的时间。如果你也将
ldi
从循环中提升出来,那么就只剩下3个周期的lpm
了。(未经测试,除了
clang -target avr
,我没有AVR工具链。我认为GAS / clang只需要普通的符号引用,并在内部处理symbol * 2
。这确实可以成功地与clang -c -target avr -mmcu=atmega128 shl.s
组装,但反汇编.o会导致llvm-objdump -d
10.0.0崩溃。)du7egjpx5#
谢谢大家的创造性的答案,但我去与查找表作为一个宏。我发现这是最灵活的解决方案,因为我可以很容易地有不同的查找表为各种目的在一个固定的7个周期。
空间不是问题,但速度是问题。然而,我认为这是一个很好的妥协,我不被迫对齐四字上的数据。7对5周期是要付出的代价。
我已经有一个“零”寄存器保留通过整个程序,所以它的成本我没有额外的做16位加法。
wbrvyc0a6#
在7条指令/ 7个节拍中,也可以不使用查找表。输出必须在高位寄存器中。寄存器压力较低,不需要宝贵的Z寄存器,也不需要包含零的寄存器:
对于右移
R22 = 0x80 >> (R11 & 7)
或对于补码R22 = 0xff ^ (1 << (R11 & 7))
,这可以容易地进行调整。如果移位偏移量已经在R30中,则从查找表加载的版本可以少1个指令,并且不需要包含零的寄存器: