title 'GOCRCGEN - Cpm utility to download code to GCP 02/12/81'
;---------------------------------------------------------
;GOCRCGEN.COM is a special load program used to get a
; copy of the GCP code that resides on disk,
; Download it to the GCP boot for storage in RAM
; and then give it control. The first block
; on disk is a header block that contains the
; download commands to download, and then execute
; downloaded code. Format of this block is as follows:
;
; Modiified by D.C.Barrick 810206
; by D.A.STEELE 12 FEB 81
; Length byte of command (6)
; Download opcode (either 7 or 7*4)
; Download program id (1). This is not used but added for
; compatibility with downloaded code.
; Download program address (2 bytes) Specifies load address
; in the GCP.
; Download program length (2 bytes) Specifies length of
; program to be downloaded.
;
; Length count for execution command (usually 3)
; Execute command opcode (16 or 16*4)
; Execute program id (1)
; Execution address (2 bytes)
;
;
;
; The second and subsequent blocks
; are the memory image.
;
; The file is always saved as CRCGEN.COM
; and is assumed to be on the A: drive.
;
;---------------------------------------------------------
cr equ 0dh
lf equ 0ah
@bdos equ 0005h
page
;--------------------------------------------------------
; The following equates establish the linkage between
; the program in the TPA and the special GCP routines
; hidden in the BIOS
;--------------------------------------------------------
msize equ 62 ; This should be set to system RAM size
; Note: This BIOS requires 2k more than the
; standard CP/M BIOS. Therefore the CCP/BDOS
; routines must be located 2k lower than normal.
; This is automactically accomplished by the
; MOVCPM.COM supplied with InterSystems
; CP/M package. For example:
; MOVCPM 64 * will create a CCP/BDOS
; which starts at DC00h instead of E400h.
�bias equ (msize-22)*1024
ccp equ 3400h+bias ; base of CCP
bdos equ ccp+806h ; base address of BDOS (about 7k below the BIOS)
bios equ ccp+1600h ; base address of BIOS (basic input/output system)
gxo equ bios+51 ; routine for transparent send to the GCP (char in <C>).
dmawrt equ bios+69 ; routine to do DMA write to GCP
; <BC> has length, <DE> has data address
page
aseg
ORG 100H
START:
; save CP/M's stack
di
lxi h,0
dad sp
shld OLD$STACK
lxi sp, USER$STACK
ei
LXI D,FCB
MVI C,0FH ;OPEN CODE
CALL @bdos
ANI 0FCH ;XXXX XX..
JZ OPENOK
;----------------------------------
; The file CRCGEN.COM doesn't exist, Tell someone and
; then exit.
;----------------------------------
lxi d,msg1
mvi c,9
call @bdos
;--------------------------------------
; return to CP/M
;--------------------------------------
jmp return
openok:
;---------------------------------------------------------
; Read in the header block
;-----------------------------------------------------------
lxi d,header
mvi c,1ah ;set dma address
call @bdos
lxi d,fcb
mvi c,20 ;read in header
call @bdos
ani 0FCh ;ignore low two bits as error
ora a
jnz rderr
;-----------------------------------------------------------
; CRCGEN file has been opened and it's header block read into
�; memory. Send the program download command and then
; start the actual reads and DMA transfers.
;----------------------------------------------------------
lxi d,rdbuffer
mvi c,1ah ;set DMA address for data
call @bdos
rdloop:
lxi d,fcb
mvi c,20 ;read a block
call @bdos
ani 0FCh ;ignore read type bits
ora a
jnz rderr ;go to write error msg
;-----------------------------------------------
; Drop the count by 128, if less than zero
; we must do a residual dma write, if new length is
; zero, we must send a full 128 and then stop
;-----------------------------------------------
lhld addr4
lxi d,128
call sub16
jc partial
;---------------------------------------------------
; Must have been 128 or greater so DMA 128 bytes
;---------------------------------------------------
shld addr4
lxi b,128 ;DMA length
lxi d,rdbuffer ;address
call dmawrt
;----------------------------------
; Now see if done. i.e. new length of zero
;-----------------------------------
lhld addr4
mov a,l
ora h
jz endit
jmp rdloop ;more
;--------------------------------------
; error condition
; on write
;---------------------------------------
rderr: lxi d,msg2
mvi c,9
call @bdos
mvi c,0
call @bdos
;----------------------------------------------
�; All done except for the last short block
;-----------------------------------------------
partial:
lhld addr4 ;get the partial buffer count
mov b,h
mov c,l
lxi d,rdbuffer
call dmawrt
;------------------------------------------------
; close the file
;-------------------------------------------------
endit:
lxi d,fcb
mvi c,10h ;close
call @bdos
ani 0fch
jz endok
;-----------------------------------------
; didn't close successfully
;------------------------------------------
lxi d,msg3
mvi c,9
call @bdos
mvi c,0
call @bdos
jmp return
;------------------------------------------------
; all done successfully
;
; send the start execution code
;------------------------------------------------
endok:
lhld execadd ;restore execute command address & send
call send
;------------------------------------------------
; wait a while for the GCP to start up
; then return to CP/M
;------------------------------------------------
lxi h,1000h
delay:
dcx h
mov a,h
ora l
jnz delay
jmp return
page
;---------------------------------------------
; Subtract 16 bit DE from 16 bit HL leaving
; result in HL
;---------------------------------------------
sub16:
mov a,l
sub e
� mov l,a
mov a,h
sbb d
mov h,a
ret
;-------------------------------------------------------
; SEND This is used to send a command sequence to the
; Skeleton GCP. The HL register must point to the
; command length byte. NOTE that the length byte
; doesn't include itself. On completeion
; <HL> should point to the next commands length byte.
;---------------------------------------------------------
send:
mov a,m ;get length byte
inr a ;add one to get length that I must send.
send2:
push h
push psw
mov c,m ;get a byte
call gxo ;and send
pop psw
pop h
inx h ;step to next
dcr a ;drop count
rz ;return on all sent
jmp send2 ;go send more
;-----------------------------------------------------------
; Restore CP/M's stack and return
;-----------------------------------------------------------
return:
di
lhld old$stack
sphl
ei
ret
page
;------------------------------------------------------------
; The following is the header block. It is an image of the
; download and the execute command that will be sent to
; cause the rest of the code in the file to download
;------------------------------------------------------------
header:
ds 1 ;length of download command
ds 1 ;download command opcode
ds 1 ;dummy program id
addr1: ds 2 ;start of image location
addr4: ds 2 ;calculated length of image
ds 1 ;length of execute command
ds 1 ;execute commands opcode
� ds 1 ;dummy program id
addr3: ds 2 ;execution start address
ds 3 ;dummy area
addr2: ds 2 ;hold area for stop address
rdaddr: ds 2 ;write address hold
execadd:ds 2 ;hold for executes command address
rdbuffer: ds 128 ;download buffer
msg1: db 'No CRCGEN.COM file on drive A.',cr,lf,'$'
msg2: db 'GCP Read file failed',cr,lf,'$'
msg3: db 'Close failed',cr,lf,'$'
fcb: db 0,'CRCGEN COM'
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
ds 80h ; user stack space
user$stack equ $
old$stack:
ds 2 ; save location for CP/M's stack pointer
end start