Shop OBEX P1 Docs P2 Docs Learn Events
FlexBasic.....For "COG" — Parallax Forums

FlexBasic.....For "COG"

Anyone figured out how to use this?

I only get compiler complaints. I suspect that there is some kind of initialization that I'm missing.

Comments

  • Here's an example:

    function for "cog" addup( a() as integer, n as integer) as integer
      var sum = 0
      for i = 0 to n
        sum += a(i)
      next i
      return sum
    end function
    
    dim shared testarr(4) = { 1, 2, 3, 4, 5 } as integer
    
    print "sum = ", addup(testarr, 4)
    

    There are significant restrictions on functions placed in COG and LUT memory; see the general compiler documentation for details. In particular, the functions should be leaf functions (not call any other functions... in theory they could call other COG or LUT functions, but the compiler doesn't allow that yet).

  • Hmmm, I may have spoken too soon about the leaf function restriction... it looks like that was lifted a while ago.

  • But I can't just launch something like this, right?

    dim shared as long cogtest
    
    sub for "cog" addup( )
    do
        cogtest = cogtest + 1
    loop
    end sub
    
    addup
    do
        print cogtest
        pausems 200
    loop
    
  • evanhevanh Posts: 16,032

    If I'm reading Eric correctly, it doesn't start a separate task. The for "cog" feature is just a way to specify routine to be compiled for cogexec rather than the default hubexec.

  • @evanh said:
    If I'm reading Eric correctly, it doesn't start a separate task. The for "cog" feature is just a way to specify routine to be compiled for cogexec rather than the default hubexec.

    Correct.
    The code @Mickster posted will jump into Addup() and never return, as Addup() runs in the same cog that has called it. But if you spawn Addup() into its own cog (with its own stack pace, etc) the code will run as intended, with the value of cogtest being printed every 200 mS.

  • Right. FOR "COG" means the function is to be placed in COG memory (and FOR "LUT" means it is to be placed in LUT memory) but the function will still run in the same cog as the rest of the program. To start a new cog you need to use the CPU pseudo-function:

    dim shared as long cogtest
    dim as long stack(20)
    
    sub addup()
    do
      cogtest = cogtest + 1
    loop
    end sub
    
    var id = cpu(addup(), @stack(0))  ' run addup() in a new COG with its own stack
    print "cog "; id; " started"
    do
      print cogtest
      pausems 1000
    loop
    
  • @ersmith said:
    Right. FOR "COG" means the function is to be placed in COG memory (and FOR "LUT" means it is to be placed in LUT memory) but the function will still run in the same cog as the rest of the program. To start a new cog you need to use the CPU pseudo-function:

    dim shared as long cogtest
    dim as long stack(20)
    
    sub addup()
    do
      cogtest = cogtest + 1
    loop
    end sub
    
    var id = cpu(addup(), @stack(0))  ' run addup() in a new COG with its own stack
    print "cog "; id; " started"
    do
      print cogtest
      pausems 1000
    loop
    

    Oh yeah, I already have a couple of these happening but I misunderstood it to be like running a routine permanently in only cog memory. Like, with the P1; in cog-mode you get the full 20MIPS but only 4 or 5 MIPS using LMM (?)

  • evanhevanh Posts: 16,032
    edited 2021-11-26 14:45

    All correct. But it's the same cog as was being used to execute in LMM, just like one cog that executes hubexec or cogexec. Your main program is using a cog, and a subroutine/function, in hubexec or cogexec, is still running on the same cog unless a new cog is explicitly launched. Prop1 with LMM is same in this respect.

  • @evanh :+1: Understood, many thanks :smile:

  • @Mickster said:
    Oh yeah, I already have a couple of these happening but I misunderstood it to be like running a routine permanently in only cog memory. Like, with the P1; in cog-mode you get the full 20MIPS but only 4 or 5 MIPS using LMM (?)

    The difference isn't that extreme in P2 mode, plus FlexBasic already caches loops in COG memory (which further reduces the penalty). So generally it's fine to run code in HUB memory. But if you want extra reliable timing, or have a very frequently used function, then FOR "COG" and FOR "LUT" may be useful. And of course you can combine them with CPU -- that is, if you want a subroutine to run permanently in another cog and be in internal memory in that cog, make the subroutine FOR "COG" or FOR "LUT" and then launch it in the new cog with a CPU command.

  • @ersmith said:
    if you want a subroutine to run permanently in another cog and be in internal memory in that cog, make the subroutine FOR "COG" or FOR "LUT" and >then launch it in the new cog with a CPU command.

    Hi Eric,

    Been trying to make this work but the compiler complains that the sub needs to be in hub memory.
    Don't suppose you have an example, please?

    Also, from the manual:
    What exactly is "noinline"?

    Craig

  • @Mickster said:

    @ersmith said:
    if you want a subroutine to run permanently in another cog and be in internal memory in that cog, make the subroutine FOR "COG" or FOR "LUT" and >then launch it in the new cog with a CPU command.

    Hi Eric,

    Been trying to make this work but the compiler complains that the sub needs to be in hub memory.

    D'oh, I forgot about that restriction. But to work around it is straightforward, just have a small stub function that launches the COG/LUT function, e.g.:

    sub for "cog" blink()
       do
         pintoggle(57)
         pausems 200
       loop
    end sub
    
    sub blinkstub()
      blink()
    end sub
    
    dim stack as byte(128)
    
    var cogid = cpu(blinkstub(), @stack(0))
    
    do
       print "running in cog "; cogid
       pausems 2000
    loop
    

    I'll see if I can make the compiler generate that stub automatically if necessary.

    Also, from the manual:
    What exactly is "noinline"?

    It says the function/subroutine should never be made inline. Normally if the routine is small, or is only called from one place, the compiler expands it in place instead of creating a CALL instruction. For example, in code like:

       function incr(x as integer) as integer
          return x + 1
       end function
       ...
       b = incr(c)
    

    the generated assembly will be exactly the same as if you had written

       b = c+1
    

    because the "incr" function is simple enough that the compiler can just do it "in place". If you specify that "incr" is FOR "noinline" then instead the generated assembly will contain a subroutine for incr and the code will include a CALL.

  • @ersmith

    Perfect 🤓.... Many thanks 👍😎👍

    Craig

Sign In or Register to comment.