My pleasure. If I convince Chip to add a clean way of coding hubexec'd pasm routines then I'll come back and put that in for those two divide functions as well.
I could still add a conditional compile for Flexspin's asm/asmend directives. That would enable hubexec with Flexspin right now. But conditional compiling looks messy in the source code and it's not a big advantage to use hubexec so I decided to bug Chip first.
@ersmith Couple questions, nothing that important...
Have a Spin2 SPI code, called from a C program, to start an assembly cog. But, it stopped working at some point.
Problem seems to be that code is expecting the variables; Dpin, Cpin, Value, and pValue to be consecutive in hub ram, but seems that pValue is somewhere else...
I'm not really sure if this is documented to be the case that they are consecutive, but think it used to be and is in Parallax version Spin1 (and Spin2?)
Not really sure if this qualifies as bug or not, might just be bad programming style
Easily fixed, now that I found the problem..
Update: Looks like @Value is before @Dpin and @Dpin, @Cpin, @pValue are in order...
PUB Read8(Dpin, Cpin): Value|pValue 'read 8 bits
pValue:=@Value 'this will be the last parameter
SendCommand(Read8_,@Dpin)
'wait for this command to finish
repeat
until command==0
return Value
Other question: Should assembly debug statements work in a Spin2 file embedded in a C program?
Never mind. See now that need to use "-gbrk"
@Rayman : In Spin1 the return value always comes first in memory, then the parameters, then the local variables. It looks like Chip changed this for Spin2 (yet another incompatibility, sigh!) and unfortunately I didn't realize this. Flexspin still uses the Spin1 memory layout.
@ersmith I just installed Version 5.9.22-beta-v5.9.21-14-g557ac5f1 Compiled on: Dec 17 2022. Editing/compilation works fine, but when I attempt to download and run to a P2-ES Rev C I get the following error:
wrong # args: should be "term_insert s"
wrong # args: should be "term_insert s"
while executing
"term_insert [format %[set space_rem_on_line]s ""] $tag_list"
(procedure "term_clear_to_eos" line 15)
invoked from within
"term_clear_to_eos"
(procedure "process_ansi_csi" line 56)
invoked from within
"process_ansi_csi $cur_save_str $c"
(procedure "term_recv" line 193)
invoked from within
"term_recv $c"
(procedure "::TkTerm::Terminal_Data" line 10)
invoked from within
"::TkTerm::Terminal_Data "
After that... the serial terminal is hung. Reverting to 5.9.21 using the same FlexBASIC code gives successful compilation and download/run, so it seems like this is a 5.9.22 beta thing. FWIW, this is with the Options->Use Internal ANSI Terminal selected.
EDIT: No idea why the forum software is doing monkey-business with the font/bolding. I swear I'm not screaming.
@ersmith Thanks for the explanation. Not sure this kind of thing is documented anywhere, but maybe it is.
I think the code was working at one point this way, but I guess that must have been with the PropTool.
Easily fixed, now that I see what's wrong. But, maybe I should fix it in a way that works with both PropTool and Flexspin...
Think the idea was adapted from P1 code. But there, you didn't have to specify a return value, even if you had one. Must be how that worked without confusion...
Fixed it like this to work with both PropTool and Flexspin:
PUB Read8(Dpin, Cpin): Value|pValue 'read 8 bits
'Note: 24Dec22: Had to adapt code to work with both FlexProp and PropTool.
' FlexProp puts Value before Dpin in memory, but PropTool leaves Value after Cpin
pValue:=Value:=@Value 'This way, the third variable will have @Value in both FlexProp and PropTool
SendCommand(Read8_,@Dpin)
'wait for this command to finish
repeat
until command==0
return Value
@ersmith Is it planned for the near future to implement the byte/word/long array DEBUG commands? They are very useful when dealing with buffers. Or the byte_array can also be used to reverse little-endian to big-endian longs.
@ersmith Is it planned for the near future to implement the byte/word/long array DEBUG commands? They are very useful when dealing with buffers. Or the byte_array can also be used to reverse little-endian to big-endian longs.
I think they're already handled in -gbrk debugging. Doing them in plain -g debugging is a little hard, because in that version DEBUG gets translated into printf, and there's no printf format for printing arrays.
@ersmith said:
I think they're already handled in -gbrk debugging. Doing them in plain -g debugging is a little hard, because in that version DEBUG gets translated into printf, and there's no printf format for printing arrays.
Ok, if has to be done by translating them into calls to a function containing a loop. Not too hard but probably more work than necessary. Can I use -gbrk debugging safely when I use C and Spin2 together? I thought there was some problem with printf() and debug() stomping on each others feet. How can I call printf() in a debug()-friendly manner?
@ersmith said:
I think they're already handled in -gbrk debugging. Doing them in plain -g debugging is a little hard, because in that version DEBUG gets translated into printf, and there's no printf format for printing arrays.
Ok, if has to be done by translating them into calls to a function containing a loop. Not too hard but probably more work than necessary. Can I use -gbrk debugging safely when I use C and Spin2 together? I thought there was some problem with printf() and debug() stomping on each others feet. How can I call printf() in a debug()-friendly manner?
I don't think there's any inherent conflict between gbrk debugging and printf, although if you call debug() from a different COG while a printf is in progress it can interrupt the printf -- the characters should be OK but the debug message will come out in the middle of the printf string.
@ersmith What's going on with "Field"? Looks like it's a reserved word inside debug statements, but should we still be able to use it elsewhere?
Seems all my Spin2 VGA type codes inherited the name "Field" as the start of the field loop. This gives an error now in FlexSpin, but not Prop Tool....
Ok, I see now it's not just for use inside debug statements... But, why doesn't Prop Tool give me an error?
On a more positive note, just found today that some Gameduino examples that didn't work before are now working. Think all your work on C is definitely making it better.
@Rayman said:
@ersmith What's going on with "Field"? Looks like it's a reserved word inside debug statements, but should we still be able to use it elsewhere?
Seems all my Spin2 VGA type codes inherited the name "Field" as the start of the field loop. This gives an error now in FlexSpin, but not Prop Tool....
Ok, I see now it's not just for use inside debug statements... But, why doesn't Prop Tool give me an error?
On a more positive note, just found today that some Gameduino examples that didn't work before are now working. Think all your work on C is definitely making it better.
@cgracey made FIELD a reserved word in Spin2. I don't know if Jeff has updated PropTool to have the new PNut yet, but once he does it will be reserved there too.
@JRoark said:
Happy to report that @ersmith changes to the internal Flex terminal seemed to have cured several random oddities! That was a nice holiday gift.
Defining a union containing fields with conflicting names causes the compiler to crash or at least exit without an error message and without a hint to a line number where the problem is. Example:
typedef struct // Reply HLP header starts at long boundary
{ //rhlp_header
union {
struct { // high level protocol (HLP) header
uint8_t rply_len; // number of HLP data bytes (without rply_len)
uint8_t rply_type;
uint16_t buf_gauge; // number of FIFO entries
uint16_t ref_num; // trace buffer reference
uint8_t status;
int8_t rsv; // padding
int32_t data[MAX_NUMAXES];
uint8_t inputs[MAX_IO_BYTES];
};
struct {
uint8_t rply_len; // number of HLP data bytes (without rply_len)
uint8_t rply_type;
uint8_t version[76]; // Versionsstring für RESCOM
};
};
} Hlp_Reply_Data;
Terminal output:
Version 5.9.21 Compiled on: Dec 6 2022
B2M_main.c
The terminal process "C:\Program Files\Git\bin\bash.exe '--login', '-c', 'flexspin.exe -2 -g -D_BAUD=230400 -Wabs-paths -Wmax-errors=99 B2M_main.c'" terminated with exit code: 2816.
@ManAtWork : Thank you for the bug report. I've fixed the crash when duplicate names are defined for anonymous structures in the current github source code (5.9.23).
@ersmith : Do method pointers in spin1 have any restrictions that spin2 doesn't?
The following code:
obj
ch: "ch1"
pub main() | putchar, getchar
ch.init(@pmethod, @gmethod)
repeat
if ch.g() == 1
repeat
!outa[56]
pub pmethod(c)
outa[26] := c
pub gmethod(): s
return ina[26]
and the child
var
long p, g
pub init(pm, gm)
p := pm
g := gm
pub method1()
p(1)
pub method2(): c
return g():1 ' tried with and without the :1
fails to build with
Press ENTER or type command to continue
Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2022 Total Spectrum Software Inc.
Version 5.9.24-beta-v5.9.23-4-g1b710c54 Compiled on: Jan 2 2023
mp1.spin
|-ch1.spin
mp1.spin:10: error: Object called is not a function
mp1.spin:10: error: Object called is not a function
mp1.spin:10: error: Unhandled indirect FUNCALL symbol
error: bad fixup
Program size: 1336 bytes
Variable size: 1048 bytes
Stack/Free: 30368 bytes
but the equivalent in spin2 builds ok. I haven't yet tried it functionally, but it does seem to build when using the pasm backend.
I have a zmodem utility that I'd originally written as an #include because I couldn't find a better/less invasive way to integrate it with something like a serial connection, but I recently had an epiphany: rewrite it as an object and point it to putchar() and getchar() methods in the serial object. This has worked great so far in spin2, but when trying to backport it to spin1 I encountered the above build failure. I have a fear it may not be possible due to some technical reason, but hope I'm wrong.
BTW method pointers have got to be one of the handiest things...it's a really slick way to fix some problems...thanks for adding support for them!
@avsa242 : I had intended this to work in Spin1, but it's missing some checks. I'll try to add those soon. In the meantime you can work around it by changing the line
if ch.g() == 1
to
if ch.g():1 == 1
(i.e. adding a Spin2 style function return specification to the method pointer call site)
Just out of curiosity, why backport the code to Spin1? Flexspin can build Spin2 code for the P1, including for P1 bytecode output.
@ersmith said:
@avsa242 : I had intended this to work in Spin1, but it's missing some checks. I'll try to add those soon. In the meantime you can work around it by changing the line
if ch.g() == 1
to
if ch.g():1 == 1
(i.e. adding a Spin2 style function return specification to the method pointer call site)
Okay that's simple enough, thanks 👍
Just out of curiosity, why backport the code to Spin1? Flexspin can build Spin2 code for the P1, including for P1 bytecode output.
In principle, I guess there's no real reason I couldn't... I know moving my spin1 lib to spin2 has crossed my mind before, as it takes a lot of extra time to maintain both codebases. I suppose any chip-specific bits could then be handled by preprocessor code within the same file.
Just out of curiosity, why backport the code to Spin1? Flexspin can build Spin2 code for the P1, including for P1 bytecode output.
In principle, I guess there's no real reason I couldn't... I know moving my spin1 lib to spin2 has crossed my mind before, as it takes a lot of extra time to maintain both codebases. I suppose any chip-specific bits could then be handled by preprocessor code within the same file.
Also note that mixing Spin1 and Spin2 objects should work fine in flexspin, so you could keep your older objects in Spin1 and create newer ones in Spin2 (with, as you say, preprocessor code to handle chip specific code). Of course if you want to interoperate with PropTool this wouldn't work but then PropTool doesn't support method pointers in Spin1 at all.
Yeah... when I started working on my library I was trying to keep it all compatible with PropTool but not having things like dead code removal, a preprocessor, and now method pointers make it too limiting (that and never had a great experience using it in Wine).
When I start a function in a seperate cog with _cogstart_C() do I have to pay special attention to pass all variables as arguments of the function or does the function have normal access to global variables?
So the value of rdBuf seems to differ depending on the cog/scope. It could also be that my code accidentally overwrites memory. But before I waste a lot of time I'd like to make sure that I don't do anything fundamentally wrong.
Edit: Ok, I found out that the global variable rdBuf can be accessed normally. If I put the printf() directly at the beginning of MotionLoop() it prints correctly. But I fear there is another compiler bug. printing it inside a switch/case inside a for loop with all other code commented out shows the wrong value, again. I have to extract a small example program that can demonstrate it. At the moment the code is too complex... I'll be back on saturday.
@ManAtWork : Yes, global variables can be accessed by any cog.
If you're running into mysterious failures with code running in another cog, the first thing you should try is to increase the stack size given to that cog (and all the cogs, for that matter). Stack overflow is a common source of problems with multi-cog code.
@ersmith said:
@ManAtWork : ...
If you're running into mysterious failures with code running in another cog, the first thing you should try is to increase the stack size given to that cog (and all the cogs, for that matter). Stack overflow is a common source of problems with multi-cog code.
That was a good hint. Originally, I set the stack size to 256 bytes because the docs recommended 64 or 128 as minimum and my code doesn't include any recursive or deeply nested calls. It's only a single function calling several other functions without many local variables, I mean less than a dozen ints and pointers but no structures or anything else that would take a serious amount of stack space.
But indeed, increasing the stack size from 256 to 512 bytes cured the problem . So I guess that calling (sub-)functions pushes a lot of registers onto the stack. Anyway, no problem, we just need to be aware of it.
Edit: After re-inserting the function calls I have commented out I had to increase the stack size to 1024. This would mean that each sub-function call level needed >256 bytes of stack which I find hard to believe. I fear the increased stack only moved the variables further away from a buffer overflow problem somewhere else in my code. I need to debug this further...
The recommended stack space isn't 128 bytes, it's 128 longs. 128 bytes are just 32 longs, which are used up surprisingly quick. Each stack frame of a non-leaf function takes 3 longs plus any registers that it needs to save (which is roughly equal to the amount of total locals+arguments). Also, the top-level function of a cog (including main) creates a stack frame even though that's completely pointless.
For example:
static long stack[32];
id = __builtin_cogstart(somefunc(a, b), &stac
...
The amount of space required for the stack depends on
code to run, but must be at least 16 longs (64 bytes).
But I don't want to argue, obviously that's not enough.
Yeah, I was thinking of the general adage of 128 long stacks, didn't even know the FlexC doc says that. IDK where that 16 long figure comes from, I think that's not actually the bare minimum, but of course is not enough for any serious code.
@ManAtWork said:
But indeed, increasing the stack size from 256 to 512 bytes cured the problem . So I guess that calling (sub-)functions pushes a lot of registers onto the stack. Anyway, no problem, we just need to be aware of it.
Edit: After re-inserting the function calls I have commented out I had to increase the stack size to 1024. This would mean that each sub-function call level needed >256 bytes of stack which I find hard to believe. I fear the increased stack only moved the variables further away from a buffer overflow problem somewhere else in my code. I need to debug this further...
I just had to extend the allocated stack to 1024 for my watchdog cog. Not sure why either.
*** Mine wasn't with flexpin, so please ignore ***
Comments
Thank you for that, @evanh !
I meant that not having "#include <stdio.h>" doesn't really help because code that isn't used is cut from final binary anyway....
But, I guess that's just the header anyway, so maybe it doesn't matter...
My pleasure. If I convince Chip to add a clean way of coding hubexec'd pasm routines then I'll come back and put that in for those two divide functions as well.
I could still add a conditional compile for Flexspin's
asm/asmend
directives. That would enable hubexec with Flexspin right now. But conditional compiling looks messy in the source code and it's not a big advantage to use hubexec so I decided to bug Chip first.@ersmith Couple questions, nothing that important...
Have a Spin2 SPI code, called from a C program, to start an assembly cog. But, it stopped working at some point.
Problem seems to be that code is expecting the variables; Dpin, Cpin, Value, and pValue to be consecutive in hub ram, but seems that pValue is somewhere else...
I'm not really sure if this is documented to be the case that they are consecutive, but think it used to be and is in Parallax version Spin1 (and Spin2?)
Not really sure if this qualifies as bug or not, might just be bad programming style
Easily fixed, now that I found the problem..
Update: Looks like @Value is before @Dpin and @Dpin, @Cpin, @pValue are in order...
Other question: Should assembly debug statements work in a Spin2 file embedded in a C program?
Never mind. See now that need to use "-gbrk"
@Rayman : In Spin1 the return value always comes first in memory, then the parameters, then the local variables. It looks like Chip changed this for Spin2 (yet another incompatibility, sigh!) and unfortunately I didn't realize this. Flexspin still uses the Spin1 memory layout.
@ersmith I just installed Version 5.9.22-beta-v5.9.21-14-g557ac5f1 Compiled on: Dec 17 2022. Editing/compilation works fine, but when I attempt to download and run to a P2-ES Rev C I get the following error:
wrong # args: should be "term_insert s"
wrong # args: should be "term_insert s"
while executing
"term_insert [format %[set space_rem_on_line]s ""] $tag_list"
(procedure "term_clear_to_eos" line 15)
invoked from within
"term_clear_to_eos"
(procedure "process_ansi_csi" line 56)
invoked from within
"process_ansi_csi $cur_save_str $c"
(procedure "term_recv" line 193)
invoked from within
"term_recv $c"
(procedure "::TkTerm::Terminal_Data" line 10)
invoked from within
"::TkTerm::Terminal_Data "
After that... the serial terminal is hung. Reverting to 5.9.21 using the same FlexBASIC code gives successful compilation and download/run, so it seems like this is a 5.9.22 beta thing. FWIW, this is with the Options->Use Internal ANSI Terminal selected.
EDIT: No idea why the forum software is doing monkey-business with the font/bolding. I swear I'm not screaming.
@ersmith Thanks for the explanation. Not sure this kind of thing is documented anywhere, but maybe it is.
I think the code was working at one point this way, but I guess that must have been with the PropTool.
Easily fixed, now that I see what's wrong. But, maybe I should fix it in a way that works with both PropTool and Flexspin...
Think the idea was adapted from P1 code. But there, you didn't have to specify a return value, even if you had one. Must be how that worked without confusion...
Fixed it like this to work with both PropTool and Flexspin:
@JRoark : a typo crept in for responding to one particular ANSI escape sequence. It should be fixed now in 5.9.22. Thanks for the bug report!
@ersmith Is it planned for the near future to implement the byte/word/long array DEBUG commands? They are very useful when dealing with buffers. Or the byte_array can also be used to reverse little-endian to big-endian longs.
I think they're already handled in -gbrk debugging. Doing them in plain -g debugging is a little hard, because in that version DEBUG gets translated into printf, and there's no printf format for printing arrays.
Ok, if has to be done by translating them into calls to a function containing a loop. Not too hard but probably more work than necessary. Can I use -gbrk debugging safely when I use C and Spin2 together? I thought there was some problem with printf() and debug() stomping on each others feet. How can I call printf() in a debug()-friendly manner?
I don't think there's any inherent conflict between gbrk debugging and printf, although if you call debug() from a different COG while a printf is in progress it can interrupt the printf -- the characters should be OK but the debug message will come out in the middle of the printf string.
@ersmith What's going on with "Field"? Looks like it's a reserved word inside debug statements, but should we still be able to use it elsewhere?
Seems all my Spin2 VGA type codes inherited the name "Field" as the start of the field loop. This gives an error now in FlexSpin, but not Prop Tool....
Ok, I see now it's not just for use inside debug statements... But, why doesn't Prop Tool give me an error?
On a more positive note, just found today that some Gameduino examples that didn't work before are now working. Think all your work on C is definitely making it better.
@cgracey made FIELD a reserved word in Spin2. I don't know if Jeff has updated PropTool to have the new PNut yet, but once he does it will be reserved there too.
Happy to report that @ersmith changes to the internal Flex terminal seemed to have cured several random oddities! That was a nice holiday gift.
Glad it worked for you, Jeff!
Defining a union containing fields with conflicting names causes the compiler to crash or at least exit without an error message and without a hint to a line number where the problem is. Example:
Terminal output:
@ManAtWork : Thank you for the bug report. I've fixed the crash when duplicate names are defined for anonymous structures in the current github source code (5.9.23).
@ersmith : Do method pointers in spin1 have any restrictions that spin2 doesn't?
The following code:
and the child
fails to build with
but the equivalent in spin2 builds ok. I haven't yet tried it functionally, but it does seem to build when using the pasm backend.
I have a zmodem utility that I'd originally written as an #include because I couldn't find a better/less invasive way to integrate it with something like a serial connection, but I recently had an epiphany: rewrite it as an object and point it to
putchar()
andgetchar()
methods in the serial object. This has worked great so far in spin2, but when trying to backport it to spin1 I encountered the above build failure. I have a fear it may not be possible due to some technical reason, but hope I'm wrong.BTW method pointers have got to be one of the handiest things...it's a really slick way to fix some problems...thanks for adding support for them!
@avsa242 : I had intended this to work in Spin1, but it's missing some checks. I'll try to add those soon. In the meantime you can work around it by changing the line
to
(i.e. adding a Spin2 style function return specification to the method pointer call site)
Just out of curiosity, why backport the code to Spin1? Flexspin can build Spin2 code for the P1, including for P1 bytecode output.
Okay that's simple enough, thanks 👍
In principle, I guess there's no real reason I couldn't... I know moving my spin1 lib to spin2 has crossed my mind before, as it takes a lot of extra time to maintain both codebases. I suppose any chip-specific bits could then be handled by preprocessor code within the same file.
Also note that mixing Spin1 and Spin2 objects should work fine in flexspin, so you could keep your older objects in Spin1 and create newer ones in Spin2 (with, as you say, preprocessor code to handle chip specific code). Of course if you want to interoperate with PropTool this wouldn't work but then PropTool doesn't support method pointers in Spin1 at all.
Yeah... when I started working on my library I was trying to keep it all compatible with PropTool but not having things like dead code removal, a preprocessor, and now method pointers make it too limiting (that and never had a great experience using it in Wine).
When I start a function in a seperate cog with _cogstart_C() do I have to pay special attention to pass all variables as arguments of the function or does the function have normal access to global variables?
I ask because I have this strange phenomenon, it outputs
So the value of rdBuf seems to differ depending on the cog/scope. It could also be that my code accidentally overwrites memory. But before I waste a lot of time I'd like to make sure that I don't do anything fundamentally wrong.
Edit: Ok, I found out that the global variable rdBuf can be accessed normally. If I put the printf() directly at the beginning of MotionLoop() it prints correctly. But I fear there is another compiler bug. printing it inside a switch/case inside a for loop with all other code commented out shows the wrong value, again. I have to extract a small example program that can demonstrate it. At the moment the code is too complex... I'll be back on saturday.
@ManAtWork : Yes, global variables can be accessed by any cog.
If you're running into mysterious failures with code running in another cog, the first thing you should try is to increase the stack size given to that cog (and all the cogs, for that matter). Stack overflow is a common source of problems with multi-cog code.
That was a good hint. Originally, I set the stack size to 256 bytes because the docs recommended 64 or 128 as minimum and my code doesn't include any recursive or deeply nested calls. It's only a single function calling several other functions without many local variables, I mean less than a dozen ints and pointers but no structures or anything else that would take a serious amount of stack space.
But indeed, increasing the stack size from 256 to 512 bytes cured the problem . So I guess that calling (sub-)functions pushes a lot of registers onto the stack. Anyway, no problem, we just need to be aware of it.
Edit: After re-inserting the function calls I have commented out I had to increase the stack size to 1024. This would mean that each sub-function call level needed >256 bytes of stack which I find hard to believe. I fear the increased stack only moved the variables further away from a buffer overflow problem somewhere else in my code. I need to debug this further...
The recommended stack space isn't 128 bytes, it's 128 longs. 128 bytes are just 32 longs, which are used up surprisingly quick. Each stack frame of a non-leaf function takes 3 longs plus any registers that it needs to save (which is roughly equal to the amount of total locals+arguments). Also, the top-level function of a cog (including main) creates a stack frame even though that's completely pointless.
FlexSipn doc (c.pdf) says
But I don't want to argue, obviously that's not enough.
Yeah, I was thinking of the general adage of 128 long stacks, didn't even know the FlexC doc says that. IDK where that 16 long figure comes from, I think that's not actually the bare minimum, but of course is not enough for any serious code.
I just had to extend the allocated stack to 1024 for my watchdog cog. Not sure why either.
*** Mine wasn't with flexpin, so please ignore ***