Title MD-11 BIOS, Copyright (c) 1984, Morrow Designs, Inc. (17_Apr_84) ; ; Copyright (c), 1983, 1984, ; Morrow Designs, Inc. ; 600 McCormick ; San Leandro, Ca. 94577 ; Bill Smith ; .z80 ;This file is assembled using Zilog nmenonics ; ; ; CP/M Plus BIOS -- Table of Contents ;------------------------------------ ; ; Include Files General Definitions File ; Drive Definitions (Dpb, Dph and Mtabs) ; Drive Type and Organization Definitions ; ; System Equates External Declarations ; Local Data Definitions ; ; Banked BIOS Character Tables and Local Equates ; Block I/O ; CCP Loader ; Extended BIOS Functions ; Data Structures, DPH ; Data Structures, DPB ; Data Structures, RAMDATY ; Data Structures, MTABs ; Data Structures, Free Space Pool ; Character I/O, Initialization ; Character I/O, Translation Level ; Character I/O, Device Level ; ; Resident BIOS Jump Table ; Bank Crossing Routines ; Inter-Bank Utilities ; Non Bank Crossing Routines ; Interrupt Handlers ; Local Data Area ; 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 Subttl Banked Bios - Include Files page ;---------------------------------------------------------------------- ; Include Files ;-------------- ; include HD21DEF.MAC ;General Definitions File include DRIVES.MAC ;Drive Definitions (Dpb, Dph and Mtabs) include DEFINE.MAC ;Drive Type and Organization Definitions Subttl Banked Bios - External Declarations and Local Equates page ;---------------------------------------------------------------------- ; External Declarations ;---------------------- ; External @civec External @covec External @aivec External @aovec External @lovec External @bnkbf External @crdma External @crdsk External @vinfo External @resel External @fx External @usrcd External @mltio External @ermde External @erdsk External @media External @bflgs External @date External @hour External @min External @sec External ?erjmp External @mxtpa Public boot Public char_tables Public ser1baud Public vnumb Public tlev Public vmsg Public vdrv Public multio Public flush Public home Public settrk Public setsec Public setbnk Public setdma Public sectrn Public seldsk Public read Public write Public rwmove Public xmove Public bnk_wboot Public bnk_format Public drvtbl Public sdpb Public ramdatY Public APIF Public mtab Public pool Public xltab Public xlt1k page ;---------------------------------------------------------------------- ; Local Equates ;-------------- ; BioRev equ 18h ;Current Bios Revision ; Address Definitions ;-------------------- ; tpa equ 100h ;Start of the TPA dffcb equ 5ch ;First Default FCB built by the CCP stack80 equ 100h ;Top of the Default Stack bdos equ 5 ;Bdos Entry Point ccp equ tpa ;Start of the CCP ; Bdos Function Numbers ;---------------------- ; getch equ 1 print equ 9 open equ 15 readseq equ 20 dma equ 26 parse equ 152 ; Rom Entry Points ;----------------- ; 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 ; Default Baud Rate Settings ;--------------------------- ; dflt1 equ 6 ;Console 9600 Baud dflt2 equ 3 ;List 1200 Baud dflt3 equ 6 ;Sio 9600 Buad ; Misc Definitions ;----------------- ; bootram equ 0 dpb_length equ 17 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 $txrdy equ 4 edv equ 40h ;bad drive from format entry primary equ 0 parity equ 7 dsktln equ 25 dsktb equ dskbuf+80h+dsktln ;address of end of table+1 dsktdb equ dskbuf+80h+9 esccod equ 1bh leadin equ 1ch Subttl Banked Bios - Character Tables and Local Data Areas page ;---------------------------------------------------------------------- ; Boot Entry ;----------- ; entry here placed at front of bnkbios as pointer ; to be used by external system programs to size system ; when examining cpm3.sys file ; dseg ;Banked Bios boot: jp boot2 ;jump to high common, end of code ;---------------------------------------------------------------------- ; Character Table ;---------------- ; these tables are provided for external programs which ; examine CPM3.SYS, must follow jump above char_tables: 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 4 ;terminal level default = 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 page ;---------------------------------------------------------------------- ; Virtual Drive Messages ;----------------------- ; 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 ;---------------------------------------------------------------------- ; Other Local Data Definitions ;----------------------------- ; lstflg: db 0FFh ;X-on X-off (initial value = 0FF) sector_length: dw 0 ;init by seldsk dmabnk: ds 1,0 baudtbl: dw 1136 *2 ;0 110 dw 417 *2 ;1 300 dw 208 *2 ;2 600 dw 104 *2 ;3 1200 dw 52 *2 ;4 2400 dw 26 *2 ;5 4800 dw 13 *2 ;6 9600 dw 13 ;7 19,200 dw 1 ;8 Reserved dw 1 ;9 Reserved dw 1 ;10 Reserved ims_flag: db 0 ;type of inject IMS ;0 = internal function key ;1 = external read_after_write: db 2 ;default = pre-reads on ims_length_byte: db 0 ;storage (dest for interbank move) Subttl Banked Bios - Block I/O page ;---------------------------------------------------------------------- ; Block I/O ;---------- ; 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 ;---------------------------------------------------------------------- setbnk: ;define dma bank ld (dmabnk),a ret ;---------------------------------------------------------------------- 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) 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 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 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 page ;---------------------------------------------------------------------- ; Extended bios functions (9_Apr_84) ;----------------------------------- ; 1) entry parameters ; bc = function number, 0 -> n (b=0) ; de,ix = parameters if needed ; hl_entry and bc_entry are also available ; 2) exit parameters vary ; bnk_services: 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,func18 max_func equ ($-function_table)/2 page ; read from system memory ;------------------------ ; [de] -> dest (tpa) ; hl_entry -> source (sys) ; bc_entry = length ; func0: ld hl,(hl_entry) ld bc,(bc_entry) jr tpa_move ;tpa_move stepping-stone ; write to system memory ;----------------------- ; [de] -> dest (sys) ; hl_entry -> source (tpa) ; bc_entry = length ; func1: ld hl,(hl_entry) ld bc,(bc_entry) jr sys_move ; read ramdaty and apif to [de] ;------------------------------ ; func2: ld hl,ramdaty ld bc,mtoff jr tpa_move ; read mtabs to [de] ;------------------- ; func3: ld hl,ramdaty+mtoff ld bc,5*16 jr tpa_move ; read drvtbl and all DPH to [de] ;-------------------------------- ; func4: ld hl,drive_table ld bc,32+drives*dphlen jr tpa_move ; read dpb_table and all DPB to [de] ;----------------------------------- ; func5: ld hl,dpb_table ld bc,dpb_table_leng jr tpa_move ; read character table to [de] ;----------------------------- ; func6: ld hl,char_tables ld bc,char_table_length jr tpa_move ; read virtual drive message to [de] ;----------------------------------- ; func7: ld hl,vmsg ld bc,vmsg_length jr tpa_move ; read free space to [de] ;------------------------ ; func8: 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 ; 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. ; func12: 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 ; enable/disable disk read after write, [e]=0=disable, 1=enable ; enable/disable disk read before write, 2=enable ;------------------------------------------------ ; [e] contains bit mask ; func13: ld hl,read_after_write ld d,(hl) ;return what it was before ld (hl),e ret ; execute in bank 1 (sys) at [hl] ;-------------------------------- ; func14: ld iy,ramdaty ld hl,(hl_entry) ld bc,(bc_entry) jp (hl) ; verify track, destructive ;-------------------------- ; func15: ld iy,ramdaty set @bufok,(iy+opflag) jr f15a ; verify track, non-destructive ;------------------------------ ; func16: 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 ; modify contents of cflag to contents of [e], return previous in [d] ;-------------------------------------------------------------------- ; func17: ld hl,ramdaty+cflag ld d,(hl) ld (hl),e ret ; Read the System ID Frame ;------------------------- ; 1) This routine moves the system ID Frame into the Tpa address ; specified by the user. ; 2) The ID Frame has the following format ; 1 Rom Revision number ; 1 Compatibility Level ; 8 Reserved for second source ID Information ; 2 Starting address of checksummed block ; 2 Length of checksummed block ; 1 Ram Checksum ; 1 Rom Checksum ; func18: ld hl,50h ;Starting location of Rom ID block ld bc,10h ;Length of Rom ID Block ld a,(system_bank_bits) ;include centronics controls push af and 0FCh ;Enable Rom And Bank 1 or $Xfer ;Set the transfer bit out (BnkStb),a ldir ;Move the Rom ID Block into the Tpa pop af out (BnkStb),a ;Restore the Bank Strobe ret ;---------------------------------------------------------------------- ;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) ; bnk_format: 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 ;login floppy by writing format's copy of disk info to diskbuf formf: 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 ;---------------------------------------------------------------------- ; enter [a] = drive, [iy] or [hl] -> ramdaty ; return [hl] -> drive's MTAB gdsk: 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 ;---------------------------------------------------------------------- ; System DPB's ;------------- ; table defines logical to physical mapping of dpb's. ; structure is same as drive_table, all dph point at same dpb_buf ; in common. dpb_table: table_gen dpb dw 0 ;terminator struct_gen dpb 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 page ;---------------------------------------------------------------------- ; 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 ;---------------------------------------------------------------------- ; System Mtabs ;------------- ; mtab: struct_gen mt Subttl Banked Bios - Free Space Pool page ;---------------------------------------------------------------------- ; Free Space Pool ;---------------- ; pool: ;beginning of managed space ; Disk Translation Table ;----------------------- ; xltab: db 0 dw 5 xlt1k: db 1,4,2,5,3 ; Console Translation Table ;--------------------------- ; 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 ; Free Space Pointer ;------------------- ; db 0ffh ;End of Free Space Header dw 870 ;Initial Free Space Length ; Sign On Message and Free Space Storage Allocation Definitions ;-------------------------------------------------------------- ; 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 Sol equ $ - Sign_On_Start ds (470 - Sol), 0 ; Ims Buffer Header ;------------------ ; db 0fdh ;Ims Buffer Header dw 0 ;Ims Length ; Function Key Translation Header ;-------------------------------- ; db 0fch ;Function Table Header dw function_table_length ;Function Table Length translation_table: db 23 ;# entries db 4ah,1,2 db 6ah,1,17h db 0ah,1,17h ;up arrow db 4bh,0 db 6bh,0 db 0bh,0 ;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 db 49h,1,18h db 69h,1,0bh db 09h,1,0bh ;Erase db 1ah,1,9h db 1bh,1,9h ;Tab function_table_length equ $-translation_table pool_length equ $-pool Subttl Banked Bios - Character I/O - Initialization page ;---------------------------------------------------------------------- ; Initialization ;--------------- ; 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: call setbaud ;do setbaud ret ;set channel mode from [A], output 2 bytes from (hl) to (c) ;---------------------------------------------------------- ; setbaud: out (baudset),a ;set mode ld a,(hl) ;timer lo inc hl out (c),a ld a,(hl) ;timer hi out (c),a ret ;index into baudtbl using [A], leaving [HL] on value ;--------------------------------------------------- ; getval: ld hl,baudtbl ;base of bit rate values add a,a ;*2 ld c,a ld b,0 add hl,bc ret Subttl Banked Bios - Character I/O - Translation Level page ;---------------------------------------------------------------------- ; Bank Console Status ;-------------------- ; bnk_const: ld a,(ramdaty+cflag) ;get cflag bit @funact,a ;see if function key IMS is active ld a,0ffh ;set ready in case ret nz ;ret if function key 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 ;---------------------------------------------------------------------- ; Console Input with Function Key Translation ;-------------------------------------------- ; 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 ;---------------------------------------------------------------------- ; Banked Ims Injection Routines ;------------------------------ ; bnk_inject_ims: ;available to tpa programs ld a,1 ;external inject ld (ims_flag),a ;set flag 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 ;enter with [DE] -> string with length byte first, ; exit with IMS active inject_ims: ld a,0 ;internal inject ld (ims_flag),a ;set flag 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 ex de,hl ;[de] -> destination end, ims buffer ld hl,ramdaty+cflag ld a,(ims_flag) ;get IMS type flag or a jr z,fcn5 ;jmp if internal 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 parity,a ; and mark it to turn-off ims at end of this string ld (de),a fcn4: set @imswet,(hl) ;activate ims set @imsact,(hl) ret ;exit with carry = clear fcn5: dec de ;point at last char, this string, ld a,(de) set parity,a ;and mark it to turn-off ims at end of this string ld (de),a set @funact,(hl) ;set function key IMS active ret 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: ld a,(ramdaty+cflag) ;get cflag bit @funact,a ;see if function key IMS is active jr nz,subgo ;get char. 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 bit @funact,a ;see if function key IMS is active res @funact,a ;clear function key IMS jr nz,skp2 ;skip if function key was active 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 ;---------------------------------------------------------------------- ; locate block in pool with id in [a] ;------------------------------------ ; find: 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. ; 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 ;---------------------------------------------------------------------- ; List Device Drivers ;-------------------- ; 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 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 centout: call cent_status ;status jr z,centout ;wait for ready jp cent_output page ;---------------------------------------------------------------------- ; Serial Port 1 - (Default 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 Port 2 - (Default 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 ;---------------------------------------------------------------------- ; Serial Port 3 (Default Auxilary 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 - Banking Considerations and Bios Jump Table page ;====================================================================== ; Resident Bios - 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. ; ;---------------------------------------------------------------------- ; External Declarations ;---------------------- ; Public devtbl Public time Public devini Public userf Public services Public wboot Public const Public conin Public conost Public auxin Public auxist Public auxost Public auxout Public listst Public list Public conout Public selmem ;select memory now, [a]=desired bank, 0 or 1 Public move Subttl Resident Bios - Jump Table page ;---------------------------------------------------------------------- ; Resident Bios - Jump Table ;--------------------------- ; cseg ;Begin the Resident Bios Module Code 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 page Subttl Resident Bios - Bank Crossing Routines page ;---------------------------------------------------------------------- ; Bank Crossing Routines ;----------------------- ; 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 (cold boot entry) ld (hl_entry),hl ld (bc_entry),bc ld b,0 ld c,a ld hl,bnk_services jr inter_bank 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 Subttl Resident Bios - InterBank Utilities page ;---------------------------------------------------------------------- ; 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. ; inter_bank: 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 ;IRQ Off while system_bank_bits Invalid 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 - Non Bank Crossing Routines page ;---------------------------------------------------------------------- ; Misc Null Routines ;------------------- ; devtbl: ld hl,0 ;no table time: devini: userf: ld a,-1 ret ;---------------------------------------------------------------------- ; InterBank Move ;--------------- ; 1) Enter with ; BC -> Count ; DE -> Source ; HL -> Destination ; 2) Exit with ; BC -> 0 ; DE -> Source + Count ; HL -> Destination + Count ; move: 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 ;---------------------------------------------------------------------- ; Select Memory ;-------------- ; 1) select memory now, [a]=desired bank, 0 or 1 ; selmem: 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 Subttl Resident BIOS - Interrupt Handling Routines page ;---------------------------------------------------------------------- ; Interrupt Handling Rotuines ;---------------------------- ; 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 - Local Data Area, Stacks and Interrupt Vectors page ;---------------------------------------------------------------------- ; Resident Bios - Local Data Area ;-------------------------------- ;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 ; hl_entry: ds 2,0 bc_entry: ds 2,0 dpb_buffer: ds dpb_length,0 ;current dpb must be in common system_bank_bits: db 0 ;Setup in Boot2 ($cntrst ! rom-off) bnkmsk: db 0 ;desired bank bits set in xmove ;---------------------------------------------------------------------- ; Stacks and Interrupt Vectors ;----------------------------- ; ;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