[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 6502 Multitasking OS announce



Ralph Mason (ralph.mason@liffe.com) wrote:
: There is much more needed that to simply save the registers! He
: doesn't explain what he is doing, the only way I can see that he is
: doing it is using his mmu to swap the bottom 4kb during each context
: switch.  This would give each process it's own stack and zeropage
: space.  You can then pass parameters on the stack or in the zeropage -
: it's up to you.  I would lean toward the stack though because you
: could not have rentrant routines or share code between processes.  

Well, I should have gone further into this.
The thing is that I have two versions of the OS, one for a computer with MMU,
and another one for a 6502 without. 

With an MMU, each task gets its real own memory space, i.e. 
zeropage and stack are remapped with the bottom 4kByte at each context 
switch. This way every task sees its own stack and has its own
view of the memory - it doesn't see anything of other tasks, or the 
system. The kernel entry/exit gates provide a way to change from
system memory mapping (which is just the botton 4kByte RAM with the 
system stuff and the top 4kByte ROM with the kernel) and the 
task environment. This is a complete mapping of the bottom 60kByte
(well, with I/O, the bottom 58kByte) of CPU address space. The task 
environment can be mapped to RAM, ROM, special addresses that have 
different features (like video RAM) and the like.
Normal tasks will have 4 or 8 kByte RAM, the system ROM for the
stdlib at $e***, the kernel at $f*** and the rest filled with nothing...
(mirroring the kernel)

Without an MMU, there is the problem with the non-relocatable stack the
6502 has. So, to avoid swapping stack contents around, I divided the 
stack into 7 parts, i.e. 6 possible tasks with 32 Byte stack each and
the system with 64 byte. Because there is no boundary testing, this
is a 'dirty trick' (tm) to get it running even without MMU.
But even then only programs that cooperate, i.e. use different memory
locations can run at the same time - otherwise bad things happen, when
one tasks writes over important data for another one.

Most kernel routines are called with the parameters in the CPU registers.
And most kernel routines do not need morei (see the kernel interface
description). But a few of them need, 
and for them there is a special area - not the zeropage but $02** - 
reserved to which the parameter are written. 
  
To share code between processes, you need not put the parameter on the
stack. The shell, e.g. is in the ROM. The same program can run several 
times in different tasks without any problem. This works because
the used RAM is mapped to different pages for different tasks. 
You can also load an executable into some RAM and let two tasks share this
RAM. As long as they don't write to it, there's no problem. For writing
they use the task specific RAM.

reentrant routines - well, the kernel is in some respect reentrant.
internal kernel routines call other kernel routines via the same 
interface as other 'user' routines as well. The kernel entry/exit gates 
detect this and do not change the memory mapping. 
Devices, that have their own memory mapping and that are called via
the DEVCMD interface call kernel routines. 
But then only some routines are a kind of reentrant, esp. the STREAM routines.
They disable Multitasking during their critical sections. The problem
with the C64 is, that is doesn't have atomic test&set operations. So all
task switches have to be disabled to test a semaphore, or when you enter
a critical region.
The memory routines, for example, cannot be called from an
interrupt. They are not protected against reentrance and therefore 
a call from an interrupt can corrupt the stuff. Though the video device
for example calls ENMEM to enable the RAM on the video board at startup.
But this startup is not called from an interrupt.

The kernel as well as the video  device are interruptable. But then, if a task
is calling a kernel function during the interrupt, the task is not 
set waiting but is kept running after the interrupt. This is needed
to avoid an interrupted system call - and then another task calling
the same routine - to corrupt internal data.
The video device interrupt routine is interruptible, but it has its own 
reentrance check to avoid confusion

hope it helps and so long
Andre



 

--
fachat@physik.tu-chemnitz.de | Andre Fachat,        Phone: ++49-371-531-3551
-----------------------------| Vettersstr. 72/622,  09126 Chemnitz,  Germany
Distribution via the         |---------------------------------------------- 
Microsoft Network prohibited!| Unix was invented prior to user-friendlyness!