This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Incorrect code generation, optimization level #7. Ethernet driver

Dear All,

I am working on a project involving XC2287M microcontroller + AX88796B Ethernet chip and use PK166 & ARTX-166 TCP/IP stack, no ARTX uOS, HLarge memory model. I had to develop firmware for the same proprietary PCB but with support of 2 targets:
a) Internal memory mode - running from on-chip MCU' flash and using on-chip MCU's RAM
b) External memory mode - running from an external flash and using an external RAM

Options for Target -> C166 are as follows (checked ones are shown):

 - favor speed
 - reorder instructions
 - alias checking
 - save DPP
 - save temporary variables on user stack
 - MODV2
 - for a) mode: optimization level #7, common tail merging
 - for b) mode: optimization level #6, constant propagation

For shown options, firmware executes OK both for a) and b) but here is the problem: when I switch to the optimization level #7 for target b), firmware crashes.

From ASM listings I see the difference in generated code: inside a function 'X', right before '}' statement in C code (i.e. return), level #7 gives JMPS instead of CALLS + RETS as for level #6: before the '}' in 'X' there is a call to another function 'Y'.

Could someone clarify:
1) If this is (un-)known compiler bug (?) - looks incorrectly to quit the function with no RETS - would not this destroy the stack?
2) How to ensure that the rest of code - other C modules - will not have similar issues when compiled at a given optimization level?
3) Why firmware running from internal memory is OK but firmware built for external memory fails? It is seen from the map file that 'distance' between function addresses is 'longer' for faulty case

I found a fix: inserting a single 'nop' in 'X' in source C file after call to 'Y' and right before '}' solves the issue, i.e. eliminates JMPS optimization. Unfortunately this fix is non-reliable, there are too many pieces of code where it is so easy to overlook inserting this extra nop.

Looking for an advice to do it on IDE/compiler level and if I am doing something wrong or missing some nessesary setting?

Below are details of my findings.

Regards,
Nikolay.

******************************************************************************

Ethernet driver snippets (Ax88796.c is a part of Keil's TCP/IP, was modified partially to work with 'B' chip):

:
void int_enable_eth (void) {
  /* Ethernet Interrupt Enable function. */
  HVAR(U8, CSR_IMR) = IMR_PRXE | IMR_PTXE | IMR_TXEE;
}

The function that was found to be problematic:

void send_frame (OS_FRAME *frame) {
  ...
  while (TxActive);
  ...
  TxActive = __TRUE;
  int_enable_eth ();
}

ASM code for Optimization Level #7 shows JMPS with no RETS (!):

             ; FUNCTION send_frame (BEGIN  RMASK = @0x5DF0)
...
0578         ?C0057:
0578 8A00FE00 R    JB        TxActive,?C0057
 ...
0602 0F00     R    BSET      TxActive
0604 FA000000 R    JMPS      SEG (int_enable_eth),int_enable_eth
             ; FUNCTION send_frame (END    RMASK = @0x5DF0)

ASM code for the same C source file compiled for optimization level #6 gives expected RETS:

             ; FUNCTION send_frame
...
0578         ?C0057:
0578 8A00FE00 R    JB        TxActive,?C0057
...
0602 0F00     R    BSET      TxActive
0604 DA000000 R    CALLS     SEG (int_enable_eth),int_enable_eth
0608 DB00          RETS
             ; FUNCTION send_frame

In other words, for Level #7, compiler 'optimizes' RETS instruction replacing it with JMPS to another function (int_enable_eth) at the end of caller's function (send_frame): it happens if call is placed right before return statement in C code.

 ...
  TxActive = __TRUE;
  int_enable_eth ();
  _nop_();              // this one 'nop' fixes the problem
}

Map file snippets (note different 'distance' in addresses for 2 functions):
a) Internal memory mode

:
      C0AA42H     int_enable_eth                   LABEL ---  FCODE   ?PR?AX88796
      C0AA42H     BLOCK     LVL=0     000CH   ---   int_enable_eth
:
      C0AC16H     send_frame                       LABEL ---  FCODE   ?PR?AX88796
      C0AC16H     BLOCK     LVL=0     0090H   ---   send_frame

b) External memory mode

      012EBCH     int_enable_eth                   LABEL ---  FCODE   ?PR?AX88796
      012EBCH     BLOCK     LVL=0     000CH   ---   int_enable_eth
:
      013090H     send_frame                       LABEL ---  FCODE   ?PR?AX88796
      013090H     BLOCK     LVL=0     0092H   ---   send_frame

a) Memory map for internal memory mode

CLASSES (ICODE (0xC00000-0xC0EFFF), FCODE (0xC00000-0xC0EFFF, 0xC10000-0xCCFFFF),
FCONST (0xC00000-0xC0EFFF, 0xC10000-0xCCFFFF), HCONST (0xC00000-0xC0EFFF, 0xC10000-0xCCFFFF),
XCONST (0xC00000-0xC0EFFF, 0xC10000-0xCCFFFF), NCONST (0xC04000-0xC07FFF),
NDATA (0xE00000-0xE03FFF), NDATA0 (0xE00000-0xE03FFF),
SDATA (0xC000-0xDFFF, 0xF600-0xFDFF), SDATA0 (0xC000-0xDFFF, 0xF600-0xFDFF),
IDATA (0xF600-0xFDFF), IDATA0 (0xF600-0xFDFF),
FDATA (0xA000-0xDFFF, 0xE00000-0xE07FFF), FDATA0 (0xA000-0xDFFF, 0xE00000-0xE07FFF),
HDATA (0xA000-0xDFFF, 0xE00000-0xE07FFF), HDATA0 (0xA000-0xDFFF, 0xE00000-0xE07FFF),
XDATA (0xA000-0xDFFF, 0xE00000-0xE07FFF), XDATA0 (0xA000-0xDFFF, 0xE00000-0xE07FFF))
 CINITTAB (0xC10000-0xCCFFFF)

b) Memory map for external memory mode (flash starts from address 0)

CLASSES (ICODE (0x0-0x7FFF), FCODE (0x0-0x7FFF, 0x10000-0xFFFFF),
FCONST (0x0-0x7FFF, 0x10000-0xFFFFF), HCONST (0x0-0x7FFF, 0x10000-0xFFFFF),
XCONST (0x0-0x7FFF, 0x10000-0xFFFFF), NCONST (0x4000-0x7FFF),
NDATA (0x400000-0x403FFF), NDATA0 (0x400000-0x403FFF),
SDATA (0xF600-0xFDFF), SDATA0 (0xF600-0xFDFF),
IDATA (0xF600-0xFDFF), IDATA0 (0xF600-0xFDFF),
FDATA (0x400000-0x4FFFFF), FDATA0 (0x400000-0x4FFFFF),
HDATA (0x400000-0x4FFFFF), HDATA0 (0x400000-0x4FFFFF),
XDATA (0x400000-0x4FFFFF), XDATA0 (0x400000-0x4FFFFF))
 CINITTAB (0x10000-0xFFFFF)

Keil IDE information:

IDE-Version: uVision V4.22.0.0
Toolchain:        PK166 Prof. Developers Kit  Version: 7.05
Middleware:       AR166 Advanced RTOS Version 3.20
EC++ Compiler:    EC166.Exe       V1.09d
C Compiler:       C166.Exe        V7.05
Assembler:        A166.Exe        V5.34
Linker/Locator:   L166.Exe        V5.25
Librarian:        LIB166.Exe      V4.29
Hex Converter:    OH166.Exe       V4.7a
CPU DLL:          S166.DLL        V3.80.0.0
Dialog DLL:       D167.DLL        V2.53
Target DLL:       BIN\UL2OCDS.DLL V1.26.0.0
Dialog DLL:       T167.DLL        V2.50.0.1

--- END

0