DataMuseum.dk

Presents historical artifacts from the history of:

Bogika Butler

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Bogika Butler

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦474e81aa1⟧ TextFile

    Length: 52096 (0xcb80)
    Types: TextFile
    Names: »UDC.SA«

Derivation

└─⟦2322e079b⟧ Bits:30009789/_.ft.Ibm2.50006594.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »UDC.SA« 
└─⟦311ba069f⟧ Bits:30009789/_.ft.Ibm2.50006625.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »UDC.SA« 
└─⟦49237ce80⟧ Bits:30009789/_.ft.Ibm2.50006627.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »UDC.SA« 

TextFile

 
æ*****************************************************************
                        Copyright 1984 by
                        NCR Corporation
                        Dayton, Ohio  U.S.A.
                        All Rights Reserved
******************************************************************
                        EOS Software produced by:
                        NCR Systems Engineering - Copenhagen
                        Copenhagen
                        DENMARK
*****************************************************************å
 
æ               UUUU     UUUU DDDDDDDDDD       CCCCCCC
                UUUU     UUUU DDDDDDDDDDDD   CCCCCCCCCCC
                UUUU     UUUU DDDD     DDDD CCCCC    CCCC
                UUUU     UUUU DDDD     DDDD CCCC
                UUUUU   UUUUU DDDD     DDDD CCCCC    CCCC
                 UUUUUUUUUUU  DDDDDDDDDDDD   CCCCCCCCCCC
                   UUUUUUU    DDDDDDDDDD       CCCCCCC
 
 
                                  U D C
 
                                  I P C
 
                               M O D U L E
 
 
               (DRIVER MODULE FOR MOTOROLA'S UDC CONTROLLER)
                           EOS Operating System
 
The UDC Ipc Module drives Motorola's Universal Disk Controller Module
     through the Intelligent Peripheral Controller interface.
 
The module adheres to the EOS architectural standard for i/o-families.
 
The UDC object manages a number of driver objects. A driver object is an
     access object which the UDC object creates on call to the Assign-entry.
     The driver object is the 'access-path' to one of the devices (flexible
     or hard disk) which are operated by the UDC controller. The controller
     operates up to eight devices numbered 0 through 7.
 
The driver object (or Disk object) has Read- and Write-entries, and the
     user may wait for a break-condition on the object.
 
In this version only one of possibly several Disk objects opened to the
     same device may have the exclusive i/o-reservation.
 
 
 
Copyright NCR Corporation 1983
 
Written:     April-May 1983
By:          Peter Mikkelsen, SE-Copenhagen.
 
 
Change history:
===============
 
83-11-09/mik   Bug in ReadSeq and ReadRandom if area to be read in middle of
               segment.
83-12-05/ear   re-translation with changed iosys.id
 
å
æ$Eå
æ
OVERVIEW OF THE MODULE'S TEXT:                                      PAGE
==============================
 
Export description
Import description
Constants and types
Global routines:
 
å
OBJECT PROGRAM Udc;
const version='udc driver vers. 01.02 83-12-05';
æ$L-å
æOBS! old univfam and knelfam are included because old
      dummy version of RefEqual is used in this program å
æ Updated to use SameEntity å
æ$F=FAMILY.UNIV.IDå
æ$F=FAMILY.KNEL.IDå
 
æ$F=FAMILY.ALLOC.IDå
æ$F=FAMILY.SCHED.IDå
æ$F=FAMILY.OBJDIR.IDå
const OrgSys=4001;
æ$F=PASINCLU.MIKTYPES.SAå
æ$F=FAMILY.IOSYS.IDå
 
æ$L+å
æ$Eå
æ***** E X P O R T   D E S C R I P T I O N *****å
æ***********************************************å
 
(* removed 83-06-02
OBJECT Ipc;
  CONST
    minDevno=0;  maxDevno=7;
  TYPE
    devnos=minDevno..maxDevno;
    IoType=integer;
 
  ENTRY Assign
    (OUT driver: ref æLAO or DAOå;
     IN iomode: IoType;
     IN devName: fullId);
        æ Creates a Line or Disc access object which acts a driver for the
          specified device. The access object attempts to reserve the use
          of the device as specified by 'iomode'å
 
  PRIVATE Close  ætermination procå
    (IN driver: ref;
        env: ref ækernel suppliedå);
        æ Cancels the reservations held by the driver å
 
  ENTRY ScanFiles
    (OUT scanOwner: ref æScanå);
        æ Not implemented in this demo-version å
 
  ENTRY RenameFile; ærejectå
  ENTRY CreateLink; ærejectå
  ENTRY DeleteLink; ærejectå
 
  ENTRY InitIpcSys
    (IN vector,level: integer;
     IN chanAddr: address);
        æ Initializes the Ipc object with controller specific info å
 
  ENTRY CreateFile
    (IN devName: fullId;
     IN devno: integer
    æIN hwConfig, swConfig: integerå);
        æ Ties a name to the device given by 'devno'. The configuration
          parameters are used to configurate MCCM devices each time it
          is Assign'ed (with ReadWrite) å
 
  ENTRY DeleteFile
    (IN devName: fullId);
        æ Deletes a device description. Drivers open to the device are
          abortedå
 
 
æ$Eå
  OBJECT Disk; ære-entrantå
    æ This object acts as an access-path to a disk.
      Although several disk objects to the same device may exist, only
      one of them is active at a time (the other objects reject all
      calls), namely the one with the (exclusive) r-, w-, or rw-Reserv
      iomode.
 
      Concurrency rules: (demo-version)
        All i/o calls are processed First-Come-First-Served. A process may
        wait independently for break on the driver object with i/o-
        reservation.
 
      Break condition:
        When a break condition occurs, all processes waiting in the driver
        object are returned with a break status (except the WaitBreak
        process which is returned with ok-status). Subsequent i/o
        calls will be rejected with break status until WaitReady is
        called and has returned.
 
      Speed up of calls:
        I/o calls:  Normally not possible to speed up (at least not if the
        i/o-operation has been sent to the ipc).
 
        WaitBreak: May be speeded up without affecting any other calls.
    å
 
    TYPE
      bufSpace=ARRAY Æ1..addrMaxÅ OF byte;
      bufRef=^^ ÆÅ bufSpace;
      BaseMode=integer;
    CONST
      FromStart=0; FromCurrent=1; FromEnd=2;
 
    ENTRY ReadSeq
      (IN segment: bufRef;
       OUT byteCount: integer);
 
    ENTRY WriteSeq
      (IN segment: bufRef;
       OUT byteCount: integer);
 
    ENTRY ReadRandom
      (IN segment: bufRef;
       OUT byteCount: integer;
       IN pos: integer;
       OUT posUsed: integer
       æhold: HoldModeå);
 
    ENTRY WriteRandom
      (IN segment: bufRef;
       OUT byteCount: integer;
       IN pos: integer;
       OUT posUsed: integer);
 
    ENTRY Seek
      (IN base: BaseMode;
       IN offset: integer;
       OUT pos: integer);
 
    ENTRY SetMode;           æ not demo å
    ENTRY GetFileInf
     æ(OUT fsId: ref;
       OUT localId: integer;
       OUT class: devClass;
       OUT descr: lineDescription); not demo å;
    ENTRY SetRights;         æ reject å
    ENTRY CheckRights;       æ not demo å
    ENTRY MoveRights;        æ not demo å æ necessary????? å
    ENTRY NewLink;           æ reject å
    ENTRY AllocSize;         æ reject å
    ENTRY DataSize;          æ reject å
 
    ENTRY WaitBreak;
          æ Waits for a break condition in the driver object. The called
            driver object must have an i/o-reservation. At most one process may
            wait in the entry independently of any concurrent i/o-calls
            to the object å
 
    ENTRY WaitReady;
          æ Clears the break condition status of the device. Dummy if there
            is no break condition on the device. The entry requires that
            the object called holds an i/o-reservation å
 
  END æDiskå;
CONST IoFamily=4;
CONST NoRights=0; ReadRight=1; WriteRight=2; ReadWrite=3;
æ***** ERROR CONSTANTS *****å
CONST
  FileNotFound      =3;
  FileNameExists    =4;
  RightsOccupied    =6;
  PosOutsideRange   =7;
  PhysIoError       =8;
  AttentionPending  =10;
ænon-standard error constantså
  alreadyNamed=100;   æCreate: devno is already namedå
  alreadyWaiting=101; æWaitBreak: one process already waiting for breakå
END æIpcå;
******end remove 83-06-02 *)
 
 
CONST
ænon-standard error constantså
  alreadyNamed=100;   æCreate: devno is already namedå
  alreadyWaiting=101; æWaitBreak: one process already waiting for breakå
  minDevno=0;  maxDevno=7;
TYPE
  devnos=minDevno..maxDevno;
æ$Eå
æ***** C O N S T A N T S   A N D   T Y P E S *****å
æ*************************************************å
CONST
  æ characters å
    nul=0;
    stx=2;
    etx=3;
    cr=13;
 
  æ module constants å
    maxIdLength=48; æ # significant characters of a fullId in this module å
    kernelStack=100; æsupervisor stack on interrupt å
 
  æ Ipc constants å
    æpacket sizeså
      rwSize=21;
      haltSize=7;
    æchannel commandså
      readCom=16#10;
      writeCom=16#20;
      haltCom=16#50;
    ædevice commandså
      ipcFormatted=16#01;
      ipcImage=16#02;
    æstatus classeså
      completion=16#70;
      abortClass=16#71;
      solicited=16#72;
      unsolicited=16#80;
    æstatus valueså
      noErrors=       0; æcompletionå
      notReady=       3; æcompletionå
      invalidDiskAddr=6; æcompletionå
æ$Eå
æ***** Ipc Command and Status Packets *****å
TYPE
  outHead=RECORD  æ common header of command packets å
    stx:        byte;
    packetId:   byte;
    size:       byte;
    devno:      byte;
    chanCom:    byte;
    devCom:     byte;  æ6 byteså
  END;
  inHead=RECORD  æ common header of status packets å
    stx:        byte;
    packetId:   byte;
    size:       byte;
    devno:      byte;
    chanCom:    byte;
    statusClass:byte;
    status:     word;  æ8 byteså
  END;
  okind=(rwMess,verifyMess,haltMess,configMess);
  outMess=RECORD
    dummy: byte; æalignå
    CASE kind: okind OF
      rwMess:                  æ read/write å
         (h0:         outHead;
          blocks0:    word;
          blkSize0:   word;
          DMAaddress: integer;
          filler:     word;
          options:    integer; æ or sector # å
          etx0:       byte);
 
      verifyMess:
         (h1:         outHead; æ verify CRC, Format track etc. å
          blocks1:    word;
          blkSize1:   word;
          sectorNo1:  integer;
          etx1:       byte);
 
      haltMess:
         (h2:         outHead; æ clear fault, format disk, halt, ready å
          etx2:       byte);
 
      configMess:
         (h3:         outHead; æ configure å
          hwConfig:   integer;
          swConfig:   integer;
          etx3:       byte);
  END;
  iKind=(okAnsw,notReAnsw,crcAnsw,udcStAnsw,mccmStAnsw);
  inMess=RECORD æ status packet å
    dummy: byte; æalignå
    CASE kind: iKind OF
      okAnsw:
         (h0:         inHead;  æ UDC: no error (i/o)           å
          blocks:     word;    æ MCCM: no error, parity, break å
          blockSize:  word;
          DMAaddress: address;
          filler:     word;
          etx0:       byte);
 
      notReAnsw:
         (h1:         inHead;  æ device not ready etc. å
          etx1:       byte);
 
      crcAnsw:
         (h2:         inHead;  æ UDC CRC-error å
          blockNo:    integer;
          etx2:       byte);
 
      udcStAnsw:
         (h3:         inHead;  æ UDC device status (unsolicited) å
          noLogBlock: integer;
          etx3:       byte);
 
      mccmStAnsw:
         (h4:         inHead;  æ MCCM device status (solicited and  å
          devStat:    integer;
          hwConfig:   integer;
          swConfig:   integer;
          etx4:       byte);
  END;
 
  requestState=(ipcNotStarted,ipcStarted,ipcAnswered);
 
  ipcRequest=RECORD
    æ output message = command packet å
    o: outMess;
    i: inMess;
    state: requestState;
  END;
æ$Eå
æ***** Ipc object *****å
TYPE
  maxFullId=ARRAY Æ1..maxIdLengthÅ OF char;
  countRec=RECORD
    transfers,   æ# i/o-transfers started in the driver å
    repeats,     æ# reated i/o-transferså
    q1,          æ# req's received when one other request occupies driverå
    q2,          æ# req's received when two other requests occupies driverå
    q3: integer; æ# req's received when three other requests occupies driverå
  END;
  ipcData=RECORD
    break:       ARRAY ÆdevnosÅ OF boolean; æ break conditions å
    ipcReserved: integer;  æ # processes waiting in ipc object å
    ackFifo:     ARRAY ÆdevnosÅ OF devnos; æ fifo of requests waiting å
    ackFifoFirst,                          æ for the use of the ipc-  å
    ackFifoLast: devnos;                   æ channel.                 å
    chanAddr:    address; æabsolute address of channel registerså
    requests:    ARRAY ÆdevnosÅ OF ipcRequest;
    vector,              æ interrupt vector å
    level:       byte;   æ interrupt level  å
    dir:         ARRAY ÆdevnosÅ OF RECORD  æ directory å
                                     name: maxFullId;
                                     nameLength: 0..maxIdLength;
                                     hwConfig,
                                     swConfig: integer
                                   END;
    count:       ARRAY ÆdevnosÅ OF countRec;
  END;
  drivLocRef=^^drivLocals;
  ipcLocRef=^^ipcLocals;
  ipcLocals=RECORD  æ local pointers in Ipc object å
    code:         ^^;
    ownLocaldata: ^^ipcData; æcreated by Stubå
    localdata:    ^^ipcData; æcopy of ownLocaldata to become residentå
    currDriver:   ARRAY ÆdevnosÅ OF drivLocRef; æenvelope ptr's to drivers
                                                  with i/o-reservationå
    stubRef:      ^^ObjDir;       æinserted by the Stubå
    iSchedRef:    ^^Scheduler;    æinserted by the Stubå
    schedRef:     ^^Scheduler;    æinserted by the Stubå
    allocRef:     ^^Allocate;     æinserted by the Stubå
    egoEnv:       ipcLocRef;      æinserted by the Stubå
    interruptPtr: ^^;  ækernel's interrupt pointerå
    ipcGate:      gateRef;
    dirGate:      gateRef; æprotects the 'dir'-datastructure, the 'drivers'
                       manager set, and the reservation status per deviceå
    drivers:      ARRAY ÆdevnosÅ OF drivLocRef; æmanager set of driver obj'så
    ownSet:       ^^; æowner set for ipcGate, complete cond's, and breakCond
                                                                 cond'så
  END;
æ$Eå
æ***** Driver object types *****å
  drivData=RECORD  æ local data in Driver object å
    devno:        devnos;
    reserv:       IoType;
    mode:         RECORD
                    timeout: integer;
                    options: integer
                    æretries, verify etc?å
                  END;
    devReserved:  integer;
    waitBreak:    boolean;
    waitEmpty:    boolean;
    count:        countRec;
    currPos:      integer; ænext byte to be transferredå
    discSize:     integer;
    cylSize:      integer;
    blockSize:    integer;
  END;
 
  drivLocals=RECORD
    code:      ^^;
    localdata: ^^drivData;
    ipc:       ipcLocRef; æto managerå
    complete:  condRef;
    breakCond: condRef;
    schedQ:    condRef; æFCFS queueå
    empty:     condRef; æsignalled when no processes wait for i/o in objå
    ownSet:    ^^; æowner set for 'complete' and 'breakCond'å
    normalGate: ^^Gate; æsynchronizes buffering associated with i/oå
  END;
æ$Eå
æ***** E X T E R N A L   P R O C E D U R E S *****å
æ*************************************************å
PROCEDURE startIpc
  (vector: byte;
   devno: devnos);
  FORWARD;
 
PROCEDURE intudc;
  FORWARD;
 
function byteaddr(univ var x: byte): integer; forward;
æ$Eå
æ***** G L O B A L   P R O C E D U R E S *****å
æ*********************************************å
 
æ----- AckFifo Routines -----å
 
æ   The following routines operate on the AckFifo datastructure. The
    AckFifo is a FIFO-type queue for ipcRequests waiting for access to
    the channel.
 
       putAckFifo:   insert request at the end of the fifo queue
       getAckFifo:   get next request in queue
       removeAckFifo: remove a specific request from the queue.
 
    The number of requests waiting in the AckFifo queue is indicated by
    'ipcReserved' (namely one less than this figure).
 
    The AckFifo datastructure is dimensioned so that overflow never
    occurs (there is room for one request per device).
å
PROCEDURE putAckFifo
  (devno: devnos;
   VAR c: ipcData);
BEGIN
   c.ackFifoLast:=(c.ackFifoLast+1) MOD (maxDevno+1);
   c.ackFifoÆc.ackFifoLastÅ:=devno;
END æ***putAckFifo***å;
 
(* implemented in interrupt procedure
FUNCTION getAckFifo
  (VAR c: ipcData)
  : devnos;
BEGIN
  getAckFifo:=c.ackFifoÆc.ackFifoFirstÅ;
  c.ackFifoFirst:=(c.ackFifoFirst+1) MOD (maxDevno+1);
END æ***getAckFifo***å;
*)
(* removed 83-04-25
PROCEDURE removeAckFifo
  (devno: devnos;
   VAR c: ipcData);
  VAR i: devnos;
BEGIN
  æassert: c.ipcReserved>0å
  i:=c.ackFifoFirst;
  WHILE c.ackFifoÆiÅ<>devno AND i<>c.ackFifoLast DO
    i:=(i+1) MOD (maxDevno+1);
  END;
  IF c.ackFifoÆiÅ<>devno THEN exception(systemError);
  WHILE i<>c.ackFifoLast DO BEGIN
    c.ackFifoÆiÅ:=c.ackFifoÆ(i+1) MOD (maxDevno+1)Å;
    i:=(i+1) MOD (maxDevno+1);
  END;
  c.ackFifoLast:=(c.ackFifoLast+maxDevno) MOD (maxDevno+1);
           æi.e. decrease ackFifoLastå
END æ***removeAckFifo***å;
end 83-04-25 *)
æ$Eå
PROCEDURE sendReq
  (VAR complete: condRef;
   VAR req: ipcRequest;
   devno: devnos;
   VAR c: ipcData);
  VAR ignore: ResultType;
BEGIN
  c.requestsÆdevnoÅ:=req;
  c.requestsÆdevnoÅ.state:=ipcNotStarted;
  c.ipcReserved:=c.ipcReserved+1;
  IF c.ipcReserved>1 THEN putAckFifo(devno,c)
  ELSE startIpc(c.vector,devno);
  ignore:=complete.Wait;
  req.i:=c.requestsÆdevnoÅ.i; æreturn answerå
END æ***sendReq***å;
æ$Eå
æ***** D I S K   O B J E C T   I M P L E M E N T A T I O N *****å
æ***************************************************************å
 
PROGRAM diskImplement OBJECT Fao WITH drivLocals;
 
æ***** LOCAL ROUTINES *****å
 
FUNCTION objStatus
  (VAR d: drivData;
   VAR c: ipcData;
   reserv: IoType)
  : resultType;
BEGIN
  IF NOT ((reserv=NoRights) OR
          (d.reserv=ReadWrite) OR
          (d.reserv=reserv)) THEN
    objStatus:=genRes(-EntryIllegal,Universal,0)
  ELSE IF c.breakÆd.devnoÅ THEN
    objStatus:=genRes(-BreakPending,IoFamily,0);
END æ***objStatus***å;
 
æ$Eå
æ----- doIo -----å
 
æ Function doIo is the central routine controlling the synchronization and
  sceduling of i/o requests from the driver object. Although it is textually
  placed here in the driver object, it logically belongs to both the driver
  and ipc objects å
 
FUNCTION doIo
  (VAR buf: ref;
   base: integer; æbase of data in bufå
   VAR req: ipcRequest;
   reserv: IoType;
   VAR d: drivData)
  : resultType;
  VAR
    i: integer;
    use: IoType;
    res: ResultType;
BEGIN
  res.main:=ok;
  req.o.kind:=rwMess; æread/write kindå
  IN
    CASE reserv OF
      ReadRight: use:=WriteRight;
      WriteRight: use:=ReadRight;
      OTHERWISE use:=reserv;
    END;
    check(ipc^^.ipcGate.Resident(buf; use));
    WITH c=ipc^^.localdata^^ DO BEGIN
      check(ipc^^.ipcGate.Lock);
      IN ægate lockedå
        check(objStatus(d,c,reserv));
        d.devReserved:=d.devReserved+1;
        d.count.transfers:=d.count.transfers+1;
        IN æd.devReserved increasedå
          IF d.devReserved>1 THEN BEGIN
æprintVar('.....doIo scheduling queue..... devReserved= ',d.devReserved);å
            æupdate countRecå
            WITH d.count DO BEGIN
              IF d.devReserved=2 THEN q1:=q1+1
              ELSE IF d.devReserved=3 THEN q2:=q2+1
              ELSE q3:=q3+1;
            END;
          æ check(Propagate(propReject));  kernel-error å
              check(schedQ.Wait); æmay be speeded upå
          æ check(Propagate(propNone));    kernel-error å
            check(objStatus(d,c,reserv));
          END;
          æ do i/o å
          check(IoBegin(buf,req.o.DMAaddress,i,i));
          IF req.o.DMAaddress MOD 2 = 0 THEN BEGIN
            req.o.DMAaddress:=req.o.DMAaddress+base; æstart of text in bufå
            sendReq(complete,req,d.devno,c); æsend request to ipcå
          END ELSE BEGIN
            res:=genRes(-DataValueIllegal,Universal,3);
          END;
          check(IoEnd(buf,i,i,i));
          IF NOT ((req.i.h0.statusClass=completion) AND
                  (req.i.h0.status=ok)) THEN
            IF ((req.i.h0.statusClass=completion) AND
                (req.i.h0.status=invalidDiskAddr)) THEN
              exception(genRes(ok,0,0)) æeofå
            ELSE IF ((req.i.h0.statusClass=completion) AND
                     (req.i.h0.status=notReady)) THEN BEGIN
              c.breakÆd.devnoÅ:=true;
              exception(genRes(BreakPending,IoFamily,0));
            END ELSE
              exception(genRes(PhysIoError,IoFamily,0));
          æupdate driver positionå
            d.currPos:=
               (req.o.options æstart sector #å + req.i.blocks)*req.i.blockSize;
        DO IF res.main=ok THEN res:=getException;
        d.devReserved:=d.devReserved-1;
        IF d.devReserved>0 THEN
          check(schedQ.Signal) æstart next in queue to this deviceå
        ELSE IF d.waitEmpty THEN BEGIN
          d.waitEmpty:=false;
          check(empty.Signal);
        END;
      DO IF res.main=ok THEN res:=getException;
      check(ipc^^.ipcGate.Open);
    END æwithå;
  DO IF res.main=ok THEN res:=getException;
  doIo:=res;
END æ***doIo***å;
æ$Eå
FUNCTION transfer
  (VAR buf: bufRef;
   bLength: integer;
   VAR byteCount: integer;
   direction: integer;
   VAR pos: integer;
   VAR d: drivData)
  : ResultType;
  VAR res: ResultType;
      req: ipcRequest;
      reserv: IoType;
BEGIN
  res.main:=ok;
  IN
    IF pos MOD d.blockSize <> 0 THEN
       exception(genRes(-DataValueIllegal,IoFamily,-3));
    IF bLength < d.blockSize THEN
      exception(genRes(-DataValueIllegal,Universal,4));
    æ set up read request å
      req.o.kind:=rwMess; æread/writeå
      req.o.h0.stx:=        stx;
      req.o.h0.packetId:=   0;
      req.o.h0.size:=       rwSize;
      req.o.h0.devno:=      d.devno;
      req.o.h0.chanCom:=    direction;
      CASE direction OF
        readCom:   req.o.h0.devCom:=ipcFormatted;
        writeCom:  req.o.h0.devCom:=ipcImage;
      END;
      req.o.blocks0:=       bLength DIV d.blockSize;
      req.o.blkSize0:=      d.blockSize;
      req.o.options:=       pos DIV d.blockSize æround downå;
      pos:=req.o.options*d.blockSize æactual pos usedå;
      req.o.etx0:=          etx;
    if direction=readCom then reserv:=ReadRight else reserv:=WriteRight;
    res:=doIo(buf,0,req,reserv,d);
    byteCount:=req.i.blocks*d.blockSize;
  DO IF res.main=ok THEN res:=getException;
  transfer:=res;
END æ***transfer***å;
æ$Eå
ENTRY ReadSeq
  æIN segment: bufRef; OUT byteCount: integerå
  WITH RECORD
    t: ^^;
    buf: bufRef;
    blockBuf: bufRef;
    superBuf: bufRef;
  END;
  VAR
    res: ResultType;
    i,ioPos,pos,bufAddr,bufSize,sbufSize,sbufRel:integer;
    bCount:integer;
    head,tail:integer;
BEGIN
 res.main:=ok;
 in
  check(normalGate.Lock);
  byteCount:=0;
  with b=segment^^ do begin
    bufSize:= elements(b);
    bufAddr:=byteAddr(bÆ1Å);
  end ;
  with d=localdata^^ do begin
    pos:=d.currPos;
    sbufRel:= pos mod d.blockSize;
    head:=(d.blockSize-sbufRel) mod d.blockSize;
æbug 83-11-09/mikå
    if head>=bufSize then tail:=0
    else tail:=(pos+bufSize)mod d.blockSize;
æ#begin#
printVar('83-10-21: readseq, head= ',head);
printVar('83-10-21: readseq, tail= ',tail);
printVar('83-10-21: readseq, sbufRel= ',sbufRel);
printVar('83-10-21: readseq, bufSize= ',bufSize);
printVar('83-10-21: readseq, bufAddr= ',bufAddr);
#end#å
    if ( ( bufAddr mod 2 = 0 æ buffer address even å ) and
         ( bufSize mod d.blockSize = 0 æ integral # blocks å ) and
         ( sbufRel = 0 æ integral block position å ) ) then begin
      check(Copy(segment,buf)); æfor recidencyå
      exception(transfer(buf,bufSize,byteCount,readCom,pos,d));
    end ;
  if (head>0) or (tail>0) then begin
    check(newSeg(blockBuf,d.blockSize));
  end;
 
   if head>0 then begin
    check(Copy(blockBuf,buf));
    ioPos:= pos - sbufRel;
    check(transfer(buf,d.blockSize,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 readseq, after transfer/head, byteCount= ',bCount);
#end#å
    if bCount > sbufRel+bufSize then bCount:=bufSize else
    if bCount < sbufRel         then bCount:= 0      else
                                        bCount:=bCount-sbufRel;
   end else bCount:=0;
   byteCount:=byteCount+bCount;
  end ; æ with då
  with b=segment^^ , sb=blockBuf^^ do
    for i:= 1 to bCount do
      bÆiÅ:= sbÆi+sbufRelÅ ;
 
 if bufSize-head-tail>0 then begin
  with d=localdata^^ do begin
    iopos:=pos+head;
æ#begin#
printVar('83-10-21 readseq: before NewSub ',i);
#end#å
    with b=segment^^ do
      check(NewSub(superBuf,var out bÆhead+1..(elements(b)-tail)Å));
æ#begin#
printVar('83-10-21 readseq: after NewSub ',i);
#end#å
    check(Copy(superBuf,buf));
    check(transfer(buf,bufSize-head-tail,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 readseq: after transfer body: bytecount=',bCount);
#end#å
    byteCount:=byteCount+bCount;
  end;
 end;
 
 if tail>0 then begin
  check(Copy(blockBuf,buf));
  with d=localdata^^ do begin
    iopos:=(pos+bufSize) div d.blockSize * d.blockSize;
      check(transfer(buf,d.blockSize,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 readseq: after transfer tail, bytecount= ',bCount);
#end#å
    if bCount>tail then bCount:=tail;
    byteCount:=byteCount+bCount;
  end æwithå;
  with b=segment^^ , sb=blockBuf^^ do
    for i:= 1 to bCount do
      bÆbufSize-tail+iÅ:=sbÆiÅ;
 end;
 
  do begin
   res:=getException;
  end ;
æ#begin#
printVar('83-10-21 readseq: return, bytecount= ',byteCount);
if byteCount>3000 then
with b=segment^^ do begin
  printVar('83-10-25 readseq: segmÆ1..100Å= ',bÆ1..100Å);
  printVar('83-10-25 readseq: segmÆbufsize-99..bufsizeÅ= ',
                   bÆelements(b)-99..elements(b)Å);
end;
#end#å
  check(normalGate.Open);
  ObjReturn(res);
END æ***ReadSeq***å;
 
 
 
ENTRY WriteSeq
  æIN segment: bufRef; OUT byteCount: integerå
  WITH RECORD
    t: ^^;
    buf: bufRef;
    superBuf: bufRef;
  END;
  VAR bLength,
      res: resultType;
      i,ioPos,pos,bufAddr,bufSize,sbufSize,sbufRel,writeCount: integer;
BEGIN
 in
  check(normalGate.Lock);
  with b=segment^^ do begin
    bufSize:= elements(b);
    bufAddr:= byteAddr(bÆ1Å);
  end ;
  with d=localdata^^ do begin
    pos:=d.currPos;
    sbufRel:= pos mod d.blocksize;
 
    if ( ( bufAddr mod 2 = 0 æ buffer address even å ) and
         ( bufSize mod d.blockSize = 0 æ integral # blocks å ) and
         ( sbufRel = 0 æ integral block position å ) ) then begin
       check(copy(segment,buf)); æfor residencyå
       exception(transfer(buf,bufSize,byteCount,writeCom,pos,d));
    end ;
 
    ioPos:= pos - sbufRel;
    sbufSize:=(bufSize+sbufRel+d.blockSize) div d.blockSize * d.blockSize;
    check(newseg(superBuf,sbufSize));
    check(copy(superBuf,buf)); æfor residencyå
    check(transfer(buf,sbufSize,byteCount,readCom,ioPos,d));
    writeCount:=byteCount;
    if byteCount > sbufRel+bufSize then byteCount:= bufSize else
    if byteCount < sbufRel         then byteCount:=  0      else
                                        byteCount:= byteCount-sbufRel;
  end ; æwith då
 
  with b=segment^^ , sb=superBuf^^ do
    for i:= 1 to byteCount do
      sbÆi+sbufRelÅ:= bÆiÅ;
 
  if byteCount > 0 then begin
    with d=localdata^^ do begin
      res:=transfer(buf,writeCount,byteCount,writeCom,ioPos,d);
      if byteCount > sbufRel+bufSize then byteCount:=bufSize else
      if byteCount < sbufRel         then byteCount:= 0      else
                                          byteCount:= byteCount-sbufRel;
    end ; æwith då
  end ;
 
  do begin
    res:= getException;
  end ;
  check(normalGate.Open);
  ObjReturn(res);
END æ***WriteSeq***å;
æ$Eå
ENTRY ReadRandom
  æIN segment:bufRef;OUT byteCount:integer;pos:integer;OUT actualPos:integerå
  WITH RECORD
    t: ^^;
    buf: bufRef;
    blockBuf: bufRef;
    superBuf: bufRef;
  END;
  VAR
    res: ResultType;
    i,ioPos,bufAddr,bufSize,sbufSize,sbufRel:integer;
    bCount:integer;
    head,tail:integer;
BEGIN
 res.main:=ok;
 in
  check(normalGate.Lock);
  byteCount:=0;
  with b=segment^^ do begin
    bufSize:= elements(b);
    bufAddr:=byteAddr(bÆ1Å);
  end ;
  with d=localdata^^ do begin
    sbufRel:= pos mod d.blockSize;
    head:=(d.blockSize-sbufRel) mod d.blockSize;
æbug 83-11-09/mikå
    if head>=bufSize then tail:=0
    else tail:=(pos+bufSize)mod d.blockSize;
æ#begin#
printVar('83-10-21: ReadRand, head= ',head);
printVar('83-10-21: ReadRand, tail= ',tail);
printVar('83-10-21: ReadRand, bufSize= ',bufSize);
printVar('83-10-21: ReadRand, bufAddr= ',bufAddr);
#end#å
    if ( ( bufAddr mod 2 = 0 æ buffer address even å ) and
         ( bufSize mod d.blockSize = 0 æ integral # blocks å ) and
         ( sbufRel = 0 æ integral block position å ) ) then begin
      check(Copy(segment,buf)); æfor recidencyå
      exception(transfer(buf,bufSize,byteCount,readCom,pos,d));
    end ;
  if (head>0) or (tail>0) then begin
    check(newSeg(blockBuf,d.blockSize));
  end;
 
   if head>0 then begin
    check(Copy(blockBuf,buf));
    ioPos:= pos - sbufRel;
    check(transfer(buf,d.blockSize,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 ReadRand, after transfer/head, byteCount= ',bCount);
#end#å
    if bCount > sbufRel+bufSize then bCount:=bufSize else
    if bCount < sbufRel         then bCount:= 0      else
                                        bCount:=bCount-sbufRel;
   end else bCount:=0;
   byteCount:=byteCount+bCount;
  end ; æ with då
  with b=segment^^ , sb=blockBuf^^ do
    for i:= 1 to bCount do
      bÆiÅ:= sbÆi+sbufRelÅ ;
 
 if bufSize-head-tail>0 then begin
  with d=localdata^^ do begin
    iopos:=pos+head;
    with b=segment^^ do
      check(NewSub(superBuf,var out bÆhead+1..(elements(b)-tail)Å));
    check(Copy(superBuf,buf));
    check(transfer(buf,bufSize-head-tail,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 ReadRand: after transfer body: bytecount=',bCount);
#end#å
    byteCount:=byteCount+bCount;
  end;
 end;
 
 if tail>0 then begin
  check(Copy(blockBuf,buf));
  with d=localdata^^ do begin
    iopos:=(pos+bufSize) div d.blockSize * d.blockSize;
      check(transfer(buf,d.blockSize,bCount,readCom,ioPos,d));
æ#begin#
printVar('83-10-21 ReadRand: after transfer tail, bytecount= ',bCount);
#end#å
    if bCount>tail then bCount:=tail;
    byteCount:=byteCount+bCount;
  end æwithå;
  with b=segment^^ , sb=blockBuf^^ do
    for i:= 1 to bCount do
      bÆbufSize-tail+iÅ:=sbÆiÅ;
 end;
 
  do begin
   res:=getException;
  end ;
  actualPos:=pos;
æ#begin#
printVar('83-10-21 ReadRand: return, bytecount= ',byteCount);
if byteCount>3000 then
with b=segment^^ do begin
  printVar('83-10-25 readrand: segmÆ1..100Å= ',bÆ1..100Å);
  printVar('83-10-25 readrand: segmÆbufsize-99..bufsizeÅ= ',
                   bÆelements(b)-99..elements(b)Å);
end;
#end#å
  check(normalGate.Open);
  ObjReturn(res);
END æ***ReadRandom***å;
 
 
æ$Eå
ENTRY WriteRandom
  æIN segment:bufRef;OUT byteCount:integer;pos:integer;OUT actualPos:integerå
  WITH RECORD t: ^^; buf: bufRef; superBuf: bufRef; END;
  VAR res: ResultType;
      i, ioPos, bufAddr, bufSize, sbufSize, sbufRel, writeCount: integer;
BEGIN
 in
  check(normalGate.Lock);
  with b=segment^^ do begin
    bufSize:= elements(b);
    bufAddr:= byteAddr(bÆ1Å);
  end ;
  with d=localdata^^ do begin
    sbufRel:= pos mod d.blocksize;
 
    if ( ( bufAddr mod 2 = 0 æ buffer address even å ) and
         ( bufSize mod d.blockSize = 0 æ integral # blocks å ) and
         ( sbufRel = 0 æ integral block position å ) ) then begin
       check(copy(segment,buf)); æfor residencyå
       exception(transfer(buf,bufSize,byteCount,writeCom,pos,d));
    end ;
 
    ioPos:= pos - sbufRel;
    sbufSize:=(bufSize+sbufRel+d.blockSize) div d.blockSize * d.blockSize;
    check(newseg(superBuf,sbufSize));
    check(copy(superBuf,buf)); æfor residencyå
    check(transfer(buf,sbufSize,byteCount,readCom,ioPos,d));
    writeCount:=byteCount;
    if byteCount > sbufRel+bufSize then byteCount:= bufSize else
    if byteCount < sbufRel         then byteCount:=  0      else
                                        byteCount:= byteCount-sbufRel;
  end ; æwith då
 
  with b=segment^^ , sb=superBuf^^ do
    for i:= 1 to byteCount do
      sbÆi+sbufRelÅ:= bÆiÅ;
 
  if byteCount > 0 then begin
    with d=localdata^^ do begin
      res:=transfer(buf,writeCount,byteCount,writeCom,ioPos,d);
      if byteCount > sbufRel+bufSize then byteCount:=bufSize else
      if byteCount < sbufRel         then byteCount:= 0      else
                                          byteCount:= byteCount-sbufRel;
    end ; æwith då
  end ;
 
  do begin
    res:= getException;
  end ;
  check(normalGate.Open);
  actualPos:=pos;
  ObjReturn(res);
END æ***WriteRandom***å;
æ$Eå
ENTRY Seek
  æbaseMode: BaseType; offset: integer; OUT pos: integerå
  WITH RECORD t: ^^; END;
  VAR res: ResultType;
BEGIN
  res.main:=ok;
  WITH d=localdata^^, c=ipc^^.localdata^^ DO BEGIN
    check(ipc^^.ipcGate.Lock);
    IN ægate lockedå
      æenter scheduling queueå
      d.devReserved:=d.devReserved+1;
      IF d.devReserved>1 THEN BEGIN
æprintVar('... seek, schedQ ... devReserved= ',d.devReserved);å
      æ check(Propagate(propReject));  kernel-errorå
          check(schedQ.Wait);  æcan be speeded up without harmå
      æ check(Propagate(propNone));    kernel-errorå
      END;
      IF d.reserv=NoRights THEN
        exception(genRes(-EntryIllegal,Universal,0));
      IF c.breakÆd.devnoÅ THEN
        exception(genRes(-BreakPending,IoFamily,0));
      CASE baseMode OF
        FromStart:   pos:=offset;
        FromCurrent: pos:=d.currPos+offset;
        FromEnd:     exception(genRes(-DataValueIllegal,Universal,-1));
      END;
      IF pos<0 THEN res:=genRes(-PosOutsideRange,IoFamily,-3)
      ELSE   d.currPos:=pos;
      d.devReserved:=d.devReserved-1;
      IF d.devReserved>0 THEN check(schedQ.Signal)
      ELSE IF d.waitEmpty THEN BEGIN
        d.waitEmpty:=false;
        check(Empty.Signal);
      END;
    DO IF res.main=ok THEN res:=getException;
    check(ipc^^.ipcGate.Open);
  END æwithå;
  ObjReturn(res);
END æ***Seek***å;
æ$Eå
ENTRY SetRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY CheckRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY MoveRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY NewLink
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY GetFileInf
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY SetMode
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY DataSize WITH tempRefs;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY AllocSize WITH tempRefs;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
æ$Eå
ENTRY WaitBreak
  WITH RECORD t: ^^; END;
  VAR res: resultType;
BEGIN
  res.main:=ok;
  WITH d=localdata^^, c=ipc^^.localdata^^ DO BEGIN
    IN
      check(ipc^^.ipcGate.Lock);
      IN æipcGate lockedå
        IF d.waitBreak THEN exception(genRes(-alreadyWaiting,IoFamily,0));
        IF d.reserv=NoRights THEN exception(genRes(-EntryIllegal,Universal,0));
        IF NOT c.breakÆd.devnoÅ THEN BEGIN
          d.waitBreak:=true;
        æ check(Propagate(propReject));  kernel-errorå
            res:=breakCond.Wait;
        æ check(Propagate(propNone));å
          d.waitBreak:=false;
        END;
      DO IF res.main=ok THEN res:=getException;
      check(ipc^^.ipcGate.Open);
    DO IF res.main=ok THEN res:=getException;
  END æwithå;
  ObjReturn(res);
END æ***WaitBreak***å;
 
ENTRY WaitReady
  WITH RECORD t: ^^; END;
  VAR res:resultType;
BEGIN
  res.main:=ok;
  WITH d=localdata^^, c=ipc^^.localdata^^ DO BEGIN
    check(ipc^^.ipcGate.Lock);
      IN
        IF d.reserv=NoRights THEN
          exception(genRes(-EntryIllegal,Universal,0));
        IF c.breakÆd.devnoÅ THEN BEGIN
          IF d.devReserved>0 THEN BEGIN
            æThis code should actually never be executed because of the
             kernel's scheduling strategy for gates and conditionså
            d.waitEmpty:=true;  check(empty.Wait);
            check(empty.signal); æif more processes are waitingå
          END;
          c.breakÆd.devnoÅ:=false;
        END;
      DO IF res.main=ok THEN res:=getException;
    check(ipc^^.ipcGate.Open);
  END æwithå;
  ObjReturn(res);
END æ***WaitReady***å;
 
ENTRY Dup
  with record t:^^; end;
begin
  exception(genRes(-EntryIllegal,Universal,2));
end;
 
OTHERWISE DiskOther
  WITH RECORD t: ^^; END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
END æ***OtherFunc***å;
 
END æ lineImplement å;
æ$Eå
æ***** I P C   O B J E C T   I M P L E M E N T A T I O N *****å
æ*************************************************************å
 
PROGRAM udcImplement OBJECT IoSys WITH ipcLocals;
 
PRIVATE Close
  (driver,env: ref ækernel suppliedå);
 
æ***** LOCAL ROUTINES *****å
 
FUNCTION same
  (dirIndex: integer;
   id: fullId;
   VAR d: ipcData)
  : boolean;
æcompares the two fullid'så
  VAR i, length: integer;
      stop: boolean;
BEGIN
  length:=d.dirÆdirIndexÅ.nameLength;
  stop:=length<>elements(id);
  i:=1;
  WHILE (i<=length) AND NOT stop DO BEGIN
    stop:=d.dirÆdirIndexÅ.nameÆiÅ<>idÆiÅ;
    i:=i+1;
  END;
  same:=NOT stop;
END æ***same***å;
 
FUNCTION search
  (id: fullId;
   VAR d: ipcData)
  : devnos;
  VAR i: integer;
      found: boolean;
BEGIN
  i:=minDevno;
  found:=false;
  WHILE (i<=maxDevno) AND NOT found DO BEGIN
    found:=same(i,id,d);
    IF NOT found THEN i:=i+1;
  END;
  IF NOT found THEN
    exception(genRes(-FileNotFound,IoFamily,-1));
  search:=i;
END æ***search***å;
æ$Eå
æ***** ENTRIES *****************************************å
æ*******************************************************å
 
ENTRY InitIpcSys
  æIN vector, level: integer; IN chanAddr: addresså
  WITH RECORD
    t: ^^;
    tempOwn:^^;
  END;
  VAR intprocAddr: address;
      i: integer;
      res: resultType;
BEGIN
  printText(version);
  res.main:=ok;
  æcreate dirGateå
    check(schedRef.NewGate(OUT dirGate));
  æcreate ipcGateå
    check(iSchedRef.NewGate(OUT tempOwn;level));
    check(Copy(tempOwn,ipcGate));
    check(MoveOwn(tempOwn,ownSet));
    check(ipcGate.Resident(ipcGate));
  æcreate interrupt ptrå
    check(iSchedRef.NewChannel(OUT interruptPtr, IN code;
                                 vector,level,kernelStack,addr(intudc)));
  æis it necessary to make code segment resident?????å
  æmake localdata residentå
    check(Copy(ownLocalData,localdata));
    check(ipcGate.Resident(localdata));
  æinitialize localdataå
    WITH d=localdata^^ DO BEGIN
      d.chanAddr:=chanAddr;
      d.vector:=vector;
      d.level:=level;
      FOR i:=minDevno TO maxDevno DO BEGIN
        d.dirÆiÅ.nameLength:=0;
        WITH d.countÆiÅ DO BEGIN
          transfers:=0;  repeats:=0;
          q1:=0;  q2:=0;  q3:=0;
        END;
      END;
      d.ipcReserved:=0;
      d.ackFifoFirst:=minDevno+1;  d.ackFifoLast:=minDevno;
    END;
  check(MakeReentrant(egoEnv));
  ObjReturn(res);
END æ***ENTRY Init***å;
æ$Eå
ENTRY CreateFile
  ædevName: fullId; devno: devnos (hwConfig, swConfig: integer)å
  WITH RECORD
    t:^^;
  END;
  VAR intPtr: ^integer;
      i,length: integer;
      res: resultType;
BEGIN
  res.main:=ok;
  check(dirGate.Lock);
  IN ædirGate lockedå
    IF NOT ((devno>=0) AND (devno<=7)) THEN
      exception(genRes(-DataValueIllegal,Universal,-2));
    WITH d=localdata^^ DO BEGIN
      IF d.dirÆdevnoÅ.nameLength<>0 THEN
        exception(genRes(-alreadyNamed,IoFamily,-2));
      FOR i:=minDevno TO maxDevno DO
        IF same(i,devName,d) THEN
          exception(genRes(-FileNameExists,IoFamily,-1));
      length:=elements(devName);
      IF length>maxIdLength THEN length:=maxIdLength;
      WITH d.dirÆdevnoÅ DO BEGIN
        FOR i:=1 TO length DO nameÆiÅ:=devNameÆiÅ;
        nameLength:=length;
      END æwithå;
    END æwithå;
  DO res:=getException;
  check(dirGate.Open);
  ObjReturn(res);
END æ***ENTRY Create***å;
æ$Eå
ENTRY DeleteFile
  ædevName: fullIdå
  WITH RECORD
    t:^^;
    refDriver: ^^;
  END;
  VAR devno: devnos;
      stop,
      res: resultType;
BEGIN
  res.main:=ok;
  check(dirGate.Lock);
  IN  ædirGate lockedå
    WITH d=localdata^^ DO BEGIN
      devno:=search(devName,d);
      IF NOT ((devno>=0) AND (devno<=7)) THEN
        exception(genRes(-DataValueIllegal,Universal,-2));
      d.dirÆdevnoÅ.nameLength:=0;
      æabort any drivers open to the deviceå
        stop:=FirstInSet(driversÆdevnoÅ,refDriver);
        WHILE stop.main=ok DO BEGIN
          check(Abort(refDriver));
          stop:=NextInSet(driversÆdevnoÅ,refDriver);
        END;
    END æwithå;
  DO IF res.main=ok THEN res:=getException;
  check(dirGate.Open);
  ObjReturn(res);
END æ***ENTRY Delete***å;
æ$Eå
ENTRY Assign
  æOUT ownedFao: ref; IN fileName: fullId; ioRights: IoTypeå
  WITH RECORD
    t:^^;
    tempMan: ^^drivLocals;
    tempEnv: ^^drivLocals;
  END;
  VAR s: sizeType;
      res, ignore: resultType;
      i: integer;
      devno: devnos;
      req: ipcRequest;
BEGIN
  res.main:=ok;
  æcreate access objectå
    check(ClearSize(s));
    check(AddEnv(s,refs(drivLocals))); check(AddSeg(s,bytes(drivData)));
    check(allocRef.NewObj(OUT ownedFao; makeSize(2000,500), OUT i));
    check(ClearSize(s));
    check(DeclGen(ownedFao,tempMan,tempEnv,refs(drivLocals),Close,s,s,
                  refs(diskImplement),bytes(diskImplement),0,
                  addr(diskImplement),s,true));
    IN  æenvelope createdå
      check(Copy(code,tempMan^^.code));
      check(Copy(egoEnv,tempMan^^.ipc));
      check(ipcGate.Resident(tempMan^^.ipc));
      check(schedRef.NewGate(OUT tempMan^^.normalGate));
      æcomplete condå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.complete));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.complete));
      æbreakCondå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.breakCond));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.breakCond));
      æschedQå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.schedQ));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.schedQ));
      æemptyå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.empty));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.empty));
      ælocaldataå
        check(NewSeg(tempMan^^.ownSet,bytes(drivData)));
        check(Copy(tempMan^^.ownSet,tempMan^^.localdata));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.localdata));
      check(dirGate.Lock);
      IN  ædirGate lockedå
        WITH d=localdata^^ DO BEGIN
          devno:=search(fileName,d);
          WITH c=tempMan^^.localdata^^ DO BEGIN
            c.devno:=devno;
            c.reserv:=ioRights;
           æc.mode.timeout:=?;å
            c.devReserved:=0;
            c.waitBreak:=false;
            c.waitEmpty:=false;
            c.currPos:=0;
            c.blockSize:=256;
            WITH c.count DO BEGIN
              transfers:=0;  repeats:=0;
              q1:=0;  q2:=0;  q3:=0;
            END;
          END;
          æcheck the ioRights reservationå
          IF ioRights<>NoRights THEN BEGIN
            IF SameEntity(currDriverÆdevnoÅ,void) THEN BEGIN
              check(Copy(tempMan,currDriverÆdevnoÅ));
              check(ipcGate.Resident(currDriverÆdevnoÅ));
              d.breakÆdevnoÅ:=false;
            END ELSE BEGIN
              exception(genRes(-RightsOccupied,IoFamily,0));
            END;
          END;
        END æwithå;
      DO BEGIN
        ignore:=dirGate.Open;
        exception(getException);
      END;
      check(dirGate.Open);
      check(MakeReentrant(tempMan));
      check(MoveMan(tempMan,driversÆdevnoÅ));
    DO BEGIN
      ignore:=DelEnv(ownedFao,tempMan);
      IF res.main=ok THEN res:=getException;
      æ'ownedFao' is deleted automatically by kernel when result is rejectå
    END;
    ObjReturn(res);
END æ***ENTRY Assign***å;
æ$Eå
PRIVATE Close
  æIN driver,env: ref (kernel supplied)å
  WITH RECORD
    t: ^^;
  END;
  VAR devno: devnos;
BEGIN
  check(ipcGate.Lock);
  WITH e=env:drivLocRef, c=e^^.localdata^^, d=localdata^^ DO BEGIN
    devno:=c.devno;
    d.countÆdevnoÅ:=c.count;
  END;
  check(ipcGate.Open);
  check(DelEnv(driver,driversÆdevnoÅ));
  check(Dealloc(driver,driver));
END æ***ENTRY Close***å;
 
ENTRY ScanFiles
  WITH RECORD
    t: ^^;
  END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
END æ***ENTRY InitScan***å;
 
ENTRY CreateLink WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY DeleteLink WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY RenameFile WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY Exclude WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY Include WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY InitFileSys WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
OTHERWISE IpcOther
  WITH RECORD t: ^^; END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
ENDæ***OtherFunc***å;
 
entry clonefileenv with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
entry clonecontrol with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
entry waitsignal with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
entry closeclone with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
END æ mccmImplement å;
æ$Eå
æ$L-å
(*//////////////////////////////////////////////////////////////////////
TYPE addrSpace=ARRAY Æaddrmin..16777200Å OF byte;
æ**************************************************************************å
æ****************************** T E S T S T U B ***************************å
æ**************************************************************************å
object Stub;
  entry BootInit;
  entry e2;
end;
program implTeststub object stub
  with record
    code: ^^;
    bootset: ownSet;
    alloc,
    sched,
    intsched: ^^;
    fullspace: ^^ ÆÅ addrSpace;
    defvirt,
    ego,
    egoenv,
    bootproc: ^^;
    ipcObj: ^^IoSys;  ipcMan: ^^;
    fao0, fao4: ^^Fao;
    p2: ^^;
    buf: bufRef;
  end;
 
procedure try (res:ResultType);
begin
  printVar('##### T R Y #####, result= ',res);
end;
 
private termUdc with tempRefs;
begin printText('udcobj terminated') end;
 
entry BootInit with record t:^^; tempEnv: ^^ipcLocals; stack:^^; end;
  const udcfirst=16#ff0000; udcvector=255; udclevel=3;
        bufsize=256;
  var s: sizeType;
      count: integer;
      pos: integer;
      i: integer;
      devno: devnos;
      name4: string8;
      res: ResultType;
begin
    check(alloc.NewObj(ipcObj; makeSize(5000,2000),out count));
    check(DeclGen(ipcObj,ipcMan,tempEnv,refs(ipcLocals),termUdc,
                  makeSize(0,0),makeSize(0,0),refs(udcImplement),
                  bytes(udcImplement),0,addr(udcImplement),
                  makeSize(0,0),true));
    check(Copy(code,    tempEnv^^.code));
    check(Copy(ego,     tempEnv^^.stubRef));
    check(Copy(intsched,tempEnv^^.iSchedRef));
    check(Copy(sched,   tempEnv^^.schedRef));
    check(Copy(alloc,   tempEnv^^.allocRef));
    check(Copy(tempEnv, tempEnv^^.egoEnv));
    check(NewSeg(tempEnv^^.ownLocaldata,bytes(ipcData)));
    check(ipcObj.InitIpcSys(;udcvector,udclevel,udcfirst));
    check(alloc.NewObj(buf; makeSize(10000,1000),out count));
    check(DeclSeg(buf,bufsize));
 
    ætest of ipc objectå
    printText('Start of test - ipc object');
    name4:=str8('4            ');
    try(ipcObj.Assign(out fao4; name4,ReadWrite));     æfile not foundå
 
    devno:=8; try(ipcObj.CreateFile(;name4,devno));    æDataValueIllegalå
 
    devno:=4; check(ipcObj.CreateFile(;name4,devno));
    devno:=0;   try(ipcObj.CreateFile(;name4,devno));  æFileNameExistså
 
    check(ipcObj.Assign(out fao4; name4,ReadWrite));
    check(fao4.ReadSeq(in buf; out count));
    check(ipcObj.DeleteFile(;name4));
    try(ipcObj.DeleteFile(;name4));                    æFileNotFoundå
 
æ  kernel-error 83-06-02
    try(fao4.ReadSeq(in buf; out count));              æDummyfiedå
å
 
    devno:=4; check(ipcObj.CreateFile(;name4,devno));
æ  kernel-error 83-06-02
    try(fao4.ReadSeq(in buf; out count));              æDummyfiedå
å
 
    check(Dealloc(fao4,fao4));
    check(ipcObj.Assign(out fao4; name4,ReadWrite));
    check(fao4.ReadSeq(in buf; out count));
æ  kernel error 83-06-02  (refEqual)
    try(ipcObj.Assign(out fao0; name4,ReadWrite));     æRightsOccupiedå
å
 
    check(ipcObj.Assign(out fao0; name4, NoRights));
    try(fao0.ReadSeq(in buf; out count));           æEntryIllegalå
 
    check(ipcObj.DeleteFile(;name4));
    check(Dealloc(fao0,fao0));  check(Dealloc(fao4,fao4));
 
    printText('End of test - ipc object ');
 
    printText('Start of test - Disk object ');
 
    devno:=4; check(ipcObj.CreateFile(;name4,devno));
    check(ipcObj.Assign(out fao4; name4,ReadWrite));
    with b=buf^^ do begin
      for i:=1 to 16 do bÆiÅ:=i;
      printVar('testbuf= ',b);
    end;
    check(fao4.WriteRandom(buf;out count,4*256,out pos));
    if pos<>4*256 then printVar('test error 1: pos= ',pos);
    check(fao4.ReadRandom(buf;out count,4*256,out pos));
    with b=buf^^,b8=bÆ1..8Å do printVar('4. sector= ',b);
 
    check(fao4.Seek(;FromCurrent,256,out pos));
    check(fao4.Seek(;FromCurrent,-6*256,out pos));
    if pos<>0 then printVar('test error 2: pos= ', pos);
 
    for i:=1 to 5 do
      check(fao4.ReadSeq(buf;out count));
    with b=buf^^ do printVar('sector= ',b);
 
    check(fao4.Seek(;FromStart,0,out pos));
    i:=0;
    repeat
      printVar('start loop, i= ',i);
      check(fao4.WaitBreak); check(fao4.WaitReady);
      check(fao4.Seek(;FromCurrent,0,out pos));
      printVar('pos= ',pos);
      in  repeat check(fao4.ReadSeq(buf;out count)); i:=i+1 until false;
      do begin
        res:=getException;
        printVar('ATTENTION, res= ',res);
        printVar('Attention, i= ',i);
        if res.main=PosOutsideRange then exception(res);
        check(fao4.WaitReady);
      end;
    until false;
end;
 
entry e2 with tempRefs;
begin end;
 
otherwise o with tempRefs;
begin printText('teststub.otherwise') end;
 
end æteststubå;
/////////////////////////////////////////////////////////////*)
æ$L+å
æ$Eå
INITIALIZE
  udcImplement 'udc':
    allocRef 'allocate',
    schedRef 'scheduler',
    iSchedRef 'intscheduler',
    stubRef 'objdir',
    egoEnv '**',
    ownLocaldata
æ implTeststub 'teststub': å
END.
 
«eof»