Title Format Program for MD-HD series Micro Decisions (17_Dec_84) ; ; Copyright 1984 ; Morrow Designs, Inc. ; San Leandro, Ca. ; John Zalabak ; .z80 Aseg org 0100h .sall ;Suppress all Macro Expansions page 60 ;---------------------------------------------------------------------- ; Index (3_Oct_84) ;----------------- ; ; Format_Main Main Proceedure of Format ; Check_Revision Check Versions/Revisions ; Get_Input_Param Get Input Parameters ; Strip_White Strip Leading White Space ; ; Get_Drive Get the Drive on Which to Format ; Valid_Drives Print the Valid Drives ; Drive_In_Range Check if the Drive Letter is in Range ; Get_Drive_Data Get the Drive Data From the Mtab ; ; Format_Hard Format a Hard Disk ; Hard_Setup Setup for a Hard Disk Format Operation ; String_Match Match Two Strings ; Do_Copysys Try to Copy a System onto Track Zero ; ; Format_Floppy Format a Floppy Disk ; Floppy_Setup Setup for a Floppy Format Operation ; ; Format_Common Common Format Routine ; Verify_Common Verify the Data ; ; Put_Boot_Image Setup the Boot Image in the Local Buffer ; Read_Boot Read Bad Map Portion of the Boot Sector ; Write_Boot Write the Boot Sector ; ; Restore_Param Restore the Input Parameters ; Next_Operation Prompt for Next Operation ; Print_Number Print a Number in the Current Base ; 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 ; Load_and_Go Load the Copysys Program ; Boot_Code Image of the Disk Boot Sector page ;---------------------------------------------------------------------- ; General Equates (17_Dec_84) ;---------------------------- ; ;Revision Numbers Frev equ 22h ;Format Program Revision Level Ccl equ 1 ;Bios Compatibility 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_Read_Seq equ 20 ; Read Sequential Bdos_Write_Seq equ 21 ; Write Sequential 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 ;Copy RamDatY and Apif to Tpa EB_Get_Mtabs equ 3 ;Copy System Mtabs to Tpa EB_Char_Tbl equ 6 ;Read the Character Table EB_Format equ 9 ;Format a Track EB_Inject_Ims equ 11 ;Inject an Ims String EB_Execute equ 14 ;Execute a in the System Bank EB_Verify_D equ 15 ;Verify a Track with Re:Mapping 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 CFlag_Offset equ 18 ;CFlag Entry from Start of RamDatY Vnum_Offset equ 4 ;Numb Log Drives from Start of Char Table 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 BadId_Offset equ 180h ;To Bad Map ID " " " " " 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 ;Boot Sector Data BadID equ 4B6Fh ;Bad Map ID Word (bad map pntr struct) BadRev equ 10h ;Bad Map Revision Number (bad map hdr) Mesg equ 3 ;Rom entry - print a message Bter equ 18h ;Rom entry - print Push Reset BnkStb equ 41h ;Bank Strobe (Rom Control for MD-11) RomCnt equ 0F6h ;Rom control port for an MD-3 Stack equ 0FF80h ;Reset loc. stack pointer; Execution seg. PcHL equ 0E9h ;z80 instruction - jp (HL) PopHL equ 0E1h ;z80 instruction - pop HL ;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 Err_Boot_Read equ 13 ;Unable to Read the Boot Sector Err_Boot_Write equ 14 ;Unable to Write the Boot Sector Msg_Banner equ 20 ;Title Banner Msg_Drive equ 21 ;Drive Prompt Msg_Hard_Opt equ 22 ;Hard Disk Options Msg_Floppy_Opt equ 23 ;Floppy Options Msg_Single equ 24 ;Start of Single Sided Floppy Format Msg_Double equ 25 ; " " Double " " " Msg_Ready equ 26 ;Ready to Fromat Prompt Msg_Format equ 27 ;Beginning Format Msg_Verify equ 28 ;Beginning Verification Msg_Warning equ 29 ;Some Errors were made Msg_Format_Done equ 30 ;Formatting Done Msg_Start_Again equ 31 ;Again ReStart Exit Msg_Reminder equ 32 ;Reminder to Insert the Boot Disk Msg_Bad_Rpt equ 33 ;Bad Sectors Found Msg_No_Bad_Rpt equ 34 ;No Bad Sectors Found Msg_Pause equ 35 ;Pause for Input Prompt Msg_New_System equ 36 ;New System Needed Msg_Chaining equ 37 ;New System Being Installed 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 ;Termination Codes Again equ 'A' ;Repeat previous format again Restart equ 'R' ;Restart format program Exit equ Control_C ;Exit to Cp/m ;Length Definitions FE_Flp_Length equ End_FE_Floppy - FE_Floppy FE_Hrd_Length equ End_FE_Hard - FE_Hard Load_Length equ End_Lgo - Start_Lgo Sysldr_Offset equ End_Lgo - Sysldr_Fcb Sector_Length equ 400h ;Length of a Sector Descriptor_Leng equ 9+15+1 ;Combined Length of Mtab/Dpb (Md3 format) Record_Length equ 80h ;Length of a Logical Record Status_Eof equ 01 ;Reading UnWritten Data (from Read Seq) Default_Fcb1 equ 5Ch ;Location of First Default Fcb Default_Fcb2 equ 6Ch ;Location of Second Default Fcb ;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 $HdMsk equ 00011100b ;Head Mask (DskDef0) $HrdDsk equ 00000010b ;Hard Disk Mask (DskDef0) @imsact equ 6 ;Cflag In memory submit flag (1=active) @imswet equ 7 ;Cflag IMS buffer full (1=active) page ;====================================================================== ; Main Line of Format Routine (13_Dec_84) ;======================================== ; Format_Main: ld sp,Local_Stack ;Set the Stack Pointer call Get_Input_Param ;Read the Input Parameters FmLp1: 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 Get_Drive ; Get the Drive to format or a ; If (Reponse eq Stop) jp nz,Bios_Entry ; Return to the System call Get_Drive_Data ; Get Drive Data From Mtabs or a ; If (this is a Hard Disk) jr z,FmSk1 call Format_Hard ; Do Hard Disk Format jr FmSk2 FmSk1: call Format_Floppy ; Else Do Floppy Disk Format FmSk2: cp Control_C ;Until (Flag eq Control_C) jp nz,FmLp1 call Restore_Param ;Restore Parameters jp Bios_Entry ;Exit page ;====================================================================== ; Check Versions/Revisions (17_Dec_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,0 ; A:= No Error ret ; Return CrSk1: call Print_Message ;Print the Error Message ld a,Control_C ;A:= Error ret ;Return page ;====================================================================== ; Get Input Parameters (17_Dec_84) ;================================= ; 1) This routine parses the command line (if any) and then gets ; the total number of logical drives from the character table. ; Get_Input_Param: ld a,Default_Dma ;A:= Command Tail Length or a jr z,GiSk1 ;If (There was a Command Tail) ld hl,Default_Dma+1 ; HL:= Start of Command Tail Data call Strip_White ; Get the 1st Character or a ; If (There really was a Char) jr z,GiSk1 ld (Cmd_Line_True),a ; Set Command Tail Active ld (Cmd_Line_Drive),a ; Save the Drive Letter call Strip_White ; Get the 2nd Character or a ; If (Line Not Null) jr z,GiSk1 ld (Cmd_Line_Sides),a ; Save as Sides GiSk1: ld c,Bdos_Crnt_Disk ;C:= Return Current Disk Function call Bdos_Entry ;Get the Current Disk ld (Initial_Drive),a ;Save the Drive we started out on ld a,EB_Char_Tbl ;A:= Read Character Table Funct call Get_Buffer ;Read the Character Table ld a,(Buffer+Vnum_Offset) ld (Total_Drives),a ;Install the Total Number of Drives ret ;Return ;---------------------------------------------------------------------- ; Strip Leading White Space (1_Oct_84) ;------------------------------------- ; 1) This routine is used by the Get_Input_Param routine to remove ; white space between tokens on the Command Tail. ; 2) Register Usage: ; A -> Returned equal to the Character found or 0 if End of Line ; HL -> Pointer to Current Location in the Command Line ; Strip_White: ld a,(hl) ;While (Not at the End of the Line) or a ret z ; (Return 0 for Eol) inc hl ; HL:= Pointer to Next Character cp ' ' ; If ( (Char ne Space) And jr z,Strip_White cp Tab ; (Char ne Tab) And jr z,Strip_White cp ',' ; (Char ne Comma) ) jr z,Strip_White ret ; Return page ;====================================================================== ; Get the Drive on Which to Format (3_Oct_84) ;============================================ ; 1) This routine picks the Drive that is to be used to format. ; 2) Register Usage: ; A -> Returned 0 to Continue; Non_Zero to Stop ; Get_Drive: ld a,(Cmd_Line_True) ;A:= Command Tail Active Flag or a jr z,GdSk1 ;If (There was a Valid Command Tail) ld a,(Cmd_Line_Drive) ; A:= Drive from Command Tail) call Drive_In_Range ; If (Drive is Valid) or a ret z ; Return GdSk1: ld a,Msg_Drive call Print_Message ;Print the Drive Prompt call Valid_Drives ;Print the List of Valid Drives ld a,Msg_Press_Rtn call Print_Message ;Print 'or Press Return to ... GdLp1: call Get_Character ;Loop Get the Response cp Control_C ; If (Repsonse is Control C) ret z ; Return cp Cr ; If (Response eq Cr) ret z ; Return call Drive_In_Range ; If (Drive is Valid) or a ret z ; Return call Erase_Character ; Erase the Character jr GdLp1 page ;---------------------------------------------------------------------- ; Print the Valid Drives (25_Sept_84) ;------------------------------------ ; 1) This routine prints the current valid drive letters in the ; format '(A,B,....N) '. ; Valid_Drives: ld a,'(' call Put_Character ;Print the Opening Parenthesis ld a,(Total_Drives) ld b,a ;B:= Number of Logical Drives ld c,'A' ;C:= Initial Drive Letter VaLp1: ld a,c ;Loop A:= Drive Letter call Put_Character ; Print the Drive Letter djnz VaSk1 ; If (all letters printed) ld a,')' call Put_Character ; Print Closing Paren. ld a,' ' call Put_Character ; Print a Space ret ; Return VaSk1: ld a,',' call Put_Character ; Print a Comma inc c ; Increment to the Next Drive jr VaLp1 page ;---------------------------------------------------------------------- ; Check if the Drive Letter is in Range (1_Oct_84) ;------------------------------------------------- ; 1) This routine checks if a drive letter is valid for the current ; system. The valid range is determined by Total_Drives setup in ; the Get_Input_Param routine. ; 2) If the Drive is valid then Drive_Number is installed and the ; accm is returned equal to zero. ; 3) If the Drive in NOT valid then the accm is returned non-zero. ; Drive_In_Range: and 5Fh ;Force to Response Upper Case sub 'A' ;Set Response to Zero Base ld c,a ;C:= User Repsone (Zero Base) ld a,(Total_Drives) dec a ;A:= Number of Drives (Zero Base) cp c ;If (Selection is NOT in Range) ld a,0FFh ; A:= Drive Not In Range ret c ; Return ld a,c ;A:= Drive to Format ld (Drive_Number),a ;Install the Drive to Format ld a,0 ;A:= Drive in Range ret ;Return page ;====================================================================== ; Get the Drive Data From the Mtab (2_Oct_84) ;============================================ ; 1) This routine figures the number of Logical Tracks and whether or ; not this is a hard disk. ; 2) Register Usage: ; A -> Returned 0 for Floppy; Non-Zero for Hard Disk ; DE -> Used to hold offsets ; HL -> Used as a Pointer and as a 16 bit accumulator ; Get_Drive_Data: 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 push af and $HdMsk ;Remove all But the Head Number srl a srl a ;Move Heads to Lsb's inc a ;A:= Absolute Number of Heads inc hl ;(DskDef1) inc hl ;(DskDef2) inc hl ;(PrkOff) inc hl ;(MaxCyl) ld e,(hl) inc hl ld d,(hl) ex de,hl ;HL:= Max Cylinders ld e,a ld d,0 ;DE:= Number of Heads call Multiply dec hl ;HL:= Number of Logical Tracks (0 base) ld (Highest_Track),hl ;Save the Number of Logical Tracks pop af ;A:= DskDef0 and $HrdDsk ;(Hard_Disk=2, Floppy_Disk=0) ret ;Return page ;====================================================================== ; Format a Hard Disk (5_Oct_84) ;============================== ; 1) This routine formats one track of the Hard Disk. ; 2) Register Usage: ; A -> Returned equal to ReStart or Control_C ; ----> All other registers are destroyed. ; Format_Hard: ld a,0FFh ;A:= Hard Disk (non zero) call Put_Boot_Image ;Setup the Boot Image call Hard_Setup ;Setup for the Format Operation or a ;If (User decided NOT to format) ret nz ; Return FhLp1: ld hl,Hrd_Gap_Skew ;Loop HL:= Hard Disk Gap/Skew Table call Format_Common ; Format the Disk or a ; If (NO Fatal Errors) jr nz,FhSk2 call Verify_Common ; Verify the Disk or a ; If (NO Fatal Errors) jr nz,FhSk2 ld hl,(ReMap_Count) ; Get ReMap Count ld a,h or l jr z,FhSk1 ; If (Errors eq True) ld a,Msg_Bad_Rpt call Print_Message ; Print Warning ld hl,(ReMap_Count) call Print_Number jr FhSk2 FhSk1: ld a,Msg_No_Bad_Rpt ; Else call Print_Message ; Print No Bad FhSk2: ld a,(System_Flag) ; If (Copysys is Needed) or a jr z,FhSk3 call Do_Copysys ; Try to do Copysys FhSk3: call Next_Operation ; Prompt for Next Operation cp Again jr z,FhLp1 ;Until (Response ne Again) push af ld a,0 ld (System_Flag),a ;Reset Destination Drive pop af ;A:= Response from Next Operation ret ;Return page ;---------------------------------------------------------------------- ; Setup for a Hard Disk Format Operation (3_Oct_84) ;-------------------------------------------------- ; 1) This routine prompts for and then aquires the Hard Disk Format ; Options (Format System or Format All). ; 2) If the response matches SYSTEM or CONTINUE then the accm is ; returned equal to 0 else its returned equal to ReStart. ; 3) If the response is equal to SYSTEM then the System_Flag indicating ; that a copysys operation is needed is set to true and the drive ; designators of the two Fcbs (for copysys and sysldr) are installed. ; Also, the highest track is reduced to 0. ; 4) Register Usage: ; A -> Returned = 0 for a match; Else its = ReStart or Control_C ; ----> All other registers destroyed. ; Hard_Setup: ld a,Msg_Banner call Print_Message ;Print the Banner ld a,Msg_Hard_Opt call Print_Message ;Print the Hard Disk Options ld de,Response_Buf ;DE:= Pointer to the Response Buffer ld c,Bdos_ConBuf_In ;C:= Read Console Input Buffer Function call Bdos_Entry ;Read the Response ld a,(Response_Buf+2) ;If (1st Character eq Control C) cp Control_C ret z ; Return ld de,System_Str ;DE:= SYSTEM String call String_Match ;If (Response Matches SYSTEM) or a jr nz,HsSk1 call Read_Boot ; Read the Boot Sector or a ; If (Boot Sector Not Read) ret nz ; Return ld bc,0 ld (Highest_Track),bc ; Reset Number of Tracks to 1 ld a,(Drive_Number) inc a ; A:= Logical Drive For Search ld (CopySys_Fcb),a ; Setup Copysys's Fcb ld (SysLdr_Fcb),a ; Setup SysLdr's Fcb ld (System_Flag),a ; Set Flag that Copysys is Needed ld a,(Boot_Reminder) ; Boot Reminder Flag for Floppys or a ; If (Floppy A: hasn't been Formatted) ret z ; Return (A:= 0) ld a,Msg_Reminder ; Else call Print_Message ; Print the Boot Reminder call Pause_for_Rtn ; Wait for the Return Key ld a,0 ; A:= Ok to Format ret ; Return HsSk1: ld de,Continue_Str ;DE:= CONTINUE String call String_Match ;If (Response Matches CONTINUE) or a jr nz,HsSk2 ld a,0 ; A:= Ok to Format ret ; Return HsSk2: ld a,ReStart ;A:= ReStart ret ;Return page ;---------------------------------------------------------------------- ; Match Two Strings (25_Sept_84) ;------------------------------- ; 1) This routine matches two strings. The 1st string is a user ; variable (pointed to by DE). ; 2) The second string is a pointer to the local data buffer. ; String_Match: ld hl,Response_Buf+1 ;HL:= Pointer to Length of Reponse Buf ld a,(de) ;A:= Length of String to Match cp (hl) ;If (String Lengths Match) jr nz,SmNo ld b,a ; B:= Length of String SmLp1: inc hl ; Repeat Inc Repsonse Buf Pntr inc de ; Inc Match String Pntr ld a,(de) ; If (String ne Response) cp (hl) jr nz,SmNo ; Break djnz SmLp1 ; Until (Whole String Checked) ld a,0 ; A:= Match Succeded ret ; Return SmNo: ld a,0FFh ;A:= Match Failed ret ;Return page ;---------------------------------------------------------------------- ; Try to Copy a System onto Track Zero (2_Oct_84) ;------------------------------------------------ ; 1) This routine checks if the files required for a copysys (copysys.com ; and sysldr.com) are present on the hard disk. ; 2) If the files required are not present then a reminder message is ; issued telling the user that a system loader will have to be put ; on the disk before it can be booted. ; 3) If the files are present then control is transferred to Load_and_Go. ; 4) Notice that the user is told about the copysys operation and given ; a chance to avoid it by typing a Control C. ; Do_Copysys: ld de,Buffer+Sector_Length ;DE:= Pointer to End of Local Buffer ld c,Bdos_Set_Dma ;C:= Set the Dma Address Function call Bdos_Entry ;Initialize the Dma Address ld de,CopySys_Fcb ;DE:= Pointer to CopySys Fcb ld c,Bdos_Search ;C:= Search for File Function call Bdos_Entry ;Search for Copysys.com cp 4 ;If (File Found) jr nc,DcSk1 ld de,SysLdr_Fcb ; DE:= Pointer to SysLdr Fcb ld c,Bdos_Search ; C:= Search for File Function call Bdos_Entry ; Search for SysLdr.com cp 4 ; If (File Found) jr nc,DcSk1 ld a,Msg_Chaining ; New System Message call Print_Message call Pause_for_Rtn ; Wait for Continue cp Control_C ; If (Continue ne True) ret z ; Return jp Load_and_Go ; Chain to Copysys DcSk1: ld a,Msg_New_System ;Else call Print_Message ; Print the Boot Warning Message ret ; Return page ;====================================================================== ; Format a Floppy Disk (3_Oct_84) ;================================ ; 1) This routine formats a floppy disk. ; 2) Boot_Reminder is set true if the floppy disk being formatted is ; the Logical A: drive. ; 3) Register Usage: ; A -> Returned equal to Control_C (Exit) or ReStart ; Format_Floppy: ld a,(Drive_Number) ;A:= Current Drive Number add a,'A' ld (Fdrive),a ;Install Drive Letter in format message cp 'A' jr nz,FfSk1 ;If (This is Drive A:) ld (Boot_Reminder),a ; Set Boot Reminder True FfSk1: ld a,0 ;A:= Floppy Disk (zero) call Put_Boot_Image ;Setup the Boot Image call Floppy_Setup ;Setup the Floppy Format Parameters or a ;If (User Decided Not to Format) ret nz ; Return FfLp1: ld a,Msg_Ready ;Loop call Print_Message ; Print the Ready Message call Pause_for_Rtn ; Wait for the Return Key cp Control_C ; If (Repsonse is Control C) ret z ; Return ld hl,Flp_Gap_Skew ; HL:= Floppy Disk Gap/Skew Table call Format_Common ; Format the Disk or a ; If (Fatal Errors eq False) jr nz,FfSk2 call Verify_Common ; Verify the Disk or a ; If (Fatal Errors eq False) jr nz,FfSk2 ld hl,(ReMap_Count) ; Get ReMap Count ld a,h or l jr z,FfSk2 ; If (Errors eq True) ld a,Msg_Warning call Print_Message ; Print Warning FfSk2: call Next_Operation ; cp Again jr z,FfLp1 ;Until (Response ne Again) ret ;Return page ;---------------------------------------------------------------------- ; Setup for a Floppy Format Operation (4_Oct_84) ;----------------------------------------------- ; 1) This routine determines the number of sides on the disk to be ; formatted either by looking at the command tail parameters (if ; present) or by interacting with the user. Using the number of ; sides value, the Highest_Track and Mtab/Dpb and (Density). Also ; the message announcing the format (sides--density) is printed. ; 2) Register Usage: ; A -> Returned 0 to continue or Control_C to Stop ; ----> All other registers are destroyed. ; Floppy_Setup: ld a,(Cmd_Line_True) ;A:= Command Tail Active Flag or a jr z,FsSk0 ;If (There was a Valid Command Tail) ld a,(Cmd_Line_Sides) ; Get the Number of Sides and 5Fh ; Force to Response Upper Case cp 'S' ; If (Char eq S) jr z,FsSk_S ; Goto Single Sided Proc cp 'D' ; Else If (Char eq D) jr z,FsSk_D ; Goto Double Sided Proc FsSk0: ld a,Msg_Banner call Print_Message ;Print the Banner ld a,Msg_Floppy_Opt call Print_Message ;Print the Floppy Options FsLp1: call Get_Character ;Loop Wait for the Response cp Control_C ; If (Response eq Return to CP/M) ret z ; Return and 5Fh ; Force Response to Upper Case cp 'S' ; If (Response eq Single Sided) jr nz,FsSk1 FsSk_S: ld de,39 ; DE:= Number of Tracks ld hl,Sngl_Mtab_Dpb ; HL:= Pointer to Mtab/Dpb ld a,Msg_Single ; A:= Single Sided Message jr FsSk4 ; Break FsSk1: cp 'D' ; If (Repsonse eq Double) jr nz,FsSk2 FsSk_D: ld de,79 ; DE:= Number of Tracks ld hl,Dbl_Mtab_Dpb ; HL:= Pointer to Mtab/Dpb ld a,Msg_Double ; A:= Double Sided Message jr FsSk4 ; Break FsSk2: cp Cr ; If (Response eq Cr) jr nz,FsSk3 ld a,ReStart ; A:= ReStart ret ; Return FsSk3: call Erase_Character ; Else Erase the Character jr nz,FsLp1 FsSk4: push af ld (Highest_Track),de ;Save the Number of Tracks ld de,Buffer+Mtab_Offset ld bc,Descriptor_Leng ldir ;Overlay the Mtab/Dpb pop af call Print_Message ;Print Number of Sides Message ld a,0 ret page ;---------------------------------------------------------------------- ; Common Format Routine (17_Dec_84) ;--------------------------------- ; 1) This routine formats from Highest_Track down to Track 0 for ; both hard and floppy disks. ; 2) At the end of routine the first 2 sectors are written with the ; contents of local buffer (Buffer). ; 3) Notice that a pointer to the appropriate Gap/Skew table is ; passed in the HL register pair. ; 4) Notice that directly after storing the Gap/Skew pointer the IMS ; buffer is turned off. ; 5) Register Usage: ; A -> Returned equal to 0 for no errors. ; HL -> On entry contains a pointer to the Gap/Skew table ; ----> All other registers are destroyed. ; Format_Common: ld (Apif+HstSec_Offset),hl ;Turn Off the Ims Buffer ld a,EB_Get_RamDatY ;A:= Copy RamDatY and Apif to Tpa Funct ld de,Buffer+Sector_Length ;DE:= Pointer to Local Buffer+Sector call Extended_Bios ;Move System Memory into local buffer ld a,(Buffer+Sector_Length+CFlag_Offset) ld (Local_Cflag),a ;Save the Entry Value of CFLag res @imsact,a ld (Buffer+Sector_Length+CFlag_Offset),a ld a,EB_Put_Sys_Mem ;A:= Write to System Memory Function ex de,hl call Extended_Bios ;Turn Off Ims ld a,Msg_Banner call Print_Message ;ReDisplay the Banner ld a,Msg_Format call Print_Message ;Print the Formatting Message ld a,(Drive_Number) ld (Apif+HstDsk_Offset),a ;Install The Drive Number ld hl,(Highest_Track) ;Install the Track Number FcLp1: ld (Apif+HstTrk_Offset),hl ;Loop push hl ld a,Cr call Put_Character ld a,Tab call Put_Character ld hl,(Apif+HstTrk_Offset) call Print_Number ; Print the Track Number ld ix,Apif ; IX:= Pointer to Local Apif ld de,Buffer+Mtab_Offset ; DE:= Pointer to Mtab/Dpb ld a,EB_Format ; A:= Format a Track Function call Extended_Bios ; Format the Track pop hl ld a,d ; A:= Returned Status or a ; If (There was an Error) ret nz ; Return ld a,h ; If (Track Number eq 0) or l jr z,FcSk1 ; Break dec hl ; Track_Number:= Track_Number - 1 jr FcLp1 FcSk1: ld hl,1 call Write_Boot ;Write Boot Sector or a ;If (There was NO Error) ret nz ld hl,2 call Write_Boot ; Write CCP Sector ret ;Return page ;---------------------------------------------------------------------- ; Verify the Data (1_Oct_84) ;--------------------------- ; 1) This routine verifies tracks on the selected disk from 0 to ; Highest_Track for both hard and floppy disks. ; 2) The variable ReMap_Count holds the number of soft error encountered. ; 3) Notice that after a soft error the entire screen is reprinted. ; 4) Register Usage: ; A -> Returned 0 if NO Error ; ----> all other registers destroyed. ; Verify_Common: ld hl,0 ld (ReMap_Count),hl ;ReMapped Sector Count ld a,Msg_Banner call Print_Message ;Print the Banner ld a,Msg_Verify call Print_Message ;Print Verifying ld bc,0 ;BC:= 0 (Current Track Number) VdLp1: push bc ;Loop ld hl,(Bios_Entry+1) ld l,SetTrk_Offset ; HL:= Vector to SetTrk ld a,EB_Execute ; A:= Execute in the System Bank call Extended_Bios ; Set the Track Number (in BC) ld a,Cr call Put_Character ld a,Tab call Put_Character pop hl push hl call Print_Number ; Print the Track Number ld a,EB_Verify_D ; A:= Verify Destructive call Extended_Bios ; Verify the Track pop bc ld a,d ; A:= Returned Error Status or a ; If (There was an Abort) ret nz ; Return ld a,e ; A:= Bad Sectors Found or a jr z,VdSk1 ; If (There were Bad Sectors) ld d,0 ; DE:= Number of ReMaps ld hl,(ReMap_Count) ; HL:= ReMaps made so far add hl,de ld (ReMap_Count),hl ; Update Total ReMap Count push bc ld a,Msg_Banner call Print_Message ; ReDisplay the Banner ld a,Msg_Verify call Print_Message ; Print Verifying pop bc VdSk1: ld hl,(Highest_Track) ; HL:= Track Number xor a ; (Clear Carry and Set Accm to 0) sbc hl,bc ; If (Current_Track eq Highest_Track) ret z ; Return inc bc ; Track_Number:= Track_Number + 1 jr nz,VdLp1 page ;---------------------------------------------------------------------- ; Setup the Boot Image in the Local Buffer (3_Oct_84) ;---------------------------------------------------- ; 1) This routine sets up the Boot Image written to sectors 1 and 2. ; 2) Register Usage: ; A -> On entry 0=Floppy, Not_0=Hard Disk ; ----> All other registers destroyed. ; Put_Boot_Image: push af ld de,Buffer ;DE:= Master copy of the Boot Sector ld hl,CCP1 ;HL:= Destination (Local Buffer) ld bc,Sector_Length ;BC:= Length of the Boot Sector ldir ;Move Boot Sector Image to Local Buffer pop af or a ;If (This is a Hard Disk) jr z,PbSk1 ld hl,FE_Hard ; HL:= Source (Hard Disk No Sys) ld de,Emsg - CCP1 + Buffer ; DE:= Destintion ld bc,FE_Hrd_Length ; BC:= Length ldir ; Load the No System Message ret ; Return PbSk1: ld hl,FE_Floppy ;Else HL:= Source (Floppy No System) ld de,Emsg - CCP1 + Buffer ; DE:= Destination ld bc,FE_Flp_Length ; BC:= Length ldir ; Load the No System Message ld hl,Buffer+BadID_Offset ld bc,Sector_Length-BadID_Offset PbLp1: ld (hl),0E5h ; Repeat Overlay w/fill Char inc hl ; Inc Storage Pointer dec bc ; Dec Fill Count ld a,b or c jr nz,PbLp1 ; Until (Rem. Sector Filled w/E5) ret ; Return page ;---------------------------------------------------------------------- ; Read Bad Map Sector (1_Oct_84) ;------------------------------- ; 1) This routine reads the boot sector from the hard disk. ; 2) If there's an error then an Error Message is Printed and the ; Pause_for_Rtn routine is executed. ; 3) If there was NO Error made in reading the boot sector then the ; local copy of the boot sector (kept in Buffer) is overlaid with ; bad map portion of boot sector (starting with the bad map Id block) ; 4) Register Usage: ; A -> Returned 0 (no error), ReStart or Control_C (user response) ; ----> all other registers destroyed ; Read_Boot: ld a,(Drive_Number) ld (Apif+HstDsk_Offset),a ;Install The Drive Number ld hl,0 ld (Apif+HstTrk_Offset),hl ;Set the Track to Zero ld hl,1 ld (Apif+HstSec_Offset),hl ;Set the Sector to One ld ix,Apif ld a,EB_Read_Host call Extended_Bios ;Read a Sector From the Disk or a ;If (There was an Error) jr z,BrSk1 ld a,Err_Boot_Read ; A:= Boot Read Error Message call Print_Message ; Print the Error Message call Pause_for_Rtn ; Wait for User to Respond ret ; Return (A=ReStart or Control_C) BrSk1: ld de,Buffer+BadID_Offset ld hl,Sys_Disk_Buffer+BadID_Offset ld bc,Sector_Length-BadID_Offset ld a,EB_Get_Sys_Mem ;A:= Read the Disk Buffer Function call Extended_Bios ;Overlay the Local Copy of the Bad Map ld a,0 ;A:= No Error ret ;Return page ;---------------------------------------------------------------------- ; Write the Boot Sector (3_Oct_84) ;--------------------------------- ; 1) This routine writes the local buffer (Buffer) out to one of the ; sectors on track 0. The actual sector is chosen by the calling ; routine and passed in the HL pair. ; 2) Register Usage: ; A -> Returned 0 for NO Errors. ; HL -> On Entry holds the Sector to write ; ----> All other registers destroyed ; Write_Boot: ld (Apif+HstSec_Offset),hl ;Install the Sector Number ld a,(Drive_Number) ld (Apif+HstDsk_Offset),a ;Install The Drive Number ld hl,0 ld (Apif+HstTrk_Offset),hl ;Set the Track to Zero ld de,Sys_Disk_Buffer ;DE:= Destination ld hl,Buffer ;HL:= Source ld bc,Sector_Length ;BC:= Length ld a,EB_Put_Sys_Mem ;A:= Write to the Disk Buffer Function call Extended_Bios ;Move Local Buffer into Disk Buffer ld ix,Apif ld a,EB_Write_Host call Extended_Bios ;Write a Sector to the Disk or a ;If (There was NO Error) ret z ; Return ld a,Err_Boot_Write ;A:= Boot Write Error call Print_Message ;Print the Error Message ld a,ReStart ;A:= ReStart Code ret ;Return page ;====================================================================== ; Restore the Input Parameters (13_Dec_84) ;========================================= ; 1) This routine restores the Entry Value of CFlag and the Logged ; on Drive. If the boot reminder flag has been set then the user ; is also prompted to re:insert the boot diskette. ; Restore_Param: ld a,EB_Get_RamDatY ;Copy RamDatY and Apif to Tpa call Get_Buffer ;Read the RamDatY ld a,(Local_Cflag) ld (Buffer+CFlag_Offset),a call Put_Buffer ;Restore the Entry Value of CFLag ld a,(Boot_Reminder) ;If (the A:Floppy was Formatted) or a jr z,RpSk1 ld a,Msg_Reminder call Print_Message ; Print the Boot Reminder Msg call Pause_for_Rtn ; Wait for the Return Key RpSk1: ld c,Bdos_Select ;C:= Select Disk Function ld a,(Initial_Drive) ld e,a ;E:= Drive to Select call Bdos_Entry ;Reselect drive we started with ret ;Return page ;---------------------------------------------------------------------- ; Prompt for Next Operation (5_Oct_84) ;------------------------------------- ; 1) This routine prints the Formatting done message. If the parameters ; came from a command tail then that's all it does; Otherwise, the ; user is given the option of using the same paramters again, choosing ; a new set of paramters or of exiting to the system. ; 2) When the exit to Cp/m option is chosen the Boot_Reminder flag is ; checked to find out if the A: drive is a) the boot drive and b) has ; been used in a format operation. If Boot_Reminder is true then the ; user is reminded to ReInsert the boot disk into drive A:. ; Next_Operation: ld a,Msg_Format_Done ;Formatting Done call Print_Message ;Print the Finished Message ld a,(Cmd_Line_True) ;A:= Command Tail Active Flag or a ;If (There was a Valid Command Tail) jr z,NoSk1 ld a,Control_C ; A:= Control C (Exit) ret ; Return NoSk1: ld a,Msg_Start_Again ;Again ReStart Exit call Print_Message ;Print the Restart options NoLp1: call Get_Character ;Loop Wait for the Response cp Control_C ; If (Response eq Return to CP/M) ret z ; Return and 5Fh ; Force Response to Upper Case cp Again ; If (Response eq Again) ret z ; Return cp ReStart ; Else If (Response eq ReStart) ret z ; Return cp Cr ; Else If (Response eq Return) ld a,Control_C ; A:= Exit ret z ; Return call Erase_Character ; Else Erase the Character jr NoLp1 page ;---------------------------------------------------------------------- ; Print a Number in the Current Base (1_Oct_84) ;---------------------------------------------- ; 1) This routine prints the 16 bit number (passed in the HL) in ascii ; in the current radix. ; 2) Note that this routine makes use of the divide routine at the end ; of this file. ; 3) Register Usage: ; HL -> On Entry is the 16 bit number to be printed ; Print_Number: ld a,l ;If (The Number is Zero) or h jr nz,Dsk1 ld a,' ' ; call Put_Character ; Print a Space ld a,'0' call Put_Character ; Print the zero ret ; Return Dsk1: ld bc,0FFFFh push bc ;Put end flag on stack DLp2: ld bc,(Output_Radix) ;Repeat divisor:= Current Radix call divide ; Divide push hl ; Save the remainder ld hl,9 or a sbc hl,de ex de,hl ; (Move quotient to dividend) jp c,DLp2 ;Until (quotient is less than 9) DLp3: ld a,l ;While (Result eq 0) or a jr nz,DLp4 ld a,' ' call Put_Character ; Print a Space pop hl ; Get the next number jr DLp3 DLp4: add a,'0' ;Repeat Convert number to ascii call Put_Character ; Print the number pop hl ; Get the next number ld a,l cp 0FFh jr nz,DLp4 ;Until (end of stack flag has been read) ld a,' ' ; call Put_Character ;Print a Space 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,EB_Put_Sys_Mem ;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_Dec_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_Boot_Read ;Unable to Read the Boot Sector dw EMbr db Err_Boot_Write ;Unable to Write the Boot Sector dw EMbw db Msg_Banner ;Title Banner dw MsgOpn db Msg_Drive ;Drive Prompt dw MsgDrv db Msg_Hard_Opt ;Hard Disk Options Prompt dw MsgHrd db Msg_Floppy_Opt ;Floppy Disk Options Prompt dw MsgFlp db Msg_Single ;Start of Single Sided Floppy Format dw MsgSgl db Msg_Double ;Start of Double Sided Floppy Format dw MsgDbl db Msg_Ready ;Ready to Fromat Prompt dw MsgRdy db Msg_Format ;Beginning Format dw MsgFmt db Msg_Verify ;Beginning Verification dw MsgVer db Msg_Warning ;Some Errors were made dw MsgWrn db Msg_Format_Done ;Formatting Done (Again ReStart Exit) dw MsgFmd db Msg_Start_Again ;Again ReStart Exit dw MsgRst db Msg_Reminder ;Reminder to Insert the Boot Disk dw MsgRem db Msg_Bad_Rpt ;Bad Sectors Found dw MsgBs db Msg_No_Bad_Rpt ;No Bad Sectors Found dw MsgNbs db Msg_Pause ;Pause for Input Prompt dw MsgPas db Msg_New_System ;New System Message dw MsgNs db Msg_Chaining ;New System Being Installed dw MsgCha 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 (17_Dec_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,'$' EMbr: db Cr,Lf,Tab db 'Unable to Read the Boot Sector',Cr,Lf,'$' EMbw: db Cr,Lf,Tab db 'Unable to Write the Boot Sector',Cr,Lf,'$' NoCode: db Cr,Lf,Tab db 'Unrecognized Error $' page ;---------------------------------------------------------------------- ; Message Strings (5_Oct_84) ;--------------------------- ; MsgOpn: db Clear_Screen,Esc,Dim,Cr db 'MD-HD ' db Esc,Bright db 'Format ' db Esc,Dim db 'Program Rev ' db ((FRev and 0F0h) shr 4) + '0', '.', (FRev and 0Fh) + '0' db Tab,Tab,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,'$' MsgDrv: db Cr,Lf,Tab,Tab,Tab db Esc,Bright db ' Drive Selection' db Esc,Dim db Cr,Lf,Lf,Lf,Tab db Esc,Bright db 'Enter ' db Esc,Dim db 'the letter of the drive you want to use ' db Esc,Bright,'$' MsgRet: db Cr,Lf,Tab db Esc,Dim db 'or Press RETURN to exit to CP/M ' db Esc,Bright,'$' MsgHrd: db Cr,Lf,Tab,Tab,Tab db Esc,Bright db ' Hard Disk Options' db Esc,Dim db Cr,Lf,Lf,Lf,Tab db 'Type ' db Esc,Bright db 'CONTINUE ' db Esc,Dim db 'to format your entire disk.' db Cr,Lf,Tab,Tab db '- This operation ' db Esc,Bright db 'WILL ERASE ALL DATA ' db Esc,Dim db 'currently on your disk.' db Cr,Lf,Tab,Tab db ' Make sure you have saved as many of your files as you can.' db Cr,Lf,Tab,Tab db ' Use PIP or Backfield.' db Cr,Lf,Lf,Tab db 'Type ' db Esc,Bright db 'SYSTEM ' db Esc,Dim db 'to format only your system tracks.' db Cr,Lf,Tab,Tab db '- If possible, this option also restores the system loader' db Cr,Lf,Tab,Tab db ' program onto the system tracks. This option does not' db Cr,Lf,Tab,Tab db ' format beyond the system tracks and does not create a map' db Cr,Lf,Tab,Tab db ' of bad sectors; therefore it is NOT to be used with' db Cr,Lf,Tab,Tab db ' brand-new (unformatted) disks.' db Cr,Lf,Lf,Tab db Esc,Bright db 'Enter ' db Esc,Dim db 'your choice in UPPER CASE and press RETURN or simply' db Cr,Lf,Tab db 'press RETURN to get back to the previous Menu: ' db Esc,Bright,'$' MsgFlp: db Cr,Lf,Tab,Tab,Tab db Esc,Bright db ' Floppy Disk Options' db Esc,Dim db Cr,Lf,Lf,Lf,Tab db 'Type ' db Esc,Bright db 'D ' db Esc,Dim db 'to format a ' db Esc,Bright db 'DOUBLE ' db Esc,Dim db 'Sided Disk' db Cr,Lf,Tab,Tab db '- This will produce a Morrow Standard 384-Kbyte Disk' db Cr,Lf,Tab,Tab db ' (compatible with all Micro Decisions except MD-2)' db Cr,Lf,Lf,Tab db 'Type ' db Esc,Bright db 'S ' db Esc,Dim db 'to format a ' db Esc,Bright db 'SINGLE ' db Esc,Dim db 'Sided Disk' db Cr,Lf,Tab,Tab db '- This will produce a Morrow Standard 192-Kbyte Disk' db Cr,Lf,Tab,Tab db ' (compatible with all Micro Decisions)' db Cr,Lf,Lf,Tab db Esc,Bright db 'Enter ' db Esc,Dim db 'the letter of your choice or simply press RETURN to ' db Cr,Lf,Tab db 'go back to the previous menu: ' db Esc,Bright,'$' MsgSgl: db Cr,Lf,Lf,Tab db Esc,Dim db 'Format specified is ' db Esc,Bright db 'Single Sided -- Double Density' db Esc,Dim,'$' MsgDbl: db Cr,Lf,Lf,Tab db 'Format specified is ' db Esc,Bright db 'Double Sided -- Double Density' db Esc,Dim,'$' MsgRdy: db Cr,Lf,Lf,Tab db Esc,Dim db 'Insert the diskette to be formatted into your ' db Esc,Bright Fdrive: db 0,': drive. ' db Esc,Dim,'$' MsgFmt: db Cr,Lf,Lf,Lf,Tab db Esc,Dim db Tab,'is the Track being ' db Esc,Bright db 'Formatted $' MsgVer: db Cr,Lf,Lf,Lf,Tab db Esc,Dim db Tab,'is the Track being ' db Esc,Bright db 'Verified $' MsgWrn: db Cr,Lf,Lf,Tab db Esc,Bright db 'Some errors were found on this diskette,' db ' use it at your own risk.' db Esc,Dim,'$' MsgFmd: db Cr,Lf,Lf,Tab db Esc,Bright db 'Formatting Operation Finished$' MsgRst: db Esc,Dim db ' -- ' db Esc,Bright db 'Press:' db Esc,Dim db Cr,Lf,Lf,Tab,Tab db Esc,Bright db 'A ' db Esc,Dim db 'to use the same format Again' db Cr,Lf,Tab,Tab db Esc,Bright db 'R ' db Esc,Dim db 'to Restart with a new format' db Cr,Lf,Tab,Tab db Esc,Bright db 'RETURN ' db Esc,Dim db 'to quit formatting and return to CP/M $' MsgRem: db Cr,Lf,Lf,Tab db Esc,Dim db 'Insert your boot disk back into your ' db Esc,Bright db 'A: drive. ' db Esc,Dim,'$' MsgBs: db Cr,Lf,Lf,Tab db Esc,Bright db 'Bad sectors found on this disk totaled $' MsgNbs: db Cr,Lf,Lf,Tab db Esc,Dim db 'There were No bad sectors found. $' 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,'$' MsgNs: db Cr,Lf,Lf,Tab db Esc,Dim db 'You will need to put SYSLDR.COM on your hard disk by' db Cr,Lf,Tab db 'using COPYSYS.COM before you can boot from it.' db Cr,Lf,Tab db 'See page 3-10 in the MD-11 User''s Guide for details.' db Cr,Lf,'$' MsgCha: db Cr,Lf,Lf,Tab db Esc,Dim db 'Ready to install the System Loader. At the end of this' db Cr,Lf,Tab db 'operation you will exit from the format program.' db Cr,Lf,'$' CrLf: db Cr,Lf,'$' page ;---------------------------------------------------------------------- ; Data Area (13_Dec_84) ;--------------------- ; ;Input Command Line Parameters Cmd_Line_Drive: db 0 ;Drive Letter from the Command Tail Cmd_Line_Sides: db 0 ;Number of Sides from the Command Tail ;Flag Bytes Cmd_Line_True: db 0 ;Command Tail Present Flag System_Flag: db 0 ;Flag that a copysys is needed Boot_Reminder: db 0 ;Boot Reminder Flag for Floppys ;Hard Disk Gap/Skew Table Hrd_Gap_Skew: dâ 0,14,° ;Harä Disk Gap Table db 2,4,6,8,1 ;Hard Disk Skew Table db 3,5,7,0 ;Floppy Disk Skew/Gap Table Flp_Gap_Skew: db 50,85,80 ;Floppy Disk Gap Table db 5,4,3,2,1 ;Floppy Disk Skew Table ;Single Density Mtab/Dpb,CheckSum Sngl_Mtab_Dpb: db 0,0,0,0,0 ;Single Density Mtab db 0,0,0,0 db 40,0,4,15,1,94 ;Single Density Dpb db 0,127,0,192,0 db 32,0,2,0 db 0E1h ;CheckSum ;Double Density Mtab/Dpb,CheckSum Dbl_Mtab_Dpb: db 0,4,0,0,0 ;Double Density Mtab db 0,0,0,0 db 40,0,4,15,1,194 ;Double Density Dpb db 0,191,0,224,0 db 48,0,2,0 db 89h ;Checksum ;Strings for Hard Disk Operations Continue_Str: db 8,'CONTINUE' ;Match String for Format All System_Str: db 6,'SYSTEM' ; " " " " System ;'Not a SYSTEM Disk' String for Floppy Disks FE_Floppy: db Cr,Lf db 'This Floppy ' db 'Disk Has NO ' db 'SYSTEM' db Cr,Lf,0 End_FE_Floppy: FE_Flp_Length equ End_FE_Floppy - FE_Floppy ;'Not a SYSTEM Disk' String for Hard Disks FE_Hard: db Cr,Lf db 'This Hard ' db 'Disk has NO ' db 'SYSTEM LOADER' db Cr,Lf,0 End_FE_Hard: ;Ims String used when formatting the hard disk system track Chain_Ims: db End_Chain_Ims - Chain_Ims - 1 db 'n',Cr End_Chain_Ims: ;Other Parameters Local_Cflag: db 0 ;Local Copy of Entry Value of CFlag Initial_Drive: db 0 ;Current Drive when program started Total_Drives: db 0 ;Number of Logical Drives Available Drive_Number: db 0 ;Format Disk Number (A:= 0) Highest_Track: dw 0 ;Highest Logical Track Number ReMap_Count: dw 0 ;ReMapped Sector Count Output_Radix: dw 10 ;Radix for Print Number Routine ;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 " " 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 ;---------------------------------------------------------------------- ; Load and Go (2_Oct_84) ;----------------------- ; Load_and_Go: ld de,Chain_Ims ;DE:= Pointer to Ims String ld a,EB_Inject_Ims ;A:= Inject Ims Function call Extended_Bios ;Inject Copysys Ims String ld hl,CopySys_Fcb ld de,Default_Fcb1 ld bc,36 ldir ;Move the Copysys Fcb Into Place ld hl,(Bdos_Entry+1) ld bc,Load_Length ;BC:= Load Length or a ;(clear the carry) sbc hl,bc push hl ex de,hl ;DE:= Destination (Base Bdos - 2 pages) ld hl,Start_Lgo ;HL:= Source (beginning of Lgo) ldir ;Move the code into place pop hl jp (hl) ;Execute the Loader page ;---------------------------------------------------------------------- ; This portion of the load and Go routine is relocated into hi memory. ;--------------------------------------------------------------------- ; Start_Lgo: ld sp,100h ;Set the Stack Pointer ;Open the Command's File 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) jp z,Bios_Entry ; Warm Start ;Read the Command File ld de,100h - Record_Length ;DE:= Dma Pointer to start Load LGlp1: ld hl,Record_Length ;Repeat add hl,de ex de,hl ; DE:= Current Addr + Record_Length push de 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 or a jr z,LGlp1 ;Until (End of File or error) cp Status_EOF ;If (it was other than end of file) jp nz,Bios_Entry ; Warm Boot ;Close the command file ld de,Default_Fcb1 ;DE:= Pointer to FCB1 ld c,Bdos_Close_File ;C:= Close file function call Bdos_Entry ;Close the command file ;Setup Page Zero Areas (Default Dma and the Fcb's) ld hl,0 ld (Default_Dma),hl ;Reset the Default Input Line Length ld hl,(Bdos_Entry+1) ld de,SysLdr_Offset or a sbc hl,de ld de,Default_Fcb1 ld bc,13 ldir ld a,(Default_Fcb1) ld (Default_Fcb2),a ld a,' ' ld (Default_Fcb2+1),a jp 100h ;---------------------------------------------------------------------- ; Data Area For Load and Go Module (2_Oct_84) ;-------------------------------------------- ; Copysys_Fcb: db 0 ;Drive for Copysys db 'COPYSYS COM',0 ds 24,0 SysLdr_Fcb: db 0 ;Drive for SysLdr db 'SYSLDR COM' ds 24,0 End_Lgo: page ;---------------------------------------------------------------------- ; Boot Sector Code (26_Sept_84) ;------------------------------ ; This code appears in sectors 1 and 2 of of track 0 of ; non-system diskettes. This position independent code outputs the ; message 'Not a SYSTEM Diskette' on the console. Putting it in ; sector 1 garantees that you'll know that there's no system on ; the disk (i.e. that it's not the wrong system, just no system). The ; reason that the code is in sector 2 as well is to catch those times ; when you've switched a data diskette for a system disk and tried to ; to do a warm boot (e.i. after using the virtual drive). ; The requirment for position independence then comes from the ; fact that, when this code is executed due to a cold boot, it will be ; in a different location than when it is executed as a result of a ; warm boot. The cold typically resides either in the TPA or in the ; unallocated memory space above the CBIOS, while the warm start ; execution address is always the start of the CCP. ; Notice that the CCP has two entry points in successive ; locations depending on the state of the submit flag. The three ; NOPs at the start of the program catch accesses to entry point 1 ; making sure that all users of this code enter at the same place. ; ;---------------------------------------------------------------------- ; Move the Execution Segment into Common Memory (26_Sept_84) ;----------------------------------------------------------- ; ; Main Entry Point 1 - Cold Boot CCP1: nop ;(Normal entry on cold boot) nop ;(and catches accesses to 1st CCP entry) nop ; Main Entry Point 2 - Warm Boot CCP2: ld sp,stack ld hl,PcHL * 256 + PopHl ;HL:= instructions pop hl, pchl ld (stack),hl ;(stack):= Instructions pop hl, pchl call stack ;Put location Here on the stack ;stack returns HL Pair pointing ;to 'here' for the following ldir Here: ld de,There-Here ;offset to .phase stack add hl,de ;HL:= Source ld bc,70h - (Ends-Begins) ;BC:= Length of move ld de,Stack ;DE:= Destination (above stack) ldir ;copy to common jp Stack ;execute it There: page ;---------------------------------------------------------------------- ; Execution Segment (4_Oct_84) ;----------------------------- ; 1) This section of code prints the Not a SYSTEM Diskette message ; and then goes to bter (prints Press Reset to try again & then halts) ; 2) This segment MUST NOT reside in the lowest 8k of memory because the ; rom must be on for the mesg and bter calls. ; .Phase Stack ;this stuff is above the stack Begins: ld de,Boot_Error_Msg ld a,0 out (BnkStb),a ;MD-11 rom on, bank 1 out (RomCnt),a ;MD-3 rom on call Mesg ;Print the error message jp Bter ;Print push reset... and then halt Boot_Error_Msg: ;No System Message is Overlaid Here Ends: .DePhase Emsg: db 0 ;Lable so message can be overlaid ds 180h - ($ - CCP1),0E5h ;Fill to start of the Pointer Structure ;---------------------------------------------------------------------- ; Bad Map Pointer Structure (26_Sept_84) ;--------------------------------------- ; dw BadID ;Validation word for pointer structure dw 0 ;Track db 0 ;Head db 0 ;Sector (Note that its zero based) dw 200h ;Offset to the start of the bad map page ds 200h - ($ - CCP1), 0E5h ;Fill to start of the Bad Map ;---------------------------------------------------------------------- ; Bad Map (26_Sept_84) ;--------------------- ; ds 4,0 ;Reserved for Link Field db 10h ;Bad Map Revision Number db 0 ;Reserved db 0 ;Current Number of Bad Map Entries db (End_Map - Begin_Map)/8 ;Maximum Number of Bad Map Entries Bad_Entry Macro Track, Head, Sector ds 4,0 ;Defective Sector (Track,Head & Sector) dw Track ;Replacement Track db Head ; " Head db Sector ; " Sector EndM Begin_Map: Bad_Entry 0,1,0 Bad_Entry 0,1,1 Bad_Entry 0,1,2 Bad_Entry 0,1,3 Bad_Entry 0,1,4 Bad_Entry 0,1,5 Bad_Entry 0,1,6 Bad_Entry 0,1,7 Bad_Entry 0,1,8 Bad_Entry 0,2,0 Bad_Entry 0,2,1 Bad_Entry 0,2,2 Bad_Entry 0,2,3 Bad_Entry 0,2,4 Bad_Entry 0,2,5 Bad_Entry 0,2,6 Bad_Entry 0,2,7 Bad_Entry 0,2,8 Bad_Entry 0,3,0 Bad_Entry 0,3,1 Bad_Entry 0,3,2 Bad_Entry 0,3,3 Bad_Entry 0,3,4 Bad_Entry 0,3,5 Bad_Entry 0,3,6 Bad_Entry 0,3,7 Bad_Entry 0,3,8 End_Map: ds 3FFh - ($ - CCP1),0E5h page ;---------------------------------------------------------------------- ; Local Buffers (3_Oct_84) ;------------------------- ; Response_Buf: db Response_Max ;Maximum Length of Input Line db 0 ;Current Line Length ds Response_Max,0 ;Response Buffer ds 40h ;Local Stack Space Local_Stack: dw 0 Buffer: ds 10h,0 ;Local Buffer (up to 1k is actually used) end page