;***********************************************************************; ; ; ; SSS DDDD SSS Y Y SSS TTTTT EEEEE M M SSS ; ; S S D D S S Y Y S S T E MM MM S S ; ; S D D S Y Y S T E M MM M S ; ; SSS D D SSS Y SSS T EEE M M SSS ; ; S D D S Y S T E M M S ; ; S S D D S S Y S S T E M M S S ; ; SSS DDDD SSS Y SSS T EEEEE M M SSS ; ; ; ; ; ; SD SYSTEMS, INC. ; ; 10111 MILLER RD. ; ; DALLAS, TX 75238 ; ; ; ; (214) - 340 - 0303 ; ; ; ; COPYRIGHT (C) 1983 ; ; ; ;***********************************************************************; Title 'BOOT loader module for CP/M3 linked BIOS' ;***********************************************************************; ; Rev. Description Initials-Date ; ;-----------------------------------------------------------------------; ; 0.1 1st working Version dkb...1/17/83 ; ; 1.0 1st release Version dkb...1/23/83 ; ; 1.1 set up timer interrupt, clock stuff B. Asner.1/29/83 ; ; 1.2 put conditional flag in maclib cond.lib dkb...2/02/83 ; ; 1.3 modified release message to 1.4 rm....3/25/83 ; ; 1.4 initilize @cbnk and @dbnk to 0 rm....3/30/83 ; ; 1.5a add in configure sector at ff80h dkb...4/18/83 ; ; 1.5 RELEASE for distribution CPM30 rel 1.5 dkb...5/05/83 ; ; 1.6a add ?time routine for io8 clock wbd...5/12/83 ; ; 1.6b remove superfluous console init. dkb...6/24/83 ; ; 1.6c ADD logic to remember drivtable config dkb...6/25/83 ; ; 1.6d ADD ?time routine for MPC4 clock wbd...7/26/83 ; ; 1.6 RELEASE for distribution CPM30 rel 1.6 wbd...7/26/83 ; ;***********************************************************************; extrn @date,@hour,@min,@sec,diretrn,eiretrn ; wbd..1.6d public ?init,?ldccp,?rlccp,?time,@slice extrn ?pmsg,?conin,?sldsk,?bank ; wbd..1.6d extrn @civec,@covec,@aivec,@aovec,@lovec extrn @cbnk,@dbnk,?bnksl,@dtbl maclib ports maclib z80 maclib cond page bdos equ 5 dtbl$order equ 0ffb0h ; drive table orders dkb...r1.6 con$in$dev equ 0FF80H ; rm..v1.03 con$out$dev equ con$in$dev+2 aux$in$dev equ con$out$dev+2 aux$out$dev equ aux$in$dev+2 lst$out$dev equ aux$out$dev+2 itable equ 0fff0h ; WARNING save room in gencpm ********** ctc0 equ 78h ctc1 equ ctc0+1 ctc2 equ ctc0+2 ctc3 equ ctc0+3 rtcrs equ 0A5h ; io8 clock address wbd...1.6 rtc equ 0A6h ; io8 clock address wbd...1.6 mpcadr equ 07h ; mpc4 addresses wbd..1.6d mpcmem equ 1000h ; wbd..1.6d sec equ mpcmem+3AAh ; wbd..1.6d min equ mpcmem+3A9h ; wbd..1.6d hour equ mpcmem+3A8h ; wbd..1.6d day equ mpcmem+3A7h ; wbd..1.6d mon equ mpcmem+3A6h ; wbd..1.6d date equ mpcmem+3A2h ; cpm date storage in mpc4 wbd..1.6d if banked tpa$bank equ 1 else tpa$bank equ 0 endif dseg ; init done from banked memory dpatch: ds 256 ; patch area below common ?init: ; cold boot init done here di ; stop interrupts while init. lhld con$in$dev ! shld @civec ; set console in vector lhld con$out$dev ! shld @covec ; and console out vector lhld lst$out$dev ! shld @lovec ; and list output vector lhld aux$in$dev ! shld @aivec ; and auxilary input vector lhld aux$out$dev ! shld @aovec ; and auxilary output vector ; from init sector at ff80h page ;***************************************************************** ;* This Subroutine save the location of the drives swapped * ;* into location 0ffb0h thru 0ffbfh in ram * ;***************************************************************** ; lxi h,100h ; set hl at drive table lxi d,101h ; and de at destination push d ! lxi b,32 ; setup for zero mem xra a ! mov m,a ldir ; zero filled 100-120h pop d ! dcx d ; restore de,hl lxi h,@dtbl ; point to drive table pushix mvi b,16 lxix dtbl$order ; set ix to order table mov$lop1: push b ! mvi b,0 ! push h ; setup for index save @dtbl ldx a,0 ; get order byte ani 15 ; strip top nibble off rlc ! mov c,a ! dad b ; set up hl for move ldi ldi ; move two bytes inxix ; increment ix pointer pop h ! pop b! djnz mov$lop1 ; do all of them popix ; restore ix register lxi h,100h ! lxi d,@dtbl ! lxi b,32 ; setup for move ldir ; move it in ; ;**************************************************************** ;* End of drive table location swap save routine * ;**************************************************************** page if not (io8 or io4 or mpc4) ; wbd..1.6d call clock$init ; setup clock interrupts endif lxi h,init$table ! call out$blocks ; set up misc hardware lxi h,signon$msg ! call ?pmsg ; print signon message ei ! ret ; finished, return with ; inerrupts enabled out$blocks: mov a,m ! ora a ! rz ; return on zero data mov b,a ! inx h ! mov c,m ! inx h ; get byte in b,port in c outir ; send byte jmp out$blocks ; loop til done ?time: if io8 or io4 or mpc4 ; wbd..1.6d push h ! push d ! mov a,c ; save regs lxi h,timout ! push h ; set return address mvi c,rtc ! mvi b,1 ; set c for port, b as filler ora a ! jz gettm ; is it set or get? jmp settm ; DO NOT REMOVE endif ;io8 or io4 or mpc4 wbd..1.6d if io8 or io4 ; wbd..1.6d settm: xra a ! sta @sec ; set seconds to zero mvi a,15h ! out rtcrs ! outp b ; start clock at 0.000 seconds mvi a,03h ! out rtcrs ! lhld @hour ! outp h ; set the minutes mvi a,04h ! out rtcrs ! outp l ; set the hours updt: mvi a,06h ! out rtcrs ! outp b ; set d-o-m to 1 mvi a,07h ! out rtcrs ! outp b ; set month to 1 lhld @date ; get date from scb mvi a,0Bh ! out rtcrs ! outp l ; store msb in clk ram (min) mvi a,0Ch ! out rtcrs ! outp h ; store lsb in clk ram (hrs) ret ; return to caller page gettm: mvi a,06h ! out rtcrs ! inp a ; get day from clock lxi h,@date ! mov m,a ! xra a ! rld ; save it and clear a add a ! mov e,a ! add a ! add a ; high nibble x2, save in e add e ! mov e,a ! xra a ! rld ; high nib x10, save in e add e ! dcr a ! mov e,a ; day is now binary (0-30) mvi a,0Bh ! out rtcrs ! inp l ; read stored date msb mvi a,0Ch ! out rtcrs ! inp h ; read stored date lsb mov a,e ! add l ! mov l,a ! mov a,h ; add days to stored date aci 0 ! mov h,a mvi a,07h ! out rtcrs ! inp a ; get month from clock push psw ! ani 0F0h ; save and check low nibble xchg ! lxi h,montbl ! jrz domon lxi h,montbl+18 ! pop psw ! inr a ! push psw domon: pop psw ! ani 0Fh dmon1: dcr a ! jz stuff ! inx h ! inx h ; index into table jr dmon1 stuff: mov a,m ! inx h ! mov h,m ! mov l,a dad d shld @date ; put in scb for CP/M call updt ; refresh date cycle rerd: mvi a,04h ! out rtcrs ! inp l ; read the hours mvi a,03h ! out rtcrs ! inp h ; read the minutes shld @hour ; put in scb for CP/M mvi a,02h ! out rtcrs ! inp d ; read the seconds mvi a,01h ! out rtcrs ! in rtc ; read tenth's of sec. ani 0F0h ! jrz rerd ; if tenth's=0, reread mov a,d ! sta @sec ; ok- restore seconds ret ; return montbl: dw 0,31,59,90,120,151,181,212,243,273,304,334 endif ; io8 or io4 wbd..1.6d if mpc4 and not (io8 or io4) ; wbd..1.6d cseg ; must be in common settm: lda @cbnk ! sta bank ! call diretrn ; save current bank mvi a,mpcadr ! call ?bank ; address mpc xra a ! sta @sec ! sta sec ; zero seconds lda @min ! sta min ; set minutes lda @hour ! sta hour ; set hours lhld @date ! shld date ; store cpm date in mpc4 lxi h,0101h ! shld mon ; set day/mon to 1 lda bank ! call ?bank ! ret ; set current bank & return gettm: lda @cbnk ! sta bank ! call diretrn ; save current bank mvi a,mpcadr ! call ?bank ! lda day ; address mpc lxi h,@date ! mov m,a ! xra a ! rld ; save it & clear a add a ! mov e,a ! add a ! add a ; high nibble x2, save in e add e ! mov e,a ! xra a ! rld ; high nib x10, save in e add e ! dcr a ! mov e,a ; day now binary (0-30) lhld date ! mov a,e ! add l ! mov l,a ; get stored date, add days mov a,h ! aci 0 ! mov h,a lda mon ! push psw ! ani 0F0h ; get month, save and xchg ! lxi h,montbl ! jrz domon ; check low nibble lxi h,montbl+18 ! pop psw ! inr a ! push psw domon: pop psw ! ani 0Fh dmon1: dcr a ! jz stuff ! inx h ! inx h ; index into table jr dmon1 stuff: mov a,m ! inx h ! mov h,m ! mov l,a dad d shld @date ! shld date ; put in scb for cpm lxi h,0101h ! shld mon ; refresh date cycle lhld hour ! shld @hour ; put hr/min in scb lda sec ! sta @sec ; put sec in scb lda bank ! call ?bank ! ret ; reset current bank & ret bank: db 0 ; current bank storage montbl: dw 0,30,60,90,120,150,180,210,240,270,300,330 dseg ; reset to dseg endif ; mpc4 and not (io8 or io4) wbd..1.6d if io8 or io4 or mpc4 ; wbd..1.6d timout: pop d ! pop h ; restore regs endif ; io8 or io4 or mpc4 wbd..1.6d if mpc4 and not (io8 or io4) jmp eiretrn endif ; mpc4 and not (io8 or io4) ret ; return if not (io8 or io4 or mpc4) ;************************************************ ; Clock Interrupt Initialization routine * ; B. Asner 01/29/83 * ;************************************************ clock$init: im2 lxi h,itable ! mov a,h ! stai ; set up i-reg mov a,l ! out ctc0 ; set up ctc vector lxi h,timeout ! shld itable+6 ; timer service routine adr mvi a,087h ! out ctc3 ; timer mode,87h=/16-0c7h=/256 mvi a,250 ! out ctc3 ; interrupt 16 msec ret ; return ;************************************************ ; Clock Interrupt Service Routine * ; B. Asner 1/29/83 * ; Vectors to here every 01.00 Millisec * ;************************************************ cseg ; must be in common memory timeout: di sspd intstk ; save users stack lxi sp,intstk ; set local stack push psw ! push h ! lhld @slice ; service every 1000 ms = 1sec dcx h ! shld @slice ! mov a,l ! ora h ; slice contents reduced by 1 jz t1s ! jmp close ; finished if not zero t1s: ; 1-sec has gone by lxi h,1000 ! shld @slice ; reset slice= 1000 lda @sec ! inr a ! sta @sec ! ani 0fh ; contents stored as BCD cpi 10 ! jnz rnd1 ; if digit = 'A' then add 6 lda @sec ! adi 6 ! sta @sec rnd1: cpi 60h ! jz t1m ! jmp close ; finished if not zero t1m: ; 1-min has gone by xra a ! sta @sec ; reset @sec = 0 lda @min ! inr a ! sta @min ! ani 0fh ; contents stored as BCD cpi 10 ! jnz rnd2 ; if digit = 'A' then add 6 lda @min ! adi 6 ! sta @min rnd2: cpi 60h ! jz t1h ! jmp close ; finished if not zero t1h: ; 1-hour has gone by xra a ! sta @min ; rset @min = 0 lda @hour ! inr a ! sta @hour ! ani 0fh ; contents stored as BCD cpi 10 ! jnz rnd3 ; if digit = 'A' then add 6 lda @hour ! adi 6 ! sta @hour rnd3: lda @hour ! cpi 24h ! jz t1d ! jmp close; finished if not zero t1d: ; 1-day has gone by xra a ! sta @hour ; reset @hour = 0 lhld @date ! inx h ! shld @date ; @date is 16 bit integer close: pop h ! pop psw ! lspd intstk ; restore registers ei reti dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h intstk: dw 0 else cseg endif ; not (io8 or io4 or mpc4) page ; ; boot loading most be done from resident memory ; This version of the boot loader loads the CCP from a file ; called CCP.COM on the system drive (A:). ; ?rlccp: if banked lxi h,0100h ! lxi b,0d00h ; clone 3.25 k rl$1: mvi a,0 ! call ?bnksl ; select CCP.COM bank mov a,m ! push psw mvi a,tpa$bank ! call ?bnksl ; select TPA pop psw ! mov m,a ; save the byte inx h ! dcx b ! mov a,b ora c ! jnz rl$1 ret endif ; ; fall thru to ldccp if non banked system ; ; First time, load the A:CCP.COM file into TPA ?ldccp: mvi a,tpa$bank! call ?bnksl ; select bank for tpa call getdrv! mvi c,14! mov e,m ; do initial select call bdos! call pusrmsg ; go print user signon xra a ! sta ccp$fcb+15 ; zero extent lxi h,0 ! shld fcb$nr ; start begin of file lxi d,ccp$fcb ! call open ; open CCP.COM inr a ! jz no$CCP ; error if no file... lxi d,0100h ! call setdma ; start of TPA lxi d,128 ! call setmulti ; allow up to 16k bytes lxi d,ccp$fcb ! call read ; load the thing ; now, if banked ; copy CCP to bank 0 for ; reloading at warm boot lxi h,0100h ! lxi b,0d00h ; clone 3.25K, just in case lda @cbnk ! push psw ; save current bank ld$1: mvi a,tpa$bank ! call ?bnksl ; select TPA bank mov a,m ! push psw ; get a byte mvi a,0 ! call ?bnksl ; set for bank 0 for 128 k vers pop psw ! mov m,a ; save the byte inx h ! dcx b ! mov a,b ! ora c ; test for done jnz ld$1 ! pop psw ! call ?bnksl ; restore original bank endif ret page ; if not banked inmsgs: db -1 endif ; pusrmsg: if not banked lda inmsgs ! ora a ! rz ; check for no inmsgs endif xra a ; clear flag if not banked sta inmsgs ; save it endif lxi d,usrfcb ! call open ; try to open Signon.Dat inr a ! lxi h,def$msg ! jrz prtdef ; no file? ,then print default lxi d,0100h ! call setdma ! lxi d,16 ; allow 2k file call setmulti ! lxi d,usrfcb ! call read lxi d,0100h ! mvi c,9 ! jmp bdos ; go print it prtdef: jmp ?pmsg ; to user message no$CCP: ; couldn't find CCP.COM lxi h,ccp$msg ! call ?pmsg ! call ?conin; get a new drive number a..p ani 0fh ! sta ccp$fcb ; update drive selected jmp ?ldccp ; and try again ; CP/M BDOS Function Interfaces open: mvi c,15 ! jmp bdos ; open file control block setdma: mvi c,26 ! jmp bdos ; set data transfer address setmulti: mvi c,44 ! jmp bdos ; set record count read: mvi c,20 ! jmp bdos ; read records getdrv: lxi h,@civec! lxi d,-15! dad d! ret ; set offset on vector page signon$msg: db 1ah,'SD Systems CP/M Plus Ver 3.0',10,13,0 if banked def$msg: db 'Banked Rel. 1.6 July 1,1983',13,10,10,0,'$' else def$msg: db 'Non-Banked R 1.6 July 1,1983',13,10,10,0,'$' endif ccp$msg: db 13,10,'BIOS Err on A: No CCP.COM file',10,13 db 'Enter Drive For CCP.COM (A..P) :',0 cpatch: dw 0,0,0,0,0,0,0,0 ; patch area in common dw 0,0,0,0,0,0,0,0 ; patch area in common ccp$fcb: db 0,'CCP ','COM',0,0,0,0 ds 16 fcb$nr: db 0,0,0 usrfcb: db 0,'SIGNON ','DAT',0,0,0,0 ds 16 db 0,0,0 init$table: db 0,0,0 @slice: dw 100 ; 1000 = 1 second end