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.

TMS320F280049C: Illegal Instruction behavior - how to retrieve the offending address

Part Number: TMS320F280049C
Other Parts Discussed in Thread: SYSBIOS

Hello support,

this question is related to the thread "e2e.ti.com/.../3615369, but more focused on ITRAP behavior.

I'm testing a reaction to NMI Illegal Operation.

In the "TMS320C28x CPU Instruction Set" document (par. 3.6) is written:

"An illegal-instruction trap cannot be blocked, not even during emulation.Once initiated, an illegal instruction
trap operates the same as a TRAP #19 instruction. The handling of an interrupt initiated by the
TRAP instruction is described in Section 3.5.2. As part of its operation, the illegal-instruction trap saves
the return address on the stack. Thus, you can detect the offending address by examining this saved
value.

I could not find further information about how get the "offending address", therefore I ask you

1. When I am inside the Illegal Operation ISR, at which SP location can I find the stored "offending address" ? (I guess it is a 32bit)

Is it at SP[-1] and SP [-2] ? Or the CPU saves it "before" the context saving ? At which offset, with respect of the current SP, can I find it ?

2. Is there a way to trigger the ITRAP #19, different than the statement __asm "TRAP #19" ?

I mean, calling TRAP #19 sure triggers the corresponding NMI, but what about the offending address, since actually there was not a real Illegal Operation ?

3. Do you have a short assembly example (suitable for Piccolo) about SP content reading, that I can insert in my TRAP #19 ISR ?

best regards

As additional information,

I have tried the following simple ISR function, triggered through TRAP #19

uint32_t IllegalOperationAddress;

interrupt void Cbk_ISR_IL_OP_handler(void)
{

    __asm(" PUSH XAR1 ");
    
    __asm(" MOVL XAR1, #IllegalOperationAddress ");
    __asm(" MOVL  ACC,*-SP[2] ");
    __asm(" MOVL *XAR1, ACC ");
    
    __asm(" POP XAR1 ");    
  
}

and I see that I can transfer the content of SP - 2 into Accumulator and then into variable IllegalOperationAddress.

It seems to me that I just need to know which is the good offset where I can find the Illegal Address in stack, and I can have this "Illegal Address" into my variable IllegalOperationAddress.

By the way, I see that entering the ISR Cbk_ISR_IL_OP_handler() the SP increments of 15 units (I believe is the context saving) and then there is an additional increment of 5 due to the following instructions:

 ASP          
 PUSH         RB
 MOV32        *SP++, STF

 that are present also in case my ISR function is empty......therefore, can it really be that it is enough to me to know the proper offset to apply to the statement

    __asm(" MOVL  ACC,*-SP[offset] ");

in order to get the "offending address" ?

best regards

  • Hi,

    Thanks for your question. See responses below:

    1. The offending adress location will still be in the return address (see answer to #3 below and this link: software-dl.ti.com/.../index.html

    2. If I understand your question properly, even with a TRAP call, the offending address will still be the address before the ISR is entered.

    3. See this E2E post, which is exactly what you're looking for to read the RPC of the TRAP call (which may answer your other questions as well).
    e2e.ti.com/.../693819
    Also see this post (which is similar, but related to PC and TRAP):
    e2e.ti.com/.../592314

    Regards,
    Vince

  • Hello support,

    I have read your suggestions and included the short assembly function of

    e2e.ti.com/.../693819

    that actually returns the RPC value.

    Nevertheless I had an unexpected result that I tried to explain in the excel file attached.

    As already reminded, in my example I trigger the IllegalOp ISR through the instruction TRAP 19.

    If you look at the excel file, the outcome of my test is that the address stored in RPC is the "return address of the function that was running when the trap occurred", i.e. the address next the "call" instruction.

    In practice,

    - the function running when trap occurred is C_ABS_NMI_LaunchIllegalOperationTest()

    - the call address of C_ABS_NMI_LaunchIllegalOperationTest() is 0x8AED6

    - the return address is 0x8AED8

    But the TRAP is triggered inside the function C_ABS_NMI_LaunchIllegalOperationTest() at address 0x8BA88, therefore my expectation is to get address

    0x8BA8A (the address next to the "TRAP 19" statement)ITRAP flow.xlsx

    As a second information,

    I saw that in the stack I really can find "the address next to the "TRAP 19" statement" because it is stored while entering the ISR Cbk_ISR_IL_OP_handler(), but I'm not sure I can get it because its position is depending on how much complex is the ISR.

    I see that the offset is (SP - 8) if the ISR just saves the context, but if the ISR uses some local variables or calls some functions the offset changes accordingly to the stack usage of the ISR.

    What do you think ?

    Could you confirm the correctness of my test ?

    Thank you in advance for your kind reply

    best regards

  • Davide Dentoni said:
    therefore, can it really be that it is enough to me to know the proper offset to apply to the statement

    Perhaps a robust solution is to declare a naked function, so that the compiler does not generate prologue and epilog sequences.

    I tried the following in a TSM320F280049C with the TI v20.12.0.STS compiler using EABI output format:

    uint32_t IllegalOperationAddress;
    
    __attribute((naked)) void Cbk_ISR_IL_OP_handler (void)
    {
        asm (" c28addr");
        asm (" pop     acc             ; Load acc with return addr");
        asm (" push    acc             ; Put return addr back on stack");
        asm (" sub acc, #1             ; return address from interrupt will be PC location where illegal instruction is executed + 1");
        asm (" push xar4");
        asm (" movl xar4, #IllegalOperationAddress");
        asm (" movl *xar4, acc         ; Save address of the illegal instruction");
        asm (" ESTOP0                  ; if debugger connected - give a chance to user to know the scenario");
        asm ("isr_trap_loop: SB isr_trap_loop, UNC ; pause device. @todo Should interrupts be disabled?");
    }
    

    When tested by a program which deliberately used an ITRAP0 instruction, then IllegalOperationAddress was set to the address of the ITRAP0 instruction.

    The idea of the pop acc / push acc sequence to get the return address was taken from bios_6_83_00_18/packages/ti/sysbios/family/c28/Hwi_disp_asm.s28, which is the SYS/BIOS C28x interrupt dispatcher.

  • Hello

    thank you for the reply.

    In the meantime I achieved a similar solution that I report here:

    __asm("NEG_OFST .set     8 ");

    __asm(" PUSH XAR1 ");
    __asm(" MOVL XAR1, #IllegalOperationAddress ");        

    __asm(" NASP ");    
    __asm(" MOVL  ACC,*-SP[NEG_OFST] ");                            
    __asm(" ASP ");    

    __asm(" MOVL *XAR1, ACC ");                
    __asm(" POP XAR1 ");

    The constraint is that the offset of "8" could change is the function changes with addition of local variables.

    Statements NASP and ASP are necessary because the ISR function could align the stack unpredictably, and the offset of 8 is computed with respect of

    unaligned stack.

    Your solution seems to have the advantage to be independent on the OFFSET, but I guess the whole function should be written in assembly, including the final IRET statement that otherwise would be missing.

    Actually, I need to have a very few C statements inside this function, therefore I will stay today on my solution that is the best compromise to me.

    Anyway I will take your suggestion and I will work on it.

    best regards