TITLE MD-11 BIOS, Copyright (c) 1984, Morrow Designs, Inc. 23_Feb_84 SUBTTL CP/M Plus BIOS -- Table of Contents ; MD-11 BIOS for CP/M Plus V3.0, Copyright (c), 1983, 1984, ; Morrow Designs, Inc. ; 600 McCormick ; San Leandro, ; California 94577 ; Bill Smith ; 1.) CP/M Plus BIOS -- Table of Contents ; 2.) Global Equates, ROM / RAM shared data areas -- RAMDATY ; 3.) Local Equates, ROM Entry Points ; 4.) Banked BIOS -- Character Tables ; 5.) Banked BIOS -- Block I/O ; 6.) Banked BIOS -- CCP Loader ; 7.) Banked BIOS -- Extended BIOS Functions ; 8.) Banked BIOS -- Data Structures, DPH ; 9.) Banked BIOS -- Data Structures, DPB ; 10.) Banked BIOS -- Data Structures, RAMDATY ; 11.) Banked BIOS -- Data Structures, MTABs ; 12.) Banked BIOS -- Data Structures, Free Space Pool ; 13.) Banked BIOS -- Character I/O, Initialization ; 14.) Banked BIOS -- Character I/O, Translation Level ; 15.) Banked BIOS -- Character I/O, Device Level ; 16.) Resident BIOS -- Jump Table ; 17.) Resident BIOS -- Bank Crossing Routines ; 18.) Resident BIOS -- Inter-Bank Moves, Banking Controls ; 19.) Resident BIOS -- Interrupt Handlers ; 20.) Resident BIOS -- Stacks and Interrupt Vectors ;credits ; The MD-11 Design Team included (alphabetically) ; David Block Len Edmondson Howard Fullmer ; Pearl Ledbetter George Morrow Bill Smith ; Mike Stolowitz Steve Tai John Zalabak .z80 true equ -1 false equ not true SUBTTL Global Equates, ROM / RAM shared data areas -- RAMDATY page include HD19DEF.MAC include DRIVES.MAC include DEFINE.MAC SUBTTL Local Equates, ROM Entry Points page BioRev equ 18h $txrdy equ 4 edv equ 40h ;bad drive from format entry primary equ 0 parity equ 7 getch equ 1 print equ 9 open equ 15 readseq equ 20 dma equ 26 parse equ 152 ;---------------------------------------------------------------------- tpa equ 100h dffcb equ 5ch stack80 equ 100h bootram equ 0 bdos equ 5 ccp equ tpa rom equ 0 msgrm equ rom+3 ;rom print signon message routine hmrm equ rom+6 ;rom home disk routine rdhsrm equ rom+9 ;rom read disk routine wrhsrm equ rom+0Ch ;rom write disk routine disrm equ rom+0Fh ;rom direct disk i/o routine bterm equ rom+18h ;rom print boot err routine APIFrm equ rom+1Bh ;rom default for application interface area rdlsec equ rom+20h ;rom read a logical sector wrlsec equ rom+23h ;Rom write a logical sector fmthst equ rom+26h ;rom format single track dpboff equ 12 ;offset from spt to dpb in dbh media_offset equ 11 ;offset into dph for media flag physoff equ 15 ;offset from spt to psh in dpb ;---------------------------------------------------------------------- ; external references ;---------------------------------------------------------------------- extrn @civec, @covec, @aivec, @aovec, @lovec, @bnkbf extrn @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd, @mltio extrn @ermde, @erdsk, @media, @bflgs extrn @date, @hour, @min, @sec extrn ?erjmp, @mxtpa SUBTTL Banked BIOS -- Character Tables page ;---------------------------------------------------------------------- dseg ;banked ;---------------------------------------------------------------------- ;cp/m plus disk functions ; these are presented here, before the jump table, in an effort ; to make their position in the system bank more obvious. ; Please read "banking considerations" following jump table ; ;---------------------------------------------------------------------- boot:: ;entry here placed at front of bnkbios as pointer ;to be used by external system programs to size system ;when examining cpm3.sys file jp boot2 ;jump to high common, end of code ;---------------------------------------------------------------------- char_tables:: ;these tables are provided for external programs which ;examine CPM3.SYS, must follow jump above ser1baud:: db dflt1 ser2baud: db dflt2 ser3baud: db dflt3 default_cflag: db 23h ;translations are on vnumb:: db drives ;number of physical drives tlev:: db 3 ;terminal level default is not installed ds 3,0 ;reserved db BioRev ;BIOS Revision Number db clevel ;compatibility level dw APIF ;Pointer to Application Interface Area dw ramdaty ;Pointer to RamdatY dw ramdaty + MToff ;Pointer to the base of the first MTAB dw pool ;Pointer to free space etblptr:dw esctbl ctblptr:dw ctrltbl evctptr:dw escvect cvctptr:dw ctvect dw dcastrt dcastrt: db 1bh,3dh,0ffh ; dca prefix string ds 3,0ffh dcamid: ds 6,0ffh ; dca seperator dcaend: ds 6,0ffh ; dca terminator string esc_lvl: db 0 ;indicates esc sequence level offset1: db 0 ;first character offset offset2: db 0 ;second character offset order: db 0 ;bit 0 = 0 --> row, then column, ; = 1 --> column, then row ;bit 1 = 0 --> binary cursor adresses ; 1 --> ascii cursor addresses first: db 0 ; temporary storage of first second: db 0 ; temporary storage of second char_table_length equ $-char_tables ;---------------------------------------------------------------------- vmsg:: db cr,lf,'Your floppy drive is being re-assigned as drive ' vdrv:: db 'a.',cr,lf,'Exchange diskettes and press [return]',0 ds 96-($-vmsg),0 vmsg_length equ $-vmsg ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Block I/O page boot2: ;enter here from loader, rom is on, system bank is on call bnk_initctc ;init bit rates ld hl,services ld (bios+1),hl ;point cold at services ld hl,dpb_buffer ;init dph.dpb -> dpb_buffer (gencpm needs 'em real) ld (dpbase+dpboff+dphlen*0),hl ld (dpbase+dpboff+dphlen*1),hl ld (dpbase+dpboff+dphlen*2),hl ld (dpbase+dpboff+dphlen*3),hl ld (dpbase+dpboff+dphlen*4),hl ld a,$cntrst ld (system_bank_bits),a out (bnkstb),a ;Turn on the rom and bank 0 ld iy,RamDatY ;IY:= Ram Data ld sp,System_Stack ;Stack:= Initialized ld de,Sign_On_Start call MsgRm ;Print the Sign On message ld a,$cntrst + 1 ld (system_bank_bits),a jp wboot ;read ccp and go ;---------------------------------------------------------------------- multio:: ;note multi-sector count ret ;not implemented ;---------------------------------------------------------------------- flush:: ;flush buffers xor a ;no error ret ;not needed ;---------------------------------------------------------------------- home:: ld bc,0 ;track 0 ; jp settrk ;---------------------------------------------------------------------- settrk:: ld (ramdaty+hsttrk),bc ;set track in ramdaty ret ;---------------------------------------------------------------------- setsec:: ld (ramdaty+hstsec),bc ;set sector in ramdaty ret sector_length: dw 0 ;init by seldsk ;---------------------------------------------------------------------- setbnk:: ;define dma bank ld (dmabnk),a ret dmabnk: ds 1,0 ;---------------------------------------------------------------------- setdma:: ld (ramdaty+dmaadr),bc ;set dma address in ramdaty ret ;---------------------------------------------------------------------- sectrn:: ld l,c ;hl=bc ld h,b inc hl ;start sectors at 1 ld a,d ;see if xlat table or e ret z ;return if no xlat ex de,hl ;hl = table address add hl,bc ;add sector to table ld l,(hl) ;get xlated sector ld h,0 ret ;---------------------------------------------------------------------- seldsk:: ;enter with [c] = number of drive to select ;exit with [hl] -> dph, or [hl] = 0 if bad drive ld a,drives-1 ;check drive bound cp c jp c,bdrv ;jmp if bad ld a,c ;new drive ld (ramdaty+hstdsk),a ;set drive as current ld hl,ramdaty ;pointer to ramdaty push de ;save primary/secondsry select call gdsk1 ;get mtab pointer in [HL] pop de ;restore primary/secondary select bit primary,e jr nz,skpset ; if first time, bit @frgn,(hl) jr nz,skpset ; then if native morrow format, bit @hrddsk,(hl) jr nz,skpset ; then if floppy, (read disk id) ; Prepare to read ID info from media push hl ;save dskdef pointer call getab ;read config table from diskette or a ;see if error jp nz,ubdrv ;back to drive a: if error jr dskchk fmtlog: ;format enters here with disk info copied to buffer push hl ;format enters with system mtab dskchk: ; Check ID info for correctness (checksum) dsktln equ 25 dsktb equ dskbuf+80h+dsktln ;address of end of table+1 ld hl,dsktb ;pointer to end of table+1 ld b,dsktln ;count must be odd! for field of E5 xor a ;init check byte ld e,a ;init 0-check byte chklp: dec hl ;dec pointer xor (hl) ;x-or table value into parity check byte ld d,a ;save parity check byte or e ;or in 0-check byte ld e,a ;save 0-check byte ld a,d ;restore pariy check byte djnz chklp ;dec table length & loop til done ; inc hl ;hl=>dskdef1, access to sided-ness or a ;a=0 if table ok ld a,e ;a = 0-check byte jr nz,sside ;assume s.s. if invalid table or a ;check 0-check byte jr nz,dskdpb ;invalid table if zero sside: ld de,sdpb ;pointer to s.s. dpb from ram pop hl ;restore ram mtab jr setsgl dskdpb: ;now we know that the media really is native morrow format dsktdb equ dskbuf+80h+9 ld de,dsktdb ;pointer to dpb in boot ;set ram MTAB according to disk MTAB bit @dblmed,(hl) ;check disk MTAB for d.s. media pop hl ;restore pointer to ram MTAB set @dblmed,(hl) ;presume double sided jr nz,dside ;but if single sided, setsgl: res @dblmed,(hl) ;set for s.s. media dside: xor a ;set z flag skpset: ;enter with z=1 if disk contains dpb to copy, pointed to by [DE] ;also, [HL] -> current MTAB push hl ;save current MTAB (in common) push af ;save z-boolean for ldir below push de ;save pointer to dpb from disk ld a,(ramdaty+hstdsk) ;get drive ld hl,drive_table call get_indexed ex (sp),hl ;put DPH on stack push hl ;under disk DPB address ld a,(ramdaty+hstdsk) ;get drive ld hl,dpb_table call get_indexed ex de,hl ;[de] -> dpb space in ram pop hl ;restore disk dpb pointer pop bc ;dph address pop af ;restore boolean push bc ;dph address push de ;current dpb (common) jr nz,notab ;skip if no dpb update ld bc,15 ;length of dpb on drive media ldir ;update dpb notab: ; Figure the number of physical sectors per track = SPT / 2^secsiz ; Figure the transfer length for sector moves = 128 * secsiz ; Figure physical record shift mask (DPB.psm) = (2^secsiz)-1 ; Initialize physical record shift factor (DPB.psh) = secsiz pop de ;DPB in common pop hl ;current DPH ex (sp),hl ;restore current MTAB inc hl ;dskdef1, for sizmsk ld a,(hl) and $sizmsk ;get size push af ;save size ld b,a ;set as a count inc b ;count +1 for djnz bit @hasbad,(hl) ;set-up bad-map ld hl,ramdaty+dflag res @curbad,(hl) jr z,notab1 set @curbad,(hl) ;dflag @curbad reflects diskdef1 @hasbad notab1: ld c,70h ;for psm calculation ld a,(de) ;read records per track add a,a ;*2 ld hl,40h ;128/2 pspt: add hl,hl ;transfer length * 2 rlc c ;shift mask * 2 circular srl a ;records per track / 2 djnz pspt ld (ramdaty+physpt),a ;set physical sectors per track ld (sector_length),hl ;set transfer length ld hl,physoff ;offset from SPT to PSH add hl,de ;[hl] -> DPB.psh pop af ;size ld (hl),a ;set DPB.psh inc hl ;[hl -> DPB.psm ld a,c and 7 ;delete remaining high order bits ld (hl),a ;set DPB.psm ex de,hl ;[hl] -> dpb ld de,dpb_buffer ;buffer in common ld bc,dpb_length ldir ;copy current dpb to common pop hl ;restore dph address ret ret ubdrv: pop hl ;drop bdrv: ld hl,0 ret get_indexed: add a,a ;*2 add a,l ld l,a jr nc,get_indexed2 inc h get_indexed2: ld a,(hl) ;dph lo inc hl ld h,(hl) ld l,a ;[hl] -> dph ret ;------------------------------------------------------------------ getab: ;read boot sector of currently selected disk ld hl,0 ld (ramdaty+hsttrk),hl ;set track 0 inc hl ld (ramdaty+hstsec),hl ;set sector 1 ld hl,ramdaty+opflag res @inmap,(hl) res @bufok,(hl) jp read2 ;read without move ;---------------------------------------------------------------------- read:: ld hl,ramdaty+opflag res @inmap,(hl) ;don't pre-read bad map res @bufok,(hl) ;errors are not re-mapable call read2 push af call rwmove pop af ret read2: push ix ;save ix & iy push iy ld iy,ramdaty ;set-up iy -> ramdaty set @readop,(iy+dflag) ;indicate read call rom_on ;turn rom on call rdhsrm ;read from disk or a ;set flags for error push af ;save error call rom_off ;turn rom off pop af pop iy pop ix ld d,a ;[d]=physical error ret z ;if error, ld a,1 ; say so ret ;endif ;---------------------------------------------------------------------- write:: ld a,(read_after_write) ;check read before enabled ld hl,ramdaty+opflag res @inmap,(hl) ;do not pre-read bad map res @bufok,(hl) ;not mapable if no data pre-read bit 1,a jr z,write1 ;if pre-read enabled, ld a,(ramdaty+dflag) bit @curbad,a jr z,write1 ;if drive has bad map set @bufok,(hl) ;errors are re-mapable call read2 ;do pre-read, don't move data ret nz ;exit on non=remap error write1: call write2 jr z,r_a_w_check ;if error, ld d,a ;[d]=physical error cp ERwp ;is it write protected? ld a,2 ;write protect error jr z,write1a ;if write protected, say so ld a,1 ;error is permanent write1a: or a ;set flags = error ret r_a_w_check: ;no apparent error, ld a,(read_after_write) ;check user enabled read-after-write bit 0,a ld a,0 ;if not enabled, no error ret z ;if enabled, ld hl,ramdaty+opflag res @inmap,(hl) set @bufok,(hl) ;same as pre-read call read2 ;read the stuff, don't move data ret z ;exit if no error call write2 ;try writing again ld a,1 ;in case error, return permanent ret nz ;exit if error on second write jp read2 ;if written, check again, return read's error read_after_write: db 2 ;default = pre-reads on write2: push ix ;save ix & iy push iy ld iy,ramdaty ;set-up iy -> ramdaty res @readop,(iy+dflag) ;indicate write call rwmove ;make transfer call rom_on ;turn rom on call wrhsrm ;write to disk or a ;set flags for error push af ;save error call rom_off ;turn rom off pop af pop iy pop ix ret page ;---------------------------------------------------------------------- ; SETEM - Set the error mode (6_Feb_84) ;-------------------------------------- ; SetEM: res @SerD,(iy+OpFlag) ;Clear the Suppress Error Display flag res @SerUR,(iy+OpFlag) ;Clear the Suppress Error Response flag ld a,(@ermde) ;A:= Current system error mode cp 0FFh ;If (Error Mode eq Return) jr nz,SEMsk1 set @SerD,(iy+OpFlag) ; Set Suppress Display flag set @SerUR,(iy+OpFlag) ; Set Suppress Response flag ret SEMsk1: cp 0FEh ;If (Error Mode eq Return & Display) ret nz set @SerUR,(iy+OpFlag) ; Set Suppress Response flag ret page ;---------------------------------------------------------------------- rwmove:: ld hl,(ramdaty+dmaadr) ;destination address, (presuming read) ld de,dskbuf ;source address ld bc,0100h ;presume destination is tpa ld a,(ramdaty+dflag) bit @readop,a ;test for write jr nz,rwmov0 ;if write, ex de,hl ; reverse direction of transfer ld bc,0001h ; reverse banks too rwmov0: ld a,(bnkmsk) push af ld a,(dmabnk) ;see if dma to/from tpa bank (2) or a call nz,xmove ;set-up for inter-bank transfer ld bc,(sector_length) ;number of bytes to transfer call move ;make transfer pop af ld (bnkmsk),a ret ;---------------------------------------------------------------------- ;note: the rom is turned on by inter_bank to facilitate migration of code ; from here to rom. all usage of read, write, and format must pass ; through this code so we can perform interrupt management in later ; releases. IY -> Ramdaty rom_on: ;turn rom on set @romio,(iy+opflag) ;we are doing rom block io di ld a,(system_bank_bits) and not $_RMENB ;rom on jr rom_common ;---------------------------------------------------------------------- rom_off: res @romio,(iy+opflag) ;done with rom block io di ld a,(system_bank_bits) or $_RMENB ;rom off rom_common: ld (system_bank_bits),a ;update out (bnkstb),a ei ret ;---------------------------------------------------------------------- xmove:: ;build memory mask modifying $xfer, $bank2, $_rmenb ;result is always non-zero ld a,c ;source bank cp b ;same as dest? ld b,$_RMENB ;presume no xfer, rom off jr z,xmove1 ld b,$XFER or $_RMENB ;set xfer, rom off xmove1: add a,a ;bank *2 for hardware or b ;add bits set above ld b,a ld a,(system_bank_bits) ;include centronics controls and not ($xfer + $bank2 + $_rmenb) or b ld (bnkmsk),a ;set for xmove ret ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- CCP Loader page bnk_wboot:: ld a,(Tlev) ;If (the terminal level is non-zero) or a ; (set brightness to HIGH) jr z,BWSkp1 ld c,1Bh ; ConOut:= Escape call conout ld c,'(' ; ConOut:= Open Paren. call conout BWSkp1: ld hl,ramdaty+cflag set @imsact,(hl) ld a,(ramdaty+OpFlag) res @SerD,a ;Clear the Suppress Error Display flag res @SerUR,a ;Clear the Suppress Error Response flag ld (ramdaty+OpFlag),a ld a,10 ;retry count ld (ramdaty+retry),a ;set retry count ld c,0 ;drive a: call seldsk if floppy ld hl,1 ld (ramdaty+hsttrk),hl ;track 1 ld (ramdaty+hstsec),hl ;sector 1 else ld hl,6 ld (ramdaty+hstsec),hl ;sector 6 ld l,h ;[hl]=0 ld (ramdaty+hsttrk),hl ;track 0 endif ld a,1 ld (dmabnk),a ;moves to tpa bank ld hl,tpa ld (ramdaty+dmaadr),hl ;transfer to tpa ld b,4 ;4k to move ld iy,ramdaty bnk_wboot1: push bc ;save sector count call read ;read a sector to dma jr nz,bnk_wboot9 ;if no error, ld (ramdaty+dmaadr),hl ;dma ++ inc (iy+hstsec) ;sector ++, no track moves pop bc djnz bnk_wboot1 ld hl,(@mxtpa) ld (lo_mem_copy+6),hl ;set bdos address ld bc,100h ;destination tpa call xmove ld hl,0 ;destination lo-mem ld de,lo_mem_copy ld bc,lo_mem_length call move jp res_wboot ;transfer control thru common bnk_wboot9: ;error has ocurred call rom_on jp bterm ;exit to rom "press reset" lo_mem_copy: jp warmpt nop nop jp warmpt lo_mem_length equ $-lo_mem_copy ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Extended BIOS Functions page bnk_inter_bank: ;continuation of inter_bank ld (save_user_stack),sp ld sp,system_stack ld a,(system_bank_bits) push af ;save for restore and not ($bank2 + $_rmenb) ;indicate rom and sys are on ld (system_bank_bits),a ;now reflects system state ei push hl ld hl,bnk_return ;force return to here ex (sp),hl ;by placing on stack jp (hl) ;execute desired function bnk_return: ;prepare to exit system bank ex (sp),hl ;get saved bank bits in [h] push af ;preserve returned value ld a,h di ;no interrupts while bits don't reflect system state ld (system_bank_bits),a jp res_bnk_return ;continue above bnk_services: ;extended bios functions ;entry parameters, bc = function number, 0 -> n (b=0) ; de,ix = parameters if needed ;hl_entry and bc_entry are also available ;exit parameters vary ld hl,-max_func add hl,bc jp c,wboot ;kill program if making illegal call ld hl,function_table add hl,bc add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a jp (hl) ;do function function_table: dw func0,func1,func2,func3,func4,func5,func6,func7 dw func8,bnk_format,bnk_initctc,bnk_inject_ims dw func12,func13,func14,func15,func16,func17 max_func equ ($-function_table)/2 func0: ;read from system memory ;[de] -> dest (tpa) ;hl_entry -> source (sys) ;bc_entry = length ld hl,(hl_entry) ld bc,(bc_entry) jr tpa_move ;tpa_move stepping-stone func1: ;write to system memory ;[de] -> dest (sys) ;hl_entry -> source (tpa) ;bc_entry = length ld hl,(hl_entry) ld bc,(bc_entry) jr sys_move func2: ;read ramdaty and apif to [de] ld hl,ramdaty ld bc,mtoff jr tpa_move func3: ;read mtabs to [de] ld hl,ramdaty+mtoff ld bc,5*16 jr tpa_move func4: ;read drvtbl and all DPH to [de] ld hl,drive_table ld bc,32+drives*dphlen jr tpa_move func5: ;read dpb_table and all DPB to [de] ld hl,dpb_table ld bc,dpb_table_leng jr tpa_move func6: ;read character table to [de] ld hl,char_tables ld bc,char_table_length jr tpa_move func7: ;read virtual drive message to [de] ld hl,vmsg ld bc,vmsg_length jr tpa_move func8: ;read free space to [de] ld hl,pool ld bc,pool_length jr tpa_move sys_move: push bc ld bc,1 ;dest = system jr do_move tpa_move: push bc ld bc,100h ;dest = tpa do_move: call xmove ;interbank pop bc push bc push de push hl ex de,hl ;for move call move pop hl pop de pop bc ret ;func9 equ bnk_format ;func10 equ bnk_initctc ;func11 equ bnk_inject_ims func12: ;enable/disable centronics interrupts [e]=0=disable ;stack currently contains (0)return to bnk_return, (+2)bank bits ;warning, this code is not intended to update centronics bits in iy.cpybnk ;this discipline will cause centronics interrupts to be disabled automatically ;during rom execution pop hl pop af ;get the bits ld d,a ;previous state res 7,a ;centronics interrupts off bit 0,e ;was this an enable? jr z,func12a set 7,a func12a: push af ;back on stack jp (hl) ;and exit func13: ;enable/disable disk read after write, [e]=0=disable, 1=enable ;enable/disable disk read before write, 2=enable ;[e] contains bit mask ld hl,read_after_write ld d,(hl) ;return what it was before ld (hl),e ret func14: ;execute in bank 1 (sys) at [hl] ld iy,ramdaty ld hl,(hl_entry) ld bc,(bc_entry) jp (hl) func15: ;verify track, destructive ld iy,ramdaty set @bufok,(iy+opflag) jr f15a func16: ;verify track, non-destructive ld iy,ramdaty res @bufok,(iy+opflag) f15a: ;md11 hard disk sectors are formatted 1,8,6,4,2,9,7,5,3, physically ;interleave for verify makes sequence 1,6,2,7,3,8,4,9,5, every other one ;set b=sector_count, c=interleave_increment, d=sectors_track+1, e=remaps ld bc,0905h ;9 sectors interleaved ld de,0A00h ;10 is illegal sector bit @hrddsk,(iy+phydrv) jr nz,f15a1 ;if floppy ld bc,0501h ;5 sectors, sequentially f15a1: ld (iy+hstsec),1 ;begin at sector 1 f15: push de push bc res @inmap,(iy+opflag) ;reset @inmap call read2 pop bc pop de jr z,f15b0 ld d,a ;cast error code in d, remapped sectors in e ret ;user abort error f15b0: bit @inmap,(iy+opflag) jr z,f15b inc e ;remaps ++ f15b: ld a,(iy+hstsec) add a,c ;interleave cp d jr c,f15c dec d sub d ;- sectors per track inc d f15c: ld (iy+hstsec),a djnz f15 ;do number of sectors ld d,0 ;no errors ret ;normal exit func17: ;modify contents of cflag to contents of [e], return previous in [d] ld hl,ramdaty+cflag ld d,(hl) ld (hl),e ret ;---------------------------------------------------------------------- bnk_format:: ;enter with [de] -> old micro decision mtab/dpb pair, as on media ; [ix] -> user's APIF area ; apif.hstdsk = logical drive to format ; apif.hsttrk = track for format ; apif.hstsec -> sector table (in reverse order) push ix ;save for exit ld iy,ramdaty push de ;save mtab push ix pop hl ;source is user's apif ld de,apif ;dest is system apif ld bc,aileng ;count is length of apif call sys_move ;copy user's to system ld a,(iy+hstdsk) ;apif.drive from user call gdsk ;get its mtab bit @hrddsk,(hl) ;see if harddsk pop de ;restore user's mtab jr z,formf ;if hard disk ld e,1 ;secondary select ld c,(iy+hstdsk) call seldsk ;secondary select jr form8 formf: ;login floppy by writing format's copy of disk info to diskbuf push de ;[de] -> new MTAB pointer (source) ex (sp),hl ;save system mtab ld de,dskbuf+80h ;ID area is destination ld bc,dsktln ;length call sys_move ;copy to system pop hl ;restore system mtab call fmtlog ;format logon for floppy form8: ld l,(iy+hstsec) ;get pointer to gap stuff ld h,(iy+hstsec+1) ld de,fmtbuf ;destination in system bank ld bc,3 ;3 bytes for gap table call sys_move ;move from tpa to sys add hl,bc ;update [hl] for sector table push hl ;save source for sector table ld a,(ramdaty+hstdsk) call gdsk ;get the mtab bit @hrddsk,(hl) ;test for hard disk ld hl,fmtbuf+3 ;table space for hard disk ld c,(iy+physpt) ;length is physical sectors per track ld b,0 ld de,0 ;zero additional offset for hard disk jp nz,formt1 ld de,12-3 ;additional offset for floppy formt1: add hl,de ex de,hl ;destination in [de] pop hl ;restore source pointer call sys_move ;move to system from tpa call rom_on ;rom is on, but chario needs to know call fmthst ;format the track pop de ;destination is user's apif push af call rom_off ld hl,apif ld bc,aileng call tpa_move ;copy to user, return to caller pop af ;restore error ld d,a ;cast in [d] ret ;---------------------------------------------------------------------- gdsk: ;enter [a] = drive, [iy] or [hl] -> ramdaty ;return [hl] -> drive's MTAB push iy ;get iy into hl pop hl gdsk1: ld de,MToff ;calc. mtab pointer add hl,de rlca ;multiply drive by 16 rlca rlca rlca ld e,a ;add (16 * drive) to pointer add hl,de ret ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Data Structure, DPH page drvtbl:: ld hl,drive_table ret drive_table: table_gen dph ds (16-drives)*2,0 dpbase: struct_gen dph dphlen equ dphb-dpha dph_struct_len equ $-drive_table ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Data Structure, DPB page dpb_table: ;table defines logical to physical mapping of dpb's. ;structure is same as drive_table, all dph point at same dpb_buf ;in common. table_gen dpb dw 0 ;terminator struct_gen dpb dpb_length equ 17 dpb_table_leng equ $-dpb_table ;default single-sided disk dpb, not part of table sdpb:: dw 40 db 4 db 15 db 1 dw 94 dw 127 db 0c0h db 0 dw 32 dw 2 db 3,7 SUBTTL Banked BIOS -- Data Structure, RAMDATY, APIF page ;---------------------------------------------------------------------- ; General Disk Operations Data Area (1_Sept_83) ;---------------------------------------------- ; ramdatY:: db 0 ;(SEKDSK) BDOS disk number dw 0 ;(SEKTRK) BDOS track number ; dw 0 ;(SEKSEC) BDOS sector number ; dw 0 ;(SEKHST) Actual sector number on the disk ; db 0 ;(UNACNT) Unallocated record count db 0 ;(UNADSK) Unallocated disk number dw 0 ;(UNATRK) Unallocated track number ; dw 0 ;(UNASEC) Unallocated sector number ; db 0 ;(UNAMAX) Sectors per Unallocated block dw 0 ;(SECTRK) Logical Sectors per track ; db 0 ;(PHYSPT) Physical sectors per track db 0 ;(WRTYPE) Write type db 0 ;(CFLAG) Flag Byte (initialized from chr_tbl db 0 ;(DFLAG) Flag Byte db 0 ;(TRSEC) Offset to logical sector within physical sector dw vmsg ;(VMSGP) Pointer to virtual drive message ; dw vdrv ;(VDRVP) Pointer to virtual drive in message ; db 0FFh ;(CDSK) Current drive db cvdsk ;(VDSK) Current virtual drive dw 2800h ;(DMAADR) disk DMA address ; dw jcono ;(CONOUT) Pointer to Current console output routine ; dw jconi ;(CONIN) Pointer to Current console input routine ; dw jcons ;(CONSTS) Pointer to Current console status routine db $CNTRST ;(CPYBNK) Copy of bank strobe (printer restore = false) ;rom is on, bank 1 (system) is on, used only by rom, ;see system_bank_bits ;---------------------------------------------------------------------- ; Default Application Interface area (13_Oct_83) ;----------------------------------------------- ; APIF:: db 0 ;(HSTDRV) BDOS Drive Number (1st floppy) dw 0000 ;(HSTTRK) Desired Cylinder (lo) ; Desired Cylinder (hi) dw 1 ;(HSTSEC) Desired Sector (lo) ; Desired Sector (hi) db 1 ;(SECCNT) Number of sectors to transfer db 10 ;(RETRY) Retry Count dw dskbuf ;(HSTBUF) Buffer Address (lo) ; Buffer Address (hi) db 0 ;(ERFLAG) Error Code db 0 ;(OPFLAG) Options Flag dw 0 ;(PHYTRK) Physical track number (lo) ; Physical track number (hi) db 0 ;(PHYSEC) Physical sector number db 0 ;(PHYHD) Desired Head db 2 ;(PHYDRV) Physical Drive Number dw 0 ;(IOADD) Execution Address (lo) ; Execution Address (hi) SUBTTL Banked BIOS -- Data Structure, MTABs page mtab:: struct_gen mt SUBTTL Banked BIOS -- Free Space Pool page pool:: ;beginning of managed space xltab:: db 0 dw 5 xlt1k:: db 1,4,2,5,3 db 0feh ; console xlt table dw clen esctbl: db 0ffh ctrltbl:db 0ffh escvect:dw 0 ctvect: dw 0 ; translation strings for the terminal go here ;--------------------------------------------- ; clen equ $-esctbl db 0ffh ;End of Free Space Header dw 870 ;Initial Free Space Length ds 400,0 Sign_On_Start: db cr, lf, 'CP/M Plus -- Ver 3.0 Rev ' db ((BioRev and 0f0h) shr 4) + '0','.',(BioRev and 0Fh) + '0' db cr,lf,'Copyright 1982, 1983 Digital Research, Inc.' db cr,lf,'Copyright 1983, 1984 Morrow Designs, Inc.' db cr,lf,0 Sign_On_End: Sol equ Sign_On_End - Sign_On_Start ds (470 - Sol), 0 db 0fdh ;Ims Buffer Header dw 0 ;Ims Length db 0fch ;Function Table Header dw function_table_length ;Function Table Length translation_table: db 18 ;# entries db 4ah,1,2 db 6ah,1,17h db 0ah,1,17h ;up arrow db 4bh,0 db 6bh,0 db 0bh,1,0Bh ;down arrow db 4ch,1,8 db 6ch,1,1 db 0ch,1,8 ;left arrow db 4dh,1,20h db 6dh,1,6h db 0dh,1,7h ;right arrow db 4Fh,5,'HELP',0dh db 6Fh,5,'HELP',0dh db 0Fh,5,'HELP',0dh ;Help Key db 4Eh,1,18h db 6Eh,1,18h db 0Eh,1,18h ;Home/Clear function_table_length equ $-translation_table pool_length equ $-pool ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Chatacter I/O, Initialization page bnk_initctc: ;initialize serial list for hardware handshake if req'd ld a,(system_bank_bits) and not $cntrst ;restore centronics out (bnkstb),a ;exiting this bank lifts restore ;since not_restore is not saved, makes ;restore signal big & fat. ld a,(default_cflag) ;defaults from SETUP.COM ld (ramdaty+cflag),a ;cast to system ;Setup Handshaking for the list device ld a,0ffh ;XON flag ld (lstflg),a ;set flag ld a,3 out (s2stat),a ;select reg 3 ld a,(ramdaty+cflag) bit @hwsync,a ld a,11000001b ;8bits/char, rxon jr z,intct1 ld a,11100001b intct1: out (s2stat),a ;8bits/char, auto, rx on in a,(s2stat) ;Read status register once to clear it ;Setup Handshaking for the aux device ld a,3 out (s3stat),a ;select reg 3 ld a,(ramdaty+cflag) bit @siosyn,a ld a,11000001b ;8bits/char, rxon jr z,intct2 ld a,11100001b intct2: out (s3stat),a ;8bits/char, auto, rx on in a,(s3stat) ;Read status register once to clear it ;initialize all 3 bit rate generators ld a,(ser1baud) ;index for table call getval ld a,0beh ;mode word for channel 2, mode 3 ld c,baud0 ;set-up channel 2 for serial 1 CON: call setbaud ld a,(ser2baud) call getval ld a,07eh ;mode word for channel 1, mode 3 ld c,baud1 ;set-up channel 1 for serial 2 LST: call setbaud ld a,(ser3baud) call getval ld a,03eh ;mode word for channel 0, mode 3 ld c,baud2 ;set-up channel 0 for serial 3 SIO: ;do setbaud setbaud: ;set channel mode from [A], output 2 bytes from (hl) to (c) out (baudset),a ;set mode ld a,(hl) ;timer lo inc hl out (c),a ld a,(hl) ;timer hi out (c),a ret getval: ;index into baudtbl using [A], leaving [HL] on value ld hl,baudtbl ;base of bit rate values add a,a ;*2 ld c,a ld b,0 add hl,bc ret baudtbl: dflt1 equ 6 ;console 9600 baud dflt2 equ 3 ;list 1200 baud dflt3 equ 3 ;sio 1200 buad dw 1136 *2 ;110 dw 417 *2 ;300 dw 208 *2 ;600 dw 104 *2 ;1200 dw 52 *2 ;2400 dw 26 *2 ;4800 dw 13 *2 ;9600 dw 13 ;19,200 dw 1 ;reserved dw 1 ;reserved dw 1 ;reserved ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Character I/O, Translation Level page bnk_const: call ims_chk ;see if IMS o.k. ld a,0 ;set not ready in case ret z ;ret not ready if IMS o.k. jp ser1_input_status leadin equ 1ch translate_input: call getchr ;get a character from current source cp leadin ;check for function key lead-in ret nz ;back to cp/m if not ld hl,ramdaty+cflag bit @xl_in,(hl) ret z call getchr ;get function key identifier push af ;save char ld a,0fch ;function table call find inc hl pop af ;restore char call scan ;look for key jp nc,fcn2 ;if not found, set parity,a ;mark as function with parity bit=1 ret fcn2: ld a,(hl) ;check for string length = 0 or a ex de,hl ;[de]->string.length call nz,inject_ims ;inject string into ims jp translate_input ;get first character in sequence ;recurse if required ;---------------------------------------------------------------------- bnk_inject_ims: ;available to tpa programs ex de,hl ;source is [de] on entry ld bc,1 ;1 byte ld de,ims_length_byte ;destination call sys_move ;read length byte ex de,hl ;point at user's string ld bc,1 ;destination is sys for move below call xmove ld a,(hl) ;get length byte from ims_length_byte jr inject_ims2 ;[de] -> input string in tpa ims_length_byte: db 0 ;storage (dest for interbank move) inject_ims: ;enter with [DE] -> string with length byte first, ; exit with IMS active ld a,(de) ;get length byte inject_ims2: ld c,a ;save ld b,0 inc de ;point at string text push de ;save string address ld a,0ffh ;free marker call find ;[de]=free length ;[hl]->free.leng(hi) push hl ;save free address ld h,d ld l,e ;[hl]=free length or a ;[cy]=0 sbc hl,bc ;free.len = free.len - string.len jr c,noims ;if not out of space, ex de,hl ;[de]=new free.len ex (sp),hl ;[hl]=free.address (save old length) ld (hl),d ;write new free.len(hi) dec hl ld (hl),e ;write new free.len(lo) inc hl inc hl ;[hl] -> free.data_area pop de ;[de] = old free.len add hl,de ;point at IMS.head (=fd) inc hl ;[hl] -> ims.len(lo) ld e,(hl) ;read ims.len inc hl ld d,(hl) ex de,hl ;[hl]=ims.len, [de]->ims.len(hi) add hl,bc ;ims.len = ims.len + string.len ex de,hl ;[hl] -> ims.len(hi) sbc hl,bc ;ims.address = ims.address - string.len ld (hl),d ;write new ims header, ims.len(hi) dec hl ld (hl),e dec hl ld (hl),0fdh ;ims head complete inc hl inc hl inc hl ;[hl] -> destination, ims buffer pop de ;[de] -> source, text call move ;copy string, may be from tpa or sys ld hl,ramdaty+cflag bit @imswet,(hl) jr z,fcn4 ;if ims already contains characters, bit @imsact,(hl) jr nz,fcn4 ;but is deactivated, dec de ; then point at last char, this string, ld a,(de) set 7,a ; and mark it to turn-off ims at end of this string ld (de),a fcn4: ;endif set @imswet,(hl) ;activate ims in either case set @imsact,(hl) ret ;exit with carry = clear noims: ;enter here if no ims available pop de ;drop pop de ;drop ret ;exit with carry = set ;---------------------------------------------------------------------- ; SCAN - Search for key in table ;------------------------------- ; enter with [hl] -> table to be searched ; [a] = key to search for ; form of table is: ; element_count (byte) ; element_list (string) ; :: element = length (byte) ; string (text) scan: ld d,0 ld b,(hl) ;element count inc b inc hl ;point at key jr scan1 scan0: cp (hl) ;key we're looking for? inc hl ;point at string.length ret z ld e,(hl) ;not key, so get length inc e ;same as inc hl add hl,de ;next element scan1: djnz scan0 ;do until out of elements scf ;abnormal exit ret ;------------------------------------------------------------------- ;IMS_CHK - Check if IMS and/or ROM are active. ; ret: 0 if IMS active and ROM in-active ; 1 otherwise ;------------------------------------------------------------------- ; ims_chk: ld a,(ramdaty+cflag) ;get cflag and 0c0h ;mask out ims flags cp 0c0h ;check if ims active ret nz ;ret if not active ld a,(ramdaty+opflag) ;check input for rom error or vdisk bit @romio,a ;1=rom is getting characters ret ;ret: 0 if rom not processing ; 1 if rom processing ;---------------------------------------------------------------------- ; GETCHR - Input a Character from the Console or the Submit Buffer ;---------------------------------------------------------------- ; getchr: call ims_chk ;see if IMS o.k. jp nz,ser1_input ;jmp if no IMS submt: call ser1_input_status jr z,subgo ;then if input ready, call ser1_input ; get the character and 7fh cp 3 jr nz,subgo ;then if control-c drop_ims: ; empty the ims buffer ld a,0fdh ;ims call find ;get count push de ;save length ld a,0ffh ;free call find ex de,hl ;[hl]=free.len pop bc ;[bc]=ims.len add hl,bc ;[hl]=total space ex de,hl ;[hl]=free.len(hi) ld (hl),d dec hl ld (hl),e ;reset free length inc hl inc hl ;[hl] -> free.data space add hl,de ;[hl] -> end of free space ld (hl),0fdh ;ims header inc hl ld (hl),0 inc hl ld (hl),0 ;reset ims.len ld a,(ramdaty+cflag) ;de-activate ims res @imsact,a res @imswet,a ld (ramdaty+cflag),a ld a,18h ret ;endif subgo: ;else, else ld a,0ffh ;free space code call find ;find free space inc de ;update free space pointer ld (hl),d dec hl ld (hl),e add hl,de ;set hl ==> ims buffer inc hl inc hl ld e,(hl) ;update ims buffer header ld (hl),0fdh inc hl ld d,(hl) dec de ld (hl),e inc hl ld a,e ;see if last char. or d ld a,(ramdaty+cflag) jr nz,skp1 ;jmp if not last char. res @imswet,a ;clear imsbuf flag skp1: bit parity,(hl) ;check parity bit of char. jr z,skp2 ;jmp if parity = 0 res @imsact,a ;de-activate ims skp2: ld (ramdaty+cflag),a ;save cflag ld a,(hl) ;get char. ld (hl),d ;finish updating ims block header res parity,a ret ;---------------------------------------------------------------------- find: ;locate block in pool with id in [a] ld hl,pool find0: cp (hl) ;see if header code matches inc hl ;increment pointer ld e,(hl) ;get offset to next block inc hl ld d,(hl) ret z ;return if block found inc hl ;set pointer to next block add hl,de jr find0 ;keep looking ;---------------------------------------------------------------------- ; Console Output with escape sequence translation ;------------------------------------------------ ; ; on entry to xlate, register c contains the character to be output. ; a test is made to see if the system is in the process of outputing ; a multiple character escape sequence, or if the character is a ; morrow standars control code. if neither test is true, than the ; character is output. ; if the character is part of a multiple character escape sequence, ; then the character is passed to the escape routine. if the ; character is a mscc, then it is converted to the appropriate ; sequence, and output. ; esccod equ 1bh translate_output: ld a,(ramdaty+cflag) bit @xl_out,a jp z,ser1_output ;if translation is enabled, ld a,(esc_lvl) ; test escape flag or a ; check if flag is set jr nz,escape ; if escape sequence, jump ld a,1fh ; test if mscc cp c jp c,ser1_output ; if not, then xmit it ld a,esccod ; check if esc char cp c jp nz,notesc ; if not, jump ld a,1 ; otherwise, set escape ld (esc_lvl),a ; level to 1st stage ret ; and return notesc: ld hl,(ctblptr) ; set to search control table call lookup ; and lookup character in table or a ; see if char found jp z,ser1_output ; if not, output char ld hl,(cvctptr) ; calculate string location ;---------------------------------------------------------------------- ; OUTSTR - Output a string of characters to the console ;------------------------------------------------------ ; ; this routine outputs a string of characters to the console. ; it is used by the translate program to output a terminal ; specific string in order to implement a control sequence. ; when entered, the hl register pair points to the base of ; the string table, and the bc register pair is the offset ; to the string. characters are output starting with the ; first character until a byte value of ffh is detected. ; outstr: add hl,bc ; add offset to base ld e,(hl) ; get location of string inc hl ld d,(hl) ex de,hl ; move address of string to hl loop: ld a,(hl) ; get a char cp 0ffh ; see if done ( ffh==>done) ret z ld c,a ; if not, get char call ser1_output ; xmit it inc hl jr loop ; until end of string page ;---------------------------------------------------------------------- ; ESCAPE - Cursor - Escape_Sequence Translation ;---------------------------------------------- ; ; this routine is used to create a string for direct ; cursor addressing, or to translate character codes. ; upon receipt of an escape code from ; a program, the esc_lvl is set to indicate an escape ; sequence is being output. when the next character is ; received, it is tested to see if it is an equals sign (=). ; if it is not, than an escape character is output, followed ; by the character received. if the character is the equal sign, ; then two more characters will be accepted, after-which a string ; will be output for positioning the cursor. ; escape: ld a,(esc_lvl) ; get current escape level cp 1 ; level 1? jr z,seq1 ; then process 1st part cp 2 ; level 2? jr z,seq2 ; then process 2nd level jr seq3 ; it must be level 3 ; seq1: ld a,'=' ; equal sign? cp c ; if char is =, then dca started jr z,set ; else, could be character to xlate xor a ; clear escape level ld (esc_lvl),a ld hl,(etblptr) ; point to xlate table call lookup ; lookup character or a ; see if char found jr nz,down ; if found, jump to output push bc ld c,esccod ; else, send escape, then char call ser1_output ; send escape pop bc ; get original character jp ser1_output ; send it down: ld hl,(evctptr) ; calculate string location jr outstr ; output the string set: ld a,2 ; otherwise, set for level 2 ld (esc_lvl),a ; processing ret ; and return seq2: ld a,c ld (first),a ; this is the first char ld a,3 ; set for level 3 ld (esc_lvl),a ret seq3: ld a,(offset2) ; get offset for 2nd char add a,c ; add to 2nd char ld (second),a ; save 2nd char ld a,0 ld (esc_lvl),a ; clear escape sequence ld de,first ; pointer to 1st char ld a,(de) ; get 1st char ld c,a ; save in c ld a,(offset1) ; get offset for 1st char add a,c ; add to 1st char ld (de),a ; save 1st char ld a,(order) push af rra sbc a,a ; 0==>1-2 : ff==>2-1 ld b,a ; save order in b ld a,e ; use order to adjust de sub b ld e,a ; de points to 1st char to output ld hl,dcastrt ; pointer to dca prefix sting call loop ; output string ld a,(de) ; get 1st char to output ld c,a pop af bit 1,a ; see if ascii push af call nz,ascout ; call ascii if nz call ser1_output ; output char ld hl,dcamid ; pointer to seperator string call loop ; output string ld a,e ; use order to adjust de add a,b inc b add a,b ld e,a ; de points to 2nd char to output ld a,(de) ; get char to output ld c,a pop af call nz,ascout ; call ascii if flag set call ser1_output ; output char outend: ld hl,dcaend ; point to dca terminator jp loop page ;---------------------------------------------------------------------- ; LOOKUP - Lookup a table ;------------------------ ; ; this routine is entered with the hl register pair pointing to ; the base of a table to be searched. register c contains the ; character to search for. upon return, the accumulator will ; contain 0 if the character was not found, and ffh if it was found. ; if the character was found in the table, then bc will contain ; the offset into the table, multiplied by 2. i.e bc / 2 = location ; of character in table. the maximum number of values in the table is ; 20 h. ; lookup: ld b,0 ; init offset nmtch: ld a,(hl) ; get value from table cp 0ffh ; see if end of table jr z,nochar ; jmp if end cp c ; see if char matches jr z,mtch ; jmp if match inc hl ; inc table pointer inc b ; inc offset inc b ; " " jr nmtch ; continue search mtch: ld c,b ; put offset in bc ld b,0 ld a,0ffh ; set a to success ret nochar: xor a ; set a to failure ret ;---------------------------------------------------------------------- ; ASCOUT - Output a byte in decimal ascii ;---------------------------------------- ; ; ascout takes a binary value in c and output its decimal ascii ; equivalent. ; ascout: push bc ld a,c ld c,'0' ;init to ascii 0 tens: sub 10 ;subtract 10 from value jr c,ones ;jmp if underflow inc c ;inc ascii tens value jr tens ;loop ones: ld b,a ;save intermediate value ld a,'0' ;a = ascii 0 cp c ;see if tens value is 0 call nz,ser1_output ;output tens value if not 0 ld a,3ah ;ascii 0 plus 10 add a,b ;add to produce ones value pop bc ld c,a ;get ready for output ret ;---------------------------------------------------------------------- SUBTTL Banked BIOS -- Character I/O, Device Level page bnk_list: ld a,(ramdaty+cflag) bit @cenlst,a jr nz,centout lstdrv: call bnk_listst ;get serial handshake status jr z,lstdrv ;idle until ready jp ser2_output ;do output centout: call cent_status ;status jr z,centout ;wait for ready jp cent_output ;---------------------------------------------------------------------- bnk_listst: ld a,(ramdaty+cflag) bit @cenlst,a ;if centronics list jp nz,cent_status bit @hwsync,a ;check handshake mode jr nz,nolx ;jmp if not XON-XOFF call ser2_input_status call nz,ser2_input ; get a character or null cp 13h ; if xoff r'cvd... jr nz,nxtchk ; if not, check if xon ld a,0 ; set flag to not rdy ld (lstflg),a ret ; return not rdy nxtchk: cp 11h ; if xon, then it might be ready jr nz,chkflg ; else, state not changing ld a,0FFh ld (lstflg),a ; set flag to rdy chkflg: ld a,(lstflg) ; get status flag lstret: or a ; set flags ret z ; if zero, then xoff pending nolx: jp ser2_output_status lstflg: db 0FFh ;X-on X-off (initial value = 0FF) page ;---------------------------------------------------------------------- ; Console Device Drivers ;----------------------- ; ser1_input_status: in a,(s1stat) and 1 ret z ld a,-1 ret ser1_input: call ser1_input_status jr z,ser1_input in a,(s1data) and 7fh ret ser1_output_status: in a,(s1stat) and $txrdy ret z ;exit if none ld a,-1 ret ser1_output: call ser1_output_status jr z,ser1_output ;wait for prev char ld a,c and 7fh out (s1data),a ret page ;---------------------------------------------------------------------- ; Serial List Device Drivers ;--------------------------- ; ser2_input_status: in a,(s2stat) and 1 ret z ld a,-1 ret ser2_input: call ser2_input_status jr z,ser2_input in a,(s2data) and 7fh ret ser2_output_status: in a,(s2stat) and $txrdy ret z ;exit if none ld a,-1 ret ser2_output: call ser2_output_status jr z,ser2_output ;wait for prev char ld a,c and 7fh out (s2data),a ret ;---------------------------------------------------------------------- ; Auxilary List Device Drivers ;----------------------------- ; ser3_input_status: in a,(s3stat) and 1 ret z ld a,-1 ret ser3_input: call ser3_input_status jr z,ser3_input in a,(s3data) and 7fh ret ser3_output_status: in a,(s3stat) and $txrdy ret z ;exit if none ld a,-1 ret ser3_output: call ser3_output_status jr z,ser3_output ;wait for prev char ld a,c and 7fh out (s3data),a ret page ;---------------------------------------------------------------------- ; Centronics Parallel Device Driver ;---------------------------------- ; cent_status: in a,(cstat) and $CNTRDY ;test for busy = zero ret z ;exit false xor a dec a ;set true ret cent_output: ld a,c ;get char and 7fh out (cdata),a ;write data di ld a,(system_bank_bits) or $CNTSTB out (bnkstb),a ;strobe on ld b,10 cntdly: djnz cntdly ;delay and not $CNTSTB out (bnkstb),a ;strobe off ei ret SUBTTL Resident BIOS -- Jump Table page ;---------------------------------------------------------------------- cseg ;resident ;---------------------------------------------------------------------- bios: jp boot ;arrive here from cold start load warmpt: jp wboot ;arrive here for warm start jcons: jp const ;return console input status jconi: jp conin ;read console character jcono: jp conout ;write conlole character jp list ;write list character jp auxout ;write aux character jp auxin ;read aux character jp home ;move to track zero on selected drive jp seldsk ;select disk drive jp settrk ;set track number jp setsec ;set sector number jp setdma ;set DMA address jp read ;read selected sector jp write ;write selected sector jp listst ;return list device status jp sectrn ;translate logical to physical sector number jp conost ;return console output status jp auxist ;return aux device input status jp auxost ;return aux device output status jp devtbl ;return address of character i/o table jp devini ;init character i/o devices jp drvtbl ;return address of disk drive table jp multio ;set number of consec. sec. to read/write jp flush ;flush user [de]blocking buffers jp move ;copy memory to memory jp time ;clock support jp selmem ;select memory bank jp setbnk ;set bank for next DMA jp xmove ;set banks for next move jp userf ;reserved for me. jp wboot ;reserved for DRI jp wboot ;reserved for DRI dpb_buffer: ds dpb_length,0 ;current dpb must be in common ;---------------------------------------------------------------------- ; BANKING CONSIDERATIONS ; we all live by rules, the following shall be observed: ; 1.) the routines SELMEM and MOVE shall always reside in common. ; 2.) interrupt entry points shall always reside in common. ; 3.) the interrupt save/restore routines, and the sytem stack ; shall always reside in common. ; 4.) the system_stack save/restore routines shall reside in common. ; 5.) the call_bank/restore_bank routines shall reside in common. ; 6.) access to rom code shall never be made from common, only ; from the banked part of the bios (except for error exits) ; 7.) routines may be freely moved from the banked part to rom ; when doing so does not require co-binding of rom and bios. ; ; observing the above will make life more pleasant and will prevent ; brutalizations of our personal joules. ; ;---------------------------------------------------------------------- devtbl:: ld hl,0 ;no table time:: devini:: userf:: ld a,-1 ret ;---------------------------------------------------------------------- SUBTTL Resident BIOS -- Bank Crossing Routines page res_wboot: ld hl,(vnumb) ;get drive & terminal level ld a,1 ;tpa call selmem ;switch to tpa bank ld (8),hl ;save in page0 jp tpa services:: ;hook-up with bios extensions ld (hl_entry),hl ld (bc_entry),bc ld b,0 ld c,a ld hl,bnk_services jr inter_bank hl_entry: ds 2,0 bc_entry: ds 2,0 wboot:: ld hl,bnk_wboot jr inter_bank ;note, return_from_inter_bank not executed const:: ld hl,bnk_const jr inter_bank conin:: ld hl,translate_input jr inter_bank conost:: ld hl,ser1_output_status jr inter_bank auxin:: ld hl,ser3_input jr inter_bank auxist:: ld hl,ser3_input_status jr inter_bank auxost:: ld hl,ser3_output_status jr inter_bank auxout:: ld hl,ser3_output jr inter_bank listst:: ld hl,bnk_listst jr inter_bank list:: ld hl,bnk_list jr inter_bank conout:: ld hl,translate_output jr inter_bank ;---------------------------------------------------------------------- inter_bank: ;transfer control to bank 1 (sys), and force path back ; ;note: this code passes control to the system bank for all character io, ; and others which should be in common. to facilitate migration ; of code from system bank to rom, the rom is turned on here. ; note that res_bdos can request the system bank, then pass control ; to bnk_bdos, and bnk_bdos can request character io while the system ; bank is already on, thus, the rom control bit is tested to prevent ; double execution. ld a,(system_bank_bits) ;get current bits bit 0,a ;see if rom already on jr nz,inter_bank2 ;if rom already on, jp (hl) ; don't do this twice, exit now. inter_bank2: ;rom is not on yet, and not ($bank2 + $_rmenb) ;select rom, bank1 di ;no interrupts while system_bank_bits don't reflect system out (bnkstb),a jp bnk_inter_bank ;do more below ;inter_bank continues in sys_bank, res_bnk_return begins in sys_bank res_bnk_return: ;return control to bank 2 (tpa) out (bnkstb),a ;restore bank 2 (tpa) ei pop af ;restore pop hl ld sp,(save_user_stack) ret ;---------------------------------------------------------------------- SUBTTL Resident BIOS -- Inter_bank Moves, Bank control page move:: ;[de]=source ;[hl]=dest ;[bc]=count ;[de]updated ;[hl]updated ;[bc]=0 ld a,(bnkmsk) ;see if xmove or a ;test jr z,move1 ;if xmove, di ;no interrupts during interbank xfer out (bnkstb),a ;select desired bank, rom off xor a ld (bnkmsk),a ;clear bank mask move1: ex de,hl ldir ;move ex de,hl ld a,(system_bank_bits) out (bnkstb),a ei ret bnkmsk: db 0 ;non-zero desired bank bits init in xmove ;---------------------------------------------------------------------- selmem:: ;select memory now, [a]=desired bank, 0 or 1 push hl ld hl,system_bank_bits di res 1,(hl) ;presume bank 0 add a,a ;*2 for bnkstb or (hl) ;switch to bank 1?? ld (hl),a ;update pop hl out (bnkstb),a ;set hardware ei ret ;note: the system_bank_bits are used by the bios to control bank switching ; and the centronics port. Ramdaty.CPYBNK is not used because it does ; not reside in common. This byte is initialized in boot2 ; system_bank_bits: db 0 ;Setup in Boot2 ($cntrst ! rom-off) ;---------------------------------------------------------------------- SUBTTL Resident BIOS -- Interrupt Handling Routines page interrupt_save: ;routine is called by interrupt entry ex (sp),hl ;save hl, get return ld (save_int_stack),sp ;save stack ld sp,interrupt_stack push af ;save [af] push hl ld hl,interrupt_exit ex (sp),hl ;save a return to exit jp (hl) ;ret ;interrupt service routines are responsible for saving [bc],[de] if used interrupt_exit: pop af ld sp,(save_int_stack) pop hl ei reti centronics_isr: call interrupt_save ld a,(system_bank_bits) push af ;save res 0,a ;rom off set 1,a ;bank 2 (tpa) on out (bnkstb),a ld hl,centronics_exit push hl ld hl,(0fffah) ;redirection vector jp (hl) centronics_exit: ;restore system pop af out (bnkstb),a ret ;---------------------------------------------------------------------- SUBTTL Resident BIOS -- Stacks and Interrupt Vectors page ;high ram definitions, not much space, be sparse interrupt_stack equ 0ffc6h save_int_stack equ 0ffc6h ;note, the interrupt stack is overwritten by ;the system stack (which is small) during ;warm boot (which is the only time the rom uses ;the system stack, and runs it down to 0ffaah, ;but character interrupts are off by then.) system_stack equ 0ffd6h save_user_stack equ 0ffd6h ;reserved space, interupt vectors: ;ffd8-ffdf 4 vectors for sio/9 ;ffe0-ffef 8 vectors for dart ;fff0-fff9 5 vectors for disk system and centronics ;fffa-fffb redirection vector reserved for spool rsx ;fffc-fffd redirection vector available ;fffe-ffff redirection vector reserved for minimon break (rst 30h) end