Shop OBEX P1 Docs P2 Docs Learn Events
propeller2.h for C compilers - Page 5 — Parallax Forums

propeller2.h for C compilers

1235789

Comments

  • RossHRossH Posts: 5,476
    samuell wrote: »
    That means "propeller2.h" should include only what is needed for it to perform, and should only handle P2 related stuff (I/O pin direction and latches/inputs/outputs, smartpins, DACs, ADCs, CORDIC stuff, registers and the works). And that is plenty to handle (don't need to make system.d out of it).

    I think we are pretty close with the currently proposed propeller2.h
  • RossHRossH Posts: 5,476
    ersmith wrote: »
    I'm not sure how Catalina works, but for some compilers once a global name is used (for example in a library) then any other use of it could conflict. That is, for some compilers if we use OUTA or INA in a library function, e.g. to bit-bang serial, then any user variable named OUTA or INA will conflict with it. So it would be safer to put an underscore in front of those names. We could then provide a #define for an alias -- that's OK, since the preprocessor only affects things in the single file being compiled.

    I think we may be overdoing the underscores a bit, but ok.

    Catalina will have a function called _outa(), a global variable called _OUTA and a #defined OUTA

    What could possibly go wrong? :)
  • RossH wrote: »
    ersmith wrote: »
    I'm not sure how Catalina works, but for some compilers once a global name is used (for example in a library) then any other use of it could conflict. That is, for some compilers if we use OUTA or INA in a library function, e.g. to bit-bang serial, then any user variable named OUTA or INA will conflict with it. So it would be safer to put an underscore in front of those names. We could then provide a #define for an alias -- that's OK, since the preprocessor only affects things in the single file being compiled.

    I think we may be overdoing the underscores a bit, but ok.

    Catalina will have a function called _outa(), a global variable called _OUTA and a #defined OUTA

    What could possibly go wrong? :)

    Isn't case sensitivity wonderful? :)

    What does the _outa() function do? Does it return the contents of the OUTA register? If so that's very useful, and I think I'll adopt it as well.
  • case sensitivity is not wonderful, but a mess.

    Mike
  • samuellsamuell Posts: 554
    edited 2019-07-05 01:40
    ersmith wrote: »
    RossH wrote: »
    ersmith wrote: »
    I'm not sure how Catalina works, but for some compilers once a global name is used (for example in a library) then any other use of it could conflict. That is, for some compilers if we use OUTA or INA in a library function, e.g. to bit-bang serial, then any user variable named OUTA or INA will conflict with it. So it would be safer to put an underscore in front of those names. We could then provide a #define for an alias -- that's OK, since the preprocessor only affects things in the single file being compiled.

    I think we may be overdoing the underscores a bit, but ok.

    Catalina will have a function called _outa(), a global variable called _OUTA and a #defined OUTA

    What could possibly go wrong? :)

    Isn't case sensitivity wonderful? :)

    What does the _outa() function do? Does it return the contents of the OUTA register? If so that's very useful, and I think I'll adopt it as well.
    _outa() would be similar to getpin(), except it wouldn't use a mask to mask out other pins except the pretended one, right?

    Anyway, as long as you are consistent throughout. And don't use cryptic names, but simple names that covey the real meaning of what the function really does (eg: getdir(int pin), setdir(int pin), getpin(int pin), getlatch(int pin), setpin(int pin)...).
    msrobots wrote: »
    case sensitivity is not wonderful, but a mess.

    Mike
    It performs miracles and avoids disasters. Works great on Linux for filenames too.

    Kind regards, Samuel Lourenço
  • RossHRossH Posts: 5,476
    ersmith wrote: »
    What does the _outa() function do? Does it return the contents of the OUTA register? If so that's very useful, and I think I'll adopt it as well.

    That is true for _ina(), but it is a bit more complicated for _outa() and _dira(). Here are the details:
    /*
     * Special Register access functions - you can either use these functions,
     * or use the Special Register definitions directly (note that you also 
     * need to include <propeller.h> to do that). For example:
     *    
     *    x = _ina()        is equivalent to    x = INA
     *    x = _get_dira()   is equivalent to    x = DIRA
     *    _dira(m,d)        is equivalent to    DIRA = ((DIRA & ~m) | d)
     *    _dira(0,d)        is equivalent to    DIRA |= d
     *    _dira(m,0)        is equivalent to    DIRA &= ~m
     *
     * NOTE: _inb, _dirb and _outb (or INB, DIRB, OUTB) are not implemented on 
     *       the propeller v1
     */
    
    extern unsigned _ina();
    extern unsigned _inb();
    
    extern unsigned _get_dira();
    extern unsigned _get_dirb();
    
    extern unsigned _dira(unsigned mask, unsigned direction);
    extern unsigned _dirb(unsigned mask, unsigned direction);
    
    extern unsigned _outa(unsigned mask, unsigned output);
    extern unsigned _outb(unsigned mask, unsigned output);
    
    

    In hindsight, for consistency I should have made _dira() just return the current value of the register, and used something like _set_dira() to set the value.

    I could be convinced to change, because the compiler would detect the change and alert you to any old code that needed to be updated.
  • Does Catalina support variadic macros? If so we could get fancy and have:
      x = _outa(); // reads outa
      _outa(y);      // sets outa to y
      _outa(m, d); // sets outa to (outa & ~m) | d
    
    Or maybe just changing the function names to be consistent would be better.
  • RossHRossH Posts: 5,476
    .
    ersmith wrote: »
    Does Catalina support variadic macros? If so we could get fancy and have:
      x = _outa(); // reads outa
      _outa(y);      // sets outa to y
      _outa(m, d); // sets outa to (outa & ~m) | d
    
    Or maybe just changing the function names to be consistent would be better.

    The Catalina preprocessor in independent of the compiler, and could fairly easily be replaced with one that accepts variadic macros. There are several such "open source" options available. I may look into that when I get time - if ever! :(

    In the meantime, I will look at just changing the function names. I could easily change them just for just the P2, but I am wondering whether I should also go back and change them for the P1. It would be preferable to keep them consistent.

  • RossH wrote: »
    .

    The Catalina preprocessor in independent of the compiler, and could fairly easily be replaced with one that accepts variadic macros. There are several such "open source" options available. I may look into that when I get time - if ever! :(

    In the meantime, I will look at just changing the function names. I could easily change them just for just the P2, but I am wondering whether I should also go back and change them for the P1. It would be preferable to keep them consistent.

    mcpp (mcpp.sourceforge.net) is a nice one that's easy to integrate into other projects. But that would be more work than changing the names, obviously :).

    Anyway, I do like your register accessor functions -- having the mask and or value is very elegant, and doing the access through functions makes register access possible in compilers where the COG memory space is hard to access via C variables. It also makes porting P1 programs to P2 easier, since for example the P1 CNT register no longer exists on P2, so you were really thinking ahead there!
  • RossHRossH Posts: 5,476
    Just to keep this thread up to date, here is the currently proposed "propeller2.h" ...
    #ifndef __PROPELLER2__H
    #define __PROPELLER2__H
    
    /*
     * special cog register names (the actual types are compiler dependent):
     */
    
    extern volatile uint32_t _IJMP3; 
    extern volatile uint32_t _IRET3;
    extern volatile uint32_t _IJMP2;
    extern volatile uint32_t _IRET2;
    extern volatile uint32_t _IJMP1;
    extern volatile uint32_t _IRET1;
    extern volatile uint32_t _PA;
    extern volatile uint32_t _PB;
    extern volatile uint32_t _PTRA;
    extern volatile uint32_t _PTRB;
    extern volatile uint32_t _DIRA;
    extern volatile uint32_t _DIRB;
    extern volatile uint32_t _OUTA;
    extern volatile uint32_t _OUTB;
    extern volatile uint32_t _INA;
    extern volatile uint32_t _INB;
    
    /*
     * For compatibility with previous programs, where the special register
     * names did not have the leading underscore, we provide the #defines 
     * to allow older programs to work with the new names:
     */
    #define DIRA _DIRA
    #define INA  _INA
    #define OUTA _OUTA
    #define DIRB _DIRB
    #define INB  _INB
    #define OUTB _OUTB
    
    /*
     * common definitions
     */
    
    #define ANY_COG 0x10
    
    /*
     * common types
     */
    
    // cartesian coordinates
    typedef struct _cartesian {
       int32_t x, y;
    } cartesian;
    
    // polar coordinates
    typedef struct _polar {
       uint32_t r, t;
    } polar;
    
    /*
     * P2 32 Bit Clock Mode (see macros below to construct)
     *
     *      0000_000e_dddddd_mmmmmmmmmm_pppp_cc_ss
     *
     *   e          = XPLL (0 = PLL Off, 1 = PLL On)
     *   dddddd     = XDIV (0 .. 63, crystal divider => 1 .. 64)
     *   mmmmmmmmmm = XMUL (0 .. 1023, crystal multiplier => 1 .. 1024)
     *   pppp       = XPPP (0 .. 15, see macro below)
     *   cc         = XOSC (0 = OFF, 1 = OSC, 2 = 15pF, 3 = 30pF)
     *   ss         = XSEL (0 = rcfast, 1 = rcslow, 2 = XI, 3 = PLL)
     */
    
    // macro to calculate XPPP (1->15, 2->0, 4->1, 6->2 ... 30->14) ...
    #define XPPP(XDIVP) ((((XDIVP)>>1)+15)&0xF)  
    
    // macro to combine XPLL, XDIV, XDIVP, XOSC & XSEL into a 32 bit CLOCKMODE ...
    #define CLOCKMODE(XPLL,XDIV,XMUL,XDIVP,XOSC,XSEL) ((XPLL<<24)+((XDIV-1)<<18)+((XMUL-1)<<8)+(XPPP(XDIVP)<<4)+(XOSC<<2)+XSEL) 
    
    // macro to calculate final clock frequency ...
    #define CLOCKFREQ(XTALFREQ, XDIV, XMUL, XDIVP) ((XTALFREQ)/(XDIV)*(XMUL)/(XDIVP))
    
    /*
     * pre-defined functions
     */
    
    void      _clkset(uint32_t clkmode, uint32_t clkfreq);
    void      _hubset(uint32_t val);
    
    int       _coginit(int cog, void *pgm, void *ptr);
    void      _cogstop(int cog);
    
    int       _cogid(void);
    int       _cogchk(int cog);
    
    int       _locknew(void);
    void      _lockret(int lock);
    
    int       _locktry(int lock);
    int       _lockrel(int lock);
    int       _lockchk(int lock);
    
    void      _cogatn(uint32_t mask);
    int       _pollatn(void);
    int       _waitatn(void);
    
    cartesian _rotxy(cartesian coord, uint32_t t);
    cartesian _polxy(polar coord);
    polar     _xypol(cartesian coord);
    
    uint32_t  _rnd(void);
    
    uint32_t  _cnt(void);
    uint32_t  _pollcnt(uint32_t tick);
    void      _waitcnt(uint32_t tick);
    
    void      _waitx(uint32_t tick);
    
    void      _pinw(int pin, int val);
    void      _pinl(int pin);
    void      _pinh(int pin);
    void      _pinnot(int pin);
    void      _pinrnd(int pin);
    void      _pinf(int pin);
    int       _pin(int pin);
    
    void      _wrpin(int pin, int val);
    void      _wxpin(int pin, int val);
    void      _wypin(int pin, int val);
    void      _akpin(int pin);
    int       _rdpin(int pin);
    int       _rqpin(int pin);
    
    void      _bytemove(void *dst, void *src, uint32_t cnt);
    void      _bytefill(void *dst, uint8_t val, uint32_t cnt);
    void      _wordmove(void *dst, void *src, uint32_t cnt);
    void      _wordfill(void *dst, uint16_t val, uint32_t cnt);
    void      _longmove(void *dst, void *src, uint32_t cnt);
    void      _longfill(void *dst, uint32_t val, uint32_t cnt);
    
    uint32_t  _strsize(void *adr);
    int       _strcomp(void *adra, void *adrb);
    
    #endif
    
    

    Still waiting for someone - anyone - to come up with some definitions for Smart Pin configurations ...
  • I agree with Eric that the *move and *fill functions need to go away.

    I also agree with him that creating a type "polar" is not good. You are far too likely to conflict with what a user would like to name their own variable. polar_t please.

    And finally, would you be alright using "unsigned int" for parameters that take a pin number?
  • Here's my proposal, based on Ross's example. I think we're pretty close to agreement on most things. @DavidZemon I've left the pin number as "int" for now, but perhaps "unsigned int" would be better. I also haven't put in the register access functions.

    @cgracey : you listed PINL, PINH, etc. functions in Spin, but how about the OUTx, DIRx, and FLTx variants? Should there be versions of those as well?
    #ifndef __PROPELLER2__H
    #define __PROPELLER2__H
    
    #include <stdint.h>
    
    /*
     * special cog register names (the actual types are compiler dependent)
     * Not all compilers will necessarily support these
     */
    
    extern volatile uint32_t _IJMP3; 
    extern volatile uint32_t _IRET3;
    extern volatile uint32_t _IJMP2;
    extern volatile uint32_t _IRET2;
    extern volatile uint32_t _IJMP1;
    extern volatile uint32_t _IRET1;
    extern volatile uint32_t _PA;
    extern volatile uint32_t _PB;
    extern volatile uint32_t _PTRA;
    extern volatile uint32_t _PTRB;
    extern volatile uint32_t _DIRA;
    extern volatile uint32_t _DIRB;
    extern volatile uint32_t _OUTA;
    extern volatile uint32_t _OUTB;
    extern volatile uint32_t _INA;
    extern volatile uint32_t _INB;
    
    /*
     * For compatibility with previous programs, where the special register
     * names did not have the leading underscore, we provide the #defines 
     * to allow older programs to work with the new names:
     */
    #define DIRA _DIRA
    #define INA  _INA
    #define OUTA _OUTA
    #define DIRB _DIRB
    #define INB  _INB
    #define OUTB _OUTB
    
    /*
     * common definitions
     */
    
    #define ANY_COG 0x10
    
    /*
     * common types
     */
    
    // cartesian coordinates
    typedef struct _cartesian {
       int32_t x, y;
    } cartesian_t;
    
    // polar coordinates
    typedef struct _polar {
       uint32_t r, t;
    } polar_t;
    
    /*
     * P2 32 Bit Clock Mode (see macros below to construct)
     *
     *      0000_000e_dddddd_mmmmmmmmmm_pppp_cc_ss
     *
     *   e          = XPLL (0 = PLL Off, 1 = PLL On)
     *   dddddd     = XDIV (0 .. 63, crystal divider => 1 .. 64)
     *   mmmmmmmmmm = XMUL (0 .. 1023, crystal multiplier => 1 .. 1024)
     *   pppp       = XPPP (0 .. 15, see macro below)
     *   cc         = XOSC (0 = OFF, 1 = OSC, 2 = 15pF, 3 = 30pF)
     *   ss         = XSEL (0 = rcfast, 1 = rcslow, 2 = XI, 3 = PLL)
     */
    
    // macro to calculate XPPP (1->15, 2->0, 4->1, 6->2 ... 30->14) ...
    #define XPPP(XDIVP) ((((XDIVP)>>1)+15)&0xF)  
    
    // macro to combine XPLL, XDIV, XDIVP, XOSC & XSEL into a 32 bit CLOCKMODE ...
    #define CLOCKMODE(XPLL,XDIV,XMUL,XDIVP,XOSC,XSEL) ((XPLL<<24)+((XDIV-1)<<18)+((XMUL-1)<<8)+(XPPP(XDIVP)<<4)+(XOSC<<2)+XSEL) 
    
    // macro to calculate final clock frequency ...
    #define CLOCKFREQ(XTALFREQ, XDIV, XMUL, XDIVP) ((XTALFREQ)/(XDIV)*(XMUL)/(XDIVP))
    
    /*
     * pre-defined functions
     */
    
    void      _clkset(uint32_t clkmode, uint32_t clkfreq);
    void      _hubset(uint32_t val);
    
    int       _coginit(int cog, void *pgm, void *ptr);
    #define _cognew(pgm, ptr) _coginit(ANY_COG, pgm, ptr)
    
    void      _cogstop(int cog);
    
    int       _cogid(void);
    int       _cogchk(int cog);
    
    int       _locknew(void);
    void      _lockret(int lock);
    
    int       _locktry(int lock);
    int       _lockrel(int lock);
    int       _lockchk(int lock);
    
    void      _cogatn(uint32_t mask);
    int       _pollatn(void);
    int       _waitatn(void);
    
    cartesian_t _rotxy(cartesian_t coord, uint32_t t);
    cartesian_t _polxy(polar_t coord);
    polar_t     _xypol(cartesian_t coord);
    
    uint32_t  _rnd(void);
    
    uint32_t  _cnt(void);
    uint32_t  _pollcnt(uint32_t tick);
    void      _waitcnt(uint32_t tick);
    
    void      _waitx(uint32_t delay);
    
    void      _pinw(int pin, int val);
    void      _pinl(int pin);
    void      _pinh(int pin);
    void      _pinnot(int pin);
    void      _pinrnd(int pin);
    void      _pinf(int pin);
    int       _pin(int pin);
    
    void      _wrpin(int pin, uint32_t val);
    void      _wxpin(int pin, uint32_t val);
    void      _wypin(int pin, uint32_t val);
    void      _akpin(int pin);
    uint32_t  _rdpin(int pin);
    uint32_t  _rqpin(int pin);
    
    #endif
    
    
  • I'm not sure that these should be in propeller2.h. Don't they basically undo what the underscore is supposed to achieve. Any program that includes propeller2.h can't use those symbols in any other way without a conflict with the macros. I suppose it would be possible to #undef them but it wouldn't be transparent usage.
    /*
     * For compatibility with previous programs, where the special register
     * names did not have the leading underscore, we provide the #defines 
     * to allow older programs to work with the new names:
     */
    #define DIRA _DIRA
    #define INA  _INA
    #define OUTA _OUTA
    #define DIRB _DIRB
    #define INB  _INB
    #define OUTB _OUTB
    
  • Maybe put an "#ifndef PROPELLER2_NO_SHORTHANDS" around anything that may conflict with user stuff in ported programs (programs written specifically for P2 will likely not want to have those annoying underscores everywhere, i'd assume)
  • David Betz wrote: »
    I'm not sure that these should be in propeller2.h. Don't they basically undo what the underscore is supposed to achieve. Any program that includes propeller2.h can't use those symbols in any other way without a conflict with the macros. I suppose it would be possible to #undef them but it wouldn't be transparent usage.
    /*
     * For compatibility with previous programs, where the special register
     * names did not have the leading underscore, we provide the #defines 
     * to allow older programs to work with the new names:
     */
    #define DIRA _DIRA
    #define INA  _INA
    #define OUTA _OUTA
    #define DIRB _DIRB
    #define INB  _INB
    #define OUTB _OUTB
    

    Agreed. I could even see a "propeller1compat.h" to add macros like this.
  • David Betz wrote: »
    I'm not sure that these should be in propeller2.h. Don't they basically undo what the underscore is supposed to achieve. Any program that includes propeller2.h can't use those symbols in any other way without a conflict with the macros.
    #defines in a header file are OK; they only affect the source file that actually #includes propeller2.h. What we don't want is for any global symbols (functions or variables) to be introduced that could conflict with globals in other source files.

    In other words, any source code that has "#include <propeller2.h>" in it is already not standard conforming, and the user is going to have to work around any defines in that file (which should be documented, of course!). What we don't want is for "#include <propeller2.h>" in one file to mess up an unrelated library file or something like that because of a symbol conflict.

  • ersmith wrote: »
    David Betz wrote: »
    I'm not sure that these should be in propeller2.h. Don't they basically undo what the underscore is supposed to achieve. Any program that includes propeller2.h can't use those symbols in any other way without a conflict with the macros.
    #defines in a header file are OK; they only affect the source file that actually #includes propeller2.h. What we don't want is for any global symbols (functions or variables) to be introduced that could conflict with globals in other source files.

    In other words, any source code that has "#include <propeller2.h>" in it is already not standard conforming, and the user is going to have to work around any defines in that file (which should be documented, of course!). What we don't want is for "#include <propeller2.h>" in one file to mess up an unrelated library file or something like that because of a symbol conflict.
    So it's only global symbols that you're worried about. In that case, putting the #defines in the header file should be okay.

  • A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.
  • ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?
  • DavidZemon wrote: »
    ersmith wrote: »
    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?

    That's a good idea. For now the propeller2.h file I put in the RISC-V compiler distribution has separate _cnt() and _cnth() macros, but adding a _cnt64() function as well would make sense.
  • evanhevanh Posts: 16,023
    edited 2019-07-08 05:49
    [deleted]
  • RossHRossH Posts: 5,476
    edited 2019-07-08 06:02
    DavidZemon wrote: »
    ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    These should be functions, not macros.
  • RossHRossH Posts: 5,476
    DavidZemon wrote: »
    ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?

    What will Spin do in this case? Does anyone know?
  • cgraceycgracey Posts: 14,206
    RossH wrote: »
    DavidZemon wrote: »
    ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?

    What will Spin do in this case? Does anyone know?

    Not sure, yet. I'll probably make two different read functions, because most usage will be for the lower 32 bits. Hmmm.... maybe I''ll need 64-bit POLLCNT and WAITCNT, too.
  • RossHRossH Posts: 5,476
    cgracey wrote: »
    RossH wrote: »
    DavidZemon wrote: »
    ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?

    What will Spin do in this case? Does anyone know?

    Not sure, yet. I'll probably make two different read functions, because most usage will be for the lower 32 bits. Hmmm.... maybe I''ll need 64-bit POLLCNT and WAITCNT, too.

    Does Spin2 have a 64 bit data type?
  • cgraceycgracey Posts: 14,206
    RossH wrote: »
    cgracey wrote: »
    RossH wrote: »
    DavidZemon wrote: »
    ersmith wrote: »
    A few more things we forgot:
    // a macro for referencing the system clock frequency
    // by convention this is placed in low HUB RAM at address $14
    #define _clkfreq (*((uint32_t*)0x14))
    #define _clkmode (*((uint32_t*)0x18))
    

    Also, in the "final" P2 chip there will actually be a 64 bit frequency counter, so we'll need a way to fetch the high word of that. @cgracey , is the Spin2 CNT function going to return two values (low and high 32 bits) or will there be two functions CNT for the low and CNTH for the high? The two functions version would be easier for C and slightly more efficient, but having both values returned from CNT might make sense too.

    Cool! Didn't know that. Wouldn't it make sense for C to provide two functions for high and low words, and one function returning a 64-bit var?

    What will Spin do in this case? Does anyone know?

    Not sure, yet. I'll probably make two different read functions, because most usage will be for the lower 32 bits. Hmmm.... maybe I''ll need 64-bit POLLCNT and WAITCNT, too.

    Does Spin2 have a 64 bit data type?

    No. That would take a lot of code to support.
  • ersmithersmith Posts: 6,068
    edited 2019-07-12 15:44
    OK, here's my latest proposal. Again, very close to what @RossH had posted earlier:
    #ifndef __PROPELLER2__H
    #define __PROPELLER2__H
    
    #include <stdint.h>
    
    /*
     * special cog register names (the actual types are compiler dependent)
     * Not all compilers will necessarily support these
     */
    
    extern volatile uint32_t _IJMP3; 
    extern volatile uint32_t _IRET3;
    extern volatile uint32_t _IJMP2;
    extern volatile uint32_t _IRET2;
    extern volatile uint32_t _IJMP1;
    extern volatile uint32_t _IRET1;
    extern volatile uint32_t _PA;
    extern volatile uint32_t _PB;
    extern volatile uint32_t _PTRA;
    extern volatile uint32_t _PTRB;
    extern volatile uint32_t _DIRA;
    extern volatile uint32_t _DIRB;
    extern volatile uint32_t _OUTA;
    extern volatile uint32_t _OUTB;
    extern volatile uint32_t _INA;
    extern volatile uint32_t _INB;
    
    /*
     * For compatibility with previous programs, where the special register
     * names did not have the leading underscore, we provide the #defines 
     * to allow older programs to work with the new names:
     */
    #define DIRA _DIRA
    #define INA  _INA
    #define OUTA _OUTA
    #define DIRB _DIRB
    #define INB  _INB
    #define OUTB _OUTB
    
    /*
     * common definitions
     */
    
    #define ANY_COG 0x10
    
    /*
     * common types
     */
    
    // cartesian coordinates
    typedef struct _cartesian {
       int32_t x, y;
    } cartesian_t;
    
    // polar coordinates
    typedef struct _polar {
       uint32_t r, t;
    } polar_t;
    
    /*
     * P2 32 Bit Clock Mode (see macros below to construct)
     *
     *      0000_000e_dddddd_mmmmmmmmmm_pppp_cc_ss
     *
     *   e          = XPLL (0 = PLL Off, 1 = PLL On)
     *   dddddd     = XDIV (0 .. 63, crystal divider => 1 .. 64)
     *   mmmmmmmmmm = XMUL (0 .. 1023, crystal multiplier => 1 .. 1024)
     *   pppp       = XPPP (0 .. 15, see macro below)
     *   cc         = XOSC (0 = OFF, 1 = OSC, 2 = 15pF, 3 = 30pF)
     *   ss         = XSEL (0 = rcfast, 1 = rcslow, 2 = XI, 3 = PLL)
     */
    
    // macro to calculate XPPP (1->15, 2->0, 4->1, 6->2 ... 30->14) ...
    #define XPPP(XDIVP) ((((XDIVP)>>1)+15)&0xF)  
    
    // macro to combine XPLL, XDIV, XDIVP, XOSC & XSEL into a 32 bit CLOCKMODE ...
    #define CLOCKMODE(XPLL,XDIV,XMUL,XDIVP,XOSC,XSEL) ((XPLL<<24)+((XDIV-1)<<18)+((XMUL-1)<<8)+(XPPP(XDIVP)<<4)+(XOSC<<2)+XSEL) 
    
    // macro to calculate final clock frequency ...
    #define CLOCKFREQ(XTALFREQ, XDIV, XMUL, XDIVP) ((XTALFREQ)/(XDIV)*(XMUL)/(XDIVP))
    
    /*
     * pre-defined functions
     */
    
    void      _clkset(uint32_t clkmode, uint32_t clkfreq);
    void      _hubset(uint32_t val);
    
    /* start PASM code in another COG */
    int       _coginit(int cog, void *pgm, void *ptr);
    #define _cognew(pgm, ptr) _coginit(ANY_COG, pgm, ptr)
    
    /* start C code in another COG */
    int _cogstart(void (*func)(void *), void *arg, void *arg, uint32_t stack_size);
    
    /* stop/check status of COGs */
    void      _cogstop(int cog);
    int       _cogchk(int cog);
    
    int       _cogid(void);
    
    int       _locknew(void);
    void      _lockret(int lock);
    
    int       _locktry(int lock);
    int       _lockrel(int lock);
    int       _lockchk(int lock);
    
    void      _cogatn(uint32_t mask);
    int       _pollatn(void);
    int       _waitatn(void);
    
    cartesian_t _rotxy(cartesian_t coord, uint32_t t);
    cartesian_t _polxy(polar_t coord);
    polar_t     _xypol(cartesian_t coord);
    
    uint32_t  _rnd(void);
    
    uint32_t  _cnt(void);
    uint32_t  _cnth(void); /* high 32 bits of CNT, on processors that support it */
    
    uint32_t  _pollcnt(uint32_t tick);
    void      _waitcnt(uint32_t tick);
    
    void      _waitx(uint32_t delay);
    
    /* regular pin I/O */
    void      _pinw(int pin, int val);
    void      _pinl(int pin);
    void      _pinh(int pin);
    void      _pinnot(int pin);
    void      _pinrnd(int pin);
    void      _pinf(int pin);
    int       _pin(int pin);
    
    /* smart pin controls */
    void      _wrpin(int pin, uint32_t val);
    void      _wxpin(int pin, uint32_t val);
    void      _wypin(int pin, uint32_t val);
    void      _akpin(int pin);
    uint32_t  _rdpin(int pin);
    uint32_t  _rqpin(int pin);
    
    /* access to previously set clock mode and frequency */
    #define _clockfreq() (*(uint32_t *)0x14)
    #define _clockmode() (*(uint32_t *)0x18)
    
    #endif
    

    Changes:

    (1) _clockfreq() and _clockmode() macros. These are the same as the ones Catalina has.

    (2) A new function _cogstart() for starting C code in another COG (_coginit() is for starting PASM code). Some compilers might be able to just use _coginit() for both, but in general the C runtime will need some setup so it seems wise to have a different function for this.

    (3) Multi-word return types are polar_t and cartesian_t. If there are strong objections to these I could certainly live with POLAR and CARTESIAN instead.

    Still missing:

    (1) We're missing some of the cordic functions
    (2) dirh/dirl/dirw, outh/outl/outw
    (3) not sure about the flth/fltl family of instructions... @cgracey , what does "PINF" do in Spin? It sounds like it sets the pin to float, but what exactly does it do to the hardware.

    Any comments / suggestions?

    Current githubs of fastspin and riscvp2 have subsets of this header file, and I plan to update to keep those current.

  • RossHRossH Posts: 5,476
    ersmith wrote: »
    (1) _clockfreq() and _clockmode() macros. These are the same as the ones Catalina has.

    The names are the same, but these are not macros in Catalina, they are functions. But they could be macros on some compilers.
  • cgraceycgracey Posts: 14,206
    "PINF(pin)" in Spin2 will actually do a FLTL in Pasm.
  • @ersmith

    What if the we wrap the "#define DIRA _DIRA" with a guard, such as "#ifndef NO_P1_COMPAT"? Or, personally.... I'd prefer that it be off by default, but I'm guessing that won't be a very popular opinion: "#ifdef P1_COMPAT"

    "int _cogstart(void (*func)(void *), void *arg, void *arg, uint32_t stack_size);"
    incorrectly named "stack" parameter
    Did you really intend to type "stack_size" and not "stackSize"? I'm fine either way, just want to make sure it was on purpose.

    "uint32_t _rnd(void);"
    does this need to be abbreviated, or can it be spelled out as _random()? I first read it as "round()" and before realizing that was probably incorrect. Or maybe the standard C function, rand(), could be used and no special Propeller function is necessary?

    These are all pretty minor comments. Overall, I do like this version a lot.
Sign In or Register to comment.