|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 13184 (0x3380) Types: TextFile Names: »COPYSYS.ASM«
└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files └─ ⟦this⟧ »COPYSYS.ASM«
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»