7 hours ago, Stefan said:
Some thoughts on the design of a task switcher:
... [a lot of excellent stuff snipped] ...
We need to think about what memory content to store, and where to store it
If we are talking about complete executables and their data, the memory usage could easily become quite large.
Example: 10 programs asking for backup of the whole low RAM would more or less fill banked RAM (512 kB).
Is it necessary to backup executable code, or should code and data be well separated so that the executable could just be reloaded from SD Card. Then the backup would contain only data.
Could it be left up to the user program to decide on how to store and restore its data when calling hide and show? To enable several programs to use banked RAM for that storage, we need memory management.
It's hard to see a solution not requiring the user program to call a register function. That means the task switcher will only work with user programs designed to work with it.
We should avoid adding a lot of features unless we want yet another operating system on our hand ?
There are two different scenarios. One is the "pop-up" scenario, the other is the full fledged task switcher. One, the other, or both could be supported.
For the pop-up, GIVEN that a pop-up wants to be able to pop-up over anything, and given that the pop-up HAS to play be the rules of the routine that pops it up, it can be more prescribed. For one thing, making a pop-up store in EXACTLY 8K for it's LowRAM usage is straightforward. You say that a pop-up program is assembled/compiled to load to and run from $8000 up to $9EFF, and it can have up to 256 bytes in the zero page and Golden RAM combined, at SPECIFIED PLACES, which is the size of the I/O page "cutout" from that 8K of RAM. The pop-up switcher has one segment to hold the "suspended" program RAM contents when the pop-up pops up.
How to handle video and audio when popping up is something I may have some ideas about, but am not so enamored of them that I don't want to hear other ideas first.
When a popup POPS UP OVER A POP UP, the task switcher knows because the first pop-up hasn't exited yet. It knows how to put a popup away, and does so, and now the second popup is popped up.
For the full fledged task switcher, it is a COOPERATIVE task switcher. You know you have a cooperating task because it has a "call next task" command. The program knows when it has to be in a state that can be shut down and restarted ... because it restarts as the return from the "call next task" command.
Full sized tasks that USE the tasl switcher can therefore be switched by it, and it has a directory on the SD card and that's where it stores dynamic data from and associated information about switched programs. For the register, it should in addition to telling the task switcher about its static and dynamic use of zero page and Golden RAM it should tell the task switcher about its STATIC use of other Low RAM by saying what file or files contains that static info and tell the switcher where it has dynamic RAM it uses. So the switcher preserves a zp block, a golden RAM block and a "program" low RAM dynamic RAM block, and REMEMBERS where to go reload the static RAM (code, static date, etc.).
In this context, maybe the "stack and heap" approach to HighRAM may make some more sense. You call the Switcher to load static data from disk into High RAM "starting from the first available HighRAM segment", and it does so, storing the file that the static data came from, and telling you the first data segment it was loaded to. And you call the Switcher to ask for a certain number of Heap segments you want for dynamic data. You can proceed to load stuff into those heap segments, but they are considered to be dynamic data. The Heap allocator is called with the address to put the base segment number. You know that if you have called the "next task" command, then the number in those base addresses may have changed.
When a task is switched, the code stack pointer is reset back to the beginning, and the code stack is loaded according to the new tasks static data. The heap is also a stack of block segments, of course. If a current heap request cannot be met from available HighRAM, heap data from the previous task is written out to the SD, and repeating if that does not make enough room. When there is enough room, ALL of the heap is copied down and the new data segment(s) allocated on top ... no deferred garbage collection ... and all of the current head item addresses updated. Probably Carry Set on the return if previously allocated Heap Data was moved.
Now, if one of the tasks in the cycle is greedy in its HighRAM usage ... sure, it will thrash when it hits that task. But the ones that are not greedy are the ones that will work together smoothly, taking a predictable amount of time to restart while it's static HighRAM pages reload. That's there is no deferred garbage collection on the heap ... the delay caused by the greedy program is not delayed until a less greedy program just happens to need a single segment when HighRAM is full, it happens when the greedy program is restarted. So the greedier programs will get a reputation for often being "slow to switch" and be less popular than the more frugal programs.