Thanks for the explanation. I would be concerned about random data matching the tag and valid heap addresses. However, I suppose the probability is quite low.
Thanks for the explanation. I would be concerned about random data matching the tag and valid heap addresses. However, I suppose the probability is quite low.
Also, the only problem that could cause is blocks of memory that are never freed even though they are not actually in use. Given the low probability that probably doesn't matter much unless the block happens to be large.
I asked this a while ago but I don't think it was ever answered. If I don't use the heap manager at all, how can I identify free areas of memory I could use for my own allocator after my program has loaded? Is there some "top of code" symbol I can use? Also, where is the stack placed? I know I could just declare a huge array in my code but I'd rather not do that.
What is the memory map used by fastspin? Where is code loaded? Where is the stack placed? How can I know what memory is still available after loading a program?
There is a command line switch (-H) to specify the starting address, but the default is 0. First comes whatever COG code is needed (very little for the P2, just enough to bootstrap). Then comes the hubexec code. Then comes the data (including all variables). The heap (the size of which is given by HEAPSIZE) is part of that data. After that comes the stack, which grows upwards towards the end of memory. You can access the stack pointer by the variable "sp" in inline assembly, or by calling __getsp() in a high level language. The stuff above that is "free" (as long as you don't need a deeper stack, of course).
Also, if you are trying to write portable C code that will work on all systems then you'll have to either use malloc() or a large fixed size array to get your "free areas of memory". (sbrk() would be an alternative for Unix, but that isn't standard C).
What is the memory map used by fastspin? Where is code loaded? Where is the stack placed? How can I know what memory is still available after loading a program?
There is a command line switch (-H) to specify the starting address, but the default is 0. First comes whatever COG code is needed (very little for the P2, just enough to bootstrap). Then comes the hubexec code. Then comes the data (including all variables). The heap (the size of which is given by HEAPSIZE) is part of that data. After that comes the stack, which grows upwards towards the end of memory. You can access the stack pointer by the variable "sp" in inline assembly, or by calling __getsp() in a high level language. The stuff above that is "free" (as long as you don't need a deeper stack, of course).
Thanks! I must have missed that when you first posted it.
Also, if you are trying to write portable C code that will work on all systems then you'll have to either use malloc() or a large fixed size array to get your "free areas of memory". (sbrk() would be an alternative for Unix, but that isn't standard C).
Yes, I realize that I will have to put any heap allocation code in an OS-specific module. I don't mind doing that. In fact, I'm already doing that with junkbasic by declaring a big array in the OS-specific code and using that as my heap. I just wanted to get away from a hardcoded array size.
@ersmith I'm having a bit of a "discussion" with the garbage collector. It occasionally wants to run when I'm doing something time-critical. Is there a way to tell the GC "hold-off for just a bit"?
Creating a bigger HEAPSIZE just kicks the can down the road, so my current workaround is to delete unused strings manually and then invoke _gc_collect() *before* entering a time-critical bit of code. But I'm thinking there is probably something more elegant.
BTW: This compiler suite is really coming together nicely. Darned impressive effort!
@ersmith I'm having a bit of a "discussion" with the garbage collector. It occasionally wants to run when I'm doing something time-critical. Is there a way to tell the GC "hold-off for just a bit"?
No, because the GC only kicks in when you're trying to allocate memory and have run out; if you told it to "hold off for a bit" then the memory allocation you were trying to do would fail.
Basically I would recommend moving any memory allocation code outside of critical regions: don't do string manipulation and such inside time critical regions. If you can't do that, try to make sure that before you enter the region there's enough available free memory, e.g. by freeing up as much as you can manually, and/or calling _gc_collect() explicitly before the critical region.
Remember, all the GC does is look for memory that could have been freed but hasn't been yet. If you have enough memory available already, it'll never be invoked.
Looks like it's not actually FastSpin.exe per se... It's something in the library...
I just discovered I've been using the 4.0.3 library for some time and it was all good..
But, even the 4.1.4 library has this issue.
It's something to do with the included files.
The old version build output ends like this:
sprintf.c
dofmt.c
fmt.c
strcpy.c
strlen.c
1080p_TileDriver_Test6i.p2asm
Done.
Program size is 422624 bytes
The new version build of a similar file ends like this:
sprintf.c
dofmt.c
fmt.c
sprintf.c
fprintf.c
posixio.c
dofmt.c
bufio.c
errno.c
1080p_TileDriver_Test7a.p2asm
Done.
d:\Propeller2\2BitTiles\1080p_TileDriver_Test7a.p2asm:16109: error: Changing hub value for symbol ___struct__anon_193f688200000005_sputc
d:\Propeller2\2BitTiles\1080p_TileDriver_Test7a.p2asm:16124: error: Changing hub value for symbol ___struct__anon_193f688200000005_sputc_ret
I imagine that sprintf.c being included twice is the issue...
Got this trying to compile on a Mac (I'm in the process of trying to get this to compile both under FastSpin and PNut):
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2020 Total Spectrum Software Inc.
Version 4.1.6 Compiled on: Apr 22 2020
FemtoBasic.spin2
error: Internal error: tried to use memory directly
because it will never return when it tries to evaluate runmouse(xmax, ymax), resulting in it running the method synchronously from the calling COG instead of in a new COG. Are passing the SPIN parameters not supported? I do understand why this is occurring if cognew is a standard function call under the covers but I think the P1 SPIN has this capability to pass input parameters IIRC. Would this difference be documented somewhere perhaps?
That's exactly the syntax you need to use to start runmouse with w and h as the two parameters. You're right about it never returning though. The cognew returns as soon as the new cog begins execution, just before runmouse is actually begun. If runmouse returns (or falls through the end of the method), the new cog does an automatic self stop.
Still doesn't work unfortunately. The Spin COG entry parameter passed into cogspin, cognew etc seems to want to first evaluate "runmouse(w, h)" as a normal Spin method call which just results in its execution by the calling COG. Maybe passing parameters just can't be done in Fastspin, or there is a different way to do it.
@Rayman: The problem is related to the libraries, but it's actually a bug in the compiler itself (in the handling of the Spin -> C interface) that's exposed by a change in the libraries. It's fixed in github now.
@"Mike Green" : Thanks for the bug report, there was a problem with evaluating arguments of FRAC if they weren't simple variables. It's fixed in github now, I'll make a new binary release soon.
Still doesn't work unfortunately. The Spin COG entry parameter passed into cogspin, cognew etc seems to want to first evaluate "runmouse(w, h)" as a normal Spin method call which just results in its execution by the calling COG. Maybe passing parameters just can't be done in Fastspin, or there is a different way to do it.
I don't know what's going wrong for you, but in general fastspin does work the same way as Spin in terms of passing parameters to Spin functions in cognew. For example here's a simple program to flash 3 LEDs:
con
_clkfreq = 180_000_000
var
long stack1[16]
long stack2[16]
pub demo
cognew(runblink(56, _clkfreq/4), @stack1)
cognew(runblink(57, _clkfreq/10), @stack2)
runblink(58, _clkfreq/3)
pub runblink(pin, delay)
repeat
pintoggle(pin)
waitx(delay)
If "runblink()" were evaluated completely then only one LED (56) would ever toggle, since the runblink function never returns. In fact I see all 3 toggling on my board, as I would expect.
So you're running into some other problem. Perhaps your stack isn't big enough?
So you're running into some other problem. Perhaps your stack isn't big enough?
Yep it's a strange one. I did consider that and had set a huge 2000 long stack just in case however the 3 called methods in the spawned COG executing my runmouse method are also very simple so shouldn't even need much stack as you can see below.
I am running an older 4.1.0 Fastspin so that may have something to do with it and I should try a more recent version. Work fine if I don't try to pass in any xmax,ymax entry parameters but fails when I do. I wonder how best to debug... I'll try to take another deeper look tomorrow.
DAT
orgh
mousestack long 0[2000]
...
' The 3 calls made from runmouse into the usbmouse object code only do this:
PUB start(mx, my)
maxx:=mx
maxy:=my
par_head:=0
par_tail:=0
cognew(mouseinit, @usbstack)
PUB getxy | x,y
return mousey << 16 + mousex
PUB buttons
return mouse buttons
If I get rid of the arguments in the runmouse method entry point, it works and the LED lights up. When it fails I also increased the stack of the caller to 2000 longs and the mousestack to be 2000 longs. Neither helped. I will have to try a newer Fastspin to see if that helps.
Update: @ersmith After a bit more testing I think I found an issue. The Spin code being spawned must come AFTER the method that spawns it in the source file. Once I moved the spawned SPIN code to come after the caller, it worked. Prior to this it was defined before the calling method in the file. So it seems to be address dependent. Does the Fastspin code compile differently based on the order of the methods in the code?
Ok try out this with your test code slightly modified Eric. It will show you the problem. Then move runblink back to be after demo method in the file and it will work differently (this is with Fastspin 4.1.0).
con
_clkfreq = 180_000_000
var
long stack1[16]
long stack2[16]
long stack3[100]
pub start
coginit(cogid, demo, @stack3)
pub runblink(pin, delay)
repeat
pintoggle(pin)
waitx(delay)
pub demo
cognew(runblink(56, _clkfreq/4), @stack1)
cognew(runblink(57, _clkfreq/10), @stack2)
runblink(58, _clkfreq/3)
You've found an interesting bug there, @rogloh . Not only is it order dependent, but also depends on the function not returning a value. Thanks for the bug report, I'll get a fix for it soon. In the meantime I think you can work around it by adding "return 0" to the end of any function that's being coginit'ed (even if it's got an infinite loop and will never hit the return). The bug is a side effect of an optimization for handling Spin functions that have no return value but are later used in an expression. It causes the coginit to no longer be recognized as a "special" Spin coginit.
No worries, and thanks for figuring out what was going on internally to cause it so that you can ultimately solve it.
A couple of weeks back I encountered other behaviour that again looked potentially like a different Fastspin bug with memory layout but it disappeared when I moved around something else I considered totally unrelated. Then once it worked I just moved on from there so unfortunately I didn't try to nail it down at the time or collect any details. If I see it again I'll definitely try to get more information and let you know. It could still have been my own bug somehow but I recall it was highly suspicious at the time. I'll need to hit it again before I know what it was.
Comments
I asked this a while ago but I don't think it was ever answered. If I don't use the heap manager at all, how can I identify free areas of memory I could use for my own allocator after my program has loaded? Is there some "top of code" symbol I can use? Also, where is the stack placed? I know I could just declare a huge array in my code but I'd rather not do that.
Not yet, no.
Creating a bigger HEAPSIZE just kicks the can down the road, so my current workaround is to delete unused strings manually and then invoke _gc_collect() *before* entering a time-critical bit of code. But I'm thinking there is probably something more elegant.
BTW: This compiler suite is really coming together nicely. Darned impressive effort!
Basically I would recommend moving any memory allocation code outside of critical regions: don't do string manipulation and such inside time critical regions. If you can't do that, try to make sure that before you enter the region there's enough available free memory, e.g. by freeing up as much as you can manually, and/or calling _gc_collect() explicitly before the critical region.
Remember, all the GC does is look for memory that could have been freed but hasn't been yet. If you have enough memory available already, it'll never be invoked.
Getting an error in the p2asm, changing hub value for symbol: ___struct__anon_193f688200000005_sputc
Seems this subroutine appears in two places in the assembly...
I just discovered I've been using the 4.0.3 library for some time and it was all good..
But, even the 4.1.4 library has this issue.
It's something to do with the included files.
The old version build output ends like this:
The new version build of a similar file ends like this:
I imagine that sprintf.c being included twice is the issue...
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2020 Total Spectrum Software Inc.
Version 4.1.6 Compiled on: Apr 22 2020
FemtoBasic.spin2
error: Internal error: tried to use memory directly
Eg. suppose I want to start this Spin Method as a new COG I can't seem to simply use this syntax... because it will never return when it tries to evaluate runmouse(xmax, ymax), resulting in it running the method synchronously from the calling COG instead of in a new COG. Are passing the SPIN parameters not supported? I do understand why this is occurring if cognew is a standard function call under the covers but I think the P1 SPIN has this capability to pass input parameters IIRC. Would this difference be documented somewhere perhaps?
@"Mike Green" : Thanks for the bug report, there was a problem with evaluating arguments of FRAC if they weren't simple variables. It's fixed in github now, I'll make a new binary release soon.
I don't know what's going wrong for you, but in general fastspin does work the same way as Spin in terms of passing parameters to Spin functions in cognew. For example here's a simple program to flash 3 LEDs:
If "runblink()" were evaluated completely then only one LED (56) would ever toggle, since the runblink function never returns. In fact I see all 3 toggling on my board, as I would expect.
So you're running into some other problem. Perhaps your stack isn't big enough?
Yep it's a strange one. I did consider that and had set a huge 2000 long stack just in case however the 3 called methods in the spawned COG executing my runmouse method are also very simple so shouldn't even need much stack as you can see below.
I am running an older 4.1.0 Fastspin so that may have something to do with it and I should try a more recent version. Work fine if I don't try to pass in any xmax,ymax entry parameters but fails when I do. I wonder how best to debug... I'll try to take another deeper look tomorrow.
And I added an LED toggle after the cognew command. It never lights up. It will light if I move the "dirb |=..." line to be before the cognew. If I get rid of the arguments in the runmouse method entry point, it works and the LED lights up. When it fails I also increased the stack of the caller to 2000 longs and the mousestack to be 2000 longs. Neither helped. I will have to try a newer Fastspin to see if that helps.
Update: @ersmith After a bit more testing I think I found an issue. The Spin code being spawned must come AFTER the method that spawns it in the source file. Once I moved the spawned SPIN code to come after the caller, it worked. Prior to this it was defined before the calling method in the file. So it seems to be address dependent. Does the Fastspin code compile differently based on the order of the methods in the code?
A couple of weeks back I encountered other behaviour that again looked potentially like a different Fastspin bug with memory layout but it disappeared when I moved around something else I considered totally unrelated. Then once it worked I just moved on from there so unfortunately I didn't try to nail it down at the time or collect any details. If I see it again I'll definitely try to get more information and let you know. It could still have been my own bug somehow but I recall it was highly suspicious at the time. I'll need to hit it again before I know what it was.
I posted this on the Flexgui thread - you may have missed it
Eric,
I just tried compiling my Monitor Demo in spin2 with Fastspin 4.16.
It does not like the "mon." prefix in the pasm operands. I presume you've not got around to this yet. Code is posted here
forums.parallax.com/discussion/171502/p2-replacing-the-rom-monitor-debugger-and-calling-from-spin-or-pasm