Posting problem, more to come...
Getting working GCC inline assembly into a macro
The percent signs were replaced with the ^ character.
asm volatile ( /* _mob->message_id = (CANIDT >> 21); */ "lds ^B[msg_id], ^C[canidt]" "\n\t" "lds ^A[msg_id], ^D[canidt]" "\n\t" "andi ^B[msg_id], 0xE0" "\n\t" "lsl ^B[msg_id]" "\n\t" "rol ^A[msg_id]" "\n\t" "rol ^B[msg_id]" "\n\t" "rol ^A[msg_id]" "\n\t" "rol ^B[msg_id]" "\n\t" "rol ^A[msg_id]" "\n\t" "rol ^B[msg_id]" "\n\t" "mov ^C[msg_id], __zero_reg__" "\n\t" "mov ^D[msg_id], __zero_reg__" "\n\t" : [msg_id] "=a" (_mob->message_id) : [canidt] "n" (_SFR_MEM_ADDR(CANIDT)) );
I would like to put this already working inline assembly code into a __asm__ __volatile__ GCC macro. I don't need to keep the msg_id and canidt naming in the macro. All I need is a macro with two general purpose arguments for the "=a" and "n" constraints. I have followed all the explanations/examples/documentation I could find and every time it compiles my macro argument names as new undeclared C variables. Could someone please show me a working GCC inline assembly macro example and the corresponding macro use example with the same argument constraints as used in this inline assembly. The code works, I just cannot get any variation of the macro arguments to compile without errors. I got 32 matches on the GCC forum search, but didn't find an answer.
The _mob->message_id variable and the four CANIDT registers are 32 bits.
For a macro shouldn't this be starting with a #define foo(a,b) of some sort?
Correct. The code is working inline assembly code (except for the percent sign AVRfreaks posting replacement), not a macro. I have failed miserably to get this working code into a working macro. I wouldn't know which version of all the variations/attempts to post, so I figured someone that knows what they are doing wouldn't benefit from showing my failed macro examples. It should be a simple straight forward process to get the arguments to pass to a macro, but.....
At the bottom of this page there are examples for both C stubs and Assembler macros. http://www.cs.mun.ca/~paul/cs4723/material/atmel/avr-libc-user-manual-1.6.5/inline_asm.html
It also has a section on C stub functions, which I would think would be a better way of doing it. Make the stub function "static inline" and you avoid the function call overhead (and still avoid the hassles and dangers of a macro).
Been there done that. I did notice the define eol continuation backwards slashes were not continued through one example macro argument list and completely missing in another example. Even changing that didn't help when rewriting it for my inline code. Although the obvious example syntax errors raises the question if these are really working examples or not. I used Google to dredge up several other documentation resources that also were not helpful for the macro problem. This one:
http://www.ibiblio.org/gferg/ldp...
enlightened me to the "n" constraint which is missing from the other cookbook document. All the documentation I have found is sparse, very abbreviated and much of it is not specific to WINAVR (for inline assembly macros). The WINAVR specific stuff like the cookbook you found with what appears to be errors and omissions is suspect. The official GCC documentation told me everything I didn't need to know about compilation options/settings, but I didn't find any useful inline assembly information.
Edit:
Using a C stub call would defeat some of the cycles that are saved by the inline assembly. I only want to use micros to pretty up the source code, which gets messy when filled up with multiple instances of duplicate or almost duplicate (sometimes with different arguments) inline code.
How about showing an example macro you tried that doesn't work.
The point is I have not found any working examples of how to do this. I certainly proved I don't know. I'm not asking anyone to rewrite my already working code into a macro, just a correct example of an inline assembly macro define and its use, one that has the same constraints as my working inline assembly code example.
Just writing the original code showed me how critical the constraints are. The cookbook uses "I" (_SFR_IO_ADDR(port)) for its examples. First I had to find _SFR_MEM_ADDR to get a usable CANIDT value that wasn't 0x20 too low, that was real easy. But the "I" constraint works with IN/OUT register addresses, not these LDS/STS register addresses. I was stuck and couldn't get it to compile at all until I found additional documentation that revealed the "n" constraint. I don't know what the problem is, but it could be allot of things, it could just be me. Specific WINAVR inline assembly isn't that hard, except for the poor quality scattered documentation.
Does anyone know the correct way to do this? A simple working example?
Using a C stub call would defeat some of the cycles that are saved by the inline assembly.
Can you try this using:
_mob->message_id = MyMacro;
#define MyMacro ( {uint32_t tmp; asm volatile ( /* _mob->message_id = (CANIDT >> 21); */ \ "lds ^B[msg_id], ^C[canidt]" "\n\t" \ "lds ^A[msg_id], ^D[canidt]" "\n\t" \ "andi ^B[msg_id], 0xE0" "\n\t" \ "lsl ^B[msg_id]" "\n\t" \ "rol ^A[msg_id]" "\n\t" \ "rol ^B[msg_id]" "\n\t" \ "rol ^A[msg_id]" "\n\t" \ "rol ^B[msg_id]" "\n\t" \ "rol ^A[msg_id]" "\n\t" \ "rol ^B[msg_id]" "\n\t" \ "mov ^C[msg_id], __zero_reg__" "\n\t" \ "mov ^D[msg_id], __zero_reg__" "\n\t" \ : [msg_id] "=a" (tmp) \ : [canidt] "n" (_SFR_MEM_ADDR(CANIDT))); tmp;})
OK. Here's an example-
#define MYMACRO(val1,val2) \ __asm__ __volatile__( \ "lds %B0,%C1" "\n\t" \ "rol %B0" "\n\t" \ "sts %A1,%C0" "\n\t" \ : "=a" (val1) : "n" (val2) \ ) uint32_t test; MYMACRO(test,&PORTB);
It works. If you look at the lss listing, the right offsets are being used (ABC). I just threw those in for kicks. I don't know what the a/n constraints are, but in this case, no complaints.
Also notice &PORTB is a mem address in c, which is what is needed for the lds/sts.
curtvm,
Thank you very much. I found the problem.
This doesn't work: MYMACRO (val1,val2) This works: MYMACRO(val1,val2)
The big difference is without thinking I put a space between the macro name and the opening parenthesis. The compiler totally chokes and errors out on the version with the space. Of course the compiler error messages give no obvious clue to the real problem. BTW, how did you get those percent signs in your post?
CirMicro,
Thank you for your help. Your example worked. It threw me off because the inline assembly has its own output "=a", so I thought the "equal" MyMacro invocation would cause a duplicate save to _mob->message_id. However this did not happen (dang smart compiler).
Steve,
Thank you for your help. I assumed the C stub would emulate a C calling function. I was wrong, but now I fail to see any functional generated code difference between the macro and C stub, aside from source syntax and code structure differences.
BTW, how did you get those percent signs in your post?
but now I fail to see any functional generated code difference between the macro and C stub
Only a % followed immediately by a number is disallowed.
Umm no, the problem is usually other way round
printf("%3d");
will get through but:
printf("#d");
won't.
From the evidence above it looks like a percent followed by a capital letter may be OK too:
printf("%D3");
Ah no, it's more subtle than that "#D" didn't work but "#D3" did.
I think it allowed D3 because it looks like a hex number?
And as an additional side note: you can always use the HTML entity to generate the percent sign:
printf("%d");
Only a % followed immediately by a number is disallowed.
Which is the point. You can use real C to get the same result without having to do all the BS of macros.
Here is my final version of the macros:
#define RIGHT_SHIFT_21(val_32, port_32) /* message_id = (CANIDT >> 21); */ \ __asm__ __volatile__( \ "lds ^B[message], ^C[canid]" "\n\t" \ "lds ^A[message], ^D[canid]" "\n\t" \ "andi ^B[message], 0xE0" "\n\t" \ "lsl ^B[message]" "\n\t" \ "rol ^A[message]" "\n\t" \ "rol ^B[message]" "\n\t" \ "rol ^A[message]" "\n\t" \ "rol ^B[message]" "\n\t" \ "rol ^A[message]" "\n\t" \ "rol ^B[message]" "\n\t" \ "clr ^C[message]" "\n\t" /* 32 bit specific */ \ "clr ^D[message]" "\n\t" /* 32 bit specific */ \ : [message] "=a" (val_32) \ : [canid] "i" (_SFR_MEM_ADDR(port_32)) \ ) RIGHT_SHIFT_21 (message_id, CANIDT); RIGHT_SHIFT_21 (message_msk, CANIDM); #define LEFT_SHIFT_21(port_32, val_16_32) /* CANIDT = (message_id << 21); */ \ __asm__ __volatile__( \ "sts ^A[canid], __zero_reg__" "\n\t" \ "sts ^B[canid], __zero_reg__" "\n\t" \ "lsr ^B[message]" "\n\t" \ "ror ^A[message]" "\n\t" \ "ror ^B[message]" "\n\t" \ "ror ^A[message]" "\n\t" \ "ror ^B[message]" "\n\t" \ "ror ^A[message]" "\n\t" \ "ror ^B[message]" "\n\t" \ "andi ^B[message], 0xE0" "\n\t" \ "sts ^C[canid], ^B[message]" "\n\t" \ "sts ^D[canid], ^A[message]" "\n\t" \ : /* built-in port_32 output */ \ : [canid] "i" (_SFR_MEM_ADDR(port_32)), [message] "a" (val_16_32) \ ) LEFT_SHIFT_21 (CANIDT, message_id); LEFT_SHIFT_21 (CANIDM, message_msk);
These are used with the AVR CAN chips.
Once again I cannot post with percent signs. I get a "bad request" error from the server every time.
Hi
in this part of "Inline Assembler Cookbook " ,said:
In order to reuse your assembler language parts, it is useful to define them as macros and put them into include files. AVR Libc comes with a bunch of them, which could be found in the directory avr/include. Using such include files may produce compiler warnings, if they are used in modules, which are compiled in strict ANSI mode.To avoid that, you can write __asm__ instead of asm and __volatile__ instead of volatile. These are equivalent aliases.
but when i use asm volatile , i can compile my code with any warning , why?
i wrote my macro in a header file then include in main file , my header is :
#ifndef _ASMMACRO_H #define _ASMMACRO_H #define loop_until_bit_is_clear_mojtaba(port,bit) \ asm volatile ( \ "L_per=: " "sbic per0, per1" "\n\t" \ "rjmp L_per=" \ : \ : "I" (_SFR_IO_ADDR(port)), \ "I" (bit) \ ) #endif /* asmmacro.h */
note: i use "per" instead percent-sign becuase forum don't respon to my request !