Files
RomWBW/CPM22/BDOS22.ASM
2014-08-30 20:09:07 +00:00

3290 lines
83 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; ******************************************
;
; REASSEMBLY OF BDOS22.COM
;
; ******************************************
; LAST REVISION: 03 JAN 82
; ******************************************
;
; DISCLAIMER NUMBER 1
;
; Digital Research makes no reprentations or warranties
; with respect to the contents hereof and specifically
; disclaims any implied warranties of merchantability
; or fitness for any particular purpose. Further,
; Digital Research reserves the right to make changes
; in the contents thereof without obligation of Digital
; Research to notify any person of such revision or
; changes.
;
; DISCLAIMER NUMBER 2
;
; This assembly listing is not the product of Digital
; Research Inc. and as such cannot be guaranteed by
; them or anybody else for accuracy or completeness.
; The assigment of labels, comments and interpretation
; of the code in general is thought to be appropriate,
; but may not be exactly what the original authors of
; the program had in mind. This disclaimer renounces
; and ignores all other claims and disclaimers including
; Disclaimer #1 above. This disclaimer also denies the
; existence of this assembly listing, and by so assuming,
; presumes that no part of this listing may be reproduced,
; transmitted, transcribed, stored in a retrieval system,
; or translated into any language or computer language,
; in any form or by any means, electronic, mechanical,
; optical, chemical, animal, vegetable, mineral,
; or otherwise.
;
; NOTE:
;
; This is just a preliminary cut at the disassembly
; of the main portion of CP/M. The non-disk portions
; are fairly well commented, but the disk portions
; are still being worked on. Further work is planned
; and will be released when ready.
;
; The points still being puzzled out are:
;
; 1. The use of the null block mask for non 8" s.d.
; disk systems.
;
; 2. The use of the upper 3 bits of FILE CONTROL
; BLOCK Byte 12 (extent byte). This is tied in with
; the null block mask mentioned in #1 above.
;
; 3. The full use of the 3- 16 bit parameters in each
; disk parameter block. The vectors to these 3 items are
; DWORD1, DWORD2 & DWORD3. These are set to 0000H when
; BIOS is first loaded. ((DWORD1)) is set to 0003H by
; LOGIN, and ((DWORD2)) & ((DWORD3)) are set to 0000H by
; SETDIR which in in turn is called by LOGIN and SERCHF.
; No explanation for these parameters is given in the
; Digital Research documentation.
;
; 4. The setting and resetting of the MSB of FCB byte
; 14. The bit is set when the file is opened, and when
; each extent is opened. It is reset when a sector is
; is written, or when the random read/write parameters
; are set up. This may be some sort of flag to prevent
; trying to read a write file. More digging into this
; is required.
;
; 5. The reason for FCB Byte 13 being skipped during
; a directory file name search. The Digital Reasearch
; documentation merely says that the byte is for int-
; ernal use only, and that it is always set to 00H.
; Does the skipping of this byte mean that it is used
; for some purpose in MP/M, or is this something reser-
; ved for future use in a subsequent release?
;
; EQUATES
;
REBOOT: EQU 0000H ;REBOOT CP/M VIA VECTOR @ 0000H
IOBYTE: EQU 0003H ;I/O ALLOCATION BYTE
DDMA: EQU 0080H ;DEFAULT DMA ADDRESS
SECLEN: EQU 0080H ;STANDARD CP/M SECTOR LENGTH= 128
;
CR: EQU 0DH ;CARRIAGE RETURN
LF: EQU 0AH ;LINE FEED
TAB: EQU 09H ;TAB
BCKSPA: EQU 08H ;BACKSPACE
RUBOUT: EQU 7FH ;DELETE
;
VER: EQU 2 ;CP/M VERSION
REL: EQU 2 ;CP/M RELEASE
REV: EQU 0 ;REVISION
SNH: EQU 00 ;SERIAL NUMBER, HIGH. 2 DIGITS
SNL: EQU 0000 ;SERIAL NUMBER, LOW. 4 DIGITS
;
;
MSIZE: EQU 48 ;SIZE OF CP/M SYSTEM
;
;FBASE: EQU (MSIZE - 20)*1024 + 3C00H
FBASE: EQU 0D800H
;
ORG FBASE ;START PROGRAM
;
;
SERNO: DB SNH ;HIGH DIGITS OF SERIAL NUMBER
DB VER*10+REL ;
DW REV ;
DB SNL/256,SNL MOD 256 ;
;
; NOTE:
; The user must insert the proper serial numbers
; into BDOS since these numbers are checked by
; MOVECPM when creating a new system, and by
; CCP every time a transient program is loaded.
; Failure to have matching serial numbers will
; cause an error condition.
;
; MAIN BDOS ENTRY POINT.
; ALL CALL ARE ROUTED THROUGH HERE BY
; VECTOR LOCATED AT 0005H
;
BDOS: JMP BDOS1 ;JUMP OVER ERROR VECTORS TO START
;
; ERROR HANDLER VECTORS
;
ERR1: DW BSERR ;<BAD SECTOR ERROR>
ERR2: DW SELER1 ;<DISK SELECT ERROR>
ERR3: DW ROERR ;<DISK READ ONLY ERROR>
ERR4: DW ROERR1 ;<FILE READ ONLY ERROR>
;
; STARTING POINT OF BASIC DISK OPERATING SYSTEM
;
BDOS1: XCHG ;
SHLD ENTPAR ;SAVE ENTRY PARAMETER FROM (DE)
XCHG ;
MOV A,E ;
STA PARAM1 ;ALSO SAVE CONTENTS OF (E)
LXI H,0000 ;
SHLD RETPAR ;ZERO OUT RETURN PARAMETER
DAD SP ;
SHLD PSTACK ;SAVE CALLING PROGRAM STACK POINTER
LXI SP,BSTACK ;SET UP BDOS STACK
XRA A ;
STA DISKNO ;ZERO OUT DISK NUMBER
STA SETUPF ; & DISK SETUP FLAG
LXI H,BDOS2 ;PUT EXIT POINT ADDRESS UP FOR
PUSH H ; USE WHEN COMMAND IS COMPLETED
MOV A,C ;MOVE COMMAND NUMBER INTO (A)
CPI 29H ;CHECK FOR VALID COMMAND NUMBER
RNC ;NO GOOD- THERE ARE ONLY 40 COMMANDS
MOV C,E ;
LXI H,COMTAB ;POINT TO START OF COMMAND TABLE
MOV E,A ;
MVI D,00H ;
DAD D ;
DAD D ;POINT TO COMMAND VECTOR
MOV E,M ;
INX H ;
MOV D,M ;MOVE COMMAND VECTOR INTO (DE)
LHLD ENTPAR ;GET BACK ORIGINAL ENTRY CONTENTS OF (DE)
XCHG ;SWAP 'EM
PCHL ;THEN GO OFF TO DO THE COMMAND
;
; BDOS COMMAND VECTOR TABLE
;
; Contains vectors for 40 commands, including two
; reserved spaces for future commands, and two
; undocumented commands. Commands marked '*' are
; different from the similarly numbered commands
; in CP/M 1.4
;
COMTAB: DW WBOOT ; BIOS CALL/WARM BOOT
DW COM01 ; CONSOLE INPUT
DW COM02 ; CONSOLE OUTPUT
DW COM03 ; TAPE READER INPUT
DW PUNCH ; BIOS CALL/PUNCH DEVICE OUTPUT
DW LIST ; BIOS CALL/LIST DEVICE OUTPUT
DW COM06 ;* DIRECT CONSOLE I/O
DW COM07 ; GET I/O BYTE
DW COM08 ; SET I/O BYTE
DW COM09 ; PRINT STRING
DW COM10 ;* READ CONSOLE BUFFER
DW COM11 ; GET CONSOLE STATUS
DW COM12 ;* RETURN VERSION NUMBER
DW COM13 ; RESET DISK SYSTEM
DW COM14 ; SELECT DISK DRIVE
DW COM15 ;* OPEN FILE
DW COM16 ; CLOSE FILE
DW COM17 ;* SEARCH FOR FIRST OCCURENCE
DW COM18 ; SEARCH FOR NEXT OCCURENCE
DW COM19 ;* DELETE FILE
DW COM20 ; READ SEQUENTIAL FILE
DW COM21 ; WRITE SEQUENTIAL FILE
DW COM22 ;* MAKE FILE
DW COM23 ;* RENAME FILE
DW COM24 ; RETURN LOG-IN VECTOR
DW COM25 ; RETURN CURRENT DISK NUMBER
DW COM26 ; GET DMA ADDRESS
DW COM27 ; INTEROGATE DISK ALLOCATION
DW COM28 ;* WRITE PROTECT DISK
DW COM29 ;* GET R/O VECTOR ADDRESS
DW COM30 ;* SET FILE ATTRIBUTES
DW COM31 ;* GET DISK PARAMETER ADDRESS
DW COM32 ;* SET USER/GET USER NUMBER
DW COM33 ;* READ RANDOM FILE
DW COM34 ;* WRITE RANDOM FILE
DW COM35 ;* COMPUTE FILE SIZE
DW COM36 ;* SET RAMDOM RECORD LENGTH
DW COM37 ;** UNDOCUMENTED COMMAND
DW DUMMY ;** RESERVED FOR FUTURE USE
DW DUMMY ;** RESERVED FOR FUTURE USE
DW COM40 ;** UNDOCUMENTED COMMAND
;
; BDOS ERROR HANDLING ROUTINES
;
BSERR: LXI H,ERMSG2 ;<BAD SECTOR ERROR>
CALL ERRMSG ;
CPI 03H ;CHECK FOR A CONTROL C
JZ REBOOT ;
RET ;
;
; NOTE:
; There should be some change made to this
; piece of code because when you have tried
; to select a non-existent drive, you will
; reboot and immediately try to select that
; drive. This gives an error message and a
; reboot which reselects the drive........
;
SELER1: LXI H,ERMSG3 ;<DISK SELECT ERROR>
JMP ROERR2 ;
;
ROERR: LXI H,ERMSG5 ;<DISK READ ONLY ERROR>
JMP ROERR2 ;
;
ROERR1: LXI H,ERMSG4 ;<FILE READ ONLY ERROR>
ROERR2: CALL ERRMSG ;
JMP REBOOT ;
;
; ERROR MESSAGE STRINGS
;
ERMSG0: DB 'Bdos Err On : $'
ERMSG1: EQU ERMSG0+12 ;
;
ERMSG2: DB 'Bad Sector$' ;
;
ERMSG3: DB 'Select$' ;
;
ERMSG4: DB 'File R/O$' ;
ERMSG5: EQU ERMSG4+5 ;
;
; PRINT OUT THE ERROR MESSAGE
;
ERRMSG: PUSH H ;SAVE THE POINTER
CALL PCRLF ;START A NEW LINE
LDA CURDSK ;GET THE CURRENT DISK NUMBER
ADI 'A' ;ADD THE ASCII BIAS+1
STA ERMSG1 ;POKE INTO ERROR MESSAGE
LXI B,ERMSG0 ;POINT TO ERROR MESSAGE
CALL PRNSTR ;PRINT ERROR MESSAGE STRING
POP B ;GET BACK ORIGINAL POINTER
CALL PRNSTR ; AND PRINT THAT STRING TOO.
;
; CONSOLE KEYBOARD INPUT
;
INPUT: LXI H,KYBDFL ;SWAP THE CONTENTS OF THE KEYBOARD FLAG BYTE
MOV A,M ;WITH A 00
MVI M,00H ;
ORA A ;
RNZ ;RETURN IF SOMETHING ALREADY THERE
JMP CONIN ;ELSE GET SOMETHING VIA A BIOS CALL TO CONSOLE INPUT
;
INCHR: CALL INPUT ;GET A CHARACTER FROM KEYBOARD
CALL SETFLG ;CHECK TO SEE IF IS A COTROL CHARACTER
RC ;RETURN IF IT IS
PUSH PSW ;ELSE ECHO IT TO THE CONSOLE
MOV C,A ; (AND PERHAPS THE LIST DEVICE)
CALL COM02 ;CONSOLE OUTPUT
POP PSW ;
RET ;
;
; SET THE CARRY FLAG IF A CONTROL CHARACTER OTHER THAN
; CR, LF, TAB OR BACKSPACE IS ENCOUNTERED
;
SETFLG: CPI CR ;
RZ ;
CPI LF ;
RZ ;
CPI TAB ;
RZ ;
CPI BCKSPA ;
RZ ;
CPI ' ' ;
RET ;
;
; CHECK TO KEYBOARD STATUS TO SEE IF THERE IS
; SOMETHING TO REPORT
;
KBSTAT: LDA KYBDFL ;CHECK THE FLAG
ORA A ;
JNZ KBSTA2 ;SOMETHING ALREADY ON HAND
;
CALL CONST ;BIOS CALL/CONSOLE STATUS
ANI 01H ;CHECK LSB ONLY
RZ ;NOTHING, SO JUST RETURN
;
CALL CONIN ;BIOS CALL/CONSOLE INPUT
CPI 13H ;CHECK FOR A CONTROL S
JNZ KBSTA1 ;EXIT ON CONTROL S
CALL CONIN ;BIOS CALL/CONSOLE INPUT
CPI 03H ;CHECK AGAIN FOR A CONTROL C
JZ REBOOT ;REBOOT IF THE IS ^C
XRA A ; ELSE CLEAR THE EVIDENCE
RET ; AND EXIT
;
KBSTA1: STA KYBDFL ;MARK THE FLAG 'IN USE'
KBSTA2: MVI A,01H ; SET RETURN BYTE
RET ;
;
; OUTPUT ONE CHARACTER TO THE CONSOLE OUTPUT DEVICE
; (AND TO THE LIST DEVICE IF THE ^P FLAG IS SET)
;
; CHARACTER TO BE OUTPUT IS RECEIVED IN (C)
;
OUTPUT: LDA CHCTR1 ;
ORA A ;
JNZ OUTPT1 ;
PUSH B ;
CALL KBSTAT ;
POP B ;
PUSH B ;
CALL CONOUT ;BIOS CALL/CONSOLE OUTPUT
POP B ;
PUSH B ;
LDA LISTFL ;CHECK TO SEE IF LIST DEVICE IS SET
ORA A ;
CNZ LIST ; IT IS SO DO A BIOS CALL TO LIST DEVICE OUTPUT
POP B ;
OUTPT1: MOV A,C ;
LXI H,CHRCTR ;
CPI RUBOUT ;DON'T COUNT RUBOUTS
RZ ;
INR M ;BUMP CHARACTER COUNTER
CPI ' ' ;
RNC ;OK- IT WAS A PRINTABLE CHARACTER
DCR M ;UNDO WHAT YOU JUST DID
MOV A,M ;** SUPERFLOUS CODE!
ORA A ;** SET FLAG LIKE IT WAS SET BY DCR M
RZ ;
MOV A,C ;
CPI BCKSPA ;CHECK FOR A BACKSPACE
JNZ OUTPT2 ;
DCR M ;DECREASE COUNTER IF BACKSPACE
RET ;
;
OUTPT2: CPI LF ;ZERO OUT CHARACTER COUNTER IF
RNZ ;A LINE FEED IS FOUND, ELSE JUST
MVI M,00H ;RETURN TO CALLER
RET ;
;
; CHARACTER OUTPUT
;
; CHARACTER TO BE PRINTED RECEIVED IN (C)
;
; PRINTS CONTROL CHARACTERS AS ^[LETTER]
; EXPANDS TABS TO 8 BYTE BOUNDARIES
;
OUTCHR: MOV A,C ;
CALL SETFLG ;
JNC COM02 ; NOT A CONTROL CHAR SO JUST DO CONSOLE OUTPUT
PUSH PSW ;STASH THE CHARACTER
MVI C,'^' ;PRINT AN UP-ARROW
CALL OUTPUT ;
POP PSW ;GET CHARACTER BACK
ORI 40H ;REPLACE ASCII BIAS
MOV C,A ;
COM02: MOV A,C ;CONSOLE OUTPUT
CPI TAB ;
JNZ OUTPUT ;NOT A TAB, JUST OUTPUT
OUTCH2: MVI C,' ' ; IT WAS A TAB, SPACE TO NEXT 8 BYTE STOP.
CALL OUTPUT ;
LDA CHRCTR ;CHECK THE COUNTER
ANI 07H ;
JNZ OUTCH2 ;NOT AT EVEN LOCATION, DO ANOTHER
RET ;
;
; BLANK OUT THE CURRENT CURSOR POSITION
; BY BACKSPACE, SPACE.
;
BLANK: CALL BLANK1 ;
MVI C,' ' ;
CALL CONOUT ;BIOS CALL/CONSOLE OUTPUT
BLANK1: MVI C,BCKSPA ;
JMP CONOUT ;BIOS CALL/CONSOLE OUTPUT
;
; BREAK OUT OF THE CURRENT DISPLAY LINE AND
; START A NEW LINE. USED BY ^U (ABORT LINE),
; AND ^R (RETYPE LINE) IN CONSOLE BUFFER INPUT.
;
BREAK: MVI C,'#' ;MARK THE EXIT POINT
CALL OUTPUT ;
CALL PCRLF ;START A NEW LINE
BREAK1: LDA CHRCTR ;OUTPUT BLANKS UNTIL COUNTERS MATCH
LXI H,CHCTR2 ;
CMP M ;
RNC ;
MVI C,' ' ;
CALL OUTPUT ;
JMP BREAK1 ;
;
; STANDARD CARRIAGE RETURN/LINE FEED SUBROUTINE
;
PCRLF: MVI C,CR ;
CALL OUTPUT ;
MVI C,LF ;
JMP OUTPUT ;
;
; PRINT A STRING UNTIL A '$' IS FOUND
;
PRNSTR: LDAX B ;
CPI '$' ;END OF STRING MARKER
RZ ;
INX B ;
PUSH B ;
MOV C,A ;
CALL COM02 ;CONSOLE OUTPUT
POP B ;
JMP PRNSTR ;
;
; BDOS COMMAND #10....READ THE CONSOLE BUFFER
; ON ENTRY (DE) POINTS TO START OF THE BUFFER
; FIRST BYTE OF BUFFER CONTAINS THE MAXIMUM
; ALLOWABLE LINE LENGTH. SECOND BYTE WILL
; CONTAIN CURRENT BUFFER LENGTH ON RETURN.
;
COM10: LDA CHRCTR ;
STA CHCTR2 ;
LHLD ENTPAR ;WHY? YOU ALREADY HAVE THIS IN (DE)!
MOV C,M ;PUT MAXIMUM COUNT IN (C)
INX H ;
PUSH H ;SAVE START+1
MVI B,00H ;ZERO THE CURRENT CHARACTER COUNTER
;
; TOP OF INPUT LINE LOOP
;
LLOOP: PUSH B ;
PUSH H ;
LINE1: CALL INPUT ;GET A CHAR FROM KEYBOARD
ANI 7FH ;STRIP OFF MSB
POP H ;
POP B ;
CPI CR ;
JZ LINE16 ;EXIT ON <CR> OR <LF>
CPI LF ;
JZ LINE16 ;
CPI BCKSPA ;
JNZ LINE2 ;
MOV A,B ;
ORA A ;
JZ LLOOP ;DO NOTHING IF AT START OF LINE
DCR B ;
LDA CHRCTR ;
STA CHCTR1 ;
JMP LINE9 ;
;
LINE2: CPI RUBOUT ;RUBOUT?
JNZ LINE3 ;
MOV A,B ;
ORA A ;
JZ LLOOP ;DO NOTHING IF AT START OF A LINE
MOV A,M ;
DCR B ;
DCX H ;
JMP LINE14 ;
;
; CONTROL E....OUTPUT A CR/LF TO THE CONSOLE, BUT
; DON'T INSERT IT INTO THE LINE
;
LINE3: CPI 05H ;^E
JNZ LINE4 ;
PUSH B ;
PUSH H ;
CALL PCRLF ;
XRA A ;
STA CHCTR2 ;
JMP LINE1 ;
;
; CONTROL P....SET THE LIST DEVICE FLAG SO THAT
; ALL CONSOLE OUTPUT IS ALSO SENT TO
; THE LIST DEVICE.
;
; NOTE: The line marked ** should be changed to
; XRA M so that the flag is toggled, not
; just made non zero. The current code does
; not work the way the CP/M manual says.
; The change makes it convenient to turn
; printer on and off without rebooting.
;
LINE4: CPI 10H ;^P
JNZ LINE5 ;
PUSH H ;
LXI H,LISTFL ;
MVI A,01H ;
SUB M ;** (SHOULD BE XRA M)
MOV M,A ;
POP H ;
JMP LLOOP ;
;
; CONTROL X....BACKSPACE OVER THE CONSOLE LINE
; AND RESTART THE LINE INPUT. THIS SOUNDS LIKE
; A NICE IDEA, BUT THINGS GET SCREWED UP BY
; BACKSPACING THEN RETYPING AT TAB LOCATIONS,
; AND BY CONTROL CHARACTERS BEING DISPLAYED AS
; TWO CHARACTERS, BUT STORED IN MEMORY AS ONLY
; ONE CHARACTER. IN SHORT, EXPECT TO SEE A MESS
; EVERY SO OFTEN. CONTROL U IS REALLY BETTER.
;
LINE5: CPI 18H ;^X
JNZ LINE7 ;
POP H ;
LINE6: LDA CHCTR2 ;WIPE OUT CHARACTERS UNTIL THE COUNTERS MATCH
LXI H,CHRCTR ;
CMP M ;
JNC COM10 ;THEY MATCH, SO RESTART CONSOLE INPUT
DCR M ;
CALL BLANK ;DESTRUCTIVE BACKSPACE
JMP LINE6 ;
;
; CONTROL U....ABORT OUT OF CURRENT INPUT LINE
; AND START OVER AGAIN.
;
LINE7: CPI 15H ;^U
JNZ LINE8 ;
CALL BREAK ;ECHO A '#' AND A CR/LF
POP H ;GET BACK POINTER TO START OF BUFFER
JMP COM10 ; AND START ALL OVER AGAIN.
;
; CONTROL R....DROP DOWN TO NEW LINE AND RETYPE
; THE CONTENTS OF THE CONSOLE BUFFER. USEFULL
; TO CLEAN UP MESS MADE WHEN BACKSPACING HAS
; SCREWED UP THE TAB COUNT OR CONTROL CHARACTER DISPLAY
;
LINE8: CPI 12H ;^R
JNZ LINE13 ;
LINE9: PUSH B ;SAVE THE CHARACTER COUNT
CALL BREAK ;OUTPUT A '#' AND CR/LF
POP B ;
POP H ;GET BACK POINTER TO START OF LINE
PUSH H ; AND RESAVE IT.
PUSH B ;RESAVE CHARACTER COUNT
;
; RETYPE UNTIL COUNT IN (B) IS 0
;
LINE10: MOV A,B ;
ORA A ;
JZ LINE11 ;
INX H ;
MOV C,M ;
DCR B ;
PUSH B ;
PUSH H ;
CALL OUTCHR ;
POP H ;
POP B ;
JMP LINE10 ;
;
LINE11: PUSH H ;
LDA CHCTR1 ;
ORA A ;
JZ LINE1 ;
LXI H,CHRCTR ;
SUB M ;
STA CHCTR1 ;
LINE12: CALL BLANK ;
LXI H,CHCTR1 ;
DCR M ;
JNZ LINE12 ;
JMP LINE1 ;
;
LINE13: INX H ;
MOV M,A ;STORE CHARACTER IN INPUT BUFFER
INR B ;INCREMENT CURRENT COUNTER
LINE14: PUSH B ;
PUSH H ;
MOV C,A ;ECHO CHARACTER TO CONSOLE OUTPUT
CALL OUTCHR ;
POP H ;
POP B ;
MOV A,M ;CHECK TO SEE IF A CONTROL C HAS
CPI 03H ; BEEN SNUCK IN ON US.
MOV A,B ;
JNZ LINE15 ;NOPE- CONTINUE ON OUR WAY
CPI 01H ;YEP- DO A REBOOT ONLY IF AT THE
JZ REBOOT ; HEAD OF A LINE.
LINE15: CMP C ;CHECK THE CURRENT LINE COUNT AGAINST MAXIMUM.
JC LLOOP ;OK- THERE'S STILL ROOM, BACK FOR MORE
;
; EXIT POINT....WE GET HERE BY A <CR>, A <LF> OR
; IF THE LINE IS AT THE MAXIMUM.
;
LINE16: POP H ;RESTORE POINTER TO HEAD OF LINE
MOV M,B ;STASH THE LINE COUNT IN IT
MVI C,CR ; AND DO A CARRIAGE RETURN TO
JMP OUTPUT ; MARK OUR DEPARTURE
;
; BDOS COMMAND #1....GET A CHARACTER FROM THE KEYBOARD
; ECHO IT TO THE CONSOLE UNLESS IT IS A
; CONTROL CHARACTER.
;
COM01: CALL INCHR ;CONSOLE INPUT
JMP EXIT1 ;
;
; BDOS COMMAND #3....READ ONE CHARACTER FROM THE
; PAPER TAKE READER ATTACHED TO YOUR
; ASR-33 TELETYPE. (YOU OWN ONE OF THOSE
; BEASTS, AND USE IT AS YOUR PRIMARY CONSOLE
; DEVICE DON'T YOU?)
;
COM03: CALL READER ;INPUTBIOS CALL/TAPE READER INPUT
JMP EXIT1 ;
;
; BDOS COMMAND #6....DIRECT CONSOLE I/O
;
; PARAMETER PASSED IN (C)
; IF (C)= 0FFH THEN DIRECT CONSOLE INPUT IS MADE
; i.e. returns (A)=0 if console is not ready
; else (A)=ASCII input character
; IF (C)<>0FFH THEN (C) IS ASSUMED TO BE A VALID ASCII
; CHARACTER, AND IT IS OUTPUT TO THE CONSOLE.
;
; NOTE:
; The lines marked ** don't make sense to me.
; Why would an entrance parameter of 0FEH,
; which is an invalid ASCII character cause a
; console status request?
;
COM06: MOV A,C ;Check the entry parameter.
INR A ;
JZ DIRINP ;It was 0FFH, direct input.
INR A ;
JZ CONST ;**(Why this call on (C)=0FEH?) BIOS CALL/CONSOLE STATUS
JMP CONOUT ;BIOS CALL/CONSOLE OUTPUT
;
DIRINP: CALL CONST ;BIOS CALL/CONSOLE STATUS
ORA A ;
JZ BDOS3 ;Key not pressed, exit emptyhanded.
CALL CONIN ;Got one. BIOS CALL/CONSOLE INPUT
JMP EXIT1 ;Go stuff it into (RETPAR) and exit.
;
; BDOS COMMAND #7....GET THE I/O BYTE AND RETURN IT
; TO A PROGRAM THAT IS NOT BRIGHT ENOUGH TO
; KNOW THAT IT IS ALWAYS AT (0003H) AND COULD
; HAVE GOTTEN IT WITH A SIMPLE LDA 0003H
; INSTEAD OF GOING THROUGH BDOS.
;
COM07: LDA IOBYTE ;GET I/O BYTE LOCATED AT 0003H
JMP EXIT1 ;
;
; BDOS COMMAND #8....SET I/O BYTE
; SAME COMMENTS AS FOR COM07.
;
COM08: LXI H,IOBYTE ;SET I/O BYTE LOCATED AT 0003H
MOV M,C ;
RET ;
;
; BDOS COMMAND #9....PRINT STRING TO THE CONSOLE
; UNTIL A '$' IS FOUND.
;
; COMMENT:
; The use of '$', or for that matter any printable
; character, is inconvenient. Business programs
; cannot use this command if a dollar sign is to
; be printed in the string. The proper way to
; mark the end of a literal is with a null or
; by setting MSB.
;
COM09: XCHG ;MOVE POINTER TO START OF STRING FROM
MOV C,L ;(DE) TO (HL), AND THEN TO (BC). WHY
MOV B,H ;THE GRAND TOUR??
JMP PRNSTR ;WHY JUMP BACK TO PRNSTR INSTEAD
;OF HAVING THE CODE RIGHT HERE? ARE WE
;TO BELIEVE THAT THIS WAS DONE IN THE
;NAME OF STRUCTURED PROGRAMMING?
;
; BDOS COMMAND #11....GET CONSOLE INPUT STATUS
; RETURNS 00 IF NO KEY PRESSED, ELSE 01
;
; NOTE:
; This command is not quite compatible with
; CP/M 1.4 or 2.0 because if a ' ' is pressed
; the console then waits for another input,
; and reboots if that input is ^C. If the
; second input is not ^C, then Command 11
; returns like nothing happened, but has
; swallowed the ' '. This does strange things
; with some older CPMUG programs like Tiny
; Basic with polled Command 11 until a key
; was pressed. If you try some of these
; programs which ran fine under 1.4, but
; do strange things under 2.2, this may be
; the place to look.
;
COM11: CALL KBSTAT ;GET CONSOLE STATUS
EXIT1: STA RETPAR ; STORE THE RETURN PARAMETER
DUMMY: RET ;(USED AS EXIT POINT FOR COM38 AND
;COM39)
;
; COMMAND EXIT POINT THAT SETS RETURN PARAMETER= 01H
;
EXIT2: MVI A,01H ;
JMP EXIT1 ;
;
; PARAMETER STORAGE AREA #1
;
CHCTR1: DB 0 ;CHARACTER COUNTER #1,
;USED IN READ CONSOLE BUFFER
CHCTR2: DB 0 ;CHARACTER COUNTER #2,
;USED IN READ CONSOLE BUFFER
CHRCTR: DB 0 ;OUTPUT LINE CHARACTER COUNTER,
;USED TO KEEP COUNT FOR TAB CHARACTER.
LISTFL: DB 0 ;LIST DEVICE FLAG. WHEN <> 00,
;OUTPUT GOES TO LIST DEVICE.
KYBDFL: DB 0 ;KEYBOARD STATUS FLAG. IF <> 0 THEN
;CHARACTER IS AVAILABLE.
PSTACK: DW 0000 ;CALLING PROGRAM STACK POINTER
DS 48 ;BDOS STACK AREA
BSTACK: EQU $ ;BDOS' OWN STACK POINTER
USERNO: DB 0 ;CURRENT USER NUMBER STORAGE
CURDSK: DB 0 ;CURRENT DISK NUMBER STORAGE
ENTPAR: DW 0000 ;ENTRY PARAMETER
RETPAR: DW 0000 ;RETURN PARAMETER
;
; ERROR HANDLING ROUTINES
;
; NOTE:
; Again we see that convoluted nature of this
; program. Why don't the error calls from the
; program just jump to the code just following
; command table instead of this intermedeate
; step of picking up an inderect jump vector?
;
SELERR: LXI H,ERR2 ;DISK SELECT ERROR
;
ERROR: MOV E,M ;Move (Vector) to (DE)
INX H ;
MOV D,M ;
XCHG ;Swap it to (HL)
PCHL ; and do the indirect jump
;
; BLOCK MOVE SUBROUTINE
;
; ENTRY PARAMETERS:
; (HL) DESTINATION
; (DE) SOURCE
; (C) BYTE COUNT
;
; NOTE:
; Z80 users may want to eliminate this and
; use LDIR with a suitable swapping of the
; HL and DE register pairs & using (BC)
; of just (C) as the counter.
;
BLKMOV: INR C ;
BLMOV1: DCR C ;
RZ ;
LDAX D ;
MOV M,A ;
INX D ;
INX H ;
JMP BLMOV1 ;
;
; SET UP DISK PARAMETERS WHEN LOGGIN IN A NEW DISK
;
; THE VARIOUS PARAMETERS FROM BIOS ARE MOVE TO
; WHERE BDOS CAN USED THEM. THE LOCATION OF THE
; DISK SIZE, DIRECTORY TRACK ETC. ARE MOVED TO
; A PARAMETER BLOCK AT THE END OF BDOS.
;
; NOTE:
; 1. If the program involves much action
; between disk drives, considerable time
; can be wasted in this swapping process.
; This may be an area where improvemnts
; can be made.
;
; 2. If the disk is not a single sided,
; double density 5 1/4" or a single density
; 8", and can thus hold more than 255K, then
; the block numbers must be double precision
; and will occupy 2 bytes. Consequently a
; single directory extent can only hold 8
; block numbers, and therefore 8K if 1K
; blocks are used. In order to get enough
; directory space either the number of
; directory entries must be increased, or
; the block size increased to 2K. For
; more details on this read the Digital
; Research documentation (and you will
; get thoroughly confused).
;
SETDSK: LDA CURDSK ;GET THE NUMBER OF THE DISK
MOV C,A ;
CALL SELDSK ;BIOS CALL/SELECT DISK DRIVE
MOV A,H ;IF SELDSK RETURNS (HL)= 0000H
ORA L ;YOU ARE TRYING TO ACCESS A
RZ ;NONEXISTENT DRIVE. ERROR RETURN.
;
; LEGAL DRIVE- LET'S SET THINGS UP
;
; SELDSK RETURNS WITH POINTER TO START OF DISK
; PARAMETER BLOCK IN (HL). THE BLOCK CONTAINS
; 8 DATA WORDS:
; DW TRANS ;START OF SECTOR TRANS TABLE
; DW DWORD1 ;
; DW DWORD2 ;
; DW DWORD3 ;
; DW DIRBUF ;DIRECTORY BUFFER LOCATION
; DW DPBLK ;DISK PARAMETER BLOCK LOCATION
; DW CHKxx ;CHECK VECTOR, DRIVE xx
; DW ALLxx ;ALLOCATION BLOCK VECTOR, DRIVE xx
;
MOV E,M ;
INX H ;
MOV D,M ;(DE) <-- ((TRANS))
INX H ;
SHLD DWORD1 ;
INX H ;
INX H ;
SHLD DWORD2 ;
INX H ;
INX H ;
SHLD DWORD3 ;
INX H ;
INX H ;
XCHG ;
SHLD SECTBL ;
;
; (DE) NOW POINTS TO DIRBUF IN PARAMETER TABLE.
; THE FOLLOWING ARE NOW MOVED INTO BDOS PARAMETER AREA:
;
; (DIRBUF) POINTER TO DIRECTORY BUFFER
; (DPBLK) POINTER TO DISK PARAMETER BLOCK
; (CHKxx) POINTER TO DIRECTORY CHECKSUM BLOCK
; (ALLxx) POINTER TO ALLOCATION BLOCK MAP
;
LXI H,DIRBPT ;DIRECTORY BUFFER POINTER
MVI C,08H ;
CALL BLKMOV ;
;
; THE DISK PARAMETER BLOCK IS NOW MOVED INTO
; BDOS'S PARAMETER AREA. THIS BLOCK IS 15
; BYTES LONG AND CONTAINS THE FOLLOWING:
; (VALUES GIVEN ARE FOR 8" SINGLE DENSITY)
;
; DW 26 ;SECTORS PER TRACK
; DB 3 ;BLOCK SHIFT FACTOR
; DB 7 ;BLOCK MASK
; DB 0 ;NULL MASK
; DW 242 ;DISK SIZE -1
; DW 63 ;DIRECTORY ENTRIES -1
; DB 192 ;ALLOC 0
; DB 0 ;ALLOC 1
; DB 2 ;DIRECTORY TRACK OFFSET
;
LHLD DPBLK ;
XCHG ;
LXI H,SECTRS ;SECTORS PER TRACK=
;HEAD OF DP BLOCK
MVI C,0FH ;
CALL BLKMOV ;
;
; DETERMINE IF WE ARE ON A 5 1/4" OR SINGLE DENSITY
; 8" DISK WHICH HAS A CAPACITY OF LESS THAN 256 K
; OR IF WE ARE ON A BIG DISK THAT REQUIRES A DOUBLE
; PRECISION BLOCK NUMBER.
;
LHLD DSKSIZ ;DISK SIZE, # OF 1K BLOCKS -1
MOV A,H ;
LXI H,BIGDSK ;8" SD: 0FFH, LARGE CAP DISK: 00H
MVI M,0FFH ;
ORA A ;
JZ SETDS1 ;
MVI M,00H ;
SETDS1: MVI A,0FFH ;
ORA A ;SET ZFLAG TO MARK NON-ERROR RETURN
RET ;
;
; HOME THE DRIVE HEAD AND ZERO OUT SOME PARAMETERS
; IN PREPARATION FOR DIRECTORY OPERATIONS.
;
SETDIR: CALL HOME ;BIOS CALL/MOVE DISK HEAD TO TRACK 00
XRA A ;
LHLD DWORD2 ;
MOV M,A ;
INX H ;
MOV M,A ;((DWORD2)) <-- 0000H
LHLD DWORD3 ;
MOV M,A ;
INX H ;
MOV M,A ;((DWORD3)) <-- 0000H
RET ;
;
; READ AND WRITE DISK SECTOR
;
; ALL CALLS TO THESE ROUTINES IN BIOS ARE ROUTED
; THROUGH THIS AREA. RETURN PARAMETER IS MONITORED
; FOR POSSIBLE ERROR CONDITION.
;
; TRACK AND SECTOR INFORMATION MUST HAVE BEEN PASSED
; TO BIOS PRIOR TO INVOKING THESE CALLS.
;
RDSECT: CALL READ ;BIOS CALL/READ DISK SECTOR
JMP WRSEC1 ;
;
WRSECT: CALL WRITE ;BIOS CALL/WRITE DISK SECTOR
WRSEC1: ORA A ;
RZ ;
LXI H,ERR1 ;
JMP ERROR ;
;
; SET TRACK AND SECTOR
;
; THIS SUBROUTINE CONVERTS THE LOGICAL BLOCK NUMBER
; INFORMATION IN THE FILE CONTROL BLOCK AND SECTOR
; COUNTERS AND POINTERS TO THE ACTUAL PHYSICAL
; TRACK AND SECTOR INFORMATION TO BE PASSED TO
; BIOS PRIOR TO A SECTOR READ OR WRITE.
;
TRKSEC: LHLD BLCTR1 ;
MVI C,02H ;
CALL SHRHLC ;SHIFT (HL) RIGHT PER COUNT IN (C)
SHLD SCNTR1 ;SECTOR COUNTER #1
SHLD BLCTR2 ;BLOCK COUNTER #2
;
; SECONDARY ENTRY POINT
;
TRSEC1: LXI H,SCNTR1 ;SECTOR COUNTER #1
MOV C,M ;
INX H ;
MOV B,M ;(BC) <-- (SCNTR1)
LHLD DWORD3 ;
MOV E,M ;
INX H ;
MOV D,M ;(DE) <-- ((DWORD3))
LHLD DWORD2 ;
MOV A,M ;
INX H ;
MOV H,M ;
MOV L,A ;(HL) <-- ((DWORD2))
;
; SUBTRACT THE NUMBER OF SECTORS/TRACK FROM SECTOR
; NUMBER UNTIL (BC) >= (DE)
; COUNT IN (HL) DECREMENTED
;
TRSEC2: MOV A,C ;
SUB E ;
MOV A,B ;
SBB D ;SET FLAG ON (BC) - (DE)
JNC TRSEC3 ;(BC)>=(DE)
PUSH H ;SAVE COUNT
LHLD SECTRS ;(HL) <-- SECTORS PER TRACK
MOV A,E ;
SUB L ;
MOV E,A ;
MOV A,D ;
SBB H ;
MOV D,A ;(DE) <-- (DE) - (SECTRS)
POP H ;GET BACK THE COUNT
DCX H ; AND DECREMENT IT
JMP TRSEC2 ; LOOP
;
; ADD NUMBER OF SECTORS/TRACK TO (DE) UNTIL (HL) > (BC)
; OR (DE) + (SECTRS) OVERFLOWS.
; COUNT IN (HL) INCREMENTED
;
TRSEC3: PUSH H ;
LHLD SECTRS ;SECTORS PER TRACK
DAD D ;
JC TRSEC4 ;
MOV A,C ;
SUB L ;
MOV A,B ;
SBB H ;(BC) - (HL)
JC TRSEC4 ;
XCHG ;
POP H ;
INX H ;BUMP COUNTER
JMP TRSEC3 ; LOOP
;
TRSEC4: POP H ;
PUSH B ;
PUSH D ;
PUSH H ;
XCHG ;
LHLD DIRTRK ;DIRECTORY TRACK NUMBER
DAD D ;
MOV B,H ;
MOV C,L ;(BC) <-- PHYSICAL TRACK NUMBER
CALL SETTRK ;BIOS CALL/SET DISK TRACK
POP D ;
LHLD DWORD2 ;
MOV M,E ;
INX H ;
MOV M,D ;((DWORD2)) <-- (DE)
POP D ;
LHLD DWORD3 ;
MOV M,E ;
INX H ;
MOV M,D ;((DWORD3)) <-- (DE)
POP B ;
MOV A,C ;
SUB E ;
MOV C,A ;
MOV A,B ;
SBB D ;
MOV B,A ;(BC) <-- LOGICAL SECTOR NUMBER
LHLD SECTBL ;
XCHG ;(DE) <-- SECTOR TRANSLATE TABLE ADDR
CALL SECTRN ;BIOS CALL/SECTOR TRANSLATE
MOV C,L ;
MOV B,H ;(BC) <-- PHYSICAL SECTOR NUMBER
JMP SETSEC ;BIOS CALL/SET DISK SECTOR
;
; POINT TO FILE CONTROL BLOCK NUMBER
;
; RETURN WITH ABSOLUTE DIRECTORY BLOCK NUMBER IN (A)
; FILE EXTENT 00= 00H THROUGH 0FH
; FILE EXTENT 01= 10H THROUGH 1FH, ETC. TO
; FILE EXTENT 15= F0H THROUGH FFH.
;
BLPNTR: LXI H,BLSHFT ;(C) <-- BLOCK SHIFT FACTOR
MOV C,M ;
LDA CURREC ;CURRENT RECORD:: FCB + 32
;
; DIVIDE (CURREC) BY 2^(BLSFT)...(USUALLY 8)
;
BLPNT1: ORA A ;CLEAR CARRY FLAG
RAR ;
DCR C ;
JNZ BLPNT1 ;
;
MOV B,A ;
MVI A,08H ;
SUB M ;SUBTRACT BLOCK SHIFT FACTOR FROM 8
MOV C,A ;AND SET AS COUNTER IN (C)
LDA EXTCTR ;GET THE FILE EXTENT COUNTER: FCB + 12
BLPNT2: DCR C ; AND MULTIPLY IT BY 2^(C)
JZ BLPNT3 ; (THIS IS 32 FOR 8" SD)
ORA A ;
RAL ;
JMP BLPNT2 ;
;
BLPNT3: ADD B ;COMBINE W/ LOCAL POINTER
RET ;
;
; GET BLOCK NUMBER
;
; ON ENTRY (BC) CONTAINS BLOCK NUMBER OFFSET
; ON RETURN (HL) CONTAINS LOGICAL BLOCK NUMBER
;
; CHECK IS MADE TO SEE IF SINGLE OR DOUBLE
; PRECISION LOGICAL BLOCK NUMBER IS CALLED FOR
;
GETBLN: LHLD ENTPAR ;POINT TO START OF FILE CONTROL BLOCK
LXI D,16 ;
DAD D ;MOVE POINTER TO FIRST BLOCK NUMBER
DAD B ; THEN TO THE DESIRED BLOCK NUMBER
LDA BIGDSK ;8" SD: 0FFH, LARGE CAP DISK: 00H
ORA A ;
JZ GETBL1 ;BIG DISK, SO HIT IT AGAIN
;
MOV L,M ;CHEAPSKATE W/ SINGLE DENSITY
MVI H,00H ;SINGLE PREC. BLOCK NUMBER
RET ;
;
GETBL1: DAD B ;DOUBLE PREC. BLOCK NUMBER
MOV E,M ; BRING BACK BOTH BYTES IN (HL)
INX H ;
MOV D,M ;
XCHG ;
RET ;
;
; SET SECTOR COUNTER #1
;
; PUT THE LOGICAL BLOCK NUMBER OF THE CURRENT
; 1K BLOCK INTO SECTOR COUNTER #1
;
SETSC1: CALL BLPNTR ;
MOV C,A ;
MVI B,00H ;
CALL GETBLN ;GET BLOCK NUMBER IN (HL)
SHLD SCNTR1 ;SECTOR COUNTER #1
RET ;
;
; CHECK TO SEE IF (SECTOR COUNTER #1)= 0000H
;
CHKSC1: LHLD SCNTR1 ;SECTOR COUNTER #1
MOV A,L ;
ORA H ;
RET ;
;
; COMPUTE LOGICAL SECTOR NUMBER
;
; ON ENTRY:-(SECTOR COUNTER #1) CONTAINS BLOCK
; NUMBER OF CURRENT BLOCK AND (FILE RECORD
; COUNTER) THE SECTOR NUMBER WITHIN THE
; CURRENT FILE EXTENT.
; ON EXIT:-(SECTOR COUNTER #1) CONTAINS TO ABSOLUTE
; SECTOR NUMBER OF THE CURRENT SECTOR OF THE
; CURRENT DISK
; -(SECTOR COUNTER #2) CONTAINS THE ABSOLUTE
; SECTOR NUMBER OF THE START OF THE CURRENT
; LOGICAL BLOCK
; -(RECORD COUNTER) IS UNCHANGED
;
COMSEC: LDA BLSHFT ;GET BLOCK SHIFT FACTOR
LHLD SCNTR1 ;SECTOR COUNTER #1
CONSE1: DAD H ;MULTIPLY BY 2^(BLSHFT)...USUALLY 8
DCR A ;
JNZ CONSE1 ;
;
SHLD SCNTR2 ;STORE RESULT IN SECTOR COUNTER #2
LDA BLMASK ;(C) <-- DISK BLOCK MASK
MOV C,A ;
LDA CURREC ;CURRENT RECORD:: FCB + 32
ANA C ;GET SECTOR NUMBER WITHIN BLOCK
ORA L ;ADD TO BLOCK STARTING SECTOR NUMBER
MOV L,A ;
SHLD SCNTR1 ;STORE IN SECTOR COUNTER #1
RET ;
;
; POINT TO FILE CONTROL BLOCK BYTE 12
;
; BYTE 12 IS THE FILE EXTENT BYTE
;
; ENTRY PARAMETERS: NONE
; RETURN PARAMETER: ADDRESS OF FCB +12 IN (HL)
;
FCB12: LHLD ENTPAR ;LOAD THE POINTER TO START OF FCB
LXI D,12 ; AND ADD 12 TO IT.
DAD D ;
RET ;
;
; SET POINTERS TO FCB+15 AND FCB+32
;
; ENTRY PARAMETERS: NONE
; EXIT PARAMETERS: POINTER TO FCB+15 IN (DE)
; POINTER TO FCB+32 IN (HL)
;
; FCB +15 IS THE RECORD COUNT OF THE CURRENT FILE EXTENT
; FCB +32 IS THE CURRENT RECORD TO BE READ/WRITTEN IN
; SEQUENTIAL R/W OPERATIONS
;
FC1532: LHLD ENTPAR ;GET THE POINTER TO START OF FCB
LXI D,15 ;
DAD D ;ADD 15 TO POINT TO RECORD COUNT
XCHG ;MOVE IT TO (DE)
LXI H,17 ;ADD ANOTHER 17 TO MAKE
DAD D ;(HL) POINT TO FCB + 32
RET ;
;
; UPDATE THE CURRENT DISK INFORMATION
; BY MOVING THE CONTENTS OF FCB+15 AND FCB+32
; INTO (RECCTR) AND (CURREC) RESPECTIVELY
;
UPDATE: CALL FC1532 ;(DE) <-- FCB+15, (HL) <-- FCB+32
MOV A,M ;GET CURRENT VALUE OF FCB+32
STA CURREC ;AND STORE IN CURRENT RECORD NUMBER
XCHG ;SWAP POINTERS
MOV A,M ;GET CURRENT VALUE OF FCB+15
STA RECCTR ;AND STORE IN FILE RECORD COUNTER
CALL FCB12 ; (HL) <-- FCB + 12 , EXT BYTE PTR
LDA NLMASK ;NULL BLOCK MASK
ANA M ;
STA EXTCTR ;FILE EXTENT COUNTER: FCB + 12
RET ;
;
; LOAD AND INCREMENT THE VALUE OF THE CURRENT RECORD
; NUMBER BY 2 IF THE SEQUENTIAL/RANDOM READ/WRITE
; FLAG=2, OR LEAVE UNCHANGED IF=0. MOVE THE VALUE TO
; (RECCTR) AND (CURREC)
;
RWEXIT: CALL FC1532 ;(DE) <-- FCB+15, (HL) <-- FCB+32
LDA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
CPI 02H ;
JNZ RWEXT1 ;
XRA A ;
RWEXT1: MOV C,A ;
LDA CURREC ;CURRENT RECORD:: FCB + 32
ADD C ;
MOV M,A ;
XCHG ;
LDA RECCTR ;FILE RECORD COUNTER:: FCB + 15
MOV M,A ;
RET ;
;
; SHIFT THE CONTENTS OF (HL) RIGHT
; PER THE COUNT IN (C)
;
; ENTRY PARAMETERS: ......... IN (HL)
; COUNT IN (C)
; EXIT PARAMETER: SHIFTED VALUE OF (HL) IN (HL)
;
SHRHLC: INR C ;
SHRHL1: DCR C ;CHECK THE COUNT
RZ ;EXIT ON ZERO
MOV A,H ;
ORA A ;CLEAR CARRY BIT
RAR ;SHIFT (H) TO THE RIGHT
MOV H,A ;
MOV A,L ;
RAR ;SHIFT (L) TO THE RIGHT
MOV L,A ;
JMP SHRHL1 ;LOOP
;
; CALCULATE CHECKSUM OF 128 BYTE DIRECTORY SECTOR
; AT ((DIRBPT))
;
; ENTRY PARAMETER: POINTER TO START OF DIRECTORY
; SECTOR IN (DIRBPT)
; EXIT PARAMETER: VALUE OF CHECKSUM IN (A)
;
CHKSUM: MVI C,SECLEN ;COUNT= 128 BYTE SECTOR LENGTH
LHLD DIRBPT ;GET DIRECTORY BUFFER POINTER
XRA A ;CLEAR CHECKSUM REGISTER
CHKSM1: ADD M ;ADD TO TOTAL IN (A)
INX H ;STEP THE POINTER
DCR C ;DECREMENT THE COUNT
JNZ CHKSM1 ;LOOP UNTIL COUNT=0
RET ;RETURN WITH CRC IN (A)
;
; SHIFT (HL) LEFT PER COUNT IN (C)
;
; ENTRY PARAMETERS: ...... IN (HL)
; COUNT IN (C)
; EXIT PARAMETER: SHIFTED VALUE OF (HL) IN (HL)
;
SHLHLC: INR C ;
SHLHL1: DCR C ;
RZ ;
DAD H ;
JMP SHLHL1 ;
;
; SET CURRENT DISK'S READ ONLY STATUS OR LOGGED IN STATUS
;
; ENTRY PARAMETER: (LOGVEC) or (ROWORD) IN (BC)
; CURRENT DISK NUMBER = (CURDSK)
; EXIT PARAMETER: UPDATED VERSION OF (BC) IN (HL).
;
; NOTE:
; (LOGVEC) AND (ROWORD) ARE 16 BIT WORDS
; EACH BIT REPRESENTS THE LOG IN AND READ ONLY
; STATUS OF THE DRIVE REPRESENTED BY THE BIT.
; LSB CORRESPONDS TO DRIVE 'A'.
; MSB CORRESPONDS TO DRIVE 'P'.
;
SETVEC: PUSH B ;SAVE ENTRY PARAMETER
LDA CURDSK ;
MOV C,A ;PUT DISK NUMBER AS COUNTER IN (C)
LXI H,0001 ;SET-BIT IN (HL)
CALL SHLHLC ;SHIFT (HL) LEFT PER COUNT IN (C)
POP B ;RESTORE PARAMETER
MOV A,C ;COMBINE SHIFTED SET-BIT WITH
ORA L ; PREVIOUS CONTENTS OF
MOV L,A ; (BC) INTO (HL)
MOV A,B ;
ORA H ;
MOV H,A ;
RET ;RETURN W/ UPDATED VALUE IN (HL)
;
; GET CURRENT READ ONLY STATUS OF DISK
;
; ENTRY PARAMETERS: NONE
; EXIT PARAMETER: LSB OF (A) SET IF DISK IS
; WRITE PROTECTED.
;
GETRO: LHLD ROWORD ;GET R/O STATUS WORD
LDA CURDSK ;GET DISK NUMBER AS COUNTER IN (C)
MOV C,A ;
CALL SHRHLC ;SHIFT (HL) RIGHT PER COUNT IN (C)
MOV A,L ;MOVE CURRENT DISK STATUS TO (A)
ANI 01H ;MASK OFF EXTRANEOUS INFORMATION
RET ;
;
; BDOS COMMAND #28....SET CURRENT DISK TO READ ONLY
;
; CONTENTS OF (ROWORD) UPDATED TO INCLUDE
; CURRENT DISK.
;
COM28: LXI H,ROWORD ;MOVE (ROWORD) TO (BC)
MOV C,M ;
INX H ;
MOV B,M ;
CALL SETVEC ;SET CURRENT DISK TO READ ONLY
SHLD ROWORD ;STORE UPDATED INFO IN (ROWORD)
LHLD DIRMAX ;MAX NUMBER OF ENTRIES IN DIRECTORY
INX H ;
XCHG ;
LHLD DWORD1 ;
MOV M,E ;
INX H ;
MOV M,D ;((DWORD1)) <-- (DIRMAX) + 1
RET ;
;
; CHECK THE READ ONLY STATUS OF A FILE DIRECTORY
; ENTRY POINTED TO BY (DIRBPT) + (DIROFF)
;
; R/O STATUS IS MARKED BY MSB OF FIRST BYTE OF
; FILE TYPE BEING SET. (FCB + 9)
;
; IF THE FILE IS WRITE PROTECTED, AN ERROR MESSAGE
; WILL BE SENT TO THE CONSOLE AND THE CHOICE OF
; REBOOTING OR LIVING WITH THE R/O FILE GIVEN
;
CHKRO: CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
CHKRO1: LXI D,09 ;
DAD D ;POINT TO FIRST BYTE OF FILETYPE
MOV A,M ;MOVE INTO (A)
RAL ;SHIFT MSB INTO CARRY
RNC ;OK- FILE NOT WRITE PROTECTED
LXI H,ERR4 ;ERROR CONDITION.......
JMP ERROR ;.....WRITE PROTECTED FILE
;
; INTEROGATE READ ONLY STATUS OF CURRENT DISK
;
; SAME GENRAL RULES AS PREVIOUS SUBROUTINE,
; EXEPT THAT IS FOR R/O DISK
;
INTRRO: CALL GETRO ;GET READ ONLY STATUS OF CURRENT DISK
RZ ;OK- THE DISK IS NOT WRITE PROTECTED
LXI H,ERR3 ;ERROR CONDITION..........
JMP ERROR ;..........WRITE PROTECTED DISK
;
; SET DIRECTORY POINTER TO START OF CURRENT
; DIRECTORY ENTRY.
;
DIRPTR: LHLD DIRBPT ;GET THE DIRECTORY BUFFER POINTER
LDA DIROFF ;AND THE DIRECTORY OFFSET
;
ADA2HL: ADD L ; ADD CONTENTS OF (A) TO (HL)
MOV L,A ; AND RETURN WITH THE RESULT
RNC ; IN (HL)
INR H ;
RET ;
;
; GET THE CONTENTS OF S2 BYTE
;
; ENTRY PARAMETER: START OF FCB IN (ENTPAR)
; EXIT PARAMETERS: POINTER TO FCB+14 IN (HL)
; CONTENTS OF (FCB+14) IN (A)
;
FCB14: LHLD ENTPAR ;POINT TO START OF FCB
LXI D,14 ;
DAD D ;POINT TO FCB+14
MOV A,M ;GET THE VALUE OF FCB+14
RET ;
;
; ZERO OUT THE VALUE OF FCB BYTE S2.(FCB + 14)
;
ZRFCTR: CALL FCB14 ;(HL) <-- FCB + 14, (A) <-- (FCB + 14)
MVI M,00H ;PUT A ZERO IN IT
RET ;
;
; SET THE MSB OF FCB BYTE S2.(FCB + 14)
;
SET14: CALL FCB14 ;(HL) <-- FCB + 14, (A) <-- (FCB + 14)
ORI 80H ;SET THE HIGH BIT
MOV M,A ;MOV IT BACK INTO MEMORY
RET ;
;
; COMPARE ((DWORD1)) TO (BLCTR1)
;
; FLAGS SET ONLY, NUMERICAL RESULT NOT STORED
; ZFLAG SET IF THEY ARE EQUAL
; CFLAG SET IF ((DWORD1)) > (BLCTR1)
;
FLB1D1: LHLD BLCTR1 ;BLOCK COUNTER #1
XCHG ;
LHLD DWORD1 ;
MOV A,E ;(BLCTR1)-((DWORD1))
SUB M ;
INX H ;
MOV A,D ;
SBB M ;
RET ;
;
; IF ((DWORD1)) > (BLCTR1) THEN RETURN UNCHANGED
; ELSE ((DWORD1)) <-- (BLCTR1) + 1
;
SWB1D1: CALL FLB1D1 ;
RC ;
INX D ;
MOV M,D ;
DCX H ;
MOV M,E ;
RET ;
;
; SUBTRACT (HL) FROM (DE)
; RESULT RETURNED IN (HL)
;
DEMIHL: MOV A,E ;(HL) <-- (DE) - (HL)
SUB L ;
MOV L,A ;
MOV A,D ;
SBB H ;
MOV H,A ;
RET ;
;
; CHECK THE DIRECTORY CHECKSUM STORED IN
; CURRENT DISK PARAMETER AREA WITH
; CHECKSUM COMPUTED FROM DIRECTORY OF
; DISK MOUNTED IN CURRENT DRIVE
;
; IF CHECKSUMS DON'T MATCH, THE DISK IS
; SET TO READ ONLY STATUS
;
CHKCRC: MVI C,0FFH ;
CHKCR1: LHLD BLCTR2 ;BLOCK COUNTER #2
XCHG ;
LHLD CHKSIZ ;NUMBER OF DIRECTORY ENTRIES TO BE CHECKED
CALL DEMIHL ;(HL) <-- (DE) - (HL)
RNC ;
PUSH B ;
CALL CHKSUM ;CRC OF 128 BYTES POINTED TO BY (DIRBPT)
LHLD DIRCRC ;DIRECTORY BUFFER POINTER
XCHG ;
LHLD BLCTR2 ;BLOCK COUNTER #2
DAD D ;
POP B ;
INR C ;
JZ CHKCR2 ;
CMP M ;
RZ ;
CALL FLB1D1 ;
RNC ;
CALL COM28 ;* WRITE PROTECT DISK
RET ;
;
CHKCR2: MOV M,A ;
RET ;
;
; DIRECTORY SECTOR WRITE
;
; DMA ADDRESS IS SET TO (DIRBPT)
; SECTOR IS WRITEN
; DMA ADDRESS IS SET BACK TO (CURDMA)
;
; (A)= 01 IS PASSED TO BIOS TO INDICATE THAT THIS
; IS A DIRECTORY WRITE OPERATION
;
DIRWRT: CALL CHKCRC ;COMPARE CHECKSUMS BEFORE WRITING
CALL DIRDMA ;SET DMA FOR DIRECTORY READ/WRITE
MVI C,01H ;TELL BIOS THAT THIS IS A DIR WRITE
CALL WRSECT ;
JMP DIRD1 ;
;
; DIRECTORY SECTOR READ
;
; DMA ADDRESS IS SET TO (DIRBPT)
; THE SECTOR IS READ, AND
; DMA ADDRESS IS SET BACK TO (CURDMA)
;
; THIS PROCEDURE AVOIDS OVERWRITING DATA AREAS
; BY THE DIRECTORY OPERATIONS A OCCURED IN CP/M 1.4
; DURING 'SAVE' OPERATIONS
;
DIREAD: CALL DIRDMA ;SET DMA FOR DIRECTORY READ/WRITE
CALL RDSECT ;
DIRD1: LXI H,CURDMA ;
JMP DIRDM1 ;
;
; SET DMA ADDRES FOR DIRECTORY READ/WRITE
;
DIRDMA: LXI H,DIRBPT ;GET DIRECTORY BUFFER POINTER
DIRDM1: MOV C,M ;(BC) <-- ((HL))
INX H ;
MOV B,M ;
JMP SETDMA ;BIOS CALL/SET DMA
;
; MOVE SECTOR FROM ((DIRBPT)) TO ((CURDMA))
;
;Z80 USERS MIGHT CHANGE THIS TO SOMETHING LIKE:
;
;MOVSEC:LD HL,(CURDMA)
; EX DE,HL
; LD HL,(DIRBPT)
; LD BC,SECLEN
; LDIR
; RET
;
MOVSEC: LHLD DIRBPT ;SOURCE
XCHG ;
LHLD CURDMA ;DESTINATION
MVI C,SECLEN ;COUNT
JMP BLKMOV ;
;
; CHECK THE CONTENTS OF BLOCK COUNTER #1
;
; RETURNS WITH (A)= LOW ORDER BYTE OF (BLCTR1)+1
; IF THE LOW ORDER BYTE = THE HIGH ORDER BYTE
; ELSE RETURNS WITH LOW ORDER BYTE
; OF (BLCTR1) IN (A).
; ZFLAG ALWAYS RESET UNLESS (BLCTR1)= -1
; COME TO THINK ABOUT IT, THIS IS REALLY A CHECK OF
; WHETHER (BLCTR1)= -1. IN THAT CASE WHY THE HELL IS
; THIS THING NOT WRITTEN AS FOLLOWS:
;
;CHKBC1:LHLD BLCTR1 ;
; INX H ;MAKE -1 INTO 00
; MOV A,L ;
; ORA H ;
; RET ;
;
; THIS SUBROUTINE IS ALWAYS CALLED IMMEDIATELY AFTER
; CALLS TO SERCHF, SERCHN, MAKEF AND CLOSEF.
;
CHKBC1: LXI H,BLCTR1 ;
MOV A,M ;
INX H ;
CMP M ;
RNZ ;NOT EQUAL- RETURN W/ LOW ORDER BYTE
INR A ;EQUAL-- BUMP LOW ORDER BYTE
RET ;
;
; SET THE CONTENTS OF BLOCK COUNTER #1 TO -1
;
SETBC1: LXI H,-1 ;
SHLD BLCTR1 ;BLOCK COUNTER #1
RET ;
;
; COMPARE THE CONTENTS OF BLOCK COUNTER #1 AGAINST
; THE MAXIMUM DIRECTORY CAPACITY OF THE DISK.
;
; SET (BLCTR1) <-- -1 IF DIRECTORY CAPACITY IS EXCEEDED
; ELSE READ DIRECTORY SECTOR AND CHECK DIRECTORY
; CHECKSUM.
;
; NOTE:
; Lines marked ** should be deleted and
; replaced with:
; JC SETBC1 ;ERROR EXIT
;
GETDIR: LHLD DIRMAX ;MAX NUMBER OF ENTRIES IN DIRECTORY
XCHG ;
LHLD BLCTR1 ;BLOCK COUNTER #1
INX H ;
SHLD BLCTR1 ;BLOCK COUNTER #1
CALL DEMIHL ;(HL) <-- (DE) - (HL)
JNC GETDI1 ;**
JMP SETBC1 ;** SET (BLCTR1) <-- -1
; ERROR EXIT
;
GETDI1: LDA BLCTR1 ;BLOCK COUNTER #1
ANI 03H ;
MVI B,05H ;
GETDI2: ADD A ;
DCR B ;
JNZ GETDI2 ;
STA DIROFF ;DIRECTORY OFFSET
ORA A ;
RNZ ;
PUSH B ;
CALL TRKSEC ;SET TRACK AND SECTOR
CALL DIREAD ;READ DIRECTORY SECTOR FROM DISK
POP B ;
JMP CHKCR1 ;OK EXIT
;
; GET STATUS OF ALLOCATION OF BLOCK IN (A)
;
; ENTRY PARAMETER:(BC) CONTAINS DISK BLOCK #
; EXIT PARAMETER: (A)... STATUS OF 1K BLOCK
; (D)... BIT NUMBER
; (HL).. POINTER TO BYTE IN ALLOCAION
; MAP
;
; THIS SUBROUTINE IS CALLED:
; TWICE BY WRSUB
; ONCE BY BLKMP5
; REPLACEMENT CODE:
;GETALC:MOV A,C ;
; ANI 07H ;
; INR A ;
; MOV E,A ;
; MOV D,A ;BIT COUNTER TO (D) & (E)
; MOV L,C ;
; MOV H,B ;
; MVI C,03H ;
; PUSH D ;
; CALL SHRHLC ;(HL) <-- ENTRY PARAMETER/8
; XCHG ;
; LHLD DALLOC ;
; DAD D ;POINT TO BYTE IN ALLOCATION BLOCK
; POP D ;RESTORE COUNTERS
; MOV A,M ;GET BIT MAP BYTE
;GETAL1:RLC ;ROTATE UNTIL DESIRED BIT
; DCR E ; IS LSB OF (A)
; JNZ GETAL1 ;
; RET ;
;
GETALC: MOV A,C ;
ANI 07H ;
INR A ;
MOV E,A ;BIT NUMBER INTO (E) & (D)
MOV D,A ;
MOV A,C ;
RRC ;/2
RRC ; /4
RRC ; /8
ANI 1FH ;
MOV C,A ;
MOV A,B ;
ADD A ;*2
ADD A ; *4
ADD A ; *8
ADD A ; *16
ADD A ; *32
ORA C ;
MOV C,A ;
MOV A,B ;
RRC ;/2
RRC ; /4
RRC ; /8
ANI 1FH ;
MOV B,A ;(BC) <-- (BC)/8= BYTE NUMBER
; IN ALLOCATION BLOCK
LHLD DALLOC ;
DAD B ;(HL) <-- POINTER TO ALLOC BYTE
MOV A,M ;ALLOCATION BYTE
GETAL1: RLC ;ROTATE BIT INTO LSB (A)
DCR E ;
JNZ GETAL1 ;
RET ;
;
; SET OR CLEAR 1K BLOCK FROM THE ALLOCATION MAP
;
; ENTRY PARAMETER: (BC)= DISK BLOCK NUMBER
; 00 OR 01 IN (E)
; IF (E)= 00 THEN THE BLOCK IS CLEARED
; IF (E)= 01 THEN THE BLOCK IS MARKED "IN USE"
;
BLKMP5: PUSH D ;SAVE ENTRY PARAMETER
CALL GETALC ;GET STATUS OF ALLOCATION BLOCK IN LSB OF (A)
ANI 0FEH ;MASK OFF LSB ::= CLEAR ALLOCATION
POP B ;GET BACK ENTRY PARAMETER TO (BC)
ORA C ;.OR. LSB WITH ENTRY PARAMETER
BLKMP6: RRC ;ROTATE (A) PER COUNT IN (D)
DCR D ;
JNZ BLKMP6 ;
;
MOV M,A ;STORE BYTE BACK INTO ALLOCATION BLOCK
RET ;
;
; SET OR CLEAR THE BIT CORRECPONDING TO THE
; 1K DISK BLOCK NUMBER IN (HL).
;
; ENTRY PARAMETER: (HL)=DISK 1K BLOCK NUMBER
; (C)= 0 WHEN CALLED BY DELETE
; (C)= 1 WHEN CALLED BY LOGIN
; PASSES ENTRY PARAMETER TO BLKMP5 IN (E)
; IF PARAMETER IS 1, THEN THE 1K BLOCK IS MARKED AS
; AS BEING IN USE.
; IF PARAMETER IS 0, THEN THE 1K BLOCK IS CLEARED AND
; CAN BE REALLOCATED.
;
BLKMAP: CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
LXI D,16 ;
DAD D ;POINT TO START OF BLOCK NUMBERS
PUSH B ;SAVE ENTRY PARAMETER
MVI C,11H ;COUNTER 16 BYTES + 1
BLKMP1: POP D ;
DCR C ;
RZ ;EXIT WHEN LAST BLOCK IS CHECKED
PUSH D ;
LDA BIGDSK ;8" SD: 0FFH, LARGE CAP DISK: 00H
ORA A ;
JZ BLKMP2 ;
;
; CODE FOR 8" SD
;
PUSH B ;
PUSH H ;
MOV C,M ;
MVI B,00H ;
JMP BLKMP3 ;
;
; CODE FOR LARGE DISK
;
BLKMP2: DCR C ;
PUSH B ;
MOV C,M ;
INX H ;
MOV B,M ;
PUSH H ;
;
; RESUME COMMON CODE
;
; IF (BC) <> 0000H AND (HL) >= (BC)\
; THEN UPDATE ALLOCATION MAP
;
BLKMP3: MOV A,C ;
ORA B ;
JZ BLKMP4 ;
LHLD DSKSIZ ;DISK SIZE, # OF 1K BLOCKS -1
MOV A,L ;
SUB C ;
MOV A,H ;
SBB B ;(HL) - (BC)
CNC BLKMP5 ;UPDATE ALLOCATION MAP
BLKMP4: POP H ;
INX H ;POINT TO NEXT BLOCK
POP B ;RESTORE INPUT PARAMETER
JMP BLKMP1 ;LOOP
;
; SECOND HALF OF DISK LOG-IN PROCEDURES
;
; THERE IS NO REASON WHY THIS CANNOT BE MOVED
; DOWN TO THE END OF LOGIN INSTEAD OF HAVING
; TO BREAK THINGS WITH A JUMP UP TO THIS
; LOCATION. PERHAPS DIGITAL RESEARCH THINKS
; THAT THE PROGRAM COUNTER NEEDS EXCERCIZE?
;
; NOTE:
; THE FOLLOWING FANDANGO OF COMPUTING THE
; NUMBER OF BYTES IN THE ALLOCATION BLOCK
; COULD BE AVOIDED BY MERELY PICKING UP
; THE VALUE DIRECTLY AS FOLLOWS:
;
;LOGIN1:LHLD ALLOC0 ;
; MOV B,H ;
; MOV C,L ;
; LHLD DALLOC ;
;LOGIN2:MVI M,00H........
;
LOG1N1: LHLD DSKSIZ ;DISK SIZE, # OF 1K BLOCKS -1
MVI C,03H ;DIVIDE THE DISK SIZE BY 8
CALL SHRHLC ;SHIFT (HL) RIGHT PER COUNT IN (C)
INX H ;ADD 1
MOV B,H ;PUT THE NUMBER OF ALLOCATION BYTES
MOV C,L ; INTO (BC)
LHLD DALLOC ;POINT TO START OF ALLOCATION BLOCK
LOGIN2: MVI M,00H ;ZERO OUT THE ALLOCATION BLOCK
INX H ;
DCX B ;
MOV A,B ;
ORA C ;
JNZ LOGIN2 ;
;
LHLD ALLOC0 ;SIZE OF ALLOCATION BLOCK
XCHG ;
LHLD DALLOC ;
MOV M,E ;
INX H ;
MOV M,D ;(DALLOC) <-- ((ALLOC0))
CALL SETDIR ;
LHLD DWORD1 ;
MVI M,03H ;
INX H ;
MVI M,00H ;((DWORD1)) <-- 0003H
CALL SETBC1 ;SET (BLCTR1) <-- -1
LOGIN3: MVI C,0FFH ;
CALL GETDIR ;GET DIRECTORY SECTOR
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
MVI A,0E5H ;
CMP M ;CHECK FOR UNUSED DIRECTORY ENTRY
JZ LOGIN3 ;NOT IN USE- GO LOOK FOR ANOTHER
;
; CHECK TO SEE IF FIRST BYTE OF FCB MATCHES
; THE CURRENT USER NUMBER.
;
LDA USERNO ;
CMP M ;
JNZ LOGIN4 ;NO MATCH- SKIP IT
INX H ;MATCH- CHECK TO SEE IF THIS IS SOME
MOV A,M ; SORT OF TEMPORARY FILE OF THE
SUI '$' ; $$$.EXT VARIETY
JNZ LOGIN4 ; NO MATCH- JUST SKIP
DCR A ;MATCH- SO MAKE RETURN PARAMETER= 0FFH
STA RETPAR ;RETURN PARAMETER
LOGIN4: MVI C,01H ;
CALL BLKMAP ;
CALL SWB1D1 ;
JMP LOGIN3 ;LOOP
;
; PICK UP THE FLAG SET BY SEARCH OPERATIONS
; THEN VAMOOSE OUT OF BDOS
;
EXIT3: LDA SRCHFL ;POINTER SET BY SERCHF FOR USE BY SERCHN
JMP EXIT1 ;
;
; SUBROUTINE CALLED BY SEARCH WHEN COMPARING
; BYTE 12. THIS HAS SOMETHING TO DO WITH THE
; EXTENT NUMBER BYTE, BUT EXACT USE NOT
; DETERMINED YET. (NLMASK)* ::= .NOT.(NLMASK)
;
; (A) <-- ((A).AND.(NLMASK)* - (C).AND.(NLMASK)*).AND.1FH
;
SERCH7: PUSH B ;
PUSH PSW ;
LDA NLMASK ;NULL BLOCK MASK
CMA ;
MOV B,A ;
MOV A,C ;
ANA B ;
MOV C,A ;
POP PSW ;
ANA B ;
SUB C ;
ANI 1FH ;
POP B ;
RET ;
;
; SEARCH FOR OCCURENCE OF FILE NAME IN DIRECTORY
;
; SERCHF IS INITIAL ENTRY POINT WHICH LEAVES
; FCB VECTOR FOR USE BY SUBSEQUENT SEARCHES
; WHICH ENTER BY WAY OF SERCHN. NO OTHER BDOS
; CALLS WHICH MAKE USE OF SRCHFP BETWEEN THE
; INTIAL CALL TO SERCHF AND CALLS TO SERCHN ARE
; ARE ALLOWED OR ELSE RATHER STRANGE THINGS MAY HAPPEN.
; REMEMBER THAT BDOS IS NOT DESIGNED FOR RECURSIVE CALLS
; AND STORED VALUES ARE OVERWRITTEN INSTEAD OF BEING
; PUSHED UP ONTO A LOCAL STACK.
;
; SERCHF INITIATES (SRCHFL) TO 0FFH.
; A SUCCESSFUL MATCH CLEARS IT TO 00
;
; ENTRY PARAMETER: (C)= NUMBER OF BYTES TO BE MATCHED
; THIS COUNT IS STORED IN (SRCHCT)
; FOR SUBSEQUENT CALLS TO SERCHN
;
SERCHF: MVI A,0FFH ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
STA SRCHFL ;POINTER SET BY SERCHF FOR USE BY SERCHN
LXI H,SRCHCT ;SEARCH BYTE COUNTER
MOV M,C ;
LHLD ENTPAR ;ENTRY PARAMETER
SHLD SRCHFP ;SEARCH FCB POINTER, SET BY SERCHF
CALL SETBC1 ;SET (BLCTR1) <-- -1
CALL SETDIR ;
;
; ENTRY POINT FOR SUBSEQUENT SEARCHES
;
SERCHN: MVI C,00H ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
CALL GETDIR ;GET DIRECTORY SECTOR
CALL CHKBC1 ;
JZ SERCH6 ;
LHLD SRCHFP ;SEARCH FCB POINTER, SET BY SERCHF
XCHG ;
LDAX D ;
CPI 0E5H ;IS THIS DIRECTORY BLOCK IN USE?
JZ SERCH1 ;NO-
PUSH D ;
CALL FLB1D1 ;
POP D ;
JNC SERCH6 ;
SERCH1: CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
LDA SRCHCT ;NUMBER OF BYTES TO BE COMPARED
MOV C,A ;
MVI B,00H ;COUNTER FOR BYTE BEING COMPARED
SERCH2: MOV A,C ;
ORA A ;CHECK THE COUNT
JZ SERCH5 ;END OF THE MATCH- EXIT TRIUMPHANTLY
LDAX D ;
CPI '?' ;WILDCARD MATCH
JZ SERCH4 ;
MOV A,B ;
CPI 0DH ;ARE WE AT BYTE 13?
JZ SERCH4 ;SKIP- WE DON'T HAVE TO MATCH BYTE 13
CPI 0CH ;ARE WE AT BYTE 12?
LDAX D ;
JZ SERCH3 ;
SUB M ;COMPARE FCB BYTE TO DIR ENTRY BYTE W/
;MSB MASKED. THIS IS SO THAT SYSTEM
;AND R/O FILENAMES CAN BE MATCHED
ANI 7FH ;
JNZ SERCHN ;NO MATCH- GET ANOTHER DIRECTORY ENTRY
JMP SERCH4 ;GOT A MATCH GOING, GO TO NEXT BYTE
;
; WE COME HERE ON BYTE 12 (EXTENT BYTE)
;
SERCH3: PUSH B ;
MOV C,M ;
CALL SERCH7 ;
POP B ;
JNZ SERCHN ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
;
; WE HAVE A MATCH GOING, BUMP THE COUNTERS & POINTERS
; FOR ANOTHER TURN AROUND THE LOOP
;
SERCH4: INX D ;INCREMENT POINTERS
INX H ;
INR B ;
DCR C ;DECREMENT LOOP COUNT
JMP SERCH2 ;LOOP
;
; FILE NAME FOUND EXIT
;
; LEAVE WITH (RETPAR) SET TO THE DIRECTORY OFFSET
; NUMBER. I.E. 0, 1, 2 OR 3 THAT MARKS THE DIRECTORY
; ENTRY IN (DIRBPT) THAT MATCHED FCB.
; (SRCHFL) CLEARED IF WAS NOT ALREADY DONE SO IN A
; PREVIOUS PASS. CODE MARKED '*' COULD BE REPLACED
; BY:
; XRA A ;
; STA SRCHFL ;
; RET ;
;
SERCH5: LDA BLCTR1 ;BLOCK COUNTER #1
ANI 03H ;
STA RETPAR ;RETURN PARAMETER
LXI H,SRCHFL ;*
MOV A,M ;*GET (SRCHFL) IN (A)
RAL ;*WAS IT PREVIOUSLY CLEARED?
RNC ;*YES- EXIT
XRA A ;*NO- SO CLEAR IT NOW
MOV M,A ;*
RET ;*
;
; FILE NAME NOT FOUND EXIT
;
; SET (BLKCTR)= 0FFFFH AND (RETVAL)= 0FFH
; TO TELL THE WORLD THAT NO MATCH WAS FOUND
;
SERCH6: CALL SETBC1 ;SET (BLCTR1) <-- -1
MVI A,0FFH ;
JMP EXIT1 ;(RETVAL) <-- (A) AND RETURN
;
; DELETE FILE FROM DIRECTORY
;
; THE FIRST 12 CHARACTERS OF THE FILENAME.TYP ARE
; COMPARED TO THE DIRECTORY ENTRIES, AND IF A MATCH
; IS FOUND, THE FIRST BYTE OF THE DIRECTORY ENTRY
; IS CHANEG TO 0E5H. THE DATA IS ON THE DISK AND
; CAN BE RECOVERED BY SUCH UTILITIES AS UNERASE OR
; SPAT.
;
DELETE: CALL INTRRO ;INTEROGATE CURRENT R/O STATUS
MVI C,0CH ;12 CHARACTER MATCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
DELET1: CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;EXIT WHEN THERE IS NO FURTHER MATCH
CALL CHKRO ;CHECK CURRENT R/O STATUS
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
MVI M,0E5H ;INSERT ERASE CHAR IN DIR FCB
MVI C,00H ;
CALL BLKMAP ;
CALL DIRWRT ;WRITE DIRECTORY SECTOR TO DISK
CALL SERCHN ;FIND NEXT OCCURENCE OF FILE NAME
JMP DELET1 ;LOOP BACK FOR ANOTHER TRY
;
; SUBROUTINE CALLED BY WRSEQ
;
; SEARCHES FOR FIRST UNUSED 1K BLOCK IN THE ALLOCATION
; ALLOCATION MAP
;
; ENTRY PARAMETERS:(BC) CURRENT BLOCK NUMBER OR 0000H
; (SEE NOTE BELOW)
; EXIT PARAMETERS: (HL) NUMBER OF NEXT FREE BLOCK OR
; 0000H IF NO BLOCK AVAILABLE
;
; NOTE:
; SEARCH STARTS AT BLOCK 0000H FOR FIRST ALLOC-
; ATION FOR A NEW DIRECTORY EXTENT, OR FROM THE
; CURRENT BLOCK NUMBER FOR SUBSEQUENT ALLOCATIONS
; THIS SAVES TIME SINCE IT ASSUMES THAT ALL
; BLOCKS UP TO THE CURRENT ONE HAVE BEEN USED.
; THIS MAY CAUSE AN 'OUT OF DISK SPACE' ERROR
; IF OTHER FILES ARE BEING DELETED WHILE THIS
; ONE IS BEING WRITTEN. A REMOTE, BUT REAL,
; POSSIBILITY.
;
WRSUB: MOV D,B ;
MOV E,C ;(DE) <-- (BC)
WRSUB1: MOV A,C ;
ORA B ;
JZ WRSUB2 ;
DCX B ;
PUSH D ;
PUSH B ;
CALL GETALC ;GET STATUS OF ALLOCATION BLOCK IN LSB OF (A)
RAR ;
JNC WRSUB3 ;FOUND AN EMPTY ONE
POP B ;
POP D ;
WRSUB2: LHLD DSKSIZ ;DISK SIZE, # OF 1K BLOCKS -1
MOV A,E ;
SUB L ;
MOV A,D ;
SBB H ;
JNC WRSUB4 ;
INX D ;
PUSH B ;
PUSH D ;
MOV B,D ;
MOV C,E ;
CALL GETALC ;GET STATUS OF ALLOCATION BLOCK IN LSB OF (A)
RAR ;
JNC WRSUB3 ;
POP D ;
POP B ;
JMP WRSUB1 ;
;
; BLOCK FOUND
;
WRSUB3: RAL ;ROTATE BACK INTO PLACE
INR A ;MARK IT 'IN USE'
CALL BLKMP6 ;PUT BACK INTO BLOCK MAP
POP H ;(HL) <-- BLOCK NUMBER
POP D ;WASTE STACK
RET ;
;
; NO EMPTY BLOCKS
;
WRSUB4: MOV A,C ;
ORA B ;
JNZ WRSUB1 ;
LXI H,0000H ;
RET ;
;
; SUBROUTINE CALLED BY MAKEF
;
; MOVES 32 BYTES FROM FILE CONTROL BLOCK TO
; DIRECTORY ENTRY THEN WRITES DIRECTORY SECTOR
; TO DISK.
;
; ALSO CALLED THROUGH SECONDARY ENTRY POINT:
;
; (C)= 16, (E)= 12 WHEN CALLED BY RENAME
; (C)= 00, (E)= 12 WHEN CALLED BY ATTRIB
;
MAKESR: MVI C,00H ;
MVI E,32 ;DIRECTORY ENTRY IS 32 BYTES
;
; SECONDARY ENTRY POINT
; (C)= OFFSET, (E)= BYTE COUNTER
;
MAKES1: PUSH D ;SAVE COUNTER
MVI B,00H ;
LHLD ENTPAR ;ENTRY PARAMETER
DAD B ; ADD OFFSET
XCHG ; MOVE TO (DE)
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
POP B ;
CALL BLKMOV ;MOVE FILENAME.EXT INTO DIR BUFFER
MAKES2: CALL TRKSEC ;SET TRACK AND SECTOR
JMP DIRWRT ;WRITE DIRECTORY BUFFER TO DISK
;
; RENAME FILE
;
; ON ENTRY THE CONTENTS OF (DE) POINTS TO A 32
; BYTE BLOCK WHERE THE FIRST 16 BYTES ARE THE
; OLD FILENAME.TYP AND THE SECOND 16 ARE THE
; NEW FILENAME.EXT. THIS PIECE OF CODE MAKES A
; 12 BYTE SEARCH TO MATCH THE OLD FILENAME.TYP
; WITH ENTRIES IN THE DIRECTORY. WHEN A MATCH
; IS MADE THE NEW FILENAME.TYP IS INSERTED INTO
; THE DIRECTORY SECTOR AND THE SECTOR WRITTTEN
; BACK ONTO THE DISK.
;
RENAME: CALL INTRRO ;INTEROGATE CURRENT R/O STATUS
MVI C,0CH ;SET UP FOR 12 BYTE SEARCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
LHLD ENTPAR ;ENTRY PARAMETER
MOV A,M ;
LXI D,16 ;
DAD D ;POINT TO NEW FILENAME.TYP
MOV M,A ;
RENAM1: CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;EXIT- NO MATCH
CALL CHKRO ;CHECK CURRENT R/O STATUS
MVI C,10H ;16 BYTE OFFSET
MVI E,0CH ;12 BYTE MOVE
CALL MAKES1 ;MOVE FILENAME.TYP & WRITE DIR TO DISK
CALL SERCHN ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
JMP RENAM1 ;LOOP BACK FOR ANOTHER GO AT IT
;
; SET FILE ATTRIBUTES
;
; THIS PIECE OF CODE IS USED OFFICIALLY TO MAKE
; SYSTEM FILES INVISIBLE TO DIRECTORY OPERATIONS
; BY SETTING MSB OF T1 HIGH AND TO MAKE FILES "READ
; ONLY" BY SETTING MSB OF T2 HIGH. COULD BE USED FOR
; OTHER MISCHIEF.
;
ATTRIB: MVI C,0CH ;12 BYTE SEARCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
ATTRB1: CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;RETURN WHEN FILENAME.EXT CANNOT BE
;FOUND, EITHER ON THE FIRST PASS OR
;SUBSEQUENT PASSES
MVI C,00H ;
MVI E,0CH ;MOVE 12 BYTES INTO DIRECTORY BUFFER
CALL MAKES1 ;REPLACING CURRENT NAME & REWRITING DIR
CALL SERCHN ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
JMP ATTRB1 ;LOOP
;
; OPEN A FILE FOR READING OR WRITING
;
OPENF: MVI C,0FH ;15 BYTES SEARCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;--ERROR EXIT FILE NOT FOUND
OPENF1: CALL FCB12 ; (HL) <-- FCB + 12 , EXT BYTE PTR
MOV A,M ;
PUSH PSW ;
PUSH H ;
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
XCHG ;
LHLD ENTPAR ;ENTRY PARAMETER
MVI C,32 ;SIZE OF DIRECTORY BLOCK
PUSH D ;
CALL BLKMOV ;MOVE DIRECTORY BLOCK INTO FCB
CALL SET14 ;SET MSB OF BYTE 14 TO SAY FILE OPEN
POP D ;
LXI H,12 ;
DAD D ;
MOV C,M ;(C) <-- (DIRECTORY ENTRYI+12)= EXTENT
LXI H,15 ;
DAD D ;
MOV B,M ;(B) <-- (DIRECTORY ENTRY+15)= RECORD CTR
POP H ;
POP PSW ;(A) <-- (FCB + 12)
MOV M,A ;
MOV A,C ;
;
; IF (FCB+12)=(DIR ENTRY+12) THEN (FCB+15) <-- (DIR ENTRY+15)
; IF (FCB+12)>(DIR ENTRY+12) THEN (FCB+15) <-- 80H
; IF (FCB+12)<(DIR ENTRY+12) THEN (FCB+15) <-- 00H
;
CMP M ;
MOV A,B ;
JZ OPENF2 ;
MVI A,00H ;
JC OPENF2 ;
MVI A,80H ;
OPENF2: LHLD ENTPAR ;ENTRY PARAMETER
LXI D,15 ;
DAD D ;
MOV M,A ;
RET ;
;
; SUBROUTINE CALLED WHILE CLOSING A BIG DISK
;
; IF ((HL)) = 0 THEN ((HL)) <-- ((DE))
;
CLOSE8: MOV A,M ;IS ((HL)) = 0?
INX H ;
ORA M ;
DCX H ;
RNZ ;NO- RETURN AS IS
LDAX D ;((HL)) IS 0, REPLACE WITH ((DE))
MOV M,A ;
INX D ;
INX H ;
LDAX D ;
MOV M,A ;
DCX D ;
DCX H ;
RET ;
;
; CLOSE DISK FILE AFTER READING OR WRITING
;
CLOSEF: XRA A ;CLOSE FILE
STA RETPAR ;RETURN PARAMETER
STA BLCTR1 ;BLOCK COUNTER #1
STA BLCTR1+1 ;BLOCK COUNTER #1
CALL GETRO ;GET READ ONLY STATUS OF CURRENT DISK
RNZ ;
CALL FCB14 ;(HL) <-- FCB + 14, (A) <-- (FCB + 14)
ANI 80H ;CHECK MSB OF (FCB+14)
RNZ ;RETURN IF MSB SET
;
MVI C,0FH ;15 BYTE SEARCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;
LXI B,16 ;
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
DAD B ;
XCHG ;
LHLD ENTPAR ;ENTRY PARAMETER
DAD B ;
;
; (DE) <-- FCB + 16
; (HL) <-- (DIRBPT) + (DIROFF) + 16
; (C) <-- COUNTER
;
; CHECK TO SEE IF THE BLOCK NUMBERS IN ((HL)) OR ((DE))
; ARE EQUAL TO ZERO. IF ONE IS ZERO, IT IS SET TO THE
; VALUE OF THE OTHER. IF THE BLOCK NUMBERS ARE NOT
; EQUAL AFTER THIS, THERE IS AN ERROR.
;
MVI C,10H ;
CLOSE1: LDA BIGDSK ;8" SD: 0FFH, LARGE CAP DISK: 00H
ORA A ;
JZ CLOSE4 ;
;
; CODE FOR 8" SD DISK
;
MOV A,M ;
ORA A ;
LDAX D ;
JNZ CLOSE2 ;
MOV M,A ;
CLOSE2: ORA A ;
JNZ CLOSE3 ;
MOV A,M ;
STAX D ;
CLOSE3: CMP M ;
JNZ CLOSE7 ;ERROR
JMP CLOSE5 ;OK
;
; CODE FOR DISK > 255K
; EQUIVALENT TO CODE ABOVE
;
CLOSE4: CALL CLOSE8 ;
XCHG ;
CALL CLOSE8 ;
XCHG ;
LDAX D ;
CMP M ;
JNZ CLOSE7 ;ERROR
INX D ;
INX H ;
LDAX D ;
CMP M ;
JNZ CLOSE7 ;
DCR C ;
;
; RESUME CODE COMMON TO ALL SIZES
;
CLOSE5: INX D ;
INX H ;
DCR C ;
JNZ CLOSE1 ;
;
LXI B,-20 ;
DAD B ;
XCHG ;
DAD B ;
; (DE)= FCB+12
; (HL)= DIR ENTRY+12
LDAX D ;
CMP M ;
; IF (DIR ENTRY+12) <= (FCB+12) THEN (DIR ENTRY+15) <-- (FCB+15)
JC CLOSE6 ;
MOV M,A ;
LXI B,03 ;
DAD B ;
XCHG ;
DAD B ;
MOV A,M ;
STAX D ;
;
; OK EXIT: DIRECTORY WRITTEN TO DISK
;
CLOSE6: MVI A,0FFH ;
STA MAKEFL ;MAKE-FILE FLAG
JMP MAKES2 ;EXIT VIA SET TRACK & SECTOR
;AND WRITE DIRECTORY TO DISK
;
; ERROR EXIT: RETURN PARAMETER SET TO 0FFH
; MEANING THAT FILE CANNOT BE CLOSED
;
CLOSE7: LXI H,RETPAR ;RETURN PARAMETER <-- 0FFH
DCR M ;
RET ;
;
; MAKE A NEW FILE ENTRY IN THE DIRECTORY
;
MAKEF: CALL INTRRO ;INTEROGATE CURRENT R/O STATUS
LHLD ENTPAR ;GET ENTRY PARAMETER
PUSH H ;STASH IT
LXI H,DMYFCB ;DUMMY FCB 0E5H
SHLD ENTPAR ;ENTRY PARAMETER
;
; SEARCH DISK DIRECTORY FOR AN ENTRY THAT
; STARTS WITH 0E5H. I.E. AN UNUSED SLOT
;
MVI C,01H ;1 BYTE MATCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
POP H ;
SHLD ENTPAR ;RESTORE ENTRY PARAMETER
RZ ;ERROR EXIT- COULD NOT FIND EMPTY SLOT
;
XCHG ;
LXI H,15 ;POINT TO FCB + 15
DAD D ;
MVI C,11H ;17 BYTE COUNT
XRA A ;(A) <-- 0
MAKEF1: MOV M,A ;ZERO OUT FCB BYTES 15 THROUGH 32
INX H ; ^
DCR C ; |
JNZ MAKEF1 ;---------------|
;
LXI H,13 ;ZERO OUT FCB BYTE 13
DAD D ;
MOV M,A ;
CALL SWB1D1 ;
CALL MAKESR ;MOVE FCB TO DIRECTORY BUFFER & WRITE
;DIRECTORY BUFFER TO DISK
JMP SET14 ;SET MSB OF FCB+14 & EXIT
;
; OPEN NEXT FILE DIRECTORY EXTENT
;
OPNNXT: XRA A ;
STA MAKEFL ;MAKE-FILE FLAG
CALL CLOSEF ;CLOSE CURRENT EXTENT
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
RZ ;ERROR EXIT...CANNOT CLOSE CURRENT EXT
;
LHLD ENTPAR ;ENTRY PARAMETER
LXI B,12 ;
DAD B ;POINT TO FCB+12 :: EXTENT BYTE
MOV A,M ;
INR A ;INCREMENT EXTENT
ANI 1FH ;
MOV M,A ;
JZ OPNXT1 ; EXTENT > 31
MOV B,A ;
LDA NLMASK ;NULL BLOCK MASK
ANA B ;
LXI H,MAKEFL ;MAKE-FILE FLAG
ANA M ;
JZ OPNXT2 ;
JMP OPNXT3 ;
;
; EXTENT IN BYTE 12 WAS > 31
; INCREMENT 3RD LEVEL COUNTER
; IN LOWER NIBBLE OF BYTE 14
;
OPNXT1: LXI B,02 ;
DAD B ;(HL) <-- FCB + 14
INR M ;
MOV A,M ;
ANI 0FH ;
JZ OPNXT5 ;OVERFLOW ERROR
;
OPNXT2: MVI C,0FH ;15 BYTE MATCH
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
JNZ OPNXT3 ;FILE NAME FOUND
LDA RDWRFL ;READ/WRITE FLAG:: 0FFH= READ/0= WRITE
INR A ;
JZ OPNXT5 ;ERROR EXIT-TRYING TO OPEN NONEXISTENT
;EXTENT FOR READING
;
CALL MAKEF ;MAKE NEW DIRECTORY ENTRY
CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
JZ OPNXT5 ;ERROR EXIT-COULD NOT OPEN NEW EXT
JMP OPNXT4 ;OK
;
OPNXT3: CALL OPENF1 ;OPEN THE EXTENT
OPNXT4: CALL UPDATE ;UPDATE SECTOR COUNTERS
XRA A ;SET OK FLAG
JMP EXIT1 ;STORE IT IN RETURN VALUE & EXIT
;
; ERROR EXIT
;
OPNXT5: CALL EXIT2 ;PUT 01 IN RETURN VALUE
JMP SET14 ;SET MSB OF FCB + 14 & EXIT
;
; READ SECTOR TO MEMORY
;
; THIS TANGLED PIECE OF CODE DOESN'T DO THE
; ACTUAL WRITING, JUST THE SETTING UP OF ALL
; KINDS OF FLAGS AND THINGS
;
; ENTRY POINT FOR SEQUENTIAL READ: RDSEQ
; ENTRY POINT FOR RANDOM READ: RDSEQ1
;
RDSEQ: MVI A,01H ;READ SEQUENTIAL FILE
STA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
;
RDSEQ1: MVI A,0FFH ;
STA RDWRFL ;READ/WRITE FLAG
CALL UPDATE ;UPDATE SECTOR COUNTERS
LDA CURREC ;CURRENT RECORD:: FCB + 32
LXI H,RECCTR ;FILE RECORD COUNTER:: FCB + 15
CMP M ;
JC RDSEQ2 ;
CPI 80H ;
JNZ RDSEQ3 ;
CALL OPNNXT ;
XRA A ;
STA CURREC ;CURRENT RECORD:: FCB + 32
LDA RETPAR ;RETURN PARAMETER
ORA A ;
JNZ RDSEQ3 ;
RDSEQ2: CALL SETSC1 ;
CALL CHKSC1 ;
JZ RDSEQ3 ;
CALL COMSEC ;COMPUTE SECTOR NUMBER
CALL TRSEC1 ;
CALL RDSECT ;
JMP RWEXIT ;
;
RDSEQ3: JMP EXIT2 ;
;
; WRITE SEQUENTIAL SECTOR
;
; ENTRY POINT FOR SEQUENTIAL WRITE: WRSEQ
; ENTRY POINT FOR RANDOM WRITE: WRSEQ1
; SERNFL= 00H FOR RANDOM WRITE (COM34)
; = 02H FOR FILL RANDOM (COM40)
;
WRSEQ: MVI A,01H ;WRITE SEQUENTIAL FILE
STA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
;
WRSEQ1: MVI A,00H ;
STA RDWRFL ;READ/WRITE FLAG
CALL INTRRO ;INTEROGATE CURRENT R/O STATUS
LHLD ENTPAR ;ENTRY PARAMETER
CALL CHKRO1 ;
CALL UPDATE ;UPDATE SECTOR COUNTERS
LDA CURREC ;CURRENT RECORD:: FCB + 32
CPI 80H ;
JNC EXIT2 ;
CALL SETSC1 ;
CALL CHKSC1 ;
MVI C,00H ;
JNZ WRSEQ6 ;
CALL BLPNTR ;
STA BLKOFF ;TEMPORARY STORAGE
LXI B,0000H ;
ORA A ;
JZ WRSEQ2 ;
MOV C,A ;
DCX B ;
CALL GETBLN ;GET BLOCK NUMBER IN (HL)
MOV B,H ;
MOV C,L ;(BC) <-- BLOCK NUMBER
WRSEQ2: CALL WRSUB ;
MOV A,L ;
ORA H ;
JNZ WRSEQ3 ;
MVI A,02H ;#2 ERROR- END OF DISK DATA
JMP EXIT1 ;ERROR EXIT
;
WRSEQ3: SHLD SCNTR1 ;SECTOR COUNTER #1
XCHG ;
LHLD ENTPAR ;ENTRY PARAMETER
LXI B,16 ;
DAD B ;
LDA BIGDSK ;8" SD: 0FFH, LARGE CAP DISK: 00H
ORA A ;
LDA BLKOFF ;TEMPORARY STORAGE
JZ WRSEQ4 ;
;
; CODE FOR 8" S.D. SMALL DISK
;
CALL ADA2HL ;(HL) <-- (HL) + (A)
MOV M,E ;STORE BLOCK NUMBER
JMP WRSEQ5 ;
;
; CODE FOR BIG DISK
;
WRSEQ4: MOV C,A ;
MVI B,00H ;
DAD B ;
DAD B ;POINT TO SLOT
MOV M,E ;
INX H ;
MOV M,D ;STORE BLOCK NUMBER
;
; RESUME CODE COMMON TO ALL DISKS
;
WRSEQ5: MVI C,02H ;
WRSEQ6: LDA RETPAR ;RETURN PARAMETER
ORA A ;
RNZ ;
PUSH B ;
CALL COMSEC ;COMPUTE SECTOR NUMBER
LDA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
DCR A ;CHECK TO SEE IF (SERNFL)= 2
DCR A ;
JNZ WRSEQ9 ;NO-
;
; (SERNFL) IS SET = 2 ONLY BY UNDOCUMENTED COMMAND #40
; THE FOLLOWING CODE WRITES 0'S TO THE DIRECTORY
; SECTOR, THEN WRITES THE SECTOR TO DISK
;
POP B ;
PUSH B ;
MOV A,C ;CHECK TO SEE IF (C)= 2, WHICH IT
;ALWAYS IS, BECAUSE IT WAS SET
;JUST 12 COMMANDS BACK. MORE USELESS
;CODE!
DCR A ;
DCR A ;
JNZ WRSEQ9 ;(THIS WILLNEVER HAPPEN)
PUSH H ;
;
; FILL ((DIRBPT)) WITH 128 0'S
;
LHLD DIRBPT ;DIRECTORY BUFFER POINTER
MOV D,A ;(D) <-- 0
WRSEQ7: MOV M,A ;((HL)) <-- 0
INX H ;
INR D ;
JP WRSEQ7 ;
;
; WRITE BLANKED SECTOR TO DISK
; UNTIL ENTIRE 1K BLOCK HAS BEEN
; WRITTEN.
;
CALL DIRDMA ;SET DMA FOR DIRECTORY READ/WRITE
LHLD SCNTR2 ;SECTOR COUNTER #2
MVI C,02H ;
WRSEQ8: SHLD SCNTR1 ;SECTOR COUNTER #1
PUSH B ;
CALL TRSEC1 ;
POP B ;
CALL WRSECT ;
LHLD SCNTR1 ;SECTOR COUNTER #1
MVI C,00H ;
LDA BLMASK ;DISK BLOCK MASK
MOV B,A ;
ANA L ;
CMP B ;
INX H ;
JNZ WRSEQ8 ;
POP H ;
SHLD SCNTR1 ;SECTOR COUNTER #1
CALL DIRD1 ;GET BACK INITIAL SECTOR OF THE 1K
;BLOCK, AND PREPARE TO WRITE IT
;BACK TO DISK (FOR REASONS UNKNOWN)
;
WRSEQ9: CALL TRSEC1 ;SET UP THE TRACK & SECTOR IN BIOS
POP B ;
PUSH B ;
CALL WRSECT ;DO THE ACTUAL WRITING OF THE SECTOR
POP B ;
LDA CURREC ;CURRENT RECORD:: FCB + 32
LXI H,RECCTR ;FILE RECORD COUNTER: FCB + 15
CMP M ;CHECK TO SEE IF BEYOND END OF EXTENT
JC WRSE10 ;NOT BEYOND END- SKIP
MOV M,A ;AT OR BEYOND-
INR M ; INCREMENT RECORD COUNTER
MVI C,02H ; ??
;
; THE FOLLOWING 5 BYTES ARE NOT NEEDED; HOWEVER
; THEY MAY BE THERE TO ALLOW CUSTOMIZERS TO INSERT
; SOMETHING WITHOUT A COMPLETE REASSEMBLY.
; Otherwise, your guess is as good as mine.
;
WRSE10: NOP ;A blank-
NOP ; and another blank.
LXI H,FBASE ;Don't know what this is for.
;
PUSH PSW ;
CALL FCB14 ;(HL) <-- FCB + 14, (A) <-- (FCB + 14)
ANI 7FH ;RESET MSB OF FCB + 14
MOV M,A ;
POP PSW ;
CPI 7FH ;HAVE WE JUST WRITTEN THE LAST SECTOR
;IN THE CURRENT EXTENT?
JNZ WRSE12 ;NO-
LDA SERNFL ;LOAD THE SEQUENTIAL/RANDOM I/O FLAG
CPI 01H ;IS THIS A SEQUENTIAL WRITE?
JNZ WRSE12 ;NOPE-
CALL RWEXIT ;YEP- CLOSE OUT THE CURRENT EXTENT
CALL OPNNXT ; AND GO ABOUT MAKING A NEW ONE
LXI H,RETPAR ;RETURN PARAMETER
MOV A,M ;
ORA A ;
JNZ WRSE11 ;
DCR A ;
STA CURREC ;CURRENT RECORD:: FCB + 32
WRSE11: MVI M,00H ;
WRSE12: JMP RWEXIT ;
;
; SET PARAMETERS FOR RANDOM READ OR WRITE
;
; ENTRY PARAMETER: (C)=00H WHEN CALLED BY RDRAND
; (C)=0FFH WHEN CALLED BY WRRAND
; EXIT PARAMETER: (A)=00 AND ZFLAG RESET-- OK
; (RETPAR)<>0 & ZFLAG SET- ERROR
;
; THE ENTRY PARAMETER IS PASSED THROUGH UNUSED,
; AND INSPECTION OF WRSEQ1 AND RDSEQ1 DOES NOT
; REVEAL ANY USE OF THE PARAMETER. THIS MAY BE
; A LEFTOVER FROM CP/M 1.4 WHEN THERE WAS ONE CALL
; FOR READING OR WRITING A SECTOR, WITH THE
; DESIRED ACTION BEING SPECIFIED BY (C).
;
SETRND: XRA A ;
STA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
SETRN1: PUSH B ;
LHLD ENTPAR ;ENTRY PARAMETER
XCHG ;
LXI H,33 ;
DAD D ;
MOV A,M ;
ANI 7FH ;(A) <-- (FCB+32).AND.7FH
PUSH PSW ;
MOV A,M ;
RAL ;CFLAG <-- MSB(FCB+32)
INX H ;
MOV A,M ;
RAL ;LSB(FCB+33) <-- CFLAG
ANI 1FH ;
MOV C,A ;
MOV A,M ;
RAR ;
RAR ;
RAR ;
RAR ;
ANI 0FH ;
MOV B,A ;
POP PSW ;
INX H ;POINT TO FCB+35, OVERFLOW BYTE
MOV L,M ;
INR L ;
DCR L ;SET FLAGS (8080 DOES NOT HAVE BIT OPCODE)
MVI L,06H ;#6 ERROR- SEEK PAST END OF DISK
JNZ SETRN5 ;
LXI H,32 ;
DAD D ;
MOV M,A ;
LXI H,12 ;
DAD D ;
MOV A,C ;
SUB M ;
JNZ SETRN2 ;
LXI H,14 ;
DAD D ;
MOV A,B ;
SUB M ;
ANI 7FH ;
JZ SETRN3 ;
SETRN2: PUSH B ;
PUSH D ;
CALL CLOSEF ;CLOSE FILE
POP D ;
POP B ;
MVI L,03H ;
LDA RETPAR ;RETURN PARAMETER
INR A ;
JZ SETRN4 ;
LXI H,12 ;
DAD D ;
MOV M,C ;
LXI H,14 ;
DAD D ;
MOV M,B ;
CALL OPENF ;OPEN FILE
LDA RETPAR ;RETURN PARAMETER
INR A ;
JNZ SETRN3 ;
POP B ;
PUSH B ;
MVI L,04H ;#4 ERROR- SEEK TO UNWRITTEN EXTENT
INR C ;
JZ SETRN4 ;
CALL MAKEF ;MAKE NEW DIRECTORY ENTRY
MVI L,05H ;#5 ERROR- CANNOT OPEN NEW DIR EXTENT
LDA RETPAR ;RETURN PARAMETER
INR A ;
JZ SETRN4 ;
SETRN3: POP B ;GET BACK ENTRY PARAMETER
XRA A ;CLEAR RETURN PARAMETER
JMP EXIT1 ;OK EXIT
;
SETRN4: PUSH H ;
CALL FCB14 ;(HL) <-- FCB + 14, (A) <-- (FCB + 14)
MVI M,0C0H ;???????
POP H ;
SETRN5: POP B ;GET BACK ENTRY PARAMETER
MOV A,L ;
STA RETPAR ;STORE ERROR # IN RETURN PARAMETER
JMP SET14 ;ERROR EXIT W/ MSB OF (FCB+14) SET
;
; READ RANDOM SECTOR
;
RDRAND: MVI C,0FFH ;SET PARAMETER FOR SETRND (USELESS)
CALL SETRND ;
CZ RDSEQ1 ;IF OK CALL, ELSE DROP THROUGH
RET ;
;
; WRITE RANDOM SECTOR
;
WRRAND: MVI C,00H ;SET PARAMETER FOR SETRND (USELESS)
CALL SETRND ;
CZ WRSEQ1 ;IF OK CALL, ELSE DROP THROUGH
RET ;
;
; COMPUTE ABSOLUTE SECTOR NUMBER FOR FSIZE & COM36
;
;ENTRY PARAMETERS:
; WHEN CALLED BY FSIZE
; (HL)= POINTER TO CURRENT ENTRY IN DIRECTORY
; BUFFER.
; (DE)= 15. OFFSET TO DIRECTORY RECORD COUNTER
;
; WHEN CALLED BY COM36
; (HL)= POINTER TO FCB, I.E. (ENTPAR)
; (DE)= 32. OFFSET TO RANDOM READ/WRITE COUNTER
;
;ON EXIT:
; REGISTERS A,B & C HOLD TRIPLE PRECISION SECTOR
; NUMBER IN THE FOLLOWING FORMAT:
; (C) LOW ORDER BYTE
; (B) HIGH ORDER BYTE
; (A) OVERFLOW
;
; (A) (B) (C) <-- (BYTE14).AND.0FH*2^12+(BYTE12).AND.1FH*2^7+(BYTE32)or(BYTE15)
;
RNDPAR: XCHG ;
DAD D ;
MOV C,M ;
MVI B,00H ;
LXI H,12 ;
DAD D ;
MOV A,M ;
RRC ;
ANI 80H ;
ADD C ;
MOV C,A ;(C) <-- ((HL)+(C))+(BYTE12)SHL7
;LOW ORDER BYTE
MVI A,00H ;
ADC B ;
MOV B,A ;SAVE POSSIBLE CARRY BIT IN (B)
MOV A,M ;
RRC ;
ANI 0FH ;
ADD B ;
MOV B,A ;
LXI H,14 ;
DAD D ;
MOV A,M ;(A) <-- (BYTE14)
ADD A ;*2
ADD A ; *4
ADD A ; *8
ADD A ; *16
PUSH PSW ;SAVE FLAGS FOR POSSIBLE OVERFLOW
ADD B ;
MOV B,A ;(B) <-- (BYTE14)SHL4+(BYTE12).AND.1FHSHR1
;HIGH ORDER BYTE
PUSH PSW ;
POP H ;(L) <-- FLAGS
MOV A,L ;(A) <-- FLAGS
POP H ;(L) <-- FLAGS AGAIN
ORA L ;.OR. THEM TOGETHER
ANI 01H ;MASK OFF ALL BUT CARRY BIT IN
;OVERFLOW BYTE.
RET ;
;
; SET FILE SIZE
;
; SEE NOTES AT HEAD OF BDOS COMMAND #35
;
FSIZE: MVI C,0CH ;COMPUTE FILE SIZE
CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
LHLD ENTPAR ;ENTRY PARAMETER
LXI D,33 ;
DAD D ;
PUSH H ;
MOV M,D ;(FCB+33) <-- 00H
INX H ;
MOV M,D ;(FCB+34) <-- 00H
INX H ;
MOV M,D ;(FCB+35) <-- 00H
FSIZE1: CALL CHKBC1 ;CHECK CONTENTS OF (BLCTR1)
JZ FSIZE3 ;EXIT LOOP- NO FILE NAME MATCH
CALL DIRPTR ;(HL) <-- (DIRBPT) + (DIROFF)
LXI D,15 ;OFFSET TO RECORD COUNTER
CALL RNDPAR ;GET ABSOLUTE SECTOR NUMBER IN (A)(B)(C)
POP H ;
PUSH H ;
;
; IF (A)(B)(C) > (FCB35)(FCB34)(FCB33) THEN \
; (FCB35)(FCB34)(FCB33) <-- (A)(B)(C)
;
MOV E,A ;
MOV A,C ;
SUB M ;
INX H ;
MOV A,B ;
SBB M ;
INX H ;
MOV A,E ;
SBB M ;(A)(B)(C) - (FCB35)(FCB34)(FCB33)
JC FSIZE2 ;
MOV M,E ;(FCB33) <-- LOW ORDER BYTE
DCX H ;
MOV M,B ;(FCB34) <-- HIGH ORDER BYTE
DCX H ;
MOV M,C ;(FCB35) <-- OVERFLOW BYTE
FSIZE2: CALL SERCHN ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
JMP FSIZE1 ;
;
FSIZE3: POP H ;
RET ;
;
; BDOS COMMAND #36....SET RANDOM RECORD LENGTH
;
; THIS PIECE OF CODE AUTOMATICALLY PRODUCES THE
; RANDOM RECORD POSITION OF A FILE THAT HAS BEEN
; READ OR WRITTEN TO UP TO THIS POINT.
;
COM36: LHLD ENTPAR ;ENTRY PARAMETER
LXI D,32 ;OFFSET TO RANDON R/W COUNTER
CALL RNDPAR ;GET ABSOLUTE SECTOR NUMBER OF
;CURRENT SECTOR NUMBER IN (A)(B)(C)
LXI H,33 ;
DAD D ;
MOV M,C ;(FCB33) <-- LOW ORDER BYTE
INX H ;
MOV M,B ;(FCB34) <-- HIGH ORDER BYTE
INX H ;
MOV M,A ;(FCB35) <-- OVERFLOW BYTE
RET ;
;
; HERE WE HAVE THE WAY THAT DISKS ARE LOGGED,
; AND A MISERABLE AND TANGLED BIT OF CODE IT IS.
; WE START HERE, THEN JUMP TO LOGIN1 WHICH THEN
; FINISHES UP THE REST OF THE JOB.
; WHY THE HECK ISN'T THIS THING WRITTEN IN A
; STRAIGHT LINE? ANYBODY FOR STRUCTURED CODE??
;
LOGIN: LHLD LOGVEC ;LOG IN VECTOR
LDA CURDSK ;
MOV C,A ;
CALL SHRHLC ;SHIFT (HL) RIGHT PER COUNT IN (C)
PUSH H ;
XCHG ;
CALL SETDSK ;SET UP DISK PARAMETERS
POP H ;
CZ SELERR ;DISK SELECT ERROR
MOV A,L ;LOG IN BIT IN LSB(A)
RAR ;CHECK TO SEE IF ON MAP
RC ;OK- DISK ALREADY LOGGED IN
LHLD LOGVEC ;LOG IN VECTOR
MOV C,L ;
MOV B,H ;
CALL SETVEC ;NEW DISK- PUT ON THE MAP
SHLD LOGVEC ;LOG IN VECTOR
JMP LOG1N1 ;--SEE COMMENTS AT START--
;
; BDOS COMMAND #14....SELECT DISK DRIVE
;
; NOW IF THIS BLOCK OF CODE WERE TO BE MOVED
; AHEAD OF LOGIN, IT COULD JUST DROP IN WITHOUT
; A JUMP. COUPLED WITH THE COMMENTS ON LOGIN,
; WE CAN SEE WHY THIS CODE IS SO HARD TO FOLLOW.
;
COM14: LDA PARAM1 ;GET THE SELECTED DISK DRIVE NUMBER
LXI H,CURDSK ;
CMP M ;COMPARE TO CURRENT DISK NUMBER
RZ ;RETURN IF NO CHANGE NEEDED
MOV M,A ;ELSE SET (CURDSK) TO NEW DRIVE
JMP LOGIN ; AND GO LOG IT IN
;
; SET UP THE DISK PARAMETERS
;
; ALL BDOS COMMANDS THAT USE THE DISKS MUST
; MAKE A PASS THROUGH THIS SUBROUTINE
;
; NOTE:
; THE DIGITAL RESEARCH DOCUMENTATION DOES
; NOT MENTION WHAT IS DONE WITH THE USER
; NUMBER. WELL HERE IT IS.....
; THE USER NUMBER IS PUT INTO THE FIRST
; BYTE OF THE DIRECTORY ENTRY. USER 0
; IS THEREFORE COMPATIBLE WITH CP/M 1.4
; BUT HIGHER USER NUMBERS ARE NOT.
; TRY CREATING A DUMMY FILE WITH VARIOUS
; USER NUMBERS, THEN INSPECTING THE
; DIRECTORY TRACK WITH SPAT.
; THIS PIECE OF CODE PUTS THE CURRENT
; USER NUMBER INTO THE START OF THE
; FILE CONTROL BLOCK SO THAT A MATCH CAN
; BE MADE DURING DIRECTORY SEARCHES.
;
SETUP: MVI A,0FFH ;SET FLAG TO TELL BDOS2 THAT
STA SETUPF ; THE DISKS HAVE BEEN USED
LHLD ENTPAR ;(HL) <-- ENTRY PARAMETER
MOV A,M ;GET THE DISK NUMBER FROM FCB
ANI 1FH ;DISK NUMBER TO BE IN RANGE OF
;0 TO 1FH. I.E. DRIVES A THROUGH P
DCR A ;
STA PARAM1 ;STORE IT FOR SELDSK
CPI 1EH ;
JNC SETUP1 ;SKIP OVER- ACCESSING LOGGED IN DISK
;
LDA CURDSK ;SAVE CURRENT DISK NUMBER IN
STA LOGDSK ;LOGDSK FOR RESTORING ON EXIT
MOV A,M ;GET DISK NUMBER FROM FCB AGAIN
STA DISKNO ;SAVE IT
;
; THE REASON FOR SETTING THE UPPER 3 BITS OF
; (FCB+12) WITH THE UPPER 3 BITS OF THE DRIVE
; NUMBER BROUGHT IN IN THE ENTRY PARAMETER IS
; NOT DOCUMENTED. THIS MAY BE SOME SORT OF
; PASSWORD SECURITY SYSTEM
;
ANI 0E0H ;KEEP UPPER 3 BITS
MOV M,A ; AND PUT THEM BACK IN FCB
CALL COM14 ;SELECT DISK DRIVE
SETUP1: LDA USERNO ;GET THE USER NUMBER
LHLD ENTPAR ;GET THE ENTRY PARAMETER
;WHICH WAS ALREADY THERE
;ANOTHER EXAMPLE OF REDUNDANCY
ORA M ;COMBINE USER NUMBER W/ (FCB)
MOV M,A ;MOVE INTO FIRST BYTE OF FCB
RET ;
;
; BDOS COMMAND #12....RETURN THE CURRENT CP/M VERSION
;
; THIS REPLACES A RETURN WITH 00 IN CP/M 1.4
; AND EARLIER. THIS IS USED BY CBASIC2 TO
; DETERMINE IF RANDOM READ/WRITE IS POSSIBLE.
;
COM12: MVI A,VER*16+REL ;LOAD VERSION NUMBER
JMP EXIT1 ;MOVE IT TO RETURN PARAMETER & EXIT
;
; BDOS COMMAND #13....RESET DISK SYSTEM
;
COM13: LXI H,0000H ;
SHLD ROWORD ;CLEAR READ ONLY WORD
SHLD LOGVEC ; AND LOG IN VECTOR
XRA A ;CLEAR CURRENT DISK
STA CURDSK ;
LXI H,DDMA ;SET TO DEFAULT DMA ADDRESS
SHLD CURDMA ;
CALL DIRD1 ;
JMP LOGIN ;LOG-IN THE DISK & EXIT
;
; BDOS COMMAND #14....OPEN FILE
;
COM15: CALL ZRFCTR ;ZERO OUT FCB COUNTER
CALL SETUP ;SET UP DISK PARAMETERS
JMP OPENF ;OPEN FILE & EXIT
;
; BDOS COMMAND #14....CLOSE FILE
;
COM16: CALL SETUP ;SET UP DISK PARAMETERS
JMP CLOSEF ;CLOSE FILE & EXIT
;
; BDOS COMMAND #17....SEARCH FOR FIRST OCCURENCE
; OF FILENAME.EXT IN DIRECTORY
;
COM17: MVI C,00H ;
XCHG ;
MOV A,M ;
CPI '?' ;FIRST FCB BYTE A WILDCARD?
JZ COM17A ;
CALL FCB12 ; (HL) <-- FCB + 12 , EXT BYTE PTR
MOV A,M ;
CPI '?' ;EXTENT BYTE A WILDCARD?
CNZ ZRFCTR ;ZERO OUT FCB COUNTER
CALL SETUP ;SET UP DISK PARAMETERS
MVI C,0FH ;15 BYTE SEARCH
COM17A: CALL SERCHF ;SEARCH FOR FIRST OCCURENCE OF FILE NAME
JMP MOVSEC ;SECTOR MOVE ((CURDMA)) <-- ((DIRBPT))
;
; BDOS COMMAND #18....SEARCH FOR NEXT OCCURERENCE
; OF FILENAME.EXT IN DIRECTORY.
;
; PICKS UP POINTER TO FILE CONTROL BLOCK LEFT BY
; THE FIRST SEARCH. IF THERE HAS BEEN A USE OF
; THE DIRECTORY SEARCH BETWEEN THE FIRST CALL AND
; THIS ONE, WATCH OUT...CP/M IS NOT REENTRANT SO
; YOU MAY NOT HAVE WHAT YOU THINK YOU HAVE.
; OF PARTICULAR DANGER ARE READ AND WRITE OPERATIONS
; TO ANOTHER FILE BECAUSE THEY MAY HAVE TO OPEN UP
; NEW DIRECTORY EXTENTS WITHOUT YOUR KNOWING ABOUT IT.
;
COM18: LHLD SRCHFP ;SEARCH FCB POINTER, SET BY SERCHF
SHLD ENTPAR ;ENTRY PARAMETER
CALL SETUP ;
CALL SERCHN ;SEARCH FOR NEXT OCCURENCE OF FILE NAME
JMP MOVSEC ;SECTOR MOVE ((CURDMA)) <-- ((DIRBPT))
;
; BDOS COMMAND #19....DELETE A FILE FROM THE DISK
;
COM19: CALL SETUP ;SET UP DISK PARAMETERS
CALL DELETE ;GO DELETE THE FILE
JMP EXIT3 ;MOVE SEARCH RESULT TO RETURN
;VALUE & EXIT
;
; BDOS COMMAND #20....READ SECTOR FROM DISK TO MEMORY
;
COM20: CALL SETUP ;SET UP DISK PARAMETERS
JMP RDSEQ ;READ SEQUENTIAL FILE & EXIT
;
; BDOS COMMAND #21....WRITE SECTOR FROM MEMORY TO DISK
;
COM21: CALL SETUP ;SET UP DISK PARAMETERS
JMP WRSEQ ;WRITE SEQUENTIAL FILE & EXIT
;
; BDOS COMMAND #22....CREATE A NEW ENTRY IN DIRECTORY
;
COM22: CALL ZRFCTR ;ZERO OUT FCB COUNTER
CALL SETUP ;SET UP DISK PARAMETERS
JMP MAKEF ;MAKE NEW DIRECTORY ENTRY & EXIT
;
; BDOS COMMAND #23....RENAME EXISTING FILE
;
COM23: CALL SETUP ;SET UP DISK PARAMETERS
CALL RENAME ;DO THE RENAMING
JMP EXIT3 ;PUT MARKER IN RETURN VALUE & EXIT
;
; BDOS COMMAND #24....RETURN LOG-IN VECTOR
;
; LOG-IN VECTOR IS A 16 BIT WORD THAT SHOWS WHICH
; DRIVES HAVE BEEN LOGGED IN. LSB= DRIVE A,
; MSB= DRIVE P.
;
COM24: LHLD LOGVEC ;GET LOG IN VECTOR IN (HL)
JMP COM31A ;PUT IT IN RETURN VALUE & EXIT
;
; BDOS COMMAND #25....RETURN CURRENT DISK NUMBER
;
COM25: LDA CURDSK ;GET CURRENT DISK NUMBER
JMP EXIT1 ;PUT IT IN RETURN VALUE & EXIT
;
; BDOS COMMAND #26....SET CURRENT DMA ADDRESS
;
COM26: XCHG ;MOVE ADDRESS INTO (HL)
SHLD CURDMA ;STORE IT
JMP DIRD1 ;GO SET ADDRESS VIA BIOS CALL
;
; BDOS COMMAND #27....INTEROGATE DISK ALLOCATION
;
; BRINGS BACK ADDRESS OF START OF DISK ALLOCATION
; MAP. GENERALLY USED FOR DISK STATUS PROGRAMS
;
COM27: LHLD DALLOC ;GET POINTER TO ALLOCATION MAP
JMP COM31A ;STORE IN RETURN VALUE & EXIT
;
; BDOS COMMAND #29....GET DISK WRITE PROTECT STATUS WORD
;
; BRINGS BACK 16 BIT WORD. FORMAT IS SIMILAR TO
; LOG-IN VECTOR EXCEPT THAT A SET BIT MEANS
; THAT THE DISK IS READ ONLY
;
COM29: LHLD ROWORD ;* GET R/O VECTOR ADDRESS
JMP COM31A ;STORE IN RETURN VALUE & EXIT
;
; BDOS COMMAND #30....SET FILE ATTRIBUTES
;
; USED TO SET A FILE TO READ ONLY, OR TO MAKE
; A SYSTEM FILE INVISIBLE TO DIRECTORY READS
;
; ON ENTRY THE FILE CONTROL BLOCK CONTAINS THE
; FILENAME.EXT EXACTLY AS IT WILL GO INTO THE
; DIRECTORY. THIS MEANS THAT THE MSB OF BYTES
; T1 AND T2 MUST BE SET FOR R/O AND SYSTEM FILES.
; A FILE OF THE SAME NAME & EXT MUST ALREADY
; EXIST IN MEMORY.
;
COM30: CALL SETUP ;SET UP DISK PARAMETERS
CALL ATTRIB ;GO SET ATTRIBUTES
JMP EXIT3 ;STORE FLAG IN RETURN VALUE & EXIT
;
; BDOS COMMAND #31....GET DISK PARAMETER ADDRESS
;
; BRINGS BACK POINTER TO START OF 15 BYTE
; DISK PARAMETER BLOCK.
;
COM31: LHLD DPBLK ;* GET DISK PARAMETER ADDRESS
COM31A: SHLD RETPAR ;STORE IN RETURN PARAMETER
RET ;EXIT
;
; BDOS COMMAND #32....SET/GET USER NUMBER
;
; ENTRY PARAMETER IS CHECKED AND IF IT IS 0FFH
; THE CURRENT USER NUMBER IS RETURNED, ELSE
; VALUE OF THE ENTRY PARAMETER IS SET AS THE
; CURRENT USER NUMBER.
;
COM32: LDA PARAM1 ;GET THE ENTRY PARAMETER
CPI 0FFH ;CHECK IT
JNZ SETUSR ;NOT 0FFH- GO SET THE NUMBER
LDA USERNO ;IT IS 0FFH- GET THE USER NUMBER
JMP EXIT1 ;PUT IN RETURN VALUE & EXIT
;
SETUSR: ANI 1FH ;NUMBER MUST BE IN THE RANGE
STA USERNO ;OF 00 TO 31
RET ;EXIT
;
; BDOS COMMAND #33....READ RANDOM FILE
;
; ON ENTRY FCB BYTES 33 AND 34 CONTAIN SECTOR
; NUMBER IN THE RANGE OF 0 TO 65535. FILE
; MUST HAVE BEEN PREVIOUSLY OPENED FOR
; RANDOM READING.
;
COM33: CALL SETUP ;SET UP DISK PARAMETERS
JMP RDRAND ;GO READ THE SECTOR
;
; BDOS COMMAND #34....WRITE RANDOM FILE
;
; SAME AS ABOVE, EXCEPT THAT THE SECTOR
; IS WRITTEN TO.
;
COM34: CALL SETUP ;SET UP DISK PARAMETERS
JMP WRRAND ;GO WRITE THE SECTOR
;
; BDOS COMMAND #35....COMPUTE FILE SIZE
;
; BRINGS BACK THE NUMBER OF THE LAST SECTOR
; OF A FILE IN FCB BYTES 33 & 34. USED TO
; CHANGE FROM SEQUENTIAL TO RANDOM WRITING
; OF A FILE AFTER PART OF THE FILE HAS BEEN
; SEQUENTIALLY WRITTEN.
;
COM35: CALL SETUP ;SET UP DISK PARAMETERS
JMP FSIZE ;GO COMPUTE FILE SIZE
;
; BDOS COMMAND #37....UNDOCUMENTED COMMAND
;
; THIS COMMAND UNLOGS AND UNPROTECTS SELECTED
; DISK DRIVES. ON ENTRY A 16 BIT WORD WITH
; BITS SET CORRESPONDING TO THE DRIVES TO BE
; CLEARED IS USED TO CLEAR THE CORRESPONDING
; BITS FROM THE LOG-IN AND R/OJ WORDS
;
COM37: LHLD ENTPAR ;GET LOG-OFF WORD
MOV A,L ;COMPLEMENT IT
CMA ;
MOV E,A ;
MOV A,H ;
CMA ;
LHLD LOGVEC ;GET LOG IN VECTOR
ANA H ;.AND. OUT THE LOG-IN WORD
MOV D,A ;
MOV A,L ;
ANA E ;
MOV E,A ;PLACE RESULT IN (DE)
LHLD ROWORD ;GET THE WRITE PROTECT STATUS WORD
XCHG ;PUT IT IN (DE)
SHLD LOGVEC ;STORE THE UPDATED LOG IN VECTOR
MOV A,L ;.AND. IT WITH THE R/O WORD TO
ANA E ; REMOVE ANY LOGGED OUT BITS
MOV L,A ;
MOV A,H ;
ANA D ;
MOV H,A ;
SHLD ROWORD ;STORE UPDATED R/O WORD
RET ;EXIT
;
; EXIT POINT FOR ALL BDOS COMMANDS
;
; CHECK IS MADE AS TO WHETHER DISK WAS USED DURING
; THE BDOS CALL. IF IT WAS, THE APPRORIATE DISK
; NUMBER IS PUT BACK INTO THE FIRST BYTE OF THE
; FILE CONTROL BLOCK.
; THE RETURN PARAMETER IS PICKED UP AND PLACED IN
; BOTH (HL) AND (A) & (B). THE USE OF (A) & (B) IS
; DONE TO MAINTAIN COMPATABILITY WITH CP/M 1.4
;
BDOS2: LDA SETUPF ;WAS DISK USED?
ORA A ;
JZ BDOS3 ;NO- SKIP OVER
;
LHLD ENTPAR ;POINT TO START OF FCB
MVI M,00H ;SET TO CURRENT DRIVE
LDA DISKNO ; AHA, BUT WAS IT A TRANSIENT DRIVE?
ORA A ;
JZ BDOS3 ;NO- SKIP OVER
MOV M,A ;YES- SET BACK TO CORRECT DRIVE
LDA LOGDSK ;NOW GET LOGGED IN DRIVE NUMBER
STA PARAM1 ; PUT IT IN PLACE FOR DISK CHANGE
CALL COM14 ;SELECT LOGGED-IN DISK DRIVE
BDOS3: LHLD PSTACK ;RESTORE CALLING PROGRAM STACK POINTER
SPHL ;
LHLD RETPAR ;GET RETURN PARAMETER IN (HL)
MOV A,L ;ECHO IT IN (A) & (B)
MOV B,H ;
RET ;GRAND EXIT FROM BDOS..........
;...............BACK TO CALLER.
;
; BDOS COMMAND #40....UNDOCUMENTED COMMAND
;
; EXACT USE HAS NOT BEEN DETERMINED AS YET,
; BUT IT SEEMS TO BE SOME SORT OF RANDOM
; WRITE.
; ....MUST LOOK INTO THIS FURTHER.
;
COM40: CALL SETUP ;SET UP DISK PARAMETERS
MVI A,02H ;SET SERNFL TO 02 (ALL OTHER
;TIMES IT IS SET TO 00 OR 0FFH)
STA SERNFL ;SEQUENTIAL/RANDOM I/O FLAG
MVI C,00H ;WRITE FLAG
CALL SETRN1 ;SET UP THE RANDOM PARAMETERS
CZ WRSEQ1 ;WRITE A SECTOR
RET ;
;
; END OF PROGRAM AREA.........
; ..........START OF PARAMETER
; STORAGE AREA #2.............
;
DMYFCB: DB 0E5H ;DUMMY FCB- USED FOR SEARCHING FOR
;UNUSED DIRECTORY SLOTS
ROWORD: DW 0000H ;READ ONLY DISK STATUS WORD
LOGVEC: DW 0000H ;LOG IN VECTOR
CURDMA: DW DDMA ;CURRENT DMA ADDRESS. INTIALLY = DDMA
DWORD1: DW 0000H ;
DWORD2: DW 0000H ;
DWORD3: DW 0000H ;
DIRBPT: DW 0000H ;DIRECTORY BUFFER POINTER
DPBLK: DW 0000H ;DISK PARAMETER BLOCK POINTER
DIRCRC: DW 0000H ;DIRECTORY CHECKSUM BLOCK POINTER
DALLOC: DW 0000H ;ALLOCATION BIT MAP POINTER
;
; DISK PARAMETER BLOCK
; Moved into place when disk is logged in
;
SECTRS: DW 0000H ;SECTORS PER TRACK
BLSHFT: DB 00H ;BLOCK SHIFT FACTOR
BLMASK: DB 00H ;DISK BLOCK MASK
NLMASK: DB 00H ;NULL BLOCK MASK
DSKSIZ: DW 0000H ;DISK SIZE, # OF 1K BLOCKS -1
DIRMAX: DW 0000H ;MAX NUMBER OF ENTRIES IN DIRECTORY
ALLOC0: DW 0000H ;SIZE OF ALLOCATION BLOCK
CHKSIZ: DW 0000H ;NUMBER OF DIRECTORY SECTORS TO BE CHECKED
DIRTRK: DW 0000H ;DIRECTORY TRACK NUMBER
;
SECTBL: DW 0000H ;VECTOR TO SECTOR TRANSLATION TABLE
MAKEFL: DB 00H ;MAKE-FILE FLAG
RDWRFL: DB 00H ;READ/WRITE FLAG
SRCHFL: DB 00H ;POINTER SET TO 0FFH BY SERCHF AND
;CLEARED TO 00 WHEN A FILE NAME MATCH
;HAS BEEN MADE
SERNFL: DB 00H ;SEQUENTIAL/RANDOM I/O FLAG
;SET 01 FOR SEQUENTIAL READ/WRITE
;SET 00 FOR RANDOM READ/WRITE
;SET 02 FOR UNDOCUMENTED COMMAND #40
PARAM1: DB 00H ;SET TO (E) ON ENTRY TO BDOS, THEN
;USED TO STORE DISK NUMBER
BLKOFF: DB 00H ;TEMPORARY STORAGE FOR OFFSET TO BLOCK
;NUMBER IN DIRECTORY DURING WRSEQ.
;POINTS TO BYTE(S) THAT CONTAIN THE
;CURRENT BLOCK NUMBER. WHEN THE 8TH
;SECTOR OF THE BLOCK HAS BEEN WRITTEN,
;BLKOFF IS INCREMENTED AND A NEW BLOCK
;SELECTED.
SRCHCT: DB 00H ;SEARCH COUNTER-NUMBER OF BYTES TO BE
;COMPARED BETWEEN THE FILE CONTROL
;BLOCK AND THE DIRECTORY ENTRY. THE
;COUNT IS SET ON ENTRY VIA SERCHF &
;PICKED UP FOR USE BY SERCHN
SRCHFP: DW 0000H ;SEARCH FCB POINTER, SET BY SERCHF/SERCHN
DW 0000H ;(NOT USED)
BIGDSK: DB 00H ;8" SD: 0FFH, LARGE CAP DISK: 00H
SETUPF: DB 00H ;
LOGDSK: DB 00H ;
DISKNO: DB 00H ;
RECCTR: DB 00H ;FILE RECORD COUNTER:: FCB + 15
EXTCTR: DB 00H ;FILE EXTENT COUNTER: FCB + 12
CURREC: DW 0000H ;CURRENT RECORD:: FCB + 32
SCNTR1: DW 0000H ;SECTOR COUNTER #1
SCNTR2: DW 0000H ;SECTOR COUNTER #2
DIROFF: DB 00H ;DIRECTORY OFFSET
BLCTR1: DW 0000H ;BLOCK COUNTER #1
BLCTR2: DW 0000H ;BLOCK COUNTER #2
;
; BIOS JUMP TABLE AREA
;
ORG FBASE+0E00H
;
CBOOT: DS 3 ;BIOS CALL/COLD BOOT
WBOOT: DS 3 ;BIOS CALL/WARM BOOT
CONST: DS 3 ;BIOS CALL/CONSOLE STATUS
CONIN: DS 3 ;BIOS CALL/CONSOLE INPUT
CONOUT: DS 3 ;BIOS CALL/CONSOLE OUTPUT
LIST: DS 3 ;BIOS CALL/LIST DEVICE OUTPUT
PUNCH: DS 3 ;BIOS CALL/PUNCH DEVICE OUTPUT
READER: DS 3 ;BIOS CALL/TAPE READER INPUT
HOME: DS 3 ;BIOS CALL/MOVE DISK HEAD TO TRACK 00
SELDSK: DS 3 ;BIOS CALL/SELECT DISK DRIVE
SETTRK: DS 3 ;BIOS CALL/SET DISK TRACK
SETSEC: DS 3 ;BIOS CALL/SET DISK SECTOR
SETDMA: DS 3 ;BIOS CALL/SET DMA
READ: DS 3 ;BIOS CALL/READ DISK SECTOR
WRITE: DS 3 ;BIOS CALL/WRITE DISK SECTOR
LISTST: DS 3 ;BIOS CALL/RETURN LIST DEVICE STATUS
SECTRN: DS 3 ;BIOS CALL/SECTOR TRANSLATE
;
FINISH: END FBASE ;END OF SOURCE CODE