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);
}