Retrocomputing

OS-9 Level I V1.2 kernal, part 2

The OS-9 kernel is split into two parts. Part 2 is position independent, but usually resides in a two-kilobyte ROM at $F000 together with other modules, such as Clock and SysGo.

         nam OS-9 Level I V1.2 kernal, part 2
         ttl Module Header


************************************************************
*                                                          *
*        Microware OS-9 Level I V1.2 Kernal, part 2        *
*                                                          *
************************************************************

* Copyright 1980 by Motorola, Inc., and Microware Systems Corp.,
* Reproduced Under License

*
* This source code is the proprietary confidential property of
* Microware Systems Corporation, and is provided to licensee
* solely  for documentation and educational purposes. Reproduction,
* publication, or distribution in any form to any party other than
* the licensee is strictly prohibited!!
*

         use  defsfile

*****
*
*  Module Header
*
Type     set  SYSTM+OBJCT
Revs     set  REENT+1
         mod  OS9End,OS9Nam,Type,Revs,OS9Ent,0
OS9Nam   fcs  /OS9p2/

********************
*
*     Edition History
*
* Edition  6 -  changes to Send routine, fixing timed sleep
*  82/09/10     wake up bug  LAC
*
* Edition  7 -  changes made to "boot" subroutine, keeping the
*               integrity of U (a ptr to D.Base)  WGP
*
* Edition  8 -  Change made to setime system call enabling it to
*               call the init routine of the clock module  WGP
*
* Edition  9 -  Set boot flag to prevent loop
*
         fcb  9          Edition number

         ttl Service Routine initialization table
         page
*****
*
* System Service Routine Table
*
SVCTBL   equ  *
         fcb  $7F
         fdb  IOHOOK-*-2
         fcb  F$Unlink
         fdb  UNLINK-*-2
         fcb  F$WAIT
         fdb  WAIT-*-2
         fcb  F$EXIT
         fdb  EXIT-*-2
         fcb  F$MEM
         fdb  USRMEM-*-2
         fcb  F$SEND
         fdb  SEND-*-2
         fcb  F$Sleep
         fdb  SLEEP-*-2
         fcb  F$ICPT
         fdb  INTCPT-*-2
         fcb  F$ID
         fdb  GETID-*-2
         fcb  F$SPrior
         fdb  SETPRI-*-2
         fcb  F$SSWI
         fdb  SETSWI-*-2
         fcb  F$STime
         fdb  SetTime-*-2
         fcb  F$Find64+$80
         fdb  F64-*-2
         fcb  F$ALL64+$80
         fdb  A64-*-2
         fcb  F$Ret64+$80
         fdb  R64-*-2
         fcb  $80



         ttl Cold Start routine
         page
*****
*
* Cold Start Routines
*
*
* Initialize Service Routine Dispatch Table
*
OS9Ent   leay SVCTBL,PCR Get ptr to service routine table
         OS9  F$SSVC     Set service table addresses
         ldx  D.PrcDBT   Get process ptr
         OS9  F$ALL64    Get a process
         bcs  COLD
         stx  D.PrcDBT   Set process block
         sty  D.PROC
         tfr  S,D        copy stack ptr
         deca            get page lower bound
         ldb  #1         set page count
         std  P$ADDR,Y   set process descriptor
         lda  #SysState  Set system state
         sta  P$State,Y
         ldu  D.Init     get configuration ptr
         bsr  SETDIRS    set default directories
         bcc  COLD10     branch if successful
         lbsr BOOT       Default failed, boot
         bsr  SETDIRS    try again
COLD10   bsr  SETSTDS    open standard i/o
         bcc  COLD20     branch if successful
         lbsr BOOT       open failed, boot
         bsr  SETSTDS    try again
COLD20   ldd  InitStr,U  Get initial execution string
         leax D,U        Get string ptr
         lda  #OBJCT     set type
         clrb            use declared memory
         ldy  #0         No parameters
         OS9  F$Chain    Start process

COLD     jmp  [$FFFE]    Abort start up

SETDIRS  clrb            clear carry
         ldd  SYSSTR,U   Get system device name
         beq  SETDIR10   Branch if none
         leax D,U        Get name ptr
         lda  #EXEC.+READ. Set both execution & data
         OS9  I$ChgDir   Set default directory
SETDIR10 rts

SETSTDS  clrb            clear carry
         ldd  STDSTR,U   get name offset
         leax D,U        get name ptr
         lda  #UPDAT.    set mode
         OS9  I$OPEN     open file
         bcs  SETSTD10   branch if error
         ldx  D.PROC     get process ptr
         sta  P$PATH,X   set standard input
         OS9  I$DUP      count open image
         sta  P$PATH+1,X set standard output
         OS9  I$DUP      count open image
         sta  P$PATH+2,X set standard error
SETSTD10 rts


         ttl SERVICE Routines
         page
*****
*
*  Subroutine Unlink
*
* Decrment Link Count. If Count Reaches Zero,
*    Delete Module From Directory & Return Memory
*
UNLINK   ldd  R$U,U      Get module address
         beq  UNLK25     Branch if none
         ldx  D.ModDir   Get directory ptr
UNLK10   cmpd 0,X        Is it this module?
         beq  UNLK15     Branch if so
         leax 4,X        Move to next entry
         cmpx D.ModDir+2 End of directory?
         bcs  UNLK10
         bra  UNLK25
UNLK15   lda  2,X        Get use count
         beq  UNLK16     Branch if not used
         deca            DOWN Link count
         sta  2,X
         bne  UNLK25     Branch if still used
UNLK16   ldy  0,X        Get ptr to module
         cmpy D.BTLO     Is it 'system' module?
         bcc  UNLK25     Branch if so
         ldb  M$TYPE,Y   Get module type
         cmpb #FLMGR     Is i/o module?
         bcs  UNLK20     Branch if not
         OS9  F$IODel    Delete from i/o system
         bcc  UNLK20
         inc  2,X        Reset link count
         bra  UNLK30
UNLK20   clra
         clrb
         std  0,X        Clear directory entry
         std  0,Y        Destroy id code
         ldd  M$SIZE,Y   Get module size
         lbsr DIV256     Divide by 256, rounding up
         exg  D,Y        Switch page count & beginning address
         exg  A,B        Make address into page number
         ldx  D.FMBM     Get bit map ptr
         OS9  F$DelBit   Deallocate memory block
UNLK25   clra            CLEAR Carry
UNLK30   rts
         page
*****
*
*  Subroutine Wait
*
* Wait for Child Process to Exit
*
WAIT     ldy  D.PROC     Get process ptr
         ldx  D.PrcDBT   Get process descriptor block ptr
         lda  P$CID,Y    Does process have children?
         bne  WAIT10     Branch if so
         comb            Set Carry
         ldb  #E$NoChld  Err: no children
         rts
WAIT10   OS9  F$Find64   Get process ptr
         lda  P$State,Y  Get child's status
         bita #DEAD      Is child dead?
         bne  WAIT20     Branch if so
         lda  P$SID,Y    More children?
         bne  WAIT10     Branch if so
         clr  R$A,U      clear child process id
         ldx  D.PROC     Get process ptr
         orcc #IRQMask+FIRQMask Set interrupt masks
         ldd  D.WProcQ   Put in waiting queue
         std  P$Queue,X
         stx  D.WProcQ
         lbra ZZZPRC     Put process to sleep
WAIT20   ldx  D.PROC     Get parent process ptr
*
*           Fall Thru to Childs
*
*****
*
*  Subroutine Childs
*
* Return Child's Death Status to Parent
*
* Input:  X - Parent Process ptr
*         Y - Child Process ptr
*         U - Parent Process Register ptr
*
CHILDS   lda  P$ID,Y     Get process id
         ldb  P$Signal,Y Get death status
         std  R$D,U      Return to parent
         pshs A,X,Y,U    Save registers
         leay P$CID-P$SID,X Fake sibling process ptr
         ldx  D.PrcDBT   Get process descriptor block ptr
         bra  CHIL20
CHIL10   OS9  F$Find64   Get process ptr
CHIL20   lda  P$SID,Y    Is child next sibling?
         cmpa 0,S
         bne  CHIL10     Branch if not
         ldu  3,S        Get process ptr
         ldb  P$SID,U    Get child's sibling
         stb  P$SID,Y    Remove child from sibling list
         OS9  F$Ret64    Return process descriptor
         puls A,X,Y,U,PC
         page
*****
*
*  Subroutine Exit
*
* Process Termination
*
EXIT     ldx  D.PROC     Get process ptr
         ldb  R$B,U      Get exit status
         stb  P$Signal,X Save status
         ldb  #NumPaths  Get number of paths
         leay P$PATH,X   Get path table ptr
EXIT10   lda  ,Y+        Get next path number
         beq  EXIT15     Branch if not in use
         pshs B          Save path count
         OS9  I$Close    Close the file
         puls B          Retrieve path count
EXIT15   decb            COUNT Down
         bne  EXIT10     Branch if more
         lda  P$ADDR,X   Get memory page number
         tfr  D,U        Copy it
         lda  P$PagCnt,X
         OS9  F$SRtMem
         ldu  P$PModul,X Get primary module ptr
         OS9  F$Unlink   Unlink it
         ldu  D.PROC     Get process ptr
         leay P$CID-P$SID,U Fake sibling process
         ldx  D.PrcDBT   Get process descriptor block
         bra  EXIT30
EXIT20   clr  P$SID,Y    Clear sibling link
         OS9  F$Find64   Get next process ptr
         lda  P$State,Y  Get process status
         bita #DEAD      Is process dead?
         beq  EXIT25     Branch if not
         lda  P$ID,Y     Return process to free
         OS9  F$Ret64    Return process descriptor
EXIT25   clr  P$PID,Y    Clear parent process ptr
EXIT30   lda  P$SID,Y    Get sibling id
         bne  EXIT20     Branch if there is one
         ldx  #D.WProcQ-P$Queue Fake process ptr
         lda  P$PID,U    Get parent process id
         bne  EXIT40     Branch if parent alive
         ldx  D.PrcDBT   Get process block ptr
         lda  P$ID,U     Get process id
         OS9  F$Ret64    Return process descriptor
         bra  EXIT50
EXIT35   cmpa P$ID,X     Is this parent?
         beq  EXIT45     Branch if so
EXIT40   leay 0,X        Copy this process ptr
         ldx  P$Queue,X  Get next process ptr
         bne  EXIT35     Branch if there is one
         lda  P$State,U  Get process status
         ora  #DEAD      Note process death
         sta  P$State,U  Update status
         bra  EXIT50     Wait for parent to notice
EXIT45   ldd  P$Queue,X  Remove parent from wait list
         std  P$Queue,Y
         OS9  F$AProc    Put parent in active process queue
         leay 0,U        Copy child ptr
         ldu  P$SP,X     Get parent's stack
         ldu  R$D,U      Get actual wait stack
         lbsr CHILDS     Return child status
EXIT50   clra            REMOVE Process from active system
         clrb
         std  D.PROC
         rts
         page
*****
*
*  Subroutine Usrmem
*
* Adjust User Memory To Requested Size
*
USRMEM   ldx  D.PROC     get process ptr
         ldd  R$D,U      Get size requested
         beq  USRM35     branch if info request
         bsr  DIV256     Divide by 256, rounding up
         subb P$PagCnt,X Subtract current size
         beq  USRM35     Branch if already requested size
         bcs  USRM20     Branch if current > requested
         tfr  D,Y        Copy pages needed
         ldx  P$ADDR,X   Get memory address & size
         pshs X,Y,U      Save registers
         ldb  0,S        Get address
         beq  USRM10     Branch if none
         addb 1,S        Get location of new
USRM10   ldx  D.FMBM     Get free memory ptrs
         ldu  D.FMBM+2
         OS9  F$SchBit   Look for memory
         bcs  BADMEM     Branch if not available
         stb  2,S        Save page number of new
         ldb  0,S        Get beginning of old
         beq  USRM15     Branch if none
         addb 1,S        Add size old
         cmpb 2,S        Is that where new begins?
         bne  BADMEM     Branch if not
USRM15   ldb  2,S        Get page number of new
         OS9  F$AllBit   Allocate memory
         ldd  2,S        Get new address & size
         suba 1,S        Get address of current
         addb 1,S        Get size current
         puls X,Y,U
         ldx  D.PROC     Get process ptr
         bra  USRM30
USRM20   negb            GET Excess page count
         tfr  D,Y        Copy it
         negb            GET Size requested
         addb P$PagCnt,X
         addb P$ADDR,X   Get page number of excess
         cmpb P$SP,X     Deallocating stack?
         bhi  USRM25     Branch if not
         comb            SET Carry
         ldb  #E$DelSP
         rts
USRM25   ldx  D.FMBM     Get free memory ptr
         OS9  F$DelBit   Deallocate memory
         tfr  Y,D        Copy excess page count
         negb
         ldx  D.PROC     Get process ptr
         addb P$PagCnt,X Adjust page count
         lda  P$ADDR,X   Get address
USRM30   std  P$ADDR,X   Set new address & size
USRM35   lda  P$PagCnt,X Get process beginning address
         clrb            CLEAR Lsb
         std  R$D,U      Return memory size
         adda P$ADDR,X   Return ptr to memory end
         std  R$Y,U
         rts

BADMEM   comb            SET Carry
         ldb  #E$MemFul  Err: memory full
         puls X,Y,U,PC



*****
*
* Subroutine Div256
*
* Divide By 256, Rounding Up
*
DIV256   addd #$FF
         clrb            ROUND Up
         exg  A,B        Divide by 256
         rts
         page
*****
*
*  Subroutine Send
*
* Send a Signal to Process(es)
*
SEND     lda  R$A,U      Get destination process id
         bne  SENSUB     Branch if not all processes
*
* Loop thru all Process Ids, send Signal to all but Sender
*
         inca            Start with process 1
SEND10   ldx  D.PROC     Get process ptr
         cmpa P$ID,X     Is this sender?
         beq  SEND15     Branch if so
         bsr  SENSUB     Signal process
SEND15   inca            Get next process id
         bne  SEND10     Branch if more
         clrb            Clear Carry
         rts
*
* Get destination Process ptr
*
SENSUB   ldx  D.PrcDBT   Get process descriptor block ptr
         OS9  F$Find64   Get process ptr
         bcc  SEND20     Branch if good
         ldb  #E$IPrcID  Err: illegal process id
         rts
*
* Check Signal type
*
SEND20   orcc #IRQMask+FIRQMask Set interrupt masks
         pshs A,Y        Save process id & ptr
         ldb  R$B,U      Is it unconditional abort signal?
         bne  SEND30     Branch if not
         lda  P$State,Y  Get process status
         ora  #CONDEM    Condem process
         sta  P$State,Y  Update status
*
* Check for Signal collision
*
SEND30   lda  P$Signal,Y Is signal pending?
         beq  SEND40     Branch if not
         deca            Is it wake-up?
         beq  SEND40     Branch if so
         comb            Set Carry
         ldb  #E$USigP   Err: unprocessed signal pending
         puls A,Y,PC
SEND40   stb  P$Signal,Y Save signal
*
* Look for Process in Sleeping Queue
*
         ldx  #D.SProcQ-P$Queue Fake process ptr
         bra  SEND55
SEND50   cmpx 1,S        Is this destination process?
*
*** Ed. 6 changes follow
*
         bne  SEND55     branch if not
         lda  P$State,x  get process state
         bita #TimSleep  is process in timed sleep?
         beq  SEND65     branch if not
         ldu  P$SP,x     get process stack ptr
         ldd  R$X,u      get remaining time
         beq  SEND65     branch if none
         ldu  P$Queue,x  get next process in queue
         beq  SEND65     branch if none
         pshs d          save remaining time
         lda  P$State,u  get process state
         bita #TimSleep  is it in timed sleep?
         puls d          retrieve remaining time
         beq  SEND65     branch if not
         ldu  P$SP,u     get process stack ptr
         addd R$X,u      add remaining time
         std  R$X,u      update it
         bra  SEND65
*
*** end of Ed. 6 changes
*
SEND55   leay 0,X        Copy process ptr
         ldx  P$Queue,Y  More in queue?
         bne  SEND50     Branch if so
*
* Look for Process in Waiting Queue
*
         ldx  #D.WProcQ-P$Queue Fake process ptr
SEND60   leay 0,X        Copy process ptr
         ldx  P$Queue,Y  More in queue?
         beq  SEND75     Branch if not
         cmpx 1,S        Is this destination process?
         bne  SEND60     Branch if not
*
* Move Process from it's current Queue to Active Queue
*
SEND65   ldd  P$Queue,X  Remove from queue
         std  P$Queue,Y
         lda  P$Signal,X Get signal
         deca            Is it wake-up?
         bne  SEND70     Branch if not
         sta  P$Signal,X Clear signal
SEND70   OS9  F$AProc    Put in active queue
SEND75   clrb            Clear carry
         puls A,Y,PC
         page
*****
*
*  Subroutine Sleep
*
* Suspend Process
*
SLEEP    ldx  D.PROC     Get current process
         orcc #IRQMask+FIRQMask Set interrupt mask
         lda  P$Signal,X Signal waiting?
         beq  SLEP20     Branch if not
CKSIGN   deca            IS It wake-up?
         bne  SLEP10     Branch if not
         sta  P$Signal,X Clear signal
SLEP10   OS9  F$AProc    Put process in active queue
         bra  ZZZPRC     Suspend process
SLEP20   ldd  R$X,U      Get length of sleep
         beq  SLEP50     Branch if indefinite
         subd #1         count current tick
         std  R$X,U      update count
         beq  SLEP10     branch if done
         pshs X,U        Save process & register ptr
         ldx  #D.SProcQ-P$Queue Fake process ptr
SLEP30   leay 0,X        Copy process ptr
         ldx  P$Queue,X  Get next process
         beq  SLEP40     Branch if end of queue
         pshs D          Save sleep time
         lda  P$State,X  Get process status
         bita #TimSleep  In timed sleep?
         puls D          Retrieve sleep time
         beq  SLEP40     Branch if not timed sleep
         ldu  P$SP,X     Get process stack ptr
         subd R$X,U      Subtract sleep time
         bcc  SLEP30     Branch if not greater
         addd R$X,U      Fix sleep time
SLEP40   puls X,U        Retrieve process & register ptr
         std  R$X,U      Set time to sleep
         ldd  P$Queue,Y  Put process in queue
         stx  P$Queue,Y
         std  P$Queue,X
         lda  P$State,X  Set timed sleep status
         ora  #TimSleep
         sta  P$State,X
         ldx  P$Queue,X  Get next process ptr
         beq  ZZZPRC
         lda  P$State,X  Get status
         bita #TimSleep  In timed sleep?
         beq  ZZZPRC     Branch if not
         ldx  P$SP,X     Get stack ptr
         ldd  R$X,X      Get sleep time
         subd R$X,U      Subtract new sleep
         std  R$X,X      Update sleep time
         bra  ZZZPRC
SLEP50   lda  P$State,X  Get status
         anda #$FF-TimSleep Set not timed sleep
         sta  P$State,X
         ldd  #D.SProcQ-P$Queue Fake process ptr
SLEP60   tfr  D,Y        Copy process ptr
         ldd  P$Queue,Y  Get next process ptr
         bne  SLEP60     Branch if one exists
         stx  P$Queue,Y  Link into queue
         std  P$Queue,X
*
*      Fall Thru To Zzzprc
*
*****
*
*  Subroutine Zzzprc
*
* Deactivate Process, Start Another
*
ZZZPRC   leay <WAKPRC,PCR Get wakeup address
         pshs Y          Make new pc
         ldy  D.PROC     Get process ptr
         ldd  P$SP,Y     Get process stack
         ldx  R$X,U      Get sleep time (if any)
         pshs CC,D,DP,X,Y,U Make new stack
         sts  P$SP,Y     Note location
         OS9  F$NProc    Start another process

WAKPRC   std  P$SP,Y     Restore previous stack
         stx  R$X,U      Return sleep time
         clrb            CLEAR Carry
         rts
         page
*****
*
*  Subroutine Intcpt
*
* Signal Intercept Handler
*
INTCPT   ldx  D.PROC     Get process ptr
         ldd  R$X,U      Get vector
         std  P$SigVec,X Save it
         ldd  R$U,U      Get data address
         std  P$SigDat,X Save it
         clrb            CLEAR Carry
         rts



*****
*
*  Subroutine Setpri
*
* Set Process Priority
*
SETPRI   lda  R$A,U      Get process id
         ldx  D.PrcDBT   Get process block ptr
         OS9  F$Find64   Find process descriptor
         bcs  SETP10
         ldx  D.PROC     Get setting process ptr
         ldd  P$USER,X   Get setting user
         cmpd P$USER,Y   Same as set user?
         bne  SETP10     Branch if not
         lda  R$B,U      Get priority
         sta  P$Prior,Y  Set priority
         rts
SETP10   comb            SET Carry
         ldb  #E$IPrcID  Err: illegal process id
         rts



*****
*
*  Subroutine Getid
*
GETID    ldx  D.PROC     Get process ptr
         lda  P$ID,X     Get process id
         sta  R$A,U      Return to user
         ldd  P$USER,X   Get user index
         std  R$Y,U      Return to user
         clrb
         rts
         page
*****
*
*  Subroutine Setswi
*
* Set Software Interrupt Vectors
*
SETSWI   ldx  D.PROC     Get process ptr
         leay P$SWI,X    Get ptr to vectors
         ldb  R$A,U      Get swi code
         decb            ADJUST Range
         cmpb #3         Is it in range
         bcc  SSWI10     Branch if not
         aslb
         ldx  R$X,U
         stx  B,Y
         rts
SSWI10   comb
         ldb  #E$ISWI
         rts



**********
*
* Subroutine Settime
*

ClockNam fcs  "Clock"

SetTime  ldx  R$X,U      get date ptr
         ldd  0,X        get year & month
         std  D.YEAR
         ldd  2,X        get day & hour
         std  D.DAY
         ldd  4,X        get minute & second
         std  D.MIN
         lda  #SYSTM+OBJCT
         leax <ClockNam,PCR
         OS9  F$Link     link to clock module
         bcs  SeTime99
         jmp  0,Y        execute clock's initialization
         clrb
SeTime99 rts
         page
***************
* Findpd
*   Find Address Of Path Descriptor Or Process Descriptor
*
* Calling Seq: (A)=Pd Number
*              (X)=Pd Table Addr
* Returns: (Y)=Addr Of Pd
*          Cc=Set If Pd Is Not Owned By Caller
* Destroys: B,Cc
*
F64      lda  R$A,U      Get block number
         ldx  R$X,U      Get block ptr
         bsr  FINDPD     Find block
         bcs  F6410
         sty  R$Y,U
F6410    rts

FINDPD   pshs D          Save registers
         tsta            LEGAL Number?
         beq  FPDERR     ..yes; error
         clrb
         lsra
         rorb
         lsra
         rorb            DIVIDED By 4 pd's per pd block
         lda  A,X        Map into high order pd address
         tfr  D,Y        (y)=address of path descriptor
         beq  FPDERR     Pd block not allocated!
         tst  0,Y        Is pd in use?
         bne  FINDP9     Allocated pd, good!
FPDERR   coma            ERROR - return carry set
FINDP9   puls D,PC       Return
         page
***************
* Aloc64
*   Allocate Path Descriptor (64 Bytes)
*
* Passed:  X=Pdbt, Path Descriptor Block Table Addr
* Returns: A=Path Number
*          Y=Pd Address
*          Cc=Set If Unable To Allocate
*           B=Error Code If Unable To Allocate
* Destroys: B
*
A64      ldx  R$X,U      Get block ptr
         bne  A6410      Branch if set
         bsr  A64ADD     Add a page
         bcs  A6420      Branch if error
         stx  0,X        Init block
         stx  R$X,U      Return block ptr
A6410    bsr  ALOC64     Alocate block
         bcs  A6420
         sta  R$A,U      Return block number
         sty  R$Y,U      Return block ptr
A6420    rts

A64ADD   pshs U          Save register ptr
         ldd  #$100      Get a page
         OS9  F$SRqMem
         leax 0,U        Copy page ptr
         puls U          Retrieve register ptr
         bcs  A64A20     Branch if no memory
         clra
         clrb
A64A10   sta  D,X        Clear page
         incb
         bne  A64A10
A64A20   rts

ALOC64   pshs X,U
         clra

ALCPD1   pshs A          Save index of pd block
         clrb
         lda  A,X
         beq  ALPD12     Empty block (not found)
         tfr  D,Y        (y)=address of pd block
         clra
ALPD11   tst  D,Y        Available pd?
         beq  ALPD13     ..yes
         addb #PDSIZE    Skip to next pd
         bcc  ALPD11     Repeat until end of pd block
ALPD12   orcc #CARRY     Set carry - not found
ALPD13   leay D,Y        Get address of path descriptor
         puls A          Restore pd block index
         bcc  ALCPD4     Found a pd, return it
         inca            SKIP To next pd block
         cmpa #PDSIZE    Last one checked?
         blo  ALCPD1     ..no; keep looking
         clra
ALCPD2   tst  A,X        Search for an unused pdb
         beq  ALCPD3     ..found one
         inca            SKIP To next
         cmpa #PDSIZE    All tried?
         blo  ALCPD2     ..no; keep looking
         ldb  #E$PthFul  No available path
         coma            RETURN Carry set - error
         bra  ALCPD9     Return

ALCPD3   pshs A,X
         bsr  A64ADD     Add a page
         bcs  ALCPDR     Allocate error
         leay 0,X        Set up pd address as first pd in block
         tfr  X,D
         tfr  A,B        (b)=page address of new pd block
         puls A,X
* (A)=Pdbt Index, (X)=Pdbt
         stb  A,X
         clrb
*
* A=Index Into Pdbt Of Pdb Containing Pd
* B=Low Order Address Of Pd In Pdb
* Y=Address Of Pd
*
ALCPD4   aslb            FORM Path number
         rola
         aslb
         rola
         ldb  #PDSIZE-1
ALCPD5   clr  B,Y
         decb
         bne  ALCPD5     Clear out fresh path descriptor
         sta  PD.PD,Y    Set pd# in pd (indicates in use)
ALCPD9   puls X,U,PC     Return carry clear


ALCPDR   leas 3,S        Return not enough memory error
         puls X,U,PC     Return


***************
* Rtrn64
*   Return Path Descriptor To Free Status
*
* Passed: (A)=Path Number
*         (X)=D.Pdbt Path Descriptor Block Table Addr
* Returns: None
* Destroys: Cc
*
R64      lda  R$A,U      Get block number
         ldx  R$X,U      Get block ptr
RTRN64   pshs D,X,Y,U    Save registers
         clrb
         lsra
         rorb
         lsra            PATH #
         rorb            DIVIDED By 4 pd's per block
         pshs A          Save a
         lda  A,X
         beq  RTRNP9     Impossible path number - return
         tfr  D,Y        Get address of pd
         clr  0,Y        Mark it as unused
         clrb
         tfr  D,U        Get address of pdb in which pd lies
         clra
RTRNP1   tst  D,U        Pd in use?
         bne  RTRNP9     ..yes; return
         addb #PDSIZE
         bne  RTRNP1     Repeat for each pd in block
         inca            (D)=$0100
         OS9  F$SRtMem   Return (unused) pdb to system store
         lda  0,S
         clr  A,X        Mark pd unused
RTRNP9   clr  ,S+        Return scratch with carry clear
         puls D,X,Y,U,PC Return to caller



         ttl BOOTSTRAP Routines
         page
*****
*
*  Subroutine Iohook
*
* Handles Locating/Loading Remainder Of System
*
* Input: Y - Service Dispatch Table ptr
*
IOSTR    fcb  'I,'O,'M,'A,'N+$80
IOHOOK   pshs D,X,Y,U    Save registers
         ldu  D.Init
         bsr  IOLink     Link ioman
         bcc  IOHOOK10
         bsr  BOOT       Ioman not found, boot
         bcs  IOHOOK20
         bsr  IOLink     Link ioman again
         bcs  IOHOOK20
IOHOOK10 jsr  0,Y        Call ioman init
         puls D,X,Y,U    Retrieve registers
         ldx  -2,Y       Get ioman entry
         jmp  0,X
IOHOOK20 puls D,X,Y,U,PC

IOLink   leax IOSTR,PCR  Get ioman name ptr
         lda  #SYSTM+OBJCT Get type
         OS9  F$LINK
         rts

BOOT     pshs U          save D.Init ptr
         comb            set carry
         tst  D.Boot
         bne  BOOTXX     Don't boot if already tried
         inc  D.Boot
         ldd  BOOTSTR,U  Get default device string
         beq  BOOTXX     Can't boot without device
         leax D,U        Get name ptr
         lda  #SYSTM+OBJCT get type
         OS9  F$LINK     find bootstrap module
         bcs  BOOTXX     Can't boot without module
         jsr  0,Y        Call boot entry
         bcs  BOOTXX     Boot failed
         stx  D.MLIM     Set memory limit
         stx  D.BTLO     Set boot area low limit
         leau D,X        Make boot area high limit
         stu  D.BTHI
BOOT10   ldd  0,X        get module beginning
         cmpd #M$ID12    is it module sync code?
         bne  BOOT20     branch if not
         OS9  F$VModul   Validate module
         bcs  BOOT20
         ldd  M$SIZE,X   Get module size
         leax D,X        Skip module
         bra  BOOT30
BOOT20   leax 1,X        Try next
BOOT30   cmpx D.BTHI     End of boot?
         bcs  BOOT10     Branch if not
BOOTXX   puls U,PC       Restore ptr and return


         emod
OS9End   equ  *



         ttl Configuration Module
         page
*****
*
* Configuration Module
*
Type     set  SYSTM
         mod  ConEnd,ConNam,Type,Revs
         fcb  0          no extended memory
         fdb  $F800      High free memory bound
         fcb  12         Entries in interrupt polling table
         fcb  12         Entries in device table
         fdb  ModNam     Initial module name
         fdb  DirNam     Default directory name
         fdb  TermNam    Standard i/o device name
         fdb  BootNam    Bootstrap module name
ConNam   fcs  "Init"
ModNam   fcs  "SysGo"
DirNam   fcs  "/D0"
TermNam  fcs  "/Term"
BootNam  fcs  "Boot"
         emod
ConEnd   equ  *

         end