forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3289 lines
83 KiB
3289 lines
83 KiB
; ******************************************
|
|
;
|
|
; 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
|
|
;
|
|
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 ' ' ;CHECK FOR A SPACE
|
|
JNZ KBSTA1 ;EXIT ON SPACE
|
|
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
|
|
|