home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ZSYS
/
SIMTEL20
/
ZCPR3
/
DU3.MAC
< prev
next >
Wrap
Text File
|
2000-06-30
|
84KB
|
4,446 lines
; 03/01/85 Richard Conn: Replaced fixed in EDPLOT that was somehow lost
; (see lines suffixed by <RLC-3/1/85>
;
; 01/18/85 Modified by Jay Sage to incorporate a set of permanent
; macros. These macros can be invoked by the command tail
; when DU is invoked. They are copied from a space of 128
; bytes near the beginning of the code. The area is
; identified by a string of text to facilitate patching.
; The macros are listed one after another, separated by
; carriage return characters. Macros that are not to be
; defined must be present as carriage returns alone or the
; program will fail.
;
; PROGRAM: DU3
; AUTHOR: RICHARD CONN
; DERIVATION: DUTIL is derived from DU Version 7.5
; DU2 is derived from DUTIL Version 1.1
; DU3 is derived from DU2 Version 1.1
; VERSION: 1.0
; DATE: 20 June 84
; PREVIOUS VERSIONS: None
; NOTE: DU3 must be assembled using M80 (or equiv)
;
VERS EQU 13
Z3ENV EQU 0F400H
;
; DU3 is derived from --
; DU.ASM V7.5 Revised 1/23/81
; DISK UTILITY - By Ward Christensen
;
; Principal Authors of DU V7.5 are --
; WLC KBP RGF BRR
;
; Key comments from DU V7.5 and DU3 follow --
;
;This version of DU is compatible with CP/M 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.
;
;*************************************************
;* *
;* This program has been heavily modified *
;* to allow it to work without modification *
;* on all versions of CP/M 2.x. *
;* 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. *
;* *
;* Ron Fowler *
;* *
;*************************************************
;
;
; SYSLIB and Z3LIB References
;
ext z3vinit,envptr,cls,at,tinit,dinit,stndout,stndend,gotoxy
ext getspeed,getcrt,getmdisk,getmuser
ext codend
;
;System equates
;
BASE EQU 0 ;SET TO 4200H FOR HEATH OR TRS-80 ALTCPM
;
;CP/M Key Areas
;
FCB EQU BASE+5CH ;CP/M FCB
BDOS EQU BASE+5 ;CP/M BDOS ENTRY POINT
TBUFF EQU BASE+80H ;CP/M TEMPORARY DISK I/O BUFFER
TPA EQU BASE+100H ;CP/M TRANSCIENT PROGRAM AREA
;
; Some Key Variables in DU3
;
EOLCH equ ',' ;Marks logical end of line
SEPCH equ ' ' ;Argument Separator
MULCH equ '*' ;Multiplication Command
DIM equ 1 ;Enter DIM Mode for ILPRT
BRIGHT equ 2 ;Enter BRIGHT Mode for ILPRT
;
;CP/M BDOS Function Codes
;
PRINT EQU 9
GVERS EQU 12
RESETDK EQU 13 ;RESET SYSTEM
SELDK EQU 14 ;SELECT DISK
CLOSEF EQU 16 ;CLOSE FILE
SRCHF EQU 17 ;SEARCH FIRST
SRCHN EQU 18 ;SEARCH NEXT
DELF EQU 19 ;DELETE FILE
WRITEF EQU 21 ;WRITE BLOCK TO FILE
MAKEF EQU 22 ;CREATE FILE
SUSER EQU 32 ;SELECT USER
GETDSK EQU 25
GETDPB EQU 31
;
;CP/M 1.4 Offsets and Some Key Values
;
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
;
; MACROS INCLUDE:
;
; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO
;
DJNZ MACRO ?N ;;DECREMENT B AND JUMP ON NO ZERO
DCR B
JNZ ?N
ENDM
;
; END OF MACROS
;
;
;Beginning of Program
;
;
; Environment Definition
;
if z3env ne 0
;
; External ZCPR3 Environment Descriptor
;
jmp start
db 'Z3ENV' ;This is a ZCPR3 Utility
db 1 ;External Environment Descriptor
z3eadr:
dw z3env
;
; Space Added for Initial Macro Definitions -- block added by <JPS>
;
;label to help locate when patching
db 'INITIAL MACROS:'
imac0: db 'G0,D',cr ;macro 0
db '-D',cr ;macro 1
db '+D',cr ;macro 2
db cr ;macro 3
db cr ;macro 4
db cr ;macro 5
db cr ;macro 6
db cr ;macro 7
db cr ;macro 8
db cr ;macro 9
;fill rest of 128 bytes with nulls
if imac0 + 128 - $ gt 0
rept imac0 + 128 - $
db 0
endm
endif
; End of Block Added by <JPS>
start:
lhld z3eadr ;pt to ZCPR3 environment
;
else
;
; Internal ZCPR3 Environment Descriptor
;
MACLIB Z3BASE.LIB
MACLIB SYSENV.LIB
z3eadr:
jmp start
SYSENV
start:
lxi h,z3eadr ;pt to ZCPR3 environment
endif
;
; Start of Program -- Initialize ZCPR3 Environment
;
call z3vinit ;initialize the ZCPR3 Env and the VLIB Env
call tinit ;init terminal
LXI H,0 ;GET PTR TO CP/M STACK
DAD SP ;HL=SP
SHLD DUTSTK ;SAVE IT
;
call codend ;get free space
lxi d,100h ;open area
dad d ;large stack area
shld savbuf
dad d ;100H for SAVBUF
push h ;save ptr
mvi m,126 ;allow 126-char input line
inx h
inx h ;ptr to INBUF
shld inbuf
pop h ;pt to beginning
lxi d,400h ;large area for expansion
dad d
shld pinbuf ;ptr to PINBUF
dad d
shld ctemp ;ptr to CTEMP
dad d
shld ctempx ;ptr to CTEMPX
shld mtabl ;ptr to MACRO TABLE
lxi d,100h*10 ;10 macros
dad d
shld gbuff ;group save buffer
shld direct ;directory load buffer
;
lhld savbuf ;top of stack
sphl ; SET STACK
;
call getspeed
sta clock ;set clock speed
call getcrt ;get CRT data
inx h ;pt to screen size
mov a,m ;get it
sta pagsiz ;set page size
call getmdisk ;get max disk
sta mdisk ;and set it
call getmuser ;get max user
sta muser ;and set it
;
;Set up local jumps to BIOS
;
START1:
LHLD BASE+1 ;WARM BOOT POINTER
LXI D,3 ;READY FOR ADD
DAD D
SHLD VCONST+1 ;CON: Status
DAD D
SHLD VCONIN+1 ;CON: Input
DAD D
SHLD VCONOT+1 ;CON: Output
DAD D
SHLD VLIST+1 ;LST: Output
DAD D ;Skip PUNCH
DAD D ;Skip RDR
DAD D
SHLD VHOME+1 ;Home Disk
DAD D
SHLD VSELDK+1 ;Select Disk
DAD D
SHLD VSETRK+1 ;Set Track
DAD D
SHLD VSTSEC+1 ;Set Sector
DAD D
SHLD SETDMA+1 ;Set DMA Address
DAD D
SHLD VREAD+1 ;Read Block From Disk
DAD D
SHLD VWRITE+1 ;Write Block To Disk
DAD D ;Skip LISTST
DAD D
SHLD VSCTRN+1 ;CP/M 2.x Sector Translation Table
; JMP HELLO
;
;Initialization Complete -- Print Signon Message and Begin Command Processing
;
HELLO:
CALL GETSTP ;SET UP CP/M PARAMETERS
CALL INITP ;INITIALIZE BUFFER PARAMETERS
CALL ILPRT
DB 'DU3 - Disk Utility III, Version '
DB VERS/10+'0','.',(VERS MOD 10)+'0'
DB CR,LF,CR,LF
DB DIM,'Type ? for Help',BRIGHT
DB CR,LF,0
;
;Clear Editor Reference
;
XRA A
STA EDRUN ;EDITOR NOT RUNNING
;
;Save initial command line in INBUF
;
LXI H,TBUFF ;PT TO COMMAND LINE BUFFER
MOV A,M ;GET CHAR COUNTER
ora a ;check for no tail <JPS>
jnz ctail ;if not, no need to increment <JPS>
inr a ;allow for blank otherwise present <JPS>
ctail: ; <JPS>
INX H ;PT TO FIRST CHAR
ADD L ;COMPUTE LOCATION OF AFTER LAST CHAR
MOV L,A
MOV A,H
ACI 0
MOV H,A
MVI M,CR ;SET ENDING CR
LHLD INBUF ;PT TO BUFFER
XCHG ;... IN DE
LXI H,TBUFF+2 ;PT TO INPUT LINE (1 changed to 2 <JPS>)
MVI B,128 ;COPY BUFFER
CALL MOVE
;
;Establish Initial Position
;
LXI D,0 ;GROUP 0
CALL DEGROUP ;POSITION TO GROUP
CALL INQSUB ;PRINT POSITION
;
;Check for initial command
;
LHLD INBUF ;INPUT BUFFER
MOV A,M
CPI CR
JZ PRMPTR ;NO INITIAL COMMAND FROM COMMAND LINE
INX H ;PT TO FIRST CHAR
;
;Got initial command, set it up
;
MOV A,M ;GET FIRST CHAR
CPI '/' ;IF SLASH, PRINT INITIAL HELP (TOOLSET CONVENTION)
JZ IHELP ;PRINT INITIAL HELP INFO
XRA A
STA IHFLG ;SET NO INITIAL HELP
; line replaced <JPS>
; JMP PRMPTI ;PROCESS AS THOUGH COMMAND LINE WAS TYPED <JPS>
jmp prmpts ;allow processing of macros in command line <JPS>
;
;Input Command Line From User at Console
;
PRMPTR:
XRA A ;A=0
STA IHFLG ;Set No Initial Help
LDA EDRUN ;Check for Editor Running
ORA A
JNZ EDIT0 ;Reenter Editor
CALL SINBUF ;Save old INBUF into PINBUF
PRMPTE:
CALL RDBUF ;Read Input Line
PRMPTS: ;Entry when Command Line has Input <JPS>
CALL EXMAC ;Expand Macros
;
;Begin Processing Command Line in INBUF
; At this point, HL points to next character to process
;
PRMPTI:
MVI A,0FFH ;SET INFINITE LOOP COUNT
STA TOGO ;LOOP COUNT FOR MULTIPLE LOOPS
STA TOGO+1
;
;Minor Command Loop; This is the entry point for each individual command in
; a Command Line; Commands may be separated by semicolons in this manner
;
PROMPT EQU $
SETSTK:
SHLD STKSAV ;SAVE HL FOR STACK LOAD
LHLD SAVBUF ;RESET STACK
SPHL
LHLD STKSAV ;RESTORE HL
XRA A ;ZERO 2-UP PRINT FOR DUAL-COLUMN PRINT
STA TWOUP ;..SWITCH
MVI A,1
STA FTSW ;TELL SEARCH NOT TO INCR
PUSH H
LXI H,TBUFF ;SET NO-READ INPUT BUFFER ADDRESS
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
;
;Begin Command Evaluation -- Check for EOL and Capitalize
;
MOV A,M ;GET NEXT CHAR IN COMMAND LINE
INX H ;POINT TO FOLLOWING CHAR
CPI CR ;END OF LINE PHYSICALLY?
JZ PRMPTR ;INPUT NEW COMMAND LINE IF SO
CPI EOLCH ;END OF LINE LOGICALLY?
JZ PROMPT ;PROCESS NEXT ELEMENT IF SO
CALL UPCASE ;CAPITALIZE COMMAND
STA DUMTYP ;TYPE OF DUMP (A,D,H)
LXI D,CMDTBL ;PT TO COMMAND TABLE
CALL CMD ;PROCESS
JMP WHAT ;ERROR RETURN
;
;Command dispatcher
; If command not found, abort with error message
; If command file, process command with HL pting to next command char and
; A containing command letter
;
CMD:
PUSH H ;SAVE HL
MOV B,A ;COMMAND IN B
XCHG ;HL PTS TO COMMAND TABLE
CMDLP:
MOV A,M ;GET COMMAND
ORA A ;0=END OF TABLE
JZ CMDER
CMP B ;COMPARE COMMAND
JZ CMDGO
INX H ;PT TO ADR
INX H
INX H ;PT TO NEXT CMND
JMP CMDLP
CMDGO:
INX H ;PT TO ADDRESS LOW
MOV E,M
INX H ;PT TO ADDRESS HIGH
MOV D,M
POP H ;RESTORE HL
POP PSW ;CLEAR RETURN ADDRESS
MOV A,B ;COMMAND BACK INTO A
PUSH D ;PLACE ADDRESS ON STACK
RET ;"RUN COMMAND"
CMDER:
POP H ;RESTORE HL
MOV A,B ;RESTORE COMMAND CHAR IN CASE CMD RUN
RET ;... IMMEDIATELY AGAIN ON A NEW TABLE
;
;Macro Expansion Routine -- Expand Macros
;
EXMAC:
LHLD CTEMP ;BUILD INTO TEMPORARY BUFFER
XCHG
LHLD INBUF ;PT TO INPUT LINE
EXMAC1:
MOV A,M ;GET CHAR
CPI '0' ;SKIP IF LESS THAN '0'
JC EXMAC2
CPI '9'+1 ;CHECK FOR RANGE
JNC EXMAC2
INX H ;PT TO NEXT CHAR
PUSH H ;SAVE PTR TO NEXT CHAR IN LINE
SUI '0' ;CONVERT TO BINARY (0-9)
MOV B,A ;RESULT IN B
MVI C,0
LHLD MTABL ;PT TO BASE OF MACROS
DAD B ;PT TO MACRO
CALL COPYM ;COPY MACRO INTO LINE
DCX D ;BACK UP OVER <CR>
POP H ;GET PTR TO NEXT CHAR IN COMMAND LINE
EXMAC2:
MOV A,M ;GET CHAR
STAX D ;PUT CHAR
INX H ;PT TO NEXT
INX D
CALL MTEST ;TEST FOR END OF BUFFER
CPI CR ;DONE?
JZ EXMAC3
CPI EOLCH ;LOGICAL EOL?
JNZ EXMAC2
JMP EXMAC1 ;PROCESS NEXT COMMAND
EXMAC3:
LHLD CTEMP ;COPY COMMAND LINE BACK
XCHG
LHLD INBUF ;INTO INBUF
XCHG
CALL COPYCR ;COPY TO <CR>
LHLD INBUF ;PT TO INBUF
RET ;EXPANSION COMPLETE
;
;Copy Macro Into Command Line Buffer
;
COPYM:
MOV A,M ;GET CHAR
STAX D ;PUT CHAR
INX H ;PT TO NEXT
INX D
CALL MTEST ;CHECK FOR LIMIT
CPI CR ;END OF MACRO?
JNZ COPYM
RET
;
;Test for Buffer Full
;
MTEST:
PUSH H ;SAVE HL
PUSH PSW ;SAVE A
LHLD CTEMPX ;CHECK FOR END OF BUFFER
MOV A,H ;GET PAGE
CMP D ;CHECK PAGE
JZ MACERR
POP PSW ;GET A
POP H ;GET HL
RET
;
;Macro Command Expansion Error
;
MACERR:
CALL ILPRT
DB CR,LF,'Error -- Macro Expanded Command Line too Long',0
JMP PRMPTR ;NEW COMMAND
;
;Save INBUF into PINBUF for later processing by '@' command
;
SINBUF:
LHLD PINBUF ;PT TO PINBUF (PREVIOUS INBUF)
XCHG
LHLD INBUF ;PT TO INBUF
;
;Copy (HL) to (DE) until <CR> Encountered
;
COPYCR:
MOV A,M ;GET CHAR
STAX D ;PUT CHAR
INX H ;PT TO NEXT
INX D
CPI CR ;DONE?
JNZ COPYCR
RET
;
;Command Not Found Error
;
WHAT:
POP H ; RESTORE HL
CALL ILPRT
DB DIM,'Invalid Command at or after ',BRIGHT,0
MOV A,B ;GET COMMAND LETTER
CALL TYPE ;PRINT IT
JMP PRMPTR
;
;Memory full error
;
MEMFUL:
CALL ILPRT
DB '+++ Out of memory +++'
DB CR,LF,0
JMP PRMPTR
;
;COMMAND: E
;Edit Current Block
;
EROW EQU 6 ;FIRST ROW OF EDITOR DISPLAY
ECOL EQU 4 ;FIRST COL OF EDITOR DISPLAY
ECOLC EQU ECOL+16*3+2 ;FIRST COL OF EDITOR CHAR DISPLAY
ECURS EQU '>' ;EDITOR CURSOR
;
EDIT:
CALL SINBUF ;SAVE COMMAND LINE AS PREVIOUS
MVI A,0FFH
STA EDRUN ;EDITOR IS RUNNING
;
; SET UP ARROW KEYS
;
LHLD ENVPTR ;PT TO ENVIRONMENT DESCRIPTOR
LXI D,80H+10H ;PT TO ARROW KEY INFO
DAD D
LXI D,EDCURT ;PT TO CURSOR TABLE
MVI B,4 ;4 ARROW KEYS
EDITA:
MOV A,M ;GET CHAR
STAX D ;STORE CHAR
INX H ;PT TO NEXT
INX D ;PT TO NEXT ENTRY
INX D
INX D
DJNZ EDITA ;COUNT DOWN
;
; REENTER EDIT WITH PTRS RESET
; REFRESH EDIT SCREEN
;
EDIT0:
CALL CLS ;NEW SCREEN
CALL AT
DB 2,32 ;ROW 2, COL 32
CALL ILPRT ;BANNER
DB 'DU3 Block Editor',0
MVI H,EROW+9 ;POSITION FOR COMMAND DISPLAY
MVI L,1
CALL GOTOXY ;POSITION CURSOR
CALL ILPRT ;PRINT COMMAND SUMMARY
DB ' -- Movement --'
DB ' -------------- Operation ---------------',CR,LF
DB ' ^E '
DB DIM,'Enter: ',BRIGHT,'A',DIM,' ASCII Chars',BRIGHT
DB ' +',DIM,' Next Sector',BRIGHT,CR,LF
DB ' ^ '
DB DIM,' ',BRIGHT,'H',DIM,' Hex Numbers',BRIGHT
DB ' -',DIM,' Last Sector',BRIGHT,CR,LF
DB ' ^S <-+-> ^D '
DB ' '
DB ' ^C',DIM,' Exit DU3 ',BRIGHT
DB CR,LF
DB ' v '
DB 'C',DIM,' DU3 Command Line ',BRIGHT
DB ' ^R',DIM,' Rescreen ',BRIGHT,CR,LF
DB ' ^X '
DB 'X',DIM,' Exit Editor to DU3',BRIGHT
DB ' ^W',DIM,' Write Block',BRIGHT
DB 0
CALL AT
DB 2,65
CALL ILPRT
DB DIM,'Position:',BRIGHT,0
; JMP EDITCMD
;
; REFRESH SCREEN DISPLAY DATA ONLY
;
EDITR:
XRA A ;A=0
STA EINDEX ;SET INDEX TO 0 (FIRST ELEMENT)
STA EDERR ;SET NO PREVIOUS ERROR
CALL AT ;POSITION CURSOR
DB EROW-2,ECOL
CALL INQSUB ;PRINT POSITION DATA
CALL EDPLOT ;PLOT BUFFER DATA
;
; INPUT EDITOR COMMAND
;
EDITCMD:
CALL EDERCL ;CLEAR EDITOR INVALID COMMAND MESSAGE
EDITCMD1:
CALL AT ;POSITION FOR COMMAND LINE
DB 22,10
CALL ILPRT
DB DIM,'Edit Command? ',BRIGHT,BS,0
CALL CONIN ;GET CHAR
CALL UPCASE ;CAPITALIZE
MOV B,A ;COMMAND IN B
LXI D,EDCURT ;PROCESS CURSOR COMMANDS FIRST
CALL CMD ;PROCESS COMMAND
LXI D,ECMDTBL ;EDITOR COMMAND TABLE
CALL CMD ;PROCESS COMMAND
MVI A,0FFH ;SET ERROR FLAG
STA EDERR
CALL AT ;CLEAR ERROR MESSAGE
DB 23,15
CALL ILPRT
DB 'Invalid Command',0
JMP EDITCMD1
;
;Clear Editor Invalid Command Message
;
EDERCL:
LDA EDERR ;PREVIOUS ERROR?
ORA A ;0=NO
RZ
XRA A ;CLEAR FLAG
STA EDERR
CALL AT ;CLEAR ERROR MESSAGE
DB 23,15
CALL ILPRT
DB ' ',0
RET
;
;PLOT BUFFER DATA
;
EDPLOT:
MVI H,EROW ;SET ROW
MVI L,ECOL-1 ;SET COLUMN <RLC-3/1/85>
CALL GOTOXY ;POSITION CURSOR
XCHG ;POSITION IN DE
LXI H,TBUFF ;PT TO DATA
MVI B,8 ;8 LINES
EDIT00:
MVI C,16 ;16 ELEMENTS
CALL SPACE ;PRINT LEADING SPACE <RLC-3/1/85>
EDIT01:
MOV A,M ;GET BYTE
CALL HEX ;PRINT AS HEX
CALL SPACE ;PRINT 1 SPACE
INX H ;PT TO NEXT
DCR C ;COUNT DOWN
JNZ EDIT01
XCHG ;POSITION AGAIN
INR H ;NEXT ROW
CALL GOTOXY
XCHG
DCR B ;COUNT DOWN
JNZ EDIT00
MVI H,EROW ;RESET ROW
MVI L,ECOLC ;RESET COL
CALL GOTOXY ;POSITION CURSOR
XCHG ;POSITION IN DE
LXI H,TBUFF ;PT TO DATA
MVI B,8 ;8 LINES
EDIT02:
CALL ASTER ;PRINT BAR
MVI C,16 ;16 ELEMENTS
EDIT03:
MOV A,M ;GET BYTE
ANI 7FH ;MASK MSB
CPI 7FH ;7FH IS DOT
JZ EDIT7F
CPI ' ' ;SPACE OR MORE?
JNC EDIT04
EDIT7F:
MVI A,'.' ;PRINT DOT
EDIT04:
CALL TYPE ;PRINT BYTE
INX H ;PT TO NEXT
DCR C ;COUNT DOWN
JNZ EDIT03
CALL ASTER ;PRINT ENDING BAR
XCHG ;POSITION AGAIN
INR H ;NEXT ROW
CALL GOTOXY
XCHG
DCR B ;COUNT DOWN
JNZ EDIT02
CALL EDCUR ;POSITION CURSOR
RET
;
;EDITOR COMMAND TABLE
;
ECMDTBL:
DB CR ;NOP
DW EDITCMD
DB 'C'-'@' ;^C = EXIT DU3
DW EDCC
DB 'R'-'@' ;^R = REFRESH
DW EDIT0
DB 'E'-'@' ;^E=UP
DW EDUP
DB 'X'-'@' ;^X=DOWN
DW EDDOWN
DB 'D'-'@' ;^D=RIGHT
DW EDRIGHT
DB 'S'-'@' ;^S=LEFT
DW EDLEFT
DB 'W'-'@' ;WRITE BLOCK
DW EDITWR
DB ' ' ;NOP
DW EDITCMD
DB '+' ;ADVANCE
DW EDITPLUS
DB '-' ;BACKUP
DW EDITMINUS
DB 'A' ;CHANGE ALPHA
DW EDITALP
DB 'C' ;COMMAND LINE
DW EDITCL
DB 'H' ;CHANGE HEX
DW EDITHEX
DB 'X' ;EXIT
DW EDITX
DB 0 ;END OF TABLE
;
; ARROW KEY DEFINITONS FROM TCAP
;
EDCURT:
DB 0 ;0 INDICATES NO ARROW KEYS
DW EDUP
DB 0
DW EDDOWN
DB 0
DW EDRIGHT
DB 0
DW EDLEFT
DB 0 ;END OF TABLE
;
;EDITOR BUFFERS
;
EINDEX:
DS 1 ;INDEX ENTRY
EDERR:
DS 1 ;ERROR FLAG
EDRUN:
DS 1 ;FLAG SAYING THAT EDITOR IS RUNNING
;
;Write Block to Disk
;
EDITWR:
CALL EDERCL ;CLEAR ERROR LINE
CALL WRITE ;WRITE BLOCK
CALL AT
DB 23,15 ;MESSAGE
CALL ILPRT
DB 'Block Written',0
MVI A,0FFH ;SET ERROR
STA EDERR
JMP EDITCMD1
;
;Enter ASCII Chars
;
EDITALP:
CALL EDERCL ;CLEAR ERROR LINE
CALL AT
DB 22,35
CALL ILPRT
DB DIM,'Enter Text (<hh> for Hex)',BRIGHT
DB CR,LF,' --> ',0
CALL RDBUF1 ;INPUT TEXT WITHOUT PROMPT
CALL EDPRCL ;CLEAR PROMPT LINE
LDA EINDEX ;PT TO POSITION
LXI D,TBUFF ;COMPUTE OFFSET
ADD E
MOV E,A
MOV A,D
ACI 0
MOV D,A ;DE PTS TO BYTE, HL PTS TO TEXT
EDITA1:
MOV A,M ;GET CHAR
CPI CR ;EOL?
JZ EDITA2 ;REFRESH SCREEN
CALL GETVAL ;GET ASCII OR <HEX> VALUE
STAX D ;UPDATE BYTE
INX H ;PT TO NEXT INPUT CHAR
INR E ;PT TO NEXT BUFFER BYTE
JNZ EDITA1
EDITA2:
CALL EDPLOT ;REPLOT
JMP EDITCMD1 ;DONE-REFRESH SCREEN
;
;Enter Numbers
;
EDITHEX:
CALL EDERCL ;CLEAR ERROR LINE
CALL AT
DB 22,35
CALL ILPRT
DB DIM,'Enter Hex Numbers (#nn for Dec)'
DB BRIGHT
DB CR,LF,' --> ',0
CALL RDBUF1 ;INPUT TEXT WITHOUT PROMPT
CALL EDPRCL ;CLEAR PROMPT LINE
LDA EINDEX ;PT TO POSITION
LXI D,TBUFF ;COMPUTE OFFSET
ADD E
MOV E,A
MOV A,D
ACI 0
MOV D,A ;DE PTS TO BYTE, HL PTS TO TEXT
EDITH1:
MOV A,M ;GET HEX DIGIT
CPI CR ;EOL?
JZ EDITA2 ;REFRESH SCREEN
CPI ' ' ;SKIP SPACES
JNZ EDITH2
INX H ;SKIP SPACE
JMP EDITH1
EDITH2:
PUSH D ;SAVE PTR
CALL HEXIN ;GET VALUE AND POSITION HL
MOV A,E ;... IN A
POP D ;GET PTR
STAX D ;PUT BYTE
INR E ;ADVANCE TO NEXT BYTE
JNZ EDITH1
JMP EDITA2 ;DONE-REFRESH
;
;CLEAR PROMPT LINE
;
EDPRCL:
CALL AT ;PROMPT LINE
DB 22,35
MVI B,40 ;40 POSITIONS
CALL EDPCL
CALL AT ;USER INPUT
DB 23,1
MVI B,79 ;79 POSITIONS
EDPCL:
CALL SPACE ;CLEAR PROMPT LINE WITH SPACES
DCR B
JNZ EDPCL
RET
;
;Enter Command Line from Editor
;
EDITCL:
CALL EDERCL ;CLEAR ERROR LINE
CALL CRLF ;NEW LINE
JMP PRMPTE ;GET COMMAND LINE FROM USER
;
;Advance to Next Block
;
EDITPLUS:
CALL NXTSEC ;ADVANCE SECTORS
EDITP1:
PUSH H
LHLD CURSEC
XCHG
CALL SETSEC ;SET SECTOR
LHLD CURTRK
XCHG
CALL SETTRK ;SET TRACK
POP H
CALL READ ;READ IN BLOCK
CALL CLCSUB ;CALCULATE GROUP DATA
JMP EDITR ;REFRESH DATA
;
;Backup to Last Block
;
EDITMINUS:
CALL LSTSEC ;BACKUP BLOCK
JMP EDITP1
;
;Exit EDIT Mode
;
EDITX:
XRA A
STA EDRUN ;EDITOR IS NOT RUNNING NOW
CALL EDERCL ;CLEAR ERROR LINE
JMP PRMPTR
;
;Exit DU3
;
EDCC:
CALL EDERCL ;CLEAR ERROR LINE
JMP EXIT
;
;EDIT MOVE: UP
;
EDUP:
CALL EDCCUR ;CLEAR CURSOR
LDA EINDEX ;BACKUP INDEX BY 16
SUI 16
;
;Common EDIT MOVE Routine - on input, A=new index
;
EDMOVE:
ANI 7FH ;MOD 128
STA EINDEX
CALL EDCUR ;SET CURSOR
JMP EDITCMD
;
;EDIT MOVE: DOWN
;
EDDOWN:
CALL EDCCUR ;CLEAR CURSOR
LDA EINDEX ;INCREMENT INDEX BY 16
ADI 16
JMP EDMOVE ;COMMON ROUTINE
;
;EDIT MOVE: RIGHT
;
EDRIGHT:
CALL EDCCUR ;CLEAR CURSOR
LDA EINDEX ;INCREMENT INDEX BY 1
INR A
JMP EDMOVE ;COMMON ROUTINE
;
;EDIT MOVE: LEFT
;
EDLEFT:
CALL EDCCUR ;CLEAR CURSOR
LDA EINDEX ;DECREMENT INDEX BY 1
DCR A
JMP EDMOVE ;COMMON ROUTINE
;
;EDIT SUBROUTINE: EDCUR
; Position Editor Cursor at EINDEX
;EDIT SUBROUTINE: EDCCUR
; Clear Editor Cursor at EINDEX
;
EDCUR:
PUSH H ;SAVE HL
MVI C,ECURS ;CURSOR CHAR
CALL EDSETCUR
CALL AT ;UPDATE DATA
DB 2,75
LDA EINDEX ;PT TO BYTE AT CURSOR
LXI H,TBUFF
ADD L
MOV L,A
MOV A,H
ACI 0
MOV H,A ;HL PTS TO BYTE AT CURSOR
MOV A,M ;GET BYTE
CALL HEX ;PRINT AS HEX
CALL SPACE
MOV A,M ;GET BYTE
POP H ;RESTORE HL
ANI 7FH ;MASK
CPI 7FH ;7FH IS DOT
JZ EDC7F
CPI ' ' ;OUTPUT CHAR OR DOT
JNC TYPE
EDC7F:
MVI A,'.' ;DOT
JMP TYPE
EDCCUR:
MVI C,' ' ;CLEAR CURSOR
EDSETCUR:
CALL EDROW ;COMPUTE ROW
ANI 0FH ;COMPUTE COL MOD 16
MOV B,A ;RESULT IN B
ADD A ;*2
ADD B ;*3
ADI ECOL ;ADD IN COL
DCR A ;SUBTRACT 1
MOV L,A ;COL POSITION SET
CALL GOTOXY ;POSITION CURSOR
MOV A,C ;OUTPUT CHAR
JMP TYPE
;
;Compute Row from EINDEX
;
EDROW:
LDA EINDEX ;GET INDEX
MOV B,A ;SAVE IN B
RRC ;DIVIDE BY 16
RRC
RRC
RRC
ANI 0FH ;MASK FOR LSB ONLY
ADI EROW ;COMPUTE ROW
MOV H,A ;ROW SET
MOV A,B ;GET INDEX
RET
;
;COMMAND: @
;Repeat Previous Command Line
;
PCMD:
MOV A,M ;GET NEXT CHAR
CPI CR ;SHOULD BE <CR>
JZ PCMD1
CALL ILPRT
DB CR,LF,'Warning: Remainder of Command Line after "@" Deleted',0
PCMD1:
CALL ILPRT
DB CR,LF,DIM,'Command --',BRIGHT,CR,LF,0
LHLD INBUF ;COPY INTO INBUF
XCHG
LHLD PINBUF ;GET PREVIOUS COMMAND
PCMD2:
MOV A,M ;GET CHAR
STAX D ;PUT CHAR
INX H ;PT TO NEXT
INX D
CPI CR ;END OF LINE?
PUSH PSW ;SAVE FLAG
CALL TYPE ;PRINT CHAR
POP PSW ;GET FLAG
JNZ PCMD2
MVI A,LF ;<LF>
CALL TYPE
LHLD INBUF ;RESTART COMMAND PROCESSING
JMP PRMPTI ;INCLUDE LOOP CAPABILITY
;
;COMMAND: :
;Define or Print Macro
;:n<text> Defines Macro n, 0<=n<=9; ::n Prints Macro n, 0<=n<=9
;
MAC:
MOV A,M ;GET NEXT CHAR
CALL UPCASE ;CAPITALIZE
CPI 'P' ;PRINT MACRO?
JNZ MACROD ;IF NOT, DEFINE MACRO
INX H ;PT TO MACRO NUMBER
MOV A,M ;GET IT
CALL UPCASE ;CAPITALIZE
CPI '@' ;PRINT PREVIOUS COMMAND?
JZ PCPR
PUSH PSW ;SAVE A
call cls
cz crlf
CALL ILPRT
DB DIM,'Macro Definitions --',BRIGHT,0
POP PSW ;GET A
CPI 'A' ;PRINT ALL MACROS?
JZ AMACPR
CALL MNUM ;CHECK FOR VALID NUMBER AND RETURN # IN D
INX H ;PT TO CHAR AFTER MACRO NUMBER
CALL MACPR ;PRINT MACRO WHOSE NUMBER IS IN D
JMP PROMPT
;
;Print Previous Command
;
PCPR:
INX H ;PT TO CHAR AFTER '@'
LXI D,PROMPT ;SET UP RET ADR
PUSH D ;RETURN ADR ON STACK
PUSH H ;SAVE PTR
CALL ILPRT
DB DIM,'Previous Command Line Definition --',BRIGHT
DB CR,LF,'@: ',0
LHLD PINBUF ;PT TO PREVIOUS COMMAND
JMP MPRINT ;USE MACRO PRINT FACILITY
;
;Print All Macros
;
AMACPR:
INX H ;PT TO CHAR AFTER 'A'
MVI D,0 ;SET FOR FIRST MACRO
AMPRL:
CALL MACPR ;PRINT MACRO WHOSE NUMBER IS IN D
INR D ;INCREMENT MACRO NUMBER
MOV A,D ;GET VALUE
CPI 10 ;DONE?
JNZ AMPRL
JMP PROMPT ;CONTINUE PROCESSING
;
;Print Macro Whose Number (0-9) is in D
;
MACPR:
PUSH H ;SAVE PTR
CALL ILPRT ;PRINT HEADER
DB CR,LF,DIM,0
MOV A,D ;GET NUMBER
ADI '0' ;CONVERT TO ASCII
CALL TYPE ;PRINT
CALL ILPRT
DB ': ',BRIGHT,0
LHLD MTABL ;PT TO TABLE OF MACROS
MVI E,0 ;PAGE OFFSET OF ZERO; MACRO NUMBER ALREADY IN D
DAD D ;PT TO MACRO
MPRINT:
MOV A,M ;GET CHAR
INX H ;PT TO NEXT
CPI CR ;END OF MACRO?
PUSH PSW ;SAVE FLAG
CALL TYPE ;PRINT CHAR
POP PSW ;GET FLAG
JNZ MPRINT
MVI A,LF ;<LF>
CALL TYPE
POP H ;GET PTR TO NEXT CHAR
RET
;
;Check char in A for valid Macro Number (0-9), print error message if
; not, return number in D if so
;
MNUM:
SUI '0' ;CONVERT TO 0-9
JC MNERR ;ERROR IF LESS
CPI 10 ;RANGE?
JNC MNERR
MOV D,A ;RESULT IN D
RET
MNERR:
CALL ILPRT
DB CR,LF,'Invalid Macro Number Specified in Command',0
JMP PRMPTR ;NEW COMMAND
;
;Define Macro
;
MACROD:
CALL MNUM ;CHECK NUMBER AND RETURN IN D
INX H ;PT TO CHAR AFTER MACRO NUMBER
PUSH H ;SAVE PTR
LHLD MTABL ;PT TO MACRO TABLE
MVI E,0 ;SET EVEN PAGE
DAD D ;PT TO MACRO ENTRY IN HL
XCHG ;... IN DE
POP H ;PT TO MACRO TEXT
CALL COPYCR ;COPY TO <CR>
JMP PRMPTR ;NEW COMMAND
;
;COMMAND: !
;Delay for user input
;
UWAIT:
CALL WAIT ; USE WAIT ROUTINE
JMP PROMPT
;
;COMMAND: #
;Print disk statistics
;
STATS:
PUSH H ;SAVE POINTER TO NEXT COMMAND
call cls
cz crlf
CALL ILPRT
DB DIM
DB ' -- Queue Information --',BRIGHT,CR,LF
DB CR,LF
DB 0
CALL QSTATS ;PRINT STATUS INFO
CALL ILPRT
DB CR,LF
DB DIM
DB ' -- Disk Information --',BRIGHT,CR,LF
DB CR,LF
DB DIM,'Disk Drive: ',BRIGHT,0
LDA DRIVE
ADI 'A' ;CONVERT TO ASCII
CALL TYPE ;PRINT DRIVE LETTER
CALL ILPRT
DB CR,LF,DIM,'Tracks: ',BRIGHT,0
LHLD MAXTRK ;PRINT NUMBER OF TRACKS
INX H
CALL DEC
CALL ILPRT
DB CR,LF,DIM,'Sectors/Track: ',BRIGHT,0
LHLD SPT ;PRINT NUMBER OF SECTORS/TRACK
CALL DEC
CALL ILPRT
DB CR,LF,DIM,'Group Size: ',BRIGHT,0
LDA BLM ;PRINT SIZE OF A GROUP
INR A
MOV L,A
MVI H,0
CALL DEC
CALL ILPRT
DB DIM,' Blocks/Group',BRIGHT
DB CR,LF,DIM,'Total Groups: ',BRIGHT,0
LHLD DSM ;PRINT TOTAL NUMBER OF GROUPS ON A DISK
CALL DEC
CALL ILPRT
DB CR,LF,DIM,'Directory Entries: ',BRIGHT,0
LHLD DRM ;PRINT NUMBER OF DIRECTORY ENTRIES
INX H
CALL DEC
CALL ILPRT
DB CR,LF,DIM,'System Tracks: ',BRIGHT,0
LHLD SYSTRK ;PRINT NUMBER OF SYSTEM TRACKS
CALL DEC
CALL SWAIT
POP H ;RESTORE POINTER TO NEXT COMMAND
JMP PROMPT
;
;COMMAND: N
;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 ;SAVE POINTER TO NEXT LETTER
MVI C,RESETDK ;BDOS RESET DISK FUNCTION
CALL BDOS
LDA DRIVE ;RESELECT CURRENT DRIVE
MOV C,A
POP H
CALL SELECT
JMP PROMPT
;
;COMMAND: Q
;Queue Control
;
QUEUER:
MOV A,M ;GET 2ND ARGUMENT
CALL UPCASE ;CAPITALIZE
CPI EOLCH ;END OF LINE?
JZ QSTAT ;STATUS REPORT
CPI CR ;END OF LINE?
JZ QSTAT
INX H ;PT TO AFTER KEY CHAR
PUSH H ;SAVE PTR
CPI 'Z' ;ZERO QUEUE?
JZ QZERO
CPI 'S' ;SAVE QUEUE?
JZ QFSAVE
POP H ;GET PTR
CALL ILPRT
DB 'Invalid Queue Command',CR,LF,0
JMP PRMPTR ;ABORT LINE ON ERROR
;
; Zero the Queue
;
QZERO:
LHLD DIRECT ;ZERO QUEUE
SHLD QNXT ;SET NEXT
SHLD QLST ;SET LAST
LXI H,0 ;ZERO COUNT
SHLD QCNT
POP H ;GET PTR AND FALL THRU TO QSTAT
;
; Print Status of Queue
;
QSTAT:
PUSH H ;SAVE PTR TO NEXT CHAR
call cls
cz crlf
CALL ILPRT
DB DIM
DB '** Queue Status Summary **'
DB BRIGHT
DB CR,LF,0
CALL QSTATS ;PRINT STATUS
POP H ;RESTORE PTR
JMP PROMPT
QSTATS:
LHLD QCNT ;GET SIZE OF QUEUE
CALL PRQCNT ;PRINT DATA
CALL PRQSPAC ;PRINT SPACE AVAILABLE INFO
CALL ILPRT
DB CR,LF
DB DIM,'Group Save Buffer Address: ',BRIGHT,0
PUSH H
LHLD GBUFF ;BC=ADDRESS
MOV B,H
MOV C,L
POP H
CALL HEXB1 ;PRINT AS HEX
CALL ILPRT
DB ' Hex',CR,LF
DB 0
CALL ILPRT
DB DIM,'Address of Head of Queue: ',BRIGHT,0
LHLD QNXT ;PRINT ADDRESS OF HEAD OF QUEUE
MOV B,H ;... ADDRESS IN BC
MOV C,L
CALL HEXB1 ;PRINT IN HEX
CALL ILPRT
DB ' Hex',CR,LF
DB DIM,'Address of Tail of Queue: ',BRIGHT,0
LHLD QLST ;PRINT ADDRESS OF TAIL OF QUEUE
MOV B,H
MOV C,L
CALL HEXB1
CALL ILPRT
DB ' Hex',CR,LF,0
RET
;
; Print Amount of Space Left in Queue
;
PRQSPAC:
LXI B,-1 ;SET COUNT
LHLD QLST ;GET PTR TO QUEUE TAIL
QSTAT1:
INX B ;INCREMENT COUNT
LXI D,80H ;PT TO NEXT QUEUE ELEMENT
DAD D
XCHG ;WRAP AROUND
CALL QWRAP
LHLD QNXT ;GET PTR TO FIRST ELEMENT
XCHG
MOV A,H ;COMPARE
CMP D
JNZ QSTAT1
MOV A,L
CMP E
JNZ QSTAT1
MOV H,B ;HL=BLOCK COUNT
MOV L,C
CALL DEC ;PRINT AS DECIMAL
CALL ILPRT
DB DIM,' Blocks Left in Queue',BRIGHT,CR,LF,0
RET
;
; Save Queue as a File
;
QFSAVE:
MOV A,M ;GET FIRST CHAR OF FILE NAME
CPI EOLCH ;EOL?
JZ WHAT
CPI CR ;EOL?
JZ WHAT
LXI D,FCB ;START TO FILL FCB
XRA A ;A=0
STAX D ;SELECT DEFAULT DRIVE
INX D ;PT TO FILE NAME
MVI B,8 ;SAVE FILE NAME
CALL MVNAME
MVI B,3 ;SAVE FILE TYPE
CALL MVNAME
PUSH H ;SAVE PTR TO NEXT CHAR
LHLD QCNT ;ANY ELEMENTS IN QUEUE?
MOV A,H
ORA L
JZ QEMPTY
PUSH H ;SAVE QUEUE COUNT
CALL NORITE ;CAN'T WRITE NOW
LXI D,FCB ;PT TO FCB
CALL FCBINIT ;INIT FCB
MVI C,DELF ;DELETE FILE
PUSH D ;SAVE DE
CALL BDOS
POP D
CALL FCBINIT ;INIT FCB AGAIN
MVI C,MAKEF ;CREATE FILE
CALL BDOS
POP B ;GET QUEUE COUNT IN BC
LHLD QNXT ;PT TO NEXT BLOCK IN QUEUE
QFS1:
PUSH B ;SAVE COUNT
LXI D,TBUFF ;COPY INTO TBUFF
MVI B,128 ;128 BYTES
CALL MOVE
XCHG ;PT TO NEXT QUEUE BLOCK IN DE
CALL QWRAP ;WRAP AROUND
PUSH D ;SAVE PTRS
LXI D,FCB ;PT TO FCB
MVI C,WRITEF ;WRITE BLOCK TO FILE
CALL BDOS
POP H ;GET PTR TO NEXT BLOCK
POP B ;GET COUNT
DCX B ;COUNT DOWN
MOV A,B ;DONE?
ORA C
JNZ QFS1
LXI D,FCB ;CLOSE FILE
MVI C,CLOSEF
CALL BDOS
CALL ILPRT
DB 'Queue Saved in File',CR,LF,0
POP H ;PT TO NEXT CHAR
JMP PROMPT
FCBINIT:
PUSH D ;SAVE PTR
LXI H,12 ;SKIP TO EX FIELD
DAD D
MVI B,24 ;ZERO 36 BYTES
XRA A ;A=0
FCBIN1:
MOV M,A ;STORE ZEROES
INX H
DJNZ FCBIN1
POP D ;RESTORE PTR
RET
;
;COMMAND: *
;Repeat buffer contents
;
REPEAT:
CALL DECIN ;NN SPECIFIED?
MOV A,D
ORA E
JZ NNN ;NO -- SET FOR INFINITE LOOP OR SIMPLE REPEAT
LHLD TOGO ;LOAD LOOP FLAG
INX H ;TEST FOR FIRST TIME
MOV A,H
ORA L ;WAS IT 0FFFFH?; IF SO, WE HAVE NEW VALUE
JNZ NNN ;NO: COUNTING
XCHG ;GET COUNT
SHLD TOGO ;SET COUNT
;
NNN:
LHLD TOGO ;GET CURRENT COUNT
XCHG ;DE=CURRENT COUNT, HL=COUNT LIMIT
LHLD INBUF ;PT TO FIRST CHAR FOR REPEAT
INX D ;TEST FOR 0FFFFH
MOV A,D ;IF 0FFFFH, INX D MADE DE=0
ORA E
JZ PROMPT ;CONTINOUS LOOP IF 0FFFFH
DCX D ;COUNT DOWN
DCX D ;MAKE UP FOR PREV INX D
XCHG
SHLD TOGO ;SET NEW COUNT (1 LESS THAN BEFORE)
MOV A,H ;ALL DONE?
ORA L
XCHG ;GET BACK INBUF PTR IN HL
JNZ PROMPT ;KEEP GOING IF NOT YET ZERO
JMP PRMPTR ;ALL DONE
;
;COMMAND: U
;Set CP/M 2.x user number
;
USER:
CALL DECIN ;GET REQUESTED USER NO.
LDA MUSER ;GET MAX USER
MOV B,A ;... IN B
MOV A,E
CMP B ;VALID?
JNC USRERR
MOV A,D ;HIGH-ORDER BYTE MUST BE ZERO FOR VALID NUMBER
ORA A
JNZ USRERR
MOV A,E ;SAVE USER NUMBER
STA UNUM
MVI C,SUSER ;SET USER NUMBER
PUSH H ;SAVE CHAR POINTER
CALL BDOS ;SET USER NO.
POP H
JMP PROMPT
USRERR:
CALL ILPRT
DB 'User Number Out of Range',CR,LF,0
JMP PRMPTR
;
;COMMAND: P
;Toggle print flag
;
PRNTFF:
LDA PFLAG ;TOGGLE PRINT FLAG
XRI 1
STA PFLAG
JMP PROMPT
;
;COMMAND: Z
;Sleep routine, in seconds
;
SLEEP:
CALL DECIN ;GET COUNT IF ANY
MOV A,E ;ANY?
ORA A
JNZ SLEPLP
MVI E,1 ; 1 SEC DEFAULT
;
SLEPLP:
LDA CLOCK ; GET CLOCK SPEED
MOV D,A
;
SLEEP1:
LXI B,41700 ; APPROX 1 SEC @ 1MHz
;
SLEEP2:
DCX B ;COUNT DOWN FOR 1 MHz [5 CYCLES]
MOV A,B ;[5 CYCLES] <-- TOTAL TIME: 24 CYCLES
ORA C ;[4 CYCLES] <-- (24 MU-SECS AT 1MHz)
JNZ SLEEP2 ;[10 CYCLES]
PUSH D
CALL CTLCS ;ABORT?
POP D
JZ PRMPTR
DCR D ;COUNT DOWN FOR CLOCK SPEED
JNZ SLEEP1
DCR E ;COUNT DOWN NUMBER OF REQUESTED SECONDS
JNZ SLEPLP
JMP PROMPT
;
;Check for control-C or S
;
CTLCS:
CALL CONST ;CHAR AVAILABLE?
ORA A
JNZ GETC
ORI 1 ;NO CHAR, RETURN NZ
RET
;
GETC: CALL CONIN ;INPUT CHAR
ANI 1FH ;ALLOW ASCII
CPI 'S'-40H ;WAIT FOR NEXT CHAR IF ^S OR S OR s
CZ CONIN
CPI 'C'-40H ;CHECK FOR ^C OR C OR c
RET ;0 SET IF CTL-C
;
;Initialize Memory Buffers
;
INITP:
XRA A ;A=0
STA HEXAD ;CLEAR ADDRESS
STA HEXAD+1
STA PFLAG ;SET NO PRINT
STA SAVEFL ;SET NO SAVE DONE
STA WRFLG ;MAY NOT WRITE
STA DIRPOS ;SET NO DIRECTORY POSITION
STA FINDFL ;SET NO POSITION
INR A ;A=1
STA FTSW ;SET SEARCH WITHOUT INCREMENT
STA NOTPOS ;NOT POSITIONED
LXI H,0 ;HL=0
SHLD QCNT ;SET NO ELEMENTS IN QUEUE
SHLD MFPTR ;SET NO MULTI FILE PTR
SHLD CURTRK ;SET TRACK 0
INX H ;HL=1
SHLD CURSEC ;SET LOGICAL SECTOR 1
SHLD PHYSEC ;SET PHYSICAL SECTOR 1
LHLD PINBUF ;SET PREVIOUS COMMAND TO NIL
MVI M,CR ;CLEAR PREVIOUS COMMAND
LHLD DIRECT ;SET FIRST AND LAST QUEUE ELEMENT PTRS
SHLD QNXT
SHLD QLST
; Initialize Default Macros -- new block by <JPS>
LHLD MTABL ;CLEAR MACRO TABLE
MVI B,10 ;10 ENTRIES
lxi d,imac0 ;point to beginning of default macro table
initp1: push h ;save pointer to start of each macro
initp2: ldax d ;get next initial macro character
mov m,a ;store it in macro table
inx d
inx h
cpi cr ;end of macro?
jnz initp2
pop h ;retrieve pointer to start of this macro
dcr b ;see if we've done all macros
rz ;if so, return
inr h ;point to next macro
jmp initp1
;INITP1:
; MVI M,CR ;STORE <CR>
; INR H ;PT TO NEXT PAGE
; DJNZ INITP1
; RET
; End of Block Changed by <JPS>
;
;Set up flags, etc, at initialization
;Find our way at initialization
;
GETSTP:
PUSH H
LHLD INBUF ;PT TO INPUT BUFFER
MVI M,CR ;INITIALIZE INPUT BUFFER
POP H
MVI C,SUSER ;GET USER NUMBER
MVI E,0FFH ;GET USER
CALL BDOS
STA UNUM ;SET USER NUMBER
MVI C,GETDSK
CALL BDOS ;GET CURRENT DISK
MOV C,A ;WE HAVE TO SELECT
JMP SELECT ;TO GET THE DPH
;
;COMMAND: L
;Log in the selected disk
;
LOGIN:
CALL DOLOG
JMP PROMPT
;
DOLOG:
MOV A,M ;DISK REQUESTED?
LXI D,0
CPI CR ;NO REQUEST OF PHYSICAL EOL
JZ LGNODK
CPI EOLCH ;NO REQUEST IF LOGICAL EOL
JZ LGNODK
CALL UPCASE ;CAPITALIZE
INX H ;POINT TO NEXT CHAR
SUI 'A' ;CONVERT TO 0-15
MOV C,A ;DISK NUMBER IN C
LDA MDISK ;GET MAX DISK
MOV B,A ;... IN B
MOV A,C
CMP B
JC SELECT
CALL ILPRT
DB 'Disk Letter Out of Range',CR,LF,0
JMP PRMPTR
;
;Select Disk Whose Number is in C (A=0, B=1, etc)
;
SELECT:
PUSH H ;SAVE PTR TO NEXT COMMAND LETTER
MOV A,C
STA DRIVE ;REMEMBER LATER WHERE WE ARE
;
VSELDK: CALL $-$ ;ADDR FILLED IN BY 'INIT'
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 ;SET THE SECTOR TABLE PTR
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
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 ;CALCULATE WHAT GROUP/GRPDISP WE ARE IN
POP H ;GET PTR TO NEXT LETTER
;
LGNODK:
CALL NORITE ;SET NO DISK I/O DONE (NO POSITION)
RET
;
;Read in the disk directory
;
REDDIR:
PUSH H ;SAVE PTR TO NEXT LETTER
CALL NORITE ;POSITIONING LOST
LHLD SYSTRK ;SAVE CURRENT TRACK
SHLD CURTRK
LXI H,1 ;SET SECTOR 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 ;BC=NUMBER OF BLOCKS TO READ
MOV C,L
XCHG
LHLD DIRECT ;DMA ADDR
XCHG ;... IN DE
;
;Read Disk Directory Loop
;
RDIRLP:
PUSH B ;SAVE REGS
PUSH D
MOV B,D ;BC=DMA ADDRESS
MOV C,E
LDA BDOS+2 ;CHECK MEM AVAIL
DCR A ;ARE WE RNNING INTO BDOS?
CMP D
JC MEMFUL ;MEMORY FULL ERROR IF SO
CALL SETDMA ;SET DMA ADDRESS TO THAT IN BC
LHLD CURTRK ;SET TRACK
XCHG
CALL SETTRK
LHLD CURSEC ;SET SECTOR
XCHG
CALL SETSEC
CALL READ ;READ DIRECTORY BLOCK
CALL NXTSEC ;INCREMENT TO NEXT SECTOR
POP D
POP B
LXI H,80H ;ADVANCE TO NEXT DMA ADDRESS
DAD D
XCHG ;DE=NEXT DMA ADDRESS
DCX B ;COUNT DOWN DIRECTORY BLOCKS
MOV A,B
ORA C
JNZ RDIRLP
LXI B,TBUFF ;RESET DMA ADDRESS TO TBUFF
CALL SETDMA
POP H ;GET PTR TO NEXT CHAR
RET
;
;COMMAND: M
;Map the directory
;
MAP:
PUSH H ;SAVE PTR
LHLD QCNT ;GET COUNT
MOV A,H
ORA L
POP H
JZ MAP1 ;PROCEED IF QUEUE EMPTY
CALL ILPRT ;PRINT ABORT MESSAGE
DB CR,LF,'MAP not permitted -- Block Queue would be overlaid',0
JMP PRMPTR
MAP1:
CALL PAGSET ;SET PAGING COUNTER
XRA A
STA ONLY1 ;SET FLAG FOR ALL GROUPS (NOT ONLY 1)
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 ;GET SPECIFIED GROUP IF ANY
PUSH H ;SAVE INBUF PTR
MOV A,E ;GET START
ORA D ;NOTHING?
JZ MAPDF ;..YES, DFLT
MVI A,0FFH ;SET FLAG FOR ONLY 1 GROUP
STA ONLY1
MOV B,D ;GET VALUE IN BC
MOV C,E
;
MAPDF:
CALL HEXB ;PRINT FIRST GROUP NUMBER
MVI A,'-' ;PRINT SEPARATOR
CALL TYPE
MVI A,' ' ;SET NO DUPLICATES
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 ;ABORT?
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 ;PRINT ENDING GROUP NUMBER
INX B
XCHG
CALL MAPNAM ;PRINT FILE NAME
LDA ONLY1 ;ONLY 1 NAME TO BE PRINTED?
ORA A ;0=NO
JNZ MAPND1
JMP MAPDF
;
;End of map
;
MAPEND:
DCX B ;GET LAST
CALL HEXB ;PRINT LAST GROUP NUMBER
CALL MAPNAM ;PRINT FILE NAME
CALL WAIT ;DELAY FOR USER
MAPND1:
POP H
CALL CRLF ;NEW LINE
;
;End of map - reposition to previous group
;
MAPND2:
PUSH H
LHLD GROUP ;POINT TO GROUP IN DE
XCHG
JMP POSGP2
;
;Print file name pointed to by HL
;
MAPNAM:
CALL SPACE ;LEADING SPACE
MOV A,H
ORA L ;NONE?
JZ NONAME
MOV A,M ;SEE IF ALLOC
CPI 0E5H ;FREE?
MVI A,' ' ;MARK ALLOCATED
JNZ MPNSP1
MVI A,'(' ;MARK NOT ALLOCATED (ERASED FILE)
;
MPNSP1:
CALL TYPE ;PRINT ALLOCATION INDICATOR (SPACE OR '(')
PUSH H ;SAVE POINTER
MOV A,M
CALL HEX ;SHOW USER NUMBER
CALL SPACE
INX H ;SKIP USER BYTE
PUSH B
MVI B,8 ;PRINT FILE NAME
CALL MAPN2
MVI A,'.' ;PRINT DECIMAL SEPARATOR
CALL TYPE
MVI B,3 ;PRINT FILE TYPE
CALL MAPN2
LDA DUPFLG ;DUPLICATE?
CALL TYPE ;SPACE OR STAR
POP B
MOV A,M ;GET EXT
CALL HEX ;PRINT EXTENT NUMBER
POP H
MOV A,M
CPI 0E5H ;DELETED ENTRY?
MVI A,' ' ;PRINT ENDING SPACE
JNZ MPNSP2
MVI A,')' ;PRINT ALLOCATION FLAG
;
MPNSP2:
CALL TYPE ;")" IF ERASED FILE OR SPACE IF NOT
JMP FLIP
;
NONAME:
CALL ILPRT
DB DIM,' ++ Free ++ ',BRIGHT,0
;
FLIP:
LDA TWOUP ;FLIP FLAG FOR TWO ENTRIES PER LINE
XRI 1
STA TWOUP
JZ PAGER ;NEW LINE WITH PAGING IF REQUIRED
;
DELIM:
MVI A,':' ;PRINT DELIMITER BETWEEN ADJACENT ENTRIES ON LINE
CALL TYPE
JMP SPACE
;
;Print name pted to by HL, 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 ;PRINT A AS HEX CHARS
JMP MAPN2Z
;
MAPN2A:
CALL TYPE ;PRINT AS CHAR
;
MAPN2Z:
DJNZ 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 ;SET MULTI-FILE (MORE THAN ONE USER) PTR
LHLD DIRECT ;PT TO DIRECTORY
;
GETGLP:
PUSH H ;SAVE POINTER TO NAME
MOV A,M ;PICK UP DN BYTE
CPI 0E5H ;ERASED?
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 NOT FOUND
;
;Found the file
;
PUSH H ;SAVE GROUP PTR
LHLD MFPTR
MOV A,H ;ANY ENTRIES?
ORA L
POP H ;GET PTR
XTHL ;SAVE ENTRY START AND SAVE PTR
JZ MPFRST ;IF ZERO, THEN FIRST ENTRY
MVI A,'*' ;SET MULTI FLAG
STA DUPFLG
MPFRST:
SHLD MFPTR ;SAVE POINTER
XTHL ;RESTORE ENTRY START AND GET PTR
NOTGOT:
DCR E ;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
;
;Set the allocation address, if any
;
LHLD MFPTR ;GET ADDRESS
RET
;
;COMMAND: <
;Save the current sector
; Special Form of <S saves current block onto queue
; Special Form of <G saves indicated group onto queue
;
SAVE:
LDA WRFLG ;READ DONE?
ORA A
JZ BADW ;NONE TO SAVE
MOV A,M ;CHECK FOR 'S'
CALL UPCASE ;CAPITALIZE
CPI 'B' ;BLOCK SAVE
JZ QSAV ;SAVE ON STACK
CPI 'G' ;GROUP SAVE
JZ SAVEG
PUSH H
LHLD SAVBUF ;PT TO SAVBUF
XCHG ;COPY INTO SAVBUF
LXI H,TBUFF ;FROM TBUFF
MVI B,128 ;128 BYTES
CALL MOVE
MVI A,1 ;..SHOW
STA SAVEFL ;..SAVED EXISTS
POP H ;GET PTR TO NEXT CHAR
JMP PROMPT
;
; Save Block on Queue
;
QSAV:
INX H ;SKIP OVER 2ND <
PUSH H ;SAVE PTR TO NEXT CHAR
LHLD QLST ;SEE IF ANOTHER SAVE WILL FILL QUEUE
LXI D,128 ;SET HL TO PT TO END OF NEXT SECTOR IN QUEUE
DAD D
XCHG ;DE PTS TO END OF NEXT BLOCK
QSAV0:
LHLD QNXT ;SEE IF QUEUE IS FULL NOW
MOV A,H ;MAY BE SAME
CMP D
JNZ QSAV1
MOV A,L ;MAY NOT BE SAME
CMP E
JZ QSAV2 ;QUEUE IS FULL, SO ABORT
QSAV1:
LHLD QLST ;GET PTR TO LAST QUEUE ELEMENT
XCHG ;... IN DE
LXI H,TBUFF ;COPY FROM TBUFF
MVI B,128 ;128 BYTES
CALL MOVE
CALL QWRAP ;CHECK FOR WRAP AROUND
XCHG ;HL PTS TO NEW LAST QUEUE POSITION
SHLD QLST ;SAVE HL
LHLD QCNT ;INCREMENT SECTOR COUNT
INX H
SHLD QCNT
CALL PRQCNT ;PRINT QUEUE COUNT
POP H ;PT TO NEXT CHAR
JMP PROMPT
QSAV2:
CALL ILPRT
DB 'Block Queue is Full -- Block Not Saved',CR,LF,0
LHLD QCNT ;GET COUNT
CALL PRQCNT ;PRINT COUNT
POP H ;PT TO NEXT CHAR
JMP PRMPTR
;
; PRINT NUMBER OF ELEMENTS IN QUEUE
;
PRQCNT:
CALL DEC ;PRINT AS DECIMAL
CALL ILPRT
DB DIM,' Blocks in Queue',BRIGHT,CR,LF,0
RET
;
; CHECK TO SEE IF QUEUE ELEMENT PTED TO BY DE SHOULD BE WRAPPED AROUND
; ON EXIT, DE PTS TO QUEUE ELEMENT WITH WRAP AROUND
;
QWRAP:
LHLD BDOS+1 ;CHECK FOR WRAP AROUND
MOV A,H
SUI 10 ;BELOW CCP
CMP D ;WRAP AROUND IF EQUAL
RNZ
XCHG
LHLD DIRECT ;NEXT ELEMENT IS HERE
XCHG ;... IN DE
RET
;
;This routine is common to Save Group (RG) and Write Group (WG); it is used
; to extract the group number, check it, and position DU3 to it
; On exit, GROUP = Group Number, GRPDIS = 0, and DU3 is positioned
;
COMG:
INX H ;PT TO CHAR AFTER 'G' OF '<G' COMMAND
PUSH H ;SAVE PTR TO NEXT CHAR
MOV A,M ;GET CHAR AFTER 'G'
LHLD GROUP ;GET CURRENT GROUP
CALL UPCASE ;CAPITALIZE
CPI EOLCH ;CURRENT IF LOGICAL EOL
JZ COMG1
CPI CR ;CURRENT IF PHYSICAL EOL
JZ COMG1
CALL HEXIN ;GET GROUP NUMBER IN HEX
LHLD DSM ;CHECK FOR BOUNDS ERROR
CALL SUBDE ;SUBTRACT GROUP NUMBER FROM DSM
POP H ;RESTORE PTR
JC OUTLIM ;LIMIT ERROR IF CARRY
PUSH H ;SAVE PTR AGAIN
XCHG ;SAVE GROUP NUMBER
SHLD GROUP
COMG1:
SHLD TGRP ;TEMPORARY GROUP NUMBER
XCHG ;GROUP NUMBER IN DE
XRA A ;A=0
STA GRPDIS ;SET GROUP DISPLACEMENT
CALL GTKSEC ;CONVERT GROUP NUMBER TO TRACK AND SECTOR
CALL SETTRK ;SET TRACK
XCHG
CALL SETSEC ;SET SECTOR
POP H ;GET PTR TO NEXT CHAR
RET
;
;This is the Save Group Routine; it copies the indicated group into the save
; buffer.
;
SAVEG:
CALL COMG ;EXTRACT COMMON GROUP INFO -- GROUP NUMBER AND POS
PUSH H
CALL ILPRT
DB 'Reading from Group ',0
LHLD GROUP ;GET CURRENT GROUP
MOV B,H ;VALUE IN BC
MOV C,L
CALL HEXB ;PRINT AS HEX
CALL ILPRT
DB CR,LF,0
LHLD QLST ;LAST PTR USED FOR READ
SHLD QPTR
POP H
MVI A,0 ;SET COPY FUNCTION TO SAVE
STA CPYFCT ;0=READ, 0FFH=WRITE
;
;Group Copy Routine -- if CPYFCT = 0, Read Group; if CPYFCT = 0FFH, Write Group
;
COPYG:
PUSH H ;SAVE PTR TO NEXT CHAR IN COMMAND LINE
CALL NORITE ;POSITIONING LOST
XCHG ;SAVE HL
LHLD QPTR ;PT TO NEXT QUEUE POSITION
XCHG ;... IN DE
LDA BLM ;GET NUMBER OF BLOCKS/GROUP
INR A ; ADD 1 TO BLM FOR CORRECT COUNT
MOV B,A ;COUNT IN B
;
COPYGL:
PUSH B ;SAVE COUNT
PUSH D ;SAVE PTR TO NEXT BLOCK TO LOAD
MOV B,D ;SET BC=DE FOR SET DMA
MOV C,E
CALL SETDMA ;SET ADDRESS TO LOAD
LDA CPYFCT ;READ OR WRITE?
ORA A ;0=READ
JNZ COPYGLW
CALL READ ;READ BLOCK
LHLD QCNT ;INCREMENT QUEUE ELEMENT COUNT
INX H
SHLD QCNT
JMP COPYGL0
COPYGLW:
LHLD QCNT ;QUEUE EMPTY?
MOV A,H
ORA L
JZ QEMPTY
CALL PWRITE ;WRITE BLOCK (NO CHECK)
LHLD QCNT ;DECREMENT QUEUE ELEMENT COUNT
DCX H
SHLD QCNT
COPYGL0:
CALL NXTSEC ;COMPUTE NEXT SECTOR ADDRESS
LHLD CURTRK ;GET NEXT TRACK ADDRESS
XCHG ;... IN DE
CALL SETTRK ;SET IT
LHLD CURSEC ;GET NEXT SECTOR ADDRESS
XCHG ;... IN DE
CALL SETSEC ;SET IT
POP D ;GET PTR TO NEXT BLOCK
POP B ;GET COUNTER
LXI H,80H ;OFFSET TO NEXT BLOCK
DAD D
SHLD QPTR
XCHG ;DE PTS TO NEXT BLOCK
CALL QWRAP ;ALLOW WRAP AROUND IN QUEUE
LDA CPYFCT ;0=READ
ORA A ;NO QUEUE OVERFLOW CHECK IF WRITE
JNZ COPYGL1
LHLD QNXT ;CHECK FOR QUEUE OVERFLOW
MOV A,H ;MUST NOT BE EQUAL
CMP D
JNZ COPYGL1
MOV A,L
CMP E
JZ QSAV2
COPYGL1:
DJNZ COPYGL ;LOOP UNTIL FINISHED
LHLD QCNT ;PRINT COUNT
CALL PRQCNT
LHLD QPTR ;GET QUEUE PTR
LDA CPYFCT ;RESET PROPER QUEUE PTR
ORA A ;0=READ
JZ COPYGL2
SHLD QNXT ;NEXT PTR USED FOR WRITE
JMP COPYGL3
COPYGL2:
SHLD QLST ;LAST PTR USED FOR READ
COPYGL3:
LXI B,TBUFF ;RESET DMA ADDRESS
CALL SETDMA
XRA A ;A=0
STA WRFLG ;SET NO READ DONE
LHLD TGRP ;GET GROUP NUMBER
XCHG ;... IN DE
POP H ;GET PTR TO NEXT CHAR
JMP POSGRP ;POSITION TO GROUP IN DE AND CONTINUE PROCESSING
;
;COMMAND: >
;Restore the current sector
; Special Form >S gets next block from queue
; Special Form >G gets next group from queue
;
RESTOR:
MOV A,M ;CHECK FOR SPECIAL FORM
CALL UPCASE ;CAPITALIZE
CPI 'B' ;BLOCK SAVE?
JZ QRESTOR
CPI 'G' ;GROUP SAVE?
JZ RESTRG
LDA SAVEFL ;SAVE DONE PREVIOUSLY?
ORA A
JZ NOSAVE ;NONE TO SAVE
PUSH H
LHLD SAVBUF ;COPY FROM SAVBUF
LXI D,TBUFF ;INTO TBUFF
MVI B,128 ;128 BYTES
CALL MOVE
POP H ;GET PTR TO NEXT CHAR
JMP PROMPT
;
; Restore Sector from Queue
;
QRESTOR:
INX H ;PT TO NEXT CHAR
PUSH H ;SAVE PTR ON STACK
LHLD QCNT ;GET ELEMENT COUNT
MOV A,H ;EMPTY?
ORA L
JZ QEMPTY ;ABORT IF EMPTY
DCX H ;COUNT DOWN
SHLD QCNT
CALL PRQCNT ;PRINT COUNT
LHLD QNXT ;PT TO NEXT ELEMENT IN QUEUE
LXI D,TBUFF ;COPY INTO TBUFF
MVI B,128 ;128 BYTES
CALL MOVE
XCHG ;DE=PTR TO NEXT ELEMENT IN QUEUE
CALL QWRAP ;CHECK FOR WRAP AROUND
XCHG ;HL PTS TO NEXT ELEMENT IN QUEUE
SHLD QNXT ;SAVE PTR
POP H ;RESTORE PTR
JMP PROMPT
QEMPTY:
CALL ILPRT
DB 'Error -- Queue Empty',CR,LF,0
POP H ;RESTORE NEXT CHAR PTR
JMP PRMPTR
;
;Write Group Loaded in GBUFF to Disk
;
RESTRG:
CALL COMG ;GET GROUP NUMBER FROM COMMAND LINE AND POS
PUSH H
CALL ILPRT
DB 'Writing to Group ',0
LHLD GROUP ;GET GROUP NUMBER
MOV B,H ;VALUE IN BC
MOV C,L
CALL HEXB ;PRINT IN HEX
CALL ILPRT
DB CR,LF,0
LHLD QNXT ;NEXT PTR USED FOR WRITE
SHLD QPTR
POP H
MVI A,0FFH ;WRITE FUNCTION
STA CPYFCT ;COPY FUNCTION FOR GROUP COPY ROUTINE
JMP COPYG ;GROUP COPY ROUTINE
;
NOSAVE:
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
DJNZ 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
LHLD INBUF
MVI M,CR
JMP CLCGRP ;SHOW WHERE STOPPED
;
;COMMAND: =
;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 ;END OF LINE?
JZ SREQU
CPI EOLCH ;LOGICAL EOL?
JNZ SRCHL
;
;Got match
;
SREQU:
CALL ILPRT
DB '= at ',0
LDA BUFAD
ANI 7FH
CALL HEX
CALL CRLF
JMP CLCGRP
;
;Get value from input buffer
;
GETVAL:
MOV A,M ;GET NEXT CHAR
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 from disk
;
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 ;ADVANCE TO NEXT BLOCK
;
READ1:
XRA A
STA FTSW ;NOT FIRST READ
LHLD CURSEC
XCHG
CALL SETSEC
LHLD CURTRK
XCHG
CALL SETTRK
CALL READ
CALL CLCSUB
LXI H,TBUFF
;
NORD:
MOV A,M
INX H
SHLD BUFAD
POP H
RET
;
;COMMAND: V
;View the file in ASCII starting at
;current sector, stepping thru the disk
;
VIEW:
LDA WRFLG
ORA A
JZ BADDMP
CALL DECIN ;GET DISPL IF ANY
PUSH H
MOV A,E
ORA A
JNZ VIEWLP
INR E ;DFLT=1
;
VIEWLP:
LXI H,TBUFF ;TO DATA
;
VEWCHR:
CALL CTLCS ;ABORT?
JZ VEWEND
MOV A,M ;GET NEXT CHAR
CPI 1AH ;EOF?
JZ VEWEOF
ANI 7FH ;MASK
CPI 7EH ;ESC CHAR FOR H1500
JNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX
CPI ' '
JNC VIEWPR
CPI CR ;CR PASS
JZ VIEWPR
CPI LF ;LF PASS
JZ VIEWPR
CPI TAB ;TAB PASS
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,DIM,' ++ EOF ++',BRIGHT,CR,LF,0
;
VEWEND:
POP H
CALL CRLF
JMP CLCGRP
;
;COMMAND: A or D
;Dump in hex or ASCII
;
DUMP:
LDA WRFLG
ORA A
JNZ DUMPOK
;
BADDMP:
CALL ILPRT
DB '++ Can''t dump, no sector read ++',CR,LF,0
;
EXPL:
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 ;GET NEXT CHAR
CPI EOLCH ;LOGICAL EOL?
JZ DUMPDF ;DFLT
CPI CR ;PHYSICAL EOL?
JNZ DMPNDF
;
;Use default
;
DUMPDF:
LXI B,TBUFF
LXI D,0FFH
JMP DUMP1
;
DMPNDF:
CALL DISP
MOV B,D
MOV C,E
CPI CR
JZ DUMP1
CPI EOLCH
JZ DUMP1
INX H ;SKIP SEPCH
CALL DISP
;
;BC = start, DE = end
;
DUMP1:
PUSH H ;SAVE COMMAND POINTER
MOV H,B
MOV L,C
;
DUMPLP:
CALL DUMPHL ;PERFORM DUMP OF DIR ENTRY AT HL
POP H ;RESTORE HL
JMP PROMPT
;
; PERFORM DUMP AT HL
;
DUMPHL:
CALL STNDOUT ;DIM
MOV A,L
ANI 7FH
CALL HEX ;PRINT HEX VALUE
CALL STNDEND ;BRIGHT
CALL SPACE
CALL SPACE
LDA DUMTYP
CPI 'A'
JZ DUMPAS
PUSH H ;SAVE START
;
; DUMP 16 BYTES STARTING AT HL (CHECK FOR DE TERMINATION)
;
DHEX:
MOV A,M
CALL HEX ;PRINT HEX VALUE PTED TO BY HL
MOV A,L
ANI 3
CPI 3 ;EXTRA SPACE EVERY 4
CZ SPACE
MOV A,L
ANI 7
CPI 7 ;TWO EXTRA SPACES EVERY 8
CZ SPACE
MOV A,E ;CHECK FOR END OF BYTES TO DUMP
CMP L
JZ DPOP
INX H
MOV A,L ;CHECK FOR END OF 16 BYTES
ANI 0FH
JNZ DHEX
;
DPOP:
CALL CTLCS ;ABORT?
JZ PRMPTR
LDA DUMTYP ;CHECK FOR ASCII ALSO
CPI 'H'
JZ DNOAS ;HEX ONLY
POP H ;GET START ADDR
;
; DUMP ASCII CHARS - HL PTS TO FIRST BYTE
;
DUMPAS:
CALL ASTER ;PRINT FIRST ASTERISK TO SEPARATE TEXT
;
DCHR:
MOV A,M ;GET CHAR
ANI 7FH
CPI ' '
JC DPER
CPI 7FH ;TRAP DEL
JC DOK
;
DPER:
MVI A,'.' ;PRINT PRINTING CHAR
;
DOK:
CALL TYPE ;PRINT CHAR
MOV A,E ;CHECK FOR END OF DUMP
CMP L
JZ DEND
INX H
MOV A,L ;CHECK FOR END OF 16 BYTES
ANI 0FH
JNZ DCHR
;
; END OF ASCII DUMP
;
DEND:
CALL ASTER ;PRINT ENDING ASTERISK
CALL CRLF ;NEW LINE
PUSH D
CALL CTLCS ;ABORT?
POP D
JZ PRMPTR
MOV A,E ;DONE WITH DUMP?
CMP L
JNZ DUMPHL
RET
;
; NO ASCII DUMP
;
DNOAS:
POP B ;CLEAR STACK (START ADDRESS OF DUMP)
CALL CRLF ;NEW LINE
MOV A,E ;DONE WITH DUMP?
CMP L
JNZ DUMPHL
RET
;
;COMMAND: G
;Position
;
POS:
PUSH PSW
MOV A,M
CPI EOLCH ;LOGICAL EOL?
JZ POSINQ
CPI CR ;PHYSICAL EOL?
JNZ POSOK
;
POSINQ:
POP PSW
JMP INQ
;
POSOK:
POP PSW
CPI 'T' ;TRACK?
JZ POSTKD
CPI 'S' ;SECTOR?
JZ POSSCD
CPI 'G' ;GROUP?
JZ POSGPH
JMP WHAT ;ERROR OTHERWISE
;
;Position to Track
;
POSTKD:
CALL DECIN ;GET NUMBER IN DECIMAL
;
POSTRK:
PUSH H
LHLD MAXTRK ;CHECK FOR BEYOND END OF DISK
CALL SUBDE
POP H
JC OUTLIM
CALL SETTRK ;SET TRACK
CALL NORITE ;TRACK DOESN'T READ
MVI A,1
STA NOTPOS ;SHOW NOT POSITIONED
JMP CLCGRP
;
;Position to Sector
;
POSSCD:
CALL DECIN ;GET NUMBER IN DECIMAL
MOV A,D
ORA E
JZ WHAT ;DON'T ALLOW SECTOR 0
;
POSSEC:
PUSH H
LHLD SPT ;CHECK FOR WITHIN RANGE
CALL SUBDE
POP H
JC WHAT
CALL SETSEC ;SET SECTOR
CALL READ ;READ
XRA A
STA NOTPOS ;POSITIONED OK
;
;Calculate Group Number/Group Displacement and Print
;
CLCGRP:
CALL CLCSUB
JMP INQ
;
;Calculate group from track and sector
; On exit, GROUP = Group Number and GRPDIS = Displacement within Group
;
CLCSUB:
PUSH H
LHLD SYSTRK
XCHG
LHLD CURTRK
CALL SUBDE ;COMPUTE RELATIVE TRACK NUMBER (SKIP SYSTEM TRACKS)
XCHG
LHLD SPT ;MULTIPLY BY NUMBER OF SECTORS/TRACK
CALL MULT
XCHG ;DE=TOTAL NUMBER OF SECTORS IN TRACKS
LHLD CURSEC ;GET SECTOR OFFSET FROM BEGINNING OF TRACK
DCX H
DAD D ;HL=TOTAL NUMBER OF SECTORS WITH OFFSET
LDA BLM
MOV B,A
MOV A,L
ANA B
STA GRPDIS ;DISPLACEMENT WITHIN GROUP
LDA BSH
MOV B,A
;
CLCLOP:
CALL ROTRHL
DJNZ CLCLOP
SHLD GROUP ;GROUP NUMBER
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
;
POSGP2:
CALL GTKSEC ;CONVERT GROUP TO SECTOR/TRACK
CALL SETTRK ;SET TRACK
XCHG
CALL SETSEC ;SET SECTOR
CALL READ ;READ BLOCK
XRA A
STA NOTPOS ;NOW POSITIONED
POP H
JMP INQ
;
;Position to Group
;
POSGPH:
CALL HEXIN ;GET PARAMETER
;
;Position to Group Numbered in DE and Print Position
;
POSGRP:
CALL DEGROUP ;GOTO GROUP
JC OUTLIM
JMP INQ ;PRINT POSITION
;
;Position to Group Numbered in DE
; Return with Carry Set if Out of Limits
;
DEGROUP:
PUSH H
LHLD DSM ;CHECK FOR WITHIN BOUNDS
CALL SUBDE
POP H
RC
PUSH H ;SAVE HL
XCHG
SHLD GROUP ;SET GROUP NUMBER
XCHG
XRA A
STA GRPDIS ;SET ZERO DISPLACEMENT
CALL GTKSEC ;CONVERT GROUP TO SECTOR/TRACK
CALL SETTRK ;SET TRACK
XCHG
CALL SETSEC ;SET SECTOR
CALL READ ;READ BLOCK
XRA A ;SET NC AND FLAG
STA NOTPOS ;NOW POSITIONED
POP H
RET
;
;Convert Group Number in DE to Sector and Track; also, GRPDIS = Offset in Grp
; On exit, DE = Track Number, HL = Sector Number
;
GTKSEC:
MOV H,D ;HL=GROUP NUMBER
MOV L,E
LDA BSH ;GET NUMBER OF SECTORS IN GROUP
;
GLOOP:
DAD H
DCR A
JNZ GLOOP
LDA GRPDIS ;ADD IN DISPLACEMENT WITHIN GROUP
ADD L ;CAN'T CARRY
MOV L,A
;
;Divide by number of sectors, quotient=track, remainder=sector
;
XCHG ;DE=TOTAL NUMBER OF SECTORS
LHLD SPT ;GET NUMBER OF SECTORS/TRACK
CALL NEG ;HL = -SECTORS/TRACK
XCHG
LXI B,0 ;SET TRACK COUNTER TO ZERO
;
DIVLP:
INX B ;INCREMENT TRACK COUNT
DAD D ;SUBTRACT SECTORS/TRACK FROM SECTORS TOTAL
JC DIVLP
DCX B ;ADJUST TRACK COUNT
XCHG
LHLD SPT ;ADD SECTORS/TRACK BACK IN TO ADJUST
DAD D ;HL=NUMBER OF SECTORS ON LAST TRACK OF GROUP
PUSH H
LHLD SYSTRK ;ADD IN NUMBER OF SYSTEM TRACKS
DAD B
XCHG ;DE=TRACK NUMBER
POP H
INX H ;HL=SECTOR NUMBER
RET
;
;COMMAND: F
;Find Directory Entry for specified file
;
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
MVI A,'?'
STAX D ;LOOK IN ALL EXTENTS
MVI A,'D' ;SET TYPE OF DUMP TO FULL
STA DUMTYP
PUSH H ;SAVE PTR TO NEXT CHAR
LXI D,FCB
MVI C,SRCHF
CALL BDOS
INR A
JNZ FLOK
STA DIRPOS ;GRP 0 IF NOT FOUND
CALL ILPRT
DB '++ File Not Found ++',CR,LF,0
POP H ;RESTORE PTR TO NEXT CHAR
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,TBUFF
DAD D ;HL POINTS TO ENTRY
LXI D,32
XCHG
DAD D
XCHG
CALL DUMPHL ;PRINT DIR ENTRY
LXI D,FCB ;LOOK FOR NEXT EXTENT
MVI C,SRCHN
CALL BDOS
INR A
JNZ FLOK
POP H ;RESTORE PTR TO NEXT CHAR
JMP PROMPT
;
MVNAME:
MOV A,M ;GET NEXT CHAR OF FILE NAME/TYPE
CPI '.' ;END OF FILE NAME?
JZ MVIPAD ;PAD OUT IF SO
CPI CR ;END OF ENTRY?
JZ PAD ;PAD OUT IF SO
CPI EOLCH ;END OF ENTRY?
JZ PAD ;PAD OUT IF SO
CALL UPCASE ;CAPITALIZE
STAX D ;STORE
INX H ;PT TO NEXT
INX D
DJNZ MVNAME
MOV A,M ;CHECK FOR ERROR
CPI CR ;OK IF EOL
RZ
CPI EOLCH ;OK IF LOGICAL EOL
RZ
INX H
CPI '.' ;OK IF DECIMAL
RZ
JMP WHAT
;
MVIPAD:
INX H
;
PAD:
MVI A,' ' ;PRINT PADDING SPACES
STAX D
INX D
DJNZ PAD
RET
;
;COMMAND: +
;Advance to Next Logical Sector
;
PLUS:
LXI D,1 ;DFLT TO 1 SECT
MOV A,M ;GET NEXT CHAR
CPI CR ;CR?
JZ PLUSGO ;..YES, DFLT TO 1
CPI EOLCH
JZ PLUSGO
CALL DECIN ;GET #
MOV A,D
ORA E
JNZ PLUSGO
LXI D,1 ;SET 1 IF VALUE OF ZERO
;
PLUSGO:
CALL NXTSEC ;ADVANCE TO NEXT LOGICAL SECTOR
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 ;SET SECTOR
LHLD CURTRK
XCHG
CALL SETTRK ;SET TRACK
POP H
CALL READ ;READ IT
JMP CLCGRP ;CALCULATE GROUP AND DISPLAY
;
;COMMAND: -
;Back up to previous sector
;
MINUS:
LXI D,1 ;SET DFLT
MOV A,M ;GET CHAR
CPI CR ;CR?
JZ MINGO ;..YES, DFLT=1
CPI EOLCH
JZ MINGO
CALL DECIN ;..NO, GET ##
MOV A,D
ORA E
JNZ MINGO
LXI D,1 ;ASSUME 1
;
MINGO:
CALL LSTSEC ;BACK UP ONE SECTOR
DCX D ;COUNT DOWN ON NUMBER OF TIMES TO BACKUP
MOV A,D
ORA E
JNZ MINGO
JMP PLUSMI ;READ BLOCK
;
;Go to last sector
; Wrap around to last sector of previous track or last sector of
; last track, as necessary
;
LSTSEC:
PUSH H
LHLD CURSEC ;BACK UP SECTOR
DCX H
MOV A,H
ORA L
JNZ LSEC1
LHLD CURTRK ;BEYOND SECTOR ZERO, SO BACK UP TRACK
MOV A,H
ORA L
JNZ LSEC0
LHLD MAXTRK ;WRAP TO END OF DISK
SHLD CURTRK
LHLD MAXSEC
JMP LSEC1
;
LSEC0:
DCX H
SHLD CURTRK
LHLD SPT ;GET NUMBER OF SECTORS/TRACK
;
LSEC1:
SHLD CURSEC ;SET NEW CURRENT SECTOR
POP H
RET
;
;Go to next sector
; On exit, CURSEC = Current Sector and CURTRK = Current Track
;
NXTSEC:
PUSH H
PUSH D
LHLD CURSEC ;INCREMENT CURRENT SECTOR
INX H
XCHG
LHLD SPT ;CHECK TO SEE IF BEYOND END OF TRACK
CALL SUBDE
XCHG
JNC NEXTOK
LHLD CURTRK ;BEYOND END OF TRACK, SO INCR CURRENT TRACK
INX H
XCHG
LHLD MAXTRK ;SEE IF BEYOND END OF DISK
CALL SUBDE
JNC TRASK
LXI D,0 ;WRAP TO START OF DISK
;
TRASK:
XCHG
SHLD CURTRK ;SET NEW CURRENT TRACK
LXI H,1 ;SET SECTOR 1
;
NEXTOK:
SHLD CURSEC ;SET NEW CURRENT SECTOR
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 ;CHECK IF IN SYSTEM TRACKS
XCHG
LHLD CURTRK
CALL SUBDE
JC NOGRP
CALL ILPRT ;PRINT GROUP NUMBER IF NOT IN SYSTEM TRACKS
DB DIM,'Group = ',BRIGHT,0
LHLD GROUP
MOV B,H
MOV C,L
CALL HEXB ;PRINT GROUP NUMBER IN BC
MVI A,':'
CALL TYPE
LDA GRPDIS
CALL HEX ;PRINT GROUP DISPLACEMENT IN A
MVI A,','
CALL TYPE
;
NOGRP:
CALL ILPRT ;PRINT TRACK NUMBER
DB DIM,' Track = ',BRIGHT,0
LHLD CURTRK
CALL DEC ;TRACK NUMBER IN DECIMAL
CALL ILPRT ;PRINT SECTOR NUMBER
DB DIM,', Sector = ',BRIGHT,0
LHLD CURSEC
CALL DEC ;SECTOR NUMBER IN DECIMAL
CALL ILPRT ;PRINT PHYSCIAL SECTOR NUMBER
DB DIM,', Physical Sector = ',BRIGHT,0
LHLD PHYSEC
CALL DEC ;PHYSICAL SECTOR NUMBER IN DECIMAL
CALL CRLF
POP H
RET
;
;COMMAND: C
;Change Contents of Current Block
;
CHG:
MOV A,M ;GET TYPE (HEX, ASCII)
CALL UPCASE
PUSH PSW ;SAVE "H" OR "A"
INX H
CALL HEXIN ;GET DISP IN HEX
CALL DISP1 ;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 HEXIN
CALL DISP1 ;GET THRU
INX H ;SKIP END DELIM
MOV B,D
MOV C,E ;BC = THRU
POP D ;GET FROM
JMP CHGAH
;
CHGNTH:
CPI SEPCH
JNZ WHAT
;
CHGAH:
POP PSW
CPI 'H' ;HEX?
JZ CHGHEX
CPI 'A' ;ASCII?
JNZ WHAT
;
;Change ASCII
;
CHGALP:
MOV A,M ;GET CHAR
CPI CR
JZ PROMPT
CPI EOLCH
JZ PROMPT
;
;The following print of the deleted byte is commented out; if leading
; semicolons are removed, deleted bytes will be printed
;
; LDAX D ;GET BYTE THAT IS REPLACED
; CPI ' '
; JC CHGAHX
; CPI 7EH ;DON'T PRINT ESC CHAR FOR H1500
; JNC CHGAHX
; JMP CHGA2
;
;CHGAHX:
; CALL BHEX
; JMP CHGA3
;
;CHGA2:
; CALL TYPE
;
;End of print of delete bytes
;
CHGA3:
SHLD BACK ;IN CASE "THRU"
CALL GETVAL ;GET ASCII OR <HEX> VALUE
STAX D ;UPDATE BYTE
INX H ;PT 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 EOLCH
JZ PROMPT
JMP WHAT
;
;Change hex
;
CHGHCM:
INX H
;
CHGHEX:
MOV A,M ;GET HEX DIGIT
CPI CR
JZ PROMPT
CPI EOLCH
JZ PROMPT
CPI SEPCH ;DELIM?
JZ CHGHCM
PUSH D
SHLD HEXAD ;IN CASE 'THRU'
CALL HEXIN ;POSITIONS TO DELIM
MOV A,E ;GET VALUE
POP D ;..ADDR
;
;The following comments out the echo of the deleted byte; removing the
; leading semicolons restores the echo
;
; PUSH PSW ;SAVE VALUE
; LDAX D ;GET OLD
; CALL HEX ;ECHO IN HEX
; POP PSW ;GET NEW
;
;End of echo of bytes
;
STAX D ;SAVE NEW BYTE
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 EOLCH
JZ PROMPT
JMP WHAT
;
;COMMAND: R
;Read Current Block into TBUFF
;COMMAND: RG
;Read Specified Group into GBUFF
;
DOREAD:
LDA NOTPOS ;POSITIONED?
ORA A
JNZ CANTRD
CALL READ ;READ BLOCK
JMP PROMPT
;
CANTRD:
CALL ILPRT
DB '++ Can''t read - not positioned ++',CR,LF
DB 'Position by:',CR,LF
DB ' Track then Sector, or',CR,LF
DB ' Group',CR,LF,0
JMP PROMPT
;
;COMMAND: W
;Write Current Block to Disk
;COMMAND: WG
;Write Specified Group from GBUFF
;
DORITE:
CALL WRITE ;DO WRITE
JMP PROMPT
;
;Print Byte in A as Hex Digits
;
BHEX:
PUSH PSW
MVI A,'<'
CALL TYPE
POP PSW
CALL HEX
MVI A,'>'
CALL TYPE
RET
;
;Print Number in BC as Hex Digits
; HEXB does not print MS Byte if DSM shows small disk size
; HEXB1 prints BC regardless
;
HEXB:
LDA DSM+1
ORA A
JZ HEXX
HEXB1:
MOV A,B
CALL HEX
;
HEXX:
MOV A,C
;
;Print Byte in A as 2 Hex Digits
;
HEX:
PUSH PSW
RAR ;GET HIGH NYBBLE
RAR
RAR
RAR
CALL NIBBL ;PRINT IT
POP PSW ;GET LOW NYBBLE
;
NIBBL:
ANI 0FH ;MASK LOW NYBBLE
CPI 10 ;0-9?
JC HEXNU
ADI 7 ;CONVERT TO A-F
;
HEXNU:
ADI '0' ;CONVERT TO ASCII
JMP TYPE ;PRINT IT
;
;Decimal output routine
; Print Number in HL as decimal digits
;
DEC:
PUSH B
PUSH D
PUSH H
XRA A ;SET NO LEADING DIGIT
STA DDIG
LXI B,10000
CALL DPRT
DAD B
LXI B,1000
CALL DPRT
DAD B
LXI B,100
CALL DPRT
DAD B
LXI B,10
CALL DPRT
DAD B
MOV A,L ;ALWAYS PRINT LSD
ADI '0' ;ASCII
CALL TYPE
POP H
POP D
POP B
RET
DPRT:
PUSH B ;SAVE BC
MVI D,0FFH ;SET -1
DPRTL:
INR D ;ADD 1 TO OUTPUT DIGIT
MOV A,L ;L-C
SUB C
MOV L,A
MOV A,H ;H-B
SBB B
MOV H,A
JNC DPRTL
POP B ;RESTORE BC
LDA DDIG ;GET LEADING DIGIT FLAG
ORA D ;CHECK FOR ZERO STILL
STA DDIG ;SET FLAG
MOV A,D ;GET DIGIT TO PRINT
RZ ;ABORT IF BOTH ZERO
ADI '0' ;ASCII
JMP TYPE
DDIG: DS 1 ;TEMP FOR DEC USE ONLY
;
;Print <SP>
;
SPACE:
MVI A,' '
JMP TYPE
;
;Print a dim '|'
;
ASTER:
CALL STNDOUT ;DIM
MVI A,'|'
CALL TYPE
JMP STNDEND ;BRIGHT
;
;Inline print routine
; Print Chars ending in 0 pted to by Return Address; return to byte after
;
ILPRT:
XTHL ;PT TO STRING
ILPLP:
CALL CTLCS ;ABORT?
JZ PRMPTR
MOV A,M ;GET CHAR
; CPI 1 ;PAUSE? -- ^A
; JNZ ILPOK
; CALL CONIN ;WAIT FOR ANY CHAR
; CPI 3 ;ABORT?
; JZ PRMPTR
; JMP ILPNX
;
;ILPOK:
CPI DIM ;GOTO DIM?
JZ ILPDIM
CPI BRIGHT ;GOTO BRIGHT?
JZ ILPBRI
CALL TYPE ;PRINT CHAR
JMP ILPNX
ILPDIM:
CALL STNDOUT ;ENTER STANDOUT MODE
JMP ILPNX
ILPBRI:
CALL STNDEND ;EXIT STANDOUT MODE
;
ILPNX:
INX H ;PT TO NEXT
MOV A,M ;GET IT
ORA A ;DONE?
JNZ ILPLP
INX H ;PT TO BYTE AFTER ENDING 0
XTHL ;RESTORE HL AND RET ADR
RET
;
;DISP calls DECIN, and validates a sector
;displacement, then converts it to an address
;
DISP:
CALL DECIN
DISP1:
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:
CALL ILPRT
DB '++ Bad Displacement (Not 0-7FH) ++'
DB CR,LF,0
JMP PRMPTR
;
;Input Number from Command Line -- Assume it to be Hex
; Number returned in DE
;
HEXIN:
LXI D,0 ;INIT VALUE
MOV A,M
CPI '#' ;DECIMAL?
JZ HDIN ;MAKE DECIMAL
;
HINLP:
MOV A,M ;GET CHAR
CALL UPCASE ;CAPITALIZE
CPI CR ;EOL?
RZ
CPI EOLCH ;EOL?
RZ
CPI SEPCH
RZ
CPI ' ' ;SPACE?
RZ
CPI '-' ;'THRU'?
RZ
CPI '>'
RZ
INX H ;PT TO NEXT CHAR
CPI '0' ;RANGE?
JC WHAT
CPI '9'+1 ;RANGE?
JC HINNUM
CPI 'A' ;RANGE?
JC WHAT
CPI 'F'+1 ;RANGE?
JNC WHAT
SUI 7 ;ADJUST FROM A-F TO 10-15
;
HINNUM:
SUI '0' ;CONVERT FROM ASCII TO BINARY
XCHG
DAD H ;MULT PREVIOUS VALUE BY 16
DAD H
DAD H
DAD H
ADD L ;ADD IN NEW DIGIT
MOV L,A
XCHG
JMP HINLP
;
HDIN:
INX H ;SKIP '#'
;
;Input Number in Command Line as Decimal
; Number is returned in DE
;
DECIN:
LXI D,0
MOV A,M ; GET 1ST CHAR
CPI '#' ; HEX?
JNZ DINLP
INX H ; PT TO DIGIT
JMP HINLP ; DO HEX PROCESSING
;
DINLP:
MOV A,M ;GET DIGIT
CALL UPCASE ;CAPITALIZE
CPI '0' ;RANGE?
RC
CPI '9'+1 ;RANGE?
RNC
SUI '0' ;CONVERT TO BINARY
INX H ;PT TO NEXT
PUSH H
MOV H,D
MOV L,E
DAD H ;X2
DAD H ;X4
DAD D ;X5
DAD H ;X10
ADD L ;ADD IN DIGIT
MOV L,A
MOV A,H
ACI 0
MOV H,A
XCHG ;RESULT IN DE
POP H
JMP DINLP
;
;Read in a console buffer
;
RDBUF:
CALL ILPRT ;PRINT PROMPT
DB CR,LF,'DU3 ',0
LDA DRIVE ;GET DRIVE NUMBER
ADI 'A' ;CONVERT TO ASCII
CALL TYPE
LDA UNUM ;DISPLAY USER NUMBER
MOV L,A ;VALUE IN HL
MVI H,0
CALL DEC ;PRINT IN DECIMAL
CALL ILPRT ;PRINT PROMPT
DB '? ',0
;
;ENTRY POINT TO READ BUFFER WITHOUT PROMPT
;
RDBUF1:
LHLD INBUF ;USE CP/M READLN
DCX H
DCX H
XCHG
MVI C,10
PUSH D
CALL BDOS
POP D
INX D ;PT TO CHAR COUNT
LDAX D ;GET CHAR COUNT
MOV B,A ;CHAR COUNT IN B
INX D ;PT TO INPUT LINE
XCHG ;... IN HL
ADD L ;ADD CHAR COUNT TO HL
MOV L,A
MOV A,H
ACI 0
MOV H,A
MVI A,CR ;STORE ENDING CR
MOV M,A ;SET CR
CALL TYPE ;ECHO IT
MVI A,LF ;ECHO..
CALL TYPE ;..LF
LHLD INBUF ;SET PTR TO FIRST CHAR IN LINE
RET
;
;Set paging flag for page routine
;
PAGSET:
LDA PAGSIZ ;GET SIZE OF PAGE
STA PAGFLG ;SET FLAG
RET
;
;Page output
;
PAGER:
LDA PAGFLG ;GET FLAG
CPI 2 ;2 LINES LEFT?
JZ WAIT ;SAME AS USER DELAY
DCR A ;COUNT DOWN
STA PAGFLG
JMP CRLF
;
;Delay Routine
;
SWAIT:
CALL AT
DB 23,5 ;POSITION CURSOR
JMP WAIT0
WAIT:
CALL CRLF ;NEW LINE
WAIT0:
PUSH H
CALL ILPRT
DB DIM,'Type Any Character to Continue or ^C to Abort - ',BRIGHT,0
POP H
CALL CONIN ;GET RESPONSE
CPI 'C'-40H ;^C?
JZ WAIT1
CALL CRLF ;NEW LINE
CALL PAGSET ;RESET PAGE COUNT
RET
WAIT1:
LDA IHFLG ;INITIAL HELP?
ORA A ;0=NO
JZ PRMPTR ;ABORT TO COMMAND PROMPT
JMP EXIT1 ;ABORT TO CP/M
;
;CRLF Routine
;
CRLF:
MVI A,CR
CALL TYPE
MVI A,LF
JMP TYPE
;
;Convert to Upper Case
;
UPCASE:
ANI 7FH ;MASK OUT MSB
CPI 60H ;LESS THAN SMALL A?
RC ;RETURN IF SO
ANI 5FH ;MAKE UPPER CASE
RET
;
;CON: Status Routine
;
CONST:
PUSH B
PUSH D
PUSH H
VCONST:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
POP D
POP B
RET
;
;CON: Input Routine
;
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
; Char in A
;
TYPE:
PUSH B ;SAVE REGS
PUSH D
PUSH H
MOV C,A ;FOR OUTPUT ROUTINE
CPI TAB
JNZ TYPE2
;Tabulate
TYPTAB:
MVI A,' ' ;PRINT SPACE
CALL TYPE
LDA TABCOL ;GET COL COUNT
ANI 7 ;DONE?
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:
;
;CON: Output Routine
;
VCONOT: CALL $-$ ;ADDR FILLED IN BY 'INIT'
;
;Update column used in tab expansion
;
MOV A,C ;GET CHAR
CPI CR
JNZ TYPNCR
MVI A,0 ;RESET TAB COLUMN IF <CR>
STA TABCOL
JMP TYPLST
;
TYPNCR:
CPI ' ' ;CTL CHAR?
JC TYPLST ;..NO CHANGE IN COL
LDA TABCOL ;INCR TAB COUNT
INR A
STA TABCOL
;
TYPLST:
LDA PFLAG ;CHECK FOR PRINTER OUTPUT
ANI 1
CNZ LIST ;FROM C REG
;
TYPRET:
POP H ;RESTORE REGS
POP D
POP B
RET
;
;LST: Output Routine
; Char in C
;
LIST:
PUSH B ;SAVED REGS
PUSH D
PUSH H
VLIST:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
POP D
POP B
RET
;
;Home Disk Routine
;
HOME:
PUSH H
VHOME:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
RET
;
;Set track # in DE
;
SETTRK:
PUSH H
LHLD MAXTRK ;CHECK FOR WITHIN BOUNDS
CALL SUBDE ;IF TRACK # IN DE > MAX, THEN ERROR
POP H
JC OUTLIM
XCHG ;RESET CURRENT TRACK
SHLD CURTRK
XCHG
MOV B,D ;BC=TRACK NUMBER
MOV C,E
PUSH H
;
VSETRK:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H
RET
;
;Set Sector Number in DE
;
SETSEC:
PUSH H
PUSH D
LHLD SYSTRK ;GET NUMBER OF SYSTEM TRACKS
XCHG
SHLD CURSEC ;SET CURRENT SECTOR
LHLD CURTRK ;GET CURRENT TRACK
CALL SUBDE ;SEE IF WE ARE IN THE SYSTEM TRACKS
POP B ;BC=SECTOR NUMBER
MOV H,B ;HL=SECTOR NUMBER
MOV L,C
JNC NOTSYS ;IF NO CARRY FOR SUBDE, WE ARE NOT IN SYSTEM TRACKS
LDA FIRST0 ;SEE IF FIRST SEC 0
ORA A
JNZ GSTSEC ;NO, JUMP AWAY
DCX H ;YES, SO DECREMENT
JMP GSTSEC ;REQUESTED, THEN GO
;
;Not in System Tracks, so Skew Factor is effective
;
NOTSYS:
LHLD SECTBL ;GET PTR TO SECTOR TABLE
XCHG ;... IN DE
DCX B ;DECREMENT SECTOR NUMBER BY 1
;
VSCTRN:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
LDA SPT+1 ;IF SPT<256 (HI-ORD = 0)
ORA A ; THEN FORCE 8-BIT TRANSLATION
JNZ GSTSEC ; ELSE KEEP ALL 16 BITS
MOV H,A
GSTSEC:
SHLD PHYSEC
MOV B,H
MOV C,L
;
VSTSEC:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
POP H ;RESTORE PTR TO NEXT CHAR
RET
;
;Out of Disk Track Limit
;
OUTLIM:
CALL ILPRT
DB '++ Not Within Tracks 0-',0
PUSH H
LHLD MAXTRK ;PRINT MAX TRACK NUMBER
CALL DEC
POP H
CALL ILPRT
DB ' ++',CR,LF,0
CALL NORITE ;NOT POSITIONED
JMP PRMPTR
;
;Set DMA Address
;
SETDMA:
JMP $-$ ;ADDR FILLED IN BY 'INIT'
;
;Read Next Block into DMA Address
;
READ:
MVI A,1 ;SET FLAG
STA WRFLG
PUSH H ;SAVE PTR TO NEXT CHAR
;
VREAD:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
ORA A ;ERROR?
JZ READOK
CALL ILPRT
DB '++ READ Failed, Sector may be Invalid ++'
DB CR,LF,0
;
READOK:
POP H ;GET PTR TO NEXT CHAR
RET
;
;Write Block in DMA Address to Disk
;
WRITE:
LDA WRFLG ;READ ALREADY PERFORMED?
ORA A ;ERROR IF NOT
JNZ PWRITE
;
BADW:
CALL ILPRT
DB '++ Cannot Write Unless Read Issued ++'
DB CR,LF,0
JMP EXPL
;
;Do Write
;
PWRITE:
PUSH H ;SAVE PTR TO NEXT CHAR
MVI C,1 ;FORCE WRITE TYPE 1 IN CASE 2.x DEBLOCK USED
;
VWRITE:
CALL $-$ ;ADDR FILLED IN BY 'INIT'
ORA A ;ERROR?
JZ WRITOK
CALL ILPRT
DB '++ WRITE Failed ++',CR,LF,0
;
WRITOK:
POP H
RET
;
;Help; HELP is entry point for HELP (?) command, HELP1 is entry point for
; Initial Help Command, and IHELP is entry point for HELP (/) from command
; line
;
IHELP:
call cls
cz crlf
call helpban
CALL ILPRT
DB DIM,'Introductory HELP on DU3 (Disk Utility)',BRIGHT,CR,LF
DB ' The DU3 program is designed to provide the user with'
DB CR,LF
DB 'the ability to manipulate information on the disk as easily'
DB CR,LF
DB 'as the DDT and SID utilities allow the user to manipulate'
DB CR,LF
DB 'information in memory.',CR,LF
DB ' The following is a summary of the commands available to'
DB CR,LF
DB 'the DU3 user. This same list is invoked internally by the'
DB CR,LF
DB '? Command of DU3. For additional information on disk'
DB CR,LF
DB 'structures and how to use DU3 in general, refer to the'
DB CR,LF
DB 'file DU3.HLP.',CR,LF,0
MVI A,0FFH ;A=0FFH
STA IHFLG ;SET INITIAL HELP
CALL SWAIT
JMP HELP1 ;PROCESS NORMALLY
HELP:
XRA A ;A=0
STA IHFLG ;SET NO INITIAL HELP
HELP1:
call cls
cz crlf
call helpban ;print help banner
CALL ILPRT
DB 'Operands in brackets [...] are optional'
DB CR,LF,CR,LF
DB ' @ ',DIM,'Repeat Previous Non-@ Command Line'
DB BRIGHT,CR,LF
DB ' +[nn] ',DIM,'Step In [nn (decimal)] Sectors'
DB BRIGHT,CR,LF
DB ' -[nn] ',DIM,'Step Out [nn (decimal)] Sectors'
DB BRIGHT,CR,LF
DB DIM
DB ' Note: + or - need not be followed by a "," to '
DB 'delimit commands.'
DB BRIGHT
DB CR,LF
DB ' # ',DIM,'Print Disk Parameters for Current Drive'
DB BRIGHT
DB CR,LF
DB ' =xxx ',DIM
DB 'Search for ASCII xxx from Current Sector'
DB BRIGHT
DB CR,LF
DB DIM
DB ' Note: upper/lower case matters. Use <xx> for hex:'
DB BRIGHT
DB CR,LF
DB DIM
DB ' To find "IN 0" use: =<db><0> or'
DB BRIGHT
DB CR,LF
DB DIM
DB ' "(tab)H,0(CR)(LF)" use: =<9>H,0<D><A>'
DB BRIGHT
DB CR,LF
DB ' *[nn] ',DIM,'Repeat [nn (decimal) times]'
DB BRIGHT,CR,LF
DB ' ! ',DIM,'Pause for User',BRIGHT,CR,LF
DB ' :ntext ',DIM,'Define ''text'' to be Macro n'
DB BRIGHT,CR,LF
DB ' n ',DIM,'Perform Macro n, 0<=n<=9',BRIGHT,CR,LF
DB ' :Pn ',DIM,'Print Macro n, 0<=n<=9',BRIGHT
DB CR,LF
DB ' :Px ',DIM
DB 'Print All Macros if x=A or Print Prev Line if x=@'
DB BRIGHT
DB 0
CALL SWAIT
call cls
cz crlf
call helpban
CALL ILPRT
DB ' A[ff,tt] ',DIM,'ASCII Dump',BRIGHT
DB CR,LF
DB ' C ',DIM,'Change:',BRIGHT
DB CR,LF
DB ' CHaddr byte byte... (hex)'
DB CR,LF
DB ' ',DIM,'or',BRIGHT
DB ' CAaddr data... (Ascii)'
DB CR,LF
DB DIM
DB ' <xx> Allowed for imbedded hex.'
DB BRIGHT
DB CR,LF
DB ' ',DIM,'or',BRIGHT
DB ' CHfrom-thru byte e.g. ch0-7f e5'
DB CR,LF
DB ' ',DIM,'or',BRIGHT,' CAfrom-thru byte'
DB CR,LF
DB ' D[ff,tt] ',DIM,'Dump (Hex and ASCII)',BRIGHT
DB CR,LF
DB ' E ',DIM,'DU3 Editor',BRIGHT,CR,LF
DB ' ',DIM,' Note: Rest of Command Line '
DB 'is Flushed',BRIGHT,CR,LF
DB ' Ffn.ft ',DIM,'Find File',BRIGHT
DB CR,LF
DB ' Gnn ',DIM,'CP/M Allocation Group nn (hex)'
DB BRIGHT,CR,LF
DB ' H[ff,tt] ',DIM,'Hex Dump',BRIGHT
DB CR,LF
DB ' L[d] ',DIM,'Log in Current Drive or Drive d'
DB BRIGHT,CR,LF
DB ' M[nn] ',DIM,'Map [from group nn (hex)]'
DB BRIGHT
DB 0
CALL SWAIT
call cls
cz crlf
call helpban
CALL ILPRT
DB ' N ',DIM,'Load New Disk',BRIGHT,CR,LF
DB ' P ',DIM,'Toggle Printer Switch',BRIGHT,CR,LF
DB ' Q ',DIM,'Queue Status;',BRIGHT,CR,LF
DB ' QZ ',DIM,'Zero (Empty) Queue',BRIGHT,CR,LF
DB ' QSfn.ft ',DIM,'Save Queue as a File on Disk',BRIGHT
DB CR,LF
DB ' < ',DIM,'Save Current Block into Temp',BRIGHT
DB CR,LF
DB ' > ',DIM,'Restore Temp Block',BRIGHT,CR,LF
DB ' <B ',DIM,'Save Block into Queue',BRIGHT,CR,LF
DB ' >B ',DIM,'Restore Queue Block',BRIGHT,CR,LF
DB ' <G[n] ',DIM,'Save Group into Queue',BRIGHT,CR,LF
DB ' >G[n] ',DIM,'Restore Queue Group',BRIGHT,CR,LF
DB ' Snn ',DIM,'Sector nn (decimal)',BRIGHT,CR,LF
DB ' Tnn ',DIM,'Track nn (decimal)',BRIGHT,CR,LF
DB ' Unn ',DIM,'Set User nn (decimal) for Find command'
DB BRIGHT,CR,LF
DB ' V[nn] ',DIM,'View [nn (decimal)] ASCII Blocks',BRIGHT
DB CR,LF
DB ' R ',DIM,'Read Current Block',BRIGHT,CR,LF
DB ' W ',DIM,'Write Current Block',BRIGHT,CR,LF
DB ' X ',DIM,'Exit Program',BRIGHT,CR,LF
DB ' Z[nn] ',DIM,'Sleep [nn (decimal) seconds]',BRIGHT
DB 0
CALL SWAIT
call cls
cz crlf
call helpban
CALL ILPRT
DB DIM,'Command Line is of the form: ',BRIGHT,'DU3 du?',CR,LF
DB ' ',DIM,'"d" is Logged-In Disk, "u" is Current User'
DB BRIGHT,CR,LF
DB CR,LF
DB 'Ctrl-C ',DIM,'Cancel a function',BRIGHT,CR,LF
DB 'Ctrl-S ',DIM,'Suspend output',BRIGHT,CR,LF
DB '"," ',DIM,'Separate commands',BRIGHT,CR,LF
DB CR,LF
DB DIM,'Examples:',BRIGHT,' g0 ',DIM,'and',BRIGHT
DB ' +,d,z2,*'
DB CR,LF
DB DIM,'Causes:',BRIGHT,CR,LF
DB ' 1. Position to group 0',CR,LF
DB ' 2. Loops on step in, dump, sleep 2 sec',CR,LF
DB ' until control-c is typed',CR,LF,CR,LF
DB '"nn" usage varies with command as follows:',CR,LF
DB ' +, -, *, T, S, U, V, Z ',DIM,'nn in Decimal'
DB BRIGHT,CR,LF
DB ' ',DIM,'(use #nn for Hex)'
DB BRIGHT,CR,LF
DB ' G, M ',DIM,'nn in Hexadecimal'
DB BRIGHT,CR,LF
DB ' ',DIM,'(use #nn for Decimal)'
DB BRIGHT,CR,LF
DB CR,LF
DB '"ff" and "tt" are in Hexadecimal (use #ff or #tt for Decimal)'
DB 0
CALL SWAIT
LDA IHFLG ;INITIAL HELP?
ORA A ;0=NO
JNZ EXIT1 ;RETURN TO CP/M IF SO
JMP PRMPTR ;NEW LINE INPUT IF NOT
helpban:
call ilprt
DB ' ',DIM,'-- DU3 Command Summary --',BRIGHT
DB CR,LF,CR,LF,0
ret
;
;COMMAND: X
;Exit to CP/M
;
EXIT:
call dinit ;deinit terminal
JMP BASE ;WARM BOOT
;
;Quick Exit to CP/M
;
EXIT1:
LHLD DUTSTK ;GET CP/M STACK PTR
SPHL ;SET SP
RET
;
;********************************
;* *
;* 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 ;NUMBER OF BITS
;
COLOP:
RAL
JNC COSKIP
INR C
;
COSKIP:
DCR B
JNZ COLOP
RET
;
;HL-DE ==> HL
; Carry Flag is Significant
;
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:
LXI D,DPB ; THEN MOVE TO LOCAL
MVI B,DPBLEN ; WORKSPACE
CALL MOVE
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
;***********************************
;
; DU3 Command Table
;
;***********************************
CMDTBL:
DB ' ' ;null command
DW PROMPT
;
DB ':'
DW MAC
;
DB '@'
DW PCMD
;
DB '+'
DW PLUS
;
DB '-'
DW MINUS
;
DB '='
DW SEARCH
;
DB '<'
DW SAVE
;
DB '>'
DW RESTOR
;
DB '#'
DW STATS
;
DB '?'
DW HELP
;
DB MULCH
DW REPEAT
;
DB '!'
DW UWAIT
;
DB 'A'
DW DUMP
;
DB 'C'
DW CHG
;
DB 'D'
DW DUMP
;
DB 'E'
DW EDIT
;
DB 'F'
DW POSFIL
;
DB 'G'
DW POS
;
DB 'H'
DW DUMP
;
DB 'L'
DW LOGIN
;
DB 'M'
DW MAP
;
DB 'N'
DW NEWDSK
;
DB 'P'
DW PRNTFF
;
DB 'Q'
DW QUEUER
;
DB 'R'
DW DOREAD
;
DB 'S'
DW POS
;
DB 'T'
DW POS
;
DB 'U'
DW USER
;
DB 'V'
DW VIEW
;
DB 'W'
DW DORITE
;
DB 'X'
DW EXIT
;
DB 'Z'
DW SLEEP
;
DB 0 ; End of Table
;*************************************
;
;Temporary storage area
;
clock:
ds 1 ;clock speed
pagsiz:
ds 1 ;page size
muser:
ds 1 ;max user
mdisk:
ds 1 ;max disk
STKSAV:
DS 2 ;SAVE HL VALUE
DUTSTK:
DS 2 ;OLD CP/M STACK POINTER; TOP OF DU3 STACK
BUFAD:
DS 2 ;FORCES INITIAL READ
QCNT:
DS 2 ;NUMBER OF SECTORS IN QUEUE
QNXT:
DS 2 ;PTR TO NEXT SECTOR IN QUEUE
QLST:
DS 2 ;PTR TO LAST SECTOR IN QUEUE
QPTR:
DS 2 ;G-P QUEUE PTR
HEXAD:
DS 2 ;TO RE-FETCH A VALUE
TOGO:
DS 2 ;REPEAT COUNT (FFFF=CONT)
TWOUP:
DS 1
UNUM:
DS 1 ;NUMBER OF CURRENT USER
ONLY1:
DS 1 ;FLAG TO PRINT ONLY 1 MAP ENTRY (0=NO)
MFPTR:
DS 2 ;MULTI FILE PTR FOR GETGRP
PAGFLG:
DS 1 ;LINE COUNTER FOR PAGING
PFLAG:
DS 1 ;1=PRINT
GROUP:
DS 2 ;GROUP NUMBER
GRPDIS:
DS 1 ;DISPLACEMENT INTO GROUP
SAVEFL:
DS 1 ;SAVE FLAG
CURTRK:
DS 2 ;CURRENT TRACK NUMBER
CURSEC:
DS 2 ;CURRENT SECTOR NUMBER
PHYSEC:
DS 2 ;CURRENT PHYSICAL SECTOR NUMBER
TABCOL:
DS 1 ;TAB COLUMN
CPYFCT:
DS 1 ;GROUP COPY FUNCTION; 0=READ, 0FFH=WRITE
FILECT:
DS 2 ;FILE COUNT
DIRPOS:
DS 1 ;POSITION IN DIRECTORY
FINDFL:
DS 1 ;1=MUST POSITION AFTER FIND
FTSW:
DS 1 ;SEARCH W/O INCREMENT
NOTPOS:
DS 1 ;INITIALLY NOT POSITIONED
WRFLG:
DS 1 ;MAY NOT WRITE UNTIL '+', '-',
; OR 'G' COMMAND
TGRP:
DS 2 ;TEMPORARY GROUP FLAG
FIRST0:
DS 1 ;SETS TO 0 IF FIRST SEC # IS 0
DRIVE:
DS 1 ;DRIVE NUMBER
MAXTRK:
DS 2 ;MAX TRACK NUMBER
MAXSEC:
DS 2 ;MAX SECTOR NUMBER
SECTBL:
DS 2 ;POINTER TO SECTOR SKEW TABLE
;
IHFLG:
DS 1 ;0=NOT AT INITIAL HELP, 0FFH=AT INITIAL HELP
DUPFLG:
DS 1 ;SPACE OR STAR TO INDICATE MULTIPLE USERS
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 2
INBUF:
DS 2 ;INPUT LINE BUFFER
PINBUF:
DS 2 ;PREVIOUS CONTENTS OF INPUT BUFFER
CTEMP:
DS 2 ;BUILD NEW COMMAND LINE BUFFER
CTEMPX:
DS 2 ;END OF CTEMP
MTABL:
DS 2 ;10 PAGES FOR 10 MACROS
GBUFF:
DS 2
DIRECT:
DS 2
;
END