Paul Tarvydas <tarvydas@visualframeworksinc.com> wrote:
+---------------
| Our variant doesn't even need the @SERVICE call - everything tends
| to be coded as state machines and the code snippets that are executed
| during transitions/entries/exits are all very short.
+---------------
To some extent IBM's PARS (Programmed Airline Reservation System)
[later broken into APPS and ACP ("Airline Control Program"), the
latter later renamed TCP ("Transaction Processing Facility")]
used many of the same principles, see:
http://en.wikipedia.org/wiki/Airlines_Control_Program
http://www.blackbeard.com/tpf/tpfhist.htm
[For many years Bank of America and other banks used TPF to run
the centralized part of their ATM applications.]
+---------------
| Our original problem was that "polling" was way too inefficient.
| PLC's (employing periodic polling) were being using on injection
| molding machines, but a certain event ("cut-over") occurred in
| such a short time span that polling strategies would completely
| miss the events.
+---------------
That's what was nice about @SERVICE: you just stuck it in someplace
where you already needed a CLA [which happens a lot in PDP-8 code,
since there is no LOAD -- you have to clear (CLA) then add (TAD)],
and if there was no pending interrupt request then it was "free".
[Well, nearly; it cost 3 cycles instead of true CLA's 1 cycle.]
+---------------
| We had to bolt fairly complicated code directly onto interrupts -
| then we discovered that the code would be better-structured if we
| used state charts, then we discovered that we might as well do all
| of the code that way, regardless of whether it was bolted to an
| interrupt or to another piece (chain) of software.
+---------------
Well, much of our code *was* state machines, with the edges sometimes
being new events and sometimes being just the continuations resulting
from the required @SERVICE points [recall that I said at least one was
mandatory in every indefinite-length loop].
+---------------
| An RTOS had been bought in, but we eventually ignored it,
| since all of the real code was written below the RTOS.
+---------------
Heh! Our WSCHED *was* the "RTOS", if you're going to use those terms.
Someday I should do a full write-up of WSCHED, but here are some
salient points:
- The "Bus Window" MMU redefined the first 64 words of each PDP-8
"field" [4 kwords] as being virtual memory: 8 pages (we called
them "chunks") of 8 words each. The virtual mapping for each field
was the *same*, so if you put some data into the virtually-addressed
area and did a cross-field subroutine call the data was still there
in the same relative locations in the target field, which made
cross-field calls *much* faster. *Only* the first 64 words of
each field were virtual; all other addresses remained as before.
- The "page table" was thus itself an 8-word chunk and by software
convention was always mapped into the first virtual page (loc. 0-7)
[trivially done by having word 0 of each page table contain the
page number of that page table itself], so that you could change
the currently-active mappings for locations #o10-#o77 by depositing
the new mappings directly into locations 1-7. [The MMU snooped such
stores and copied them into its TLB automagically.]
- This 8-word chunkiness was pervasive throughout the data structures
of the system. *All* dynamic data was organized in chunk-sized pieces,
and linked lists were constructed by having word 7 of a chunk contain
the chunk (page) number of the next chunk in the list. If a chunk in
such a list was currently mapped in (virtual) locations #o70-77, one
could remap those locations to the next chunk in the list with only
two instructions [assuming the AC was clear, almost always the case] --
"TAD 77 ; DCA 7". That took word 7 of the current chunk and slammed it
into the 7th mapping of the current page table. Et voila!
- The application (data communications) layer of WSCHED was organized
around the MMU as a sort of "software crossbar" between some input
device (say, UART#73) and some output device (say, network trunk #5
logical channel #17). Virtual pages 1-3 were owned by the "source",
while pages 4-6 were owned by the "destination". [Page 7 was universally
a "scratch" page, mainly used as a temp for linked-list traversals,
as above.] A reverse mapping -- flipping the roles of "source" and
"destination" always existed at a fixed place in the "destination"
area, so one could flip roles in two instructions -- "TAD 46; WENABL".
[Aside: When an device was not "connected" in the software crossbar,
by convention it was mapped to itself. This meant that one could
create a crossbar connection with only a six load/store pairs to
swap the "destination" mappings of the two devices, whereupon they
were suddenly "connected" as above.]
- Associated with each multi-unit device controller was a vector of
page tables (called "contexts") for the units of that controller.
So all you had to do to process some input was add the unit number
of the interrupting device to the base of the page tables for that
controller and "light the context" with a WENABL instruction, then
call the "source" input-handling subroutine whose address was at
a fixed address in the "context" (virtual area).
Anyway, not to go on *too* long [though I probably have already!],
the point being that scheduled-task control blocks were built out
of these same "chunks". When you ran a task (or a continuation from
an @SERVICE) you simply "lit its context" and then did a subroutine
return into the saved PC stored *in* the context [at yet another
fixed location in the now-active virtual memory]. Input-data-driven
"software crossbar" data flow, event-driven, state-driven, or timed
scheduled tasks -- all of these models co-existed within WSCHED and
all used the *same* dispatch mechanism! The whole thing meshed together
*quite* nicely, thank you very much. ;-} ;-}
-Rob
p.s. I have replicated the WSCHED style a number of times over the
years in various embedded network applications, except using "source"
and "destination" base or index registers (now that CPUS *have* such
things -- the PDP-8 didn't!) instead of a special-purpose MMU [starting
with the Zilog Z-80, in which we used the X & Y registers for "source"
and "destination"]. The "software crossbar" style is still quite useful,
as is the interrupt-off "very-light-weight RTOS" style.
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607