Shop OBEX P1 Docs P2 Docs Learn Events
Assembly "waitcnt" — Parallax Forums

Assembly "waitcnt"

parskoparsko Posts: 501
edited 2006-08-08 21:34 in Propeller 1
Hello all,

Is the assembly instruction sequence:
add        time,cnt
waitcnt   time,period

time       long
period    long   100




The same as the following Spin instruction:
waitcnt (100 + cnt)




I keep reading and interpreting the assm. "waitcnt" to mean that it only aligns the assm. routine with "cnt", but not execute a pause in the COG operation.

Otherwise, would it look more like this, (which is how I can think to code it with my interpretation):
mov     time,#0            'Zero out time
add      time,cnt            'Add current cnt value to time
add      time,period       'Add period to wait to time
waitcnt time,#0            'Wait until cnt = time = 0+cnt+period




Unlitmately, I need to pause the COG for "period" clocks.

Thanks again. Never learned assm. My ears are still drenched!

-Parsko

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-02 17:59
    The waitcnt instruction could be a bit confusing.· You're right about the SPIN version vs the assembly one.· They're functionally the same.· The assembly instruction has this extra feature where the source gets added into the destination after the wait is done.· This is done differently in SPIN:
    [noparse][[/noparse]code]
    · mov· time,#500
    · add·· time,cnt
    ··waitcnt time,#510
    · ...
    · waitcnt time,#510

    is roughly equivalent to
    · time := 500 + cnt
    · waitcnt(time)
    · ...
    · waitcnt(time += 510)
    [noparse][[/noparse]/code]
    The reason is that, in assembly, the 510 gets added after the waitcnt, while in SPIN, the 510 gets added before the total is used for the waitcnt.· There's an operator in SPIN to increment by 1 after using the old value, but there's no way to increment by something else (like 510) while using the old value in the calculation (like as the value for waitcnt).· In SPIN, the "time" value is always the last value used for waiting.· In assembly, the "time" value is the next value to be used for waiting.· If you're doing a sequence of "waitcnt"s with different pauses, you always have to plan for the next pause, while, in SPIN, you can deal with the present pause.



    Post Edited (Mike Green) : 8/2/2006 6:37:54 PM GMT
  • parskoparsko Posts: 501
    edited 2006-08-02 19:32
    So,

    I would be correct is saying that:

    (Let us assume the counter will be 0 when the time comes to add it)
    
    mov        time, #510
    add         time, cnt      'Assume cnt is 0 here
    waitcnt    time,#0
    
    



    Will yield a pause of 510 clocks? Actually, it should be about 514 if you add the command, I think.

    If I were to write:
    mov       time, #510
    add        time, cnt       'Again, assume it's 0
    waitcnt   time, #390
    waitcnt   time, #0
    
    



    Will yield, first, a pause of 510 clocks, then a pause of 900 clocks?

    -Parsko
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-02 20:37
    Your first example is correct. The waitcnt will wait until cnt is equal to 510, then the instruction will take a couple of clocks to complete (Chip has posted a previous comment about just where in its 5 clock cycles that it pauses. I don't know if he's indicated where in the execution of the add instruction that cnt is accessed).

    Your second example is not quite correct. The first pause is at an absolute time of 510 cycles from the add instruction. The second pause is at a time interval of 900 cycles from the add instruction, but 390 cycles from the previous waitcnt. Both the 390 and the 510 are relative times, first from the access to cnt, then from the first waitcnt. The waitcnt essentially waits until an absolute time mark occurs (with the value wrapping around every 2^32 clock cycles).
  • parskoparsko Posts: 501
    edited 2006-08-02 21:15
    hmmmmm, reeeeeaaalllllly........

    Okay, I think I get it now. I will obviously have to experiment, but you have finally explained it in a manner my pee-brain can understand! Thank you (for the nth time!).

    Hey, if you're bored, I have started to write my SPI assembly routine. It's about 80% done, I have to check values and stick the variables in there, and add "DAT" line, but the code is there. It won't compile, but you'll start to see what I'm doing.

    You have been paramount to the attached file, Mike!

    Time to hit the hey. P-R-O-G-R-E-S-S!!!! It helps me sleep at night.

    -Luke
  • parskoparsko Posts: 501
    edited 2006-08-07 09:13
    con
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    pub Main
      cognew (@toggle, 0)
    dat
                            org       0
    toggle                                                'Assume counter is 0
                            mov     dira,   Pin           '0-3              Set SCL to output
                            mov     Time,   cnt           '4-7              Time = 8
                            add     Time,   #21           '8-11             Time = 29
    :loop
                            xor     outa,   Pin           '12-15  
                            add     Delay,  #18           '16-19
                            sub     Delay,  #18           '20-23
                            waitcnt Time,   Delay         '24-29            Time = 40_029
                            xor     outa,   Pin           '40_030-40_034
                            waitcnt Time,   Delay2        '40_035-40_038    Time = 120_038
     
                            xor     outa,   Pin           '120_039-120_042
                            add     Delay,  #18           '120_043-120_046
                            sub     Delay,  #18           '120_047-120_050
                            waitcnt Time,   Delay         '120_051-120_054  Time = 160_054
                            xor     outa,   Pin           '160_055-160_058
                            waitcnt Time,   Delay2        '160_059-160_062  Time = 240_062
     
                            jmp     #:loop                '240_063-240_066
     
    Pin     long            |< 1
    Delay   long            40_000
    Delay2  long            80_000
    Time                    res 1
    

    In the comments field·I have added the absolute clock cycle count (value of "cnt").· Are my times·correct?·

    I'm sorry to keep asking, but I keep getting unpredictable waitcnt instructions.· Since I don't fully understand, I will keep asking for spoon fed answers...

    Thanks,

    -Luke
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-07 14:35
    I think the problem is that the first waitcnt instruction is waiting for a time that's passed. Try changing the "add Time,#21" to at least "add Time,#29"

    Why the "add Delay,#18" "sub Delay,#18"? The following waitcnt is going to absorb the time these instructions use since it's based on waiting for an absolute time tick.

    I didn't check your numbers carefully, but they seem to be "in the ballpark".

    Usually in coming up with an initial time value, the CNT is added last. It makes it easier to see just where the time is counted from. In your case, you'd have: "mov Time,#29" "add Time,cnt". I know that puts the time a little further into the future, but you don't want to accidentally cut it too close and have to wait for another 2^32 cycle. If your initial SCL edge has to be really close in relation to entering the loop, you may not want to use an initial waitcnt for the timing.
  • parskoparsko Posts: 501
    edited 2006-08-07 15:58
    Mike,

    The "add delay,#18" and "sub delay, #18" were simply to test the requirement for having the previous "add Time, #21". I think it is supposed to be 29, but I was working from memory. I could remove them, and reduce this by 8, since it is 4 clocks each for ADD and SUB. Then it would be okay, but that isn't my question (good catch though!)

    I am mostly looking to confirm the timing of the waitcnt command. I am not sure if it executes the proceeding "xor outa, Pin" command first, or waits for the WAITCNT to finish before executing the "xor outa, Pin" command.

    Also, if it is the case that it waits to execute the "xor outa, Pin", then if "Time" is not reset to zero, there could be a point when the square wave goes to "infinity" then resets itself to 0, and cause the loop to fail. Notice that the value of Time keeps increasing in my sample code breakdown. Is that true?

    -Luke
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-07 19:24
    1) Preceeding instructions are executed. It is the waitcnt instruction itself that "stalls" until the clock (CNT) is equal to the destination value.

    2) Using the increment feature of the waitcnt instruction, Time indeed keeps increasing. The value will wraparound at 2^32 as will CNT since they're all 32 bit values. Since the test in the waitcnt instruction is for equality, the wraparound is not a problem

    3) Think of instruction execution as even marks on a paper tape. The waitcnt instruction is a little piece of elastic between two marks. There's a pin board with evenly spaced pins marked with successive 32-bit integers (CNT). You place the paper tape over the pins. When you find a waitcnt instruction, you have to see what's in the Time register and stretch the waitcnt until its hole goes over the appropriately numbered pin, then continue with the other holes/pins in order until the next waitcnt.
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-08-08 13:05
    I have written an object that produces pulses on a pin with a given on and off time that uses waitcnt in assembly, I'll post it when I get home from work. I commented the timer stuff quite a bit as I also got confused and had to read the manual page a few times.

    As Mike says you have to be careful not to wait for a time that has passed, I ended up adding limits to the minium times that could be set for on and off times.

    Graham
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-08-08 19:51
    hope this helps
  • parskoparsko Posts: 501
    edited 2006-08-08 20:23
    Graham,

    You're a rock star too. <<Pertinent tangent: I bought my lady a nice pair of wireless headphones so I can PAY ATTENTION when I am playing with this stuff and not hear the TV>> So, I've been playing with the waitcnt command tonight, and making progress. I find that, all you need to do is initialize it to zero, add cnt to the value. When it is called, "waitcnt wcnt, Delay" it simply pauses the amount of the delay, no matter what. I could be wrong, but it's working for me consistently (finally). If (after a pin toggle) I do another "waitcnt wcnt, Delay2" it will pause for the delay2 value. Loop this, and it toggles and pauses expectedly.

    The short version of what I'm saying looks like this...

    ...
    move wcnt, #0
    add wcnt, cnt
    add wcnt, #13 'not sure this is needed, but I leave it cause the 13 clock pause is practically nothing
    :loop
      xor outa, pin
      waitcnt wcnt, Delay
      xor outa, pin
      waitcnt wcnt, Delay2
      jmp #:loop
    ...
    
    



    My O-scope is still toggling with my values as I type, and has been for the better part of the last hour.

    Honestly, I still cannot see the correlation between the Prop Manual "waitcnt" description and reality. So, I hope Parallax can clarify this to us assembly beginners, it would make a HUGE difference. With that said, I am continuing with my SPI object knowing that the delays should work... fingers crossed!

    -Parsko
  • parskoparsko Posts: 501
    edited 2006-08-08 20:27
    Graham,

    "First assembly example in manual provided inspiraton along with much staring at how mouse.spin works"

    lolololo!!!!!!!!!!!

    Great man, I've been bug-eyed myself over this!

    -Parsko
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-08 21:04
    Delay = 100
    Delay2 = 200
    move wcnt, #12 ' This sets the # clocks between the "add wcnt,cnt" and the 1st waitcnt
    add wcnt, cnt ' Say the absolute time (cnt) is 1000 here.  wcnt will be 1012 (see note below)
    :loop
      xor outa, pin  ' This executes 4 clocks after the add
      waitcnt wcnt, Delay  ' This starts 8 cycles after the add (or 1008), but hangs until 1012, sets wcnt to 1112
      xor outa, pin  ' This executes 4 cycles later, roughly 1016
      waitcnt wcnt, Delay2 ' This starts roughly 1024, but hangs until 1112 and sets wcnt to 1312
      jmp #:loop ' This starts roughly at 1114, the xor will start at 1118, the 1st waitcnt starts at 1122 and hangs until 1312
    
    


    I say roughly because I don't remember at which cycle the waitcnt hangs, the 2nd or 3rd. This is important here because
    it affects how many clocks there is left in the waitcnt after execution continues. The clock counts those cycles so you need
    to know that to know precisely what value CNT has when the next instruction begins. Similarly, I don't remember which
    cycle is used to fetch the CNT value in the add instruction. Again, that sets the clock value used to calculate the delays.
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-08-08 21:34
    Parkso, I think the confusion may all come down to the fact that it is easy to mess things up so your logic gets confused. The command is just like the spin version but with the delta option you can use or not.

    You start by setting the wcnt to some number that is cnt plus a bit then the first "waitcnt wcnt delay" will wait until cnt = wcnt

    it will then add delay to the wcnt automatically so that the next waitcnt command will have the new target of wcnt = wcnt+delay.

    So in your code Parkso your delay is really your delay2 and your delay2 your first delay except on the first occasion when the delay is 13, clear [noparse]:)[/noparse]

    Graham
Sign In or Register to comment.