
 lib environment
 sttl System Initialization
 pag
 name Sysinit

*
* All routines in this file are called once during
* main system initialization.  Their prime function
* is to setup the correct system table structure.
*
* Note:  These routines, along with the user provided
* machine initialization routine "mach" may reside at
* logical addresses $B000-$B7FF.
*

*
* This is the system entry point.  All of the once
* called system init routines are called from here.
*

uniflex seti
 lds #(USRLOC<<12)+USTKO set up stack pointer
 clr kernal set "system" mode
 lbsr syscon init system console
 lbsr mchint init hardware stuff
 lbsr spagin set up system page
 lbsr makmem go find all memory
 lbsr stinit set up system tables
 lbsr tskzer set up task 0
 lbsr clinit init the character buffers
 lbsr bfinit make the buffer cache
 lbsr fninit init fdn lists
 lbsr ttinit init terminal tables
 lbsr tminit init the timeout structures
 lbsr sirint init the sir block table
 lbsr endinit clean up initialization
 clri
 lbsr izswd init the swap device and space
 lbsr signon issue sign-on message
 lda corcnt how much core?
 cmpa #24 less than 96k left?
 bhi unifl4
 lda #12 set max mem value for small system
 sta smxm
unifl4 clri
 lbsr srinit initialize the root sir
 ldd stmz get time zone from config table
 std tzone set in ram
 lda sdlt get dlst flag
 sta dstflg set in ram
 ldd srtd get root device number
 ldy #1 set up root fdn
 lbsr UFE_001 asnfdn assign an fdn entry
 lda fstat,x get status
 anda #!FLOCK unlock the fdn
 sta fstat,x
 stx rtdir save the root fdn
 ldd srtd get root device number
 ldy #1 set up root fdn
 lbsr UFE_001 asnfdn assign the fdn
 lda fstat,x get the status
 anda #!FLOCK unlock the fdn
 sta fstat,x save the new status
 stx ucrdir save current dir fdn
 ldd unidat+2 get internal date
 pshs d save it
 ldd unidat get rest of it
 pshs d
 ldd unidat2+2 get boot date
 subd 2,s get difference
 std 2,s save result
 ldd unidat2
 sbcb 1,s
 sbca 0,s
 std 0,s save result
 bne unifl6 error?
 leas 2,s
 puls d get lo result
 cmpd #4 less than 4?
 bls unifl7
unifl6 ldx mtable point to mount table
 ldx msir,x get sir of root
* tst unikey key byte zero?
* beq unifl7
 ldd #0 zero out swap space!
 std sswpsz,x this is nasty!?
 ldx #sviolm point to message
 lbra blowup good bye!
unifl7 seti
 lbsr clkinz go start clock
 ldb sysmap+USRLOC get user segment
 lda BLKHOL set up no mem!
 std umem+NBLKS-2 save in user block
 clri
 lbsr UFE_005 lfork go fork task 1
 cmpd #1 are we task 0 or 1?
 lbeq strtup if 1, go startup
 ldd ROMmap set up ROM map registers
 std umem+NBLKS-2

* temp *

 seti
 ldx tsktab point to first task
 leax TSKSIZ,x point to task 1
 lda tsutop,x get user page
 pshs a save it
 lbsr UFE_008 mapxbf map in this page
 puls a reset page number
 sta XBUFFR|((umem+USRLOC)&$FFF) set in mem map
 clri
 jmp UFE_007 swpguy go start swapper


*
* clinit
*
* Initialize character buffer lists.  This routine
* is only called once at startup time.
*

clinit ldx cbuffr point to clist
 ldb schl set count
 stx cfreel set head pointer
clini2 leay CBSIZE,x
 sty 0,x set fwd link
 tfr y,x advance to next
 decb
 bne clini2
 lda schl get buffer count
 suba #2 dec by 2
 sta lcbuf set max count
 clra make d=0
 std -CBSIZE,x clear last link
 clr cbufct
 rts all done!

*
* ttinit
*
* Init the tty tables and queues.
*

ttinit ldy ttqtab point to q tables
 ldb strm get terminal count
 lda #AWORD init word configuration byte
 ldx ttytab point to tty table
ttini2 sty tqin,x set input q
 leay 5,y get next q
 sty tqproc,x set pr q
 leay 5,y set next q
 sty tqout,x set output q
 leay 5,y get next q
 sta tbaud,x set conf word
 leax TTYSIZ,x next tty entry
 decb dec the count
 bne ttini2 repeat?
 rts return

 pag
*
* bfinit
*
* Initialize the io buffer lists.  Both the free
* list and the device lists are setup.
*

bfinit lbsr makbuf make up the buffer list
 ldx #buflst point to free list header
 bsr dtinit init it
 stx dtqfl,x set q pointers
 stx dtqbl,x
 lda siob get total buffer count
 pshs a save as count
 ldy hdrtab point to buffer headers
bfini2 bsr hdinit init a buffer header
 leay HDRSIZ,y move to next header
 dec 0,s dec the count of buffers
 bne bfini2 repeat til all init
 puls a clean up stack
 lda #BLKDEV get # block devices
 beq bfini6 jump if none
 pshs a
 ldy #blktab point to block device table
bfini4 ldx blktpt,y get device table address
 bsr dtinit init the device table
 leay BLKSIZ,y move to next device
 dec 0,s dec count
 bne bfini4 go initialize next table
 puls a clean up stack
bfini6 rts return


 pag

*
* hdinit
*
* Initialize an io buffer header.  Set the list
* pointers so header is both in the free list and
* in the NODEV list.  The buffer address is also
* assigned to the header here.
*

hdinit pshs y save header ptr
 lda #HDRSIZ get header size
hdini2 clr 0,y+ clear all header info
 deca
 bne hdini2
 puls y reset hdr pointer
 ldx #buflst point to free list
 ldd bffbl,x link buffer into list
 std bffbl,y
 sty bffbl,x
 stx bfffl,y
 tfr d,x
 sty bfffl,x
 ldx #buflst point to NODEV list
 lbsr UFE_006 reasoc link in this buffer
 lbsr instbf install buffer address
 ldd #NODEV set device number
 std bfdvn,y
 rts return


*
* dtinit
*
* Initialize a device table.  The table is cleared
* except for the device list pointers are set.
*

dtinit ldd #0 get zero word
 std dtbusy,x
 std dtspr,x
 std dtqfl,x clear q pointers
 std dtqbl,x
 stx dtdfl,x set device chain ptrs
 stx dtdbl,x
 rts return

 pag

*
* fninit
*
* Initialize the fdn free and busy lists.  The busy
* list is set to empty, and all fdn table entries
* are put in the free list.
*

fninit ldd #0 init the busy list
 std fdnbsy set it empty
 ldx #fdnfre get free list
 ldb sfdn get fdn count
 ldy fdntab point to fdn table
fnini2 sty ffwdl,x set fwd link
 tfr y,x mark path
 leay FDNSIZ,x point to next entry
 decb dec the count
 bne fnini2 finished yet?
 clra set 0 link
 std ffwdl,x to mark list end
 stx fdnfre+2 set back link
 rts return

*
* sirint
*
* Initialize the blocks used for sir info.
* They are simply linked into a list headed
* by 'fstsir'.
*

sirint lda smnt get mount count
 ldx fstsir get start of table
sirin2 leay 512,x bump to next
 sty 0,x set fwd link
 deca dec the count
 beq sirin4 finished?
 tfr y,x advance to next entry
 bra sirin2 repeat
sirin4 ldd #0 set null link
 std 0,x
 stb updlck clear out lock
 rts return

 pag

*
* stinit
*
* Build all system tables.  Memory is added to the
* system address space as needed.  If too much
* memory is required, a system blowup will occur.
*

stinit ldx #sysmap+STABPG point to sys mem map
 stx syspnt save position
 ldx #STBEG point to begin of tables
 lda stxt set up text table
 ldb #TXSSIZ entry size
 lbsr nspage check for new page
 stx txttab set table begin
 lbsr clrstb clear the table
 lda stim set up time out table
 ldb #TMSSIZ
 lbsr nspage
 stx timtab set table begin
 lbsr clrstb clear the table
 lda smnt get mount table size
 ldb #MSTSIZ get entry size
 lbsr nspage
 stx mtable set table begin
 lbsr clrstb clear the table
 lda stsk get task size
 ldb #TSKSIZ
 lbsr nspage
 stx tsktab set begin
 sty tskend set end
 lbsr clrstb clear the table
 lda siob get buffer count
 ldb #HDRSIZ get header size
 lbsr nspage
 stx hdrtab set begin point
 jsr clrstb clear table
 lda strm get terminal count
 ldb #TTYSIZ siae of tty structure
 lbsr nspage
 stx ttytab set table begin
 jsr clrstb clear out table
 lda strm get terminal count
 ldb #5*3 q header count
 lbsr nspage
 stx ttqtab save table begin
 bsr clrstb clear table
* -- Align pointer (X) to CBSIZE boundary
* -- Checking to see if this alignment crosses a page boundary
 pshs x save current address
 tfr x,d now must find next
 addd #CBSIZE-1 CBSIZE byte boundary
 andb #!(CBSIZE-1)
 subd ,s++ compute adjustment size
 lbsr nspag0 did we cross seg boundary?
 leax 0,y
 stx cbuffr set buffer begin
 lda schl get character list count
 ldb #CBSIZE
 lbsr nspage
 bsr clrstb clear out buffers
 lda sfdn get fdn table count
 ldb #FDNSIZ get entry size
 lbsr nspage
 stx fdntab set table begin
 bsr clrstb clear the table
 lda sfdn set up open file table
 ldb #FSTSIZ
 lbsr nspage
 stx ofiles set table begin
 bsr clrstb clear table
 lda slok get lock entry count
 ldb #LKTSIZ get entry size
 lbsr nspage
 stx lkbeg set table start
 sty lkend set table end
 bsr clrstb clear out table
 lda #DPLCNT get buffer count
 ldb #DPLSIZ set buffer size
 jsr nspage get page
 stx dpoolb set pool begin
 sty dpoole set pool end
 bsr clrstb zero out table
 lda MAXMAP set map size
 beq 00f
 ldb #2 set entry size
 jsr nspage get memory space
 stx maptbl set table start
 bsr clrstb zero table
 ldd tsktab
 std [maptbl] set entry 0 to busy
00 lda stsk get task count
 ldb #8 set entry size
 jsr nspage make table
 stx exctbl mark table start
 bsr clrstb zero table
 lda smnt get mount count
 clrb calc table size
 asla which is smnt*512
 lbsr nspag0 extend sys table space
 stx fstsir set table start


*
* clrstb
*
* Clear a system table.  X points to beginning of
* table, Y marks the end.
*

clrstb pshs y save end ptr
clrst2 clr 0,x+ clear a byte
 cmpx 0,s end of table?
 bne clrst2
 puls y,pc return

 pag

*
* srinit
*
* Initialize the root sir.  Essentially all that
* is done here is to read in the root devices
* sir into a system buffer.
*

srinit clr uerror clear out error
 ldd srtd get root device number
 pshs d save it
 ldb #BLKSIZ set up entry size
 mul calculate block position
 ldx #blktab point to table
 leax d,x point to entry
 puls d get the device
 jsr [blkopn,x] call open routine
 ldy #0 read in the sir block
 ldd srtd set root device
 ldx #1 its in block 1
 lbsr rdbuf read the block
 pshs y save the buffer
 lbsr UFE_002 asnsir get an sir block
 pshs x save buffer
 lda uerror any errors?
 bne srini6 blowup if so
 ldx 2,s get buffer
 ldy 0,s get sir pointer
 ldu #0 set buffer offset
 ldd #512 set byte count
 lbsr cpybts copy buffer to sir block
 ldy 2,s get 1st buffer
 lbsr freebf free it up
 puls y get buffer
 leas 2,s clean up stack
 ldd #0 clear sir flags
 std supdt,y update cleared
 std slkfr,y clear locks
 ldd sutime,y get system time
 std stimh
 ldd sutime+2,y
 std stiml
 ldx mtable point to mount table
 sty msir,x save sir pointer
 ldd srtd get root dev number
 std mdevic,x save device number
 rts return
srini6 ldx #rterms point to string
 lbra blowup blowup system


 pag

*
* tminit
*
* Initialize the system timeout structures.  A linked
* list of entries is made as the available list
* 'tmavl' and the active list is nulled ('tmhead').
*

tminit ldx timtab point to table
 ldb stim get timeout count
 pshs b save counter
 stx tmavl set list head
tmini2 stx tmlst set end of list
 leax TMSSIZ,x bump to next entry
 stx -TMSSIZ,x set forward link
 dec 0,s dec the count
 bne tmini2 finished?
 puls b reset stack
 clra make d=0
 std -TMSSIZ,x set last link to 0
 std tmhead set active list empty
 rts return


 pag

*
* nspage
*
* Check if a system table is crossing a segment
* boundary.  If so, allocate a new segment to
* the system address space for the table.
*

nspage mul calculate table size
nspag0 leay d,x point to end of table
 tfr x,d
 anda #$f0 get segment number
 pshs a
 tfr y,d
 anda #$f0 also ends segment number
nspag2 cmpa 0,s are they the same?
 beq nspag4
 cmpa #SYSTXT<<4 table overflow?
 bhs nspag6
 pshs x,y,a save pointers
 lbsr UFE_004 getpag get a new segment
 beq nspag8 mem overflow?
 ldx syspnt point to system mem map
 stb 0,x+ save new segment
 stx syspnt
 pshs b save segment
 tfr x,d calculate offset into table
 subd #sysmap
 decb
 tfr b,a
 puls b get segment number
 lbsr UFE_009 mapspg map in new segment
 puls x,y,a reset pointers
 puls b
 addb #$10 bump page number
 pshs b
 bra nspag2
nspag4 puls a,pc return
nspag6 ldx #sysofl point to message
nspag7 lbra blowup blow up system!
nspag8 ldx #memofl point to message
 bra nspag7


 pag

*
* spagin
*
* Initialize all system page variables.
*

 ifnc &A,'DEBUG'
spagin ldx #sbpag
spagi2 clr 0,x+ clear out system page
 cmpx #$e0 end of list?
 bne spagi2
 ldx #buflst clear out some more junk
spagi3 clr 0,x+
 cmpx #STBEG end of it?
 bne spagi3
 else
spagin ldx #SYSPAG<<12 point to start of vars
spagi2 clr 0,x+ zero out core
 cmpx #STBEG finished?
 bne spagi2
 endif
 ldx #irqhan set up interrupt vectors
 stx irqvec
 ldx NMIhan set up nmi
 beq 0f
 stx nmivec
0 ldx SWI2han set up swi2 handler
 beq 0f
 stx sw2vec
0 ldx #swi3han system call vector
 stx sw3vec save as swi3 vector
 ldx #swihan set up emt trap
 stx swivec set the vector
 ldx srtd set root device
 stx rtdev
 ldx sppd set pipe device
 stx pipdev
 ldx sswd get swap device
 stx swapdv
 ldx #change set change task vector
 stx chgvec save in memory
 lda schl get char buffer count
 suba #2 dec for max
 sta lcbuf remember max
 rts return

*
* makbuf
*
* Make the list of segments used by the buffer
* cache.  Leave the pointer to the list in
* 'systmp' and 'sbpag' should contain 0 on exit.
*

makbuf ldb siob get buffer count
 bne makbu1 is it zero?
 ldb #8 set default of 8
 bra makbu2
makbu1 cmpb #248 check for overflow
 bls makbu2
 ldb #248 this is max
makbu2 addb #7 make mod 8
 andb #!7
 stb siob corrected buffer count
 ldx #prcbuf use this buffer for list
 stx systmp mark beginning of list
 tfr b,a
makbu4 pshs x,a
 lbsr UFE_004 getpag get a memory segment
 puls x,a
 lbeq nspag8 error?
 stb 0,x+ save segment
 suba #8 dec count by 8 buffers
 bne makbu4 repeat til all allocated
 clr sbpag
 rts return



*
* tskzer
*
* Set up task #0.
*

tskzer ldx #ust point to user structure
 ldy #USTSIZ point to end of user
 lbsr clrstb clear out space
 ldx tsktab get first task slot
 lda sysmap+USRLOC get user block segment
 sta tsutop,x save in entry
 sta usrtop set user top page
 lda #1 set swap image size
 sta tssize,x
 lda #TRUN set status
 sta tsstat,x save it
 lda #TCORE|TLOCK|TSYSTM set modes
 sta tsmode,x save it
 lda #SWAPPR set high priority
 sta tsprir,x
 lda #$ff set default perms
 sta udperm
 stx utask save task pointer
 ldx #sysmap point to sysmap
 ldy #umem point to user map
 ldb #NBLKS set segment count
tskze4 lda 0,x+ copy sys map
 sta 0,y+
 decb dec the counter
 bne tskze4
 incb set up a 1
 stb usizes set stack size
 clr usized zero other sizes
 clr usizet
 rts return

 pag

*
* izswd
*
* Init the swap device and swap space
*

izswd ldd sswd get swap device
 pshs d save it
 ldb #BLKSIZ find device drivers
 mul
 ldx #blktab point to table
 leax d,x point to this guy
 puls d get device number
 jsr [blkopn,x] open device
 ldy #0 set block 1
 ldx #1
 ldd sswd get device
 jsr rdbuf read in block 1
 lda bfflag,y get error status
 bita #BFERR
 lbne UFE_003 doswa9 error?
 pshs y save buffer
 ldx 0,s point to buffer
 ldy #swpbeg point to data space
 ldd #5 set byte count
 ldu #sswpbg set buffer offset
 jsr cpybts copy data from buffer
 puls y get buffer
 jsr freebf free it
 ldd swpsiz get swap size
 beq izswd8 if zero - blowup!
 lsra calc number of 4K blocks
 rorb
 lsra
 rorb
 lsra
 rorb 8 blocks per 4K
 std swpsiz save new size
 beq izswd8 if zero - blowup!
 ldx #swpmap point to swap map
 leax SMAPSZ-4,x set end pointer
 stx swpend mark end
 ldd #1 set up swap table
 std swpmap
 ldd swpsiz set size
 std swpmap+2
 jsr badswp remove any bad swap blocks
 rts return
izswd8 ldx #noswdv set error
 jmp blowup Bye!

 pag
*
* badswp
*
* Remove sections of the swap space which appear in the
* file .badblocks on the swap device.  NOTE: As the code
* is written now - the swap device must be the same as
* the root device.
*

badswp ldd sswd get swap device number
 cmpd srtd same as root?
 bne 5f if not - exit
 ldy #2 set fdn 2 (badblocks fdn #)
 jsr UFE_001 asnfdn get the fdn
 cmpx #0 was it found?
 beq 5f if not - exit
 pshs x save fdn pointer
 ldd #0
 pshs d set up block counter
 pshs d
 clr umaprw set for read mode for mapfil
1 ldy 0,s get block number
 ldx 2,s
 ldu 4,s get fdn
 jsr UFE_012 mapfil get physical block number
 beq 4f if eq - end of badblocks file
 tfr y,d get hi block part
 cmpb swpbeg check for swap block
 blo 3f
 bhi 2f
 cmpx swpbeg+1 check rest of block
 blo 3f
2 jsr rmvswb remove the swap block
3 ldd 2,s bump block number by 1
 addd #1
 std 2,s
 bne 1b
 inc 1,s
 bra 1b repeat
4 leas 4,s clean stack
 puls x get fdn
 jmp UFE_013 frefdn free the fdn
5 rts return


*
* rmvswb
*
* Remove the swap segment which contains the block in Y:X.
*

rmvswb pshs x
 pshs y save block on stack
 ldd 2,s subtract swap address bias
 subd swpbeg+1
 std 2,s
 lda 1,s
 sbca swpbeg
 sta 1,s
 ldb #3 set count for shift
1 lsr 1,s do divide by 8 by shifting
 ror 2,s
 ror 3,s
 decb dec count
 bne 1b
 ldd 2,s add 1 for swap address
 addd #1
 std 2,s
 ldu #swpmap point to swap map
2 ldd 0,u find segment containing this block
 addd 2,u
 cmpd 2,s
 bhi 4f
 leau 4,u get next entry
 cmpu swpend end of list?
 beq 3f
 ldd 2,u end of list?
 bne 2b
3 leas 4,s clean stack
 rts return
4 ldd 2,s get swap address
 cmpd 0,u start of this segment?
 blo 3b
 bne 6f
 ldd 0,u yes - so just inc start address
 addd #1
 std 0,u
 ldd 2,u dec size field
 subd #1
 std 2,u
 bne 3b last one?
5 leau 4,u get to next entry
 cmpu swpend end of map?
 beq 3b
 ldd 0,u move all entries down a slot
 std -4,u
 ldd 2,u
 std -2,u
 bne 5b end of list?
 bra 3b
6 ldd 0,u is it last guy in segment?
 addd 2,u
 subd #1
 cmpd 2,s
 bne 7f
 ldd 2,u if so - just dec count field
 subd #1
 std 2,u
 lbra 3b
7 ldd 2,u get size field
 pshs d save it
 ldd 4,s get block to remove
 subd 0,u calculate size entry
 std 2,u save as new size
 pshs u remember space
 leau 8,u
8 cmpu swpend end of table?
 bhs 95f if so - blowup
 ldd -4,u move all entries up one slot
 std 0,u
 ldd -2,u
 std 2,u
 beq 9f end of list?
 leau 4,u skip to next slot
 bra 8b repeat
9 puls u get original entry
 ldd 4,s get record number
 addd #1 set to start of new segment
 std 4,u
 puls d get old size entry
 subd #1 reduce by one
 subd 2,u reduce by size of last segment
 std 6,u save in new entry
 lbra 3b exit
95 ldx #swtofl point to message
 jmp blowup halt system!

 pag


*
* signon
*
* Print sign-on message.
*

signon ldx #sgnmsg point to message
 lbsr sysmsg print it
 ldx #memmsg point to mem message
 lbsr sysmsg print it
 ldb corcnt get core count
 clra
 lslb fix for number of K
 rola
 lslb
 rola
 lbsr sysdec print the number of K
 ldx #mm2msg point to 2nd mem message
 lbra sysmsg print and return


* memory messages

memmsg fcb $d,$a,$d,$a
 fcc 'Total user memory = ',0
mm2msg fcc 'K'
 fcb $d,$a,$d,$a,0

 end uniflex
