【问题标题】:How to convert a code in Assembly language to C code? [closed]如何将汇编语言中的代码转换为 C 代码? [关闭]
【发布时间】:2016-12-19 07:24:36
【问题描述】:

我有汇编代码,我想在 c 中转换为等效代码
加法但我想如果它只是简单的加法所以需要提前帮助和thnx:

Flash_Check_SUM:

 clr ZH
 clr ZL
 clr XH
 clr XL 

FCK_1: 

lpm R1,z+
add XL,R1 
brcc FCK_2
inc XH   ;carry set so inc Hi Bit

FCK_2:

cpi ZH,HIGH(BSTART*2 -16) 
brne FCK_1 
cpi ZL,LOW(BSTART*2 -16) 
brne FCK_1

lpm R0,Z+ 
lpm R1,Z 
cp R0,XH 
brne CK_Fail 
cp R1,XL 
brne CK_Fail 
ret
CK_Fail:

【问题讨论】:

  • 使用adc XH 代替inc 上的那个分支不是更容易吗?无论如何,您不会说您无法理解其中的哪一部分,并且 asm 中没有 cmets。准确解释每条指令的作用以及为什么完整的详细信息需要太长时间,因此投票结束时过于宽泛。
  • 坦率地说,我无法理解汇编,但我知道那部分是关于通过加法完成的校验和,所以我想确保它是正常的加法@peter cordes
  • @PeterCordes 不,adc不会工作。该代码将单个字节添加为 16 位。必须有一条指令,如“将立即数添加到带有进位的字节”才能将 0 添加到带有进位的 XH,但没有。
  • 看起来这个函数将字节 ptr [0] 与字节 ptr [BSTART*2 -18] 相加并将总和与字 ptr [BSTART*2 -16] 进行比较?
  • @UncleO:哦,我现在明白了,谢谢。 x86 有一个 adc-immediate,但我猜如果你在循环中这样做,AVR 可以使用一个归零的寄存器。我猜 AVR 中的分支非常便宜,但由于这个添加发生在循环内,可能值得在循环外清除一个额外的寄存器,因为 adc is always only 1 cycle

标签: assembly avr


【解决方案1】:

将其转换为 C 代码并不能回答您的实际问题。对程序集正在做什么的描述会更有帮助。

X 和 Z 寄存器实际上是两个寄存器,所以它们是两个字节长。一些指令使用 Z 寄存器作为输入的地址。这就是这段代码中发生的事情。

函数从地址 0 开始,逐字节添加到 16 位 X 寄存器中

lpm R1,z+  ; load the byte at address Z into R1 and post-increment Z
add XL,R1  ; Add R1 to X

如果低字节溢出,则有一些代码可以增加 X 的高字节(通常的加法算法)。

循环一直持续到 Z 到达 BSTART*2 -16,这似乎是校验和之前的所有字节。

最后一部分将存储的校验和加载到 R0 和 R1 中,然后将其与代码刚刚在 X(XH 和 XL)中计算的校验和进行比较。

如果校验和失败,则代码跳过返回语句并继续执行校验和函数后面的代码,这可能向用户表明某种错误情况。

【讨论】:

    【解决方案2】:

    应该是这样的:

    typedef union {
        unsigned short u16;
        unsigned char u8[2];
    } Pointer;
    
    const Pointer BSTART = ???;
    
    int Flash_Check_SUM( Pointer Z, Pointer X ){
    
        unsigned char XH = ((unsigned char *)&X)[0];
        unsigned char XL = ((unsigned char *)&X)[1];
        unsigned char ZH = ((unsigned char *)&Z)[0];
        unsigned char ZL = ((unsigned char *)&Z)[1];
    
    AddZ:
        unsigned short R1 = *Z++;
        X += *R1;
        if( XH > 0 ) goto IsEqual;
        XH++;
    
    IsEqual:
        if( ZH != ((unsigned char *)&(BSTART * 2 - 16))[0] ) goto AddZ;
        if( ZL != ((unsigned char *)&(BSTART * 2 - 16))[1] ) goto AddZ;
        unsigned short R0 = *Z++;
        R1 = *Z;
        if( R0 != XH ) return -1;
        if( R1 != XL ) return -1;
        return 0;
    }
    

    【讨论】:

    • 一些问题:1) 为什么在加起来时要取消引用 R1? 2) goto IsEqual 有什么用? 3) 你不能直接比较(256*ZH+ZL)(BStart*2-16) 吗?
    • @Tommylee2k 1)我假设寄存器被建模为指针,2)我遗漏了我添加的一行代码,3)我试图或多或少地翻译代码而不使各种C 中可能的简化。
    • with 1) 你没有把 Z 点的内存加起来。我会用这个简单的循环替换 asm 函数:int CSUM(char * Z ) { unsigned short sum=0; do { sum += *Z++; } while ( Z != BSTART*2-16 ); return (*Z++==(sum/256) && *Z==(sum%255)); }