eric 发表于 2005-12-31 23:19:48

请问马老师:用汇编写的子程序带参数的在C中如何调用?

一个问题困扰我多时,就是在C中如何把参数 int 或char 传递给汇编写的子程序。比如你的书里的通用延时子程序



delay:push r16

      push r17

del1:push r16

del2:push r16

del3:dec r16

   brne del3

   pop r16

   del r16

   brne del2

   pop r16

   dec r16

   brne del1

   pop r16

   ret

希望马老师及各位大侠不吝赐教,谢谢!

machao 发表于 2006-1-22 14:39:52

使用不同的C平台,调用的方式有些不同,并且汇编子程序要做稍微的变化,以适合C的调用以及传递参数。但总的讲,比使用KEIL(8051)要方便。



下面给出在CVAVR和ICC中的例子,这些都在它们的在线帮助中。



------------------------------------------------------

CVAVR的调用说明:

The following example shows how to access functions written in assembly language from a C program:



// function in assembler declaration

// this function will return a+b+c

#pragma warn- // this will prevent warnings

int sum_abc(int a, int b, unsigned char c) {

#asm

    ldd   r30,y+3 ;R30=LSB a

    ldd   r31,y+4 ;R31=MSB a

    ldd   r26,y+1 ;R26=LSB b

    ldd   r27,y+2 ;R27=MSB b

    add   r30,r26 ;(R31,R30)=a+b

    adc   r31,r27

    ld    r26,y   ;R26=c

    clr   r27   ;promote unsigned char c to int



    add   r30,r26 ;(R31,R30)=(R31,R30)+c

    adc   r31,r27

#endasm

}

#pragma warn+ // enable warnings



void main(void) {

int r;

// now we call the function and store the result in r

r=sum_abc(2,4,6);

}



The compiler passes function parameters using the Data Stack.

First it pushes the integer parameter a, then b, and finally the unsigned char parameter c.

On every push the Y register pair decrements by the size of the parameter (4 for long int, 2 for int, 1 for char).



For multiple byte parameters the MSB is pushed first.

As it is seen the Data Stack grows downward.

After all the functions parameters were pushed on the Data Stack, the Y register points to the last parameter c, so the function can read its value in R26 using the instruction: ld r26,y.

The b parameter was pushed before c, so it is at a higher address in the Data Stack.

The function will read it using: ldd r27,y+2 (MSB) and ldd r26,y+1 (LSB).

The MSB was pushed first, so it is at a higher address.



The a parameter was pushed before b, so it is at a higher address in the Data Stack.

The function will read it using: ldd r31,y+4 (MSB) and ldd r30,y+3 (LSB).



The functions return their values in the registers (from LSB to MSB):

    R30 for char and unsigned char

    R30, R31 for int and unsigned int

    R30, R31, R22, R23 for long and unsigned long.



So our function must return its result in the R30, R31 registers.



After the return from the function the compiler automatically generates code to reclaim the Data Stack space used by the function parameters.



The #pragma warn- compiler directive will prevent the compiler from generating a warning that the function does not return a value.

This is needed because the compiler does not know what it is done in the assembler portion of the function.





------------------------------------------------------

在ICC中比较复杂些,但使用INLINE方式汇编时还是比较方便的:

Besides writing assembly functions in assembly files, inline assembly allows you to write assembly code within your C file. (Of course, you may use assembly source files as part of your project as well.) The syntax for inline assembly is:



asm("<string>");



Multiple assembly statements can be separated by the newline character
. String concatenations can be used to specify multiple statements without using additional asm keywords. To access a C variable inside an assembly statement, use the %<name> format:



register unsigned char uc;

asm("mov %uc,R0
"

    "sleep
");



Any C variable can be referenced this way (excluding C goto labels). If you use an assembly instruction that requires a CPU register, then you must use the register storage class to force a local variable to be allocated in a CPU register.

In general, using inline assembly to reference local registers is limited in power: it is possible that no CPU registers are available if you have declared too many register variables in that function. In that case, you would get an error from the assembler. There is also no way to control allocation of register variables, so your inline instruction may fail. For example, using the ldi instruction requires the register to be one of the 16 upper registers, but there is no way to request that using inline assembly. There is also no way to reference the upper half of an integer register.



Inline assembly may be used inside or outside of a C function. The compiler indents each line of the inline assembly for readability. Unlike the AVR assembler, the ImageCraft assembler allows labels to be placed anywhere (not just at the first character of the lines in your file) so you may create assembly labels in your inline assembly code. You may get a warning on asm statements that are outside of a function. You may ignore these warnings.
页: [1]
查看完整版本: 请问马老师:用汇编写的子程序带参数的在C中如何调用?