Title Floppy Disk Backup Program for MD-HD (17_Oct_84) ; ; Copyright 1984 ; Morrow Designs, Inc. ; San Leandro, Ca. ; John Zalabak ; .z80 Aseg org 0100h ;---------------------------------------------------------------------- ; Index (17_Oct_84) ;------------------ ; ; Backup_Main Main Proceedure of Backup ; Check_Revision Check Versions/Revisions ; ; Setup_Param Get the Initial Parameters ; Get_Mtab_Data Retrieve Data Carried in the Drive's Mtab ; Get_Dpb_Data Retrieve Data Carried in the Drive's Dpb ; Restore_Param Restore the Entry Parameters ; ; Read_Disk Read the the Disk ; Write_Disk Write the Disk ; ; Read_Flp_Track Read a Track from the Floppy Disk ; Write_Flp_Track Write a Track to the Floppy Disk ; Next_Phy_Sector Calculate the Next Physical Sector ; Read_Dsk_Track Read a Track from the Save File ; Write_Dsk_Track Write a Track to the Save File ; ; Erase_Character Erase a character from the console screen ; Pause_for_Rtn Wait the Return Key ; Get_Character Get a Character from the Console ; Put_Character Put a Character to the Console ; ; Divide 16 bit Divide ; Multiply 16 bit Multiply ; Extended_Bios Call the Extended Bios Entry ; Get_Buffer Read a Buffer (Extended Bios) ; Put_Buffer Write a Buffer (Extended Bios) ; Print_Message Print a Message on the Console ; ; Data Areas page 60 ;---------------------------------------------------------------------- ; General Equates (4_Oct_84) ;--------------------------- ; ;Revision Numbers Frev equ 20h ;Format Program Revision Level Ccl equ 1 ;Bios Compatibility Level Rrl equ 19h ;Rom Revision Level ;Bios/Bdos Equates Bios_Entry equ 0 ;Bios Entry Point Bdos_Entry equ 5 ;Bdos: Entry Vector Location Bdos_PString equ 9 ; Print a Sting on the Console Bdos_ConBuf_In equ 10 ; Read Console input buffer Bdos_Ret_Ver equ 12 ; Return CP/M version Bdos_Select equ 14 ; Select Disk Bdos_Open_File equ 15 ; Open a File Bdos_Close_File equ 16 ; Close a File Bdos_Search equ 17 ; Search for File Bdos_Delete equ 19 ; Delete a File Bdos_Read_Seq equ 20 ; Read Sequential Bdos_Write_Seq equ 21 ; Write Sequential Bdos_Make_File equ 22 ; Make a File Bdos_Crnt_Disk equ 25 ; Return the Current Disk Number Bdos_Set_DMA equ 26 ; Set the DMA Address ;Extended Bios Function Calls EB_Get_Sys_Mem equ 0 ;Read from System Memory EB_Put_Sys_Mem equ 1 ;Write to System Memory EB_Get_RamDatY equ 2 ;Read RamDatY and Apif EB_Get_Mtabs equ 3 ;Read the System Mtabs EB_Get_Dpbs equ 5 ;Read the System Dpbs EB_Char_Tbl equ 6 ;Read the Character Table EB_Execute equ 14 ;Execute a in the System Bank EB_ID_Frame equ 18 ;Read the ID Frame EB_Read_Host equ 20 ;Read a Physical Sector EB_Write_Host equ 21 ;Write a Physical Sector ;Offsets Ccl_Offset equ 10 ;Bios Compatibility from Start of Character Table Rrl_Offset equ 0 ;Rom Revision Level from Start of ID Frame Vnum_Offset equ 04h ;To Numb Log Drives from Start of Char Table Psh_Offset equ 14 ;To Psh - 1 from start of Dpb ConIn_Offset equ 9 ;Bios Console Input Offset ConOut_Offset equ 0Ch ; " Console Output Offset ConSt_Offset equ 33h ; " Console Status Offset SetTrk_Offset equ 1Eh ; " Jump Table Set Track Offset Mtab_Offset equ 80h ;To Mtab/Dpb From Start of Local Buffer HstDsk_Offset equ 0 ;Drive Number from Start of Apif HstTrk_Offset equ 1 ;Track " " " " " HstSec_Offset equ 3 ;Sector " " " " " OpFlag equ 2Eh ;Offset to OpFlag from start of RamDatY ;Length Definitions L_Sector_Length equ 80h ;Logical Sector Length Descriptor_Leng equ 9+15+1 ;Combined Length of Mtab/Dpb (Md3 format) Fcb_Length equ 36 ;Length of a Fcb Default_Fcb1 equ 5Ch ;Location of First Default Fcb ;Termination Codes Again equ 'A' ;Repeat previous format again Restart equ 'R' ;Restart format program Exit equ Control_C ;Exit to Cp/m ;Message Codes Err_Cpm_Rev equ 10 ;Cpm Revision is NOT Cpm 3 Err_Ccp_Rev equ 11 ;Bios Compatability Rev too low Err_Rom_Rev equ 12 ;Rom Revision is too low Msg_Banner equ 20 ;Title Banner Msg_Reading equ 21 ;Reading from Floppy Msg_Writing equ 22 ;Writing to Floppy Msg_Pause equ 35 ;Pause for Input Prompt Msg_Press_Rtn equ 38 ;Press Return to Exit Msg_CrLf equ 39 ;New Line ;Non Printing Ascii Equates Control_C equ 03h ;Control C (Force CPM Warm Boot) Bell equ 07h ;Console Bell BackSpace equ 08h ;Back Space One Character Tab equ 09h ;Tab Lf equ 0Ah ;Line Feed Cr equ 0Dh ;Carriage Return Clear_Screen equ 1Ah ;Clear Screen Esc equ 1Bh ;Escape Bright equ '(' ;Hight Brightness Dim equ ')' ;Low Brightness ;Other Equates Sys_Disk_Buffer equ 2800h ;System's Disk Buffer Default_Dma equ 80h ;Cpm Default Dma Address Response_Max equ 10h ;Maximum Length of the Response Buffer @SerUR equ 6 ;Suppress Error Response Flag @SerD equ 7 ;Suppress Error Display Flag @DblMed equ 2 ;Single/Double Sided Media Flag $HdMsk equ 00011100b ;Head Mask (DskDef0) $HrdDsk equ 00000010b ;Hard Disk Mask (DskDef0) $SizMsk equ 00000011b ;Sector Size Mask (DskDef1) page ;====================================================================== ; Main Line of Format Routine (5_Oct_84) ;======================================= ; Backup_Main: ld sp,Local_Stack ;Set the Stack Pointer BuLp1: ld a,Msg_Banner ;Repeat call Print_Message ; Print the Opening Message call Check_Revision ; If (Revisions Don't Match) or a jp nz,Bios_Entry ; Return to the System call Setup_Param ; Setup to Copy a Disk or a ; If (There was an Error) jr nz,Quit ; Quit call Copy_Disk ; Copy the Disk Quit: call Restore_Param ;Restore the Entry Parameters jp Bios_Entry ;Exit page ;====================================================================== ; Check Versions/Revisions (3_Oct_84) ;==================================== ; 1) This routine checks the CP/M version, the Bios Compatibility ; level and the Rom Revision Level. ; Check_Revision: ld c,Bdos_Ret_Ver ;C:= Return version Bdos call call Bdos_Entry ;Get the Cpm Revision ld a,0F0h and l cp 30h ;If (this is Cp/m 3) ld a,Err_Cpm_Rev jr nz,CrSk1 ld a,EB_Char_Tbl ; A:= Get Char Table Function call Get_Buffer ; Read the Character Table ld a,(Buffer+Ccl_Offset) cp Ccl ; If (Compatibility Level in Range) ld a,Err_Ccp_Rev jr c,CrSk1 ld a,EB_ID_Frame ; A:= Read Rom ID Frame call Extended_Bios ; Read the ID Frame ld a,(Buffer+Rrl_Offset) cp Rrl ; If (Rom Rev in Range) ld a,Err_Rom_Rev jr c,CrSk1 ld a,0 ; A:= No Error ret ; Return CrSk1: call Print_Message ;Print the Error Message ld a,Control_C ;A:= Error ret ;Return page ;====================================================================== ; Get Ready to Copy the Disk (17_Oct_84) ;======================================= ; Setup_Param: ld c,Bdos_Crnt_Disk ;Return the Current Disk Number call Bdos_Entry ld (Initial_Drive),a ;Save the Logged on Drive call Get_Log_Tracks ;Get Number of Logical Tracks call Get_Log_Spt ;Get Number of Logical Sectors/Track call Get_Phy_Spt ;Get Number of Physical Sectors/Track call Get_P_Sect_Len ;Get Size of a Physical Sector ld hl,Default_Fcb ;HL:= Source (Default Fcb in Data Area) ld de,Default_Fcb1 ;DE:= Destination (Default Dma) ld bc,Fcb_Length ;BC:= Length (of Fcb) ldir ;Install the Fcb ld a,0 ret ;---------------------------------------------------------------------- ; Get the Number of Logical Tracks (17_Oct_84) ;--------------------------------------------- ; 1) This routine figures the number of Logical Tracks, sets the ; sector size code and the local copy of DskDef0. ; Get_Log_Tracks: ld a,EB_Get_Mtabs call Get_Buffer ;Read the System Mtabs ld a,(Drive_Number) sla a sla a sla a sla a ld e,a ld d,0 ;DE:= Drive_Number * 16 ld hl,Buffer ;HL:= Base of Mtabs add hl,de ;HL:= Pointer to Start of Current Mtab ld a,(hl) ;A:= DskDef0 ld (DskDef0),a and $HdMsk ;Remove all But the Head Number srl a srl a ;Move Heads to Lsb's inc a ;A:= 1 Based Number of Heads ld e,a ld d,0 push de inc hl ;(DskDef1) ld a,(hl) and $SizMsk ;Remove all bits but the Sector Size inc a ;Set Sector Code to 1 Base (1 to 4) ld (Size_Code),a ;Save the Sector Size Code inc hl ;(DskDef2) inc hl ;(PrkOff) inc hl ;(MaxCyl) ld e,(hl) inc hl ld d,(hl) ex de,hl ;HL:= Max Cylinders pop de ;DE:= Number of Heads call Multiply ld (Logical_Tracks),hl ;Save the Number of Logical Tracks ret ;Return page ;---------------------------------------------------------------------- ; Get the Number of Logical Sectors per Track (17_Oct_84) ;-------------------------------------------------------- ; 1) This routine figures the number of Logical Sectors per Track. ; 2) Register Usage: ; DE -> Used to hold offsets ; HL -> Used as a Pointer and as a 16 bit accumulator ; Get_Log_Spt: ld a,EB_Get_Dpbs ;A:= Get the System's Dpbs Function (5) call Get_Buffer ;Fill Local Buffer ld hl,(Drive_Number) ;DE:= Drive Number (0-15) rlc l ld h,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_HL) ;DE:= Start of system buffer xor a ;(Clear the carry) sbc hl,de ;HL:= Offset to start of Dpb/Dph ld de,Buffer add hl,de ;HL:= Pointer to Dpb/Dph in loc buf ld e,(hl) inc hl ld d,(hl) ;DE:= Logical Sectors/Track ld (Logical_Spt),de ;Save Number of Logical Sectors/Track ret ;Return page ;---------------------------------------------------------------------- ; Get the Number of Physical Sectors per Track (17_Oct_84) ;--------------------------------------------------------- ; 1) This routine figures the number of Physical Sectors per Track based ; on the Number of Logical Sectors/Track (from Dpb Data) and the ; Sector_Size Code (from Mtab Data). ; Get_Phy_Spt: ld hl,(Logical_Spt) ;HL:= Logical Sectors/Track ld a,(Size_Code) ld c,a ld b,0 ;BC:= (1 Based) Sector Size Code call Divide ;Divide (Logical Records/Track)/Psh+1 ld a,(DskDef0) ;A:= Copy of DskDef0 bit @DblMed,a ;If (This is a Double Sided Disk) jr z,GpSk1 srl d rr e ; Divide the Result by 2 GpSk1: ld (Physical_Spt),de ;Save Number of Physical Sectors/Track ret ;---------------------------------------------------------------------- ; Get the Length of a Physical Sector (17_Oct_84) ;------------------------------------------------ ; Get_P_Sect_Len: ld a,(Size_Code) ld hl,L_Sector_Length ;HL:= Logical Sector Length dec a ;If (Size is 128) jr z,GsSk1 ; Skip add hl,hl ;HL:= 256 dec a ;If (Size is 256) jr z,GsSk1 ; Skip add hl,hl ;HL:= 512 dec a ;If (Size is 512) jr z,GsSk1 ; Skip add hl,hl ;HL:= 1024 GsSk1: ld (P_Sector_Leng),hl ;Install the Physical Sector Length ret ;Return ;====================================================================== ; Restore the Entry Parameters (17_Oct_84) ;========================================= ; Restore_Param: ld c,Bdos_Delete ;C:= Delete a File ld de,Default_Fcb1 ;DE:= Destination (Default Dma) call Bdos_Entry ;Delete the Save File ld c,Bdos_Select ;C:= Select Disk Function ld a,(Initial_Drive) ld e,a ;E:= Drive to Select call Bdos_Entry ;Reselect the Entry Drive ld a,0 ret ;Return page ;====================================================================== ; Copy a Floppy Disk (17_Oct_84) ;=============================== ; Copy_Disk: call Read_Disk or a ;If (There was an Error) jr nz,CdSk1 ; Quit call Pause_for_Rtn ;Prompt User cp Control_C ;If (Response eq Control C) jr z,CdSk1 ; Quit ld hl,Default_Fcb ;HL:= Source (Default Fcb in Data Area) ld de,Default_Fcb1 ;DE:= Destination (Default Dma) ld bc,Fcb_Length ;BC:= Length (of Fcb) ldir ;Install the Fcb call Write_Disk or a ;If (There was an Error) jr nz,CdSk1 ; Quit CdSk1: ret ;Return ;====================================================================== ; Read the the Disk (17_Oct_84) ;============================== ; Read_Disk: ld a,Msg_Banner call Print_Message ;Print Title Banner ld a,Msg_Reading call Print_Message ;Print Reading from Floppy ld de,Buffer ;DE:= Start of Local Buffer ld c,Bdos_Set_DMA ;C:= Set DMA Address Function call Bdos_Entry ;Set the Dma Address ld de,Default_Fcb1 ;DE:= Start of Command_Fcb ld c,Bdos_Delete ;C:= Delete File Function call Bdos_Entry ;Delete the Temp File ld de,Default_Fcb1 ;DE:= Start of Command_Fcb ld c,Bdos_Make_File ;C:= Open File Function call Bdos_Entry ;Open the command file cp 0FFh ;If (file can't be opened) ret z ; Return ld hl,(Logical_Tracks) ;BC:= Number of Logical Tracks ld (Track_Count),hl ld hl,0 ;HL:= Track_Number ld (Apif+HstTrk_Offset),hl ;Initialize the Track Number RdLp1: ld a,(Drive_Number) ;Repeat ld (Apif+HstDsk_Offset),a ; Install The Drive Number call Read_Flp_Track ; Read a Track from the Floppy or a ; If (There was an Error) ret nz ; Return call Write_Dsk_Track ; Write the Track to the File or a ; If (There was an Error) ret nz ; Return ld hl,(Apif+HstTrk_Offset) inc hl ld (Apif+HstTrk_Offset),hl ; Increment the Track Number ld hl,(Track_Count) dec hl ld (Track_Count),hl ; Decrement the Track Count ld a,h or l jr nz,RdLp1 ;Until (Track Count eq 0) ld de,Default_Fcb1 ;DE:= Pointer to FCB1 ld c,Bdos_Close_File ;C:= Close file function call Bdos_Entry ;Close the command file ld a,0 ret ;Return page ;====================================================================== ; Write the Disk (17_Oct_84) ;=========================== ; Write_Disk: ld a,Msg_Banner call Print_Message ;Print Title Banner ld a,Msg_Writing call Print_Message ;Print Writing to Floppy ld de,Buffer ;DE:= Start of Local Buffer ld c,Bdos_Set_DMA ;C:= Set DMA Address Function call Bdos_Entry ;Set the Dma Address ld de,Default_Fcb1 ;DE:= Start of Command_Fcb ld c,Bdos_Open_File ;C:= Open File Function call Bdos_Entry ;Open the command file cp 0FFh ;If (file can't be opened) ret z ; Return ld hl,(Logical_Tracks) ;BC:= Number of Logical Tracks ld (Track_Count),hl ld hl,0 ;HL:= Track_Number ld (Apif+HstTrk_Offset),hl ;Initialize the Track Number WrLp1: ld a,(Drive_Number) ;Repeat ld (Apif+HstDsk_Offset),a ; Install The Drive Number call Read_Dsk_Track ; Read a Track from the File or a ; If (There was an Error) ret nz ; Return call Write_Flp_Track ; Write a Track to the Floppy or a ; If (There was an Error) ret nz ; Return ld hl,(Apif+HstTrk_Offset) inc hl ld (Apif+HstTrk_Offset),hl ; Increment the Track Number ld hl,(Track_Count) dec hl ld (Track_Count),hl ; Decrement the Track Count ld a,h or l jr nz,WrLp1 ;Until (Track Count eq 0) ld de,Default_Fcb1 ;DE:= Pointer to FCB1 ld c,Bdos_Close_File ;C:= Close file function call Bdos_Entry ;Close the command file ld a,0 ret ;Return page ;---------------------------------------------------------------------- ; Read a Track from the Floppy Disk (17_Oct_84) ;---------------------------------------------- ; 1) This routine reads a track from the Floppy Disk. ; 2) If there's an error then an Error Message is Printed and the ; Pause_for_Rtn routine is executed. ; 3) Register Usage: ; A -> Returned 0 for NO errors ; ----> All other registers are destroyed ; Read_Flp_Track: ld hl,(Physical_Spt) ld (Sector_Count),hl ;Initialize the Sector Count ld hl,1 ld (Current_Sector),hl ;Initialize the Current Sector RdfLp1: ld hl,(Current_Sector) ;Repeat ld (Apif+HstSec_Offset),hl ; Install the Sector Number ld ix,Apif ; IX:= Start of Local Apif ld a,EB_Read_Host ; A:= Read Host Function call Extended_Bios ; Read a Sector From Floppy Disk or a ; If (There was an Error) jr z,RdfSk1 ; ld a,Err_Boot_Read ; A:= Read Error Message ; call Print_Message ; Print Error Message ; call Pause_for_Rtn ; Wait for User Response ld a,0FFh ret ; Return RdfSk1: ld de,(P_Sector_Leng) ; DE:= Length of One Sector ld hl,(Current_Sector) ; HL:= Current Sector dec hl ; (0 Based Sector Number) call Multiply ; HL:= Offset to Current Sector ld de,Buffer ; DE:= Start of the Buffer add hl,de ; HL:= Pointer to Sector Addr ex de,hl ; DE:= Destination (in Local Buffer) ld hl,Sys_Disk_Buffer ; HL:= Source (System Disk Buffer) ld bc,(P_Sector_Leng) ; BC:= Length (Length of 1 Sector) ld a,EB_Get_Sys_Mem ; A:= Read Disk Buffer Function call Extended_Bios ; Move the Sector Into Place call Next_Phy_Sector or a jr nz,RdfLp1 ;Until (All Sectors Have Been Read) ret ;Return page ;---------------------------------------------------------------------- ; Write a Track to the Floppy Disk (17_Oct_84) ;--------------------------------------------- ; 1) This routine writes a Track to the Floppy Disk. ; 2) Register Usage: ; A -> Returned 0 for NO Errors. ; ----> All other registers are destroyed ; Write_Flp_Track: ld hl,(Physical_Spt) ld (Sector_Count),hl ;Initialize the Sector Count ld hl,1 ld (Current_Sector),hl ;Initialize the Current Sector WrfLp1: ld hl,(Current_Sector) ;Repeat ld (Apif+HstSec_Offset),hl ; Install the Sector Number ld de,(P_Sector_Leng) ; DE:= Length of One Sector ld hl,(Current_Sector) ; HL:= Current Sector dec hl ; (0 Based Sector Number) call Multiply ; HL:= Offset to Current Sector ld de,Buffer ; DE:= Start of the Buffer add hl,de ; HL:= Source (in Local Buffer) ld de,Sys_Disk_Buffer ; DE:= Destination (Sys Buffer) ld bc,(P_Sector_Leng) ; BC:= Length (Length of 1 Sector) ld a,EB_Put_Sys_Mem ; A:= Write to System Memory call Extended_Bios ; Move Buffer into Disk Buffer ld ix,Apif ; IX:= Local APIF ld a,EB_Write_Host ; A:= Write Host Function call Extended_Bios ; Write a Sector to the Disk or a ; If (There was NO Error) jr z,WrfSk1 ; ld a,Err_Boot_Write ; A:= Write Error ; call Print_Message ; Print Error Message ; ld a,ReStart ; A:= ReStart Code ld a,0FFh ret ; Return WrfSk1: call Next_Phy_Sector ; Get the Next Sector or a jr nz,WrfLp1 ;Until (All Sectors have been Written) ret ;Return page ;---------------------------------------------------------------------- ; Calculate the Next Physical Sector (17_Oct_84) ;----------------------------------------------- ; 1) This routine checks if all the sectors have been accessed and ; adjusts the next sector accordingly (based on a skew of 2). ; 2) Register Usage: ; A -> Returned 0 for last sector. ; HL -> Returned equal to the Current Sector Number ; ----> No other registers are effected ; Next_Phy_Sector: ld hl,(Sector_Count) dec hl ld (Sector_Count),hl ;Decrement the Sector Count ld a,h ;If (All Sectors have Been Accessed) or l ret z ; Return ld hl,(Current_Sector) inc hl inc hl ld (Current_Sector),hl ;Increment the Current Sector push hl push de ld de,(Physical_Spt) ;DE:= Maximum Number of Sectors or a ;(Clear Carry but don't touch accm) sbc hl,de ;If (Sector Count le Maximum Sectors) pop de pop hl ret c ; Return ret z ld hl,2 ;Else ld (Current_Sector),hl ; Current_Sector:= 2 ret ; Return page ;---------------------------------------------------------------------- ; Read a Track from the Save File (17_Oct_84) ;-------------------------------------------- ; Read_Dsk_Track: ld bc,(Logical_Spt) ;BC:= Logical Sectors/Track ld de,Buffer ;DE:= Dma Pointer to start Load RfLp1: push bc push de ;Repeat ld c,Bdos_Set_DMA ; C:= Set DMA Address Function call Bdos_Entry ; Set the Dma Address ld de,Default_Fcb1 ; DE:= Start of Command_Fcb ld c,Bdos_Read_Seq ; C:= Read Sequential Function call Bdos_Entry ; Read the Next record pop de pop bc or a jr z,RfSk1 ; If (Bdos Error) ret ; Return RfSk1: ld hl,L_Sector_Length add hl,de ex de,hl ; DE:= Next Sector Address dec bc ; Decrement the Sector Length ld a,b or c jr nz,RfLp1 ;Until (All sectors have been read) ret ;Return page ;---------------------------------------------------------------------- ; Write a Track to the Save File (17_Oct_84) ;------------------------------------------- ; Write_Dsk_Track: ld bc,(Logical_Spt) ;BC:= Logical Sectors/Track ld de,Buffer ;DE:= Dma Pointer to start Load WfLp1: push bc push de ;Repeat ld c,Bdos_Set_DMA ; C:= Set DMA Address Function call Bdos_Entry ; Set the Dma Address ld de,Default_Fcb1 ; DE:= Start of Command_Fcb ld c,Bdos_Write_Seq ; C:= Write Sequential Function call Bdos_Entry ; Write the Next record pop de pop bc or a jr z,WfSk1 ; If (Bdos Error) ret ; Return WfSk1: ld hl,L_Sector_Length add hl,de ex de,hl ; DE:= Next Sector Address dec bc ; Decrement the Sector Length ld a,b or c jr nz,WfLp1 ;Until (All sectors have been written) ret ;Return page ;---------------------------------------------------------------------- ; Erase a Character from the Console Screen (1_Oct_84) ;----------------------------------------------------- ; 1) This routine erases one character from the console screen. ; 2) None of the Registers are effected. ; Erase_Character: push af ld a,BackSpace call Put_Character ;Backup over the Character ld a,' ' call Put_Character ;Print a Space over the Character ld a,BackSpace call Put_Character ;Backup the cursor pop af ret ;Return ;---------------------------------------------------------------------- ; Wait for the Return Key to be Pressed (3_Oct_84) ;------------------------------------------------- ; 1) This routine prints a prompting message and then loops, waiting ; for either a carriage return or a Control C to by typed. ; 2) Register Usage: ; A -> Returned equal to ReStart or Control_C (Exit) ; ----> None of the other registers are effected ; Pause_for_Rtn: push bc push de push hl ld a,Msg_Pause call Print_Message ;Print the Prompt pop hl pop de pop bc PrLp1: call Get_Character ;Loop Wait for the Response cp Control_C ; If (Response eq Return to CP/M) ret z ; Return cp Cr ; If (Response eq Cr) ld a,ReStart ; A:= ReStart ret z ; Return call Erase_Character ; Else Erase the Character jr PrLp1 page ;---------------------------------------------------------------------- ; Get a Character from the Console (1_Oct_84) ;-------------------------------------------- ; 1) This routine gets one character from the console device by ; vectoring through the bios jump table and then echoes the ; character by calling Put_Character. ; 2) Notice that Control Characters are echoed as spaces. ; 2) Register Usage: ; A -> On exit holds the character read ; ----> No other register effected ; Get_Character: push bc push de push hl ld de,(Bios_Entry+1) ld e,0 ;DE:= Base of Bios Jump Table ld hl,ConIn_Offset ;HL:= Offset to ConIn Jump in Bios Table add hl,de ;HL:= Pointer to ConIn Jump ld a,EB_Execute ;A:= Execute in the System Bank call Extended_Bios ;Get a Character push af cp 20h ;If (Character is Control) jr nc,GcSk1 ld a,' ' ; Echo a Space GcSk1: call Put_Character ;Echo the Character pop af pop hl pop de pop bc ret ;Return page ;---------------------------------------------------------------------- ; Put a Character to the Console (1_Oct_84) ;------------------------------------------ ; 1) This routine prints one character on the console screen by ; vectoring through the bios jump table. ; 2) Register Usage: ; A -> On entry and exit holds the character printed ; ----> No other register effected ; Put_Character: push bc push de push hl push af ld c,a ;C:= Character to Print ld de,(Bios_Entry+1) ld e,0 ;DE:= Base of Bios Jump Table ld hl,ConOut_Offset ;HL:= Offset to ConOut Jump in Bios Table add hl,de ;HL:= Pointer to ConOut Jump ld a,EB_Execute ;A:= Execute in the System Bank call Extended_Bios ;Print the Character pop af pop hl pop de pop bc ret ;Return page ;---------------------------------------------------------------------- ; 16 bit Divide ;-------------- ; divide 16-bit number in [hl] by [bc] ; on exit, [de] is 16-bit quotient, [hl] is remainder ; Divide: add hl,hl ;hi *2 ex de,hl ;[de] becomes lo ld hl,0 ;init hi ld a,16 ;16 bits divid0: adc hl,hl ;Repeat hi *2 or a ; clear borrow sbc hl,bc ; sbc hl,bc ;hi=hi-divisor ccf ; invert borrow for shift later jr c,divid1 ; if borrow { adc hl,bc ; Restore the value of the HL ccf divid1: ex de,hl ; get lo adc hl,hl ; lo *2 + remainder ex de,hl dec a ; count-- jr nz,divid0 ;Until (bit count eq 0) ret page ;---------------------------------------------------------------------- ; 16 bit Multiply ;---------------- ; 1) This routine multiplies the contents of the HL register by the ; contents of the DE register leaving the result in the HL register. ; 2) Register Usage: ; BC -> [Preserved] Temp Storage ; DE -> [Preserved] Multiplier ; HL -> Multiplicand/Result ; Multiply: push bc push de ;(Save Registers) ld c,l ld b,h ld hl,00000h MuLp1: ld a,b ;While (Count ne zero) or c jr nz,MuSk1 pop de pop bc ; (Restore Registers) ret ; (Return) MuSk1: ld a,b rra ld b,a ld a,c rra ld c,a jr nc,MuSk2 add hl,de MuSk2: ex de,hl add hl,hl ex de,hl jr MuLp1 page ;---------------------------------------------------------------------- ; Call the Bios Extended Bios (Cold Boot) Entry Point (1_Aug_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,(1) ;HL:= Warm Boot Address ld l,0 ;HL:= Cold Boot Address ex (sp),hl ;HL:= Entry Value; Stack:= Cold Boot Entry ret ;Goto The Cold Boot entry ;---------------------------------------------------------------------- ; Move system memory into the local buffer (30_Jul_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. ; 2) Enter with Accm equal to the extended bios function desired ; Get_Buffer: ld de,Buffer ;DE:= Pointer to Local Buffer call Extended_Bios ;Move System Memory into local buffer ld (Save_BC),bc ;Save the returned registers ld (Save_DE),de ld (Save_HL),hl ret ;Return ;---------------------------------------------------------------------- ; Put the Local Buffer into System Memory (30_Jul_84) ;---------------------------------------------------- ; 1) This is the inverse of GetBuf; It replaces the system's memory ; with the contents of the local buffer. ; Put_Buffer: ld a,1 ;Function_1:= Write to system memory ld bc,(Save_BC) ld de,(Save_DE) ld hl,(Save_HL) ;Restore the Returned Registers ex de,hl ;HL:= Swap Source and Destination call Extended_Bios ;Write Buffer back into system memory ret page ;---------------------------------------------------------------------- ; Print a Message on the Console (25_Sept_84) ;-------------------------------------------- ; 1) This routine prints the message string, whose code is passed in the ; accm, on the console. ; 2) Register Usage: ; A -> Has Message Code on entry and exit ; B -> Counter ; C -> Holds copy of Message Code ; DE -> Used to hold pointers/Bdos print string functions ; HL -> Used to hold pointers ; Print_Message: ld c,a ;C:= Message Code to Find ld b,Max_Message ld hl,Msg_Table ;HL:= Start of the Message Table PmLp1: ld a,(hl) ;Repeat A:= Table's Message Code inc hl ld e,(hl) inc hl ld d,(hl) ; DE:= Pointer to String inc hl ; (HL equal to start next entry) cp c ; If (Code eq table) jr z,Pmprn ; Goto Print djnz PmLp1 ;Until (the whole tables been checked) ld de,NoCode ;(Pointer:= 'Unrecognized Message') PmPrn: push bc ld c,Bdos_PString ;C:= Bdos Print String Function call Bdos_Entry ;Print the Message pop bc ld a,c ;A:= Message Code ret page ;---------------------------------------------------------------------- ; Message Vector Table (17_Oct_84) ;--------------------------------- ; Msg_Table: db Err_Cpm_Rev ;Cpm Revision is NOT Cpm 3 dw EMrCpm db Err_Ccp_Rev ;Bios Compatability Rev too low dw EMrCcp db Err_Rom_Rev ;Rom Revision is too low dw EMrRom db Msg_Banner ;Title Banner dw MsgOpn db Msg_Reading ;Reading from Floppy dw MsgRd db Msg_Writing ;Writing to Floppy dw MsgWr db Msg_Pause ;Pause for Input Prompt dw MsgPas db Msg_Press_Rtn ;Press Return to Exit dw MsgRet db Msg_CrLf ;New Line dw CrLf End_Table: Max_Message equ ( (End_Table - Msg_Table)/3 ) + 1 page ;---------------------------------------------------------------------- ; Error Strings (3_Oct_84) ;------------------------- ; EMrCpm: db Cr,Lf,Tab db 'This version of Format Requires CP/M vers 3.0' db Cr,Lf,'$' EMrCcp: db Cr,Lf,Tab db 'This version of Format Requires Cbios rev ' db ((Ccl and 0F0h) shr 4) + '0' db ' or higher.' db Cr,Lf,'$' EMrRom: db Cr,Lf,Tab db 'This version of Format Requires Rom Revision ' db ((Rrl and 0F0h) shr 4) + '0', '.', (Rrl and 0Fh) + '0' db ' or higher.' db Cr,Lf,'$' NoCode: db Cr,Lf,Tab db 'Unrecognized Error $' page ;---------------------------------------------------------------------- ; Message Strings (17_Oct_84) ;---------------------------- ; MsgOpn: db Clear_Screen,Esc,Dim,Cr db 'MD-HD ' db Esc,Bright db 'Floppy Disk Backup ' db Esc,Dim db 'Program Rev ' db ((FRev and 0F0h) shr 4) + '0', '.', (FRev and 0Fh) + '0' db Tab,Tab,Tab,' Copyright 1984' db Cr,Lf db 'Morrow Designs Inc.' db Tab,Tab,Tab,Tab,Tab,Tab,'San Leandro, Ca' db Cr,Lf,'$' MsgRd: db Cr,Lf,Lf,'Reading from Floppy $' MsgWr: db Cr,Lf,Lf,'Writing to Floppy $' MsgRet: db Cr,Lf,Tab db Esc,Dim db 'or Press RETURN to exit to CP/M ' db Esc,Bright,'$' MsgPas: db Cr,Lf,Tab db Esc,Dim db 'Press ' db Esc,Bright db 'RETURN ' db Esc,Dim db 'when you are ready to continue. ' db Esc,Bright,'$' CrLf: db Cr,Lf,'$' page ;---------------------------------------------------------------------- ; Data Area (17_Oct_84) ;---------------------- ; ;Drive Characteristics Parameters Logical_Tracks: dw 0 ;Highest Logical Track Number Logical_Spt: dw 0 ;Number of Logical Sectors/Track Physical_Spt: dw 0 ;Number of Physical Sectors/Track P_Sector_Leng: dw 0 ;Physical Sector Length Initial_Drive: db 0 ;Current Drive when program started DskDef0: db 0 ;Save of DskDef0 Size_Code: db 0 ;Save of Sector Size Code + 1 Drive_Number: db 1 ;Format Disk Number (A:= 0) Current_Sector: dw 0 ;Current Sector being Read/Written Sector_Count: dw 0 ;Physical Sector Count Track_Count: dw 0 ;Logical Track Count ;Register Save Locations for Get/Put Buffer Functions Save_BC: dw 0 ;Save location for the BC register pair Save_DE: dw 0 ; " " " " DE " " Save_HL: dw 0 ; " " " " HL " " Default_Fcb: db 0 db 'SAVEFILE$$$',0 ;Save File Name for Disk Data ds 24,0 page ;---------------------------------------------------------------------- ; Default Application Interface area (26_Sept_84) ;------------------------------------------------ ; Apif: db 0 ;(HSTDSK) BDOS Drive Number (1st floppy) dw 0000 ;(HSTTRK) Desired Cylinder (lo,hi) dw 0 ;(HSTSEC) Desired Sector (lo,hi) db 0 ;(SECCNT) Number of sectors to transfer db 2 ;(RETRY) Retry Count dw Sys_Disk_Buffer ;(HSTBUF) Buffer Address (lo,hi) db 0 ;(ERFLAG) Error Code db 18h ;(OPFLAG) Options Flag dw 0 ;(PHYTRK) Physical track number (lo,hi) db 0 ;(PHYSEC) Physical sector number db 0 ;(PHYHD) Desired Head db 0 ;(PHYDRV) Physical Drive Number dw 0 ;(IOADD) Execution Address (lo,hi) page ;---------------------------------------------------------------------- ; Local Buffers (3_Oct_84) ;------------------------- ; ds 40h ;Local Stack Space Local_Stack: dw 0 Buffer: ds 10h,0 ;Local Buffer (up to 1k is actually used) end