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.

TMS320F28377D: how to set error flag for divide by zero

Part Number: TMS320F28377D
Other Parts Discussed in Thread: C2000WARE

Hi Champs,

When we confirm  value divide by zero , value shows  FFFFFFFFh and continue to processing without exception processing.

I referred bellow e2e thread. 

e2e.ti.com/.../83453

Then I confirmed "LVF or LUF" detect overflow or underflow FLAG.

 

Could you tell us how to set exception flag in case of value divide by zero ?

 

  • The LVF and LUF flags protect the algorithm if a numeric overflow or underflow respectively occurs while an appropriate FPU assembly instruction is being executed.  These are flags in the FPU status register, so they are only relevant to floating-point division.  Is that what you are doing?

    If you are coding in C and performing a floating-point division the compiler will make a call to an RTS library function.  For a single-precision divide, the FS$$DIV function will be called.  That function will detect a division by zero and return the maximum floating point value expressible in single precision (i.e. single precision divide by zero will return  3.38953139e+38).

    I have attached the code for that function, because this is explained in the comments near the top.  You can find this and other RTS source at:  C:\ti\ccsv7\tools\compiler\c2000_#.#.#\lib\src

    Since the call is handling the exception itself, neither LVF nor LUF flags will be set.  If you want to trap this case you could modify the source to set those flags using the SETFLG instruction at the appropriate line.  This applies also to the double precision routine.

    I have explained all this carefully because you asked about the LVF and LUF flags, which exist only on the FPU.  From your description you say you are seeing an ACC value of 0xFFFFFFFF, which would occur if you attempted an integer divide by zero.  Integer math instructions execute on the C28x core (not the FPU) so the LVF and LVF flags are not involved.

    At this point I'd need mode clarity on what you want to do.  Could you send a code snippet to explain it please?

    Regards,

    Richard

    fs_div28.asm

  • Richard,

    Thanks. I will send this code by another mail.

    > From your description you say you are seeing an ACC value of 0xFFFFFFFF, which would occur if you attempted an integer divide by zero. Integer math >instructions execute on >the C28x core (not the FPU) so the LVF and LVF flags are not involved.
    -Yes, I think we use C28x core. So, typically, If we don't use FPU , is it able to set "exception /NMI" processing when divide by zero happen ?

    Also, can we use ITRAP function for integer devide by zero case ?
    because, it has NMI type and Interrupt_illegalOperationHandler() API function.
  • Yes, it is possible to do that, but the RTS assembly routine will have to be modified.

    Executing the division with the integer types you sent me results in the LL$$DIV function being called. You will see the call in the dis-assembly window in CCS. To force a user interrupt on divide-by-zero you will have to modify the "ll_div28.asm" file to insert a TRAP instruction in the code. I have not done this, but it should be straightforward to compare the denominator argument against zero and insert a conditional branch. Then you insert and assembly instruction to generate the software interrupt, for example:
    TRAP #20
    ...will force the USER1 interrupt.

    Having modified the source, you will need to re-build the RTS library, which is described in section 8.4 od the C Compiler User's Guide:
    http://www.ti.com/lit/ug/spru514m/spru514m.pdf

    Having done this, in your C code you write an ISR (say, "TrapIsr()") and load the address to the PIE vector table as you would for any other ISR:
    PieVectTable.USER1 = &TrapIsr;

    You can then write the code in the ISR to handle the divide-by-zero event as you wish.

    Regards,

    Richard

  • Hi Richard,

    Appricate your help.

    But, I couldn't find ll_div28.asm file on my c2000ware.

    C:\ti\c2000\C2000Ware_1_00_00_00.

    Could you point out this location ?

    Regards,

    Kz777

  • You are welcome!

    The file is not in C2000Ware.  It's part of the codegen tools and you can find it in the path in my first post:

    C:\ti\ccsv7\tools\compiler\c2000_#.#.#\lib\src

    ...where "#.#.#" is the version of CGT you have installed.  For example, on my machine the full path name is:

    C:\ti\ccsv7\tools\compiler\ti-cgt-c2000_16.9.3.LTS\lib\src

    Regards,

    Richard

  • Hi Richard,
    Thanks for your information. I would like to one more thing .
    As I explained above thread, we found such an API.
    DriberLib provide C:\ti\c2000\C2000Ware_1_00_00_00\driverlib\f2837xd\driverlib\interrupt.c
    Interrupt_illegalOperationHandler() API function
    Even if we use above API, do we have to set above compiler re-setting ? Or Does this API not use for our integer divide use case ?

    Regards,
    Kz777
  • Yes, you will still need to insert the TRAP as Richard instructed. Interrupt_illegalOperationHandler() is just the default ISR provided by driverlib that gets called when an ITRAP occurs. If you want to use the same ISR for the inserted TRAP, you can do that by calling Interrupt_register() to put its address in the PIE vector table.

    Interrupt_register(INT_USER1, &Interrupt_illegalOperationHandler);

    Or you could do the same with a totally new ISR.

    Whitney

  • Hi, Whitney,

    Could you please let me know how to enable INT_USER1 in C-code?

    main(){

       :
       :

       int64 s64_temp;
       Uint32 u32_temp;

       Interrupt_register(INT_USER1, &Interrupt_illegalOperationHandler);

       for(;;)
       {
          s64_temp = s64_temp / u32_temp;
          if(s64_temp < 0){
              // How should user set INT_USER1 for iLLEGAL interrupt?
          }
       }

    }

    static void Interrupt_illegalOperationHandler(void)
    {
        //
        // Something has gone wrong.  The CPU has tried to execute an illegal
        // instruction, generating an illegal instruction trap (ITRAP).
        //
        ESTOP0;
        for(;;)
        {
            ;
        }
    }

    Regards,
    Nagata.

  • Hello,

    You should be able to use __asm() to insert the instruction

    __asm(" TRAP #20");

    Is that what you were looking for?

    Whitney

  • In order to detect a divide-by-zero condition for the code in your post you will need to modify the "ll_div28.asm" file accordingly and re-build the RTS library.

    Before you do anything, please MOVE (don't copy) the "ll_div28.asm" file from the library source directory (see previous post) to somewhere safe on your hard drive, so you have a back-up.

    I have attached a modified file to this post.  If you look in the attached file you will see some additional instructions around line 176 to force a USER1 interrupt if the denominator is zero.  I haven't changed anything else.  Put this file in the library source directory where the old one was.

    Locate your lib directory.  On my machine, the directory is:
    C:\ti\ccsv7\tools\compiler\ti-cgt-c2000_16.9.3.LTS\lib

    Then, MOVE (don't copy) the libraries (files with .lib extension) from your lib directory somewhere safe, again so you have a back-up.  Removing these will force CCS to re-build the library when you build your project. 

    In your project you will need to enable the USER1 interrupt in your initialization code...
    PieVectTable.USER1 = &TrapIsr;

    ...and write an ISR as I indicated previously...

    interrupt void TrapIsr(void)
    {
        asm(" NOP"); // break-point here
    }

    Then re-build your CCS project.  You should be getting USER1 interrupts when the denominator is identically zero, otherwise it works as before.

    It seems to work fine on my setup.  Can you try this please? 

    Regards,

    Richard

    ll_div28.asm

  • Hi Richard,
    Thanks.