This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3352: executed vldr s0, [r12, #8] and mode goes to abort.

Part Number: AM3352


In below picture, ARM is going to load variable "UI_SPL_SensingMic" from within union "SPL_SensingMic".

ARM is going to do

1. get the base address from sp.

It makes sense. It's the base address of struct *(element).

2. load value from address 0x803657D2+8 to register s0.

The logic here is no problem.

3. After executing it, the arm goes to abort mode from supervisor.

quoted from ARM System Developers Guide-Designing and Optimizing System Software:

「Prefetch abort vector occurs when the processor attempts to fetch an instruction from an address without the correct access permissions. The actual abort occurs in the decode stage.」

「Data abort vector is similar to a prefetch abort but is raised when an instruction attempts to access data memory without the correct access permissions.」


I'm not sure, in this case, is this abort Prefetch or data?

And Why this happen?

Here is the compiler test case

"C:/ti/ccsv8/tools/compiler/ti-cgt-arm_5.2.5/bin/armcl" -mv7A8 --code_state=32 --float_support=VFPv3 --abi=eabi -me --include_path="C:/ti/ccsv8/tools/compiler/ti-cgt-arm_5.2.5/include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/uCOS Include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Source Code/Include/armv7a/am335x" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/NandFlash Include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/lwip Include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/FatSystem" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/MP3" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/OSIP" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/mmcsdlib" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/RTP" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/Lib_DSP_Math" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/Lib_DSP_Function" --include_path="C:/ti/ccsv8/ATEIS AM335X/Include/Lib_DSP_Filter" --include_path="C:/ti/ccsv8/ATEIS AM335X/Source Code/Include" --include_path="C:/ti/ccsv8/ATEIS AM335X/Source Code/Include/hw" --include_path="C:/ti/ccsv8/ATEIS AM335X/Source Code/Include/armv7a" -g --preproc_with_comment --preproc_with_compile --define=am3352 --define=ccs --define=AM335X --define=_FUNCTION_PERFORMANCE_xx --diag_warning=225 --diag_wrap=off --display_error_number --neon --enum_type=int --wchar_t=16 -k --c_src_interlist --obj_directory="Middleware" "../Middleware/DNM_Channel.c"
Finished building: "../Middleware/DNM_Channel.c"

DNM_Channel.pp.txt

edit:

quoted from ARM System Developers Guide-Designing and Optimizing System Software again.

I guess the reason for abort is that address 0x803657D2+8 is not a multiple of four bytes.

But why compiler doesn't allocate this variable to address multiple of 4? I didn't specify packed to the struct, and therefore it should be address of multiple 4.

  • Hi,

    Which SDK is this? What version?
  • Hi.
    I'm sorry. I don't know what is SDK you're referring to.
  • I am referring to the AM335x Processor SDK: www.ti.com/.../PROCESSOR-SDK-AM335X Are you using it? If not, what software is this?
  • I just want to solve this problem that I came across.
    I don't know what SDK I'm using.
    May I ask this problem is related with SDK?
    or Maybe I posted this problem in wrong forum?
  • The problem starts with this function ...

    DNMChannel_t* DNMChannel_New(void)
    {
    	return (DNMChannel_t*)&AP_Table_DSP.DNM.Ch;
    }
    

    The structure type DNMChannel_t presumes the field Ch is at a 4-byte aligned address, but it is only aligned to a 2-byte aligned address.  The compiler does not check whether this alignment constraint is met.  By inserting the cast, you indicate this change in type is OK.  

    First, I show that Ch is not guaranteed to be 4 byte aligned.  The field Ch is a structure of this type ...

    typedef struct
    {
    	uint16_t IP[2];
    	uint16_t Zone_MechanicID;
    	uint16_t LED_Working_Status;
    	uint16_t SPL_SensingMic[2];
    	uint16_t Weight[2];
    	uint16_t HwVersion;
    }AP_Channel_DNM_s;
    

    The important point is it contains nothing which requires 4-byte alignment.  The field Ch comes from this structure ...

    typedef struct
    {
    	AP_Main_DNM_s           Main;
    	Amp_Mode_Struct_s       ModeAmp[NumAmpMode];
    	AP_Channel_DNM_s      Ch;
    }AP_Master_DNM_s;
    

    It turns out that the field Ch is at an offset of 86 bytes from the start of that structure.  Whether this structure is itself 4-byte aligned is perhaps interesting, but it doesn't matter.  If it is 4-byte aligned, then Ch is never 4-byte aligned.  If it is 2-byte aligned, then Ch could be 4-byte aligned, but that is not guaranteed.

    Now, I show that the structure type DNMChannel_t requires 4-byte alignment.  Here is that type ...

    struct DNMChannel_t
    {
    	union
    	{
    		uint32_t MCU_IP;
    		uint16_t DSP_IP[2];
    	}IP;
    	uint16_t Zone_MechanicID;
    	uint16_t LED_Working_Status;
    	union
    	{
    		float UI_SPL_SensingMic;
    		uint16_t DSP_SPL_SensingMic[2];
    	}SPL_SensingMic;
    	uint16_t Weight[2];
    	uint16_t HwVersion;
    };

    The types uint32_t and float each require that this structure type be 4-byte aligned.

    This code contains a large number of types, with lots of relationships between them.  Therefore, I hesitate to recommend a solution.  Someone familiar with the code needs to recommend a solution.

    Thanks and regards,

    -George

  • Thanks, an excellent explanation.

    I have few questions for this.

    Quoted from ARM system developers guide designing and optimizing system software:

    There are several instructions for different transfer size in addition to LDR.

    I thought Compiler would be smart enough to decide which instruction should be used.

    In this case, Compiler knows the address is at multiple of 2 and transfer size is 4. Why Compiler uses LDR instead of LDRH?

  • Andy Lin94 said:
    Why Compiler uses LDR instead of LDRH?

    Because the compiler presumes it is accessing a field in a structure of type DNMChannel_t.  Every such structure the compiler allocates is aligned to a 4-byte boundary.  When you assign (or return from a function, or something similar) to a DNMChannel_t pointer, the expression being assigned either must be of the same type, or it is changed to that type by casting.  By casting, the user accepts responsibility for insuring any alignment constraints are met.  

    Here is some rationale.  If it worked differently, then the compiler would have to conservatively presume all pointers might be unaligned, and issue 4 LDRB instructions for a 32-bit load.  This is a waste of cycles and code space.

    Thanks and regards,

    -George

  • Every such structure the compiler allocates is aligned to a 4-byte boundary.

    Compiler only allocates variable, does not allocate structure type.

    In this case the way Compiler sees is: Oh, I know there is a variable I need to allocate with type AP_Channel_DNM_s, so I take a look how AP_Channel_DNM_s is defined by programmer in order to decide how this variable is aligned. As a result, the variable Ch is aligned with 2 bytes.

    Then, programmer requests this action:

    DNMChannel_t* DNMChannel_New(void)
    {
        return (DNMChannel_t*)&AP_Table_DSP.DNM.Ch;
    }

    Compiler will be like: Okay, I can look this variable, Ch, in this way, too.

    By casting, the user accepts responsibility for insuring any alignment constraints are met.

    Yes, you are right, and it does. Ch has indeed achieved alignment constraints: All member's in Ch are starting at the same address either Compiler see it in the way of  AP_Channel_DNM_s or DNMChannel_t.

    If it worked differently, then the compiler would have to conservatively presume all pointers might be unaligned

    I'm not sure what do you mean by "pointers might be unaligned". In this case the pointer is actually aligned, pointing to the same address, and the transfer size is also the same.

    and issue 4 LDRB instructions for a 32-bit load.  This is a waste of cycles and code space.

    How do I tell Compiler, like: Hey! You cannot use LDR by default, because the member might at address of multiple of 2 or 4. You should check the address first and then decide which instruction used.

    An other way I can do is force Compiler allocate Ch at address of multiple 4, so that it's no problem with casting. But how do I tell Compiler to do it?

  • Andy Lin94 said:
    How do I tell Compiler, like: Hey! You cannot use LDR by default, because the member might at address of multiple of 2 or 4.

    Unfortunately, there is no method for doing that.

    Andy Lin94 said:
    You should check the address first and then decide which instruction used.

    This implies the compiler should emit code that checks, at runtime, whether the address is aligned.  This is impractical.

    Andy Lin94 said:
    An other way I can do is force Compiler allocate Ch at address of multiple 4

    Add a field to the structure which requires 4-byte alignment, even if you never use it.  If you use this method, comment it clearly.

    Thanks and regards,

    -George