home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
sigm
/
vol247
/
du-75e.aq6
/
DU-75E.A86
Wrap
Text File
|
1986-02-27
|
55KB
|
3,130 lines
; 29-Jul-85 fixed code at CLCSUB to prevent int 0, same ver 7.5-E
; 21-Jul-85 revised for 32 bit mult/div in GTLSEC and CLCSUB routines
; changed to rev 7.5-E. WHAT A MESS....
; 29-Mar-85 relaxed for CCP/M ver 4.1 and up changed to -D ver
; 8-11-84 revsed for PC_MODE support renamed DU-V75C.A86
; 04/15/84 revised to correct minor bugs - renamed DU-V75B.A86
;
; DU.ASM V7.5 Revised 1/23/81 ( CP/M-80 version )
; DISK UTILITY - By Ward Christensen
;
; DU-75A.A86 is a CP/M-86 translation of the CP/M-80 version.
;
; The original translation came from the SLICER USER GROUP
; disk #2, via Micro Cornucopia, PO Box 223, Bend, OR
; It did not indicate the name of the translator who should
; be thanked for his work. That version appeared as DU-75.A86
;
; See DU77.DOC for description and detailed instructions.
; See original issue ver 7.5 for history of changes and authors
; NOTE: see below for change in multiple cmd symbol.
;
; 03/05/84 by H.M. Van Tassell, (201)-755-5372
; 120 Hill Hollow Road, Watchung, NJ 07060
;
; Added direct BIOS disk routines for CP/M-86 Plus ver 3.1
; and CCP/M-86 ver 3.1, with minimum changes to get it to work.
; There is now a check for version number with exit if unknown.
;
; Fixed a bug with Map when using directory initialized for time
; stamping, added user&drive to prompt, and changed the multiple
; command symbol from ';' to '!'. *** THIS IS CP/M CONVENTION ***
;
; Changed LISTOUT to use BDOS rather than BIOS call since under
; CCP/M-86, a BIOS call to LIST must have it's device number in
; register DL. The BDOS call uses the default list device and DU
; will "own" the printer once it is called using L_WRITE.
;
; to generate: ASM86 DU ! GENCMD DU 8080 CODE[MF00]
;
; ----------------
;
L_WRITE equ 5 ;write to default list device
S_BIOS equ 50 ;direct bios call
DRV_DPB equ 31 ;get drive DPB, returns SYSDAT in ES
; bios disk call data structure
;
SELECT_DISK equ word ptr 0[bx]
SET_TRACK equ word ptr 2[bx]
SET_DMASEG equ word ptr 4[bx]
SET_DMAOFF equ word ptr 6[bx]
SET_SECTOR equ word ptr 8[bx]
READ_SECTOR equ word ptr 10[bx]
WRITE_SECTOR equ word ptr 12[bx]
SECTOR_XLAT equ word ptr 14[bx]
HOME_DISK equ word ptr 16[bx]
BIO_SELDSK equ 9 ;BIOS function number
BIO_READ equ 10 ;BIOS function number
BIO_WRITE equ 11 ;BIOS function number
; partial data structure of Disk Parameter Header (DPH)
;
DPH_XLATE equ word ptr 0 ;offset to xlate table
LOG_SEQN equ byte ptr 6 ;to force reset of permanent media
DPB_PTR31 equ word ptr 8 ;offset of DPB pointer in DPH (v3.1)
DPB_PTR11 equ word ptr 10 ;offset in version 1.1
DPB_SIZE equ 17 ;size of Disk Parameter Block
;------- for CP/M ver 3.1 & CCP/M ver 3.1 ----
BIOS_ENTRY equ dword ptr .28h ;loc of BIOS entry in SYStem DATa
;------------ for CP/M ver 3.1 --------------
UDA_SEG equ word ptr .4eh ;loc of UDA seg in SYStem DATa area
;------------- for CCP/M ver 3.1 -------------
S_SYSDAT equ 154 ;get SYStem DATa area addr
P_PDADR equ 156 ;get PDA address
CCPM_31 equ 1431h ;CCP/M-86 version number
P_UDA equ word ptr 10h ;loc of UDA seg in User Data Area
;-------------------------------------------------------------------------
;
;System equates
;
BASE EQU 0
;
ORG BASE +5CH
FCB DB 0
;
PRINT EQU 9
RESETDK EQU 13
SELDK EQU 14
SRCHF EQU 17 ;SEARCH FIRST
SUSER EQU 32
GETDSK EQU 25
GETDPB EQU 31
;
; BIOS
;
CONSTF EQU 2
CONINF EQU 3
CONOUTF EQU 4
LISTF EQU 5
;
S2OFF EQU 14 ;OFFSET INTO FCB FOR S2 BYTE
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
;
CSEG
ORG 100H
;
JMP PASTCK ;JUMP OVER CLOCK BYTE AND I.D.
;
BCONST:
MOV AL,CONSTF
JMP BIOS
;
BCONIN:
MOV AL,CONINF
JMP BIOS
;
BCONOUT:
MOV AL,CONOUTF
JMP BIOS
;
BLIST:
MOV AL,LISTF
JMP BIOS
;------------------------------------------------------------------------
BHOME:
mov bx,bios_call_tbl
jmp home_disk
;
SEL:
mov bx,bios_call_tbl
jmp select_disk
;
TRK:
mov bx,bios_call_tbl
jmp set_track
;
SEC:
mov bx,bios_call_tbl
jmp set_sector
;
DMA:
mov bx,bios_call_tbl
jmp set_dmaoff
;
DSKREAD:
mov bx,bios_call_tbl
jmp read_sector
;
DSKWRITE:
mov bx,bios_call_tbl
jmp write_sector
;
BSECTTRAN:
mov bx,bios_call_tbl
jmp sector_xlat
;
SETDMAB:
mov bx,bios_call_tbl
jmp set_dmaseg
;
; checks cpm version and initializes things
cpmchk:
mov cl,12 ;get version number
int 224
mov cpm_version,ax ;and save it
test ah,01h ;is it mp/m ?
jnz is_mpm
cmp al,22h ;is it version 11?
je ver_11
cmp al,31h ;is it version 31?
jae ver_31
;else it is unknown version
unk_ver: ;say unknown and exit
mov dx,offset wvmsg
mov cl,9
int 224
jmp exit
is_mpm: ;MP/M is not supported
mov dx,offset mpmsg ;say it and exit
mov cl,9
int 224
jmp exit
ver_11:
mov bios_call_tbl,offset table11
jmps ver_ok
ver_31:
mov bios_call_tbl,offset table31
ver_ok:
mov ax,ds ;setup our dseg for
mov idmaseg,ax ;sector buffer read/write
mov dmaseg,ax
mov dmaoff,80h ;and default buffer
ret
; direct bios call for cp/m-86 version 1.1
;
select_disk11:
mov al,9 ;bios fucn 9
jmps bios ;returns dph addr in es:bx
set_track11:
mov al,10
jmps bios
set_dmaseg11:
mov al,17
jmps bios
set_dmaoff11:
mov al,12
jmps bios
set_sector11:
mov al,11
jmps bios
read_sector11:
mov al,13
jmps bios
write_sector11:
mov al,14
jmps bios
sector_xlat11:
mov al,16
jmps bios
home_disk11:
mov al,8
jmps bios
;
bios:
mov bpb_func,al ;bios function number
mov bpb_cx,cx
mov bpb_dx,dx
mov dx,offset bpb
mov cl,S_BIOS ;direct bios function call = 50
bdos: int 224 ;fall thru
ret
;
; direct bios disk calls for CP/M-86 version 3.1
;
set_sector31:
call logi_2_phy ;convert logical record number to
mov isector,cx ;physical sector number
ret
set_track31:
mov itrack,cx
ret
sector_xlat31:
call pseudo_xlat ;translate logical records
ret ;BX = pseudo xlate record number
set_dmaseg31:
mov dmaseg,cx ;user dma segment
ret
set_dmaoff31:
mov dmaoff,cx ;user dma offset
ret
home_disk31: ;do nothing, there aint no home
xor ax,ax ;but make sure al=0
ret
pseudo_xlat:
;---------
; ENTRY: CX = logical record number (relative 1)
; EXIT: BX = pseudo logical sector number
; (gives same result as if disk had same number of
; physical sectors as there are 128 byte records)
mov bx,cx ;just in case there is no xlate
cmp sec_xlat_tbl,0 ! jz no_xlat ;is there an xlate table?
inc cx ;do this only for DU-V75
call logi_2_phy ;returns AX = physical sector
mov bx,sec_xlat_tbl ;point to disk xlate table
push ds ! mov ds,sysaddr ;in the SYStem DATa area
xlat sec_xlat_tbl ;AL = translated phy sector number
pop ds
mov cl,PHYSHF ;get physical shift factor
shl ax,cl
add ax,rec_offset ;add in the record offset into sector
inc ax ;make it relative to 1
mov bx,ax ;move to BX
no_xlat:
ret
logi_2_phy:
;----------
; ENTRY: CX = logical record number (relative to 1)
; EXIT: CX=AX = physical sector number (relative to 0)
; rec_offset contains record offset into phy sector
;
dec cx ;now relative to zero
mov ax,cx ;move logical record number
xor bh,bh ;clear high byte
mov bl,PHYMSK ;get physical mask
and cx,bx ;CX = logical record offset into
mov rec_offset,cx ;...physical sector
mov cl,PHYSHF ;get physical shift factor
shr ax,cl
mov cx,ax ;CX=AX = physical sector number
ret
;++++++++++++++++++++++++++++++++++++++
select_disk31: ;selects a drive
;-------------
; resets login sequence number of drive to 0, to force
; permanent media to be logged in again on disk reset
; Entry: CL = drive to select
; DL = 0 if initial select, else 1
mov trk_sect,0ffffh ;indicate not in memory
mov idrive,cl ;put drive in table
push es ! push ds ;save context
push cx ;save drive
call getsu ;set up DS and ES
pop cx ;restore drive
mov ax,BIO_SELDSK ;do the BIOS SELDSK call
callf BIOS_ENTRY ;call the BIOS thru entry point
cmp bx,0 ! jz sel_error ;bx = 0 is an illegal drive
mov LOG_SEQN[bx],0 ;to force a disk reset set the
;...login sequence no. to zero
mov cx,DPH_XLATE[bx] ;get xlate table offset in SYSDAT
;copy DPB to local storage
pop es ! push es ;get our dseg into ES
mov es:sec_xlat_tbl,cx ;save xlate table address
mov di,offset dpb ;setup dest of dpb
mov si,DPB_PTR31[bx] ;get the info from DPH (ver 31)
cmp Word Ptr[si],0FFFFh ; is this a PC_MODE dpb?
jne not_pc_dpb
add si,12 ;yes, correct for difference
not_pc_dpb:
mov cx,DPB_SIZE
rep movsb ;copy DPB into local storage
sel_error:
pop ds ! pop es ;restore context
mov cl,PHYSHF ; This is a dirty trick
shl SPT,cl ; to get a SPT for DU
cmp PHYSHF,4 ;make sure sector_buf is OK
jbe buf_ok ; >>> PHYSHF TABLE <<<
mov dx,offset toobig ; 128 = 0 1024 = 3
mov cl,9 ; 256 = 1 2048 = 4
int 224 ; 512 = 2 4096 = 5
jmp exit
buf_ok:
ret
sect_to_mem:
;------------
; ENTRY: itrack & isector specified
; EXIT: sector is in memory, does read if required
; AX BX = 0 if no error
;
mov ax,itrack ;get track
cmp ax,0 ! jnz not_zero
cmp ax,1 ! jmps no_match
not_zero:
mov bx,isector ;and sector numbers
cmp ax,trk_sect ! jne no_match ;if same as last time
cmp bx,trk_sect+2 ;then sector is in memory
no_match:
mov trk_sect,ax ;save for next time
mov trk_sect+2,bx
mov ax,0 ! mov bx,ax ;clear AX BX registers
je got_sect ;if not in memory, then
mov bx,BIO_READ ;signal a read
call biosiopb ;read a physical sector
got_sect:
ret
read_sector31: ;reads a logical record from disk to buffer
;-------------
;
call sect_to_mem ;get sector
push si ! push di ! push es
cld ! mov es,dmaseg ;setup user dma segment
mov di,dmaoff ;where to copy 128 byte record
mov si,rec_offset ;record offset into sector buffer
mov cl,7 ! shl si,cl ;times 128
add si,offset sector_buf ;points to start of record
mov cx,128/2 ;move 128 bytes
rep movsw ;so do the move
pop es ! pop di ! pop si
ret
write_sector31: ;writes a physical sector
;--------------
;
call sect_to_mem
push si ! push di ! push es ! push ds
mov ds,dmaseg ;source of user data to copy
mov si,dmaoff ;into sector buffer
cld ! mov es,idmaseg ;setup for sector buffer dma segment
mov di,rec_offset ;record offset into sector buffer
mov cl,7 ! shl di,cl ;times 128
add di,offset sector_buf ;points to start of record
mov cx,128/2 ;move 128 bytes
rep movsw ;so do the move
pop ds ! pop es ! pop di ! pop si
mov bx,BIO_WRITE ;signal a write
;fall thru to write sector to disk
biosiopb: ;put the IOPB on the stack, call BIOS
push ds ;ds will contain SYSDAT seg
push es ;es will contain UDA seg
;push iopb onto stack
mov ah,imcnt
mov al,idrive
push ax ;drive and multi-sector count
push itrack ;track #
push isector ;sector # = 0
push idmaseg ;sector buffer DMA segment
push idmaoff ;sector buffer DMA offset
call getsu ;set up DS-SYSDAT and ES-UDA
mov ax,bx ;set I/O function into AX
callf BIOS_ENTRY ;call indirect the BIOS
;AL,BL = return status
add sp,10 ;restore stack
pop es ;restore original ES
pop ds ;ditto for DS
ret
;======
getsu:
;======
; entry: DS = local data seg
; exit: DS = SYSDAT seg, ES=UDA seg (for call to XIOS)
mov ax,udaaddr ;get the saved value
or ax,ax ;set flags
jz get_ds_es ;uninitialized, go get DS and ES
mov es,ax ;we've been here before, so load regs
mov ds,sysaddr
ret
get_ds_es: ;this is the initial call
;---------
cmp cpm_version,CCPM_31 ;is it CCP/M-86 version 1431+?
jb get_ds_es10 ;or version 1031
get_ds_es14: ;use this for CCP/M-86 version 1431
;----------
mov cl,P_PDADR ;will return Process Desc Addr in BX
int 224 ;...and SYStem DATa seg in ES
mov ax,es:P_UDA[bx] ;grab UDA_seg
jmps com_su ;jmp to common
get_ds_es10: ;use this with CP/M-86 version 1031
;----------
mov cl,DRV_DPB ;will return SYStem DATa seg in ES
int 224
mov ax,es:UDA_seg ;grab UDA_seg
;fall thru to common
com_su: ;this is common to both versions
mov sysaddr,es ;save system data segment (SYSDAT)
push es
mov udaaddr,ax ;save for UDS_seg for future calls
mov es,ax ;get UDA_seg into ES
pop ds ;get SYSDAT into DS
ret
;-----------------------------------------------------------------------
;
CLOCK DB 1 ;<---PUT NON-ZERO HERE FOR 4 MHZ CLOCK
;
PASTCK:
MOV AX,CS
MOV DS,AX
MOV SS,AX
MOV ES,AX
MOV SP,OFFSET STACK
call cpmchk ;make sure right version, do setup
;
HELLO: CALL ILPRT
DB CR,LF,'DISK UTILITY ver 7.5-E',CR,LF
DB 'For CP/M-86 & CCP/M-86 ver 3.1-4.1',CR,LF
DB CR,LF
DB 'Type ? for help, X or ESC Quits'
DB CR,LF,0
CALL GETSTP ;SET UP PARAMETERS
MOV BX,OFFSET BASE +80H ;TO INPUT BUFF
MOV AL,BYTE PTR [BX]
OR AL,AL
JZ PRMPTR ;NO COMMAND
;
;Got initial command, set it up
MOV CH,AL ;SAVE LENGTH
DEC CH
JZ PRMPTR
MOV DX,OFFSET INBUF
INC BX ;SKIP LEN
INC BX ;SKIP ' '
CALL MOVE
MOV AL,CR
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
MOV BX,OFFSET INBUF
JMP PRMPTI
;
PRMPTR: XOR AL,AL
MOV QFLAG,AL
CALL RDBUF
;
PRMPTI: MOV AL,255
MOV BYTE PTR TOGO,AL ;LOOP COUNT FOR "/"
MOV BYTE PTR TOGO+1,AL
;
PROMPT EQU $
SETSTK:
MOV SP, OFFSET STACK
XOR AL,AL ;ZERO 2-UP PRINT
MOV TWOUP,AL ;..SWITCH
MOV AL,1
MOV FTSW,AL ;TELL SEARCH NOT TO INCR
PUSH BX
MOV BX,OFFSET BASE +100H
MOV BUFAD,BX ;FOR RDBYTE
POP BX
CALL CTLCS ;ABORT?
JZ PRMPTR ;..YES, READ BUFFER
;
;Do we have to position in directory after find?
MOV AL,FINDFL
OR AL,AL
JZ L@00005
JMP POSDIR ;POSITION IN DIRECTORY
L@00005:
MOV AL,BYTE PTR [BX]
CMP AL,CR
JZ PRMPTR
CMP AL,'!' ;LOGICAL CR?
PUSHF
INC BX
POPF
JZ PROMPT
CALL UPCASE
MOV DUMTYP,AL ;TYPE OF DUMP (A,D,H)
;
;Command dispatcher
;
CMP AL,'+'
JNZ L@00008
JMP PLUS
L@00008:
;
CMP AL,'-'
JNZ L@00009
JMP MINUS
L@00009:
;
CMP AL,'='
JNZ L@00010
JMP SEARCH
L@00010:
;
CMP AL,'<'
JNZ L@00011
JMP SAVE
L@00011:
;
CMP AL,'>'
JNZ L@00012
JMP RESTOR
L@00012:
;
CMP AL,'#'
JNZ L@00013
JMP STATS
L@00013:
;
CMP AL,'?'
JNZ L@00014
JMP HELP
L@00014:
;
CMP AL,'A'
JNZ L@00015
JMP DUMP
L@00015:
;
CMP AL,'C'
JNZ L@00016
JMP CHG
L@00016:
;
CMP AL,'D'
JNZ L@00017
JMP DUMP
L@00017:
;
CMP AL,'F'
JNZ L@00018
JMP POSFIL
L@00018:
;
CMP AL,'G'
JNZ L@00019
JMP POS
L@00019:
;
CMP AL,'H'
JNZ L@00020
JMP DUMP
L@00020:
;
CMP AL,'L'
JNZ L@00021
JMP LOGIN
L@00021:
;
CMP AL,'M'
JNZ L@00022
JMP MAP
L@00022:
;
CMP AL,'N'
JNZ L@00023
JMP NEWDSK
L@00023:
;
CMP AL,'P'
JNZ L@00024
JMP PRNTFF
L@00024:
;
CMP AL,'Q'
JNZ L@00025
JMP QUIET
L@00025:
;
CMP AL,'R'
JNZ L@00026
JMP DOREAD
L@00026:
;
CMP AL,'S'
JNZ L@00027
JMP POS
L@00027:
;
CMP AL,'T'
JNZ L@00028
JMP POS
L@00028:
;
CMP AL,'U' ;******CP/M 2.x ONLY******
JNZ L@00029
JMP USER
L@00029:
;
CMP AL,'V'
JNZ L@00030
JMP VIEW
L@00030:
;
CMP AL,'W'
JNZ L@00031
JMP DORITE
L@00031:
;
CMP AL,'X'
JNZ L@00032
QUIT:
CALL ILPRT
DB 'Confirm Quiting (Y/N)? ',0
CALL CONIN
CALL UPCASE
CMP AL,'Y'
JE EXIT
CALL CRLF
JMP PRMPTR
;
EXIT:
MOV CL,0
MOV DL,0
JMP BDOS ;RETURN TO CP/M 86
L@00032:
;
CMP AL,'Z'
JNZ L@00033
JMP SLEEP
L@00033:
;
CMP AL,'/'
JNZ L@00034
JMP REPEAT
L@00034:
;
WHAT: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '?',0
JMP PRMPTR
;
;Memory full error
;
MEMFUL: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '+++ Out of memory +++'
DB CR,LF,0
JMP PRMPTR
;
;Print disk statistics
;
STATS: PUSH BX
CALL ILPRT
DB 'Disk Information:',CR,LF
DB 'Tracks:',9,9,0
MOV BX,MAXTRK
INC BX
CALL DEC
CALL ILPRT
DB CR,LF,'Sec/trk:',9,0
MOV BX,SPT
CALL DEC
CALL ILPRT
DB CR,LF,'Grpsize:',9,0
MOV AL,BLM
INC AL
MOV BL,AL
MOV BH,0
CALL DEC
CALL ILPRT
DB ' (sectors per group)',CR,LF
DB 'Tot grps:',9,0
MOV BX,DSM
CALL DEC
CALL ILPRT
DB CR,LF,'Dir entries:',9,0
MOV BX,DRM
INC BX
CALL DEC
CALL ILPRT
DB CR,LF,'Sys tracks:',9,0
MOV BX,SYSTRK
CALL DEC
CALL CRLF
POP BX
JMP PROMPT
;
;The following command resets the disk
;system thru CP/M, and may be usable for
;changing the disk density or format.
;This can only be done if your BIOS resets
;the auto-density select parameters at
;every track-zero access.
;
NEWDSK: PUSH BX
MOV CL,RESETDK
CALL BDOS
MOV AL,DRIVE
MOV CL,AL
POP BX
CALL SELECT
JMP PROMPT
;
;Quite mode
;
QUIET: MOV QFLAG,AL ;NOW QUIET
JMP PROMPT
;
;Repeat buffer contents
;
REPEAT: CALL DECIN ;NN SPECIFIED?
MOV AL,DH
OR AL,DL
JZ NNN ;NO.
MOV BX,TOGO
INC BX ;TEST FOR FIRST TIME
MOV AL,BH
OR AL,BL ;WAS IT 0FFFFH?
JNZ NNN ;NO: COUNTING
XCHG BX,DX ;GET COUNT
MOV TOGO,BX ;SET COUNT
;
NNN: MOV BX,TOGO
XCHG BX,DX
MOV BX,OFFSET INBUF ;READY TO REPEAT
INC DX ;TEST FOR 0FFFFH
MOV AL,DH
OR AL,DL
JNZ L@00037
JMP PROMPT ;CONTINOUS
L@00037:
DEC DX ;COUNT DOWN
DEC DX ;MAKE UP FOR PREV INX D
XCHG BX,DX
MOV TOGO,BX
MOV AL,BH ;ALL DONE?
OR AL,BL
XCHG BX,DX ;GET BACK INBUF PTR
JZ L@00038
JMP PROMPT ;NO, KEEP GOING
L@00038:
JMP PRMPTR ;ALL DONE
;
;Set CP/M 2.x user number
;
USER:
CALL DECIN ;GET REQUESTED USER NO.
MOV AL,DL
CMP AL,32 ;VALID?
JNAE L@00040
JMP WHAT
L@00040:
MOV AL,DH
OR AL,AL
JZ L@00041
JMP WHAT
L@00041:
MOV UNUM,DL ;SAVE IT
MOV CL,SUSER
PUSH BX ;SAVE CHAR POINTER
CALL BDOS ;SET USER NO.
POP BX
JMP PROMPT
;
;Toggle print flag
;
PRNTFF: MOV AL,PFLAG
XOR AL,1
MOV PFLAG,AL
JMP PROMPT
;
;Sleep routine, in tenths of a sec
;
SLEEP: CALL HEXIN ;GET COUNT IF ANY
MOV AL,DL ;ANY?
OR AL,AL
JNZ SLEPLP
MOV DL,10
;
SLEPLP: MOV CX,OFFSET 10000
MOV AL,CLOCK
OR AL,AL
JZ SLEEP2
MOV CX,OFFSET 32000
;
SLEEP2:
DEC CX
MOV AL,CH
OR AL,CL
JNZ SLEEP2
PUSH DX
CALL CTLCS
POP DX
JNZ L@00045
JMP PRMPTR
L@00045:
DEC DL
JNZ SLEPLP
JMP PROMPT
;
;Check for control-C or S
;
CTLCS: CALL CONST
OR AL,AL
JNZ GETC
OR AL,1 ;NO CHAR, RETN NZ
RET
;
GETC: CALL CONIN
and al,5fh
cmp al,'Q' ;a Q will quit
jz quit_ret
AND AL,1FH ;ALLOW ASCII
CMP AL,'S'-40H
JNZ L@00048
CALL CONIN
L@00048:
CMP AL,'['-40H ;AN ESCAPE WILL QUIT
JZ QUIT_RET
CMP AL,'C'-40H ;AND SO WILL ^C
QUIT_RET:
RET ;0 SET IF CTL-C,esc
;
;Find our way at initialization
;
GETSTP:
MOV CL,SUSER ;GET USER NUMBER
MOV DL,0FFH ;GET USER
CALL BDOS
MOV UNUM,AL ;SET USER NUMBER
MOV CL,GETDSK
CALL BDOS ;GET CURNT DSK
MOV CL,AL ; WE HAVE TO SELECT
JMP SELECT ; TO GET THE DPH
;
LOGIN: CALL DOLOG
JMP PROMPT
;
DOLOG: MOV AL,BYTE PTR [BX] ;DISK REQ?
MOV DX,OFFSET 0
CMP AL,CR
JNZ L@00049
JMP LGNODK
L@00049:
CMP AL,'!'
JNZ L@00050
JMP LGNODK
L@00050:
CALL UPCASE
INC BX
SUB AL,'A'
MOV CL,AL
;
SELECT: PUSH BX
MOV AL,CL ;put drive in AL
push cx ;save drive
mov dl,0 ;indicate first select
CALL SEL ;SELECT DISK THRU BIOS
MOV AL,BH
OR AL,BL
pop cx
JNZ L@00052
JMP WHAT ;SELECT ERROR
L@00052:
MOV DRIVE,CL ;REMEMBER LATER WHERE WE ARE
;
MOV AX,ES:[BX] ;GET THE SECTOR TABLE PTR
MOV SECTBL,AX
MOV AX,8 ;IN VER 31 OFFSET IS 8
CMP BYTE PTR CPM_VERSION,31H
JAE AX8
MOV AX,10 ;BUT IN VER 11 IT IS 10 BYTES
AX8: ADD BX,AX
MOV BX,ES:[BX] ;GET DPB PTR
;
SELSKP: CALL LOGIT
MOV BX,SYSTRK ;RESET TRACK AND SECTOR
XCHG BX,DX ; TO DIRECTORY
CALL SETTRK ; ON EVERY
MOV DX,OFFSET 1 ; LOGIN
CALL SETSEC ; CHANGE
MOV BX,PHYSEC ;THIS LOGIC WILL TELL
MOV AL,BH ; IF FIRST SEC
OR AL,BL ; IS PHYSICAL 0
MOV FIRST0,AL
cmp byte ptr cpm_version,31h ;if ver 31 then
jb no_set_0 ;use first sector=1
mov first0,1
no_set_0:
CALL CLCSUB
POP BX
;
LGNODK: CALL NORITE
RET
;
;Read in the disk directory
;
REDDIR: PUSH BX
CALL NORITE ;POSITIONING LOST
MOV BX,SYSTRK
MOV CURTRK,BX
MOV BX,OFFSET 1
MOV CURSEC,BX
MOV BX,DRM ;GET DIR SIZE FROM DPB
INC BX ; MAKE 1-RELATIVE
CALL ROTRHL
CALL ROTRHL ;DIVIDE BY 4 (4 NAMES/SECTOR)
MOV CX,BX
MOV DX,OFFSET DIRECT ;DMA ADDR
;
RDIRLP: PUSH CX
PUSH DX
MOV CX,DX
MOV AL,0F0H ;FORCE MEMORY
CMP AL,DH
JAE L@00053
JMP MEMFUL
L@00053:
CALL SETDMA
MOV BX,CURTRK
XCHG BX,DX
CALL SETTRK
MOV BX,CURSEC
XCHG BX,DX
CALL SETSEC
CALL READ
CALL NXTSEC
POP DX
POP CX
MOV BX,OFFSET 80H
ADD BX,DX
XCHG BX,DX
DEC CX
MOV AL,CH
OR AL,CL
JNZ RDIRLP
MOV CX,OFFSET BASE +80H
CALL SETDMA
POP BX
RET
;
;Map the directory
;
MAP: CALL REDDIR ;READ IN DIRECTORY
MOV CL,0 ;INIT START GRP #
MOV AL,AL0 ;READ DIR GRP BITS
CALL COLECT ;COLLECT COUNT OF DIR GRPS..
MOV AL,AL1 ;..IN REGISTER C
CALL COLECT
MOV CH,0 ;BC NOW HAS A DEFAULT START GRP #
CALL HEXIN
PUSH BX ;SAVE INBUF PTR
MOV AL,DL ;GET START
OR AL,DH ;NOTHING?
JZ MAPDF ;..YES, DFLT
MOV CX,DX
;
MAPDF: CALL HEXB
MOV AL,'-'
CALL TYPEOUT
CALL GETGRP ;GET GRP(C) TO HL
;
MAPCNT:
INC CX ;NEXT GRP #
PUSH BX
MOV BX,DSM ;GET HIGHEST GRP #
INC BX ;PLUS 1 FOR COMPARISON
MOV AL,BL ;WHEN BC REACHES DSM+1..
CMP AL,CL ;..THEN WE HAVE EXCEEDED..
JNZ MAPC1 ;.. THE DISK CAPACITY..
MOV AL,BH
CMP AL,CH
;
MAPC1: POP BX
JZ MAPEND ;.. AND WE ARE DONE
PUSH BX
CALL GETGRP ;GET ANOTHER
POP DX ;SEE IF SAME
CALL CTLCS
JZ MAPND2
MOV AL,DH
CMP AL,BH
JNZ MAPDIF
MOV AL,DL
CMP AL,BL
JZ MAPCNT ;SAME, CONTINUE
;
;Different file encountered
MAPDIF:
DEC CX
CALL HEXB
INC CX
XCHG BX,DX
CALL MAPNAM
JMP MAPDF
;
;End of map
;
MAPEND:
DEC CX ;GET LAST
CALL HEXB
CALL MAPNAM
POP BX
CALL CRLF
;
;End of map - reposition to previous group
;
MAPND2: PUSH BX
MOV BX,GROUP
XCHG BX,DX
JMP POSGP2
;
;Print file name pointed to by HL
;
MAPNAM: CALL SPACE
MOV AL,BH
OR AL,BL ;NONE?
JZ NONAME
MOV AL,BYTE PTR [BX] ;SEE IF ALLOC
; cmp al,20h ! je noname
; cmp al,21h ! je noname
CMP AL,0E5H ;FREE?
MOV AL,' '
JNZ MPNSP1
MOV AL,'['
;
MPNSP1: CALL TYPEOUT
PUSH BX ;SAVE POINTER
MOV AL,BYTE PTR [BX]
CALL HEX ;SHOW USER NUMBER
CALL SPACE
INC BX ;SKIP USER BYTE
PUSH CX
MOV CH,8
CALL MAPN2
MOV AL,'.'
CALL TYPEOUT
MOV CH,3
CALL MAPN2
POP CX
CALL SPACE
MOV AL,BYTE PTR [BX] ;GET EXT
CALL HEX
POP BX
MOV AL,BYTE PTR [BX]
CMP AL,0E5H
MOV AL,' '
JNZ MPNSP2
MOV AL,']'
;
MPNSP2: CALL TYPEOUT ;")" IF ERASED FILE
JMP FLIP
;
NONAME: CALL ILPRT
DB ' ++FREE++ ',0
;
FLIP: MOV AL,TWOUP
XOR AL,1
MOV TWOUP,AL
JNZ L@00064
JMP CRLF
L@00064:
;
DELIM: MOV AL,':'
CALL TYPEOUT
JMP SPACE
;
;Print name, length in B
;
MAPN2: MOV AL,BYTE PTR [BX]
AND AL,7FH ;STRIP POSSIBLE 2.x ATTRIBUTE BIT
INC BX
CMP AL,' ' ;PRINTABLE?
JNAE MAPN2H ;..NO, IN HEX
CMP AL,7EH ;7E IS LEADIN ON SOME CRTS
JNAE MAPN2A
;
MAPN2H: CALL BHEX
JMP MAPN2Z
;
MAPN2A: CALL TYPEOUT
;
MAPN2Z: DEC CH
JNZ MAPN2
RET
;
;Find which file group (BC) belongs to
;
GETGRP: MOV BX,DRM ;MAX DIR ENTRY #
INC BX ;MAKE 1-RELATIVE
MOV FILECT,BX
MOV BX,OFFSET DIRECT
;
GETGLP: PUSH BX ;SAVE POINTER TO NAME
MOV AL,BYTE PTR [BX] ;PICK UP user number
cmp al,20h ! je getgnf ;user must be <20h
cmp al,21h ! je getgnf ;
MOV DX,OFFSET 14 ;NOW GET RECORD COUNT
ADD BX,DX ; S2 PORTION ..
MOV AL,BYTE PTR [BX] ; IS 0 IN CP/M 1.4
CMP AL,0E5H
JZ GETGNF
AND AL,0FH
MOV DL,AL
INC BX
MOV AL,BYTE PTR [BX]
OR AL,DL
JZ GETGNF
MOV DL,16 ;FIRST SET FOR 8-BIT GRPS
MOV AL,BYTE PTR DSM+1
OR AL,AL
JZ SMALGP
MOV DL,8 ;NOPE, BIG GROUPS
;
SMALGP: MOV DH,AL ;SAVE GRP SIZE INDICATOR
;
GETGL2:
INC BX ;POINTING INTO DM FIELD
CALL GRPCMP ;COMPARE BC GP # AGAINST 1 DM FLD
JZ GETGOT ;JUMP IF FOUND ONE
DEC DL ;ELSE COUNT DOWN
JNZ GETGL2 ;GO TEST SOME MORE
;
GETGNF: POP BX ;NOT THIS ONE
MOV DX,OFFSET 32 ;SO GO TO NEXT
ADD BX,DX
XCHG BX,DX
MOV BX,FILECT ;THERE IS LIMIT TO EVERYTHING
DEC BX
MOV FILECT,BX
MOV AL,BH
OR AL,BL
XCHG BX,DX ;RE-ALIGN
JNZ GETGLP
;
;Group is not allocated to any file
MOV BX,OFFSET 0 ;SAY SO
RET
;
;Found the file
;
GETGOT: POP BX
RET
;
;Save the current sector
;
SAVE: MOV AL,WRFLG
OR AL,AL
JNZ L@00074
JMP BADW ;NONE TO SAVE
L@00074:
PUSH BX
MOV BX,OFFSET BASE +80H
MOV DX,OFFSET SAVBUF
MOV CH,128
CALL MOVE
MOV AL,1 ;..SHOW
MOV SAVEFL,AL ;..SAVED EXISTS
POP BX
JMP PROMPT
;
;Restore the current sector
;
RESTOR: MOV AL,SAVEFL
OR AL,AL
JZ NOSAVE ;NONE TO SAVE
PUSH BX
MOV BX,OFFSET SAVBUF
MOV DX,OFFSET BASE +80H
MOV CH,128
CALL MOVE
POP BX
JMP PROMPT
;
NOSAVE: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++NO "<" SAVE COMMAND ISSUED'
DB CR,LF,0
JMP PRMPTR
;
;Move (HL) to (DE) length in B
;
MOVE: MOV AL,BYTE PTR [BX]
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
INC BX
INC DX
DEC CH
JNZ MOVE
RET
;
MOVEFROMBIOS:
MOV AL,ES:BYTE PTR [BX]
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
INC BX
INC DX
DEC CH
JNZ MOVEFROMBIOS
RET
;
NORITE: XOR AL,AL ;GET 0
MOV WRFLG,AL ;CAN'T WRITE NOW
RET
;
;No match in search, try next char
;
SRNOMT: POP BX
CALL CTLCS ;ABORT?
JNZ SEARCH ;...YES
MOV BX,OFFSET INBUF
MOV BYTE PTR [BX],CR
JMP CLCGRP ;SHOW WHERE STOPPED
;
;Search for character string
;
SEARCH: PUSH BX ;SAVE STRING POINTER
;
SRCHL: CALL RDBYTE ;GET A BYTE
MOV CH,AL ;SAVE IT
MOV AL,BYTE PTR [BX] ;CHECK NEXT MATCH CHAR.
CMP AL,'<' ;WILL IT BE HEX?
MOV AL,CH ;RESTORE DISK CHAR
JZ SRCHL1
AND AL,7FH ;NEXT CHAR IS ASCII...STRIP BIT 7
;
SRCHL1: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
CALL GETVAL ;GET SEARCH VALUE
MOV CH,AL
POP AX
XCHG AL,AH
SAHF
CMP AL,CH ;MATCH?
JNZ SRNOMT ;NO MATCH
INC BX
MOV AL,BYTE PTR [BX] ;DONE?
CMP AL,CR
JZ SREQU
CMP AL,'!'
JNZ SRCHL
;
;Got match
SREQU: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '= AT ',0
MOV AL,BYTE PTR BUFAD
AND AL,7FH
CALL HEX
CALL CRLF
JMP CLCGRP
;
;Get value from input buffer
;
GETVAL: MOV AL,BYTE PTR [BX]
CMP AL,'<' ;HEX ESCAPE?
JZ L@00082
RET ;NO, RETURN
L@00082:
;"<<" means one "<"
INC BX
MOV AL,BYTE PTR [BX]
CMP AL,'<'
JNZ L@00083
RET
L@00083:
;Got hex
PUSH DX
CALL HEXIN ;GET VALUE
CMP AL,'>' ;PROPER DELIM?
MOV AL,DL ;GET VALUE
POP DX
JZ L@00084
JMP WHAT ;ERROR
L@00084:
RET
;
;Read a byte at a time
;
RDBYTE: PUSH BX
MOV AL,FTSW ;FIRST READ?
OR AL,AL
JNZ READ1
MOV BX,BUFAD
MOV AL,BL
OR AL,AL ;IN BUFFER?
JS NORD ;YES, SKIP READ
;
;Have to read
CALL NXTSEC
;
READ1: XOR AL,AL
MOV FTSW,AL ;NOT FIRST READ
MOV BX,CURSEC
XCHG BX,DX
CALL SETSEC
MOV BX,CURTRK
XCHG BX,DX
CALL SETTRK
CALL READ
CALL CLCSUB
MOV BX,OFFSET BASE +80H
;
NORD: MOV AL,BYTE PTR [BX]
INC BX
MOV BUFAD,BX
POP BX
RET
;
;View the file in ASCII starting at
;current sector, stepping thru the disk
;
VIEW: MOV AL,WRFLG
OR AL,AL
JNZ L@00087
JMP BADDMP
L@00087:
CALL HEXIN ;GET DISPL IF ANY
PUSH BX
MOV AL,DL
OR AL,AL
JNZ VIEWLP
INC DL ;DFLT=1
;
VIEWLP: MOV BX,OFFSET BASE +80H ;TO DATA
;
VEWCHR: CALL CTLCS
JZ VEWEND
MOV AL,BYTE PTR [BX]
CMP AL,1AH
JZ VEWEOF
AND AL,7FH
CMP AL,7EH
JAE VIEWHX ;SHOW RUBOUT AND TILDE AS HEX
CMP AL,' '
JAE VIEWPR
CMP AL,CR
JZ VIEWPR
CMP AL,LF
JZ VIEWPR
CMP AL,TAB
JZ VIEWPR
;
VIEWHX: MOV AL,BYTE PTR [BX] ;NOT ASCII...PRINT AS <NN>
CALL BHEX
JMP VIEWNP
;
VIEWPR: CALL TYPEOUT
;
VIEWNP: INC BL
JNZ VEWCHR
DEC DL
JZ VEWEND
PUSH DX ;SAVE COUNT
CALL NXTSEC
MOV BX,CURSEC
XCHG BX,DX
CALL SETSEC
MOV BX,CURTRK
XCHG BX,DX
CALL SETTRK
CALL READ
POP DX ;RESTORE COUNT
JMP VIEWLP
;
VEWEOF: CALL ILPRT
DB CR,LF,TAB,'++EOF++',CR,LF,0
;
VEWEND: POP BX
CALL CRLF
JMP CLCGRP
;
;Dump in hex or ASCII
;
DUMP: MOV AL,WRFLG
OR AL,AL
JNZ DUMPOK
;
BADDMP: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++Can''t dump, no sector read.',CR,LF,0
;
EXPL: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB 'Use G command following F,',CR,LF
DB 'or R or S following T',CR,LF,0
JMP PRMPTR
;
DUMPOK: MOV AL,BYTE PTR [BX]
CMP AL,'!'
JZ DUMPDF ;DFLT
CMP AL,CR
JNZ DMPNDF
;
;Use default
DUMPDF: MOV CX,OFFSET BASE +80H
MOV DX,OFFSET 0FFH
JMP DUMP1
;
DMPNDF: CALL DISP
MOV CX,DX
CMP AL,CR
JZ DUMP1
CMP AL,'!'
JZ DUMP1
INC BX ;SKIP ','
CALL DISP
;
;BC = start, DE = end
;
DUMP1: PUSH BX ;SAVE COMMAND POINTER
MOV BX,CX
;
DUMPLP: MOV AL,BL
AND AL,7FH
CALL HEX
CALL SPACE
CALL SPACE
MOV AL,DUMTYP
CMP AL,'A'
JZ DUMPAS
PUSH BX ;SAVE START
;
DHEX: MOV AL,BYTE PTR [BX]
CALL HEX
MOV AL,BL
AND AL,3
CMP AL,3
JNZ L@00104
CALL SPACE
L@00104:
MOV AL,BL
AND AL,7
CMP AL,7
JNZ L@00105
CALL SPACE
L@00105:
MOV AL,DL
CMP AL,BL
JZ DPOP
INC BX
MOV AL,BL
AND AL,0FH
JNZ DHEX
;
DPOP: CALL CTLCS
JNZ L@00108
JMP PRMPTR
L@00108:
MOV AL,DUMTYP
CMP AL,'H'
JZ DNOAS ;HEX ONLY
POP BX ;GET START ADDR
;
DUMPAS: CALL ASTER
;
DCHR: MOV AL,BYTE PTR [BX]
AND AL,7FH
CMP AL,' '
JNAE DPER
CMP AL,7EH
JNAE DOK
;
DPER: MOV AL,'.'
;
DOK: CALL TYPEOUT
MOV AL,DL
CMP AL,BL
JZ DEND
INC BX
MOV AL,BL
AND AL,0FH
JNZ DCHR
;
DEND: CALL ASTER
CALL CRLF
PUSH DX
CALL CTLCS
POP DX
JNZ L@00114
JMP PRMPTR
L@00114:
MOV AL,DL
CMP AL,BL
JZ L@00115
JMP DUMPLP
L@00115:
POP BX
JMP PROMPT
;
DNOAS: POP CX
CALL CRLF
MOV AL,DL
CMP AL,BL
JZ L@00116
JMP DUMPLP
L@00116:
POP BX
JMP PROMPT
;
;Position
;
POS: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
MOV AL,BYTE PTR [BX]
CMP AL,'!'
JZ POSINQ
CMP AL,CR
JNZ POSOK
;
POSINQ: POP AX
XCHG AL,AH
SAHF
JMP INQ
;
POSOK: POP AX
XCHG AL,AH
SAHF
CMP AL,'T'
JZ POSTKD
CMP AL,'S'
JZ POSSCD
CMP AL,'G'
JNZ L@00121
JMP POSGPH
L@00121:
JMP WHAT
;
POSTKD: CALL DECIN
;
POSTRK: PUSH BX
MOV BX,MAXTRK
CALL SUBDE
POP BX
JAE L@00122
JMP OUTLIM
L@00122:
CALL SETTRK
CALL NORITE ;TRACK DOESN'T READ
MOV AL,1
MOV NOTPOS,AL ;SHOW NOT POSITIONED
JMP CLCGRP
;
POSSCD: CALL DECIN
MOV AL,DH
OR AL,DL
JNZ L@00123
JMP WHAT ;DON'T ALLOW SECTOR 0
L@00123:
;
POSSEC: PUSH BX
MOV BX,SPT
CALL SUBDE
POP BX
JAE L@00124
JMP WHAT
L@00124:
CALL SETSEC
CALL READ
XOR AL,AL
MOV NOTPOS,AL ;POSITIONED OK
;
CLCGRP: CALL CLCSUB
JMP INQ
;
;Calculate group from track and sector
;
CLCSUB: push bx
mov ax,CURTRK
mov bx,SYSTRK
cmp bx,ax ! ja a_systrack
sub ax,SYSTRK
a_systrack:
xor dx,dx
mul SPT ;TRK*SPT=hi bits in DX lo bits in AX
mov bx,CURSEC
dec bx
add ax,bx ;add in cursec - 1
adc dx,0
divide1:
mov bx,1
mov cl,BSH
shl bx,cl ;BX = 2^BSH
div bx ;DX:AX=((CURTRK-SYSTRK)*SPT+CURSEC-1)/(2^BSH)
mov group,ax ;AX=quotent, DX=remainder
mov GRPDIS,dl
pop bx
ret
;
;Position in the dorectory after a find
;(Does not work in CP/M-2.x)
;
POSDIR: PUSH BX ;SAVE INBUF
MOV BX,WORD PTR BSH
XOR AL,AL
MOV FINDFL,AL ;CANCEL POS REQ
MOV AL,DIRPOS ;GET POSITION
RCR AL,1
RCR AL,1
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
AND AL,BH
MOV GRPDIS,AL
POP AX
XCHG AL,AH
SAHF
;
POSDLP: RCR AL,1
DEC BL
JNZ POSDLP
AND AL,1 ;GET GROUP
MOV BL,AL ;SETUP FOR POSGP2
MOV BH,0
MOV GROUP,BX
XCHG BX,DX
JMP POSGP2 ;POSITION TO IT
;
POSGPH: CALL HEXIN
;
POSGRP: PUSH BX
MOV BX,DSM
CALL SUBDE
POP BX
JAE L@00127
JMP OUTLIM
L@00127:
XCHG BX,DX
MOV GROUP,BX
XCHG BX,DX
XOR AL,AL
MOV GRPDIS,AL
PUSH BX
;
POSGP2: CALL GTKSEC
CALL SETTRK
XCHG BX,DX
inc dx
CALL SETSEC
CALL READ
XOR AL,AL
MOV NOTPOS,AL ;NOW POSITIONED
POP BX
JMP INQ
;
GTKSEC:
MOV BX,DX ;BX = number of blocks
mov cl,BSH
mov ax,1
shl ax,cl ;AX=2^BSH
xor dx,dx ;clear DX register
mul bx ;AX*BX=hi 16 bits in DX, lo in AX
xor bx,bx
mov bl,GRPDIS
add ax,bx ;add in GRPDIS
adc dx,0 ;with carry into DX
;
;Divide by nbr of sectors, quotient=track, remainder=sector
;NOTE for O/S = ver 3.1+, SPT is in 128 byte units, not phy sectors
;
divide2:
div Word Ptr SPT ;DX:AX/SPT=AX(quotent)=track, DX(remainder)=sector
add ax,SYSTRK ;add in track offset
mov bx,dx ;and get stuff into proper registers
mov dx,ax ;for the return
or bx,bx ;don't allow a zero sector number
ret
;
POSFIL: CALL NORITE
MOV AL,1
MOV FINDFL,AL ;SO WE POSITION LATER
MOV DX,OFFSET FCB
XOR AL,AL ;LOGGED IN DISK
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
INC DX
MOV CH,8
CALL MVNAME
MOV CH,3
CALL MVNAME
MOV DX,OFFSET FCB
MOV CL,SRCHF
PUSH BX
CALL BDOS
INC AL
JNZ FLOK
MOV DIRPOS,AL ;GRP 0 IF NOT FOUND
CALL ILPRT
DB '++FILE NOT FOUND',CR,LF,0
POP BX
JMP PROMPT
;
FLOK: DEC AL
MOV DIRPOS,AL ;SAVE POS. IN DIR
AND AL,3
MOV BL,AL
MOV BH,0
ADD BX,BX
ADD BX,BX
ADD BX,BX
ADD BX,BX
ADD BX,BX
MOV DX,OFFSET BASE +80H
ADD BX,DX
MOV DX,OFFSET 32
XCHG BX,DX
ADD BX,DX
XCHG BX,DX
MOV AL,'D'
MOV DUMTYP,AL
JMP DUMPLP ;WHICH POPS H
;
MVNAME: MOV AL,BYTE PTR [BX]
CMP AL,'.'
JZ MVIPAD
CMP AL,CR
JZ PAD
CMP AL,'!'
JZ PAD
CALL UPCASE
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
INC BX
INC DX
DEC CH
JNZ MVNAME
MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00135
RET
L@00135:
CMP AL,'!'
JNZ L@00136
RET
L@00136:
INC BX
CMP AL,'.'
JNZ L@00137
RET
L@00137:
JMP WHAT
;
MVIPAD:
INC BX
;
PAD: MOV AL,' '
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX
INC DX
DEC CH
JNZ PAD
RET
;
PLUS: MOV DX,OFFSET 1 ;DFLT TO 1 SECT
MOV AL,BYTE PTR [BX] ;GET NEXT CHAR
CMP AL,CR ;CR?
JZ PLUSGO ;.. YES, DFLT TO 1
CMP AL,'!'
JZ PLUSGO
CALL HEXIN ;GET #
MOV AL,DH
OR AL,DL
JNZ L@00141
JMP WHAT
L@00141:
;
PLUSGO: CALL NXTSEC
DEC DX ;MORE TO GO?
MOV AL,DH
OR AL,DL
JNZ PLUSGO ;..YES
;
;Ok, incremented to sector. Setup and read
;
PLUSMI: PUSH BX
MOV BX,CURSEC
XCHG BX,DX
CALL SETSEC
MOV BX,CURTRK
XCHG BX,DX
CALL SETTRK
POP BX
CALL READ
JMP CLCGRP
;
MINUS: MOV DX,OFFSET 1 ;SET DFLT
MOV AL,BYTE PTR [BX] ;GET CHAR
CMP AL,CR ;CR?
JZ MINGO ;.. YES, DFLT=1
CMP AL,'!'
JZ MINGO
CALL HEXIN ;..NO, GET ##
MOV AL,DH
OR AL,DL
JNZ L@00145
JMP WHAT
L@00145:
;
MINGO: PUSH BX
MOV BX,CURSEC
DEC BX
MOV AL,BH
OR AL,BL
JNZ MINOK
MOV BX,CURTRK
MOV AL,BH
OR AL,BL
JNZ SEASH
MOV BX,MAXTRK ;WRAP TO END OF DISK
MOV CURTRK,BX
MOV BX,MAXSEC
JMP MINOK
;
SEASH:
DEC BX
MOV CURTRK,BX
MOV BX,SPT
;
MINOK: MOV CURSEC,BX
POP BX
DEC DX
MOV AL,DH
OR AL,DL
JNZ MINGO
JMP PLUSMI
;
;Go to next sector
;
NXTSEC: PUSH BX
PUSH DX
MOV BX,CURSEC
INC BX
XCHG BX,DX
MOV BX,SPT
CALL SUBDE
XCHG BX,DX
JAE NEXTOK
MOV BX,CURTRK
INC BX
XCHG BX,DX
MOV BX,MAXTRK
CALL SUBDE
JAE TRASK
MOV DX,OFFSET 0 ;WRAP TO START OF DISK
;
TRASK: XCHG BX,DX
MOV CURTRK,BX
MOV BX,OFFSET 1
;
NEXTOK: MOV CURSEC,BX
POP DX
POP BX
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 BX
MOV BX,SYSTRK
XCHG BX,DX
MOV BX,CURTRK
CALL SUBDE
JNAE NOGRP
CALL ILPRT
DB 'G=',0
MOV BX,GROUP
MOV CH,BH
MOV CL,BL
CALL HEXB
MOV AL,':'
CALL TYPEOUT
MOV AL,GRPDIS
CALL HEX
MOV AL,','
CALL TYPEOUT
;
NOGRP: CALL ILPRT
DB ' T=',0
MOV BX,CURTRK
CALL DEC
CALL ILPRT
DB ', S=',0
MOV BX,CURSEC
CALL DEC
CALL ILPRT
DB ', PS=',0
MOV BX,PHYSEC
CALL DEC
CALL CRLF
POP BX
RET
;
CHG: MOV AL,BYTE PTR [BX] ;GET TYPE (HEX, ASCII)
CALL UPCASE
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH ;SAVE "H" OR "A"
INC BX
CALL DISP ;GET, VALIDATE DISP TO DE
INC BX
MOV CX,OFFSET 0 ;SHOW NO 'THRU' ADDR
CMP AL,'-' ;TEST DELIM FR. DISP
JNZ CHGNTH ;NO THRU
PUSH DX ;SAVE FROM
CALL DISP ;GET THRU
INC BX ;SKIP END DELIM
MOV CX,DX ;BC = THRU
POP DX ;GET FROM
JMP CHGAH
;
CHGNTH: CMP AL,','
JZ L@00153
JMP WHAT
L@00153:
;
CHGAH: POP AX
XCHG AL,AH
SAHF
CMP AL,'H'
JNZ L@00154
JMP CHGHEX
L@00154:
CMP AL,'A'
JZ L@00155
JMP WHAT
L@00155:
;
;Change ASCII
CHGALP: MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00156
JMP PROMPT
L@00156:
CMP AL,'!'
JNZ L@00157
JMP PROMPT
L@00157:
XCHG BX,DX
MOV AL,[BX]
XCHG BX,DX
CMP AL,' '
JNAE CHGAHX
CMP AL,7EH
JAE CHGAHX
JMP CHGA2
;
CHGAHX: CALL BHEX
JMP CHGA3
;
CHGA2: CALL TYPEOUT
;
CHGA3: MOV BACK,BX ;IN CASE "THRU"
CALL GETVAL ;ASCII OR <HEX>
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX ;UPDATE CHAR
INC BX ;TO NEXT INPUT CHAR
;See if 'THRU' requested
MOV AL,CL
OR AL,AL
JZ CHANTH
CMP AL,DL ;DONE?..
JNZ L@00161
JMP PROMPT ;..YES
L@00161:
MOV BX,BACK
;
CHANTH: INC DL
JZ L@00162
JMP CHGALP
L@00162:
MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00163
JMP PROMPT
L@00163:
CMP AL,'!'
JNZ L@00164
JMP PROMPT
L@00164:
JMP WHAT
;
;Change hex
;
CHGHCM:
INC BX
;
CHGHEX: MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00165
JMP PROMPT
L@00165:
CMP AL,'!'
JNZ L@00166
JMP PROMPT
L@00166:
CMP AL,',' ;DELIM?
JZ CHGHCM
PUSH DX
MOV HEXAD,BX ;IN CASE 'THRU'
CALL HEXIN ;POSITIONS TO DELIM
MOV AL,DL ;GET VALUE
POP DX ;..ADDR
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH ;SAVE VALUE
XCHG BX,DX
MOV AL,[BX]
XCHG BX,DX ;GET OLD
CALL HEX ;ECHO IN HEX
POP AX
XCHG AL,AH
SAHF ;GET NEW
XCHG BX,DX
MOV [BX],AL
XCHG BX,DX ;SAVE NEW
MOV AL,CL ;SEE IF 'THRU'
OR AL,AL
JZ CHHNTH ;..NO.
CMP AL,DL ;..YES, DONE?
JNZ L@00169
JMP PROMPT
L@00169:
MOV BX,HEXAD ;..NO: MORE
;
CHHNTH: INC DL
JNZ CHGHEX
MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00171
JMP PROMPT
L@00171:
CMP AL,'!'
JNZ L@00172
JMP PROMPT
L@00172:
JMP WHAT
;
DOREAD: MOV AL,NOTPOS
OR AL,AL
JNZ CANTRD
CALL READ
JMP PROMPT
;
CANTRD: XOR AL,AL
MOV QFLAG,AL ;NOT QUIET
CALL ILPRT
DB '++Can''t read - not positioned',CR,LF
DB 'Position by:',CR,LF
DB 9,'Track then Sector, or',CR,LF
DB 9,'Group',CR,LF,0
JMP PROMPT
;
DORITE: CALL WRITE
JMP PROMPT
;
BHEX: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
MOV AL,'<'
CALL TYPEOUT
POP AX
XCHG AL,AH
SAHF
CALL HEX
MOV AL,'>'
CALL TYPEOUT
RET
;
HEXB: MOV AL,BYTE PTR DSM+1
OR AL,AL
JZ HEXX
MOV AL,CH
CALL HEX
;
HEXX: MOV AL,CL
;
HEX: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
RCR AL,1
RCR AL,1
RCR AL,1
RCR AL,1
CALL NIBBL
POP AX
XCHG AL,AH
SAHF
;
NIBBL: AND AL,0FH
CMP AL,10
JNAE HEXNU
ADD AL,7
;
HEXNU: ADD AL,'0'
JMP TYPEOUT
;
;Decimal output routine
;
DEC: PUSH CX
PUSH DX
PUSH BX
MOV CX,-OFFSET 10
MOV DX,-OFFSET 1
;
DECOU2: PUSHF
ADD BX,CX
RCR SI,1
POPF
RCL SI,1
PUSHF
INC DX
POPF
JNAE DECOU2
MOV CX,OFFSET 10
ADD BX,CX
XCHG BX,DX
MOV AL,BH
OR AL,BL
JZ L@00177
CALL DEC
L@00177:
MOV AL,DL
ADD AL,'0'
CALL TYPEOUT
POP BX
POP DX
POP CX
RET
;
SPACE: MOV AL,' '
JMP TYPEOUT
;
ASTER: MOV AL,'*'
JMP TYPEOUT
;
;Inline print routine
;
ILPRT: POP SI
XCHG BX,SI
PUSH SI
;
ILPLP: CALL CTLCS ;ABORT?
JNZ L@00178
JMP PRMPTR
L@00178:
MOV AL,BYTE PTR [BX]
CMP AL,1 ;PAUSE?
JNZ ILPOK
CALL CONIN
CMP AL,1bh ! je il_abort ;escape
CMP AL,'Q'-40h ! je il_abort ;^Q
CMP AL,'C'-40h ! je il_abort ;^C=ABORT?
JMPS L@00180
IL_ABORT:
JMP PRMPTR
L@00180:
JMP ILPNX
;
ILPOK: CALL TYPEOUT
;
ILPNX:
INC BX
MOV AL,BYTE PTR [BX]
OR AL,AL
JNZ ILPLP
INC BX
POP SI
XCHG BX,SI
PUSH SI
RET
;
;DISP calls HEXIN, and validates a sector
;displacement, then converts it to an address
;
DISP: CALL HEXIN
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH ;SAVE DELIMITER
MOV AL,DH
OR AL,AL
JNZ BADISP
MOV AL,DL
OR AL,AL
JS BADISP
ADD AL,80H ;TO POINT TO BUFFER AT BASE+80H
MOV DL,AL
MOV DH,BASE/256
POP AX
XCHG AL,AH
SAHF ;GET DELIM
RET
;
BADISP: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++BAD DISPLACEMENT (NOT 0-7F)'
DB CR,LF,0
JMP PRMPTR
;
HEXIN: MOV DX,OFFSET 0
MOV AL,BYTE PTR [BX]
CMP AL,'#' ;DECIMAL?
JZ HDIN ;MAKE DECIMAL
;
HINLP: MOV AL,BYTE PTR [BX]
CALL UPCASE
CMP AL,CR
JNZ L@00185
RET
L@00185:
CMP AL,'!'
JNZ L@00186
RET
L@00186:
CMP AL,','
JNZ L@00187
RET
L@00187:
CMP AL,'-' ;'THRU'?
JNZ L@00188
RET
L@00188:
CMP AL,'>'
JNZ L@00189
RET
L@00189:
INC BX
CMP AL,'0'
JAE L@00190
JMP WHAT
L@00190:
CMP AL,'9'+1
JNAE HINNUM
CMP AL,'A'
JAE L@00192
JMP WHAT
L@00192:
CMP AL,'F'+1
JNAE L@00193
JMP WHAT
L@00193:
SUB AL,7
;
HINNUM: SUB AL,'0'
XCHG BX,DX
ADD BX,BX
ADD BX,BX
ADD BX,BX
ADD BX,BX
ADD AL,BL
MOV BL,AL
XCHG BX,DX
JMP HINLP
;
HDIN:
INC BX ;SKIP '.'
;
DECIN: MOV DX,OFFSET 0
;
DINLP: MOV AL,BYTE PTR [BX]
CALL UPCASE
CMP AL,CR
JNZ L@00194
RET
L@00194:
CMP AL,'!'
JNZ L@00195
RET
L@00195:
CMP AL,','
JNZ L@00196
RET
L@00196:
CMP AL,'-' ;'THRU'?
JNZ L@00197
RET
L@00197:
INC BX
CMP AL,'0'
JAE L@00198
JMP WHAT
L@00198:
CMP AL,'9'+1
JNAE L@00199
JMP WHAT
L@00199:
SUB AL,'0'
PUSH BX
MOV BH,DH
MOV BL,DL
ADD BX,BX
ADD BX,BX
ADD BX,DX
ADD BX,BX
ADD AL,BL
MOV BL,AL
MOV AL,BH
ADC AL,0
MOV BH,AL
XCHG BX,DX
POP BX
JMP DINLP
;
;Read in a console buffer full
;
RDBUF: ;PRINT PROMPT AS DU nnA:
CALL ILPRT
DB CR,LF,'DU ',0 ;SAY WHO WE ARE
MOV AL,UNUM
CMP AL,0 ! JZ DONT_0
MOV BL,AL ;DISPLAY USER NUMBER
MOV BH,0
CALL DEC ;PRINT IN DECIMAL
DONT_0:
MOV AL,DRIVE ;GET DRIVE NUMBER
ADD AL,'A' ;CONVERT TO ASCII
CALL TYPEOUT
CALL ILPRT ;PRINT THE PROMPT
DB ': ',0
;
RDBF1: MOV BX,OFFSET INBUF
MOV CH,0
;
RDBLP: CALL CONIN
MOV CL,AL ;SAVE FOR BS TEST
;
;Evaluate control characters
;
CMP AL,'U'-40H
JNZ L@00200
JMP RDCTLU
L@00200:
;
CMP AL,CR
JZ RDCR
;
CMP AL,'H'-40H
JZ RDBS
;
CMP AL,7FH
JZ RDBS
;
CMP AL,'R'-40H
JZ RDCTLR
;
CMP AL,'X'-40H
JZ RDCTLX
CMP AL,'['-40H
JNE NO_QUIT
JMP QUIT
NO_QUIT:
;
CMP AL,' '
JNAE RDBLP
;
MOV BYTE PTR [BX],AL
INC BX
INC CH
JS FULL
CALL TYPEOUT
JMP RDBLP
;
FULL: DEC CH
PUSHF
DEC BX
POPF
MOV AL,'*' ;SIGNAL WE'RE FULL
CALL TYPEOUT
JMP RDBLP
;
;Got CR
;
RDCR: MOV BYTE PTR [BX],AL ;SAVE IT
CALL TYPEOUT ;ECHO IT
MOV AL,LF ;ECHO..
CALL TYPEOUT ;..LF
MOV BX,OFFSET INBUF
RET
;
;Got DELETE or BS, echo if BS
;
RDBS: XOR AL,AL ;AT FRONT..
OR AL,CH ;..OF LINE?
JZ RDCTLU ;.. YES, ECHO ^U
DEC BX
DEC CH
MOV AL,CL
CMP AL,'H'-40H ;BS?
JZ BACKUP ;ECHO THE BS
MOV AL,BYTE PTR [BX] ;ECHO..
CALL TYPEOUT ;..DELETED CHAR
JMP RDBLP
;
BACKUP: CALL WIPER
JMP RDBLP
;
RDCTLX: INC CH
;
RDCX1: DEC CH
JZ RDBF1
CALL WIPER
JMP RDCX1
;
WIPER: PUSH CX
PUSH DX
PUSH BX
MOV DX,OFFSET BSMSG ;BACKSPACE, SPACE, BACKSPACE
MOV CL,PRINT
CALL BDOS
POP BX
POP DX
POP CX
RET
;
BSMSG DB BS,' ',BS,'$'
;
;Got CTL-R, retype
;
RDCTLR: MOV BYTE PTR [BX],CR
CALL CRLF
MOV BX,OFFSET INBUF
MOV CH,0
;
RDCRL: MOV AL,BYTE PTR [BX]
CMP AL,CR
JNZ L@00211
JMP RDBLP
L@00211:
CALL TYPEOUT
INC CH
INC BX
JMP RDCRL
;
;Got CTL-U or backup to beginning of line.
;
RDCTLU: MOV AL,'^'
CALL TYPEOUT
MOV AL,'U'
CALL TYPEOUT
JMP RDBUF
;
CRLF: MOV AL,CR
CALL TYPEOUT
MOV AL,LF
JMP TYPEOUT
;
UPCASE: CMP AL,60H
JNB L@00212
RET
L@00212:
AND AL,5FH ;MAKE UPPER CASE
RET
;
CONST: PUSH CX
PUSH DX
PUSH BX
CALL BCONST ;GET CONSOLE STATUS USING BIOS CALL
POP BX
POP DX
POP CX
RET
;
CONIN: PUSH CX
PUSH DX
PUSH BX
CALL BCONIN ;GET CONSOLE CHAR FROM BIOS
POP BX
POP DX
POP CX
RET
;
;Console out with TAB expansion
; Enter: char in AL
;
TYPEOUT:
PUSH CX
PUSH DX
PUSH BX
MOV CL,AL ;FOR OUTPUT ROUTINE
CMP AL,TAB
JNZ TYPE2
;
TYPTAB: MOV AL,' '
CALL TYPEOUT
MOV AL,TABCOL
AND AL,7
JNZ TYPTAB
JMP TYPRET
;
;Filter out control characters to
;prevent garbage during view of file
;
TYPE2: CMP AL,' '
JAE TYPEQ
CMP AL,CR
JZ TYPEQ
CMP AL,LF
JNZ TYPNCR
;
TYPEQ: MOV AL,QFLAG
OR AL,AL
VCONOT: JNZ L@00218
PUSH CX
CALL BCONOUT ;CONSOLE OUT THRU BIOS
POP CX
L@00218:
;
;Update column used in tab expansion
MOV AL,CL ;GET CHAR
CMP AL,CR
JNZ TYPNCR
MOV AL,0
MOV TABCOL,AL
JMP TYPLST
;
TYPNCR: CMP AL,' ' ;CTL CHAR?
JNAE TYPLST ;..NO CGANGE IN COL
MOV AL,TABCOL
INC AL
MOV TABCOL,AL
;
TYPLST: MOV AL,PFLAG
AND AL,1
JZ L@00221
CALL LISTOUT ;FROM C REG.
L@00221:
;
TYPRET: POP BX
POP DX
POP CX
RET
;
LISTOUT: ;enter char in CL
mov dl,cl ;put char in DL
mov cl,L_WRITE ;write to default list device
CALL BDOS ;LIST TO PRINTER THRU BDOS
RET
;
HOME: PUSH BX
CALL BHOME ;HOME DRIVE THRU BIOS
POP BX
RET
;
;Set track # in DE
;
SETTRK: PUSH BX
MOV BX,MAXTRK
CALL SUBDE
POP BX
JNAE OUTLIM
XCHG BX,DX
MOV CURTRK,BX
XCHG BX,DX
MOV CX,DX
PUSH BX
CALL TRK ;SET TRACK THRU BIOS
POP BX
RET
;
SETSEC: PUSH BX
PUSH DX
MOV BX,SYSTRK
XCHG BX,DX
MOV CURSEC,BX
MOV BX,CURTRK
CALL SUBDE
POP CX
MOV BX,CX
JAE NOTSYS
MOV AL,FIRST0 ;SEE IF FIRST SEC 0
OR AL,AL
JNZ GSTSEC ;NO, JUMP AWAY
DEC BX ;YES, SO DECREMENT
JMP GSTSEC ; REQUESTED, THEN GO
;
NOTSYS: MOV BX,SECTBL
XCHG BX,DX
DEC CX
CALL BSECTTRAN
MOV AL,BYTE PTR SPT+1 ;IF SPT<256 (HI-ORD = 0)
OR AL,AL ; THEN FORCE 8-BIT TRANSLATION
JNZ VSCTR1 ; ELSE KEEP ALL 16 BITS
MOV BH,AL
VSCTR1:
GSTSEC:
MOV PHYSEC,BX
cmp byte ptr cpm_version,31h
jb aint31
mov bx,cursec ;version 31 does it's own xlate, use cursec
aint31:
MOV CX,BX
CALL SEC ;SET SECTOR THRU BIOS
POP BX
RET
;
OUTLIM: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++not within tracks 0-',0
PUSH BX
MOV BX,MAXTRK
CALL DEC
POP BX
CALL ILPRT
DB '++'
DB CR,LF,0
CALL NORITE
JMP PRMPTR
;
SETDMA:
CALL DMA ;SET UP DMA FOR BIOS
MOV CX,CS ;SET DMA SEGMENT FOR BIOS
JMP SETDMAB
;
;
READ: MOV AL,1
MOV WRFLG,AL
PUSH BX
CALL DSKREAD ;READ DISK THRU BIOS
OR AL,AL
JZ READOK
XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++READ failed, sector may be invalid++'
DB CR,LF,0
;
READOK: POP BX
RET
;
WRITE: MOV AL,WRFLG
OR AL,AL
JNZ PWRITE
;
BADW: XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++CANNOT WRITE UNLESS READ ISSUED'
DB CR,LF,0
JMP EXPL
;
PWRITE: PUSH BX
MOV CL,1 ;FORCE WRITE TYPE 1 IN CASE 2.x DEBLOCK USED
CALL DSKWRITE ;WRITE DISK
OR AL,AL
JZ WRITOK
XOR AL,AL
MOV QFLAG,AL
CALL ILPRT
DB '++WRITE failed++',CR,LF,0
;
WRITOK: POP BX
RET
;
;Help
;
HELP: CALL ILPRT
DB 'Operands in brackets [...] are optional'
DB CR,LF
DB 'Numeric values: ''n'' are decimal, ''x'' hex'
DB CR,LF,CR,LF
DB '+[n] step in [n] sectors;'
DB CR,LF
DB '-[n] step out [n] sectors'
DB CR,LF
DB '# print disk parameters for curr drive.'
DB CR,LF
DB '=xxx search for ASCII xxx from curr sector.'
DB CR,LF
DB ' Caution: upper/lower case matters.'
DB CR,LF
DB ' Use <xx> for hex:'
DB CR,LF
DB ' To find "IN AL,0C0h" use: =<E4><C0> or'
DB CR,LF
DB ' "(tab)H,0(CR)(LF)" use: =<9>H,0<D><A>'
DB CR,LF
DB '< save current sector into mem. buff.'
DB CR,LF
DB '> restore saved sector'
DB CR,LF
DB '? give help'
DB CR,LF
DB 'A[ff,tt] ASCII dump'
DB CR,LF,CR,LF
DB '(Type SP bar to continue)'
DB 1,CR,LF,CR,LF
DB 'C Change:'
DB CR,LF
DB ' CHaddr,byte,byte... (hex)'
DB CR,LF
DB ' or CAaddr,data... (Ascii)'
DB CR,LF
DB ' <xx> Allowed for imbedded hex.'
DB CR,LF
DB ' or CHfrom-thru,byte e.g. ch0-7f,e5'
DB CR,LF
DB ' or CAfrom-thru,byte'
DB CR,LF
DB 'D[ff,tt] Dump (hex+ASCII)'
DB CR,LF
DB 'Fn.t Find file'
DB CR,LF
DB 'Gnn CP/M Allocation Group nn'
DB CR,LF
DB 'H[ff,tt] hex dump'
DB CR,LF
DB 'L Log in drive'
DB CR,LF
DB 'Lx Log in drive x'
DB CR,LF
DB 'M[nn] Map [from group nn]'
DB CR,LF,CR,LF
DB '(Type SP bar to continue)'
DB 1,CR,LF,CR,LF
DB 'N New disk'
DB CR,LF
DB 'P Toggle printer switch'
DB CR,LF
DB 'Q Quiet mode (no msgs)'
DB CR,LF
DB 'R Read current sector'
DB CR,LF
DB 'Snn Sector nn'
DB CR,LF
DB 'Tnn Track nn'
DB CR,LF
DB 'Unn Set User nn for Find command'
DB CR,LF
DB 'V[nn] View [nn] ASCII sectors'
DB CR,LF
DB 'W Write current sector'
DB CR,LF
DB 'X Exit program'
DB CR,LF
DB 'Z[nn] Sleep [nn tenths]'
DB CR,LF
DB '/[nn] Repeat [nn (decimal) times]'
DB CR,LF,CR,LF
DB '(Type SP bar to continue)'
DB 1,CR,LF,CR,LF
DB 'Cancel a function with ESC or Ctl-C.'
DB CR,LF
DB 'Suspend output with S or Ctl-S.'
DB CR,LF
DB 'Separate commands with "!".'
DB CR,LF
DB ' Example: g0'
DB CR,LF
DB ' +!d!z#20!/'
DB CR,LF
DB ' would step in, dump, sleep 2 sec, '
DB CR,LF
DB ' and repeat until control-c typed.'
DB CR,LF
DB 'All "nn" usage except "/", "T", and "S" are'
DB CR,LF
DB ' HEX. Use #nn for decimal.'
DB CR,LF,CR,LF
DB 'See DU.DOC for complete examples.'
DB CR,LF,CR,LF,0
JMP PROMPT
;
;********************************
;* *
;* Utility Subroutines *
;* *
;********************************
;
GRPCMP: MOV AL,CL
INC DH
DEC DH
JZ CMP8
CMP AL,BYTE PTR [BX]
PUSHF
INC BX
POPF
JZ L@00231
RET
L@00231:
MOV AL,CH
;
CMP8: CMP AL,BYTE PTR [BX]
RET
;
;2's complement HL ==> HL
;
NEG:
NOT BX
PUSHF
INC BX
POPF
RET
;
;HL/2 ==> HL
;
ROTRHL: OR AL,AL
MOV AL,BH
RCR AL,1
MOV BH,AL
MOV AL,BL
RCR AL,1
MOV BL,AL
RET
;
;Collect the number of '1' bits
;in A as a count in C
;
COLECT: MOV CH,8
;
COLOP: RCL AL,1
JAE COSKIP
INC CL
;
COSKIP: DEC CH
JNZ COLOP
RET
;
;HL-DE ==> HL
;
SUBDE:
SUB BX,DX
RET
;
;Quick Kludge multiply
;HL=DE ==> HL
;
MULT: PUSH CX
PUSH DX
XCHG BX,DX
MOV CX,DX
MOV AL,CH
OR AL,CL
JNZ MULCON
MOV BX,OFFSET 0 ;FILTER SPECIAL CASE
JMP MLDONE ; OF MULTIPLY BY 0
;
MULCON:
DEC CX
MOV DX,BX
;
MULTLP: MOV AL,CH
OR AL,CL
JZ MLDONE
ADD BX,DX
DEC CX
JMP MULTLP
;
MLDONE: POP DX
POP CX
RET
;
;Routine to fill in disk params
;with every drive change
;
LOGIT:
cmp byte ptr cpm_version,31h ;if it's ver 31 the select
jae logcal ;routine done moved DPB
MOV DX,OFFSET DPB ; THEN MOVE TO LOCAL
MOV CH,DPBLEN ; WORKSPACE
CALL MOVEFROMBIOS
;
LOGCAL: MOV BX,OFFSET GRPDIS
MOV AL,BYTE PTR [BX]
PUSH AX
MOV AL,BLM
MOV BYTE PTR [BX],AL
PUSH BX
MOV BX,DSM
XCHG BX,DX
CALL GTKSEC
MOV MAXSEC,BX
XCHG BX,DX
MOV MAXTRK,BX
POP BX
POP AX
MOV BYTE PTR [BX],AL
RET
;
;
DATAOFFSET EQU OFFSET$
DSEG
ORG DATAOFFSET
;
;
;
RW 200
STACK RW 1 ;LOCAL STACK
;
;Temporary storage area
;
BUFAD DW BASE +100H ;FORCES INITIAL READ
HEXAD DW 0 ;TO RE-FETCH A VALUE
TOGO DW 0FFFFH ;REPEAT COUNT (FFFF=CONT)
TWOUP DB 0
PFLAG DB 0 ;1=PRINT
GROUP DW 0
GRPDIS DB 0
SAVEFL DB 0
CURTRK DW 0
CURSEC DW 1
PHYSEC DW 1
TABCOL DB 0
FILECT DW 0
DIRPOS DB 0
FINDFL DB 0 ;1=MUST POSITION AFTER FIND
FTSW DB 1 ;SEARCH W/O INCREMENT
NOTPOS DB 1 ;INITIALLY NOT POSITIONED
WRFLG DB 0 ;MAY NOT WRITE UNTIL '+', '-',
; OR 'G' COMMAND
QFLAG DB 0 ;QUIET? (0=NO)
FIRST0 DB 0 ;SETS TO 0 IF FIRST SEC # IS 0
UNUM DB 0 ;USER NUMBER
DRIVE DB 0
MAXTRK DW 0
MAXSEC DW 0
SECTBL DW 0 ;POINTER TO SECTOR SKEW TABLE
;
BACK RW 1 ;TO BACK UP IN "CA0-7F,X"
DUMTYP RS 1
;
;--------------------------------------------------
bios_call_tbl rw 1 ;address of bios call table goes here
table11 dw offset select_disk11 ;direct bios calls for cp/m-11
dw offset set_track11
dw offset set_dmaseg11
dw offset set_dmaoff11
dw offset set_sector11
dw offset read_sector11
dw offset write_sector11
dw offset sector_xlat11
dw offset home_disk11
table31 dw offset select_disk31 ;direct bios calls for cp/m-31
dw offset set_track31
dw offset set_dmaseg31
dw offset set_dmaoff31
dw offset set_sector31
dw offset read_sector31
dw offset write_sector31
dw offset sector_xlat31
dw offset home_disk31
bpb rs 0 ;bios parameter block
bpb_func rb 1 ;for direct bios call 50
bpb_cx rw 1
bpb_dx rw 1
cpm_version dw 0 ;cpm version
sysaddr dw 0 ;SYSDAT addr
udaaddr dw 0 ;process UDA addr
imcnt db 1 ;multi-sector count (preset to 1)
idrive rb 1 ;drive number (a:=0)
itrack rw 1 ;track number (first track=0)
isector rw 1 ;sector number (first sector=0)
idmaseg rw 1 ;dma segment for sector buffer
idmaoff dw offset sector_buf ;dma offset for sector buffer
dmaseg rw 1 ;dma segment for data
dmaoff rw 1 ;dma offset for data
trk_sect dw 0ffffh,0 ;number of track/sector in memory
sec_xlat_tbl dw 0 ;address of BIOS xlat table
rec_offset dw 0 ;logical record offset into phy sec
; data storage for Disk Parameter Block (DPB)
;
dpb rs 0 ;17 bytes of storage
;
SPT rw 1
BSH rb 1
BLM rb 1
EXM rb 1
DSM rw 1
DRM rw 1
AL0 rb 1
AL1 rb 1
CKS rw 1
SYSTRK rw 1
PHYSHF rb 1 ;not in CP/M-86 ver 1.1
PHYMSK rb 1 ; " " " " "
;
;End of disk parameter block
wvmsg db 13,10,'Only CP/M-86 ver 1.1 & 3.1 Plus '
db 'and CCP/M ver 3.1-4.1 are Supported$'
mpmsg db 13,10,'THE MP/M OPERATING SYSTEM IS NOT SUPPORTED$'
toobig db 13,10,'SECTOR SIZE TOO BIG - ABORTING$'
sector_buf rs 2048
;--------------------------------------------------
;
SAVBUF RS 128
INBUF RS 128
;
;Directory read in here; also search work area
;
WORK EQU $
DIRECT EQU $
END