I would have expected to get the watchdog fault 500 mS after calling the ST routine, not after several seconds of running.
Agreed. @Steve Bailey's stack overflow scenario is another possibility.
Another unlikely possibility would be that the 16*500 passes of the inner loop per scan cycle averages nearly, but just under, 500ms***, and it takes several scan cycles, plus some stochastic noise, before the we get scan cycle that finally triggers the watchdog timeout.
*** or whatever the watchdog timeout is; do we know what that is for OP yet?
But I think @Steve's first comment is the most likely explanation: the code is logically correct and is not an infinite loop; rather it is a finite loop that simply takes too long.
Perhaps the simplest diagnostic would be a
MyTimer(IN:=False,PT:=32767);
at the start of the function to reset a TON, then a
MyTimer(IN=True,ET=>MyTimerElapsedTime_ms);
at the end of the function to measure (estimate) how long the function takes, and then vary the duration of the inner x loop e.g. 1 TO 10 instead of 1 TO 1000, then 1 TO 100, etc.
You could also move the second MyTimer call to just before the END_FOR of the outer y loop**, then when the watchdog triggers a fault, you would have a rough idea, from y and MyTimerElapsedTime_ms, how long each pass of the outer loop was taking.
** or even that of the inner x loop, but that would significantly affect the duration of the inner x loop.
TL;DR
I.e. the outer loop takes too long to complete and exit, so the watchdog timer simply times out while the loops are still running during a single scan, which timer faults the PLC.
I am not saying it's good code (e.g.
ELSE Lamps:=Lamps; is a useless statement)
One pass of the inner
FOR x := ... loop has least three operations: the x:=x+1 statement; the increment of x at the END_FOR; the test of x against 1000 at the END_FOR. There is probably another for the FOR statement (a label?). So that is 2000 operations per inner loop (4 operations/pass * 500 passes per inner loop), or 32000 instructions per outer loop. So if each operation takes an average of 15µs, that is 480000µs or 480ms to complete the loops and a 500ms watchdog timer would not trigger a fault*. But at 16µs per operation the loops would take 512ms if allowed to complete, but a 500ms watchdog timer would interrupt the loops and the scan cycle, and trigger a fault.
* I am ignoring the rest of the code executed in each scan: the calling JSR; the y loop; the test of the Lamps value; etc.