View Full Version : Pre-check for waitcnt?
01-12-2009, 02:52 AM
I have some cog code that occasionally runs long and causes waitcnt to stall for a minute 'cuz it's missed the boat.
I thought I'd try to skip the waitcnt if cnt has already passed the target value. This is what I have so far; what do you think of it?
mov temp, cntTarget
sub temp, cnt
cmps temp, #10 wc, wz
if_b jmp #:skipWaitcnt
waitcnt cntTarget, cntPeriod
The 10 is just a number I pulled out of my... head. Anyone know what the correct value is? I figure it shouldn't be too big, because I don't want to skip the waitcnt unnecessarily, but it has to be big enough to account for the extra instructions leading up to waitcnt.
What I'd really like to do is figure out why my %$# code runs long in the first place, but after chasing it for a day I'm ready to put in this stopgap and move on. Unfortunately I have lost all faith in my ability to reason about waitcnt and timing, so I'd appreciate less bleary eyes checking me on this little snippet.
01-12-2009, 03:14 AM
You don't want to use CMPS. That's a signed compare and CNT is treated as a 32 bit unsigned value. Use CMP instead. I'd use at least 20 for the value to compare. The SUB, CMP, and JMP will take 4 clock cycles each (or slightly less from the fetch of the CNT value) and the WAITCNT will take at least 5 clocks. You could shorten this a little by eliminating the JMP and making the WAITCNT conditional.
01-12-2009, 03:42 AM
But I'm not comparing aginst cnt, I'm comparing against (cntTarget - cnt) which is signed, no?
Good points about 20 and making waitcnt conditional (slaps forehead).
01-12-2009, 04:00 AM
cntTarget is an unsigned 32 bit number. CNT is an unsigned 32 bit number. When you subtract them, you still have a 32 bit unsigned number. You need to do an unsigned compare. Try some examples.
Phil Pilgrim (PhiPi)
01-12-2009, 04:39 AM
With all due respect to Mike, I think cmps is the way to go. Consider the following examples:
Target CNT Target - CNT CMP #$0A CMPS #$0A Desired Action
$2000_0010 $2000_0000 $0000_0010 NC NZ NC NZ WAITCNT
$2000_0010 $2000_0006 $0000_000A NC Z NC Z WAITCNT
$2000_0010 $2000_0007 $0000_0009 C NZ C NZ Skip
$2000_0010 $2000_0011 $FFFF_FFFF NC NZ C NZ Skip
cmp will only return the desired carry when CNT hasn't yet passed Target but is very close. cmps also handles the case where CNT has already passed Target.
One thing to note is that cmps will work only when your timed interval is less than $8000_0000 (about 27 seconds). To encompass the entire 53-second interval, you will need something like this:
sub temp,cnt wc
if_nc cmp temp,#LIMIT wc
if_nc waitcnt target,interval
At least I think that's correct. I still need to work through some examples.
Post Edited (Phil Pilgrim (PhiPi)) : 1/11/2009 8:50:55 PM GMT
01-12-2009, 01:31 PM
Thanks Phil (and yes, mad respect for Mike Green).
Your addendum is giving me a headache. I may be misunderstanding your scenario, but I think there's a problem here.
After "sub temp, cnt wc", C means "cnt passed target up to 27 seconds ago" and NC means "cnt will hit target in 27 seconds or less". Of course, because of modular arithmetic, C also means "cnt will hit target between 27 and 54 seconds from now".
If I set target to 50 seconds from now and then do my work, and it only takes say 10 seconds, I'll hit the sub instruction with 40 seconds to go before cnt reaches target, so sub will set C (the second meaning, but there's no way to tell) and the waitcnt will be skipped, thus exiting prematurely.
Edit: Never mind, I was thinking subs, not sub. I gotta stop trying to think about this stuff.
Post Edited (mpark) : 1/12/2009 5:42:58 AM GMT
Phil Pilgrim (PhiPi)
01-12-2009, 01:56 PM
Your addendum is giving me a headache.
Yeah, me too! Sorry, it's not right. I knew there was still a possible range issue, and it's something I dashed off too quickly, thinking I could solve it. But in thinking more about it, there really is no solution. The problem is endemic to modular arithmetic. If target - CNT were $8000_0000, say, does this mean that we have $8000_0000 more clocks to wait, or have we passed the target by $8000_0000? There's just no way to tell, which reduces the effective timing interval to 27 seconds in principle.