Subttl -MD11 Cbios for CP/M 2.2 (Rev_0 21_Sept_1983) ; ; Copyright 1983 ; Morrow Designs, Inc. ; San Leandro, Ca. ; Last Update 21_Sept_83 ; ; .z80 ;Set switch for zilog nmenonics include HD11DEF.MAC ;Include the common defintions ;---------------------------------------------------------------------- ; System Equates ;--------------- ; ; Location Defintions ;-------------------- ; memsize equ 64 cpm equ (memsize-9)*1024 bdos equ cpm+806h bios equ cpm+1600h ; Rom Jump Table Definitions ;--------------------------- ; rom equ 0 msgrm equ rom+3 ;rom print signon message routine hmrm equ rom+6 ;rom home disk routine rdhsrm equ rom+9 ;rom read disk routine wrhsrm equ rom+0Ch ;rom write disk routine disrm equ rom+0Fh ;rom direct disk i/o routine bterm equ rom+18h ;rom print boot err routine romdatx equ rom+1Bh ;rom initial values for 'ramdatx' rdlsec equ rom+20h ;rom read a logical sector wrlsec equ rom+23h ;Rom write a logical sector ; I/O Port Definitions ;--------------------- ; s1stat equ 061h ;console status i/o port s1data equ 060h ;console data i/o port s2data equ 062h ;list status i/o port s2stat equ 063h ;list data i/o port page ; Bit Defintions for MTABs ;------------------------- ; sizmsk equ 03h ;isolate sector size in 'mtab' entry for drive dsm equ 2 ;double sided media bit in 'mtab' and disk parm ;... block from disk dpboff equ 10 ;offset into dph for dpb pointer ;rom Error return codes ;---------------------- ; nrdy equ 2 ;drive not ready bdfm equ 5 ;match failure page .phase bios ;---------------------------------------------------------------------- ; Bios Jump Table ;---------------- start: jp boot wbot: jp wboot jp const jp cnin ; jp cin$ ;*** cnout: jp cout ; jp cout$ ;*** jp lst jp pun jp ptr jp home jp seldsk jp settrk jp setsec jp setdma jp read jp write jp listst jp sectran jp cvmsg ;change virtual drive mesg. jp rdblk ;direct disk read jp wrblk ;direct disk wr jp discio ;direct disk i/o db rev dw ramdatx dw ramdaty dw mtab dw xltab etblptr:dw esctbl ctblptr:dw ctrltbl evctptr:dw escvect cvctptr:dw ctvect dw dcastrt page ;---------------------------------------------------------------------- ; WARM - Warm Boot ;----------------- ; wboot: ld sp,stack ld ix,ramdatX ld iy,ramdatY ld (ix+hstdsk),0 ;select drive a ld (ix+hsttrk),0 ;set track 0 ld (ix+hsttrk+1),0 ld (ix+hstsec),2 ;start at sector 2 ld (ix+hstsec+1),0 ;start at sector 2 ld (ix+hstbuf),0 ;Initialize the Disk_Buffer address ld (ix+hstbuf+1),high dskbuf ld bc,cpm ;Initialize the system load base addr. call setdma ;(set iy+dmaadr:= load base) rdlop: call rdhst ;Repeat Read the next sector of system ld a,(ix+erflag) ; If (error eq true) or a jp nz,bterr ; exit to rom ld hl,dskbuf ; HL:= Source (disk buffer) ld e,0 ld d,(iy+dmaadr+1) ; DE:= Destination (cpm) ld a,high (bios - 512) ; If (this is the last sector) cp d jr nz,notlst ld b,11111111b xor ($BANK2 or $XFER) ld c,00000000b or (000000 or $XFER) call wrtbnk ; Set the Transfer Bit ld bc,512 ; BC:= Length of transfer ldir ; move sector ld b,11111111b xor ($BANK2 or $XFER) ld c,00000000b or ($BANK2 or 00000) call wrtbnk ; Clear Transfer ld hl,cpm+3 jp gocpm ; setup low core, xeq cpm notlst: ld b,11111111b xor ($BANK2 or $XFER) ld c,00000000b or (000000 or $XFER) call wrtbnk ; Set the Transfer Bit ld bc,1024 ; BC:= Length of transfer ldir ; move sector ld b,11111111b xor ($XFER) ld c,00000000b or (00000) call wrtbnk ; Clear Transfer ld (iy+dmaadr+1),d ; Update Destination address ld a,(ix+hstsec) inc a ld (ix+hstsec),a ; Sector:= Sector + 1 cp 6 ; If (last sector on track) jp nz,rdlop ld (ix+hstsec),1 ; Sector:= 1 inc (ix+hsttrk) ; Track:= Track + 1 jp rdlop ;On Boot Error exit to the rom bterr: ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or (000000 or 0000000) call wrtbnk ;Enable the Rom and Bank 1 jp bterm page ;---------------------------------------------------------------------- ; GOCPM - Setup CPM's system variables and then enter the CCP ;------------------------------------------------------------ ; gocpm: push hl ld bc,80h call setdma ;Dma_Address:= 80h (default) ld a,0c3h ld (0),a ;Loc_0:= Jump ld hl,wbot ld (1),hl ;loc_1->2:= Base of BIOS + 3 ld (5),a ;Loc_5:= Jump ld hl,bdos ld (6),hl ;Loc_6->7:= Base of BDOS xor a ld (3),a ;Loc_3:= 0 ld hl,(vnumb) ld (8),hl ;Loc_8:= Version Number ld a,(iy+dflag) and 80h ;mask imsbuf flag (forget any dirty buffer) set ims,a ;activate ims ld (iy+dflag),a ld (iy+unacnt),0 ld a,(4) ld c,a ;get drive for ccp pop hl jp (hl) page ;---------------------------------------------------------------------- ; CONST - Get the Console input status ;------------------------------------- ; const: in a,(s1stat) ;console status routine bit 0,a ;see if rdy ld a,0 ret z ;return with 0 if not rdy ld a,0ffh ;return with ff if rdy ret ;---------------------------------------------------------------------- ; CONIN - Input a Character from the Console or the Submit Buffer ;---------------------------------------------------------------- ; cin$: ld a,(ramdaty+dflag) ;get dflag and 0c0h ;mask out ims flags cp 0c0h ;check if ims active jr z,submt ;jmp if submit active ;If not then fall through to cnin ;---------------------------------------------------------------------- ; CNIN - Input a Character from the Console ;------------------------------------------ ; cnin: in a,(s1stat) ;console input routine bit 0,a ;see if rdy jr z,cnin ;jmp if not rdy in a,(s1data) ;get character chret: and 7fh ;mask off parity ret page ;---------------------------------------------------------------------- ; In Memory Submit ;----------------- ; ; submt locates the submit string block within the bios ram area, ; the next character is taken from the buffer and passed to cp/m. ; the free block and submit string block pointers are updated. ; if this was the last character in the buffer, then the imsbuf ; bit in dflag is cleared. ; if the parity bit is set on the character, then the ims bit in ; dflag is cleared, which de-activates ims until the next warm ; boot. ; parity equ 7 submt: in a,(s1stat) ;see if char. ready bit 0,a jr z,subgo ;jmp if no input in a,(s1data) ;get char. cp 3 ;see if cntl-c jr nz,subgo ;jmp if not ld a,(ramdaty+dflag) ;de-activate ims res imsbuf,a ld (ramdaty+dflag),a ld a,18h ret subgo: ld hl,xltab ;pointer to ram area ld a,0ffh ;free space code call find ;find free space inc de ;update free space pointer ld (hl),d dec hl ld (hl),e add hl,de ;set hl ==> ims buffer inc hl inc hl ld e,(hl) ;update ims buffer header ld (hl),0fdh inc hl ld d,(hl) dec de ld (hl),e inc hl ld a,e ;see if last char. or d ld a,(ramdaty+dflag) jr nz,skp1 ;jmp if not last char. res imsbuf,a ;clear imsbuf flag skp1: bit parity,(hl) ;check parity bit of char. jr z,skp2 ;jmp if parity = 0 res ims,a ;de-activate ims skp2: ld (ramdaty+dflag),a ;save dflag ld a,(hl) ;get char. ld (hl),d ;finish updating ims block header jr chret ;return to cp/m ;---------------------------------------------------------------------- ; FIND - Find a block header ;--------------------------- ; find searches bios ram area starting from hl for the block ; header contained in a. ; find: cp (hl) ;see if header code matches inc hl ;increment pointer ld e,(hl) ;get offset to next block inc hl ld d,(hl) ret z ;return if block found inc hl ;set pointer to next block add hl,de jr find ;keep looking page ;---------------------------------------------------------------------- ; Console Output with escape sequence translation ;------------------------------------------------ ; ; on entry to xlate, register c contains the character to be output. ; a test is made to see if the system is in the process of outputing ; a multiple character escape sequence, or if the character is a ; morrow standars control code. if neither test is true, than the ; character is output. ; if the character is part of a multiple character escape sequence, ; then the character is passed to the escape routine. if the ; character is a mscc, then it is converted to the appropriate ; sequence, and output. ; esc equ 1bh cout$: ld a,(esc_lvl) ; test escape flag or a ; check if flag is set jr nz,escape ; if escape sequence, jump ld a,1fh ; test if mscc cp c jp c,cout ; if not, then xmit it ld a,esc ; check if esc char cp c jp nz,notesc ; if not, jump ld a,1 ; otherwise, set escape ld (esc_lvl),a ; level to 1st stage ret ; and return notesc: ld hl,(ctblptr) ; set to search control table call lookup ; and lookup character in table or a ; see if char found jp z,cout ; if not, output char ld hl,(cvctptr) ; calculate string location page ;---------------------------------------------------------------------- ; OUTSTR - Output a string of characters to the console ;------------------------------------------------------ ; ; this routine outputs a string of characters to the console. ; it is used by the translate program to output a terminal ; specific string in order to implement a control sequence. ; when entered, the hl register pair points to the base of ; the string table, and the bc register pair is the offset ; to the string. characters are output starting with the ; first character until a byte value of ffh is detected. ; outstr: add hl,bc ; add offset to base ld e,(hl) ; get location of string Š inc hl ld d,(hl) ex de,hl ; move address of string to hl loop: ld a,(hl) ; get a char cp 0ffh ; see if done ( ffh==>done) ret z ld c,a ; if not, get char call cout ; xmit it inc hl jr loop ; until end of string page ;---------------------------------------------------------------------- ; ESCAPE - Cursor - Escape_Sequence Translation ;---------------------------------------------- ; ; this routine is used to create a string for direct ; cursor addressing, or to translate character codes. ; upon receipt of an escape code from ; a program, the esc_lvl is set to indicate an escape ; sequence is being output. when the next character is ; received, it is tested to see if it is an equals sign (=). ; if it is not, than an escape character is output, followed ; by the character received. if the character is the equal sign, ; then two more characters will be accepted, after-which a string ; will be output for positioning the cursor. ; escape: ld a,(esc_lvl) ; get current escape level cp 1 ; level 1? jr z,seq1 ; then process 1st part cp 2 ; level 2? jr z,seq2 ; then process 2nd level jr seq3 ; it must be level 3 ; seq1: ld a,'=' ; equal sign? cp c ; if char is =, then dca started jr z,set ; else, could be character to xlate xor a ; clear escape level ld (esc_lvl),a ld hl,(etblptr) ; point to xlate table call lookup ; lookup character or a ; see if char found jr nz,down ; if found, jump to output push bc ld c,esc ; else, send escape, then char call cout ; send escape pop bc ; get original character jp cout ; send it down: ld hl,(evctptr) ; calculate string location jr outstr ; output the string set: ld a,2 ; otherwise, set for level 2 ld (esc_lvl),a ; processing ret ; and return seq2: ld a,c ld (first),a ; this is the first char ld a,3 ; set for level 3 ld (esc_lvl),a ret Š seq3: ld a,(offset2) ; get offset for 2nd char add a,c ; add to 2nd char ld (second),a ; save 2nd char ld a,0 ld (esc_lvl),a ; clear escape sequence ld de,first ; pointer to 1st char ld a,(de) ; get 1st char ld c,a ; save in c ld a,(offset1) ; get offset for 1st char add a,c ; add to 1st char ld (de),a ; save 1st char ld a,(order) push af rra sbc a,a ; 0==>1-2 : ff==>2-1 ld b,a ; save order in b ld a,e ; use order to adjust de sub b ld e,a ; de points to 1st char to output ld hl,dcastrt ; pointer to dca prefix sting call loop ; output string ld a,(de) ; get 1st char to output ld c,a pop af bit 1,a ; see if ascii push af call nz,ascout ; call ascii if nz call cout ; output char ld hl,dcamid ; pointer to seperator string call loop ; output string ld a,e ; use order to adjust de add a,b inc b add a,b ld e,a ; de points to 2nd char to output ld a,(de) ; get char to output ld c,a pop af call nz,ascout ; call ascii if flag set call cout ; output char outend: ld hl,dcaend ; point to dca terminator jp loop page ;---------------------------------------------------------------------- ; LOOKUP - Lookup a table ;------------------------ ; ; this routine is entered with the hl register pair pointing to ; the base of a table to be searched. register c contains the ; character to search for. upon return, the accumulator will ; contain 0 if the character was not found, and ffh if it was found. ; if the character was found in the table, then bc will contain ; the offset into the table, multiplied by 2. i.e bc / 2 = location Š; of character in table. the maximum number of values in the table is ; 20 h. ; lookup: ld b,0 ; init offset nmtch: ld a,(hl) ; get value from table cp 0ffh ; see if end of table jr z,nochar ; jmp if end cp c ; see if char matches jr z,mtch ; jmp if match inc hl ; inc table pointer inc b ; inc offset inc b ; " " jr nmtch ; continue search mtch: ld c,b ; put offset in bc ld b,0 ld a,0ffh ; set a to success ret nochar: xor a ; set a to failure ret page ;---------------------------------------------------------------------- ; ASCOUT - Output a byte in decimal ascii ;---------------------------------------- ; ; ascout takes a binary value in c and output its decimal ascii ; equivalent. ; ascout: push bc ld a,c ld c,'0' ;init to ascii 0 tens: sub 10 ;subtract 10 from value jr c,ones ;jmp if underflow inc c ;inc ascii tens value jr tens ;loop ones: ld b,a ;save intermediate value ld a,'0' ;a = ascii 0 cp c ;see if tens value is 0 call nz,cout ;output tens value if not 0 ld a,3ah ;ascii 0 plus 10 add a,b ;add to produce ones value pop bc ld c,a ;get ready for output ret page ;---------------------------------------------------------------------- ; COUT - Console Output ;---------------------- ; cout: in a,(s1stat) ;console output routine bit 2,a ;see if rdy jr z,cout ;jmp if not rdy ld a,c ;output character out (s1data),a ret ;---------------------------------------------------------------------- ; LST - List Output ;------------------ ; lst: call listst ; status of lstflg jr z,lst ; if not ready, loop over: ld a,c ; else, get char out (s2data),a ; xmit it ret ;---------------------------------------------------------------------- ; LISTST - Get the Status of the List Device ;------------------------------------------- ; 1) has xon/xoff protocol handler for micro decision cbios ; listst: call rdrstat ; get a character, or null cp 13h ; if xoff r'cvd... jr nz,nxtchk ; if not, check if xon xor a ; set flag to not rdy ld (lstflg),a ret ; return not rdy nxtchk: cp 11h ; if xon, then it might be ready jr nz,chkflg ; else, state not changing ld a,0ffh ld (lstflg),a ; set flag to rdy chkflg: ld a,(lstflg) ; get status flag lstret: or a ; set flags ret z ; if zero, then xoff pending in a,(s2stat) ; get status and 28h ; check if xmit ready (cts and dcd) cp 28h ld a,0 ; set not ready status jr nz,lstret ; jmp if not ready dec a ; set ready status ret ; and return it. page ;---------------------------------------------------------------------- ; RDRSTAT - Get the Reader Status (and the Character if its ready) ;----------------------------------------------------------------- ; rdrstat: in a,(s2stat) ; get status and 1 ret z ; return if no char in a,(s2data) ; else, get char and 7fh ; mask parity scf ; set flag ret ;---------------------------------------------------------------------- ; PTR - Get a character from the reader ;-------------------------------------- ; ptr: call rdrstat ;get status or char. jr nc,ptr ;loop if no char. ret pun equ lst ;Punch Device page ;---------------------------------------------------------------------- ; HOME - Home the Disk Heads ;--------------------------- home: call mstk ;fix stack push ix ;save ix & iy push iy ld ix,ramdatx ;init ix & iy ld iy,ramdaty ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or (000000 or 0000000) call wrtbnk ;Enable the Rom call hmrm ;call rom cretn: ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or ($BANK2 or $_RMENB) call wrtbnk ;Disable the Rom pop iy ;restore ix & iy pop ix pop hl ld sp,hl ;fix stack ret ;---------------------------------------------------------------------- ; MSTK - Move the stack pointer ;------------------------------ mstk: pop de ;save ret. addr. ld hl,0 ;get current stack add hl,sp ;in hl. ld sp,stack ;move stack push hl ;save old stack push de ;restore ret. addr. ret page ;---------------------------------------------------------------------- ; SELDSK - Select a disk ;----------------------- ; seldsk: ld a,4 ;check drive bound cp c jr c,bdrv ;jmp if bad bit 0,e ;see if first time jr nz,skpset ;jp if not first ld hl,ramdaty ;pointer to ramdaty ld a,c call gdsk1 ;get mtab pointer jp skpset ;force foreign drive for now ;---------------------- ; bit 7,(hl) ;see if foreign drive ; jr nz,skpset ;jp if foreign ; ; inc hl ; push hl ;save dskdef pointer ; push bc ; call getab ;read config table from diskette ; pop bc ; or a ;see if error ; jp nz,0 ;warm boot if error ; ;dsktb equ dskbuf+80h+25 ;check for valid table ; ld hl,dsktb ;pointer to end of table+1 ; ld b,25 ;count must be odd! ; ld e,0 ;init 0-check byte ; ; acc is 0 already ;chklp: dec hl ;dec pointer ; xor (hl) ;x-or table value into parity check byte ; ld d,a ;save parity check byte ; or e ;or in 0-check byte ; ld e,a ;save 0-check byte ; ld a,d ;restore pariy check byte ; djnz chklp ;dec table length & loop til done ; inc hl ;hl=>dskdef1 ; ; or a ;a=0 if table ok ; ld a,e ;a = 0-check byte ; ld de,sdpb ;pointer to s.s. dpb ; jr nz,sside ;assume s.s. if invalid table ; ; or a ;check 0-check byte ; jr z,sside ;invalid table if zero ; ;dsktdb equ dskbuf+80h+9 ; ld de,dsktdb ;pointer to dpb in boot ; ; bit dsm,(hl) ;see if d.s. media ; jr z,sside ;jp if s.s. ; ; pop hl ;get dskdef pointer ; set dsm,(hl) ;set for d.s. media ; jr dside ; ;sside: pop hl ; res dsm,(hl) ;set for s.s. media ;dside: xor a ;set z flag ;------------------------- skpst1: ld a,c ;set drive ld (sekdsk+ramdaty),a ld h,0 ;calc. dph address ld l,c add hl,hl add hl,hl add hl,hl add hl,hl ;get drive times 16 ld bc,dpbase add hl,bc ;hl=dph address push hl ;save dph address push de ;save new dpb pointer ld de,dpboff ;offset to dpb address add hl,de ;get pointer to dpb address ld e,(hl) inc hl ld d,(hl) ;de points to dpb pop hl ;restore new dpb pointer push de ;save curr dpb pointer ; ; jr nz,notab ;skip if no dpb update ; ; ld bc,15 ; ldir ;update dpb ; notab: pop hl ;restore curr dpb pointer ld a,(hl) ;get sectors per track ld (sectrk+ramdaty),a ;save in ramdaty inc hl ;inc pointer inc hl ld a,8 ;get records per alloc. block bit 2,(hl) ;check for block shift = 4 jr z,k1 ;jmp if 1k blocks ld a,16 ;2k value bit 0,(hl) ;check for block shift = 5 jr z,k1 ;skip if 2k blocks ld a,32 ;4k value for hard disk k1: ld (unamax+ramdaty),a ;save in ramdaty pop hl ;restore dph address ret ret skpset: or 0ffh ;clear z flag jr skpst1 ; Bad Drive bdrv: ld hl,4 ;return error code and ld (hl),h ;set to drive a. ld l,h ret page ;---------------------------------------------------------------------- ; Set the Track Number ;--------------------- ; settrk: ld (sektrk+ramdaty),bc ;set track in ramdaty ret ;---------------------------------------------------------------------- ; Set the Sector Number ;---------------------- ; setsec: ld (seksec+ramdaty),bc ;set sector in ramdaty ret ;---------------------------------------------------------------------- ; Set the DMA Address ;-------------------- ; setdma: ld (dmaadr+ramdaty),bc ;set dma address in ramdaty ret page ;---------------------------------------------------------------------- ; Read a Sector ;-------------- ; read: call mstk ;fix the stack push ix ;save ix & iy push iy ld ix,ramdatx ;init ix & iy ld iy,ramdaty ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or (000000 or 0000000) call wrtbnk ;Enable the Rom and select Bank 1 call rdlsec ;read a logical sector jp rwmove ;move data ;---------------------------------------------------------------------- ; Write a Sector ;--------------- ; write: call mstk ;fix the stack push ix ;save ix & iy push iy ld ix,ramdatx ;init ix & iy ld iy,ramdaty ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or (000000 or 0000000) call wrtbnk ;Enable the Rom and select Bank 1 call wrlsec ;write a logical sector rwmove: push af ;Save error code call wrtbnk ;Enable the Rom (BC set in the Rom) pop af or a ;set flags on acc jp nz,diret ;jump if error during read or write ld b,11111111b xor ($XFER) ld c,00000000b or ($XFER) call wrtbnk ;Set the Transfer Bit ld bc,128 ;BC:= Length of transfer ldir ;move sector ld b,11111111b xor ($XFER) ld c,00000000b or (00000) call wrtbnk ;Clear Transfer ld a,(iy+wrtype) ;check if dir write cp wrdir ld a,0 ;a=no error status in case we're done jp nz,diret ;jmp if not dir write res hstwrt,(iy+dflag) ;clear write flag call wrthst ;write buffer diret: push af ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or ($BANK2 or $_RMENB) call wrtbnk ;Disable Transfer and Select Bank-2 pop af pop iy ;restore ix & iy pop ix pop hl ;restore stack ld sp,hl cp bdfm ;see if unreadable jp z,bdrv ;jmp if unreadable cp nrdy ;see if not ready jp z,bdrv ;jmp if not ready ret page ;----------------------------------------------------------------------- ; GETAB - Read the Media Table from the current drive's boot sector ;------------------------------------------------------------------ getab: call mstk ;fix stack push ix push iy push bc ld ix,ramdatx ld iy,ramdaty xor a bit hstwrt,(iy+dflag) call nz,wrthst res hstwrt,(iy+dflag) res hstact,(iy+dflag) pop bc or a ;see if error jr nz,diret ld (ix+hstdsk),c ;set ramdatx to read boot sector ld (ix+hsttrk),0 ld (ix+hsttrk+1),0 ld (ix+hstsec),1 call rdhst ;read boot sector jr diret page ;---------------------------------------------------------------------- ; SECTRAN - Perform Sector Translation ;------------------------------------- ; sectran:ld l,c ;hl=bc ld h,b inc hl ;start sectors at 1 ld a,d ;see if xlat table or e ret z ;return if no xlat ex de,hl ;hl=xlt add hl,bc ;add to table ld l,(hl) ;get xlated sector ld h,0 ret ;---------------------------------------------------------------------- ; Write Host ;----------- ; wrthst: ld b,11111111b xor ($_RMENB or $BANK2) ld c,00000000b or (0000000 or 000000) call wrtbnk ;Enable the Rom and select Bank 1 call wrhsrm ;call the rom jr hstret ;return ;---------------------------------------------------------------------- ; Read Host ;---------- ; rdhst: ld b,11111111b xor ($_RMENB or $BANK2) ld c,00000000b or (0000000 or 000000) call wrtbnk ;Enable the Rom and select Bank 1 call rdhsrm ;call rom hstret: ld b,11111111b xor ($_RMENB or $BANK2) ld c,00000000b or ($_RMENB or $BANK2) call wrtbnk ;DisAble the Rom and select Bank 2 ld a,(ix+erflag) ;get status ret page ;---------------------------------------------------------------------- ; Read a Block ;------------- ; rdblk: ld (ix+erflag),0 ;clear error flag ld iy,ramdaty ;init iy call mstk ;fix the stack call rdhst ;call rom jr dret ;---------------------------------------------------------------------- ; Write a block ;-------------- ; wrblk: ld (ix+erflag),0 ;clear error flag ld iy,ramdaty ;init iy call mstk ;fix stack call wrthst ;call rom jr dret dret: pop hl ;restore the stack ld sp,hl ret ;---------------------------------------------------------------------- ; Disk I/O ;--------- ; discio: ld (ix+erflag),0 ;clear error flag ld iy,ramdaty call mstk ;fix the stack ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or (000000 or 0000000) call wrtbnk ;Enable the Rom call disrm ;call the rom ld b,11111111b xor ($BANK2 or $_RMENB) ld c,00000000b or ($BANK2 or $_RMENB) call wrtbnk ;DisAble the Rom ld a,(ix+erflag) jr dret ;return ;---------------------------------------------------------------------- ; GDSK - Get a Pointer to the Current MTAB ;----------------------------------------- ; gdsk: push iy ;get iy into hl pop hl gdsk1: ld de,mtoff ;calc. mtab pointer add hl,de ld e,a ;multiply drive by 16 rlca rlca rlca rlca ld e,a ;add (16 * drive) to pointer add hl,de ret ;---------------------------------------------------------------------- ; wrtbnk - Write to the Bank Register (12_Sept_83) ;------------------------------------------------- ; 1) This is the common routine for seting or clearing bits in the ; Bank Strobe register. ; 2) Notice that the IY area (ramdatY) must be initialized before ; this routine is used. ; 3) Register Usage: ; A -> General purpose ; B -> Mask to clear the selected bit (i.e. NOT-bit) ; C -> Mask to set the bit (i.e. 0=clear bit, otherwise set bit) ; IY -> Pointer to ramdatY ; 5) Example: to set bit 3; B=11110111b, C=00001000b A=Don't Care ; wrtbnk: ld a,(iy+cpybnk) ;A:= Current bank strobe contents and b ;(remove the selected bit) or c ;(set/clear the selected bit) ld (iy+cpybnk),a ;Save the new contents out (bnkstb),a ret ;---------------------------------------------------------------------- ; CVMSG - Change the Virtual Drive Message ;----------------------------------------- ; ; cvmsg is a routine to change the virtual drive message. ; on entry: hl points to the begining of the new message. ; de points to the location of the character ; which will be set to the logical drive ; that the virtual drive is to become. ; bc is the length of the new message. ; ; af,bc,de,hl are changed, all other regs. are unchanged. ; cvmsg: push hl ex de,hl xor a sbc hl,de ld de,vmsg add hl,de ld (vdrvp+ramdaty),hl pop hl ldir ret page vnumb: db 3 ; # of physical drives - 1 tlev: db 0 ; terminal level ;---------------------------------------------------------------------- ; disk parameter headers ;----------------------- ; dpbase equ $ ;First Floppy Drive dpe0: dw xlt1k dw 0 dw 0 dw 0 dw dirbuf dw dpb0 dw csv0 dw alv0 ;Second Floppy Drive dpe1: dw xlt1k dw 0 dw 0 dw 0 dw dirbuf dw dpb0 dw csv1 dw alv1 ;First Hard Disk dpe2: dw 0 dw 0 dw 0 dw 0 dw dirbuf dw dpb1 dw 0 dw alv2 ;Second Hard Disk dpe3: dw 0 dw 0 dw 0 dw 0 dw dirbuf dw dpb2 dw 0 dw alv3 page ;---------------------------------------------------------------------- ; Disk Parameter Blocks ;---------------------- ; ; floppy disk parameter blocks ;----------------------------- ; ;single sided disk sdpb: dw 40 db 4 db 15 db 1 dw 94 dw 127 db 0c0h db 0 dw 32 dw 2 ;double sided dpb0: dw 40 db 4 db 15 db 1 dw 194 dw 191 db 0e0h db 0 dw 48 dw 2 ; hard disk parameter blocks ;--------------------------- ; ;8 meg drive b dpb1: dw 288 db 5 db 31 db 1 dw 2047 dw 1023 db 0ffh db 0ffh dw 0 dw 1 ;remainder in drive c dpb2: dw 288 db 5 db 31 db 1 dw 692 dw 1023 db 0ffh db 0ffh dw 0 dw 229 page ;---------------------------------------------------------------------- ; Default IX area (13_Sept_83) ;----------------------------- ; ramdatX:db 0 ;(HSTDRV) BDOS Drive Number (1st floppy) dw 0000 ;(HSTTRK) Desired Cylinder (lo) ; Desired Cylinder (hi) dw 1 ;(HSTSEC) Desired Sector (lo) ; Desired Sector (hi) db 0 ;(SECCNT) Spare (Multi-Sector Transfer) db 20 ;(RETRY) Retry Count dw dskbuf ;(HSTBUF) Buffer Address (l) ; Buffer Address (m) db 0 ;(ERFLAG) Error Code dw 0 ;(PHYTRK) Physical track number (lo) ; Physical track number (hi) db 0 ;(PHYHD) Desired Head db 2 ;(PHYDRV) Physical Drive Number dw 0 ;(IOADD) Execution Address iyoff equ $-ramdatY ;Offset to start of IY area page ;---------------------------------------------------------------------- ; Default IY area (13_Sept_83) ;----------------------------- ; ramdatY:db 0 ;(SEKDSK) BDOS disk number dw 0 ;(SEKTRK) BDOS track number ; dw 0 ;(SEKSEC) BDOS sector number ; dw 0 ;(SEKHST) Actual sector number on the disk ; db 0 ;(UNACNT) Unallocated record count db 0 ;(UNADSK) Unallocated disk number dw 0 ;(UNATRK) Unallocated track number ; dw 0 ;(UNASEC) Unallocated sector number ; db 0 ;(UNAMAX) Sectors per Unallocated block dw 0 ;(SECTRK) Sectors per track ; db 0 ;(WRTYPE) Write type db 0 ;(DFLAG) Flag Byte db 0 ;(TRSEC) Offset to logical sector within physical sector dw 0 ;(VMSGP) Pointer to virtual drive message ; dw 0 ;(VDRVP) Pointer to virtual drive in message ; db 0FFh ;(CDSK) Current drive db 0 ;(VDSK) Current virtual drive dw 0 ;(DMAADR) BDOS DMA address ; dw cout$ ;(CONOUT) Pointer to Current console output device ; dw cin$ ;(CONIN) Pointer to Current console input device ; db $BANK2 ;(CPYBNK) Copy of the bank strobe register mtoff equ $-ramdaty ;Offset to MTABs from start of ramdatY page ;---------------------------------------------------------------------- ; Ram MTABs (13_Sept_83) ;----------------------- ; ;Drive 1 MTAB (Standard 5.25" Drive) db 10100100b ;(DSKDEF0) 1st 5" drive, virtual drive db 00100011b ;(DSKDEF1) double density, 1024bytes dw 0FFFFh ;(CRNCYL) Current Cylinder (lo) ; Current Cylinder (hi) dw 40 ;(MAXCYL) Max Cylinders (lo) ; Max Cylinders (hi) db 7 ;(STPRAT) Step Rate (3ms) db 7 ;(STPSET) Settling Time (15ms) db 7 ;(STPRCL) Recal Step Rate (3ms) db 0 ;(HLDDLY) Head Load time (0) db 500/3 ;(MOTDLY) Motor On time (1/2 sec) dw 23 ;(STRPRE) Start Write Pre-Comp (lo) ; Start Write Pre-Comp (hi) dw 0FFFFh ;(STRLOC) Start Lo-Current (lo) ; Start Lo-Current (hi) db 0 ;(FMTTYP) Format Type ;Drive 2 MTAB (Standard 5.25" Drive) db 00100101b ;(DSKDEF0) 2nd 5" drive db 00100011b ;(DSKDEF1) double density, 1024bytes dw 0FFFFh ;(CRNCYL) Current Cylinder (lo) ; Current Cylinder (hi) dw 40 ;(MAXCYL) Max Cylinders (lo) ; Max Cylinders (hi) db 7 ;(STPRAT) Step Rate (3ms) db 7 ;(STPSET) Settling Time (15ms) db 7 ;(STPRCL) Recal Step Rate (3ms) db 0 ;(HLDDLY) Head Load time (0) db 500/3 ;(MOTDLY) Motor On time (1/2 sec) dw 23 ;(STRPRE) Start Write Pre-Comp (lo) ; Start Write Pre-Comp (hi) dw 0FFFFh ;(STRLOC) Start Lo-Current (lo) ; Start Lo-Current (hi) db 0 ;(FMTTYP) Format Type page ;Drive 3 MTAB (Seagate st506) db 01001110b ;(DSKDEF0) Ready_Line hard_disk-1 db 01100011b ;(DSKDEF1) Not applicable dw 0FFFFh ;(CRNCYL) Current Cylinder (lo) ; Current Cylinder (hi) dw 153 ;(MAXCYL) Max Cylinders (lo) ; Max Cylinders (hi) db 1 ;(STPRAT) Step Rate (3ms) db 5 ;(STPSET) Settling Time (15ms) db 1 ;(STPRCL) Recal Step Rate (3ms) db 0 ;(HLDDLY) Head Load time (0) db 0 ;(MOTDLY) Motor On time (0) dw 128 ;(STRPRE) Start Write Pre-Comp (lo) ; Start Write Pre-Comp (hi) dw 128 ;(STRLOC) Start Lo-Current (lo) ; Start Lo-Current (hi) db 0 ;(FMTTYP) Format Type ;Drive 4 MTAB (Seagate st506) db 01001111b ;(DSKDEF0) Ready_Line hard_disk-1 db 01100011b ;(DSKDEF1) Not applicable dw 0FFFFh ;(CRNCYL) Current Cylinder (lo) ; Current Cylinder (hi) dw 153 ;(MAXCYL) Max Cylinders (lo) ; Max Cylinders (hi) db 1 ;(STPRAT) Step Rate (3ms) db 5 ;(STPSET) Settling Time (15ms) db 1 ;(STPRCL) Recal Step Rate (3ms) db 0 ;(HLDDLY) Head Load time (0) db 0 ;(MOTDLY) Motor On time (0) dw 128 ;(STRPRE) Start Write Pre-Comp (lo) ; Start Write Pre-Comp (hi) dw 128 ;(STRLOC) Start Lo-Current (lo) ; Start Lo-Current (hi) db 0 ;(FMTTYP) Format Type datlng equ $-ramdatX page ;---------------------------------------------------------------------- ; Space for the Directory Buffer ;------------------------------- ; dirbuf: ds 128 ;---------------------------------------------------------------------- ; Messages Escape Strings and Misc ;--------------------------------- ; vmsgº db cr,lf,'your lower drive is being re-assigned as drive ' vdrv: db 'a.',cr,lf,'exchange diskettes and press [return]',0 lstflg: db 0ffh ; printer ready flag dcastrtº äb 1bh,3dh,0ffh » dcá prefiø string Š ds 3,0ffh dcamid: ds 6,0ffh ; dca seperator dcaend: ds 6,0ffh ; dca terminator string esc_lvlº äb 0 ;indicateó esã sequencå level offset1: db 0 ;first character offset offset2: db 0 ;second character offset order: db 1 ;bit 0 = 0 --> row, then column, ; = 1 --> column, then row ;bit 1 = 0 --> binary cursor adresses ; 1 --> ascii cursor addresses first: db 0 ; temporary storage of first second: db 0 ; temporary storage of second xltab: db 0 dw 40 xlt1k: db 1,2,3,4,5,6,7,8 db 25,26,27,28,29,30,31,32 db 9,10,11,12,13,14,15,16 db 33,34,35,36,37,38,39,40 db 17,18,19,20,21,22,23,24 db 0feh ; console xlt table dw clen esctbl: db 0ffh ctrltbl:db 0ffh escvect:dw 0 ctvect: dw 0 page ; translation strings for the terminal go here ;--------------------------------------------- ; clen equ $-esctbl db 0ffh ;eot dw bios+0800h-$-57 ;space for more xlt's ds (bios+0800h-$-55),0 db 0FDh ;ims buffer header dw 0 page ;---------------------------------------------------------------------- ; Allocation and Checksum Vectors ;-------------------------------- ; ;First Floppy Disk alv0 equ $ ;ds 25 csv0 equ alv0 + 25 ;ds 48 ;Second Floppy Disk alv1 equ csv0 + 48 ;ds 25 csv1 equ alv1 + 25 ;ds 48 ;First Hard Disk alv2 equ csv1 + 48 ;ds 256 ;Second Hard Disk alv3 equ alv2 + 256 ;ds 87 endbios equ alv3 + 87 ;top of bios in memory ;---------------------------------------------------------------------- ;boot time data residing in uninitialized data areas ;--------------------------------------------------- ; signon: db 0dh,0ah,'hd1 -- 64k CP/M Vers. 2.2 -- Rev. ' db ((rev and 0f0h) shr 4)+asc0,'.',(rev and 0fh)+asc0 db cr,lf db "Copyright '76,'77,'78,'79,'80 Digital Research, Inc." db cr,lf db 'Copyright 1982,1983 Morrow Designs, Inc.' db cr,lf,lf db '************** double sided system **************' db cr,lf,0 ;---------------------------------------------------------------------- ;cold boot entry from 1 sector disk boot ;--------------------------------------- ; boot: ld sp,stack ld iy,ramdaty ld de,signon ld b,11111111b xor ($_RMENB) ld c,00000000b or (0000000) call wrtbnk ;Enable the Rom call msgrm ;print signon ld b,11111111b xor ($_RMENB) ld c,00000000b or ($_RMENB) call wrtbnk ;DisAble the Rom xor a ld (3),a ld (4),a ;Set the default drive for gocpm ld (iy+dflag),0 ld hl,cpm jp gocpm end