Retrocomputing

Input/Output Manager

IOMan provides common processing to all I/O operations.

         nam   Input/Output Manager
         ttl   Module Header

* Copyright 1980 by Motorola, Inc., and Microware Systems Corp.,
* Copyright 1982 by Microware Systems Corporation
* 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!

* This is a disassembly of the IOMan edition 10 distributed with OS-9 for Dragon 128
* OS-9 Level 2. It contains modifications in some allocation routines.

***************
* I/O Manager

         mod  IOEnd,IOName,Systm+Objct,ReEnt+1,IOINIT,0
IOName   fcs  /IOMan/ module name

************************************************************
*
*     Edition History
*
* Edition   Date    Comments
*
*    1   pre-82/08  beginning of history                LAC
*
*    2    82/08/24  modifications for MC6829            LAC
*
*    3    82/09/27  conditionals added for LI & LII     WGP
*
*    4    82/10/21  I$Deletx system call added          WGP
*
*    5    83/01/17  change "F$Load" to set loading process priority
*                   and to not use the system process descriptor
*
*    6    83/02/18  change "PortBlk" to ignore untranslated
*                   address bits
*         83/02/24  Moved device termination routines from IODEL
*                   into DETACH.  Minimized ATTACH and DETACH use
*                   of system's process pointer.  Changed SCDIR
*                   to leave device table use count of old directory
*                   unchanged.
*
*    7    83/04/06  Removed testing for device being busy(re-entrant).
*                   This should be taken care of in the link call.
*                   Removed to take care of problems in using multiple
*                   devices at the same address. (IO Processor)  RES
*         83/04/27  Change F$Load to open file before gobbling up
*                   it's large memory block.
*
*    8    83/05/04  extensive mods for non-contiguous modules.
*         83/06/16  fixed load bugs - mod dir entry returned must
*                   be searched for after load, by keeping block
*                   and offset for reference.  Also link count is
*                   temporarily bumped to keep module around during
*                   load.
*
*    9    83/07/17  add limit checking for I$Read, I$ReadLn, I$Write,
*                   and I$WritLn
*
*  10     83/11/01 add error path/module messages, improved error printing
*                                 Vivaway Ltd.             PSD

         fcb  10         edition number

         use  defsfile

         ttl Initialization
         page
**********
* Ioinit
* Entry Point For Start-Up Initialization
*
IOINIT   ldx  D.Init     From configuration table
         lda  PollCnt,x  get polling table entries
         ldb  #POLSIZ    get entry size
         mul             get polling table size
         pshs d          save it
         lda  DEVCNT,X   Get device table size
         ldb  #DEVSIZ
         mul             get device table size
         addd 0,s        add polling table size
         addd #$FF
         clrb            round up to nearest page
         os9  F$SRqMem   allocate required I/O tbl memory
         bcs  CRASH      Death: not enough memory
         leax 0,u
IOINI1   clr  ,x+        Clear systems I/O tables
         subd #1
         bhi  IOINI1
         stu  D.PolTbl   save addr of Polling tbl
         ldd  ,s++       polling tbl size
         leax d,u        allocate room for polling table
         stx  D.DevTbl   Save device tbl addr
         ldx  D.PthDBT   Signal pdbt allocation
         os9  F$All64    Allocate/initialize pdbt
         bcs  CRASH      ..can't run without memory
         stx  D.PthDBT   Save path descriptor block tbl addr
         os9  F$Ret64    Return unneeded pd
         leax IOIRQ,pcr  Get interrupt polling routine
         stx  D.Poll
         leay <SVCTBL,pcr Get service initialization
         os9  F$SSvc     Init service routine entries
         rts

**********
CRASH    jmp  [D$REBOOT] Doom
**********
         page
**********
* Service Routine Initialization Table
*
system   set  $80        system only calls
user     set  $7F        system or user calls

SVCTBL   equ  *
         fcb  $FF&user
         fdb  USERIO-*-2
         fcb  F$Load&user
         fdb  LOAD-*-2
 ifgt LEVEL-1
fcb F$Load+SysState fdb SysLoad-*-2
endc fcb F$PERR&user fdb PRTERR-*-2 ifne EXTERR
fcb F$InsErr&User fdb InsErr-*-2
endc fcb F$IOQu!system fdb IOQUEU-*-2 fcb $FF!system fdb SYSIO-*-2 fcb F$IRQ!system fdb IOPOLL-*-2 fcb F$IODel!system fdb IODel-*-2 fcb $80 end of table page ********** * Iodel * * Called When An I/O Module Is Unlinked For The * Final Time. Error Returned if Module Busy, And * Module Link Count Should Stay At One. * Passed: (U)=Register Pack * R$X,U=Module Addr * Returns: CC=Set if Error * Destroys: D IODEL ldx R$X,u Get module addr ldu D.Init From configuration module ldb DevCnt,u Get device table size ldu D.DevTbl Get device table address IODEL10 ldy V$DESC,u empty table entry? beq IODEL20 ..yes; skip it cmpx V$DESC,u This logical device? beq IODELErr ..yes; return error cmpx V$DRIV,u This physical device driver? beq IODELErr ..yes; return error cmpx V$FMGR,u This file manager? beq IODELErr ..yes; return error IODEL20 leau DEVSIZ,u skip to next entry decb bne IODEL10 Loop until end of table clrb return carry clear rts IODELErr comb I/O Delete module error ldb #E$ModBsy Error: module busy rts ifgt LEVEL-1
*************** * Subrouting PortBlk * Passed: (D)=MS port addr * Returns: (D)=Port Extended Block number * CC = Equal if port is in System's I/O Block * Destroys: PortBlk lsra rorb ifge DAT.BlSz-2048
lsra rorb ifge DAT.BlSz-4096
lsra rorb
endc
endc lsra rorb (D)=Extended Block number anda #DAT.BlMx/256 clear untranslated bits ifle DAT.BlMx-255
ifeq MappedIO-true
cmpb #IOBlock System's I/O Block? rts
else
endc
else
endc
endc ttl File Manager I/O functions page UTABLE equ * TBLBGN set UTABLE fdb ATTACH-TBLBGN fdb DETACH-TBLBGN fdb UDUPE-TBLBGN fdb UCREAT-TBLBGN fdb UOPEN-TBLBGN fdb UMDIR-TBLBGN fdb UCDIR-TBLBGN fdb UDELET-TBLBGN fdb USEEK-TBLBGN fdb UREAD-TBLBGN fdb UWRITE-TBLBGN fdb URDLN-TBLBGN fdb UWRLN-TBLBGN fdb UGSTT-TBLBGN fdb USSTT-TBLBGN fdb UCLOSE-TBLBGN fdb UDELETX-TBLBGN STABLE equ * TBLBGN set STABLE fdb ATTACH-TBLBGN Attach (x)=device, (a)=mode fdb DETACH-TBLBGN Detach (u)=devtbl ptr fdb SDUPE-TBLBGN (nop) duplicate (a)=pathnumber * File Manager Name Functions * (X)=Pathname Ptr * (A)=Mode fdb SCREAT-TBLBGN Create file fdb SOPEN-TBLBGN Open file fdb SMDIR-TBLBGN Make new directory fdb SCDIR-TBLBGN Change directory fdb SDELET-TBLBGN Delete (assumes write mode) * File Manager Path Functions * (A)=Path Number fdb SSEEK-TBLBGN Seek to position (x,u) fdb SREAD-TBLBGN read (x)=destin, (y)=count fdb SWRITE-TBLBGN Write (x)=source, (y)=count fdb SRDLN-TBLBGN readline (x)=destin, (y)=cnt fdb SWRLN-TBLBGN writeline (x)=source, (y)=cnt fdb SGSTT-TBLBGN Get status fdb SSSTT-TBLBGN Set status fdb SCLOSE-TBLBGN Close path fdb SDELETX-TBLBGN Delete from execution directory ********** * I/O Dispatcher * USERIO leax <UTABLE,pcr Use user table bra SYSIO1 SysIO leax <STABLE,pcr Use system table SYSIO1 cmpb #I$DeletX Function out of range? bhi SYSIO2 ..yes; error pshs b Save function code lslb TIMES Two bytes per entry ldd b,x Get offset of routine leax d,x Form absolute entry of routine puls b Restore function code jmp 0,x Dispatch SYSIO2 comb RETURN Carry set ldb #E$UnkSvc Error: unknown service code rts page ********** * Attach I/O Device * * Passed: (A)=R/W/Exec Mode * (X)=Device Name Ptr * Returns: (U)=Dev Tbl Ptr * org 0 Stack temporary storage rmb DEVSIZ Temp device table entry S.MODE rmb 1 R/w mode S.BUSY rmb 1 Non-zero if device in use S.PORT rmb 3 Temp port addr S.DEVT rmb 2 Temp device table ptr ifgt LEVEL-1
S.LclAdr rmb 2 Local Port Absolute addr S.Block rmb 2 Port extended Block number S.Proc rmb 2 user's process ptr
endc S.STAK rmb 2 User's register stack S.TMPS equ . Total temp size ATTACH ldb #S.TMPS-1 ATTA02 clr ,-S Clear out temporary storage decb bpl ATTA02 stu S.STAK,S Save user stack ptr lda R$A,u sta S.MODE,s Save requested mode ifgt LEVEL-1
ldx D.Proc get process ptr stx S.Proc,s save it leay P$DATImg,x get process dat image ptr ldx D.SysPRC get syste, process ptr stx D.Proc make current for link
endc ldx R$X,u Get device name ptr lda #DEVIC ifeq LEVEL-1
OS9 F$Link link to device desc.
else
OS9 F$SLink Link device descriptor module (x)
endc bcs ATTERR0 ..error; non-existing module stu V$DESC,s Save addr ldy S.STAK,s stx R$X,y Return updated pathname to caller ifgt LEVEL-1
lda M$PORT,u Port Extended Addr sta S.PORT,S
endc ldd M$PORT+1,u Get "base" port addr std S.PORT+1,s Save it ldd M$PDEV,u offset of driver module name leax D,U Get absolute addr of name lda #DRIVR os9 F$Link Link device driver module bcs ATTERR0 ..error; non-existing module stu V$DRIV,s Save device driver module addr ldu V$DESC,s get device descriptor addr ldd M$FMGR,u offset of file mgr name leax D,U Get absolute addr lda #FLMGR OS9 F$LINK Link file manager module ATTERR0 ifgt LEVEL-1
ldx S.Proc,s get process ptr stx D.Proc restore it
endc bcc ATTA15 .. found; continue ATTERR stb S.TMPS-1,S Save error code leau 0,S Addr og psuedo device tbl entry os9 I$Detach ..detach device leas S.TMPS-1,s comb puls pc,b Return error * * Device Moudle Components Are All Located * Search Device Tbl For Device * ATTA15 stu V$FMGR,S Save file manager module addr ldx D.Init From configuration rom addr ldb DevCnt,x Get device table entry count lda DevCnt,x Save an extra copy ldu D.DevTbl Get device tbl addr ATTA20 ldx V$DESC,u Descriptor ptr beq ATTA30 ..unused entry; skip cmpx V$DESC,s Device descriptor module found? bne ATTA25 ..no; continue ldx V$STAT,u Is device in TERMINATE routine? bne ATTA22 ..No; continue pshs a lda V$USRS,u TERMINATING PROCESS ID beq ATTA21 ..ZERO; impossible os9 F$IOQu Wait for termination ATTA21 puls a bra ATTA20 Try again ATTA22 stu S.DEVT,s Save tbl ptr of found entry ATTA25 ldx V$DESC,u Descriptor ptr ldy M$PORT+1,x Get device port addr cmpy S.PORT+1,s bne ATTA30 ifgt LEVEL-1
ldy M$PORT,x cmpy S.PORT,s Same PORT addr? bne ATTA30 ..No
endc ldx V$DRIV,u cmpx V$DRIV,s Save device driver? bne ATTA30 ..no; skip to next entry ldx V$STAT,u Don't re-initialize it stx V$STAT,s Save static memory of found driver tst V$USRS,u Currently in use? beq ATTA30 ..no; continue sta S.BUSY,s Mark it busy (non-zero) ATTA30 leau DEVSIZ,u Skip to next dev tbl entry decb bne ATTA20 Loop until there are no more ldu S.DEVT,s Device descriptor already in table? lbne ATTA70 yes; use same entry * * Create New Device Table Entry * ldu D.DevTbl Get device tbl addr ATTA35 ldx V$DESC,u Search for a free entry beq ATTA40 ..found one, exit loop leau DEVSIZ,u Skip to next entry deca bne ATTA35 Loop until end of tbl ldb #E$DevOvf Error: device table overflow bra ATTERR ERMODE ldb #E$BMode Error: illegal mode bra ATTERR * this code removed for edition 7 * *ERBUSY ldb #E$DevBsy Error: device is busy * bra ATTERR * * end of code removed for edition 7 ATTA40 ldx V$STAT,s Is device already initialized? lbne ATTA60 ..yes; don't need new static * * Allocate New Static Storage For Device * stu S.DEVT,s save Dev Tbl Entry Ptr ldx V$DRIV,s Get device driver addr ldd M$Mem,x Driver Static Storable requirement addd #$FF clrb Round up to nearest page os9 F$SRqMem request Device Static Storage lbcs ATTERR ..ABORT if error stu V$STAT,s Save static storage ptr ATTA57 clr ,U+ Clear out driver static subd #1 bhi ATTA57 * Map Port into System addr space ifeq LEVEL-1
ldd S.Port+1,s get port addr off stack
else
ldd S.Port,s Get extended port addr lbsr PortBlk convert to block addr std S.Block,s save working block addr ldu #0 clear DAT entry ptr tfr u,y clear local address ptr stu S.LclAdr,s System Local addr=0 ldx D.SysDAT get system DAT image ptr IOMap20 ldd ,x++ get next DAT Entry ifne DAT.WrEn+DAT.WrPr
endc cmpd S.Block,S same as Desirec Block? beq IOMap40 ..Yes; good cmpd #DAT.Free Unused Entry? bne IOMap30 ..No, continue sty S.LclAdr,s save System Local addr leau -2,x save DAT Image ptr IOMap30 leay DAT.BLSz,y update Local Address bne IOMap20 repeat until Total addr space searched ldb #E$MemFul prime err: System process mem full cmpu #0 free table entry found? lbeq ATTERR ..No; ABORT: System Dat Image Fill ldd S.Block,s ifne DAT.WrEn
endc std 0,u fill in DAT Image with block ldx D.SysPRC get system process ptr lda P$State,x ora #ImgChg indicate DAT image change sta P$State,x os9 F$ID Dummy SVC call to update DAT image ldy S.LclAdr,s get local address * (D)=System Local addr corresponding to $XX X000 of addr IOMap40 sty S.LclAdr,s save High order local addr ldd S.Port+1,S LS 2-bytes of port addr anda #^DAT.Addr strip off translated bits addd S.LclAdr,s add to local block addr
endc ldu V$STAT,s Device Static Storage ptr clr V.PAGE,u std V.PORT,u save abs port addr in Static storage ldy V$DESC,s Pass Descriptor addr to Driver ldx V$DRIV,s Driver Module addr ldd M$EXEC,x Get execution addr jsr D,X Execute dev driver's init routine lbcs ATTERR ..error; return error code ldu S.DEVT,s Device table ptr to new entry ATTA60 ldb #DEVSIZ-1 ATTA65 lda B,S sta B,U Copy new device table entry decb bpl ATTA65 ATTA70 ldx V$DESC,u Dev descriptor module ptr ldb M$REVS,x Get re-entrant (sharable) bit lda S.MODE,s Caller's mode specified? anda M$MODE,x Check with device capabilities ldx V$DRIV,u Get device driver ptr anda M$MODE,x Compare with capabilities cmpa S.MODE,s legal? lbne ERMODE ..no; error: illegal mode * this code removed for edition 7 * * tst S.BUSY,S Device busy? * beq ATTA90 ..no * andb M$REVS,X Descriptor re-entrant bit * bitb #REENT Sharable logical device? * lbeq ERBUSY ..no; error: device busy *ATTA90 * * end of code remove for edition 7 inc V$USRS,u Update user count bne ATTA91 branch if no overflow dec V$USRS,u keep high count ATTA91 ldx S.STAK,S stu R$U,x Return device tbl ptr leas S.TMPS,S clrb RETURN Carry clear rts page ********** * Process Detach Request * * Passed: (R$U)=Dev Tbl Entry Ptr * Destroys: None * DETACH ldu R$U,u Get device tbl addr ldx V$DESC,u (get for DETACH80) lda #255 cmpa V$USRS,u high count lbeq DETACH90 ..yes; don't detach dec V$USRS,u Decrement user count lbne DETACH80 * Device is not busy, so delete it's device table entry. * First search for other devices using the same static * storage, and if none are found, execute TERMINATE routine. * (U)=device table ptr to delete ldx D.Init ldb DevCnt,x get device count pshs u,b ldx $02,u clr $02,u clr $03,u ldy D.DevTbl DETACH10 cmpx $02,y beq DETACH20 leay DEVSIZ,y decb bne DETACH10 * Terminate Physical Device * (X)-Static Storage Addr ldy D.Proc ldb P$ID,y stb $08,u ldy $04,u ldu ,u exg x,u ldd $09,x leax d,x pshs u jsr $0F,x puls u ldx 1,s ldx V$Driv,x ldd M$Mem,x addd #$FF clrb os9 F$SRtMem * Determine if this was the only active I/O port in it's * memory block, and release the block if so ldx 1,s ldx V$DESC,x ifgt LEVEL-1
ldd M$PORT,x beq DETACH20 ..No port lbsr PortBlk beq DETACH20 tfr D,X ldb 0,s Size of DevTbl pshs x,b ldu D.DevTbl UnMap10 cmpu 4,s beq UnMap20 ldx V$DESC,u beq UnMap20 ldd M$PORT,x beq UnMap20 lbsr PortBlk cmpd 1,s beq UnMap90 UnMap20 leau DevSiz,u dec 0,s bne UnMap10 ldx D.SysPRC ldu D.SysDAT ldy #DAT.BlCt number of DAT Blocks per image UnMap25 ldd ,u++ ifne DAT.WrEn+DAT.WrPr
endc cmpd 1,s beq UnMap30 leay -1,y bne UnMap25 * that's odd, block not found ??? bra UnMap90 UnMap30 ldd #DAT.Free std -2,u mark DAT block as free lda P$State,x ora #ImgChg Inform system of image change sta P$State,x UnMap90 leas 3,S discard scratch
endc DETACH20 puls u,b ldx V$DESC,u clr V$DESC,u clr V$DESC+1,u clr V$USRS,u DETACH80 ifgt LEVEL-1
ldd D.Proc get user process ptr pshs d save it ldd D.SysPRC get system process ptr std D.Proc make it current
endc * (X)=V$DESC, U device descriptor ptr ldy V$DRIV,u ldu V$FMGR,u os9 F$UnLink Unlink file manager leau 0,y os9 F$UnLink unlink device driver leau 0,x os9 F$UnLink unlink device descriptor ifgt LEVEL-1
puls d retrieve user process ptr std D.Proc restore it
endc DETACH90 lbsr UnQueue Restart any process in I/O queue clrb rts ********** * Dupe * Process Path Duplication Request * UDUPE bsr FNDPTH bcs SDUP90 pshs x,a lda R$A,u lda a,x bsr SDUP10 bcs SDUPER puls x,b stb R$A,u sta b,x rts SDUPER puls pc,x,a SDUPE lda R$A,u SDUP10 lbsr FPATH bcs SDUP90 inc PD.CNT,y SDUP90 rts ttl I/O Name function calls page ********** * Fndpth * Find Unused Entry in User'S Local Path Tbl * FNDPTH ldx D.Proc leax P$PATH,x clra FNDPD1 tst a,x beq FNDP90 inca cmpa #NumPaths bcs FNDPD1 comb ldb #E$PthFul rts FNDP90 andcc #$FF-CARRY Return carry clear rts ********** * Open * Process Open/Create Request * UCREAT equ * UOPEN bsr FNDPTH bcs UOPEN9 pshs u,x,a bsr SOPEN puls u,x,a bcs UOPEN9 ldb R$A,u stb a,x sta R$A,u UOPEN9 rts SCREAT equ * SOPEN pshs B ldb R$A,u bsr PDINIT bcs SOPENX puls b lbsr FMEXEC bcs SMDIR2 lda PD.PD,y sta R$A,u rts SOPENX puls pc,a ********** * Makdir * Process Makdir Request * UMDIR equ * SMDIR pshs b ldb #DIR.+WRITE. SMDIR1 bsr PDINIT bcs SOPENX puls b lbsr FMEXEC SMDIR2 pshs b,cc ldu PD.DEV,y os9 I$Detach lda PD.PD,y ldx D.PthDBT os9 F$Ret64 puls pc,b,cc ********** * Cdir * Process Change Directory Request * UCDIR equ * SCDIR pshs b ldb R$A,u orb #DIR. bsr PDINIT bcs SOPENX puls b lbsr FMEXEC bcs SMDIR2 ldu D.Proc ldb PD.MOD,y bitb #PREAD.+PWRIT.+READ.+WRITE. beq SCDIR2 ldx PD.DEV,y stx P$DIO,u inc V$USRS,x bne SCDIR2 dec V$USRS,x SCDIR2 bitb #PEXEC.+EXEC. beq SCDIR5 ldx PD.DEV,y stx P$DIO+6,u inc V$USRS,x bne SCDIR5 dec V$USRS,x SCDIR5 clrb bra SMDIR2 ********** * Delet * Process Delete Request * UDELET equ * SDELET pshs b ldb #$02 bra SMDIR1 ********** * DeletX * delete from specified directory * UDELETX equ * SDELETX ldb #I$Delete pshs B ldb R$A,u bra SMDIR1 ********** * Pdinit * PDINIT ifeq LEVEL-1
pshs u
else
ldx D.Proc get current process ptr pshs u,x save process & registers ptr
endc ldx D.PthDBT Get addr of path descr block tbl os9 F$All64 bcs PDIN90 inc PD.CNT,y stb PD.MOD,y ifeq LEVEL-1
PDIN10 lda ,x+
else
ldx D.Proc get process ptr ldb P$Task,x get process task number ldx R$X,u Get caller's pathname ptr PDIN10 os9 F$LDABX get next character leax 1,x move ptr
endc cmpa #$20 Skip spaces beq PDIN10 leax -1,x stx R$X,u ldb PD.MOD,y cmpa #PDELIM beq PDIN40 ldx D.Proc bitb #$24 beq PDIN20 ldx P$DIO+6,x bra PDIN30 PDIN20 ldx P$DIO,x PDIN30 beq ERRBPN ifgt LEVEL-1
ldd D.SysPRC get system process ptr std D.Proc set current process ptr
endc ldx V$DESC,x Device descriptor module ptr ldd M$NAME,x leax d,x PDIN40 pshs y os9 F$PrsNam puls y bcs ERRBPN lda $01,y os9 I$Attach stu $03,y bcs PDIN.ERR ldx $04,u leax <$11,x ldb ,x+ leau <$20,y cmpb #$20 bls PDIN60 ldb #$1F PDIN50 lda ,x+ sta ,u+ PDIN60 decb bpl PDIN50 clrb PDIN90 ifeq LEVEL-1
puls PC,U
else
puls U,X retrieve current process ptr stx D.Proc reset current process rts
endc ERRBPN ldb #E$BPNam PDIN.ERR pshs b lda PD.PD,y ldx D.PthDBT os9 F$Ret64 puls b coma bra PDIN90 ttl I/O Path function calls page ********** * Chkpth * Validate User Path, And Map Into System Path * * Passed: (U)=User Regs, (R$A)=User Path# * Returns: (A)=System Path# * (X)=User Path Table Ptr * CHKPTH lda R$A,u cmpa #NumPaths bcc CHKERR ldx D.Proc leax P$PATH,x andcc #$FF-CARRY lda a,x bne CHKP90 CHKERR comb ldb #E$BPNum CHKP90 rts ********** * Seek * Position File * USEEK bsr CHKPTH Validate path number bcc SSEEK1 ..continue if va rts SSEEK lda R$A,u Get (system) path# SSEEK1 bsr FPATH lbcc FMEXEC rts ********** * Read * Process Read Or Readln Request * UREAD equ * URDLN bsr CHKPTH get user path # bcc SRDLN1 rts SREAD equ * SRDLN lda R$A,u get user path SRDLN1 pshs b ldb #$05 SRDLN2 bsr FPATH bcs SRDLNX bitb PD.MOD,y test bits against mode in path desc beq BADPTH * * check limits of read/write buffer * ldd R$Y,u else get count from user beq SRDLN.d addd R$X,u else update buffer pointer with size bcs BADBUF ifge LEVEL-2
subd #1 lsra lsra ifge DAT.BlSz-2048
lsra ifge DAT.BlSz-4096
lsra
endc
endc ldb R$X,u get address of buffer to hold read data lsrb lsrb ifge DAT.BlSz-2048
lsrb ifge DAT.BlSz-4096
lsrb
endc
endc pshs b suba ,s+ ldx D.Proc leax P$DATImg,x aslb leax b,x SRDLN.c pshs a ldd ,x++ cmpd #DAT.Free puls a beq BADBUF deca bpl SRDLN.c
endc SRDLN.d puls b lbra FMEXEC BADBUF ldb #E$Read lda 0,s bita #WRITE. beq SRDLNX ldb #E$Write bra SRDLNX BADPTH ldb #E$BPNam SRDLNX com ,S+ rts ********** * Write * Process Write or Writeln Request * UWRITE equ * UWRLN bsr CHKPTH bcc SWRLN1 rts SWRITE equ * SWRLN lda R$A,u SWRLN1 pshs b ldb #$02 bra SRDLN2 FPath pshs x save x ldx D.PthDBT os9 F$Find64 Find (x)=path desc ptr puls x retrieve x lbcs CHKERR ..error; return useful error code FPath9 rts ********** * Gstt * Process Getstat Request * UGSTT lbsr CHKPTH ifgt LEVEL-1
ldx D.Proc get process ptr
endc bcc SGSTT10 ..good rts SGSTT lda R$A,u ifeq LEVEL-1
else
ldx D.SysPRC SGSTT10 pshs x,b,a lda R$B,u sta $01,s puls a lbsr SSEEK1 puls x,a pshs u,y,cc tsta beq SGSTT20 cmpa #$0E beq SGSTT30 puls pc,u,y,cc SGSTT20 lda D.SysTsk ldb P$Task,x leax PD.OPT,y SGSTT25 ldy #32 Copy 32 Bytes ldu R$X,u os9 F$Move leas 1,s puls pc,u,y SGSTT30 lda D.SysTsk ldb P$Task,x pshs D ldx PD.DEV,y ldx V$DESC,x ldd M$Name,x leax D,X puls D bra SGSTT25 move 32 bytes
endc *********** * PSTT USSTT equ USEEK SSSTT equ SSEEK ********** * Close * Process Close Request * UCLOSE lbsr CHKPTH get user path # bcs FPATH9 pshs b ldb $01,u clr b,x puls b bra SCLOS1 SCLOSE lda R$A,u SCLOS1 bsr FPATH bcs FPATH9 dec $02,y tst $05,y bne SCClos2 bsr FMEXEC SCClos2 tst Pd.Cnt,y bne FPATH9 lbra SMDIR2 *************** * Subroutine GainPath * Gain control of Current Path GainP.zz os9 F$IOQu comb ldb <$19,x bne GainP.9 GainPath ldx D.Proc ldb ,x clra lda $05,y bne GainP.zz stb $05,y GainP.9 rts *************** * Subroutine FMEXEC * Dispatch To File MgrS Routine * * Passed: (B)=Function Code * (Y)=Path Descriptor Ptr * (U)=User'S Register Stack * Error: B,CC=Set id Error * Destroys: D * FMEXEC pshs u,y,x,b Save regs bsr GainPath gain control of path bcc FMEX20 ..gotten; continue leas 1,S discard function code bra FMEX30 ..Exit if Signal Error FMEX20 stu PD.RGS,y Save user register stack ldx PD.DEV,y Get device tbl entry address ldx V$FMGR,x Get file manager module address ldd M$EXEC,X leax D,X Get file mgr's execution entry addr ldb ,S+ Restore caller's function byte subb #I$Create Make it an index lda #3 mul TIMES 3 bytes per lbra entry jsr D,X Exec file mgr's routine FMEX30 pshs B,CC save error status, code bsr UnQueue Wake Up next in I/O Queue ldy 4,s path descriptor ptr ldx D.Proc lda P$ID,x get current process id cmpa PD.CPR,y controlling Path Descriptor? bne FMEX90 ..No clr PD.CPR,y release path FMEX90 puls pc,u,y,x,b,cc return *************** * Subroutine UnQueue * Wake next process in I/O queue (if any) UnQueue pshs y,x save regs ldy D.Proc bra UnQue80 While not last proc in IO queue UnQue10 clr P$IOQN,y clear next ptr ldb #S$Wake os9 F$Send wake up next process in queue ifeq LEVEL-1
ldx D.PrcDBT os9 F$Find64
else
os9 F$GProcP find next process descriptor
endc clr P$IOQP,y clear previous link in next UnQue80 lda P$IOQN,y process ID of next process bne UnQue10 Endwhile puls pc,y,x page *************** * Irq Service Routines * ==================== ************************ * Irq Polling Table Format * * Polling Address (2) * Flip Byte (1) * Poll Mask (1) Must Be Non-Zero * Service Address (2) * Static Storage (2) Must Be Unique To Device * Priority (1) 0=Lowest, 255=Highest * * Irq Polling Table Maintenance Entry Point * * (U)=Caller'S Register Save * R$D,U=Polling Addr * R$X,U=Ptr To Flip,Mask,Priority * R$Y,U=Service Addr * R$U,U=Storage Addr * IOPOLL ldx R$X,u Get ptr to flip,mask,priority ldb 0,x ldx 1,x clra default carry clear pshs cc save Interrupt State pshs x,b Save flip,mask,priority ldx D.Init From configuration rom addr ldb PollCnt,x Get polling table entry count ldx D.PolTbl Get addr of polling tbl ldy R$X,u Delete? beq IOPOL4 ..yes tst 1,s Mask zero? beq POLFUL ..yes; error: mask must be non-zero decb lda #POLSIZ mul leax D,X Compute addr of last tbl entry lda Q$MASK,x Is the table full (mask not 0)? bne POLFUL ..yes; error: polling table full orcc #IntMasks Disable IRQs during Maintenance IOPOL1 ldb 2,s Get priority of new device cmpb (Q$PRTY-POLSIZ),X Above the previous entry's? bcs IOPOL3 ..no; insert it here in the table ldb #POLSIZ IOPO11 lda ,-x sta POLSIZ,x Copy table entry down decb bne IOPO11 (move to next higher entry) cmpx D.PolTbl Is this the top of the table? bhi IOPOL1 ..no; repeat IOPOL3 ldd R$D,u Copy parameters into tbl entry std Q$POLL,x ..polling address ldd ,s++ sta Q$FLIP,x ..flip stb Q$MASK,x ..masl ldb ,s+ stb Q$PRTY,x ..priority ldd R$Y,u std Q$SERV,x ..service address ldd R$U,u std Q$STAT,x ..static storage address puls PC,CC return (carry clear) * Delete An Entry From Polling Tbl IOPOL4 leas 4,s Clean up stack ldy R$U,u Caller's static address IOPOL5 cmpy Q$STAT,x Is this the entry? beq IOPOL6 ..yes; good leax POLSIZ,x Skip to next table entry decb end of table? bne IOPOL5 ..no; repeat * Error? - Table Entry Not Found clrb return Carry clear IORTS rts IOPOL6 pshs b,cc Save entry count orcc #IntMasks Disable IRQs during Maintenance bra IOPO75 IOPOL7 ldb POLSIZ,x stb ,x+ Copy next entry up over this one deca bne IOPOL7 (move down to next entry) IOPO75 lda #POLSIZ Get polling table entry size dec 1,s At last entry yet? bne IOPOL7 ..no; copy another entry IOPOL8 clr ,x+ Clear out last entry deca bne IOPOL8 puls pc,a,cc return POLFUL leas 4,S discard temps POLLERR comb return carry set ldb #E$Poll Error: polling table entry not found rts page *************** * Irq Polling Routine * =================== * Polling Table Format: * Polling Address (2) * Flip Byte (1) * Poll Mask (1) * Service Address (2) * Static Storage (2) * Priority (1) * Interrupt Request (Irq) Service Entry Point IOIRQ ldy D.PolTbl Get addr of polling table ldx D.Init From configuration module ldb PollCnt,x Get polling table entry count bra IOIRQ2 IOIRQ1 leay POLSIZ,y Skip to next entry in table decb end of table? beq POLLERR ..yes; exit - not found IOIRQ2 lda [Q$POLL,y] Poll device eora Q$FLIP,y Flip any inverted hardware bits bita Q$MASK,y Is device interrupting? beq IOIRQ1 ..no; go try next device ldu Q$STAT,y Get storage for device handler pshs Y,B jsr [Q$SERV,y] Exec interrupt service routine puls y,b bcs IOIRQ1 false interrupt, keep checking rts page ifeq LEVEL-1
jmp NOWHERE
else
************************************************************ * * Subroutine Load * * Load Module service routine * Load pshs u save registers ptr ldx R$X,u get path name ptr bsr LModule load module bcs LoadXit puls y Load.A pshs y stx R$X,y save updated pathlist ldy ,u get DAT image pointer ldx $04,u get offset within DAT image ldd #$0006 os9 F$LDDDXY ldx ,s std $01,x leax ,u os9 F$ELink bcs LoadXit ldx ,s sty $06,x stu $08,x LoadXit puls pc,u page ************************************************************ * * Subroutine Sysload * SysLoad pshs u save registers ptr ldx R$X,u get name string ptr bsr LModule load module bcs SysLXit branch if error puls y retrieve registers ptr ldd D.Proc get current process ptr pshs y,d save registers ldd R$U,y get process ptr std D.Proc make it current bsr Load.A link loaded module puls x retrieve current process ptr stx D.Proc reset current process SysLXit puls pc,u page ************************************************************ * * Subroutine Lmodule * * Open specified path, read and validate modules until error realorg set . org 0 TotRAM rmb 2 total ram acquired for block TotMod rmb 2 total module size in block CurrProc rmb 2 current process ptr Path rmb 1 path number ErrCode rmb 1 error code Header rmb M$IDSize module header scratch locals set . org realorg ModPtr set locals+0 Module block offset PathName set locals+2 Path name string ptr ProcPtr set locals+4 temporary process ptr ModBlk set locals+6 Module block number stacked set 0 LModule os9 F$AllPrc get process descriptor bcc LMod.1 rts LMod.1 leay 0,u copy process ptr ldu #0 clear directory entry ptr pshs u,y,x,b,a save registers leas -locals,s make room for scratch clr ErrCode+stacked,s clear error code stu TotRAM+stacked,s stu TotMod+stacked,s ldu D.Proc stu CurrProc+stacked,s clr Path+stacked,s lda P$Prior,u get priority sta P$Prior,y save lda #EXEC. from exec dir os9 I$Open bcs LModErr sta Path+stacked,s stx PathName+stacked,s ldx ProcPtr+stacked,s os9 F$AllTsk bcs LModErr stx D.Proc LMod.J ldd #M$IDSize ldx TotMod+stacked,s lbsr GetModul bcs LModErr ldu ProcPtr+stacked,s lda P$Task,u ldb D.SysTsk leau Header+stacked,s pshs x stacked set stacked+2 ldx ToTMod+stacked,s os9 F$Move puls x stacked set stacked-2 ldd 0,u get module sync bytes cmpd #M$ID12 bne LModErrA ldd M$Size,u subd #M$IDSize * X already contains old modsiz + new ID lbsr GetModul bcs LModErr ldy <$15,s get proc desc ptr leay <P$DATImg,y tfr y,d ldx $02,s os9 F$VModul bcc LMod.K cmpb #E$KwnMod beq LMod.L bra LModErr LMod.K ldd $02,s addd $0A,s std $02,s LMod.L ldd <$17,s bne LMod.J ldd MD$MPtr,u std <$11,s ldx MD$MPDAT,u ldd 0,x std <$17,s ldd $06,u addd #1 beq LMod.J std MD$Link,u bra LMod.J LModErrA ldb #E$BMID LModErr stb $07,s ldd $04,s beq LMod.M std D.Proc LMod.M lda $06,s beq LMod.O os9 I$Close LMod.O ldd $02,s addd #DAT.BlSz-1 round to next block lsra get block number lsra ifge DAT.BlSz-2048
lsra ifge DAT.BlSz-4096
lsra
endc
endc sta TotMod+stacked,s save block number ldb ,s beq LMod.Q lsrb make block count lsrb ifge DAT.BlSz-2048
lsrb ifge DAT.BlSz-4096
lsrb
endc
endc subb $02,s beq LMod.Q ldx <$15,s leax <P$DATImg,x lsla leax a,x clra tfr d,y ldu D.BlkMap LMod.O2 ldd ,x++ clr d,u leay -$01,y bne LMod.O2 LMod.Q ldx <$15,s lda P$ID,x os9 F$DelPrc ldd <$17,s bne LMod.R ldb $07,s stb <$12,s comb bra LModXit LMod.R ldu D.ModDir ldx <$11,s ldd <$17,s leau -MD$ESize,u LMod.S leau MD$ESize,u cmpu D.ModEnd bcs LMod.T comb ldb #E$MNF stb <$12,s bra LModXit LMod.T cmpx MD$MPtr,u bne LMod.S cmpd [MD$MPDAT,u] bne LMod.S ldd MD$Link,u beq LMod.U subd #1 std MD$Link,u LMod.U stu <$17,s clrb LModXit leas <$11,s puls pc,u,y,x,b,a page stacked set stacked+8 ***************************************************** * * GetModul routine * * Input: D = Size of new section * X = Present module size in RAM * * Output: X = New module size in RAM * GetModul pshs y,x,b,a save regs addd 2,s find new totmod size std 4,s save it for caller cmpd TotRAM+stacked,s is there enough RAM? ifeq CPUType-DRG128
lbls GetM.R yes. skip mem request
else
bls GetM.R yes. skip mem request
endc addd #DAT.BlSz-1 round to next block lsra lsra ifge DAT.BlSz-2048
lsra ifge DAT.BlSz-4096
lsra
endc
endc cmpa #DAT.BlCt-1 check for full map bhi GetM.Err bra if so ldb TotRAM+stacked,s get RAM used lsrb lsrb get blks RAM used ifge DAT.BlSz-2048
lsrb ifge DAT.BlSz-4096
lsrb
endc
endc pshs b stack it exg b,a subb ,s+ lsla ldu ProcPtr+stacked,s leau P$DATImg,u leau a,u clra tfr d,x ldy D.BlkMap clra TESTM set 0 ifeq CPUTYPE-DRG128+TESTM
ldb #DAT.GBlk start above graphics blocks leay b,y
else
clrb
endc GetM.B tst ,y+ chk if blk free beq GetM.D bra if so GetM.C addd #1 update blk number cmpy D.BlkMap+2 bne GetM.B ifeq CPUTYPE-DRG128+TESTM
ldy D.BlkMap now try graphics blocks clra GetM.F pshs y leay BlkTrans,pcr ldb a,y puls y tst b,y beq GetM.H GetM.G inca cmpa #DAT.GBlk bcs GetM.F
endc GetM.Err comb ldb #E$MemFul bra GetM.X exit ifeq CPUTYPE-DRG128+TESTM
GetM.H inc b,y clr ,u+ stb ,u+ pshs a stacked set stacked+1 ldd $09,s addd #DAT.BlSz std $09,s puls a stacked set stacked-1 leax -1,x bne GetM.G bra GetM.I
endc GetM.D inc -1,y std ,u++ stacked set stacked+2 pshs d ldd $0A,s addd #DAT.BlSz std $0A,s puls d stacked set stacked-2 leax -1,x bne GetM.C GetM.I ldx <$1D,s os9 F$SetTsk bcs GetM.X GetM.R lda $0E,s ldx $02,s ldy ,s os9 I$Read GetM.X leas 4,s return scratch puls pc,x done ifeq CPUTYPE-DRG128
* * Graphics block translation table. * Optimizes graphics memory allocation * BlkTrans fcb $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F fcb $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F
endc page
endc ***** * * Print Error Routine * ifne EXTERR
********************************************** * * Subroutine PrtErr * * Print error message * * Input: U = registers pointer * R$B,U=error number * * Output: U unchanged * Carry clear * * Data: D.Proc, D.SysPrc * * Calls: F$Link, F$Unlink, I$Open, I$Close, * I$ReadLn, I$WritLn * * CAUTION: THIS SUBROUTINE TAKES 100+ BYTES OF STACK * * The mechanism. * A 32 byte space in the process descriptor of each process * is reserved for a name/pathlist of a module or file * that is assumed to contain the error messages for that * process. This name is installed by a call to InsErr, * (F$InsErr). When PrtErr is called, this name is first * used to try and link to a module, then to a file, * in the EXEC mode. Both file and module * have the same structure - i.e., the file is the module * on disk! The message table in the module/file is then * searched for the error number, just as in Printerr. If * it is not found, or no module or file could be found, * there is a default for the whole system, and a process * can install a replacement for a subset of error numbers. * Because of the module structure - the offset * to the table follows the memory size in the header - * program modules can contain error message tables that * they install themselves. Because the structure is that * of a module, but can also be read from disk, error * message tables can be left on disk to save memory, or * loaded into memory for speed. * PrtBufSz equ 80 org 0 PrtPath rmb 1 PrtNum rmb 1 PrtProc rmb 2 PrtMod rmb 2 PrtTbl rmb 2 PrtEPath rmb 1 PrtPFlag rmb 1 PrtFlag rmb 1 PrtBuf rmb PrtBufSz PrtMem equ . PrtErr ldb R$B,u beq PrtErr90 ldx D.Proc lda <P$PATH+2,x get stderr path beq PrtErr90 return if not there pshs u leas -PrtMem,s leau ,s std 0,u stx $02,u ldy D.SysPRC sty D.Proc lbsr PrtErrNm Write label and error number clr $0A,u ldx $02,u PrtErr10 leax P$ErrNam,x clr $09,u pshs u,x clra os9 F$Link tfr u,y puls u,x sty $04,u bcc PrtErr20 lda #$05 os9 I$Open sta $08,u inc $09,u bcc PrtErr20 PrtErr15 tst $0A,u bne PrtErr85 inc $0A,u ldx D.SysPRC bra PrtErr10 PrtErr85 lda #C$CR just print CR-LF pshs a leax ,s ldy #1 lbsr PrtLine leas 1,s bra PrtErr95 PrtErr80 lbsr PrtUndo PrtErr95 ldy $02,u sty D.Proc leas <$5B,s puls u PrtErr90 clrb rts PrtErr20 tst $09,u bne PrtErr30 ldx $04,u ldd $0D,x leax d,x stx $06,u bra PrtErr40 PrtErr30 ldx #$000D bsr PrtSeek bcs PrtErr70 lda $08,u ldy #$0002 leas -$02,s leax ,s os9 I$Read puls x bcs PrtErr70 bsr PrtSeek bcs PrtErr70 PrtErr40 lbsr PrtRdRcd bcs PrtErr70 lbsr PrtGetNm beq PrtErr70 cmpb $01,u bne PrtErr40 pshs x leax >ErrMsg2,pcr Write hyphen ldy #$0003 bsr PrtLine puls x PrtErr50 ldy #PrtBufSz-1 bsr PrtLine bsr PrtRdRcd bcs PrtErr80 lda ,x+ beq PrtErr80 cmpa #$30 bcs PrtErr50 bra PrtErr80 PrtErr70 bsr PrtUndo lbra PrtErr15 PrtErrNm leax ErrMsg1,pcr ldy #MsgLen1 string length bsr PrtLine ldb PrtNum,u leax PrtBuf,u tfr x,y lda #'0-1 PrtNm1 inca subb #100 bcc PrtNm1 sta ,y+ lda #'9+1 PrtNm2 deca addb #10 bcc PrtNm2 sta ,y+ addb #'0 stb ,y+ ldy #3 * Fall through to print it PrtLine lda ,u os9 I$WritLn rts PrtSeek lda $08,u pshs u,x tfr x,u ldx #0 os9 I$Seek puls pc,u,x PrtUndo lda $08,u tst $09,u bne PrtUndo1 pshs u ldu $04,u os9 F$UnLink puls pc,u PrtUndo1 os9 I$Close rts PrtRdRcd leax PrtBuf,u point at the buffer ldy #PrtBufSz max line length lda PrtEPath,u get path number tst PrtPFlag,u beq PrtRd10 ..none; must be a module os9 I$ReadLn read a line rts PrtRd10 tfr y,d put buffer size in B ldy PrtTbl,u get table ptr PrtRd20 lda ,y+ sta ,x+ put in buffer decb end of buffer? beq PrtRd30 ..yes cmpa #C$CR end of line? bne PrtRd20 ..no; get more PrtRd30 leax PrtBuf,u retrieve buffer ptr sty PrtTbl,u update table ptr clrb rts PrtGetNm clrb initialise counter PrtGet10 lda ,x+ get a chr beq PrtGet20 ..end of table suba #'0 name numeric bcs PrtGet30 ..exit if separator pshs a save digit lda #10 mul multiply present result by 10 addb ,s+ add new digit bra PrtGet10 next! PrtGet20 tstb check answer PrtGet30 rts ErrMsg1 fcc 'Error #' MsgLen1 equ *-ErrMsg1 ErrMsg2 fcc ' - ' MsgLen2 equ *-ErrMsg2 ****************************** * * Subroutine InsErr * * Install error message path/module * name string * * Input: U = Registers ptr * R$X,U=ptr to name string * * Output: U unchanged * Carry set if error, B has error code * * Data: D.Proc * * Calls: F$Move, F$Link, F$UnLink, I$Open, I$Close * * The name string MUST be 32 chrs or less * InsErr pshs u ldx R$X,u clra os9 F$Link Is it already loaded? bcs InsErr1 ..no, then try to open the file pshs x os9 F$UnLink bra InsErr2 InsErr1 ldu ,s ldx R$X,u lda #READ. os9 I$Open bcs InsErrx pshs x os9 I$Close InsErr2 ldu D.Proc lda P$Task,u ldb D.SysTsk ldy #$0020 leau P$ErrNam,u ldx $02,s ldx $04,x os9 F$Move ldu $02,s puls x stx R$X,u clrb InsErrx puls pc,u
else
* Normal error service ******************************** * * F$PErr System call entry point * * Entry: U = Register stack pointer * ErrMsg1 fcc "ERROR #" ErrNum equ *-ErrMsg1 fcb '0-1,'9+1,'0 fcb C$CR ErrMessL equ *-ErrMsg1 PrtErr ldx D.Proc lda <P$PATH+2,x get stderr path beq L08CC leas -ErrMessL,s make room on stack leax <ErrMsg1,pcr leay ,s L0893 lda ,x+ sta ,y+ cmpa #C$CR done? bne L0893 ldb R$B,u * Convert error code to decimal L089D inc ErrNum+0,s subb #100 bcc L089D L08A3 dec ErrNum+1,s addb #10 bcc L08A3 addb #$30 stb ErrNum+2,s ldx D.Proc ldu P$SP,x get the stack pointer leau -ErrMessL,u put a buffer on it lda D.SysTsk ldb P$Task,x get task number of process leax ,s ldy #ErrMessL get length of text L08BD os9 F$Move leax ,u ldu D.Proc lda <P$PATH+2,u get path number os9 I$WritLn leas ErrMessL,s purge the buffer L08CC rts
endc page ***** * * Subroutine Ioqueu * * Link Process Into Ioqueue And Go To Sleep * IOQueu ldy D.Proc IOQ.A lda P$IOQN,y beq IOQ.C cmpa R$A,u bne IOQ.B clr P$IOQN,y ifeq LEVEL-1
ldx D.PrcDBT os9 F$Find64
else
os9 F$GProcP get process ptr
endc bcs IOQuExit clr P$IOQP,y ldb #S$Wake os9 F$Send bra IOQ.E IOQ.B ifeq LEVEL-1
else
os9 F$GProcP get process ptr
endc bcc IOQ.A IOQ.C lda R$A,u IOQ.D ifeq LEVEL-1
else
os9 F$GProcP get process ptr
endc bcs IOQuExit IOQ.E lda P$IOQN,y bne IOQ.D ldx D.Proc lda P$ID,x sta P$IOQN,y lda P$ID,y sta P$IOQP,x ldx #0 os9 F$Sleep ldu D.Proc lda P$IOQP,u beq IOQ.F ifeq LEVEL-1
ldx D.PrcDBT os9 F$Find64
else
os9 F$GProcP get process ptr
endc bcs IOQ.F branch if dead lda P$IOQN,y normal queue exit? beq IOQ.F branch if so * * Graceful Abnormal Queue Queue Exit * lda P$IOQN,u get next process ID sta P$IOQN,y put in previous process beq IOQ.F branch if none clr P$IOQN,u clear next process link ifeq LEVEL-1
ldx D.PrcDBT os9 F$Find64
else
os9 F$GProcP get process ptr
endc bcs IOQ.F branch if dead lda P$IOQP,u get previous process ID sta P$IOQP,y put in next process IOQ.F clr P$IOQP,u clear predecessor link IOQuExit rts emod Module Crc IOEnd equ *