Issue
The POPNE (or LDMNEIA) instruction seems to be executed in the simulator even if the Zero flag is set.
C Compiler: V4.1.0.567 CPU DLL: V4.14
How to reproduce
Create a new project with the following options:
Device -> NXP (founded by Philips) -> LPC2129 C/C++ -> Optimization: level 3 (-O3), check "Optimize for Time"
C code (part of an original project):
#include <stdio.h> #include <string.h> #include <stdint.h> #define MAX_CMD_LEN 32 #define MAX_CMD_ARGS 3 static const char * command; static const char * args[MAX_CMD_ARGS]; static unsigned num_args; static void cmd_read(void); static const struct cmd_info { const char * name; void (* func)(void); } commands[] = { /* other commands ... */ { "read", cmd_read }, { 0 } }; static void parse_cmd_buff(void) { /* here we pretend we are parsing something ... */ command = "read"; args[0] = "eeprom"; args[1] = "0"; args[2] = "128"; num_args = 3; } static void read_eeprom(uint32_t * addr, size_t len) { } static void cmd_read(void) { static void read_eeprom(uint32_t * addr, size_t len); uint32_t addr; size_t len; /* This condition is true, so read_eeprom() must get called. But it doesn't. See below for details. */ if (!strcmp(args[0], "eeprom") && num_args == 3 && sscanf(args[1], "%i", &addr) && sscanf(args[2], "%i", &len)) read_eeprom(&addr, len); } static int interactive_mode(void) { const struct cmd_info * cmd; for (;;) { parse_cmd_buff(); for (cmd = commands; cmd->name; cmd++) if (!strcmp(cmd->name, command)) break; if (cmd->name) cmd->func(); else /* printf("*** bad command: %s\n", command) */; } } int main() { /* ... */ interactive_mode(); return 0; }
Here's the listing of cmd_read().
;;;38 static void cmd_read(void) { 000000 e92d4010 PUSH {r4,lr} ;;;39 static void read_eeprom(uint32_t * addr, size_t len); ;;;40 uint32_t addr; ;;;41 size_t len; ;;;42 ;;;43 if (!strcmp(args[0], "eeprom") && num_args == 3 && 000004 e59f4070 LDR r4,|L1.124| ; R4 = args 000008 e24dd008 SUB sp,sp,#8 ;38 00000c e5940000 LDR r0,[r4,#0] ; args[0] 000010 e28f1068 ADR r1,|L1.128| 000014 ebfffffe BL strcmp 000018 e3500000 CMP r0,#0 ; Z = 1 ;;;44 sscanf(args[1], "%i", &addr) && sscanf(args[2], "%i", &len)) ;;;45 ;;;46 read_eeprom(&addr, len); ;;;47 } 00001c 128dd008 ADDNE sp,sp,#8 000020 18bd4010 POPNE {r4,lr} ; This instruction gets executed even ; though Z = 1. This results in R4 ; being clobbered and args[1] pointing ; to the wrong place in the subsequent ; call to sscanf(). 000024 112fff1e BXNE lr 000028 e59f0058 LDR r0,|L1.136| 00002c e5900004 LDR r0,[r0,#4] ;43 ; num_args 000030 e3500003 CMP r0,#3 ;43 000034 128dd008 ADDNE sp,sp,#8 000038 18bd4010 POPNE {r4,lr} 00003c 112fff1e BXNE lr 000040 e5940004 LDR r0,[r4,#4] ;43 ; args 000044 e1a0200d MOV r2,sp ;43 000048 e28f103c ADR r1,|L1.140| 00004c ebfffffe BL __0sscanf 000050 e3500000 CMP r0,#0 ;43 000054 028dd008 ADDEQ sp,sp,#8 000058 08bd4010 POPEQ {r4,lr} 00005c 012fff1e BXEQ lr 000060 e5940008 LDR r0,[r4,#8] ;43 ; args 000064 e28d2004 ADD r2,sp,#4 ;43 000068 e28f101c ADR r1,|L1.140| 00006c ebfffffe BL __0sscanf 000070 e28dd008 ADD sp,sp,#8 000074 e8bd4010 POP {r4,lr} 000078 e12fff1e BX lr |L1.124| DCD ||.bss|| |L1.128| 000080 65657072 DCB "eeprom",0 000084 6f6d00 000087 00 DCB 0 |L1.136| DCD ||.data|| |L1.140| 00008c 256900 DCB "%i",0 00008f 00 DCB 0 ENDP