Title Force an MsDos Disk Foreign Drive B: (16_Oct_84) ; ; Copyright 1982,1983,1984 ; Morrow Designs, Inc. ; San Leandro, Ca ; John Zalabak ; .z80 aseg org 100h ;---------------------------------------------------------------------- ; Index: Foreign (16_Oct_84) ;--------------------------- ; ; Begin_Foreign Main Line of Foreign Drive Routine ; ; Install_Xlt Install the translate table for this drive ; Enter_Xlt Enter a new translation table into the free space ; Install_Dph Install the Xlt pointer in the Dph ; Install_Dpb OverLay the current drive's Dpb ; Get_Pointer Get a Pointer into the current data structure ; Install_Mtab Update the drive's MTAB ; ; Get_Buffer Move system memory into the local buffer ; Put_Buffer Put the Local Buffer into System Memory ; Extended_Bios Call the Bios Cold Boot Entry Point ; ; Message Strings ; Data Areas page 60 ;---------------------------------------------------------------------- ; Local Equates (15_Oct_84) ;-------------------------- ; ;Bdos Functions Bdos_Entry equ 5 ;Bdos Entry Location Bdos_PString equ 9 ;Print a String ;Bios Entry Definitions Bios_Entry equ 0 ;Bios Entry Location EB_Write_Sys equ 1 ;Write to System Memory EB_Get_Mtabs equ 3 ;Get the System Mtabs EB_Get_DPHs equ 4 ;Get the System's Dphs EB_Get_DPBs equ 5 ;Get the System's Dpbs EB_Get_Char_Tbl equ 6 ;Get the Character Table EB_Get_Free equ 8 ;Get the Free Space Pool EB_Execute equ 14 ;Execute in the System Bank ;Length Definitions Dpb_Length equ 15 ;Define the length of a DPB ;Offset Definitions SelDsk_Offset equ 9 * 3 ;" SelDsk " " " " " MftOff equ 14 ;format type in MTAB from dskdef1 ;MTAB's Dskdef0 Mask Bytes $DEF0 equ 11111111b xor ($FRGN or $SECZRO or $DBLMED) $FRGN equ 01000000b ;Drive is Foreign (Not Morrow) $SECZRO equ 00100000b ;Sectors Start w/Sector 0 not 1 $DBLMED equ 00000100b ;Double Sided Media $HRDDSK equ 00000010b ;Hard Disk (used in drive selection) ;MTAB's Dskdef1 Mask Bytes $DEF1 equ 11111111b xor ($DRVDEN or $128 or $256 or $512 or $1024) $DRVDEN equ 00100000b ;Double Density Media $128 equ 00000000b ;128 Bytes per Sector $256 equ 00000001b ;256 Bytes per Sector $512 equ 00000010b ;512 Bytes per Sector $1024 equ 00000011b ;1024 Bytes per Sector ;Translation Table Code ib2cod equ 9 ;MsDos Ibm Code ;Ascii Character Equates Control_C equ 3 ;Control C (Cp/m warm boot) BackSpace equ 8 ;Back Space one Character Tab equ 9 ;Tab Cr equ 0Dh ;Carriage Return Lf equ 0Ah ;Line Feed Esc equ 1Bh ;Escape Bright equ '(' ;Set High Lighting Mode Dim equ ')' ;Set Low Lighting Mode page ;---------------------------------------------------------------------- ; Main Line of Foreign Drive Routine (15_Oct_84) ;----------------------------------------------- ; Begin_Foreign: ld sp,Local_Stack ;(local stack's at end of local buffer) call Install_Xlt ;Get the translate table for this drive or a ;If (Translate Table was Installed) jr nz,Quit call Install_Dph ; Install xlt pointer in the dph call Install_Dpb ; Overlay the Dpb call Install_Mtab ; Update the drive's MTAB ld a,0 Quit: jp Bios_Entry ;Warm Boot page ;---------------------------------------------------------------------- ; Install the translate table for this drive (4_Jan_84) ;------------------------------------------------------ ; 1) Drives with no translation tables return Immediately (with accm=0). ; 2) If the table was found or successfully installed then the accm is ; returned equal to zero. ; 3) If there was insufficient room in the table for the new translate ; table or the program failed to find a native drive then the accm ; is returned non-zero. ; 4) Register Usage: ; A -> General Purpose ; BC -> Length for moves ; DE -> Pointer to Xtl - 1 ; HL -> Pointer into free space ; Install_Xlt: ld de,(xltlen) ;If (the drive has NO translate table) ld a,d or e ret z ; Return (status 0 = ok) ld a,EB_Get_Free ; A:= Function_8 (get free space) call Get_Buffer ; HL:= Pointer to Start Free Space ;Search for a matching xlt or the end of the free space nomtch: ld a,(xlt) ;Loop A:= xlt code in template cp (hl) ; If (table header MATCHES xlt code) jp nz,skip1 ex de,hl ; DE:= Start of Xtl inc de inc de ; (use matching xlt table) jr SXout ; Goto get xtl address skip1: ld a,0FFh ; A:= End of Table code cp (hl) ; If (entry type eq EOT) jr nz,skip3 ld a,(dsk0) ; If (drive eq foreign) and $FRGN jr nz,skip2 ld de,MisTbl ; DE:= error message ld c,Bdos_PString ; (bdos print string function) call Bdos_Entry ; BDOS Print String Function Fatalº jð Fataì » Hang: Fataì Error ;Enter the Translate table into the free space pool skip2: call Enter_Xlt ; enter the new xlt table or a ; If (entry could not be made) ret nz ; Return (error) ;Generate the System's address for the new translate table SXout: inc de ex de,hl ; HL:= Start of Xtl in loc buf ld de,Local_Buffer ; DE:= Start of Local Buffer or a ; (clear the carry) sbc hl,de ; HL:= Offset from start Loc Buf ld de,(Save_DE) ; DE:= Start of system free space add hl,de ; HL:= Pointer to xtl in free space ld (Save_DPH),hl ; Save Xlt Pointer call Put_Buffer ; ReWrite free space to sys mem ld a,0 ret ; Return (no error) ;Move the pointer to the start of the next entry skip3: inc hl ; get length of this xlt table ld e,(hl) ; and add it to the pointer. inc hl ld d,(hl) inc hl add hl,de jp nomtch ; (look at next xlt) page ;---------------------------------------------------------------------- ; Enter a new translation table into the free space (7_Nov_83) ;------------------------------------------------------------- ; 1) This routine is only used by the getxlt routine. ; 2) If the table was successfully installed then the DE register ; pair is returned pointing to the start of the table - 1 and the ; accm is returned zero. ; 3) If there wasn't enough room in the table then the DE register ; pair is returned pointing to the start of the error message and ; accm is returned non-zero. ; 4) Register Usage: ; A -> General Purpose, returned non-zero for error ; BC -> Used to hold offsets ; DE -> Temp data storage, returned with pointer to xlt or error ; HL -> Data pointer, enter with HL pointing at type byte ; Enter_Xlt: inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl ;HL:= Space Remaining push de ;DE:= Start of Xtl Pointer - 1 ;Check if the xlt will fit ld bc,(xltlen) ;BC:= length of table inc bc inc bc inc bc ;(include type byte and length word) xor a ;(clear carry) sbc hl,bc ;If (space insufficient) jr nc,NewSkp ld c,Bdos_PString ; (bdos print string function) ld de,Nosp ; DE:= out of space message call Bdos_Entry ; BDOS Print String Function ld a,0FFh ; A:= error return status jr NewErr ; GOTO error return ;Copy the new xlt into the free space (type, leng-lo, leng-hi, table..) NewSkp: push hl ;(save space remaining) ld hl,xlt ;HL:= new xlt table pntr. dec de ;(DE overlays current end of table entry) dec de ;DE:= Pointer to Xtl in free space ldir ;move xlt pop hl ;(hl=space remaining) ;Setup new EOT entry (type, space_remaining-lo, space_remaining-hi) ex de,hl ;DE:= remaining space ld (hl),0FFh ;put eot code at end of table inc hl ld (hl),e ;put space left at end of table inc hl ld (hl),d ld a,0 ;A:= Successful Completion NewErr: pop de ;DE:= xlt-1 pointer ret ;Return page ;---------------------------------------------------------------------- ; Install the Xlt pointer in the Dph (5_Jan_84) ;---------------------------------------------- ; Install_Dph: ld a,EB_Get_DPHs ;A:= Get the System's Dphs Function (4) call Get_Pointer ;HL:= Pointer to start of Dph ld de,(xltlen) ;If (the drive has a translate table) ld a,e or e jr z,setsk1 ld de,(Save_DPH) ;DE:= Xtl Pointer SetSk1: ld (hl),e inc hl ld (hl),d call Put_Buffer ;Restore the Dph Buffer ret ;---------------------------------------------------------------------- ; OverLay the current drive's Dpb (5_Jan_84) ;------------------------------------------- ; Install_Dpb: ld a,EB_Get_DPBs ;A:= Get the System's Dpbs Function (5) call Get_Pointer ;HL:= Pointer to start of Dpb ex de,hl ;DE:= Start of Current Dph ld hl,dpb ;HL:= pointer to new Dpb ld bc,Dpb_Length ;BC:= length of Dpb ldir ;replace Dpb call Put_Buffer ;ReWrite the Dpb Buffer ret ;---------------------------------------------------------------------- ; Get a Pointer into the current data structure (5_Jan_84) ;--------------------------------------------------------- ; 1) This routine (used only by GetDph and GetDpb) returns the ; HL register pair pointing to the start of the current Dpb/Dph ; in the local buffer ; 2) Notice that a function number is passed in the accm: ; 4 - Get System Dphs ; 5 - Get System Dpbs ; Get_Pointer: call Get_Buffer ;Fill Local Buffer (function 4 or 5) ld hl,Local_Buffer ld de,(Save_Drive) ;DE:= Drive Number (0-15) rlc e ld d,0 ;multiply drive number by 2 add hl,de ;HL:= Pointer to pointer to Dpb/Dph ld e,(hl) inc hl ld d,(hl) ex de,hl ;HL:= Pointer to Dpb/Dph in sys mem ld de,(Save_DE) ;DE:= Start of system buffer xor a ;(Clear the carry) sbc hl,de ;HL:= Offset to start of Dpb/Dph ld de,Local_Buffer add hl,de ;HL:= Pointer to Dpb/Dph in loc buf ret page ;---------------------------------------------------------------------- ; Update the drive's MTAB (4_Jan_83) ;----------------------------------- ; 1) This routine updates the disk definition bytes in the current ; drive's MTAB. ; 2) The first byte of the MTAB is dskdef0. It contains flags for ; 1) Foreign Drive ($FRGN bit 6) ; 2) Sector Numbering Starting with Sector 0 (SECZRO bit 5) ; 3) Double Sided Media (DBLMED bit 2) ; 3) The second byte of the MTAB is dskdef1. It contains flags for ; 1) Double Density Media (DRVDEN bit 5) ; 2) Sector Size Code ($128, $256, $512 and $1024 in bits 0 & 1) ; 4) Register Usage: ; A -> General Purpose ; BC -> General Purpose ; HL -> Pointer ; Install_Mtab: ld a,EB_Get_Mtabs ;A:= Function_3 (get mtabs) call Get_Buffer ;HL:= Start of Mtabs ld bc,(Save_Drive) ;BC:= Drive Number (0-15) call Set_HL_to_Mtab ;HL:= Pointer to Drive's Mtab ;Update dskdef0 ld a,(hl) ;A:= dskdef0 for this drive and $DEF0 ;Remove bits that're (potentially) set ld b,a ld a,(dsk0) ;B:= dskdef0 for this media or b ld (hl),a ;set dskdef0 ;Update dskdef1 inc hl ;HL:= dskdef1 for this drive ld a,(hl) ;A:= dskdef1 for this drive and $DEF1 ;Remove bits that're (potentially) set ld b,a ld a,(dsk1) ;B:= dskdef1 for this media or b ld (hl),a ;set dskdef1 ;Update the format type byte ld bc,mftoff ;BC:= Offset to format type (dskdef1) add hl,bc ;HL:= Pointer to format byte in MTAB ld a,(xlt) ld (hl),a ;Format type:= current media's format code call Put_Buffer ;Write the Mtabs back into system memory ret ;Return ;---------------------------------------------------------------------- ; Set the HL Pair Pointing to the Current Mtab (15_Oct_84) ;--------------------------------------------------------- ; 1) This routine Sets the HL pair as a pointer to the current drive's ; Mtab. This routine assmume that the Mtabs have been read into ; the local buffer (Local_Buffer). ; 2) The BC register pair contains the drive number (0 to max drives) ; Set_HL_to_Mtab: push bc rlc c ;Drive_Number * 16 (length of 1 mtab) rlc c rlc c rlc c ld b,0 ;BC:= drive number * single mtab length ld hl,Local_Buffer ;HL:= Start of Local Buffer add hl,bc ;HL:= pointer to start of current mtab pop bc ret ;Return page ;---------------------------------------------------------------------- ; Move system memory into the local buffer (4_Jan_84) ;---------------------------------------------------- ; 1) This routine forces the destination to be the local buffer, calls ; the cold start (extended bios functions) entry point, and then saves ; the registers after swapping hl and de. ; Get_Buffer: ld de,Local_Buffer ;DE:= Pointer to Local Buffer call Extended_Bios ;Move System Memory into local buffer ld (Save_BC),bc ;Save the returned registers ex de,hl ;HL:= Pointer to first xlt ld (Save_DE),de ld (Save_HL),hl ret ;Return ;---------------------------------------------------------------------- ; Put the Local Buffer into System Memory (4_Jan_84) ;--------------------------------------------------- ; 1) This is the inverse of Get_Buffer; It replaces the system's memory ; with the contents of the local buffer. ; 2) Get_Buffer MUST be called before entering this routine. ; Put_Buffer: ld a,EB_Write_Sys ;Function_1:= Write to system memory ld bc,(Save_BC) ld de,(Save_DE) ld hl,(Save_HL) ;Restore the Returned Registers call Extended_Bios ;Write Mtabs back into system memory ret ;---------------------------------------------------------------------- ; Call the Bios Cold Boot Entry Point (4_Jan_84) ;----------------------------------------------- ; 1) The Cold Boot Entry point to the bios (1st entry in the bios ; jump table) is located by looking at locations 1 & 2 which ; point to the warm boot address (the desired address + 3). ; Extended_Bios: push hl ;Save the HL Register Pair ld hl,(Bios_Entry+1) ;HL:= Warm Boot Address ld l,0 ;HL:= Cold Boot Address ex (sp),hl ;Restore the HL Register Pair ret ;Goto The Cold Boot entry page ;---------------------------------------------------------------------- ; Error Messages (15_Oct_84) ;--------------------------- ; mistbl: db Esc,Bright,Cr,Lf,Tab db 'Portions of CP/M are missing from memory.' db Cr,Lf db 'Push reset to re-boot CP/M.$' nosp: db Esc,Bright,Cr,Lf,Tab db 'Too many foreign drives are defined.' db Cr,Lf db 'Push reset to clear all foreign drives. $' page ;---------------------------------------------------------------------------- ; IBM: D.S. - D.D. Media Characteristics - 9 sectors/track (11_Oct_84) ;---------------------------------------------------------------------- ; Physical Media Characteristics: ; Double Sided ; Sector numbering starts with sector 1 ; Double Density ; 512 bytes per sector ; 9 sectors per track ; dsk0: db $FRGN or $DBLMED ;(dsk0) value to be ored into dskdef0 dsk1: db $DRVDEN or $512 ;(dsk1) value to be ored into dskdef1 ;DPB Definiton dpb: dw 36 ;secs per track db 3 ;block shift db 7 ;block mask db 1 ;extnt mask dw 359 ;disk size-1 dw 111 ;directory max db 0f0h ;alloc0 db 0 ;alloc1 dw 16 ;check size dw 1 ;offset ;XLT Table Definition xlt: db ib2cod ;format code for IBM Drives xltlen: dw 0 ;Translation table length ;---------------------------------------------------------------------- ; General Data Area (15_Oct_84) ;------------------------------ ; ;Save Location for Max_Drives, Current_Drive and Dph Values Save_Drive: dw 1 ;Save Location for the drive number Save_DPH: dw 0 ;Save Location for replacement Dph Xlt pointer ;Save Locations for Get/Put Buffer Save_BC: dw 0 ;Save of the BC registers after bios_0 call Save_DE: dw 0 ;Save of the DE registers after bios_0 call Save_HL: dw 0 ;Save of the HL registers after bios_0 call ;Local Buffers ds 40h Local_Stack: dw 0 ;Local Stack Area builds down Local_Buffer: dw 0 ;Local Buffer for system data end