OS-9 Level 2 V1.2 kernal, part 1
The OS-9 kernel from Positron 9000
NOTE: The statements containing "jmp NOWHERE" forces the assembler to abort if the relevant conditional assembly is selected. This is because we know there is a selector, but we don't know what one of the branches contain.
nam OS-9 Level II V1.2
ttl Module Header
use defsfile
Type set Systm
Revs set ReEnt+8
mod OS9End,OS9Name,Type,Revs,0,0
OS9Name equ *
fcs /OS9p1/
fcb 11
ttl Coldstart Routines
pag
************************************************************
*
* Routine Cold
*
* System Coldstart; determines system state, initializes
* system data structures, searches for the remainder of the
* system and attempts to start operation.
*
LoRAM set $20 set low RAM limit
HiRAM set DAT.Blsz*RAMCount
TEST set 0 not test mode
COLD ldx #DAT.WrEn+$146
lda #$03
clrb
L0019 stx DAT.Regs
sta >$0000
leax 2,x
incb
cmpb #$05
bne L0019
ldu #$0000
clrb
L002A ldx #DAT.WrEn+$144
stx DAT.Regs
lda b,u
leax 4,x
lslb
leax b,x
lsrb
stx DAT.Regs
sta >$0002
incb
cmpb #4
bne L002A
ldx #$144
stx DAT.Regs
lda >$0000
anda #$E0
bne L0080
ldx #DAT.WrEn+$150
stx DAT.Regs
lda #$80
sta >$0003
clr >$0000
clr >$0001
lda #$8F
sta >$0003
clr >$0003
lda #$14
L006B deca
bne L006B
lda #$0F
sta >$0003
ldd >$0000
lda #$90
sta >$0003
lda #$12
sta >$0003
L0080 ldx #DAT.WrEn+$100
ldy #$0000
L0087 clra
clrb
stx DAT.Regs
L008C clr d,y
incb
cmpb #$50
bne L008C
clrb
inca
cmpa #$08
bne L008C
leax 1,x
cmpx #DAT.WrEn+$140
bne L0087
ldx #DAT.WrEn+$108
stx DAT.Regs
ldd #$0702
std ,y++
ldd #$0401
std ,y
ldx #DAT.WrEn+$000
stx DAT.Regs
ldx #LoRAM get low limit ptr
ldy #HiRAM-LoRAM get byte count
clra clear d
clrb
Cold10 std ,X++ clear memory
leay -2,Y count bytes
bne Cold10 branch if more
*
* initialize DAT image, Memory Block Map, &
* Module Directory ptrs
*
inca skip direct page
std D.Tasks set Task User Table ptr
addb #DAT.TkCt allocate Task User Table
std D.TmpDAT set temporary DAT stack ptr
clrb
inca allocate DAT stack
std D.BlkMap set free memory block map
adda #DAT.BMSz/256 allocate memory block map
std D.BlkMap+2 set initialization ptr
std D.SysDis set System Dispatch Table ptr
inca allocate table
std D.UsrDis set User Dispatch Table ptr
inca allocate table
std D.PrcDBT set Process Descriptor Block ptr
inca allocate table
std D.SysPrc set system process ptr
std D.Proc set current process
adda #P$Size/256 allocate system process descriptor
tfr d,s set stack
inca allocate system stack
std D.SysStk set top of system stack
std D.SysMem set system memory map ptr
inca allocate memory map
std D.ModDir set module directory ptr
std D.ModEnd set end of directory ptr
adda #$07
std D.ModDir+2 set end ptr
std D.ModDAT set end ptr for Module DAT area
leax IntXfr,pcr get interrupt transfer
tfr X,D copy it
ldx #D.SWI3 get entry vectors ptr
Cold14 std ,X++ set vector
cmpx #D.NMI end of vectors?
bls Cold14 branch if not
leax ROMEnd,PCR get entry offset
pshs X save it
leay HdlrVec,PCR get interrupt handlers
ldx #D.Clock get psuedo-vector ptr
Cold15 ldd ,Y++ get vector
addd 0,s add offset
std ,X++ set psuedo-vector
cmpx #D.XNMI end of vectors?
bls Cold15 branch if not
leas 2,s return scratch
ldx D.XSWI2 get user service routine
stx D.UsrSvc set user entry
ldx D.XIRQ get user IRQ routine
stx D.UsrIRQ set user entry
leax SysSvc,PCR get system service routine
stx D.SysSVC set system entry
stx D.XSWI2 set system entry
leax SysIRQ,PCR get system IRQ routine
stx D.SysIRQ set system entry
stx D.XIRQ set IRQ entry
leax GoPoll,pcr get call to [D.Poll]
stx D.SvcIRQ set in-system IRQ service
leax IOPoll,PCR get polling routine ptr
stx D.POLL set it
leay SvcTbl,PCR get service routine initial
lbsr SetSvc install service routines
ldu D.PrcDBT get process descriptor block ptr
ldx D.SysPrc get system process ptr
stx 0,u set process zero page
stx 1,u set process one page
lda #1 set process ID
sta P$ID,X
lda #SysState get system state
sta P$State,X set state
lda #SysTask get system task
sta D.SysTsk set system task number
sta P$Task,X set process task number
lda #255 get high priority
sta P$Prior,X set process priority
sta P$Age,X set process age
leax P$DATImg,X get DAT image ptr
stx D.SysDAT set system DAT image ptr
ifeq DAT.WrEn
clra
clrb
else
ldd #DAT.WrEn
endc
std ,X++ use block zero for system
ifge RAMCount-2
incb
std ,x++
ifge RAMCount-3
incb
std ,x++
endc
endc
ldy #Dat.BlCt-ROMCount-RAMCount-1 get free block count
ldd #DAT.Free
Cold16 std ,X++ mark free entry
leay -1,Y count block
bne Cold16 branch if more
ldd #DAT.WrEn+$0150 IOBlock?
std ,x++
ldd #DAT.WrEn+$0140
std ,x++
ldd #ROMBlock ($01FE)
L0190 std ,x++
incb
bne L0190
ldx D.Tasks get task number table
inc 0,X claim system task
inc $01,x
ldx D.SysMem get system memory map ptr
ldb D.ModDir+2 get number of pages used
Cold17 inc ,X+ claim page
decb count it
bne Cold17 branch if more
*
* build Memory Block Map
*
ifeq RAMCheck-BlockTyp
ldy #DAT.BlSz*RAMCount get unused block ptr
ldx D.BlkMap
endc
Cold20 equ *
ifeq RAMCheck-BlockTyp
pshs X
ldd 0,s
endc
subd D.BlkMap get block number
cmpd #DAT.BlMx
bcc Cold30
ifne DAT.WrEn
ora #(DAT.WrEn/256)
endc
std DAT.Regs+(RAMCount*2) set block register
ifeq RAMCheck-BlockTyp
ldu 0,y get current contents
ldx #$00FF get first test pattern
stx 0,Y store it
cmpx 0,Y did it store?
bne Cold30 branch if not
ldx #$FF00 get second test pattern
stx 0,Y store it
cmpx 0,Y did it store?
bne Cold30 branch if not
stu 0,y replace original contents
bra Cold40
Cold30 ldb #NotRAM get not-RAM flag
stb [0,s] mark block not-RAM
Cold40 puls x retrieve block map ptr
leax 1,X next Block Map entry
cmpx D.BlkMap+2 end of map?
bcs Cold20 branch if not
endc
*
* search Not-Ram, excluding I/O, for modules
*
ldx D.BlkMap
inc 0,X claim block zero for system
ifge RAMCount-2
inc 1,x
ifge RAMCount-3
inc 2,x
endc
endc
ifeq ROMCheck-Limited
ldx D.BlkMap+2
leax >-(DAT.BlCt*2),x check uppermost 64K only
endc
Cold50 lda 0,x is this RAM block?
beq Cold80 branch if so
tfr X,D copy block map ptr
subd D.BlkMap get Block Number
cmpd #DAT.Free
beq Cold80
leas -(DAT.BlCt*2),s reserve temp DAT area on stack
leay 0,s move DATTmp ptr to Y
ifne TEST
else
bsr MovDAT
endc
pshs x save Block Map ptr
ldx #0 make block offset
Cold55 equ *
Cold60 pshs Y,X save ptrs
lbsr AdjImg adjust DAT image ptr
ldd ,y
std DAT.Regs
lda ,x
ldx #$0000+DAT.WrEn
stx DAT.Regs
puls y,x retrieve ptrs
cmpa #$87 could be module?
bne Cold70 branch if not
Cold62 lbsr ValMod validate module
bcc Cold65 branch if successful
cmpb #E$KwnMod known module?
bne Cold70 branch if not
Cold65 ldd #M$Size get module size offset
lbsr LDDDXY get module size
leax D,X move ptr
bra Cold75
Cold70 leax 1,X move ptr
Cold75 tfr X,D copy ptr
tstb end of block?
bne Cold60 branch if not
bita #^DAT.Addr end of block?
bne Cold60 branch if not
lsra make block count
lsra
ifge DAT.BlSz-2048
lsra
ifge DAT.BlSz-4096
lsra
endc
endc
deca adjust number
puls X
leax A,X
Cold79 leas DAT.BlCt*2,s throw away temp DAT area
Cold80 leax 1,x move Block Map ptr
cmpx D.BlkMap+2
bcs Cold50
ifne TEST
endc
Cold.z1 leax InitName,pcr get name ptr
bsr LinkSys link to "Init"
bcc Cold.z2 branch if found
ifne TEST
endc
os9 F$Boot call bootstrap
bcc Cold.z1 branch if bootstrapped
ifne TEST
endc
bra ColdErr
Cold.z2 stu D.Init save module ptr
Cold.z3 leax P2Name,pcr get name str str
bsr LinkSys link to "OS9p2"
bcc Cold.xit branch if found
ifne TEST
endc
os9 F$Boot call bootstrapper
bcc Cold.z3 branch if bootstrapped
ColdErr equ *
jmp [>$FFFE]
Cold.xit jmp 0,y go to "OS9p2"
LinkSys lda #Systm set module type
os9 F$Link link to it
rts
************************************************************
*
* Subroutine MovDAT
*
* Make temporary image of of DAT-Block Addr
*
* Input: D = DAT image offset
* Y = ptr to DAT temp area
*
* Output: DAT image moved to temp area
*
* Data: D.TmpDAT
*
* Calls: None
*
MovDAT pshs y,x,d save regs
ldb #DAT.BlCt get block count
ldx 0,s get starting block number
MovDAT.B stx ,Y++ set DAT image
leax 1,X mov ptr
decb done?
bne MovDAT.B bra if not
puls PC,Y,X,D return
ttl Coldstart Constants
page
************************************************************
*
* Service Routines Initialization Table
*
SvcTbl equ *
fcb F$Link
fdb Link-*-2
fcb F$PRSNAM
fdb PNam-*-2
fcb F$CmpNam
fdb UCNam-*-2
fcb F$CmpNam+SysState
fdb SCNam-*-2
fcb F$CRC
fdb CRCGen-*-2
fcb F$SRqMem+SysState
fdb SRqMem-*-2
fcb F$SRtMem+SysState
fdb SRtMem-*-2
fcb F$AProc+SysState
fdb AProc-*-2
fcb F$NProc+SysState
fdb NextProc-*-2
fcb F$VModul+SysState
fdb VModule-*-2
fcb F$SSvc
fdb SSvc-*-2
fcb F$SLink+SysState
fdb SLink-*-2
fcb F$Boot+SysState
fdb Boot-*-2
fcb F$BtMem+SysState
fdb SRqMem-*-2
fcb F$Move+SysState
fdb Move-*-2
fcb F$AllRAM
fdb AllRAM-*-2
fcb F$AllImg+SysState
fdb AllImg-*-2
fcb F$SetImg+SysState
fdb SetImg-*-2
fcb F$FreeLB+SysState
fdb FreeLB-*-2
fcb F$FreeHB+SysState
fdb FreeHB-*-2
fcb F$AllTsk+SysState
fdb AllTsk-*-2
fcb F$DelTsk+SysState
fdb DelTsk-*-2
fcb F$SetTsk+SysState
fdb SetTsk-*-2
fcb F$ResTsk+SysState
fdb ResTsk-*-2
fcb F$RelTsk+SysState
fdb RelTsk-*-2
fcb F$DATLog+SysState
fdb DATLog-*-2
fcb F$LDAXY+SysState
fdb F.LDAXY-*-2
fcb F$LDDDXY+SysState
fdb F.LDDDXY-*-2
fcb F$LDABX+SysState
fdb F.LDABX-*-2
fcb F$STABX+SysState
fdb F.STABX-*-2
fcb F$ELink+SysState
fdb ELink-*-2
fcb F$FModul+SysState
fdb FMod-*-2
fcb $80
************************************************************
*
* Module Names
*
InitName fcs "Init"
P2Name fcs "OS9p2"
BootName fcs "Boot"
ttl System Service Request Routines
pag
************************************************************
*
* Interrupt Transfer
*
IntXfr jmp [-16,x] transfer to interrupt routine
************************************************************
*
* User State Interrupt Routines
*
* Checks for user defined routine; uses system if none
*
* Data: D.Proc
*
* Calls: UserSvc
*
UserSWI3 ldx D.Proc get current process ptr
ldu P$SWI3,X get user interrupt routine
beq UserSvc branch if none
UsrSWI10 lbra PassSWI
UserSWI2 ldx D.Proc get current process ptr
ldu P$SWI2,X get user interrupt routine
beq UserSvc branch if none
bra UsrSWI10
UserSWI ldx D.Proc get current process ptr
ldu P$SWI,X get SWI routine
bne UsrSWI10 branch if set
*
* fall through to UserSvc
*
page
************************************************************
*
* User Service Request Routine
*
* Process User service requests
*
* Input: X = Process descriptor ptr
* S = value of stack after interrupt
*
* Output: none
*
* Data: D.SysSvc, D.SWI2, D.SysIRQ, D.IRQ, D.Proc, D.UsrDis
*
* Calls: GetRegs, PutRegs, LDBBX, Dispatch, UserRet
*
UserSvc ldd D.SysSvc get system SWI2 service routine
std D.XSWI2 set SWI2 entry
ldd D.SysIRQ get system IRQ service routine
std D.XIRQ set IRQ entry
lda P$State,X get state flag
ora #SysState set system state
sta P$State,X update state
sts P$SP,X save stack ptr
leas (P$Stack-R$Size),X move to local stack
andcc #^IntMasks clear interrupt masks
leau 0,s get system stack ptr
bsr GetRegs get user stack
ldb P$Task,X get process task number
ldx R$PC,u get program counter
lbsr LDBBX get service request code
leax 1,X move PC past code
stx R$PC,u update program counter
ldy D.UsrDis get user dispatch table ptr
lbsr Dispatch dispatch to service routine
ldb R$CC,u get user condition codes
andb #^IntMasks clear interrupt masks
stb R$CC,u update condition codes
ldx D.Proc get process ptr
bsr PutRegs return user stack
lda P$State,X get process state flags
anda #^SysState clear system state
lbra UsrRet.a
page
************************************************************
*
* Subroutine GetRegs
*
* Copy User interrupt register stack
*
* Input: X = Process Descriptor ptr
* U = local stack ptr
*
* Output: none
*
* Data: none
*
* Calls: MoveRegs
*
GetRegs pshs u,y,x,cc
ldb P$Task,X get process task
ldx P$SP,X get process stack ptr
lbsr L0C6F
leax >-$2000,x
bra PutReg.A
************************************************************
*
* Subroutine PutRegs
*
* Copy User interrupt register stack
*
* Input: X = Process Descriptor ptr
* U = local stack ptr
*
* Output: none
*
* Data: none
*
* Calls: MoveRegs
*
PutRegs pshs u,y,x,cc
ldb P$Task,X get process task
ldx P$SP,X get process stack ptr
lbsr L0C6F
leax >-$2000,x
exg x,u
PutReg.A pshs u
ldu #DAT.Regs
leau a,u
orcc #IntMasks set interrupt masks
stb DAT.Accs
pulu y,b,a
clr DAT.Accs
ldu #$FFBC
pshu y,b,a
puls u
ldy #R$Size get double byte count
L0389 ldd ,x++
std ,u++
leay -2,y
bne L0389
ldx D.SysDAT
ldd <$38,x
std >$FFB8
ldd <$3A,x
std >$FFBA
puls pc,u,y,x,cc
page
************************************************************
*
* System Service Request Routine
*
* Process system service requests
*
* Input: S = value of stack after interrupt
*
* Output: none
*
* Data: D.SysDis, D.SysPrc
*
* Calls: Dispatch, SvcRet
*
SysSvc leau 0,s get registers ptr
lda R$CC,u get caller's interrupt masks
tfr a,cc restore interrupt masks
ldx R$PC,u get program counter
ldb ,X+ get service code
stx R$PC,u update program counter
ldy D.SysDis get system dispatch table ptr
bsr Dispatch dispatch to service routine
lbra SysRet
page
************************************************************
*
* Subroutine Dispatch
*
* Calls service routing using service request code as an
* index in table of service routine addresses
*
* Input: B = Service Request code
* Y = Service Routine Address Table ptr
* U = registers ptr
*
* Output: none
*
* Data: none
*
* Calls: [max(B*2,254),Y]
*
Dispatch aslb make table offset
bcc Dispat10 branch if not I/O request
rorb correct code
ldx IOEntry,y get i/o entry
bra Dispat20
Dispat10 clra
ldx D,Y get routine entry
bne Dispat20 branch if good code
comb set carry
ldb #E$UnkSvc err: unknown service request
bra Dispat30
Dispat20 pshs u save registers ptr
jsr 0,X call service routine
puls u retrieve registers ptr
Dispat30 tfr cc,a copy condition codes
bcc Dispat40 branch if no error
stb R$B,u return error code
Dispat40 ldb R$CC,u get calling condition
andb #%11010000 save masks & flag
stb R$CC,u save them
anda #%00101111 clear masks & flag
ora R$CC,u add masks & flag
sta R$CC,u update condition
rts
page
************************************************************
*
* Subroutine SSvc
*
* Set Service Routine Table entry Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear
*
* Data: none
*
* Call: SetSvc
*
SSvc ldy R$Y,u get table address
bra SetSvc
************************************************************
*
* Subroutine SetSvc
*
* Set Service Routine Table entries
*
* Input: Y = Routine Initialization ptr
*
* Output: none
*
* Data: D.SysSvc, D.UsrSvc
*
* Calls: none
*
SetSvc10 clra
aslb make table offset & set flag
tfr D,u save offset
ldd ,Y++ get routine offset
leax D,Y make routing ptr
ldd D.SysDis get system dispatch table ptr
stx D,u set routine entry
bcs SetSvc branch if system only
ldd D.UsrDis get user dispatch table ptr
stx D,u set routine entry
SetSvc ldb ,Y+ get next request code
cmpb #$80 end of table code?
bne SetSvc10 branch if not
rts
page
***********************************************************
*
* Subroutine SLink
*
* System Link Service routine
*
* Input: U = registers ptr
* R$A,u = Module Type
* R$X,u = Name String ptr
* R$Y,a = Name string DAT Image ptr
*
* Output: U unchanged
* R$A,u = Module Type
* R$B,u = Module Revision
* R$X,u = updated Name String ptr
* R$Y,u = Module Entry ptr
* R$U,u = Module ptr
* Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: SysLink
*
SLink ldy R$Y,u get DAT image ptr
bra SysLink
***********************************************************
*
* Subroutine ELink
*
* Link using already located Module Directory entry
*
* Input: U = registers ptr
* R$B,u = Module type byte
* R$X,u = Module Directory entry ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: EntLink
*
ELink pshs u save registers ptr
ldb R$B,u get module revision
ldx R$X,u get directory entry ptr
bra EntLink
page
***********************************************************
*
* Subroutine Link
*
* Find specified module & switch it into process space
*
* Input: U = registers ptr
* R$A,u = Module Type
* R$X,u = Name String ptr
*
* Output: U unchanged
* R$A,u = Module Type
* R$B,u = Module Revision
* R$X,u = updated Name String ptr
* R$Y,u = Module Entry ptr
* R$U,u = Module ptr
* Carry clear if successful; set otherwise
*
* Data: D.Proc
*
* Calls: AdjImg, FModule, DATtoLog, LDDDXY, SrchPDAT,
* FreeHBlk
*
Link ldx D.Proc get process ptr
leay P$DATImg,x get DAT image ptr
SysLink pshs U save register pptr
ldx R$X,u get name string ptr
lda R$A,u get type/language byte
lbsr FModule search module directory
lbcs LinkErr branch if not found
leay 0,u copy directory entry ptr
ldu 0,s get registers ptr
stx R$X,u return string to user
std R$D,u return type/language & revision
leax 0,Y copy directory entry ptr
EntLink bitb #ReEnt is module reentrant?
bne Link10 branch if so
ldd MD$Link,x is module busy?
beq Link10 branch if not
ldb #E$ModBsy err: module busy
bra LinkErr
Link10 ldd MD$MPtr,X get module block ptr
pshs X,D save offset & entry ptr
ldy MD$MPDAT,X get DAT image ptr
ldd MD$MBSiz,X get block size
addd #DAT.BlSz-1 round to next block
tfr a,b copy MSB size
lsrb get block count
lsrb
ifge DAT.BlSz-2048
lsrb
ifge DAT.BlSz-4096
lsrb
endc
endc
pshs b
leau 0,Y copy group DAT image ptr
bsr SrchPDAT is group mapped in?
bcc Link30 branch if so
lbsr FreeHBlk
bcc Link20 branch if so
leas 5,s clean stack
ldb #E$MemFul err: memory full
bra LinkErr
Link20 lbsr SetImage set process DAT image
ifne DAT.WrPr
endc
ifne DAT.WrEn
pshs u,b,a
lsla
leau a,y
ldy 9,s
lda 2,y
bita #$40
beq L0477
clra
tfr d,y
L046D ldd ,u
ora #(DAT.WrEn/256)
std ,u++
leay -1,y
bne L046D
L0477 puls u,b,a
endc
Link30 leax P$Links,X get link count table ptr
sta 0,s save block number
asla make table offset
leau A,X get link ptr
ldx 0,u get link count
leax 1,X count link
beq Link40 branch if overflow
stx 0,u update link count
Link40 ldu 3,s get entry ptr
ldx MD$Link,u get link count
leax 1,X count use
beq Link50 branch if overflow
stx MD$Link,u update link count
Link50 puls U,Y,X,B retrieve offset, entry, & registers
lbsr DATtoLog convert to logical
stx R$U,u return to user
ldx MD$MPtr,Y get module ptr
ldy MD$MPDAT,Y get DAT image ptr
ldd #M$EXEC get module execution offset
lbsr LDDDXY get module execution offset
addd R$U,u make execution logical address
std R$Y,u return to user
clrb clear carry
rts
LinkErr orcc #Carry set carry
puls PC,u
page
***********************************************************
*
* Subroutine SrchPDAT
*
*
* Input: B = Number of blocks
* U = Module DAT Image ptr
*
* Output: A = beginning block number, if found
* Y = Process DAT image ptr
*
* Data: none
*
* Calls: SrchDAT
*
SrchPDAT ldx D.Proc get process ptr
leay P$DATImg,X get process DAT image ptr
*
* fall through to SrchDAT
*
***********************************************************
*
* Subroutine SrchDAT
*
* Search DAT image for specified blocks
*
* Input: B = block count
* Y = search DAT image ptr
* U = target DAT image ptr
*
* Output: A = beginning block number, if found
*
* Data: none
*
* Calls: none
*
SrchDAT clra clear MSB count
pshs Y,X,D save count & registers
subb #DAT.BlCt get negative limit
negb get true beginning limit
aslb shift for two-byte entries
leay B,Y move to first search location
SrchD10 ldx 0,s get count
pshs U,Y save DAT image ptrs
SrchD20 ldd ,Y++ get search DAT block
ifne DAT.WrPr+DAT.WrEn
anda #1
endc
cmpd ,u++ does it match target?
bne SrchD30 branch if not
leax -1,X count block
bne SrchD20 branch if more
puls U,D retrieve DAT image ptrs
subd 4,s get beginning block offset
lsrb convert to local block number
stb 0,s save it
clrb clear carry
puls PC,Y,X,D
SrchD30 puls U,Y retrieve DAT image ptrs
leay -2,Y move one block lower
cmpy 4,s end of DAT image?
bcc SrchD10 branch if not
puls PC,Y,X,D
page
***********************************************************
*
* Subroutine VModule
*
* Module Validation Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear if successful; set if not
*
* Data: none
*
* Calls: ValMod
*
VModule pshs U save registers ptr
ldx R$X,u get module offset
ldy R$D,u get DAT image ptr
bsr ValMod validate module
ldx 0,s get registers ptr
stu R$U,x return entry ptr
VModXit puls pc,u
***********************************************************
*
* Subroutine ValMod
*
* Validate Module and update Module Directory
*
* Input: X = Module Block offset
* Y = Module DAT Image ptr
*
* Output: D destroyed
* U = Directory Entry
* Carry clear if successful; set if not
*
* Data: none
*
* Calls: ModCheck, LDDDXY, AdjImg, FModule, DATtoLog
*
ValMod pshs Y,X save new module ptr
lbsr ModCheck is it good module?
bcs ValMoErr branch if not
ldd #M$Type get module type offset
lbsr LDDDXY get module type & revision
andb #Revsmask get revision level
pshs D save them
ldd #M$Name get module name offset offset
lbsr LDDDXY get module name offset
leax D,X make name string ptr
puls a retrieve module type
lbsr FModule search module directory
puls a retrieve new revision level
bcs ValMod20 branch if not found
pshs a save new revision level
andb #Revsmask get old module revision
subb ,s+ get old-new difference
bcs ValMod20 branch if new is higher
ldb #E$KwnMod err: known module
bra ValMoErr
ValMoErA ldb #E$DirFul error: directory full
ValMoErr orcc #carry set carry
puls PC,Y,X
ValMod20 ldx 0,s get block offset
lbsr SetMoImg set DAT image for module
bcs ValMoErA bra if error
sty MD$MPDAT,u install new module
stx MD$MPtr,u store block offset in dir
clra
clrb
std MD$Link,u clear out link count
ldd #M$Size get module size offset
lbsr LDDDXY get module size
pshs X copy module ptr
addd ,s++ get module end address
std MD$MBSiz,u set block size
ldy [MD$MPDAT,u] get block number
ldx D.ModDir get module directory ptr
pshs U save ptr for check
bra ValMod35 jif done
ValMod30 leax MD$ESize,X next entry
ValMod35 cmpx D.ModEnd chk for end of dir
bcc ValMod55 jif done
cmpx 0,s chk if entry is new one
beq ValMod30 jif don't check
cmpy [MD$MPDAT,X] module in this block?
bne ValMod30 branch if not
bsr FreDATI update mod dat ptr, and free old img
ValMod55 puls U rid pos ptr
ldx D.BlkMap get block map ptr
ldd MD$MBSiz,u get block size
addd #DAT.BlSz-1 round to next block
lsra get block count
lsra
ifge DAT.BlSz-2048
lsra
ifge DAT.BlSz-4096
lsra
endc
endc
ldy MD$MPDAT,u get ptr to DAT img
ValMod60 pshs x,a save count, blkmap ptr
ldd ,Y++ get blk number to mark
leax D,X get map position
ldb 0,X get status bits
orb #ModBlock mark blk
stb 0,X save status bits
puls X,A restore count,blkmap ptr
deca next blk
bne ValMod60 jif not done
clrb clear carry
puls PC,Y,X
* non-contiguous modules
FreDATI pshs U,Y,X,D save regs
ldx MD$MPDAT,X get DAT image ptr
pshs X save copy of ptr
clra
clrb
Fre.Lp ldy 0,X get blk number
beq Fre.Out bra if end of DAT image
std ,X++ mark entry free
bra Fre.Lp back for more
Fre.Out puls x restore reg
ldy 2,s get ptr to position
ldu MD$MPDAT,u get new image ptr
puls D get blk size
Fre.Lp2 cmpx MD$MPDAT,Y chk if same blk as new
bne Fre.NoCh bra if not
stu MD$MPDAT,Y make ptr to new dat image
cmpd MD$MBSiz,y chk if size bigger
bcc Fre.Not bra if so
ldd MD$MBSiz,Y get old size
Fre.Not std MD$MBSiz,y set new size
Fre.NoCh leay MD$ESize,Y next mdir entry
cmpy D.ModEnd chk for end of dir
bne Fre.Lp2 bra if not done
puls PC,u,Y,X done
* non-contiguous modules
SetMoImg pshs U,Y,X save DAT image ptr, entry ptr
ldd #M$Size get module size offset
lbsr LDDDXY get module size
addd 0,s get total blks so far
addd #DAT.BlSz-1 round to next whole blk
lsra make blk count
lsra
ifge DAT.BlSz-2048
lsra
ifge DAT.BlSz-4096
lsra
endc
endc
tfr A,B make proper register
pshs B save count
incb make bytes for mod DAT img
lslb
negb
sex
bsr chkspce check if space for expand
bcc SetI.out jif ok
os9 F$GCMDir garbage collect
ldu #0 clear entry found
stu 5,s
bsr chkspce check again for space
SetI.out puls PC,u,Y,X,B done: return result
chkspce ldx D.ModDAT get DAT-top ptr
leax D,X make ptr to new dat img
cmpx D.ModEnd check if overrun
bcs Chks.err jif no space
ldu 7,s get entry ptr
bne chksp1 jif don't check
pshs X save for chk
ldy D.ModEnd check if entry space
leay MD$ESize,Y
cmpy ,s++
bhi Chks.err jif no space
sty D.ModEnd set new modend
leay -MD$ESize,Y make entry ptr
sty 7,s return entry ptr
chksp1 stx D.ModDAT ser new moddat
ldy 5,s get DAT image ptr
ldb 2,s and blk count
stx 5,s set new mod DAT image ptr
Chks.D ldu ,Y++ xfer DAT img to Mod dat img
stu ,X++
decb
bne Chks.D jif more
clr 0,X make end of Mod Dat img
clr 1,X
rts done
Chks.err orcc #CARRY show error
rts done
page
***********************************************************
*
* Subroutine ModCheck
*
* Check Module ID, Header Parity, & CRC
*
* Input: X = Module block offset
* Y = Module DAT Image ptr
*
* Output: D = 0, if good module
* Carry clear if good module; set if not
*
* Data: none
*
* Calls: LDDDXY, AdjImg, LDAXYP, CRCCal
*
ModCheck pshs Y,X save module ptr
clra
clrb
lbsr LDDDXY get sync bytes
cmpd #M$ID12 is it good ID?
beq ModChk10 branch if so
ldb #E$BMID err: bad module ID
bra ModChErr
ModChk10 leas -1,s get scratch
leax 2,X skip ID bytes
lbsr AdjImg adjust DAT image ptr
ldb #M$Parity-1 get byte count
lda #($87!$CD)-($87&$CD) init parity
ModChk20 sta 0,s save parity
lbsr LDAXYP get next header byte
eora 0,s accumulate it
decb count byte
bne ModChk20 branch if more
leas 1,s return scratch
inca good parity?
beq ModChk30 branch if so
ldb #E$BMHP err: bad module header parity
bra ModChErr
ModChk30 puls Y,X retrieve module ptr
ldd #M$Size get module size offset
lbsr LDDDXY get module size
pshs Y,X,D save module size & ptr
ldd #$FFFF init CRC accumulator
pshs d
pshs b
lbsr AdjImg adjust DAT image ptr
leau 0,s get CRC accumulator ptr
ModChk40 equ *
tstb time for a break?
bne ModChk45 branch if not
pshs x save module ptr
ldx #1
os9 F$Sleep give up time slice
puls x retrieve module ptr
ModChk45 lbsr LDAXYP get next module byte
bsr CRCCal accumulate it
ldd 3,s get module size
subd #1 count byte
std 3,s save count
bne ModChk40 branch if more
puls y,x,b retrieve CRC & scratch
cmpb #CRCCon1 is first byte correct?
bne ModChk50 branch if not
cmpx #CRCCon23 are other bytes correct?
beq ModChk60 branch if so
ModChk50 ldb #E$BMCRC err: bad module crc
ModChErr orcc #carry set carry
ModChk60 puls x,y,pc
page
***********************************************************
*
* Subroutine CRCCal
*
* Calculate Next CRC Value
*
* Input: A = next data byte
* U = CRC accumulator ptr
*
* Output: A = MSB CRC accumulator
* B = LSB CRC accumulator
*
* Data: none
*
* Calls: none
*
CRCCal eora 0,u add CRC MSB
pshs A save it
ldd 1,u get CRC mid & low
std 0,u shift to high & mid
clra
ldb 0,s get old high
lslb shift d
rola
eora 1,u add old lsb
std 1,u Set crc mid & low
clrb
lda 0,s get old MSB
lsra shift d
rorb
lsra shift d
rorb
eora 1,u add new mid
eorb 2,u add new low
std 1,u set mid & low
lda 0,s get old MSB
lsla
eora 0,s add old MSB
sta 0,s
lsla
lsla
eora 0,s add altered MSB
sta 0,s
lsla
lsla
lsla
lsla
eora ,s+ add altered MSB
bpl CRCC99
ldd #$8021
eora 0,u
sta 0,u
eorb 2,u
stb 2,u
CRCC99 rts
***********************************************************
*
* Subroutine CRCGen
*
* CRC Accumulation Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear if successful; set if not
* D, X, Y, U destroyed
*
* Data: none
*
* Calls: Mover, AdjImg, LDAXYP, CRCCal
*
CRCGen ldd R$Y,u zero byte count?
beq CRCGen20 branch if so
ldx R$X,u get data ptr
pshs X,D save count & ptr
leas -3,s make accumulator scratch
ldx D.Proc get process ptr
lda P$Task,X get process task number
ldb D.SysTsk get system task number
ldx R$U,u get accumulator ptr
ldy #3 get byte count
leau 0,s get scratch ptr
pshs Y,X,D save parameters
lbsr Mover copy accumulator
ldx D.Proc get process ptr
leay P$DATImg,X get DAT image ptr
ldx 11,s get data ptr
lbsr AdjImg adjust DAT image ptr
CRCGen10 lbsr LDAXYP get data byte
lbsr CRCCal accumulate it
ldd 9,s get byte count
subd #1 count it
std 9,s update it
bne CRCGen10 branch if more
puls Y,X,D retrieve parameters
exg A,B reverse tasks
exg X,u reverse ptrs
lbsr Mover copy accumulator
leas 7,s return scratch
CRCGen20 clrb clear carry
rts
page
***********************************************************
*
* Subroutine FMod
*
* Find Module Directory Entry Service routine
*
* Input: U = registers ptr
* R$A,u = Module Type
* R$X,u = Name string offset
* R$Y,u = DAT Image ptr
*
* Output: Y = registers ptr
* R$A,u = Module Type
* R$B,u = Module Revision
* R$X,u = Updated Name string offset
* R$U,u = Directory Entry ptr
* Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: FModule
*
FMod pshs u save registers ptr
lda R$A,u get module type
ldx R$X,u get name string offset
ldy R$Y,u get DAT image ptr
bsr FModule search Module Directory
puls y retrieve registers ptr
std R$D,Y return type/revision
stx R$X,Y return name string offset
stu R$U,Y return directory entry ptr
rts
page
***********************************************************
*
* Subroutine FModule
*
* Search Module Directory
*
* Input: A = Module type
* X = Name string block offset
* Y = Name DAT Image ptr
*
* Output: A = Module type
* B = Module revision
* X = updated Name String ptr
* U = Directory Entry ptr
* Carry clear if found; set if not
*
* Data: D.ModDir, D.TmpDAT
*
* Calls: SkipsSpc, PrsNam, ChkNam, LDDDXY
*
FModule ldu #0 clear directory entry ptr
pshs u,d save registers
bsr SkipSpc skip leading spaces
cmpa #'/ ss there "/" prefix?
beq FModul55 branch if so
lbsr PrsNam parse name
bcs FModul60 branch if bad
ldu D.ModDir get module directory ptr
bra FModul53 enter loop
FModul10 pshs Y,X,D save name length & ptr
pshs Y,X make DAT-Block address for PrsNam
ldy MD$MPDAT,u get module DAT image ptr
beq FModul40 branch if entry entry
ldx MD$MPtr,u get module ptr
pshs Y,X save module ptr
ldd #M$NAME get module name offset offset
lbsr LDDDXY get module name offset
leax D,X get name string ptr
pshs Y,X save name length & ptr
leax 8,s get target DAT-block address ptr
ldb 13,s get name size
leay 0,s get module DAT-block address ptr
lbsr ChkNam compare names
leas 4,s return module name ptr
puls Y,X retrieve module ptr
leas 4,s return target name ptr
bcs FModul50 branch if names differ
ldd #M$Type get module type offset
lbsr LDDDXY get module type & revision
sta 0,s save module type
stb 7,s return module revision
lda 6,s get desired type/language
beq FModul30 branch if any
anda #TypeMask get type
beq FModul20 branch if any
eora 0,s get type difference
anda #TypeMask clear language difference
bne FModul50 branch if different
FModul20 lda 6,s get desired type/language
anda #LangMask get desired language
beq FModul30 branch if any
eora 0,s get language difference
anda #LangMask clear type difference
bne FModul50 branch if different
FModul30 puls Y,X,D retrieve type & name ptr
abx move string ptr
clrb clear carry
ldb 1,s retrieve register
leas 4,s return scratch
rts
FModul40 leas 4,s return scratch
ldd 8,s free entry found?
bne FModul50 branch if so
stu 8,s save free entry ptr
FModul50 puls Y,X,D retrieve type & name ptr
leau MD$ESize,u next directory entry
FModul53 cmpu D.ModEnd end of directory?
bcs FModul10 branch if not
comb set carry
ldb #E$MNF err: module not found
bra FModul60
FModul55 comb set carry
ldb #E$BNam err: bad name
FModul60 stb 1,s save for return
puls D,u,PC
***********************************************************
*
* Subroutine SkipSpc
*
* Skip spaces
*
* Input: X = Block offset
* Y = DAT Image ptr
*
* Output: A = first non-blank character
*
* Data: none
*
* Calls: LDAXY, AdjImg
*
SkipSpc pshs y save initial DAT image ptr
SkipSp10 lbsr AdjImg adjust DAT image ptr
lbsr LDAXY get character
leax 1,x move ptr
cmpa #' is it space?
beq SkipSp10 branch if so
leax -1,x backup to character
pshs a save character
tfr Y,D copy DAT image ptr
subd 1,s get logical block number
asrb adjust for two-byte entries
lbsr DATtoLog convert to logical ptr
puls pc,y,a
page
***********************************************************
*
* Subroutine PNam
*
* Parse Name Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear if successful; set if not
*
* Data: D.Proc
*
* Calls: AdjImg, PrsNam
*
PNam ldx D.Proc get process ptr
leay P$DATImg,X get DAT image ptr
ldx R$X,u get name string ptr
bsr PrsNam parse name
std R$D,u return delimiter; byte count
bcs PNam10 branch if error
stx R$X,u return ptr
abx get end of name ptr
PNam10 stx R$Y,u return end ptr
rts
page
***********************************************************
*
* Subroutine PrsNam
*
* Parse OS-9 type name
*
* Input: B = Block number
* X = Block offset
* Y = DAT Image ptr
*
* Output: A = Delimiter char
* B = Name size (byte count)
* X,Y updated past "/" prefix
*
* Data: none
*
* Calls: LDAXY, AdjImg, Alpha, AlphaNum
*
PrsNam pshs y save initial DAT image ptr
lbsr AdjImg adjust DAT image ptr
pshs Y,X save ptr
lbsr LDAXYP get next byte
cmpa #'/ is it "/" prefix
bne PrsNam10 branch if not
leas 4,s unsave ptr
pshs Y,X save string ptr
lbsr LDAXYP get next byte
PrsNam10 bsr Alpha is it alphabetic?
bcs PrsNam40 branch if not
clrb clear byte count
PrsNam20 incb count byte
tsta is this last byte?
bmi PrsNam30 branch if so
lbsr LDAXYP get next byte
bsr AlphaNum is it alphanumeric?
bcc PrsNam20 branch if so
PrsNam30 andcc #$ff-carry clear carry
bra PrsNam70
PrsNam40 cmpa #', is it comma?
bne PrsNam60 branch if not
PrsNam50 leas 4,s pitch last ptr
pshs Y,X save string ptr
lbsr LDAXYP get next byte
PrsNam60 cmpa #$20 is there a space?
beq PrsNam50 branch if so
comb set carry
ldb #E$BNam err: bad name
PrsNam70 puls Y,X retrieve string ptr
pshs d,cc save registers
tfr Y,D copy DAT image ptr
subd 3,s get image offset
asrb get block number
lbsr DATtoLog convert to logical address
puls PC,Y,D,CC
page
***********************************************************
*
* Subroutine AlphaNum
*
* Determine if byte is alphanumeric
*
* Input: A = Byte
*
* Output: carry set if not alphanumeric
*
* Data: none
*
* Calls: Alpha
*
AlphaNum pshs a save byte
anda #^Sign clear sign bit
cmpa #'. is it period?
beq IsAlpha branch if so
cmpa #'0 BELOW ZERO?
blo NotAlpha branch if so
cmpa #'9 NUMERIC?
bls IsAlpha branch if so
cmpa #'_ UNDERSCORE?
bne Alpha10 branch if not
IsAlpha clra clear carry
puls PC,a
***********************************************************
*
* Subroutine Alpha
*
* Determine if byte is alphabetic
*
* Input: A = Byte
*
* Output: carry set if not alphabetic
*
* Data: none
*
* Calls: none
*
Alpha pshs a save byte
anda #^Sign clear sign bit
Alpha10 cmpa #'A below alphabet?
blo NotAlpha branch if so
cmpa #'Z upper case alphabetic?
bls IsAlpha branch if so
cmpa #'a below alphabet?
blo NotAlpha branch if so
cmpa #'z lower case alphabetic?
bls IsAlpha branch if so
NotAlpha coma set carry
puls PC,a
page
***********************************************************
*
* Subroutine CNam
*
* Compare Names Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear if same; set if not
*
* Data: D.Proc
*
* Calls: AdjImg, ChkNam
*
UCNam ldx D.Proc get process ptr
leay P$DATImg,X get DAT image ptr
ldx R$X,u get target ptr
pshs Y,X save DAT image
bra SCNam10
SCNam ldx D.Proc get current process ptr
leay P$DATImg,X get DAT image ptr
ldx R$X,u get target string ptr
pshs Y,X save them
ldy D.SysDAT get system DAT ptr
SCNam10 ldx R$Y,u get module name ptr
pshs Y,X save them
ldd R$D,u get target name length
leax 4,s get target name ptr
leay 0,s get module name ptr
bsr ChkNam compare names
leas 8,s return scratch
rts
page
***********************************************************
*
* Subroutine ChkNam
*
* Compare two OS-9 type names
*
* Input: D = Target name length
* X = Target DAT-Block address ptr
* [ x :x+1] = Target name block offset
* [x+2:x+2] = Target DAT Image ptr
* Y = Module DAT-Block address ptr
* [ y :y+1] = Module name block offset
* [y+2:y+3] = Module DAT Image ptr
*
* Output: Carry clear if names are the same
* set if names differ
*
* Data: none
*
* Calls: LDAXYP
*
ChkNam pshs U,Y,X,D save registers
ldu 2,s get target ptr ptr
pulu Y,X get target ptr
lbsr AdjImg adjust DAT image ptr
pshu Y,X save them
ldu 4,s get module ptr ptr
pulu Y,X get module ptr
lbsr AdjImg adjust DAT image ptr
bra ChkNam15
ChkNam10 ldu 4,s get module ptr
pulu Y,X get module ptr
ChkNam15 lbsr LDAXYP get next byte
pshu Y,X save module ptr
pshs a save module byte
ldu 3,s get target ptr
pulu Y,X get target ptr
lbsr LDAXYP get next byte
pshu Y,X save target ptr
eora 0,s get module-target difference
tst ,s+ is this last module?
bmi ChkNam30 branch if not
decb is this last target?
beq ChkNam20 branch if so
anda #^('a-'A) clear case difference
beq ChkNam10 ..yes; repeat
ChkNam20 comb Set carry
puls PC,u,Y,X,D
ChkNam30 decb is this last target?
bne ChkNam20 branch if not
anda #^(Sign+'a-'A) clear case & sign difference
bne ChkNam20 branch if different
clrb clear carry
puls PC,u,Y,X,D
***********************************************************
*
* Subroutine SRqMem
*
* Allocate memory for system
*
* Input: U = registers ptr
*
* Output: Carry clear if successful; set if not
*
* Data: D.SysPrc. D.TmpDAT
*
* Calls: none
*
SRqMem ldd R$D,u get byte count
addd #$FF round up to page
clrb
std R$D,u return size to user
ldy D.SysMem get system memory map ptr
leas -2,s get scratch
stb 0,s set DAT image offset
SRqMem10 ldx D.SysDAT get system DAT image ptr
aslb shift for two-byte entries
ldd B,X get block number
cmpd #DAT.Free is it free block?
beq SRqMem20
ldx D.BlkMap branch if so
ifne DAT.WrPr+DAT.WrEn
anda #1
endc
lda D,X get block flags
cmpa #RAMinUse is it allocatable?
bne SRqMem30 branch if not
leay DAT.BlSz/256,Y leave map as is
bra SRqMem40
SRqMem20 clra cleat page flags
SRqMem30 ldb #DAT.BlSz/256 get page count
SRqMem35 sta ,y+ set map
decb countr page
bne SRqMem35 branch if more
SRqMem40 inc 0,s count block
ldb 0,s get DAT image offset
cmpb #DAT.BlCt checked all blocks?
bcs SRqMem10 branch if not
SRqMem50 ldb R$D,u get page count
SRqMem55 cmpy D.SysMem beginning of map?
bhi SRqMem60 branch if not
comb set carry
ldb #E$MemFul err: memory full
bra SRqMem80
SRqMem60 lda ,-y get page flag
bne SRqMem50 branch if not free
decb countr free page
bne SRqMem55 branch if not enough
sty 0,s same map ptr
lda 1,s get page number
lsra get block number
lsra
ifge DAT.BlSz-2048
lsra
ifge DAT.BlSz-4096
lsra
endc
endc
ldb 1,s get page number
andb #^DAT.Addr get page within block
addb R$D,u add number of pages
addb #^DAT.Addr round up to next block
lsrb get block count
lsrb
ifge DAT.BlSz-2048
lsrb
ifge DAT.BlSz-4096
lsrb
endc
endc
ldx D.SysPrc get system process ptr
lbsr AllImage allocate RAM
bcs SRqMem80 branch if error
ldb R$A,u get page count
SRqMem70 inc ,Y+ get page flag
decb count page
bne SRqMem70 branch if more
lda 1,s get page number
std R$U,u return it to user
clrb clear carry
SRqMem80 leas 2,s return scratch
rts
page
***********************************************************
*
* Subroutine SRtMem
*
* Deallocate system memory
*
* Input: U = registers ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: D.SysMem
*
* Calls: ClrBit
*
SRtMem ldd R$D,u get byte count
beq SrTM.F branch if none
addd #$FF round up to page
ldb R$U+1,u is address good?
beq SRtM.A branch if so
comb set carry
ldb #E$BPAddr err: bad page address
rts
SRtM.A ldb R$U,u get page number
beq SrTM.F branch if returning nothing
ldx D.SysMem get system memory map ptr
abx get entry ptr
SRtM.B ldb 0,X get page flags
andb #^RAMinUse clear RAM in use flag
stb ,x+ update entry
deca count page
bne SRtM.B branch if more
ldx D.SysDAT get system DAT image
ldy #DAT.BlCt get image block count
SRtM.C ldd 0,X get block number
cmpd #DAT.Free is it free block?
beq SRtM.E branch if so
ldu D.BlkMap get block map ptr
ifne DAT.WrPr+DAT.WrEn
anda #1
endc
lda d,u get block flags
cmpa #RAMinUse is it just RAM in use?
bne SRtM.E branch if not
tfr X,D copy DAT image ptr
subd D.SysDAT get image block number
aslb get memory page map offset
ifge DAT.BlSz-2048
aslb
ifge DAT.BlSz-4096
aslb
endc
endc
ldu D.SysMem get memory page map ptr
leau d,u get block pages ptr
ldb #DAT.BlSz/256 get pages per block
SRtM.D lda ,u+ get page flags
bne SRtM.E branch if not free
decb count page
bne SRtM.D branch if more pages
ldd 0,X get block number
ldu D.BlkMap get block map ptr
ifne DAT.WrPr+DAT.WrEn
anda #1
endc
clr D,u mark block free
ldd #DAT.Free get free block
std 0,X mark image free
SRtM.E leax 2,X skip to next block
leay -1,Y count block
bne SRtM.C branch if more
SrTM.F clrb clear carry
rts
page
***********************************************************
*
* Subroutine Boot
*
* Links to module name "Boot" or as specified in "Init" module,
* calls linked module expects return of ptr & size of area which
* is searched for new modules
*
* Input: none
*
* Output: Carry clear if successful; set otherwise
*
* Data: D.Boot, D.Init
*
* Calls: module linked
*
Boot comb set carry
lda D.Boot has Bootstrap been tried?
bne BootXX branch if so
inc D.Boot set flag
ldx D.Init get init address
beq Boot10 branch if none
ldd BootStr,X get bootstrap name ptr
beq Boot10 branch if none
leax D,X get name ptr
bra Boot20
Boot10 leax BootName,pcr get default name ptr
Boot20 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
leau D,X get bootstrap end ptr
tfr X,D copy bootstrap ptr
anda #DAT.Addr get translated bits
clrb
pshs U,D
lsra get DAT image offset
ifge DAT.BlSz-2048
lsra
ifge DAT.BlSz-4096
lsra
endc
endc
ldy D.SysDAT get system DAT image ptr
leay A,Y get DAT image ptr
Boot30 ldd 0,X get module beginning
cmpd #M$ID12 is it module sync code?
bne Boot40 branch if not
tfr X,D copy boot ptr
subd 0,s get block offset
tfr D,X copy offset
tfr Y,D pass DAT img ptr
ifne DAT.WrEn
anda #^(DAT.WrEn/256)
endc
OS9 F$VModul validate module
pshs B save error code (if any)
ldd 1,s get bootstrap begin
leax D,X get current ptr
puls B retrieve error code
bcc Boot35 branch if no error
cmpb #E$KwnMod is it known module?
bne Boot40 branch if not
Boot35 ldd M$SIZE,X get module size
leax D,X skip module
bra Boot50
Boot40 leax 1,X try next
Boot50 cmpx 2,s end of Boot?
bcs Boot30 branch if not
leas 4,s return scratch
BootXX rts
page
ttl Dynamic Address Translator Routines
page
***********************************************************
*
* Subroutine RAMBlk
*
* Search Memory Block Map for contiguous free RAM blocks
*
* Input: B = block count
*
* Output: D = block number
*
* Data: D.BlkMap
*
* Calls: none
*
AllRAM ldb R$B,u get block count
bsr RAMBlk allocate blocks
bcs AllRAM10 branch if failed
std R$D,u get block number
AllRAM10 rts
RAMBlk pshs Y,X,D save registers
ldx D.BlkMap get Block Map ptr
RAMBlk10 leay 0,X copy map ptr
ldb 1,s get block count
RAMBlk20 cmpx D.BlkMap+2 end of map?
bcc RAMBlk30 branch if so
lda ,x+ free block?
bne RAMBlk10 branch if not
decb found enough?
bne RAMBlk20 branch if not
tfr Y,D copy beginning block ptr
subd D.BlkMap get block number
sta 0,s return block number
lda 1,s get block count
stb 1,s return block number
RAMBlk25 inc ,y+ update flags
deca done?
bne RAMBlk25 branch if not
clrb clear carry
puls PC,Y,X,D
page
RAMBlk30 comb set carry
ldb #E$NoRam err: no RAM
stb 1,s
puls PC,Y,X,D
***********************************************************
*
* Subroutine AllImg
*
* Allocate RAM blocks for DAT image
*
* Input: U = registers ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: AllImage
*
AllImg ldd R$D,u get block number & count
ldx R$X,u get process ptr
*
* fall through to AllImage
*
***********************************************************
*
* Subroutine AllImage
*
* Allocate RAM blocks for process DAT image
*
* Input: A = beginning Block Number
* B = Block count
* x = Process Descriptor ptr
*
* Output: none
*
* Data: D.TmpDAT
*
* Calls: none
*
AllImage pshs u,Y,X,D save registers
asla shift for two-byte entries
leay P$DATImg,X get process DAT image ptr
leay A,Y get block image ptr
clra
tfr D,X copy block count
ldu D.BlkMap get block map ptr
pshs U,Y,X,D save registers
AllI.A ldd ,Y++ get current image
cmpd #DAT.Free is block allocated?
beq AllI.B branch if not
ifne DAT.WrPr+DAT.WrEn
anda #1
endc
lda D,u get block flags
cmpa #RAMinUse is it just RAM in use?
puls D get new block needed
bne AllImErr branch if not RAM
subd #1 uncount allocated block
pshs D save it
AllI.B leax -1,X enough blocks?
bne AllI.A branch if not
ldx ,s++ get new blocks needed
beq AllI.E branch if none
AllI.C lda ,u+ get block flags
bne AllI.D branch if not free
leax -1,X count free block
beq AllI.E branch if enough
AllI.D cmpu D.BlkMap+2 end of map?
bcs AllI.C branch if not
AllImErr ldb #E$MemFul err: memory full
leas 6,s return scratch
stb 1,s save error code
comb set carry
puls PC,u,Y,X,D
AllI.E puls U,Y,X retrieve registers
AllI.F ldd ,Y++ get block number
cmpd #DAT.Free is it free block?
bne AllI.H branch if not
AllI.G lda ,u+ is this free block?
bne AllI.G branch if not
inc ,-U claim block
tfr U,D copy map ptr
subd D.BlkMap get block number
ifne DAT.WrEn
ora #(DAT.WrEn/256)
endc
std -2,y set image
AllI.H leax -1,x count block
bne AllI.F branch if more
ldx 2,s get process descriptor ptr
lda P$State,X
ora #ImgChg
sta P$State,X
clrb
puls PC,u,Y,X,D
***********************************************************
*
* Subroutine FreeHB
*
* Free High Block Service routine
*
* Input: U = registers ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: FreeHBlk
*
FreeHB ldb R$B,u get block count
ldy R$Y,u get DAT image ptr
bsr FreeHBlk get free high block
bcs FrHB10 branch if error
sta R$A,u return block number
FrHB10 rts
***********************************************************
*
* Subroutine FreeHBlk
*
* Search DAT image for highest free block
*
* Input: B = block count
* Y = DAT image ptr
*
* Output: A = beginning block number
*
* Data: none
*
* Calls: FreeBlk
*
FreeHBlk tfr b,a copy block count
FreeHB10 suba #DAT.BlCt+1 get negative beginning
nega make it positive
pshs X,D save beginning, count & register
ldd #-1 set next-try & limit
pshs D save them
bra FreeBlk
page
***********************************************************
*
* Subroutine FreeLB
*
* Free Low Block Service routine
*
* Input: U = registers ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: FreeLBlk
*
FreeLB ldb R$B,u get block count
ldy R$Y,u get DAT image ptr
bsr FreeLBlk get free low block
bcs FrLB10 branch if error
sta R$A,u return block number
FrLB10 rts
***********************************************************
*
* Subroutine FreeLBlk
*
* Search DAT image for lowest free block
*
* Input: B = block count
* Y = DAT image ptr
*
* Output: A = beginning block number
*
* Data: none
*
* Calls: FreeBlk
*
FreeLBlk lda #-1 set low beginning
pshs X,D save beginning, count & register
lda #1 set next-try increment
subb #DAT.BlCt+1 get negative limit
negb get limit block
pshs d save them
bra FreeBlk
page
***********************************************************
*
* Subroutine FreeBlk
*
* Search DAT image for free block
*
* Input: Y = DAT image ptr
* 0,s = next-try increment
* 1,s = search limit
* 2,s = beginning block number
* 3,s = block count
* 4,s:5,s = return address
*
* Output: A = beginning block number
* B = block count
*
* Data: none
*
* Calls: none
*
FreeBlk clra clear found count
ldb 2,s get beginning block number
addb 0,s add increment
stb 2,s save beginning
cmpb 1,s hit limit?
bne FreeB20 branch if not
ldb #E$MemFul err: memory full
stb 3,s save for return
comb set carry
bra FreeBXit
FreeB10 tfr A,B copy found count
addb 2,s add beginning block number
FreeB20 aslb shift for two-byte entries
ldx B,Y get next block image
cmpx #DAT.Free is it free?
bne FreeBlk branch if not
inca count block
cmpa 3,s found enough?
bne FreeB10 branch if not
FreeBXit leas 2,s return parameters
puls PC,X,D
page
***********************************************************
*
* Subroutine SetImage
*
* Set Process DAT Image
*
* Input: A = Beginning image block number
* B = block count
* X = Process Descriptor ptr
* U = New Image ptr
*
* Output: none
*
* Data: none
*
* Calls: none
*
SetImg ldd R$D,u get block number & count
ldx R$X,u get process ptr
ldu R$U,u get new image ptr
SetImage pshs U,Y,X,D save registers
leay P$DATImg,X get DAT image ptr
asla shift for two-byte entries
leay A,Y get image ptr
SetImg10 ldx ,u++ get new image
stx ,Y++ set process image
decb done?
bne SetImg10 branch if not
ldx 2,s get process descriptor ptr
lda P$State,X get process state
ora #ImgChg make image change
sta P$State,X update state
clrb clear carry
puls PC,u,Y,X,D
page
***********************************************************
*
* Subroutine DATLog
*
* Convert DAT image block number and block offset to
* logical address Service routine
*
* Input: U = registers ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: DATtoLog
*
DATLog ldb R$B,u get DAT image offset
ldx R$X,u get block offset
bsr DATtoLog convert it
stx R$X,u return logical address
clrb clear carry
rts
***********************************************************
*
* Subroutine DATtoLog
*
* Input: B = DAT Image offset
* X = Block offset
*
* Output: X = Logical address
*
* Data: none
*
* Calls: none
*
DATtoLog pshs X,D save registers
aslb shift image to block offset
aslb
ifge DAT.BlSz-2048
aslb
ifge DAT.BlSz-4096
aslb
endc
endc
addb 2,s combine nibbles
stb 2,s
puls PC,X,D
page
***********************************************************
*
* Subroutine FLDAXY
*
* Load A X, [Y] Service routine
*
* Input: U = registers ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: LDAXY
*
F.LDAXY ldx R$X,u get block offset
ldy R$Y,u DAT get DAT image ptr
bsr LDAXY
sta R$A,u return byte
clrb
rts
***********************************************************
*
* Subroutine LDAXY
*
* Load A register from X offset of Y block
*
* Input: X = Block offset
* Y = DAT Image ptr
*
* Output: A = [X,Y]
*
* Data: none
*
* Calls: none
*
LDAXY equ *
ifge DAT.BlSz-4096
pshs cc save masks
lda 1,Y get block number
orcc #IntMasks set interrupt masks
sta DAT.Regs set block zero
lda 0,X get byte
clr DAT.Regs reset block zero
puls pc,cc
else
pshs x,b,cc
ldd 0,y get block number
orcc #IntMasks set interrupt masks
std DAT.Regs set block zero
lda 0,X get byte
ldx #$0000+DAT.WrEn
stx DAT.Regs reset block zero
puls pc,x,b,cc
endc
page
***********************************************************
*
* Subroutine LDAXYP
*
* Load A register from X offset of Y block; post increment
*
* Input: X = Block offset
* Y = DAT Image ptr
*
* Output: A = [X,Y]
* X,Y updated
*
* Data: none
*
* Calls: AdjImg
*
LDAXYP equ *
ifge DAT.BlSz-4096
lda 1,y get DAT block image
pshs cc save masks
orcc #IntMasks set interrupt masks
sta DAT.Regs set block zero
lda ,x+ get byte
clr DAT.Regs reset block zero
puls cc reset interrupt masks
else
pshs x,b,cc
ldd 0,y get DAT block image
orcc #IntMasks set interrupt masks
std DAT.Regs set block zero
lda 0,x
ldx #$0000+DAT.WrEn
stx DAT.Regs reset block zero
puls x,b,cc
leax 1,x
endc
bra AdjImg adjust image
***********************************************************
*
* Subroutine AdjImg
*
* Adjust offset to within block range
*
* Input: X = Block offset
* Y = DAT Image ptr
*
* Output: X,Y updated
*
* Data: none
*
* Calls: none
*
AdjImg10 leax -DAT.BlSz,x reduce offset
leay 2,y move image ptr
AdjImg cmpx #DAT.BlSz is offset in block range?
bcc AdjImg10 branch if not
rts
page
***********************************************************
*
* Subroutine FLDDDXY
*
* Load D D+X,[Y]] Service routine
*
* Input: U = registers ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: LDDDXY
*
F.LDDDXY ldd R$D,u get offset offset
leau R$X,u get ptrs ptr
pulu Y,X get ptrs
bsr LDDDXY get bytes
std R$D-R$U,u return bytes
clrb clear carry
rts
***********************************************************
*
* Subroutine LDDDXY
*
* Load D register from X+D offset of Y block
*
* Input: D = Address offset
* X = Block offset
* Y = DAT Image ptr
*
* Output: D = [D+X,Y]
*
* Data: none
*
* Calls: AdjImg, LDAXYP, LDAXY
*
LDDDXY pshs Y,X save registers
leax D,X add address offset
lbsr L0C6F
leay a,y
bsr LDAXYP get MSB
pshs a,cc
ldd ,y
orcc #IntMasks set interrupt masks
std DAT.Regs
ldb 0,x
ldx #$0000+DAT.WrEn
stx DAT.Regs reset block zero
puls pc,y,x,a,cc
page
***********************************************************
*
* Subroutine F.LDABX
*
* Load A 0,X from address space B
*
* Input: U = registers ptrs
*
* Output: Carry clear
*
* Data: none
*
* Calls: LDABX
*
F.LDABX ldb R$B,u get task number
ldx R$X,u get data ptr
lbsr LDABX call routine
sta R$A,u return data
rts
***********************************************************
*
* Subroutine F.STABX
*
* Store A 0,X in address space B
*
* Input: U = registers ptrs
*
* Output: Carry clear
*
* Data: none
*
* Calls: STABX
*
F.STABX ldd R$D,u get data & task number
ldx R$X,u get data ptr
lbra STABX
page
***********************************************************
*
* Subroutine Move
*
* Move Data service routine
*
* Input: U = Registers ptr
* R$A,u = Source Task number
* R$B,u = Destination Task number
* R$X,u = Source ptr
* R$Y,u = Byte count
* R$U,u = Destination ptr
*
* Output: carry clear
*
* Data: none
*
* Calls: Mover
*
Move ldd R$D,u get user D register
ldx R$X,u get user X register
ldy R$Y,u get user Y register
ldu R$U,u get user U register
*
* fall through to Mover
*
***********************************************************
*
* Subroutine Mover
*
* Move data from one task to another
*
* Input: A = Source Task number
* B = Destination Task number
* X = Source ptr
* Y = Byte count
* U = Destination ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: Mover00
*
Mover pshs u,y,x,b,a
leay 0,y zero byte count?
lbeq MoveNone
pshs y,b,a
ldu #DAT.Regs
lbsr L0C6F
leay a,u
pshs y,x
ldx $0E,s
lbsr L0C6F
leay a,u
pshs y,x
ldd #$0800
subd ,s
pshs b,a
ldd #$0800
subd $06,s
pshs b,a
ldx $08,s
leax >-$2000,x
ldu $04,s
leau >-$1800,u
L0BD4 pshs cc
orcc #IntMasks set interrupt masks
lda <$11,s
sta DAT.Accs
ldd [<$0B,s]
clr DAT.Accs
std >$FFB8
lda <$12,s
sta DAT.Accs
ldd [<$07,s]
clr DAT.Accs
std >$FFBA
ldd $0F,s
cmpd $01,s
bls L0BFF
ldd $01,s
L0BFF cmpd $03,s
bls L0C06
ldd $03,s
L0C06 cmpd #$0040
bls L0C0F
ldd #$0040
L0C0F std $0D,s
lsra
rorb
tfr d,y
bcc L0C1F
lda ,x+
sta ,u+
leay ,y
beq L0C27
L0C1F ldd ,x++
std ,u++
leay -$01,y
bne L0C1F
L0C27 ldy D.SysDAT
ldd <$38,y
std >$FFB8
ldd <$3A,y
std >$FFBA
puls cc
ldd $0E,s
subd $0C,s
beq L0C69
std $0E,s
ldd ,s
subd $0C,s
bne L0C51
ldd #$0800
leax >-$0800,x
inc $0B,s
inc $0B,s
L0C51 std ,s
ldd $02,s
subd $0C,s
bne L0C64
ldd #$0800
leau >-$0800,u
inc $07,s
inc $07,s
L0C64 std $02,s
lbra L0BD4
L0C69 leas <$10,s
MoveNone clrb
puls pc,u,y,x,b,a
* Get page number from task address
*
* Input: X = task address
*
* Output: A = page number
* X = address in page
*
L0C6F pshs b
tfr x,d
anda #$F8 mask all but page #
beq L0C7F
exg d,x
anda #$07 mask high bits of address
exg d,x
lsra find physical page
lsra
L0C7F puls pc,b
LDABX andcc #^Carry clear carry
pshs u,x,b,cc
bsr L0C6F
ldu #DAT.Regs
orcc #IntMasks set interrupt masks
stb DAT.Accs switch tasks
ldu a,u
ldb D.SysTsk get system task
stb DAT.Accs switch tasks
stu DAT.Regs
lda 0,X get data byte
ldu #$0000+DAT.WrEn
stu DAT.Regs
puls pc,u,x,b,cc
STABX andcc #^Carry clear carry
pshs u,x,b,a,cc
bsr L0C6F
ldu #DAT.Regs
orcc #IntMasks set interrupt masks
stb DAT.Accs switch tasks
ldd a,u
ora #$02 activate write-enable
tfr d,u
ldb D.SysTsk get system task
stb DAT.Accs switch tasks
lda 1,s
stu DAT.Regs load block into segment #0
sta 0,X store data byte
ldu #$0000+DAT.WrEn
stu DAT.Regs
puls pc,u,x,b,a,cc
LDBBX andcc #$FE
pshs u,x,a,cc
bsr L0C6F
ldu #DAT.Regs
orcc #IntMasks set interrupt masks
stb DAT.Accs
ldu a,u
ldb D.SysTsk
stb DAT.Accs
stu DAT.Regs
ldb ,x
ldu #$0000+DAT.WrEn
stu DAT.Regs
puls pc,u,x,a,cc
page
***********************************************************
*
* Subroutine AllTsk
*
* Process Task allocation service routine
*
* Input: U = registers ptr
* R$X,y = Process ptr
*
* Output: Carry clear if successful; set otherwise
*
* Data: none
*
* Calls: AllPrTsk
*
AllTsk ldx R$X,u get process ptr
*
* fall through to AllPrTsk
*
***********************************************************
*
* Subroutine AllPrTsk
*
* Allocate process task number
*
* Input: X = Process ptr
*
* Output: carry clear if successful; set otherwise
*
* Data: none
*
* Calls: ResvTask, SetPrTsk
*
AllPrTsk ldb P$Task,x get process task number
bne AllPrT10 branch if assigned
bsr ResvTask get free DAT
bcs AllPrXit branch if none
stb P$Task,x set process task number
bsr SetPrTsk set process task
AllPrT10 clrb clear carry
AllPrXit rts
page
***********************************************************
*
* Subroutine DelTsk
*
* Deallocate Process Task service routine
*
* Input: U = Registers ptr
* R$X,y = Process Descriptor ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: DelPrTsk
*
DelTsk ldx R$X,u get process ptr
*
* fall through to DelPrTsk
*
***********************************************************
*
* Subroutine DelPrTsk
*
* Deallocate Process Task number
*
* Input: X = Process Descriptor ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: RelsTask
*
DelPrTsk ldb P$Task,x get process task
beq AllPrXit branch if none
clr P$Task,x clear process task
bra RelsTask release task number
page
***********************************************************
*
* Subroutine ChkPrTsk
*
* Update process task in DAT image has changed
*
* Input: X = Process ptr
*
* Output: A = Process state
*
* Data: none
*
* Calls: SetPrTsk
*
ChkPrTsk lda P$State,x get process state
bita #ImgChg has DAT image changed?
bne SetPrTsk branch if so
rts
page
***********************************************************
*
* Subroutine SetTsk
*
* Set task DAT registers service routine
*
* Input: U = Registers ptr
* R$X,y = Process Descriptor ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: SetPrTsk
*
SetTsk ldx R$X,u get process ptr
*
* fall through to SetPrTsk
*
***********************************************************
*
* Subroutine SetPrTsk
*
* Set Process Task DAT registers
*
* Input: X = Process Descriptor ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: none
*
SetPrTsk lda P$State,X
anda #^ImgChg
sta P$State,X
andcc #^Carry clear carry
pshs U,Y,X,D,CC
ldb P$Task,X
leax P$DATImg,X
ldy #DAT.ImSz/2
ldu #DAT.Regs
orcc #IntMasks set interrupt masks
stb DAT.Accs
L0D2B ldd ,x++
ora #$02 Turn on write-enable
std ,u++
leay -1,y
bne L0D2B
ldb D.SysTsk
stb DAT.Accs
puls pc,u,y,x,b,a,cc
***********************************************************
*
* Subroutine ResTsk
*
* Reserve Task Number
*
* Output: B = New task number
*
* Calls: ResvTask
*
ResTsk bsr ResvTask
stb R$B,u set task number
rts
* Find free task and reserve it
ResvTask pshs x
ldb #$02
ldx D.Tasks
ResTsk10 lda B,X
beq ResTsk20
incb
cmpb #DAT.TkCt Last task slot?
bne ResTsk10 ..yes
comb
ldb #E$NoTask err: no tasks
bra ResTsk30
ResTsk20 inc b,x reserve task
orb D.SysTsk set selected bits
clra clear carry
ResTsk30 puls PC,X
***********************************************************
*
* Subroutine RelsTask
*
* Release Task number
*
* Input: B = Task number
*
* Output: none
*
* Data: D.Tasks
*
* Calls: none
*
RelTsk ldb R$B,u get task number
RelsTask pshs x,b save registers
ldb D.SysTsk get selected bits
comb make mask
andb 0,s clear selected bits
beq RelTsk10 branch if system task
ldx D.Tasks get task number table
clr B,X release task number
RelTsk10 puls PC,x,b
page
***********************************************************
*
* Clock Tick Subroutine
*
* Update timed-sleep processes' time, make active if
* time expires; update current process's time slice
*
* Input: none
*
* Output: Carry clear
*
* Data: D.SProcQ, D.Slice, D.TSlice, D.Proc
*
* Calls: ActvProc
*
Tick ldx D.SProcQ get sleep queue ptr
beq Slice branch if queue empty
lda P$State,X get process state
bita #TimSleep timed-sleep state?
beq Slice branch if not
ldu P$SP,X get process stack ptr
ldd R$X,u get sleep time
subd #1 count tick
std R$X,u update time
bne Slice branch if not expired
Tick.A ldu P$Queue,X get next queue ptr
bsr ActvProc make process active
leax 0,u copy next queue ptr
beq Tick.B branch if none
lda P$State,X get process state
bita #TimSleep timed-sleep state
beq Tick.B branch if not
ldu P$SP,X get process stack ptr
ldd R$X,u get sleep time
beq Tick.A branch if expired
Tick.B stx D.SProcQ update queue ptr
*
* fall through to Slice
*
Slice dec D.Slice Count tick
bne Slic.a Branch if slice not over
inc D.Slice reset to last tick of slice
ldx D.Proc get current process ptr
beq Slic.a branch if none
lda P$State,X get process state
ora #TIMOUT set time-out flag
sta P$State,X update state
Slic.a clrb clear carry
rts
page
***********************************************************
*
* Subroutine AProc
*
* Put process in Active Process Queue Service routine
*
* Input: U = Registers ptr
*
* Output: Carry clear
*
* Data: none
*
* Calls: ActvProc
*
AProc ldx R$X,u get process ptr
*
* fall through to ActvProc
*
***********************************************************
*
* Subroutine ActvProc
*
* Put process in Active Process Queue
*
* Input: X = Process Descriptor ptr
*
* Output: Carry clear
*
* Data: D.AProcQ
*
* Calls: none
*
ActvProc clrb clear carry
pshs U,Y,X,CC save registers
lda P$Prior,X get new process priority
sta P$AGE,X set queue age
orcc #IRQMask+FIRQMask set interrupt masks
ldu #D.AProcQ-P$Queue fake process ptr
bra ActvPr30
ActvPr10 inc P$AGE,u get process queue age
bne ActvPr20 branch if not high
dec P$AGE,u update age
ActvPr20 cmpa P$AGE,u is new higher priority
bhi ActvPr40 branch if so
ActvPr30 leay 0,u copy process ptr
ActvPr40 ldu P$Queue,u get next process ptr
bne ActvPr10 branch if more
ldd P$Queue,Y get next process ptr
stx P$Queue,Y attach new to previous
std P$Queue,X attach previous to new
puls PC,u,Y,X,CC
page
***********************************************************
*
* User Hardware Interrupt Service Routine
*
* Handle state/stack, call polling routine, & return
*
* Input: S = value of stack after interrupt
*
* Output: none directly
*
* Data: D.Proc, D.SysSvc, D.SWI2, D.SysIRQ, D.IRQ, D.Poll
*
* Calls: [D.Poll], UIRQRet
*
UserIRQ ldx D.Proc get process ptr
sts P$SP,x save stack ptr
lds D.SysStk move to system stack
ldd D.SysSvc get system service routine
std D.XSWI2 set SWI 2 vector
ldd D.SysIRQ get system interrupt routine
std D.XIRQ set IRQ vector
jsr [D.SvcIRQ] call IRQ service
bcc UserRet branch if serviced
ldx D.Proc get process ptr
ldb P$Task,X get process task number
ldx P$SP,x get process stack
lbsr LDABX get condition codes
ora #IntMasks set interrupt masks
lbsr STABX update condition codes
*
* fall through to UserRet
*
***********************************************************
*
* Subroutine UserRet
*
* Return to User process after interrupt
*
* Input: A = Process State flags
* X = Process Descriptor ptr
*
* Output: none
*
* Data: none
*
* Calls: NextProc (@ CurrProc), ActvProc, NextProc
*
UserRet orcc #IntMasks set interrupt masks
ldx D.Proc get process ptr
ldu P$SP,x get process stack ptr
lda P$State,x get process state
bita #TimOut time slice over?
beq CurrProc branch if not
UsrRet.a anda #^TimOut clear time-out flag
sta P$State,X update state
lbsr DelPrTsk deallocate process task
GoActv bsr ActvProc put in active process queue
*
* fall through to NextProc
*
***********************************************************
*
* Subroutine NextProc
*
* Start next process in Active Process Queue
*
* Input: none
*
* Output: does not return to caller
*
* Data: D.SysPrc, D.Proc, D.AProcQ
*
* Calls: SvcRet
*
NextProc ldx D.SysPrc get system process ptr
stx D.Proc set current process
lds D.SysStk move to system stack
andcc #^IntMasks clear interrupt masks
bra NextPr20
NextPr10 cwai #^IntMasks wait with clear masks
NextPr20 orcc #IntMasks set interrupt masks
ldy #D.AProcQ-P$Queue get ptr proc queue
bra NextPr40 enter search loop
NextPr30 leay 0,x move ptr
NextPr40 ldx P$Queue,Y get ptr to next proc
beq NextPr10 branch if none
lda P$State,X get process state
bita #Suspend is it suspended?
bne NextPr30 bra if so
ldd P$Queue,X get remainder of queue
std P$Queue,Y update queue ptr
stx D.Proc set current process
lbsr AllPrTsk allocate process task number
bcs GoActv branch if none available
lda D.TSlice get ticks/slice
sta D.Slice reset slice tick count
ldu P$SP,X get process stack ptr
lda P$State,X get process state flags
bmi SysRet branch if system state
CurrProc bita #Condem is process condemmed?
bne KillProc branch if so
lbsr ChkPrTsk update process task
ldb P$Signal,X is signal waiting?
beq CurrPr25 branch if not
decb is it wake signal?
beq CurrPr20 branch if so
leas -R$Size,s get scratch
leau 0,s get local stack
lbsr GetRegs get current stack
lda P$Signal,X get signal
sta R$B,u pass to process
ldd P$SigVec,X get intercept entry
beq KillProc branch if none
std R$PC,u get program counter
ldd P$SigDat,X get data ptr
std R$U,u
ldd P$SP,X get process stack
subd #R$Size make room for intercept
std P$SP,X update stack ptr
lbsr PutRegs copy new stack
leas R$Size,s Reset stack
ldu P$SP,X get process stack ptr
clrb
CurrPr20 stb P$Signal,X clear signal code
CurrPr25 ldd D.UsrSvc get user service routine
std D.XSWI2 get SWI2 vector
ldd D.UsrIRQ get user interrupt routine
std D.XIRQ set IRQ vector
lbra SvcRet
KillProc lda P$State,x get process state
ora #SysState set system state
sta P$State,X update process
leas P$Stack,X move stack
andcc #^IntMasks clear interrupt masks
ldb P$Signal,X get lethal signal code
clr P$Signal,X clear signal
OS9 F$Exit terminate process
page
page
***********************************************************
*
* System Hardware Interrupt Service Routine
*
* Call Device Polling routine & return
*
* Input: S = value of stack after interrupt
*
* Output: non directly
*
* Data: D.Poll
*
* Calls: [D.Poll]
*
SysIRQ equ *
jsr [D.SvcIRQ] call service routine
bcc SysIRQ20 branch if serviced
ldb R$CC,s get condition codes
orb #IntMasks set interrupt masks
stb R$CC,s update masks
SysIRQ20 rti
***********************************************************
* Routine SysRet
*
* Return to system after service request
*
* Input: U = reqisters ptr
*
* Output: does not return to caller
*
* Data: D.SysPrc
*
* Calls: SvcRet
*
SysRet ldx D.SysPrc get system process ptr
lbsr ChkPrTsk get task
leas 0,u move stack ptr
rti start process
***********************************************************
*
* In-System IRQ Transfer
*
GoPoll jmp [D.Poll] call polling routine
***********************************************************
*
* Subroutine IOPoll
*
IOPoll orcc #Carry set carry
rts
***********************************************************
*
* Routine DATInit
*
* The DAT register map starts at $FF80 and uses 2 KB blocks. It therefore
* has 32 sections mapped with a 16 bit word. I.e. the DAT RAM is located
* at the address range $FF80 to $FFBF. In the 16 bit word, the bottom 9 bits
* selects a 2 KB block. Bit 9 is write-enable and must be set for RAM.
*
DATInit clra
tfr a,dp
ldu #DAT.MMU0+8 point to last MMU key value register + 1
ldb #7 initialize value
KVInit stb ,-u write unique value into each key value reg
decb
bne KVInit
leay ,-u Make y = FFC0
* Map top 4 KB of ROM to $F800 and $F000
ldx #$1FF
ldb #2
L0ECA stx ,--y
leax -1,x
decb
bne L0ECA
* Devices
ldx #DAT.WrEn+$140
stx ,--y
ldx #DAT.WrEn+$150
stx ,--y
* Declare unused memory blocks
ldb #Dat.BlCt-ROMCount-RAMCount-1
ldx #DAT.Free
L0EE0 stx ,--y
decb
bne L0EE0
* Map lowest 3 blocks of RAM to $1000, $0800 and $0000
ldd #DAT.WrEn+2
L0EE8 std ,--y
decb
bpl L0EE8
clra
sta ,u Let MMU #0 go
lbra COLD go to cold start
***********************************************************
*
* Service Request Return
*
* Switch to user's address space
*
* Input: X = Process Descriptor ptr
* U = Process Stack ptr
*
* Output: does not return
*
* Data: none
*
* Calls: none
*
SvcRet ldb P$Task,x get task number
orcc #IntMasks set interrupt masks
stb DAT.Task switch to task
leas 0,u move stack ptr
ldb #2
stb DAT.Fuse delay switching to user task until rti is executed
rti
PassSWI ldb P$Task,x get process task
stb DAT.Task switch to task
ldb #3
stb DAT.Fuse delay switching to user task until jmp is executed
jmp 0,u go to user routine
SWI3RQ orcc #IntMasks set interrupt masks
ldb #D.SWI3 get direct page offset
bra Switch
SWI2RQ orcc #IntMasks set interrupt masks
ldb #D.SWI2 get direct page offset
bra Switch
FIRQ ldb #D.FIRQ get direct page offset
bra Switch
IRQ orcc #IntMasks set fast interrupt masks
ldb #D.IRQ get direct page offset
Switch equ *
lda #SysTask get system task number
sta DAT.Task set system memory
clra
tfr a,dp clear direct page register
tfr d,x copy direct page ptr
jmp [0,x] go through vector
SWIRQ ldb #D.SWI get direct page offset
bra Switch
NMIRQ ldb #D.NMI get direct page offset
bra Switch
page
emod
OS9End equ *
fcb $39,$39,$39,$39,$39,$39,$39
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
fcb $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
offset set $FFE0-*
***********************************************************
*
* System Interrupt Psuedo-Vectors
*
HdlrVec fdb Tick+offset
fdb UserSWI3+offset
fdb UserSWI2+offset
fdb offset
fdb UserIRQ+offset
fdb UserSWI+offset
fdb offset
fdb offset
***********************************************************
*
* System Interrupt Vectors
*
fdb offset
fdb SWI3RQ+offset
fdb SWI2RQ+offset
fdb FIRQ+offset
fdb IRQ+offset
fdb SWIRQ+offset
fdb NMIRQ+offset
fdb DATInit+offset
ROMEnd equ *
end