Some time ago, there has been a discussion about multitasking and
solutions have been proposed with interrupts ...
Does any of you has an idea of a multitask kernel (2 tasks should cover
most applications) without usong interrupt facilities in order to be put
on a PIC 12C509 for example ?

> Does any of you has an idea of a multitask kernel (2 tasks should cover
> most applications) without using interrupt facilities in order to be put
> on a PIC 12C509 for example ?

Are you looking for a commercially built kernal? Or are you looking
for ideas on how to structure code to multi-task?

If you are asking for ideas, we need to know more about what the tasks
will do. To multi-task without interrupts, you will end up with a
main loop which calls the tasks, or portions of them. The taks must
be structured to run for some time, then let another task run. And
there will usually be some other code to coordinate any shared
variables or communication between the tasks.

Two important things are to know how the tasks must communicate, and
whether there is hardware that they must share. Also, it is
important to know what latency is acceptable, that is, how long can
one of the tasks be stopped before it fails?

| Some time ago, there has been a discussion about multitasking and
|solutions have been proposed with interrupts ...
|Does any of you has an idea of a multitask kernel (2 tasks should cover
|most applications) without usong interrupt facilities in order to be put
|on a PIC 12C509 for example ?

Here's a nice simple method, assuming one of the tasks will fit within
256 bytes of codespace, won't call subroutines more than 1-deep, and no
task switch will need to occur within a subroutine.

Define a register called "VirtPC". When it starts up, your main task
should set it equal to the start address of your "alternate" task. You
should also have a code address called "Springboard" at which is coded:

Springboard:
movf VirtPC,w
movwf PC

>From the main program, when you want to yield control to the alternate
task you just use the two instructions:

call Springboard
movwf VirtPC

When your alternate program wants to yield control, it should either do
a

retlw $+1

if its execution should resume at the next instruction the next time the
main program yields, or else

retlw label

if execution should resume at /label/.

Aside from the restrictions on call depth and the fact that W is trashed
on a context switch, this is probably just about the cheapest little multi-
tasker for ANY CPU platform (5 cycles to switch to the alternate task; 3
to switch back to the main line). Cute, eh?

Though not a PIC application, I did a multitasking system in
Borland Pascal several years ago. Each task had its own stack space.
When a task finished something or went into a loop waiting for something
else to happen, it called "NextTask." This pushed the current program
counter on this task's stack, saved the current stack pointer value,
advanced (or cleared if this was the last task) a "task pointer" which
determined which stack to use. This task pointer then loaded the stack
pointer with the appropriate value for this stack, then did a return.
Each task's stack held variables local to that task and held return
addresses, as mentioned above. When interrupts occurred, they just used
the current stack, whichever one was active.
I did a similar thing years earlier with a 6800 processor. The
"separate stack" idea had not occurred to me yet. Also, due to limited
memory space, it may not have worked anyway. Here, each task was a
subroutine. Prior to exiting the subroutine (going on to the next task),
the "continue address" was stored in RAM. When we got back to this task,
we always called the first location in the subroutine. This location had
an indirect jump (good old self modifying code!) to the appropriate
location in the current task. Another, similar, approach (that could be
used on the PIC) would be to have a byte hold a number representing the
entry point where you want the task to continue. The top of our task
subroutine would have a jump table the same as we use in a state machine.

This multitasking approach is really just a state machine. Each
time the task is called, it evaluates the state variable and picks up
based on it. Prior to exiting the task's routine, we save an appropriate
value in the state variable.
Just some thoughts...

> Hello all PICers,
>
> Some time ago, there has been a discussion about multitasking
>and
>solutions have been proposed with interrupts ...
>Does any of you has an idea of a multitask kernel (2 tasks should
>cover
>most applications) without usong interrupt facilities in order to be
>put
>on a PIC 12C509 for example ?
>
>Thanks
>

___________________________________________________________________
You don't need to buy Internet access to use free Internet e-mail.
Get completely free e-mail from Juno at http://www.juno.com/getjuno.html
or call Juno at (800) 654-JUNO [654-5866]

I am very interested in this as a project. I've worked with some trivial
Multitasking executives in the past, and I currently work at Wind River
Systems, writers of a very popular real time OS for embedded applications.
I would very much like to kick around ideas, to develop code, and to test
ideas. Granted, vxWorks (what we sell) is made for 32 bit high end processors,
so I will have to rethink for the PIC world, but I still think I can
contribute to the project.

If there are objections to using this forum I'd be happy to set up a
mailing list elsewhere for this as a project.

There is Microchip appnote on multitasking (cooperative) with PIC. It's
an585. Although I haven't used it, it seems to do simple things given
limited resources of PIC.

I've been looking for a job lately, and it looks like every embedded
engineering job _requires_ knowledge of VxWorks. Too bad it won't work
with PIC so I can learn, so the job hunt goes on... ;)

It would be very interesting to see other RTOS for PIC. I wonder how
things will be saved with context switch, especially for low end PICs;
is there enough memory for doing anything useful? I suppose watchdog
timer coule be used in limited sense for time slicing, but it will be
challenging. Please do keep the list updated if anything comes of this.

>
> I am very interested in this as a project. I've worked with some trivial
> Multitasking executives in the past, and I currently work at Wind River
> Systems, writers of a very popular real time OS for embedded applications.
> I would very much like to kick around ideas, to develop code, and to test
> ideas. Granted, vxWorks (what we sell) is made for 32 bit high end processors,
> so I will have to rethink for the PIC world, but I still think I can
> contribute to the project.
>
> If there are objections to using this forum I'd be happy to set up a
> mailing list elsewhere for this as a project.
>
> I'm also happy to discuss this privately, if you wish
> Michael Shiloh
> Wind River Systems
> 510-749-2171
> michaelsspam_OUTwrs.com
> alternate email at
> @spam@michaelKILLspamsrl.org

>Are you looking for a commercially built kernal? Or are you looking
>for ideas on how to structure code to multi-task?
>
>If you are asking for ideas, we need to know more about what the tasks
>will do. To multi-task without interrupts, you will end up with a
>main loop which calls the tasks, or portions of them. The taks must
>be structured to run for some time, then let another task run. And
>there will usually be some other code to coordinate any shared
>variables or communication between the tasks.
>
>Two important things are to know how the tasks must communicate, and
>whether there is hardware that they must share. Also, it is
>important to know what latency is acceptable, that is, how long can
>one of the tasks be stopped before it fails?

I'm looking for ideas for a specific project :

I have to check for serial inputs while out-puting one or more PWM depending
on the input(s).

In fact, my first application should be an attempt to read 1 RC pulsed
command, ie :

1) Measure the "n"st positive pulse among 7 overall pulses ; synchro being
made by a 1st larger pulse and length of the usefull pulse varying between 1
and 2 ms ; overall time = 10 to 20 ms

2) While outputing a PWM at 10 to 100 Hz, from #0 to #100% duty cycle

3) That's all !

4) I've thought of an absolute timing that each individual task could check
and determine if their allowed time have passed. That shouldn't be very
accurate but enough for me ?

> I'm looking for ideas for a specific project :
>
> I have to check for serial inputs while out-puting one or more PWM depending
> on the input(s).
>
> In fact, my first application should be an attempt to read 1 RC pulsed
> command, ie :
>
> 1) Measure the "n"st positive pulse among 7 overall pulses ; synchro being
> made by a 1st larger pulse and length of the usefull pulse varying between 1
> and 2 ms ; overall time = 10 to 20 ms
>
> 2) While outputing a PWM at 10 to 100 Hz, from #0 to #100% duty cycle
>
> 3) That's all !
>
> 4) I've thought of an absolute timing that each individual task could check
> and determine if their allowed time have passed. That shouldn't be very
> accurate but enough for me ?

This an all-software, 256-level pwm routine capable of 0 to 100% duty
cycles. Since it doesn't use interrupts, it's suitable for the 12 bit
core. Roughly half of the 256 cycles are available for other (isochronous)
tasks.

The only problem I can see with it is that it may be too fast for your
application. For example, with a 20Mhz clock this routine can produce a
nearly 20khz pwm'd square wave. I suppose you could slow the pic down a
factor of 200 or so, but I don'tsee this as being too practical.

Another possibility is to use the 16-bit delay loop that we were
discussing just last week. There was one solution that a) created a delay
with 3 instruction cycle resolution and 16-bits of dynamic range and b)
provided additonal cycles for simultaneously performing other tasks. The
number of 'additional cycles' can be varied between 1 to ~240 out of every
256 cycles. In fact, this number could vary depending on the time required
for each task. I unfortunately don't have time to expand upon the details
(gotta go to the Mchip seminar) - perhaps someone else may?

In my (never-ending) meter counter, I used a "micro-routine task sweeper" [I
invented the name, not the concept! 8)]. Anyway, it's a trivial solution, I
think.

I used the 16f84.
All timers are maintained by an Interrupt timer.
Resources are managed through semaphores (which are also used to signal end of
delays.).
Tasks are made to be short. The execution time must be smaller than the maximum
latency to answer to a given event. (This is not very annoying, anyway).
Since, memory is short, all variables are global.
Typical cycles are not closed, but can be. It all depends on the timing
constraints (maximum atomic execution time for each task.).

Tasks are polled in the main cycle. Since resources are handled through
semaphores, tasks can be quite ignorant of what other tasks do. This is quite
useful to change code.

It worked quite well, and allowed for easy change of code, as I added (and
still add) features, and correct bugs.

>
> I am very interested in this as a project. I've worked with some trivial
> Multitasking executives in the past, and I currently work at Wind River
> Systems, writers of a very popular real time OS for embedded applications.
> I would very much like to kick around ideas, to develop code, and to test
> ideas. Granted, vxWorks (what we sell) is made for 32 bit high end processors,
> so I will have to rethink for the PIC world, but I still think I can
> contribute to the project.
>
> If there are objections to using this forum I'd be happy to set up a
> mailing list elsewhere for this as a project.
>
> I'm also happy to discuss this privately, if you wish
> Michael Shiloh
> Wind River Systems
> 510-749-2171
> KILLspammichaelsKILLspamwrs.com
> alternate email at
> RemoveMEmichaelTakeThisOuTsrl.org

My first analysis leads to roughly the same approach. But I still have some
inquiries :

> All timers are maintained by an Interrupt timer.
>
Do you mean you must wait for a timer induced interruption to increment your
several auxilliary timers ?
Remember I must use a 12C509 without an interrupt :-(
Somebody told me I could use a watchdog wakeup ? (but the timing would be :
1st not accurate, 2nd too long)
-> any other idea ?

> Resources are managed through semaphores (which are also used to signal
> end of
> delays.).
>
By "semaphore", I think you mean 1-bit-"flag" at H or L level ?

> Since, memory is short, all variables are global.
>
That was also my way of thinking : no need to use stacks !

> Typical cycles are not closed, but can be. It all depends on the timing
> constraints (maximum atomic execution time for each task.).
>
What do you mean by "cycles are not closed" ?

> > All timers are maintained by an Interrupt timer.
> >
> Do you mean you must wait for a timer induced interruption to increment your
> several auxilliary timers ?
> Remember I must use a 12C509 without an interrupt :-(
> Somebody told me I could use a watchdog wakeup ? (but the timing would be :
> 1st not accurate, 2nd too long)
> -> any other idea ?

Well, the interrupt based timers, guarantee that time is always correct.
In my case, I use the 16f84 on 8.192MHz. I increment timers with 125us
resolution.

Without interrupts, things get a little more difficult. To keep accurate
timing, you would need isochronous tasks. This means that you need to know how
much time each task takes, and keep timing based on this.

> By "semaphore", I think you mean 1-bit-"flag" at H or L level ?

Yep. Flag 1, resource busy. Flag 0, resource free.

> >
> That was also my way of thinking : no need to use stacks !

Stacks are still a good option with more complex routines. But not on a 12C509.
It would be overkill.

> > Typical cycles are not closed, but can be. It all depends on the timing
> > constraints (maximum atomic execution time for each task.).
> >
> What do you mean by "cycles are not closed" ?

To me, a closed cycle means that the full cycle is executed without
interruption.
Suppose you need to write 10 chars to an LCD: you can send them all at once, or
you can send one, task switch, send another, switch, and so on. The first
approach will be a bit easier to code. The second allows other task to do small
jobs in between.

If you choose to take my approach, try to keep tasks as simple and as short as
possible. The less time they take to execute, the more you will approach to a
multi-tasking environment. 8)

Seyler Jean-Yves wrote:
>
> Remember I must use a 12C509 without an interrupt :-(
> Somebody told me I could use a watchdog wakeup ? (but the timing would be :
> 1st not accurate, 2nd too long)
> -> any other idea ?
>

Ok. I went look on the 12C509 datasheet.
Here's an idea to keep timings:

You have TMR0, and a pre-scaler. I forgot the kind of timings you needed, so
this may not work for you. It would avoid the assle of making sure that each
task is isochronous....

Imagine this is your main block:

main
call update_timers
call task_1
call task_2
call task_3
goto main

TMR0 has a resolution of 1 instruction cycle.
When update_timers is called, it reads TMR0 value, and adds it to the timers.
If a timer reachs the value you wanted or more, set the flag from that timer.
Subtraction might be easier, since you can check flags for a result of zero or
less. In this case, timers start with the value you want.

This kind of timing is accurate over time, but does not guarantee that you act
precisely when the timer ended. There is some jitter. The larger your timers
are, the less important the error becomes.

You do need to guarantee that update_timers is called in less than 255
instructions, before TMR0 rolls over. This can be done with multiple calls to
update_timers, or with small tasks. Your choice.
Pre-scaler can be used if timer resolution is bigger.
This is just an idea, and details must be sorted out. But it seems to be ok, I
think.

As near as I can tell the only real benefit an interrupt gives you, is
the ability to do instantaneous changes in context. You can get much the
same effect without an interrupt simply by planning your code so that it
always takes the same amount of time, to execute, for each portion of a
task you have it do.

Instead of getting instantaneous service, you get essentially, a known
delay time between the mainline code, and the service routine. If you use
a cooperative system that leaves the processor in a known state, or
dedicate some registers to saving the context for each task, you can
manage less instantaneous but certainly timely effects that would be hard
to tell from an interrupt.

The absolute minimum multi-tasking system, for such a processor would of
course be the simple round robin sequencer, which gives each task its own
time slice. By designating one task as a foreground task, and the other as
a background task, you can signal the need for a supporting background
task to be launched from your main application in the foreground.

A perfect example of this, is spooling, which is a background task that
runs the printer, while the foreground tasks, are ongoing.

Each time the spooling task is called, it sends another small string of
characters to the printer, then returns control to the main task. The main
task, runs for a period, and then returns control to the sequencer, which
can call the spooler, or another background task, such as garbage clean
up, to take care of the print buffer after the data has been printed.

In such a two task system control passes back and forth between the tasks
in an oscillating effect, advancing both of them just as easily as one.

The main difference between this and an interrupt driven system, that does
two tasks at the same time, lies in the design of the code to be packaged
in standard length snippets, rather than running any code at all, and
using the interrupt to switch contexts.

Such programs where the coding co-operates, is called co-operative
multi-tasking rather than standard multi-tasking, and requires a bit more
sophistication of the programmer, in order to make more efficient.

> Hello all PICers,
>
> Some time ago, there has been a discussion about multitasking and
> solutions have been proposed with interrupts ...
> Does any of you has an idea of a multitask kernel (2 tasks should cover
> most applications) without usong interrupt facilities in order to be put
> on a PIC 12C509 for example ?
>
> Thanks
>

> I have been working on such a machine....
>
> As near as I can tell the only real benefit an interrupt gives you, is
> the ability to do instantaneous changes in context. You can get much the
> same effect without an interrupt simply by planning your code so that it
> always takes the same amount of time, to execute, for each portion of a
> task you have it do.
>
> Instead of getting instantaneous service, you get essentially, a known
> delay time between the mainline code, and the service routine. If you use
> a cooperative system that leaves the processor in a known state, or
> dedicate some registers to saving the context for each task, you can
> manage less instantaneous but certainly timely effects that would be hard
> to tell from an interrupt.
>
> The absolute minimum multi-tasking system, for such a processor would of
> course be the simple round robin sequencer, which gives each task its own
> time slice. By designating one task as a foreground task, and the other as
> a background task, you can signal the need for a supporting background
> task to be launched from your main application in the foreground.
>
> A perfect example of this, is spooling, which is a background task that
> runs the printer, while the foreground tasks, are ongoing.
>
> Each time the spooling task is called, it sends another small string of
> characters to the printer, then returns control to the main task. The main
> task, runs for a period, and then returns control to the sequencer, which
> can call the spooler, or another background task, such as garbage clean
> up, to take care of the print buffer after the data has been printed.
>
> In such a two task system control passes back and forth between the tasks
> in an oscillating effect, advancing both of them just as easily as one.
>
> The main difference between this and an interrupt driven system, that does
> two tasks at the same time, lies in the design of the code to be packaged
> in standard length snippets, rather than running any code at all, and
> using the interrupt to switch contexts.
>
> Such programs where the coding co-operates, is called co-operative
> multi-tasking rather than standard multi-tasking, and requires a bit more
> sophistication of the programmer, in order to make more efficient.
>
> GREY
>
> GRAEME SMITH email: RemoveMEgrysmithEraseMEEraseMEfreenet.edmonton.ab.ca
> YMCA Edmonton
>
> Address has changed with little warning!
> (I moved across the hall! :) )
>
> Email will remain constant... at least for now.
>
> On Mon, 10 May 1999, Seyler Jean-Yves wrote:
>
> > Hello all PICers,
> >
> > Some time ago, there has been a discussion about multitasking and
> > solutions have been proposed with interrupts ...
> > Does any of you has an idea of a multitask kernel (2 tasks should cover
> > most applications) without usong interrupt facilities in order to be put
> > on a PIC 12C509 for example ?
> >
> > Thanks
> >

Yes, multitasking is quite possible without interrupts and I have written
some "cooperative" code on the 12c672 platform (i didn't use interrupts
specifically because they were asynchronous, therefore I really had no
idea exactly when they were happening). My application was generating a
28kHz PWM ouput in sofware while simultaneously monitoring an analog input
and a digital input (PWM enable/disable), and setting some digital outputs
based on the analog input. Whew! I used the internal oscillator and the
PWM output was limited 40%. So each cycle was 1us and I had to fit litle
pieces of the non-PWM code in between. I did this mostly by writing
routines in blocks that had a fixed execution time no matter what there
side-effects or results were. (i.e. very clever padding with nops or by
calling pause functions etc [depending on the time length])

> I have been working on such a machine....
>
> As near as I can tell the only real benefit an interrupt gives you, is
> the ability to do instantaneous changes in context. You can get much the
> same effect without an interrupt simply by planning your code so that it
> always takes the same amount of time, to execute, for each portion of a
> task you have it do.
>
> Instead of getting instantaneous service, you get essentially, a known
> delay time between the mainline code, and the service routine. If you use
> a cooperative system that leaves the processor in a known state, or
> dedicate some registers to saving the context for each task, you can
> manage less instantaneous but certainly timely effects that would be hard
> to tell from an interrupt.
>
> The absolute minimum multi-tasking system, for such a processor would of
> course be the simple round robin sequencer, which gives each task its own
> time slice. By designating one task as a foreground task, and the other as
> a background task, you can signal the need for a supporting background
> task to be launched from your main application in the foreground.
>
> A perfect example of this, is spooling, which is a background task that
> runs the printer, while the foreground tasks, are ongoing.
>
> Each time the spooling task is called, it sends another small string of
> characters to the printer, then returns control to the main task. The main
> task, runs for a period, and then returns control to the sequencer, which
> can call the spooler, or another background task, such as garbage clean
> up, to take care of the print buffer after the data has been printed.
>
> In such a two task system control passes back and forth between the tasks
> in an oscillating effect, advancing both of them just as easily as one.
>
> The main difference between this and an interrupt driven system, that does
> two tasks at the same time, lies in the design of the code to be packaged
> in standard length snippets, rather than running any code at all, and
> using the interrupt to switch contexts.
>
> Such programs where the coding co-operates, is called co-operative
> multi-tasking rather than standard multi-tasking, and requires a bit more
> sophistication of the programmer, in order to make more efficient.
>
> GREY
>
> GRAEME SMITH email: RemoveMEgrysmithspam_OUTKILLspamfreenet.edmonton.ab.ca
> YMCA Edmonton
>
> Address has changed with little warning!
> (I moved across the hall! :) )
>
> Email will remain constant... at least for now.
>
>
> On Mon, 10 May 1999, Seyler Jean-Yves wrote:
>
> > Hello all PICers,
> >
> > Some time ago, there has been a discussion about multitasking and
> > solutions have been proposed with interrupts ...
> > Does any of you has an idea of a multitask kernel (2 tasks should cover
> > most applications) without usong interrupt facilities in order to be put
> > on a PIC 12C509 for example ?
> >
> > Thanks
> >
>

Hi,
only as a small remark: the DOS print spooler (I do not know whether
another ones...) is working on an interrupt basis, as the printer tells
with an IT if the data has been printed, so asks for new data. There is no
time slicing.
Imre

> I have been working on such a machine....
>
> As near as I can tell the only real benefit an interrupt gives you, is
> the ability to do instantaneous changes in context. You can get much the
> same effect without an interrupt simply by planning your code so that it
> always takes the same amount of time, to execute, for each portion of a
> task you have it do.
>
> Instead of getting instantaneous service, you get essentially, a known
> delay time between the mainline code, and the service routine. If you use
> a cooperative system that leaves the processor in a known state, or
> dedicate some registers to saving the context for each task, you can
> manage less instantaneous but certainly timely effects that would be hard
> to tell from an interrupt.
>
> The absolute minimum multi-tasking system, for such a processor would of
> course be the simple round robin sequencer, which gives each task its own
> time slice. By designating one task as a foreground task, and the other as
> a background task, you can signal the need for a supporting background
> task to be launched from your main application in the foreground.
>
> A perfect example of this, is spooling, which is a background task that
> runs the printer, while the foreground tasks, are ongoing.
>
> Each time the spooling task is called, it sends another small string of
> characters to the printer, then returns control to the main task. The main
> task, runs for a period, and then returns control to the sequencer, which
> can call the spooler, or another background task, such as garbage clean
> up, to take care of the print buffer after the data has been printed.
>
> In such a two task system control passes back and forth between the tasks
> in an oscillating effect, advancing both of them just as easily as one.
>
> The main difference between this and an interrupt driven system, that does
> two tasks at the same time, lies in the design of the code to be packaged
> in standard length snippets, rather than running any code at all, and
> using the interrupt to switch contexts.
>
> Such programs where the coding co-operates, is called co-operative
> multi-tasking rather than standard multi-tasking, and requires a bit more
> sophistication of the programmer, in order to make more efficient.
>
> GREY
>
> GRAEME SMITH email: RemoveMEgrysmithTakeThisOuTspamfreenet.edmonton.ab.ca
> YMCA Edmonton
>
> Address has changed with little warning!
> (I moved across the hall! :) )
>
> Email will remain constant... at least for now.
>
>
> On Mon, 10 May 1999, Seyler Jean-Yves wrote:
>
> > Hello all PICers,
> >
> > Some time ago, there has been a discussion about multitasking and
> > solutions have been proposed with interrupts ...
> > Does any of you has an idea of a multitask kernel (2 tasks should cover
> > most applications) without usong interrupt facilities in order to be put
> > on a PIC 12C509 for example ?
> >
> > Thanks
> >
>
>

How does it work on PC's without a printer IRQ? I thought I had used it on
ones that probably didn't have a printer interrupt.

Sean

At 11:32 AM 5/17/99 +0200, you wrote:
>Hi,
>only as a small remark: the DOS print spooler (I do not know whether
>another ones...) is working on an interrupt basis, as the printer tells
>with an IT if the data has been printed, so asks for new data. There is no
>time slicing.
>Imre
>
>

Hi Sean, I do not know how did it work and whether it did work. PRINT
definitely runs on IT basis (the ACK causes the printer IT).
Unfortunately, the printer IRQ-s (IRQ7 for LPT1 and IRQ5 for LPT2) are
often misused for another things (e. g. some sound cards defaults IRQ7
also) causing funny things when you try to print with PRINT. Such way, the
IRQ seems to be the bottleneck on the PC from my point of view. Of course,
there are also a few printers with serial interface, or you can install a
multitasking environment, and one task prints a normal way (i. e. with
time slicing). But it is not the printer spooler for the DOS. I hope
this helped.
Regards,
Imre

Hi,
I must retire. I checked and it seems really so, that PRINT itself does
not use the IRQ of the printer. The following statement has deceived me:
"IRQ 7 [ ... means] data request on LPT1" from Helppc. It seemed logical
for me...
Sorry again.
Imre

"Dr. Imre Bartfai" wrote:
>
> Hi,
> I must retire. I checked and it seems really so, that PRINT itself does
> not use the IRQ of the printer. The following statement has deceived me:
> "IRQ 7 [ ... means] data request on LPT1" from Helppc. It seemed logical
> for me...
> Sorry again.
> Imre

You guys have it all wrong. This is what really happens :

If a packet hits a pocket on a socket on a port,
And the interrupt controller has a reason to report,
And the packet for your printer has no paper tray to sort,
Then the socket packet pocket has an error and will abort.

Actually .... I disassembled the print.exe of dos 6.0 today, just to satisfy
my curiosity (there is nothing much on the net about old technologie) and
print seems to use one of the oldest multitasking mechanisms around (in dos
and windows) the msdos multitask interrupt. and this is timer driven

>|Does any of you has an idea of a multitask kernel (2 tasks should cover
>|most applications) without using interrupt facilities in order to be put
>|on a PIC 12C509 for example ?
>
>Here's a nice simple method, assuming one of the tasks will fit within
>256 bytes of codespace, won't call subroutines more than 1-deep, and no
>task switch will need to occur within a subroutine.
>
>Define a register called "VirtPC". When it starts up, your main task
>should set it equal to the start address of your "alternate" task. You
>should also have a code address called "Springboard" at which is coded:
>
>Springboard:
> movf VirtPC,w
> movwf PC
>
>From the main program, when you want to yield control to the alternate
>task you just use the two instructions:
>
> call Springboard
> movwf VirtPC
>
>When your alternate program wants to yield control, it should do
>
> retlw $+1

<snip>

I've used state machines to manage multiple tasks in the past and thought
I'd give John's method a try. The target is a 12 bit core device which
limits my options.

It occured to me that there is a tiny bit more overhead in John's technique
than necessary. Here is my reasoning.

Anything that modifies PCL on the 12 bit core must live within the first 256
words of a page (512 spaces per page). Bit 8 of the PC is always cleared.
If the code is small enough to fit in a small device (12c508), you can shave
1 cycle off John's method *and* allow 2 levels of subroutine to be used in
either task. All you do is set PCL to the entry point of the 2nd task.

All subtasks are located within the 1st 256 codespaces. Each subtask ends
with the following:

movlw $+2 ;or 'movlw label' to re-enter somewhere else
goto Tsk2Rtn

Thats it!

The downside is that each subtask occupies 1 more codespace than John's method.

Things are a tiny bit more interesting when dealing with a larger 12 bit
core device such as the 12c509. With both methods, you have to manipulate
the page bit to ensure you end up where you want to be. When using John's
method, you can simply set the page bit to the proper value so long as
anything else that modifies PCL is on the same page as the 2nd task - it is
still just 8 cycles total since the stack contains the full return address.
If anything changes the page bit, you have to add 2 cycles for a total of 10.

In my case, the 2nd task is going to have to be on the 2nd page since I have
have numerous table jumps in the main task on the 1st page. I also have to
add the 2 cycles to set and clr the page bit, leaving me with a 9 cycle
context change. The revised version looks like this: