waitpxx & jmp
While working on a particular piece of PASM I ran into problems. It took me a while to figure out the cause but it comes down to not being able to jump to a waitpxx.
This is what I started with, does not work :
This code fails after the first iteration of the loop. Correcting was as simple as adding a nop as such :
Still, I could not find any information in the manual about this. My thought is it comes down to the pipelining? This took me a while to figure out. (and quite a bit of frustration.) Maybe I'm missing something? Any help would be greatly appreciated!
This is what I started with, does not work :
:loop waitpeq zero, trigger ' wait for trigger pin to be idle
waitpne zero, trigger ' wait for trigger pin to be active
...
'do something
...
jmp :loop ' repeat
This code fails after the first iteration of the loop. Correcting was as simple as adding a nop as such :
:loop nop
waitpeq zero, trigger ' wait for trigger pin to be idle
waitpne zero, trigger ' wait for trigger pin to be active
...
'do something
...
jmp :loop ' repeat
Still, I could not find any information in the manual about this. My thought is it comes down to the pipelining? This took me a while to figure out. (and quite a bit of frustration.) Maybe I'm missing something? Any help would be greatly appreciated!

Comments
{{ // 64 bit clock source // // Author : Joe Heinz // // Copyright : Joe Heinz - 2013 // }} _ctr1_apin = 16 ' pin to use as output from counter A to counter B _sample_pin = 15 ' pin to sample both counters phase VAR long long1, long2 long cog ' byte to store cog running timer in PUB TESTf start repeat GetSample PUB NULL '' not a top level object PUB Start '' Start timing cog long1 := 0'|< _sample_pin ' move sample pin into longa long2 := 0 outa[_sample_pin] := 0 ' set samplePin to LOW dira[_sample_pin] := 1 ' make samplePin an output cog := cognew(@entry, @long1) +1 ' start assembly cog result := cog PUB Stop '' Stop timing cog if cog ' if cog started cogstop(cog ~~ -1) ' stop cog and clear cog variable PUB GetSample '' Get a sample time outa[_sample_pin] := 1 ' make samplePin HIGH ' if long1 < $FFFF_FFFC ' if near overflow at sample ' long2 -= 1 ' subtract 1 from high 32 bits outa[_sample_pin] := 0 ' make samplePin LOW PUB GetBuffer result := @long1 ' return address of longa DAT org entry mov dira, diraval 'set APIN to output mov frqa, #1 'set counter to increment 1 each cycle mov frqb, #1 'set counter to increment 1 each cycle mov wr2add, par ' move par address to wr2add add wr2add, #4 ' add long offset mov ctrb, ctrbmode ' establish counter A mode and APIN mov ctra, ctramode ' establish counter B mode and APIN :loop waitpeq zero, trigger ' wait for trigger pin to be idle waitpne zero, trigger ' wait for trigger pin to be active mov long_1, phsa ' move phsa to long1 mov long_2, phsb ' move phsb to long2 wrlong long_1,par ' write long1 wrlong long_2, wr2add ' write long2 jmp #:loop ' repeat diraval long |< _ctr1_apin ctramode long (%00100 << 26) + _ctr1_apin ' PLL mode - single ended, APIN is input for counter B ctrbmode long (%01110 << 26) + _ctr1_apin ' neg edge triggered, APIN is output from counter A zero long 0 trigger long |< _sample_pin ' pin to trigger sample long_1 res long_2 res wr2add resWhile working on this I realized that if I take a sample within 4 clock of a wrap, the high 32 bits would increment. I tried using the commented out code, but does not seem to work properly. I'm still trying to figure out the right way to handle this.
*edit*
Think I've got it. Easier (and quicker) to do in PASM.
:loop waitpeq zero, trigger ' wait for trigger pin to be idle waitpne zero, trigger ' wait for trigger pin to be active mov long_1, phsa ' move phsa to long1 mov long_2, phsb ' move phsb to long2 cmp wrap, long_1 wc ' if near overflow at sample if_c sub long_2, #1 ' subtract 1 from high 32 bits wrlong long_1,par ' write long1 wrlong long_2, wr2add ' write long2 jmp #:loop ' repeatNext, internal overhead. Let's assume you read $FFFFFFFC for the low part (high is 0). This means not carry and therefore the high part is not modified. However, the high part is read 4 cycles later (low is 0). During this clock the link output goes low. Another cycle later this low makes it into the A1 counter flipflop. In the next cycle the counter increment logic sees the !A1&A2 condition which finally causes it to increment the high part. This means the change you're hoping to read is two cycles late. That said, you could use a 6 cycle DMZ to adjust for internal delays (my initial implementation) but this wouldn't protect you from external delays. In the end I increased the DMZ and simply re-read both values in case of a wrap collision (see posted example code).
In propgcc another solution is used. IIRC, high is read first followed by low. Then high is read again, if it has changed the low part is re-read then this value is reported. I'll post a link later if I can find it again.
*edit*
So I come up with something like this :
:loop waitpne zero, trigger ' wait for trigger pin to be active mov long_2, phsb ' move phsb to long2 mov long_1, phsa ' move phsa to long1 mov tmp, phsb ' re-read phsb cmp tmp, long_2 wz ' compare both samples of phsb if_nz mov long_1, phsa if_nz mov long_2, tmp wrlong long_1,par ' write long1 wrlong long_2, wr2add ' write long2 waitpeq zero, trigger ' wait for trigger pin to be idle jmp #:loop ' repeatNot sure if I can compensate for the small delay, or if it's even necessary at this point.
Above version slightly shorter.
mov long_2, phsb ' move phsb to long2 mov long_1, phsa ' move phsa to long1 cmp long_2, phsb wz ' compare both samples of phsb if_nz mov long_1, phsa ' re-read phsa if_nz add long_2, frqb ' apply incrementWhat delay are you worried about? The compensation? That's only 12 extra cycles (which you probably already get by waiting for hub windows). You could move the long_2 adjustment between both wrlongs though.