home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol044
/
du-v77.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
42KB
|
2,616 lines
; DU.ASM V7.7 Revised 7/07/81
; DISK UTILITY - By Ward Christensen
;
;See DU.DOC for description and detailed instructions.
;
;This version of DU is compatible with CP/M 1.4 and 2.x
;and does not require alteration for various hardware
;configurations. It adjusts itself automatically to
;the correct number of sectors, tracks, directory size,
;etc. It has been tested on 5-1/4" and 8" floppy, and
;10 megabyte hard disk systems.
;
;Because of the automatic adaption feature, no conditional
;assembly options are included. The only alteration that
;needs to be done is to use DDT to set the byte at 103h
;to zero for systems using a 2 mHz clock or non-zero for
;4 mHz clock. This only affects the time delay used in
;the 'sleep' command.
;
;*************************************************
;* *
;* This program has been heavily modified *
;* to allow it to work without modification *
;* on most versions of CP/M 1.4 and, hopefully, *
;* all versions of CP/M 2.x. *
;* If you have difficulty getting this program *
;* to run, AND if you are using CP/M 2.x, AND *
;* if you know your BIOS to be bug-free, leave *
;* a message on Technical CBBS of Dearborn, *
;* Michigan (313)-846-6127 with a description *
;* of the problem and a summary of your hard- *
;* ware configuration. *
;* One known possible problem involves the *
;* system tracks on some systems, and results *
;* from the system sectors being skewed. There *
;* is NO way for a program executing under CP/M *
;* to know about this. This program assumes the *
;* standard convention of no skew being used on *
;: the system tracks. This usually isn't a prob- *
;* lem because the SYSGEN program can be used to *
;* get the system from the disk so that it can *
;* be modified. *
;* This program should work under standard *
;* versions of CP/M 1.4. The only requirement *
;* is that the BIOS "SETSEC" routine not modify *
;* the sector number passed to it in the B *
;* register. Again, system tracks with skewed *
;* sectors will be a problem. *
;* If you add any features or make any useful *
;* changes to this program, please modem a copy *
;* to the above CBBS, so the currency of the *
;* program can be maintained. *
;* *
;* Ron Fowler *
;* *
;*************************************************
;
;
;07/12/81 Merged DJH vers 7.6 and Bill Ernest ver 7.6
; to form new vers 7.7 (RGF)
;
;07/07/81 Added "Y" command to allow sectors to be written
; sequentially into memory starting at 3000H, for
; later recovery by DDT, etc. (DJH)
;
;04/02/81 Added * to map showing multiple group assign-
; ment errors. Fixed bug in getgrp record counw
; (William Ernest)
;
;01/23/81 Changed SETSEC to ignore high-order result of
; SECTRN if SPT<256. This fixes some translation
; problems where the BIOS leaves garbage in H. (BRR)
;
;01/15/81 Changed labels to be no more than 6 characters
; long. Moved stack. Cleaned up file. (KBP)
;
;01/13/81 Updated help messages for '#' and 'N' commands.
; Modified sign-on message. (RGF)
;
;01/12/81 Fixed problem with sector translation under
; CP/M 1.4. (RGF)
;
;01/11/81 Fixed problem with CP/M 1.4. Added 'N' command.
; Hard-code 'FASTCLOCK' as a boolean at 103h. Add
; fix for sector number being 0 in system tracks,
; as suggested by Keith Petersen, W8SDZ. Added '#'
; command and memory-full check. Changed login to
; position to directory track at every log. This
; is necessary to set up the 'FIRST0' flag. (RGF)
;
;01/08/81 Corrected error in MAP routine that caused map
; to fail when >255 groups allocated. Changed
; 'REPEAT' to allow up to 65535 repeats. (RGF)
;
;01/06/81 Modified to allow use with ALL systems, without
; conditional assembly, thru use of disk parameter
; block. By Ron Fowler, Westland, Mich.
;
;01/05/81 Modified '+' and '-' commands as follows:
; 1) + at end of disk now wraps to start
; 2) - at start wraps back to end
; 3) argument for + & - now good to 65535
; (RGF)
;
;01/03/81 Modified logic in console status test to allow
; any non-zero value to indicate char waiting.
; (RGF)
;
;01/02/81 Made compatible with MACRO80 assembler (labels
; made unique within 6 chars, and separated multi-
; statement lines). (RGF)
;
;11/14/80 Corrected missing conditional in CLCSUB routine
; for MICROP or DIGDBL. Cleaned up file. (KBP)
;
;11/04/80 Forced write type 1 (pre-read and immediate write)
; so deblocking BIOS's don't mess up. Ignore bit 7
; in = command unless <nn> form was used. Display
; unprintables as <nn> in V command. Show user no.
; in M command (will always be 00 for 1.4) and only
; print parentheses if E5 present. (BRR)
;
;10/30/80 Fixed bug in backspace/control-X. Corrected more
; bit-7 stuff. Added 'U' command to change user no.
; under CP/M 2.x. Added pauses in help file. (BRR)
;
;10/27/80 Added Thinkertoys DBL DENS, Micromation DBL DENS,
; Industrial Micro Systems DBL and QUAD DENS.
; Fixed several bit-7 problems in MAP and DUMP logic.
; Added control-X (CRT erase line) to command input
; logic. (Bruce R. Ratoff, ACGNJ-SIG/M)
;
;09/16/80 Fix backspace in line enter routine, add MAXDIR
; equate, general cleanup of ASM file. (KBP)
;
;06/22/80 Put in 'Q' command. Fix so 'P' (printer)
; mode outputs L/F's. (WLC)
;
;05/21/80 Make sector, track, be decimal, not hex.
; Also dis-allow a read until positioned.
; (DU otherwise not in sync with CP/M) (WLC)
;
;03/24/80 Mod for Micropolis, Digital Microsystems DD,
; and Northstar DD CP/M. Trap out garbage
; during VIEW of file. By Keith Petersen, W8SDZ
;
;02/24/80 Mod login command to not really do log, just
; drive select. (WLC)
;
;02/12/80 Mod for heath CP/M. (WLC)
;
;01/08/80 Reposition after 'M' command. (WLC)
;
;01/07/79 Add VIEW command. (WLC)
;
;01/06/80 Rewrite 'F' command. (WLC)
;
;10/10/79 Save regs in BIOS calls, translate input to upper case
; add commands: < save sector
; > restore sect
; / repeat
; allow change from-thru. (WLC)
;
;02/25/79 Put sector read into 'S' command. (WLC)
;
;11/26/78 Add disk # to login command. (WLC)
;
;11/12/78 Add login command. (WLC)
;
;08/06/78 Originally written to reconstruct blown
; disks on CBBS via remote access. (WLC)
;
;
; ----------------
;Sorry for the lack of comments in the code
;portion of this program - it was just hacked
;together to satisfy my needs, but lots of
;other people found it useful. Its external
;documentation is good, but its sadly lacking
;comments on the instructions. (WLC)
; ----------------
;
;System equates
;
BASE EQU 0 ;SET TO 4200H FOR HEATH OR TRS-80 ALTCPM
;
FCB EQU BASE+5CH
BDOS EQU BASE+5
PRINT EQU 9
GVERS EQU 12
RESETDK EQU 13
SELDK EQU 14
SRCHF EQU 17 ;SEARCH FIRST
SUSER EQU 32
GETDSK EQU 25
GETDPB EQU 31
;
TRNOFF EQU 15 ;CP/M 1.4 OFFSET FROM BASE
;OF BDOS TO SECTRAN ROUTINE
SKWOFF EQU 1AH ;CP/M 1.4 OFFSET TO SKEW TABLE
S2OFF EQU 14 ;OFFSET INTO FCB FOR S2 BYTE
DPBOFF EQU 3AH ;CP/M 1.4 OFFSET TO DPB WITHIN BDOS
S2MASK EQU 0FH ;MASK FOR EXTENDED RC BITS OF S2
DPBLEN EQU 15 ;SIZE OF CP/M 2.x DISK PARM BLOCK
;
;
;Define ASCII characters
;
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
TAB EQU 09H ;TAB
BS EQU 08H ;BACKSPACE
;
ORG BASE+100H
;
JMP PASTCK ;JUMP OVER CLOCK BYTE AND I.D.
;
CLOCK: DB 0 ;<---PUT NON-ZERO HERE FOR 4 MHZ CLOCK
DB 'DU.COM ver 7.7 7/12/81'
;
PASTCK: LHLD BDOS+1 ;GET POINTER TO BDOS ENTRY
MVI L,0 ;SET HL=BASE OF BDOS
SPHL ;PUT STACK THERE
SHLD SETSTK+1 ;SAVE FOR LATER LXI SP INSTR.
MVI C,GVERS ;GET CP/M VERSION NR
CALL BDOS
MOV A,H ;COMBINE THE TWO BYTE...
ORA L ;...VERSION NR FOR A FLAG
STA VER2FL ;SAVE IT
LXI H,3000H ;INITIALIZE "Y" COMMAND MEMORY POINTER
SHLD YNKADR
;
;Set up local jumps to BIOS
LHLD BASE+1 ;WARM BOOT POINTER
LXI D,3 ;READY FOR ADD
DAD D
SHLD VCONST+1
DAD D
SHLD VCONIN+1
DAD D
SHLD VCONOT+1
DAD D
SHLD VLIST+1
DAD D ;PUNCH
DAD D ;RDR
DAD D
SHLD VHOME+1
DAD D
SHLD VSELDK+1
DAD D
SHLD VSETRK+1
DAD D
SHLD VSTSEC+1
DAD D
SHLD SETDMA+1
DAD D
SHLD VREAD+1
DAD D
SHLD VWRITE+1
LDA VER2FL
ORA A
JZ DOCPM1
DAD D ;LISTST
DAD D
SHLD VSCTRN+1
JMP HELLO
;
DOCPM1: LHLD BDOS+1
MVI L,0 ;BDOS ON PAGE BOUNDARY
PUSH H
LXI D,TRNOFF ;CP/M 1.4 SECTRAN ROUTINE OFFSET
DAD D
SHLD VSCTRN+1
POP H
LXI D,SKWOFF ;CP/M 1.4 SKEW TABLE OFFSET
DAD D
SHLD SECTBL ;SET UP SKEW TABLE POINTER
;
HELLO: CALL ILPRT
DB CR,LF,'DISK UTILITY ver 7.7',CR,LF
DB 'Universal Version',CR,LF
DB CR,LF
DB 'Type ? for help',CR,LF
DB 'Type X to exit'
DB CR,LF,0
CALL GETSTP ;SET UP PARAMETERS
LXI H,BASE+80H ;TO INPUT BUFF
MOV A,M
ORA A
JZ PRMPTR ;NO COMMAND
;
;Got initial command, set it up
MOV B,A ;SAVE LENGTH
DCR B
JZ PRMPTR
LXI D,INBUF
INX H ;SKIP LEN
INX H ;SKIP ' '
CALL MOVE
MVI A,CR
STAX D
LXI H,INBUF
JMP PRMPTI
;
PRMPTR: XRA A
STA QFLAG
CALL RDBUF
;
PRMPTI: MVI A,255
STA TOGO ;LOOP COUNT FOR "/"
STA TOGO+1
;
PROMPT EQU $
SETSTK: LXI SP,$-$ ;MODIFIED AT INIT
XRA A ;ZERO 2-UP PRINT
STA TWOUP ;..SWITCH
MVI A,1
STA FTSW ;TELL SEARCH NOT TO INCR
PUSH H
LXI H,BASE+100H
SHLD BUFAD ;FOR RDBYTE
POP H
CALL CTLCS ;ABORT?
JZ PRMPTR ;..YES, READ BUFFER
;
;Do we have to position in directory after find?
LDA FINDFL
ORA A
JNZ POSDIR ;POSITION IN DIRECTORY
MOV A,M
CPI CR
JZ PRMPTR
CPI ';' ;LOGICAL CR?
INX H
JZ PROMPT
CALL UPCASE
STA DUMTYP ;TYPE OF DUMP (A,D,H)
;
;Command dispatcher
;
CPI '+'
JZ PLUS
;
CPI '-'
JZ MINUS
;
CPI '='
JZ SEARCH
;
CPI '<'
JZ SAVE
;
CPI '>'
JZ RESTOR
;
CPI '#'
JZ STATS
;
CPI '?'
JZ HELP
;
CPI 'A'
JZ DUMP
;
CPI 'C'
JZ CHG
;
CPI 'D'
JZ DUMP
;
CPI 'F'
JZ POSFIL
;
CPI 'G'
JZ POS
;
CPI 'H'
JZ DUMP
;
CPI 'L'
JZ LOGIN
;
CPI 'M'
JZ MAP
;
CPI 'N'
JZ NEWDSK
;
CPI 'P'
JZ PRNTFF
;
CPI 'Q'
JZ QUIET
;
CPI 'R'
JZ DOREAD
;
CPI 'S'
JZ POS
;
CPI 'T'
JZ POS
;
CPI 'U' ;******CP/M 2.x ONLY******
JZ USER
;
CPI 'V'
JZ VIEW
;
CPI 'W'
JZ DORITE
;
CPI 'X'
JZ BASE
;
CPI 'Y'
JZ YANK
;
CPI 'Z'
JZ SLEEP
;
CPI '/'
JZ REPEAT
;
WHAT: XRA A
STA QFLAG
CALL ILPRT
DB '?',0
JMP PRMPTR
;
;Memory full error
;
MEMFUL: XRA A
STA QFLAG
CALL ILPRT
DB '+++ Out of memory +++'
DB CR,LF,0
JMP PRMPTR
;
;Print disk statistics
;
STATS: PUSH H
CALL ILPRT
DB 'Disk Information:',CR,LF
DB 'Tracks:',9,9,0
LHLD MAXTRK
INX H
CALL DEC
CALL ILPRT
DB CR,LF,'Sec/trk:',9,0
LHLD SPT
CALL DEC
CALL ILPRT
DB CR,LF,'Grpsize:',9,0
LDA BLM
INR A
MOV L,A
MVI H,0
CALL DEC
CALL ILPRT
DB ' (sectors per group)',CR,LF
DB 'Tot grps:',9,0
LHLD DSM
CALL DEC
CALL ILPRT
DB CR,LF,'Dir entries:',9,0
LHLD DRM
INX H
CALL DEC
CALL ILPRT
DB CR,LF,'Sys tracks:',9,0
LHLD SYSTRK
CALL DEC
CALL CRLF
POP H
JMP PROMPT
;
;The following command resets the disk
;system thru CP/M, and may be usable for
;changing the disk density or format.
;This can only be done if your BIOS resets
;the auto-density select parameters at
;every track-zero access.
;
NEWDSK: PUSH H
MVI C,RESETDK
CALL BDOS
LDA DRIVE
MOV C,A
POP H
CALL SELECT
JMP PROMPT
;
;Quite mode
;
QUIET: STA QFLAG ;NOW QUIET
JMP PROMPT
;
;Repeat buffer contents
;
REPEAT: CALL DECIN ;NN SPECIFIED?
MOV A,D
ORA E
JZ NNN ;NO.
LHLD TOGO
INX H ;TEST FOR FIRST TIME
MOV A,H
ORA L ;WAS IT 0FFFFH?
JNZ NNN ;NO: COUNTING
XCHG ;GET COUNT
SHLD TOGO ;SET COUNT
;
NNN: LHLD TOGO
XCHG
LXI H,INBUF ;READY TO REPEAT
INX D ;TEST FOR 0FFFFH
MOV A,D
ORA E
JZ PROMPT ;CONTINOUS
DCX D ;COUNT DOWN
DCX D ;MAKE UP FOR PREV INX D
XCHG
SHLD TOGO
MOV A,H ;ALL DONE?
ORA L
XCHG ;GET BACK INBUF PTR
JNZ PROMPT ;NO, KEEP GOING
JMP PRMPTR ;ALL DONE
;
;Set CP/M 2.x user number
;
USER: LDA VER2FL
ORA A
JZ WHAT
CALL DECIN ;GET REQUESTED USER NO.
MOV A,E
CPI 32 ;VALID?
JNC WHAT
MOV A,D
ORA A
JNZ WHAT
MVI C,SUSER
PUSH H ;SAVE CHAR POINTER
CALL BDOS ;SET USER NO.
POP H
JMP PROMPT
;
;Toggle print flag
;
PRNTFF: LDA PFLAG
XRI 1
STA PFLAG
JMP PROMPT
;
;Sleep routine, in tenths of a sec
;
SLEEP: CALL HEXIN ;GET COUNT IF ANY
MOV A,E ;ANY?
ORA A
JNZ SLEPLP
MVI E,10
;
SLEPLP: LXI B,8000 ;APPROX .1 SEC @ 2MHz
LDA CLOCK
ORA A
JZ SLEEP2
LXI B,16000 ;APPROX .1 SEC @ 4 MHz
;
SLEEP2: DCX B
MOV A,B
ORA C
JNZ SLEEP2
PUSH D
CALL CTLCS
POP D
JZ PRMPTR
DCR E
JNZ SLEPLP
JMP PROMPT
;
;Check for control-C or S
;
CTLCS: CALL CONST
ORA A
JNZ GETC
ORI 1 ;NO CHAR, RETN NZ
RET
;
GETC: CALL CONIN
ANI 1FH ;ALLOW ASCII
CPI 'S'-40H
CZ CONIN
CPI 'C'-40H
RET ;0 SET IF CTL-C
;
;Find our way at initialization
;
GETSTP: MVI C,GETDSK
CALL BDOS ;GET CURNT DSK
MOV C,A ; WE HAVE TO SELECT
JMP SELECT ; TO GET THE DPH
;
LOGIN: CALL DOLOG
JMP PROMPT
;
DOLOG: MOV A,M ;DISK REQ?
LXI D,0
CPI CR
JZ LGNODK
CPI ';'
JZ LGNODK
CALL UPCASE
INX H
SUI 'A'
MOV C,A
;
SELECT: PUSH H
MOV A,C
STA DRIVE ;REMEMBER LATER WHERE WE ARE
;
VSELDK: CALL $-$ ;ADDR FILLED IN BY 'INIT'
LDA VER2FL
ORA A ;IF NOT CP/M 2.x ...
JZ SELSKP ;..THEN SKIP THIS JUNK
MOV A,H
ORA L
JZ WHAT ;SELECT ERROR
MOV E,M ;GET THE SECTOR TABLE PNTR
INX H
MOV D,M
INX H
XCHG
SHLD SECTBL
LXI H,8 ;OFFSET TO DPBPTR
DAD D
MOV A,M ;PICK UP DPB POINTER
INX H ; TO USE
MOV H,M ; AS PARAMETER
MOV L,A ; TO LOGIT
;
SELSKP: CALL LOGIT
LHLD SYSTRK ;RESET TRACK AND SECTOR
XCHG ; TO DIRECTORY
CALL SETTRK ; ON EVERY
LXI D,1 ; LOGIN
CALL SETSEC ; CHANGE
LHLD PHYSEC ;THIS LOGIC WILL TELL
MOV A,H ; IF FIRST SEC
ORA L ; IS PHYSICAL 0
STA FIRST0
CALL CLCSUB
POP H
;
LGNODK: CALL NORITE
RET
;
;Read in the disk directory
;
REDDIR: PUSH H
CALL NORITE ;POSITIONING LOST
LHLD SYSTRK
SHLD CURTRK
LXI H,1
SHLD CURSEC
LHLD DRM ;GET DIR SIZE FROM DPB
INX H ;MAKE 1-RELATIVE
CALL ROTRHL
CALL ROTRHL ;DIVIDE BY 4 (4 NAMES/SECTOR)
MOV B,H
MOV C,L
LXI D,DIRECT ;DMA ADDR
;
RDIRLP: PUSH B
PUSH D
MOV B,D
MOV C,E
LDA BDOS+2 ;CHECK MEM AVAIL
DCR A
CMP D
JC MEMFUL
CALL SETDMA
LHLD CURTRK
XCHG
CALL SETTRK
LHLD CURSEC
XCHG
CALL SETSEC
CALL READ
CALL NXTSEC
POP D
POP B
LXI H,80H
DAD D
XCHG
DCX B
MOV A,B
ORA C
JNZ RDIRLP
LXI B,BASE+80H
CALL SETDMA
POP H
RET
;
;Map the directory
;
MAP: CALL REDDIR ;READ IN DIRECTORY
MVI C,0 ;INIT START GRP #
LDA AL0 ;READ DIR GRP BITS
CALL COLECT ;COLLECT COUNT OF DIR GRPS..
LDA AL1 ;..IN REGISTER C
CALL COLECT
MVI B,0 ;BC NOW HAS A DEFAULT START GRP #
CALL HEXIN
PUSH H ;SAVE INBUF PTR
MOV A,E ;GET START
ORA D ;NOTHING?
JZ MAPDF ;..YES, DFLT
MOV B,D
MOV C,E
;
MAPDF: CALL HEXB
MVI A,'-'
CALL TYPE
MVI A,' '
STA DUPFLG
CALL GETGRP ;GET GRP(C) TO HL
;
MAPCNT: INX B ;NEXT GRP #
PUSH H
LHLD DSM ;GET HIGHEST GRP #
INX H ;PLUS 1 FOR COMPARISON
MOV A,L ;WHEN BC REACHES DSM+1..
CMP C ;..THEN WE HAVE EXCEEDED..
JNZ MAPC1 ;..THE DISK CAPACITY..
MOV A,H
CMP B
;
MAPC1: POP H
JZ MAPEND ;..AND WE ARE DONE
PUSH H
CALL GETGRP ;GET ANOTHER
POP D ;SEE IF SAME
CALL CTLCS
JZ MAPND2
MOV A,D
CMP H
JNZ MAPDIF
MOV A,E
CMP L
JZ MAPCNT ;SAME, CONTINUE
;
;Different file encountered
MAPDIF: DCX B
CALL HEXB
INX B
XCHG
CALL MAPNAM
JMP MAPDF
;
;End of map
;
MAPEND: DCX B ;GET LAST
CALL HEXB
CALL MAPNAM
POP H
CALL CRLF
;
;End of map - reposition to previous group
;
MAPND2: PUSH H
LHLD GROUP
XCHG
JMP POSGP2
;
;Print file name pointed to by HL
;
MAPNAM: CALL SPACE
MOV A,H
ORA L ;NONE?
JZ NONAME
MOV A,M ;SEE IF ALLOC
CPI 0E5H ;FREE?
MVI A,' '
JNZ MPNSP1
MVI A,'('
;
MPNSP1: CALL TYPE
PUSH H ;SAVE POINTER
MOV A,M
CALL HEX ;SHOW USER NUMBER
CALL SPACE
INX H ;SKIP USER BYTE
PUSH B
MVI B,8
CALL MAPN2
MVI A,'.'
CALL TYPE
MVI B,3
CALL MAPN2
LDA DUPFLG
CALL TYPE ;SPACE OR STAR
POP B
MOV A,M ;GET EXT
CALL HEX
POP H
MOV A,M
CPI 0E5H
MVI A,' '
JNZ MPNSP2
MVI A,')'
;
MPNSP2: CALL TYPE ;")" IF ERASED FILE
JMP FLIP
;
NONAME: CALL ILPRT
DB ' ++FREE++ ',0
;
FLIP: LDA TWOUP
XRI 1
STA TWOUP
JZ CRLF
;
DELIM: MVI A,':'
CALL TYPE
JMP SPACE
;
;Print name, length in B
;
MAPN2: MOV A,M
ANI 7FH ;STRIP POSSIBLE 2.x ATTRIBUTE BIT
INX H
CPI ' ' ;PRINTABLE?
JC MAPN2H ;..NO, IN HEX
CPI 7EH ;7E IS LEADIN ON SOME CRTS
JC MAPN2A
;
MAPN2H: CALL BHEX
JMP MAPN2Z
;
MAPN2A: CALL TYPE
;
MAPN2Z: DCR B
JNZ MAPN2
RET
;
;Find which file group (BC) belongs to
;
GETGRP: LHLD DRM ;MAX DIR ENTRY #
INX H ;MAKE 1-RELATIVE
SHLD FILECT
LXI H,0
SHLD MFPTR
LXI H,DIRECT
;
GETGLP: PUSH H ;SAVE POINTER TO NAME
MOV A,M ;PICK UP DN BYTE
CPI 0E5H
JZ GETGNF
LXI D,14 ;NOW GET RECORD COUNT
DAD D ; S2 PORTION ..
MOV A,M ; IS 0 IN CP/M 1.4
ANI 0FH
MOV E,A
INX H
MOV A,M
ORA E
JZ GETGNF
MVI E,16 ;FIRST SET FOR 8-BIT GRPS
LDA DSM+1
ORA A
JZ SMALGP
MVI E,8 ;NOPE, BIG GROUPS
;
SMALGP: MOV D,A ;SAVE GRP SIZE INDICATOR
;
GETGL2: INX H ;POINTING INTO DM FIELD
CALL GRPCMP ;COMPARE BC GP # AGAINST 1 DM FLD
JNZ NOTGOT ;JUMP IF FOUND ONE
;
;Found the file
;
PUSH H ;SAVE GP PTR
LHLD MFPTR
MOV A,H
ORA L
POP H
XTHL ;GET ENTRY START & SAVE PTR
JZ MPFRST
MVI A,'*'
STA DUPFLG
MPFRST: SHLD MFPTR
XTHL ;AS THEY WERE
NOTGOT: DCR E ;ELSE COUNT DOWN
JNZ GETGL2 ;GO TEST SOME MORE
;
GETGNF: POP H ;NOT THIS ONE!
LXI D,32 ;SO GO TO NEXT
DAD D
XCHG
LHLD FILECT ;THERE IS LIMIT TO EVERYTHING
DCX H
SHLD FILECT
MOV A,H
ORA L
XCHG ;RE-ALIGN
JNZ GETGLP
;
;Get the allocation address, if {ny
LHLD MFPTR
RET
;
;Yank the current sector into memory at location YNKADR
;
YANK: LDA 7 ;GET TOP BYTE OF CCP POINTER
MOV B,A
LDA YNKADR+1 ;GET TOP BYTE OF MEMORY POINTER
CMP B
JNC YMFULL ;IF MEMORY FULL, THEN SAY SO AND ABORT YANK
LDA WRFLG ;CHECK IF A READ HAS BEEN DONE
ORA A
JZ BADW ;IF NO READ, THEN CAN'T YANK, SO ABORT YANK
PUSH H
LHLD YNKADR ;MOVE SECTOR INTO YANK MEMORY
XCHG
LXI H,BASE+80H
MVI B,128
CALL MOVE
CALL ILPRT ;TELL WHERE LAST BYTE IS
DB 'LAST ADDR=',0
LHLD YNKADR ;CALCULATE LAST BYTE
LXI B,80H
DAD B
SHLD YNKADR ;SAVE LAST BYTE+1 FOR NEXT YANK
DCX H
MOV A,H
CALL HEX
MOV A,L
CALL HEX
CALL ILPRT
DB CR,LF,0
POP H
JMP PROMPT
;
YMFULL: XRA A ;MEMORY FULL, SO SAY SO
STA QFLAG ;SET TO NOT QUIET MODE FIRST
CALL ILPRT
DB '++YANK MEMORY FULL'
DB CR,LF,0
JMP PROMPT
;
;Save the current sector
;
SAVE: LDA WRFLG
ORA A
JZ BADW ;NONE TO SAVE
PUSH H
LXI H,BASE+80H
LXI D,SAVBUF
MVI B,128
CALL MOVE
MVI A,1 ;..SHOW
STA SAVEFL ;..SAVED EXISTS
POP H
JMP PROMPT
;
;Restore the current sector
;
RESTOR: LDA SAVEFL
ORA A
JZ NOSAVE ;NONE TO SAVE
PUSH H
LXI H,SAVBUF
LXI D,BASE+80H
MVI B,128
CALL MOVE
POP H
JMP PROMPT
;
NOSAVE: XRA A
STA QFLAG
CALL ILPRT
DB '++NO "<" SAVE COMMAND ISSUED'
DB CR,LF,0
JMP PRMPTR
;
;Move (HL) to (DE) length in B
;
MOVE: MOV A,M
STAX D
INX H
INX D
DCR B
JNZ MOVE
RET
;
NORITE: XRA A ;GET 0
STA WRFLG ;CAN'T WRITE NOW
RET
;
;No match in search, try next char
;
SRNOMT: POP H
CALL CTLCS ;ABORT?
JNZ SEARCH ;..YES
LXI H,INBUF
MVI M,CR
JMP CLCGRP ;SHOW WHERE STOPPED
;
;Search for character string
;
SEARCH: PUSH H ;SAVE STRING POINTER
;
SRCHL: CALL RDBYTE ;GET A BYTE
MOV B,A ;SAVE IT
MOV A,M ;CHECK NEXT MATCH CHAR.
CPI '<' ;WILL IT BE HEX?
MOV A,B ;RESTORE DISK CHAR
JZ SRCHL1
ANI 7FH ;NEXT CHAR IS ASCII...STRIP BIT 7
;
SRCHL1: PUSH PSW
CALL GETVAL ;GET SEARCH VALUE
MOV B,A
POP PSW
CMP B ;MATCH?
JNZ SRNOMT ;NO MATCH
INX H
MOV A,M ;DONE?
CPI CR
JZ SREQU
CPI ';'
JNZ SRCHL
;
;Got match
SREQU: XRA A
STA QFLAG
CALL ILPRT
DB '= AT ',0
LDA BUFAD
ANI 7FH
CALL HEX
CALL CRLF
JMP CLCGRP
;
;Get value from input buffer
;
GETVAL: MOV A,M
CPI '<' ;HEX ESCAPE?
RNZ ;NO, RETURN
;"<<" means one "<"
INX H
MOV A,M
CPI '<'
RZ
;Got hex
PUSH D
CALL HEXIN ;GET VALUE
CPI '>' ;PROPER DELIM?
MOV A,E ;GET VALUE
POP D
JNZ WHAT ;ERROR
RET
;
;Read a byte at a time
;
RDBYTE: PUSH H
LDA FTSW ;FIRST READ?
ORA A
JNZ READ1
LHLD BUFAD
MOV A,L
ORA A ;IN BUFFER?
JM NORD ;YES, SKIP READ
;
;Have to read
CALL NXTSEC
;
READ1: XRA A
STA FTSW ;NOT FIRST READ
LHLD CURSEC
XCHG
CALL SETSEC
LHLD CURTRK
XCHG
CALL SETTRK
CALL READ
CALL CLCSUB
LXI H,BASE+80H
;
NORD: MOV A,M
INX H
SHLD BUFAD
POP H
RET
;
;View the file in ASCII starting at
;current sector, stepping thru the disk
;
VIEW: LDA WRFLG
ORA A
JZ BADDMP
CALL HEXIN ;GET DISPL IF ANY
PUSH H
MOV A,E
ORA A
JNZ VIEWLP
INR E ;DFLT=1
;
VIEWLP: LXI H,BASE+80H ;TO DATA
;
VEWCHR: CALL CTLCS
JZ VEWEND
MOV A,M
CPI 1AH
JZ VEWEOF
ANI 7FH
CPI 7EH
JNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX
CPI ' '
JNC VIEWPR
CPI CR
JZ VIEWPR
CPI LF
JZ VIEWPR
CPI TAB
JZ VIEWPR
;
VIEWHX: MOV A,M ;NOT ASCII...PRINT AS <NN>
CALL BHEX
JMP VIEWNP
;
VIEWPR: CALL TYPE
;
VIEWNP: INR L
JNZ VEWCHR
DCR E
JZ VEWEND
PUSH D ;SAVE COUNT
CALL NXTSEC
LHLD CURSEC
XCHG
CALL SETSEC
LHLD CURTRK
XCHG
CALL SETTRK
CALL READ
POP D ;RESTORE COUNT
JMP VIEWLP
;
VEWEOF: CALL ILPRT
DB CR,LF,TAB,'++EOF++',CR,LF,0
;
VEWEND: POP H
CALL CRLF
JMP CLCGRP
;
;Dump in hex or ASCII
;
DUMP: LDA WRFLG
ORA A
JNZ DUMPOK
;
BADDMP: XRA A
STA QFLAG
CALL ILPRT
DB '++Can''t dump, no sector read.',CR,LF,0
;
EXPL: XRA A
STA QFLAG
CALL ILPRT
DB 'Use G command following F,',CR,LF
DB 'or R or S following T',CR,LF,0
JMP PRMPTR
;
DUMPOK: MOV A,M
CPI ';'
JZ DUMPDF ;DFLT
CPI CR
JNZ DMPNDF
;
;Use default
DUMPDF: LXI B,BASE+80H
LXI D,0FFH
JMP DUMP1
;
DMPNDF: CALL DISP
MOV B,D
MOV C,E
CPI CR
JZ DUMP1
CPI ';'
JZ DUMP1
INX H ;SKIP ','
CALL DISP
;
;BC = start, DE = end
;
DUMP1: PUSH H ;SAVE COMMAND POINTER
MOV H,B
MOV L,C
;
DUMPLP: MOV A,L
ANI 7FH
CALL HEX
CALL SPACE
CALL SPACE
LDA DUMTYP
CPI 'A'
JZ DUMPAS
PUSH H ;SAVE START
;
DHEX: MOV A,M
CALL HEX
MOV A,L
ANI 3
CPI 3
CZ SPACE
MOV A,L
ANI 7
CPI 7
CZ SPACE
MOV A,E
CMP L
JZ DPOP
INX H
MOV A,L
ANI 0FH
JNZ DHEX
;
DPOP: CALL CTLCS
JZ PRMPTR
LDA DUMTYP
CPI 'H'
JZ DNOAS ;HEX ONLY
POP H ;GET START ADDR
;
DUMPAS: CALL ASTER
;
DCHR: MOV A,M
ANI 7FH
CPI ' '
JC DPER
CPI 7EH
JC DOK
;
DPER: MVI A,'.'
;
DOK: CALL TYPE
MOV A,E
CMP L
JZ DEND
INX H
MOV A,L
ANI 0FH
JNZ DCHR
;
DEND: CALL ASTER
CALL CRLF
PUSH D
CALL CTLCS
POP D
JZ PRMPTR
MOV A,E
CMP L
JNZ DUMPLP
POP H
JMP PROMPT
;
DNOAS: POP B
CALL CRLF
MOV A,E
CMP L
JNZ DUMPLP
POP H
JMP PROMPT
;
;Position
;
POS: PUSH PSW
MOV A,M
CPI ';'
JZ POSINQ
CPI CR
JNZ POSOK
;
POSINQ: POP PSW
JMP INQ
;
POSOK: POP PSW
CPI 'T'
JZ POSTKD
CPI 'S'
JZ POSSCD
CPI 'G'
JZ POSGPH
JMP WHAT
;
POSTKD: CALL DECIN
;
POSTRK: PUSH H
LHLD MAXTRK
CALL SUBDE
POP H
JC OUTLIM
CALL SETTRK
CALL NORITE ;TRACK DOESN'T READ
MVI A,1
STA NOTPOS ;SHOW NOT POSITIONED
JMP CLCGRP
;
POSSCD: CALL DECIN
MOV A,D
ORA E
JZ WHAT ;DON'T ALLOW SECTOR 0
;
POSSEC: PUSH H
LHLD SPT
CALL SUBDE
POP H
JC WHAT
CALL SETSEC
CALL READ
XRA A
STA NOTPOS ;POSITIONED OK
;
CLCGRP: CALL CLCSUB
JMP INQ
;
;Calculate group from track and sector
;
CLCSUB: PUSH H
LHLD SYSTRK
XCHG
LHLD CURTRK
CALL SUBDE
XCHG
LHLD SPT
CALL MULT
XCHG
LHLD CURSEC
DCX H
DAD D
LDA BLM
MOV B,A
MOV A,L
ANA B
STA GRPDIS
LDA BSH
MOV B,A
;
CLCLOP: CALL ROTRHL
DCR B
JNZ CLCLOP
SHLD GROUP
POP H
RET
;
;Position in the directory after a find
;(Does not work in CP/M-2.x)
;
POSDIR: PUSH H ;SAVE INBUF
LHLD BSH
XRA A
STA FINDFL ;CANCEL POS REQ
LDA DIRPOS ;GET POSITION
RAR
RAR
PUSH PSW
ANA H
STA GRPDIS
POP PSW
;
POSDLP: RAR
DCR L
JNZ POSDLP
ANI 1 ;GET GROUP
MOV L,A ;SETUP FOR POSGP2
MVI H,0
SHLD GROUP
XCHG
JMP POSGP2 ;POSITION TO IT
;
POSGPH: CALL HEXIN
;
POSGRP: PUSH H
LHLD DSM
CALL SUBDE
POP H
JC OUTLIM
XCHG
SHLD GROUP
XCHG
XRA A
STA GRPDIS
PUSH H
;
POSGP2: CALL GTKSEC
CALL SETTRK
XCHG
CALL SETSEC
CALL READ
XRA A
STA NOTPOS ;NOW POSITIONED
POP H
JMP INQ
;
GTKSEC: MOV H,D
MOV L,E
LDA BSH
;
GLOOP: DAD H
DCR A
JNZ GLOOP
LDA GRPDIS
ADD L ;CAN'T CARRY
MOV L,A
;
;Divide by nr of sectors, quotient=track, remainder=sector
;
XCHG
LHLD SPT
CALL NEG
XCHG
LXI B,0
;
DIVLP: INX B
DAD D
JC DIVLP
DCX B
XCHG
LHLD SPT
DAD D
PUSH H
LHLD SYSTRK
DAD B
XCHG
POP H
INX H
RET
;
POSFIL: CALL NORITE
MVI A,1
STA FINDFL ;SO WE POSITION LATER
LXI D,FCB
XRA A ;LOGGED IN DISK
STAX D
INX D
MVI B,8
CALL MVNAME
MVI B,3
CALL MVNAME
LXI D,FCB
MVI C,SRCHF
PUSH H
CALL BDOS
INR A
JNZ FLOK
STA DIRPOS ;GRP 0 IF NOT FOUND
CALL ILPRT
DB '++FILE NOT FOUND',CR,LF,0
POP H
JMP PROMPT
;
FLOK: DCR A
STA DIRPOS ;SAVE POS. IN DIR
ANI 3
MOV L,A
MVI H,0
DAD H ;X32 BYTES/ENTRY
DAD H
DAD H
DAD H
DAD H
LXI D,BASE+80H
DAD D ;HL POINTS TO ENTRY
LXI D,32
XCHG
DAD D
XCHG
MVI A,'D'
STA DUMTYP
JMP DUMPLP ;WHICH POPS H
;
MVNAME: MOV A,M
CPI '.'
JZ MVIPAD
CPI CR
JZ PAD
CPI ';'
JZ PAD
CALL UPCASE
STAX D
INX H
INX D
DCR B
JNZ MVNAME
MOV A,M
CPI CR
RZ
CPI ';'
RZ
INX H
CPI '.'
RZ
JMP WHAT
;
MVIPAD: INX H
;
PAD: MVI A,' '
STAX D
INX D
DCR B
JNZ PAD
RET
;
PLUS: LXI D,1 ;DFLT TO 1 SECT
MOV A,M ;GET NEXT CHAR
CPI CR ;CR?
JZ PLUSGO ;..YES, DFLT TO 1
CPI ';'
JZ PLUSGO
CALL HEXIN ;GET #
MOV A,D
ORA E
JZ WHAT
;
PLUSGO: CALL NXTSEC
DCX D ;MORE TO GO?
MOV A,D
ORA E
JNZ PLUSGO ;..YES
;
;Ok, incremented to sector. Setup and read
;
PLUSMI: PUSH H
LHLD CURSEC
XCHG
CALL SETSEC
LHLD CURTRK
XCHG
CALL SETTRK
POP H
CALL READ
JMP CLCGRP
;
MINUS: LXI D,1 ;SET DFLT
MOV A,M ;GET CHAR
CPI CR ;CR?
JZ MINGO ;..YES, DFLT=1
CPI ';'
JZ MINGO
CALL HEXIN ;..NO, GET ##
MOV A,D
ORA E
JZ WHAT
;
MINGO: PUSH H
LHLD CURSEC
DCX H
MOV A,H
ORA L
JNZ MINOK
LHLD CURTRK
MOV A,H
ORA L
JNZ SEASH
LHLD MAXTRK ;WRAP TO END OF DISK
SHLD CURTRK
LHLD MAXSEC
JMP MINOK
;
SEASH: DCX H
SHLD CURTRK
LHLD SPT
;
MINOK: SHLD CURSEC
POP H
DCX D
MOV A,D
ORA E
JNZ MINGO
JMP PLUSMI
;
;Go to next sector
;
NXTSEC: PUSH H
PUSH D
LHLD CURSEC
INX H
XCHG
LHLD SPT
CALL SUBDE
XCHG
JNC NEXTOK
LHLD CURTRK
INX H
XCHG
LHLD MAXTRK
CALL SUBDE
JNC TRASK
LXI D,0 ;WRAP TO START OF DISK
;
TRASK: XCHG
SHLD CURTRK
LXI H,1
;
NEXTOK: SHLD CURSEC
POP D
POP H
RET
;
;Tell what group, displacement, track, sector, physical sector
;
INQ: CALL INQSUB
JMP PROMPT
;
;Position inquiry subroutine
;Executed via: G S or T (with no operands)
;
INQSUB: PUSH H
LHLD SYSTRK
XCHG
LHLD CURTRK
CALL SUBDE
JC NOGRP
CALL ILPRT
DB 'G=',0
LHLD GROUP
MOV B,H
MOV C,L
CALL HEXB
MVI A,':'
CALL TYPE
LDA GRPDIS
CALL HEX
MVI A,','
CALL TYPE
;
NOGRP: CALL ILPRT
DB ' T=',0
LHLD CURTRK
CALL DEC
CALL ILPRT
DB ', S=',0
LHLD CURSEC
CALL DEC
CALL ILPRT
DB ', PS=',0
LHLD PHYSEC
CALL DEC
CALL CRLF
POP H
RET
;
CHG: MOV A,M ;GET TYPE (HEX, ASCII)
CALL UPCASE
PUSH PSW ;SAVE "H" OR "A"
INX H
CALL DISP ;GET, VALIDATE DISP TO DE
INX H
LXI B,0 ;SHOW NO 'THRU' ADDR
CPI '-' ;TEST DELIM FR. DISP
JNZ CHGNTH ;NO THRU
PUSH D ;SAVE FROM
CALL DISP ;GET THRU
INX H ;SKIP END DELIM
MOV B,D
MOV C,E ;BC = THRU
POP D ;GET FROM
JMP CHGAH
;
CHGNTH: CPI ','
JNZ WHAT
;
CHGAH: POP PSW
CPI 'H'
JZ CHGHEX
CPI 'A'
JNZ WHAT
;
;Change ASCII
CHGALP: MOV A,M
CPI CR
JZ PROMPT
CPI ';'
JZ PROMPT
LDAX D
CPI ' '
JC CHGAHX
CPI 7EH
JNC CHGAHX
JMP CHGA2
;
CHGAHX: CALL BHEX
JMP CHGA3
;
CHGA2: CALL TYPE
;
CHGA3: SHLD BACK ;IN CASE "THRU"
CALL GETVAL ;ASCII OR <HEX>
STAX D ;UPDATE CHAR
INX H ;TO NEXT INPUT CHAR
;See if 'THRU' requested
MOV A,C
ORA A
JZ CHANTH
CMP E ;DONE?..
JZ PROMPT ;..YES
LHLD BACK
;
CHANTH: INR E
JNZ CHGALP
MOV A,M
CPI CR
JZ PROMPT
CPI ';'
JZ PROMPT
JMP WHAT
;
;Change hex
;
CHGHCM: INX H
;
CHGHEX: MOV A,M
CPI CR
JZ PROMPT
CPI ';'
JZ PROMPT
CPI ',' ;DELIM?
JZ CHGHCM
PUSH D
SHLD HEXAD ;IN CASE 'THRU'
CALL HEXIN ;POSITIONS TO DELIM
MOV A,E ;GET VALUE
POP D ;..ADDR
PUSH PSW ;SAVE VALUE
LDAX D ;GET OLD
CALL HEX ;ECHO IN HEX
POP PSW ;GET NEW
STAX D ;SAVE NEW
MOV A,C ;SEE IF 'THRU'
ORA A
JZ CHHNTH ;..NO.
CMP E ;..YES, DONE?
JZ PROMPT
LHLD HEXAD ;..NO: MORE
;
CHHNTH: INR E
JNZ CHGHEX
MOV A,M
CPI CR
JZ PROMPT
CPI ';'
JZ PROMPT
JMP WHAT
;
DOREAD: LDA NOTPOS
ORA A
JNZ CANTRD
CALL READ
JMP PROMPT
;
CANTRD: XRA A
STA QFLAG ;NOT QUIET
CALL ILPRT
DB '++Can''t read - not positioned',CR,LF
DB 'Position by:',CR,LF
DB 9,'Track then Sector, or',CR,LF
DB 9,'Group',CR,LF,0
JMP PROMPT
;
DORITE: CALL WRITE
JMP PROMPT
;
BHEX: PUSH PSW
MVI A,'<'
CALL TYPE
POP PSW
CALL HEX
MVI A,'>'
CALL TYPE
RET
;
HEXB: LDA DSM+1
ORA A
JZ HEXX
MOV A,B
CALL HEX
;
HEXX: MOV A,C
;
HEX: PUSH PSW
RAR
RAR
RAR
RAR
CALL NIBBL
POP PSW
;
NIBBL: ANI 0FH
CPI 10
JC HEXNU
ADI 7
;
HEXNU: ADI '0'
JMP TYPE
;
;Decimal output routine
;
DEC: PUSH B
PUSH D
PUSH H
LXI B,-10
LXI D,-1
;
DECOU2: DAD B
INX D
JC DECOU2
LXI B,10
DAD B
XCHG
MOV A,H
ORA L
CNZ DEC
MOV A,E
ADI '0'
CALL TYPE
POP H
POP D
POP B
RET
;
SPACE: MVI A,' '
JMP TYPE
;
ASTER: MVI A,'*'
JMP TYPE
;
;Inline print routine
;
ILPRT: XTHL
;
ILPLP: CALL CTLCS ;ABORT?
JZ PRMPTR
MOV A,M
CPI 1 ;PAUSE?
JNZ ILPOK
CALL CONIN
CPI 3 ;ABORT?
JZ PRMPTR
JMP ILPNX
;
ILPOK: CALL TYPE
;
ILPNX: INX H
MOV A,M
ORA A
JNZ ILPLP
INX H
XTHL
RET
;
;DISP calls HEXIN, and validates a sector
;displacement, then converts it to an address
;
DISP: CALL HEXIN
PUSH PSW ;SAVE DELIMITER
MOV A,D
ORA A
JNZ BADISP
MOV A,E
ORA A
JM BADISP
ADI 80H ;TO POINT TO BUFFER AT BASE+80H
MOV E,A
MVI D,BASE/256
POP PSW ;GET DELIM
RET
;
BADISP: XRA A
STA QFLAG
CALL ILPRT
DB '++BAD DISPLACEMENT (NOT 0-7F)'
DB CR,LF,0
JMP PRMPTR
;
HEXIN: LXI D,0
MOV A,M
CPI '#' ;DECIMAL?
JZ HDIN ;MAKE DECIMAL
;
HINLP: MOV A,M
CALL UPCASE
CPI CR
RZ
CPI ';'
RZ
CPI ','
RZ
CPI '-' ;'THRU'?
RZ
CPI '>'
RZ
INX H
CPI '0'
JC WHAT
CPI '9'+1
JC HINNUM
CPI 'A'
JC WHAT
CPI 'F'+1
JNC WHAT
SUI 7
;
HINNUM: SUI '0'
XCHG
DAD H
DAD H
DAD H
DAD H
ADD L
MOV L,A
XCHG
JMP HINLP
;
HDIN: INX H ;SKIP '.'
;
DECIN: LXI D,0
;
DINLP: MOV A,M
CALL UPCASE
CPI CR
RZ
CPI ';'
RZ
CPI ','
RZ
CPI '-' ;'THRU'?
RZ
INX H
CPI '0'
JC WHAT
CPI '9'+1
JNC WHAT
SUI '0'
PUSH H
MOV H,D
MOV L,E
DAD H ;X2
DAD H ;X4
DAD D ;X5
DAD H ;X10
ADD L
MOV L,A
MOV A,H
ACI 0
MOV H,A
XCHG
POP H
JMP DINLP
;
;Read in a console buffer full
;
RDBUF: CALL ILPRT
DB CR,LF,':',0
;
RDBF1: LXI H,INBUF
MVI B,0
;
RDBLP: CALL CONIN
MOV C,A ;SAVE FOR BS TEST
;
;Evaluate control characters
;
CPI 'U'-40H
JZ RDCTLU
;
CPI CR
JZ RDCR
;
CPI 'H'-40H
JZ RDBS
;
CPI 7FH
JZ RDBS
;
CPI 'R'-40H
JZ RDCTLR
;
CPI 'X'-40H
JZ RDCTLX
;
CPI ' '
JC RDBLP
;
MOV M,A
INX H
INR B
JM FULL
CALL TYPE
JMP RDBLP
;
FULL: DCR B
DCX H
MVI A,'*' ;SIGNAL WE'RE FULL
CALL TYPE
JMP RDBLP
;
;Got CR
;
RDCR: MOV M,A ;SAVE IT
CALL TYPE ;ECHO IT
MVI A,LF ;ECHO..
CALL TYPE ;..LF
LXI H,INBUF
RET
;
;Got DELETE or BS, echo if BS
;
RDBS: XRA A ;AT FRONT..
ORA B ;..OF LINE?
JZ RDCTLU ;..YES, ECHO ^U
DCX H
DCR B
MOV A,C
CPI 'H'-40H ;BS?
JZ BACKUP ;ECHO THE BS
MOV A,M ;ECHO..
CALL TYPE ;..DELETED CHAR
JMP RDBLP
;
BACKUP: CALL WIPER
JMP RDBLP
;
RDCTLX: INR B
;
RDCX1: DCR B
JZ RDBF1
CALL WIPER
JMP RDCX1
;
WIPER: PUSH B
PUSH D
PUSH H
LXI D,BSMSG ;BACKSPACE, SPACE, BACKSPACE
MVI C,PRINT
CALL BDOS
POP H
POP D
POP B
RET
;
BSMSG: DB BS,' ',BS,'$'
;
;Got CTL-R, retype
;
RDCTLR: MVI M,CR
CALL CRLF
LXI H,INBUF
MVI B,0
;
RDCRL: MOV A,M
CPI CR
JZ RDBLP
CALL TYPE
INR B
INX H
JMP RDCRL
;
;Got CTL-U or backup to beginning of line.
;
RDCTLU: MVI A,'^'
CALL TYPE
MVI A,'U'
CALL TYPE
JMP RDBUF
;
CRLF: MVI A,CR
CALL TYPE
MVI A,LF
JMP TYPE
;
UPCASE: CPI 60H
RC
ANI 5FH ;MAKE UPPER CASE
RET
;
CONST: PUSH B
PUSH D
PUSH H
VCONST: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
POP D
POP B
RET
;
CONIN: PUSH B
PUSH D
PUSH H
VCONIN: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
POP D
POP B
RET
;
;Console out with TAB expansion
;
TYPE: PUSH B
PUSH D
PUSH H
MOV C,A ;FOR OUTPUT ROUTINE
CPI TAB
JNZ TYPE2
;
TYPTAB: MVI A,' '
CALL TYPE
LDA TABCOL
ANI 7
JNZ TYPTAB
JMP TYPRET
;
;Filter out control characters to
;prevent garbage during view of file
;
TYPE2: CPI ' '
JNC TYPEQ
CPI CR
JZ TYPEQ
CPI LF
JNZ TYPNCR
;
TYPEQ: LDA QFLAG
ORA A
VCONOT: CZ $-$ ;ADDR FILLED IN BY 'INIT'
;
;Update column used in tab expansion
MOV A,C ;GET CHAR
CPI CR
JNZ TYPNCR
MVI A,0
STA TABCOL
JMP TYPLST
;
TYPNCR: CPI ' ' ;CTL CHAR?
JC TYPLST ;..NO CHANGE IN COL
LDA TABCOL
INR A
STA TABCOL
;
TYPLST: LDA PFLAG
ANI 1
CNZ LIST ;FROM C REG.
;
TYPRET: POP H
POP D
POP B
RET
;
LIST: PUSH B ;SAVED REGS
PUSH D
PUSH H
VLIST: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
POP D
POP B
RET
;
HOME: PUSH H
VHOME: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
RET
;
;Set track # in DE
;
SETTRK: PUSH H
LHLD MAXTRK
CALL SUBDE
POP H
JC OUTLIM
XCHG
SHLD CURTRK
XCHG
MOV B,D
MOV C,E
PUSH H
VSETRK: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
RET
;
SETSEC: PUSH H
PUSH D
LHLD SYSTRK
XCHG
SHLD CURSEC
LHLD CURTRK
CALL SUBDE
POP B
MOV H,B
MOV L,C
JNC NOTSYS
LDA FIRST0 ;SEE IF FIRST SEC 0
ORA A
JNZ GSTSEC ;NO, JUMP AWAY
DCX H ;YES, SO DECREMENT
JMP GSTSEC ; REQUESTED, THEN GO
;
NOTSYS: LHLD SECTBL
XCHG
DCX B
VSCTRN: CALL $-$ ;ADDR FILLED IN BY 'INIT'
LDA SPT+1 ;IF SPT<256 (HI-ORD = 0)
ORA A ; THEN FORCE 8-BIT TRANSLATION
JNZ VSCTR1 ; ELSE KEEP ALL 16 BITS
MOV H,A
;
VSCTR1: LDA VER2FL ;SEE IF VERSION 2.x
ORA A ;SET FLAGS
JNZ GSTSEC ;JUMP IF CP/M 2.x
MVI H,0 ;CP/M 1.4 GOOD TO ONLY 8 BITS
MOV L,C ;MOST BIOS'S RETURN THE
; PHYSICAL SEC # IN REG C
GSTSEC: SHLD PHYSEC ;THIS MAY BE REDUNTANT IN
; MOST 1.4 VERSIONS, BUT
; SHOULD CAUSE NO PROBLEMS
MOV B,H
MOV C,L
VSTSEC: CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
RET
;
OUTLIM: XRA A
STA QFLAG
CALL ILPRT
DB '++not within tracks 0-',0
PUSH H
LHLD MAXTRK
CALL DEC
POP H
CALL ILPRT
DB '++'
DB CR,LF,0
CALL NORITE
JMP PRMPTR
;
SETDMA: JMP $-$ ;ADDR FILLED IN BY 'INIT'
;
READ: MVI A,1
STA WRFLG
PUSH H
VREAD: CALL $-$ ;ADDR FILLED IN BY 'INIT'
ORA A
JZ READOK
XRA A
STA QFLAG
CALL ILPRT
DB '++READ failed, sector may be invalid++'
DB CR,LF,0
;
READOK: POP H
RET
;
WRITE: LDA WRFLG
ORA A
JNZ PWRITE
;
BADW: XRA A
STA QFLAG
CALL ILPRT
DB '++CANNOT WRITE UNLESS READ ISSUED'
DB CR,LF,0
JMP EXPL
;
PWRITE: PUSH H
MVI C,1 ;FORCE WRITE TYPE 1 IN CASE 2.x DEBLOCK USED
VWRITE: CALL $-$ ;ADDR FILLED IN BY 'INIT'
ORA A
JZ WRITOK
XRA A
STA QFLAG
CALL ILPRT
DB '++WRITE failed++',CR,LF,0
;
WRITOK: POP H
RET
;
;Help
;
HELP: CALL ILPRT
DB 'Operands in brackets [...] are optional'
DB CR,LF
DB 'Numeric values: ''n'' are decimal, ''x'' hex'
DB CR,LF,CR,LF
DB '+[n] step in [n] sectors;'
DB CR,LF
DB '-[n] step out [n] sectors'
DB CR,LF
DB '# print disk parameters for curr drive.'
DB CR,LF
DB '=xxx search for ASCII xxx from curr sector.'
DB CR,LF
DB ' Caution: upper/lower case matters.'
DB CR,LF
DB ' Use <xx> for hex:'
DB CR,LF
DB ' To find "IN 0" use: =<db><0> or'
DB CR,LF
DB ' "(tab)H,0(CR)(LF)" use: =<9>H,0<D><A>'
DB CR,LF
DB '< save current sector into mem. buff.'
DB CR,LF
DB '> restore saved sector'
DB CR,LF
DB '? give help'
DB CR,LF
DB 'A[ff,tt] ASCII dump'
DB CR,LF,CR,LF
DB '(Type any char. to continue)'
DB 1,CR,LF,CR,LF
DB 'C Change:'
DB CR,LF
DB ' CHaddr,byte,byte... (hex)'
DB CR,LF
DB ' or CAaddr,data... (Ascii)'
DB CR,LF
DB ' <xx> Allowed for imbedded hex.'
DB CR,LF
DB ' or CHfrom-thru,byte e.g. ch0-7f,e5'
DB CR,LF
DB ' or CAfrom-thru,byte'
DB CR,LF
DB 'D[ff,tt] Dump (hex+ASCII)'
DB CR,LF
DB 'Fn.t Find file'
DB CR,LF
DB 'Gnn CP/M Allocation Group nn'
DB CR,LF
DB 'H[ff,tt] hex dump'
DB CR,LF
DB 'L Log in drive'
DB CR,LF
DB 'Lx Log in drive x'
DB CR,LF
DB 'M[nn] Map [from group nn]'
DB CR,LF,CR,LF
DB '(Type any char. to continue)'
DB 1,CR,LF,CR,LF
DB 'N New disk'
DB CR,LF
DB 'P Toggle printer switch'
DB CR,LF
DB 'Q Quiet mode (no msgs)'
DB CR,LF
DB 'R Read current sector'
DB CR,LF
DB 'Snn Sector nn'
DB CR,LF
DB 'Tnn Track nn'
DB CR,LF
DB 'Unn Set User nn for Find command (CP/M-2 only)'
DB CR,LF
DB 'V[nn] View [nn] ASCII sectors'
DB CR,LF
DB 'W Write current sector'
DB CR,LF
DB 'X Exit program'
DB CR,LF
DB 'Y Yank current sector into sequential memory'
DB CR,LF
DB 'Z[nn] Sleep [nn tenths]'
DB CR,LF
DB '/[nn] Repeat [nn (decimal) times]'
DB CR,LF,CR,LF
DB '(Type any char. to continue)'
DB 1,CR,LF,CR,LF
DB 'Cancel a function with C or Ctl-C.'
DB CR,LF
DB 'Suspend output with S or Ctl-S.'
DB CR,LF
DB 'Separate commands with ";".'
DB CR,LF
DB ' Example: g0'
DB CR,LF
DB ' +;d;z#20;/'
DB CR,LF
DB ' would step in, dump, sleep 2 sec, '
DB CR,LF
DB ' and repeat until control-c typed.'
DB CR,LF
DB 'All "nn" usage except "/", "T", and "S" are'
DB CR,LF
DB ' HEX. Use #nn for decimal.'
DB CR,LF,CR,LF
DB 'See DU.DOC for complete examples.'
DB CR,LF,CR,LF,0
JMP PROMPT
;
;********************************
;* *
;* Utility Subroutines *
;* *
;********************************
;
GRPCMP: MOV A,C
INR D
DCR D
JZ CMP8
CMP M
INX H
RNZ
MOV A,B
;
CMP8: CMP M
RET
;
;2's complement HL ==> HL
;
NEG: MOV A,L
CMA
MOV L,A
MOV A,H
CMA
MOV H,A
INX H
RET
;
;HL/2 ==> HL
;
ROTRHL: ORA A
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
RET
;
;Collect the number of '1' bits
;in A as a count in C
;
COLECT: MVI B,8
;
COLOP: RAL
JNC COSKIP
INR C
;
COSKIP: DCR B
JNZ COLOP
RET
;
;HL-DE ==> HL
;
SUBDE: MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
RET
;
;Quick Kludge multiply
;HL=DE ==> HL
;
MULT: PUSH B
PUSH D
XCHG
MOV B,D
MOV C,E
MOV A,B
ORA C
JNZ MULCON
LXI H,0 ;FILTER SPECIAL CASE
JMP MLDONE ; OF MULTIPLY BY 0
;
MULCON: DCX B
MOV D,H
MOV E,L
;
MULTLP: MOV A,B
ORA C
JZ MLDONE
DAD D
DCX B
JMP MULTLP
;
MLDONE: POP D
POP B
RET
;
;Routine to fill in disk params
;with every drive change
;
LOGIT: LDA VER2FL
ORA A ;IF NOT CP/M 2.x THEN
JZ LOG14 ; DO IT AS 1.4
LXI D,DPB ; THEN MOVE TO LOCAL
MVI B,DPBLEN ; WORKSPACE
CALL MOVE
JMP LOGCAL
;
LOG14: LHLD BDOS+1 ;FIRST FIND 1.4 BDOS
MVI L,0
LXI D,DPBOFF ;THEN OFFSET TO 1.4'S DPB
DAD D
MVI D,0 ;SO 8 BIT PARMS WILL BE 16
MOV E,M ;NOW MOVE PARMS
INX H
XCHG
SHLD SPT
XCHG
MOV E,M
INX H
XCHG
SHLD DRM
XCHG
MOV A,M
INX H
STA BSH
MOV A,M
INX H
STA BLM
MOV E,M
INX H
XCHG
SHLD DSM
XCHG
MOV E,M
INX H
XCHG
SHLD AL0
XCHG
MOV E,M
XCHG
SHLD SYSTRK
;
LOGCAL: LXI H,GRPDIS
MOV A,M
PUSH PSW
LDA BLM
MOV M,A
PUSH H
LHLD DSM
XCHG
CALL GTKSEC
SHLD MAXSEC
XCHG
SHLD MAXTRK
POP H
POP PSW
MOV M,A
RET
;
;Temporary storage area
;
BUFAD: DW BASE+100H ;FORCES INITIAL READ
HEXAD: DW 0 ;TO RE-FETCH A VALUE
TOGO: DW 0FFFFH ;REPEAT COUNT (FFFF=CONT)
TWOUP: DB 0
PFLAG: DB 0 ;1=PRINT
GROUP: DW 0
GRPDIS: DB 0
SAVEFL: DB 0
CURTRK: DW 0
CURSEC: DW 1
PHYSEC: DW 1
TABCOL: DB 0
FILECT: DW 0
DIRPOS: DB 0
FINDFL: DB 0 ;1=MUST POSITION AFTER FIND
FTSW: DB 1 ;SEARCH W/O INCREMENT
NOTPOS: DB 1 ;INITIALLY NOT POSITIONED
WRFLG: DB 0 ;MAY NOT WRITE UNTIL '+', '-',
; OR 'G' COMMAND
QFLAG: DB 0 ;QUIET? (0=NO)
FIRST0: DB 0 ;SETS TO 0 IF FIRST SEC # IS 0
DRIVE: DB 0
MAXTRK: DW 0
MAXSEC: DW 0
VER2FL: DB 0
SECTBL: DW 0 ;POINTER TO SECTOR SKEW TABLE
MFPTR: DW 0
DUPFLG: DB 0
YNKADR: DW 0 ;POINTER TO CURRENT YANK ADDRESS
;
BACK: DS 2 ;TO BACK UP IN "CA0-7F,X"
DUMTYP: DS 1
;
;--------------------------------------------------
;The disk parameter block
;is moved here from CP/M
;
DPB EQU $ ;DISK PARAMETER BLOCK (COPY)
SPT: DS 2
BSH: DS 1
BLM: DS 1
EXM: DS 1
DSM: DS 2
DRM: DS 2
AL0: DS 1
AL1: DS 1
CKS: DS 2
SYSTRK: DS 2
;
;End of disk parameter block
;--------------------------------------------------
;
SAVBUF: DS 128
INBUF: DS 128
;
;Directory read in here; also search work area
;
WORK EQU $
DIRECT EQU $
;
END