Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: Example of C and inline ASM in a file?

2006-04-10 by jayasooriah

This is an add-on to Danish Ali's contribution to AH's original question.

I hope it will show how one can use GCC's inline assembly features in
an effective way to produce code that is both readable *and* efficient.

I am not sure if I could have handcrafted the assembler code to be
that efficient, considering the three primitives I created in the
header file are not specific to the WATCHDOG or the LPC.

Sorry it is longish but striking a balance between being brief and
clear is not always easy considering the nature of this audience.

Enjoy!

Jaya

PS:  All you need to know about inline assembly for purposes of
understanding this tutorial can be found at:

  http://www.ethernut.de/en/documents/arm-inline-asm.html

I am happy to explain finer points if anyone wants to know more.

--- In lpc2000@yahoogroups.com, "Danish Ali" <danish@...> wrote:

> Attached is an example of something that gcc likes (as
> supplied with Rowley Crossworks).

> void Watchdog_Feed(void) { /* NOT fiq safe! */
> 	int irqStat;
> 	asm volatile (
> 		" mrs r0, cpsr\n"
> 		" mov %0,r0\n" : "=r" (irqStat) : : "r0" );
> 	if (128 & ~irqStat)
> 		__ARMLIB_disableIRQ();
> 	asm volatile (
> 		"WDFEED = 0xE0000008\n"
> 		" LDR r0, =WDFEED\n"
> 		" MOV r1,#0xAA\n"
> 		" MOV r2,#0x55\n"
> 		" STRB r1,[r0]\n"
> 		" STRB r2,[r0]\n" : : : "r0", "r1", "r2");
> 	if (128 & ~irqStat)
> 		__ARMLIB_enableIRQ();
> }

I wrote a header file, foo.h with three primitives to do what the
above code does.  This is included at the end of this post E&OE.

I wrote foo.c which includes foo.h (and other header files), and in
which I invoked the equivalent of the Watchdog_Feed() function as follows:

>  feedSeq(&WATCHDOG);

I used GCC to generate the optimised assembler source file as follows:

> arm-esdk-gcc -Wall -Werror -O3 -S foo.c

The assembler output for the feedSeq() call I got is as follows
(comments added)

> 	mov	r0, #128		@ 0x80 (IRQ BIT)
> 	mov	lr, #-536870912		@ 0xe0000000 (&WATCHDOG)
> 	mrs	ip, cpsr		@ save copy of CPSR
> 	orr	r0, r0, ip		@ set IRQ bit in temp
> 	msr	cpsr, r0		@ disable interrupts
> 	mov	r0, #170		@ 0xAA (feed byte #1)
> 	mov	r3, #85			@ 0x55 (feed byte #2)
> 	str	r0, [lr, #0]		@ WATCHDOG FEED #1
> 	str	r3, [lr, #0]		@ WATCHDOG FEED #2
> 	msr	cpsr, ip		@ restore interrupts


The header file where I make use of inline functions and inline
assembly to achieve the above result follows.  Note that I do not
refer to any register by name, but let the compiler tell me what
register to use.

The name of the game here is not to override the compiler with your
choices, but to tell the compiler (in the nicest way possible) what
you want it to do for you ... to produce the code shown above.

> // ===========================================================
> // 'irqMask'
> 
> // mask either irq or fiq bit
> inline int
> irqMask(mask)
> {
> 	int mode;
> 
> 	// set mask bit
> 	asm volatile
> 	(
> 		"mrs\t%0, cpsr"		"\n\t"
> 		"orr\t%1, %1, %0"	"\n\t"
> 		"msr\tcpsr, %1"	
> 		: "=&r" (mode)
> 		: "r" (mask)
> 	);
> 
> 	// previous mode
> 	return (mode);
> 
> } // irqMask()
> 
> // End of 'irqMask'
> // ===========================================================
> 
> 
> // ===========================================================
> // 'irqMode'
> 
> // restore mode and irq bits
> inline void
> irqMode(int mode)
> {
> 
> 	// restore CPSR
> 	asm volatile ("msr\tcpsr, %0" : : "r" (mode));
> 
> } // irqMode()
> 
> // End of 'irqMode'
> // ===========================================================
> 
> 
> // ===========================================================
> // 'feedSeq'
> 
> // atomic feed sequence
> inline void
> feedSeq(int *loc)
> {
> 	int mode;
> 
> 	// enter critical section
> 	mode = irqMask(IRQ_BIT);
> 
> 	// atomic feed sequence
> 	asm volatile
> 	(
> 		"str\t%1, [%0, #0]"	"\n\t"
> 		"str\t%2, [%0, #0]"
> 		: 
> 		: "r" (loc), "r" (0xaa), "r" (0x55)
> 		: "r1", "r2"
> 	);
> 
> 	// leave critical section
> 	irqMode(mode);
> 
> } // feedSeq()
> 
> // End of 'feedSeq'
> // ===========================================================

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.