is there any kind if c struct in arm assembly language?

I saw somewhere an assembler with constructions looking like c struct

is there this kind of structure on gnu assembler of arm ?

the use of their .struct pseudo instruction does not seem really clear.

I have this kind of data

ring_buffer:

in_ptr: .word 0 ;# in_ptr (r2)

out_ptr .word 0 ;# out_ptr (r3)

count .word 0 ;# character count (r4)

size .word 128 ;# buffer size (r5)

mutex .word 0 ;# mutex

buffer .zero 128

it would be easier if I could this strcture once the use:

input_ring_buffer: .struct ring_buffer

output_ring_buffer: .struct ring_buffer

the access the ring buffer by:

ldr r0, = input_ring_buffer.in_ptr

any idea ?

thanks

Other than some arcane macros, nope.

I think plain and obvious is best, in coding styles.

One must wonder: why assembly language?

LOL :smiley:

why not :smiley:

check the output of gcc :shock:

I recently did some test on an ipod touch latest release

the function:

objective C 560 ms

C 240 ms

arm asm 80 ms

I’m thinking to start a web site on assembly programming for arm

something practical

I’m bored to see young programmer such as the one on the seat next to me at the office

who is looking at you if you where a martian each time you tell them that a few lines of assembly language would largely

increase the performance for their program (and I know he is not alone :mrgreen: )

didier:
I’m bored to see young programmer such as the one on the seat next to me at the office

who is looking at you if you where a martian each time you tell them that a few lines of assembly language would largely

increase the performance for their program (and I know he is not alone :mrgreen: )

Just my two cents. :mrgreen:

This “young programmer” is probably more concerned by readable, maintainable, expandable, reusable code of a long life product, than by pure speed execution of some obscure assembly code. :mrgreen:

And if speed is really the key point, and assembly should be used in a large part of the code, you probably made the wrong microcontroller choice.

If I had to hire one of you, it would not be you :mrgreen:

Angelo

This “young programmer” is probably more concerned by readable, maintainable, expandable, reusable code of a long life product, than by pure speed execution of some obscure assembly code. :mrgreen:

And if speed is really the key point, and assembly should be used in a large part of the code, you probably made the wrong microcontroller choice.

and his application will work in four or five years with a new generation of processor

when 20 to 40 lines of assembly language would solve the bottleneck…

I have to partially agree with didier.

If you program properly in C, it is not an issue to use assembler.

Personally i write the larger parts of the code in C. Whenever i use a function a lot, i call it from within C with the proper calling convention and procedure call standard. Just as everybody else. See this pdf provided by ARM for details.

http://infocenter.arm.com/help/topic/co … _aapcs.pdf

However, at times it can be useful to hand optimize in assembler small functions. Thus instead of writing the entire program in assembler, only small functions that are often used are hand optimized in assembler.

This way, the program code keeps the readability, re-usability and maintenance advantages of a language such as C.

But you also have the benefits of assembler. The key is that the function written in assembler acts exactly as a c function and is called as a c function.

As a plus, you will learn to maximize the control you have over your ARM hardware. The mantra of Linus Torvalds for example is to make a function do only one thing and make it do that as good as possible. I agree, because then it is easier to make assembler optimized versions which you can replace with functions written in c for the new hardware/model/product. This will shorten time to market. Then when there is time and requests for it, assembler optimized versions can be produced without the strain of having an aggressive time to market cycle.

And that C code is reusable, depends on the situation. More then once, a new version of a processor will also have new hardware that will not work with the old c code right away.

I will post later some links here about my own experiences. The forum where the links are pointing to, is down because of maintenance.

Here are the links :

I have taken the SAM7S256 as my example since this is the ARM processor i use.

I hope you find it interesting, remarks, comments and positive critique are always welcome.

My venture with a hand optimized StrLen function called StrLen32 for little Endian ARM processors.

http://forums.anandtech.com/showthread.php?t=2171329

My venture about how smart hardware helps speed up and reduce code.

http://forums.anandtech.com/showpost.ph … stcount=12

Do you have numbers comparing the performance of Strlen at -O2 or -O3 and your Strlen32 code?

It seems to me that another strong argument for programming in C is that the code produced is far less error prone…

BTW, did you find out if your strlen32 works on a string that isn’t byte aligned, for example Strlen32(sz_bl_startup + 1)? I would hate to lose programmer-days debugging obscure problems caused by asm libraries that act in bizarre ways

20+ years ago I spent years writing zillions of lines of ASM code in my job.

In more recent times, the code is all C (portable) except for the inevitable 1% or even less.

Today, one writes ASM code to learn, and in the professions, one does so when the product must cost $0.50 at giant volumes. Maybe.

benstabler:
Do you have numbers comparing the performance of Strlen at -O2 or -O3 and your Strlen32 code?

It seems to me that another strong argument for programming in C is that the code produced is far less error prone…

BTW, did you find out if your strlen32 works on a string that isn’t byte aligned, for example Strlen32(sz_bl_startup + 1)? I would hate to lose programmer-days debugging obscure problems caused by asm libraries that act in bizarre ways

To be honest, after that brilliant poster Schmide made the almost perfect assembler version, i did no longer much research. I fooled around a bit, but not until it was what i made after the assembler version was optimized and the (little endian) error removed.

As with all optimizations, there is always a weak point. The string must be word aligned (address : BIT0 = 0, BIT1 = 0). Depending on if you use a little endian or big endian architecture (SAM7S = little endian only, ARM architecture itself is bi endian in general). With little endian, The first byte of the string is the lowest byte of the register, the second byte of the string is the second byte of the register, the third byte of the string is the third byte of the register, the fourth byte of the string is the fourth byte of the register. The fifth byte of the string is the lowest byte of the register. Etectera.

The error i made and the resulting behavior of the code, is your answer. It will only return multitudes of 4 back.

Also as another brilliant poster degibson pointed out, it may not work on systems with cache or a memory management unit if you have not requested memory for the string to be placed in. Then an exception may occur, or the processor may show slow downs because it is loading a lot of data from main memory into cache.

Thus the string must be word aligned. (Just do a check if BIT0 and BIT1 are zero just as the final assembler version.)

The current version of StrLen32, i make it return with the result 0. But perhaps a modification is handy that makes it return 0xFF FF FF FF. I myself am thinking of adjusting the code to return 0x FF FF FF FF when it is not word aligned. Then it is immediately known that a non word aligned string was requested to test on length. Then a normal StrLen that searches at byte level can be used.

Make sure that you do not cross any paging boundary or memory boundary that could cause an exception.

This means that you must have requested memory. I am planning to make for myself a tiny version of calloc and free that can have as part of the argument that the requested memory must be word aligned.

http://www.cs.umass.edu/~verts/cs32/endian.html

An Essay on Endian Order

Copyright (C) Dr. William T. Verts, April 19, 1996

Depending on which computing system you use, you will have to consider the byte order in which multibyte numbers are stored, particularly when you are writing those numbers to a file. The two orders are called “Little Endian” and “Big Endian”.

The Basics

“Little Endian” means that the low-order byte of the number is stored in memory at the lowest address, and the high-order byte at the highest address. (The little end comes first.) For example, a 4 byte LongInt

Byte3 Byte2 Byte1 Byte0

will be arranged in memory as follows:

Base Address+0 Byte0

Base Address+1 Byte1

Base Address+2 Byte2

Base Address+3 Byte3

Intel processors (those used in PC’s) use “Little Endian” byte order.

“Big Endian” means that the high-order byte of the number is stored in memory at the lowest address, and the low-order byte at the highest address. (The big end comes first.) Our LongInt, would then be stored as:

Base Address+0 Byte3

Base Address+1 Byte2

Base Address+2 Byte1

Base Address+3 Byte0

Motorola processors (those used in Mac’s) use “Big Endian” byte order.

stevech:
20+ years ago I spent years writing zillions of lines of ASM code in my job.

In more recent times, the code is all C (portable) except for the inevitable 1% or even less.

Today, one writes ASM code to learn, and in the professions, one does so when the product must cost $0.50 at giant volumes. Maybe.

Well, to be honest. I am building some sort of animatronic device for a friend to use in his bar. (Maybe i will have to build more if other people like it as well).

Sinds it is mostly statemachine, i decided to use a PIC16F884. Because of the low price point and because i know how to write PIC assembler. But today i was thinking it trough, how much time i would need and (YES :smiley: ) i have become smarter on a different level. The technical dude in me, feels ashamed that i do not take on the personal contest to program in PIC assembler. I decided to use a Sam7S16 or SAM7S32 instead. Why, because then when i make an error i can find it more easy. I have a lot of experience with PIC assembler, but i know how much time debugging costed when i used multiple interrupt simultaneously and only on a rare ocassion a crash. Since i want to advance in C anyway, and it was an opportunity to make small experimental pcb’s (MCU,power, reset supervisor and usb) to be used on general eurocard experimental pcb’s.

At digikey, the SAM7S16 or SAM7S32 is 2 to 4 times the cost of a PIC16F884, but it makes up for the time i save. I still feel it is massive overkill, but it allows me to design from scratch, build and program hopefully within less than 5 weekends. Because i am going to use such a powerful MCU, i am already thinking of adding future functionality after i have finished my initial goals.

This is a modified version (GCC 4.4.2).

I just tested it, i seems to work, but i am tired. I can have missed something.

StrLen32 returns 0xFFFFFFF0 with a NULL pointer.

StrLen32 returns 0xFFFFFFFF with a non word aligned address value (Lowest digit of address does not equal : 0x0,0x4,0x8 or 0xC.

StrLen32 returns 0x0000FF00 with a stringsize greater then 65280 characters.

Screendump of terminal program.

StrLen test.

Amount of characters in sz_test is : 9.

Amount of characters in sz_test2 is : 10.

Amount of characters in sz_test3 is : 12.

Amount of characters in sz_bl_startup is : 48.

StrLen32 test.

Amount of characters in sz_test is : 9.

Amount of characters in sz_test2 is : 10.

Amount of characters in sz_test3 is : 12.

Amount of characters in sz_bl_startup is : 48.

StrLen32 test 2, argument = 0.

returnvalue is : FF FF FF F0.

StrLen32 test 3, argument = 3.

returnvalue is : FF FF FF FF.

Here is the code :

I am sorry if it is a bit messed up. I use TAB widths of 2 spaces. The forum software is confused of my use of tabs.

// *************************************************************************************************
// Counts the amount of characters with a mxaimum of 65280 in a "NULL" terminated string.
// Returns amount of characters in string.
// This is an higly optimized version that retrieves 4 bytes at once by doing a word access.
// Thus the string must be word aligned. 
// W-ARM generates output files in the little endian format by default.
// This function expects the little endian format to work. 
// When the argument is a NULL pointer, return 0xFFFFFFF0.
// When the value of argument is a not aligned memory address, StrLen32 will return 0xFFFFFFFF.
//
// This function issues a warning because the compiler is not aware of the assembler code.
// I do not know yet how to solve this.
//
uint32_t StrLen32( uint32_t *ui_pntr)
{
register uint32_t	ui_cntr asm("r0"); 

asm volatile(
		"					subs  r1, r0, #0  				\r\n"	// Do a NULL pointer check.
		"					beq .ENDLB6								\r\n"	// Jump if ui_pntr = 0.
		"					ands  r0, r1, #0x00000003	\r\n" // Check if BIT0 and BIT1 are both 0. 
		"					bne .ENDLB5 							\r\n" // If not, jump.
		
		".LPLBL1:	ldr r2, [r1, r0]					\r\n" // r3 = memory address pointed at by r2 + r0.
		"					tst r2, #0x000000FF				\r\n"	// tst.
		"					beq .JLABL1								\r\n" // jump if Z is set.
		"					tst r2, #0x0000FF00				\r\n" // tst.
		"					beq .JLABL2								\r\n"	// jump if Z is set.
		"					tst r2, #0x00FF0000				\r\n"	// tst.
		"					beq .JLABL3      					\r\n"	// jump if Z is set.
		"					tst r2, #0xFF000000				\r\n"	// tst.
		"					beq .JLABL4								\r\n"	// jump if Z is set.
		"					add r0, r0, #4  					\r\n"	// r0 = r0 + 4.
		"					cmp r0, #0x0000FF00				\r\n"	// r0 - 0x0000FF00. Max string length = 65280 characters.
		"					bne .LPLBL1								\r\n" // jump if Z is cleared.
		"					bx  lr										\r\n"	// return.		

		".JLABL4:	    add r0, r0, #1  					\r\n" // r0++.
		".JLABL3:	    add r0, r0, #1						\r\n"	// r0++.
		".JLABL2:	    add r0, r0, #1  					\r\n"	// r0++.
		".JLABL1:	    bx  lr  									\r\n" // return.  
		
		".ENDLB5:	    mvn r0, #0								\r\n"	// create the value 0xFFFFFFFF
		"					bx lr											\r\n"	// return.
		".ENDLB6:	    mvn r1, #0								\r\n"	// create the value 0xFFFFFFFF
		"		   		sub %[reg0],r1,#15				\r\n" : [reg0]"=r" (ui_cntr));
																							//   Subtract 15. Thus return 0XFFFFFFF0
return(ui_cntr);
}