Recover space lost to LMM/CMM kernel?
Rayman
Posts: 14,670
Just wondering...
Can we use the upper 32k of a 64k eeprom for code without the kernel and then
use the lower 32k for the loader and kernel?
Maybe this would make CMM come out even closer to Spin?
Can we use the upper 32k of a 64k eeprom for code without the kernel and then
use the lower 32k for the loader and kernel?
Maybe this would make CMM come out even closer to Spin?
Comments
Hmmm... that's an interesting problem. Perhaps the solution would be to have the COG clone itself, i.e. write its internal memory out to a (temporary) hub ram buffer and then do a cognew from there? It would require a change to the kernel's initialization code, of course (it could no longer live in the registers) but it seems like it should be quite do-able.
Trick would be to use a much smaller buffer say 16 longs or so.
That would have a "bootstrap" written into it which is used to start the second COG.
The bootstrap running in the second COG then recieves the kernel copy in chunks posted to that buffer by the first.
Nice puzzle.
Do we have a fork() function in the C libs anywhere?
Actually, this is all sounding like more trouble than it's worth...
Wow, that would be cool, although a lot more work.
I think we're trying to make too generic a solution here. If we need to fork a new CMM or LMM cog, simply require the programmer to do that before he recovers the Hub space used for the kernel; it would be similar to the boot I2C methods already in place.
David Voss
I always want as much control over the process as I can get, so I'd rather it be done at run-time. I already pass a pointer to a mailbox for each cog I start up, and the first parameter in that structure is usually the CNT that the cog should start at (usually for the purposes of synchronization between cogs), or a command that will be zero until the cog is needed. While there could be default examples (or recommendations) that people can follow if they want to, ultimately, I'd want to be able to define this myself.
It's not very much trouble to add in our own code to start device drivers in cogs. When I'm done doing that (including starting any additional CMM or LMM cogs), I would also like to recover the memory used for the kernel in Hub ram using a library call for that purpose. Actually, there could be two different library calls, depending on how directly we'd like to manage memory. One of them would return the memory to the heap, and malloc would control it; the other would return a pointer (and a length) to the memory block that I could then use directly.
Welcome to the forum.
It is theoretically possible for a programmer to start all COGs with some reserved memory mailbox space today with a PropellerGCC program then read the application from EEPROM or other media by over-writing most of HUB memory and start a COG. This was the subject of a discussion several months ago. The issue of having the kernel available for starting multiple COG threads remains. No one ever created a demo AFAIK - I assume that they just lost interest, and we didn't have much time.
We provide a method where all COG drivers can be loaded into EEPROM rather than HUB RAM - sometimes it's called ECOG mode. In SimpleIDE this can be done with COGC drivers by using the extension .ecogc . It can be done with linker scripts to take advantage of all COG drivers. The amount of code and number of drivers being used has to outweigh the startup needs though - the I2C driver space gets recycled by the cog loader. It is all done in keeping with the idea of the programmer having direct control on the loading. See the cog_load demo for an example of using an EEPROM based COG library.
Hope this helps.
No, I don't want to write the first-stage loader myself; I just want to define the interface to the device drivers myself, which would entail me creating my own mailbox structures, and passing a pointer to the mailbox to the device driver when I start it with coginit (or the equivalent ecog library call). In practice, it seems to me that the most common interfaces will be a busy loop waiting for a command, and a synchronized start at a given system clock CNT, but there could also be shared memory that should best be defined by the developer, rather than trying to make some sort of standard mailbox interface that will work for any eventuality.
At the same time, it would be useful to provide one or two default ways of doing this in examples so people don't have to re-invent the wheel, and so device drivers are more easily shared, because they have a relatively standard interface that people will recognize. None of my applications currently use HMI, but I guess the people that do use it might want a relatively standard mailbox for that.
Ideally, from the main program, I would first start any additional CMM/LMM cogs that I want, recover the memory from where the CMM/LMM kernel was stored in hub RAM with a library call, use that memory to temporarily store ecog device drivers as they are started, and then use that memory for my own purposes (or it could be returned to the heap to be managed by malloc). While this could be automated in initialization code at link time, I'd rather do it myself from the main program at run-time so I can define the interface between the main program, the additional CMM or LMM cog(s), and the cog device drivers myself.
By the way, I really want to commend everyone involved with propgcc for a job extremely well done; it has worked for me from the start (about 2 weeks ago), and I'm already using it as the only way I program my Props. My code is now more professional, modular, and maintainable (with the godsends of conditional compilation and make files, not to mention C) than was possible before.
Thanks !!!
Which brings us neatly back to the old and long debate about standardizing how cog code is written. How the mailboxes are specified, how the cogs are started, How they can be used from different languages, etc, etc, and the wondeful world of "plugins"and first-stage loaders, as exemplifed by RossH's efforts to document such a standard (Sorry can't find the thread now)
Personally I think Parallax was wise to want GCC to keep away from all that. It presents an all together too complex face to the user. I would like to see all COG code written to such a standard mailbox with a standardized way of being started and useable from different languages, but I think propgcc is right in keeping with simplicity and flexibility. As Jazzed says above "...They didn't want magic driver loading ...it also causes problems and invites overly complicated solutions."
A half way house here is to concatonate all drivers into a single continuous area, leave it to the programmer to reuse that space for data if he likes, after all he knows where it is and how big it is. Yes, that space may not be contiuous with other data areas, heap or stack but so what? Data can be overlaid against it.
I think I saw that it needs to be changed to single buffering because there is not enough room (even in CMM mode?) for the second buffer.
But, what if we were to define a 12,000 byte space that would initially hold the cmm interpreter, TV driver, mouse driver, and graphics driver?
Then, after starting all the drivers, use that for the second buffer...
Any chance that would work?
(or, maybe just doing the drivers (without the cmm interpreter) would be enough to make that work?)
But, I think I could almost group the drivers myself... Maybe if I made a structure that contained all the driver cog code and the extra space to make up 12,000 bytes it would work...
With that and some idea how big it is, that should be enough info to use that space for something else, right?
In SimpleIDE right-click on project file -> Show Map File. It tells you addresses of all symbols.
The graphics_demo wants to use the top of HUB ram for buffers and maybe this way it could just overlap the kernel after the cogs were started?
Maybe I need to figure out where the C++ stack is though...