Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 3.X/CPM 3.0/SOURCE/copysys.asm
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

837 lines
14 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'Copysys - updated sysgen program 6/82'
; System generation program
VERS equ 30 ;version x.x for CP/M x.x
;
;**********************************************************
;* *
;* *
;* Copysys source code *
;* *
;* *
;**********************************************************
;
FALSE equ 0
TRUE equ not FALSE
;
;
NSECTS equ 26 ;no. of sectors
NTRKS equ 2 ;no. of systems tracks
NDISKS equ 4 ;no. of disks drives
SECSIZ equ 128 ;size of sector
LOG2SEC equ 7 ;LOG2 128
SKEW equ 2 ;skew sector factor
;
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
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
CR equ 0Dh ;Carriage Return
LF equ 0Ah ;Line Feed
STACKSIZE equ 016h ;size of local stack
;
WBOOT equ 01 ;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
;
org TPA ;Transient Program Area
jmp START
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0
db 0,0,0
maclib makedate
@LCOPY
@BDATE
db 0,0,0,0
db '654321'
;
; Translate table-sector numbers are translated here to decrease
; the systen tie for missed sectors when slow controllers are
; involved. Translate takes place according to the "SKEW" factor
; set above.
;
OST: db NTRKS ;operating system tracks
SPT: db NSECTS ;sectors per track
TRAN:
TRELT set 1
TRBASE set 1
rept NSECTS
db TRELT ;generate first/next sector
TRELT set TRELT+SKEW
if TRELT gt NSECTS
TRBASE set TRBASE+1
TRELT set TRBASE
endif
endm
;
; Now leave space for extensions to translate table
;
if NSECTS lt 64
rept 64-NSECTS
db 0
endm
endif
;
; Utility subroutines
;
MLTBY3:
;multiply the contents of regE to get jmp address
mov a,e ;Acc = E
sui 1
mov e,a ;get ready for multiply
add e
add e
mov e,a
ret ;back at it
;
SEL:
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz SEL2
;
sta CREG ;CREG = selected register
lxi h,0000h
shld EREG ;for first time
mvi a,SELDSK
sta BIOSFC ;store it in func space
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
SEL2:
mov c,a
lhld WBOOT
lxi d,SELDSK
call MLTBY3
dad d
pchl
;
TRK:
; Set up track
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz TRK2
;
mvi a,00h
sta BREG ;zero out B register
mov a,c ;Acc = track #
sta CREG ;set up PB
mvi a,SETTRK ;settrk func #
sta BIOSFC
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
TRK2:
lhld WBOOT
lxi d,SETTRK
call MLTBY3
dad d
pchl ;gone to set track
;
SEC:
; Set up sector number
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz SEC2
;
mvi a,00h
sta BREG ;zero out BREG
mov a,c ; Acc = C
sta CREG ;CREG = sector #
mvi a,SETSEC
sta BIOSFC ;set up bios call
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
SEC2:
lhld WBOOT
lxi d,SETSEC
call MLTBY3
dad d
pchl
;
DMA:
; Set DMA address to value of BC
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz DMA2
;
mov a,b ;
sta BREG ;
mov a,c ;Set up the BC
sta CREG ;register pair
mvi a,SETDMA ;
sta BIOSFC ;set up bios #
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
DMA2:
lhld WBOOT
lxi d,SETDMA
call MLTBY3
dad d
pchl
;
READ:
; Perform read operation
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz READ2
;
mvi a,READF
sta BIOSFC
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
READ2:
lhld WBOOT
lxi d,READF
call MLTBY3
dad d
pchl
;
WRITE:
; Perform write operation
sta TEMP
lda V3FLG
cpi TRUE
lda TEMP
jnz WRITE2
;
mvi a,WRITF
sta BIOSFC ;set up bios #
mvi c,DRBIOS
lxi d,BIOSPB
jmp BDOS
WRITE2:
lhld WBOOT
lxi d,WRITF
call MLTBY3
dad d
pchl
;
MULTSEC:
; Multiply the sector # in rA by the sector size
mov l,a
mvi h,0 ;sector in hl
rept LOG2SEC
dad h
endm
ret ;with HL - sector*sectorsize
;
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 rA
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 ;isit ^C?
jz REBOOT
;
sui 'A' ;normalize drive #
cpi NDISKS ;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
sui 'A'
mov e,a ;move disk into E for select func
call SEL ;select the 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'
cpi NDISKS ;valid disk
jc PUTC
;
; Invalid drive
call BADDISK ;tell user bad drive
jmp PUTSYS ;to try again
;
PUTC:
; Set disk fron rA
adi 'A'
sta PDISK ;message sent
sui 'A'
mov e,a ;disk # in E
call SEL ;select destination drive
; 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
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
lda OST ;# of OS tracks
cmp m ;=track # ?
jz ENDRW ;end of read/write
;
; Otherwise not done
mov c,m ;track number
call TRK ;set to track
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 ;A=26 and M=0,1,..,25
jz ENDTRK
;
; Read or write sector to or from current DMA address
lxi h,SECTOR
mov e,m ;sector number
mvi d,0 ;to DE
lxi h,TRAN
mov b,m ;tran(0) in B
dad d ;sector translated
mov c,m ;value to C ready for select
push b ;save tran(0)
call SEC
pop b ;recall tran(0),tran(sector)
mov a,c ;tran(sector)
sub b ;--tran(sector)
call MULTSEC ;*sector size
xchg ;to DE
lhld DMADDR ;base DMA
dad d
mov b,h
mov c,l ;to set BC for SEC call
call DMA ;dma address set from BC
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
call WRITE
jmp CHKRW
TRYREAD:
call READ
CHKRW:
ora a
jz RWSEC ;zero flag if read/write ok
;
;Error, retry operation
jmp TRYSEC
;
; End of track
ENDTRK:
lda SPT ;sectors per track
call MULTSEC ;*secsize
xchg ; to DE
lhld DMADDR ;base dma for this track
dad d ;+spt*secsize
shld DMADDR ;ready for next track
jmp RWTRK ;for another track
;
ENDRW:
; End of read or write
ret
;
;*******************
;*
;* MAIN ROUTINE
;*
;*
;*******************
;
START:
lxi sp,STACK
lxi d,SIGNON
call OUTMSG
;
;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 OLDRVR ;
mvi a,TRUE
sta V3FLG ;
jmp FCBCHK
OLDRVR:
mvi a,FALSE
sta V3FLG
;
; 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
mov b,h
mov c,l
call DMA ;DMA address set
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,SECSIZ
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
call GETPUT ;get or read system
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
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
;****************************
;*
;*
;* DATA STRUCTURES
;*
;*
;****************************
;
BIOSPB:
; BIOS Parameter Block
BIOSFC: db 0 ;BIOS function number
AREG: db 0 ;A register contents
CREG: db 0 ;C register contents
BREG: db 0 ;B register contents
EREG: db 0 ;E register contents
DREG: db 0 ;D 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
;
;
V3FLG: db 0 ;flag for version #
TEMP: db 0
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
SIGNON: db 'CP/M 3 COPYSYS - Version '
db VERS/10+'0','.',VERS 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......
;
QDISK: db 'ERROR: Invalid drive name (Use A, B, C, or D)$'
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