The idea of interfaces is kind of like structs but for functions (only). So for example you could have something like:
con
%interface winio(
pubputs(p_str)pubnewline()
)
pubmyfunc(^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!
Very strange because the code compiles fine. This is with latest release.
Doesn't like this line: _setbaud(2_000_000)
Gives this error: /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
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.
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.)
@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.
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?
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.
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
};
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:
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.
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?)
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.
Hm, tried to use the return address on the stack somehow to get the methods offset somehow. Need a better idea:
voidgetMethods1(void) __attribute__(no_inline){
__asm { // const?
pop PR0
push PR0
sub PR0,#4// not correct
};
}
int offset;
int dummy;
voidgetMethods2(void){
getMethods1();
offset=PR0-((int)(&getMethods2)>>18&(~3));
dummy=(int)&getMethods1; // suppress inline- does not work
}
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.
@"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.
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.
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.
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.
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.
Comments
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
andnewline
methods can be passed to themyfunc
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!
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:
/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
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 namedpadmap_builtin.dat
, or else comment out thefile "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.
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.
Could it just make the zip and issue any warning messages it wants to?
Then maybe there should be a sample one, or an empty one, in the archive as shipped. Or use
#ifdef
around thefile
statement instead ofif
.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.
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
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
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.
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?)
No,
&&bar
would just be a plainvoid *
. This is kind of like the GNU C&&label
extension, which returns avoid *
which is only valid forgoto
. 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.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.
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!
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); } } }
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.
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.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
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.
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 resultingbuild
directory into your shell search pathAnd 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.I will be making a release soon (in the next day or two, I hope).
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_21Thank 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.