Shop OBEX P1 Docs P2 Docs Learn Events
FlexProp: a complete programming system for P2 (and P1) - Page 59 — Parallax Forums

FlexProp: a complete programming system for P2 (and P1)

1535455565759»

Comments

  • ersmithersmith Posts: 6,192

    The idea of interfaces is kind of like structs but for functions (only). So for example you could have something like:

    con
      %interface winio(
        pub puts(p_str)
        pub newline()
    )
    
    pub myfunc(^winio w)
        w.puts(@"hello, world")
        w.newline()
    

    Then any object which implements the puts and newline methods can be passed to the myfunc method.

    I have a tentative implementation for Spin2 checked in to github now, but it's probably buggy. We could also change the way it works a bit, if there are shortcomings we find now.

  • Ah man that is fantastic :) That worked straight away...That's a nice simple syntax and I think it really fills a good space between function pointers and object pointers.
    Thanks a million!

  • RaymanRayman Posts: 15,390

    Getting a strange error when trying to create a .zip archive, described here: https://forums.parallax.com/discussion/176083/3d-teapot-demo#latest

    Very strange because the code compiles fine. This is with latest release.
    Doesn't like this line: _setbaud(2_000_000)

    Gives this error:
    D:/Propeller2/9DOF/teapot_demo3_2/teapot_demo3_2_wIMU2.spin2:93: error: unknown identifier _setbaud used in function call
    error: Unable to write file padmap_builtin.dat to zip
    child process exited abnormally

  • ersmithersmith Posts: 6,192

    The setbaud error is spurious (I've fixed it in github, but it won't prevent a .zip file from being created). The real problem is on the next line:

     error: Unable to write file padmap_builtin.dat to zip
    

    it's missing a file that's referred to in the source code. As it happens in your configuration that file isn't needed (it's inside an if clause that's false) so you can work around it by creating an empty file named padmap_builtin.dat, or else comment out the file "padmap_builtin.dat" line in usbnew.zip.

  • I already complained about this. https://github.com/totalspectrum/spin2cpp/issues/450
    Strange behaviors when trying to make zip files.

  • ersmithersmith Posts: 6,192

    @Wuerfel_21 said:
    I already complained about this. https://github.com/totalspectrum/spin2cpp/issues/450
    Strange behaviors when trying to make zip files.

    This is WAI -- if you want to distribute a zip file which contains conditional parts, it's actually reasonable to check that all of the conditional parts are there. Otherwise if the receiver changes their configuration then they won't be able to build.

    (Unfortunately this is inconsistent between if and #ifdef, because the preprocessor runs before everything else and erases the #ifdef'd parts so the zip file processor never even gets to see them. That is a bug, but it's hard to fix. So for now, at least, if you really don't want to package the whole thing, use #ifdef on the parts you don't have.)

  • But in this case it's a user-supplied file, it doesn't exist if it doesn't need to.

  • RaymanRayman Posts: 15,390

    Could it just make the zip and issue any warning messages it wants to?

  • ersmithersmith Posts: 6,192

    @Wuerfel_21 said:
    But in this case it's a user-supplied file, it doesn't exist if it doesn't need to.

    Then maybe there should be a sample one, or an empty one, in the archive as shipped. Or use #ifdef around the file statement instead of if.

    @Rayman said:
    Could it just make the zip and issue any warning messages it wants to?

    If it can't find a file that's supposed to be included in the zip that seems like a potential recipe for disaster. It's good in some cases (when the file deliberately isn't present, as in Ada's example) but bad if the user really did mean to have the file but forgot to copy it to somewhere flexspin can find it.

  • RaymanRayman Posts: 15,390

    Think the Prop Tool will only create a zip file if the main file can compile (or was compiled? not sure, but one of those). Maybe that check is good enough?

  • Can't be #ifdef because it's CON configuration.

    The file not neccesarily being present is a feature, I think most people do not want a zero-byte file related to a gamepad mapping feature that may not even be compiled in at all cluttering up their project dir.

  • Possible solution might be to somehow annotate the intent, but uhhh don't ask me how.

  • Hi,
    I would like to be able to call a C-function from my XBYTE machine.
    The function has no parameters and no result.
    void fibo46(void) {
    PR0= 12345;
    }

    This does not work:
    PR1=(int)&fibo46;
    __asm { // const?
    call PR1
    };

    How do I get the actual address of the function?

    Thanks for any hints!
    Christof

  • ersmithersmith Posts: 6,192

    C function pointers are implemented the same as Spin2 method pointers and C++ method pointers, namely (in assembly) they are a 32 bit number containing a 12 bit index into the global method table and a 20 bit pointer to the object data. So calling them is a little bit complicated. The easiest way to see how this works is to compile a little test program like:

    void foo(void) {
        __builtin_printf("foo called\n");
    }
    
    void (*fptr)(void) = &foo;
    
    void main() {
        (*fptr)();
    }
    

    The generated code looks like (I've added comments to describe what is happening):

    00984     49 A5 02 FB |     rdlong  local01, ptr__dat__   ' fetch fptr
    00988     52 A7 02 F6 |     mov local02, local01      ' make a copy
    0098c     13 A4 46 F7 |     zerox   local01, #19          ' extract object pointer
    00990     14 A6 46 F0 |     shr local02, #20          ' extract method index
    00994     02 A6 66 F0 |     shl local02, #2
    00998     44 A7 02 F1 |     add local02, __methods__
    0099c     53 A7 02 FB |     rdlong  local02, local02      ' load address of function
    009a0     47 A9 02 F6 |     mov local03, objptr       ' save old object pointer
    009a4     52 8F 02 F6 |     mov objptr, local01       ' set new object pointer
    009a8     2D A6 62 FD |     call    local02               ' call function
    009ac     54 8F 02 F6 |     mov objptr, local03       ' restore object pointer
    

    I realize this is overkill and a little frustrating for a simple static C function that doesn't access any member variables. I think in the next release I will add a && operator that extracts the raw function address, with the caveat that the caller must ensure the object pointer is set correctly before calling it.

  • Thank you @ersmith,
    unfortunately methods seems not to be available during compilation.
    (I am surprised, that you can use the tiny hardware stack for this...)
    Christof

  • @"Christof Eb." said:
    (I am surprised, that you can use the tiny hardware stack for this...)

    The variable push/pop prologue/epilogue that non-leaf functions have also pops the top level of the HW stack and restores it afterward. Nice little optimization.

    @ersmith said:
    I realize this is overkill and a little frustrating for a simple static C function that doesn't access any member variables. I think in the next release I will add a && operator that extracts the raw function address, with the caveat that the caller must ensure the object pointer is set correctly before calling it.

    :+1::+1::+1:

    How would the raw function ptr be distinguished? I think that needs some sort of type annotation, which I guess would have to look something like void (__rawfunc * foo)(void) = &&bar; (ugh C syntax)

    (Speaking of overkill, can we also get rid of remaining cases where regular benign code generates calls to gc_alloc functions?)

  • ersmithersmith Posts: 6,192

    @Wuerfel_21 said:

    How would the raw function ptr be distinguished? I think that needs some sort of type annotation, which I guess would have to look something like void (__rawfunc * foo)(void) = &&bar; (ugh C syntax)

    No, &&bar would just be a plain void *. This is kind of like the GNU C &&label extension, which returns a void * which is only valid for goto. I'll probably try to add that as well. The use on a function identifier Isn't intended for calling from C, it's for generating an object which PASM can easily use.

    (Speaking of overkill, can we also get rid of remaining cases where regular benign code generates calls to gc_alloc functions?)

    There's a long standing open bug for fixing stack allocation. If we can do that then we can replace most of the gc_alloc uses with __builtin_alloca. I don't think it's too bad, but it's sufficiently complex that I haven't gotten to it yet.

  • Christof Eb.Christof Eb. Posts: 1,371
    edited 2025-07-22 08:11

    Hm, tried to use the return address on the stack somehow to get the methods offset somehow. Need a better idea:

    void getMethods1(void) __attribute__(no_inline)
    {
        __asm { // const?
            pop PR0
            push PR0
            sub PR0,#4  // not correct          
        };
    }
    
    int offset;
    int dummy;
    
    void getMethods2(void) {
        getMethods1();
        offset=PR0-((int)(&getMethods2)>>18&(~3));
            dummy=(int)&getMethods1; // suppress inline- does not work  
    }   
    

    I there a way to suppress inlining?
    Thank you!

  • ersmithersmith Posts: 6,192
    edited 2025-07-22 10:48

    You want __attribute__(noinline), not __attribute__(no_inline). Something like:

    unsigned getcalleraddr(void) __attribute__((noinline))
    {
        unsigned r;
        __asm {
            pop r
            push r
            zerox r, #19 /* remove CZ bits */
        }
        return r;
    }
    
  • Thanks! it was just a guess, did not find it in the docs.

  • Hm this works, but is idiotic, and can we rely on it?

    void getMethods1(void) __attribute__(noinline)
    {
        __asm { // const?
            pop PR0
            push PR0
            zerox PR0, #19 /* remove CZ bits */
            sub PR0,#12  // correct ???         
        };
    }
    
    int methodTable=0;
    
    void getMethods2(void) {
        getMethods1();
        int index1=(((int)&getMethods2)>>20)<<2;
        printf("Startaddr: %x \n",PR0); 
        for(int i=0;i<512*1024;i+=4) { // search for magic number = startaddress
            if(PR0==*(int*)i) { 
                methodTable=i-index1;
                printf("Tablestart: %x \n", methodTable);
            }
        }       
    }    
    
  • evanhevanh Posts: 16,605

    That's quite a good candidate for fixing into lutRAM, ie: void getMethods1(void) __attribute__(lut)
    It's a tiny routine so doesn't take much of lutRAM, and you get the bonus speed benefit of branching into cog space rather than hubRAM.

  • ersmithersmith Posts: 6,192

    @"Christof Eb." said:
    Hm this works, but is idiotic, and can we rely on it?

    No, it will probably fail in "exciting" ways sometimes :(.

    I've pushed some code to github so that @@@func returns the address of the first instruction of a function; this should work in all 3 languages and in both bytecode and assembly output. I had hoped to implement the GCC && syntax for both labels and functions, but getting addresses of local labels is complicated and so I've left that alone for the time being.

    Note that @@@func is not a compile time constant, so it can't go in DAT sections or static initializers. Someday I hope to fix that.

  • @ersmith said:

    I've pushed some code to github so that @@@func returns the address of the first instruction of a function; this should work in all 3 languages and in both bytecode and assembly output. I had hoped to implement the GCC && syntax for both labels and functions, but getting addresses of local labels is complicated and so I've left that alone for the time being.

    Hi, thank you very much for @@@func!
    Unfortunately I have not found a fresh release. I have never tried to compile flexprop. So I am looking forward for the next release.

    Christof

  • pik33pik33 Posts: 2,414

    Go to spin2cpp github, click actions, select the last commit, download the compiled version for win or linux. You have to be logged in github to do this. Then unpack downloaded zip and overwrite files in your flexprop with the new version.

  • Thanks @pik33 so far I have no github account. :D

  • evanhevanh Posts: 16,605
    edited 2025-07-23 09:53

    Another option, which doesn't need a login, is to use git directly.

    $ git clone https://github.com/totalspectrum/spin2cpp
    Cloning into 'spin2cpp'...
    remote: Enumerating objects: 47833, done.
    remote: Counting objects: 100% (548/548), done.
    remote: Compressing objects: 100% (254/254), done.
    remote: Total 47833 (delta 390), reused 397 (delta 294), pack-reused 47285 (from 3)
    Receiving objects: 100% (47833/47833), 20.26 MiB | 9.31 MiB/s, done.
    Resolving deltas: 100% (34251/34251), done.
    
    $ cd spin2cpp
    $ make clean; make
    [compiling text spews forth]
    

    Then copy flexspin binary from the resulting build directory into your shell search path
    And copy the includes to your compiler includes directory. In my case, this is right next to the binary path directory. I delete the entire old includes directory tree then replace it. Flexspin searches for includes there as one of its defaults.
    Flexprop will also have a particular path for each if you're using that.

    From this point on you can update the sources by opening a shell in the spin2cpp source code directory and using

    $ git pull
    [updating details]
    

    It pays to examine what has actually been updated. Sometimes the includes are untouched. Then you only need to copy the binary after compiling.

    $ make clean; make
    [compiling text spews forth]
    

    Then copy flexspin binary and the includes.
    You'll note I issue a make clean. That's quite important to delete the prior build directory contents.

  • ersmithersmith Posts: 6,192

    I will be making a release soon (in the next day or two, I hope).

  • ersmithersmith Posts: 6,192

    I've released FlexProp 7.4.1 on both Patreon and github. Besides the @@@func feature mentioned above, it also has many bug fixes to structure handling, some bug fies for inline assembly, and some optimization improvements thanks to @Wuerfel_21

  • @ersmith said:
    I've released FlexProp 7.4.1 on both Patreon and github. Besides the @@@func feature mentioned above, it also has many bug fixes to structure handling, some bug fies for inline assembly, and some optimization improvements thanks to @Wuerfel_21

    Thank you!

    I like the enhancements of the docu !

    Perhaps you might add something in the memory map section about PR0....PR7, like
    Predefined PR0–PR7 extern register int variables are located in COG memory at $1D8–$1DF and can be used to communicate between assembler and high level language.

Sign In or Register to comment.