DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦360e2feeb⟧ TextFile

    Length: 13184 (0x3380)
    Types: TextFile
    Names: »COPYSYS.ASM«

Derivation

└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files
    └─ ⟦this⟧ »COPYSYS.ASM« 

TextFile


	title	'COPYSYS UTILITY DATE:840401'
	PAGE 43

;************************************************************************
;*									*
;************************************************************************
	MACLIB	Z80

	MACLIB	PORTS

CVERS	equ	10		;version 1.0 for CP/M 3.0
;
NTRKS	equ	2		;no. of systems tracks
SECSIZ	equ	512		;size of sector
;
FCB	equ	005Ch		;location of FCB
FCBCR	equ	FCB+32		;current record location
TPA	equ	0100h		;Transient Program Area
LOADP	equ	1000h		;LOAD Point for system
BDOS	equ	05h		;DOS entry point

BOOT	equ	00h		;reboot for system
CONI	equ	1h		;console input function
CONO	equ	2h		;console output function
SELD	equ	14		;select a disk
OPENF	equ	15 		;disk open function
CLOSEF	equ	16		;open a file
DWRITF	equ	21		;Write func
MAKEF	equ	22		;mae a file
DELTEF 	equ	19		;delete a file
RETDSK	equ	25		;return current disk
DREADF	equ	20		;disk read function
DRBIOS	equ	50		;Direct BIOS call function
EIGHTY	equ	080h		;value of 80
CTLC	equ	'C'-'@'		;ConTroL C
Y	equ	89		;ASCII value of Y
;
MAXTRY	equ	01		;maximum number of tries
STACKSIZE equ	016h		;size of local stack
;
WBOOT	equ	0		;address of warm boot
;
SELDSK	equ	9		;BIOS func #9 SELect DiSK
SETTRK	equ	10		;BIOS func #10 SET TRacK
SETSEC	equ	11		;BIOS func #11 SET SECtor
SETDMA	equ	12		;BIOS func #12 SET DMA address
READF	equ	13		;BIOS func #13 READ selected sector
WRITF	equ	14		;BIOS func #14 WRITe selected sector


;*******************
;*
;*	MAIN ROUTINE
;*
;*******************
;
START:

	lxi	sp,STACK
	lxi	d,SIGNON
	call	OUTMSG

				;CHECK NUMBERS OF FLOPPY DISKS
	IN	P$SWITCH	;
	ANI	M$HD$SELECT	;
	JZ	ONEFLOP		;
	MVI	A,2		;
	STA	NDISKS		;
	JMP	NEXT		;
ONEFLOP:
	MVI	A,6		;
	STA	NDISKS		;	

NEXT:
;
;get version number to check compatability
	mvi	c,12		;version check
	call	BDOS
	mov	a,l		;version in Acc
	cpi	30h		;version 3 or newer?
	jc	NOEXEC		;
	jmp	FCBCHK

NOEXEC:	
	LXI	D,REQCPM3	;PRINT "REQUIRES CP/M PLUS"
	CALL	OUTMSG		;
	MVI	C,WBOOT		;
	JMP	BDOS		;
	
				; Check for default file liad instead of get
FCBCHK:	
	lda	FCB+1		;blank if no file
	cpi	' '
	jz	GETSYS		;skip to system message
	lxi	d,FCB		;try to open it
	call	OPEN
	inr	a		;255 becomes 00
	jnz	RDOK

				; File not present
	lxi	d,NOFILE
	call	CRMSG
	jmp	REBOOT
				;file present
RDOK:
	xra	a
	sta	FCBCR		;current record = 0
	lxi	h,LOADP
RDINP:
	push	h
	XCHG
	CALL	DSTDMA		;
	lxi	d,FCB		;ready fr read
	call	DREAD
	pop	h		;recall
	ora	a		;00 if read ok
	jnz	PUTSYS		;assume eof if not
; More to read continue
	lxi	d,128 
	dad	d		;HL is new load address
	jmp	RDINP

;;------------------------------------------------------------------


GETSYS:
	call	SOURCE		;find out source drive
	xra	a		;zero out a
	sta	RW		;RW = 0 to signify read
	LDA	GDISK
	call	GETPUT		;get or read system
DONEMSG:
	lxi	d,DONE		;end message of get or read func
	call	OUTMSG		;print it out

				; Put the system
PUTSYS:
	call	DESTIN		;get dest drive
	lxi	h,RW		;load address
	mvi	m,1
	LDA	PDISK
	call	GETPUT		;to put system back on disk
	lxi	d,DONE
	call	OUTMSG		;print out end prompt

;============================
;	FILE COPY FOR CPM.SYS
;============================
CPYCPM:
; Prompt the user for the source of CP/M3.SYS
;
	lxi	d,CPYMSG	;print copys prompt
	call	CRMSG		;print it
	call	GETCHAR		;obtain reply
	cpi	Y		;is it yes?
	jnz	REBOOT		;if not exit
				;else
;
;
	mvi	c,13		;func # for reset
	call	BDOS		;
	inr	a

	lxi	d,ERRMSG
	cz	FINIS
;
	call	SOURCE		;get source disk for CPM3.SYS
CNTNUE:
	lda	GDISK		;Acc = source disk
	sui	'A'
	mvi	d,00h
	mov	e,a		;DE = selected disk
	call	SELCT
; now copy the FCBs
	mvi	c,36		;for copy
	lxi	d,SFCB		;source file
	lxi	h,DFCB		;destination file
MFCB:

	ldax	d
	inx	d		;ready next
	mov	m,a
	inx	h		;ready next dest
	dcr	c		;decrement coun
	jnz	MFCB
;
	lda	GDISK		;Acc = source disk
	sui	40h		;correct disk
	lxi	h,SFCB
	mov	m,a		;SFCB has source disk #
	lda 	PDISK		;get the dest. disk
	lxi	h,DFCB		;
	sui	040h		;normalize disk
	mov	m,a
;
	xra	a		;zero out a
	sta	DFCBCR		;current rec = 0
;
; Source and destination fcb's ready
;
	lxi	d,SFCB		;
	call	OPEN		;open the file
	lxi	d,NOFILE	;error messg
	inr	a		;255 becomes 0
	cz	FINIS		;done if no file
;
; Source file is present and open
	lxi	d,LOADP		;get DMA address
	xchg			;move address to HL regs
	shld	BEGIN		;save for begin of write
;
	lda	BEGIN		;get low byte of
	mov	l,a		;DMA address into L
	lda	BEGIN+1		;
	mov	h,a		;into H also
COPY1:
	xchg			;DE = address of DMA
	call	DSTDMA		;
;
	lxi	d,SFCB		;
	call	DREAD		;read next record
	ora	a		;end of file?
	jnz	EOF		;skip write if so
;
	lda	CRNREC
	inr	a		;bump it
	sta	CRNREC
;
	lda	BEGIN
	mov	l,a
	lda	BEGIN+1
	mov	h,a
	lxi	d,EIGHTY
	dad	d		;add eighty to begin address
	shld	BEGIN
	jmp	COPY1		;loop until EOF
;
EOF:
	lxi	d,DONE
	call	OUTMSG
;
COPY2:
	call	DESTIN		;get destination drive for CPM3.SYS
	lxi	d,DFCB		;set up dest FCB
	xchg	
	lda	PDISK
	sui	040h		;normalize disk
	mov	m,a		;correct disk for dest
	xchg			;DE = DFCB
	call	DELETE		;delete file if there
;
	lxi	d,DFCB		;
	call	MAKE		;make a new one
	lxi	d,NODIR
	inr	a		;check directory space
	cz	FINIS		;end if none
;
	lxi	d,LOADP
	xchg
	shld	BEGIN
;
	lda	BEGIN
	mov	l,a
	lda	BEGIN+1
	mov	h,a
LOOP2:
	xchg
	call	DSTDMA
	lxi	d,DFCB
	call	DWRITE
	lxi	d,FSPACE
	ora	a
	cnz	FINIS
	lda	CRNREC
	dcr	a
	sta	CRNREC
	cpi	0
	jz	FNLMSG
	lda	BEGIN
	mov	l,a
	lda	BEGIN+1
	mov	h,a
	lxi	d,EIGHTY
	dad	d
	shld	BEGIN
	jmp	LOOP2
; Copy operation complete
FNLMSG:
	lxi	d,DFCB
	mvi	c,CLOSEF
	call	BDOS
;
	lxi	d,DONE
;
FINIS:
; Write message given by DE, reboot
	call	OUTMSG
;
REBOOT:
	mvi	c,13
	call	BDOS
	call	CRLF
	jmp	BOOT
;
BADDISK:
	lxi	d,QDISK
	call	CRMSG
	ret


;
; Utility subroutines
;=============================================================================
BIOS:
	STA	BIOSFC		;DIRECT BIOS CALL 
	MVI	C,DRBIOS	;
	LXI	D,BIOSPB	;
	CALL	BDOS		;
	RET			;

;============================================================================
SECTRN:
	XRA	A		;
	MOV	B,A		;
	MOV	H,A		;
	LDA	SECTOR		;GET LOGICAL SECTOR NO.
	MOV	C,A		;
	MOV	L,A		;
	LDED	TRANS		;
	MOV	A,D		;	<DE> SKEW TABLE ADDR
	ORA	E		;	<BC> LOGICAL SECTOR
	RZ			;RETURN IF NO TRANSLATE TABLE
	XCHG			;
	DAD	B		;
	MOV	L,M		;	RETURN PHYSICAL SECTOR IN <HL>
	MVI	H,0
	RET

SKEW:	DB	1,5,9,13,3,7,11,15
TRANS:	DW	00H
;============================================================================
GETSPT:
	SUI	'A'
	MVI	D,0
	MOV	E,A
	CALL	SELCT		;SELECT DRIVE
	MVI	C,1FH		;GET ADDR(DPB PARMS)
	CALL	BDOS		;
	MOV	A,M		;
	ANI	0FCH		;
	RRC			;
	RRC			;DIVIDE BY (512/128)
	STA	SPT		;
	CPI	8
	lxi	h,0
	JNZ	HD$SKEW
MFD$SKEW:
	LXI	H,SKEW	
HD$SKEW:
	SHLD	TRANS
	RET

;=============================================================================
GETCHAR:			; Read console character to rA
	mvi	c,CONI
	call	BDOS
				; Convert to upper case
	cpi	'A' or 20h
	rc
	cpi	('Z' or 20h)+1
	rnc
	ani	05Fh
	ret

;=============================================================================
PUTCHAR:			; Write character from rA to console
	mov	e,a
	mvi	c,CONO
	call	BDOS
	ret

;=============================================================================
CRLF:				; Send Carriage Return, Line Feed
	mvi	a,CR
	call	PUTCHAR
	mvi	a,LF
	call	PUTCHAR
	ret

;=============================================================================
CRMSG:				;Print message addressed by the HL
				; until zero with leading CRLF
	push	d
	call	CRLF
	pop	d		;drop through to OUTMSG
OUTMSG:
	mvi	c,9
	jmp	BDOS

;=============================================================================
SELCT:				; Select disk given by rE
	mvi	c,0Eh
	jmp	BDOS

DWRITE:				; Write for file copy
	mvi	c,DWRITF
	jmp	BDOS

DREAD:				; Disk read function
	mvi	c,DREADF
	jmp	BDOS

OPEN:				; File open function
	mvi	c,OPENF
	jmp	BDOS

CLOSE:
	mvi	c,CLOSEF
	jmp	BDOS

MAKE:
	mvi	c,MAKEF
	jmp	BDOS

DELETE:	
	mvi	c,DELTEF
	jmp	BDOS

DSTDMA:
	mvi	c,26
	jmp	BDOS

;=============================================================================
SOURCE:
	lxi	d,GETPRM	;ask user for source drive
	call	CRMSG
	call	GETCHAR		;obtain response
	cpi	CR		;is it CR?
	jz	DFLTDR		;skip if CR only
	cpi	CTLC		;is it ^C?
	jz	REBOOT
;
	sui	'A'		;normalize drive #
	PUSH	PSW
	LDA	NDISKS
	MOV	B,A
	POP	PSW
	CMP	B		;valid drive?
	jc	GETC		;skip to GETC if so
;
; Invalid drive
	call	BADDISK		;tell user bad drive
	jmp	SOURCE		;try again
;
GETC:
; Select disk given by Acc.
	adi	'A'
	sta	GDISK		;store source disk
	jmp	GETVER
;
DFLTDR:
	mvi	c,25		;func 25 for current disk
	call	BDOS		;get curdsk
	adi	'A'
	sta	GDISK
	call	CRLF
	lxi	d,VERGET
	call	OUTMSG
	jmp	VERCR
;
GETVER:	
; Getsys set r/w to read and get the system
	call	CRLF
	lxi	d,VERGET	;verify source disk
	call	OUTMSG
VERCR:	call	GETCHAR
	cpi	CR
	jnz	REBOOT		;jmp only if not verified
	call	CRLF
	ret

;=============================================================================
DESTIN:
	lxi	d,PUTPRM	;address of message
	call	CRMSG		;print it
	call	GETCHAR		;get answer
	cpi	CR
	jz	REBOOT		;all done
	sui	'A'
	PUSH	PSW
	LDA	NDISKS
	MOV	B,A
	POP	PSW
	CMP	B		;valid disk
	jc	PUTC
;
; Invalid drive
	call	BADDISK		;tell user bad drive
	jmp	PUTSYS		;to try again

;
PUTC:
; Set disk from rA
	adi	'A'
	sta	PDISK		;message sent

; Put system, set r/w to write
	lxi	d,VERPUT	;verify dest prmpt
	call	CRMSG		;print it out
	call	GETCHAR		;retrieve answer
	cpi	CR	
	jnz	REBOOT		;exit to system if error
	call	CRLF
	ret
;
;
GETPUT:
; Get or put CP/M (rw = 0 for read, 1 for write)
; disk is already selected

	CALL	GETSPT

	lxi	h,LOADP		;load point in RAM for DMA address
	shld	DMADDR
;
; Clear track 00
	mvi	a,-1		;
	sta	TRACK
;
RWTRK: 
; Read or write next track
	lxi	h,TRACK
	inr	m		;track = track+1
	MVI	A,NTRKS		;# of OS tracks
	cmp	m		;=track # ?
	RZ			;end of read/write
;
; Otherwise not done
	mov	L,M		;track number
	mvi	H,0
	SHLD	BCREG		;set up PB
	mvi	a,SETTRK	;settrk func #
	CALL	BIOS
	mvi	a,-1		;counts 0,1,2,...,25
	sta	SECTOR
;
RWSEC:				; Read or write a sector
	lda	SPT		;sectors per track
	lxi	h,SECTOR	
	inr	m		;set to next sector
	cmp	m		;
	jz	RWTRK
;
; Read or write sector to or from current DMA address

	CALL	SECTRN		;RETURNS PHYSICAL SEC IN <HL>
	SHLD	BCREG		;BCREG = sector #
	mvi	a,SETSEC
	CALL	BIOS

	lhld	DMADDR		;base DMA
	SHLD	BCREG		;
	LXI	D,512		;
	DAD	D		;
	SHLD	DMADDR		;SAVE NEW ADDR
	MVI	A,SETDMA
	CALL	BIOS
	xra	a
	sta	RETRY		;to set zero retries
;
TRYSEC:
; Try to read or write current sector
	lda	RETRY
	cpi	MAXTRY
	jc	TRYOK
;
; Past MAXTRY, message and ignore
	lxi	d,ERRMSG
	call	OUTMSG
	call	GETCHAR
	cpi	CR
	jnz	REBOOT
;
; Typed a CR, ok to ignore
	call	CRLF
	jmp	RWSEC
;
TRYOK:
; Ok to tyr read write
	inr	a
	sta	RETRY	
	lda	RW
	ora	a
	jz	TRYREAD
;
; Must be write
				; Perform write operation
	mvi	a,WRITF
	CALL	BIOS
	jmp	CHKRW

TRYREAD:			; Perform read operation
	mvi	a,READF
	CALL	BIOS
CHKRW:
	ora	a
	jz	RWSEC		;zero flag if read/write ok
;
;Error, retry operation
	jmp	TRYSEC
;
;
;****************************
;*
;*
;*	DATA STRUCTURES     
;*
;*
;****************************
;
BIOSPB:
; BIOS Parameter Block
BIOSFC:	db	0		;BIOS function number
AREG:	db	0		;A register contents
BCREG:	DW	0		;BC register contents
DEREG:	DW	0		;DE register contents
HLREG:	dw	0		;HL register contents
;
SFCB:
DR:	ds	1
F1F8:	db	'CPM3    '
T1T3:	db	'SYS'
EXT:	db	0
CS:	db	0
RS:	db	0
RCC:	db	0
D0D15:	ds	16
CCR:	db	0
R0R2:	ds	3
;
DFCB:	ds	36
DFCBCR	equ	DFCB+32
;
;
SDISK:	ds	1		;selected disk
BEGIN:	dw	0
DFLAG:	db	0
TRACK:	ds	1		;current track
CRNREC:	db	0		;current rec count
SECTOR:	ds	1		;current sector
RW:	ds	1		;read if 0 write if 1
DMADDR:	ds	2		;current DMA address
RETRY:	ds	1		;number of tries on this sector
NDISKS:	DS	1		;number of disks drives
SPT:	DS	1		;sector per track

SIGNON:	db	'CP/M 3 COPYSYS - Version '
	db	CVERS/10+'0','.',CVERS mod 10 +'0'
	db	'$'
GETPRM:	db	'Source drive name (or return for default) $'
VERGET:	db	'Source on '
GDISK:	ds	1
	db	' then type return $'
PUTPRM:	db	'Destination drive name (or return to reboot) $'
VERPUT:	db	'Destination on '
PDISK:	ds	1
	db	' then type return $'
CPYMSG:	db	'Do you wish to copy CPM3.SYS? $'
DONE:	db	'Function complete$'
;
; Error messages......
;
REQCPM3:db	'Requires CP/M PLUS.$'
QDISK:	db	'ERROR: Invalid drive name.$'
NOFILE:	db	'ERROR: No source file on disk.$'
NODIR:	db	'ERROR: No directory space.$'
FSPACE:	db	'ERROR: Out of data space.$'
WRPROT:	db	'ERROR: Write protected?$'
ERRMSG: db	'ERROR: Possible incompatible disk format.'
	db	CR,LF,' Type return to ignore.$' 
CLSERR:	db	'ERROR: Close operation failed.$'
;
	ds	STACKSIZE * 3
STACK:
	end
«eof»