Shop OBEX P1 Docs P2 Docs Learn Events
Inline Assembly: Labels and Other Things — Parallax Forums

Inline Assembly: Labels and Other Things

SRLMSRLM Posts: 5,045
edited 2013-02-16 10:30 in Propeller 1
This is the code that I'm using as an example for this question:
int strlenASM(char * string){
	int i = 0;
	int t1;
	
	//C version:
//	for(; string[i] != '\0'; i++){
//	}

	__asm__ volatile (
		"strloop: "
		"rdbyte %[t1], %[string]\n\t"
		"cmp %[t1], #0 wz\n\t"
		"if_nz add %[i], #1\n\t"
		"if_nz add %[string], #1\n\t"
		/*"if_nz jmp #strloop"*/
		"if_nz brw #strloop"
		
	: /*outputs (+inputs) */
		[i]	     "+r" (i)
	: /*inputs */
		[string] "r" (string), [t1] "r" (t1)			
	);
	return i;
}

1) Is the label and branch above correct form? It seems to work for me in both CMM and LMM modes, but I don't know if that's just luck or it's the way it's done.

1.5) Also, is the label guaranteed to be unique, or can it collide? I think I can answer this one by looking at the generated .s file (with -save-temps). It appears that any inline ASM labels are, in fact, global.

2) If the code above has the correct jumping scheme, what about DJNZ? Is there a corollary? I also see that there is BRS and BRW. Is one preferred over the other?

3) What about GAS local labels? They are of the form 1:, so a jump would be
jmp #1
But that conflicts with literal constants. Is that a jump to address 1, or label 1:? I know that PropGCC doesn't support local labels of the form ":label:", but is this different?
Reference:
http://stackoverflow.com/questions/3898435/labels-in-gcc-inline-assembly

4) Is it possible to call a C/C++ function from assembly? From this page (link, section 5.1.2) I see it's possible to give a function an ASM name. So, is there a way to call that function?

5) For inline assembly, what is the difference for LMM and CMM modes? Can I use the same ASM code for both and in all optimizations?

6) Is there a way to move this assembly into an external .S file, but still execute it as if it was "inline" (ie, not in a new cog)?

7) I'm using the variables that I declare with standard C/C++ syntax. Do I have to do anything special with their addressing? ie, where do they live: in the cog or the hub? Can I have as many as I want, and address them all the same? Continuing this line of thought, what about hub operations such as rdbyte and wrlong? Are these used?

8)Can we use char literals in the inline assembly? I tried using single quotes (ie, #'A'), but it doesn't seem to do anything.

9)Does mova vs. mov have any effect for inline assembly? This code gives the same result both ways:
 __asm__ volatile (
            "mov    %[t2], #48\n\t"
            "wrbyte %[t2], %[string]"
            
			: /*outputs (+inputs) */
				[string] "+r" (string)
			: /*inputs */
				[t2] "r" (t2)
			);

10) What are the Propeller specific inline constraints? I don't see it listed here: http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints

Thanks for any and all responses.

Comments

  • ersmithersmith Posts: 6,092
    edited 2013-02-14 08:36
    SRLM wrote: »
    1) Is the label and branch above correct form? It seems to work for me in both CMM and LMM modes, but I don't know if that's just luck or it's the way it's done.
    Yes. brw and brs are macros which expand to a branch in both LMM and CMM modes.
    1.5) Also, is the label guaranteed to be unique, or can it collide? I think I can answer this one by looking at the generated .s file (with -save-temps). It appears that any inline ASM labels are, in fact, global.
    As you note, they are global. You can make them unique for multiple invocations (e.g. if you want this in a macro used multiple places) by appending the label with %= everywhere it is used. %= expands to a unique integer in every snippet of assembly code (the same integer throughout the asm).
    2) If the code above has the correct jumping scheme, what about DJNZ? Is there a corollary? I also see that there is BRS and BRW. Is one preferred over the other?

    There is no equivalent to DJNZ in CMM or LMM mode. BRS is preferred for short branches (within +-511 bytes); in both CMM and LMM it expands to smaller code than BRW.
    3) What about GAS local labels? They are of the form 1:, so a jump would be
    jmp #1
    
    But that conflicts with literal constants. Is that a jump to address 1, or label 1:? I know that PropGCC doesn't support local labels of the form ":label:", but is this different?
    I've never really tried using GAS local labels. I'd stick with the %= form if I were you.
    4) Is it possible to call a C/C++ function from assembly? From this page (link, section 5.1.2) I see it's possible to give a function an ASM name. So, is there a way to call that function?
    Yes. By default C functions have their own name but with an underscore prepended (so to call strcpy you have to use _strcpy). The exact form of the call depends on the memory model and whether the function is declared _NATIVE or not. _NATIVE functions are always called with the call instruction. COG mode functions are called with jmpret lr,#_func. LMM mode functions are called with lcall #_func.
    5) For inline assembly, what is the difference for LMM and CMM modes? Can I use the same ASM code for both and in all optimizations?
    Generally you can, although you'll get better (smaller) code if you use the CMM macros like brw, lcall, and so on rather than calling into the kernel directly.
    6) Is there a way to move this assembly into an external .S file, but still execute it as if it was "inline" (ie, not in a new cog)?
    Sure, just declare the entry point as .global and then call it from another file.
    7) I'm using the variables that I declare with standard C/C++ syntax. Do I have to do anything special with their addressing? ie, where do they live: in the cog or the hub? Can I have as many as I want, and address them all the same? Continuing this line of thought, what about hub operations such as rdbyte and wrlong? Are these used?
    Variables are always in HUB memory unless they are declared as _COGMEM. Note though that local variables in functions are often allocated to registers (and function parameters are always in registers, at least for the first 6 parameters) so to access those from assembly you have to use the GNU inline assembly syntax. But for global and static variables just use rdlong/wrlong (for normal variables) or mov (for _COGMEM variables).
    8)Can we use char literals in the inline assembly? I tried using single quotes (ie, #'A'), but it doesn't seem to do anything.
    No, GAS doesn't understand char literals.
    9)Does mova vs. mov have any effect for inline assembly? This code gives the same result both ways:
     __asm__ volatile (
                "mov    %[t2], #48\n\t"
                "wrbyte %[t2], %[string]"
                
                : /*outputs (+inputs) */
                    [string] "+r" (string)
                : /*inputs */
                    [t2] "r" (t2)
                );
    
    For immediate constants mov and mova are the same, I think.
    10) What are the Propeller specific inline constraints? I don't see it listed here: http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints

    The Propeller port hasn't been integrated into official GCC releases yet. The PDF from http://code.google.com/p/propgcc does have some Propeller specific documentation. For constraints it says:
    Propeller—‘config/propeller/constraints.md’
    C A variable which has been placed in cog memory. This may usually
    be used anywhere one of the predefined registers (the ‘r’ constraint)
    may be used.
    I An unsigned integer that fits in 9 bits
    M A constant whose complement fits in 9 bits, that is a value in the
    range −512 to −1
    N A constant whose negative fits in 9 bits, that is a value in the range
    −511 to 0
    W A wide integer, one whose representation does not fit in 9 bits
    Note that the W constraint doesn't actually work properly, and does not match anything (it isn't used in the propeller machine description, so we didn't notice it until recently).

    Thanks for the good questions,
    Eric
  • SRLMSRLM Posts: 5,045
    edited 2013-02-16 10:30
    Thanks for your detailed reply! It really helps clear up some of the inline PASM points.

    As a side note, I really like inline PASM. Before I started, I was bothered by the syntax (the really archaic notation and the "\n\t" on each line), and the lack of documentation in general. But, after spending a few days working on it, inline PASM has turned out to be a cool feature.
Sign In or Register to comment.