Machine Code Made Easy - Part 23a
Author
Description
From Fred 34, note that same number was used twice!
MULTITASKING ON YOUR SAM
Now for the ignorant, naive or Dundee-supporting readers
(although I don't think many Dundee fans can actually read. Ooh,
bitchy!!!) multitasking is the ability of a machine to run more
than one program similtaneously. Now, since the poor wee
processor inside this bundle of tricks can only do one
instuction at a time, real multitasking is impossible. What I
propose to dicuss is a method for simulating multitasking on the
Coupe.
I should probably start by mentioning existing software which
allows this to some extent. MasterBasic has facilities for
background/ foreground tasking, that is, a non-urgent process is
carried out at the same time as one which requires more
processor attention - Interrupt driver printing is the obvious
example, but MB also allows interrupt driven sound.
In fact, you could do a whole host of stuff "interrupt-driven",
mainly input/output. Most of you will have written, or at least
seen, interrupt-driven scrollers. I remember one of the first decent programs I wrote on the Speccy was an interrupt driven
clock. (Aaah, nostaligia. Shame about SU wasn't it? Ha!)
I'm sorry. For the Dundee supporter I'd better remind you what
interrupts actually are. When a peripheral wants to be serviced
(I WILL resist cheap gags, I WILL resist cheap gags) it tugs on
the Z80's interrupt line. The processor then completes its
current instruction and runs a servicing routine. When the
routine's finished, the CPU resumes its previous task. In fact
the Z80 has 3 modes of maskable interrupts, but I will normally
use mode 1, which is the normal one. Chris White's column has
mentioned mode 2 recently, but if you want to know more then
consult the back issues of this esteemed organ.
The most-used interrupt on the SAM (and the Speccy, for that
matter) was the frame int. This happens regularly 50 times a
second after the TV has completed one scan of the screen. The Masterbasic background taskers use this, but some people prefer (for whatever perverse reason) to envoke a line interrupt somewhere on the screen and use that instead. I covered the line int in an earlier article.
WHAT? HOW? WHY?
I suppose the big question is why the hell do we want to
multi-task, anyway? In fact, aside from the background tasking
mentioned previously, there seems no reason. It's really only on
big machines (eg. mainframes) where it becomes important. I'm
only writing this to avoid another horrible confrontation with
Brian (I still haven't got the blood stains off the wall. Blue
blood, of course), and to stimulate (something I'm rather good
at, as the females among the Perth public will tesify to. Ahem)
the coders amongst you.
Besides, it sounds pretty cool to say that the SAM can
multitask. Makes a nonsense of the Amiga manual's claim to be
the only comparable machine capable of it. And the ST can stick
itself up a user port too.
Now, after consulting a heavy (both in weight and content) book
on the subject, I reckon that there are two ways to do this.
*** 1. The "I'm doing f**k all, you can have a go" Method ***
Using this, we have a main program which trundles along minding
its own business until it has to wait for something to happen. A
keypress, input from a modem, Saints to win the cup, that kind
of thing. (I guess you're beginning to see the problems
already.) When this happens, control reverts to a secondary
program which executes until either the first program is ready
to continue, or it is held up be a peripheral or whatever, in
which case control reverts to a third program, and so on...
Well, this certainly has its advantages. The SAM only has one
user interface, so only one program can have priority. In fact a
priority scheme would be very easy to implement.
The problem is, simply, how the hell to do it! The first bit,
when the program executes until it comes up against a brick
wall, is easy enough to do. The smelly bit is trying to include
a method for testing whether or not the program can continue,
when the second task is running.
*** 2. The "Time Slicing/ Gerrof it's my turn" Method. ***
Here, each program is given a certain amount of time to run, and
control switches to the next one once time runs out, or the
"brick wall" is encountered. Simple, but effective.
It sounds too easy to be true - and it is. How the f**k do we
"time" the running of a program? And this doesn't allow for
priorities, producing time delays. People can only use one at a
time!
So, in fact, multitasking isn't possible, and I've led you all
blindly up a wild goose. Or something. Ha!
What d'ya mean I can't do that? Why not? No money? Grumble,
grumble...
Okay, okay. Howsabout we combine the two systems. My idea is
this: (rolls up sleeves, runs figures back through hair, lick
lips)
We have a control program running off the frame interrupt. It
handles everything; mouse movement, key scanning, port I/O, the
economy, the SFA, Fergie. Everything.
Every 50th of a second it calls round all the "tasks" in order
(highest priority first) asking them whether they could run. The
call will be to a routine in the task which checks what it's
waiting for: keypress, port input, mouse click, nothing etc. and
responds accordingly.
As soon as a routine says it's waiting for nothing, or whatever
it's been waiting for has happened, the controller checks
whether it is currently running. If so, do nothing. If not, this
means that a lower priority task IS running and must be halted.
A seperate routine in that is called to inform it (so that it
can save registers, data etc), and a third routine in the new
task is called to tell it to start running.
It all sounds kinda complicated, but it isn't really. All that
the tasks need attached are three routines:
A. Check ready to run.
B. Terminate execution.
C. Run.
When a task hits the brick wall, it calls the controller to tell
it, routine B is called, the controller checks the most suitable
tasks out with A, and starts one with C.
If a smaller time slice is required, line interrupts can be
used. Easy eh? Easy as scoring.