Shop OBEX P1 Docs P2 Docs Learn Events
Function to be used in a cog - rules — Parallax Forums

Function to be used in a cog - rules

John KauffmanJohn Kauffman Posts: 653
edited 2015-04-15 07:16 in Propeller 1
Please confirm, for C language, the rules for a function that will run in a cog. Thanks.

A function to run in a cog must have return of void.
A function to run in a cog must be an infinite loop - or - contain a cog_end(cog).

Above true or should be stated alternately?
Any other basic rules?

Thanks.

Comments

  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-13 07:57
    Please confirm, for C language, the rules for a function that will run in a cog. Thanks.

    A function to run in a cog must have return of void.
    A function to run in a cog must be an infinite loop - or - contain a cog_end(cog).

    Above true or should be stated alternately?
    Any other basic rules?

    Thanks.

    There are a couple ways to run code in a new cog. If using lmm or cmm models, you could start a new lmm/cmm kernel in the next available cog by using the cogstart function.

    From any memory model, you can use the Propeller's native cognew to start a new cog running pure PASM (or PASM compiled from C... aka, cogc).

    So first, it would likely be helpful if you specify what type of cog you want to start.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2015-04-13 09:49
    David: Sorry to skip that. CMM Main RAM Compact
  • ersmithersmith Posts: 6,053
    edited 2015-04-13 17:41
    Please confirm, for C language, the rules for a function that will run in a cog. Thanks.

    A function to run in a cog must have return of void.
    A function to run in a cog must be an infinite loop - or - contain a cog_end(cog).

    Above true or should be stated alternately?
    Any other basic rules?

    Thanks.

    It very much depends on exactly what you're trying to do. The simplest way to start C code in another cog is to use the cogstart function, and that does indeed take as a parameter a pointer to a function returning void (to be precise the argument has type void (*func)(void *arg). That function does not have to loop forever -- if it exits the cog it was running on stops automatically. The function will be run in the same memory model you are currently in (LMM or CMM).

    Other ways to run C code in another cog are:

    (1) with the pthread library function pthread_start (very similar to cogstart)
    (2) with OpenMP pragmas (probably not available in simpleIDE)
    (3) by compiling the C code with -mcog and linking it specially ("COGC mode"). This is different from the other ways because the C code is running directly on the COG, so it is very fast but must fit in the COG memory

    What are you trying to accomplish in the other cog?
  • John KauffmanJohn Kauffman Posts: 653
    edited 2015-04-14 06:25
    Goal is to get students through their first few experiments of running a function in a cog (using C) to blink LEDs from different cogs at different rates. I'm seeking just the simplest possible scenario to make it work for their first tries. A checklist will help them catch problems before testing and to troubleshoot.

    Current checklist:
    proper function declaration/protoype
    forward declaration
    matching number arguments in call with number of parameters in declaration
    * special rules for functions to be used in cogs:
    *- function is infinite loop (later add option of cog_end)
    *- function return is void
    Vars visible across cogs need to be volatile
    etc.

    Thanks.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-14 06:55
    Looks like an excellent list so far :)

    I would think cogstart would be the simplest - by far.

    And for this case, you definitely want an infinite loop and return value of void... but I never liked it when my professors would say something is "required" when it isn't truly. Strongly suggested, yes. Required by your grading rubric... probably lol. But not required by the compiler.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-14 07:22
    I would guess that if you did a return from a cog it would just stop the cog like it does in Spin. That could be verified by running it under spinsim to see what instructions it executes.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2015-04-14 07:23
    Thanks for help & confirmations.
    Right, cog_start is also on there.
    Sometimes I start with "required" then after initial success introduce exceptions.
    Joke on grading well received - necessary but a drag.
  • Courtney JacobsCourtney Jacobs Posts: 903
    edited 2015-04-14 07:50
    Hi John,

    Just checking to make sure you've seen or know about Andy's Multicore Approaches tutorials. They go through a lot of what you're asking about here.

    If you've already gone through them – great! If not, I definitely recommend them.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-14 09:21
    John Kauffman,

    Not sure I know what you mean. If you actually want to write code that will be loaded into COG and run entirely in COG, then you need to know about, dare I say it, _NAKED functions and _COGMEM variable declarations.

    Do have a look in the demos that come with prop-gcc. Should be in /opt/parallax/demos.

    Or on line in the source code repository. For example: https://github.com/parallaxinc/propgcc/blob/master/demos/toggle/cog_c_toggle/toggle_fw.c

    I seem to recall that SimpleIDE has some convention about naming such sources as *,cogc rather than *.c. Is that still true?
  • ElectrodudeElectrodude Posts: 1,658
    edited 2015-04-14 10:34
    Or you could just use Spin and only have one simple cognew that does everything... No prototypes to go wrong, no cog_end to forget, no volatile keywords to forget...

    C is nice, but why does it have to overcomplicate everything?
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-14 10:39
    C is nice, but why does it have to overcomplicate everything?

    Flexibility and optimization. That of course has it's drawbacks, and arguing which is better has been done a thousand times already. But the answer to your question is quite simple.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-14 11:16
    Electrodude,
    C is nice, but why does it have to over complicate everything?
    C is actually very simple. Being an abstraction over what most "normal" computer processors do.

    The Propeller architecture does not support C at all well. Hence the contortions required to get it to work.
  • ElectrodudeElectrodude Posts: 1,658
    edited 2015-04-14 20:49
    Heater. wrote: »
    Electrodude,

    C is actually very simple. Being an abstraction over what most "normal" computer processors do.

    The Propeller architecture does not support C at all well. Hence the contortions required to get it to work.
    Exactly. C is my favorite low-level language for programming a PC. However, most C compilers, especially GCC, were never intended to target anything like the Propeller. I suspect, however, that C could be made to work with some modifications (and a custom compiler).
  • Heater.Heater. Posts: 21,230
    edited 2015-04-14 21:07
    Electrodude,

    I'm not sure what you mean. Do you mean modifications to the C language itself to make it somehow Propeller friendly? In that case it is not C any more and nobody would be interested in using it.

    GCC is quite happy targeting small devices. Like AVR, the Arduino uses GCC.

    Seems the Problem is that the Prop can only run native code in it's 2K COG spaces. But it has 32 bit instructions so not much compiler generated code can be made to fit.

    After that we get into the world of code in HUB and LMM. Big code and slow.

    I'm actually quite happy with that because writing assembler for the Prop is so easy. That's where the fast bits go. The rest of the app can amble along in C.

    All in all I'm very impressed with how well the prop-gcc guys have gotten GCC to work with the Propeller.
  • ElectrodudeElectrodude Posts: 1,658
    edited 2015-04-14 22:14
    I'm not really sure what I mean. I don't mean any changes to the language, other than some extra builtins maybe. What I want basically involves rewriting the compiler, possibly basing it off of LLVM, which has many of the features I want. Optimization and code generation should occur post-link, when everything going into the final program is known, so things like smart automatic small function inlines can happen. It should be possible to define a function once and then have the compiler automatically figure out which targets (cogc, cmm, xmm, etc.) it needs to be compiled for. Also, the compiler should be better at knowing when it should blockload functions, and should be capable of having multiple functions loaded at once. For example, inside a printf (which you shouldn't use on a propeller), the main printf loop and putc should remain resident in cogram until the printf returns.

    PropGCC came along, and suddenly almost everyone but Parallax itself decides that Spin, which I consider to be a nearly perfect language for the Prop, is to shunned in favor of C. Not just people new to the Propeller scene are using PropGCC (it's a great entry point for them) - many people who have been using the Propeller with Spin and PASM for years seem to be switching to C for a reason completely unknown to me. If Spin was designed specifically for the Propeller, and C is such a bad fit for the propeller and not much faster and around the same code size, why would anyone prefer C over Spin?
  • David BetzDavid Betz Posts: 14,516
    edited 2015-04-15 03:54
    I'm not really sure what I mean. I don't mean any changes to the language, other than some extra builtins maybe. What I want basically involves rewriting the compiler, possibly basing it off of LLVM, which has many of the features I want. Optimization and code generation should occur post-link, when everything going into the final program is known, so things like smart automatic small function inlines can happen. It should be possible to define a function once and then have the compiler automatically figure out which targets (cogc, cmm, xmm, etc.) it needs to be compiled for. Also, the compiler should be better at knowing when it should blockload functions, and should be capable of having multiple functions loaded at once. For example, inside a printf (which you shouldn't use on a propeller), the main printf loop and putc should remain resident in cogram until the printf returns.

    PropGCC came along, and suddenly almost everyone but Parallax itself decides that Spin, which I consider to be a nearly perfect language for the Prop, is to shunned in favor of C. Not just people new to the Propeller scene are using PropGCC (it's a great entry point for them) - many people who have been using the Propeller with Spin and PASM for years seem to be switching to C for a reason completely unknown to me. If Spin was designed specifically for the Propeller, and C is such a bad fit for the propeller and not much faster and around the same code size, why would anyone prefer C over Spin?
    It would certainly be interesting to have a C compiler that was custom written for the Propeller or even one based on LLVM. Is that something that you're interested in building?

    You say that Spin is designed for the Propeller but that C isn't a good fit. I'd like to suggest that Spin isn't a very good fit either. Spin is dog slow and has to run on top of a bytecode VM. The truth is, the Propeller isn't designed for high-level languages of any sort. It's great for PASM though. In fact, PropBASIC might be the language best suited for writing programs that run entirely in a COG.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2015-04-15 06:02
    Yikes! I didn't mean to re-ignite the language war. Maybe that would fit better in another thread.

    Thanks for suggestions re my question. That should guide students making their first custom functions to run in a cog.

    One small thing on default cog use with C written in SIDE and the default of CMM Main RAM compact. I see conflicting information. Is this the normal pattern that occurs by default in the simplest case?

    main() in cog 0
    simpletools.h in cog #1
    (if math library) in cog #2
    user-created functions start in cog #3 (#2 if no math library)

    Thanks.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-15 06:38
    All C programs start at main(). As far as I can tell that is always run in COG 0.

    Also as far as I can tell simpletools.h will only add defines and code that will be used from your program. In COG 0 (Unless it actually starts a serial driver or whatever which could be in any other COG)

    Same for the maths functions. They are just code that is called and run on your COG0

    Same for user created functions.

    When do other COGs get used then? I hope the answer to that is only when your program asks for code to be run from other COGs. Either explicitly or implicitly by using some driver from a library. This should be in the documentation for the driver.

    What COGs get used? We do not know. In general when code is started in a COG the next free COG is used, whatever it is.

    Do we need to know what COG is used for what? Not usually.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-04-15 06:50
    Heater. wrote: »
    All C programs start at main(). As far as I can tell that is always run in COG 0.

    Also as far as I can tell simpletools.h will only add defines and code that will be used from your program. In COG 0 (Unless it actually starts a serial driver or whatever which could be in any other COG)

    Same for the maths functions. They are just code that is called and run on your COG0

    Same for user created functions.

    When do other COGs get used then? I hope the answer to that is only when your program asks for code to be run from other COGs. Either explicitly or implicitly by using some driver from a library. This should be in the documentation for the driver.

    What COGs get used? We do not know. In general when code is started in a COG the next free COG is used, whatever it is.

    Do we need to know what COG is used for what? Not usually.
    You're basically right that only COG 0 is used unless you invoke code that explicitly starts another COG. The only exception is if you are using XMM mode where an additional COG is used for the external memory interface driver.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2015-04-15 07:13
    Thanks for correcting my mental model.

    To conclude, this is accurate for students starting cogs for the first time?

    Cog #0 holds main() and any user-defined functions in the main file. Since the #include brings additional functions into main() before it loads, simpletools is also in cog#0. Additional cogs are used only if started by a command. Sometimes that is explicit by int *cog = cog(...). Sometimes a new cog is started implicitly by a high-level function like the servo commands. Exactly which cog is used beyond #0 is not important to us at this level.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-15 07:16
    Sounds like you have it down pat.

    In general no matter if using C or Spin one should use gognew rather than coginit. That way the Propeller sorts out where things end up and you don't have to keep track of which COG is doing what.
Sign In or Register to comment.