mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-22 16:04:18 +00:00
508 lines
11 KiB
Plaintext
508 lines
11 KiB
Plaintext
title 'LDCOPY Ver 1.1 Oct 81'
|
||
|
||
vers equ 10
|
||
|
||
; Copyright, (C) 1981
|
||
; Digital Research, Inc.
|
||
; P.O. Box 579
|
||
; Pacific Grove, CA 93950
|
||
|
||
|
||
; LDCOPY is used to generate and propagate bootable CP/M-86 systems.
|
||
|
||
; It copies a CP/M-86 Loader image (either from a disk file, or from
|
||
; the system tracks of an existing CP/M-86 system diskette) to a new
|
||
; diskette.
|
||
|
||
; The following equates will require modification for different
|
||
; diskette formats. For convienence, they are only referenced
|
||
; by a pair of data bytes near the end of the data segment.
|
||
; In addition, the skew table in the data area will need modification.
|
||
|
||
sdspt equ 26 ; number of sectors per track
|
||
sdlt equ 2 ; " of tracks for loader
|
||
|
||
|
||
|
||
; **************************
|
||
; *
|
||
; * global equates
|
||
; *
|
||
; **************************
|
||
|
||
bdosint equ 224 ;BDOS interrupt number
|
||
|
||
false equ 0
|
||
true equ not false
|
||
cr equ 0dh ;carriage return
|
||
lf equ 0ah ;line feed
|
||
|
||
|
||
sdndisks equ 16 ; maximum number of drives
|
||
sdsecsiz equ 128 ; size of each sector
|
||
|
||
tpa equ 100h
|
||
fcbaddr equ 5ch
|
||
fcbname equ fcbaddr + 1 ;1st char of file name
|
||
fcbtype equ fcbaddr + 9 ;file type
|
||
fcbcr equ fcbaddr + 32 ;current record
|
||
|
||
cseg
|
||
|
||
jmp start
|
||
db ' COPYRIGHT (C) 1981, DIGITAL RESEARCH '
|
||
|
||
Rs 100H ; Emergency patch area
|
||
|
||
; ***********************
|
||
; *
|
||
; * program begins here
|
||
; *
|
||
; ***********************
|
||
|
||
start:
|
||
mov ax,ds
|
||
mov es,ax
|
||
|
||
mov dx,offset signon
|
||
call outmsg
|
||
cmp byte ptr .fcbname,' '
|
||
jz gl ;check for file given on command line
|
||
call getfile ;read ldr from file
|
||
jmp ps
|
||
gl: call getldr ;read ldr from 1st 2 tracks
|
||
ps: call putldr ;put ldr on " " "
|
||
jmp reboot
|
||
|
||
; ***************************
|
||
; *
|
||
; * getfile: get the file specified in command tail into ram
|
||
; *
|
||
; ***************************
|
||
|
||
getfile:
|
||
cmp byte ptr .fcbtype,' '
|
||
jnz opn
|
||
mov byte ptr .fcbtype, 'C'
|
||
mov byte ptr .fcbtype + 1,'M'
|
||
mov byte ptr .fcbtype + 2,'D'
|
||
opn:
|
||
mov dx,fcbaddr ;try to open it
|
||
call open
|
||
inc al ;255 becomes 00
|
||
jnz rdok ;ok to read if not 255
|
||
|
||
mov dx,offset nofile
|
||
call crmsg ;file not present, error and reboot
|
||
jmp reboot
|
||
rdok:
|
||
mov byte ptr .fcbcr,0 ;current record = 0
|
||
mov dx,offset loadp ;base of buffer
|
||
mov cx,maxsecs ;sector count
|
||
rdinp:
|
||
push cx
|
||
push dx ;ready for dma
|
||
call bdma ;bdos dma function
|
||
mov dx,fcbaddr ;ready for read
|
||
call dread
|
||
pop dx ;recall dma address
|
||
pop cx ;recall sector count
|
||
cmp al,1 ;check for eof
|
||
jz don
|
||
dec cx ;don't read to far
|
||
jz don
|
||
or al,al ;0 if read ok
|
||
jnz badrd
|
||
add dx,secsiz ;inc dma by sector size
|
||
jmp rdinp
|
||
don:
|
||
ret
|
||
badrd: ;read error encountered in input file
|
||
mov dx,offset badfile
|
||
call crmsg
|
||
jmp reboot
|
||
|
||
; **************************
|
||
; *
|
||
; * getldr: get CP/M loader from 1st N tracks
|
||
; *
|
||
; **************************
|
||
|
||
getldr:
|
||
mov dx,offset askget
|
||
call crmsg ;which drive is source on ?
|
||
call getchar ;must get from disk - not from memory
|
||
mov ah,al ;save ascii char
|
||
sub al,'A' ;normalize drive number
|
||
cmp al,ndisks ;valid drive?
|
||
jb getc ;skip to getc if so
|
||
call baddisk ;invalid drive number
|
||
jmp getldr ;to try again
|
||
getc:
|
||
mov gdisk,ah ;ascii drive letter for message
|
||
call sel ;to select the drive in al
|
||
call crlf
|
||
mov dx,offset getmsg
|
||
call outmsg ;make sure right drive
|
||
call getchar
|
||
cmp al,cr ;user mistake, no cr
|
||
jnz gboot
|
||
call crlf
|
||
mov rewr,0 ;set to read for getput
|
||
call getput
|
||
mov dx,offset done
|
||
call outmsg
|
||
ret
|
||
gboot: jmp reboot ;back to cp/m
|
||
|
||
; *******************************
|
||
; *
|
||
; * putldr: put CP/M loader on 1st N tracks
|
||
; *
|
||
; *******************************
|
||
|
||
putldr:
|
||
mov dx,offset askput
|
||
call crmsg ;what drive to put ldr
|
||
call getchar
|
||
cmp al,cr ;all done if cr
|
||
jz pboot ;this is normal program exit point
|
||
mov ah,al ;save ascii drive letter
|
||
sub al,'A' ;make it a number
|
||
cmp al,ndisks
|
||
jb putc
|
||
call baddisk ;invalid drive name
|
||
jmp putldr ;to try again
|
||
putc:
|
||
mov pdisk,ah ;drive letter in message
|
||
call sel ;select dest drive in al
|
||
mov dx,offset putmsg
|
||
call crmsg ;check with user for ok
|
||
call getchar
|
||
cmp al,cr ;user mistake if not cr, reboot
|
||
jnz pboot
|
||
call crlf
|
||
mov rewr,1 ;set to write for getput
|
||
call getput ;to put loader back on diskette
|
||
mov dx,offset done
|
||
call outmsg
|
||
jmp putldr ;for another put operation
|
||
pboot: jmp reboot ;back to cp/m
|
||
|
||
; ***********************
|
||
; *
|
||
; * getput: get or put loader (rewr=0 for read, 1 for write)
|
||
; * disk is already selected
|
||
; *
|
||
; ***********************
|
||
|
||
getput:
|
||
mov bx,offset loadp ;load point in ram for cp/m during LDCOPY
|
||
mov dmaddr,bx
|
||
;clear track to 00
|
||
mov track,-1 ;start with track equal -1
|
||
rwtrk: ;read or write next track
|
||
inc track ;track = track + 1
|
||
mov cx,track
|
||
cmp cx,nlt ;number of loader tracks = current track ?
|
||
jnz nxttrk ;end of this routine > 128 bytes
|
||
jmp endrw ;end of read or write
|
||
;otherwise notdone, go to next track
|
||
nxttrk:
|
||
mov cx,track
|
||
call trk ;to set track
|
||
mov sector,-1 ;counts 0, 1, 2, . . . 25
|
||
;sector incremented before read or write
|
||
rwsec: ;read or write sector
|
||
inc sector ;to next sector
|
||
mov bx,sector ;current sector
|
||
cmp bx,spt ;sectors per track
|
||
jz endtrk
|
||
;read or write sector to or from
|
||
l_5: ;current dma address
|
||
mov si,offset tran
|
||
add bx,bx ; double sector number
|
||
mov cx,[bx+si] ;xlate to physical sector
|
||
push si
|
||
push cx
|
||
call sec ;set up sector number
|
||
pop cx
|
||
pop si
|
||
mov bx,[si]
|
||
sub cx,bx ;tran(sector)-tran(0)
|
||
call multsec ;cx * sector size
|
||
add cx,dmaddr ;base of dma for this track
|
||
;+(tran(sector)-tran(0))*secsiz
|
||
call dma ;dma address set from cx
|
||
;dma address set, clear retry count
|
||
trysec: ;try to read or write current sector
|
||
Mov Cl, 00
|
||
Mov Ax, Track
|
||
Inc Ax
|
||
Cmp Ax, Nlt
|
||
Jne Normal_Write
|
||
|
||
Mov Ax, Sector
|
||
Inc Ax
|
||
Cmp Ax, Spt
|
||
Jne Normal_Write
|
||
Mov Cl, 01
|
||
Normal_Write:
|
||
or rewr,0 ;read or write?
|
||
jz tryread
|
||
;must be write
|
||
call write
|
||
jmp chkrw ;check for error returns
|
||
tryread:
|
||
call read
|
||
chkrw:
|
||
or al,al
|
||
jz rwsec
|
||
|
||
mov dx,offset errmsg
|
||
call outmsg
|
||
call getchar
|
||
cmp al,cr
|
||
jne reboot1 ;local jmp then to reboot, >128
|
||
;typed a cr, ok to ignore
|
||
call crlf
|
||
jmp rwsec
|
||
|
||
endtrk: ;end of track
|
||
mov cx,spt ;sectors per track
|
||
call multsec ;*secsiz
|
||
mov bx,dmaddr ;base dma for this track
|
||
add bx,cx
|
||
;+ spt * secsiz
|
||
mov dmaddr,bx ;ready for next track
|
||
jmp rwtrk ;for another track
|
||
|
||
endrw: ;end of read or write, return to caller
|
||
ret
|
||
|
||
reboot1:jmp reboot ;farther than 128 bytes
|
||
|
||
; *****************************************
|
||
; *
|
||
; * utility subroutines
|
||
; *
|
||
; ****************************************
|
||
;
|
||
;*****
|
||
multsec: ;cx * sector size
|
||
push dx ;return value in cx
|
||
mov ax,secsiz
|
||
mul cx
|
||
mov cx,ax
|
||
pop dx
|
||
ret
|
||
;*****
|
||
baddisk:
|
||
mov dx,offset qdisk ;bad disk name
|
||
call crmsg
|
||
ret
|
||
|
||
; **********************
|
||
; *
|
||
; * bdos subroutines
|
||
; *
|
||
; **********************
|
||
|
||
bdos: int bdosint
|
||
ret
|
||
;function numbers in cl
|
||
|
||
reset equ 0 ;warm boot
|
||
coni equ 1 ;console input
|
||
cono equ 2 ;console output
|
||
prstr equ 9 ;print string
|
||
rconb equ 10 ;read console buffer
|
||
self equ 14 ;select disk
|
||
openf equ 15 ;disk open
|
||
setdmaf equ 26 ;where data will go
|
||
dreadf equ 20 ;disk read
|
||
biosf equ 50 ;bios call
|
||
|
||
reboot:
|
||
mov al,0
|
||
call sel
|
||
call crlf
|
||
mov cl,reset
|
||
mov dl,0 ; release memory
|
||
jmp bdos
|
||
;****
|
||
getchar: ;get an upper case char into al
|
||
call getbuf ;use buffered console read
|
||
cmp conbuf+1,0 ;just a crlf?
|
||
mov al,cr
|
||
jz ex
|
||
mov al,conbuf+2 ;first char read
|
||
cmp al,'a' ;translate to upper case if lower
|
||
jb ex
|
||
cmp al,'z'
|
||
ja ex
|
||
and al,5fh ;it is lower, make upper
|
||
ex: ret
|
||
;****
|
||
getbuf:
|
||
;read console buffer
|
||
mov cl,rconb
|
||
mov dx,offset conbuf
|
||
jmp bdos
|
||
;****
|
||
putchar:
|
||
;write character from al to console
|
||
mov dl,al
|
||
mov cl,cono
|
||
jmp bdos
|
||
;****
|
||
crlf: ;send carriage return, line feed
|
||
mov al,cr
|
||
call putchar
|
||
mov al,lf
|
||
call putchar
|
||
ret
|
||
;****
|
||
crmsg: ;print message addressed by dx til zero
|
||
;with leading crlf
|
||
push dx
|
||
call crlf
|
||
pop dx ;drop thru to outmsg0
|
||
;****
|
||
outmsg:
|
||
mov cl,prstr
|
||
jmp bdos ;dx has string addr
|
||
;****
|
||
bdma: ;dx has address
|
||
mov cl,setdmaf
|
||
jmp bdos
|
||
;****
|
||
dread: ;disk read function
|
||
mov cl,dreadf
|
||
jmp bdos
|
||
;****
|
||
open: ;file open function
|
||
mov cl,openf
|
||
jmp bdos
|
||
;****
|
||
bios:
|
||
mov fnum,al ;bios function number
|
||
mov bcx,cx
|
||
mov bdx,dx
|
||
mov dx,offset(bds)
|
||
mov cl,biosf
|
||
jmp bdos
|
||
|
||
; ****************************
|
||
; *
|
||
; * bios utilities
|
||
; *
|
||
; ****************************
|
||
|
||
seldsk equ 9 ;wboot+24 for disk select
|
||
settrk equ 10 ;wboot+27 for set track function
|
||
setsec equ 11 ;wboot+30 for set sector function
|
||
setdma equ 12 ;wboot+33 for set dma address
|
||
readf equ 13 ;wboot+36 for read function
|
||
writf equ 14 ;wboot+39 for write function
|
||
|
||
sel:
|
||
;select disk given by register a
|
||
mov cl,al
|
||
mov al,seldsk
|
||
jmp bios
|
||
;****
|
||
trk: ;set up track
|
||
mov al,settrk ;offset for settrk entry
|
||
jmp bios ;gone to settrk
|
||
;****
|
||
sec: ;set up sector number
|
||
mov al,setsec
|
||
jmp bios
|
||
;****
|
||
dma: ;set dma address to value of cx
|
||
mov al,setdma
|
||
jmp bios
|
||
;****
|
||
read: ;perform read operation
|
||
mov al,readf
|
||
jmp bios
|
||
;****
|
||
write: ;perform write operaton
|
||
mov al,writf
|
||
jmp bios
|
||
|
||
; **************************
|
||
; *
|
||
; * data areas
|
||
; *
|
||
; **************************
|
||
|
||
|
||
dseg
|
||
org 0100h ; skip past page zero
|
||
;messages
|
||
|
||
signon db 'LDCOPY VERS '
|
||
db vers/10+'0','.',vers mod 10+'0','$'
|
||
askget db 'Source Drive Name $'
|
||
getmsg db 'Source On '
|
||
gdisk rs 1 ;filled in at get function
|
||
db ', Then Type Return$'
|
||
askput db 'Destination Drive Name (Or Return To Reboot) $'
|
||
putmsg db 'Destination On '
|
||
pdisk rs 1 ;filled in at put function
|
||
db ', Then Type Return$'
|
||
errmsg db 'Permanent Error, Type Return To Ignore$'
|
||
done db 'Function Complete$'
|
||
qdisk db 'Invalid Drive Name$'
|
||
nofile db 'No Source File On Disk$'
|
||
badfile db 'Source File Read Error$'
|
||
|
||
;translate table
|
||
|
||
tran dw 1,3,5,7,9,11,13,15,17,19,21,23,25
|
||
dw 2,4,6,8,10,12,14,16,18,20,22,24,26
|
||
|
||
;leave room for double density
|
||
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 ; (64 extra bytes reserved)
|
||
|
||
|
||
; *************************
|
||
; *
|
||
; * variables
|
||
; *
|
||
; ************************
|
||
|
||
|
||
bds: ;bios data structure
|
||
fnum rb 1 ;storage for bios parameters
|
||
bcx rw 1 ;the bdos bios func puts these
|
||
bdx rw 1 ;in registers before jumping to bios
|
||
|
||
|
||
nlt dw sdlt ;number of loader tracks
|
||
spt dw sdspt ;sectors per track
|
||
|
||
ndisks db sdndisks ;number of disks
|
||
secsiz dw sdsecsiz ;sector size
|
||
maxsecs dw sdlt * sdspt ;maximum sectors to read from file
|
||
sdisk rb 1 ;selected disk for current operation
|
||
track rw 1 ;current track
|
||
rewr rb 1 ;read if 0,write if 1
|
||
sector rw 1 ;current sector
|
||
dmaddr dw 0 ;current dma address
|
||
retry rb 1 ;number of tries on this sector
|
||
conbuf db 30
|
||
rb 32 ;console buffer
|
||
;make stack on even address
|
||
|
||
loadp rs sdsecsiz*sdspt*sdlt
|
||
|
||
db 0 ; force out last data segement byte
|
||
|
||
end
|
||
|