The way I've usually done it is embodied in the PDP11 RH and RQ controllers. Essentially, the code is made "re-entrant", with every reference to an absolute variable replaced with pointers or array references.

Basically, all the global DECtape variables get collected into a large struct, called a context. Then the DEVICE, UNIT, and context structures are replicated and given unique names. There's a routine to map from the IO address (IOT number) to an index, and some arrays to map from context index to context structure and DEVICE structure. (Reset typically puts the context index in a user-defined field of every unit.)

Now look at td77. It would start with a call to get the index from the device number and the context pointer from the index:

int32 cidx = td_map_dev (IR);
struct td_ctx *cp = td_ctxmap[cidx];

Now every global variable td_xxx becomes cp->td_xxx. The cidx variable gets added to every routine that gets called, so that the routine can find the proper DEVICE, UNITs, or CONTEXT.

For unit service, the proper context index is retried from the UNIT argument.

For reset, a reverse lookup is done to derive a context index by looking up the DEVICE structure in the DEVICE map.

You made need to add some additional navigation aids to make "getting around" more convenient.

A slightly different approach was taken in the RH and in the i7094 tape controllers. There, the DEVICE structures were arrayed, so that the context index could directly select a DEVICE structure; and conversely, a context index could be derived from a DEVICE pointer by simple pointer subtraction. That gets rid of one context index map.

Alternately, you could just clone the code and change every td_ and TD_ to tdb_ and TDB_, respectively. You'd get pretty close, with no possibility of damaging the existing TD.
/Bob Supnik



_______________________________________________
Simh mailing list
[email protected]
http://mailman.trailing-edge.com/mailman/listinfo/simh

Reply via email to