IMD 1.15: 16/05/2007 8:33:28 DOUBLE SIDED RELEASE DISK 2 OF 7 10/14/84 DAB BIOSSOURCE V1.3 EXCBIOS DOCOPQRSTUVWEXCBIOS5BAK~ !"#$EXCBIOS5MAC|^_`abcdefghijEXCBIOS1BAK/EXCBIOS0BAK%28@EXCBIOS1MAC2CHIJDSWTSYS MACX 34567EXCBIOS4BAK 9:;<=>?EXCBIOS0MAC& ABEXCBOOT MACN DEFGEXCBIOSELIB+ MASSY kEXCBIOS6MACEXCBIOS3MAC&SCB RELxEXCBIOS2MACL%&'()*+,-./01SCB PRNlEXCBIOS0RELmEXCBIOS1RELnEXCBIOS2REL oEXCBIOS3RELpSCB ASMKLEXCBIOS MACNEXCWTSYSMACUXYZ[\]EXCBIOS4RELqEXCBIOS5RELrsEXCBIOS6RELtEXCBOOT RELuDSWTSYS REL vSCB SYMwEXCBIOS4MAC|yz{|}~SYSIN58 $$$ DSWTSYS COMDSWTSYS SYMCPMLDR COM EXCBOOT COMEXCBOOT SYMCPMLDR SYMBNKBIOS3SPR*BNKBIOS3SYMXXABS $$$; EXCBIOS.DOC ; ; ; ; CP/M Plus BIOS V1.10 ; for the Osborne Executive ; ; ; Copyright (c) 1983 Osborne Computer Corp. ; ; ; ; 1983-06-23 set for 2nd release ; device time-out modification ; ; 1983-03-20 set for 1st release (+ fix some doc) ; 1983-03-13 restructured doc into separate file ; clarified gen procedures ; ; ; ; Table of Contents for this documentation: ; ; (1) The components of this BIOS. ; (2) The generation procedures. ; (3) General assumptions and requirements. ; (4) Messages issued by the BIOS. ; (5) General thoughts and notes. ; ; ; Note: CP/M Plus is also referred to as CP/M 3.0 ; page ; The components of this BIOS. ; ; ; Each source file contains a change history at the ; front. This tracking began from the first alpha ; release not from the time the BIOS was created. ; ; ; A. EXCBIOS.DOC (and .MAC) ; This file which contains only documentation. ; It is assembled solely to produce a .PRN file ; for printing with the rest of the BIOS. ; ; B. EXCBIOSx.MAC (m80 source files) ; ; 0 The jump table and unchanging routines ; 1 The disk tables (dph, dpb and sectran) ; 2 The serial i/o routines and tables ; 3 A few misc. routines (move, xmove) ; 4 The disk i/o routines proper ; 5 The warm and cold boot routines ; 6 The special cpmldr bios (replacing 2 & 5) ; ; C. EXCBIOSE.LIB (included during all other assemblies) ; These are common system equates including common ram ; locations and rom addresses. This file is listed only ; at the end of this assembly. ; ; D. EXCBOOT.MAC ; The first track bootstrap loader. ; ; E. EXCWTSYS.MAC ; This is a special program that takes EXCBOOT.COM, ; CPMLDR.COM and CCP.COM and writes them out to the ; system tracks (0 and 1) of the diskette in drive B. ; If files FONTM.COM, FONTA.COM and ROMRAM.COM exist, ; they are used to create track 2. Note that the bios ; override sector of track 1 is created from the ; currently running system. ; ; F. .z80 title bios5 (excbios5) cold / warm boots ;1984-09-22 DAB Installed code to support Vixen format dsdd. ; Reads CCP.COM from file at wboot if boot disk is dsdd. ; Reads alternate font from ALTFONT.SYS if boot is dsdd. ; 06-23-1983 added initialization of device timeout values, ; changed serno to check for status, display message and restore screen ; and to change delay value after first time ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; this module contains the code for the cold and warm ; boots for the actual bios. The cboot will always ; load the ccp from the system tracks into low mem of ; bank 0, but will attempt to load the file.z80 title bios6 (excbios6) LDRBIOS cold / warm boots ; 1983-03-20 set for 1st release ; 1983-02-23 nop support of err msgs (disk, dev not rdy) ; 1983-02-22 change name romjmp to torom ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; this is a fairly stripped down bios allowing the ; std bios to be used as much as possible. This bios ; is used ONLY for cpmldr and could be a single source ; module, but uses the std bios disk drivers, jump table ; and misc routines (move etc.). Obviously, the boot ; functions are different for this ldrbios. ; This module written by Glenn S. Tenney ; include EXCBIOSE.LIB .xlist  'EXECST.COM' ; into the tpa (only on cboot). This allows some user ; program to gain control instead of the ccp and without ; using the profile.sub feature which requires submit ; and a writeable disk. .xlist include EXCBIOSE.LIB .list public cboot,wboot public stdsen,stderr ; std disk i/o err rtns public sernr ; serial not ready err rtn extrn wboot@,@mxtpa extrn conout,conin,conist extrn @civec,selmem ; setbnk extrn @sec ; seconds field of tod extrn move,xmove ; for ccp.com in bank 0 extrn drvtbl,devtbl ; cboot init from sys tracks extrn @media ; media change flag in bios extrn dph0,dph1 ; our own built-in dph's extrn dpbtbl ; table of dpb's extrn signon ; signon message at cboot extrn initvec ; initial i/o redirection vectors extrn devini ; serial device init extrn @bnkbf ; 128 byte area for use during boots extrn drive,actcnt,dmabk ; for err msgs extrn @ermde ; flag if errs passed to bdos extrn vers ; the version number this bios ex include EXCBIOSE.LIB .list public cboot,wboot public area0 ; so we can know where i/o area is extrn drvtbl ; we have to change the drive 0 dph extrn setbnk ; init the bank for disk i/o too public devtbl ; the device table public devini ; device init public conout,auxout,list ; output routines public conost,auxost,listst ; output status public conin,auxin ; input routines public conist,auxist ; input status public stdsen,stderr,stdnr ; err msg routines extrn torom ; off to rom cseg ; to be like rest of bios cboot: wboot: ; we have to dummy up the bcb's in a,(sys) ; current bank call setbnk ; this is bank for doing all disk i/o ld hl,(drvtbl) ; pt to list of drives ld de,18 add hl,de ; hl=dph0+18 ( dirbcb field ) ld bc,ldrbcb0 ; now store in addr of 1st bcb ld (hl),c inc hl ld (hl),b inc hl ; hl=dph0+ 20 ( dtabcb field ) ld bc,ldrbcb1 ; now store in addr of 2nd bcb ld (hl),c inc hl ld (hl),b ret ; these d.z80 title bios5 (excbios5) cold / warm boots ;1984-09-22 DAB Installed code to support Vixen format dsdd. ; Reads CCP.COM from file at wboot if boot disk is dsdd. ; Reads alternate font from ALTFONT.SYS if boot is dsdd. ; 06-23-1983 added initialization of device timeout values, ; changed serno to check for status, display message and restore screen ; and to change delay value after first time ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; this module contains the code for the cold and warm ; boots for the actual bios. The cboot will always ; load the ccp from the system tracks into low mem of ; bank 0, but will attempt to load the file ; cboot ; the cboot entry is in common so in case some ; weirdo jp's to it the system won't go south. cboot: ld sp,(@bnkbf) ; put a stack in common ld a,80h ; force rom + bank 0 out (sys),a jp cboot0 ; go do real cboot work dseg ; cold boot ok in bank 0 (it really is) cboot0: ; actual cold boot work here ; set rom's ram to keep time in scb ld hl,@sec ; pt to seconds field ld (clkptr),hl ; now rom knows where to keep time ; point rom's ram to media change flags so that interrupt ; routine can post a disk changing di ; data changed during interrupts ld hl,@media ; pt to scb's flag ld (media),hl ; so rom know's what to post ld hl,dph0+dphmf ; and built-in drive a ld (adrive),hl ld hl,dph1+dphmf ; and b drive ld (bdrive),hl ei ; rom can handle interrupts now ld hl,(romver) ; copy rom's version # ld (rvers),hl ld hl,(romver-2) ; and product+feature ld (rvers+2),hl ; read ccp.com into bank 0 location 0 if disk is ssdd 840924 ; Also loa 'EXECST.COM' ; into the tpa (only on cboot). This allows some user ; program to gain control instead of the ccp and without ; using the profile.sub feature which requires submit ; and a writeable disk. .xlist include EXCBIOSE.LIB .list public cboot,wboot public stdsen,stderr ; std disk i/o err rtns public sernr ; serial not ready err rtn extrn wboot@,@mxtpa extrn conout,conin,conist extrn @civec,selmem ; setbnk extrn @sec ; seconds field of tod extrn move,xmove ; for ccp.com in bank 0 extrn drvtbl,devtbl ; cboot init from sys tracks extrn @media ; media change flag in bios extrn dph0,dph1 ; our own built-in dph's extrn dpbtbl ; table of dpb's extrn signon ; signon message at cboot extrn initvec ; initial i/o redirection vectors extrn devini ; serial device init extrn @bnkbf ; 128 byte area for use during boots extrn drive,actcnt,dmabk ; for err msgs extrn @ermde ; flag if errs passed to bdos extrn vers ; the version number this bios exds BIOS/SETUP override from sector 5 840924 call 100h+senden ; Call sense density to force setting 840924 ; of side bit 840924 ld a,(savtyp) ; Check for ssdd 840924 bit 1,a ; Bit 1 (side bit) is nz if dsdd 840924 jr nz,notssdd ; Not ssdd... 840924 xor a ; Set dsdd flag zero (false) 840924 ld (dsdd),a ; 840924 ld hl,0 ; ssdd, so load ccp from sys tracks 840924 ld (dmabank),hl ; set bank 0 ld (dmadr),hl ; set dma addr to zero ld hl,0101h ; track 1 sector 1 ld (actsec),hl ld b,5 ; read 5 sectors (full track) ; 1-4 ccp.com 5 our tables table equ 1000h ; this is where sector 5 ; appears in memory call 0100h+rsec ; ask rom to read it in or a ; see if any error jp nz,booterr ; yes, issue a msg and hang ; jp chktbl ; No, Check the table 840925 ; notssdd: ; Disk is dsdd 840924 ld a,0ffh ; Set dsdd flag true 840924 ld (dsdd),a ; 840924 ld a,(savtyp) ; Load current savtyp 840925 push af ; Save on stk 840trn rvers ; place to put rom's version EXTRN DELAY,DELAY0 EXTRN OUTST EXTRN ROMMV ; equates used by the boot tpa equ 0100h ; start of the tpa bdos equ 5 ; where to call the bdos open equ 15 ; bdos open call setdma equ 26 ; bdos set dma addr call setmult equ 44 ; bdos set multi sector count read equ 20 ; bdos read that many sectors flush equ 48 ; bdos purge buffers dphmf equ 0bh ; offset from dph to its media flag byte dpbcks equ 0bh ; offset fm dpb to its cks (for perm disk) dpblen equ 17 ; length of one dpb (not our header) ccplen equ 0cffh ; length of ccp.com ; cboot ; perform cold (onetime) initialization ; This sets up various areas as needed, including ; reading the ccp.com from track 1 into bank 0 location 0. ; Special note: @bnkbf is a ptr to a 128 byte buffer ; within resident bdos for use during cboot or wboot. ; Well, this is being used as the boot time stack to ; help conserve space. cseg ; bios jmp table pts to a common entry 925 set 1,a ; Set side 1 840925 ld (savtyp),a ; Save it 840925 ld hl,0 ; Load BIOS/SETUP override 840925 ld (dmabank),hl ; set bank 0 840925 ld hl,table ; Specify address of table 840925 ld (dmadr),hl ; as dma addr 840925 ld hl,0001h ; Read from (side 1) track 0 sector 1 840925 ld (actsec),hl ; 840925 ld b,1 ; read 1 sector 840925 call 0100h+rsec ; ask rom to read it in or a ; see if any error jp nz,booterr ; yes, issue a msg and hang 840925 ; old savtyp still on stk 840925 pop af ; Restore old savtyp from stk 840925 ld (savtyp),a ; Save it back 840925 chktbl: ; 840925 ; (Note: still bank 0) xor a ; turn rom off for a while now out (sys),a ; while we look at what we just read ; copy our tables from system track (last sector) just ; after the ccp.com ; the problem here is making sure that when the bios is ; re-assembled the old data on disk doesn't get used ; this is taken care of by verifying that the d.z80 title wtsys (excwtsys) writes cpmldr.com to system tracks ;1984-09-22 DAB ;1983-06-23 Set for second release ; added initialization of track 1 sector 5 for device time-out ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; this is really a very crude program designed for ; the infrequent need to create a diskette with ; new system tracks (0, 1 and sometimes 2) composed of: ; excboot, cpmldr, ccp, the special bios overlays, ; the fonts and the rom's ram overrides. ; Written by: Glenn S. Tenney ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list open equ 15 read equ 20 setdma equ 26 pmsg equ 9 bdo title bios1 (excbios1) disk drive tables ;1984-10-14 DAB Changed OFFset field in OCC DSDD to 1 to make Vixen ; compatible. ; Added extra dpb for later use. ;1983-07-27 Set up new DPB and sector XLT table for DSDD ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; This module is only the various disk parameter ; tables. ; Built-in drives are generated as permanent with ; directory checksums. ; Written by: Glenn S. Tenney, November 1982 ; Various macros used to generate disk tables for ; CP/M Plus. ; define the 16-drive drive table dtbl macro ?list local ?n ?n set 0 irp ?drv, ?n set ?n+1 s equ 5 getdev equ 3ch ; bios fcn: hl=devtbl getdrv equ 42h ; bios fcn: hl=drvtbl move equ 4bh ; bios fcn: move xmove equ 57h ; bios fcn: set banks for move start: ld sp,stack ; pt to a stack ld bc,codelen ; len of our code ld de,himem ; destination ld hl,ourcode ; from here ldir ; move a hunk to non-rom area ld bc,secend-sec1 ; init entire area 1st ld de,sec1 ; i/o area ld hl,initial ; what to init it with ldir ; all cleared out ld de,startmsg ; tell what we're going to do call msg ; the following are NOT optional files xor a ld (optional),a ; indicate not optional ld de,excboot ; 1st fcb to open ld hl,bootsec ; and where to read it call dofile ; open and read it in ld de,cpmldr ; 2nd file ld hl,ldrsec call dofile ; note: cpmldr.com is limited in size ld de,ldrmsg ; in case msg needed cp 4096/128+1 ; see if cpmldr too long jp nc,abort ; yes, abort ; ld de,ccp ; 3rd file to read in 840923 ; ld hl,ccpsec 840923 ; dw ?drv endm if ?n gt 16 .' Too many drives. Max 16 allowed' exitm endif if ?n lt 16 rept (16-?n) dw 0 endm endif endm ; defines the disk parameter header dph macro ?trans,?dpb,?csize,?asize local ?csv,?alv dw ?trans ; translate (skew) table db 0,0,0,0,0,0,0,0,0 ; BDOS scratch area db 0 ; media flag dw ?dpb ; disk parameter block if not nul ?csize dw ?csv ; checksum vector else dw 0fffeh ; GENCPM sets checksum vector endif if not nul ?asize dw ?alv ; allocation vector else dw 0fffeh ; GENCPM sets allocation vector endif dw 0fffeh,0fffeh,0fffeh ; GENCPM sets: dirbcb, dtabcb, hash alloc'd db 0 ; hash bank if not nul ?csize ?csv: ds ?csize ; checksum vector endif if not nul ?asize ?alv: ds ?asize ; allocation vector endif endm ; defines disk parameter blocks dpb macro ?psize,?pspt,?trks,?bls,?ndirs,?off,?ncks local ?spt,?bsh,?blm,?exm,?dsm,?drm,?al0,?al1,?cks,?psh,?psm local ?n ;; physical sector mas.Z80 TITLE bios4 (excbios4) disk i/o ; 1983-07-27 add double sided handling in stdrw ; 1983-03-20 set for 1st release ; 1983-03-13 fix in BIOS for DRI bug in BDOS ; 1983-02-21 support extrn rtn for i/o err msgs + retry ; 1983-02-17 re-did stacks for going to bank 0 ; 1983-02-15 slight restructure for code in bank 80h ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; Some original code still remains which was written ; by Roger Chapman. This code appears in upper case. ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list PUBLIC HOME, SELDSK, SETTRK, SETSEC, SETDMA PUBLIC READ, WRITE, SECTRN, MULTIO, FLUSH lenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; Table of contents of this module: ; (1) the signon message, with copyright ; (2) The bios jump table ; (3) A few unchanging routines of the bios. page dseg ; signon message only needed at cboot signon: ; signon message at cold boot db 1ah ; clear screen db 'Osborne Executive CP/M Plus BIOS' db ' V' ; external version follows db ($version/1000h and 0fh)+'0' ; v db '.' ; . db ($version/100h and 0fh)+'0' ; m if ($version/10h and 0fh) OR ($VERSION AND 0Fh) db ($version/10h and 0fh)+'0' ; m endif IF $VERSION AND 0Fh db ($version and 0fh)+'0' ; m ENDIF db 0dh,0ah ; official copyright warning message db 'Copyright ',1bh,'g',13h,1bh,'G ' ; "c" within a circle d '198 Osborn Compute Corporation',0dh,0ah db 'Copyright ',1bh,'g',13h,1bh,'G '  public setbnk public dmabk ; selmem must set this public stdini,stdsel,stdrd,stdwt ; std routines 5.25 built-in public drive,actcnt ; so can be in err msgs extrn drvtbl ; table of drives extrn dpbtbl ; table of dpb info extrn stdsen,stderr ; std i/o err rtns dpblen equ 17+4 ; length of dpb + prefix cseg ; initial entry shd be common bank always SETDMA: ; ; Set source/destination address for later disk write/read ; ; ENTRY BC = Direct memory access address ; LD (DMAADR),BC in a,(sys) ; get current bank ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall through to set this bank for future i/o's too SETBNK: ; ; ENTRY A = Memory bank for next disk transfer ; LD (DMABK),A RET HOME: ; ; Sets track value to 0 ; ; ENTRY None ; ld bc,0 ; track zero ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall thru to settrk SETTRK: ; ; Sets track number. The track number is saved fo.z80 title boot (excboot) 1st sector rom bootstrap ;1984-09-22 DAB Installed code to boot Vixen format dsdd disk. ;1983-03-21 issue bios boot err msg on read errors ;1983-03-20 set for 1st release ;1983-02-21 boot hdr, enable key table ;1983-02-17 clear screen before font load, len err msg ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; By: Glenn S. Tenney 1982-12-27 ; this code is limited to 1 physical sector ; (or 1k) and must read in the ccpldr from the ; remainder of the 1st track ; dsdd system track layout 840924 ; track 0 side 0 this program (sector 1) 840924 ; cpmldr (sectors 2-5) 840924 ; track.Z80 TITLE bios0 (excbios0) jmp table & unchanging rtns ; ************************************************* ; external version # ; 1.3 $version equ 1300h ; Must be in hex form 840924 ; v m m m ; v=version # ; mmm = mod level ; (leading zeroes not shown) ; internal version # ; date last changed version equ 4288h ; MUST be in hex form ; y d d d ; y=last digit of year ; ddd = days since 1 January ; ************************************************* ;1984-10-14 DAB Changed version for Vixen dsdd compatible. ; Added Future Systems Copyright ; Added 64 byte patch area ; Added ptr to dpbtbl ;1983-08-01 Modified internal and external version numbers to ; show the changes made to support DSDD ;1983-06-23 changed version # etc. for 2nd release ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* G 0 side 1 bios (SETUP) overrides (sector 1) 840924 ; main font (sectors 2-3) 840924 ; ROM's RAM override (sector 4) 840924 ; sector 5 is unused 840924 ; ; ; ssdd system track layout ; track 0 this program sector 1 (max of 1k) ; cpmldr sector 2-5 (max of 4k) ; track 1 sector 1-4 ccp.com (actually only 3+k) ; sector 5 bios overrides ; track 2 sectors 1-4 are character generation tables ; sector 5 rom's ram overrides ; this bootstrap is read in by the rom into bank 0 ; location 4000h and then reads the ccpldr into 4400h ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list aseg ; the following is the layout of the rom's ram ; override sector (track 2 sector 5) table equ 0f000h ; place in common to load a table ; 1st is rom's version number (not used) ikbdtbl equ table+2 ; keyboard masks and decode tables ; function keys ikbdlen equ 11+320+512 ; length of all of that ihz equ ikbdtbl+ikbdlen ; frequency (50 or 60) icur equ ihz+1 ;  0fd51h ; sector size savsec equ 0fd4dh ; sector savtyp equ 0fd51h ; sector size rommove equ 0fd44h ; address of rom's move routine rsbank equ 0fd56h ; source bank rdbank equ rsbank+1 ; destination bank ieadr equ 0fd52h ; ieee device address ; the following address defines an area in common ; as follows: ; ds 60 Only this many bytes ---> watch out ; tbuf: ds 100h (for xmove use) ; ; therefore, this area is being used cautiously for ; various stack usage. tbuf equ 0fddch ; start of xmove buffer ; this stack is used by xmove or serial i/o savesp equ tbuf-2 ; place to save incoming sp comnsp equ savesp ; and a common stack area ; this stack is used by disk i/o routines ; because of error messages it is a different stack dsksave equ tbuf+64 ; another 64 byte area dsksp equ dsksave ; and its stack ; these are areas in rom's ram which are really ; primarily used during serial i/o and during ; cold boot time for initialization. They are ; included here so th; excbiose.lib ; ; these are common equates for the BIOS ; ;1984-09-24 DAB Added equate for sekdel, ROM's RAM step rate cell. ;1983-06-23 set for 2nd release ;1983-06-83 added equ's for device time-out sys equ 0 ; port to get/set crnt bank sysb equ 3 ; port to set clock frequency ; equates for various drive types dstype equ 0eh ; 1024 byte sector dsdd dsks1 equ 5 ; 256 byte sector sssd dskd1 equ 0ch ; 1024 byte sector ssdd xerox equ 1 ; 128 byte sector sssd ibm equ 8 ; 512 byte sector ssdd dec equ 8 ; 512 byte sector ssdd (+1/track) ; equates for serial device table characteristics devin equ 1 ; input device devout equ 2 ; output device devbaud equ 4 ; selectable baud rate devser equ 8 ; serial device (xon possible?) devxact equ 16 ; xon/xoff active ; equates to rom routines used rsec equ 5ah ; bios level read sector wsec equ 5dh ; bios level write sector senden equ 60h ; sense denisty ; serial device routines setbaud equ 24h ; set baud rate at any changes to the rom ; require only this file to be changed. clkptr equ 2000h ; ptr to seconds field of time-of-day media equ clkptr+2 ; ptr to media changed byte w/in scb adrive equ media+2 ; ptr to media change byte drive A (built-in) bdrive equ adrive+2 ; ptr to media change byte drive B (built-in) kbdtbl equ 200ah ; kbd masks and decode tables (11+320) ; immediately followed by fcn key table (512) hertz equ 2355h ; clock frequency (50 or 60) ; this is followed by cursor type, bg type ; and key click. These are init'ed differently. sekdel equ 23f0h ; This cell contains the head step 840924 ; rate, encoded per Western Digital's 840924 ; 179X FDC. It is used by the dsdd BIOS 840924 ; to set the step rate to 12 ms. The 840924 ; ROM inits head step to 20 ms. 840924 ; these are the protocol bytes for the rom handling ; the xon/etx protocol. aproto equ 2008h ; serial A protocol byte bproto equ aproto+1 ; serial B protocol byte romxon equ 1serial A or B skey equ 03h ; kbd status ci equ 06h ; kbd input cout equ 09h ; console output serain equ 18h ; modem input (A) saistat equ 0ch ; modem input status (A) seraout equ 1eh ; modem output (A) saostat equ 12h ; modem output status (A) serbin equ 1bh ; printer input (B) sbistat equ 0fh ; printer input status (B) serbout equ 21h ; printer output (B) sbostat equ 15h ; printer output status (B) parinp equ 51h ; centronics input pistat equ 4bh ; centronics input status parout equ 54h ; centronics output postat equ 4eh ; centronics output status ; ieee 488 interface rom routines ieistat equ 3fh ; input device status ieostat equ 42h ; output device status ieinp equ 45h ; input char ieout equ 48h ; output char ; the following are equates to absolute ram areas ; used by the rom dmabank equ 0fd4ah ; bank for disk xfr dmadr equ 0fd4bh ; disk dma address actsec equ 0fd4dh ; sector acttrk equ 0fd4eh ; track actdsk equ 0fd50h ; disk unit acttyp equk and physical sector shift ;; ?psh set 0 ?n set ?psize/128 ?psm set ?n-1 rept 8 ?n set ?n/2 if ?n eq 0 exitm endif ?psh set ?psh+1 endm ?spt set ?pspt*(?psize/128) ?bsh set 3 ?n set ?bls/1024 rept 8 ?n set ?n/2 if ?n eq 0 exitm endif ?bsh set ?bsh + 1 endm ?blm set ?bls/128-1 ?size set (?trks-?off)*?spt ?dsm set ?size/(?bls/128)-1 ?exm set ?bls/1024 if ?dsm gt 255 if ?bls eq 1024 .' Invalid disk size with 1k block size' exitm endif ?exm set ?exm/2 endif ?exm set ?exm-1 ?al1 set 0 ?n set ((?ndirs and 7fffh)*32+?bls-1)/?bls rept ?n ?al1 set (?al1 shr 1) or 8000h endm ?al0 set high ?al1 ?al1 set low ?al1 ?drm set (?ndirs and 7fffh)-1 if not nul ?ncks ?cks set ?ncks else ?cks set (?ndirs and 7fffh)/4+(?ndirs and 8000h) endif ;; all computed finally dw ?spt ; 128 byte sectors per track db ?bsh,?blm ; block shift and mask db ?exm ; extent mask dw ?dsm ; maximum block number dw ?drm ; maximum directory number db ?al0,?al1 ; alloc ve ; Xerox db 18 dw xrxxlt dpbx0: dpb 128,18,40,1024,32+8000h,3 db ibm ; IBM db 8 dw ibmxlt dpbibm: dpb 512,8,40,1024,64+8000h,1 db dec ; DEC db 9 dw decxlt dpbdec: dpb 512,9,40,1024,64+8000h,2 db 0 ; 8" sssd db 0ffh ; end of table 26 dw stdxlt ibm8: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra: dpb 128,26,77,1024,64+8000h,2 dseg ; ok in bank 0 ; these are the actual skew tables odsxlt: db 0,2,4,1,3,5,7,9,6,8 oddxlt equ 0 ; no skewing needed osdxlt: db 0,2,4,6,8,1,3,5,7,9 xrxxlt: db 0,5,10,15 ; physical equals logical db 2,7,12,17 db 4,9,14 db 1,6,11,16 db 3,8,13 ibmxlt equ 0 ; no skewing needed decxlt: db 0,2,4,6,8,1,3,5,7 stdxlt: db 0,6,12,18,24,4,10,16,22,2,8,14,20 db 1,7,13,19,25,5,11,17,23,3,9,15,21 end 24,5,40,1024,64+8000h,3 db dsks1 ; Osborne sssd db 10 dw osdxlt dpbs1: dpb 256,10,40,2048,64+8000h,3 db xerox ctor for directory dw ?cks ; checksum size dw ?off ; number of reserved tracks db ?psh,?psm ; physical sector size and mask endm ; ; ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list page ; declare the drive table public drvtbl ; table of drives public dpbtbl ; our dpb table w/ prefix public dph0,dph1 ; Built-in drive's dph's extrn stdini,stdsel,stdrd,stdwt ; built-in std routines cseg ; must be in common drvtbl: dtbl ; Note: With disk change in the interrupt routine, the dph must be ; in common memory. ; every dph MUST have a prefix as follows: ; -9 dw init-routine (at cboot once only) ; -7 dw read-routine ; -5 dw write-routine ; -3 dw seldisk-routine ; -1 db controller-relative drive number ; +0 dph --- the dph itself --- ; see the stdsel, stdrd and stdwt routines ; for documentation ; drive 0 dw stdini ; standard init routine dw stdrd ; standard read routine dw stdwt ; standard write routine dwon't need to do anything page ; just a very stripped down bios ; the following are dummy error routines so that the same ; disk drivers can be used by ldrbios stdsen: stderr: stdnr: cp a ; force zero flag (=no retry) ret ; devini ; dummy serial device init devini: ret ; nothing for now ! ! ; conout, auxout and list ; output the character to console crt conout: auxout: list: ld e,cout ; rom to type a character jp torom ; output it and exit ; conost, auxost, listst ; all return aok now conost: auxost: listst: xor a ; all ready ret ; and done ; conist, auxist ; just check status conist: auxist: ld e,skey ; check keyboard jp torom ; let rom do it ; conin, auxin ; get console character conin: auxin: ld e,ci ; get character jp torom ; also let rom do it ; devtbl ; only a dummy table for cpmldr devtbl: db 'CRT ' ; device 0 crt db devin+devout,0 ; i/o device no b stdsel ; standard seldisk routine db 0 ; controller drive # 0 dph0: dph oddxlt,dpbds ; use Osborne dsdd for now (as max) ; drive 1 dw stdini ; standard init routine dw stdrd ; standard read routine dw stdwt ; standard write routine dw stdsel ; standard seldisk routine db 1 ; controller drive # 1 dph1: dph oddxlt,dpbds cseg ; must be in common dpbtbl: ; each dpb is preceeded by ; associated device type code ; then sectors per track (actual) ; then addr of skew table (or 0) ; the table is terminated by an entry ; with a sectors/trk of 0ffh ; db disk-type-code ; db sectors-per-track ; dw skew-table ; lbl: dpb psize , pspt , trks , bls , ndirs , off , ncks db dstype ; Osborne dsdd db 5 dw odsxlt dpbds: dpb 1024,10,40,2048,128+8000h,1 db dskd1 ; Osborne ssdd db 5 dw oddxlt dpbd1: dpb 1024,5,40,1024,64+8000h,3 db dsks1 ; Osborne sssd db 10 dw osdxlt dpbs1: dpb 256,10,40,2048,64+8000h,3 db xerox aud db 0 ; end of table ; the following are the bcb's to be used during cpmldr ONLY ; they are dummyed up and used for a non-banked system for ; booting from drive A: ONLY! ! ! ! ! ! ! ldrbcb0: ; for dirbcb db 0ffh,0,0,0,0,0 dw 0,0 dw area0 ; i/o area db 0 dw 0 ; (link and bank for longest bcb) ldrbcb1: ; for dtabcb db 0ffh,0,0,0,0,0 dw 0,0 dw area1 ; and it's i/o area db 0 dw 0 dseg ; so areas appear last (I hope) ; ; WARNING ; ; the i/o areas are equated so as to not take up ; space on the system tracks. Therefore, this module ; must be linked LAST ! ! ! ! ! ! area0: ds 1 ; the end of the ldrbios area1 equ area0+1024 ; the 2nd i/o area end UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU move done, reset s and d bank dmove: ; move between different banks ld (rsbank),hl ; copy s and d banks for rom pop hl ; restore push ix ; save ex de,hl ; make regs look like ldir call rommv ; off to rom's move routine ex de,hl ; and back to d.r.'s way pop ix ; (used to get to rom) jp done ; and all done rommv: ld ix,(rommove) ; get address of rom's move routine jp (ix) ; off to rom's move routine (ret back) DONE: ld a,(ubank) ; restore current bank out (sys),a ; all back to what it shd be xor a ; clear kludge flag for dri ld (kludge),a ; no more xmoves in sight ld sp,(savesp) ; restore stack too RET XMOVE: ; set for cross bank moves ; ; ENTRY B = Destination bank ; C = Source bank ; ; EXIT DBANK = Destination bank ; SBANK = Source bank ; an alternate method.... ld hl,sbank ; pt to 3 byte area ld (hl),c ; source bank inc hl ld (hl),b ; destination bank inc hl ld (hl),h ; kludge to a known non-zero (h) R.z80 title bios3 (excbios3) misc routines (memory, time...) ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** .xlist include EXCBIOSE.LIB .list PUBLIC MOVE, XMOVE public sbank,dbank,kludge ; allow xmove's PUBLIC SELMEM public time public torom ; to rom and comn stack PUBLIC ROMMV extrn dmabk ; selmem must set this too cseg ; common ;;;;;;;; warning !!!!!!!!!!! ; Read the DRI documentation carefully regarding ; move and xmove. They may not work as you might be ; led to believe from some of the wording. It is ; like this: the xmove most recently before the move ; determines the source/destination banks, any move ; ET PAGE cseg ; must be common SELMEM: ; ; ENTRY A = Memory bank to select ; ; EXIT None ; ; USES A-reg only! OUT (SYS),A RET PAGE ; torom ; calls rom with a common stack not user's stack ; this is for the tpa user to allow calls to rom ; This routine jumps to ROM address and switches stacks ; ; ENTRY E = ROM address (offset from 0100h) ; A, BC, HL, IX = Any necessary parameters ; ; EXIT All ROM exit parameters remain in tact ; torom: ld (savesp),sp ; save user's stack ld sp,comnsp ; pt to one in common ld d,a ; save a in a,(sys) ; get crnt bank ld (ubank),a ; save for later exit or 80h ; force into rom out (sys),a ; now ld a,d ; restore a ld d,01h ; de=01xxh call romjp ; off to the rom (via our code) push af ; save a and flags ld a,(ubank) ; incoming bank info out (sys),a ; restore bank now pop af ; all regs now restored ld sp,(savesp) ; and return ret ; with user's stack romjp: push de ; dummy up like a resets an xmove setting. This version works with ; the stack anywhere (it is saved). MOVE: ; ; ENTRY HL = Destination address ; DE = Source address ; BC = Count ; ; EXIT HL = Next destination address ; DE = Next source address ; re-done by Glenn Tenney 1982-12-17 ld a,(kludge) ; should we kludge s/d banks or a ; 0=no previous xmove jr nz,maybed ; previous xmove, may be difficult smove: ex de,hl ; simple move ldir ; just move ex de,hl ; leaving regs aok ret ; and get out quickly maybed: ; see if a difficult xbank move ld (savesp),sp ; save crnt stack ld sp,comnsp ; and use one in common in a,(sys) ; current bank ld (ubank),a ; save current bank push hl ; save ld hl,(sbank) ; get s and d bank ld a,h cp l ; both in same bank jr nz,dmove ; no--difficult move ; same bank move (but may not be current bank) pop hl ; restore hl 1st ld a,(sbank) ; desired bank for move out (sys),a call smove ; do a simple move jp done ;call to rom ret ; off to rom (addr was in de) page ; time ; this routine is used to get/set the date ; and time ; the time is being updated by the rom interrupt routine time: ret ; do nothing ; these are areas used only within this module ubank: ds 1 ; save crnt bank here going to rom ; or when flipping banks ; these are bank numbers for transfers ; they MUST be in this order ! ! ! ! ! ! sbank: ds 1 ; current source bank dbank: ds 1 ; current destination bank ; this is a kludge because dri calls xmove then selmem and then move kludge: db 0 ; nonzero = use s/d bank end 00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5F7 :101E9B00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E7 :101EAB00E5E5E5E5E5E5E5F74E4E4E4E4E4E4E4E7D :101EBB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E37 :101ECB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E27 :101EDB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4 @AOVEC equ scb$base+28h ; Auxiliary Output Redirection ; Vector (word, r/w) FE2A = @LOVEC equ scb$base+2Ah ; List Output Redirection ; Vector (word, r/w) FE35 = @BNKBF equ scb$base+35h ; Address of 128 Byte Buffer ; for Banked BIOS (word, r/o) FE3C = @CRDMA equ scb$base+3Ch ; Current DMA Address ; (word, r/o) FE3E = @CRDSK equ scb$base+3Eh ; Current Disk (byte, r/o) FE3F = @VINFO equ scb$base+3Fh ; BDOS Variable "INFO" ; (word, r/o) FE41 = @RESEL equ scb$base+41h ; FCB Flag (byte, r/o) FE43 = @FX equ scb$base+43h ; BDOS Function for Error ; Messages (byte, r/o) FE44 = trn rvers ; place to put rom's version EXTRN DELAY,DELAY0 EXTRN OUTST EXTRN ROMMV ; equates used by the boot tpa equ 0100h ; start of the tpa bdos equ 5 ; where to call the bdos open equ 15 ; bdos open call setdma equ 26 ; bdos set dma addr call setmult equ 44 ; bdos set multi sector count read equ 20 ; bdos read that many sectors flush equ 48 ; bdos purge buffers dphmf equ 0bh ; offset from dph to its media flag byte dpbcks equ 0bh ; offset fm dpb to its cks (for perm disk) dpblen equ 17 ; length of one dpb (not our header) ccplen equ 0cffh ; length of ccp.com ; cboot ; perform cold (onetime) initialization ; This sets up various areas as needed, including ; reading the ccp.com from track 1 into bank 0 location 0. ; Special note: @bnkbf is a ptr to a 128 byte buffer ; within resident bdos for use during cboot or wboot. ; Well, this is being used as the boot time stack to ; help conserve space. cseg ; bios jmp table pts to a common entry  CP/M RMAC ASSEM 1.1 #001 SYSTEM CONTROL BLOCK DEFINITION FOR CP/M3 BIOS title 'System Control Block Definition for CP/M3 BIOS' public @civec, @covec, @aivec, @aovec, @lovec, @bnkbf public @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd public @mltio, @ermde, @erdsk, @media, @bflgs public @date, @hour, @min, @sec, ?erjmp, @mxtpa FE00 = scb$base equ 0FE00H ; Base of the SCB FE22 = @CIVEC equ scb$base+22h ; Console Input Redirection ; Vector (word, r/w) FE24 = @COVEC equ scb$base+24h ; Console Output Redirection ; Vector (word, r/w) FE26 = @AIVEC equ scb$base+26h ; Auxiliary Input Redirection ; Vector (word, r/w) FE28 =  ; cboot ; the cboot entry is in common so in case some ; weirdo jp's to it the system won't go south. cboot: ld sp,(@bnkbf) ; put a stack in common ld a,80h ; force rom + bank 0 out (sys),a jp cboot0 ; go do real cboot work dseg ; cold boot ok in bank 0 (it really is) cboot0: ; actual cold boot work here ; set rom's ram to keep time in scb ld hl,@sec ; pt to seconds field ld (clkptr),hl ; now rom knows where to keep time ; point rom's ram to media change flags so that interrupt ; routine can post a disk changing di ; data changed during interrupts ld hl,@media ; pt to scb's flag ld (media),hl ; so rom know's what to post ld hl,dph0+dphmf ; and built-in drive a ld (adrive),hl ld hl,dph1+dphmf ; and b drive ld (bdrive),hl ei ; rom can handle interrupts now ld hl,(romver) ; copy rom's version # ld (rvers),hl ld hl,(romver-2) ; and product+feature ld (rvers+2),hl ; read ccp.com into bank 0 location 0 if disk is ssdd 840924 ; Also loaata on disk ; has a chance of being useable. The sector begins with the ; bios' version number and must be an EXACT match. ld hl,(vers) ; get our version number ex de,hl ld hl,(ivers+table) ; and version from disk xor a ; clear carry sbc hl,de ; ours - disk = 0 iff same jr nz,notbls ; not same, forget changing tables ld a,80h out (sys),a ld c,'U' call 100h+cout xor a out (sys),a ; drvtbl table of dph pointers ld de,drvtbl ; pt to where to put drv tables ld hl,idrvtbl+table ; copy it in ld bc,idrvlen ; all entries ldir ; devtbl table of serial devices ld de,devtbl ; same as for drvtbl ld hl,idevtbl+table ld bc,idevlen ; primary only ldir ; shadow table, initvec and init strings ld de,(devtbl-2) ; get prefix (ptr to shadow) ld hl,idevshd+table ; move it from here ld bc,ishdlen+idvilen+idvslen ldir ; move all 3 tables in ; Device delay variables LD HL,(IDELAY+TABLE) LD (DELAY),HL jp foo ; 840925 ; the disk has now beds BIOS/SETUP override from sector 5 840924 call 100h+senden ; Call sense density to force setting 840924 ; of side bit 840924 ld a,(savtyp) ; Check for ssdd 840924 bit 1,a ; Bit 1 (side bit) is nz if dsdd 840924 jr nz,notssdd ; Not ssdd... 840924 xor a ; Set dsdd flag zero (false) 840924 ld (dsdd),a ; 840924 ld hl,0 ; ssdd, so load ccp from sys tracks 840924 ld (dmabank),hl ; set bank 0 ld (dmadr),hl ; set dma addr to zero ld hl,0101h ; track 1 sector 1 ld (actsec),hl ld b,5 ; read 5 sectors (full track) ; 1-4 ccp.com 5 our tables table equ 1000h ; this is where sector 5 ; appears in memory call 0100h+rsec ; ask rom to read it in or a ; see if any error jp nz,booterr ; yes, issue a msg and hang ; jp chktbl ; No, Check the table 840925 ; notssdd: ; Disk is dsdd 840924 ld a,0ffh ; Set dsdd flag true 840924 ld (dsdd),a ; 840924 ld a,(savtyp) ; Load current savtyp 840925 push af ; Save on stk 840en processed, proceed notbls: ; all overlayed from disk ld a,80h out (sys),a ld c,'N' call 100h+cout xor a out (sys),a foo: ; 840925 ld hl,0 llpp: dec hl ld a,h or l jp nz,llpp ld hl,initvec ; init the re-direction vectors ld de,@civec ; into the scb ld bc,10 ; length (always 5 words = 5*2 ) ldir ; moved into scb ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; init the serial devices ; we call the devini routine to allow whatever needs ; to be done to get done. The way it is (was?) coded ; is that the devini sets up the via tables so that ; the init is actually done the 1st activity. ld bc,16*256 ; # of times to loop + dev = 0 initdlp: ; loop here to init each device push bc ; save crnt value call devini ; init device # in c pop bc inc c ; advance device # djnz initdlp ; do all devices (0-15) ; init the disk controllers ; each dph prefix has a pointer to an init routine ; this routine is called now to allow925 set 1,a ; Set side 1 840925 ld (savtyp),a ; Save it 840925 ld hl,0 ; Load BIOS/SETUP override 840925 ld (dmabank),hl ; set bank 0 840925 ld hl,table ; Specify address of table 840925 ld (dmadr),hl ; as dma addr 840925 ld hl,0001h ; Read from (side 1) track 0 sector 1 840925 ld (actsec),hl ; 840925 ld b,1 ; read 1 sector 840925 call 0100h+rsec ; ask rom to read it in or a ; see if any error jp nz,booterr ; yes, issue a msg and hang 840925 ; old savtyp still on stk 840925 pop af ; Restore old savtyp from stk 840925 ld (savtyp),a ; Save it back 840925 chktbl: ; 840925 ; (Note: still bank 0) xor a ; turn rom off for a while now out (sys),a ; while we look at what we just read ; copy our tables from system track (last sector) just ; after the ccp.com ; the problem here is making sure that when the bios is ; re-assembled the old data on disk doesn't get used ; this is taken care of by verifying that the d any one time ; initialization. ld hl,drvtbl ; pt to table of dph's ld b,16 ; do 16 disks inidsk: ld e,(hl) ; pick up ptr to dph inc hl ld d,(hl) inc hl ; hl ready for next in tbl push bc ; save count push hl ; save drvtbl pointer ld a,d ; first, check to see if any dph or e ; 0=no dph call nz,inidsk2 ; there is a dph, init it pop hl ; restore drvtbl pointer pop bc ; restore count djnz inidsk ; and init all disk drives jp ready ; all init work taken care of inidsk2: ; de=this drive's dph, jp to init ld hl,-9 ; offset for init addr add hl,de ; hl=addr of addr of init rtn ld a,(hl) ; pick up init routine addr inc hl ld h,(hl) ld l,a ; hl=init routine address jphl: jp (hl) ; off to init routine ; all done with init's, tell the world ready: ; all ready to rip now! ld de,signon ; pt to the message ld hl,conout ; use this routine ld a,80h ; force back to bank 0 out (sys),a call outmsg ; issue signon msg ; copy 140924 ld a,(dsdd) ; Check dsdd flag 840924 or a ; 840924 jp z,notdsdd ; Not dsdd, load from bank 0 840924 ; ld a,(ccploaded) ; DSDD. Check to see if CCP loaded 840924 or a ; already. 840924 jp nz,not1st ; Yes; load from bank 0 840924 ; ld a,1 ; No. Set flag so next time CCP will 840924 ld (ccploaded),a ; load from bank 0 840924 ; First load alternate font RAM data from ALTFONT.SYS, if it 840926 ; exists. xor a ; Clear extent byte so open will start 840926 ld (altfcb+15),a ; file at beginning 840926 ld hl,0 ; Clear record field for same reason 840926 ld (altnr),hl ; 840926 ld de,altfcb ; Point at FCB 840926 call bopen ; Call BDOS open 840926 inc a ; Check for not found (A = 0ffh) 840926 jp z,noalt ; Not there, skip reading. Alternate 840926 ; font initialized by EXCBOOT 840926 ; ld de,4000h ; ALTFONT.SYS found, set DMA address to 840924 call bsetdma ; TPA above ROM 840924 ld de,128 ; Set multi record count to 128 to 84st time fcb to 5ch to try to open ; execst.com ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,fcb ; destination in bank 1 ld de,thefcb ; source in bank 0 ld bc,fcblen ; length of an fcb call move ; move it in jp wboot ; blend to warm boot page ; subroutines and constants used during cboot only ; booterr ; come here when we got a disk error of any kind ; reading our special sectors from the system ; tracks (including ccp.com). An error msg is ; issued and the system hangs. booterr: ; issue a msg saying disk error during boot ld hl,100h+cout ; pt to crt output rtn ld de,bootmsg ; and special error msg call outmsg ; issue this message hang: jr hang ; loop forever bootmsg: ; the message on disk error w/in boot d 0dh,0ah,0 beeeeeep db 'BIOS boot error reading disk. ' db 'System reset required.' db 0dh,0ah,0 ; 00 ends the msg ; thefcb ; this is the fcb to load a special file ; it is defined here 0924 call bsetmulti ; read the whole thing at one shot 840924 ld de,altfcb ; Point at FCB again and 840924 call bread ; call BDOS read to suck it in 840924 ; ALTFONT.SYS now loaded in TPA above ROM. Now move 2K into 840926 ; character generator RAM (i.e., write to ROM address space). 840926 ld hl,4000h ; Point at source in bank 1 840926 ld de,800h ; Point at destination in bank 0 840926 ld bc,2 * 1024 ; Set count of bytes to move 840926 in a,(sys) ; Save current bank state 840926 or 80h ; Shadow in ROM 840926 out (sys),a ; 840926 ldir ; Move it 840926 and 7fh ; Take ROM out 840926 out (sys),a ; 840926 noalt: ; 840926 ; Now load CCP from file. 840924 xor a ; Clear extent byte so open will start 840924 ld (ccp$fcb+15),a ; file at beginning 840924 ld hl,0 ; Clear record field for same reason 840924 ld (cfcb$nr),hl ; 840922 ld de,ccp$fcb ; Point at FCB 840922 call bopen ; Call BDOS open 840922 inc a ; Chand copied into bank 1 ; location 5c just before 1st wboot fcb equ 5ch ; where we will put it later thefcb: db 0,'EXECST ','COM',0,0,0,0 ds 16 fcbnr equ $-thefcb+fcb ; where the nr field will be db 0,0,0 fcblen equ $-thefcb ; length of an fcb page cseg ; common wboot: ld sp,(@bnkbf) ; set up a stack ; setup jumps in page 0 bank 1 ld a,1 ; force into bank 1 call selmem ; for execution and i/o ; copy special page 0 common area (at 40h) ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,40h ; destination in bank 1 ld de,vers ; source in bank 0 ld bc,16 ; maximum length of common area call move ; move it in ; set up jumps in page zero too ld a,0c3h ; a JMP opcode ld (0),a ; at loc 0000h ld (5),a ; and 0005h ld hl,wboot@ ; pt to that entry of jmp tbl ld (1),hl ; at loc 0001h ld hl,(@mxtpa) ; bdos entry pt from scb ld (6),hl ; at loc 0006h ; Load ccp from file if dsdd and 1st time through 8eck for not found (A = 0ffh) 840922 jp z,no$CCP ; Oops, not there 840922 ; ld de,100h ; CCP.COM found, set DMA address to 840924 call bsetdma ; TPA base 840924 ld de,128 ; Set multi record count to 128 to 840924 call bsetmulti ; read the whole thing at one shot 840924 ld de,ccp$fcb ; Point at FCB again and 840924 call bread ; call BDOS read to suck it in 840924 ; CCP now loaded in TPA; Next we must move a copy of him into 840924 ; the reserved area of bank 0. 840924 ld hl,100h ; Point at source in bank 1 (TPA base) 840924 ld de,0 ; Point at destination in bank 0 840924 ld bc,ccplen ; Set count of bytes to move 840924 in a,(sys) ; Save current bank state 840924 push af ; on stk 840924 mvccp2: ld a,1 ; Put bank 1 in context 840924 out (sys),a ; 840924 ld a,(hl) ; Load a byte from TPA 840924 push af ; Save byte while we switch to bank 0 840924 xor a ; Put bank 0 in context 840924 out (sys),a ; 840924 pop af ; Restore bytge notdsdd: ; 840924 not1st: ; 840924 chexecst: ; 840926 ; First check for 1st time through. If 1st, try to load EXECST 840926 ld a,(first) ; Check flag 840926 or a ; 840926 jr z,ldccp ; Not 1st, load ccp from bank 0 840926 ; xor a ; First time. Clear flag. 840926 ld (first),a ; 840926 call tryfile ; Try loading EXECST. If not there, 840926 ; returns and falls through to load 840926 ; CCP 840926 ldccp: ; 840926 ; now, move the ccp into bank 1 from bank 0 ; and execute it ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,100h ; destination in bank 1 ld de,0 ; source in bank 0 ld bc,ccplen ; for length of ccp.com call move ; move ccp in jp tpa ; and off to it ; tryfile ; one time only (at 1st wboot after cboot) ; if the special file exists, use it. tryfile: xor a ; clear ld (fcb+12),a ; current extent ld (fcb+15),a ; record count ld hl,0 ld (fcbne 840924 ld (de),a ; Save it in bank 0 840924 inc hl ; Point at next byte in TPA 840924 inc de ; and next destination in bank 0 840924 dec bc ; Decrement counter 840924 ld a,b ; Are we done yet (b = c = 0) ? 840924 or c ; 840924 jp nz,mvccp2 ; No, keep on a goin' 840924 ; pop af ; Yup, all done. Retrieve old bank 840924 out (sys),a ; from stack and restore it 840924 jp chexecst ; Check for execst 840924 no$CCP: ; CCP.COM not on disk. Print err and 840924 ; hang. 840924 xor a ; Select bank 0 so outmsg will work 840924 out (sys),a ; 840924 ld de,ccpmsg ; Point at message 840924 ld hl,conout ; Specify BIOS conout routine 840924 call outmsg ; Print it to console 840924 ccphang: ; And hang 840924 jp ccphang ; 840924 ccpmsg: ; Message to display if CCP not home 840924 db 0dh,0ah,07 ; toot toot 840924 db 'BIOS error: CCP.COM not present. ' ; 840924 db 'System reset required.' ; 840924 db 0dh,0r),hl ld de,fcb ; pt to the fcb ld c,open ; open the file call bdos or a ; was there an error? ret nz ; yes --- no special file ; read the file into the tpa one logical sector at a time ; this way it can be as long or short as need be l de,tp ini wher t rea it filelp: push de ; save across bdos call ld c,setdma ; read into there call bdos ld de,fcb ; pt to fcb ld c,read call bdos ; read one more logical sector pop de ; restore dma address ld hl,128 add hl,de ; bump dma address ex de,hl ; de=next dma address or a ; any errors?? jr z,filelp ; no, keep reading dec a ; see if eof or error ret nz ; error, forget using the file ; we now have read in the file with no errors ld hl,0 ; dummy up ld (80h),hl ; to look like no cmnd line jp tpa ; execute it (ret will do ccp) page dseg ; the following are the std disk i/o err routines ; they are in this source module so that for the ; ldrbios they need not do anything ah,0 ; terminate with 0. Would that this 840924 ; were C. 840924 ; BDOS call interfaces 840924 bopen: ld c,15 ; BDOS open (fn 15) 840924 jp bdos ; 840924 bsetdma:ld c,26 ; Set DMA (26) 840924 jp bdos ; 840924 bsetmulti: ; Set multi record I/O (44) 840924 ld c,44 ; 840924 jp bdos ; 840924 bread: ld c,20 ; Read (20) 840924 jp bdos ; 840924 ccploaded: ; Flag. Not zero if CCP loaded from 840924 db 0 ; dsdd disk and in bank 0 840924 dsdd: ; Flag. Not zero if boot disk is dsdd 840924 db 0 ; 840924 ccp$fcb: ; FCB for accessing CCP.COM 840924 db 1,'CCP ','COM',0,0,0,0 ; 840924 ds 16 ; 840924 cfcb$nr: ; 840924 db 0,0,0 ; 840924 altfcb: ; FCB for accessing ALTFONT.SYS 840926 db 1,'ALTFONT ','SYS',0,0,0,0 ; 840926 ds 16 ; 840926 altnr: ; 840926 db 0,0,0 ; 840926 first: db 0ffh ; Flag. Not zero if first time through 840926 ; wboot 840926 pa ; These routines issue some message of the general form: ; BIOS error xxxxxing drive x: ; Accept this condition (y=yes)? ; The xxx above is either 'select', 'read' or 'writ' ; and the x is the alpha of the drive number. The ; depends on the type of error. ; For a select error, all we can say is either the drive ; is not ready or the disk is not properly formatted. ; For an i/o error the is the breakdown of the ; fdc status bits (in english) followed by: xx/yy-zz..zz ; Where: ; xx the fdc code in hex ; yy the number of sectors this i/o ; zz.zz the 8 bytes beginning at dmabank ; bank(1),address(2),sector(1), ; track(2),unit(1),type(1) ; stdsen ; err on std seldisk, say not ready ; return 'z' if no retry, else 'nz' to retry stdsen: ld a,(@ermde) ; 0ffh=no err msgs pls inc a ; is bdos passing errs back ret z ; yes (z=no retry) call beep ; honk horn and start a line ld de,selfcn ; select function call saydrive ; tell what drive ld c,'-' ; another separator call conout ld hl,dmabank ; start here to display zz..zz ld b,8 ; for 8 bytes codelp: ; loop showing all of code ld a,(hl) ; next byte to display push bc push hl call hexout ; displayed in hex pop hl pop bc inc hl djnz codelp ; display all bytes ld de,codeend ; issue trailer of code msg call conmsg call askrc ; see whether to retry (nz=retry) jr z,stddn ; all done, no retry desired ; retry was wanted, see if media did change ld hl,(adrive) ; assume it was unit 0 ld a,(actdsk) ; get our internal # or a ; was it a (unit 0) jr z,was0 ; yes, hl proper ptr ld hl,(bdrive) ; no, pt to proper flag byte was0: ld a,(hl) ; see if that drive did change or a jr z,retryok ; it did not change, retry allowed push hl ; save ptr to media chg flag byte ld de,mediamsg ; it did change, verify fm opr call conmsg call askyn ; then ask for yes or no reply ; nz=yes (continue?) pop hl ; restore ptr to media chg byte  w/msg ld de,selmsg ; text of select msg call conmsg ; issue text to console jp askrc ; ask if we should retry ; z=no retry nz=retry ; stderr ; std disk i/o read or write err ; return 'z' = no retry 'nz' = retry ; a error code to bdos (1 or 2) ; b fdc status from rom ; e rom rtn offset (rsec or wsec) ; must return a and e as on input stderr: ld c,a ; save error code for bdos ld a,(@ermde) ; passing errors back to user inc a ld a,c ; (error code passed back) ret z ; yes, no msgs (z=no retry) push bc ; save error codes push de ; save fcn code call beep ; honk horn and start a line pop de ; get rd or wt rtn address push de ; must return de valid ld a,rsec ; see if read or write cp e ; equal if read ld de,rdfcn ; assume it is jr z,isrd ; yup ld de,wtfcn ; nope (must be a write) isrd: call saydrive ; say function and drive pop de ; rom rtn addr pop bc ; b=fdc err code c=bdos err code push de ; save rom rtn for exit  jr z,stddn ; no means no retry attempt xor a ; force a=0 ld (hl),a ; and clear media chg byte ; fall thru to allow retry retryok: ; retry allowed, force nz inc a ; nz=retry z=no retry ; here to return to caller. z=no retry nz=retry stddn: ; bc, de were saved earlier pop bc ld a,c ; restore bdos err flag pop de ; restore rom rtn addr too ret ; z/nz set by askrc page ; sernr ; device not ready ; issue the std bios error message, but ; only to crt. This is important, because ; conout may be the serial device. ; device #, must be retained ; ; ENTRY B = Device # ; ; EXIT Z-flag = Set Unassign this device ; Z-flag = Clear Leave device assigned ; SERNR: PUSH HL ;Save caller's regs PUSH DE PUSH BC ;Save device # SERCLR: ;Clear kbd 1st CALL 100h+SKEY ;Is there a key JR Z,SEROK ;No, ready to issue msg CALL 100h+CI ;Yes, get the key JR SERCLR ;Then throw it away SEROK: LD C,07H ;Beep to notify user of er push bc ; and bdos err flag too ; tell what fdc errors we got + a hex sequence ld a,b ; fdc status ld hl,stattbl-1 ; pt to start of msg tbl statlp: inc hl ; next tbl entry sla a ; check next bit left to right jr nc,statno ; that one not on push af ; save fdc status (z=done) ld d,0 ld e,(hl) ; get this tbl entry push hl ; save crnt tbl addr ld hl,statmsg ; pt to start of msgs proper add hl,de ; pt to this message itself ex de,hl ; whew, de->msg for this bit call conmsg ; tell opr this one ld de,comma ; separate status messages call conmsg pop hl ; tbl ptr pop af ; crnt fdc status statno: jr nz,statlp ; if more status bits ld de,codemsg ; status decoded, show in hex call conmsg pop bc ; restore fdc code (in c) push bc ; and keep saving it back ; code=xx/yy ld a,b ; fdc code call hexout ; xx is fdc code ld c,'/' ; weird separator call conout ld a,(actcnt) ; yy is #sectors this i/o call hexout ; code=xx/yy-zz..zzror condition CALL COUT+100H ;Use ROM routine POP BC ;Device # PUSH BC LD A,B ;Get device # in A-reg ADD A,A ;A * 8 to get appropriate entry ADD A,A ADD A,A LD B,0 LD C,A LD HL,DEVTBL ;Start of device table ADD HL,BC ;HL = this device entry ;HL is address of device name LD DE,DEVMSG ;Point to message position for device name LD BC,6 ;Length of device name LDIR ;Move it CALL SAVEMSG ;Save last video line in temp locations LD HL,DNRMSG ;Address of device not ready message LD DE,DNRATR ;Address of attributes for message CALL RESTOR ;Move 'em to last video line ISITAGAIN: POP BC ;Retrieve device # PUSH BC ;and save it again CALL OUTST ;Check to see if the device has become ready JR NZ,DONE ;Ready, restore screen and leave device assigned ;Check for response CALL 100H+SKEY ;Is there a key JR Z,ISITAGAIN ;No, check again CALL 100H+CI ;Get key AND 1Fh ;Accept upper or lower case CP 'Y' and 1Fh Uses high ram routine to transfer data between banks ; must save IX-reg, as ROMMV uses IX to preform jump to ; High RAM routine (see EXCBIOS3) ; ; ENTRY HL = Source start address ; DE = Destination start address ; BC = # bytes to transfer ; ; EXIT None ; PUSH IX CALL ROMMV POP IX RET PAGE ; askrc ; ask opr to accept this error (only y = yes) ; to conout, from conin askrc: call crlf ; start a new line 1st ld de,dskmsg ; pt to message call conmsg ; to console askyn: ld de,yorn ; append the y or n message call conmsg ynagain: ; loop here to read from conin push hl ; save output rtn addr call conin ; get next keystroke pop hl call isity ; see if answer is valid ret nc ; valid (Y or N) jr ynagain ; keep trying isity: ld de,ymsg ; assume only yes one and 1fh ; make upper/lower/ctl same cp 'Y' and 1fh ; is it Yes jr z,isyes ; yup ld de,nmsg ; may be no, pt to proper msg cp 'N' and 1fh ; not yes, was it No jr z,isn;Is the response "Yes"? JR Z,DONE ;Yes, unassign device and restore screen CP 'N' and 1Fh ;Is the response "No"? JR NZ,ISITAGAIN ;No, try again LD A,1 ;Clear Z-flag to indicate leave device assigned OR A DONE: PUSH AF ;Save Z-flag (exit state) LD HL,TEMPVID ;Point to user's last screen line LD DE,TEMPATR ;Point to last line's attributes CALL RESTOR ;and move them back to screen LD A,(DELAY) ;Get user defined delay for next time LD (DELAY0),A ;Save it POP AF ;Restore exit parameter POP BC ;Restore all regs POP DE POP HL RET page TEMPVID: DS 80 ;Buffer to save last screen line TEMPATR: DS 80 ;Buffer to save attributes for last screen line SAVEMSG: ; This routine saves the last line of the screen into temporary ; storage and its corresponding attributes ; ; ENTRY None ; ; EXIT TEMPVID contains last screen line ; TEMPATR contains last screen line attributes ; IN A,(SYS) ;Get current bank LD H,A ;For destination Lo ; it was no scf ; show not a valid response ret ; and exit as is isyes: or a ; a=Y, set NZ to show yes isno: ; if no, a=N and Z is set push af ; save retry/continue flag call outmsg ; tell what we saw opr enter call newline ; and complete the line pop af ; restore 'a' ret ; and all done page ; hexout ; displays 'a' as two ascii characters ; to conout hexout: push af ; save full value rrca ; get left nibble 1st rrca rrca rrca call hexify ; display it pop af ; restore original hexify: ; display the lower nibble in 'a' and 0fh ; make it a nibble cp 0ah ; is it a-f jr c,hex2 ; no, ok as is add a,7 ; adjust for a-f hex2: add a,'0' ; now valid hex character ld c,a ; prep to output it jp conout ; send it to console device page ; saydrive ; display msg pointed to be de to conout, ; then say 'ing drive x:' ; to conout saydrive: call conmsg ; 1st issue fcn name ld de,drmsg ; pt to drive message ld a,(D L,40H ;Video bank for source LD (RSBANK),HL ;Set parameters LD HL,0CB80h ;Last line of video LD DE,TEMPVID ;Destination of move LD BC,80 ;Move complete line CALL MOVEMSG ;Move it LD HL,0DB80h ;Last attribute line LD DE,TEMPATR LD BC,80 ; CALL MOVEMSG JR MOVEMSG ;Movemsg will return correctly ; RET PAGE RESTOR: ; This routine moves 80 bytes from HL pointer to the last video line ; and 80 bytes from DE pointer to last line video attribute ; ; ENTRY HL = address of message ; DE = address of attributes ; ; EXIT None ; PUSH DE ;Save attribute pointer PUSH HL ;Save message pointer LD H,40H ;Video for destination bank IN A,(SYS) ;Get current bank LD L,A ;For source LD (RSBANK),HL ;Set parameters POP HL ;Status message (source) LD DE,0CB80H ;Last video line (destination) LD BC,80 CALL MOVEMSG POP HL ;Attribute pointer LD DE,0DB80H LD BC,80 ; CALL MOVEMSG ;Fall through ; RET PAGE MOVEMSG: ; drive) ; get bdos drive add a,'A' ; adjust to an alpha char ld (drmsgdr),a ; save in msg conmsg: ld hl,conout ; pt to console output rtn jp outmsg ; and output that message ; msg text will follow ; crlf ; output crlf to conout ; newline ; output crlf to routine in hl crlf: ld hl,conout ; newline to conout newline: ld de,acrlf ; pt to msg jr outmsg ; and do it ; beep ; crlf, honk the horn and say who we are ; BIOS error ....... ; to conout ; Note: also clear any waiting keys from conin 1st beep: call crlf ; new line 1st beepclr: ; clear any waiting keys call conist ; is there anything waiting jr z,beepok ; nothing waiting call conin ; something waiting, get it jr beepclr ; and ignore it beepok: ld de,abeep ; pt to bell + crlf jr conmsg page ; outmsg ; send msg to some device up to 255 chars ; in length and terminated by a 00h character. ; this is intended for the initial logon msg, ; disk error messages or device te following are the various fdc status messages statmsg: ; start of table fdcnr: db 'not-ready',0 fdcwp: db 'write-protected',0 fdcwf: db 'fault',0 fdcnf: db 'not-found',0 fdccrc: db 'crc-error',0 fdclst: db 'lost-data',0 fdcdrq: db 'drq',0 fdcbsy: db 'busy',0 stattbl: ; table of 1 byte offsets db fdcnr-statmsg db fdcwp-statmsg db fdcwf-statmsg db fdcnf-statmsg db fdccrc-statmsg db fdclst-statmsg db fdcdrq-statmsg db fdcbsy-statmsg ; a separator between status texts comma: db ', ',0 ; the following is the lead-in for the hex code of error codemsg: db 1bh,')(code=',0 ; enter dim mode codeend: db ')',1bh,'(',0 ; end dim mode end each other JMPSPOT DS 1 ;To be filled in with a JMP instruction by the ROM JMPADDR DS 2 ;Address to jump to for BANKJMP and BANKCALL JMPBANK DS 1 ;Bank to jump to for BANKJMP and BANKCALL EMRAM = * ; INTERRUPT VARIABLES USR_BNK DS 1 ;Uimeout msgs ; note: this resides in bank 0 ; bc destroyed ; de ptr to start of msg (0 terminated) ; hl ptr to routine to output a char (rom or bios) ; typically conout or cout (rom) ; preserved on output ; outlen ; an alternate entry to output a message, but the ; length is specified in 'b'. The message may ; not contain a 00h character. ; b # characters to send outmsg: ld b,00h ; maximum # of characters in msg outlen: ; alternate entry: 'b' = msg length ld a,(de) ; next char or a ; is this a terminator? ret z ; yes -- all done then ld c,a ; char to be output push bc ; save char count push de ; and ptr to char push hl ; and routine addr call jphl ; call routine pt'ed to by hl pop hl pop de pop bc ; all restored inc de ; next char djnz outlen ; loop 'b' number of characters ret ; done page ; messages ; a crlf acrlf: db 0dh,0ah,0 ; a beep (bell) followed by who we are abeep: db 07h db 'BIOS error ',0 ; disk function names (fol.z80 title bios2 (excbios2) serial i/o tables & routines ; 1983-11-07 Changed initial configuration to no printer assigned ; Change made in initvec ; ; 1983-23-06 Made device time-out delay a SETUP definable value, ; can disable timeout feature, user prompt will go away and ; restore original screen/cursor, message will continue to ; check for device ready ; ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; This module handles all of the non-disk i/o. ; This supports full re-direction, xon/xoff, etx/ack ; and IEEE devices. .xlist include EXCBIOSE.LIB ; common equates .list public devtbl ; the device table public devini ; lowed by 'ing') selfcn: db 'select',0 rdfcn: db 'read',0 wtfcn: db 'writ',0 ; generic drive name message (after function, ; before error text) drmsg: db 'ing drive ' drmsgdr: ; drive char inserted here db 'X: ',0 ; select error text selmsg: db 'not ready or not formatted.',0 ; unassign msg for device not ready msg DNRMSG: DB 'BIOS error. ' DEVMSG: DS 6 ;Space for device name DB ' not ready or buffer full, unassign this device (Y or N)? ' DB 0A0h ;Simulate cursor DB ' ' ;Pad with spaces DNRATR: DW 0,0,0,0,0,0,0,0,0,0 ;No attributes set DW 0,0,0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0,0,0 ; part of the yes or no question yorn: db ' (Y or N)? ',0 ; retry msg for a disk error dskmsg: db 'Retry this operation',0 ; retry desired, but media changed mediamsg: db 1bh,'^WARNING:',1bh,'q ' ; blinking db 'data on disk inserted may be destroyed. Continue',0 ; tell what opr said nmsg: db 'No',0 ymsg: db 'Yes',0 ; thdevice init public conout,auxout,list ; output routines public conost,auxost,listst ; output status public conin,auxin ; input routines public conist,auxist ; input status public initvec ; initial i/o redirection vector public vecptr ; ptr to crnt vector wd PUBLIC DELAY ;Device delay time-out value PUBLIC DELAY0 PUBLIC OUTST ;Output device ready status extrn @covec,@aovec,@lovec ; re-direction extrn @civec,@aivec ; of serial i/o EXTRN SERNR ;Not ready routine ; special equates for this routine only etx equ 03h ; the etx char sent for etx/ack ack equ 06h ; the ack to our etx xon equ 11h ; xon lets output continue xoff equ 13h ; xoff pauses output 'til an xon xonact equ 4 ; (devxact) 1=xon (or etx) active ; (bit number) ; we have a serial shadow table ; these are the meanings of the bits in the flag byte ; (these are all bit numbers) xonetx equ 7 ; (80h) 1=etx/ack 0=xon/xoff waiting equ 6 ; (40h) 1=waiting for ack/xon 0=not waiting isieroutine in bank 0 dseg ; following routine in bank 0 ; init ; set this device to 'requires init' ; then call its init routine ; when calling the real init routine, regs must be the ; same as when calling the vecio routine (b=device, ; de->flag byte) init: push bc ; save incoming device # (in c) ld a,c ; get device # and 0fh ; force to 0 - 15 add a,a ; *4 add a,a ld e,a ; and into 16 bits ld d,0 ld hl,viareal+2 ; pt to real table add hl,de ex de,hl ld bc,viadev ; and to active table add hl,bc ; hl->active de->real ld bc,vec1st ; pt to our 1st time code ld (hl),c ; active table pts to 1st time inc hl ld (hl),b inc hl ld a,(de) ; then copy flag bytes fm real ld (hl),a ; to active push hl ; save ptr to active flag byte inc de inc hl ld a,(de) ld (hl),a dec de ; back up to rtn addr dec de ld a,(de) ; hi of rtn ptr ld h,a dec de ld a,(de) ; lo ld l,a ; hl=real rtn addr or h ; is addr = 0 lee equ 5 ; (20h) 1=is an ieee device ; serial device vectoring request codes vecist equ 0 ; input status vecin equ 1 ; input a char vecost equ 2 ; output status vecout equ 3 ; output a char ; serial device output delay counter before ; issuing device not ready message FIVESEC EQU 0B000h ; about 5 seconds page cseg ; common ; todseg ; call a routine in bank 80h (0 + rom) ; hl= routine to jp to in bank 80h ; a= destroyed ; all of the bios routines gain control in any bank ; and to conserve bank 1 space have most of the actual ; routine in bank 0. The sp is switched too. todseg: ld (savesp),sp ; (banks changing, sp has to) ld sp,comnsp ; (stack into common area) in a,(sys) ; (save current bank) push af ld a,80h ; (and set bank 0 + rom) out (sys),a call setvec ; off to it after getting ready ; return here when done pop hl ; h=saved bank # ld l,a ; save result to pass back ld a,h ; get saved bank out (sys),a ; reset band de,-3 ; but 1st, back up to init rtn jmp add hl,de ; hl pts to jmp to init rtn pop de ; restore ptr to active table flag byte pop bc ; restore device # too ld b,c ; must pass it in b ret z ; finally, addr=0 -- init all done jp (hl) ; off to rtn pt'ed to in hl ; (it will ret) ; each active vector initially points to the following ; 1st time code. When the first activity occurs for that ; device, this code is executed. It is at this time that ; the initial string is sent out to this device. vec1st: ; de->flag byte of active table push af ; save fcn type (may be needed) push de ; save ptr to flags for real rtn push bc ; save device # and char ld hl,-2 add hl,de ; hl=start of entry in viadev ex de,hl ; hl=viadev+2+(dev#*4) ld bc,viadev+2 ; bc=viadev+2 xor a sbc hl,bc ; hl-bc = offset fm viadev ld bc,viareal add hl,bc ; hl->real de->active ld a,(hl) ; copy real address in ld (de),a ld c,a ; and save the addr too inc dek # (flags still ok) ld a,l ; restore a (result) ld sp,(savesp) ; and restore sp too ret ; now all done dseg ; finally go off to routine pointed to in hl ; setting up for re-direction vectors setvec: push hl ; hl=routine address ex de,hl ; get ptr to vector ld (vecptr),hl ; save in case we have to unassign ld a,(hl) ; then get the vector itself inc hl ld h,(hl) ld l,a ; hl=i/o redirection vector xor a ; clear carry ld b,a ; and device # for redirecting ret ; off to routine in hl originally vecptr: ds 2 ; ptr to crnt vector cseg page ; devini ; perform serial device initialization ; there are 2 kinds of init: (1) viavec which ; can init onboard hardware and (2) sndstr which ; sends the init string of characters for this ; device. This routine is coded the way it is ; for the sake of cboot (see there for details). devini: ; perform serial device init ld hl,init ; pt to init routine in bank 80h jp todseg ; call that   inc hl ld a,(hl) ld (de),a ld b,a ; bc=copy of addr (now in viadev) pop de ; restore incoming bc pop hl ; and incoming de pop af ; and fcn code push bc ; real rtn addr (ret to there) push af ; incoming fcn code push hl ; real de (as on entry) push de ; re-save real bc ld hl,initstr ; pt to table of strings xor a ; clear it ld b,d ; get device # for loop counter ld d,a ; to use de as 16 bit value or b ; is device # 0 ? jr z,sndfnd ; yes, then hl pts to string sndflp: ; loop here til at start of string ld e,(hl) ; get length byte crnt string inc hl ; bump over length byte add hl,de ; then bump over string itself djnz sndflp ; continue thru strings sndfnd: ; hl->length byte of string pop bc ; restore b=device # push bc ; re-save it for when done ld a,(hl) ; get starting length inc a ; dummy up for the dec following sndlp: dec a ; drop count until 0 jr nz,sndmor ; not done yet, send more snddn: pop bc ; restorother device wanted ret ; all done ; on the cr, see if xon/etx (either) is active gotcr: call chkact ; is xon active (could be xon or etx) jr z,outnxt1 ; no, done this device bit xonetx,(hl) ; ok, now is it etx that is active jr z,outnxt1 ; no (after all that) done this device ; we finally know that we just sent a cr to a device with ; etx/ack protocol active, so send the etx outetx: call outwait ; wait til ready for etx jr z,outnxt1 ; ignore this character push bc ; save original char (and dev #) ld c,etx ; ask for an ack ld a,vecout ; say we want to vector output call viavec ; do that output pop bc ; restore char and dev # jr outnxt1 ; proceed to next device page DELAY0: DB 1 ;For 5 sec delay time ; outwait ; common routine to wait for output device ; to become ready to send a char ; this routine will go off to the error routine ; after a delay ; returns z if output to be ignored outwait: ld a,(delayon) ;use delay loop ande incoming dev # + char pop de ; and de pop af ; restore, may be fcn type ret ; off to real device driver now sndmor: push af ; save crnt length inc hl ; pt to next char push hl ; save string ptr too call outwait ; wait for device to get ready pop hl ; restore string ptr jr z,snduna ; it got unassigned -- oops push hl ; and save it back ld c,(hl) ; get next char to send it out ld a,vecout ; to output a char device in b ; note that viavec is called by us and we were ; called by viavec. This is ok, since we reset ; viadev to pt to the real routine address push bc ; save device # call viavec pop bc ; restore device # pop hl pop af jr sndlp ; keep going, 'til 0 that is snduna: pop hl ; dummy to dump af saved on stack jr snddn ; and all done sending string cseg ; back to bank 1 page ; conout, auxout and list ; output the character to all such devices list: ld de,@lovec ; list re-direction jp doout ; output to those devic message? or a jr nz,outloop ;yes, go to delay loop wait: push bc ;no, try forever call outst pop bc jr z,wait ;if device not ready, try again ret ;else return outloop: ld a,(delay0) ;get number of times to loop ld e,a deloop: ld hl,fivesec outwlp: push hl push de push bc ; save char while checking call outst ; is that device ready? pop bc ; restore each time pop de pop hl ret nz ; all done, device ready dec hl ; hmm not ready yet ld a,h or l ; did we count down to zero jr nz,outwlp ; no, keep waiting dec e jr nz,deloop call sernr ; yes, tell operator and ask jr nz,outloop ; retry again and again ; we have been told to unassign this device push bc ; save device # ld hl,(vecptr) ; pt to redirection vector ld a,b ; get device # sub 8 ; convert to 0-7 jr nc,unalo ; use lo byte inc hl ; pt to hi byte ld a,b ; get device back (it is 0-7) unalo: ld b,a ; b=loop count inc b ; adjust for 1 indexed xoes auxout: ld de,@aovec ; auxout re-direction jp doout conout: ld de,@covec ; conout re-direction word doout: ld hl,output ; pt to common output routine jp todseg ; and off to it in bank 80h dseg output: ; common output routine outnext: or h ; leftmost bit = 1 ? jp p,outnxt2 ; no, try next device push hl ; yes, send char to that device call outwait ; wait until device ready jr z,outnxt1 ; told to ignore this char push bc ; back to send it now ld a,vecout ; say we want to vector output call viavec ; do that output ; if we sent a cr and etx/ack is enabled, then send the etx ; is this the cr (this is faster, so is 1st) pop bc ; restore character ld a,c ; get char sent cp 0dh ; is it cr? jr z,gotcr ; yes--check for etx this char outnxt1: ; restore hl before advancing to next pop hl outnxt2: ; actually advance to next device inc b ; next device # xor a ; clear a and carry adc hl,hl ; shift left and see if 0 jr nz,outnext ; some  r a ; clear a scf ; and set carry unalp: rra ; dev # 0-7 into mask 80h-01h djnz unalp cpl ; make a bit into a mask and (hl) ; turns that assignment off ld (hl),a ; device now unassigned ld hl,(vecptr) ; point to it again ld a,(hl) ; lo inc hl or (hl) ; see if it went to 0000 jr nz,unardy ; no, then it is unassigned ok ld bc,@covec ; see if it is conout inc bc ; pt to high byte of vector word ld a,c ; check only low byte of address cp l ; is this the one being unassigned? jr nz,unardy ; no, ok to be set to 0000h ; conout cannot be unassigned to 0000h, force to something ld (hl),80h ; force to device 0 (crt) unardy: xor a ; show unassigned and to be ignored pop bc ; restore device # ret ; otherwise ignore char (z set) cseg page ; conost, auxost, listst ; same as output, just check status listst: ld de,@lovec jp doostat ; common rtn to chk status auxost: ld de,@aovec jp doostat conost: ld de,@covec ; re-direction wor ready istnxt1: inc b ; next device # xor a ; clear a and carry adc hl,hl ; shift left and see if 0 jp nz,istnext ; some other device wanted dec a ; a=ff, all were ready ret ; and all done ; ist ; input status b=device # ;; save bc,hl because used during xon/off checking ist: push hl ; save regs push bc ld a,vecist ; ask for input status call viavec ; vector it now pop bc pop hl ret ; and done cseg ; back to bank 1 page ; conin, auxin ; like in status, but get first avail character auxin: ld de,@aivec jp doin ; common rtn to chk status conin: ld de,@civec ; re-direction word doin: ld hl,input ; pt to common input routine jp todseg ; call it in bank 0 dseg ; following in bank 0 input: ; common input routine inwait: push hl ; save re-direction vector xor a ; a=0 for inner loop ld b,a ; b=device # (0-15) innext: or h ; leftmost bit = 1 ? jp p,innxt1 ; no, try next device call ist ; yes, is that devid doostat: ; here to call common output status rtn ld hl,outstat ; pt to common routine jp todseg ; call it in bank 80h dseg ; into bank 0 ; outstat ; common output status routine outstat: ; de=redirection vector ostnext: or h ; leftmost bit = 1 ? jp p,ostnxt1 ; no, try next device push hl ; yes, send char to that device push bc ; save regs 1st call outst ; is that device ready? pop bc ; but first restore regs pop hl ret z ; exit NOW if any not ready ostnxt1: inc b ; next device # xor a ; clear a and carry adc hl,hl ; shift left and see if 0 jr nz,ostnext ; some other device wanted dec a ; make a=0ffh to show ready ret ; and all done page ; a couple of common outst routines ; chkact ; sees if xon (or etx) active this device ; z=no hl=ptr to flag byte in shadow table chkact: ld l,b ; get device # ld h,0 ; into 16 bits add hl,hl ; * 8 (offset devtbl) add hl,hl push hl ; save *4 for shadow tbl access add hce ready jr nz,inready ; yes, go get that character innxt1: inc b ; next device # xor a ; clear a and carry adc hl,hl ; shift left and see if 0 jp nz,innext ; some other device wanted pop hl ; restore re-direction vector jr inwait ; loop til someone ready ! ! inready: pop hl ; drop off vector ; and proceed to get the character getin: ; common routine to get a character ld a,vecin ; ask for input ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall through ; jp viavec ; off to do it ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; page ; viavec ; off to device routine via a vector ; a=type of request (see vecxxx equates) ; b=device # ; goes off to proper routine based on viadev table ; ; viavia as viavec, but de->table to vector thru viavec: ; off to routine handling this device ld de,viadev ; addr is 1st 2 bytes of the 4 viavia: ; here when de->table to use to via ld h,0 ld l,b ; hl=device # 16 bil,hl ld de,devtbl+6 ; the mode byte add hl,de ; this device's mode byte bit xonact,(hl) ; is xon (or etx) active pop hl ; and restore so hl=device# ld de,viadev+2 ; pt to shadow table flag byte add hl,de ; hl pts to flag byte ret ; flag and hl set ; outst ; common output status routine ; b=device #, return a=z if not ready, ff if ready outst: ; bios no longer does xon/etx, rom does outst1: ; get real output device status ld a,vecost ; as for output status jp viavec ; for this device cseg ; back to bank 1 page ; conist, auxist ; same as output, just check status auxist: ld de,@aivec jp doist ; common rtn to chk status conist: ld de,@civec ; re-direction word doist: ld hl,instat ; pt to common input status rtn jp todseg ; call it in bank 0 dseg instat: ; common input status routine istnext: or h ; leftmost bit = 1 ? jp p,istnxt1 ; no--check next device call ist ; yes, is that device ready ret z ; exit NOW if any not ts add hl,hl ; *2 add hl,hl ; *4 (each entry is 4 bytes wide) add hl,de ; hl points to entry this device ld e,(hl) ; get routine address inc hl ld d,(hl) ; de -> routine for this device inc hl ; hl -> flags for this device ex de,hl ; de->flags hl->routine jp (hl) ; off to routine (like a call) ; called routine will do the RET ; the following is what an unused device will vector to ; it is preceeded by the specified prefix which is 'jp'ed to ; to do an init. Please note that it is essentially a 'nop' ; but MUST be there and this way. jp unused ; 3 byte prefix to a vector routine unused: xor a ; just set a=0 and ret ret ; used to be part of outst page ; stdrom ; standard rom serial i/o driver (no init) ; because bank 80h is in effect, we can call rom ; directly ; a=type of i/o (see vecxxx equates) ; b=device # ; de=pointer to flag byte, then rom table offset ; NOTE: ; every routine called for i/o via the viadev ; table must hav clrlp: push bc ; save device # ld a,vecist ; vector for input status ld de,viareal ; thru the real table (not active table) call viavia ; get status directly pop bc ; restore device # jr z,serproto ; status shows nothing there---done ; status shows something there, clear it out and throw it away ld a,vecin ; ask for an input now ld de,viareal ; thru real vector ptrs call viavia ; get the char just to throw it away jr clrlp ; keep going til none left serproto: ; determine protocol this device pop af ; restore port a or b code ld e,a ; cnvrt to 16 bits ld d,0 ld hl,aproto add hl,de ; pt to protocol this port ld (hl),0 ; assume no protocol at all push hl ; save proto ptr call chkact ; see what protocol if any pop de ; restore ptr to proto ret z ; no protocol, all done ld a,romxon ; assume it is xon bit xonetx,(hl) ; ahhh is it xon or etx jr z,serset ; it is xon, a=proper value inc a ; make it show etx proto serset: ld (de),a ; pose a 3 byte prefix. This prefix ; is jp'ed to to do the init, if any, for this ; device. jp romini ; stdrom init stdrom: ex de,hl ; make ptr to flags be in hl inc hl ; bump over flag byte to table offset ld e,(hl) ; table offset ld d,0 ; 16 bits worth ld hl,romtbl ; pt to std rom table add hl,de ; hl=start of proper rom table ld e,a ; get type of request add hl,de ; hl points to proper rom offset ld a,(hl) ; get low byte of rtn addr or a ; 00=do nothing (special case) jp z,romnop ; a nop that always gives a=ff ld h,01h ; h=hi addr (always 01) ld l,a ; hl=true rom address jp (hl) ; off to rom directly romnop: dec a ; show ready (a=ff) always stdret: ret ; and exit ; romini ; stdrom comes here to init a rom driven ; device. If it is serial A or B it's baud ; rate is set. If not, nothing is done. ; registers same as for stdrom call. romini: ; process device init for a rom serial driver inc de ; pt beyond flag byte ld a,t protocol flag to rom ret ; and all done ; stdieee ; standard ieee serial device type i/o ; this uses the rom routines for simple ieee i/o ; and may get confused if more than one ; bios supported ieee device is active. ; a type of request (viaxxx) ; b device # ; de ptr to flag byte (next byte is ieee device addr) jp stdret ; stdieee init (none) stdieee: ld l,a ; convert to 16 bit value ld h,0 inc de ; byte after flags is ieee addr ld a,(de) ; get ieee device address ld (ieadr),a ; let rom know what device ld de,ieeetbl ; pt to table of routine addrs add hl,de ; hl pts to proper addr ld l,(hl) ; lo of rom addr ld h,01h ; always 100h+ jphl: jp (hl) ; let rom do it directly cseg page ; devtbl ; this table defines the valid serial devices ; by name as well as by functionality. ; This is the standard DRI table. All 16 entries ; MUST be here because setup uses this data. ; this table has a special prefix: ; dw our-tables-i(de) ; get rom table offset byte cp (romprt-romtbl)+1 ; rommod or romprt ret nc ; neither, do nothing ; a=0 if port a, a=04 if port b (this might change, watch out) rrca rrca ; a=0 port a, =1 if port b push af ; save a or b indication too push bc ; save device # ld l,b ; make it 16 bits ld h,0 add hl,hl ; *8 add hl,hl add hl,hl ld de,devtbl+7 ; pt to baud rate byte add hl,de ; hl=proper table entry ld b,a ; save which device (0 or 1) ld a,(hl) ; get baud rate or a ; is it 0 (0=no setting) jr z,serclr ; yes, ready to clear port ld c,a ; no, get baud rate code (1-15) ld a,b ; get saved device code (0 or 1) call 100h+setbaud ; let rom handle it directly ; this clears out any characters waiting on input from ; this device. This does not use IST nor GETIN to avoid ; using viavec which might would run us thru vec1st and ; send out the init string. All we want to do is clear ; the input queue. serclr: pop bc ; restore device #  n-bank-0 dw viareal ; pt to start of ours in bank 0 devtbl: db 'CRT ' ; device 0 crt db devin+devout,0 ; i/o device no baud db 'CEN ' ; device 1 std printer db devin+devout,0 ; may be i/o no baud db 'MODEM ' ; device 2 is modem port (A) db devin+devout+devser+devbaud,0 ; baud rate 0=no set needed db 'PRNTR ' ; device 3 is serial printer port (B) db devin+devout+devser+devbaud,0 ; again, 0=no setbaud needed db 'IEEE ' ; the ieee-488 port db devin+devout,0 db 0,0,0,0,0,0,0,0 ; 05 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 06 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 07 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 08 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 09 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 10 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 11 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 12 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 13 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 14 unused slot fill to 16 db 0,0,0,0,0,0,0ds 15*16 ; remainder of table space ; DELAY is used by the output routines for a delay in printing ; device not ready message DELAY DB 2 ;Fo minut delay DELAYON: DB 1 ;Use delay time (0 means ignore) page ; additional things that can be in bank 0 ; viadev ; this is the table that viavec really uses ; this allows us to take care of 1st time ; init and strings with no overhead on each ; character. viadev: dw vec1st,0 ; 0 room for all 16 devices dw vec1st,0 ; 1 dw vec1st,0 ; 2 dw vec1st,0 ; 3 dw vec1st,0 ; 4 dw vec1st,0 ; 5 dw vec1st,0 ; 6 dw vec1st,0 ; 7 dw vec1st,0 ; 8 dw vec1st,0 ; 9 dw vec1st,0 ; 10 dw vec1st,0 ; 11 dw vec1st,0 ; 12 dw vec1st,0 ; 13 dw vec1st,0 ; 14 dw vec1st,0 ; 15 ; romtbl ; one entry each device accessed directly via rom ; routines. Each device is ist, in, ost, out ; rom offsets. 00=do nothing. ; note: modem must be first, followed by printer. ; That is how we know whether the device is ; serial ,0 ; 15 unused slot fill to 16 db 0 ; end of table dseg ; following tables appear in bank 0 ; and MUST be in this order for setup ; general device shadow table ; this is the real table, but not the one ; viavec uses. ; this is a table with one entry for each of the 16 ; devices. Each entry is 4 bytes wide as follows: ; dw routine call this routine ; Note: this routine has a 3 byte ; prefix that is called to do ; an init. (see stdrom) ; db flags see flag equates ; see equ's at beginning ; db anything up to you ; stdrom: offset to romtbl ; stdieee: ieee device address viareal: ; vector each device ; crt dw stdrom ; a rom routine db 0 ; flags db romcrt-romtbl ; offset from table start ; cent dw stdrom ; uses std rom routines db 0 ; flags db romcen-romtbl ; offset from table start ; modem dw stdrom ; again db 0 db rommod-romtbl ; printer dw stdrom db 0 db romprt-romtbl ; ieee dw stdieee ; routine address port A or B for devini. romtbl: ; 4 bytes each device ; modem must be 1st rommod: db saistat,serain,saostat,seraout ; printer must be 2nd romprt: db sbistat,serbin,sbostat,serbout ; crt romcrt: db skey,ci,0,cout ; centronics romcen: db pistat,parinp,postat,parout ; ieeetbl ; this is the table of rom routine offsets for ; the std ieee interface ieeetbl: ; std viaxxx order excluding init which is ignored db ieistat,ieinp,ieostat,ieout end for std ieee db 20h ; flags (show this is an ieee) db 04 ; ieee device address (default) ; unused slots (up to 16 devices) dw unused,0 ; 5 dw unused,0 ; 6 dw unused,0 ; 7 dw unused,0 ; 8 dw unused,0 ; 9 dw unused,0 ; 10 dw unused,0 ; 11 dw unused,0 ; 12 dw unused,0 ; 13 dw unused,0 ; 14 dw unused,0 ; 15 ; initvec ; initializes the re-direction vectors ; All 5 entries MUST be here. initvec: dw 8000h ; conin = crt dw 8000h ; conout = crt dw 0000h ; auxin = nothing dw 0000h ; auxout = nothing DW 0000h ; LIST = Nothing ; initstr ; strings of characters sent to a device ; during its initialization ; this table contains 1 string for each device ; (0-15) in the following format: ; db length-of-string (may be 0) ; db 'string-itself' (if any) initstr: ; strings (1 each device) ; each string <= 255 ; entire table only 256 bytes db 0,0,0,0,0,0,0,0 ; initially no strings each device db 0,0,0,0,0,0,0,0  .Z80 TITLE bios0 (excbios0) jmp table & unchanging rtns ; ************************************************* ; external version # ; 1.3 $version equ 1300h ; Must be in hex form 840924 ; v m m m ; v=version # ; mmm = mod level ; (leading zeroes not shown) ; internal version # ; date last changed version equ 4288h ; MUST be in hex form ; y d d d ; y=last digit of year ; ddd = days since 1 January ; ************************************************* ;1984-10-14 DAB Changed version for Vixen dsdd compatible. ; Added Future Systems Copyright ; Added 64 byte patch area ;1983-08-01 Modified internal and external version numbers to ; show the changes made to support DSDD ;1983-06-23 changed version # etc. for 2nd release ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* tbl addr call bios push hl ; save to get prefix later ld de,idevtbl+oursec ; where to put it ld bc,idevlen ; primary only ldir ld bc,0100h ; set banks src=00 dest=01 ld a,xmove call bios ; set next move across banks pop hl ; restore devtbl addr dec hl ; back up to use prefix ld d,(hl) ; get addr of initvector dec hl ld e,(hl) ; shadow ptr is at devtbl-2 ; de is source for 'move' ld hl,idevshd+oursec ; copy it to our sector ld bc,ishdlen+idvilen+idvslen+idellen ; shadow+initvec+strings+time-out ld a,move call bios ; ask bios to move x banks ; entire area now all set up, just write it out ; set up the ram for doing the i/o ; track 0 side 0 ld hl,trk00 ; pt to data area 840923 ld de,0 ; and track number call write5 ; write it all (5 sectors) ; track 0 side 1 840923 ld hl,savtyp ; Point at savtyp 840923 set 1,(hl) ; Set side bit to select side 1 840923 ld hl,oursec ; Point at SETUP override 840 and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; Table of contents of this module: ; (1) the signon message, with copyright ; (2) The bios jump table ; (3) A few unchanging routines of the bios. page dseg ; signon message only needed at cboot signon: ; signon message at cold boot db 1ah ; clear screen db 'Osborne Executive CP/M Plus BIOS' db ' V' ; external version follows db ($version/1000h and 0fh)+'0' ; v db '.' ; . db ($version/100h and 0fh)+'0' ; m if ($version/10h and 0fh) OR ($VERSION AND 0Fh) db ($version/10h and 0fh)+'0' ; m endif IF $VERSION AND 0Fh db ($version and 0fh)+'0' ; m ENDIF db 0dh,0ah ; official copyright warning message db 'Copyright ',1bh,'g',13h,1bh,'G ' ; "c" within a circle d '198 Osborn Compute Corporation',0dh,0ah db 'Copyright ',1bh,'g',13h,1bh,'G ' ; "c" within a circle 923 ld de,0000h ; sector 1 (1-1=0) track 0 840923 ld a,1 ; One sector 840925 call write ; write it 840923 ld a,(wtfm) ; see if writing main font ld hl,fmsec ; starting data area ld de,0100h ; sector 2 (2-1=1) track 0 840923 or a ; shd we write? ld a,2 ; if we do, write 2 sectors call nz,write ; write only if something to write ; ld a,(wtfa) ; see if writing alt font 840923 ; ld hl,fasec ; starting data area ; ld de,0202h ; sector 3 (3-1=2) track 2 ; or a ; shd we write? ; ld a,2 ; if we do, write 2 sectors ; call nz,write ; write only if something to write ld a,(wtrom) ; see if writing rom's ram ld hl,romsec ; starting data area ld de,0300h ; sector (4-1=3) track 0 840923 or a ; shd we write? ld a,1 ; if we do, write only 1 sector call nz,write ; write only if something to write ld de,donemsg ; that is it! call msg ; all done exit: jp 0 ; warm boot ; call the bios with rtn addr (lo) in a bios: ld (biosl),a ; set lo of call dofile 840923 ; the following files are optional ld a,-1 ld (optional),a ; indicate now optional ld de,fontm ; main font file ld hl,fmsec call dofile ld (wtfm),a ; 00=not there xx=is there ; ld de,fonta ; alt font file 840923 ; ld hl,fasec 840923 ; call dofile 840923 ; ld (wtfa),a ; 00=not there xx=is there 840923 ld de,romram ; final file is rom's ram override ld hl,romsec call dofile ld (wtrom),a ; 00=not there xx=is there ; all files have been read in ; from the running system, build up the special bios ; override sector. This is needed so that setup will ; function. Of course setup could do this itself ; when taking the current values from memory (the ; running system), but......... ld hl,(40h) ; bios version number ld (ivers+oursec),hl ; into our sector ld a,getdrv ; ask bios to get drvtbl addr call bios ld de,idrvtbl+oursec ; where to put it ld bc,idrvlen ldir ld a,getdev ; ask bios to get dev  bios addr ld a,(2) ; get hi of addr ld (biosh),a ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; modified code follows ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; biosjp: jp 0 ; really jp to bios entry biosl equ biosjp+1 ; lo of bios fcn addr biosh equ biosl+1 ; and hi of addr msg: ld c,pmsg ; let bdos issue a msg jp bdos ; pt'ed to by de page ; write ; write all or part of a sector to disk ; a # sectors to write ; e track # ; d sector number-1 (0=1) ; hl ptr to dma address ; write5 ; same, but sets a to 5 (full track) write5: ld a,5 ; set to full track write: or a ; see if anything to write ret z ; no, all done ld b,a ; save # sectors to write ld (wtaddr),hl ; set dma addr ld a,d ; get sector number inc a ; adj properly ld (wtsec),a ld a,e ; get track number ld (wttrk),a ld a,b ; restore # sectors to write ld bc,iolen ; length of i/o init area ld de,dmabank ; in hi common ram ld hl,wtparms ; tge ; torom ; a=rom routine address ; aka ourcode (before it is moved) ourcode: ; code which is moved above 4000h ld (thecall+1),a ; alter the call in a,(sys) or 80h ; turn on rom out (sys),a xcall: call 100h ; call the rom push af ; save in a,(sys) and 07fh ; turn rom off out (sys),a pop af ret ; and all done codelen equ $-ourcode ; length to move up himem equ 5000h ; move the code here torom equ himem ; routine to call to rom thecall equ torom+(xcall-ourcode) ; the call instruction stack equ himem+400h ; someplace also in non-rom page ; misc variables etc.... optional: db 0 ; non-zero if file is optional wtfm: db 0 ; ? write fontm (0=no) wtfa: db 0 ; ? write fonta (0=no) wtrom: db 0 ; ? write rom's ram (0=no) thefcb: dw excboot ; ptr to current fcb startmsg: db 0dh,0ah db 'This version of EXCWTSYS will write boot, cpmldr, main font,' db 0dh,0ah db 'SETUP override and ROM''s RAM override only to dsdd disk in' db 0dh,0ah db 'drio do some track ldir ; this is it ld b,a ; get # sectors to write ld a,wsec ; and the offset to write it call torom or a ; any errors writing? ret z ; no, all done writing jp wterr ; yes, then abort page ; dofile ; open then read in a file ; if "optional"<>0 then file is optional ; a returned=#sectors actually read in ; de ptr to fcb to use ; hl dma address starting dofile: ; open then read this file push hl ; save dma addr ld (thefcb),de ; and ptr to fcb ld hl,1 ; copy fname and ftype add hl,de ; from=fcb+1 ld de,fname ; copy in this file name ld bc,8 ldir inc de ; bump over the '.' ld bc,3 ; for file type ldir ld de,(thefcb) ; pt to file ld c,open ; open the file call bdos inc a ; ff=not found pop de ; restore starting dma addr jr z,badopen ; open error ld b,-1 ; init # sectors read count rdloop: inc b ; bump # setors read push de push bc ; save sector counter ld c,setdma ; set dma addr call bdos lve B' db 0dh,0ah,'$' donemsg: db 0dh,0ah db 'System tracks aok',0dh,0ah,'$' fname: ds 8 ; common name for messages db '.' ftype: ds 3 db 0dh,0ah,07h,'$' readmsg: db 0dh,0ah,'Error reading $' openmsg: db 0dh,0ah,'Unable to open $' wtmsg: db 0dh,0ah,'Error writing system tracks',0dh,0ah,'$' ldrmsg: db 0dh,0ah,'Error: cpmldr.com is too long' db 7,0dh,0ah,'$' ; this is set of parms passed to the rom ; to write 1-5 sectors wtparms: db 1 ; bank wtaddr: dw 0 ; addr wtsec: db 1 ; sector wttrk: dw 0 ; track db 1 ; unit 'B' ;;; db 0ch ; type 840923 iolen equ $-wtparms ; length to move up there excboot: db 0,'EXCBOOT COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 cpmldr: db 0,'CPMLDR COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;ccp: 840923 ; db 0,'CCP COM' ; dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 fontm: db 0,'FONTM COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;fonta: d de,(thefcb) ; crnt fcb ld c,read call bdos ; read one 128 byte sector pop bc ; restore sector count pop de ld hl,128 ; advance dma addr too add hl,de ex de,hl or a ; see if done or error jr z,rdloop ; not done yet dec a ; 1=done jr nz,badread ; no, error or b ; pass back # sectors read in ret ; all done reading, no errors wterr: ld de,wtmsg ; write error (no fname) abort: call msg jp exit ; and all done badopen: ld de,openmsg ; issue msg jr fabort badread: ld de,readmsg ; issue msg ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall through ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; common open/read error handler ; if "optional" then return a=0 and done, else error msg. fabort: ; error opening then reading a file call msg ; isse msg ld de,fname ; then say file name call msg ld a,(optional) ; is this file optional or a jp z,exit ; no, abort now xor a ; yes, pass back a=0 ret ; and done with file pa  840923 ; db 0,'FONTA COM' ; dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 romram: db 0,'ROMRAM COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 initial: ; do not change this ; db 'Glenn S. Tenney ' db 'ReservedReserved' ; oh well, fill the unused ; areas on the system ; tracks with something sec1 equ $ ; start of i/o areas ( 2 tracks long) 840923 ;sector 1 track 0 side 0 840923 sec2 equ sec1+1024 sec3 equ sec2+1024 sec4 equ sec3+1024 sec5 equ sec4+1024 trk00 equ sec1 ; 840923 sec6 equ sec5+1024 ; sector 1 track 0 side 1 840923 sec7 equ sec6+1024 sec8 equ sec7+1024 sec9 equ sec8+1024 sec10 equ sec9+1024 trk01 equ sec6 ; 840923 secend equ sec10+1024 ; 840923 bootsec equ sec1 ; excboot sec 1 trk 0 ldrsec equ sec2 ; cpmldr sec 2 trk 0 oursec equ sec6 ; where special stuff goes fmsec equ sec7 ; where main font begins romsec equ sec9 ; rom's ram override end n memory JP CBOOT wboot@: JP WBOOT JP CONIST JP CONIN JP CONOUT JP LIST JP AUXOUT JP AUXIN JP HOME JP SELDSK JP SETTRK JP SETSEC JP SETDMA JP READ JP WRITE JP LISTST JP SECTRN JP CONOST JP AUXIST JP AUXOST JP ptdev ; DEVTBL JP DEVINI JP ptdrv ; DRVTBL JP MULTIO JP FLUSH JP MOVE JP TIME JP SELMEM JP SETBNK JP XMOVE JP torom ; USERF JP RESERV1 JP RESERV2 ; Patch area in case of emergency ; DAB 10/14/84 patch: db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 page ; the following are (or should be) routines that will ; not change reserv1: reserv2: ret ; not currently implemented extrn devtbl,drvtbl ; tables ; ptdev point to device table ; returns address of serial device table ptdev: ld hl,devtbl ; just pt to the table ret ; ptdrv point to drive table ; returns address of dph (diskr ; later use during a disk transfer operation. ; ; ENTRY BC = Track number ; LD (SEKTRK),BC RET SETSEC: ; ; Set the sector number for later disk read/write operation. ; ; ENTRY BC = Sector number ; ld a,c ; get sector number inc a ; adjust for 1 origin ld (seksec),a ; save for later use RET FLUSH: ; ; Force physical buffer flushing for user supported deblocking ; ; ENTRY None ; ; EXIT None ; xor a ; do nothing, but did it ok RET PAGE MULTIO: ; ; Set count of consecutive sectors for READ or WRITE ; ; ENTRY C = Mutisector count ; ; EXIT None ; LD A,C LD (SECCNT),A xor a ; clear actual mult count ld (actcnt),a ; to start 'er off RET PAGE SECTRN: ; ; Translate sector number given translate table ; ; ENTRY BC = Logical sector number ; DE = Translate table address ; DE = 0, No translation required ; ; EXIT HL = Physical sector number ; LD l,c ; get logical sector # LD h,b LD A,E OR D RET Z Ad '1984 Future Systems, 828 Nob Hill Avenue, ' db 'Pinole, CA 94564',0dh,0ah db 0dh,0ah,0ah ; cr lf lf db 0 ; ends the msg ; Note: the very first data in common (cseg) MUST be ; the jump table. The above messages are in bank 0 ; (dseg) and therefore can appear first in the source. page .xlist include EXCBIOSE.LIB .list public wboot@ ; to reference jmp tbl public signon ; signon message for cboot public vers ; and version number public rvers ; and place to put rom's vers public patch ; Patch area 841014 EXTRN CBOOT, WBOOT ;SYSTEM INITIALIZATION EXTRN DEVINI EXTRN CONIST, CONIN, CONOUT ;CHARACTER I/O EXTRN LIST, AUXOUT, AUXIN EXTRN LISTST, CONOST EXTRN AUXIST, AUXOST EXTRN HOME, SELDSK, SETTRK ;DISK I/O EXTRN SETSEC, SETDMA, SECTRN EXTRN READ, WRITE EXTRN MULTIO, FLUSH EXTRN MOVE, XMOVE, SELMEM, SETBNK ;MEMORY MANAGEMENT EXTRN TIME extrn drvtbl,devtbl ; various tables extrn torom ; to give access to rom cseg ; commo DD HL,DE ; the tables MUST be in bank 0 or common in a,(sys) ; get crnt bank ld e,a ; save bank xor a ; force to bank 0 out (sys),a ; to locate sectran table LD L,(HL) ; pick up sector number from table ld h,a ; (a was 0) hl=sector number ld a,e ; restore bank number out (sys),a RET page ; this starts the routines that are further vectored ; by disk device via the dph prefix. We may be ; in other than bank 0 and the dph header is in bank 0, ; so we switch to bank 0 first. ; todseg ; transfer control to a bank 0 routine ; af destroyed on entry, preserved on exit ; bc preserved ; de preserved ; hl entry: addr of routine, preserved on exit todseg: ld (dsksave),sp ; save sp ld sp,dsksp ; make sure it is in common in a,(sys) ; save current bank ld (curbnk),a ld a,80h ; select bank 0 + rom out (sys),a ; and select rom + bank 0 call jphl ; call rtn in hl push af ; save result if any ld a,(curbnk) ; get saved bank out (sys),a ctor read or write ; de=offset from start of this dph for prefix ; word having address of routine. drw: ld hl,(dphnow) ; pt to current dph add hl,de ; hl=addr of write routine addr ld a,(hl) ; lo inc hl ld h,(hl) ; hi ld l,a ; hl=write routine addr jp (hl) ; off to write for this dph cseg page ; these are the various routines used by the standard ; built-in 5.25" floppies (or flopsies for comic strip aficionados) ; These must be in either common or bank 0. They will ; be called with bank 0 active (see above parent routines ; which call these). dseg ; stdini ; one time initialization (at cboot) stdini: ret ; nothing ; stdsel ; standard built-in 5.25" floppy select disk ; with sense density ; e bit 0 =1 if no sense density needed ; (ld a,e ... rra ; to chk lo bit of e) ; note: carry already set on entry ; hl addr of dph for that drive ; in may not = out of hl if error on sense density stdsel: jp c,seltyp ; done, set type ld a,h ; bank is now back pop af ; restore result ld sp,(dsksave) ; restore sp ret ; and all done jphl: jp (hl) ; simulate 'call (hl)' curbnk: ds 1 ; a place to save bank # page ; ; Select the specified Disk Drive ; ; ENTRY C = Disk Drive (0 - 15) ; BIT 0 E = 0, first call for this disk ; ; EXIT HL = DPH address for specified drive ; HL = 0000 if drive does not exist ; seldsk: ld hl,dsel ; pt to bank 0 routine jp todseg ; change to other bank dseg dsel: ld a,c ; save drive # ld (drive),a ; change to that drive now ld l,c ; get drive # ld h,0 ; into 16 bits ld bc,drvtbl ; start of table add hl,hl ; drive * 2 add hl,bc ; hl=ptr to proper entry ld a,(hl) ; lo byte inc hl ld h,(hl) ; hi byte ld l,a ; hl=that entry from table ld (dphnow),hl ; post current dph addr or h ; is there any such drive?? ret z ; no, get out NOW ; hl is dph for this drive push hl ; save for when we exit dec hl ; back up to drive # ld a,(hl) ; dr; 1st time, is drive valid or l ; hl=0 means no real drive ret z ; not valid, no senden and no seltyp! push hl ; save ptr to dph selrtry: ; here to retry ld a,(sekdsk) ; desired disk number ld (actdsk),a ; so senden can see it call 100h+senden ; call rom directly jr z,selok ; some diskette there ; no diskette or sense density didn't work call stdsen ; see if msg needed jr nz,selrtry ; yes, and user said RETRY pop hl ; just to clear the air ld hl,0 ; show no drive xor a ; and show things rather screwed up ld (sektyp),a ; some weird type (NOT Osborne dd) ld (spt),a ; dummy up to spt=0 ret ; and exit quickly! ; sense returned something, see what it was selok: ld hl,dpbtbl ; pt to head of table ld de,dpblen-1 ; length each entry sellp: ; figure out which dpb to use ld a,(acttyp) ; actual device push af ; 840930 push bc push de push hl call hexout ; 840930 pop hl pop de pop bc pop af ; 840930 push af ; 8ive # controller relative ld (sekdsk),a ; post controller's drive # ; let seldsk routine for this dph handle it now dec hl ; back up to hi of rtn addr ld a,(hl) dec hl ; to lo of seldsk addr ld l,(hl) ld h,a ; hl= seldsk for this dph ld a,e ; show if sense density needed rra ; carry=no no carry=yes ex (sp),hl ; hl=dph tos=seldsk rtn addr ret ; off to seldsk for this dph cseg page READ: ; ; Read a sector from the specfied drive ; ; ENTRY None ; ; EXIT A = 00h, if no errors ; A = 01h, if non-recoverable error occurred ; ld de,-7 ; offset of read addr in dph prefix jr torw ; off to other bank (common rtn) WRITE: ; ; Write a sector to the specified drive ; ; ENTRY None ; ; EXIT A = 00h, if no errors ; A = 01h, if physical error ; A = 02h, if disk is Read Only ; ld de,-5 ; offset of write addr in dph prefix torw: ld hl,drw ; pt to bank 0 routine jp todseg ; and off to other bank dseg ; common routine to ve 40930 push bc push de push hl ld a,b call hexout ; 840930 pop hl pop de pop bc pop af ; 840930 cp (hl) ; same as this tbl entry? inc hl ; 1st bump to sec/trk ld a,(hl) ; get spt from table jr nz,selnxt ; no, try next tbl entry cp b ; same as this drive jr z,selfnd ; yes--found it selnxt: inc a ; see if end of table jr z,selfnd ; yes (0ffh sec/trk) add hl,de ; bump to next entry jr sellp ; and try next entry ; this is the proper dpb selfnd: inc hl ; pt to skew ptr ex de,hl ; let de pt to this dpb entry pop hl ; restore ptr to dph push hl ld a,(de) ; copy skew ptr ld (hl),a ; into dph inc hl inc de ld a,(de) ld (hl),a ld bc,11 ; offset into dph for dpb add hl,bc ; hl=dph+12 inc de ; de=addr of dpb ld (hl),e ; plunk dpb addr in inc hl ld (hl),d ; dph now all set pop hl ; seldsk done, just set type for possible i/o ; and multok = or of skew tbl addr ; hl=dph ptr, get type from dpb prefix seltyp:  jp nz,rwmayb ; no, may be a real i/o though ld a,(seksec) ; crnt sector ld (sec1st),a ; is 1st sector of multiple ld hl,(dmaadr) ; same for dma addr ld (dma1st),hl rwmayb: ld hl,actcnt ; adj cnts inc (hl) ; actual count +1 inc hl dec (hl) ; multio count -1 jp z,rwrdy ; 0=this must be last rw of mult ld a,(multok) ; 00=multio allowed or a ; xx=no multio (skew active) jp nz,rwrdy ; not supported for multio inc hl ; pt to spt ld a,(seksec) ; crnt sector for r/w cp (hl) ; is this last sector of track? jp z,rwnow ; yes, read full or partial track ; no i/o done this time, just say it went ok xor a ; then just clear it for no err ret ; and exit as if it was ok rwrdy: ; rw ready (count reached 0) ld (hl),1 ; set seccnt to 1 rwnow: ; i/o required this time push de ; save rom jmp offset push bc ;save original seksec to restore after ldir ; Transfer BIOS variables to ROM varibles LD HL,dmabk ; copy our disk parms to rom's LD DE,dmald a,(hl) ; pick up skew tbl addr inc hl or (hl) ; a=0 if no skewing dec hl ; restore dph address ld (multok),a ; so multio will work ex de,hl ; de=dph ld hl,12 add hl,de ; hl=dph+12 (ptr to dpb) ld a,(hl) ; lo of dpb addr inc hl ld h,(hl) ; hi of dpb addr ld l,a ; hl=this dpb dec hl ; back up to sectors per track dec hl dec hl ld a,(hl) ; get sectors per track ld (spt),a ; for multio usage dec hl ; back up to disk type value ld a,(hl) ; get crnt disk type info ld (sektyp),a ; and that is to be used ex de,hl ; restore regs ret ; all done with seldsk hexout: ; 840930 push af rrca rrca rrca rrca call hexify pop af hexify: and 0fh cp 0ah jr c,hex2 add a,7 hex2: add a,'0' ld c,a jp 100h+cout ; stdrd ; stdwt ; standard 5.25" built-in floppy read and ; write routines (see read/write above) stdrd: ld e,rsec ; to read a sector jp stdrw ; common for read or write stdwt: ld e,wsec ; to write a bank ; this is start of rom's ram LD BC,SEKTYP-dmabk+1 ; length to copy LDIR pop af ;get seksec and-- ld (sektyp),a ; restore to previous dorw: ld a,(sec1st) ; 1st sector of multiple ld (actsec),a ld hl,(dma1st) ; and starting addr ld (dmadr),hl ld a,(actcnt) ; get number of sectors ld b,a ; for rom to read/write ; now ready to do the actual i/o then check for errors pop hl ; restore rom rtn addr (l) push hl ; save rom rtn addr offset ld h,01h ; make it true addr call jphl ; call (hl) pop de ; restore rom rtn offset or a ; were there any errors jr z,rwok ; no, ok to exit rw then ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; NOTICE: ; The following is a bit of a kludge inserted because ; the BDOS does not appear to handle both media change ; and density change on the same drive. The problem is ; that when the media changes (which is posted by an ; interrupt routine) the BDOS notices the flag and tries ; to see if tsector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; jp stdrw ; fall thru to common routine ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Performs a read or a write ; ; entry e=offset to proper rom routine (rsec or wsec) stdrw: ; i/o may be deferred based on multio ; Check if read or write to double sided media ld a,(sektyp) ;chk disk type ld b,a ;save disk type to restore later bit 1,a ;check double sided bit jr z,sngsd ;if not double sided , just do rw ; the target is double sided , so reajust the sector number ld hl,spt ;point to max phy sector/track ld a,(seksec) ;get the seek sector sub (hl) ;a = seksec - spt jr z,rwside0 ;if seksec = spt , no adjust jr c,rwside0 ;if seksec < spt , no adjust rwside1: ld (seksec),a ;adjust the bios seksec jr sngsd rwside0: ld hl,sektyp ;point to rom sektyp res 1,(hl) ;reset side bit of savtyp sngsd: ld a,(actcnt) ; is this 1st rw? or a ; to init dma and sector  he media really changed. Although the ; documentation states that the BDOS will then issue ; an initial SELDISK and then read the directory, the ; BDOS just goes ahead and blindly reads the new disk. ; Well, if the density, sector size or sectors per track ; just happen to be different on the new disk, the ; results are UNPREDICTABLE!!!!!! ; If the density changes, then an error will be posted. ; If the density remains the same, it is likely that the ; read will, if it is for a sector valid on the new media, ; detect that the directory is different. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; we had some error, see if media changed push af ; save error condition push de ; save rom rtn addr push bc ; and fdc status byte call 100h+senden ; see if same density jr nz,dskchg ; error on sense, media changed ld a,(spt) ; sense ok, see if same as old cp b ; same sectors per track? jr nz,dskchg ; no -- must have changed ld hl,sektyp ; hmm then check disk) table ptdrv: ld hl,drvtbl ; just pt to the table ret page ; the following represents the special area in page 0 ; of bank 1 (the tpa) that allows programs to reference ; information about the rom and bios ; This information is initialized during cboot and then ; moved to 40h bank 1 during every wboot. dseg ; ok to keep it over there ; (1) for the bios vers: dw version ; version number of this bios db 2 ; product code db 0 ; feature code ; (2) same for the rom rvers: ds 4 ; version, product and feature ds 8 ; 16 bytes currently available END  db 'Patch',0,0,0 page ; the following are (or should be) routines that will ; not change reserv1: reserv2: ret ; not currently implemented extrn devtbl,drvtbl ; tables ; ptdev point to device table ; returns address of serial device table ptdev: ld hl,devtbl ; just pt to the table ret ; ptdrv point to drive table ; returns address of dph (disk type ld a,(acttyp) ; new type cp (hl) ; vs. old type jr nz,dskchg ; different! a changed disk ; at least it is the same type of media, as far as ; we can tell, so process the error pop bc ; b=fdc status byte pop de ; e=rom rtn addr pop af ; seems the same, process error ; let our error routine process the error. ; That routine may issue an error message or ask ; us to retry. ; We pass to it: ; a error flag ; b fdc status byte ; e rom rtn addr ; The error routine must restore all regs and: ; Z no retry, return error ; NZ retry again call stderr ; issue std err msg (maybe) jr nz,rwnow ; asked to retry rwok: ld hl,actcnt ; reset sector count ld (hl),0 ; without changing af ret ; and all done dskchg: pop bc ; media HAS changed, show it pop de pop af ; clear the stack xor a dec a ; a=ffh to show media changed jr rwok ; and exit w/ i/o completed cseg page cseg ; common cause of dmabk ; the following are a few areas used onl#)r;L#)r;L! !H@ !ɠme ; the time is being updated by the rom interrupt routine time: ret ; do nothing ; these are areas used only within this module ubank: ds 1 ; save crnt bank here going to rom ; or when flipping banks ; these are bank numbers for transfers ; they MUST be in this order ! ! ! ! ! ! sbank: ds 1 ; current source bank dbank: ds 1 ; current destination bank ; this is a kludge because dri calls xmove then selmem and then move kludge: db 0 ; nonzero = use s/d bank end 00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5F7 :101E9B00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E7 :101EAB00E5E5E5E5E5E5E5F74E4E4E4E4E4E4E4E7D :101EBB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E37 :101ECB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E27 :101EDB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4y w/in this ; module ; parameters local to the bios re: disk i/o drive: db 0 ; current drive # 0 relative dphnow: dw 0 ; addr of crnt dph (set by seldsk) multok: db 0 ; the or of skew table addr ; 0=multio ok this drive ; x=no multio this drive ; these 3 items must be in this sequence actcnt: db 0 ; actual number of sectors this i/o seccnt: db 1 ; multio number of sectors spt: ds 1 ; sectors per track crnt drive sec1st: ds 1 ; starting sector when multiples dma1st: ds 2 ; starting dma addr when multiples ; the following MUST be the SAME as the rom dmabk: db 00h ; desired bank for xfr ( default = 00 ) dmaadr: ds 2 ; desired address for xfr seksec: ds 1 ; desired sector sektrk: ds 2 ; track sekdsk: ds 1 ; disk unit sektyp: db 0ch ; sector size ------>>> forced to Osborne dd ; sector size end UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU; "c" within a circle d '1984 Future Systems, 828 Nob Hill Avenue, ' db 'Pinole, CA 94564',0dh,0ah db 0dh,0ah,0ah ; cr lf lf db 0 ; ends the msg ; Note: the very first data in common (cseg) MUST be ; the jump table. The above messages are in bank 0 ; (dseg) and therefore can appear first in the source. page .xlist include EXCBIOSE.LIB .list public wboot@ ; to reference jmp tbl public signon ; signon message for cboot public vers ; and version number public rvers ; and place to put rom's vers public patch ; Patch area 841014 extrn dpbtbl ; 841014 EXTRN CBOOT, WBOOT ;SYSTEM INITIALIZATION EXTRN DEVINI EXTRN CONIST, CONIN, CONOUT ;CHARACTER I/O EXTRN LIST, AUXOUT, AUXIN EXTRN LISTST, CONOST EXTRN AUXIST, AUXOST EXTRN HOME, SELDSK, SETTRK ;DISK I/O EXTRN SETSEC, SETDMA, SECTRN EXTRN READ, WRITE EXTRN MULTIO, FLUSH EXTRN MOVE, XMOVE, SELMEM, SETBNK ;MEMORY MANAGEMENT EXTRN TIME extrn drvtbl,devtbl ; various tables extr512,8,40,1024,64+8000h,1 db dec ; DEC db 9 dw decxlt dpbdec: dpb 512,9,40,1024,64+8000h,2 db 0 ; 8" sssd db 0ffh ; end of table 26 dw stdxlt ibm8: dpb 128,26,77,1024,64+8000h,2 dseg ; ok in bank 0 ; these are the actual skew tables odsxlt: db 0,2,4,1,3,5,7,9,6,8 oddxlt equ 0 ; no skewing needed osdxlt: db 0,2,4,6,8,1,3,5,7,9 xrxxlt: db 0,5,10,15 ; physical equals logical db 2,7,12,17 db 4,9,14 db 1,6,11,16 db 3,8,13 ibmxlt equ 0 ; no skewing needed decxlt: db 0,2,4,6,8,1,3,5,7 stdxlt: db 0,6,12,18,24,4,10,16,22,2,8,14,20 db 1,7,13,19,25,5,11,17,23,3,9,15,21 end 00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5F7 :101E9B00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E7 :101EAB00E5E5E5E5E5E5E5F74E4E4E4E4E4E4E4E7D :101EBB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E37 :101ECB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E27 :101EDB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4n torom ; to give access to rom cseg ; common memory JP CBOOT wboot@: JP WBOOT JP CONIST JP CONIN JP CONOUT JP LIST JP AUXOUT JP AUXIN JP HOME JP SELDSK JP SETTRK JP SETSEC JP SETDMA JP READ JP WRITE JP LISTST JP SECTRN JP CONOST JP AUXIST JP AUXOST JP ptdev ; DEVTBL JP DEVINI JP ptdrv ; DRVTBL JP MULTIO JP FLUSH JP MOVE JP TIME JP SELMEM JP SETBNK JP XMOVE JP torom ; USERF JP RESERV1 JP RESERV2 dw dpbtbl ; Pointer to dpb table 841014 ; Patch area in case of emergency ; DAB 10/14/84 patch: db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 db 'Patch',0,0,0 page ; the following are (or should be) routines that will ; not change reserv1: reserv2: ret ; not currently implemented extrn devtbl,drvtbl ; tables ; ptdev point to device table ; returns address of serial device table ptdev: ld hl, title bios1 (excbios1) disk drive tables ;1984-10-14 DAB Changed OFFset field in OCC DSDD to 1 to make Vixen ; compatible. ; Added extra dpb for later use. ;1983-07-27 Set up new DPB and sector XLT table for DSDD ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* and * ;* Roger W. Chapman * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; This module is only the various disk parameter ; tables. ; Built-in drives are generated as permanent with ; directory checksums. ; Written by: Glenn S. Tenney, November 1982 ; Various macros used to generate disk tables for ; CP/M Plus. ; define the 16-drive drive table dtbl macro ?list local ?n ?n set 0 irp ?drv, ?n set ?n+1 devtbl ; just pt to the table ret ; ptdrv point to drive table ; returns address of dph (disk) table ptdrv: ld hl,drvtbl ; just pt to the table ret page ; the following represents the special area in page 0 ; of bank 1 (the tpa) that allows programs to reference ; information about the rom and bios ; This information is initialized during cboot and then ; moved to 40h bank 1 during every wboot. dseg ; ok to keep it over there ; (1) for the bios vers: dw version ; version number of this bios db 2 ; product code db 0 ; feature code ; (2) same for the rom rvers: ds 4 ; version, product and feature ds 8 ; 16 bytes currently available END e ; the following are (or should be) routines that will ; not change reserv1: reserv2: ret ; not currently implemented extrn devtbl,drvtbl ; tables ; ptdev point to device table ; returns address of serial device table ptdev: ld hl, dw ?drv endm if ?n gt 16 .' Too many drives. Max 16 allowed' exitm endif if ?n lt 16 rept (16-?n) dw 0 endm endif endm ; defines the disk parameter header dph macro ?trans,?dpb,?csize,?asize local ?csv,?alv dw ?trans ; translate (skew) table db 0,0,0,0,0,0,0,0,0 ; BDOS scratch area db 0 ; media flag dw ?dpb ; disk parameter block if not nul ?csize dw ?csv ; checksum vector else dw 0fffeh ; GENCPM sets checksum vector endif if not nul ?asize dw ?alv ; allocation vector else dw 0fffeh ; GENCPM sets allocation vector endif dw 0fffeh,0fffeh,0fffeh ; GENCPM sets: dirbcb, dtabcb, hash alloc'd db 0 ; hash bank if not nul ?csize ?csv: ds ?csize ; checksum vector endif if not nul ?asize ?alv: ds ?asize ; allocation vector endif endm ; defines disk parameter blocks dpb macro ?psize,?pspt,?trks,?bls,?ndirs,?off,?ncks local ?spt,?bsh,?blm,?exm,?dsm,?drm,?al0,?al1,?cks,?psh,?psm local ?n ;; physical sector mast back as current 840922 ; reads in 4k of character sets from track 2 bit 1,a ; Is disk dsdd or ssdd? 840924 jr nz,dschar ; It's dsdd... 840924 ; ld hl,chrinit ; No, it's ssdd, point at ssdd data 840924 ld a,4 ; structure and specify 4 sectors to 840924 jr readchr ; read. Then read it, just read it. 840924 ; dschar: ; Disk is dsdd 840924 ld hl,dschrinit ; init parms to read in char sets 840923 ld a,2 ; read just 1 char set 840923 readchr: ; 840924 call read ; read disk jp nz,booterr ; yes--issue a msg and hang ; font ram will be loaded a little later ; read in table of rom's ram to init ld a,(savtyp) ; Check for dsdd or ssdd 840924 bit 1,a ; 840924 jr nz,dsrom ; It dsdd... 840924 ; ld hl,tblinit ; No, it's ssdd...Point at data struct 840924 jr readrom ; and go read it. 840924 ; dsrom: ; 840924 ld hl,dstblinit ; disk parm table 840923 ; readrom: ; 840924 ld a,1 ; read 1 sector call read jp nz,booteescape sequence char for cursor type ibg equ icur+1 ; esc seq char for background type iclick equ ibg+1 ; esc seq char for kbd click cpmldr equ 4400h ; place cpmldr is linked to execute org 4000h ; must be here !!! ; the following is the header that MUST appear ; at the beginning of the 1st sector of the system ; disk. This header is used by the rom to verify ; that this is a valid system diskette and may be ; used in the future by this and other bios'es to ; determine diskette formats. nop ; x'00' = system bootable disk jp start ; followed by jmp to real code db 2 ; product code (must match rom) db 0 ; feature code ; the next byte is a length byte. ; this tells how many table bytes follow. ; it is here for future expansion, since it is ; expected that the media type byte and the dpb for ; this diskette will be here. That will allow diskettes ; to be other than O1 format double density. ; It is zero now so that when the format is resolved ; futurr ; yes--issue a msg and hang ; table is as follows ; rom version (2) unused ; kbd decode (11+320) ; fcn keys (512) ; hertz (1) ; crt esc chars (3) curtype,bg,click di ; just in case kbd is touched ld bc,11+320+512 ; copy keyboard masks, decode and function keys ld de,kbdtbl ; where it is to be in rom's ram ld hl,ikbdtbl ; from disk ldir ; move it in ld b,08h ; bit on if 50hz ld a,(ihz) ; get hertz value ld (hertz),a ; set into rom's ram cp 60 ; see how to init the port jr nz,not50 ; 50hz means b is right ld b,0 ; 60hz, so no bit gets set not50: in a,(sysb) ; get crnt status and 255-08h ; clear 50/60 bit or b ; and set to desired rate out (sysb),a ; so it is all set ei ; now ready to alter the screen etc. ld c,1ah ; ctl-z = clear screen call 100h+cout ; 1st clear the screen ; then copy font data to font memory ld a,(savtyp) ; Is disk dsdd? 840924 bit 1,a ; 840924 jr z,moveall ; Yes, move main and alt char sets 840924 ;re bios'es can tell the difference. db 0 ; number of table bytes following start: ld sp,0fd00h ; stack up in common in a,(sys) ; current bank or 80h ; turn on rom out (sys),a ; Set head step rate to 12 ms. 840924 ld a,(sekdel) ; Load current step rate 840924 and 11111100b ; Strip off low order two bits 840924 or 00000001b ; Set low order bit (this means 12 ms 840924 ; given the Executive's 1MHz FDC clock) 840924 ld (sekdel),a ; Save it back 840924 ; reads in cpmldr from system track 0 ld a,(savtyp) ; Load current savtype 840922 push af ; Save it on stk 840922 res 1,a ; Reset side bit to select side 0 840922 ld (savtyp),a ; Save it as current savtyp 840922 ld hl,raminit ; init parms in ram from here ld a,04 ; read 4 sectors (2-5) call read ; read disk or a ; any errors? jp nz,booterr ; yes--issue a msg and hang (savtyp 840922 ; still on stk) 840922 pop af ; Restore old savtyp 840922 ld (savtyp),a ; and save i ; No. Move main font into main font & 840924 ; alt font memory 840924 ld a,2 ; Do it twice. 840924 ld de,0 ; Point at destination 840924 mvlp: ld hl,chrfont ; Point at disk data 840924 ld bc,2*1024 ; Only main font (2K) 840924 ldir ; Move it 840924 dec a ; Check for end 840924 jr nz,mvlp ; No... 840924 ; jr movedchar ; Yes... 840924 moveall: ; 840924 ld hl,chrfont ; from what we just read ld de,0 ; into font memory ld bc,4*1024 ; both fonts ldir ; just move it in ; (rom is already enabled) movedchar: ; 840924 ; send escape sequences to set cursor type, bg type and click ld c,1bh ; escape call cout+100h ld c,'.' ; period call cout+100h ld a,(icur) ; and initial cursor type ld c,a call cout+100h ld c,1bh call cout+100h ld c,'x' call cout+100h ld a,(ibg) ; initial background ld c,a call cout+100h ld c,1bh call cout+100h ld a,(iclick) ; and initial keyboard click ld c,a c any bank (really in common) dw table ; up in hi memory db 5 ; sector 5 dw 2 ; track 2 db 0 ; drive 0 dstblinit: ; to init rom's other ram areas from disk 840923 db 80h ; any bank (really in common) 840923 dw table ; up in hi memory 840923 db 4 ; sector 840923 dw 0 ; track 0 (side 1) 840924 db 0 ; drive 0 840923 ; at the very end of this boot sector will be the ; serialization info. Therefore, show it takes up some ; space in case the boot is too large. bootlen equ $-start ; length of this program if bootlen and 0fc00h ; if > 1k (1 sector) .' error, boot is too large ' endif end FONTM COMROMRAM COMReservedReservedall cout+100h ld c,1bh call cout+100h ld c,'e' ; enable kbd table decode call cout+100h ; all done, turn rom off in a,(sys) ; current bank and 07fh ; turn off rom out (sys),a ; all ready for cpmldr jp cpmldr ; off to it now page ; subroutines etc.... ; read ; hl=ptr to parms in our ram area here ; a=number of sectors to read ; setup disk parms and read disk read: ld de,dmabank ; to common ram area ld bc,ramilen ; this many bytes ldir ; copy ld b,a ; copy number of sectors to read jp rsec+100h ; let rom read now! ; booterr ; when we detect any disk error we come ; here to issue a message and then just hang booterr: ; issue an error message ld hl,errmsg ; pt to start of message errlp: ld c,(hl) ; get next character of msg ld a,c ; see if this is the end of the msg or a ; if so, forcibly loop forever jr z,errlp ; end ----> loop forever inc hl ; advance to next character push hl call cout+100h ; send that charactk and physical sector shift ;; ?psh set 0 ?n set ?psize/128 ?psm set ?n-1 rept 8 ?n set ?n/2 if ?n eq 0 exitm endif ?psh set ?psh+1 endm ?spt set ?pspt*(?psize/128) ?bsh set 3 ?n set ?bls/1024 rept 8 ?n set ?n/2 if ?n eq 0 exitm endif ?bsh set ?bsh + 1 endm ?blm set ?bls/128-1 ?size set (?trks-?off)*?spt ?dsm set ?size/(?bls/128)-1 ?exm set ?bls/1024 if ?dsm gt 255 if ?bls eq 1024 .' Invalid disk size with 1k block size' exitm endif ?exm set ?exm/2 endif ?exm set ?exm-1 ?al1 set 0 ?n set ((?ndirs and 7fffh)*32+?bls-1)/?bls rept ?n ?al1 set (?al1 shr 1) or 8000h endm ?al0 set high ?al1 ?al1 set low ?al1 ?drm set (?ndirs and 7fffh)-1 if not nul ?ncks ?cks set ?ncks else ?cks set (?ndirs and 7fffh)/4+(?ndirs and 8000h) endif ;; all computed finally dw ?spt ; 128 byte sectors per track db ?bsh,?blm ; block shift and mask db ?exm ; extent mask dw ?dsm ; maximum block number dw ?drm ; maximum directory number db ?al0,?al1 ; alloc veer pop hl jr errlp ; keep sending the msg page ; equates and constants ; the error message we issue in case of any disk read error ; (a 00h byte ends the msg) errmsg: db 0dh,0ah,07 db 'BIOS boot error reading disk. ' db 'System reset required.' db 0dh,0ah,00 raminit: ; table to init ram parms for disk read db 00h ; bank dw cpmldr ; dma address db 2 ; start at sector 2 dw 0 ; of track 0 db 0 ; from drive 0 ramilen equ $-raminit ; length to init chrfont equ cpmldr+4096 ; after cpmldr comes fonts chrinit: ; table for reading character sets db 80h ; rom bank dw chrfont ; where character sets are db 1 ; start sector 1 dw 2 ; track 2 db 0 ; from drive 0 dschrinit: ; table for reading character sets 840923 db 80h ; rom bank 840923 dw chrfont ; where character sets are 840923 db 2 ; start sector 2 840923 dw 0 ; track 1 (side 1) 840923 db 0 ; from drive 0 840923 tblinit: ; to init rom's other ram areas from disk db 80h ;ctor for directory dw ?cks ; checksum size dw ?off ; number of reserved tracks db ?psh,?psm ; physical sector size and mask endm ; ; ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list page ; declare the drive table public drvtbl ; table of drives public dpbtbl ; our dpb table w/ prefix public dph0,dph1 ; Built-in drive's dph's extrn stdini,stdsel,stdrd,stdwt ; built-in std routines cseg ; must be in common drvtbl: dtbl ; Note: With disk change in the interrupt routine, the dph must be ; in common memory. ; every dph MUST have a prefix as follows: ; -9 dw init-routine (at cboot once only) ; -7 dw read-routine ; -5 dw write-routine ; -3 dw seldisk-routine ; -1 db controller-relative drive number ; +0 dph --- the dph itself --- ; see the stdsel, stdrd and stdwt routines ; for documentation ; drive 0 dw stdini ; standard init routine dw stdrd ; standard read routine dw stdwt ; standard write routine dw db 4,9,14 db 1,6,11,16 db 3,8,13 ibmxlt equ 0 ; no skewing needed decxlt: db 0,2,4,6,8,1,3,5,7 stdxlt: db 0,6,12,18,24,4,10,16,22,2,8,14,20 db 1,7,13,19,25,5,11,17,23,3,9,15,21 end  end of table 26 dw stdxlt ibm8: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra2: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra3: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra4: dpb 128,26,77,1024,64+8000h,2 dseg ; ok in bank 0 ; these are the actual skew tables odsxlt: db 0,2,4,1,3,5,7,9,6,8 oddxlt equ 0 ; no skewing needed osdxlt: db 0,2,4,6,8,1,3,5,7,9 xrxxlt: db 0,5,10,15 ; physical equals logical db 2,7,12,17 stdsel ; standard seldisk routine db 0 ; controller drive # 0 dph0: dph oddxlt,dpbds ; use Osborne dsdd for now (as max) ; drive 1 dw stdini ; standard init routine dw stdrd ; standard read routine dw stdwt ; standard write routine dw stdsel ; standard seldisk routine db 1 ; controller drive # 1 dph1: dph oddxlt,dpbds cseg ; must be in common dpbtbl: ; each dpb is preceeded by ; associated device type code ; then sectors per track (actual) ; then addr of skew table (or 0) ; the table is terminated by an entry ; with a sectors/trk of 0ffh ; db disk-type-code ; db sectors-per-track ; dw skew-table ; lbl: dpb psize , pspt , trks , bls , ndirs , off , ncks db dstype ; Osborne dsdd db 5 dw odsxlt dpbds: dpb 1024,10,40,2048,128+8000h,1 db dskd1 ; Osborne ssdd db 5 dw oddxlt dpbd1: dpb 1024,5,40,1024,64+8000h,3 db dsks1 ; Osborne sssd db 10 dw osdxlt dpbs1: dpb 256,10,40,2048,64+8000h,3 db xerox  ; Xerox db 18 dw xrxxlt dpbx0: dpb 128,18,40,1024,32+8000h,3 db ibm ; IBM db 8 dw ibmxlt dpbibm: dpb 512,8,40,1024,64+8000h,1 db dec ; DEC db 9 dw decxlt dpbdec: dpb 512,9,40,1024,64+8000h,2 db 0 ; 8" sssd db 0ffh ; end of table 26 dw stdxlt ibm8: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra2: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra3: dpb 128,26,77,1024,64+8000h,2 db 0 ; 8" sssd extra 841014 db 0ffh ; end of table 26 dw stdxlt extra4: dpb 128,26,77,1024,64+8000h,2 dseg ; ok in bank 0 ; these are the actual skew tables odsxlt: db 0,2,4,1,3,5,7,9,6,8 oddxlt equ 0 ; no skewing needed osdxlt: db 0,2,4,6,8,1,3,5,7,9 xrxxlt: db 0,5,10,15 ; physical equals logical db 2,7,12,17 title 'System Control Block Definition for CP/M3 BIOS' public @civec, @covec, @aivec, @aovec, @lovec, @bnkbf public @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd public @mltio, @ermde, @erdsk, @media, @bflgs public @date, @hour, @min, @sec, ?erjmp, @mxtpa scb$base equ 0FE00H ; Base of the SCB @CIVEC equ scb$base+22h ; Console Input Redirection ; Vector (word, r/w) @COVEC equ scb$base+24h ; Console Output Redirection ; Vector (word, r/w) @AIVEC equ scb$base+26h ; Auxiliary Input Redirection ; Vector (word, r/w) @AOVEC equ scb$base+28h ; Auxiliary Output Redirection ; Vector (word, r/w) @LOVEC equ scb$base+2Ah ; List Output Redirection ; Vector (word, r/w) @BNKBF equ scb$base+35h ; Address of 128 Byte Buffer ; for Banked BIOS (word, r/o) @CRDMA equ scb$base+3Ch ; Current DMA Address ; (word, r/o) @CRDSK equ scb$base+3Eh ; Current Disk (byte, r/o) @VINFO equ scb$base+3Fh ; BDOS Variable "INFO" ; (word, r/o) @RESEL equ scb$base+41h ; FCB Flag (byte, r/o) @FX equ scb$base+43h ; BDOS Function for Error ; Messages (byte, r/o) @USRCD equ scb$base+44h ; Current User Code (byte, r/o) @MLTIO equ scb$base+4Ah ; Current Multi-Sector Count ; (byte,r/w) @ERMDE equ scb$base+4Bh ; BDOS Error Mode (byte, r/o) @ERDSK equ scb$base+51h ; BDOS Error Disk (byte,r/o) @MEDIA equ scb$base+54h ; Set by BIOS to indicate ; open door (byte,r/w) @BFLGS equ scb$base+57h ; BDOS Message Size Flag (byte,r/o) @DATE equ scb$base+58h ; Date in Days Since 1 Jan 78 ; (word, r/w) @HOUR equ scb$base+5Ah ; Hour in BCD (byte,  ; indicates xon protocol used rometx equ 2 ; indicates etx protocol used romver equ 00feh ; 2 byte rom version number ; of the form: DW ydddH (year day day day) romprod equ romver-2 ; rom's product code and feature code ; special override equates ; these specify the area on sector 5 track 1 (after ccp) ; which allow the disk to override the assembly of ; various tables. The table begins with the 2 byte ; version number of the bios. No overrides are processed ; unless the number from the diskette matches our own number. ; This is because the tables being overriden contain ; actual memory addresses. The remainder of the table ; is best described by the following equates. ivers equ 0 ; version number must match idrvtbl equ ivers+2 ; drvtbl tbl of dph ptrs idrvlen equ 16*2 ; length of data part idevtbl equ idrvtbl+idrvlen ; devtbl serial device table idevlen equ 16*8 ; primary table idevshd equ idevtbl+idevlen ; devtbl serial device ishdlen equ 16*4r/w) @MIN equ scb$base+5Bh ; Minute in BCD (byte, r/w) @SEC equ scb$base+5Ch ; Second in BCD (byte, r/w) ?ERJMP equ scb$base+5Fh ; BDOS Error Message Jump ; (word, r/w) @MXTPA equ scb$base+62h ; Top of User TPA ; (address at 6,7)(word, r/o) end EVTBLdE%eD$HFLUSHDXȀLISTdĕ5E5H`MOVEdTD@READ1U%dU%8ɈSECTRNe4TE4ʐSELMEMe4UD$(SETDMAe4UE4T8SETTRKe4txTIMEUD$VERSUt$HWBOOT@Uu$DXXMOVESTd45HhCONOUTdDUd(DEn(ZVi @װE-4-D5ldZ/x0KZK\% kZ-{G[2 ru&%Ɣ2"du)$"Ƃ2"dt`&*GB"Bzj,th&*$W"* $t))'GU2*b"\t)!'%@2*"j tH))C@2*\i)"")G@2"JrL{")"G2"*di)")G*"u$"5ldZ/x0KZK\% kZ-{G[2 ru&%Ɣ2"du)$ ; sahdow table idvini equ idevshd+ishdlen ;then comes init values ;first is init re-direction idvilen equ 5*2 idvstr equ idvini+idvilen ; then init strings idvslen equ 16*16 ; (total max length) idelay equ idvstr+idvslen ; Device delay variables idellen equ 2 iexd equ idelay+idellen ; End (or next entry) ; ; ;; -30- excbiose.lib 0 @8(Ba(,"AX DPBTBLDEXDPH1dE%eD$STDINIU5DE$H@STDSELU5DEuI  `pH UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEXCASM.SUB ; A submit file to assemble all of the source files. ; This uses M80 and RMAC. ; ; G. EXCLINK.SUB ; A submit file to create all .COM files and the CPM3.SYS ; file. This uses LINK and GENCPM. ; ; H. EXCPIP.SUB ; A submit file to copy all files created by EXCLINK to ; a 5.25" diskette for generation. ; ; I. EXCPRT.SUB ; Combines all printout files for later printing. ; ; J. GENCPM.DAT ; This is the script containing the answers to all of the ; questions asked by GENCPM.COM. This is a standard ; feature of GENCPM, but the contents of this file are ; the answers needed to properly generate this BIOS. ; ; K. EXCPATCH.SUB ; This file indicates the way to patch CPMLDR.COM to ; fix the DRI bug of disabling interrupts then issuing a ; HALT whenever an error is found. Such a condition ; is unacceptable. As a submit file, this requires ; the program XSUB. ; page ; Generation Procedures ; ; A. Requirements: ; 1. The following programs will be used:  title EXCBIOS documentation and generation procedures include EXCBIOS.DOC ; include EXCBIOSE.LIB include EXCBIOSE.LIB end  this drive ; these 3 items must be in this sequence actcnt: db 0 ; actual number of sectors this i/o seccnt: db 1 ; multio number of sectors spt: ds 1 ; sectors per track crnt drive sec1st: ds 1 ; starting sector when multiples dma1st: ds 2 ; starting dma addr when multiples ; the following MUST be the SAME as the rom dmabk: db 00h ; desired bank for xfr ( default = 00 ) dmaadr: ds 2 ; desired address for xfr seksec: ds 1 ; desired sector sektrk: ds 2 ; track sekdsk: ds 1 ; disk unit sektyp: db 0ch ; sector size ------>>> forced to Osborne dd ; sector size end UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ; SUBMIT, PIP, M80, RMAC, LINK, GENCPM, ; and XSUB and SID if running EXCPATCH.SUB. ; ; 2. The following disks are referred to throughout ; this document and are needed: ; ; All of the source files (.MAC, .LIB, ; .DOC). ; The object files supplied by DRI (.SPR, ; .DAT, CPMLDR.REL and CCP.COM) and ; where our object files will be written. ; Where all the .PRN files will be ; written (from our assemblies). ; These files occupy over 350K. ; Where the single combined (and large) ; .PRN file will be written. ; Where the files will be PIP'ed which ; will write the system tracks. This disk ; will be used on a running Executive to ; create . ; This will be the bootable CP/M Plus ; system disk. ; ; It is anticipated that and will be the ; same physical (logical) disk with being a ; separate disk. is used to combine all the ; various files for a complete listing and would ; likely be on a disk shared by the printer. ; Disks and are different physical 5.25" disks. ; ; ; ; B. Procedures ; ; 1. Assemble all source files. ; ; Enter: ; SUBMIT EXCASM ; ; where: ; is the letter of the drive which ; contains the source files ; is the letter of the drive which ; will contain the .REL files (object). ; is the letter of the drive which will ; contain the .PRN files (printouts). ; ; Example: ; SUBMIT EXCASM B C D ; ; ; ; 2. Process all .REL files (create the bios proper) ; ; Enter: ; SUBMIT EXCLINK ; ; ; Special Notes: ; ; The current drive for this step MUST be the ; same as specified in step 1 above. This ; means that the object files (.REL and .SPR) ; must be on the same drive as the GENCPM files ; and the resulting .COM files and CPM3.SYS will ; be placed onto this drive. ; ; At the end of EXCLINK, you will be instructed ; to copy down the last few lines on thsince the fonts are being loaded the ; screen might have garbage on it. Since the ; keyboard decode tables are being loaded, the ; keyboard may produce weird results. If the ; disk being gen'ed by EXCWTSYS did once contain ; this information on its system track, then ; everything may appear to work, but may not ; function as expected since that disk may have ; been setup for someone's weird configuration. ; ; ; 5. Warning: ; ; If you are doing a very normal generation, ; proceed to the next step, but if the BIOS you ; are generating has the same internal version ; number as the previous system, you MUST heed ; this warning. ; ; If the new bios was changed in ANY way, but ; still has the same internal (not external) ; version number, you will have to proceed ; cautiously. The system tracks are tied to this ; version number and contain absolute addresses. ; In the following step (which will execute ; EXCWTSYS) you will have to execute EXe console. ; This is the only place that this information ; is made available and will be of help to people ; debugging various parts of the system. The ; information displayed are the final actual ; addresses of the various portions of the BDOS ; and the BIOS. ; ; ; Special Note: ; ; The CPMLDR distributed by DRI has a problem ; which is fixed by a patch. This patch can ; be applied by now entering: ; ; SUBMIT EXCPATCH ; ; ; ; ; Informational note: ; ; After this step, you can produce a listing ; of all pieces of the bios. ; ; Enter: ; SUBMIT EXCPRT ; ; where: ; is the letter of the drive containing ; the object files (and the .SYM files). ; is the letter of the drive containing ; the .PRN files already created. ; is the letter of the drive to which ; the single combined .PRN file is to ; be written. ; ; Typically, this would be followed by: ; ; SPOOL :EXCBIOS.PRN CWTSYS ; as follows: ; ; Enter: ; SID EXCWTSYS.COM ; S40 change location 40 ; 00 to 00 ; 00 and 41 to 00 ; . done changing ; G100 execute EXCWTSYS now ; ; ; ; 6. Create a diskette with new boot tracks. ; ; a. You must have a running 3.0 system. ; (Proceed only if the system has been ; booted and is now running) ; b. Insert diskette (the diskette ; created from step 3 above) into ; drive A of the running system. ; c. Insert a freshly formatted double ; density diskette into drive B. This ; will be diskette . ; d. Enter: ; EXCWTSYS ; e. That program will attempt to write out ; the new boot tracks to the diskette in ; drive B. If the system tracks were ; written with no errors, an AOK message ; will be displayed. ; f. Re-insert the running system's CP/M ; utilities diskette into drive A. ; g. Enter: ; PIP ; h. Re-insert diskette into drive A. ; i. Enter: ; B:=A:CPM3.SYS[; ; ; ; ; 3. Copy all files to a 5.25" diskette. ; ; Enter: ; SUBMIT EXCPIP ; ; Where: ; is the letter of the drive to which ; the required bios files will be pip'ed. ; ; Example: ; SUBMIT EXCPIP G ; ; Special Notes: ; ; Again, be sure that the current drive is the ; same as the current drive in step 2 above. ; ; ; 4. Warning: ; ; Additional files are used by EXCWTSYS to create ; the boot tracks. These files are NOT part of ; the BIOS and are considered optional to ; EXCWTSYS. It is STRONGLY suggested that the ; following files be copied onto the same 5.25" ; diskette as created in step 3 above. ; ; FONTM.COM main font image ; FONTA.COM alternate font image ; ROMRAM.COM rom's ram overrides ; including keyboard decode ; tables. ; ; If EXCWTSYS does not find these files, it will ; just not write that information to the system ; track. The results are UNPREDICTABLE. For ; example, OV ; j. Just press return to end PIP. ; k. The diskette in drive B is now a new ; bootable CP/M 3.0 system disk, but ; with no utilities. This is diskette . ; This diskette is NOT finished yet. ; ; 7. Update the system tracks to the proper version. ; ; Follow this carefully. ; a. Insert the new bootable diskette () ; created in step 6 above into drive A. ; b. Boot the new system. ; c. Move the diskette from drive A to drive ; B. Diskette is now in B. ; d. Insert the diskette created from step 3 ; above into drive A. Diskette is in A. ; e. The diskettes are now situated as they ; were the last time you ran EXCWTSYS, ; but now you are already running on the ; new system. ; f. Enter: ; EXCWTSYS ; g. The diskette in drive B has now been ; updated with the proper override tables ; for the new and running system. This is ; diskette and is now generated and ; ready for having utilities added to it. ; ; ; ; The Vx.y is the external version number for this BIOS ; and bears no relationship to the internal version ; number which is the critical number for proper ; execution of this BIOS. ; ; ; B. Boot time error messages ; During either EXCBOOT or CBOOT if a disk error is detected ; the following message is displayed: ; ; BIOS boot error reading disk. System reset required. ; ; After issuing this message, the system hangs (an infinite ; loop) forcing the user to press reset to try again. ; ; ; C. Error messages ; ; As a general note: ; ; Before the operator is asked "(Y or N)?" the input ; device is purged of waiting characters. Then only a ; Y or N is acceptable. In fact, upper or lower or ; even control is acceptable. When a valid response is ; entered, a "Yes" or "No" is displayed accordingly. ; ; The BIOS begins its error message with a "bell" to ; alert the operator. ; ; Disk error messages are only issued when the SCB ; error mode flag indicates that t ; 8. That's all....... ; Except.....to copy whatever files are needed. ; The resulting diskette is only bootable and ; does not contain any utilities. ; ; ; ; page ; ; General assumptions and requirements. ; ; ; A. Anyone attempting to modify this BIOS in ANY way ; must be VERY well versed in Z80 assembly language ; coding in a multiple bank system. ; ; B. All of the DRI CP/M Plus (CP/M 3.0) manuals have been ; used to various degrees in writing this BIOS. This ; includes: the User's Guide, the Programmer's Guide, ; the Programmer's Utilities Guide and the single most ; important manual the System Guide. ; ; C. This BIOS was written in M80 instead of RMAC for many ; reasons, including that this BIOS will only run on a ; Z80 and it was begun before DRI's sample BIOS. ; ; D. This is the only module that enables printing of the ; EXCBIOSE.LIB file which is included in every assembly. ; When anything changes in the equate file (such as ROM's ; RAM addhe BIOS may issue ; a message (the user may still be doing its own ; error recovery). ; ; ; 1. When a physical device (not disk) is sent a ; character and it times out, the following ; message is sent to the CRT: ; ; BIOS error device xxxxxx not ready, unassign this ; device (Y or N)? ; ; The "xxxxxx" is replaced by the name of this ; device (eg. IEEE). The operator's response ; either keeps retrying to send the character ; or unassigns this physical device from the ; logical device being used. In other words, ; if IEEE were assigned to LST: and it ; timed out and the operator replied "Y" then ; IEEE would no longer be assigned to LST:. As ; it happens, if nothing is assigned to a logical ; device characters output to that device are ; just ignored (sent to the proverbial bit bucket) ; ; If the CONOUT: device would get assigned to ; nothing, then it is forced to be assigned to ; the CRT. ; ; If you don't want this message to appear, resses) EVERY program MUST be re-assembled. ; ; E. Extreme care must be taken when either the ROM entry ; points or the disk i/o table in high memory change. ; These areas are used extensively by EXCWTSYS and it ; must execute on an existing system to generate a new ; system. ; ; F. The following programs are used or potentially used ; in generating and writing this BIOS: ; ; M80 The Microsoft assembler ; LINK The DRI linker (w/CP/M 3.0) ; RMAC The DRI assembler (w/CP/M 3.0) ; SUBMIT From the running CP/M system ; PIP From the running CP/M system ; GENCPM From CP/M 3.0 ; XSUB From the running CP/M system ; SID From any system (or DDT or ZSID) ; page ; ; Messages issued by the BIOS. ; ; A. The initial sign-on. ; ; After CPMLDR has loaded the system, the bios' cboot ; routine issues a message of the form: ; ; Osborne Executive CP/M Plus Vx.y ; Copyright (c) 1983 Osborne Computer Corporation ; 26538 Danti Court ; Hayward, CA 94545 ; ; code your programs by asking for status first ; and then when status shows ready to send a ; character issue the BIOS call to send it. ; ; 2. When attempting to select a disk for the first ; time and an error occurs (or the format can't ; be determined) the following message is sent ; to CONOUT: ; ; BIOS error selecting drive x: not ready or not ; formatted. Retry this operation (Y or N)? ; ; The "x" is the letter of the drive having the ; problem. This time the operator's response ; comes from CONIN. ; ; 3. When the ROM reports a disk error the following ; happens before an error message is issued: ; ; a. The media format is determined ; and if unable to do so, the media ; changed return code is passed to the ; calling program with no error message. ; ; b. If the media format is different than ; what it used to be, this is also passed ; back as a media change with no error ; message. ; ; c. If everything looks like it cks are documented ; in the source for EXCBOOT.MAC. ; ; All bios entry points can be entered with any bank enabled. ; When bank 0 is needed, it is enabled. Also, the stack is ; normally handled so that the caller can have the stack ; anywhere in memory. Because of this, many routines will ; do some weird things keeping track of which stack area to use. ; ; For the most part, things that change are grouped together. ; For example, the rom entry addresses are located in the ; equates file. Therefore, if you have a question about ; the disk routines, look in module 4 serial in module 2, ; etc. Because not all of the system track data is processed ; by the bootstrap, other information must be found in ; module 5 which handles the cboot. ; ; Both disk error recovery and serial output recovery have ; been added. Because I am trying to keep the bios source ; the same (as much as possible) between std bios and the ; ldrbios, the actual err routines (stderr, stdsen and seris the same ; then the error message is issued. ; ; The error message takes the form: ; ; BIOS error yyyyyy drive x: zzzzz, ; (code=aa/bb-cccccccccccccccc) ; ; Where: ; ; y...y is either "reading" or "writing" as appropriate ; x is the drive letter ; z...z reflects the controller's status in ; "English" and is one or more of the following: ; not-ready, write-protected, fault, not-found, ; crc-error, lost-data, drq or busy ; aa Is the controller's status in hex. ; bb is the number of sectors (in hex) being read ; or written. ; c...c is the following (in hex): ; bank (1 byte), dma address (2 bytes), starting ; sector (1 byte), track (2 bytes), internal unit ; number (1 byte) and media type (1 byte). ; ; ; This message is then followed by: ; ; Retry this operation (Y or N)? ; ; The response is taken from CONIN. If the operation is ; not being retried, then an appropriate error code is ; returned. If, however, the operation is to be retrnr) ; are called from the appropriate place, but reside in ; excbios5. This is because '5' is definitely different for ; the ldrbios. Therefore, be sure to look there for info about ; the error messages. ; ; These disk error messages are not displayed if the bdos ; error mode flag indicates that the user program wants ; all errors with NO messages. This is the way it is, but ; that may change. It seems that PIP runs this way and then ; only knows 'read or write error' and 'write protected'. PIP ; then in its infinite wisdom issues a somewhat cryptic message. ; ; Serial output that waits longer than some predetermined ; loop count will cause a message to appear on the crt. ; The operator is asked if this device should be unassigned. ; Again, with the Y or N response. If not, this operation is ; retried. When unassigning the device, if the i/o redirection ; vector for that logical device would become 0000, then it is ; forced to be 8000h (the crt). Note that the mesied ; yet again, the media change flag is checked. If this ; media may have changed, the operator is asked: ; ; WARNING: data on disk inserted may be ; destroyed. Continue (Y or N)? ; ; If the response is to NOT continue, then it is as if ; no retry had been requested. If, however, the operator ; says YES, then the media flag is cleared and the ; read or write is retried. This is there on purpose ; so that if you just forgot to take the write protect ; tag off you can correct it and recover yet the message ; is nasty enough that you will think twice before ; potentially destroying a disk. ; page ; ; Some general thoughts ... ; ; ; The bootstrap loader gains control in bank 0 at location ; 4000h (it must be linked as such) which then reads in ; pieces from the system track. CPMLDR is passed control ; and then reads in the cpm3.sys (this is a standard DRI ; program). Finally, the standard bios cboot gains control ; and the system is up. The system trasages for serial ; output not ready appear only on the crt/keyboard. This is because ; conout may be assigned to the serial device in question. The only ; way to avoid the time-out message is by using the output ; status routines yourself. Since that is most often the case, ; this should not be any problem to any user reasonable software. ; ; An objective has been to allow the bios to be changed as ; easily as possible, in some areas during cboot itself. ; ; You might be wondering why this bios doesn't look like the ; kernel documented by DRI. Well...........work was started ; on this bios before DRI documented that method. ; ; ; ; Good luck. ; ; Glenn S. Tenney ; ; ; -30- 00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5F7 :101E9B00E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E5E7 :101EAB00E5E5E5E5E5E5E5F74E4E4E4E4E4E4E4E7D :101EBB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E37 :101ECB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4E4E27 :101EDB004E4E4E4E4E4E4E4E4E4E4E4E4E4E4 optional ld a,-1 ld (optional),a ; indicate now optional ld de,fontm ; main font file ld hl,fmsec call dofile ld (wtfm),a ; 00=not there xx=is there ld de,fonta ; alt font file ld hl,fasec call dofile ld (wtfa),a ; 00=not there xx=is there ld de,romram ; final file is rom's ram override ld hl,romsec call dofile ld (wtrom),a ; 00=not there xx=is there ; all files have been read in ; from the running system, build up the special bios ; override sector. This is needed so that setup will ; function. Of course setup could do this itself ; when taking the current values from memory (the ; running system), but......... ld hl,(40h) ; bios version number ld (ivers+oursec),hl ; into our sector ld a,getdrv ; ask bios to get drvtbl addr call bios ld de,idrvtbl+oursec ; where to put it ld bc,idrvlen ldir ld a,getdev ; ask bios to get devtbl addr call bios push hl ; save to get prefix later ld de,idevtbl+oursec ; where to put i.z80 title wtsys (excwtsys) writes cpmldr.com to system tracks ;1983-06-23 Set for second release ; added initialization of track 1 sector 5 for device time-out ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; this is really a very crude program designed for ; the infrequent need to create a diskette with ; new system tracks (0, 1 and sometimes 2) composed of: ; excboot, cpmldr, ccp, the special bios overlays, ; the fonts and the rom's ram overrides. ; Written by: Glenn S. Tenney ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list open equ 15 read equ 20 setdma equ 26 pmsg equ 9 bdos equ 5 getdt ld bc,idevlen ; primary only ldir ld bc,0100h ; set banks src=00 dest=01 ld a,xmove call bios ; set next move across banks pop hl ; restore devtbl addr dec hl ; back up to use prefix ld d,(hl) ; get addr of initvector dec hl ld e,(hl) ; shadow ptr is at devtbl-2 ; de is source for 'move' ld hl,idevshd+oursec ; copy it to our sector ld bc,ishdlen+idvilen+idvslen+idellen ; shadow+initvec+strings+time-out ld a,move call bios ; ask bios to move x banks ; entire area now all set up, just write it out ; set up the ram for doing the i/o ; track 0 ld hl,track0 ; pt to data area ld de,0 ; and track number call write5 ; write it all (5 sectors) ; track 1 ld hl,track1 ld de,1 call write5 ; track 2 ld a,(wtfm) ; see if writing main font ld hl,fmsec ; starting data area ld de,0002h ; sector 1 (1-1=0) track 2 or a ; shd we write? ld a,2 ; if we do, write 2 sectors call nz,write ; write only if something to wriev equ 3ch ; bios fcn: hl=devtbl getdrv equ 42h ; bios fcn: hl=drvtbl move equ 4bh ; bios fcn: move xmove equ 57h ; bios fcn: set banks for move start: ld sp,stack ; pt to a stack ld bc,codelen ; len of our code ld de,himem ; destination ld hl,ourcode ; from here ldir ; move a hunk to non-rom area ld bc,secend-sec1 ; init entire area 1st ld de,sec1 ; i/o area ld hl,initial ; what to init it with ldir ; all cleared out ld de,startmsg ; tell what we're going to do call msg ; the following are NOT optional files xor a ld (optional),a ; indicate not optional ld de,excboot ; 1st fcb to open ld hl,bootsec ; and where to read it call dofile ; open and read it in ld de,cpmldr ; 2nd file ld hl,ldrsec call dofile ; note: cpmldr.com is limited in size ld de,ldrmsg ; in case msg needed cp 4096/128+1 ; see if cpmldr too long jp nc,abort ; yes, abort ld de,ccp ; 3rd file to read in ld hl,ccpsec call dofile ; the following files arete ld a,(wtfa) ; see if writing alt font ld hl,fasec ; starting data area ld de,0202h ; sector 3 (3-1=2) track 2 or a ; shd we write? ld a,2 ; if we do, write 2 sectors call nz,write ; write only if something to write ld a,(wtrom) ; see if writing rom's ram ld hl,romsec ; starting data area ld de,0402h ; sector 5 (5-1=4) track 2 or a ; shd we write? ld a,1 ; if we do, write only 1 sector call nz,write ; write only if something to write ld de,donemsg ; that is it! call msg ; all done exit: jp 0 ; warm boot ; call the bios with rtn addr (lo) in a bios: ld (biosl),a ; set lo of bios addr ld a,(2) ; get hi of addr ld (biosh),a ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; modified code follows ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; biosjp: jp 0 ; really jp to bios entry biosl equ biosjp+1 ; lo of bios fcn addr biosh equ biosl+1 ; and hi of addr msg: ld c,pmsg ; let bdos issue a msg jp bdos wterr: ld de,wtmsg ; write error (no fname) abort: call msg jp exit ; and all done badopen: ld de,openmsg ; issue msg jr fabort badread: ld de,readmsg ; issue msg ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall through ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; common open/read error handler ; if "optional" then return a=0 and done, else error msg. fabort: ; error opening then reading a file call msg ; isse msg ld de,fname ; then say file name call msg ld a,(optional) ; is this file optional or a jp z,exit ; no, abort now xor a ; yes, pass back a=0 ret ; and done with file page ; torom ; a=rom routine address ; aka ourcode (before it is moved) ourcode: ; code which is moved above 4000h ld (thecall+1),a ; alter the call in a,(sys) or 80h ; turn on rom out (sys),a xcall: call 100h ; call the rom push af ; save in a,(sys) and 07fh ; turn rom off out (sys),a pop af ret ; and all done codelen equ $-ourcode ; length to ; pt'ed to by de page ; write ; write all or part of a sector to disk ; a # sectors to write ; e track # ; d sector number-1 (0=1) ; hl ptr to dma address ; write5 ; same, but sets a to 5 (full track) write5: ld a,5 ; set to full track write: or a ; see if anything to write ret z ; no, all done ld b,a ; save # sectors to write ld (wtaddr),hl ; set dma addr ld a,d ; get sector number inc a ; adj properly ld (wtsec),a ld a,e ; get track number ld (wttrk),a ld a,b ; restore # sectors to write ld bc,iolen ; length of i/o init area ld de,dmabank ; in hi common ram ld hl,wtparms ; to do some track ldir ; this is it ld b,a ; get # sectors to write ld a,wsec ; and the offset to write it call torom or a ; any errors writing? ret z ; no, all done writing jp wterr ; yes, then abort page ; dofile ; open then read in a file ; if "optional"<>0 then file is optional ; a returned=#sectors actually read in ; de ptr to fcb to us move up himem equ 5000h ; move the code here torom equ himem ; routine to call to rom thecall equ torom+(xcall-ourcode) ; the call instruction stack equ himem+400h ; someplace also in non-rom page ; misc variables etc.... optional: db 0 ; non-zero if file is optional wtfm: db 0 ; ? write fontm (0=no) wtfa: db 0 ; ? write fonta (0=no) wtrom: db 0 ; ? write rom's ram (0=no) thefcb: dw excboot ; ptr to current fcb startmsg: db 0dh,0ah db 'EXCWTSYS will write 3.0 system tracks to drive B' db 0dh,0ah,'$' donemsg: db 0dh,0ah db 'System tracks aok',0dh,0ah,'$' fname: ds 8 ; common name for messages db '.' ftype: ds 3 db 0dh,0ah,07h,'$' readmsg: db 0dh,0ah,'Error reading $' openmsg: db 0dh,0ah,'Unable to open $' wtmsg: db 0dh,0ah,'Error writing system tracks',0dh,0ah,'$' ldrmsg: db 0dh,0ah,'Error: cpmldr.com is too long' db 7,0dh,0ah,'$' ; this is set of parms passed to the rom ; to write 1-5 sectors wtparms: db 1 ; bank wtadde ; hl dma address starting dofile: ; open then read this file push hl ; save dma addr ld (thefcb),de ; and ptr to fcb ld hl,1 ; copy fname and ftype add hl,de ; from=fcb+1 ld de,fname ; copy in this file name ld bc,8 ldir inc de ; bump over the '.' ld bc,3 ; for file type ldir ld de,(thefcb) ; pt to file ld c,open ; open the file call bdos inc a ; ff=not found pop de ; restore starting dma addr jr z,badopen ; open error ld b,-1 ; init # sectors read count rdloop: inc b ; bump # setors read push de push bc ; save sector counter ld c,setdma ; set dma addr call bdos ld de,(thefcb) ; crnt fcb ld c,read call bdos ; read one 128 byte sector pop bc ; restore sector count pop de ld hl,128 ; advance dma addr too add hl,de ex de,hl or a ; see if done or error jr z,rdloop ; not done yet dec a ; 1=done jr nz,badread ; no, error or b ; pass back # sectors read in ret ; all done reading, no errors r: dw 0 ; addr wtsec: db 1 ; sector wttrk: dw 0 ; track db 1 ; unit 'B' db 0ch ; type iolen equ $-wtparms ; length to move up there excboot: db 0,'EXCBOOT COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 cpmldr: db 0,'CPMLDR COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ccp: db 0,'CCP COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 fontm: db 0,'FONTM COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 fonta: db 0,'FONTA COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 romram: db 0,'ROMRAM COM' dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 initial: ; do not change this ; db 'Glenn S. Tenney ' db 'ReservedReserved' ; oh well, fill the unused ; areas on the system ; tracks with something sec1 equ $ ; start of i/o areas ( 3 tracks long) sec2 equ sec1+1024 sec3 equ sec2+1024 sec4 equ sec3+1024 sec5 equ sec4+1024 track0 equ sec1 sec6 equ sec5+1024 ; sector 1 track 1 sec7 equ seata on disk ; has a chance of being useable. The sector begins with the ; bios' version number and must be an EXACT match. ld hl,(vers) ; get our version number ex de,hl ld hl,(ivers+table) ; and version from disk xor a ; clear carry sbc hl,de ; ours - disk = 0 iff same jr nz,notbls ; not same, forget changing tables ; drvtbl table of dph pointers ld de,drvtbl ; pt to where to put drv tables ld hl,idrvtbl+table ; copy it in ld bc,idrvlen ; all entries ldir ; devtbl table of serial devices ld de,devtbl ; same as for drvtbl ld hl,idevtbl+table ld bc,idevlen ; primary only ldir ; shadow table, initvec and init strings ld de,(devtbl-2) ; get prefix (ptr to shadow) ld hl,idevshd+table ; move it from here ld bc,ishdlen+idvilen+idvslen ldir ; move all 3 tables in ; Device delay variables LD HL,(IDELAY+TABLE) LD (DELAY),HL ; the disk has now been processed, proceed notbls: ; all overlayed from disk ld hl,initvec ; init the re-directioc6+1024 sec8 equ sec7+1024 sec9 equ sec8+1024 sec10 equ sec9+1024 track1 equ sec6 sec11 equ sec10+1024 ; sector 1 track 2 sec12 equ sec11+1024 sec13 equ sec12+1024 sec14 equ sec13+1024 sec15 equ sec14+1024 track2 equ sec11 secend equ sec15+1024 bootsec equ sec1 ; excboot sec 1 trk 0 ldrsec equ sec2 ; cpmldr sec 2 trk 0 ccpsec equ sec6 ; ccp sec 1 tk 1 oursec equ sec10 ; where special stuff goes fmsec equ sec11 ; where main font begins fasec equ sec13 ; where alt font begins romsec equ sec15 ; rom's ram override end n vectors ld de,@civec ; into the scb ld bc,10 ; length (always 5 words = 5*2 ) ldir ; moved into scb ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; init the serial devices ; we call the devini routine to allow whatever needs ; to be done to get done. The way it is (was?) coded ; is that the devini sets up the via tables so that ; the init is actually done the 1st activity. ld bc,16*256 ; # of times to loop + dev = 0 initdlp: ; loop here to init each device push bc ; save crnt value call devini ; init device # in c pop bc inc c ; advance device # djnz initdlp ; do all devices (0-15) ; init the disk controllers ; each dph prefix has a pointer to an init routine ; this routine is called now to allow any one time ; initialization. ld hl,drvtbl ; pt to table of dph's ld b,16 ; do 16 disks inidsk: ld e,(hl) ; pick up ptr to dph inc hl ld d,(hl) inc hl ; hl ready for next in tbl push bc ; save count push hl ; save drvtbl pointer ld a,d ; first, check to see if any dph or e ; 0=no dph call nz,inidsk2 ; there is a dph, init it pop hl ; restore drvtbl pointer pop bc ; restore count djnz inidsk ; and init all disk drives jp ready ; all init work taken care of inidsk2: ; de=this drive's dph, jp to init ld hl,-9 ; offset for init addr add hl,de ; hl=addr of addr of init rtn ld a,(hl) ; pick up init routine addr inc hl ld h,(hl) ld l,a ; hl=init routine address jphl: jp (hl) ; off to init routine ; all done with init's, tell the world ready: ; all ready to rip now! ld de,signon ; pt to the message ld hl,conout ; use this routine ld a,80h ; force back to bank 0 out (sys),a call outmsg ; issue signon msg ; copy 1st time fcb to 5ch to try to open ; execst.com ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,fcb ; destination in bank 1 ld de,thefcb ; source in bank 0 ld bc,fcblen ; length of an fcb call move ; mo 840924 ; ld a,1 ; No. Set flag so next time CCP will 840924 ld (ccploaded),a ; load from bank 0 840924 ; First load alternate font RAM data from ALTFONT.SYS, if it 840926 ; exists. xor a ; Clear extent byte so open will start 840926 ld (altfcb+15),a ; file at beginning 840926 ld hl,0 ; Clear record field for same reason 840926 ld (altnr),hl ; 840926 ld de,altfcb ; Point at FCB 840926 call bopen ; Call BDOS open 840926 inc a ; Check for not found (A = 0ffh) 840926 jp z,noalt ; Not there, skip reading. Alternate 840926 ; font initialized by EXCBOOT 840926 ; ld de,4000h ; ALTFONT.SYS found, set DMA address to 840924 call bsetdma ; TPA above ROM 840924 ld de,128 ; Set multi record count to 128 to 840924 call bsetmulti ; read the whole thing at one shot 840924 ld de,altfcb ; Point at FCB again and 840924 call bread ; call BDOS read to suck it in 840924 ; ALTFONT.SYS now loaded in TPA above ROM. Now move 2K into 840926 ; character generave it in jp wboot ; blend to warm boot page ; subroutines and constants used during cboot only ; booterr ; come here when we got a disk error of any kind ; reading our special sectors from the system ; tracks (including ccp.com). An error msg is ; issued and the system hangs. booterr: ; issue a msg saying disk error during boot ld hl,100h+cout ; pt to crt output rtn ld de,bootmsg ; and special error msg call outmsg ; issue this message hang: jr hang ; loop forever bootmsg: ; the message on disk error w/in boot d 0dh,0ah,0 beeeeeep db 'BIOS boot error reading disk. ' db 'System reset required.' db 0dh,0ah,0 ; 00 ends the msg ; thefcb ; this is the fcb to load a special file ; it is defined here and copied into bank 1 ; location 5c just before 1st wboot fcb equ 5ch ; where we will put it later thefcb: db 0,'EXECST ','COM',0,0,0,0 ds 16 fcbnr equ $-thefcb+fcb ; where the nr field will be db 0,0,0 fcblen equ $-thefcb ; length otor RAM (i.e., write to ROM address space). 840926 ld hl,4000h ; Point at source in bank 1 840926 ld de,800h ; Point at destination in bank 0 840926 ld bc,2 * 1024 ; Set count of bytes to move 840926 in a,(sys) ; Save current bank state 840926 or 80h ; Shadow in ROM 840926 out (sys),a ; 840926 ldir ; Move it 840926 and 7fh ; Take ROM out 840926 out (sys),a ; 840926 noalt: ; 840926 ; Now load CCP from file. 840924 xor a ; Clear extent byte so open will start 840924 ld (ccp$fcb+15),a ; file at beginning 840924 ld hl,0 ; Clear record field for same reason 840924 ld (cfcb$nr),hl ; 840922 ld de,ccp$fcb ; Point at FCB 840922 call bopen ; Call BDOS open 840922 inc a ; Check for not found (A = 0ffh) 840922 jp z,no$CCP ; Oops, not there 840922 ; ld de,100h ; CCP.COM found, set DMA address to 840924 call bsetdma ; TPA base 840924 ld de,128 ; Set multi record count to 128 to 840924 call bsetmulti ; read tf an fcb page cseg ; common wboot: ld sp,(@bnkbf) ; set up a stack ; setup jumps in page 0 bank 1 ld a,1 ; force into bank 1 call selmem ; for execution and i/o ; copy special page 0 common area (at 40h) ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,40h ; destination in bank 1 ld de,vers ; source in bank 0 ld bc,16 ; maximum length of common area call move ; move it in ; set up jumps in page zero too ld a,0c3h ; a JMP opcode ld (0),a ; at loc 0000h ld (5),a ; and 0005h ld hl,wboot@ ; pt to that entry of jmp tbl ld (1),hl ; at loc 0001h ld hl,(@mxtpa) ; bdos entry pt from scb ld (6),hl ; at loc 0006h ; Load ccp from file if dsdd and 1st time through 840924 ld a,(dsdd) ; Check dsdd flag 840924 or a ; 840924 jp z,notdsdd ; Not dsdd, load from bank 0 840924 ; ld a,(ccploaded) ; DSDD. Check to see if CCP loaded 840924 or a ; already. 840924 jp nz,not1st ; Yes; load from bank 0 he whole thing at one shot 840924 ld de,ccp$fcb ; Point at FCB again and 840924 call bread ; call BDOS read to suck it in 840924 ; CCP now loaded in TPA; Next we must move a copy of him into 840924 ; the reserved area of bank 0. 840924 ld hl,100h ; Point at source in bank 1 (TPA base) 840924 ld de,0 ; Point at destination in bank 0 840924 ld bc,ccplen ; Set count of bytes to move 840924 in a,(sys) ; Save current bank state 840924 push af ; on stk 840924 mvccp2: ld a,1 ; Put bank 1 in context 840924 out (sys),a ; 840924 ld a,(hl) ; Load a byte from TPA 840924 push af ; Save byte while we switch to bank 0 840924 xor a ; Put bank 0 in context 840924 out (sys),a ; 840924 pop af ; Restore byte 840924 ld (de),a ; Save it in bank 0 840924 inc hl ; Point at next byte in TPA 840924 inc de ; and next destination in bank 0 840924 dec bc ; Decrement counter 840924 ld a,b ; Are we done yet (b = c = 0) ? 840924 or c ; 8nk 0 840926 ; xor a ; First time. Clear flag. 840926 ld (first),a ; 840926 call tryfile ; Try loading EXECST. If not there, 840926 ; returns and falls through to load 840926 ; CCP 840926 ldccp: ; 840926 ; now, move the ccp into bank 1 from bank 0 ; and execute it ld bc,0100h ; source 0, destination bank 1 call xmove ; set to just move in ld hl,100h ; destination in bank 1 ld de,0 ; source in bank 0 ld bc,ccplen ; for length of ccp.com call move ; move ccp in jp tpa ; and off to it ; tryfile ; one time only (at 1st wboot after cboot) ; if the special file exists, use it. tryfile: xor a ; clear ld (fcb+12),a ; current extent ld (fcb+15),a ; record count ld hl,0 ld (fcbnr),hl ld de,fcb ; pt to the fcb ld c,open ; open the file call bdos or a ; was there an error? ret nz ; yes --- no special file ; read the file into the tpa one logical sector at a time ; this way it can be as long or short as need be40924 jp nz,mvccp2 ; No, keep on a goin' 840924 ; pop af ; Yup, all done. Retrieve old bank 840924 out (sys),a ; from stack and restore it 840924 jp chexecst ; Check for execst 840924 no$CCP: ; CCP.COM not on disk. Print err and 840924 ; hang. 840924 xor a ; Select bank 0 so outmsg will work 840924 out (sys),a ; 840924 ld de,ccpmsg ; Point at message 840924 ld hl,conout ; Specify BIOS conout routine 840924 call outmsg ; Print it to console 840924 ccphang: ; And hang 840924 jp ccphang ; 840924 ccpmsg: ; Message to display if CCP not home 840924 db 0dh,0ah,07 ; toot toot 840924 db 'BIOS error: CCP.COM not present. ' ; 840924 db 'System reset required.' ; 840924 db 0dh,0ah,0 ; terminate with 0. Would that this 840924 ; were C. 840924 ; BDOS call interfaces 840924 bopen: ld c,15 ; BDOS open (fn 15) 840924 jp bdos ; 840924 bsetdma:ld c,26 ; Set DMA (26) 840924 jp bdos ; 840924  l de,tp ini wher t rea it filelp: push de ; save across bdos call ld c,setdma ; read into there call bdos ld de,fcb ; pt to fcb ld c,read call bdos ; read one more logical sector pop de ; restore dma address ld hl,128 add hl,de ; bump dma address ex de,hl ; de=next dma address or a ; any errors?? jr z,filelp ; no, keep reading dec a ; see if eof or error ret nz ; error, forget using the file ; we now have read in the file with no errors ld hl,0 ; dummy up ld (80h),hl ; to look like no cmnd line jp tpa ; execute it (ret will do ccp) page dseg ; the following are the std disk i/o err routines ; they are in this source module so that for the ; ldrbios they need not do anything ; These routines issue some message of the general form: ; BIOS error xxxxxing drive x: ; Accept this condition (y=yes)? ; The xxx above is either 'select', 'read' or 'writ' ; and the x is the alpha of the drive number. The ; dep bsetmulti: ; Set multi record I/O (44) 840924 ld c,44 ; 840924 jp bdos ; 840924 bread: ld c,20 ; Read (20) 840924 jp bdos ; 840924 ccploaded: ; Flag. Not zero if CCP loaded from 840924 db 0 ; dsdd disk and in bank 0 840924 dsdd: ; Flag. Not zero if boot disk is dsdd 840924 db 0 ; 840924 ccp$fcb: ; FCB for accessing CCP.COM 840924 db 1,'CCP ','COM',0,0,0,0 ; 840924 ds 16 ; 840924 cfcb$nr: ; 840924 db 0,0,0 ; 840924 altfcb: ; FCB for accessing ALTFONT.SYS 840926 db 1,'ALTFONT ','SYS',0,0,0,0 ; 840926 ds 16 ; 840926 altnr: ; 840926 db 0,0,0 ; 840926 first: db 0ffh ; Flag. Not zero if first time through 840926 ; wboot 840926 page notdsdd: ; 840924 not1st: ; 840924 chexecst: ; 840926 ; First check for 1st time through. If 1st, try to load EXECST 840926 ld a,(first) ; Check flag 840926 or a ; 840926 jr z,ldccp ; Not 1st, load ccp from baends on the type of error. ; For a select error, all we can say is either the drive ; is not ready or the disk is not properly formatted. ; For an i/o error the is the breakdown of the ; fdc status bits (in english) followed by: xx/yy-zz..zz ; Where: ; xx the fdc code in hex ; yy the number of sectors this i/o ; zz.zz the 8 bytes beginning at dmabank ; bank(1),address(2),sector(1), ; track(2),unit(1),type(1) ; stdsen ; err on std seldisk, say not ready ; return 'z' if no retry, else 'nz' to retry stdsen: ld a,(@ermde) ; 0ffh=no err msgs pls inc a ; is bdos passing errs back ret z ; yes (z=no retry) call beep ; honk horn and start a line ld de,selfcn ; select function call saydrive ; tell what drive w/msg ld de,selmsg ; text of select msg call conmsg ; issue text to console jp askrc ; ask if we should retry ; z=no retry nz=retry ; stderr ; std disk i/o read or write err ; return 'z' = no retry 'nz' = retry ; a error  pop bc inc hl djnz codelp ; display all bytes ld de,codeend ; issue trailer of code msg call conmsg call askrc ; see whether to retry (nz=retry) jr z,stddn ; all done, no retry desired ; retry was wanted, see if media did change ld hl,(adrive) ; assume it was unit 0 ld a,(actdsk) ; get our internal # or a ; was it a (unit 0) jr z,was0 ; yes, hl proper ptr ld hl,(bdrive) ; no, pt to proper flag byte was0: ld a,(hl) ; see if that drive did change or a jr z,retryok ; it did not change, retry allowed push hl ; save ptr to media chg flag byte ld de,mediamsg ; it did change, verify fm opr call conmsg call askyn ; then ask for yes or no reply ; nz=yes (continue?) pop hl ; restore ptr to media chg byte jr z,stddn ; no means no retry attempt xor a ; force a=0 ld (hl),a ; and clear media chg byte ; fall thru to allow retry retryok: ; retry allowed, force nz inc a ; nz=retry z=no retry ; here to return to caller. z=no retrcode to bdos (1 or 2) ; b fdc status from rom ; e rom rtn offset (rsec or wsec) ; must return a and e as on input stderr: ld c,a ; save error code for bdos ld a,(@ermde) ; passing errors back to user inc a ld a,c ; (error code passed back) ret z ; yes, no msgs (z=no retry) push bc ; save error codes push de ; save fcn code call beep ; honk horn and start a line pop de ; get rd or wt rtn address push de ; must return de valid ld a,rsec ; see if read or write cp e ; equal if read ld de,rdfcn ; assume it is jr z,isrd ; yup ld de,wtfcn ; nope (must be a write) isrd: call saydrive ; say function and drive pop de ; rom rtn addr pop bc ; b=fdc err code c=bdos err code push de ; save rom rtn for exit push bc ; and bdos err flag too ; tell what fdc errors we got + a hex sequence ld a,b ; fdc status ld hl,stattbl-1 ; pt to start of msg tbl statlp: inc hl ; next tbl entry sla a ; check next bit left to right jr nc,statno ; that oy nz=retry stddn: ; bc, de were saved earlier pop bc ld a,c ; restore bdos err flag pop de ; restore rom rtn addr too ret ; z/nz set by askrc page ; sernr ; device not ready ; issue the std bios error message, but ; only to crt. This is important, because ; conout may be the serial device. ; device #, must be retained ; ; ENTRY B = Device # ; ; EXIT Z-flag = Set Unassign this device ; Z-flag = Clear Leave device assigned ; SERNR: PUSH HL ;Save caller's regs PUSH DE PUSH BC ;Save device # SERCLR: ;Clear kbd 1st CALL 100h+SKEY ;Is there a key JR Z,SEROK ;No, ready to issue msg CALL 100h+CI ;Yes, get the key JR SERCLR ;Then throw it away SEROK: LD C,07H ;Beep to notify user of error condition CALL COUT+100H ;Use ROM routine POP BC ;Device # PUSH BC LD A,B ;Get device # in A-reg ADD A,A ;A * 8 to get appropriate entry ADD A,A ADD A,A LD B,0 LD C,A LD HL,DEVTBL ;Start of device table ADD HL,ne not on push af ; save fdc status (z=done) ld d,0 ld e,(hl) ; get this tbl entry push hl ; save crnt tbl addr ld hl,statmsg ; pt to start of msgs proper add hl,de ; pt to this message itself ex de,hl ; whew, de->msg for this bit call conmsg ; tell opr this one ld de,comma ; separate status messages call conmsg pop hl ; tbl ptr pop af ; crnt fdc status statno: jr nz,statlp ; if more status bits ld de,codemsg ; status decoded, show in hex call conmsg pop bc ; restore fdc code (in c) push bc ; and keep saving it back ; code=xx/yy ld a,b ; fdc code call hexout ; xx is fdc code ld c,'/' ; weird separator call conout ld a,(actcnt) ; yy is #sectors this i/o call hexout ; code=xx/yy-zz..zz ld c,'-' ; another separator call conout ld hl,dmabank ; start here to display zz..zz ld b,8 ; for 8 bytes codelp: ; loop showing all of code ld a,(hl) ; next byte to display push bc push hl call hexout ; displayed in hex pop hlBC ;HL = this device entry ;HL is address of device name LD DE,DEVMSG ;Point to message position for device name LD BC,6 ;Length of device name LDIR ;Move it CALL SAVEMSG ;Save last video line in temp locations LD HL,DNRMSG ;Address of device not ready message LD DE,DNRATR ;Address of attributes for message CALL RESTOR ;Move 'em to last video line ISITAGAIN: POP BC ;Retrieve device # PUSH BC ;and save it again CALL OUTST ;Check to see if the device has become ready JR NZ,DONE ;Ready, restore screen and leave device assigned ;Check for response CALL 100H+SKEY ;Is there a key JR Z,ISITAGAIN ;No, check again CALL 100H+CI ;Get key AND 1Fh ;Accept upper or lower case CP 'Y' and 1Fh ;Is the response "Yes"? JR Z,DONE ;Yes, unassign device and restore screen CP 'N' and 1Fh ;Is the response "No"? JR NZ,ISITAGAIN ;No, try again LD A,1 ;Clear Z-flag to indicate leave device assigned OR A DONE: PUSH AF ;Save Z-fXIT None ; PUSH IX CALL ROMMV POP IX RET PAGE ; askrc ; ask opr to accept this error (only y = yes) ; to conout, from conin askrc: call crlf ; start a new line 1st ld de,dskmsg ; pt to message call conmsg ; to console askyn: ld de,yorn ; append the y or n message call conmsg ynagain: ; loop here to read from conin push hl ; save output rtn addr call conin ; get next keystroke pop hl call isity ; see if answer is valid ret nc ; valid (Y or N) jr ynagain ; keep trying isity: ld de,ymsg ; assume only yes one and 1fh ; make upper/lower/ctl same cp 'Y' and 1fh ; is it Yes jr z,isyes ; yup ld de,nmsg ; may be no, pt to proper msg cp 'N' and 1fh ; not yes, was it No jr z,isno ; it was no scf ; show not a valid response ret ; and exit as is isyes: or a ; a=Y, set NZ to show yes isno: ; if no, a=N and Z is set push af ; save retry/continue flag call outmsg ; tell what we saw opr enter call newline lag (exit state) LD HL,TEMPVID ;Point to user's last screen line LD DE,TEMPATR ;Point to last line's attributes CALL RESTOR ;and move them back to screen LD A,(DELAY) ;Get user defined delay for next time LD (DELAY0),A ;Save it POP AF ;Restore exit parameter POP BC ;Restore all regs POP DE POP HL RET page TEMPVID: DS 80 ;Buffer to save last screen line TEMPATR: DS 80 ;Buffer to save attributes for last screen line SAVEMSG: ; This routine saves the last line of the screen into temporary ; storage and its corresponding attributes ; ; ENTRY None ; ; EXIT TEMPVID contains last screen line ; TEMPATR contains last screen line attributes ; IN A,(SYS) ;Get current bank LD H,A ;For destination LD L,40H ;Video bank for source LD (RSBANK),HL ;Set parameters LD HL,0CB80h ;Last line of video LD DE,TEMPVID ;Destination of move LD BC,80 ;Move complete line CALL MOVEMSG ;Move it LD HL,0DB80h ;Last attribute line LD DE,TEMPA; and complete the line pop af ; restore 'a' ret ; and all done page ; hexout ; displays 'a' as two ascii characters ; to conout hexout: push af ; save full value rrca ; get left nibble 1st rrca rrca rrca call hexify ; display it pop af ; restore original hexify: ; display the lower nibble in 'a' and 0fh ; make it a nibble cp 0ah ; is it a-f jr c,hex2 ; no, ok as is add a,7 ; adjust for a-f hex2: add a,'0' ; now valid hex character ld c,a ; prep to output it jp conout ; send it to console device page ; saydrive ; display msg pointed to be de to conout, ; then say 'ing drive x:' ; to conout saydrive: call conmsg ; 1st issue fcn name ld de,drmsg ; pt to drive message ld a,(drive) ; get bdos drive add a,'A' ; adjust to an alpha char ld (drmsgdr),a ; save in msg conmsg: ld hl,conout ; pt to console output rtn jp outmsg ; and output that message ; msg text will follow ; crlf ; output crlf to conout TR LD BC,80 ; CALL MOVEMSG JR MOVEMSG ;Movemsg will return correctly ; RET PAGE RESTOR: ; This routine moves 80 bytes from HL pointer to the last video line ; and 80 bytes from DE pointer to last line video attribute ; ; ENTRY HL = address of message ; DE = address of attributes ; ; EXIT None ; PUSH DE ;Save attribute pointer PUSH HL ;Save message pointer LD H,40H ;Video for destination bank IN A,(SYS) ;Get current bank LD L,A ;For source LD (RSBANK),HL ;Set parameters POP HL ;Status message (source) LD DE,0CB80H ;Last video line (destination) LD BC,80 CALL MOVEMSG POP HL ;Attribute pointer LD DE,0DB80H LD BC,80 ; CALL MOVEMSG ;Fall through ; RET PAGE MOVEMSG: ; Uses high ram routine to transfer data between banks ; must save IX-reg, as ROMMV uses IX to preform jump to ; High RAM routine (see EXCBIOS3) ; ; ENTRY HL = Source start address ; DE = Destination start address ; BC = # bytes to transfer ; ; E ; newline ; output crlf to routine in hl crlf: ld hl,conout ; newline to conout newline: ld de,acrlf ; pt to msg jr outmsg ; and do it ; beep ; crlf, honk the horn and say who we are ; BIOS error ....... ; to conout ; Note: also clear any waiting keys from conin 1st beep: call crlf ; new line 1st beepclr: ; clear any waiting keys call conist ; is there anything waiting jr z,beepok ; nothing waiting call conin ; something waiting, get it jr beepclr ; and ignore it beepok: ld de,abeep ; pt to bell + crlf jr conmsg page ; outmsg ; send msg to some device up to 255 chars ; in length and terminated by a 00h character. ; this is intended for the initial logon msg, ; disk error messages or device timeout msgs ; note: this resides in bank 0 ; bc destroyed ; de ptr to start of msg (0 terminated) ; hl ptr to routine to output a char (rom or bios) ; typically conout or cout (rom) ; preserved on output ; outlen ; an alternate entry tdcbsy: db 'busy',0 stattbl: ; table of 1 byte offsets db fdcnr-statmsg db fdcwp-statmsg db fdcwf-statmsg db fdcnf-statmsg db fdccrc-statmsg db fdclst-statmsg db fdcdrq-statmsg db fdcbsy-statmsg ; a separator between status texts comma: db ', ',0 ; the following is the lead-in for the hex code of error codemsg: db 1bh,')(code=',0 ; enter dim mode codeend: db ')',1bh,'(',0 ; end dim mode end ror dskmsg: db 'Retry this operation',0 ; retry desired, but media changed mediamsg: db 1bh,'^WARNING:',1bh,'q ' ; blinking db 'data on disk inserted may be destroyed. Continue',0 ; tell what opr said nmsg: db 'No',0 ymsg: db 'Yes',0 ; the following are the various fdc status messages statmsg: ; start of table fdcnr: db 'not-ready',0 fdcwp: db 'write-protected',0 fdcwf: db 'fault',0 fdcnf: db 'not-found',0 fdccrc: db 'crc-error',0 fdclst: db 'lost-data',0 fdcdrq: db 'drq',0 fo output a message, but the ; length is specified in 'b'. The message may ; not contain a 00h character. ; b # characters to send outmsg: ld b,00h ; maximum # of characters in msg outlen: ; alternate entry: 'b' = msg length ld a,(de) ; next char or a ; is this a terminator? ret z ; yes -- all done then ld c,a ; char to be output push bc ; save char count push de ; and ptr to char push hl ; and routine addr call jphl ; call routine pt'ed to by hl pop hl pop de pop bc ; all restored inc de ; next char djnz outlen ; loop 'b' number of characters ret ; done page ; messages ; a crlf acrlf: db 0dh,0ah,0 ; a beep (bell) followed by who we are abeep: db 07h db 'BIOS error ',0 ; disk function names (followed by 'ing') selfcn: db 'select',0 rdfcn: db 'read',0 wtfcn: db 'writ',0 ; generic drive name message (after function, ; before error text) drmsg: db 'ing drive ' drmsgdr: ; drive char inserted here db 'X: ',0 ; select error text B>type a:exassy.sub ;Submit procedure to assembly BIOS source 10/14/84 DAB A:M80 =EXCBIOS0 A:M80 =EXCBIOS1 A:M80 =EXCBIOS2 A:M80 =EXCBIOS3 A:M80 =EXCBIOS4 A:M80 =EXCBIOS5 A:M80 =EXCBIOS6 A:M80 =EXCBOOT A:M80 =DSWTSYS A:RMAC SCB B>a:submit a:exassy B>;Submit procedure to assembly BIOS source 10/14/84 DAB B>A:M80 =EXCBIOS0 No Fatal error(s) B>A:M80 =EXCBIOS1 No Fatal error(s) B>A:M80 =EXCBIOS2 No Fatal error(s) B>A:M80 =EXCBIOS3 No Fatal error(s) B>A:M80 =EXCBIOS4 No Fatal error(s) B>A:M80 =EXCBIOS5 No Fatal error(s) B>A:M80 =EXCBIOS6 No Fatal error(s) B>A:M80 =EXCBOOT No Fatal error(s) B>A:M80 =DSWTSYS No Fatal error(s) B>A:RMAC SCB CP/M RMAC ASSEM 1.1 0000 001H USE FACTOR END OF ASSEMBLY B>a:put console FT MARGIN COLUMN NUMBERumn)? (ESCAPE for cursor col RIGHT For decimal tab stop enter "#" and decimal point column  SE selmsg: db 'not ready or not formatted.',0 ; unassign msg for device not ready msg DNRMSG: DB 'BIOS error. ' DEVMSG: DS 6 ;Space for device name DB ' not ready or buffer full, unassign this device (Y or N)? ' DB 0A0h ;Simulate cursor DB ' ' ;Pad with spaces DNRATR: DW 0,0,0,0,0,0,0,0,0,0 ;No attributes set DW 0,0,0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0,0,0 ; part of the yes or no question yorn: db ' (Y or N)? ',0 ; retry msg for a disk error dskmsg: db 'Retry this operation',0 ; retry desired, but media changed mediamsg: db 1bh,'^WARNING:',1bh,'q ' ; blinking db 'data on disk inserted may be destroyed. Continue',0 ; tell what opr said nmsg: db 'No',0 ymsg: db 'Yes',0 ; the following are the various fdc status messages statmsg: ; start of table fdcnr: db 'not-ready',0 fdcwp: db 'write-protected',0 fdcwf: db 'fault',0 fdcnf: db 'not-found',0 fdccrc: db 'crc-error',0 fdclst: db 'lost-data',0 fdcdrq: db 'drq',0 f>623y"!v36*5"3$"32:4*W"#5GJ2:42942(524> 2S(0>24ɯ242T!4~@`65!^4#:(5O:4yD(w~$w:(50 |:(5D(A:(5?ʱ@ʱD(Aɷ͙| ;!Cͻ2(5:'5:)5:5:(5ͫ%:(5 !J24:(5 ʞ;{>24:'5ʋ:)5.:5‹;Ž*-5*%5++{Iz]~ T++]!]+?"%5:'52'5hͫ%2'5ä:(5*—:S —ʤË ¤24͙ʳ>|ʾ>:(5'2(5> :u3>+2P4(0!K46 >24>24:(52SR:4Z:'5:4=!EQM<8!LE:(5=I!NE>I!LTM>!GT:(5=M!GE2(5"4!44>24!(5:4ruͳ u͇:(5D(OʓQ˜>ßH©>2T2(5:SD(B¹>D> !452T!"4!4N#~#A07O!T/!~*4! ) "4 :(5 5!'':(5 :(5,;%:(5 !:(5; ,J242Z$ l ` / ‰ >24#!:(52S:4; ¡ :4/!:Z/!)!:4 :(5'#!R:(5'z 24É :(5' >24#!^ :(5 #! #!;!)!<!!Z~4z X[ e4t] ==QVERSTTUD4E\'F " 3v2ey4@P6Nb$S"4C7'#It0@1byo9p: ! r8Fnfi3ٜ&##@F:#(y9 Ә@8y@H4  n:Eo6E@9 F@h( % 00` a 00` a 00õ 0l` a 00vk@c4c4c4c4c4c4c4c4c4Hd@LB%`ȰAUXINdU5HAUXOSTdUUHCBOOTT48CONISTd45HhCONOUTdDUdxDEVTBLdE%D$͘DRVTBLTdU4HOMEDĕ5HpLISTSTDdX0MULTIOUD4@READWU%dU%8ɈSECTRNe4TE4ʐSELMEMe4UD$(SETDMAe4UE4T8SETTRKe4txTIMEUD$XVERSUt$HWBOOT@Uu$DXXMOVEOUTdDUdxDEVTBLdE%D$͘DRVTBLTdU4HOMEDĕ5HpLISTSTDdX0MULTIOUDserial device table idevlen equ 16*8 ; primary table idevshd equ idevtbl+idevlen ; devtbl serial device ishdlen equ 16*4 @USRCD equ scb$base+44h ; Current User Code (byte, r/o) FE4A = @MLTIO equ scb$base+4Ah ; Current Multi-Sector Count ; (byte,r/w) FE4B = @ERMDE equ scb$base+4Bh ; BDOS Error Mode (byte, r/o) FE51 = @ERDSK equ scb$base+51h ; BDOS Error Disk (byte,r/o) FE54 = @MEDIA equ scb$base+54h ; Set by BIOS to indicate ; open door (byte,r/w) FE57 = @BFLGS equ scb$base+57h ; BDOS Message Size Flag (byte,r/o) FE58 = @DATE equ scb$base+58h ; Date in Days Since 1 Jan 78 ; (word, r/w) FE5A = @HOUR equ scb$base+5Ah ; Hour in BCD (byte, r/w) FE5B = @MIN equ scb$base+5Bh ; Minute in BCD (byte, r/w) FE5C = @SEC equ scb$base+5Ch ; Second in BCD (byte, r/w) FE5F = ?ERJMP equ scb$base+5Fh ; BDOS Error Message Jump ; (word, r-25L-15Q-8*1,-x#ñ,~A,-#ñ,#6 !1*!*!E**e !N*+-!j**%,r-6* ,,:=*ʂ-:>*…-2:?*ʨ-!***ѯ2:*29* ,,!3*60#60#60#>235!"*:5ͨ/-!"f*2Q*2e**E*+!1*z{:*5G.*B*-.!"B**\..*B*#"B*+~¤.:u32*5G.*\!F2+*f*-•.*!"f**h*ʹ*E*€.a.Ò.Ҫ.ʒ.6# ‹.͹**h**f*#"f*~!2*G:=*..xx/.x.1,..****w#"*!-*!"***j*!*-/~5/ʹ*9//͹*!2*1L/****w#"*!-*!"****/_!5*~ ͳ.27**/5}!1~ /ͳ.#/> ͳ.>#ͳ.ͅ/> ͳ.*/5~/ͳ.#/> ͳ.> ͳ.> ó.}26*!7*è/Oͳ.:K4 :5:=*yx/:8*!5I0:25!*5—0~0:K4 0!K4~ —0:350:P4+—0:,50ʗ0:Q4#0:L4 0:,5=ʗ0!K4~ ʇ0!4s!7*~!6*Ԩ/4:4!K4ʺ0G~ 0#x=ë0> 0> 024!K4>x6 #=0G!K4~ p%,**}0>ͳ.0*j*+:+5/w) FE62 = @MXTPA equ scb$base+62h ; Top of User TPA ; (address at 6,7)(word, r/o) 0000 end EQGEGTIFINLELTNEORSPACIADCADDADIANAANDANICMACMCCMPCPIDAADADDCRDCXENDEQUHLTINRINXIRPJMPLDALOWLXIMODMOVMVINOPNOTNULORAORGORIOUTPOPPSWRALRARRETRLCRRCRSTSBBSBISETSHLSHRSTASTCSUBSUIXORXRAXRIASEGCALLCSEGDSEGELSEENDMHIGHIRPCLDAXLHLDNAMEPAGEPCHLPUSHREPTSHLDSPHLSTAXXCHGXTHLENDIFEXITMEXTRNLOCALMACROSTKLNTITLECOMMONINPAGEMACLIBPUBLIC7 PF FPA A A* A A A(#&&#&2#/?&#' '( v'( %:P!@"<& #*)&# PP%27&#(&#  $ %*%"$  NZZ NCC POPEP M a{xʑ(_BH!f(4D(#ƒ( p({ڍ(KR(CR(<:4 JCR:4(ʿ((!46 4(!4(# ( ɯ<:4O=_.)!D'F!%V#fjQM()X[`dE%eD$A Q 2DPH0 e Th)` )"?KY\P`@@.@08 <-A@  `pH `   @ U @008^~`?xh@ @ y 08% `@ 0( 80" `X@@@0 ``H0 @8(Ba(,"AX DPBTBLDEXDPH1dE%eD$STDINIU5DE$H@STDSELU5DEuI^~`?xh@ @ y The remainder of the table ; is best described by the following equates. ivers equ 0 ; version number must match idrvtbl equ ivers+2 ; drvtbl tbl of dph ptrs idrvlen equ 16*2 ; length of data part idevtbl equ idrvtbl+idrvlen ; devtbl serial device table idevlen equ 16*8 ; primary table idevshd equ idevtbl+idevlen ; devtbl serial device ishdlen equ 16*4%Z\ f4 @DM$i IH@ 4@ $i I\ 0?1 ~c?1 ~cAxl*!YDTHD@AIVECddT8@CIVECd4dT8@LOVECTU`AUXISTdU5H@AUXOUTT4CONISTd45HpCONOUT+DTHDELAY0dDUd`DEVTBL&dEdXLISTdĕ5E5H8 OUTSTyU4U$(`VECPTRcAxl*!YDTHD@AIVECddT8@CIVECd4(C(͆7:9):o9:o9H4!"p9>:o929*p9"95*.:~(*.:~ʐn*.:~)p̀^*.:~*.:~(HҍDO:9ʛD*Ͳ!6~̈́6*& 6:[],()?$! : @: <_2 <: !#<ڲ*#<& :<«>!#<4>*.:#".:*.:N2<&õ͵:< ͵!<6 !%<6+6:%< :%<  !UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUX[DdXa5=YSBANKQSdTDtXM156TIMEUԓ`U$i@Z: qX:.ӛi1m?[`rz 8GVf`Aͧ`녇P@#X^2i #:2e 0%sm?F-]X=,X=%-Ka0 (Iq@ ȱӰ hH)qՀ )հ O ȳZ: qX:.ӛi1m?[`rz 8GVf`AA, BC, HL, IX = Any necessary parameters ; ; EXIT All ROM exit parameters remain in tact ; torom: ld (savesp),sp ; save user's stack ld sp,comnsp ; pt to one in common ld d,a ; save a in a,(sys) ; get crnt bank ld (ubank),a ; save for later exit or 80h ; force into rom out (sys),a ; now ld a,d ; restore a ld d,01h ; de=01xxh call romjp ; off to the rom (via our code) push af ; save a and flags ld a,(ubank) ; incoming bank info out (sys),a ; restore bank now pop af ; all regs now restored ld sp,(savesp) ; and return ret ; with user's stack romjp: push de ; dummy up like a X[̠dDUeD$Y%9&CONOUTUVU Dĕ5H =9=MRAUXOSTT T4Ua%:CONISTUVT dEdXY AQJDELAYSVL TUE5IEh״Z9z 078MƘ=p"ޯ#ea ppC.YqFpP4w Fph޴_ᖋtZQ urB I$O ";Eb\QWW@# l)x=-%#rvPP r6+7@\/ÍqH @1$à T9Y(P bl€$ax OЎ LEA@Ȥ@IB)4@ DH@HR(@:DM9͏5*:@ ~ !92(< !92)<7 :)<ր2) >!:*!^:6+":^:$t 8'> *0< ~L*0< DMB5*0< 6*0w#6!4w#6*0<##N#F*.< ~O`i~8p8!6Ͷ8ikS*0< DMv5*0< DMd5*0< *0<##N#Fq#pä*0<##q#p*u:#^#V*u: ^#V*u: ^#V*u:~*u:~*u:>*u:~*u: ^#V*w: ^#V!8:=<Hw!>:><Hw!?:?<Hw!@:@<Hw!B͔8>ͥG<X[`T4$H] ==RSTDSENTU4U$)EP,hZ=L"bDd` @? T@x`/Y<@W"[B0ZX,4_V[ !  cvJlݞdAx=.`{81a=Y #@2Ālb a7f@@` 8ݐOb\hBa$ DyL@e9!e6Lg@a2#Ii7CeBt!@o9 o9L'C.$r9B\ 7΂d< !f3NB1l i3CA 2NƓ@(, !8R?( 7H@)N#Ȁh4a:MlW Ēqt8 @o7 @i7̧# 6O"@d2·#yd3yi7LqY2yZr2Li:Ee1 @u6yZf7M@cNG#yl7΂!aGs<ЀT4lR(1̆QR#! 9- 5nUP̈́d:8+s#r!r=s+q+p+q*o=DM*q=̈́*^=&^<) ^#V"d:>d:ͫ8ʆh!q=}*o=*d: DM*q=>*}U!r=}>M"d:<>!|=r+s+q+q+q+p+q+q+p+q:u=2}=:z=Һ!}=44*`:"d:*}=& "`:q:ͮ896<*s=DM*u=̈́*^=&^<) N#FU*^=&^<) *d:s#r*}=M͍*v=DM>*y=M*u=Ms*x=Mf*u=*d: *s=DM -B:z=Y*{=DM*d: ~#k!{96 MODULE TOP $UNDEFINED START SYMBOL: $YY???? $$$XX???? $$$RQST$ UNDEFINED SYMBOLS: $ABSOLUTE $CODE SIZE $DATA SIZE $COMMON SIZE $USE FACTOR $!=q*=MͲ!~=4!=q> !=8:=0OͲC:= AOͲ!=q:=O:=O!=p+q!=̈́8MD>=08MD:;!t;!;!;:u;2\. ] -Ÿ\ͩ6!t;6!;6!;6!;6!=6+6>!=*=&f;) ^#V"= *= ~ *= DMv5 *= 6!=6:=<2=:=7::2\. ] -)\ͩ6*p9###H:ͮ8!D:U!\:6*p9###F:ͮ8!C:r!\:6*p9###X:ͮ8҉!\:6:R:>S:ͫ8:U:H:C:/HҼ!\:6!\:6:E:!C:!\:6!\:6:C:*F:"::\:*p9###":Q9I54QQPc&5aQA4P[9 Q 9R:PГ#[u =9%:5ӒT#Yy =9=UR4QSVcP@Y1d5UScH YYQ 20QPPA Q 24 #BA 5~QUcY@IYQ 25hSUc3 15=Y4SU#LuI=55Z4HTT"@M156 !  cvJlݞdAx=.`{81a=Y #@2Ālb a7f@@` 8ݐOb\hBa$ DyL@e9!e6Lg@a2#Ii7CeBt!@o9 o9L'C.$r9B\ 7΂d< !f3NB1l i3CA 2NƓ@(, !8R?( 7H@)N#Ȁh4a:MlW Ēqt8 @o7 @i7̧# 6O"@d2·#yd3yi7LqY2yZr2Li:Ee1 @u6yZf7M@cNG#yl7΂!aGs<ЀT4lR(1̆QR#! 9- 5nUP*!J>4,*p9"A::\:(-ͦ-ͦ-ͦ-!L>6::=!L>|-*L>&: ~2K>u-*K>&:) A:͠8e-ͦ-J-:r-.u--!L>4--*p9*A>A:ͮ8ҕ-ͦ-|-:7>ʥ-ͦ-Õ-!O>q*O>Mͧ**A:#"A:M>A:͞8-ͦ-ù-ͦ-*K>&i:) ^#V"u:>u:ͫ8.ͥ*K>&:) 8"M>͹-ͺ"u:-*K>&<) N#F.*0< ~R.*0< DMd5*0< *0<##N#Fq#p].*0<##q#p2P>:P>ʤ.*K>&:) 8"M>"9:P>O>Ҙ."9͹-2P>c.>5:08>͔8ʾ.q*å.>*5:DM\͔5\v5:w9Z.. \": -.:e /.*o9&\8_* DMe - /:w9#/:w92\\B5:9 A/. ~9\ -9/!"5:}28>27>*ͥ.:x9Z^/. \": -f/.en* -v/:x9ʌ/:x92\\B5!"5:}2R>ͽ"d:`:d:͞8(0͹/H02DMv0 q*!Q>6h!Q>/:Q>=O! *d:Nq*:Q><2Q>/:R><2R>0 q* q*0 q*̈́d:8+s#râ/ q* q*ͥ.!S>q> !S>O0:S>0Oq*Z0:S> AOq*!T>q:T>O60:T>O60!V>p+q*U>|O[0*U>}O[0*9>!=8"W>*W>!=8!Y>s:h0:Y>2h\͕60\>645*W>!=8!|s2*9͗8"9>. \~9 -0:9 1y:) q#p*&>&:) >w#6:&><2&>$s:q:͞87%*q:"s::G%͸*9"q:^ :_:/2^::{9]%!!)>s+p+q:)>ˆ%*g:*'>"'>:f:҅%!)>6Ý%*)>&:) '>8+s#r*]:&y:) N#F*]:%*'>DM*)>M͋%*]:&y:) N#F*'>*)>*]:5y y !*>q:*> &>!*>&:*>#&+"ÿ&:*>1&p"ÿ&:*>?&k$ÿ&:^:ҿ&:*>=O!& ^#VI"ÿ&ÿ&͈"ÿ&>ÿ&͵"ÿ&#ÿ&T#ÿ&#ÿ&#ÿ&$ÿ&$ÿ&Q$ÿ&d$ÿ&W&]&`&f&o&u&{&&&&&&&!+>6)&)2->:^:&*->My (')2,>')2+>:+> '*+>M%('͕".>:^:('*.>DM*,>^%:+>&7','!0:6&H'='!0:6!"1:"7::!:'*:͗8"1:"7:. 9\ -u')29!hʦ':92h\͕6¦'\=45)2|29!:6*7:"1:!"9"9^ :_:/2^::!:!_:' ',':e (.e -'e>*2!:\d5I'}/B(}͉ͽ"d:`:d:͞8)͹(:v92\!0>6>!0>گ(h!0>҈(*0>&\ 6 å(:0>=O! *d:*0>&\ w:0><20>g(!!:6.e -¼(\W5/(!!:6.e -(\d5*d:"1>!_:6I'*1>"d:̈́% @{ `F~=#'tQ~YhE!!GFka>E'I| D%vOeQ \K 0ڰDטȪ# 0s= 0f@#O ! C`==C ` A p 2{4٠8GD= lHtPy٠86AVh$90 D8ڰ#@ N< C0h(B$btNG#y@r2Lq@d4bLs:Me:FSr2P"T N#O ! C`==C ` A p 2{4٠8GD= lHtPy٠,0,0,0,0,0,0,0 ; 05 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 06 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 07 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 08 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 09 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 10 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 11 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 12 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 13 unused slot fill to 16 db 0,0,0,0,0,0,0,0 ; 14 unused slot fill to 16 db 0,0,0,0,0,0,0X[͠T4$H] ==RAREA0U dDUd =9=URAUXOUTT d45HUa=MRLISTSTPӒSTU =9%MRAUXISTSe5DDU%(MQ9JP5U6 TB@DgDgJX`x ä2P@  p<PTPL# Ua%::HUVT#@Ua=MR::UVU# ==R:RPӒS =9%MR:Dӓ# =9=UR:8UScYQ 22 #1%MR:DT# `MQ 9.:4T@MQ9J:4S%Q=I=6:UГ'x ä2P@  p<PTPL# Ua ; conost, auxost, listst ; all return aok now conost: auxost: listst: xor a ; all ready ret ; and done ; conist, auxist ; just check status conist: auxist: ld e,skey ; check keyboard jp torom ; let rom do it ; conin, auxin ; get console character conin: auxin: ld e,ci ; get character jp torom ; also let rom do it ; devtbl ; only a dummy table for cpmldr devtbl: db 'CRT ' ; device 0 crt db devin+devout,0 ; i/o device no b N#F*t>?8*]>~   +5{>.+55OͲ5w66ͩ6́5;6<566́5͕6<>́5͕6<>645͜6<H66! w #ˆ5>Ö5>2,6""6"$6yo`"&6!"*6͋6-66*&6|6 "&6*"6MD6*$6DM:,65ͷ6g666Ͱ66**6|6U6*$645*"6""6**6#"*6ú56**6ABORTED$NO SPACE$NO FILE: $CANNOT CLOSE$DISK READ ERROR: $DISK WRITE ERROR$YYYP   YP6YPYPYPYPYPYP Ͳ ò!>6#6͐6">*>|$7>9ͫ8"|>##*|> ~!7!>6D7*>|?7!>66"|>D7!>6:>Y7!~>6#6#6Å7*|>~2~>*|> ~2>:>z7:>2>*|> ~2>!>6>!>ڰ7*>&v> ~/*>&: w!>4‹7:72"g:^ *:"|> *g:":*9My *9My *9My *~>My *>My *>My *|>":i`N#Fog_og_{ozg_ogDM!>))덑o|gV8 =D8DM!>))k8 =c8_{ozg^#V) ~8^#V|g}o ˆ8_{ozgi`N#Fogo&og_{_z#WFE00 SCBBASE FE5F ?ERJMP FE26 @AIVEC FE28 @AOVEC FE57 @BFLGS FE35 @BNKBF FE22 @CIVEC FE24 @COVEC FE3C @CRDMA FE3E @CRDSK FE58 @DATE FE51 @ERDSK FE4B @ERMDE FE43 @FX FE5A @HOUR FE2A @LOVEC FE54 @MEDIA FE5B @MIN FE4A @MLTIO FE62 @MXTPA FE41 @RESEL FE5C @SEC FE44 @USRCD FE3F @VINFO S1 No Fatal error(s) B>A:M80 =EXCBIOS2 No Fatal error(s) B>A:M80 =EXCBIOS3 No Fatal error(s) B>A:M80 =EXCBIiK2q!vj*vK2qqf!vv͉d>267ɯ2v{͹qq6q{͹q*q7?Cqͧq{xq͹qͶqʆqͧq>2v͹qͶqsqE7:v7͹qSʝqD q͹q-7+vM"v#{ʿq2'K? ܔ ڿq7*qɾ#45qs6RqhqwqÑq&rSrqqqqrrërrqq r9s{IQ0 ENTER space OR NEW LINE SPACING (1-9): LEFT MARGIN COLUMN NUMBERumn)? (ESCAPE for cursor col RIGHT For decimal tab stop enter "#" and decimal point column  SE]\Z1  V#j@6d ڰmWPFԁmH6o(ԃh`F?-*>PFmH6XFmI6hZq t6\ ;V69B7,\;V|Wf0+/jXٷLCj@ 6J/[8CjE ͼ!#an>1/0ƀmID[,KL۾Wtt  X`P dV<ZP# pD 'j>.@!T\ҝ@,ՀL;Vݎ٠P(Ff@ݎP!@.= _f #O|#K|ubV쫠dEi նs`$-H4T4Nbs4y@E,Bd ;Mi:D#y,a,L&po7QLT*r4  )ɢsA& c)i2Dq :C 2Nf F@BQLs:Mc5y KMӀ h($# 9L&CI AESql2e7Qr7si73e6# sQr7Bl23y@i9xo7P@X!򠀆O&ei0RdhO' O& DiHMdh$ CP/M 3 Sys $ Memseg No. $ Bank $ Accept new memory segment table entries $Default entries are shown in (parens). Default base is Hex, precede entry with # for decimal $ Use GENCPM.DAT for defaults $Create a new GENCPM.DAT file $Display Load Map at Cold Boot $Number of console columns $Number of lines in console page $Backspace echoes erased character $Rubout echoes erased character $Initial default drive ($:) ? $Top page of memory $Bank switched memory $Common memory base page $Long error messages $Double allocation vectors $Accept new system definition $ CP/M 3.0 System Generation Copyright (C) 1982, Digital Research $ BNKBIOS3 SPR$BIOS3 SPR$BNKBIOS3 SPR$BDOS3 SPR$RESBDOS3 SPR$BNKBDOS3 SPR$ 64K TPA Copyright (C) 1982, Digital Research *** CP/M 3.0 SYSTEM GENERATION DONE ***$!Tq:UM*T&!Tp+q:Ud*T !Tp+q*T#6:UҀ:Tڀ*T *T#N! *T6 7 7!Tr+s+q+q!U6N*TDMN:TTN͜:T.:T/!U!]6 !m6 !TpHs2S!Hs2S$ei0RdhINDEX ERROR$MULTIPLE DEFINITION: $MAIN MODULE ERROR$FIRST COMMON NOT LARGEST$COMMON ERROR$UNRECOGNIZED ITEM $UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUРd4dT8 =Y@AIVECSՑPddT8 9- @CRDMAԑdddIM2@FXTԐ dDI5@ERDSKQQP`d$du8Q@HOURRSD4T8I)5B@MXTPAM@#_ %Y8IՑP%Y8QSՑP_1=Y8kБ I58}ԑY%9>8TS#b8TԐ#_51Q%>8TQc?IM.8QQPc 1N8PUc_!=UJ8RSM8TT#_5aQApN@Nw#2@.ʷN!ڷNw#N2@.ʾN!ҥNþN6 #·N:@.Nw#NpMMN2M2M:M=OMM0O!M"M>2M*M~+O70O#"M0on the same input line. Submitted jobs may be nested...SUPERSUB does not erase any existing submit job (appends to them instead). To insert a control character into the output, pre- fix it with a "^" (works in any mode). $mmands on the same input line.Submitted jobs may be nested...SUPERSUB does not erase any existing submit job (appends to them inst public setbnk public dmabk ; selmem must set this public stdini,stdsel,stdrd,stdwt ; std routines 5.25 built-in public drive,actcnt ; so can be in err msgs extrn drvtbl ; table of drives extrn dpbtbl ; table of dpb info extrn stdsen,stderr ; std i/o err rtns dpblen equ 17+4 ; length of dpb + prefix cseg ; initial entry shd be common bank always SETDMA: ; ; Set source/destination address for later disk write/read ; ; ENTRY BC = Direct memory access address ; LD (DMAADR),BC in a,(sys) ; get current bank ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall through to set this bank for future i/o's too SETBNK: ; ; ENTRY A = Memory bank for next disk transfer ; LD (DMABK),A RET HOME: ; ; Sets track value to 0 ; ; ENTRY None ; ld bc,0 ; track zero ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; fall thru to settrk SETTRK: ; ; Sets track number. The track number is saved foV6? ͜*VDMN*V~  (7*VN !V6>!Vn *V#"V:V:-Q/HX *V6d ,7*VN :V<2V, *V++"VNÊ *VN*V !V6!V6Te!Vr+s+q:-Q/Ү >!V6#q#p!V6:5Q!Vڳ*V&+SFQ  VzSک:VM*V&+SFQ  ~*V&+SFQ  VzSHJ:V2V*V&+SFQ  ^#V"Vé*V&+SFQ  ~*V&+SFQ  VzSHҩ:V2V*V&+SFQ  ^#V"V:V<2V¿ :V:VH`!V6:5Q!V`*V&+SFQ  VzS/*V&+SFQ  ~H*V&+SFQ  VzSHV:V2V*V&+SFQ  ^#V"V:V<2V:V!$V6!U6ͬ#Q$!H> U͇Sʔ* U|2Uß*U|2U!U:.Q2T*U|!UO:/Q2T*U|O:T2TUTI:-Q/!$V>O:T2T* U|O:T!$V2T:T=2T* U|O:T2TҮ:-Qқ*nV*U*V |!UO:/Q2T*U|O:T2T2Uͬ:U/Ҙ!!V6>!!Vژ*!V&$SQ  6:!V<2!Vsà!U6:V/ҫ*:U2T:T2TTͩ:-Q*T&+SDM*U*T&+SDM*U:-Q/r ; later use during a disk transfer operation. ; ; ENTRY BC = Track number ; LD (SEKTRK),BC RET SETSEC: ; ; Set the sector number for later disk read/write operation. ; ; ENTRY BC = Sector number ; ld a,c ; get sector number inc a ; adjust for 1 origin ld (seksec),a ; save for later use RET FLUSH: ; ; Force physical buffer flushing for user supported deblocking ; ; ENTRY None ; ; EXIT None ; xor a ; do nothing, but did it ok RET PAGE MULTIO: ; ; Set count of consecutive sectors for READ or WRITE ; ; ENTRY C = Mutisector count ; ; EXIT None ; LD A,C LD (SECCNT),A xor a ; clear actual mult count ld (actcnt),a ; to start 'er off RET PAGE SECTRN: ; ; Translate sector number given translate table ; ; ENTRY BC = Logical sector number ; DE = Translate table address ; DE = 0, No translation required ; ; EXIT HL = Physical sector number ; LD l,c ; get logical sector # LD h,b LD A,E OR D RET Z A.Z80 TITLE bios4 (excbios4) disk i/o ; 1983-07-27 add double sided handling in stdrw ; 1983-03-20 set for 1st release ; 1983-03-13 fix in BIOS for DRI bug in BDOS ; 1983-02-21 support extrn rtn for i/o err msgs + retry ; 1983-02-17 re-did stacks for going to bank 0 ; 1983-02-15 slight restructure for code in bank 80h ;**************************************** ;* * ;* EXECUTIVE BIOS * ;* for * ;* CP/M 3.XX * ;* by * ;* * ;* Glenn S. Tenney * ;* COMPRO * ;* P.O. Box 5260 * ;* San Mateo, CA 94402 * ;* * ;* Copyright (c) 1983 * ;* Osborne Computer Corporation * ;* * ;**************************************** ; Some original code still remains which was written ; by Roger Chapman. This code appears in upper case. ; include EXCBIOSE.LIB .xlist include EXCBIOSE.LIB .list PUBLIC HOME, SELDSK, SETTRK, SETSEC, SETDMA PUBLIC READ, WRITE, SECTRN, MULTIO, FLUSH DD HL,DE ; the tables MUST be in bank 0 or common in a,(sys) ; get crnt bank ld e,a ; save bank xor a ; force to bank 0 out (sys),a ; to locate sectran table LD L,(HL) ; pick up sector number from table ld h,a ; (a was 0) hl=sector number ld a,e ; restore bank number out (sys),a RET page ; this starts the routines that are further vectored ; by disk device via the dph prefix. We may be ; in other than bank 0 and the dph header is in bank 0, ; so we switch to bank 0 first. ; todseg ; transfer control to a bank 0 routine ; af destroyed on entry, preserved on exit ; bc preserved ; de preserved ; hl entry: addr of routine, preserved on exit todseg: ld (dsksave),sp ; save sp ld sp,dsksp ; make sure it is in common in a,(sys) ; save current bank ld (curbnk),a ld a,80h ; select bank 0 + rom out (sys),a ; and select rom + bank 0 call jphl ; call rtn in hl push af ; save result if any ld a,(curbnk) ; get saved bank out (sys),a ctor read or write ; de=offset from start of this dph for prefix ; word having address of routine. drw: ld hl,(dphnow) ; pt to current dph add hl,de ; hl=addr of write routine addr ld a,(hl) ; lo inc hl ld h,(hl) ; hi ld l,a ; hl=write routine addr jp (hl) ; off to write for this dph cseg page ; these are the various routines used by the standard ; built-in 5.25" floppies (or flopsies for comic strip aficionados) ; These must be in either common or bank 0. They will ; be called with bank 0 active (see above parent routines ; which call these). dseg ; stdini ; one time initialization (at cboot) stdini: ret ; nothing ; stdsel ; standard built-in 5.25" floppy select disk ; with sense density ; e bit 0 =1 if no sense density needed ; (ld a,e ... rra ; to chk lo bit of e) ; note: carry already set on entry ; hl addr of dph for that drive ; in may not = out of hl if error on sense density stdsel: jp c,seltyp ; done, set type ld a,h ; bank is now back pop af ; restore result ld sp,(dsksave) ; restore sp ret ; and all done jphl: jp (hl) ; simulate 'call (hl)' curbnk: ds 1 ; a place to save bank # page ; ; Select the specified Disk Drive ; ; ENTRY C = Disk Drive (0 - 15) ; BIT 0 E = 0, first call for this disk ; ; EXIT HL = DPH address for specified drive ; HL = 0000 if drive does not exist ; seldsk: ld hl,dsel ; pt to bank 0 routine jp todseg ; change to other bank dseg dsel: ld a,c ; save drive # ld (drive),a ; change to that drive now ld l,c ; get drive # ld h,0 ; into 16 bits ld bc,drvtbl ; start of table add hl,hl ; drive * 2 add hl,bc ; hl=ptr to proper entry ld a,(hl) ; lo byte inc hl ld h,(hl) ; hi byte ld l,a ; hl=that entry from table ld (dphnow),hl ; post current dph addr or h ; is there any such drive?? ret z ; no, get out NOW ; hl is dph for this drive push hl ; save for when we exit dec hl ; back up to drive # ld a,(hl) ; dr; 1st time, is drive valid or l ; hl=0 means no real drive ret z ; not valid, no senden and no seltyp! push hl ; save ptr to dph selrtry: ; here to retry ld a,(sekdsk) ; desired disk number ld (actdsk),a ; so senden can see it call 100h+senden ; call rom directly jr z,selok ; some diskette there ; no diskette or sense density didn't work call stdsen ; see if msg needed jr nz,selrtry ; yes, and user said RETRY pop hl ; just to clear the air ld hl,0 ; show no drive xor a ; and show things rather screwed up ld (sektyp),a ; some weird type (NOT Osborne dd) ld (spt),a ; dummy up to spt=0 ret ; and exit quickly! ; sense returned something, see what it was selok: ld hl,dpbtbl ; pt to head of table ld de,dpblen-1 ; length each entry sellp: ; figure out which dpb to use ld a,(acttyp) ; actual device cp (hl) ; same as this tbl entry? inc hl ; 1st bump to sec/trk ld a,(hl) ; get spt from table jr nz,selnxt ; no, try next tbl entry cp b ; ive # controller relative ld (sekdsk),a ; post controller's drive # ; let seldsk routine for this dph handle it now dec hl ; back up to hi of rtn addr ld a,(hl) dec hl ; to lo of seldsk addr ld l,(hl) ld h,a ; hl= seldsk for this dph ld a,e ; show if sense density needed rra ; carry=no no carry=yes ex (sp),hl ; hl=dph tos=seldsk rtn addr ret ; off to seldsk for this dph cseg page READ: ; ; Read a sector from the specfied drive ; ; ENTRY None ; ; EXIT A = 00h, if no errors ; A = 01h, if non-recoverable error occurred ; ld de,-7 ; offset of read addr in dph prefix jr torw ; off to other bank (common rtn) WRITE: ; ; Write a sector to the specified drive ; ; ENTRY None ; ; EXIT A = 00h, if no errors ; A = 01h, if physical error ; A = 02h, if disk is Read Only ; ld de,-5 ; offset of write addr in dph prefix torw: ld hl,drw ; pt to bank 0 routine jp todseg ; and off to other bank dseg ; common routine to vesame as this drive jr z,selfnd ; yes--found it selnxt: inc a ; see if end of table jr z,selfnd ; yes (0ffh sec/trk) add hl,de ; bump to next entry jr sellp ; and try next entry ; this is the proper dpb selfnd: inc hl ; pt to skew ptr ex de,hl ; let de pt to this dpb entry pop hl ; restore ptr to dph push hl ld a,(de) ; copy skew ptr ld (hl),a ; into dph inc hl inc de ld a,(de) ld (hl),a ld bc,11 ; offset into dph for dpb add hl,bc ; hl=dph+12 inc de ; de=addr of dpb ld (hl),e ; plunk dpb addr in inc hl ld (hl),d ; dph now all set pop hl ; seldsk done, just set type for possible i/o ; and multok = or of skew tbl addr ; hl=dph ptr, get type from dpb prefix seltyp: ld a,(hl) ; pick up skew tbl addr inc hl or (hl) ; a=0 if no skewing dec hl ; restore dph address ld (multok),a ; so multio will work ex de,hl ; de=dph ld hl,12 add hl,de ; hl=dph+12 (ptr to dpb) ld a,(hl) ; lo of dpb addr inc hl ld h,(hl) ; hi of dpb  ld a,(seksec) ; crnt sector for r/w cp (hl) ; is this last sector of track? jp z,rwnow ; yes, read full or partial track ; no i/o done this time, just say it went ok xor a ; then just clear it for no err ret ; and exit as if it was ok rwrdy: ; rw ready (count reached 0) ld (hl),1 ; set seccnt to 1 rwnow: ; i/o required this time push de ; save rom jmp offset push bc ;save original seksec to restore after ldir ; Transfer BIOS variables to ROM varibles LD HL,dmabk ; copy our disk parms to rom's LD DE,dmabank ; this is start of rom's ram LD BC,SEKTYP-dmabk+1 ; length to copy LDIR pop af ;get seksec and-- ld (sektyp),a ; restore to previous dorw: ld a,(sec1st) ; 1st sector of multiple ld (actsec),a ld hl,(dma1st) ; and starting addr ld (dmadr),hl ld a,(actcnt) ; get number of sectors ld b,a ; for rom to read/write ; now ready to do the actual i/o then check for errors pop hl ; restore rom rtn addr (l) push hl ; save roaddr ld l,a ; hl=this dpb dec hl ; back up to sectors per track dec hl dec hl ld a,(hl) ; get sectors per track ld (spt),a ; for multio usage dec hl ; back up to disk type value ld a,(hl) ; get crnt disk type info ld (sektyp),a ; and that is to be used ex de,hl ; restore regs ret ; all done with seldsk ; stdrd ; stdwt ; standard 5.25" built-in floppy read and ; write routines (see read/write above) stdrd: ld e,rsec ; to read a sector jp stdrw ; common for read or write stdwt: ld e,wsec ; to write a sector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; jp stdrw ; fall thru to common routine ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Performs a read or a write ; ; entry e=offset to proper rom routine (rsec or wsec) stdrw: ; i/o may be deferred based on multio ; Check if read or write to double sided media ld a,(sektyp) ;chk disk type ld b,a ;save disk type to restore later bit 1,a ;checkm rtn addr offset ld h,01h ; make it true addr call jphl ; call (hl) pop de ; restore rom rtn offset or a ; were there any errors jr z,rwok ; no, ok to exit rw then ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; NOTICE: ; The following is a bit of a kludge inserted because ; the BDOS does not appear to handle both media change ; and density change on the same drive. The problem is ; that when the media changes (which is posted by an ; interrupt routine) the BDOS notices the flag and tries ; to see if the media really changed. Although the ; documentation states that the BDOS will then issue ; an initial SELDISK and then read the directory, the ; BDOS just goes ahead and blindly reads the new disk. ; Well, if the density, sector size or sectors per track ; just happen to be different on the new disk, the ; results are UNPREDICTABLE!!!!!! ; If the density changes, then an error will be posted. ; If the density remains the same, it is likely that the  double sided bit jr z,sngsd ;if not double sided , just do rw ; the target is double sided , so reajust the sector number ld hl,spt ;point to max phy sector/track ld a,(seksec) ;get the seek sector sub (hl) ;a = seksec - spt jr z,rwside0 ;if seksec = spt , no adjust jr c,rwside0 ;if seksec < spt , no adjust rwside1: ld (seksec),a ;adjust the bios seksec jr sngsd rwside0: ld hl,sektyp ;point to rom sektyp res 1,(hl) ;reset side bit of savtyp sngsd: ld a,(actcnt) ; is this 1st rw? or a ; to init dma and sector jp nz,rwmayb ; no, may be a real i/o though ld a,(seksec) ; crnt sector ld (sec1st),a ; is 1st sector of multiple ld hl,(dmaadr) ; same for dma addr ld (dma1st),hl rwmayb: ld hl,actcnt ; adj cnts inc (hl) ; actual count +1 inc hl dec (hl) ; multio count -1 jp z,rwrdy ; 0=this must be last rw of mult ld a,(multok) ; 00=multio allowed or a ; xx=no multio (skew active) jp nz,rwrdy ; not supported for multio inc hl ; pt to spt ; read will, if it is for a sector valid on the new media, ; detect that the directory is different. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; we had some error, see if media changed push af ; save error condition push de ; save rom rtn addr push bc ; and fdc status byte call 100h+senden ; see if same density jr nz,dskchg ; error on sense, media changed ld a,(spt) ; sense ok, see if same as old cp b ; same sectors per track? jr nz,dskchg ; no -- must have changed ld hl,sektyp ; hmm then check disk type ld a,(acttyp) ; new type cp (hl) ; vs. old type jr nz,dskchg ; different! a changed disk ; at least it is the same type of media, as far as ; we can tell, so process the error pop bc ; b=fdc status byte pop de ; e=rom rtn addr pop af ; seems the same, process error ; let our error routine process the error. ; That routine may issue an error message or ask ; us to retry. ; We pass to it: ; a error flag ; b fdc status byte; BIOS generation 10/14/84 DAB ; ; Put this disk in A-Drive, Source disk in B-Drive. ; ; Run EXASSY.SUB before this to assemble all requisite files. ; Run with B: drive logged in (from B> prompt) ; ; First link the boot files:(3.217) ; a:link dswtsys[l100]=dswtsys ; a:link excboot[l4000]=excboot ; ; EXCBIOS6 must be linked last DAB 3.217 ; a:link cpmldr[l4400]=a:cpmldr,excbios0,excbios1,excbios3,excbios4,excbios6 ; a:link bnkbios3[b]=excbios0,excbios1,excbios2,excbios3,excbios4,excbios5,scb ; ; create the new cpm3.sys: ; a: era excboot.com era dswtsys.com era cpmldr.com era bnkbios3.spr pip a:=b:excboot.com[v] pip a:=b:dswtsys.com[v] pip a:=b:cpmldr.com pip a:=b:bnkbios3.spr[v] gencpm auto display ; ; Format a dsdd disk. Place it in drive B. Place this disk in drive A. ; Type dswtsys. This puts the boot loader, et. al., on the disk in drive B. ; Next, copy CPM3.SYS and CCP.COM from drive A to drive B using PIP. ; Finally, copy FONTM.COM on drive A to ALTFONT.SYS on drive B u ; e rom rtn addr ; The error routine must restore all regs and: ; Z no retry, return error ; NZ retry again call stderr ; issue std err msg (maybe) jr nz,rwnow ; asked to retry rwok: ld hl,actcnt ; reset sector count ld (hl),0 ; without changing af ret ; and all done dskchg: pop bc ; media HAS changed, show it pop de pop af ; clear the stack xor a dec a ; a=ffh to show media changed jr rwok ; and exit w/ i/o completed cseg page cseg ; common cause of dmabk ; the following are a few areas used only w/in this ; module ; parameters local to the bios re: disk i/o drive: db 0 ; current drive # 0 relative dphnow: dw 0 ; addr of crnt dph (set by seldsk) multok: db 0 ; the or of skew table addr ; 0=multio ok this drive ; x=no multio this drive ; these 3 items must be in this sequence actcnt: db 0 ; actual number of sectors this i/o seccnt: db 1 ; multio number of sectors spt: ds 1 ; sectors per track crnt drive sec1st: ds 1 ; ssing PIP. ; The disk can then be booted. CPM3.SYS, CCP.COM and ALTFONT.SYS should ; be set read/only and system using SET. Or, COPYSYS can be used to copy ; the system on drive B to another disk. It will set the files R/O and SYS. G: PROGRAM INPUT IGsys[l100]=dswtsys ; a:link excboot[l4000]=excboot ; ; EXCBIOS6 must be linked last DAB 3.217 ; a:link cpmldr[l4400]=a:cpmldr,excbios0,excbios1,excbios3,excbios4,excbios6 ; a:link bnkbios3[b]=excbios0,excbios1,excbios2,excbios3,excbios4,excbios5,scb ; ; create the new cpm3.sys: ; a: era excboot.com era dswtsys.com era cpmldr.com era bnkbios3.spr pip a:=b:excboot.com[v] pip a:=b:dswtsys.com[v] pip a:=b:cpmldr.com pip a:=b:bnkbios3.spr[v] gencpm auto display ; ; Format a dsdd disk. Place it in drive B. Place this disk in drive A. ; Type dswtsys. This puts the boot loader, et. al., on the disk in drive B. ; Next, copy CPM3.SYS and CCP.COM from drive A to drive B using PIP. ; Finally, copy FONTM.COM on drive A to ALTFONT.SYS on drive B utarting sector when multiples dma1st: ds 2 ; starting dma addr when multiples ; the following MUST be the SAME as the rom dmabk: db 00h ; desired bank for xfr ( default = 00 ) dmaadr: ds 2 ; desired address for xfr seksec: ds 1 ; desired sector sektrk: ds 2 ; track sekdsk: ds 1 ; disk unit sektyp: db 0ch ; sector size ------>>> forced to Osborne dd ; sector size end mabk ; the following are a few areas used only w/in this ; module ; parameters local to the bios re: disk i/o drive: db 0 ; current drive # 0 relative dphnow: dw 0 ; addr of crnt dph (set by seldsk) multok: db 0 ; the or of skew table addr ; 0=multio ok this drive ; x=no multio this drive ; these 3 items must be in this sequence actcnt: db 0 ; actual number of sectors this i/o seccnt: db 1 ; multio number of sectors spt: ds 1 ; sectors per track crnt drive sec1st: ds 1 ; s1TP!u(!2! ! !U>2!! 2]!$ 2*@">B ><>W+V+^!KL>K!!Q!>:!>:!$>2:2 >G"z<2{2xJ!G>]PRS!,[<(+[!(= _M<,:2 P This version of EXCWTSYS will write boot, cpmldr, main font, SETUP override and ROM's RAM override only to dsdd disk in drive B $ System tracks aok $. $ Error reading $ Unable to open $ Error writing system tracks $ Error: cpmldr.com is too long $EXCBOOT COMCPMLDR COMFONTM COMROMRAM COMReservedReservedCF = 01 NDIRRECG = 01 NDIRRECH = 01 NDIRRECI = 01 NDIRRECJ = 01 NDIRRECK = 01 NDIRRECL = 01 NDIRRECM = 01 NDIRRECN = 01 NDIRRECO = 01 NDIRRECP = 01 NDTARECA = 1E NDTARECB = 00 NDTARECC = 01 NDTARECD = 01 NDTARECE = 01 NDTARECF = 01 NDTARECG = 01 NDTARECH = 01 NDTARECI = 01 NDTARECJ = 01 NDTARECK = 01 NDTARECL = 01 NDTARECM = 01 NDTARECN = 01 NDTARECO = 01 NDTARECP = 01 ODIRDRVA = A ODIRDRVB = A ODIRDRVC = A ODIRDRVD = A ODIRDRVE = A ODIRDRVF = A ODIRDRVG = A ODIRDRVH = A ODIRDRVI = A ODIRDRVJ = A ODIRDRVK = A ODIRDRVL = A ODIRDRVM = A ODIRDRVN = A ODIRDRVO = A ODIRDRVP = A ODTADRVA = A ODTADRVB = A ODTADRVC = A ODTADRVD = A ODTADRVE = A ODTADRVF = A ODTADRVG = A ODTADRVH = A ODTADRVI = A ODTADRVJ = A ODTADRVK = A ODTADRVL = A ODTADRVM = A ODTADRVN = A ODTADRVO = A ODTADRVP = A OVLYDIRA = Y OVLYDIRB = Y OVLYDIRC = Y OVLYDIRD = Y OVLYDIRE = Y OVLYDIRF = Y OVLYDIRG = Y OVLYDIRH = Y OVLYDIRI = Y OVLYDIRJ = Y OVLYDIRK = Y OVLYDIRL = Y OVLYDIRM 1EN ͍E %E͍ED͍EDʢDC͏D͕D!CE~# 4D͕D C͍E:Eg:EsD:E_Dg:EsD!]C~$oD#~B̩D1EɷW|g ͏D͕D%zD͍ED͍ED ͍EvCPM3 SYS CPMLDR error: failed to open CPM3.SYS $ CPMLDR error: failed to read CPM3.SYS $ CP/M V3.0 Loader Copyright (C) 1982, Digital Research $021182"LyڥE2L2L:L2L{2L!" G"L9"@F1F!NLy2EK!EEdڛJ_^#V*LFFFFFFFFFFFFFLLLFFFF;LFFFFALGLFFFFFFFFFFFFFFFFFFFFFFF:FžF Ny!L4 5~yµF5 6y ’F ͒F:LF!L OͻFFMDF2 G>F BDOS ERR: $Select$Perm.$FFF GFFGFv{_zW{_zW )8G# ?G w#JGJN|^#V###"L##"L######"L!L IG*L!LIG*L|!L6ʕG67N*Lw#w*Lw#w#w!L^#V#FͪG'NOGG*L&I!Ls#r#p*LN#F*L^#V#F*L:LO}|yH*L%G +V+^!KL>K!!Q!>:!>:!$>2:2 >G"z<2{2xJ!G>]PRS!,[<(+[!(= _M<,:2 P This version of EXCWTSYS will write boot, cpmldr, main font, SETUP override and ROM's RAM override only to dsdd disk in drive B $ System tracks aok $. $ Error reading $ Unable to open $ Error writing system tracks $ Error: cpmldr.com is too long $EXCBOOT COMCPMLDR COMFONTM COMROMRAM COMReservedReserved+G*L.G}|yH#H*L%G*LDM"LN*Ls#r*Ls#r#pyoxgkHDM*L0NMD"L!N*LMD$N:LO&I!LN:L yHG>O:L ʐHÇH*L͒H :LʨHn` ~#forH2LO͚H"L}:LO*L7G"L2L"L:LO:LG2L!Lw*L *LH!H~2L~2LH:L2LH:Lw:Lw |g}o'I )4I:LO!3Iyoxg:LO&I}*L:Lo$H~w{ozg ^#VG:LʏI>LÛI͡I"LGͳG*LçI*LrI"L!L~#O&IE:LIHN/*L"Ly2LʹI͗GͻIͫIʛJ*LXI:LO~JJyʔJx ʍJ ʂJJJÍJNIJJ# hJ2 GG>GF:JH~XI*L IGIOw!JxJ>Fwx2L2L~:L:L6:LJw2LH~O I!K>w:JͨJH2LF4IO.K5FJͿJKH:L!LSKFJ: GFͮHFH:LL͛IGͳGI:L< G=!LwW*LMI_SG G-*LMD:I"L:L2Lɯ2LK>G=O*L~~w#~2L~wcIH~K~p2L!"L>2L*L~=2LK~2L͛KoK>*Lw512B AUXIN 5126 AUXIST 5124 AUXOST 511F AUXOUT 5102 CBOOT 512B CONIN 5126 CONIST 5124 CONOST 511F CONOUT 511E DEVINI 5130 DEVTBL 4F1A DPBTBL 4EB6 DRVTBL 509E FLUSH 5090 HOME 511F LIST 5124 LISTST 5001 MOVE 50A0 MULTIO 4E65 PATCH 50E2 READ 5206 RVERS 50A9 SECTRN 50DC SELDSK 5059 SELMEM 508C SETBNK 5086 SETDMA 5098 SETSEC 5093 SETTRK 5157 SIGNON 5081 TIME 505C TOROM 5202 VERS 5102 WBOOT 4E03 WBOOT@ 50E7 WRITE 5050 XMOVE 4EDF DPH0 4F01 DPH1 5288 STDINI 52F4 STDRD 5289 STDSEL 52F9 STDWT 5084 DBANK 50FA DMABK 5085 KLUDGE 503C ROMMV 5083 SBANK 50F4 ACTCNT 50F0 DRIVE 511C STDERR 511C STDSEN 539F AREA0 511C STDNR P~#foR|:Q2P`(Q !2Q2P!O:Q#~ (<(#w#w s#r~#+2P! ~#fo+++~2P+~2QZR]:QGO(!P:P(82P!Qˎ:P+S:P2P*P"P!P4#5ES:PES#:PGS6!PJ2Q:P2M*P"K:PG&Pѷ(` :P !Q:Q Q !P6=!"L2L=2L!"LÛI͛KoK͢K͢J'LͫIH~<7Lw@ͩK7K:LF"LÛI:L~L:L2L:L~L*L6:LpLw#:LwH:Lw*@F* G}D>LI$*LL*LTM:L_2L{2L"LrI"L[MM?G,MdM>lM[MIG6:L<!=6M*LJM"L*LKN:LG/O*LL*LG=GdM##LIGQQ&Q+QQQQ+QÐPPÓPØPÆPPP$QéP$Q&Q$QîNQòNàPÞPPÁPYPÌPPP\PíNíNOPatchPatchPatchPatchPatchPatchPatchPatchPatch!0Q!NNORRRRORRRRORP  (? R-?&RR ? 8R$?AR?AR?AR?AR?AR?:P s12P*P| :PPBP"VP:P{![RûP!RûP ͌P*N9Qq#p#HQq#pɿ \P\P\PCRT SWOsborne Executive CP/M Plus BIOS V1.3 Copyright gG 1983 Osborne Computer Corporation Copyright gG 1984 Future Systems, 828 Nob Hill Avenue, Pinole, CA 94564 B            y2Pi&N) ~#fo"P+~2Q+~+ng{*P~#foR|:Q2P`(Q !2Q2P!O:Q#~ (<(#w#w s#r~#+2P! ~#fo+++~2P+~2QZR]:QGO(!P:P(82P!Qˎ:P+S:P2P*P"P!P4#5ES:PES#:PGS6!PJ2Q:P2M*P"K:PG&Pѷ(` :P !Q:Q Q !P6=Sb/#)\}ÀÅs8ÖDM>îòÍËnFy=IííPatchPatchPatchPatchPatchPatchPatchPatchPatch!m! J O  J O P  (? -?R ? $??????s1>o|}{!*2(2$!*G(G$!$&V"!P&e"!k CRT CEN MODEM PRNTR IEEE :r s1!:Q#~ (<(#w#w s#r~#+2! ~#fo+++~2+~2ZQ ]:GO(!:(82!ˎ: :2*"!4#5ʛ :› #:ʝ 6!J2:2M*"K:G&ѷ(` : !:Q  !6=!\" !T" !" ! " *"*"`:QO 2#!"J"K!"MZ q >2#:Q2Q!"J!"K!"MZ 2Q**R (! m!"[k!J*"[ !Q "  !^#V#z  !~#fo!/>=!\E #!   BIOS boot error reading disk. System reset required. EXECST COM:K<ͭͻ`O:KZ( ͭx!#'0^!@ͻͻ ͻx͖//:͖-/!J~͖#ͻ`( * :P(* ~(ͻi(w!~=:[ 22o*p| :p/"V)/*D:o2r{!pq#p#ts1W2ozl:o{C2Cy<2ɯy22i`{_ng{s12>:{! è! è {5> {5>F=!@>22!"*b":#k:"k>2"2V!"gG~# x©k!/ BIOS error: CCP.COM not present. System reset required. ,CCP COMALTFONT SYS:j(2j͍=! 2h2k!"|\\!(=!"Osborne Executive CP/M Plus BIOS V1.3 Copyright gG 1983 Osborne Computer Corporation Copyright gG 1984 Future Systems, 828 Nob Hill Avenue, Pinole, CA 94564 B           g.@"V!~PX!P&@o"VPXP)ͻͻbz<( 9(7ɷ͟ 80O/ͻ:A2!/!/S(bO  BIOS error selectreadwriting drive X: not ready or not formatted.BIOS error. not ready or buffer full, unassign this device (Y or N)? (Y or N)? Retry this operation^WARNING:q data on disk inserted may be destroyed. ContinueNoYesnot-readywrite-protectedfaultnot-foundcrc-errorlost-datadrqbusy  *4>B, )(code=)($I$I$I$I(@TU @$I$I$I( A@"H D "@ HA$ @" D@@@@H  """""""""""""""  @ "~#foGy_! ] Cq#p#w#wgoA!_ B ~O#~G![ BW(^#~<= #( N>̈́( >̈́y (j 8(~((>̈́:\ K(:_!K+|   *x0#xG7/w*~# $y 6ɴ0Kj =h&)))sf_ >ÄXajP=>̈́Gwa jn>] &h))^#V#Öñ#^! _~ʯ&o=h&)))tG~(Ox$> ͇( > ͇_! 68>~(<ðo&2R n&  CCCCCCCCCCCCCCCC ! KQNT?EBHy2i&) ~#fo"+~2+~+ng{*~#fo, |:2P`(h !22 !$H@@    @$@ !$ !  H!$ IH@ $A$" $$lectreadwriting drive X: not ready or not formatted.BIOS error. not ready or buffer full, unassign this device (Y or N)? (Y or N)? Retry this operation^WARNING:q data on disk inserted may be destroyed. ContinueNoYesnot-readywrite-protectedfaultnot-foundcrc-errorlost-datadrqbusy  *4>B, )(code=)($I$I$I$I(@TU @$I$I$I( A@"H D "@ HA$ @" D@@@@H  """""""""""""""  @025C AUXIN 024D AUXIST 023E AUXOST 0229 AUXOUT 03EF CBOOT 0262 CONIN 0253 CONIST 0244 CONOST 022F CONOUT 021D DEVINI 026D DEVTBL 011A DPBTBL 00B6 DRVTBL 038B FLUSH 037D HOME 0223 LIST 0238 LISTST 02EE MOVE 038D MULTIO 0065 PATCH 03CF READ 06AF RVERS 0396 SECTRN 03C9 SELDSK 0346 SELMEM 0379 SETBNK 0373 SETDMA 0385 SETSEC 0380 SETTRK 0600 SIGNON 036E TIME 0349 TOROM 06AB VERS 03FA WBOOT 0003 WBOOT@ 03D4 WRITE 033D XMOVE 00DF DPH0 0101 DPH1 0ADE STDINI 0B4A STDRD 0ADF STDSEL 0B4F STDWT FE26 @AIVEC FE28 @AOVEC FE22 @CIVEC FE24 @COVEC FE2A @LOVEC 0A5B DELAY 07CD DELAY0 0951 INITVE 084B OUTST 0E1A SERNR 0710 VECPTR 0371 DBANK 03E7 DMABK 0372 KLUDGE 0329 ROMMV 0370 SBANK 03E1 ACTCNT 03DD DRIVE 0D7F STDERR 0D68 STDSEN FE35 @BNKBF FE4B @ERMDE FE54 @MEDIA FE62 @MXTPA FE5C @SEC FE3C @CRDMA FE3E @CRDSK FE3F @VINFO FE41 @RESEL FE43 @FX FE44 @USRCD FE4A @MLTIO FE51 @ERDSK FE57 @BFLGS FE58 @DATE FE5A @HOUR FE5B @MIN @1:#2#:Qˏ2Q!BA>@@2QO !IA>!PA>@@:QO !WA!^A>@@K !:M2U#<  :QO(>!T=  !T . :NO  x :OO  :PO  e DJGZ!ANy(#  BIOS boot error reading disk. System reset required. DTT$D$ $I"B IIBB"$B@DH"$$ IH $$ !I"AD B!B  BI$A$"@$I$!!""@ _{ozg^#V) "^#V|g}o "_{ozgO{ozgi`N#Fogo&ogUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUð**(}+*(}+"(*(x+"(x+m+*(^#V*( s#r*(*(s#r*(:(Y+4Y+̓+*(*(~#ng+*( s#r ^#V|:(w:(ʴ+>2d,:+#++>29+2~2#! , , ,)x,) ,O +"!w [,O?WGzO:(V,xGyOG,xwq*}(}2*i(^#V+ d,!(K*}(@+*)):( K:(ڗ>2#-×:#-<)2#-*(BI$"" HB@ UUUUUUUUUUUUUUUUUAPDA$! @I !@D@BDI@!B$ @$I$$ "@$$@@HHBD"D$H D@!IB@ A"B HBIB$$ "$ D$!"D$H$D$I@D BD" H$BHHBDHB"H!" ͧ`녇P@#X^2i #:2e 0%sm?F-]X=,X=%-Ka0 (Iq@ ȱӰ hH)qՀ )հ O ȳZ: qX:.ӛi1m?[`rz 8GVf`AA, BC, HL, IX = Any necessary parameters ; ; EXIT All ROM exit parameters remain in tact ; torom: ld (savesp),sp ; save user's stack ld sp,comnsp ; pt to one in common ld d,a ; save a in a,(sys) ; get crnt bank ld (ubank),a ; save for later exit or 80h ; force into rom out (sys),a ; now ld a,d ; restore a ld d,01h ; de=01xxh call romjp ; off to the rom (via our code) push af ; save a and flags ld a,(ubank) ; incoming bank info out (sys),a ; restore bank now pop af ; all regs now restored ld sp,(savesp) ; and return ret ; with user's stack romjp: push de ; dummy up like a   !!""##$$%%&&''