home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol099
/
du2.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
69KB
|
3,903 lines
;
; PROGRAM: DU2
; AUTHOR: RICHARD CONN
; DERIVATION: DUTIL is derived from DU Version 7.5
; DU2 is derived from DUTIL Version 1.1
; VERSION: 1.0
; DATE: 10 JAN 83
; PREVIOUS VERSIONS: None
; NOTE: DU2 must be assembled using MAC (or equiv) and will only run on
; a Z80
;
VERS EQU 10
;
; DU2 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 DU2 follow --
;
;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.
;
;For DU2, the additional value of PAGSIZ at 104h should
;be set for the size of the display (in lines) on the user's
;CON: device. Under DU2, all output is paged, and this
;determines the page limit.
;
;*************************************************
;* *
;* 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. *
;* 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 *
;* *
;*************************************************
;
; The last few revision notes for note are --
;
;
;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 DU2
;
EOLCH equ ',' ;Marks logical end of line
SEPCH equ ' ' ;Argument Separator
MULCH equ '*' ;Multiplication Command
;
;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
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 TO PROVIDE Z80 EXTENSIONS
; MACROS INCLUDE:
;
$-MACRO ;FIRST TURN OFF THE EXPANSIONS
;
; JR - JUMP RELATIVE
; JRC - JUMP RELATIVE IF CARRY
; JRNC - JUMP RELATIVE IF NO CARRY
; JRZ - JUMP RELATIVE IF ZERO
; JRNZ - JUMP RELATIVE IF NO ZERO
; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO
; LDIR - MOV @HL TO @DE FOR COUNT IN BC
; LXXD - LOAD DOUBLE REG DIRECT
; SXXD - STORE DOUBLE REG DIRECT
; EXX - EXCHANGE BC, DE, HL WITH BC', DE', HL'
;
;
;
; @GENDD MACRO USED FOR CHECKING AND GENERATING
; 8-BIT JUMP RELATIVE DISPLACEMENTS
;
@GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS
IF (?DD GT 7FH) AND (?DD LT 0FF80H)
DB 100H ;Displacement Range Error on Jump Relative
ELSE
DB ?DD
ENDIF ;;RANGE ERROR
ENDM
;
;
; Z80 MACRO EXTENSIONS
;
JR MACRO ?N ;;JUMP RELATIVE
DB 18H
@GENDD ?N-$-1
ENDM
;
JRC MACRO ?N ;;JUMP RELATIVE ON CARRY
DB 38H
@GENDD ?N-$-1
ENDM
;
JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY
DB 30H
@GENDD ?N-$-1
ENDM
;
JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
DB 28H
@GENDD ?N-$-1
ENDM
;
JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO
DB 20H
@GENDD ?N-$-1
ENDM
;
DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
DB 10H
@GENDD ?N-$-1
ENDM
;
LDIR MACRO ;;LDIR
DB 0EDH,0B0H
ENDM
;
LDED MACRO ?N ;;LOAD DE DIRECT
DB 0EDH,05BH
DW ?N
ENDM
;
LBCD MACRO ?N ;;LOAD BC DIRECT
DB 0EDH,4BH
DW ?N
ENDM
;
SDED MACRO ?N ;;STORE DE DIRECT
DB 0EDH,53H
DW ?N
ENDM
;
SBCD MACRO ?N ;;STORE BC DIRECT
DB 0EDH,43H
DW ?N
ENDM
;
EXX MACRO ;;EXCHANGE PRIMARY AND ALTERNATE REGISTERS
DB 0D9H
ENDM
;
; END OF Z80 MACRO EXTENSIONS
;
;
;Beginning of Program
;
ORG TPA
jmp start
;
;******************************************************************
;
; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
; This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;
;
; EXTERNAL PATH DATA
;
EPAVAIL:
DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE
;
; INTERNAL PATH DATA
;
INTPATH:
DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT
; DISK = 1 FOR A, '$' FOR CURRENT
; USER = NUMBER, '$' FOR CURRENT
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT
DB 0 ; END OF PATH
;
; MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE
;
; DISK/USER LIMITS
;
MDISK:
DB 4 ; MAXIMUM NUMBER OF DISKS
MUSER:
DB 31 ; MAXIMUM USER NUMBER
;
; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
;DOK:
DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
;UOK:
DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES)
;
; PRIVILEGED USER DATA
;
PUSER:
DB 10 ; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS
DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL
;
; CURRENT USER/DISK INDICATOR
;
CINDIC:
DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS)
;
; DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
DW 80H ; TBUFF AREA
;
; NAMED DIRECTORY INFORMATION
;
NDRADR:
DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
DB 64 ; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
DB 'NAMES ' ; NAME OF DISK NAME FILE
DB 'DIR' ; TYPE OF DISK NAME FILE
;
; REQUIREMENTS FLAGS
;
EPREQD:
DB 000H ; EXTERNAL PATH?
MCREQD:
DB 000H ; MULTIPLE COMMAND LINE?
MXREQD:
DB 0FFH ; MAX USER/DISK?
UDREQD:
DB 000H ; ALLOW USER/DISK CHANGE?
PUREQD:
DB 000H ; PRIVILEGED USER?
CDREQD:
DB 000H ; CURRENT INDIC AND DMA?
NDREQD:
DB 000H ; NAMED DIRECTORIES?
Z2CLASS:
DB 6 ; CLASS 6
DB 'ZCPR2'
DS 10 ; RESERVED
;
; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;
;
; Extra Buffers et al
;
CLOCK:
DB 2 ;<---Put Processor Speed Here (1=1MHZ, 2=2MHZ, etc)
PAGSIZ:
DB 24 ;<---Put CRT Screen Size Here (24 Lines default)
DB 'DU2.COM from DU.COM ver 7.5 1/23/81 by RLC'
;
; Start of Program
;
START:
LXI H,0 ;GET PTR TO CP/M STACK
DAD SP ;HL=SP
SHLD DUTSTK ;SAVE IT
;
LXI SP,DUTSTK ; SET STACK
;
MVI C,GVERS ;GET CP/M VERSION NR
CALL BDOS
MOV A,H ;MUST NOT BE VERSION 1.4
ORA L
JRNZ START1
CALL ILPRT
DB CR,LF,'DU2 cannot run on CP/M Version 1.4 -- Aborting',0
JMP EXIT1
;
;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
JR 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 CR,LF,'DU2 - Disk Utility II, Version '
DB VERS/10+'0','.',(VERS MOD 10)+'0'
DB CR,LF
DB 'Type ? for Help'
DB CR,LF,0
LXI H,TBUFF ;TO INPUT BUFF
MOV A,M
ORA A
JRZ PRMPTR ;NO INITIAL COMMAND FROM COMMAND LINE
;
;Got initial command, set it up
;
MOV B,A ;SAVE LENGTH
DCR B ;JUST A SPACE?
JRZ PRMPTR ;GOTO COMMAND PROCESSOR IF SO
LXI D,INBUF ;PT TO INLINE BUFFER
INX H ;SKIP LEN
INX H ;SKIP ' '
MOV A,M ;GET FIRST CHAR
CPI '/' ;IF SLASH, PRINT INITIAL HELP (TOOLSET CONVENTION)
JZ IHELP ;PRINT INITIAL HELP INFO
CALL MOVE ;COPY INPUT LINE INTO INLINE BUFFER
MVI A,CR ;STORE ENDING <CR>
STAX D
LXI H,INBUF ;PT TO FIRST BYTE OF INLINE BUFFER
JR PRMPTI ;PROCESS AS THOUGH IT WAS TYPED
;
;Input Command Line From User at Console
;
PRMPTR:
XRA A ;A=0
STA IHFLG ;Set No Initial Help
CALL SINBUF ;Save old INBUF into PINBUF
CALL RDBUF ;Read Input Line
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:
LXI SP,DUTSTK ;RESET STACK
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?
JRZ 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?
JRZ PRMPTR ;INPUT NEW COMMAND LINE IF SO
CPI EOLCH ;END OF LINE LOGICALLY?
JRZ PROMPT ;PROCESS NEXT ELEMENT IF SO
CALL UPCASE ;CAPITALIZE COMMAND
STA DUMTYP ;TYPE OF DUMP (A,D,H)
;
;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
;
PUSH H ;SAVE HL
MOV B,A ;COMMAND IN B
LXI H,CMDTBL ;SCAN COMMAND TABLE FOR USER COMMAND
CMDLP:
MOV A,M ;GET COMMAND
ORA A ;0=END OF TABLE
JZ WHAT
CMP B ;COMPARE COMMAND
JRZ CMDGO
INX H ;PT TO ADR
INX H
INX H ;PT TO NEXT CMND
JR CMDLP
CMDGO:
INX H ;PT TO ADDRESS LOW
MOV E,M
INX H ;PT TO ADDRESS HIGH
MOV D,M
MOV A,B ;COMMAND BACK INTO A
POP H ;RESTORE HL
PUSH D ;PLACE ADDRESS ON STACK
RET ;"RUN COMMAND"
;
;Macro Expansion Routine -- Expand Macros
;
EXMAC:
LXI H,INBUF ;PT TO INPUT LINE
LXI D,CTEMP ;BUILD INTO TEMPORARY BUFFER
EXMAC1:
MOV A,M ;GET CHAR
CPI '0' ;SKIP IF LESS THAN '0'
JRC EXMAC2
CPI '9'+1 ;CHECK FOR RANGE
JRNC 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
LXI H,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?
JRZ EXMAC3
CPI EOLCH ;LOGICAL EOL?
JRNZ EXMAC2
JR EXMAC1 ;PROCESS NEXT COMMAND
EXMAC3:
LXI H,CTEMP ;COPY COMMAND LINE BACK
LXI D,INBUF ;INTO INBUF
CALL COPYCR ;COPY TO <CR>
LXI H,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?
JRNZ COPYM
RET
;
;Test for Buffer Full
;
MTEST:
PUSH H ;SAVE HL
PUSH PSW ;SAVE A
LXI H,CTEMPX ;CHECK FOR END OF BUFFER
MOV A,H ;GET PAGE
CMP D ;CHECK PAGE
JRZ 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:
LXI H,INBUF ;PT TO INBUF
LXI D,PINBUF ;PT TO PINBUF (PREVIOUS 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?
JRNZ COPYCR
RET
;
;Command Not Found Error
;
WHAT:
POP H ; RESTORE HL
CALL ILPRT
DB 'Invalid Command at or after ',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: @
;Repeat Previous Command Line
;
PCMD:
MOV A,M ;GET NEXT CHAR
CPI CR ;SHOULD BE <CR>
JRZ PCMD1
CALL ILPRT
DB CR,LF,'Warning: Remainder of Command Line after "@" Deleted',0
PCMD1:
CALL ILPRT
DB CR,LF,'Command --',CR,LF,0
LXI H,PINBUF ;GET PREVIOUS COMMAND
LXI D,INBUF ;COPY INTO INBUF
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
JRNZ PCMD2
MVI A,LF ;<LF>
CALL TYPE
LXI H,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?
JRZ PCPR
PUSH PSW ;SAVE A
CALL ILPRT
DB 'Macro Definitions --',0
POP PSW ;GET A
CPI 'A' ;PRINT ALL MACROS?
JRZ 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 'Previous Command Line Definition --'
DB CR,LF,'@: ',0
LXI H,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?
JRNZ 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,0
MOV A,D ;GET NUMBER
ADI '0' ;CONVERT TO ASCII
CALL TYPE ;PRINT
CALL ILPRT
DB ': ',0
LXI H,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
JRNZ 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
JRC MNERR ;ERROR IF LESS
CPI 10 ;RANGE?
JRNC 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
LXI H,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 ILPRT
DB '+=============================+',CR,LF
DB '| -- Queue Information -- |',CR,LF
DB '+-----------------------------+',CR,LF
DB 0
CALL QSTATS ;PRINT STATUS INFO
CALL ILPRT
DB CR,LF,CR,LF
DB '+=============================+',CR,LF
DB '| -- Disk Information -- |',CR,LF
DB '+-----------------------------+',CR,LF
DB CR,LF,'Disk Drive: ',0
LDA DRIVE
ADI 'A' ;CONVERT TO ASCII
CALL TYPE ;PRINT DRIVE LETTER
CALL ILPRT
DB CR,LF,'Tracks: ',0
LHLD MAXTRK ;PRINT NUMBER OF TRACKS
INX H
CALL DEC
CALL ILPRT
DB CR,LF,'Sectors/Track: ',0
LHLD SPT ;PRINT NUMBER OF SECTORS/TRACK
CALL DEC
CALL ILPRT
DB CR,LF,'Group Size: ',0
LDA BLM ;PRINT SIZE OF A GROUP
INR A
MOV L,A
MVI H,0
CALL DEC
CALL ILPRT
DB ' Blocks/Group'
DB CR,LF,'Total Groups: ',0
LHLD DSM ;PRINT TOTAL NUMBER OF GROUPS ON A DISK
CALL DEC
CALL ILPRT
DB CR,LF,'Directory Entries: ',0
LHLD DRM ;PRINT NUMBER OF DIRECTORY ENTRIES
INX H
CALL DEC
CALL ILPRT
DB CR,LF,'System Tracks: ',0
LHLD SYSTRK ;PRINT NUMBER OF SYSTEM TRACKS
CALL DEC
CALL ILPRT
DB CR,LF
DB '===============================',CR,LF,0
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?
JRZ QSTAT ;STATUS REPORT
CPI CR ;END OF LINE?
JRZ QSTAT
INX H ;PT TO AFTER KEY CHAR
PUSH H ;SAVE PTR
CPI 'Z' ;ZERO QUEUE?
JRZ 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:
LXI H,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 ILPRT
DB '** Queue Status Summary **',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 'Address of Head of Queue: ',0
LHLD QNXT ;PRINT ADDRESS OF HEAD OF QUEUE
MOV B,H ;... ADDRESS IN BC
MOV C,L
CALL HEXB ;PRINT IN HEX
CALL ILPRT
DB ' Hex',CR,LF
DB 'Address of Tail of Queue: ',0
LHLD QLST ;PRINT ADDRESS OF TAIL OF QUEUE
MOV B,H
MOV C,L
CALL HEXB
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
JRNZ QSTAT1
MOV A,L
CMP E
JRNZ QSTAT1
MOV H,B ;HL=BLOCK COUNT
MOV L,C
CALL DEC ;PRINT AS DECIMAL
CALL ILPRT
DB ' Blocks Left in Queue',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
JRNZ 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
JRZ 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
JRNZ NNN ;NO: COUNTING
XCHG ;GET COUNT
SHLD TOGO ;SET COUNT
;
NNN:
LHLD TOGO ;GET CURRENT COUNT
XCHG ;DE=CURRENT COUNT, HL=COUNT LIMIT
LXI H,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
JRNZ 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
JRNZ 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
MVI A,CR ;CLEAR PREVIOUS COMMAND
STA PINBUF ;SET PREVIOUS COMMAND TO NIL
LXI H,DIRECT ;SET FIRST AND LAST QUEUE ELEMENT PTRS
SHLD QNXT
SHLD QLST
LXI H,MTABL ;CLEAR MACRO TABLE
MVI B,10 ;10 ENTRIES
INITP1:
MVI M,CR ;STORE <CR>
INR H ;PT TO NEXT PAGE
DJNZ INITP1
RET
;
;Set up flags, etc, at initialization
;Find our way at initialization
;
GETSTP:
MVI A,CR ;INITIALIZE INPUT BUFFER
STA INBUF ;EMPTY BUFFER
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
JRZ LGNODK
CPI EOLCH ;NO REQUEST IF LOGICAL EOL
JRZ 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
JRC 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
LXI D,DIRECT ;DMA ADDR
;
;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
JRNZ 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?
JRZ 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..
JRNZ MAPC1 ;..THE DISK CAPACITY..
MOV A,H
CMP B
;
MAPC1:
POP H
JRZ MAPEND ;..AND WE ARE DONE
PUSH H
CALL GETGRP ;GET ANOTHER
POP D ;SEE IF SAME
CALL CTLCS ;ABORT?
JRZ MAPND2
MOV A,D
CMP H
JRNZ MAPDIF
MOV A,E
CMP L
JRZ 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
JRNZ MAPND1
JR 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
JRNZ 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
JR FLIP
;
NONAME:
CALL ILPRT
DB ' ++ Free ++ ',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?
JRC MAPN2H ;..NO, IN HEX
CPI 7EH ;7E IS LEADIN ON SOME CRTS
JRC 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
LXI H,DIRECT ;PT TO DIRECTORY
;
GETGLP:
PUSH H ;SAVE POINTER TO NAME
MOV A,M ;PICK UP DN BYTE
CPI 0E5H ;ERASED?
JRZ 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
JRZ 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
JRNZ 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
JRZ 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
JRNZ 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
JRNZ 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
JRZ QSAV ;SAVE ON STACK
CPI 'G' ;GROUP SAVE
JZ SAVEG
PUSH H
LXI H,TBUFF ;COPY FROM TBUFF
LXI D,SAVBUF ;INTO SAVBUF
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
JRNZ QSAV1
MOV A,L ;MAY NOT BE SAME
CMP E
JRZ 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 ' Blocks in Queue',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
LXI D,DIRECT ;NEXT ELEMENT IS HERE
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 DU2 to it
; On exit, GROUP = Group Number, GRPDIS = 0, and DU2 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
JRZ COMG1
CPI CR ;CURRENT IF PHYSICAL EOL
JRZ 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
JRNZ COPYGLW
CALL READ ;READ BLOCK
LHLD QCNT ;INCREMENT QUEUE ELEMENT COUNT
INX H
SHLD QCNT
JR 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
JRNZ COPYGL1
LHLD QNXT ;CHECK FOR QUEUE OVERFLOW
MOV A,H ;MUST NOT BE EQUAL
CMP D
JRNZ 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
JRZ COPYGL2
SHLD QNXT ;NEXT PTR USED FOR WRITE
JR 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?
JRZ QRESTOR
CPI 'G' ;GROUP SAVE?
JZ RESTRG
LDA SAVEFL ;SAVE DONE PREVIOUSLY?
ORA A
JZ NOSAVE ;NONE TO SAVE
PUSH H
LXI H,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
JRZ 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?
JRNZ SEARCH ;..YES
LXI H,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
JRZ 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?
JRZ SREQU
CPI EOLCH ;LOGICAL EOL?
JRNZ 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
JRNZ 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
JRNZ VIEWLP
INR E ;DFLT=1
;
VIEWLP:
LXI H,TBUFF ;TO DATA
;
VEWCHR:
CALL CTLCS ;ABORT?
JRZ VEWEND
MOV A,M ;GET NEXT CHAR
CPI 1AH ;EOF?
JRZ VEWEOF
ANI 7FH ;MASK
CPI 7EH ;ESC CHAR FOR H1500
JRNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX
CPI ' '
JRNC VIEWPR
CPI CR ;CR PASS
JRZ VIEWPR
CPI LF ;LF PASS
JRZ VIEWPR
CPI TAB ;TAB PASS
JRZ VIEWPR
;
VIEWHX:
MOV A,M ;NOT ASCII...PRINT AS <NN>
CALL BHEX
JR VIEWNP
;
VIEWPR:
CALL TYPE
;
VIEWNP:
INR L
JRNZ VEWCHR
DCR E
JRZ VEWEND
PUSH D ;SAVE COUNT
CALL NXTSEC
LHLD CURSEC
XCHG
CALL SETSEC
LHLD CURTRK
XCHG
CALL SETTRK
CALL READ
POP D ;RESTORE COUNT
JR VIEWLP
;
VEWEOF:
CALL ILPRT
DB CR,LF,' ++ EOF ++',CR,LF,0
;
VEWEND:
POP H
CALL CRLF
JMP CLCGRP
;
;COMMAND: A or D
;Dump in hex or ASCII
;
DUMP:
LDA WRFLG
ORA A
JRNZ 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?
JRZ DUMPDF ;DFLT
CPI CR ;PHYSICAL EOL?
JRNZ DMPNDF
;
;Use default
;
DUMPDF:
LXI B,TBUFF
LXI D,0FFH
JR DUMP1
;
DMPNDF:
CALL DISP
MOV B,D
MOV C,E
CPI CR
JRZ DUMP1
CPI EOLCH
JRZ DUMP1
INX H ;SKIP SEPCH
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 ;PRINT HEX VALUE
CALL SPACE
CALL SPACE
LDA DUMTYP
CPI 'A'
JRZ DUMPAS
PUSH H ;SAVE START
;
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
CMP L
JRZ DPOP
INX H
MOV A,L
ANI 0FH
JRNZ DHEX
;
DPOP:
CALL CTLCS ;ABORT?
JZ PRMPTR
LDA DUMTYP
CPI 'H'
JRZ DNOAS ;HEX ONLY
POP H ;GET START ADDR
;
DUMPAS:
CALL ASTER ;PRINT FIRST ASTERISK TO SEPARATE TEXT
;
DCHR:
MOV A,M ;GET CHAR
ANI 7FH
CPI ' '
JRC DPER
CPI 7EH ;TRAP ESC FOR H1500
JRC DOK
;
DPER:
MVI A,'.' ;PRINT PRINTING CHAR
;
DOK:
CALL TYPE ;PRINT CHAR
MOV A,E
CMP L
JRZ DEND
INX H
MOV A,L
ANI 0FH
JRNZ DCHR
;
DEND:
CALL ASTER ;PRINT ENDING ASTERISK
CALL CRLF ;NEW LINE
PUSH D
CALL CTLCS ;ABORT?
POP D
JZ PRMPTR
MOV A,E
CMP L
JRNZ DUMPLP
POP H
JMP PROMPT
;
DNOAS:
POP B
CALL CRLF
MOV A,E
CMP L
JRNZ DUMPLP
POP H
JMP PROMPT
;
;COMMAND: G
;Position
;
POS:
PUSH PSW
MOV A,M
CPI EOLCH ;LOGICAL EOL?
JRZ POSINQ
CPI CR ;PHYSICAL EOL?
JRNZ POSOK
;
POSINQ:
POP PSW
JMP INQ
;
POSOK:
POP PSW
CPI 'T' ;TRACK?
JRZ POSTKD
CPI 'S' ;SECTOR?
JRZ 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
JR 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
JRNZ POSDLP
ANI 1 ;GET GROUP
MOV L,A ;SETUP FOR POSGP2
MVI H,0
SHLD GROUP
XCHG
JR POSGP2 ;POSITION TO IT
;
;Position to Group
;
POSGPH:
CALL HEXIN ;GET PARAMETER
;
;Position to Group Numbered in DE and Print Position
;
POSGRP:
PUSH H
LHLD DSM ;CHECK FOR WITHIN BOUNDS
CALL SUBDE
POP H
JC OUTLIM
XCHG
SHLD GROUP ;SET GROUP NUMBER
XCHG
XRA A
STA GRPDIS ;SET ZERO DISPLACEMENT
PUSH H
;
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
;
;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
JRNZ 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
JRC 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
LXI D,FCB
MVI C,SRCHF
PUSH H
CALL BDOS
INR A
JRNZ 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,TBUFF
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 ;GET NEXT CHAR OF FILE NAME/TYPE
CPI '.' ;END OF FILE NAME?
JRZ MVIPAD ;PAD OUT IF SO
CPI CR ;END OF ENTRY?
JRZ PAD ;PAD OUT IF SO
CPI EOLCH ;END OF ENTRY?
JRZ 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?
JRZ PLUSGO ;..YES, DFLT TO 1
CPI EOLCH
JRZ PLUSGO
CALL DECIN ;GET #
MOV A,D
ORA E
JRNZ 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
JRNZ 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?
JRZ MINGO ;..YES, DFLT=1
CPI EOLCH
JRZ MINGO
CALL DECIN ;..NO, GET ##
MOV A,D
ORA E
JRNZ MINGO
LXI D,1 ;ASSUME 1
;
MINGO:
PUSH H
LHLD CURSEC ;BACK UP SECTOR
DCX H
MOV A,H
ORA L
JRNZ MINOK
LHLD CURTRK ;BEYOND SECTOR ZERO, SO BACK UP TRACK
MOV A,H
ORA L
JRNZ SEASH
LHLD MAXTRK ;WRAP TO END OF DISK
SHLD CURTRK
LHLD MAXSEC
JR MINOK
;
SEASH:
DCX H
SHLD CURTRK
LHLD SPT ;GET NUMBER OF SECTORS/TRACK
;
MINOK:
SHLD CURSEC ;SET NEW CURRENT SECTOR
POP H
DCX D ;COUNT DOWN ON NUMBER OF TIMES TO BACKUP
MOV A,D
ORA E
JRNZ MINGO
JR PLUSMI ;READ BLOCK
;
;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
JRNC NEXTOK
LHLD CURTRK ;BEYOND END OF TRACK, SO INCR CURRENT TRACK
INX H
XCHG
LHLD MAXTRK ;SEE IF BEYOND END OF DISK
CALL SUBDE
JRNC 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
JRC NOGRP
CALL ILPRT ;PRINT GROUP NUMBER IF NOT IN SYSTEM TRACKS
DB 'Group = ',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 ' Track = ',0
LHLD CURTRK
CALL DEC ;TRACK NUMBER IN DECIMAL
CALL ILPRT ;PRINT SECTOR NUMBER
DB ', Sector = ',0
LHLD CURSEC
CALL DEC ;SECTOR NUMBER IN DECIMAL
CALL ILPRT ;PRINT PHYSCIAL SECTOR NUMBER
DB ', Physical Sector = ',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
JRNZ 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
JR CHGAH
;
CHGNTH:
CPI SEPCH
JNZ WHAT
;
CHGAH:
POP PSW
CPI 'H' ;HEX?
JRZ 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
JRZ 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?
JRZ 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
JRZ CHHNTH ;..NO.
CMP E ;..YES, DONE?
JZ PROMPT
LHLD HEXAD ;..NO: MORE
;
CHHNTH:
INR E
JRNZ 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
JRNZ 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:
LDA DSM+1
ORA A
JZ HEXX
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?
JRC 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
JRNC 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 '*'
;
ASTER: MVI A,'*'
JMP TYPE
;
;Inline print routine
; Print Chars ending in 0 pted to by Return Address; return to byte after
;
ILPRT:
XTHL ;GET PTR AND SAVE HL
;
ILPLP:
CALL CTLCS ;ABORT?
JZ PRMPTR
MOV A,M ;GET CHAR
CPI 1 ;PAUSE? -- ^A
JRNZ ILPOK
CALL CONIN ;WAIT FOR ANY CHAR
CPI 3 ;ABORT?
JZ PRMPTR
JR ILPNX
;
ILPOK:
CALL TYPE ;PRINT CHAR
;
ILPNX:
INX H ;PT TO NEXT
MOV A,M ;GET IT
ORA A ;DONE?
JRNZ 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
JRNZ 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
MOV A,M
CPI '#' ;DECIMAL?
JRZ HDIN ;MAKE DECIMAL
;
HINLP:
MOV A,M ;GET CHAR
CALL UPCASE ;CAPITALIZE
CPI CR ;EOL?
RZ
CPI EOLCH ;EOL?
RZ
CPI SEPCH
RZ
CPI '-' ;'THRU'?
RZ
CPI '>'
RZ
INX H ;PT TO NEXT CHAR
CPI '0' ;RANGE?
JC WHAT
CPI '9'+1 ;RANGE?
JRC 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
JR 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?
JRNZ DINLP
INX H ; PT TO DIGIT
JR 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
JR DINLP
;
;Read in a console buffer
;
RDBUF:
CALL ILPRT ;PRINT PROMPT
DB CR,LF,'DU2 ',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
LXI D,INBUF-2 ;USE CP/M READLN
MVI C,10
CALL BDOS
LDA INBUF-1 ;GET CHAR COUNT
MOV B,A ;CHAR COUNT IN B
LXI H,INBUF ;STORE ENDING <CR>
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 ;SAVE IT
CALL TYPE ;ECHO IT
MVI A,LF ;ECHO..
CALL TYPE ;..LF
LXI H,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?
JRZ WAIT ;SAME AS USER DELAY
DCR A ;COUNT DOWN
STA PAGFLG
JMP CRLF
;
;Delay Routine
;
WAIT:
PUSH H
CALL ILPRT
DB CR,LF,'Type Any Character to Continue or ^C to Abort - ',0
POP H
CALL CONIN ;GET RESPONSE
CPI 'C'-40H ;^C?
JRZ 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
JRNZ TYPE2
;Tabulate
TYPTAB:
MVI A,' ' ;PRINT SPACE
CALL TYPE
LDA TABCOL ;GET COL COUNT
ANI 7 ;DONE?
JRNZ TYPTAB
JR TYPRET
;
;Filter out control characters to
;prevent garbage during view of file
;
TYPE2:
CPI ' '
JRNC TYPEQ
CPI CR
JRZ TYPEQ
CPI LF
JRNZ 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
JRNZ TYPNCR
MVI A,0 ;RESET TAB COLUMN IF <CR>
STA TABCOL
JR TYPLST
;
TYPNCR:
CPI ' ' ;CTL CHAR?
JRC 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
JRNC NOTSYS ;IF NO CARRY FOR SUBDE, WE ARE NOT IN SYSTEM TRACKS
LDA FIRST0 ;SEE IF FIRST SEC 0
ORA A
JRNZ GSTSEC ;NO, JUMP AWAY
DCX H ;YES, SO DECREMENT
JR 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
JRNZ 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?
JRZ 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
JRNZ 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?
JRZ 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 ILPRT
DB 'Introductory HELP on DU2 (Disk Utility)',CR,LF
DB ' The DU2 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 DU2 user. This same list is invoked internally by the'
DB CR,LF
DB '? Command of DU2. For additional information on disk'
DB CR,LF
DB 'structures and how to use DU2 in general, refer to the'
DB CR,LF
DB 'files DU2.DOC and DU2.HLP.',CR,LF,0
MVI A,0FFH ;A=0FFH
STA IHFLG ;SET INITIAL HELP
CALL WAIT
JR HELP1 ;PROCESS NORMALLY
HELP:
XRA A ;A=0
STA IHFLG ;SET NO INITIAL HELP
HELP1:
CALL ILPRT
DB '=======================================================',CR,LF
DB ' -- Command Summary -- ',CR,LF
DB '-------------------------------------------------------',CR,LF
DB CR,LF
DB 'Operands in brackets [...] are optional'
DB CR,LF,CR,LF
DB '@ Repeat Previous Non-@ Command Line'
DB CR,LF
DB '+[nn] Step In [nn (decimal)] Sectors; -[nn] Step Out '
DB 'Sectors'
DB CR,LF
DB ' Note: + or - need not be followed by a "," to '
DB 'delimit commands.'
DB CR,LF
DB '# Print Disk Parameters for Current Drive'
DB CR,LF
DB '=xxx Search for ASCII xxx from Current Sector'
DB CR,LF
DB ' Note: upper/lower case matters. 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 '*[nn] Repeat [nn (decimal) times]; ! Pause for User'
DB CR,LF
DB ':ntext Define ''text'' to be Macro n; n Perform Macro'
DB ' n, 0<=n<=9'
DB CR,LF
DB ':Pn Print Macro n, 0<=n<=9'
DB CR,LF
DB ':Px Print All Macros if x=A or Print Prev Line if x=@'
DB CR,LF,CR,LF,0
CALL WAIT
CALL ILPRT
DB '-------------------------------------------------------',CR,LF
DB 'A[ff,tt] ASCII Dump'
DB 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 and ASCII)'
DB CR,LF
DB 'Ffn.ft Find File'
DB CR,LF
DB 'Gnn CP/M Allocation Group nn (hex)'
DB CR,LF
DB 'H[ff,tt] Hex Dump'
DB CR,LF
DB 'L[d] Log in Current Drive or Drive d'
DB CR,LF
DB 'M[nn] Map [from group nn (hex)]'
DB CR,LF,CR,LF,0
CALL WAIT
CALL ILPRT
DB '-------------------------------------------------------',CR,LF
DB CR,LF
DB 'N Load New Disk; P Toggle Printer Switch'
DB CR,LF
DB 'Q Queue Status; QZ Zero (Empty) Queue'
DB CR,LF
DB 'QSfn.ft Save Queue as a File on Disk'
DB CR,LF
DB '< Save Current Block into Temp; > Restore Temp '
DB 'Block'
DB CR,LF
DB '<B Save Block into Queue; >B Restore Queue '
DB 'Block'
DB CR,LF
DB '<G[n] Save Group into Queue; >G[n] Restore Queue '
DB 'Group'
DB CR,LF
DB 'Snn Sector nn (decimal)'
DB CR,LF
DB 'Tnn Track nn (decimal)'
DB CR,LF
DB 'Unn Set User nn (decimal) for Find command (CP/M-2 only)'
DB CR,LF
DB 'V[nn] View [nn (decimal)] ASCII Blocks'
DB CR,LF
DB 'R Read Current Block; W Write Current Block'
DB CR,LF
DB 'X Exit Program'
DB CR,LF
DB 'Z[nn] Sleep [nn (decimal) seconds]'
DB CR,LF,CR,LF,0
CALL WAIT
CALL ILPRT
DB '-------------------------------------------------------',CR,LF
DB CR,LF
DB 'Command Line is of the form: DU2 du?',CR,LF
DB ' "d" is Logged-In Disk, "u" is Current User',CR,LF
DB CR,LF
DB 'Cancel a function with C or Ctrl-C.'
DB CR,LF
DB 'Suspend output with S or Ctrl-S.'
DB CR,LF
DB 'Separate commands with ",".'
DB CR,LF
DB ' Example: g0'
DB CR,LF
DB ' +,d,z2,*'
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 '"nn" usage varies with command as follows:',CR,LF
DB ' +, -, *, T, S, U, V, Z nn in Decimal',CR,LF
DB ' (use #nn for Hex)',CR,LF
DB ' G, M nn in Hexadecimal',CR,LF
DB ' (use #nn for Decimal)'
DB CR,LF
DB '"ff" and "tt" are in Hexadecimal (use #ff or #tt for Decimal)'
DB CR,LF,CR,LF
DB '=======================================================',CR,LF
DB 0
CALL WAIT
CALL ILPRT
DB '=======================================================',CR,LF
DB 'DU2 Status Information',CR,LF
DB '-------------------------------------------------------',CR,LF
DB 'Processor Speed: ',0
LDA CLOCK ;GET CLOCK SPEED
ADI '0' ;CONVERT TO ASCII
CALL TYPE ;PRINT
CALL ILPRT
DB ' MHz',CR,LF
DB 'Number of Lines on CON: ',0
LDA PAGSIZ ;GET PAGE SIZE
MOV L,A ;NUMBER IN HL
MVI H,0
CALL DEC ;PRINT NUMBER IN DECIMAL
CALL ILPRT
DB CR,LF,'Group Save Buffer Address: ',0
LXI B,GBUFF ;BC=ADDRESS
CALL HEXB ;PRINT AS HEX
CALL ILPRT
DB ' Hex',CR,LF
DB '=======================================================',CR,LF
DB 0
LDA IHFLG ;INITIAL HELP?
ORA A ;0=NO
JRNZ EXIT1 ;RETURN TO CP/M IF SO
JMP PRMPTR ;NEW LINE INPUT IF NOT
;
;COMMAND: X
;Exit to CP/M
;
EXIT:
CALL ILPRT ;PRINT
DB CR,LF,'Exit to CP/M -- Do you wish to Warm Boot (Y/N/<CR>=N)?'
DB ' ',0
CALL CONIN ;GET RESPONSE
CALL UPCASE ;CAPITALIZE
CPI 'Y' ;YES?
JZ BASE ;WARM BOOT IF SO
;
;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
JRZ 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
JRNC COSKIP
INR C
;
COSKIP:
DCR B
JRNZ 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
JRNZ MULCON
LXI H,0 ;FILTER SPECIAL CASE
JR MLDONE ; OF MULTIPLY BY 0
;
MULCON:
DCX B
MOV D,H
MOV E,L
;
MULTLP:
MOV A,B
ORA C
JRZ MLDONE
DAD D
DCX B
JR 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
;***********************************
;
; DU2 Command Table
;
;***********************************
CMDTBL:
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 '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' ;******CP/M 2.x ONLY******
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
;
DS 100 ;50-ELT STACK
DUTSTK:
DS 2 ;OLD CP/M STACK POINTER; TOP OF DU2 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 128+2+2
;
;Set INBUF to a Page Boundary
;
ORG $/100H*100H+100H-2
DB 126 ; SIZE OF BUFFER FOR CP/M
DS 1
INBUF:
DS 400H ;EXTRA SPACE FOR MACRO EXPANSION
PINBUF:
DS 400H ;PREVIOUS CONTENTS OF INPUT BUFFER
CTEMP:
DS 400H ;BUILD NEW COMMAND LINE BUFFER
CTEMPX EQU $ ;END OF CTEMP
;
;Directory read in here; also loaded group area and Macros
;
MTABL: DS 100H*10 ;10 PAGES FOR 10 MACROS
GBUFF EQU $
DIRECT EQU $
;
END