ror ; Print the Error Code jr MnDone ; Return to the System MnLp1: call Get_Source ;Repeat Get the Source Specification or a jr z,MnLp2 ; If (there was an Error) call Report_Error ; Print the Error Code jr MnLp1 ;Until (there is no error) MnLp2: call Get_Destination ;Repeat Get the Destination Spec. or a jr z,MnSk1 ; If (there was an Error) call Report_Error ; Print Error Code jr MnLp2 ;Until (there is no Error) MnSk1: call Do_Again? ;If (the Users wants another copy) jr z,MnLp2 ; Goto Loop 2 MnDone: jp 0 ;Goto Warm Boot Entry ;---------------------------------------------------------------------- ; Setup the Initial Parameters (2_Jul_84) ;---------------------------------------- ; Setup_Param: ld c,get_version ;Get the Version Number of Cp/m call Bdos_Entry ld a,l ;If (Incorrect Version Number) cp 31h ld a,wrong_version ; (A:= Wrong Version Message) ret nz ; Return Stsk1: ld hl,fcb2 ;HL:= Source (2nd fcb) ld de,fcb2a ;DE:= Destination (Save area) ld bc,fcb_length ;BC:= Counter (length of Fcb) ldir ;Save the Second Fcb ld c,get_drive ;Get the current drive number (0-15) call Bdos_Entry ld (CrnDrv),a ;Save the current drive on Entry ld hl,400h ld (Sector_Size),hl ;Initialize the Sector Size ld a,0 ;A:= No Error ret ;Return page ;---------------------------------------------------------------------- ; Get the Source Specification (2_Jul_84) ;---------------------------------------- ; Get_Source: ld hl,Fcb1+1 ;Loop DE:= Pointer to Fcb1 + 1 call File_or_Drive? ; If (File or a Drive Specified) or a jr z,GsSk2 cp 1 ; If (it was a File) jr nz,GsSk1 call Read_File ; Read the File jr GsDone ; Break GsSk1: call Read_System ; Else Read the System jr GsDone ; Break GsSk2: ld hl,signon_f ; If (Sign_On Hasn't been Printed) ld a,(hl) or a jp nz,GsSk3 inc (hl) ld a,signon call Print_Message ; Print Sign_On Message GsSk3: ld a,get_prompt ; Load Prompt: Get_File or Drive call get_response ; Obtain Get_File or Drive ld de,parse1 ld c,parse_filename call Bdos_Entry ; Parse the New File/Drive Spec. jr Get_Source GsDone: call Restore_Drive ;Restore the current drive ld hl,2000h ld (fcb1),hl ;clear the fcb ret ;Return page ;---------------------------------------------------------------------- ; Get the Destination and Write the System (2_Jul_84) ;---------------------------------------------------- ; Get_Destination: ld hl,Fcb2a+1 ;Loop HL:= Pointer to Current Fcb call File_or_Drive? ; If (File or Drive Specified) or a jr z,GdSk2 cp 1 ; If (File Specified) jr nz,GdSk1 call Write_File ; Write File jr GdDone ; Break GdSk1: call Write_System ; Else Write System jr GdDone ; Break GdSk2: ld a,put_prompt ; Else Prompt: Put_File/Drive call get_response ; Obtain Put_File/Drive ld a,(tib+2) ; If (Secret Code) cp '<' ; (secret code) jr nz,GdSk3 ld (same_flag),a ; Stop Error Checks ld a,hi_wizard ; Supress Splice call Print_Message jp Get_Destination ; prompt real answer GdSk3: ld de,parse2 ; DE:= Start of buffer ld c,parse_filename ; C:= Function Number call Bdos_Entry ; Parse the File Name jr Get_Destination GdDone: call Restore_Drive ;Restore the current drive ld hl,2000h ld (fcb2a),hl ;clear 2 bytes, prevent repeats ret ;Return (Returned status set in Write) page ;---------------------------------------------------------------------- ; Check if the user wants another copy (2_Jul_84) ;------------------------------------------------ ; 1) This routine issues the Do Again Prompt and then gets the user's ; response. If the Response was yes (Y or y) then the Z flag is ; set else its cleared. ; Do_Again?: ld a,again ; Prompt for another copy message call get_response ; Obtain Response to Copy Msg. ld a,(tib+2) ; A:= Response Char and 5Fh ; Force Upper Case cp 'Y' ret ;Return ;---------------------------------------------------------------------- ; Determine Whether a File or a Drive is the Source/Dest (2_Jul_84) ;------------------------------------------------------------------ ; 1) This routine looks at the File contol block (passed in the HL) ; to determine whether to use a drive or a file as the source/dest. ; 2) Register Usage: ; A -> Returned Status (0=Neither, 1=File, 2=Drive) ; C -> Returned Drive Number (If Accm is returned = 2) ; HL -> Pointer to the Current Fcb ; File_or_Drive?: ld a,' ' cp (hl) ;If (1st char of Fcb is NOT a space) jp z,FdSk1 inc hl cp (hl) ; If (2nd Char is NOT a Space) ld a,1 ; A:= File ret nz ; Return dec hl ; Else ld a,(hl) ; Get the Drive Letter ld (hl),' ' ; (Reset the FCB Char) dec hl and 5Fh ; Force Upper Case sub 'A' - 1 ; Adjust to Drive Number ld (hl),a ; (Save the Drive Spec) jr FdSk2 ; Goto Finish Drive Proc. FdSk1: dec hl ld a,(hl) ;Else If (drive NOT specified) or a ret z ; Return (A:= 0) FdSk2: dec a ;Adjust the Drive Number to zero base ld c,a ;C:= Drive Number ld a,2 ;A:= Drive ret ;Return page ;---------------------------------------------------------------------- ; Get a Response from the Console (28_Jun_84) ;-------------------------------------------- ; 1) This routine issues a Prompt and then Inputs a Response to the ; terminal input buffer. This process is repeated until there is ; a Non_Null Response. ; Get_Response: ld c,a GrLp1: push bc ;Repeat ld a,c call Print_Message ; Print the Message ld de,tib ; DE:= Pointer: Start of Term. Buffer ld c,get_line ; C:= Get Line Function call Bdos_Entry ; Read a Line ld hl,tib+1 ; HL:= Pointer to Line Length ld a,(hl) ; A:= length add a,l ld l,a jr nc,GRsk1 inc h GRsk1: inc hl ; HL:= End of Buffer + 1 ld (hl),0 ; terminate line for parse pop bc ld a,(tib+2) ; A:= First Character of Line or a jr z,GrLp1 ;Until (there's a response) ret page ;---------------------------------------------------------------------- ; Read the System from a File (2_Jul_84) ;--------------------------------------- ; 1) This routine reads the Source of the Boot Code from a File. ; If there was an error then the accm is returned with the error ; code. ; Read_File: ld de,fcb1 ;DE:= Pointer to Fcb ld c,open_file ;C:= Open File Function call Bdos_Entry ;Open the File or a ;If (there was a file open error) ld a,no_file ; A:= Returned Status ret m ; Return ld a,16 ld (fcb1+32),a ;Current Record:= 16 (900h in tpa) ld de,sys_buffer RFlp1: push de ;Repeat ld c,set_dma call Bdos_Entry ; Set the DMA Address ld de,fcb1 ; DE:= Pointer to Fcb ld c,read_Sequent ; C:= Read Sequential call Bdos_Entry ; Read the Next Sector pop de ld hl,record_length add hl,de ex de,hl ; DE:= Pointer to Next Record or a jr z,RFlp1 ;Until (Error encountered) cp 1 ;If (other than end of file error) ld a,No_Message ; A:= No Error Message ret nz ; Return (rom gave error message) ld de,-2900h ;DE:= min file (8k) add hl,de ;If (File size is too small) ld a,File_Size ; A:= File Size Error ret nc ; Return (file too small) ld a,system_in call Print_Message ld a,0 ; A:= No Error ret ; Return page ;---------------------------------------------------------------------- ; Get the System from a Disk (2_Jul_84) ;-------------------------------------- ; 1) enter with C -> desired drive. If the was an error then its ; code is returned in the accm else the accm's returned = 0. ; Read_System: ld a,c ld (source_drive),a ld (DstDrv),a ld (RwDrv),a call check_bootable ;abort if drive foreign or logical or a ;If (There was an Error) ret nz ; Return ld a,bios_read ld (rw_op),a ;set for read call rw_sys ;Read the System or a ;If (There was an Error) ret nz ; Return ld a,system_in call Print_Message ld a,0 ;A:= No Error ret ;Return page ;---------------------------------------------------------------------- ; Write the System to a File (2_Jul_84) ;-------------------------------------- ; Write_File: ld de,fcb2a ld c,delete_file call Bdos_Entry ;Delete any file with the same name ld de,fcb2a ld c,make_file call Bdos_Entry ;Create the File Name or a ;If (Insufficient room in directory) ld a,no_directory ; A:= Error Code ret m ; Return xor a ld (fcb2a+32),a ;current_record = 0 ld b,72+16 ;72 data records, 16 records junk ld de,100h ;begin at tpa, sysgen format WFlp1: push bc ;Repeat push de ld c,set_dma call Bdos_Entry ; Set the Current Dma Address ld de,fcb2a ld c,Write_Sequent call Bdos_Entry ; Write the Next Record pop de ld hl,record_length add hl,de ex de,hl ; DE:= Pointer to Next Dma Addr. or a ; If (there was an error) jr z,WFsk3 ld de,fcb2a ld c,delete_file call Bdos_Entry ; Delete the File ld a,no_space ; A:= Error Code ret ; Return WFsk3: pop bc djnz WFlp1 ;Until (whole file transferred) ld de,fcb2a ld c,close_file call Bdos_Entry ;Close the File ld a,0 ;A:= No Error ret ;Return page ;---------------------------------------------------------------------- ; Put the System to a Disk (2_Jul_84) ;------------------------------------ ; 1) enter with C -> desired drive ; Write_System: ld a,c ld (DstDrv),a ld (RwDrv),a call check_bootable ;abort if drive foreign or logical or a ;If (Error) ret nz ; Return call check_same ;abort if system in ram bad for drive or a ;If (Error) ret nz ; Return ld a,(same_flag) or a jr nz,PSsk1 ;no splice if wizard mode ld hl,splice_buffer ld (DmaAdd),hl ld a,bios_read ld (rw_op),a call rw_sysx ;read system to splice buffer or a ;If (there was an Error) ret nz ; return ld hl,splice_buffer+256 ld de,sys_buffer+256 ld bc,1024-256 ldir ;splice PsSk1: ld a,bios_write ld (rw_op),a call rw_sys ;Write the System or a ;If (there was an Error) ret nz ; Return ld a,remember call Print_Message ld a,0 ;A:= No Error ret ;Return page ;---------------------------------------------------------------------- ; Read/Write the System (2_Jul_84) ;--------------------------------- ; rw_sys: ld hl,sys_buffer ;dma address ld (DmaAdd),hl rw_sysx: ld b,9 ;9 sectors ld hl,0 ;track 0 ld (track),hl inc hl ;sector 1 ld (sector),hl RwLp1: push bc call bios db bios_seldsk db 0 RwDrv: dw 0,0,0 call bios db bios_setbnk db 1 ;tpa dw 0,0,0 call bios db bios_setdma db 0 DmaAdd: dw 0,0,0 call bios db bios_settrk db 0 track: dw 0,0,0 call bios db bios_setsec db 0 sector: dw 0,0,0 call bios rw_op: db 0 ;read or write db 0 dw 0,0,0 or a ;If (There Was an Error) ld a,No_Message ; (A:= no message) jr nz,RwDone ; Skip to End of Routine ld hl,(DmaAdd) ld de,(sector_size) add hl,de ld (DmaAdd),hl ld hl,sector inc (hl) ld a,(iy_buffer+physpt) ;physical sectors per track inc a ;first illegal sector number cp (hl) jr nz,RwSk1 ld (hl),1 ;sector 1 ld hl,track inc (hl) RwSk1: pop bc djnz RwLp1 ld a,0 ;Returned_Status:= Ok RwDone: call Restore_Drive ;Restore the current drive ret ;Return ;---------------------------------------------------------------------- ; Restore the Current Drive (2_Jul_84) ;------------------------------------- ; 1) This routine restores the current drive on Entry as the current ; drive. ; Restore_Drive: push af ;(Save Returned Status) call bios db bios_seldsk db 0 CrnDrv: dw 0,0,0 ;re-select Current bdos drive pop af ;(Restore Returned Status) ret page ;---------------------------------------------------------------------- ; Check If the Current Drive is Bootable (2_Jul_84) ;-------------------------------------------------- ; check_bootable: call bios db bios_seldsk ;primary select db 0 ;a DstDrv: dw 0,0,0 ;Destination Drive ld a,h ;If (there was a Select Error) or l ld a,Select_Error ; A:= Error Code ret z ; return ;check if bootable (less than 32 system tracks) ;[hl] -> dph copied to common, dpb also in common ld de,dpb_offset add hl,de ld e,(hl) inc hl ld d,(hl) ld hl,offset_offset add hl,de ld e,(hl) inc hl ld d,(hl) ;de = offset ld hl,-32 add hl,de ld a,not_bootable ;If (Drive is not Bootable) ret c ; Return ;Check if the Drive is Foreign CkSk1: call bios db bios_func db func_read_iy dw 0 dw iy_buffer dw 0 call bios db bios_func db func_read_mtabs dw 0 ;bc dw mtab_buffer dw 0 ;hl ld a,(source_drive) call get_mtab bit @frgn,(hl) ;is drive foreign? ld a,foreign_drive ; A:= Error Code ret nz ; Return inc hl ld a,(hl) and 3 inc a ld b,a ld hl,40h CkLp1: add hl,hl djnz CkLp1 ;calc sec size ld (sector_size),hl ld a,0 ;A:= No Error ret ;Return ;---------------------------------------------------------------------- ; Check if the Destination Disk Matches the Source Disk format ;------------------------------------------------------------- ; check_same: ld a,(same_flag) or a ld a,0 ;A:= No Error ret nz ;no checking if it's me doing this ld a,(DstDrv) call get_mtab ld de,sys_buffer+70h ;def 0 in sysgen ld a,(hl) ;def 0 in mtab for system and 00111110b ;seczro,head_mask,hard_disk ld c,a ld a,(de) and 00111110b cp c jr nz,NsSk1 inc hl inc de ld a,(hl) ;def 1 and 01111111b ;all but calibrated ld c,a ld a,(de) and 01111111b cp c ;If (code is the same) ld a,0 ; A:= No Error ret z ; Return NsSk1: ld a,not_same_err ;A:= Error Code ret ;Return page ;---------------------------------------------------------------------- ; Set the HL pointing to an Mtab ;------------------------------- ; get_mtab: ;[a] = drive ld hl,mtab_buffer rlca rlca rlca rlca add a,l ld l,a ret nc inc h ret ;---------------------------------------------------------------------- ; Preform a Direct Bios Call ;--------------------------- ; 1) This routine does a Bdos 50 (direct bios) Call. The Data Structure ; for the call is coded inline, immediately after the invokation of ; this routine. ; bios: pop de ;biospb is at return address ld hl,8 ;length of biospb add hl,de ;step over biospb push hl ;new return address ld c,direct_bios jp Bdos_Entry page ;---------------------------------------------------------------------- ; Report Errors (2_Jul_84) ;------------------------- ; Report_Error: push af ld a,Error_Msg call Print_Message ;Print the Error Message pop af call Print_Message ;Print the Error Message ret ;Return ;---------------------------------------------------------------------- ; Print a Message on the Console (29_Jun_84) ;------------------------------------------- ; 1) This routine Prints a Message on the Console. ; 2) Register Usage: ; A -> Has Message Code on entry ; B -> Counter ; C -> Holds copy of Error Code ; DE -> Used to hold pointers/Bdos print string functions ; HL -> Used to hold pointers ; Print_Message: push af ld de,CrLf ;DE:= Pointer to Cr/Lf String ld c,Print_Line ;C:= Print String Function call Bdos_Entry ;Print Carriage Return Line Feed pop af ld c,a ;C:= Error Code to Find ld b,Max_Message ld hl,Message_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 ;(set pointer to 'Unrecognized Error') PmPrn: ld c,Print_Line ; call Bdos_Entry ;Print the Message ret ;Return page ;---------------------------------------------------------------------- ; Message Strings (2_Jul_84) ;--------------------------- ; Message_Table: ;Message Strings db SignOn ;Sign On Message dw SOmsg db get_prompt ;Prompt for Source dw GPmsg db put_prompt ;Prompt for Destination dw PPmsg db system_in ;System has been read message dw SImsg db again ;Make another copy message dw AGmsg db remember ;Remember to copy CPM3(f).SYS dw RRmsg db hi_wizard ;Secret Code Message dw HWmsg ; Error Messages db Error_Msg ;Fatal Error Header dw ERmsg db wrong_version ;Not Cpm 3 dw WVmsg db no_file ;Can't find the source file dw NFmsg db no_directory ;No Directory Space dw NDmsg db no_space ;No Disk Space dw NAmsg db not_bootable ;Not a bootable image dw NBmsg db foreign_drive ;Destination is Foreign dw FDmsg db not_same_err ;Disks are not compatible dw NEmsg db File_Size ;File Size is Too Small dw FSmsg db Select_Error ;Disk Select Error dw SEmsg db No_Message ;No Error Message dw NMmsg End_Table: Max_Message equ ( (End_Table - Message_Table)/3 ) + 1 page ;---------------------------------------------------------------------- ; Message Text (2_Jul_84) ;------------------------ ; ; Message Strings ;---------------- ; SOmsg: db 1Ah,'MD-HD System Copy Utility Rev ' db ((frev and 0f0h) shr 4) + '0', '.', (frev and 0fh) + '0' db Tab,Tab,Tab,Tab,' Copyright 1984' db cr,lf,'Morrow Designs Inc.' db Tab,Tab,Tab,Tab,Tab,Tab,'San Leandro, Ca' db Cr,Lf,Lf,Lf,Lf,'$' GPmsg: db Lf,'Enter: Source Drive or File Name > $' PPmsg: db Lf,'Enter: Destination Drive or File Name > $' SImsg: db Lf,'Valid system copy in memory $' AGmsg: db Lf,'System Transferred, want to make another? $' RRmsg: db Lf,'Don''t Forget CPM3(F).SYS is required on the Boot Disk $' HWmsg: db Lf,'I like wizards and lizards, give me a cookie $' page ; Error Message Strings ;---------------------- ; ERmsg: db Lf,Bell,'*=> Error$' WVmsg: db Tab,'Requires CP/M Plus $' NFmsg: db Tab,'No File by that name $' NDmsg: db Tab,'No Directory Space $' NAmsg: db Tab,'No Disk Space $' NBmsg: db Tab,'Drive Does Not have Boot $' FDmsg: db Tab,'Can''t copy system from foreign drive $' NEmsg: db Tab,'Incompatible System $' FSmsg: db Tab,'File is too Small $' SEmsg: db Tab,'Disk Select Error $' NMmsg: db '$' NoCode: db Tab,'Unrecognized Error $' CrLf: db Cr,Lf,'$' ;---------------------------------------------------------------------- ; Data Area (27_Jun_84) ;---------------------- ; same_flag: db 0 ;off signon_f: db 0 ;signon flag, print once only source_drive: db 0 ;local copy sector_size: dw 400h parse1: dw tib+2,fcb1 ;parse chars from buffer to fcb1 (get) parse2: dw tib+2,fcb2a ;parse chars from buffer to fcb2 (put) tib: db tib_length ds Tib_Length,' ' end