mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
1327 lines
35 KiB
NASM
1327 lines
35 KiB
NASM
; ***********************************************************
|
||
;
|
||
; DISASSEMBLY OF CONSOLE COMMAND PROCESSOR
|
||
; FOR CP/M VERSION 2.2
|
||
;
|
||
; ***********************************************************
|
||
; LAST REVISION: 23 DEC 1981
|
||
; ***********************************************************
|
||
;
|
||
; LEGAL NOTICE:
|
||
;
|
||
; This assembly listing is not the product of Digital
|
||
; Research Inc. and as such cannot be guaranteed for
|
||
; accuracy or completeness. The assignment of labels,
|
||
; comments and interpretation of the code is thought
|
||
; to be appropriate, but may not be what was originally
|
||
; intended. This disclaimer renounces and ignores all
|
||
; other claims and disclaimers regardless of source.
|
||
; No warrantee is made as to the merchantability or
|
||
; fitness for any purpose. Similarity between this
|
||
; program listing and any other program living or dead
|
||
; is purely coincidental.
|
||
;
|
||
; EQUATES
|
||
;
|
||
MSIZE: EQU 56 ;CPM SIZE IN KILOBYTES
|
||
;
|
||
;START: EQU (MSIZE - 20) * 1024 + 2D00H
|
||
START: EQU 0D000H
|
||
;
|
||
BDOS: EQU 0005H ;Link to operating system
|
||
IOBYTE: EQU 0003H ;I/O assigment byte for transient programs
|
||
LOGIN: EQU 0004H ;User number and disk number for transient programs
|
||
DFCB: EQU 005CH ;Default file control block
|
||
TPA: EQU 0100H ;Start of transient program area
|
||
DDMA: EQU 0080H ;Default DMA block
|
||
SECLEN: EQU 0080H ;Sector length := 128 bytes.
|
||
FBASE: EQU START + 0800H ;Start of operating system &
|
||
;location of BDOS serial numbers.
|
||
;
|
||
; SERIAL NUMBERS
|
||
;
|
||
VER: EQU 2 ;CPM VERSION
|
||
REL EQU 2 ;CPM RELEASE
|
||
REV: EQU 00 ;USER REVISION
|
||
SNH EQU 00 ;SERIAL NUMBER, HIGH
|
||
SNL EQU 00 ;SERIAL NUMBER, LOW
|
||
;
|
||
; NOTE:
|
||
; USER MUST INSERT CORRECT SERIAL NUMBER
|
||
; IN THE FORMAT HH-LLLL, WHERE HH IS TWO
|
||
; DIGITS & LLLL IS FOUR DIGITS. IF THE
|
||
; SERIAL NUMBERS IN CCP/CPM AND BDOS/CPM
|
||
; DO NOT MATCH, YOU WILL BOMB OUT WHEN
|
||
; LOADING A TRANSIENT PROGRAM.
|
||
;
|
||
;
|
||
ORG START ;SET PROGRAM START
|
||
;
|
||
; NOTE:
|
||
; On entry (C) contains the user number in the
|
||
; upper 4 bits, and the current logged in disk
|
||
; number in to lower 4 bits. This is why you log
|
||
; back to disk B: if you rebooted while logged
|
||
; into B:
|
||
;
|
||
ORIGIN: JMP CCP1 ;JUMP TO START OF CONSOLE COMMAND PROGRAM
|
||
;
|
||
JMP CCP0 ;JUMP TO START OF CCP W/ CLEARING OF INPUT BUFFER COUNTER
|
||
;
|
||
; INPUT BUFFER WITH COPYRIGHT MESSAGE THROWN IN
|
||
;
|
||
INPB: DB 127 ;MAXIMUM LENGTH OF INPUT BUFFER
|
||
INBLEN: DB 0 ;CURRENT LENGTH OF INPUT BUFFER
|
||
BUFFER: DB ' '
|
||
DB 'COPYRIGHT (C) 1979, '
|
||
DB 'DIGITAL RESEARCH '
|
||
DS BUFFER+128-$
|
||
;
|
||
; POINTERS TO INPUT BUFFER
|
||
;
|
||
BPTR1: DW BUFFER ;Pointer to input buffer used while parsing input line
|
||
BPTR2: DW 0000H ;Pointer to start of current command inn input buffer.
|
||
;Used by WHAT for error prompt.
|
||
; ***************
|
||
; SUBROUTINE AREA
|
||
; ***************
|
||
;
|
||
; TIES TO BDOS VIA VECTOR IN 0005H
|
||
;
|
||
; NOTE:
|
||
; The code in this section could be cleaned up
|
||
; shortened by rearranging things to have the
|
||
; code flow from one segment to the next
|
||
; instead of jumping back.
|
||
;
|
||
OUTPUT: MOV E,A ;OUTPUT 1 BYTE TO CONSOLE
|
||
MVI C,02H ;
|
||
JMP BDOS ;
|
||
;
|
||
; NOTE:
|
||
; Why not include OUTPUT inside of PCHAR and
|
||
; thus eliminate an- extra call?
|
||
; The only other call to OUTPUT is in PMSG,
|
||
; which should be changed anyway.
|
||
;
|
||
;PCHAR: PUSH B ;
|
||
; MOV E,A ;
|
||
; MVI C,02H ;
|
||
; CALL BDOS ;
|
||
; POP B ;
|
||
; RET ;
|
||
;
|
||
PCHAR: PUSH B ;PRINT A CHARACTER ON THE CONSOLE
|
||
CALL OUTPUT ;
|
||
POP B ;
|
||
RET ;
|
||
;
|
||
PCRLF: MVI A,0DH ;PRINT A CARRIAGE RETURN & LINE FEED
|
||
CALL PCHAR ;
|
||
MVI A,0AH ;
|
||
JMP PCHAR ;
|
||
;
|
||
SPACE: MVI A,20H ;PRINT A SPACE
|
||
JMP PCHAR ;
|
||
;
|
||
CRMSG: PUSH B ;PRINT A STRING PRECEDED BY A CR/LF
|
||
CALL PCRLF ;
|
||
POP H ;
|
||
;
|
||
; This code could be shortened by terminating the
|
||
; error code strings with a '$' and using BDOS
|
||
; command 9.
|
||
;
|
||
PMSG: MOV A,M ;PRINT A STRING TERMINATED BY A NULL
|
||
ORA A ;
|
||
RZ ;
|
||
INX H ;
|
||
PUSH H ;
|
||
CALL OUTPUT ;
|
||
POP H ;
|
||
JMP PMSG ;
|
||
;
|
||
RESET: MVI C,0DH ;RESET THE DISK SYSTEM
|
||
JMP BDOS ;
|
||
;
|
||
SELDSK: MOV E,A ;SELECT DISK
|
||
MVI C,0EH ;
|
||
JMP BDOS ;
|
||
;
|
||
BDOS1: CALL BDOS ; CALL TO BDOS W/ RETURN VALUE SAVED
|
||
STA RETVAL ;
|
||
INR A ;Set the ZFLAG for error condition
|
||
RET ;
|
||
;
|
||
OPENF: MVI C,0FH ;OPEN DISK FILE FOR READING OR WRITING
|
||
JMP BDOS1 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
OPENF1: XRA A ;OPEN FILE @ FCB, AND ZERO RECORD COUNTER
|
||
STA FCB+32 ;
|
||
LXI D,FCB ;
|
||
JMP OPENF ;
|
||
;
|
||
CLOSEF: MVI C,10H ;CLOSE FILE AFTER READING OR WRITING
|
||
JMP BDOS1 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
SRCHF: MVI C,11H ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
|
||
JMP BDOS1 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
SRCHNX: MVI C,12H ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
|
||
JMP BDOS1 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
SRCHF1: LXI D,FCB ;SEARCH FOR FIRST OCCURENCE OF FILE
|
||
JMP SRCHF ; NAME USING (FCB).
|
||
;
|
||
DELETF: MVI C,13H ;DELETE FILE FROM DIRECTORY
|
||
JMP BDOS ;
|
||
;
|
||
BDOS2: CALL BDOS ; CALL TO BDOS W/ RETURN VALUE
|
||
ORA A ;
|
||
RET ;
|
||
;
|
||
READF: MVI C,14H ;READ ONE SECTOR FROM DISK
|
||
JMP BDOS2 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
READ1: LXI D,FCB ;READ ONE SECTOR USING 'FCB'
|
||
JMP READF ;
|
||
;
|
||
WRITEF: MVI C,15H ;WRITE ONE SECTOR TO DISK
|
||
JMP BDOS2 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
CREATE: MVI C,16H ;CREATE A NEW FILE NAME IN DISK DIRECTORY
|
||
JMP BDOS1 ; CALL TO BDOS W/ RETURN VALUE
|
||
;
|
||
RENAME: MVI C,17H ;RENAME EXISTING FILE IN DISK DIRECTORY
|
||
JMP BDOS ;
|
||
;
|
||
GETUSR: MVI E,0FFH ;GET CURRENT USER NUMBER
|
||
;
|
||
; SET USER NUMBER TO VALUE IN (E), EXCEPT IF
|
||
; VALUE IS 0FFH.
|
||
;
|
||
SETUSR: MVI C,20H ;
|
||
JMP BDOS ;
|
||
;
|
||
; Set log-in byte for transient program with current
|
||
; user number in upper 4 bits and current drive in
|
||
; lower 4 bits.
|
||
;
|
||
SETLOG: CALL GETUSR ; SET LOG-IN BYTE W/ CURRENT DRIVE & USER NUMBER
|
||
ADD A ;
|
||
ADD A ;
|
||
ADD A ;
|
||
ADD A ;Shift user number to upper nibble
|
||
LXI H,CURDSK ;
|
||
ORA M ;Combine with disk number
|
||
STA LOGIN ;Place where transient programs
|
||
RET ; can find it.
|
||
;
|
||
; LOG IN CURRENT DISK
|
||
; Place current drive number in log-in byte without
|
||
; including user number.
|
||
;
|
||
LOGCUR: LDA CURDSK ;
|
||
STA LOGIN ;
|
||
RET ;
|
||
;
|
||
; CONVERT lower case INPUT TO UPPER CASE
|
||
;
|
||
LCUC: CPI 61H ;'a'
|
||
RC ;
|
||
CPI 7BH ;'z'+1
|
||
RNC ;
|
||
ANI 5FH ;MASK OFF BIT 5
|
||
RET ;
|
||
;
|
||
; COMMAND INPUT
|
||
;
|
||
; IF SUBMIT FLAG <> 0 THEN INPUT FROM SUBMIT FILE\
|
||
; ELSE INPUT FROM KEYBOARD INPUT BUFFER
|
||
;
|
||
CMNDIN: LDA SUBFL ;CHECK SUBMIT FILE FLAG
|
||
ORA A ;
|
||
JZ LINEIN ;FLAG RESET: GET INPUT FROM KEYBOARD
|
||
;
|
||
; NOTE ABOUT SUBMIT FILES:
|
||
;
|
||
; When the command SUBMIT <filename>
|
||
; is given, a file named $$$.SUB is compiled with
|
||
; one command line per record in the file.
|
||
; the file is unusual in that the commands are stored
|
||
; in reverse order. This makes it simple for the
|
||
; following code to pull one command off at a time,
|
||
; erasing as it goes. Note that the sector counter is
|
||
; decremented and the file closed each time.
|
||
; When the last command has been executed, or if an
|
||
; error is encountered, the $$$.SUB file is erased
|
||
; and control reverts to the keyboard for input.
|
||
;
|
||
LDA CURDSK ;FLAG SET: GET INPUT FROM SUBMIT FILE ON CURRENT DISK
|
||
ORA A ;
|
||
MVI A,00H ;
|
||
CNZ SELDSK ;Set to disk 0 if not there already
|
||
LXI D,SUBFCB ; Point to submit file's file control block
|
||
CALL OPENF ; Open the submit file for reading
|
||
JZ LINEIN ;Go to console on Open File Error
|
||
LDA SUBFCB+15 ;Get top sector number
|
||
DCR A ;Decrement? Yes $$$.SUB files are backwards
|
||
STA SUBFCB+32 ;Put number in Next Sector slot
|
||
LXI D,SUBFCB ;
|
||
CALL READF ;Read sector into buffer
|
||
JNZ LINEIN ;Go to console on read error
|
||
LXI D,INBLEN ;Point to start of keyboard buffer
|
||
LXI H,DDMA ;Point to start of default buffer
|
||
MVI B,SECLEN ;Set counter
|
||
CALL BLKMOV ;Move line into keyboard buffer
|
||
LXI H,SUBFCB+14 ;
|
||
MVI M,00H ;
|
||
INX H ;
|
||
DCR M ;Decrement sector count
|
||
LXI D,SUBFCB ;close the file
|
||
CALL CLOSEF ;
|
||
JZ LINEIN ;Go to console on close error
|
||
LDA CURDSK ;
|
||
ORA A ;
|
||
CNZ SELDSK ;Set to current disk if not so already
|
||
LXI H,BUFFER ;
|
||
CALL PMSG ;Echo the $$$.SUB line to console
|
||
CALL KSTAT ;Check for a keyboard break
|
||
JZ LINP1 ;NO BREAK- Continue
|
||
CALL EXITSB ; BREAK- Close off submit mode
|
||
JMP NXTCMD ;This leaves the return address on the
|
||
;stack, but NXTCMD re-initializes stack
|
||
;
|
||
; Get the input from the Console Device
|
||
;
|
||
LINEIN: CALL EXITSB ;RESET SUBMIT MODE FLAGS< ETC
|
||
CALL SETLOG ; SET LOG-IN BYTE W/ CURRENT DRIVE & USER NUMBER
|
||
MVI C,0AH ;BDOS COMMAND 10 ::= READ INPUT BUFFER
|
||
LXI D,INPB ;POINT TO START OF INPUT BUFFER
|
||
CALL BDOS ;GET A LINE FROM THE CONSOLE
|
||
CALL LOGCUR ;
|
||
LINP1: LXI H,INBLEN ;
|
||
MOV B,M ;Move the line byte count into (B)
|
||
LINP2: INX H ;Step through buffer changing lower
|
||
MOV A,B ;case into upper case.
|
||
ORA A ;
|
||
JZ LINP3 ;Exit when (B)=0
|
||
MOV A,M ;
|
||
CALL LCUC ;Convert lower case to UPPER CASE
|
||
MOV M,A ;
|
||
DCR B ;
|
||
JMP LINP2 ;Loop
|
||
;
|
||
LINP3: MOV M,A ;Poke a zero into end of line to mark end
|
||
LXI H,BUFFER ;Save command starting address
|
||
SHLD BPTR1 ; for later use.
|
||
RET ;
|
||
;
|
||
; KEYBOARD STATUS CHECK
|
||
; Return with ZFLAG set is no key pressed
|
||
; Else return with character in accumulator
|
||
;
|
||
KSTAT: MVI C,0BH ;
|
||
CALL BDOS ;
|
||
ORA A ;
|
||
RZ ;
|
||
MVI C,01H ;
|
||
CALL BDOS ;
|
||
ORA A ;
|
||
RET ;
|
||
;
|
||
; INTEROGATE THE DISK
|
||
;
|
||
INTDSK: MVI C,19H ;
|
||
JMP BDOS ;
|
||
;
|
||
; SET THE DMA ADDRESS
|
||
;
|
||
SETDMA: LXI D,DDMA ;
|
||
STDMA1: MVI C,1AH ;
|
||
JMP BDOS ;
|
||
;
|
||
; EXIT THE SUBMIT MODE
|
||
; Check to see if the Submit flag is set
|
||
; and reset it, along with the disk selection
|
||
; Erase any $$$.SUB file that may be in the directory
|
||
;
|
||
EXITSB: LXI H,SUBFL ;SUBMIT FILE FLAG
|
||
MOV A,M ;
|
||
ORA A ;
|
||
RZ ;Not in submit mode, exit
|
||
MVI M,00H ;Reset submit flag
|
||
XRA A ;
|
||
CALL SELDSK ;Select correct disk
|
||
LXI D,SUBFCB ;
|
||
CALL DELETF ;Delete the $$$.SUB file from disk
|
||
LDA CURDSK ;
|
||
JMP SELDSK ;Restore current disk and exit
|
||
;
|
||
; COMPARE SERIAL NUMBERS
|
||
; Serial numbers of CCP and BDOS are
|
||
; compared. If there is no match, you
|
||
; are banished to Digital Siberia.
|
||
; This S/R is called before a transient
|
||
; program is loaded into the TPA.
|
||
;
|
||
CMPSER: LXI D,SERNO ;Point to serial no in CCP
|
||
LXI H,FBASE ;Point to serial no in BDOS
|
||
MVI B,6 ;Number of bytes to compared
|
||
CMPSN1: LDAX D ;
|
||
CMP M ;
|
||
JNZ FATAL ; OK, you've had it. You are locked out.
|
||
INX D ;
|
||
INX H ;
|
||
DCR B ;
|
||
JNZ CMPSN1 ;
|
||
RET ; Good comparison. You are home free
|
||
;
|
||
; GENERAL PURPOSE ERROR HANDLING ROUTINE
|
||
; Anything that you do wrong in entering a
|
||
; command lands you here. The command line
|
||
; is typed back at you for your edification
|
||
; and embarrassment. After you have been shown
|
||
; a '?', you are put back in the command mode.
|
||
;
|
||
WHAT: CALL PCRLF ;
|
||
LHLD BPTR2 ; Point to the offending command
|
||
WHAT1: MOV A,M ; and print until a space or null is found
|
||
CPI ' ' ;
|
||
JZ WHAT2 ;
|
||
ORA A ;
|
||
JZ WHAT2 ;
|
||
PUSH H ;
|
||
CALL OUTPUT ;
|
||
POP H ;
|
||
INX H ;
|
||
JMP WHAT1 ;
|
||
;
|
||
WHAT2: MVI A,'?' ; OK, what did you have in mind?
|
||
CALL OUTPUT ;
|
||
CALL PCRLF ;
|
||
CALL EXITSB ;
|
||
JMP NXTCMD ; Back for another command.
|
||
;
|
||
; SPECIAL CHARACTER CHECK
|
||
; Returns with ZFLAG set if any of the special
|
||
; characters is found, or bombs you out if a
|
||
; control character is found. Contains a useless
|
||
; byte.
|
||
;
|
||
CHRCHK: LDAX D ;
|
||
ORA A ;
|
||
RZ ;Exit on null
|
||
CPI ' ' ;
|
||
JC WHAT ;Bomb out on control character
|
||
RZ ;
|
||
CPI '=' ;
|
||
RZ ;
|
||
CPI '_' ;
|
||
RZ ;
|
||
CPI '.' ;
|
||
RZ ;
|
||
CPI ':' ;
|
||
RZ ;
|
||
CPI ';' ;
|
||
RZ ;
|
||
CPI '<' ;
|
||
RZ ;
|
||
CPI '>' ;
|
||
RZ ; This command is redundant!
|
||
RET ;
|
||
;
|
||
; STEP (DE) UNTIL A NULL OR NON-SPACE IS FOUND
|
||
; Return with the character in the accumulator.
|
||
;
|
||
STEP: LDAX D ;
|
||
ORA A ;
|
||
RZ ;
|
||
CPI 20H ;' '
|
||
RNZ ;
|
||
INX D ;
|
||
JMP STEP ;
|
||
;
|
||
; ADD THE ACCUMULATOR TO (HL)
|
||
; Return with the result in (HL)
|
||
;
|
||
ADDAH: ADD L ; (HL) <- (HL) + (A)
|
||
MOV L,A ;
|
||
RNC ;
|
||
INR H ;
|
||
RET ;
|
||
;
|
||
; TRANSFER FILE CONTROL BLOCK
|
||
; This is a key subroutine that handles all
|
||
; of the setting up of file control blocks
|
||
; and of moving around the control buffer.
|
||
;
|
||
; No entry parameters are passed in registers
|
||
; On exit (A) contains a count of the number of
|
||
; '?' wildcards in file control block and ZFLAG
|
||
; is set if this count =0 and FCB contains the
|
||
; file block. The input buffer pointer has been
|
||
; advanced to one beyond end of information used.
|
||
;
|
||
; This subroutine is not only used to set up
|
||
; file control blocks, but also the numbers
|
||
; for SAVE and USER.
|
||
;
|
||
TRFCB: MVI A,00H ;Initial offset=0, primary entry point
|
||
TRFCB1: LXI H,FCB ;(Alternate entry point, offset in (A))
|
||
CALL ADDAH ;Point to current character in FCB
|
||
PUSH H ;
|
||
PUSH H ;Save pointer twice.
|
||
XRA A ;
|
||
STA TRDISK ;
|
||
LHLD BPTR1 ;Get current pointer to the input buffer
|
||
XCHG ;
|
||
CALL STEP ;Get first non-blank character
|
||
XCHG ;
|
||
SHLD BPTR2 ;Save pointer in case of error
|
||
XCHG ;
|
||
POP H ;Get FCB pointer
|
||
LDAX D ;
|
||
ORA A ;Check for null command
|
||
JZ TRFCB2 ;
|
||
SBI 40H ;Remove ASCII bias.
|
||
MOV B,A ;Save possible disk number in (B)
|
||
INX D ;
|
||
LDAX D ;
|
||
CPI ':' ; This means that this is a disk number.
|
||
JZ TRFCB3 ; Go set transient disk.
|
||
DCX D ; Get current logged in disk number.
|
||
TRFCB2: LDA CURDSK ;
|
||
MOV M,A ;
|
||
JMP TRFCB4 ;
|
||
;
|
||
TRFCB3: MOV A,B ; Set transient disk number.
|
||
STA TRDISK ;
|
||
MOV M,B ; Put disk number into head of File Control Block.
|
||
INX D ;
|
||
;
|
||
; Move file name of up to 8 characters into bytes
|
||
; 1 through 8 of FCB. Exit at reaching a special
|
||
; character or a null. Pad excess with blanks.
|
||
; If a '*' is found, fill the rest of the name block
|
||
; with '?'
|
||
;
|
||
TRFCB4: MVI B,08H ; Move file name of up to 8 Characters.
|
||
TRFCB5: CALL CHRCHK ; Exit if a special character is found.
|
||
JZ TRFCB9 ; Go pad the rest of the block w/ ' '
|
||
INX H ;
|
||
CPI '*' ;This is a Wild card match
|
||
JNZ TRFCB6 ;
|
||
MVI M,'?' ;This is an 'anything match'.
|
||
JMP TRFCB7 ;
|
||
;
|
||
TRFCB6: MOV M,A ;
|
||
INX D ;
|
||
TRFCB7: DCR B ;
|
||
JNZ TRFCB5 ;
|
||
;
|
||
TRFCB8: CALL CHRCHK ;Check for special character
|
||
JZ TRFC10 ;
|
||
INX D ;
|
||
JMP TRFCB8 ;
|
||
;
|
||
TRFCB9: INX H ; Pad the rest of the file name with blanks.
|
||
MVI M,' ' ;
|
||
DCR B ;
|
||
JNZ TRFCB9 ;
|
||
;
|
||
; Move the file extention into bytes 9 through 11 of
|
||
; FCB. Pad excess with blancks, and fill with '?'
|
||
; in the same manner as the filename.
|
||
;
|
||
TRFC10: MVI B,03H ; Move a file type of up to 3 Characters.
|
||
CPI '.' ;A period is the only legal special character in this case.
|
||
JNZ TRFC15 ;
|
||
INX D ;
|
||
TRFC11: CALL CHRCHK ; Check for special characters.
|
||
JZ TRFC15 ;
|
||
INX H ;
|
||
CPI '*' ;Wild card match- Pad the 3 bytes with ???
|
||
JNZ TRFC12 ;
|
||
MVI M,'?' ;
|
||
JMP TRFC13 ;
|
||
;
|
||
TRFC12: MOV M,A ;Put the character into FCB
|
||
INX D ;Advance FCB pointer
|
||
TRFC13: DCR B ;Decrement character counter
|
||
JNZ TRFC11 ;Loop until counter is zero
|
||
TRFC14: CALL CHRCHK ;Step buffer until special character,
|
||
JZ TRFC16 ; or null is found.
|
||
INX D ;
|
||
JMP TRFC14 ;
|
||
;
|
||
TRFC15: INX H ;Pad the rest of the extent with ' '
|
||
MVI M,' ' ;
|
||
DCR B ;
|
||
JNZ TRFC15 ;
|
||
;
|
||
TRFC16: MVI B,03H ;Zero out bytes 12 through 14
|
||
TRFC17: INX H ;
|
||
MVI M,00H ;
|
||
DCR B ;
|
||
JNZ TRFC17 ;
|
||
;
|
||
XCHG ;
|
||
SHLD BPTR1 ;Save the input buffer pointer
|
||
POP H ;(HL) = FCB
|
||
LXI B,11 ;Set counter
|
||
TRFC18: INX H ;Count number of '?' in filename.ext
|
||
MOV A,M ;
|
||
CPI '?' ;
|
||
JNZ TRFC19 ;Skip if not'?'
|
||
INR B ;
|
||
TRFC19: DCR C ;
|
||
JNZ TRFC18 ;
|
||
MOV A,B ;Move '?' count into (A)
|
||
ORA A ;Set flags to indicate ambigous filename
|
||
RET ;
|
||
;
|
||
; COMMAND NAME LIST
|
||
;
|
||
CMNDL: DB 'DIR ' ;Read directory
|
||
DB 'ERA ' ;Erase file
|
||
DB 'TYPE' ;Output named file to console
|
||
DB 'SAVE' ;Save named file on disk
|
||
DB 'REN ' ;Rename file
|
||
DB 'USER' ;Set user number
|
||
;
|
||
; SERIAL NUMBERS
|
||
;
|
||
SERNO: DB SNH ;
|
||
DB VER*10+REL ;2.2 IS 16H
|
||
DW REV ;
|
||
DB SNL/256 ;
|
||
DB SNL MOD 256 ;
|
||
;
|
||
; COMMAND SEARCH
|
||
;
|
||
; Try to match command name starting at FCB + 1
|
||
; with those in the intrinsic command list.
|
||
; Exit with command number (0 to 5) in (A) if a
|
||
; match has been made, else exit with a 6 in (A)
|
||
; signifying that this may be a transient command.
|
||
;
|
||
CSRCH: LXI H,CMNDL ; Point to start of command list.
|
||
MVI C,00H ; Zero out command counter.
|
||
CSRCH1: MOV A,C ; Check counter for maximum number of tries.
|
||
CPI 6 ;(There are 6 intrinsic commands + transients)
|
||
RNC ; Return is no match in six tries. It is a transient command.
|
||
LXI D,FCB+1 ; Point to start of command to be matched.
|
||
MVI B,04H ; Maximum number of characters in command name.
|
||
CSRCH2: LDAX D ;
|
||
CMP M ;
|
||
JNZ CSRCH3 ; No match- exit loop.
|
||
INX D ;
|
||
INX H ;
|
||
DCR B ;
|
||
JNZ CSRCH2 ; Back for another match.
|
||
LDAX D ; Found the command, now check for a separating space.
|
||
CPI ' ' ;
|
||
JNZ CSRCH4 ; No space, try for something else.
|
||
MOV A,C ; Put command count in accumulator.
|
||
RET ; Exit routine with command number.
|
||
;
|
||
CSRCH3: INX H ; Step forwards to that start of the next command name.
|
||
DCR B ;
|
||
JNZ CSRCH3 ;
|
||
CSRCH4: INR C ; Bump command counter by one.
|
||
JMP CSRCH1 ; Back for another try.
|
||
;
|
||
; ******************************
|
||
; MAIN OPERATING ROUTINE FOR CCP
|
||
; ******************************
|
||
;
|
||
; Entry point number 1
|
||
; Input buffer counter is zeroed out so no imbedded
|
||
; command can be executed on initial boot up.
|
||
;
|
||
CCP0: XRA A ;
|
||
STA INBLEN ;
|
||
;
|
||
;
|
||
; Entry point number 2
|
||
; Entry a this point allows commands inbedded in
|
||
; input buffer to be automatically executed
|
||
; on initial boot up.
|
||
;
|
||
; On entry (C) has user number in the high nibble
|
||
; and the disk drive in the lower nibble
|
||
;
|
||
CCP1: LXI SP,STACK ;Set up loacal stack
|
||
PUSH B ;Save entry parameter
|
||
MOV A,C ;
|
||
RAR ;Move upper 4 bits down
|
||
RAR ;
|
||
RAR ;
|
||
RAR ;
|
||
ANI 0FH ;Extract user number from input parameter
|
||
MOV E,A ;
|
||
CALL SETUSR ;Put user number in its place
|
||
CALL RESET ;Reset disk system
|
||
STA SUBFL ;SUBMIT FILE FLAG
|
||
POP B ;Get back entry parameter
|
||
MOV A,C ;
|
||
ANI 0FH ;Extract disk drive number from input parameter
|
||
STA CURDSK ;Set to correct disk drive
|
||
CALL SELDSK ;
|
||
LDA INBLEN ;
|
||
ORA A ;Check to see if there is anything in the input buffer
|
||
JNZ CCP2 ;There is, so don't bother with input.
|
||
;
|
||
; RE-ENTRY POINT FOR NEXT COMMAND
|
||
;
|
||
NXTCMD: LXI SP,STACK ; Reset stack, and put out a prompt so
|
||
; that you know what disk you are operating on.
|
||
CALL PCRLF ;
|
||
CALL INTDSK ;Get drive number
|
||
ADI 'A' ;Add ASCII bias
|
||
CALL OUTPUT ;
|
||
MVI A,'>' ;Prompt character
|
||
CALL OUTPUT ;
|
||
CALL CMNDIN ; Input the next command line from the console or submit file.
|
||
CCP2: LXI D,DDMA ;Set to the default DMA (0080H)
|
||
CALL STDMA1 ;
|
||
CALL INTDSK ;Check disk drive
|
||
STA CURDSK ;
|
||
CALL TRFCB ;Put command name in FCB
|
||
CNZ WHAT ;Ambigous filename.ext No good
|
||
LDA TRDISK ;
|
||
ORA A ;
|
||
JNZ TRANS ;Transient command
|
||
CALL CSRCH ;Find command in command list
|
||
LXI H,CMNDT ;Point to command vector table
|
||
MOV E,A ;Put command number in (DE)
|
||
MVI D,00H ;
|
||
DAD D ;
|
||
DAD D ;(HL) <-- CMNDT + 2 * Command number
|
||
MOV A,M ;Move command vector into (HL)
|
||
INX H ;
|
||
MOV H,M ;
|
||
MOV L,A ;
|
||
PCHL ;Go forth and execute the command.
|
||
;
|
||
; COMMAND VECTOR TABLE
|
||
;
|
||
CMNDT: DW DIR ;Display directory
|
||
DW ERA ;Erase file
|
||
DW TYPE ;Type file to console
|
||
DW SAVE ;Save file on disk
|
||
DW REN ;Rename file
|
||
DW USER ;Set user number
|
||
DW TRANS ;Load and execute transient command
|
||
;
|
||
; OK- You were warned about the serial numbers, but
|
||
; you went ahead anyway. Now you must pay the penalty
|
||
;
|
||
FATAL: LXI H,76F3H ;STUFF A DI & HLT
|
||
SHLD ORIGIN ;AT THE HEAD OF CCP
|
||
LXI H,ORIGIN ;
|
||
PCHL ;HANG UP THERE UNTIL RESET
|
||
;
|
||
; FILE READ ERROR
|
||
;
|
||
RDERR: LXI B,MSG1 ;Load pointer to message
|
||
JMP CRMSG ;Display message & return
|
||
;
|
||
MSG1: DB 'READ ERROR',0
|
||
;
|
||
; FILE NOT FOUND ERROR
|
||
;
|
||
NFERR: LXI B,MSG2 ;Load pointer to message
|
||
JMP CRMSG ;Display message & return
|
||
;
|
||
MSG2: DB 'NO FILE',0
|
||
;
|
||
; DECIMAL TO BINARY CONVERSION
|
||
; Used by SAVE and USER
|
||
;
|
||
; NOTE:
|
||
;
|
||
; There is some inefficient code in this subroutine
|
||
; TRFCB will move the numbers into FCB and pad the
|
||
; rest of the block with ' '. The number can be 3
|
||
; digits long at most, so that the elaborate stepping
|
||
; past blanks, etc is not needed. Code that can be
|
||
; revised is marked by '*'
|
||
;
|
||
DECIML: CALL TRFCB ;Move numbers into FCB
|
||
LDA TRDISK ;
|
||
ORA A ;
|
||
JNZ WHAT ;
|
||
LXI H,FCB+1 ;
|
||
LXI B,11 ;8 NUMBER FILE NAME & 3 CHAR EXT
|
||
DEC1: MOV A,M ;
|
||
CPI ' ' ;
|
||
JZ DEC2 ;
|
||
INX H ;
|
||
SUI '0' ;REMOVE ASCII BIAS
|
||
CPI 10 ;
|
||
JNC WHAT ;
|
||
MOV D,A ;
|
||
MOV A,B ;*
|
||
ANI 0E0H ;*
|
||
JNZ WHAT ;*
|
||
MOV A,B ;*
|
||
RLC ;MULTIPLY BY 10
|
||
RLC ;
|
||
RLC ;
|
||
ADD B ;
|
||
JC WHAT ;Overflow
|
||
ADD B ;
|
||
JC WHAT ;Overflow
|
||
ADD D ;
|
||
JC WHAT ;Overflow
|
||
MOV B,A ;
|
||
DCR C ;*
|
||
JNZ DEC1 ;* Should be JMP DEC1
|
||
RET ;*
|
||
;
|
||
DEC2: MOV A,M ;*Step over blanks to end of block
|
||
CPI ' ' ;*
|
||
JNZ WHAT ;*
|
||
INX H ;*
|
||
DCR C ;*
|
||
JNZ DEC2 ;*
|
||
MOV A,B ;Return with binary value in (A)
|
||
RET ;
|
||
;
|
||
; BLOCK MOVE
|
||
; Source :: ((HL))
|
||
; Destination :: ((DE))
|
||
; Count :: (B)
|
||
;
|
||
MOVE3: MVI B,03H ;3 byte move
|
||
BLKMOV: MOV A,M ;Source
|
||
STAX D ;Destination
|
||
INX H ;
|
||
INX D ;
|
||
DCR B ;Counter
|
||
JNZ BLKMOV ;
|
||
RET ;
|
||
;
|
||
; SET DIRECTORY POINTER
|
||
; Point to (DDMA) + (C) + (A)
|
||
; Return with character in (A)
|
||
;
|
||
; On entry (C) contains directory entry offset
|
||
; i.e. 00H, 20H, 40H, or 60H.
|
||
; Accumulator (A) contains number of the byte
|
||
; within the directory that the pointer is to
|
||
; be set to.
|
||
;
|
||
DIRPTR: LXI H,DDMA ;Point to start of directory sector
|
||
ADD C ;Add byte number to directory offset
|
||
CALL ADDAH ; then add the result to (HL)
|
||
MOV A,M ; and get the byte pointed to.
|
||
RET ;
|
||
;
|
||
; SET TO TRANSIENT DISK
|
||
; Set the disk specified by (TRDISK) for
|
||
; reading or writing. If (TRDISK) = (CURDISK), you
|
||
; are already on the right disk, so no change is needed
|
||
;
|
||
SETTRD: XRA A ;
|
||
STA FCB ;Set first byte of FCB to 0
|
||
LDA TRDISK ;
|
||
ORA A ;Check to see if transient disk= 0
|
||
RZ ;OK- no change needed
|
||
DCR A ;
|
||
LXI H,CURDSK ;Now check current disk
|
||
CMP M ;
|
||
RZ ;OK- no change needed
|
||
JMP SELDSK ;Disk different, so go get right one
|
||
;
|
||
; SET CURRENT DISK
|
||
; Restore the current logged-in disk as the read/write
|
||
; disk. If already on the proper disk, no action is required
|
||
;
|
||
SETCUR: LDA TRDISK ;
|
||
ORA A ;
|
||
RZ ;OK- On log-in disk, no change
|
||
DCR A ;
|
||
LXI H,CURDSK ;
|
||
CMP M ;
|
||
RZ ;OK
|
||
LDA CURDSK ;On different disk.
|
||
;(NOTE: Change this command to MOV A,M and save 2 bytes)
|
||
JMP SELDSK ; so go make change
|
||
;
|
||
; START OF INTRINSIC COMMANDS
|
||
;
|
||
; *******************************
|
||
; DIR SEARCHES FILE DIRECTORY FOR
|
||
; FILES BY FILE NAME OR FILE TYPE
|
||
; ? MATCHES ANY LETTER
|
||
; * MATCHES THE WHOLE FILENAME OR
|
||
; FILETYPE
|
||
; *******************************
|
||
;
|
||
; NOTE ON SYSTEM FILES:
|
||
; 'System' type files are rendered invisible to the
|
||
; DIR command because the MSB of the second byte of
|
||
; the file ext is set. A minor change in the following
|
||
; code could make these files listable in the Directory
|
||
;
|
||
DIR: CALL TRFCB ; TRANSFER THE COMMAND LINE INTO 005CH.
|
||
CALL SETTRD ; SET TO TRANSIENT DISK
|
||
LXI H,FCB+1 ; POINT TO START OF FILE NAME
|
||
MOV A,M ; CHECK FOR A BLANK
|
||
CPI 20H ;' '
|
||
JNZ DIR1 ; NOT BLANK, GO FIND WHAT IS WANTED.
|
||
;
|
||
MVI B,11 ; BLANK ::= DISPLAY ENTIRE DIRECTORY
|
||
DIR0: MVI M,3FH ; FILL ENTIRE FILENAME/TYPE ARE WITH WILDCARD [?]'?'
|
||
INX H ;
|
||
DCR B ;
|
||
JNZ DIR0 ;
|
||
;
|
||
DIR1: MVI E,00H ; SEARCH FOR FILE.
|
||
PUSH D ;
|
||
CALL SRCHF1 ;
|
||
CZ NFERR ; <NOT FOUND> ERROR
|
||
DIR2: JZ DIR10 ;
|
||
LDA RETVAL ;Get directory entry number
|
||
RRC ;Convert to directory block pointer
|
||
RRC ;by multiplying by 32 and masking off
|
||
RRC ;the excess
|
||
ANI 60H ;
|
||
MOV C,A ;Stash block pointer
|
||
MVI A,10 ;
|
||
CALL DIRPTR ;Get character @ DDMA + block pointer + 10 = Second char of ext
|
||
RAL ;Check for MSB set :: SYSTEM file
|
||
JC DIR9 ;Skip- System files are not listed by DIR
|
||
POP D ;
|
||
MOV A,E ;
|
||
INR E ;
|
||
PUSH D ;
|
||
ANI 03H ;Check for every 4th directory item
|
||
PUSH PSW ;
|
||
JNZ DIR3 ;Not the 4th
|
||
CALL PCRLF ; 4th, so start new line and mark
|
||
PUSH B ; with disk drive letter
|
||
CALL INTDSK ;Get disk number
|
||
POP B ;
|
||
ADI 'A' ;Print the disk number & colon at the
|
||
CALL PCHAR ;start of each directory print line
|
||
MVI A,':' ;
|
||
CALL PCHAR ;
|
||
JMP DIR4 ;
|
||
;
|
||
DIR3: CALL SPACE ;Print a space/colon/space between
|
||
MVI A,':' ;directory items
|
||
CALL PCHAR ;
|
||
DIR4: CALL SPACE ;
|
||
MVI B,01H ;
|
||
;
|
||
; The code in this area is somewhat tangled
|
||
; Space could be saved by redoing some of the
|
||
; ways that pointers are set up. Currently the
|
||
; pointer to the directory entry is recomputed
|
||
; for each byte. Why not just load (HL) once
|
||
; and increment?
|
||
;
|
||
DIR5: MOV A,B ;Print the filename.ext to the console
|
||
CALL DIRPTR ;Point to byte and reurn w/ byte in (A)
|
||
ANI 7FH ;
|
||
CPI ' ' ;
|
||
JNZ DIR7 ;
|
||
POP PSW ;
|
||
PUSH PSW ;
|
||
CPI 03H ;Chack for file ext end
|
||
JNZ DIR6 ;
|
||
MVI A,09H ;Check for file name end
|
||
CALL DIRPTR ;
|
||
ANI 7FH ;
|
||
CPI ' ' ;Check for no file ext
|
||
JZ DIR8 ;
|
||
DIR6: MVI A,' ' ;Separator between filename & ext
|
||
DIR7: CALL PCHAR ;
|
||
INR B ;
|
||
MOV A,B ;
|
||
CPI 12 ;File ext end +1
|
||
JNC DIR8 ;
|
||
CPI 9 ;File name end +1
|
||
JNZ DIR5 ;
|
||
CALL SPACE ;
|
||
JMP DIR5 ;
|
||
;
|
||
DIR8: POP PSW ;
|
||
DIR9: CALL KSTAT ;CHECK KEY BOARD, ANY KEY BREAKS
|
||
JNZ DIR10 ;Exit on break
|
||
CALL SRCHNX ;Look for another directory item
|
||
JMP DIR2 ;Loop back for more
|
||
;
|
||
DIR10: POP D ;
|
||
JMP COMEND ;EXIT
|
||
;
|
||
; ******************************************************
|
||
; ERASE FILES FROM DISK
|
||
;
|
||
; '*' and '?' can be used the same as in 'DIR'
|
||
; Does not actually wipe out information from the disk,
|
||
; but merely has the first byte of the file control block
|
||
; set to 0E5H. This routine in CCP merely sets up the
|
||
; file names to be erased; the real work is done by BDOS
|
||
; ******************************************************
|
||
;
|
||
ERA: CALL TRFCB ;Set up the file control block
|
||
CPI 11 ;If 11 '?' are in the FCB then you are
|
||
JNZ ERA1 ;asking to erase the whole disk. *.*
|
||
LXI B,MSG3 ;Ask for verification before proceeding
|
||
CALL CRMSG ;
|
||
CALL CMNDIN ;Get keyboard entry
|
||
LXI H,INBLEN ;check for return without entry
|
||
DCR M ;
|
||
JNZ NXTCMD ;Abort on empty line
|
||
INX H ;
|
||
MOV A,M ;
|
||
CPI 'Y' ;Yes, proceed with erasing everything
|
||
JNZ NXTCMD ;Chickened out
|
||
INX H ;
|
||
SHLD BPTR1 ;
|
||
ERA1: CALL SETTRD ;set the transient disk
|
||
LXI D,FCB ;Point to the file control block
|
||
CALL DELETF ;Call the routine that calls th e BDOS erase
|
||
INR A ;Check the return parameter
|
||
CZ NFERR ;Warn if item not found
|
||
JMP COMEND ;EXIT
|
||
;
|
||
MSG3: DB 'ALL (Y/N)?',0
|
||
;
|
||
; ***********************************
|
||
; OUTPUT NAMED FILE TO THE CONSOLE
|
||
; File name.ext must be unconditional
|
||
; ***********************************
|
||
;
|
||
TYPE: CALL TRFCB ;Set up file name in FCB
|
||
JNZ WHAT ;Badly formed filename: ambigous
|
||
CALL SETTRD ;Set the disk
|
||
CALL OPENF1 ;Open the file for reading
|
||
JZ TYPE4 ;Error on opening
|
||
CALL PCRLF ;
|
||
LXI H,TYPCTR ;Initiate counter
|
||
MVI M,0FFH ;
|
||
TYPE1: LXI H,TYPCTR ;
|
||
MOV A,M ;Get the buffer counter
|
||
CPI 80H ;Check for end of buffer
|
||
JC TYPE2 ;Not at end, get character from buffer
|
||
;
|
||
; At end of buffer- Read from disk
|
||
;
|
||
PUSH H ;Read a sector from disk to the buffer
|
||
CALL READ1 ;
|
||
POP H ;
|
||
JNZ TYPE3 ;RETURN VALUE <> 0. End of file or bad read
|
||
XRA A ;
|
||
MOV M,A ;Zero (TYPCTR)
|
||
TYPE2: INR M ;
|
||
LXI H,DDMA ;
|
||
CALL ADDAH ;Point to character
|
||
MOV A,M ;Get the character
|
||
CPI 1AH ;Check for end of file
|
||
JZ COMEND ;EXIT
|
||
CALL OUTPUT ;Not EOF, output the byte to the console
|
||
CALL KSTAT ;Check for keyboard break
|
||
JNZ COMEND ;EXIT ON ANY KEY
|
||
JMP TYPE1 ;Back for the next letter
|
||
;
|
||
; (A) = 1 :: End of file
|
||
; (A) = 2 :: Read error
|
||
;
|
||
TYPE3: DCR A ;
|
||
JZ COMEND ;EXIT AT END OF FILE
|
||
CALL RDERR ;
|
||
TYPE4: CALL SETCUR ;This piece of code can be used to
|
||
JMP WHAT ;replace REN4 and TRANS8
|
||
;
|
||
; **********************************
|
||
; SAVE CREATES DISK FILE FROM MEMORY
|
||
; STARTING AT 0100H. 256 BYTE PAGES
|
||
; FILENAME MUST BE UNCONDITIONAL
|
||
; IF A FILE OF THE SAME NAME & TYPE
|
||
; ALREADY EXISTS, IT IS ERASED.
|
||
; **********************************
|
||
;
|
||
SAVE: CALL DECIML ;GET THE NUMBER OF PAGES TO BE SAVED
|
||
PUSH PSW ;
|
||
CALL TRFCB ;SET UP THE FILE NAME
|
||
JNZ WHAT ;Cannot be ambigous file
|
||
CALL SETTRD ;SET UP DISK
|
||
LXI D,FCB ;
|
||
PUSH D ;
|
||
CALL DELETF ;DELETE OLD FILE OF SAME NAME
|
||
POP D ;
|
||
CALL CREATE ;CREATE A NEW FILE IN DIRECTORY
|
||
JZ SAVE3 ;
|
||
XRA A ;
|
||
STA FCB+32 ;ZERO OUT SECTOR COUNTER
|
||
POP PSW ;
|
||
MOV L,A ;
|
||
MVI H,00H ;CHECK PAGE COUNTER
|
||
DAD H ;
|
||
LXI D,TPA ;
|
||
SAVE1: MOV A,H ;CHECK PAGE COUNTER
|
||
ORA L ;
|
||
JZ SAVE2 ;EXIT, LAST PAGE HAS BEEN WRITTEN
|
||
DCX H ;
|
||
PUSH H ;SAVE COUNTER
|
||
LXI H,SECLEN ;ADVANCE DMA LOCATION
|
||
DAD D ;BY ONE SECTOR
|
||
PUSH H ;
|
||
CALL STDMA1 ;SET THE DMA ADDRESS
|
||
LXI D,FCB ;
|
||
CALL WRITEF ;WRITE THE SECTOR TO DISK
|
||
POP D ;
|
||
POP H ;
|
||
JNZ SAVE3 ;ERROR CONDITION
|
||
JMP SAVE1 ;LOOP BACK TO WRITE ANOTHER SECTOR
|
||
;
|
||
SAVE2: LXI D,FCB ;CLOSE THE FILE TO MAKE IT OFFICIAL
|
||
CALL CLOSEF ;
|
||
INR A ;CHECK FOR GOOD CLOSING
|
||
JNZ SAVE4 ;OK
|
||
SAVE3: LXI B,MSG4 ;<NO SPACE> ERROR
|
||
CALL CRMSG ;
|
||
SAVE4: CALL SETDMA ;
|
||
JMP COMEND ;EXIT
|
||
;
|
||
MSG4: DB 'NO SPACE',0
|
||
;
|
||
; *******************************************
|
||
; RENAME A FILE THE FORMAT IS
|
||
; <NEW FILENAME>.<TYPE>=<OLD FILENAME>.<TYPE>
|
||
; A '_' may be substituted for the '='
|
||
; *******************************************
|
||
;
|
||
REN: CALL TRFCB ;Put new filename into FCB
|
||
JNZ WHAT ;Cannot be ambigous filename
|
||
LDA TRDISK ;Get the disk number
|
||
PUSH PSW ;
|
||
CALL SETTRD ;Log into the correct disk
|
||
CALL SRCHF1 ;Check to see if such a name exists
|
||
JNZ FEERR ;ERROR- File name already used
|
||
LXI H,FCB ;Move new filename to upper half of FCB
|
||
LXI D,FCB+16 ;
|
||
MVI B,10H ;
|
||
CALL BLKMOV ;
|
||
LHLD BPTR1 ;Back to input buffer
|
||
XCHG ;
|
||
CALL STEP ;
|
||
CPI '=' ;Check for proper separator
|
||
JZ REN1 ;OK
|
||
CPI '_' ;
|
||
JNZ REN4 ;NO GOOD
|
||
REN1: XCHG ;
|
||
INX H ;Step over separartor
|
||
SHLD BPTR1 ;Store pointer for TRFCB to use
|
||
CALL TRFCB ;Move name.type of Old file into place
|
||
JNZ REN4 ;Error- cannot be ambigous
|
||
POP PSW ;Get back disk number
|
||
MOV B,A ;
|
||
LXI H,TRDISK ;
|
||
MOV A,M ;
|
||
ORA A ;
|
||
JZ REN2 ;OK- current disk=transient disk
|
||
CMP B ;Check disk number
|
||
MOV M,B ;Save back into TRDISK
|
||
JNZ REN4 ;Error
|
||
REN2: MOV M,B ;
|
||
XRA A ;
|
||
STA FCB ;Zero in FCB :: Logged in disk
|
||
CALL SRCHF1 ;Does old file exist?
|
||
JZ REN3 ;NO- <NO FILE> Error
|
||
LXI D,FCB ;OK- Rename it
|
||
CALL RENAME ; via call to BDOS
|
||
JMP COMEND ;EXIT
|
||
;
|
||
REN3: CALL NFERR ;<NO FILE> Error
|
||
JMP COMEND ;EXIT
|
||
;
|
||
; This piece of code can be deleted, and jumps
|
||
; to it rerouted to TYPE4
|
||
;
|
||
REN4: CALL SETCUR ;Return to current disk
|
||
JMP WHAT ;??????????
|
||
;
|
||
; FILE EXISTS ERROR
|
||
;
|
||
FEERR: LXI B,MSG6 ;Load error message pointer
|
||
CALL CRMSG ;Display maessage
|
||
JMP COMEND ;EXIT
|
||
;
|
||
; NOTE:
|
||
; If these error messages ended with '$' instead of
|
||
; a null, then the BDOS string output command could
|
||
; be used instead of the PMSG subroutine.
|
||
;
|
||
MSG6: DB 'FILE EXISTS',0
|
||
;
|
||
; ************************************
|
||
; SET THE USER NUMBER FROM THE CONSOLE
|
||
; Nobody uses this in one-user CP/M
|
||
; ************************************
|
||
;
|
||
USER: CALL DECIML ;Convert number to binary
|
||
CPI 10H ;Must be 0 to 15
|
||
JNC WHAT ;Out of range
|
||
MOV E,A ;Set in place for BDOS call
|
||
LDA FCB+1 ;Check for blank 'filename'
|
||
CPI ' ' ;
|
||
JZ WHAT ;Error
|
||
CALL SETUSR ;Set via BDOS
|
||
JMP CMEND1 ;EXIT
|
||
;
|
||
; *************************************************
|
||
; TRANS LOADS A PROGRAM INTO THE TPA IF IT IS NOT A
|
||
; COMMAND NAME, AND A PROPER <FILENAME>.COM FILE
|
||
; EXISTS ON THE TRANSIENT DISK.
|
||
; *************************************************
|
||
;
|
||
TRANS: CALL CMPSER ; CHECK FOR A KOSHER SERIAL NUMBER. BOMB OUT IF NO GOOD.
|
||
LDA FCB+1 ; SPACE ::= NO FILE NAME PRESENT.
|
||
CPI ' ' ;
|
||
JNZ TRANS1 ;OK- Filename present
|
||
LDA TRDISK ;NG- Just clean things up and leave
|
||
ORA A ;
|
||
JZ CMEND1 ;EXIT IF ON THE LOGIN DISK
|
||
DCR A ;
|
||
STA CURDSK ;OTHERWISE LOG BACK TO THE LOGIN DISK
|
||
CALL LOGCUR ;
|
||
CALL SELDSK ;
|
||
JMP CMEND1 ;AND GO BACK FOR ANOTHER COMMAND
|
||
;
|
||
TRANS1: LXI D,FCB+9 ; CHECK THE FILE TYPE.
|
||
LDAX D ;
|
||
CPI ' ' ;
|
||
JNZ WHAT ; YOU'RE NOT SUPPOSED TO HAVE A FILE TYPE W/ A TRANSIENT.
|
||
PUSH D ;
|
||
CALL SETTRD ; SET TO TRANSIENT DRIVE.
|
||
POP D ;
|
||
LXI H,COM ; MOVE FILE TYPE "COM" INTO FCB.
|
||
CALL MOVE3 ;
|
||
CALL OPENF1 ; OPEN FILE FOR READING.
|
||
JZ TRANS8 ; ERROR CONDITION, FILE NOT FOUND.
|
||
LXI H,TPA ; STARTING POINT FOR PROGRAM LOADING.
|
||
;
|
||
TRANS2: PUSH H ; MOVE PROGRAM INTO TPA SECTOR BY SECTOR.
|
||
XCHG ;
|
||
CALL STDMA1 ; POINT TO LOADING LOCATION.
|
||
LXI D,FCB ;
|
||
CALL READF ; READ 1 SECTOR INTO MEMORY.
|
||
JNZ TRANS3 ; ZFLAG RESET ::= GOOD READ, GO AROUND FOR MORE.
|
||
POP H ;
|
||
LXI D,SECLEN ;
|
||
DAD D ; ADVANCE POINTER FOR NEXT SECTOR.
|
||
LXI D,ORIGIN ; CHECK FOR PROGRAM OVERLAPPING CCP AREA.
|
||
MOV A,L ;
|
||
SUB E ;
|
||
MOV A,H ;
|
||
SBB D ;
|
||
JNC LDERR ; ERROR CONDITION, PROGRAM TOO BIG FOR MEMORY.
|
||
JMP TRANS2 ; BACK FOR NEXT SECTOR.
|
||
;
|
||
TRANS3: POP H ; CLEAR STACK.
|
||
DCR A ; 1 ::= END OF FILE (GOOD) OR 2 ::= READ ERROR (BAD).
|
||
JNZ LDERR ; READ ERROR.
|
||
CALL SETCUR ; SET BACK TO CURRENT DRIVE.
|
||
CALL TRFCB ; MOVE ANY FURTHER FCB'S AT 005CH AND 006CH.
|
||
LXI H,TRDISK ;
|
||
PUSH H ;
|
||
MOV A,M ;Put transient disk number into
|
||
STA FCB ; first byte of file control block.
|
||
MVI A,16 ;Set offset for TRFCB to upper half of FCB
|
||
CALL TRFCB1 ;Move seconf file name into FCB + 16
|
||
POP H ;
|
||
MOV A,M ;Get transient disk number of second FN
|
||
STA FCB+16 ; and insert it into FCB + 16
|
||
XRA A ;Zero out sector counter
|
||
STA FCB+32 ;
|
||
LXI D,DFCB ;Move filenames to default FCB
|
||
LXI H,FCB ;
|
||
MVI B,33 ;File control block & sector counter
|
||
CALL BLKMOV ;
|
||
;
|
||
LXI H,BUFFER ;Start at the head of buffer
|
||
TRANS4: MOV A,M ;Step until blank or null found
|
||
ORA A ; i.e. step over transient name
|
||
JZ TRANS5 ;
|
||
CPI ' ' ;
|
||
JZ TRANS5 ;
|
||
INX H ;
|
||
JMP TRANS4 ;Loop
|
||
;
|
||
TRANS5: MVI B,00H ;Command line byte counter
|
||
LXI D,DDMA+1 ;
|
||
TRANS6: MOV A,M ;Move command line into default buffer
|
||
STAX D ;
|
||
ORA A ;Exit on null
|
||
JZ TRANS7 ;
|
||
INR B ;Bump counter
|
||
INX H ;
|
||
INX D ;
|
||
JMP TRANS6 ;
|
||
;
|
||
TRANS7: MOV A,B ;Put buffer counter at start
|
||
STA DDMA ; of default buffer
|
||
CALL PCRLF ;
|
||
CALL SETDMA ;Set DMA to default buffer
|
||
CALL SETLOG ; SET LOG-IN BYTE W/ CURRENT DRIVE & USER NUMBER
|
||
CALL TPA ; GO OUT AND RUN THE PROGRAM.
|
||
LXI SP,STACK ; RESTORE STACK ON RETURN.
|
||
CALL LOGCUR ;Log back to the current disk
|
||
CALL SELDSK ;
|
||
JMP NXTCMD ; READY FOR ANOTHER ASSIGNMENT.
|
||
;
|
||
; Redundant code:
|
||
; This can be deleted, and jumps to this
|
||
; point changed to TYPE4
|
||
;
|
||
TRANS8: CALL SETCUR ;Error exit
|
||
JMP WHAT ;
|
||
;
|
||
; LOAD ERROR
|
||
;
|
||
LDERR: LXI B,MSG7 ;Load the error pointer
|
||
CALL CRMSG ;Display the message
|
||
JMP COMEND ;EXIT
|
||
;
|
||
MSG7: DB 'BAD LOAD',0
|
||
;
|
||
COM: DB 'COM' ; FILE TYPE FOR TRANSIENT COMMANDS.
|
||
;
|
||
; COMMAND END
|
||
; CLEAN-UP AND EXIT POINT FOR ALL COMMANDS
|
||
; EXCEPT TRANSIENT COMMANDS.
|
||
;
|
||
COMEND: CALL SETCUR ;PRIMARY EXIT POINT
|
||
CMEND1: CALL TRFCB ;SECONDARY EXIT POINT
|
||
LDA FCB+1 ; CHECK FOR FURTHER COMMANDS.
|
||
SUI ' ' ;
|
||
LXI H,TRDISK ;
|
||
ORA M ;
|
||
JNZ WHAT ;
|
||
JMP NXTCMD ; BACK TO THE RATRACE.
|
||
;
|
||
; END OF THE PROGRAM AREA
|
||
;
|
||
; START OF PARAMETER STORAGE AREA
|
||
;
|
||
DS 16 ;STACK AREA
|
||
STACK: EQU $ ;CCP STACK
|
||
;
|
||
SUBFL: DS 1 ; SUBMIT FLAG. FLAG SET WHEN COMMANDS COME FROM $$$.SUB FILE.
|
||
SUBFCB: DB 0,'$$$ SUB',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
FCB: DS 33 ;FILE CONTROL BLOCK FOR CCP READ/WRITE
|
||
RETVAL: DS 1 ; VALUE RETURNED IN (A) FROM CALLS TO BDOS.
|
||
CURDSK: DS 1 ; CURRENT LOGGED IN DISK.
|
||
TRDISK: DS 1 ; CURRENT TRANSIENT DISK.
|
||
TYPCTR: DS 1 ; INPUT BUFFER COUNTER USED BY 'TYPE' TO KEEP TRACK
|
||
; OF INPUT DISK BUFFER.
|
||
;
|
||
FINISH: END ORIGIN ;END OF SOURCE CODE
|
||
|