home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
UTILS
/
A
/
CCP105P.ARC
/
LOADER.MAC
< prev
next >
Wrap
Text File
|
1986-10-17
|
14KB
|
567 lines
.Z80
;Modified LOADER for CP/M version 3.1
;
;This Loader is to be combined with the modified CCP before installing
;the CCP. It is especially useful in an RCPM
;environment. See CCP+.DOC for more details.
;
;This is the modified dissasembled version of the LOADER.
;
;Jim Lopushinsky, Edmonton, Alberta, Canada
;484-5981 @ 300/1200 bps
bdos EQU 5
;.............
;
;RSX header for the loader.
;
;
begin:
ds 4 ; 100H
dw end-begin ;Length of loader module 104H
JP LOADER ;Loader entry point
NEXT: JP 6 ;modified to JMP BDOS
PREV: DEFW 7 ;modified to point to prev RSX
DEFB 0 ;remove flag
DEFB 0 ;non-banked flag
DEFB 'LOADER ' ;The name of this RSX
DEFB 0FFH ;Loader flag
DEFB 0,0 ;reserved
;.........
;
;End of RSX header
;
scbbase: ;Address of Base of System Control Block
DEFW 0 ; 11BH
membase: ;Address of Base of Common memory
DEFB 0 ; 11DH
;...........
;
;Jump table for service routines that the CCP uses in the non-relocated
;version of the loader
;
JP chkrsx ;Remove inactive RSXs 11EH
JP reloc ;Relocate RSX 121H
JP setload ;compute relocate address 124H
JP setnext ;set up next RSX pointer 127H
JP setrsx ;set up RSX chains 12AH
;
;save IX and call BDOS 12DH
;
xbdos:
push ix
call bdos
pop ix
ret
;............
;
;Loader entry point. All BDOS calls are intercepted here. We only
;need to intercept function 59, Load overlay
;
LOADER:
LD A,C ;Get BDOS function
CP 59 ;is it Load overlay?
jr NZ,NEXT ;on to BDOS if not
POP BC ;GET RETURN ADDRESS IN [BC]
PUSH BC
LD (STKSAVE),sp
LD SP,LDRSTACK
PUSH BC ;Save return address on stack
ld ix,(scbbase) ;SCB in IX
EX DE,HL
LD (LFCBADDR),HL ;Save Load FCB address
LD A,H ;Test for load address of 0
OR L
PUSH AF ;save flags
CALL Z,CHKRSX ;Delete inactive RSXs if 0
POP AF ;restore flags
CALL NZ,LOAD ;if load address non-zero, load the program
POP DE ;Get return address
LD HL,100H ;point to start of .COM file
LD A,(HL) ;Get first byte
CP 0C9H ;Is it a return inst?
jr Z,DORSX ;RSXs attached. Go relocate them
LD A,D ;Test for return address of 100H
DEC A
OR E
jr NZ,NOT100H ;Jump if not loading a .COM or .PRL file
LD A,(PREV+1) ;Get High byte prev address
OR A ;is it 0?
jr NZ,NOT100H ;Nope
LD HL,(NEXT+1) ;Get next RSX address
LD (BDOS+1),HL ;Save in JMP BDOS in page 0
LD (BDOSJMP),HL ;And save it for us
CALL SETTPA ;Set Top of TPA address in SCB
NOT100H:
LD sp,(STKSAVE) ;Restore callers stack
XOR A ;flag no error
LD L,A
LD H,A
RET
;...............
;
;HERE IF BAD LOAD ADDRESS
;
BADADDR:
LD DE,0FEH ;init error code
ERRRET:
LD sp,(STKSAVE) ;restore callers stack
POP HL ;get return address
PUSH HL
DEC H ;test for return to 100H (called from CCP)
LD A,H
OR L
EX DE,HL ;error code in HL
LD A,L ;propagate error code to A and B
LD B,H
RET NZ ;return if called by user program (not CCP)
BADADRA:
LD C,9 ;print string function
LD DE,LOADMSG ;point to load error message
CALL xbdos ;print the error message
RST 0 ;and warm boot.
;.................
;
;RELOCATE THE RSX
;
MOVERSX:
INC HL
LD C,(HL) ;Get length of RSX into BC
INC HL
LD B,(HL)
LD A,(MEMBASE) ;Get common memory base
OR A ;Test for banked system
jr Z,NONBNK ;Jump if non-banked system
INC HL
INC (HL) ;Test for non-banked only load
jr Z,LNOLOAD ;jump if non-banked only RSX
NONBNK:
PUSH DE ;Save RSX start address
CALL SETLOAD ;Set up relocation address
POP HL ;RSX start address in HL
CALL RELOC ;Relocate the RSX
CALL SETRSX ;Set up the RSX pointers
LNOLOAD:
POP HL ;restore COM header table location
;...............
;
;LOAD RSX'S AND ADJUST COM FILE
;
DORSX:
LD DE,16 ;offset in COM file header to start of
;RSX length table
ADD HL,DE ;form address
PUSH HL ;save on stack
LD E,(HL) ;Get start address of RSX in DE
INC HL
LD D,(HL)
LD A,E ;Test for end of RSX table
OR D
jr NZ,MOVERSX ;Go do it if not at end
CALL 0103H ;Call init routine in COM file RSX header
LD A,(200H) ;Get first byte of .COM file
CP 0C9H ;Is it return inst?
jr NZ,NO2NDHDR ;Jump if no second header page
set 1,(ix+33h) ;Set RSX flag
;...........
;
;Here to move the COM file down one page
;
NO2NDHDR:
LD bc,(0101H) ;Get length of COM file into bc
LD HL,200H ;source
LD DE,100H ;destination
LDIR ;Move COM file down one page
jr NOT100H ;and process next header
;............
;
;SET UP RSX HEADERS. DE = base of RSX
;
SETRSX:
LD HL,(BDOS+1) ;get top of TPA
LD L,0 ;align on page boundary
LD BC,6 ;length of move
LDIR ;move Serial number into place
xor a
LD E,18H ;point to loader flag
LD (DE),A ;zero the loader flag
LD E,0DH ;High byte of prev address
LD (DE),A ;zero prev high byte
DEC DE ;low byte of prev
LD A,7
LD (DE),A ;prev = 0007H
LD L,E ;point to prev in next RSX
LD E,0BH ;next field in this RSX
LD (HL),E ;set prev field of next RSX
INC HL ;to point to this RSX
LD (HL),D
;..............
;
;SET UP NEXT FIELD IN RSX HEADER
;HL = base of next RSX, DE= next field in this RSX
;
SETNEXT:
EX DE,HL ;HL=next field, DE=next RSX
LD (HL),D ;save page number
DEC HL ;point to low byte
LD (HL),6 ;always 6
STNEXTA:
LD L,6 ;adjust
LD (BDOS+1),HL ;alter JMP BDOS
LD (BDOSJMP),HL ;and save it for us
;.............
;
;SET TOP OF TPA IN SCB
;
SETTPA:
LD DE,LSCBPB ;point to SCB paramater block
;.............
;
;GET/SET SCB AT [DE]
;
LGSSCB:
LD C,49 ;get/set SCB
jp xbdos ;Set the Top TPA address in SCB
;.............
;
;DELETE ANY INACTIVE RSX'S
;
CHKRSX:
LD HL,(BDOS+1) ;get top of TPA
LD B,H ;top of TPA page in B
RSXRMLOOP:
LD H,B ;get RSX base page
LD L,18H ;offset to loader flag
INC (HL) ;test loader flag
DEC (HL)
RET NZ ;return if at loader
LD L,0BH ;offset to high byte of next field
LD B,(HL) ;get next RSX page into B
LD L,0EH ;point to remove flag
LD A,(HL) ;get remove flag
OR A ;test remove flag
jr Z,RSXRMLOOP ;jump if not to remove this RSX
LD L,0CH ;point to prev field
LD E,(HL) ;get prev address into DE
INC HL
LD D,(HL)
LD A,B ;get next RSX page
LD (DE),A ;set prev RSX to bypass this RSX
DEC DE
LD A,6 ;always 6
LD (DE),A
INC DE ;back to high byte of prev field
LD H,B ;form address of next RSX
LD L,0CH ;offset to prev field in next RSX
LD (HL),E ;set prev address in next RSX
INC HL ;to bypass this RSX
LD (HL),D
LD A,D ;test for page zero prev pointer
OR A
PUSH BC ;save RSX page
CALL Z,STNEXTA ;alter location 6 if we just removed
;lowest RSX
POP BC ;restore RSX page
jr RSXRMLOOP ;and loop for more RSXs
;............
;
;LOAD THE PROGRAM
;
LOAD:
PUSH HL ;save FCB address
LD DE,DMASCB ;point to SCB param block for get DMA
CALL LGSSCB ;Get current DMA address
EX DE,HL ;DMA into DE
ex (sp),iy ;restore FCB address, save IY
bit 7,(ix+25h) ;test library member load
jr z,notlbr
ld l,(iy+23h)
ld h,(iy+24h) ;get member length into HL
ld (memlen),hl ;save member length
jr load1
notlbr:
ld (iy+20h),0 ;zero record count
load1:
ld l,(iy+21h)
ld h,(iy+22h) ;get load address into HL
ex (sp),iy ;restore IY, save FCB address
DEC H ;test for load address < 100H
INC H
jp Z,BADADDR ;jump if attempt to load below 100H
PUSH HL ;save load address
PUSH DE ;save old DMA address
PUSH HL ;save load address again
CALL setusr ;set up multi-sector count, user number
POP HL ;restore load address
PUSH AF ;save old mult-sector count on stack
MOREREAD:
LD A,(BDOS+2) ;get base page of top of TPA
DEC A ;less one
SUB H ;compare with load address
jp C,TOHIGH ;jump if too high
jp Z,tohigh
LD (nextaddr),HL ;save current sector address
CP 64
jr C,ok64
LD a,64
ok64:
PUSH HL
LD d,a
ADD A,a
bit 7,(ix+25h) ;test library flag
jr z,load3
ld hl,(memlen) ;get member length left
ld c,a ;sector count in c
ld b,0
sbc hl,bc ;calculate new length left
jr nc,load2 ;jump if no overflow
ld a,(memlen) ;get length left
ld hl,0
load2:
ld (memlen),hl ;save new length left
or a ;at end of member?
jr nz,load3
pop hl ;restore stack
inc a ;A = 1
jr readend
load3:
LD e,a
CALL setmce
LD e,0
POP HL
PUSH HL
PUSH DE
CALL LREAD ;read a sector
POP DE ;restore block length
POP HL ;restore sector address
ADD HL,DE ;bump sector address
jr Z,MOREREAD ;jump if no read errors
READEND:
POP BC ;get old multi-sector count
DEC A ;if EOF, A = zero
LD E,B ;old multi-sector count in E
CALL SETMCE ;restore old multi-sector count
LD C,26 ;set DMA function
POP DE ;restore old DMA address
PUSH AF ;save read EOF status
CALL setous ;set DMA to old value, restore old user number
POP AF ;restore read EOF status
LD de,(ERRCODE) ;get read error flags
jp NZ,ERRRET ;jump if read error (not EOF)
POP DE ;restore load address into DE
POP HL ;restore FCB address into HL
;.............
;
;CHECK FOR PRL FILE (PAGE RELOCATABLE)
;
bit 6,(ix+25h) ;is it PRL?
ret z
;.............
;
;here if .PRL file loaded
;
LD A,E
OR A ;must be on even page boundary
jp NZ,BADADDR ;jump if not on page boundary
LD H,D ;load address into HL
LD L,E
INC HL ;point to code length in PRL header
LD C,(HL) ;get code length into BC
INC HL
LD B,(HL)
LD L,E ;L = 0
;...............
;
;RELOCATE THE LOADED MODULE
;
RELOC:
INC H ;point to start of code
PUSH DE ;save load address
PUSH BC ;save length
LDIR ;move the module to target location
;[HL] NOW POINTS TO START OF BIT MAP
POP BC ;restore length
POP DE ;restore target address
PUSH DE
LD E,D ;target page into E
DEC E ;adjust relocation offset
PUSH HL ;save bit map address
LD H,E ;relocation offset in H
LD E,0 ;init bit offset
RELOCLP:
LD A,B ;test for end
OR C
jr Z,RELOCDN ;Jump if done
DEC BC ;Decrement length left
LD A,E ;get number of bits left
AND 7
jr NZ,NOBUMP ;jump ok
EX (SP),HL ;get bit map address
LD A,(HL) ;get next byte from bit map
INC HL ;bump
EX (SP),HL ;back to stack
LD L,A ;bits in L
NOBUMP:
RL l ;shift into carry
jr NC,NOADJUST ;jump if no need to adjust
LD A,(DE) ;get a byte
ADD A,H ;adjust it
LD (DE),A ;put it back
NOADJUST:
INC DE ;bump pointer
jr RELOCLP ;and loop for more
RELOCDN: ;relocation complete
POP DE ;adjust stack
POP DE
RET
;................
;
;HERE IF LOAD ADDRESS IS TOO HIGH
;
TOHIGH:
CALL SETMSC ;restore things
LD HL,80H ;point to TBUFF
CALL LREAD ;read one more sector into TBUFF
jr NZ,READEND ;jump if read error
LD HL,0FEH ;set error code
LD (ERRCODE),HL
jr READEND ;and jump to read return
;..............
;
;SET UP THE LOAD PARAMETERS
;
SETLOAD:
LD A,(BDOS+2) ;get top of TPA page
DEC A ;less one
DEC BC ;decrement load length
SUB B ;compute target page
INC BC ;correct load length
CP 0FH ;load must start at page 15 or higher
jp C,BADADRA ;jump if too low
LD HL,(NEXTADDR) ;get target address
CP H ;compare with load page
jp C,BADADRA ;jump if target address > load address
LD D,A ;relocation address into DE
LD E,0
RET
;..............
;
;RETURN MULTI-SECTOR COUNT IN [A] AND SET IT TO 1
;
SETMSC:
LD E,1 ;set multi-sector count to 1
;...............
;
;RETURN MULTI-SECTOR COUNT IN [A] AND SET IT TO [E]
;
SETMCE:
LD A,(ix+66H) ;get the old multi-sector count
LD (ix+66H),E ;set the new multi-sector count
RET
;..............
;
;SET DMA ADDRESS AND READ a sector
;
LREAD:
EX DE,HL ;DMA address in DE
LD C,26 ;Set DMA function
CALL xbdos ;set the DMA address
LD C,20 ;Read sequential function
LD HL,(LFCBADDR) ;point to FCB
EX DE,HL ; into DE
CALL xbdos ;read a sector
LD (ERRCODE),HL ;save return code
OR A ;set read return flag
RET
;............
;
;set up load user number
;
SETUSR:
LD A,(ix+25H) ;get load user number
and 1fh ;default user number
jr Z,setmsc ;go and set multi-sector count if default
DEC A ;adjust to true user number
LD E,A ;into E for BDOS
LD A,(ix+60H) ;get old user number
LD (curusr),A ;save it
LD (ix+60H),E ;set new user number
jr setmsc ;and on to set multi-sector count
;................
;
;restore old user number
;
setous:
LD A,(ix+25H) ;get load user number
and 1fh ;default?
Jr Z,setous1 ;on to restore old DMA if default
LD A,(curusr) ;get old user number
LD (ix+60H),A ;restore it
setous1:
LD (ix+25H),0 ;set load user to default
jp xbdos
;..............
;
;LOAD ERROR MESSAGE
;
LOADMSG: DEFB 0DH,0AH
DEFB 'Load Error$'
;............
;
;SCB FOR GET DMA ADDRESS
;
DMASCB: DEFB 3ch ;offset to DMA address
DEFB 0 ;return value from SCB
;...........
;
;SCB PARAMETER BLOCK TO SET OFFSET 62H (TOP OF TPA)
;
LSCBPB:
DEFB 62h ;offset to top of TPA address
DEFB 0FEH ;set word in SCB
end equ $
BDOSJMP equ $ ;Top of TPA address
NEXTADDR equ $+2 ;next load sector address
LFCBADDR equ $+4 ;load FCB address
STKSAVE equ $+6 ;user stack save
ERRCODE equ $+8 ;read error return code
;local stack space
LDRSTACK EQU $+45
curusr equ $+10 ;old user number
memlen equ $+11 ;library member length
END