6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 2:26 am

All times are UTC




Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
 Post subject: Multi tasking?
PostPosted: Sat Sep 22, 2012 8:34 pm 
Offline

Joined: Sun May 08, 2011 7:39 am
Posts: 104
Hi everyone!

I was thinking just now... can I implement a preemptive multitasking OS on the Micro UK101? Presumably I'd need a few extra bits (RTC? Better I/O?), but I fancy it might make an interesting challenge. Start with a simple round robin scheduler (I guess this is what you'd call "co-operative multitasking") then introduce a timed interrupt (and so on).

I guess the question is this: is the 6502 capable of this sort of thing? It needs to do context switching, have some means of memory protection (that'll be interesting and not at all do-able in hardware as far as i can see - which isn't very far, ha ha), etc.

Thoughts...? Of course, this may just be so much pie in the sky, but I'm pretty curious!


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sat Sep 22, 2012 8:54 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
You don't necessarily have to bother with memory protection: the Amiga didn't, nor the original Mac, I think.
As you say, a timed interrupt would be a normal approach, but cooperative multitasking means that the running task chooses when to yield to the scheduler so you don't even need that.
Of course you haven't got much space for the various tasks (their program, data and stack areas) but that just means they need to be small...
Good luck!
Ed


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sat Sep 22, 2012 10:22 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8504
Location: Midwestern USA
jonb wrote:
Hi everyone!

I was thinking just now... can I implement a preemptive multitasking OS on the Micro UK101? Presumably I'd need a few extra bits (RTC? Better I/O?), but I fancy it might make an interesting challenge. Start with a simple round robin scheduler (I guess this is what you'd call "co-operative multitasking") then introduce a timed interrupt (and so on).

I guess the question is this: is the 6502 capable of this sort of thing? It needs to do context switching, have some means of memory protection (that'll be interesting and not at all do-able in hardware as far as i can see - which isn't very far, ha ha), etc.

Thoughts...? Of course, this may just be so much pie in the sky, but I'm pretty curious!

As Ed noted, it can be done without hardware memory protection—you just have to formulate inviolate rules about RAM and I/O accesses. As Ed also noted, memory could get tight. However, these things can be worked around with careful planning.

Most likely your primary challenge will be in managing each process' environment so a context switch will be transparent to all processes. Although I've never tried this sort of thing with a 6502 running on hardware with no protection or segmentation, I could envision a context switch occurring as follows:

  1. Disable IRQs—you don't want an interrupt hitting while changing context.
  2. Push all registers to the stack, including the status register.
  3. Copy the stack to safe storage assigned to the current process.
  4. Copy the current stack pointer to safe storage assigned to the current process.
  5. Load the stack pointer with the next process' saved stack pointer.
  6. Copy the next process' stack image to the stack.
  7. Pull all registers from the stack, including the status register.
  8. Enable IRQs and restart the process.

The tricky part will be what to do about the program counter. The 65xx family doesn't have any instruction that can push the program counter without altering it (no PHC and PLC instructions, alas). You can either call a subroutine, which pushes PC+2 (relative to the JSR instruction) and double decrements the stack pointer or execute BRK, which also pushes PC+2. In a RR scheduling environment, the latter would be better, since it also takes care of SR and disabling IRQs—you'd only have to push the registers to completely save context. So, if you are going to use RR scheduling, the task that has control has to make the context switch at a defined location. Restart can be accomplished with RTI, which will reload PC with the next instruction to be executed. Be sure to follow BRK with a signature byte—any value will work, although you may want to take advantage of the signature to tell the BRK handler which process is relinquishing control.

When all is said and done, using a timer interrupt, while a bit more complicated, will give you quite a bit more flexibility, since programs can be preempted at any point, assuming your interrupt handler properly saves context. The only thing that could trip you up with a context switch via a jiffy IRQ is interrupting I/O. You'd have to temporarily inhibit a context switch until the I/O was finished.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 4:39 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
I don't think the basic mechanics of multi-tasking per se are the issue. The bigger problem is simply defining/relocating the code for each task, since there is no virtual memory.

You could look at something higher level, like a multi-tasking Forth, or some other style of interpreter. That can simplify the problem. Typically 6502 Forths use zero page for the parameter stack, and the system stack for the return stack. But that's not required. Both of those could be replaced by blocks of memory, then accessed via LDA (PSTACK),Y and LDA (RSTACK),Y. Then during context switch, you wouldn't have to copy entire stacks. Just swap out the stack locations in to zero page. This will likely slow down overall performance (since stack operations would be more costly), but pretty dramatically reduce context switch performance.

You don't need an interrupt to do task switching, you could tweak NEXT to do it on a schedule (every time at least N micro seconds have passed, it could switch). Wouldn't interrupt code words, but would work fine for high level words.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multitasking?
PostPosted: Sun Sep 23, 2012 5:57 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
See André Fachat's GeckOS/A65 V2.0, a scalable, full-featured Multitasking/Multithreading operating system for the 6502 that is preemptive and implements some Unix-like features, like signals, semaphores, relocatable fileformat, standard library, internet support via a kind of simplified sockets and last but not least virtual consoles. The only disadvantage I am aware of is that it makes for terrible interrupt response.

The 6502 isn't very good at multitasking, but doing it in Forth with non-preemptive multitasking is easy, and would give a lot less overhead than preemptive. With a real-time system, I think the delays from preemptive multitasking's task switches would be prohibitive. With a good interrupt system though, I have found I don't really need multitasking. I'm not doing the kinds of things we do on the desktop computers, but I have had background programs running on the workbench computer while at the same time it interprets, compiles, or assembles source code coming in over the RS-232 from the PC, and there are several kinds of interrupts hitting all the time and getting serviced to make all this happen. As whartung said, Forth on the 6502 normally uses ZP for the data stack and the hardware stack for the return stack. As I envision doing a multitasking Forth, those two pages, according to tests, could be divided into sections to run three tasks with no trouble, and six (or maybe even more) with care, such that you wouldn't even have to swap them out when changing tasks.

Other topics that had a lot of multitasking discussion (even if their names don't let on) are:
BRK detection: viewtopic.php?f=2&t=24
POC Version 2: viewtopic.php?f=4&t=1688
Idea for multitasking support on 65Org16 (or 65Org32): viewtopic.php?f=10&t=2156
interrupt latency (and 6502 die size): viewtopic.php?f=1&t=2015
and the topic that started the 32-bit 65Org32, "Improving the 6502, some ideas": viewtopic.php?f=1&t=1419

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 6:02 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
If you're running a bytecode/threaded system like Forth, the least overhead and an actually pretty easy way to trigger a swap is to have an interrupt handler selfmod the dispatch routine to jump somewhere else at the beginning of what would be an instruction dispatch. Then there's no polling whatsoever.

You might need to design your dispatch so that you can change a single byte to run the trap behavior, to keep things consistent. Changing the instruction byte of a dispatching JMP to a BIT so that it falls through to a trap handler would be one way.


For swapping out regular machine code processes, the easiest way to get the PC onto the stack is to simply let the timeslice timer interrupt it, or cooperatively BRK (as BDD mentioned).


The only situation I'd recommend implementing some sort of MMU-isms is if your system has expandable or banked memory and you want programs to have easy access to it. One implementation I had used ZP pointers that the OS modified, to give a window into allocated buffers. The program would have to call the OS to say "Hey, I want this ZP address pointing to this handle", and the OS remaps things to suit, adjusting the ZP pointer in question and/or banking or DMAing memory as needed. On context switch, this would have to be restored again, and there's a limit to how many of those pointers can be "active" at once.

It's kind of complex, but anything with a MMU tends to be.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 6:46 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
BigDumbDinosaur wrote:
  1. Disable IRQs—you don't want an interrupt hitting while changing context.
  2. Push all registers to the stack, including the status register.
  3. Copy the stack to safe storage assigned to the current process.
  4. Copy the current stack pointer to safe storage assigned to the current process.
  5. Load the stack pointer with the next process' saved stack pointer.
  6. Copy the next process' stack image to the stack.
  7. Pull all registers from the stack, including the status register.
  8. Enable IRQs and restart the process.

The part of the stack that's already used, and that needs to be copied isn't going to be changed by any interrupts. So, during the stack copy, you can leave interrupts enabled. The only thing you need to worry about is that you don't try to perform a context switch while already in the middle of one. This can be done with a simple flag somewhere.
Quote:
The tricky part will be what to do about the program counter. The 65xx family doesn't have any instruction that can push the program counter without altering it (no PHC and PLC instructions, alas).

There's no need to save the program counter, since it's always pointing to the same place in the context switch routine. The previous program counter (from calling the context switch code) is safely stored on the stack. Also, the context switch routine doesn't need to preserve A, X, Y or the status register. So, all you need to do for a context switch is:

  1. Save stack size in per-process memory
  2. Pop all data from stack, and store it in per-process memory
  3. Get memory area of next process
  4. Read stack data, and push it on stack
  5. RTS

You can use this for non-preemptive context switching, which I recommend for most applications. If you need preemptive context switching, you can call the context switching routine from the interrupt handler, but since you'll generally want to re-enable interrupts during the long stack copies, this requires a reentrant interrupt handler, and a mechanism that prevents multiple calls to the context switcher.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 7:31 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8504
Location: Midwestern USA
Arlet wrote:
The part of the stack that's already used, and that needs to be copied isn't going to be changed by any interrupts. So, during the stack copy, you can leave interrupts enabled. The only thing you need to worry about is that you don't try to perform a context switch while already in the middle of one. This can be done with a simple flag somewhere.

I, of course, was generalizing in my post. Optimally, you'd only save the active part of the stack, which can be done by indexing off the stack pointer. Otherwise, the system will be slower than a snake in a snowstorm.

Quote:
There's no need to save the program counter, since it's always pointing to the same place in the context switch routine.

Not true if a jiffy IRQ triggers the context switch, as would be the case with a truly preemptive scheme. There's no telling where PC will be pointing when the IRQ hits. Of course, servicing the IRQ automatically takes care of PC, as well as SR.

Quote:
Also, the context switch routine doesn't need to preserve A, X, Y or the status register. So, all you need to do for a context switch is:

  1. Save stack size in per-process memory
  2. Pop all data from stack, and store it in per-process memory
  3. Get memory area of next process
  4. Read stack data, and push it on stack
  5. RTS

You can use this for non-preemptive context switching, which I recommend for most applications.

jonb said he wanted preemptive operation, hence the outline I gave him. Assuming he decides to use a preemptive model, he has to save the MPU state to assure that the interrupted process will restart without error when it is run again. You could get away with not saving MPU state in a round-robin scheme, but that's a shaky way to do it. If the in-context process gets stuck in a loop the whole system screeches to a halt. Preemptive multitasking via jiffy IRQs is more reliable, although more technically challenging to implement. In any case, a jiffy IRQ is easy to produce with a 65C22, a watchdog timer (as I do in POC V1) or other periodic timing source, e.g. a 555C timer operating in free-run mode.

BTW, I have done this sort of thing with a 65C02 running on a Fiscal Information Uni-FI terminal server board (a project from some 20 years ago). The board logic segmented 1MB of RAM into 16 banks, plus common RAM, thus affording some measure of hardware memory protection. No stack copying was required on context switches, because each process ran in one of the 16 segments and had its own private zero page and stack. A context switch was basically a case of saving the MPU state, selecting a different segment and restore MPU state from that segment. I did it with a 100 Hz jiffy IRQ being generated by a 2698 octart timer.

A process could voluntarily relinquish its time slice by calling a kernel sub that told the scheduler that the current task was to be put back into the run queue. The sub ended by toggling an input to the glue logic (GALs) and executing WAI. The input toggle generated an IRQ a couple of clock cycles later and the context switch occurred with almost no wasted MPU time. It something that I will put to use in POC V2 when I get to it.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 7:36 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Maybe it's about time for me to dig out that article again on cooperative multitasking in Forth that showed how efficient it can be. They definitely were not moving stacks around. IIRC, they were just storing the stack-pointer values for the task that was taking a break and replacing them with the stack-pointer values the next task had when it left off the last time. They had their own segments of the stack area, so they did not step on each other's space. Since it was cooperative, a task would only pause when it was at a good stopping point, where it was the least work to put its stuff down to let other tasks run for awhile and then resume the next time its turn came. I imagine the OS could tell it in essence, "Until further notice, every time you reach a good stopping point, just transfer control to the task at address ____ . You don't need to bother me."

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 8:05 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
BigDumbDinosaur wrote:
Quote:
There's no need to save the program counter, since it's always pointing to the same place in the context switch routine.

Not true if a jiffy IRQ triggers the context switch, as would be the case with a truly preemptive scheme. There's no telling where PC will be pointing when the IRQ hits. Of course, servicing the IRQ automatically takes care of PC, as well as SR.

That's my point. The interrupt handler already takes care of saving PC, SR, A, X and Y. There's no need to do it again in the context switch routine.
Quote:
jonb said he wanted preemptive operation, hence the outline I gave him.

True, but preemptive multitasking is much more complex, and if you're not careful, can even result in worse performance. I find a lot of people wanting preemptive multitasking, just because it's "standard", and not because it's actually a better solution to the given problem. When dealing with customers in my business, I always try to solve their problems, and not their solutions.
Quote:
If the in-context process gets stuck in a loop the whole system screeches to a halt.

I'd fix the bad code, rather than designing a complex system around it to deal with it. Of course, this may not be an option for 3rd party code, but hey, realistically speaking, what's the chance that somebody will be running bad 3rd party code on a Micro UK 101 ? :)


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 8:07 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Another option would be to divide the 6502 stack space into a small number of chunks, and give each process their own part of the stack. This avoids the copying of stacks. Of course, this requires good knowledge of the number of processes, and their stack requirements.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 12:14 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
Take a look at Miro Samek's "Super Simple Tasker". It is a run to completion (RTC) environment suitable for limited stack environments like the 6502. He's taken the concepts commercial, but the basic multitasking concepts are described in the referenced "Embedded Systems" article.

_________________
Michael A.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 1:40 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Thanks for the pointer - the article can be found at http://www.embedded.com/design/embedded ... ple-Tasker

I agree with Arlet, that on a small well-controlled system you could define (say) 8 regions of page 1 for the different stacks.

On the subject of relocation: the Amiga relocated the program at load time and never moved it afterwards. There's a risk of fragmentation. but it removes the question of relocating later. The load time relocation is done by accompanying an executable with a table of offsets for patching-up.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multi tasking?
PostPosted: Sun Sep 23, 2012 6:18 pm 
Offline

Joined: Sun May 08, 2011 7:39 am
Posts: 104
Err... wow. Thinking hat on, methinks. Thanks!


Top
 Profile  
Reply with quote  
 Post subject: Re: Multitasking?
PostPosted: Mon Oct 01, 2012 11:14 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
GARTHWILSON wrote:
See André Fachat's GeckOS/A65 V2.0, a scalable, full-featured Multitasking/Multithreading operating system for the 6502 that is preemptive and implements some Unix-like features, like signals, semaphores, relocatable fileformat, standard library, internet support via a kind of simplified sockets and last but not least virtual consoles. The only disadvantage I am aware of is that it makes for terrible interrupt response.


Garth, thank you for the pointer to my work. Everything you say is true, even the bad interrupt response! ;-)

The only thing I have to add is that the OS supports multiple platforms, from a 32k Commodore PET, via C64 up to my selfbuilt machine with MMU...

André

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 13 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: