An odd REPEAT bug in Spin?
JRoark
Posts: 1,215
Longtime listener / first-time caller. If any of the group can give me some guidance here, I'd appreciate it. Note that I've googled this issue and looked in the manuals, but I have yet to find a resolution.
My issue involves the Spin REPEAT statement. It appears to me that the REPEAT statement can only handle about 4K longs of code in the REPEATed block before it goes wonky. A trivial pair of programs can demonstrate this.
This program works:
The program above does exactly what it should do. It just wiggles Pin 0 on and off forever. But the program below fails. The only difference is the number of OUTA statements in the REPEAT block. If we insert a whole bunch of OUTA statements in the REPEATed block (enough to bring the compilers "Program Size" counter up to 4100 longs), the issue manifests. The Propeller makes one pass through the REPEATed block, but instead of looping back at the end and repeating the block forever, it seems to runoff the end of the world
This program breaks every time:
At a complier-indicated "Program Size" of 4,099 longs, the program works fine. But add just **one** more "OUTA := 1" statement and it fails after a single pass through the REPEAT loop. Experimenting with it a bit I found that adding instructions before the REPEAT statement does not affect the crash behavior at all. It seems that only statements within the REPEAT body "count" toward creating the error.
Am I being incredibly obtuse here and missing something obvious, or has anyone else ever seen this behavior? Is this a known limit or issue with the Prop1?
My issue involves the Spin REPEAT statement. It appears to me that the REPEAT statement can only handle about 4K longs of code in the REPEATed block before it goes wonky. A trivial pair of programs can demonstrate this.
This program works:
CON _clkfreq = 5_000_000 'using the 5mhz clock on the FLiP Model #32123 _clkmode = XTAL2 + PLL8X 'Set PLL to 8x for 40 mhz clock PUB SetOutputs dira := %1 'Setup Pin 0 as an output repeat OUTA := 1 'Set Pin 0 high OUTA := 0 'Set Pin 0 low OUTA := 1 'Set Pin 0 high OUTA := 0 'Set Pin 0 low
The program above does exactly what it should do. It just wiggles Pin 0 on and off forever. But the program below fails. The only difference is the number of OUTA statements in the REPEAT block. If we insert a whole bunch of OUTA statements in the REPEATed block (enough to bring the compilers "Program Size" counter up to 4100 longs), the issue manifests. The Propeller makes one pass through the REPEATed block, but instead of looping back at the end and repeating the block forever, it seems to runoff the end of the world
This program breaks every time:
CON _clkfreq = 5_000_000 'using the 5mhz clock on the FLiP Model #32123 _clkmode = XTAL2 + PLL8X 'Set PLL to 8x for 40 mhz clock PUB SetOutputs dira := %1 'Setup Pin 0 as an output repeat OUTA := 1 'Set Pin 0 high OUTA := 0 'Set Pin 0 low ' .... lather, rinse repeat a WHOLE bunch of times. ' ....Keep adding OUTA := 1, OUTA := 0 using copy/paste ' .... until the program size hits 4101 Longs... then it dies OUTA := 1 'Set Pin 0 high OUTA := 0 'Set Pin 0 low
At a complier-indicated "Program Size" of 4,099 longs, the program works fine. But add just **one** more "OUTA := 1" statement and it fails after a single pass through the REPEAT loop. Experimenting with it a bit I found that adding instructions before the REPEAT statement does not affect the crash behavior at all. It seems that only statements within the REPEAT body "count" toward creating the error.
Am I being incredibly obtuse here and missing something obvious, or has anyone else ever seen this behavior? Is this a known limit or issue with the Prop1?
Comments
It's a three-beer story, but I was chasing what I thought to be a stability or thermal bug. Eventually that "bug" was determined to be the power supply falling-out of limits, but in the process of fault isolation I started brute-forcing things to see if I could just get it to break. At one point I just did a repeat cut/copy of lots of IO instructions... and sure enough I broke it big-time. Different "bug" entirely, but it was interesting so I followed it.
I don't think the failure scenario listed in my samples would be encountered in the real world. That is truly some DIRTY code!
-Phil
Fair question.
Before things started getting wonky in the power supply, I was playing with the Prop trying to get some very symmetrical square waves. The code you posted is great for compactness (and readability, and just about everything else) but the resulting output waveform has a lopsided duty cycle. The REPEAT causes the last OUTA polarity to persist longer due to the jump at the end of the REPEATed block. So I had 3 sets of IO high/low pairs in my initial loop and I did my scope measurements on the middle pair where the loop instruction wouldnt affect the measurement. When I went hunting the error I just did a bunch if dirty copy/pastes of that code. (No sane human writes code like my example... I hope).
Agreed, and agreed.
Interesting find though
Just fits
Too much
BTW - REPEAT is not really an instruction in itself but more of a compiler directive so that at the end of the indented block it will compile a branch back to the REPEAT "label". This is the same as a BEGIN in Tachyon, it is simply a marker whereas the end of the code would be marked by an AGAIN/REPEAT/UNTIL that actually compiles the branch code.
In Tachyon/TAQOZ my relative conditional branches are even smaller at +/- 127 words whereas the unconditional absolute are anywhere within 64K.
Bingo! Wise words. And a big thank you for taking the time to run this down. Muchly appreciated and nice to know the underlying mechanism. I may need to spend some quality time with Tachyon after the current project clears the bench.
@JohnnyMac: I confess that using a screwdriver for a chisel is somewhat amusing to me, but your way makes for much nicer square waves.
@All: thanks for everything.