title RCPSAMPL.ASM 7/8/88 ; .xlist ; Author: Bridger Mitchell (Plu*Perfect Systems) ; Program: RCPSAMPL.ASM ; Date: 7/8/88 ; Systems: Z-Systems on CP/M 2.2 or CP/M Plus ; ; ; This is a small, sample Resident Command Processor source file. ; Its purpose is to illustrate the use of named-common relocation ; bases to create Z-System Relocatable (ZRL) files for use on any ; Z-System. ; ; The basic routines are somewhat modified from those in the ; RCP package supplied with ZCPR33, (c) 1987 Jay Sage. ; ; Significant changes from Jay's code are marked in the right ; margin with "++". ; ; The key points are: ; 1. All intersegment references must either -- ; a. be computed from an address in the external environment ; e.g. whl address ; ; b. or be obtained from a named-common relocation base equate. ; e.g. z3env ; ; 2. The address of the ccp is obtained from the extended environment. ; ; 3. For CP/M Plus (CP/M 3) compatibility, disk space must ; be calculated by using the bdos function #46 for that purpose. ; (Joe Wright contributed the compact divide-by-eight routine). ; ; The resulting REL file can be loaded with JetLDR. For easy ; identification it should be renamed to type ZRL. ; ; See JetLDR.MMO for information about named-commons. ; ; ; Declare the module name: "RCP" plus version/feature characters. ; name RCP000 ; ++ ; ; ; The _ID_ common data are embedded in the ZRL file and displayed by ; JetLDR. Terminate the information with a nul byte. Don't ; exceed 255 bytes. ; ; COM /_ID_/ ; ++ ; ; ++ db 'RCPSAMPL - example of an RCP in named-common ZRL form.'; ++ db CR,LF ; ++ db 'Also CP/M 3-compatible SP and H commands' ; ++ db CR,LF ; ++ db 'SP, WHL, H',0 ; ++ ; ; ; Include the named-common relocation base declarations. ; maclib Z3COMMON ; ++ ; ; CR equ 0dh LF equ 0ah ; bdos equ 5 fcb1 equ 5ch tbuff equ 80h offcmd equ 25 ; Offset to command table cmdsline equ 5 ; # commands per line cmdspace equ 8 ; MUST BE > # chars in a command! CSEG origin: db 'Z3RCP' ; Package ID db 4 ; Length of each command name ; db 'SP ' ; first command dw space ; address db 'H ' dw clist db 'WHL ' dw whl db 0 ; NUL marks end of command jump table ; Name of RCP ; rcpname: db 'RCP-sample ZRL segmen','t'+80h ; ;---------------------------------------- page ; ; D I S K S P A C E C O M M A N D ; ; Command: SP (CP/M 2 and CP/M 3 compatible) ++ ; Function: Shows space remaining on designated drive ; Syntax: SP [DIR:|DU:] space: ld a,(fcb1) ; Determine requested drive or a ; If drive explicitly selected jr nz,space1 ; ..then skip ; ld c,25 ; BDOS get current drive function call bdos inc a ; Shift to range 1..16 ; space1: dec a ; Shift to range 0..15 ld e,a ; Save in E for selecting disk below ld (spacedrv),a ; save for cp/m 3 ++ add 'A' ; Convert to letter and ld (seldrv),a ; save in message string below ld c,14 ; BDOS select disk function call bdos ; Not needed if no drive selected, but ; .. smallest possible code size this way. ; ; check for cp/m 3 ; ++ ; ld c,12 ; get bdos version ++ call bdos ; if not cp/m 3 system ++ cp 30h ; ++ jr c,dparams ; ..jump to calculate from alv ++ ; ld de,0080h ; set default dma at 0080h ++ ld c,26 ; ++ call bdos ; ++ ld c,46 ; get disk freespace ++ spacedrv equ $+1 ; ++ ld e,00 ; ..on this drive ++ call bdos ; ++ ; ; Disk space is returned by CPM+ at tbuff for 3 bytes. ++ ; ld hl,(tbuff) ; Low to L, Mid to H ++ ld a,(tbuff+2) ; High to A ++ ld b,3 ; Divide by 8 (SHR 3) ++ ; ; Shift everything right into HL (64 MB max reportable) [jww] ++ ; div: or a ; Clear carry ++ rra ; High ++ rr h ; Mid ++ rr l ; Low ++ djnz div ; Again? ++ ; jr free6 ; result: hl = space free in Kbytes ++ ; ; For CP/M 2 use this method: ; ++ ; Here we extract the following disk parameter information from the disk ; parameter block (DPB): ; BLKSHF: block shift factor (1 byte) ; BLKMAX: max number of blocks on disk (2 bytes) dparams: ld c,31 ; BDOS get disk parameters function call bdos inc hl ; Advance to block shift factor byte inc hl ld a,(hl) ; Get value and ld (blkshf),a ; ..save it in code below inc hl ; Advance to max block number word inc hl inc hl ld e,(hl) ; Get value into HL inc hl ld d,(hl) inc de ; Add 1 for max number of blocks ; Compute amount of free space left on disk dfree: ld c,27 ; BDOS get allocation vector function push de ; Save BLKMAX value call bdos ; Get allocation vector into HL ld b,h ; Copy allocation vector to BC ld c,l pop hl ; Restore MAXBLK value to HL ld de,0 ; Inititialize count of free blocks ; At this point we have ; BC = allocation vector address ; DE = free block count ; HL = number of blocks on disk free1: push bc ; Save allocation address ld a,(bc) ; Get bit pattern of allocation byte ld b,8 ; Set to process 8 blocks free2: rla ; Rotate allocated block bit into carry flag jr c,free3 ; If set (bit=1), block is allocated inc de ; If not set, block is not allocated, so ; ..increment free block count free3: ld c,a ; Save remaining allocation bits in C dec hl ; Count down number of blocks on disk ld a,l ; See if we are down to zero or h jr z,free4 ; Branch if no more blocks to check ld a,c ; Get back current allocation bit pattern djnz free2 ; Loop through 8 bits pop bc ; Get pointer to allocation vector inc bc ; Point to next allocation byte jr free1 ; Continue by processing next allocation byte free4: pop bc ; Clean up stack ex de,hl ; Free block count to HL blkshf equ $+1 ; Pointer for in-the-code modification ld a,0 ; Get block shift factor sub 3 ; Convert to log base 2 of K per block jr z,free6 ; Done if single density (1k per block) ; Convert for blocks of more than 1K each free5: add hl,hl dec a jr nz,free5 ; ; At this point HL = amount of free space on disk in K free6: call print db ' Space on ' seldrv: db 0 ; Modified above to contain drive letter db ':',[' '+80h] ; Display decimal value of HL ld b,0 ; Initialize count of digits already printed ld de,10000 ; Divisor in DE call decdsp ; Print digit (or space if leading '0') ld de,1000 call decdsp call decdsp3 ; Display hundreds, tens, and units ld a,'K' jp conout ; Final return from space routine ; ;---------------------------------------- page ;Command: WHL/WHLQ ;Function: Set the Wheel Byte on or off ; ;Form: ; WHL -- turn Wheel Byte OFF ; WHL password -- turn Wheel Byte ON if password is correct ; WHLQ -- find out status of Wheel Byte ; whl: ld hl,fcb1+1 ; Pt to first char ld a,(hl) ; Get it cp ' ' ; Turn byte off if no password jr z,whloff ld de,whlpass ld b,8 ; Check 8 chars call comp ; Compare jr nz,whlmsg ; TURN ON WHEEL BYTE ld a,0ffh ; Turn on wheel byte jr whlset ; TURN OFF WHEEL BYTE whloff: xor a ; Turn off wheel byte whlset: ld hl,(z3env+29h) ; Set wheel byte and print message ++ ld (hl),a ; ++ ; PRINT WHEEL BYTE MESSAGE whlmsg: call print db ' Wheel Byte',' '+80h call testz3whl ; Get wheel byte ++ jr z,offm ; Zero is off call print db 'O','N'+80h ret offm: call print db 'OF','F'+80h ret ; ; Test wheel byte ; testz3whl: push hl ; ++ ld hl,(z3env+29h) ; ++ ld a,(hl) ; ++ or a ; ++ pop hl ; ++ ret ; ++ db 'Z'-'@' ; Leading ^z to block attempt to type rcp file whlpass: db 'PASSWORD' ; ; ;---------------------------------------- page ; ; H E L P C O M M A N D ; ; This command displays a list of all resident commands that are supported, ; including those in the CPR (command processor), RCP, and FCP. ; ; All inter-segment references are obtained from named-common bases ; (z3env, ccp). ; clist: ; Print the FCP-resident command names call print db lf db 'FC','P'+80h ld hl,(z3env+12h) ; Point to FCP command table ++ ld de,5 add hl,de call cmdlist ; ; Print the CPR-resident command names call print db lf db 'CP','R'+80h ld hl,(z3env+3fh) ; Point to command table in CPR ++ ld de,offcmd ; ++ add hl,de ; ++ call cmdlist ; Print the RCP-resident command names call crlf ; Skip a line ld hl,rcpname ; Print RCP name call printhl ld hl,(z3env+0ch) ; Point to RCP command table ++ ld de,5 add hl,de cmdlist: call crlf ld e,(hl) ld d,0 inc hl ld c,cmdsline ; Set names-per-line value cmdlist1: ld a,(hl) or a jr nz,cmdlist1a ld a,cmdsline cp c call nz,crlf ret cmdlist1a: rla jr nc,cmdlist2 call testz3whl jr nz,cmdlist2 add hl,de jr cmdlist5 ; Print leading spaces between names cmdlist2: ld a,cmdspace ; Spacing between command names sub e ld b,a ld a,' ' cmdlist3: call conout djnz cmdlist3 ; Print name of command ld b,e cmdlist4: ld a,(hl) call conout inc hl djnz cmdlist4 dec c jr nz,cmdlist5 call crlf ld c,cmdsline ; Skip to next command name cmdlist5: inc hl inc hl jr cmdlist1 ;---------------------------------------- ; Subroutines extracted from rcpsubs.lib for zcpr33. ; (c) 1987 Jay Sage ; crlf: call print db cr,lf+80h ret decdsp3: ld de,100 call decdsp ld e,10 call decdsp ld a,l add '0' jr conout decdsp: ld c,'0'-1 xor a decdsp1: inc c sbc hl,de jr nc,decdsp1 add hl,de ld a,c cp '0' jr nz,decdsp2 ld a,b or a ld a,' ' ret z decdsp2: inc b ld a,c ; ; fall thru to conout ; Console Output Routine conout: push bc push de push hl push af and 7fh ld e,a ld c,2 call bdos pop af pop hl pop de pop bc ret print: ex (sp),hl call printhl ex (sp),hl ret printhl: ld a,(hl) inc hl or a ret z call conout ret m jr printhl ; ; comp compares de w/hl for b bytes; ret w/carry if de