Page	55,132
Title	FREECOPY Version 1.13 (C)Copyright 1984
;***********************  F R E E C O P Y  ******************************
;*									*
;*	Program: FREECOPY						*
;*									*
;*	Author: Donald L. Buresh, C.D.P.				*
;*		Squire Buresh Associates, Inc.				*
;*		Post Office Box 112					*
;*		Millbury, MA  01527					*
;*		(617) 865-3435						*
;*									*
;*    !!!!!!!!!!!!!!!!!!!!!!   N O T I C E   !!!!!!!!!!!!!!!!!!!!!!     *
;*									*
;*	A limited license is granted to all users of this program to	*
;*	make copies of this source code and to distribute them to	*
;*	other users under the following conditions:			*
;*									*
;*	1. The notice contained in the variable MES00_Copy_Notice	*
;*	   is not to be altered, bypassed or removed.			*
;*									*
;*	2. The program is not to be distributed to others in		*
;*	   modified form.						*
;*									*
;*	3. If you think that this program has helped you, we request	*
;*	   a $25.00 contribution.					*
;*									*
;*	4. No other fee is to be charged or any consideration received	*
;*	   for copying or distributing the program without the		*
;*	   expressed written permission of Squire Buresh Assoc, Inc.	*
;*									*
;*									*
;*  (C) Copyright  1984		Squire Buresh Associates, Inc.		*
;*									*
;************************************************************************
Page
;************************************************************************
;*									*
;*	REVISION HISTORY						*
;*									*
;*	Version								*
;*	Number    Date		Comments				*
;*									*
;*	1.00	16-SEP-84	This is the first version of FREECOPY	*
;*									*
;*	1.01	13-OCT-84	Corrected a problem when copying	*
;*				diskettes on 512K systems. Reversed	*
;*				the order of testing the ES:BX table	*
;*				counter and the read/write track	*
;*				counter. Fix was near C2005, C2006,	*
;*				C2105 and C2106.			*
;*									*
;*	1.02	13-OCT-84	Flushed the standard input keyboard	*
;*				buffer before accepting a character.	*
;*				Fix was near U1101 and U1102.		*
;*									*
;*	1.03	21-OCT-84	Added parsing a tab character on the	*
;*				command line.  Fix was below C1215.	*
;*									*
;*	1.04 - 1.09		These versions never really existed in	*
;*				any decent form.  They are incorporated	*
;*				into fixing the memory allocation	*
;*				problems stemming from the original	*
;*				version of FREECOPY.			*
;*									*
;*	1.10	02-FEB-85	Allocated and freed memory when running	*
;*				FREECOPY under PC-DOS versions 2.00	*
;*				and greater.  The fix involved finding	*
;*				out the version of the operating system,*
;*				allocating the memory, establishing	*
;*				the ES:BX table entries and freeing	*
;*				memory before returning control to	*
;*				PC-DOS.					*
;*									*
;*	1.11	06-JUN-85	Modified the sequence of turning inter- *
;*				rupts on and off in the S1000 and S1100 *
;*				modules.				*
;*									*
;*	1.12	06-JUN-85	Allowed users to write more than one	*
;*				target diskette, by setting FLG17 to	*
;*				True and jumping to B1105A after ini-	*
;*				tializing the appropriate variables.	*
;*									*
;*	1.13	07-JUN-85	Fixed a stack imbalance that appeared	*
;*				only when running PC-DOS 3.00 on a PC	*
;*				rather than on an XT or AT		*
;*									*
;************************************************************************
Page
;************************************************************************
;*									*
;*	EQUATES								*
;*									*
;*	The constants defined below are used to to specify:		*
;*									*
;*			o Disk commands,				*
;*									*
;*			o Keyboard commands,				*
;*									*
;*			o Video commands				*
;*									*
;*			o Miscellaneous parameters,			*
;*									*
;*			o Various ASCII characters.			*
;*									*
;************************************************************************
;
Disk_Parameter_Addr	Equ	001EH*4	; Address of Disk Parameter Table
;
Reset_Command		Equ	0000D	; Diskette reset command
Status_Command		Equ	0001D	; Diskette status command
Read_Command		Equ	0002D	; Diskette read command
Write_Command		Equ	0003D	; Diskette write command
Verify_Command		Equ	0004D	; Diskette verify command
Format_Command 		Equ	0005D	; Diskette format command
;
Time_Out_Error		Equ	0080H	; Diskette error codes
Seek_Error		Equ	0040H	; .
Controller_Error	Equ	0020H	; .
CRC_Error		Equ	0010H	; .
DMA_Boundary_Error	Equ	0009H	; .
DMA_Error		Equ	0008H	; .
Sector_Error		Equ	0004H	; .
Write_Protect_Error	Equ	0003H	; .
Address_Mark_Error	Equ	0002H	; .
Command_Error		Equ	0001H	; ..End
;
Video_Address		Equ	0A000H	; Starting segment addr of Video RAM
;
Set_Mode_Command	Equ	0000D	; Set the video mode
Set_CType_Command	Equ	0001D	; Set the cursor type
Set_CPos_Command	Equ	0002D	; Set the cursor position
Read_Cursor_Command	Equ	0003D	; Get cursor position and attributes
Read_LPen_Command	Equ	0004D	; Get the light pen position
Set_ADPage_Command	Equ	0005D	; Set the active display page
Scroll_Up_Command	Equ	0006D	; Scrool up or blank a portion of
					; . the video display
;
Page
;************************************************************************
;*									*
;*	EQUATES		Page 2						*
;*									*
;************************************************************************
;
Scroll_Down_Command	Equ	0007D	; Scroll down or blank a portion
					; . of the video display
Read_AChar_Command	Equ	0008D	; Read the attribute and character
Write_AChar_command	Equ	0009D	; Write the attribute and character
Write_Char_Command	Equ	0010D	; Write the character only
Set_Color_Command	Equ	0011D	; Set the color pallette
Write_Dot_Command	Equ	0012D	; Write a pixel to a graphics screen
Read_Dot_Command	Equ	0013D	; Read a pixel from a graphics screen
Write_TTY_Command	Equ	0014D	; Write a character with automatic
					; . processing for LF, CR, Bell & BS
Video_State_Command	Equ	0015D	; Get the current video state
;
Read_Keyboard_Command	Equ	0007D	; Reads character from the keyboard
Flush_Keyboard_Command	Equ	0012D	; Clears the standard keyboard buffer
Get_DOS_Version_Number	Equ	0030H	; Gets the current version of PC-DOS
Allocate_Memory		Equ	0048H	; Allocate a block of memory
Free_Memory		Equ	0049H	; Free a block of memory
Modify_Memory_Block	Equ	004AH	; Modify the size of memory block
;
Default_Drive_Command	Equ	0025D	; Get PC DOS default drive number
;
Video_Interrupt		Equ	0010H	; Interrupt 10H for video calls
Equipment_Interrupt	Equ	0011H	; Interrupt 11H for equipment
Disk_Interrupt		Equ	0013H	; Interrupt 13H for disk calls
PC_DOS_Interrupt	Equ	0021H	; Interrupt 21H for PC DOS calls
;
Parallel_Ports_Mask	Equ	0C000H	; Equipment masks
Game_Adapters_Mask	Equ	00100H	; .
RS232_Ports_Mask	Equ	00E00H	; .
Disk_Drives_Mask	Equ	000C0H	; .
Init_Video_Mask		Equ	00030H	; .
Planar_RAM_Mask		Equ	0000CH	; .
IPL_Diskette_Mask	Equ	00001H	; ..End
;
Page
;************************************************************************
;*									*
;*	EQUATES		Page 3						*
;*									*
;************************************************************************
;
Command_Com_Size	Equ	0410D	; Size of various tables and programs
CHRN_Table_Size		Equ	0180D	; in 16 byte paragraphs
					; .
					; .
ESBX_Table_Size		Equ	0020D	; .
					; .
					; .
FAT_Sector_Size		Equ	0032D	; ..End
;
DMA_Boundary_Mask	Equ	0FFFH	; Mask to isolate the high nibble of
					; . the ES segment address
;
Invalid_Drive		Equ	0255D	; Invalid drive parameter
Maximum_Drives		Equ	0003D	; Maximum number of floppy drives 
Minimum_Drives		Equ	0000D	; Minimum number of floppy drives
;
Sector_Size		Equ	0512D	; Number of bytes per sector
Paragraph_Size		Equ	0016D	; Number of bytes per paragraph
Number_of_Retries	Equ	0005D	; Number of attempts to copy 
					; . a track before admitting failure
Final_Track		Equ	0039D	; The last track on a PC DOS diskette
;
One_Side_Eight_Sectors	Equ	00FEH	; First entry in the File Allocation
Two_Sides_Eight_Sectors	Equ	00FFH	; Table (FAT)
One_Side_Nine_Sectors	Equ	00FCH	; .
Two_Sides_Nine_Sectors	Equ	00FDH	; .
Fixed_Disk		Equ	00F8H	; ..End
;
Keyboard_Buffer_Size	Equ	0080D	; Maximum number of characters in
					; . the keyboard buffer
;
Minimum_Memory_Size	Equ	0288D	; Minimum memory size in 16 byte
					; . paragraphs to hold a nine
					; . sectored track
;
Blank_Cursor		Equ	0F0FH	; Blank cursor value
Underline_Cursor	Equ	0D0DH	; Underline cursor value
;
False			Equ	0000D	; Incorrect processing occured
True			Equ Not False	; Correct processing occured
High_Values		Equ	0FFFFH	; High values
;
Page
;************************************************************************
;*									*
;*	EQUATES		Page 4						*
;*									*
;************************************************************************
;
NUL			Equ	0000D	; Null character
SOH			Equ	0001D	; SOH character
STX			Equ	0002D	; STX character
ETX			Equ	0003D	; Control Break character
Bell			Equ	0007D	; Bell character
BS			Equ	0008D	; Backspace character
HT			Equ	0009D	; Horizontal tab character
LF			Equ	0010D	; Line feed character
CR			Equ	0013D	; Carriage return character
Space			Equ	0032D	; Space or blank character
Slash			Equ	0047D	; Slash character
Zero_Digit		Equ	0048D	; Digit Zero
One_Digit		Equ	0049D	; Digit One
Capital_Letter_A	Equ	0065D	; Capital letter A
Capital_Letter_N	Equ	0078D	; Capital letter N
Capital_Letter_Y	Equ	0089D	; Capital letter Y
Small_Letter_n		Equ	0110D	; Small letter n
Small_Letter_y		Equ	0121D	; Small letter y
EOT			Equ	0255D	; End of text character
;
Minus_One		Equ	  -1D	; Numbers used in FREECOPY
Zero			Equ	0000D	; .
One			Equ	0001D	; .
Two			Equ	0002D	; .
Three			Equ	0003D	; .
Four			Equ	0004D	; .
Six			Equ	0006D	; .
Eight			Equ	0008D	; .
Nine			Equ	0009D	; .
Ten			Equ	0010D	; .
Eleven			Equ	0011D	; .
Twelve			Equ	0012D	; .
Fourteen		Equ	0014D	;.
Fifteen			Equ	0015D	; .
Twenty_Four		Equ	0024D	; .
Twenty_Five		Equ	0025D	; .
Thirty_Four		Equ	0034D	; .
Thirty_Six		Equ	0036D	; .
Thirty_Nine		Equ	0039D	; .
Seventy_Nine		Equ	0079D	; ..End
;
Page
;************************************************************************
;*									*
;*	CSEG Segment							*
;*									*
;*	This segment contains all of the code of the program.  It is	*
;*	named CSEG because this name conforms with ASM-86.		*
;*									*
;************************************************************************
;
CSEG	Segment Para Public 'CSEG'
	Assume CS:CSEG,DS:CSEG,ES:CSEG,SS:Nothing
;
Page
;************************************************************************
;*									*
;*	PROGRAM SEGMENT PREFIX						*
;*									*
;*	The first 256 bytes of every program executed under PC DOS	*
;*	contains a Program Segment Prefix control block.  The data	*
;*	stored in this block of memory is used by FREECOPY to process	*
;*	the parameters when invoking the program.			*
;*									*
;************************************************************************
;
	Org	05CH
Source_Drive		Label Byte	; Source diskette drive number
	Org	05DH
Source_Filename		Label Byte	; Source diskette filename
	Org	068H
Source_Filler_Area	Label Byte
	Org	06CH
Target_Drive		Label Byte	; Target diskette drive number
	Org	06DH
Target_Filename		Label Byte	; Target diskette filename
	Org	078H
Target_Filler_Area	Label Byte
	Org	080H
Parameter_Count		Label Byte	; Number of parameters
	Org	081H
Parameter_String	Label Byte	; String entered by the user
;
Page
;************************************************************************
;*									*
;*	A1000_MAIN_MODULE						*
;*									*
;*	This is the top level of FREECOPY and it controls the flow of	*
;*	the program.  The first sequence of commands in the routine	*
;*	preserve the state of the machine.  Next, there is a set of	*
;*	three (3) calls to sub-modules that control the initial		*
;*	processing, detail processing and final processing.  Finally,	*
;*	FREECOPY restores the state of the machine an returns to 	*
;*	PC DOS via INT 20H.						*
;*									*
;************************************************************************
;
	Org	0100H
;
Public	A1000_Main_Module
;
A1000_Main_Module Proc Far
;
A1001:
	Cli				; Set up the top of the stack
	Mov	SP,Offset MEM04_Top_of_the_Stack
	Sti				; ..End
; 
	Push	BP			; Save the state of the machine
	Push	DS			; .
	Push	ES			; .
	Push	SS			; .
	Push	AX			; .
	Push	BX			; .
	Push	CX			; .
	Push	DX			; .
	Push	SI			; .
	Push	DI			; .
	Pushf				; ..End
;
	Cli				; Save the current stack pointer
	Mov	Word Ptr SYS15_Stack_Pointer,SP
	Add	Word Ptr SYS15_Stack_Pointer,Two			; .
	Sti				; ..End
;
	Call	B1000_Initial_Process	; Main flow of control
	Cmp	Byte Ptr FLG01_Good_Command,False
	Je	A1002			; .
	Cmp	Byte Ptr FLG03_Default_Drive,False
	Je	A1002			; .
	Call	B1100_Detail_Process	; .
A1002:					; .
	Call	B1200_Final_Process	; ..End
A1090:
	Popf				; Restore the state of the machine
	Pop	DI			; .
	Pop	SI			; .
	Pop	DX			; .
	Pop	CX			; .
	Pop	BX			; .
	Pop	AX			; .
	Pop	SS			; .
	Pop	ES			; .
	Pop	DS			; .
	Pop	BP			; ..End
A1099:
	Int	20H			; Return to PC DOS
;
A1000_Main_Module Endp
;
Page
;************************************************************************
;*									*
;*	B1000_INITIAL_PROCESS						*
;*									*
;*	This module performs the following functions after control	*
;*	passess to FREECOPY:						*
;*									*
;*	 1. Sets up the Disk Parameter Table.				*
;*									*
;*	 2. Gets the current PC-DOS version number.			*
;*									*
;*	 3. Initializes various parameters.				*
;*									*
;*	 4. Gets and sets the video mode.				*
;*									*
;*	 5. Displays the intiial message.				*
;*									*
;*	 6. Parses the command line entered by a user.			*
;*									*
;*	 7. Determines the amount of equipment on the machine.		*
;*									*
;*	 8. Validates the number of disk drives on the system.		*
;*									*
;*	 9. Displays the appropriate disk copying message.		*
;*									*
;*	10. Gets the amount of available memory.			*
;*									*
;*	11. Calculates the number and position of the entries in the	*
;*	    ES:BX buffer address table.					*
;*									*
;************************************************************************
;
Page
;
Public	B1000_Initial_Process
;
B1000_Initial_Process Proc Near
;
B1001:
	Call	S1000_Setup_Disk_Param_Table
	Call	S1200_Get_Version_Number
;
	Mov	Byte Ptr FLG01_Good_Command,True
	Mov	Byte Ptr FLG02_Double_Side,True
	Mov	Byte Ptr FLG03_Default_Drive,True
	Mov	Byte Ptr FLG04_Single_Drive,True
	Mov	Byte Ptr FLG07_First_Time,True
	Mov	Byte Ptr FLG16_Free_Memory,True
	Mov	Byte Ptr FLG17_Copy_More_Disks,False
B1002:
	Call	C1000_Get_And_Set_Video	; Get and set current video state
	Call	C1100_Display_Intro	; Display the intial screen
	Call	C1200_Parse_Commands	; Parse the command line entered
					; . by the user
	Cmp	Byte Ptr FLG01_Good_Command,False
	Je	B1099			; If false, go to end of the module
	Call	C1300_Get_Equipment	; Find out the equipment on the PC
	Call	C1400_Validate_Drives	; Validate the drive numbers
	Cmp	Byte Ptr FLG03_Default_Drive,False
	Je	B1099			; If false, go to end of the module
	Call	C1500_Diskette_Messages	; Display the appropriate messages
;
	Cmp	Byte Ptr SYS19_Major_Vers_Number,Zero
	Jne	B1003			; Get available memory in paragraphs
	Call	C1600A_Get_Free_Memory	; . and create the ES:BX table
	Jmp	B1004			; .
B1003:					; .
	Call	C1600B_Get_Free_Memory	; .
B1004:					; .
	Cmp	Byte Ptr FLG01_Good_Command,False
	Je	B1099			; .
	Call	C1700_Create_ESBX_Table; ..End
B1099:
	Ret
;
B1000_Initial_Process Endp
;
Page
;************************************************************************
;*									*
;*	B1100_DETAIL_PROCESS						*
;*									*
;*	This module performs the following functions when copying one	*
;*	or more diskettes:						*
;*									*
;*	1. Initializes various parameters.				*
;*									*
;*	2. Validates the contents of the source diskette.		*
;*									*
;*	3. Creates all of the entries of the CHRN table used in		*
;*	   formatting the target diskette.				*
;*									*
;*	4. Reads the tracks of the source diskette.			*
;*									*
;*	5. If the diskette is being copied on only one drive, the	*
;*	   routines asks the user to enter the target diskette.		*
;*									*
;*	6. Writes the tracks on the target diskette.			*
;*									*
;*	7. If FREECOPY is finished copying the source diskette, the	*
;*	   program asks whether to write another target diskette,	*
;*	   provided the source diskette fits completely in memory;	*
;*	   otherwise, the program asks whether to copy a new diskette.	*
;*	   If not, the module returns to A1000_Main_Module.  If so,	*
;*	   control transfers to 1.					*
;*									*
;*	8. If FREECOPY is not completed copying the source diskette,	*
;*	   control transfers to 4.					*
;*									*
;************************************************************************
;
Page
;
Public	B1100_Detail_Process
;
B1100_Detail_Process Proc Near
;
B1101:
	Mov	Byte Ptr WRK20_Current_Source_Head,Zero
	Mov	Byte Ptr WRK21_Current_Source_Track,Zero
	Mov	Byte Ptr WRK22_Current_Target_Head,Zero
	Mov	Byte Ptr WRK23_Current_Target_Track,Zero
	Mov	Word Ptr WRK33_CHRN_Table_Address,Offset MEM02_CHRN_Table
	Mov	Byte Ptr FLG13_First_Read_Write,True
	Mov	Byte Ptr FLG14_Copy_Complete,False
	Mov	Byte Ptr FLG15_IO_Error,Three
B1102:
	Call	C1800_Validate_Source_Disk
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	B1103			; If it is a valid source, continue
	Mov	SI,Offset MES07_Correct_And_Press_Key
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	Byte Ptr FLG05_Store_Buffer,False
	Call	U1100_Get_Response	; Get the user's response
	Jmp	B1101			; Go back and try again
B1103:
	Call	C1900_Create_CHRN_Table
B1104:
	Call	C2000_Read_Source_Disk
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	B1105			; If read disk correctly, continue
	Mov	SI,Offset MES07_Correct_And_Press_Key
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	Byte Ptr FLG05_Store_Buffer,False
	Call	U1100_Get_Response	; Get the user's response
	Jmp	B1101			; Go back and try again
B1105:
	Cmp	Byte Ptr FLG04_Single_Drive,False
	Je	B1106			; If a single drive copy, continue
B1105A:
	Mov	SI,Offset MES10_Insert_Target
	Mov	AL,Byte Ptr WRK02_Target_Drive
	Add	AL,Capital_Letter_A	; Put drive letter into AL
	Mov	[SI+Thirty_Four],AL	; Put the drive letter into the
					; . correct position in the message
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	SI,Offset MES16_Press_Any_Key
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	Byte Ptr FLG05_Store_Buffer,False
	Call	U1100_Get_Response	; Get the user's response
B1106:
	Call	C2100_Write_Format_Target_Disk
	Cmp	Byte Ptr FLG09_Good_Write,False
	Je	B1110			; If bad write, go to bottom of loop
	Cmp	Byte Ptr FLG11_Good_Format,False
	Je	B1110			; If bad format, go to bottom of loop
B1107:
	Cmp	Byte Ptr FLG14_Copy_Complete,True
	Je	B1109			; If copy done, go to bottom of loop
	Cmp	Byte Ptr FLG04_Single_Drive,False
	Je	B1108			; If double drive copy, continue
	Mov	SI,Offset MES09_Insert_Source
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Add	AL,Capital_Letter_A	; Put the drive letter into AL
	Mov	[SI+Thirty_Four],AL	; Put the drive letter into the
					; . correct position in the message
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	SI,Offset MES16_Press_Any_Key
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	Byte Ptr FLG05_Store_Buffer,False
	Call	U1100_Get_Response	; Get the user's response
B1108:
	Call	C2200_Check_File_Alloc_Table
	Cmp	Byte Ptr FLG12_Good_FAT,False
	Je	B1110			; If bad FAT, go to bottom of loop
	Mov	Byte Ptr FLG13_First_Read_Write,False
	Jmp	B1104			; Go back and read some more
B1109:
	Mov	Byte Ptr FLG07_First_Time,False
	Mov	SI,Offset MES02_Copy_Complete
	Call	U1000_Display_Message
B1110:
	Cmp	Byte Ptr FLG17_Copy_More_Disks,False
	Je	B1111
	Mov	SI,Offset MES01A_Write_Another_Diskette
	Call	U1000_Display_Message
	Call	U1200_Get_Yes_or_No
	Cmp	Byte Ptr FLG06_Yes_or_No,False
	Je	B1111			; Continue
	Mov	Byte Ptr WRK22_Current_Target_Head,Zero
	Mov	Byte Ptr WRK23_Current_Target_Track,Zero
	Mov	Word Ptr WRK33_CHRN_Table_Address,Offset MEM02_CHRN_Table
	Mov	Byte Ptr FLG13_First_Read_Write,True
	Mov	Byte Ptr FLG14_Copy_Complete,False
	Mov	Byte Ptr FLG15_IO_Error,Three
	Jmp	B1105A			; Start writing a diskette again
B1111:
	Mov	SI,Offset MES01B_Copy_Another_Diskette
	Call	U1000_Display_Message
	Call	U1200_Get_Yes_or_No
	Cmp	Byte Ptr FLG06_Yes_or_No,False
	Je	B1199			; Go to the end of the module
	Call	C1500_Diskette_Messages	; Print out the messages on screen
	Jmp	B1101			; Start copying a diskette again
B1199:
	Ret
;
B1100_Detail_Process Endp
;
Page
;************************************************************************
;*									*
;*	B1200_FINAL_PROCESS						*
;*									*
;*	This module performs the following functions before returning 	*
;*	control to PC DOS:						*
;*									*
;*	1. Restores the value of the stack pointer.			*
;*									*
;*	2. Displays the final message of the program.			*
;*									*
;*	3. Restores the underline cursor.				*
;*									*
;*	4. Restores the settings in the Disk Parameter Table.		*
;*									*
;*	5. Returns control to A1000_Main_Module.			*
;*									*
;************************************************************************
;
Page
;
Public	B1200_Final_Process
;
B1200_Final_Process Proc Near
;
B1201:
	Cli				; Establish the stack pointer
	Mov	SP,Word Ptr SYS15_Stack_Pointer
	Sti				; ..End
;
	Call	C2300_Free_Memory	; Free allocated memory  if necessary
;
	Mov	SI,Offset MES100_Freecopy_Finished
	Call	U1000_Display_Message	; Display the message on the screen
;
	Mov	AH,Set_CType_Command	; Restore the underline cursor
	Mov	CX,Underline_Cursor	; .
	Int	Video_Interrupt		; ..End
;
	Call	S1100_Restore_Disk_Param_Table
;
	Mov	AX,Offset A1090		; Setup to return to the main module
	Push	CS			; .
	Push	AX			; ..End
B1299:
	Ret
;
B1200_Final_Process Endp
;
Page
;************************************************************************
;*									*
;*	C1000_GET_AND_SET_VIDEO						*
;*									*
;*	This module gets the current video state and saves this		*
;*	information in the various SYStem variables.			*
;*									*
;************************************************************************
;
Public	C1000_Get_And_Set_Video
;
C1000_Get_And_Set_Video Proc Near
;
C1001:
	Push	AX			; Save the registers
	Push	BX			; .
	Push	CX			; ..End
C1002:
	Mov	AH,Video_State_Command	; Get the current video state
	Int	Video_Interrupt		; ..End
	Mov	Byte Ptr SYS01_Number_Columns,AH
	Mov	Byte Ptr SYS02_Current_Mode,AL
	Mov	Byte Ptr SYS03_Active_Page,BH
C1003:
	Mov	AH,Set_CType_Command	; Set the cursor to blanks
	Mov	CX,Blank_Cursor		; .
	Int	Video_Interrupt		; ..End
C1090:
	Pop	CX			; Restore the registers
	Pop	BX			; .
	Pop	AX			; ..End
C1099:
	Ret
;
C1000_Get_And_Set_Video Endp
;
Page
;************************************************************************
;*									*
;*	C1100_DISPLAY_INTRO						*
;*									*
;*	This module displays the introductory message to FREECOPY.	*
;*	Please do not disable this message, since it states the		*
;*	conditions under which a person may copy this program.		*
;*									*
;************************************************************************
;
Public	C1100_Display_Intro
;
C1100_Display_Intro Proc Near
;
C1101:
	Mov	SI,Offset MES00_Copy_Notice	; Display the copy notice
	Call	U1000_Display_Message		; ..End
C1199:
	Ret
C1100_Display_Intro Endp
;
Page
;************************************************************************
;*									*
;*	C1200_PARSE_COMMANDS						*
;*									*
;*	This module parses the command line entered by the user		*
;*	by checking the following conditions:				*
;*									*
;*	1. The source and/or the target drives do not exist.		*
;*									*
;*	2. The command line contains any characters other than two	*
;*	   drive letters (e.g., a filename).				*
;*									*
;*	3. The /1 (single side) parameter is on the command line.	*
;*									*
;************************************************************************
;
Public	C1200_Parse_Commands
;
C1200_Parse_Commands Proc Near
;
C1201:
	Cmp	AH,Invalid_Drive	; Compare for invalid drive parms
	Jne	C1202			; .
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES14_Invalid_Drive
	Call	U1000_Display_Message
	Jmp	C1299			; .
C1202:					; .
	Cmp	AL,Invalid_Drive	; .
	Jne	C1203			; .
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES14_Invalid_Drive
	Call	U1000_Display_Message
	Jmp	C1299			; ..End
C1203:
	Mov	AL,Byte Ptr Source_Drive
	Mov	Byte Ptr WRK01_Source_Drive,AL
	Mov	AL,Byte Ptr Target_Drive
	Mov	Byte Ptr WRK02_Target_Drive,AL
C1204:
	Mov	SI,Offset Source_Filename
	Mov	DI,Offset WRK03_Valid_Filename
	Mov	CX,Eleven		; Set CX to compare 11 characters 
C1205:
	Mov	AL,[SI]			; Compare for valid source diskette
	Mov	AH,[DI]			; filename in the FCB at 05DH
	Cmp	AH,AL			; .
	Je	C1206			; .
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES12_Invalid_Parameter
	Call	U1000_Display_Message
	Jmp	C1299			; .
C1206:					; .
	Inc	SI			; .
	Inc	DI			; .
	Loop	C1205			; ..End
C1207:
	Mov	SI,Offset Target_Filename
	Mov	DI,Offset WRK03_Valid_Filename
	Mov	CX,Eleven		; Set CX to comapre 11 characters
C1208:
	Mov	AL,[SI]			; Compare for valid target diskette
	Mov	AH,[DI]			; . filename in the FCB at 06DH
	Cmp	AH,AL			; .
	Je	C1209			; .
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES12_Invalid_Parameter
	Call	U1000_Display_Message
	Jmp	C1299			; .
C1209:					; .
	Inc	SI			; .
	Inc	DI			; .
	Loop	C1208			; ..End
C1210:
	Mov	AL,Byte Ptr Parameter_Count
	Mov	Byte Ptr WRK04_Parameter_Count,AL
	Mov	SI,Offset Parameter_String
	Inc	Byte Ptr WRK04_Parameter_Count
C1211:
	Dec	Byte Ptr WRK04_Parameter_Count
	Jz	C1299			; Go to the end of the module
	Mov	AL,[SI]			; Put the character into AL
	Cmp	AL,Slash		; Compare character with a slash
	Je	C1212			; If so, then continue processing
	Inc	SI			; Increment the command string addr
	Jmp	C1211			; Go back and try again
C1212:
	Inc	SI			; Increment the command string addr
	Mov	AL,[SI]			; Get the next char after the slash
	Cmp	AL,One_Digit		; Compare with the char 1
	Je	C1214			; Set double side flag to false
C1213:
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES12_Invalid_Parameter
	Call	U1000_Display_Message
	Jmp	C1299			; Go to the end of the module
C1214:
	Mov	Byte Ptr FLG02_Double_Side,False
	Dec	Byte Ptr WRK04_Parameter_Count
	Jz	C1299			; Go to the end of the module
C1215:
	Dec	Byte Ptr WRK04_Parameter_Count
	Jz	C1299			; Go to the end of the module
	Inc	SI			; Increment the command string addr
	Mov	AL,[SI]			; Get the next char in command line
	Cmp	AL,HT			; Check for tabs and spaces
	Je	C1215			; .
	Cmp	AL,Space		; .
	Je	C1215			; ..End
C1216:
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES12_Invalid_Parameter
	Call	U1000_Display_Message
C1299:
	Ret
;
C1200_Parse_Commands Endp
;
Page
;************************************************************************
;*									*
;*	C1300_GET_EQUIPMENT						*
;*									*
;*	This module determines the peripheral devices on the machine.	*
;*	It invokes the equipment status interrupt and places the	*
;*	information into the appropriate SYStem parameters.		*
;*									*
;************************************************************************
;
Public	C1300_Get_Equipment


C1300_Get_Equipment Proc Near
;
C1301:
	Int	Equipment_Interrupt	; Get the equipment on machine
	Mov	BX,AX			; Save the result for future use
;
	And	AX,Parallel_Ports_Mask	; Get the number of parallel ports
	Mov	CL,Fourteen		; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS07_No_Parallel_Ports,AL
;
	Mov	AX,BX			; Get the game adapter attachments
	And	AX,Game_Adapters_Mask	; .
	Mov	CL,Twelve		; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS08_Game_Adapters,AL
;
	Mov	AX,BX			; Get the number of RS-232 ports
	And	AX,RS232_Ports_Mask	; .
	Mov	CL,Nine			; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS09_No_RS232_Ports,AL
;
	Mov	AX,BX			; Get the number of diskette drives
	And	AX,Disk_Drives_Mask	; .
	Mov	CL,Six			; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS10_No_Disk_Drives,AL
;
	Mov	AX,BX			; Get the initial video mode
	And	AX,Init_Video_Mask	; .
	Mov	CL,Four			; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS11_Init_Video_Mode,AL
;
	Mov	AX,BX			; Get planar RAM size
	And	AX,Planar_RAM_Mask	; .
	Mov	CL,Two			; .
	Shr	AX,CL			; .
	Mov	Byte Ptr SYS12_Planar_RAM_Size,AL
;
	Mov	AX,BX			; Get IPL from diskette flag
	And	AX,IPL_Diskette_Mask	; .
	Mov	Byte Ptr SYS13_IPL_From_Diskette,AL
;
C1399:
	Ret
;
C1300_Get_Equipment Endp
; 
Page
;************************************************************************
;*									*
;*	C1400_VALIDATE_DRIVES						*
;*									*
;*	This module determines if the drives specified in the		*
;*	command line are floppy disk drives or RAM disk drives.		*
;*	It also checks if copying the source diskette takes place	*
;*	on a single drive.						*
;*									*
;************************************************************************
;
Public	C1400_Validate_Drives
;
C1400_Validate_Drives Proc Near
;
C1401:
	Mov	AH,Default_Drive_Command; Get the PC DOS default drive
	Int	PC_DOS_Interrupt	; .
	Mov	Byte Ptr SYS14_Default_Drive,AL
C1402:
	Cmp	Byte Ptr SYS10_No_Disk_Drives,Minimum_Drives
	Ja	C1403			; If not single drive copy, set
					; . FLG04 to false
	Mov	Byte Ptr SYS14_Default_Drive,Minimum_Drives
	Mov	Byte Ptr WRK01_Source_Drive,Minimum_Drives
	Mov	Byte Ptr WRK02_Target_Drive,Minimum_Drives
	Jmp	C1499			; Go to the end of the module
C1403:
	Mov	Byte Ptr FLG04_Single_Drive,False
C1404:
	Cmp	Byte Ptr SYS14_Default_Drive,Maximum_Drives
	Jbe	C1405			; If below maximum, continue
	Mov	Byte Ptr FLG03_Default_Drive,False
	Mov	SI,Offset MES13_Invalid_Default
	Call	U1000_Display_Message
	Jmp	C1499			; Go to the end of the module
C1405:
	Dec	Byte Ptr WRK01_Source_Drive
	Cmp	Byte Ptr WRK01_Source_Drive,Minus_One
	Jne	C1406
	Mov	AL,Byte Ptr SYS14_Default_Drive
	Mov	Byte Ptr WRK01_Source_Drive,AL
C1406:
	Dec	Byte Ptr WRK02_Target_Drive
	Cmp	Byte Ptr WRK02_Target_Drive,Minus_One
	Jne	C1407
	Mov	AL,Byte Ptr SYS14_Default_Drive
	Mov	Byte Ptr WRK02_Target_Drive,AL
C1407:
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	AH,Byte Ptr WRK02_Target_Drive
	Cmp	AH,AL			; Check source drive = target drive
	Jne	C1499			; If so, then continue
	Mov	Byte Ptr FLG04_Single_Drive,True
C1499:
	Ret
;
C1400_Validate_Drives Endp
;
Page
;************************************************************************
;*									*
;*	C1500_DISKETTE_MESSAGES						*
;*									*
;*	This module displays the appropriate source and target		*
;*	insertion diskette messages on the screen.			*
;*									*
;************************************************************************
;
Public	C1500_Diskette_Messages
;
C1500_Diskette_Messages Proc Near
;
C1501:
	Cmp	Byte Ptr FLG07_First_Time,False
	Je	C1502			; If not first time, continue
	Cmp	Byte Ptr FLG04_Single_Drive,False
	Je	C1502			; If false, then continue
	Mov	SI,Offset MES15_Single_Drive_Copy
	Call	U1000_Display_Message
C1502:
	Mov	SI,Offset MES09_Insert_Source
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Add	AL,Capital_Letter_A	; Put the drive letter into AL
	Mov	[SI+Thirty_Four],AL	; Put the drive letter into the
					; . correct position in the message
	Call	U1000_Display_Message	; Display the message on the screen
C1503:
	Cmp	Byte Ptr FLG04_Single_Drive,True
	Je	C1505			; If true, go to the message to press
					; . any key to continue
C1504:
	Mov	SI,Offset MES10_Insert_Target
	Mov	AL,Byte Ptr WRK02_Target_Drive
	Add	AL,Capital_Letter_A	; Put the drive letter into AL
	Mov	[SI+Thirty_Four],AL	; Put the drive letter into the
					; . correct position in the message
	Call	U1000_Display_Message	; Display the message on the screen
C1505:
	Mov	SI,Offset MES16_Press_Any_Key
	Call	U1000_Display_Message
	Mov	Byte Ptr FLG05_Store_Buffer,False
	Call	U1100_Get_Response
C1599:
	Ret
;
C1500_Diskette_Messages Endp
;
Page
;************************************************************************
;*									*
;*	C1600A_GET_FREE_MEMORY						*
;*									*
;*	This module calculates the amount of free 16 byte paragraphs	*
;*	available on the machine. The segment address of the beginning	*
;*	of free memory is obtained by setting DX to:			*
;*									*
;*		1. The contents of the stack segment SS plus		*
;*									*
;*		2. 256 bytes for the Program Segment Prefix plus	*
;*									*
;*		3. 128 bytes for the stack.				*
;*									*
;*	After saving the ES segment register on the stack and		*
;*	initializing both the offset register BX and the 16 byte	*
;*	counter register CX to zero, the routine begins the looping	*
;*	through memory 16 bytes at a time (incrementing the segment	*
;*	register ES by one) until either the module encounters one	*
;*	of the two (2) conditions:					*
;*									*
;*		1. The beginning of Video RAM at the segment address	*
;*		   specified in Video_Address.				*
;*									*
;*		2. The memory pattern defined by the machine that	*
;*		   indicates no more memory.				*
;*									*
;*	When either of these two (2) conditions occur, CX contains	*
;*	the  number of 16 bytes paragraphs of free memory.		*
;*									*
;*	Since we do not know the size of the transient portion of	*
;*	COMMAND.COM, FREECOPY makes the worst case assumption that	*
;*	all of the bytes in COMMAND.COM reside in high memory.		*
;*									*
;*	This module also allocates space for the ES:BX table, the	*
;*	CHRN table, the File Allocation Table (FAT) of the source	*
;*	diskette and at least one track (4608 bytes).			*
;*									*
;*	This module executes only when running PC-DOS 1.0 and 1.1!!!	*
;*									*
;************************************************************************
;
Page
;
Public	C1600A_Get_Free_Memory
;
C1600A_Get_Free_Memory Proc Near
;
C1601A:
	Mov	DX,SS			; Calculate the segment address for
					; . the beginning of free memory
	Add	DX,Offset MEM04_Top_of_the_Stack
;
	Push	ES			; Save ES on the stack for a moment
	Mov	BX,NUL			; Initialize BX and CX registers
	Mov	CX,NUL			; ..End
C1602A:
	Mov	ES,DX			; Set ES to the appropriate value
	Cli				; Turn off interrupts for a moment
	Mov	AX,ES:[BX]		; Read a word from memory into AX
	Mov	Word Ptr ES:[BX],SOH	; Put the test pattern into memory
	Cmp	Word Ptr ES:[BX],SOH	; Compare memory with test pattern
	Mov	ES:[BX],AX		; Restore the contents of memory
	Sti				; Turn on the interrupts
	Jne	C1603A			; If not equal, stop looping
	Inc	DX			; Increment DX segment register
	Cmp	DX,Video_Address	; Compare for start of Video RAM
	Jae	C1603A			; If so, stop looping
	Inc	CX			; Increment 16 byte counter CX
	Jmp	C1602A			; Go back and try again
C1603A:
	Pop	ES			; Restore the ES register
	Cmp	CX,Command_Com_Size	; Compare the paragraph size of
					; . free memory with the paragraph
					; . size of COMMAND.COM.
	Ja	C1604A			; If greater, continue
;
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699A			; Go to the end of the module
C1604A:
	Sub	CX,Command_Com_Size	; Subtract the size of COMMAND.COM
	Cmp	CX,ESBX_Table_Size	; Compare the paragraph size of the
					; . free memory with the paragraph
					; . size of the ES:BX table
	Ja	C1605A			; If greater, continue
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699A			; Go to the end of the module
C1605A:
	Sub	CX,ESBX_Table_Size	; Subtract the size of ES:BX table
	Cmp	CX,CHRN_Table_Size	; Compare the paragraph size of the
					; . free memory with the paragraph
					; . size of the CHRN table
	Ja	C1606A			; If greater, continue
;
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699A			; Go to the end of the module
C1606A:
	Sub	CX,CHRN_Table_Size	; Subtract the size of CHRN Table
	Cmp	CX,FAT_Sector_Size	; Determine if there is enough memory
	Jae	C1607A			; to read the File Allocation Table
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699A			; Go to the end of the module
C1607A:
	Sub	CX,FAT_Sector_Size	; Subtract the size of the source FAT
	Cmp	CX,Minimum_Memory_Size	; Determine if the amount of memory
	Jae	C1608A			; can hold a nine sectored track
;
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699A			; Go to the end of the module
C1608A:
	Mov	Word Ptr SYS05_Para_RAM_Size,CX
C1699A:
	Ret
;
C1600A_Get_Free_Memory Endp
;
Page
;************************************************************************
;*									*
;*	C1600B_GET_FREE_MEMORY						*
;*									*
;*	This module calcules the amount of available memory.  It	*
;*	executes when running PC-DOS versions 2.0 and above.		*
;*									*
;************************************************************************
;
Public	C1600B_Get_Free_Memory
;
C1600B_Get_Free_Memory Proc Near
;
C1601B:
	Mov	AH,Modify_Memory_Block	; Allocate enough space for the
	Mov	BX,Offset MEM00_Bottom_Free_Memory
	Mov	CL,Four			; . program and all tables
	Shr	BX,CL			; .
	Inc	BX			; .
	Int	PC_DOS_Interrupt	; .
	Jnc	C1603B			; ..End
C1602B:
	Mov	Byte Ptr FLG01_Good_Command,False
	Mov	SI,Offset MES11_Insufficient_Memory
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699B			; Go to the end of the module
C1603B:
	Mov	AH,Allocate_Memory	; Get the amount of available memory
	Mov	BX,High_Values		; .
	Int	PC_DOS_Interrupt	; .
	Mov	Word Ptr SYS21_Alloc_Segment,AX
	Mov	Word Ptr SYS05_Para_RAM_Size,BX
	Jnc	C1699B			; .
	Cmp	AL,Eight		; .
	Je	C1605B			; .
C1604B:
	Mov	SI,Offset MES97_Return_Linefeed
	Call	U1000_Display_Message	; Issue a carriage return/linefeed
	Mov	SI,Offset MES99_Memory_Block_Destroyed
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1699B			; Go to the end of the module
C1605B:
	Mov	AH,Allocate_Memory	; .
	Int	PC_DOS_Interrupt	; ..End
	Mov	Word Ptr SYS21_Alloc_Segment,AX
	Mov	Word Ptr SYS05_Para_RAM_Size,BX
	Jnc	C1606B			; Set the allocation flag
	Jmp	C1604B			; Go to the error condition
C1606B:
	Mov	Byte Ptr FLG16_Free_Memory,False
C1699B:
	Ret
;
C1600B_Get_Free_Memory Endp
;
Page
;************************************************************************
;*									*
;*	C1700_CREATE_ESBX_TABLE						*
;*									*
;*	This module creates the correct ES:BX addresses that are	*
;*	used when storing tracks read from the source diskette.		*
;*	The routine allocates at most 80 entries in the table for	*
;*	double sided diskettes.						*
;*									*
;************************************************************************
;
Public	C1700_Create_ESBX_Table
;
C1700_Create_ESBX_Table Proc Near
;
C1701:
	Mov	Word Ptr WRK34_DMA_OverFlow_Counter,ZERO
;
	Mov	Word Ptr WRK18_Counter_ESBX_Entries,Zero
	Mov	AX,Nine			; Calculate DI = the number of bytes
	Mov	BX,Sector_Size		; per track and BX = the number of
	Mul	BX			; paragraphs per track
	Mov	DI,AX			; .
	Mov	BX,Paragraph_Size	; .
	Mov	DX,Zero			; .
	Div	BX			; .
	Mov	BX,AX			; ..End
;
	Cmp	Byte Ptr SYS19_Major_Vers_Number,Zero
	Je	C1702			; Compare for PC DOS 1.0 and 1.1
	Mov	AX,Word Ptr SYS21_Alloc_Segment
	Jmp	C1703			; Continue
C1702:
	Mov	AX,CS			; Calculate the address of the 1st
	Mov	CL,Four			; that will be copied into memory
	Shl	AX,CL			; .
	Add	AX,Offset MEM00_Bottom_Free_Memory
	Shr	AX,CL			; .
	Inc	AX			; ..End
C1703:
	Mov	SI,Offset MEM03_ESBX_Table
	Mov	Word Ptr [SI],Zero	; Put the 1st entry into the table
	Mov	Word Ptr [SI+Two],AX	; ..End
C1704:
	Cmp	Word Ptr WRK18_Counter_ESBX_Entries,Seventy_Nine
	Jae	C1707			; Calculate the ES:BX valid entries
	Add	SI,Four			; Get the next ES:BX table address
;
	Mov	AX,[SI-Two]		; Check for DMA overflow error
	And	AX,DMA_Boundary_Mask	; .
	Shl	AX,CL			; .
	Add	AX,DI			; .
	Jnc	C1705			; ..End
;
	Mov	AX,[SI-Two]		; Correction for DMA overflow
	Add	AX,BX			; .
	Mov	[SI-Two],AX		; ..End
	Inc	Word Ptr WRK34_DMA_Overflow_Counter
C1705:
	Mov	AX,[SI-Two]		; Increment the ES segment address
	Add	AX,BX			; ..End
C1706:
	Mov	Word Ptr [SI],Zero	; Put the address into the table
	Mov	Word Ptr [SI+Two],AX	; ..End
	Inc	Word Ptr WRK18_Counter_ESBX_Entries
	Jmp	C1704			; Go back and find another entry
C1707:
	Mov	AX,Word Ptr SYS05_Para_RAM_Size
	Mov	DX,Zero			; Divide by the number of paragraphs
	Div	BX			; . per track
	Mov	Word Ptr WRK19_Number_ESBX_Entries,AX
	Mov	AX,Word Ptr WRK34_DMA_Overflow_Counter
	Sub	Word Ptr WRK19_Number_ESBX_Entries,AX
	Cmp	Word Ptr WRK19_Number_ESBX_Entries,Seventy_Nine
	Jb	C1799			; If less than 79, continue
	Mov	Word Ptr WRK19_Number_ESBX_Entries,Seventy_Nine
	Mov	Byte Ptr FLG17_Copy_More_Disks,True
C1799:
	Ret
;
C1700_Create_ESBX_Table Endp
;
Page
;************************************************************************
;*									*
;*	C1800_VALIDATE_SOURCE_DISK					*
;*									*
;*	This module determines if the source diskette is readable	*
;*	and whether it was formatted under PC DOS 1.0, 1.1, 2.0 or	*
;*	2.1.  The routine also reads the first copy of the File		*
;*	Allocation Table (FAT) storing it for future comparisons	*
;*	as well as analyzing it first entry.				*
;*									*
;*	A series of comparisons for the number of sectors per track	*
;*	is done for the following reasons.  All diskettes formatted	*
;*	under PC DOS 2.0 and 2.1 really have nine sectors.  In order	*
;*	to obtain an eight sectored diskette, the operating system	*
;*	sets the first byte of the File Allocation Table (FAT)		*
;*	accordingly.  In contrast, PC DOS 1.0 and 1.1 formats a track	*
;*	to have exactly eight sectors.					*
;*									*
;************************************************************************
;
Public	C1800_Validate_Source_Disk
;
C1800_Validate_Source_Disk Proc Near
;
C1801:
	Mov	Byte Ptr FLG08_Good_Read,True
;
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	Byte Ptr WRK07_Head_Number,Zero
	Mov	Byte Ptr WRK08_Track_Number,Zero
	Mov	Byte Ptr WRK09_Sector_Number,Nine
	Mov	Byte Ptr WRK10_Number_of_Sectors,One
	Push	CS			; Establish the address ES:BX
	Pop	ES			; ..End
	Mov	BX,Offset MEM01_File_Allocation_Table
;
	Call	D1000_Read_Diskette
;
	Cli				; Set the number of sectors to nine
	Mov	Byte Ptr SYS18_Disk_Parameter_Table[Four],Nine
	Sti				; .
	Mov	Byte Ptr WRK17_Maximum_Sectors,Nine
;				
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	C1803			; Check for good read of sector nine
	Cmp	Byte Ptr WRK14_Status_Operation,Sector_Error
	Je	C1802			; If so, continue
	Mov	Byte Ptr FLG15_IO_Error,One
	Call	D1200_Disk_IO_Error	; Process the error
	Jmp	C1899			; ..End
C1802:
	Cli				; Set the number of sectors to eight
	Mov	Byte Ptr SYS18_Disk_Parameter_Table[Four],Eight
	Sti				; .
	Mov	Byte Ptr WRK17_Maximum_Sectors,Eight
C1803:					; .
	Mov	Byte Ptr FLG08_Good_Read,True
;
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	Byte Ptr WRK07_Head_Number,Zero
	Mov	Byte Ptr WRK08_Track_Number,Zero
	Mov	Byte Ptr WRK09_Sector_Number,Two
	Mov	Byte Ptr WRK10_Number_of_Sectors,One
	Push	CS			; Establish the address ES:BX
	Pop	ES			; ..End
	Mov	BX,Offset MEM01_File_Allocation_Table
;
	Call	D1000_Read_Diskette
;
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	C1804			; If the read operation was
					; . successful, continue
	Mov	Byte Ptr FLG15_IO_Error,One
	Call	D1200_Disk_IO_Error	; Display appropriate error message
	Jmp	C1899			; Go to the end of the module
C1804:
	Mov	AL,Byte Ptr MEM01_File_Allocation_Table[Zero]
;
	Cmp	AL,One_Side_Eight_Sectors
	Jne	C1805			; If not, continue
	Mov	Byte Ptr WRK15_Maximum_Heads,Zero
	Mov	Byte Ptr WRK16_Maximum_Tracks,Thirty_Nine
	Mov	SI,Offset MES03_Copy81_Sectors
	Jmp	C1809			; Continue the processing
C1805:
	Cmp	AL,Two_Sides_Eight_Sectors
	Jne	C1806			; If not, continue
	Mov	Byte Ptr WRK15_Maximum_Heads,One
	Mov	Byte Ptr WRK16_Maximum_Tracks,Seventy_Nine
	Mov	SI,Offset MES04_Copy82_Sectors
	Jmp	C1809			; Continue the processing
C1806:
	Cmp	AL,One_Side_Nine_Sectors
	Jne	C1807			; If not, continue
	Mov	Byte Ptr WRK15_Maximum_Heads,Zero
	Mov	Byte Ptr WRK16_Maximum_Tracks,Thirty_Nine
	Mov	SI,Offset MES05_Copy91_Sectors
	Jmp	C1809			; Continue the processing
C1807:
	Cmp	AL,Two_Sides_Nine_Sectors
	Jne	C1808			; If not, continue
	Mov	Byte Ptr WRK15_Maximum_Heads,One
	Mov	Byte Ptr WRK16_Maximum_Tracks,Seventy_Nine
	Mov	SI,Offset MES06_Copy92_Sectors
	Jmp	C1809			; Continue the processing
C1808:
	Mov	Byte Ptr FLG08_Good_Read,False
	Mov	SI,Offset MES19_Unrecoverable_Read
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	SI,Offset MES90_Unknown_FAT_Error
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1899			; Go to display the message
C1809:
	Cmp	Byte Ptr WRK15_Maximum_Heads,Zero
	Je	C1810			; If the diskette is single sided,
					; . display the diskette message
	Cmp	Byte Ptr FLG02_Double_Side,True
	Je	C1810			; If the flag indicates to copy 
					; . both sides of the diskette,
					; . then continue
	Mov	Byte Ptr WRK15_Maximum_Heads,Zero
	Mov	Byte Ptr WRK16_Maximum_Tracks,Thirty_Nine
C1810:
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	Byte Ptr WRK07_Head_Number,One
	Mov	Byte Ptr WRK08_Track_Number,Zero
	Mov	Byte Ptr WRK09_Sector_Number,One
	Mov	Byte Ptr WRK10_Number_of_Sectors,One
	Push	CS			; Establish the ES segment register
	Pop	ES			; .
	Push	ES			; ..End
	Mov	BX,Offset MEM00_Bottom_Free_Memory
	Cmp	SYS19_Major_Vers_Number,Zero
	Je	C1811			; If PC DOS 1.0 or 1.1, continue;
					; . otherwise, setup ES:BX a little
	Mov	ES,Word Ptr SYS21_Alloc_Segment
	Mov	BX,Zero			; . differently
C1811:
	Call	D1000_Read_Diskette
	Pop	ES			; Restore ES in any case
;
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	C1813		; Go to display the message
	Cmp	Byte Ptr WRK15_Maximum_Heads,One
	Je	C1812		; If double sided diskette, error!!!
	Mov	Byte Ptr FLG08_Good_Read,True
	Mov	Byte Ptr FLG02_Double_Side,False
	Jmp	C1813		; Display the appropriate message
C1812:
	Mov	SI,Offset MES19_Unrecoverable_Read
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	SI,Offset MES91_Single_Side_Error
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C1899			; Go to the end of the module
C1813:
	Call	U1000_Display_Message	; Display the message on the screen
C1899:
	Ret
;
C1800_Validate_Source_Disk Endp
;
Page
;************************************************************************
;*									*
;*	C1900_CREATE_CHRN_TABLE						*
;*									*
;*	This module creates the CHRN table to be used in case the	*
;*	target diskette needs to be formatted.	The abbreviation	*
;*	stands for C = track number, H = head number, R = sector	*
;*	number and N = a code for the number of bytes per sector.	*
;*									*
;************************************************************************
;
Public	C1900_Create_CHRN_Table
;
C1900_Create_CHRN_Table Proc Near
;
C1901:
	Mov	BH,Byte Ptr WRK15_Maximum_Heads
	Mov	BL,Byte Ptr WRK16_Maximum_Tracks
	Mov	AL,Nine
;
	Mov	CL,BH			; Establish correct track number
	Shr	BL,CL			; ..End
;
	Mov	DL,Two			; . DL = number of sectors
	Mov	DH,Zero			; . DH = head number
	Mov	CH,Zero			; . CH = track number
	Mov	CL,One			; . CL = sector number
	Mov	SI,Offset MEM02_CHRN_Table; Set up initial registers
C1902:
	Mov	[SI],CH			; Establish an entry in the CHRN
	Mov	[SI+One],DH		; . table
	Mov	[SI+Two],CL		; .
	Mov	[SI+Three],DL		; ..End
;
	Add	SI,Four			; Get the addr of next CHRN entry
	Inc	CL			; Increment the sector number
	Cmp	CL,AL			; Compare for maximum sectors
	Jbe	C1902			; If not, go back and try again
;
	Mov	CL,One			; Initialize sector number
	Inc	DH			; Increment the head number
	Cmp	DH,BH			; Compare for maximum heads
	Jbe	C1902			; If not, go back and try again
;
	Mov	CL,One			; Initialize sector number
	Mov	DH,Zero			; Initialize head number
	Inc	CH			; Increment the track number
	Cmp	CH,BL			; Compare for maximum tracks
	Jbe	C1902			; If not, go back and try again
C1999:
	Ret
;
C1900_Create_CHRN_Table Endp
;
Page
;************************************************************************
;*									*
;*	C2000_READ_SOURCE_DISK						*
;*									*
;*	This module reads a diskette track by track until it fills	*
;*	all of available memory specified by the ES:BX table.  The	*
;*	processing sequence is:						*
;*									*
;*	1. Initializes the SI resgister to point to the correct entry	*
;*	   in the ES:BX table.						*
;*									*
;*	2. Prints the initial read message on the screen.		*
;*									*
;*	3. Compares for the end of the ES:BX table and/or the number	*
;*	   of tracks on the diskette.  If not, continue.  If so,	*
;*	   return to B1100_Detail_Processing.				*
;*									*
;*	4. Reads a track from the source diskette.			*
;*									*
;*	5. Displays the track and head numbers on the screen.		*
;*									*
;*	6. Transfers control to 3.					*
;*									*
;************************************************************************
;
Page
;
Public	C2000_Read_Source_Disk
;
C2000_Read_Source_Disk Proc Near
;
C2001:
	Mov	Byte Ptr FLG08_Good_Read,True
;
	Mov	SI,Offset MEM03_ESBX_Table
	Mov	Word Ptr WRK18_Counter_ESBX_Entries,Zero
;
	Cmp	Byte Ptr FLG13_First_Read_Write,False
	Je	C2002			; If not first time, continue
	Mov	Byte Ptr WRK31_Track_Read_Counter,Zero
	Jmp	C2003			; Go to display the message
C2002:
	Cmp	Byte Ptr FLG04_Single_Drive,False
	Je	C2004			; If double drive copy, continue
C2003:
	Push	SI			; Save SI = Addr of ES:BX table
	Mov	SI,Offset MES97_Return_Linefeed
	Call	U1000_Display_Message	; Display a return and linefeed
	Mov	SI,Offset MES17_Reading_Track
	Mov	AL,Byte Ptr WRK21_Current_Source_Track
	Call	U1300_Convert_Binary_to_ASCII
	Mov	[SI+Fifteen],AX		; Put the track number into message
	Mov	AL,Byte Ptr WRK20_Current_Source_Head
	Call	U1300_Convert_Binary_to_ASCII
	Mov	[SI+Twenty_Five],AL	; Put the head number into message
	Call	U1000_Display_Message	; Display the message on the screeen
;
	Mov	AH,Read_Cursor_Command	; Get the current cursor position
	Mov	BH,Byte Ptr SYS03_Active_Page
	Int	Video_Interrupt		; ..End
;
	Dec	DH			; Save the row of the read track and
	Mov	Byte Ptr WRK24_Read_Message_Row,DH; . head message
;
	Pop	SI			; Restore SI = Addr of ES:BX table
C2004:
	Mov	AL,Byte Ptr WRK31_Track_Read_Counter
	Cmp	AL,Byte Ptr WRK16_Maximum_Tracks
	Jbe	C2005			; If more tracks, then continue
	Jmp	C2099			; Go to the end of the module
C2005:
	Mov	AX,Word Ptr WRK18_Counter_ESBX_Entries
	Cmp	AX,Word Ptr WRK19_Number_ESBX_Entries
	Jbe	C2006			; If more memory exists, continue
	Jmp	C2099			; Go to the end of the module
C2006:
;					; Display the current track and head
	Mov	AL,Byte Ptr WRK24_Read_Message_Row
	Mov	Byte Ptr WRK28_Current_Message_Row,AL
	Mov	AL,Byte Ptr WRK20_Current_Source_Head
	Mov	Byte Ptr WRK29_Current_Head,AL
	Mov	AL,Byte Ptr WRK21_Current_Source_Track
	Mov	Byte Ptr WRK30_Current_Track,AL
;
	Call	U1400_Display_Head_and_Track
;
					; Establish the disk parameters
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	AL,Byte Ptr WRK20_Current_Source_Head
	Mov	Byte Ptr WRK07_Head_Number,AL
	Mov	AL,Byte Ptr WRK21_Current_Source_Track
	Mov	Byte Ptr WRK08_Track_Number,AL
	Mov	Byte Ptr WRK09_Sector_Number,One
	Mov	AL,Byte Ptr WRK17_Maximum_Sectors
	Mov	Byte Ptr WRK10_Number_of_Sectors,AL
	Mov	AX,DS:[SI]		; .
	Mov	BX,AX			; .
	Mov	AX,DS:[SI+Two]		; .
	Mov	ES,AX			; ..End
;
	Call	D1000_Read_Diskette	; Read the source diskette
C2007:
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	C2008			; If the read operation was 
					; . successful, then continue
	Mov	Byte Ptr FLG15_IO_Error,One
	Call	D1200_Disk_IO_Error	; Display appropriate error message
	Jmp	C2099			; Go to the end of the module
C2008:
	Inc	Byte Ptr WRK31_Track_Read_Counter
	Inc	Word Ptr WRK18_Counter_ESBX_Entries
	Add	SI,Four			; Increment addr of the ES:BX table
	Cmp	Byte Ptr FLG02_Double_Side,False
	Je	C2009			; If single sided, then continue
	Inc	Byte Ptr WRK20_Current_Source_Head
	Cmp	Byte Ptr WRK20_Current_Source_Head,One
	Jbe	C2010			; If the head number is less than or
					; . equal to one, then continue
	Mov	Byte Ptr WRK20_Current_Source_Head,Zero
C2009:
	Inc	Byte Ptr WRK21_Current_Source_Track
C2010:
	Jmp	C2004			; Go back and read another track
C2099:
	Ret
;
C2000_Read_Source_Disk Endp
;
Page
;************************************************************************
;*									*
;*	C2100_WRITE_FORMAT_TARGET_DISK					*
;*									*
;*	This module formats and writes  a diskette track by track	*
;*	until it fills all of available memory specified by the		*
;*	ES:BX table.  The processing sequence is:			*
;*									*
;*	1. Initializes the SI resgister to point to the correct entry	*
;*	   in the ES:BX table.						*
;*									*
;*	2. Prints the initial write message on the screen.		*
;*									*
;*	3. Compares for the end of the ES:BX table and/or the number	*
;*	   of tracks on the diskette.  If not, continue.  If so,	*
;*	   return to B1100_Detail_Processing.				*
;*									*
;*	4. Writes a track from the source diskette.			*
;*									*
;*	5. Displays the track and head numbers on the screen.		*
;*									*
;*	6. Transfers control to 3.					*
;*									*
;************************************************************************
;
Public	C2100_Write_Format_Target_Disk
;
C2100_Write_Format_Target_Disk Proc Near
;
C2101:
	Mov	Byte Ptr FLG09_Good_Write,True
	Mov	Byte Ptr FLG11_Good_Format,True
;
	Mov	Byte Ptr WRK13_Retry_Counter,Number_of_Retries
;
	Mov	SI,Offset MEM03_ESBX_Table
	Mov	Word Ptr WRK18_Counter_ESBX_Entries,Zero
;
	Cmp	Byte Ptr FLG13_First_Read_Write,False
	Je	C2102			; If not first time, continue
	Mov	Byte Ptr WRK32_Track_Write_Counter,Zero
	Jmp	C2103			; Go to display the message
C2102:
	Cmp	Byte Ptr FLG04_Single_Drive,False
	Je	C2104			; If double drive copy, continue
C2103:
	Push	SI			; Save SI = Addr of ES:BX table
;
	Mov	SI,Offset MES97_Return_Linefeed
	Call	U1000_Display_Message	; Display return and line feed
	Mov	SI,Offset MES23_Writing_Track
	Call	U1000_Display_Message	; Display write track message
;
	Mov	AH,Read_Cursor_Command	; Get the current cursor position
	Mov	BH,Byte Ptr SYS03_Active_Page
	Int	Video_Interrupt		; ..End
;
	Dec	DH			; Save the row of the I/O track and
	Mov	Byte Ptr WRK27_Write_Message_Row,DH; . head information
	Sub	DH,Two			; .
	Mov	Byte Ptr WRK24_Read_Message_Row,DH
;
	Pop	SI			; Restore SI = Addr of ES:BX table
C2104:
	Mov	AL,Byte Ptr WRK32_Track_Write_Counter
	Cmp	AL,Byte Ptr WRK16_Maximum_Tracks
	Jbe	C2105			; If more tracks, then continue
	Mov	Byte Ptr FLG14_Copy_Complete,True
	Jmp	C2199			; Go to the end of the module
C2105:
	Mov	AX,Word Ptr WRK18_Counter_ESBX_Entries
	Cmp	AX,Word Ptr WRK19_Number_ESBX_Entries
	Jbe	C2106			; If more memory exists, continue
	Jmp	C2199			; Go to the end of the module
C2106:
;					; Establish the disk parameters
	Mov	AL,Byte Ptr WRK02_Target_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	AL,Byte Ptr WRK22_Current_Target_Head
	Mov	Byte Ptr WRK07_Head_Number,AL
	Mov	AL,Byte Ptr WRK23_Current_Target_Track
	Mov	Byte Ptr WRK08_Track_Number,AL
	Mov	Byte Ptr WRK09_Sector_Number,One
	Mov	AL,Byte Ptr WRK17_Maximum_Sectors
	Mov	Byte Ptr WRK10_Number_of_Sectors,AL
	Mov	AX,DS:[SI+Two]		; .
	Mov	Word Ptr WRK11_Segment_Address,AX
	Mov	AX,DS:[SI]		; .
	Mov	Word Ptr WRK12_Offset_Address,AX
;
	Call	D1100_Write_Format_Diskette
;
	Cmp	Byte Ptr FLG11_Good_Format,True
	Je	C2107			; If a good format, continue
	Cmp	Byte Ptr FLG09_Good_Write,True
	Je	C2107			; If a good write, continue
	Call	D1200_Disk_IO_Error	; Display appropriate error message
	Jmp	C2199			; Go to the end of the module
C2107:
	Inc	Byte Ptr WRK32_Track_Write_Counter
	Inc	Word Ptr WRK18_Counter_ESBX_Entries
	Add	SI,Four			; Increment addr of the ES:BX table
	Cmp	Byte Ptr FLG02_Double_Side,False
	Je	C2108			; If single sided, then continue
	Inc	Byte Ptr WRK22_Current_Target_Head
	Cmp	Byte Ptr WRK22_Current_Target_Head,One
	Jbe	C2109			; If the head number is less than or
					; . equal to one, then continue
	Mov	Byte Ptr WRK22_Current_Target_Head,Zero
C2108:
	Inc	Byte Ptr WRK23_Current_Target_Track
C2109:
	Jmp	C2104			; Go back and write another track
C2199:
	Ret
;
C2100_Write_Format_Target_Disk Endp
;
Page
;************************************************************************
;*									*
;*	C2200_CHECK_FILE_ALLOC_TABLE					*
;*									*
;*	This module checks the File Allocation Table (FAT) of the	*
;*	diskette in the source drive and compares it with the File	*
;*	Allocation Table (FAT) of the original source diskette.  If	*
;*	there are any differences, the program sets the flag		*
;*	FLG12_Good_FAT to False; otherwise, the flag is True.		*
;*									*
;************************************************************************
;
Public	C2200_Check_File_Alloc_Table
;
C2200_Check_File_Alloc_Table Proc Near
;
C2201:
	Mov	Byte Ptr FLG12_Good_FAT,True
;
	Mov	AL,Byte Ptr WRK01_Source_Drive
	Mov	Byte Ptr WRK06_Drive_Number,AL
	Mov	Byte Ptr WRK07_Head_Number,Zero
	Mov	Byte Ptr WRK08_Track_Number,Zero
	Mov	Byte Ptr WRK09_Sector_Number,Two
	Mov	Byte Ptr WRK10_Number_of_Sectors,One
	Push	CS			; Establish the ES segment register
	Pop	ES			; .
	Push	ES			; ..End
	Mov	BX,Offset MEM00_Bottom_Free_Memory
	Cmp	SYS19_Major_Vers_Number,Zero
	Je	C2202			; If PC DOS 1.0 or 1.1, continue;
					; . otherwise, set up ES:BX a little
	Mov	ES,Word Ptr SYS21_Alloc_Segment
	Mov	BX,Zero			; . differently
C2202:
	Call	D1000_Read_Diskette	; Read the File Allocation Table
	Pop	ES			; Restore ES in any case
;
	Cmp	Byte Ptr FLG08_Good_Read,True
	Je	C2203			; If the read operation was
					; . successful, continue
	Mov	Byte Ptr FLG15_IO_Error,One
	Call	D1200_Disk_IO_Error	; Display appropriate error message
	Jmp	C2299			; Go to the end of the module
C2203:
	Mov	SI,Offset MEM01_File_Allocation_Table
	Mov	DI,Offset MEM00_Bottom_Free_Memory
	Push	ES			; Save ES for a moment
	Cmp	Byte Ptr SYS19_Major_Vers_Number,Zero
	Je	C2204			; If PC DOS 1.0 or 1.1, continue
	Mov	ES,Word Ptr SYS21_Alloc_Segment
	Mov	DI,Zero			; Set up ES:DI for PC DOS 2.0+
C2204:
	Mov	CX,Sector_Size		; Set counter CX to compare the
					; . sector size in words
	Shr	CX,1			; ..End
	Cld				; Clear the direction flag
	Rep	Cmpsw			; Compare all of the 512 bytes
	Jne	C2205			; If there is a discrepancy, go to
					; . the error message routine
	Jmp	C2206			; Go to the end of the module
C2205:
	Pop	ES			; Restore the ES register
	Mov	Byte Ptr FLG12_Good_FAT,False
	Mov	SI,Offset MES19_Unrecoverable_Read
	Call	U1000_Display_Message	; Display the message on the screen
	Mov	SI,Offset MES90_Unknown_FAT_Error
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	C2299			; Go to the end of the module
C2206:
	Pop	ES			; Restore the ES register
C2299:
	Ret
;
C2200_Check_File_Alloc_Table Endp
;
Page
;************************************************************************
;*									*
;*	C2300_FREE_MEMORY						*
;*									*
;*	This module free up allocated memory, provided that a user	*
;*	is running PC DOS 2.0 or greater; otherwise, it does nothing.	*
;*									*
;************************************************************************
;
Public	C2300_Free_Memory
;
C2300_Free_Memory Proc Near
;
C2301:
	Cmp	Byte Ptr SYS19_Major_Vers_Number,Zero
	Je	C2399			; If PC DOS 1.0 or 1.1, go to the
					; . end of the module
	Cmp	Byte Ptr FLG16_Free_Memory,True
	Je	C2399			; If memory was not allocated, go
					; . to the end of the module
;
	Mov	AH,Free_Memory		; Free allocated memory
	Push	ES			; .
	Mov	ES,Word Ptr SYS21_Alloc_Segment
	Int	PC_DOS_Interrupt	; .
	Pop	ES			; .
	Jnc	C2399			; ..End
;
	Mov	SI,Offset MES97_Return_Linefeed
	Call	U1000_Display_Message	; Issue a carriage return/linefeed
	Mov	SI,Offset MES99_Memory_Block_Destroyed
	Call	U1000_Display_Message	; Display the message on the screen
C2399:
	Ret
;
C2300_Free_Memory Endp
;
Page
;************************************************************************
;*									*
;*	D1000_READ_DISKETTE						*
;*									*
;*	This module reads a track at a time from a diskette. If it	*
;*	fails to read the diskette it tries Number_of_Retries = 5	*
;*	times.								*
;*									*
;************************************************************************
;
Public	D1000_Read_Diskette
;
D1000_Read_Diskette Proc Near
;
D1001:
	Mov	Byte Ptr WRK13_Retry_Counter,Number_of_Retries
D1002:
	Clc				; Clear the carry flag
	Mov	AH,Read_Command		; Read the data on the diskette
	Mov	DL,Byte Ptr WRK06_Drive_Number
	Mov	DH,Byte Ptr WRK07_Head_Number
	Mov	CH,Byte Ptr WRK08_Track_Number
	Mov	CL,Byte Ptr WRK09_Sector_Number
	Mov	AL,Byte Ptr WRK10_Number_of_Sectors
	Int	Disk_Interrupt		; ..End
;
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1099			; Go to the end of the module
D1003:
	Dec	Byte Ptr WRK13_Retry_Counter
	Jz	D1004			; Could not read the diskette
	Clc				; Clear the carry flag
	Mov	AH,Reset_Command	; Initialize the disk controller
	Int	Disk_Interrupt		; .
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1002			; .
	Jmp	D1003			; ..End
D1004:
	Mov	Byte Ptr FLG08_Good_Read,False
D1099:
	Ret
;
D1000_Read_Diskette Endp
;
Page
;************************************************************************
;*									*
;*	D1100_WRITE_FORMAT_DISKETTE					*
;*									*
;*	This module formats and writes a track at a time to a 		*
;*	diskette.  If it fails to format or a write a track, it tries	*
;*	Number_of_Retries = 5 times.					*
;*									*
;************************************************************************
;
Public	D1100_Write_Format_Diskette
;
D1100_Write_Format_Diskette Proc Near
;
D1101:
	Mov	Byte Ptr WRK13_Retry_Counter,Number_of_Retries
D1102:
	Clc				; Clear the carry flag
	Mov	AH,Format_Command	; Format the diskette
	Mov	DL,Byte Ptr WRK06_Drive_Number
	Mov	DH,Byte Ptr WRK07_Head_Number
	Mov	CH,Byte Ptr WRK08_Track_Number
	Mov	CL,Byte Ptr WRK09_Sector_Number
	Mov	AL,Byte Ptr WRK10_Number_of_Sectors
	Push	CS			; .
	Pop	ES			; .
	Mov	BX,Word Ptr WRK33_CHRN_Table_Address
	Int	Disk_Interrupt		; ..End
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1105			; Formatted the diskette
D1103:
	Dec	Byte Ptr WRK13_Retry_Counter
	Jz	D1104			; Go to format error processing
	Clc				; Clear the carry flag
	Mov	AH,Reset_Command	; Initialize the disk controller
	Int	Disk_Interrupt		; .
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1102			; Try to format the disk again
	Jmp	D1103			; Try to initialize the disk again
D1104:
	Mov	Byte Ptr FLG15_IO_Error,Zero
	Mov	Byte Ptr FLG11_Good_Format,False
	Jmp	D1199			; Go to the end of the module
D1105:
	Mov	Byte Ptr WRK13_Retry_Counter,Number_of_Retries
D1106:
	Clc				; Clear the carry flag
	Mov	AH,Write_Command	; Write the diskette
	Mov	ES,Word Ptr WRK11_Segment_Address
	Mov	BX,Word Ptr WRK12_Offset_Address
	Mov	AL,Byte Ptr WRK10_Number_of_Sectors
	Int	Disk_Interrupt		; .
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1109			; ..End
D1107:
	Dec	Byte Ptr WRK13_Retry_Counter
	Jz	D1108			; Go to write error processing
	Clc				; Clear the carry flag
	Mov	AH,Reset_Command	; Initialize the disk controller
	Int	Disk_Interrupt		; .
	Mov	Byte Ptr WRK14_Status_Operation,AH
	Jnc	D1106			; .
	Jmp	D1107			; ..End
D1108:
	Mov	Byte Ptr FLG15_IO_Error,Two
	Mov	Byte Ptr FLG09_Good_Write,False
	Jmp	D1199			; Go to the end of the module
D1109:
	Add	Word Ptr WRK33_CHRN_Table_Address,Thirty_Six
;
	Mov	AL,Byte Ptr WRK27_Write_Message_Row
	Mov	Byte Ptr WRK28_Current_Message_Row,AL
	Mov	AL,Byte Ptr WRK22_Current_Target_Head
	Mov	Byte Ptr WRK29_Current_Head,AL
	Mov	AL,Byte Ptr WRK23_Current_Target_Track
	Mov	Byte Ptr WRK30_Current_Track,AL
	Call	U1400_Display_Head_and_Track
D1199:
	Ret
;
D1100_Write_Format_Diskette Endp
;
Page
;************************************************************************
;*									*
;*	D1200_DISK_IO_ERROR						*
;*									*
;*	This module fans out a disk error.  It tells a user if it	*
;*	occured on a read, format or write operation.  If it cannot	*
;*	determine the nature of the error, the routine displays an	*
;*	unknown disk error message.					*
;*									*
;************************************************************************
;
Public	D1200_Disk_IO_Error
;
D1200_Disk_IO_Error Proc Near
;
D1201:
	Cmp	Byte Ptr WRK14_Status_Operation,Time_Out_Error
	Jne	D1202			; If not time out error, continue
	Mov	SI,Offset MES08_Drive_Not_Ready
	Mov	AL,Byte Ptr WRK06_Drive_Number
	Add	AL,Capital_Letter_A	; Convert drive number to a letter
	Mov	[SI+Twenty_Four],AL	; Put the drive letter into position
	Call	U1000_Display_Message
	Jmp	D1299			; Go to the end of the module
D1202:
	Cmp	Byte Ptr FLG15_IO_Error,Zero
	Jne	D1203			; If not a format error, continue
	Mov	SI,Offset MES18_Unrecoverable_Format
	Jmp	D1206			; Continue processing
D1203:
	Cmp	Byte Ptr FLG15_IO_Error,One
	Jne	D1204			; If not a read error, continue
	Mov	SI,Offset MES19_Unrecoverable_Read
	Jmp	D1206			; Continue processing
D1204:
	Cmp	Byte Ptr FLG15_IO_Error,Two
	Jne	D1205			; If not a write error, continue
	Mov	SI,Offset MES21_Unrecoverable_Write
	Jmp	D1206			; Continue processing
D1205:
	Mov	SI,Offset MES22_Unrecoverable_IO
D1206:
	Call	U1000_Display_Message	; Display the message on the screen
D1207:
	Cmp	Byte Ptr WRK14_Status_Operation,Seek_Error
	Jne	D1208			; If not a seek error, continue
	Mov	SI,Offset MES80_Seek_Error
	Jmp	D1217			; Continue processing
D1208:
	Cmp	Byte Ptr WRK14_Status_Operation,Controller_Error
	Jne	D1209			; If not a controller error, continue
	Mov	SI,Offset MES81_Controller_Error
	Jmp	D1217			; Continue processing
D1209:
	Cmp	Byte Ptr WRK14_Status_Operation,CRC_Error
	Jne	D1210			; If not a CRC error, continue
	Mov	SI,Offset MES82_CRC_Error
	Jmp	D1217			; Continue processing
D1210:
	Cmp	Byte Ptr WRK14_Status_Operation,DMA_Boundary_Error
	Jne	D1211			; If not DMA boundary error, continue
	Mov	SI,Offset MES83_DMA_Boundary_Error
	Jmp	D1217			; Continue processing
D1211:
	Cmp	Byte Ptr WRK14_Status_Operation,DMA_Error
	Jne	D1212			; If not a DMA error, continue
	Mov	SI,Offset MES84_DMA_Error
	Jmp	D1217			; Continue processing
D1212:
	Cmp	Byte Ptr WRK14_Status_Operation,Sector_Error
	Jne	D1213			; If not a sector error, continue
	Mov	SI,Offset MES85_Sector_Error
	Jmp	D1217			; Continue processing
D1213:
	Cmp	Byte Ptr WRK14_Status_Operation,Write_Protect_Error
	Jne	D1214			; If not write protected, continue
	Mov	SI,Offset MES86_Write_Protect_Error
	Jmp	D1217			; Continue processing
D1214:
	Cmp	Byte Ptr WRK14_Status_Operation,Address_Mark_Error
	Jne	D1215			; If not addr mark error, continue
	Mov	SI,Offset MES87_Address_Mark_Error
	Jmp	D1217			; Continue processing
D1215:
	Cmp	Byte Ptr WRK14_Status_Operation,Command_Error
	Jne	D1216			; If not a command error, continue
	Mov	SI,Offset MES88_Command_Error
	Jmp	D1217			; Continue processing
D1216:
	Mov	SI,Offset MES89_Unknown_Error
D1217:
	Call	U1000_Display_Message	; Display the message on the screen
D1299:
	Ret
;
D1200_Disk_IO_Error Endp
;
Page
;************************************************************************
;*									*
;*	S1000_SETUP_DISK_PARAM_TABLE					*
;*									*
;*	This module sets up the Disk Parameter Table (Int 1EH) so that	*
;*	it points to the disk parameters for PC DOS 2.1 contained in	*
;*	this program.							*
;*									*
;************************************************************************
;
Public	S1000_Setup_Disk_Param_Table
;
S1000_Setup_Disk_Param_Table Proc Near
;
S1001:
	Push	AX			; Save the registers
	Push	BX			; .
	Push	DS			; ..End
;
	Cli				; Turn off the interrupts

;
	Sub	AX,AX			; Initialize DS to Absolute Zero
	Mov	DS,AX			; ..End
;
	Mov	BX,Disk_Parameter_Addr	; Save and redirect the address
	Mov	AX,[BX]			; .
	Mov	Word Ptr CS:SYS16_Save_DPT_Offset,AX
	Mov	AX,[BX+Two]		; .
	Mov	Word Ptr CS:SYS17_Save_DPT_Segment,AX
					; .
	Mov	AX,Offset SYS18_Disk_Parameter_Table
	Mov	[BX],AX			; .
	Mov	AX,CS			; .
	Mov	[BX+Two],AX		; ..End
;
	Sti				; Turn on interrupts
;
	Pop	DS			; Restore the registers
	Pop	BX			; .
	Pop	AX			; ..End
S1099:
	Ret
;
S1000_Setup_Disk_Param_Table Endp
;
Page
;************************************************************************
;*									*
;*	S1100_RESTORE_DISK_PARAM_TABLE					*
;*									*
;*	This module restores the Disk Parameter Table to its original	*
;*	address in PC DOS.						*
;*									*
;************************************************************************
;
Public	S1100_Restore_Disk_Param_Table
;
S1100_Restore_Disk_Param_Table Proc Near
;
S1101:
	Push	AX			; Save the registers
	Push	BX			; .
	Push	DS			; ..End
;
	Cli				; Turn off the interrupts
;
	Sub	AX,AX			; Initialize DS to Absolute Zero
	Mov	DS,AX			; ..End
;
	Mov	BX,Disk_Parameter_Addr	; Restore Disk Parameter Address
	Mov	AX,Word Ptr CS:SYS16_Save_DPT_Offset
	Mov	[BX],AX			; .
	Mov	AX,Word Ptr CS:SYS17_Save_DPT_Segment
	Mov	[BX+Two],AX		; ..End
;
	Sti				; Turn on the interrupts
;
	Pop	DS			; Restore the registers
	Pop	BX			; .
	Pop	AX			; ..End
S1199:
	Ret
;
S1100_Restore_Disk_Param_Table Endp
;
Page
;************************************************************************
;*									*
;*	S1200_GET_VERSION_NUMBER					*
;*									*
;*	This module gets the current version number of PC DOS and	*
;*	stores the information in determining whether to allocate	*
;*	memory using the PC DOS 2.0 function calls.			*
;*									*
;************************************************************************
;
Public	S1200_Get_Version_Number
;
S1200_Get_Version_Number Proc Near
;
S1201:
	Push	AX			; Save the registers and flags
	Pushf				; ..End
;
	Mov	AH,Get_DOS_Version_Number
	Int	PC_DOS_Interrupt
	Mov	Byte Ptr SYS19_Major_Vers_Number,AL
	Mov	Byte Ptr SYS20_Minor_Vers_Number,AH
;
	Popf				; Restore the registers and flags
	Pop	AX			; ..End
S1299:
	Ret
;
S1200_Get_Version_Number Endp
;
Page
;************************************************************************
;*									*
;*	U1000_DISPLAY_MESSAGE						*
;*									*
;*	This module displays a message on the screen. Before calling	*
;*	this module, the offset of the message should be in SI 		*
;*	relative to the DS register.  This routine preserves the	*
;*	registers and the flags.					*
;*									*
;************************************************************************
;
Public	U1000_Display_Message
;
U1000_Display_Message Proc Near
;
U1001:
	Push	AX			; Save the registers and flags
	Push	BX			; .
	Push	SI			; .
	Pushf				; ..End
U1002:
	Mov	AL,[SI]			; Put the character into AL
	Cmp	AL,EOT			; Compare for the end of the string
	Je	U1090			; If so, go to end of the module
	Mov	AH,Write_TTY_Command	; Write the Character
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
	Inc	SI			; Increment the SI counter
	Jmp	U1002			; Go back and try again
U1090:
	Popf				; Restore the registers and flags
	Pop	SI			; .
	Pop	BX			; .
	Pop	AX			; ..End
U1099:
	Ret
;
U1000_Display_Message Endp
;
Page
;************************************************************************
;*									*
;*	U1100_GET_RESPONSE						*
;*									*
;*	This module gets the response from the keyboard and displays	*
;*	the information on the video display unit.  The keyboard	*
;*	buffer is WRK05_Keyboard_Buffer.  The first byte of this	*
;*	buffer contains the length of the buffer and must be less	*
;*	than or equal to 80 characters.  The next 80 characters are	*
;*	the acutal buffer. The character EOT denotes the end of the	*
;*	buffer and can occur in any one of the 80 characters.		*
;*									*
;************************************************************************
;
Public	U1100_Get_Response
;
U1100_Get_Response Proc Near
;
U1101:
	Push	AX			; Save the registers and flags
	Push	BX			; .
	Push	CX			; .
	Push	SI			; .
	Pushf				; ..End
U1102:
	Mov	SI,Offset WRK05_Keyboard_Buffer+1
	Mov	CX,NUL			; Initialize the CX counter register
U1103:
	Mov	AH,Flush_Keyboard_Command; Read the character from keyboard
	Mov	AL,Read_Keyboard_Command; .
	Int	PC_DOS_Interrupt	; ..End
	Cmp	AL,ETX			; Compare for a control break
	Jne	U1104			; If not, then continue
	Mov	SI,Offset MES98_Control_Break
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	A1002			; Go to B1200_Final_Process
U1104:
	Cmp	Byte Ptr FLG05_Store_Buffer,True
	Je	U1105			; If store keyboard entries, continue
	Jmp	U1190			; If not, go to end of the module
U1105:
	Cmp	AL,BS			; Is AL a backspace character???
	Jne	U1106			; If not, continue processing AL
	Cmp	CX,NUL			; Is the cursor at column zero????
	Je	U1103			; Yes, so get another character
	Dec	CX			; Decrement CX to point to the
					; . previous cursor location
	Dec	SI			; Decrement SI to go back to the
					; . previos buffer location
;
	Mov	AH,Write_TTY_Command	; Write a backspace to the screen
	Mov	AL,BS			; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	AH,Write_TTY_Command	; Write a space to the screen
	Mov	AL,Space		; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	AH,Write_TTY_Command	; Write a backspace to the screen
	Mov	AL,BS			; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Jmp	U1103			; Go back and get another character
U1106:
	Cmp	AL,CR			; Compare char for a carriage return
	Je	U1108			; If so, insert an EOT into buffer
	Cmp	CX,Keyboard_Buffer_Size	; Check for keyboard buffer full
	Jae	U1107			; If so, sound bell and get new char
	Mov	[SI],AL			; Put the character into the buffer
	Inc	SI			; Increment the keyboard address
	Inc	CX			; Increment the CX character counter
	Jmp	U1103			; Go back and get another character
U1107:
	Mov	AH,Write_TTY_Command	; Sound the beep from the screen
	Mov	AL,Bell			; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
	Jmp	U1103			; Go back and get another character
U1108:
	Mov	AL,EOT			; Put an EOT into the buffer
	Mov	[SI],AL			; ..End
;
	Mov	AH,Write_TTY_Command	; Write a carriage return to the
	Mov	AL,CR			; . screen
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	AH,Write_TTY_Command	; Write a line feed to the screen
	Mov	AL,LF			; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	WRK05_Keyboard_Buffer[0],CL; Set the length accrodingly
U1190:
	Popf				; Restore the registers and flags
	Pop	SI			; .
	Pop	CX			; .
	Pop	BX			; .
	Pop	AX			; ..End
U1199:
	Ret
U1100_Get_Response Endp
;
Page
;************************************************************************
;*									*
;*	U1200_GET_YES_OR_NO						*
;*									*
;*	This module asks for a [Yy]es or [Nn]o answer from a user.  The	*
;*	routine accepts only a [Yy] or [Nn] and exists with the flag	*
;*	FLG06_Yes_or_No set to True for YES and False for NO.		*
;*									*
;************************************************************************
;
Public	U1200_Get_Yes_or_No
;
U1200_Get_Yes_or_No Proc Near
;
U1201:
	Push	AX			; Save the registers and flags
	Push	SI			; .
	Pushf				; ..End
U1202:
	Mov	AH,Flush_Keyboard_Command; Read the character from keyboard
	Mov	AL,Read_Keyboard_Command; .
	Int	PC_DOS_Interrupt	; ..End
	Cmp	AL,ETX			; Compare for control break
	Jne	U1203			; If not, then continue
	Mov	SI,Offset MES98_Control_Break
	Call	U1000_Display_Message	; Display the message on the screen
	Jmp	A1002			; Go to B1200_Final_Process
U1203:
	Cmp	AL,Capital_Letter_Y	; Check for capital letter Y
	Jne	U1204			; ..End
	Mov	Byte Ptr FLG06_Yes_or_No,True
	Mov	SI,Offset MES24_Yes	; Display YES on the screen
	Call	U1000_Display_Message	; ..End
	Jmp	U1290			; Go to the end of the module
U1204:
	Cmp	AL,Small_Letter_y	; Check for small letter y
	Jne	U1205			; ..End
	Mov	Byte Ptr FLG06_Yes_or_No,True
	Mov	SI,Offset MES24_Yes	; Display YES on the screen
	Call	U1000_Display_Message	; ..End
	Jmp	U1290			; Go to the end of the module
U1205:
	Cmp	AL,Capital_Letter_N	; Check for capital letter N
	Jne	U1206			; ..End
	Mov	Byte Ptr FLG06_Yes_or_No,False
	Mov	SI,Offset MES25_No	; Display NO on the screen
	Call	U1000_Display_Message	; ..End
	Jmp	U1290			; Go to the end of the module
U1206:
	Cmp	AL,Small_Letter_n	; Check for small letter n
	Jne	U1207			; ..End
	Mov	Byte Ptr FLG06_Yes_or_No,False
	Mov	SI,Offset MES25_No	; Display NO on the screen
	Call	U1000_Display_Message	; ..End
	Jmp	U1290			; Go to the end of the module
U1207:
	Jmp	U1202			; Go back and get another character
U1290:
	Popf				; Restore the registers and flags
	Pop	SI			; .
	Pop	AX			; ..End
U1299:
	Ret
;
U1200_Get_Yes_or_No Endp
;
Page
;************************************************************************
;*									*
;*	U1300_CONVERT_BINARY_TO_ASCII					*
;*									*
;*	This module BCD contained in the AL register into an ASCII	*
;*	character.  The output is returned in the AX register.		*
;*									*
;************************************************************************
;
Public	U1300_Convert_Binary_to_ASCII
;
U1300_Convert_Binary_to_ASCII Proc Near
;
U1301:
	Push	DX			; Save the registers
	Pushf				; ..End
;
	Cbw				; Perform sign extension for division
	Mov	DL,Ten			; Set DL disvisor to 10D
	Div	DL			; Divide AL by 10D remainder in AH
	Add	AL,Zero_Digit		; Setup the characters in AL & AH
	Add	AH,Zero_Digit		; ..End
;
	Popf				; Restore the registers
	Pop	DX			; ..End
U1399:
	Ret
;
U1300_Convert_Binary_to_ASCII Endp
;
Page
;************************************************************************
;*									*
;*	U1400_DISPLAY_HEAD_AND_TRACK					*
;*									*
;*	This module displays the current track and head number that	*
;*	is being read from the source diskette or written to the 	*
;*	target diskette.						*
;*									*
;************************************************************************
;
Public	U1400_Display_Head_and_Track
;
U1400_Display_Head_and_Track Proc Near
;
U1401:
	Push	AX			; Save the registers
	Push	BX			; .
	Push	DX			; .
	Pushf				; ..End
;
	Mov	AH,Set_CPos_Command	; Set cursor to track position
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	DH,Byte Ptr WRK28_Current_Message_Row
	Mov	DL,Fifteen		; .
	Int	Video_Interrupt		; ..End
;
					; Write the current track number
	Mov	AL,Byte Ptr WRK30_Current_Track
	Call	U1300_Convert_Binary_to_ASCII
	Push	AX			; .
	Mov	AH,Write_TTY_Command	; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; .
	Pop	AX			; .
	Mov	AL,AH			; .
	Mov	AH,Write_TTY_Command	; .
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	AH,Set_CPos_Command	; Set cursor to head position
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	DH,Byte Ptr WRK28_Current_Message_Row
	Mov	DL,Twenty_Five		; .
	Int	Video_Interrupt		; ..End
;					; Write the current head number
	Mov	AL,Byte Ptr WRK29_Current_Head
	Call	U1300_Convert_Binary_to_ASCII
	Mov	AL,AH			;.
	Mov	AH,Write_TTY_Command	;.
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	BL,Byte Ptr SYS04_Foreground_Color
	Int	Video_Interrupt		; ..End
;
	Mov	AH,Set_CPos_Command	; Set cursor to the next line
	Mov	BH,Byte Ptr SYS03_Active_Page
	Mov	DH,Byte Ptr WRK28_Current_Message_Row
	Inc	DH			; .
	Mov	DL,Zero			; .
	Int	Video_Interrupt		; ..End
U1490:
	Popf				; Restore the registers
	Pop	DX			; 
	Pop	BX			; .
	Pop	AX			; ..End
U1499:
	Ret
;
U1400_Display_Head_and_Track Endp
;
Page
;************************************************************************
;*									*
;*	FLAGS								*
;*									*
;*	This portion of FREECOPY contains the definitions of all of	*
;*	flags defined in the program.					*
;*									*
;************************************************************************
;
FLG01_Good_Command	DB (?)		; Establishes any errors in the
					; . command line entered by a user
FLG02_Double_Side	DB (?)		; Points out whether the user wants
					; . to copy only the top side of a
					; . floppy diskette
FLG03_Default_Drive	DB (?)		; Shows if the default drive is a
					; . valid floppy disk drive
FLG04_Single_Drive	DB (?)		; Determines if the machine is a
					; . single drive system
FLG05_Store_Buffer	DB (?)		; Establishes whether to put the
					; . characters entered from the
					; . keyboard into the buffer
FLG06_Yes_or_No		DB (?)		; Points out the user's response
					; . NO = False   YES = True
FLG07_First_Time	DB (?)		; Shows the number of times the user
					; . copies a diskette
					; . ONCE = True  MORE = False
FLG08_Good_Read		DB (?)		; Flags establish whether the
FLG09_Good_Write	DB (?)		; . operation was performed correctly
FLG10_Good_Verify  	DB (?)		; . YES = True    NO = False
FLG11_Good_Format	DB (?)		; ..End
FLG12_Good_FAT		DB (?)		; Establishes a good FAT when reading
					; . source diskette more than once
FLG13_First_Read_Write	DB (?)		; Shows if a diskette is being read
					; . or written for the first time
					; . YES = True    NO  = False
FLG14_Copy_Complete	DB (?)		; Points out if a diskette has been
					; . copied completely
					; . YES = True    NO = False
FLG15_IO_Error		DB (?)		; Establishes the type of IO error
					; . Zero = Format error
					; . One  = Read error
					; . Two  = Write error
					; ..End
FLG16_Free_Memory	DB (?)		; Determines whether memory should
					; . using the PC DOS function calls
FLG17_Copy_More_Disks	DB (?)		; Indicates whether to ask a user to
					; . write the same disk over again
;
Page
;************************************************************************
;*									*
;*	MESSAGES							*
;*									*
;*	This portion of FREECOPY contains the definitions of all of	*
;*	messages defined in the program.				*
;*									*
;************************************************************************
;
MES00_Copy_Notice		Label Byte
	DB	CR,LF
	DB	'FREECOPY Disk Utility',CR,LF
	DB	'IBM Personal Computer/Jr.',CR,LF
	DB	'Version 1.13 (C)Copyright 1984, 1985',CR,LF
	DB	CR,LF
	DB	'Squire Buresh Assoc., Inc.',CR,LF
	DB	'Post Office Box 112',CR,LF
	DB	'Millbury, MA 01527',CR,LF
	DB	CR,LF
	DB	'$25.00 requested contribution.',CR,LF,EOT
MES01A_Write_Another_Diskette	Label Byte
	DB	CR,LF
	DB	'Write source diskette again (Y/N)? ',EOT
MES01B_Copy_Another_diskette	Label Byte
	DB	CR,LF
	DB	'Copy another diskette (Y/N)? ',EOT
MES02_Copy_Complete		Label Byte
	DB	CR,LF
	DB	'Copy complete.',CR,LF,EOT
MES03_Copy81_Sectors		Label Byte
	DB	CR,LF
	DB	'Copying 8 sectors per track, 1 side.',CR,LF,EOT
MES04_Copy82_Sectors		Label Byte
	DB	CR,LF
	DB	'Copying 8 sectors per track, 2 sides.',CR,LF,EOT
MES05_Copy91_Sectors		Label Byte
	DB	CR,LF
	DB	'Copying 9 sectors per track, 1 side.',CR,LF,EOT
MES06_Copy92_Sectors		Label Byte
	DB	CR,LF
	DB	'Copying 9 sectors per track, 2 sides.',CR,LF,EOT
MES07_Correct_And_Press_Key	Label Byte
	DB	CR,LF
	DB	'Correct, and press any key to continue',CR,LF,EOT
MES08_Drive_Not_Ready		Label Byte
	DB	CR,LF
	DB	'Diskette not in drive  :.',CR,LF,EOT
MES09_Insert_Source		Label Byte
	DB	CR,LF
	DB	'Insert source diskette in drive  :.',CR,LF,EOT
MES10_Insert_Target		Label Byte
	DB	CR,LF
	DB	'Insert target diskette in drive  :.',CR,LF,EOT
MES11_Insufficient_Memory	Label Byte
	DB	CR,LF
	DB	'Insufficient memory.',Bell,CR,LF,EOT
MES12_Invalid_Parameter		Label Byte
	DB	CR,LF
	DB	'Invalid parameter(s) specified.',CR,LF,EOT
MES13_Invalid_Default		Label Byte
	DB	CR,LF
	DB	'Invalid default floppy disk drive',CR,LF,EOT
MES14_Invalid_Drive		Label Byte
	DB	CR,LF
	DB	'Invalid drive specification.',CR,LF,EOT
MES15_Single_Drive_Copy		Label Byte
	DB	CR,LF
	DB	'NOTE: Copying diskette on single drive.',Bell,CR,LF,EOT
MES16_Press_Any_Key		Label Byte
	DB	CR,LF
	DB	'Press any key when ready.',CR,LF,EOT
MES17_Reading_Track		Label Byte
	DB	'Reading track (  ) head ( ).',CR,LF,EOT
MES18_Unrecoverable_Format	Label Byte
	DB	CR,LF
	DB	'Unrecoverable format error on target.',CR,LF,EOT
MES19_Unrecoverable_Read	Label Byte
	DB	CR,LF
	DB	'Unrecoverable read error on source.',CR,LF,EOT
MES20_Unrecoverable_Verify	Label Byte
	DB	CR,LF
	DB	'Unrecoverable verify error on target.',CR,LF,EOT
MES21_Unrecoverable_Write	Label Byte
	DB	CR,LF
	DB	'Unrecoverable write error on target.',CR,LF,EOT
MES22_Unrecoverable_IO		Label Byte
	DB	CR,LF
	DB	'Unrecoverable IO error.',CR,LF,EOT
MES23_Writing_Track		Label Byte
	DB	'Writing track (  ) head ( ).',CR,LF,EOT
MES24_Yes			Label Byte
	DB	'YES',CR,LF,EOT
MES25_No			Label Byte
	DB	'NO',CR,LF,EOT
MES80_Seek_Error		Label Byte
	DB	'Seek operation has failed.',CR,LF,EOT
MES81_Controller_Error		Label Byte
	DB	'Disk controller has failed.',CR,LF,EOT
MES82_CRC_Error			Label Byte
	DB	'Cyclic redundancy check (CRC) error.',CR,LF,EOT
MES83_DMA_Boundary_Error	Label Byte
	DB	'Attempted to DMA across a 64K boundary.',CR,LF,EOT
MES84_DMA_Error			Label Byte
	DB	'DMA overrun on I/O operation.',CR,LF,EOT
MES85_Sector_Error		Label Byte
	DB	'Requested sector not found.',CR,LF,EOT
MES86_Write_Protect_Error	Label Byte
	DB	'Output diskette is write protected.',CR,LF,EOT
MES87_Address_Mark_Error	Label Byte
	DB	'Address mark was not found.',CR,LF,EOT
MES88_Command_Error		Label Byte
	DB	'Bad command passed to the disk interrupt 13H.',CR,LF,EOT
MES89_Unknown_Error		Label Byte
	DB	'Unknown diskette error encountered.',CR,LF,EOT
MES90_Unknown_FAT_Error		Label Byte
	DB	'First byte of the FAT does not',CR,LF
	DB	'match any known diskette type.',CR,LF,EOT
MES91_Single_Side_Error		Label byte
	DB	'Double sided diskette in a',CR,LF
	DB	'single sided disk drive.',CR,LF,EOT
MES97_Return_Linefeed		Label Byte
	DB	CR,LF,EOT
MES98_Control_Break		Label Byte
	DB	'^C',CR,LF,EOT
MES99_Memory_Block_Destroyed	Label Byte
	DB	'Memory control block destroyed.',CR,LF,EOT
MES100_Freecopy_Finished	Label Byte
	DB	CR,LF
	DB	'Returning to PC DOS.',CR,LF,EOT
;
Page
;************************************************************************
;*									*
;*	WORK VARIABLES							*
;*									*
;*	This portion of FREECOPY contains the definitions of the work	*
;*	variables that are used by the program.				*
;*									*
;************************************************************************
;
WRK01_Source_Drive		DB (?)	; Source diskette drive number
WRK02_Target_Drive		DB (?)	; Target diskette drive number
WRK03_Valid_Filename		DB 11 Dup (32D); Valid diskette file name
WRK04_Parameter_Count		DB (?)	; Valid diskette filler area
;
WRK05_Keyboard_Buffer		Label Byte
				DB 80D	; Length of the keyboard buffer
				DB 80 Dup (?); Actual keyboard buffer
				DB EOT	; Last char denotes the end of text
;
WRK06_Drive_Number		DB (?)	; Drive number of a disk drive
WRK07_Head_Number		DB (?)	; Head number of a disk drive
WRK08_Track_Number		DB (?)	; Track number of a diskette
WRK09_Sector_Number		DB (?)	; Sector number of a diskette
WRK10_Number_of_Sectors		DB (?)	; Number of sectors on a track
WRK11_Segment_Address		DW (?)	; ES segment address
WRK12_Offset_Address		DW (?)	; BX offset address
WRK13_Retry_Counter		DB (?)	; Number of retrys to make
WRK14_Status_Operation		DB (?)	; Result of the operation
;
WRK15_Maximum_Heads		DB (?)	; Maximum heads, tracks and sectors
WRK16_Maximum_Tracks		DB (?)	; .
WRK17_Maximum_Sectors		DB (?)	; ..End
;
WRK18_Counter_ESBX_Entries	DW (?)	; Counter to calculate ES:BX entries
WRK19_Number_ESBX_Entries	DW (?)	; Maximum ES:BX table entires
;
Page
;************************************************************************
;*									*
;*	WORK VARIABLES	Page 2						*
;*									*
;************************************************************************
;
WRK20_Current_Source_Head	DB (?)	; Current source head & track number
WRK21_Current_Source_Track	DB (?)	; ..End
WRK22_Current_Target_Head	DB (?)	; Current target head & track number
WRK23_Current_Target_Track	DB (?)	; . End
;
WRK24_Read_Message_Row		DB (?)	; Cursor row of read, verify, format
WRK25_Verify_Message_Row	DB (?)	; and write message
WRK26_Format_Message_Row	DB (?)	; .
WRK27_Write_Message_Row		DB (?)	; .
WRK28_Current_Message_Row	DB (?)	; ..End
;
WRK29_Current_Head		DB (?)	; Current head and track to display
WRK30_Current_Track		DB (?)	; . on the screen
;
WRK31_Track_Read_Counter        DB (?)	; Counter of tracks processed
WRK32_Track_Write_Counter       DB (?)  ; ..End
;
WRK33_CHRN_Table_Address	DW (?)	; Current address of the CHRN table
;
WRK34_DMA_Overflow_Counter	DW (?)	; Counts how many times FREECOPY
					; . adjusted for DMA overflow
;
Page
;************************************************************************
;*									*
;*	SYSTEM VARIABLES						*
;*									*
;*	This portion of FREECOPY contains the definitions of all of	*
;*	the system variables used by the program.			*
;*									*
;************************************************************************
;
SYS01_Number_Columns	DB (?)		; Number of columns in current mode
SYS02_Current_Mode	DB (?)		; Current video mode
SYS03_Active_Page	DB (?)		; Active display page
SYS04_Foreground_Color	DB (?)		; Foreground color number
SYS05_Para_RAM_Size	DW (?)		; Number of free 16 byte paragraphs
SYS06_Monitor_Flag	DB (?)		; 0 = monochrome  1 = graphics
SYS07_No_Parallel_Ports	DB (?)		; Number of parallel ports
SYS08_Game_Adapters	DB (?)		; Number of RS-232 ports
SYS09_No_RS232_Ports	DB (?)		; 0 = no adapter  1 = has adapter
SYS10_No_Disk_Drives	DB (?)		; Number of floppy disk drives
SYS11_Init_Video_Mode	DB (?)		; Initial video mode when powering
					; up the machine
SYS12_Planar_RAM_Size	DB (?)		; Planar RAM size
SYS13_IPL_From_Diskette	DB (?)		; Location of initial program load
SYS14_Default_Drive	DB (?)		; Default disk drive
;
SYS15_Stack_Pointer	DW (?)		; Stack pointer value when entering
					; . FREECOPY from PC DOS
SYS16_Save_DPT_Offset	DW (?)		; Address of Disk Parameter Table
SYS17_Save_DPT_Segment	DW (?)		; ..End
;
SYS18_Disk_Parameter_Table	Label Byte
			DB 11011111B	; SRT = 0D & Head Unload = 0FH
			DB 002H		; Head Load = 1 Mode = DMA
			DB 025H		; Wait to turn the motor off
			DB 002H		; 512 bytes per sector
			DB 009H		; 9 sectors per track
			DB 02AH		; PC DOS gap length for I/O
			DB 0FFH		; Data length parameter
			DB 050H		; PC DOS gap length for format
			DB 0F6H		; Fille byte for format
			DB 00FH		; Head Settle time in milliseconds
			DB 002H		; Motor start-up time (1/8 sec.)
;
SYS19_Major_Vers_Number DB (?)		; Major and minor version number
SYS20_Minor_Vers_Number DB (?)		; . of the operating system
;
SYS21_Alloc_Segment	DW (?)		; Beginning segment address of
					; . free memory
;
Page
;************************************************************************
;*									*
;*	SETUP STACK POINTER AND MEMORY					*
;*									*
;*	This portion of FREECOPY is contains the stack and the label	*
;*	that indicates the beginning of available memory.		*
;*									*
;************************************************************************
;
MEM05_Bottom_of_the_Stack	Label Word
			DW 64 Dup (?)
MEM04_Top_of_the_Stack		Label Word
;
MEM03_ESBX_Table		Equ MEM04_Top_of_the_Stack+2
;
MEM02_CHRN_Table		Equ MEM03_ESBX_Table+320
;
MEM01_File_Allocation_Table	Equ MEM02_CHRN_Table+2880
;
MEM00_Bottom_Free_Memory	Equ MEM01_File_Allocation_Table+512
;
Page
;************************************************************************
;*									*
;*	END OF THE PROGRAM						*
;*									*
;************************************************************************
;
CSEG	Ends
	End   A1000_Main_Module


