Shop OBEX P1 Docs P2 Docs Learn Events
An odd REPEAT bug in Spin? — Parallax Forums

An odd REPEAT bug in Spin?

JRoarkJRoark Posts: 1,215
edited 2019-01-02 22:40 in Propeller 1
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:

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

  • JRoarkJRoark Posts: 1,215
    edited 2019-01-02 22:38
    Formatting fixed. Apologies. Looks like I need to work on the code formatting in my post. Ack.
  • Whether or not this is a bug, why do you have so much code in a repeat loop?
  • I do not have an answer to your question, by why are you programming like that, instead of:
        repeat
    
          OUTA := 1            'Set Pin 0 high 
          OUTA := 0            'Set Pin 0 low
    
  • Whether or not this is a bug, why do you have so much code in a repeat loop?

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2019-01-02 23:11
    I wouldn't necessarily call it a "bug." But if it really is a limitation, I think it's a reasonable one. After all, 4K longs is half of hub RAM! Further, if such a limitation exists, I do believe it's something the compiler should catch if it's exceeded.

    -Phil
  • JRoarkJRoark Posts: 1,215
    edited 2019-01-02 23:16
    idbruce wrote: »
    I do not have an answer to your question, by why are you programming like that, instead of:
        repeat
    
          OUTA := 1            'Set Pin 0 high 
          OUTA := 0            'Set Pin 0 low
    

    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).
  • I wouldn't necessarily call it a "bug." But if it really is a limitation, I think it's a reasonable one. After all, 4K longs is half of hub RAM! Further, if such a limitation exists, I do believe it's something the compiler should catch if it's exceeded.

    -Phil

    Agreed, and agreed.

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2019-01-03 00:45
    Using BST you can see the listing and here are two outputs showing the branches at the end of the code, one where it just fits, and the other where it is doesn't. You can see that even the BST compiler doesn't perform a range change and if it were me writing the compiler at the time I probably wouldn't either as there would be many other ridiculous situations to cater for and just to try to imagine as well :)

    Interesting find though :)

    Just fits
    Addr : 4017: JMP Label0004
    Addr : 4017:       04 C0 01  : Jmp 001B -16383
    

    Too much
    Addr : 401A: JMP Label0004                      
    Addr : 401A:       04 BF FE  : Jmp 801B 16382
    

    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.
  • "Every non-trivial computer program has at least one bug". Sorry I don't recall who said it first.
  • I was playing with the Prop trying to get some very symmetrical square waves.
    If that's the goal, it seems like using a counter in a loop (running in its own cog) is a better way to go. With waitcnt in the loop you can control the frequency (up to about 38kHz), and the reload value of the phsx register will control the duty cycle.
  • Cluso99Cluso99 Posts: 18,069
    In Windoze, there are no bugs, just features ;)
  • Using BST you can see the listing and here are two outputs showing the branches at the end of the code, one where it just fits, and the other where it is doesn't. You can see that even the BST compiler doesn't perform a range change and if it were me writing the compiler at the time I probably wouldn't either as there would be many other ridiculous situations to cater for and just to try to imagine as well :)

    Interesting find though :)

    Just fits
    Addr : 4017: JMP Label0004
    Addr : 4017:       04 C0 01  : Jmp 001B -16383
    

    Too much
    Addr : 401A: JMP Label0004                      
    Addr : 401A:       04 BF FE  : Jmp 801B 16382
    

    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. :smiley:

    @All: thanks for everything.
  • Generating a square wave in Tachyon is even easier since it is interactive via the serial terminal. Just type "0 APIN 1 KHZ" for a continuous 1kHz square wave on pin 0 (or try" 10 MHZ" just for fun).
Sign In or Register to comment.