home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG008.ARK
/
DSKDIR.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
17KB
|
845 lines
;-------------------------------------------------------
;
; CP/M DISK DIRECTORY UTILITY
;
; VERSION 1.3 - 5 NOV 77
;
; WRITTEN IN TLC
;
; COPYRIGHT 1977, BY
;
; JEFFREY W. SHOOK
; P. O. BOX 185
; ROCKY POINT, NEW YORK
; 11778
;
;---------------------------------------------------
ORG 100H ; CP/M STARTS EXECUTION HERE
JMP START ;
DB 'DSKDIR VERSION 1.1',CR,LF
DB CR,LF
DB 'COPYRIGHT 1977',CR,LF
DB CR,LF
DB 'JEFFREY W. SHOOK',CR,LF
DB 'PO BOX 185',CR,LF
DB 'ROCKY POINT, NEW YORK',CR,LF
DB '11778',CR,LF,0
;
; $DECLARE.CONSTANT
;
BDOS: EQU 5 !
CR: EQU 0DH !
LF: EQU 0AH !
!
; * FILE CONTROL BLOCK OFFSET VALUES
;
ENTRYP: EQU 0 ; ENTRY.TYPE = 0
FILNAM: EQU 1 ; FILE.NAME = 1
FILTYP: EQU 9 ; FILE.TYPE = 9
EXTNT: EQU 12 ; EXTENT = 12
RECCNT: EQU 15 ; RECORD.COUNT = 15
DSKMAP: EQU 16 ; DISK.MAP = 16
NXTREC: EQU 32 ; NEXT.RECORD = 32
;
SECSIZ: EQU 128 ; SECTOR.SIZE(2) = 128
DIRSEC: EQU 16 ; DIRECT.SECTORS(1) = 16
MAXENT: EQU 64 ; MAX.ENTRY(1) = 64
FALSE: EQU 0 ; FALSE(1) = 0
TRUE: EQU 0FFH ; TRUE(1) = 0FFH
TFCB: EQU 05CH ; TFCB(2) = 05CH
NAMLEN: EQU 11 ; NAME.LENGTH(1) = 11
ENTLEN: EQU 32 ; ENTRY.LENGTH(1) = 32
;
; $DECLARE.LOGICAL
;
REDERR: DS 1 ; READ.ERROR(1)
ENTUSD: DS MAXENT ; ENTRY.USED(MAX.ENTRY)
NAMEOK: DS 1 ; NAME.OK(1)
SAMNAM: DS 1 ; SAME.NAME(1)
BLNKNM: DS 1 ; BLANK.NAME(1)
;
; $DECLARE.VARIABLE
;
ENTRY: DS 1 ; ENTRY(1)
ENTNUM: DS 1 ; ENTRY.NUM(1)
ENTPTR: DS 2 ; ENTRY.POINTER(2)
TENPTR: DS 2 ; TEMP.ENTRY.PTR(2)
PRONAM: DS 11 ; PROTO.NAME(11)
CHRCNT: DS 1 ; CHAR.COUNT(1)
; BUFFER(DIRECT.SECTORS * SECTOR.SIZE)
BUFFER: DS DIRSEC * SECSIZ
DMADDR: DS 2 ; DMA.ADDRESS(2)
TRACK: DS 1 ; TRACK(1)
RECORD: DS 1 ; RECORD(1)
FILSIZ: DS 2 ; FILE.SIZE(2)
FILEXT: DS 2 ; FILE.EXTENTS(2)
TMPENT: DS 1 ; TEMP.ENTRY(1)
TOTSIZ DS 2 ; TOTAL.SIZE(2)
TOTEXT: DS 2 ; TOTAL.EXTENTS(2)
NAMEA: DS 2 ; NAME.A(2)
NAMEB: DS 2 ; NAME.B(2)
USDPTR: DS 2 ; USED.POINTER(2)
LZRO: DS 1 ; LEAD.ZERO.SUPRESS(1)
STPSAV: DS 2 ; CP/M.STACK.PTR(2)
DS 248 ; STACK.AREA(248)
STACK: DS 2 ; STACK.START(2)
;
; $DECLARE.END
;
;--------------------------------------
;
START: ; * DISK DIRECTORY UTILITY
;
LXI SP,STACK; INITIALIZE.STACK.POINTER
CALL GPFNFT ; GET.PROTOTYPE.FILE.NAME.FROM.TFCB
CALL RDFDIB ; READ.DIRECTORY.FROM.DISK.INTO.BUFFER
LDA REDERR ; IF READ.ERROR
CPI FALSE !
JZ ELSE01 !
CALL PREM ; PRINT.READ.ERROR.MESSAGE
JMP FI01 ; ELSE
ELSE01: !
LXI H,0 ; TOTAL.SIZE = 0
SHLD TOTSIZ !
LXI H,0 ; TOTAL.EXTENTS = 0
SHLD TOTEXT !
CALL IEUF ; INITIALIZE.ENTRY.USED.FLAGS
CALL PDH ; PRINT.DIRECTORY.HEADING
MVI A,0 ; ENTRY = 0
STA ENTRY !
LOOP01: ; LOOP
LXI D,ENTUSD; . IF (ADDR[ENTRY.USED] + ENTRY) = FALSE
LXI H,ENTRY !
MOV L,M !
MVI H,0 !
DAD D !
MOV A,M !
CPI FALSE !
JNZ FI02 !
CALL CETPN ; . . COMPARE.ENTRY.TO.PROTOTYPE.NAME
LXI H,NAMEOK; . . IF NAME.OK
MOV A,M !
CPI TRUE !
JNZ FI03 !
CALL PEWSFN ; . . . PROCESS.ENTRYS.WITH.SAME.FILE.NAME
CALL PFIL ; . . . PRINT.FILE.INFORMATION.LISTING
FI03: ; . . FI
FI02: ; . FI
LXI H,ENTRY ; . ENTRY = ENTRY + 1
INR M !
LXI H,ENTRY ; . EXIT.IF ENTRY >= MAX.ENTRY
MOV A,M !
CPI MAXENT !
JP POOL01 !
JMP LOOP01 ; POOL
POOL01: !
CALL PTL ; PRINT.TOTALS.LISTING
FI01: ; FI
JMP WBOOT ; RETURN.TO.CP/M
;
;
;--------------------------------------
;
GPFNFT: ; $ GET.PROTOTYPE.FILE.NAME.FROM.TFCB
;
LXI H,CHRCNT; CHAR.COUNT = NAME.LENGTH
MVI M,NAMLEN!
LXI H,PRONAM; NAME.A = ADDR[PROTOTYPE.NAME]
SHLD NAMEA !
; NAME.B = TFCB + FILE.NAME
LXI H,TFCB+FILNAM
SHLD NAMEB !
LXI H,BLNKNM; BLANK.NAME = TRUE
MVI M,TRUE !
LOOP02: ; LOOP
LHLD NAMEB ; IF (NAME.B <> " "
MOV A,M !
CPI ' ' !
JZ FI09 !
LXI H,BLNKNM; BLANK.NAME = FALSE
MVI M,FALSE !
FI09: ; FI
LHLD NAMEB ; (NAME.A) = (NAME.B)
MOV A,M !
LHLD NAMEA !
MOV M,A !
LHLD NAMEA ; NAME.A = NAME.A + 1
INX H !
SHLD NAMEA !
LHLD NAMEB ; NAME.B = NAME.B + 1
INX H !
SHLD NAMEB !
LXI H,CHRCNT; CHAR.COUNT = CHAR.COUNT - 1
DCR M !
LXI H,CHRCNT; EXIT.IF CHAR.COUNT <= 0
MOV A,M !
CPI 0 !
JZ POOL02 !
JMP LOOP02 ; POOL
POOL02: !
IF10: LXI H,BLNKNM; IF BLANK.NAME = TRUE
MOV A,M
CPI TRUE !
JNZ FI10 !
LXI H,PRONAM; NAME.A = PROTOTYPE.NAME
SHLD NAMEA !
LXI H,CHRCNT; CHAR.COUNT = NAME.LENGTH
MVI M,NAMLEN!
LOOP07: ; LOOP
LHLD NAMEA ; (NAME.A) = "?"
MVI M,'?' !
LHLD NAMEA ; NAME.A = NAME.A + 1
INX H !
SHLD NAMEA !
LXI H,CHRCNT; CHAR.COUNT = CHAR.COUNT - 1
DCR M !
LXI H,CHRCNT; EXIT.IF CHAR.COUNT <= 0
MOV A,M !
CPI 0 !
JZ POOL07 !
JMP LOOP07 ; LOOP
POOL07: !
FI10: ; FI
RET ; RETURN
;
;
;--------------------------------------
;
RDFDIB: ; $ READ.DIRECTORY.FROM.DISK.INTO.BUFFER
;
LXI H,TFCB ; SELECT.DISK.FROM.TFCB.ENTRY
MOV A,M !
ORA A !
JZ TXXX !
DCR A !
MOV C,A !
MVI B,0 !
MVI A,24 !
CALL FBIOS !
TXXX: LXI H,BUFFER; DMA.ADDRESS = ADDR[BUFFER]
SHLD DMADDR !
LXI H,TRACK ; TRACK = 2
MVI M,2 !
LXI H,RECORD; RECORD = 1
MVI M,1 !
MVI A,27 ; SET.DISK.TRACK
LXI H,TRACK !
MOV C,M !
MVI B,0 !
CALL FBIOS !
LOOP03: ; LOOP
MVI A,33 ; SET.DMA.ADDRESS
LHLD DMADDR !
MOV B,H !
MOV C,L !
CALL FBIOS !
LXI H,RECORD; SET.NEXT.SECTOR
MOV C,M !
CALL RECSEC !
MVI A,30 !
CALL FBIOS !
MVI A,36 ; READ.ONE.RECORD
CALL FBIOS !
CPI FALSE ; SET.READ.ERROR.FLAG
JZ RDFDI1 !
MVI A,TRUE !
RDFDI1: LXI H,REDERR!
MOV M,A !
LXI H,REDERR; EXIT.IF READ.ERROR
MOV A,M !
CPI TRUE !
JZ POOL03 !
LXI D,SECSIZ; DMA.ADDRESS = DMA.ADDRESS + SECTOR.SIZE
LHLD DMADDR !
DAD D !
SHLD DMADDR !
LXI H,RECORD; RECORD = RECORD + 1
INR M !
LXI H,RECORD; EXIT.IF RECORD > DIRECT.SECTORS
MOV A,M !
CPI DIRSEC+1!
JP POOL03 !
JMP LOOP03 ; POOL
POOL03: !
RET ; RETURN
;
;
;--------------------------------------
;
PREM: ; $ PRINT.READ.ERROR.MESSAGE
;
RET ; RETURN
;
;
;--------------------------------------
;
IEUF: ; $ INITIALIZE.ENTRY.USED.FLAGS
;
LXI H,ENTNUM; ENTRY.NUM = 0
MVI M,0 !
LXI H,BUFFER; ENTRY.PTR = ADDR[BUFFER]
SHLD ENTPTR !
LOOP04: ; LOOP
LHLD ENTPTR; IF (ENTRY.PTR) = 0
MOV A,M !
CPI 0 !
JNZ ELSE04 !
LXI H,ENTNUM; (ADDR[ENTRY.USED] + ENTRY.NUM) = FALSE
MOV E,M !
MVI D,0 !
LXI H,ENTUSD!
DAD D !
MVI M,FALSE !
JMP FI04 ; ELSE
ELSE04: !
LXI H,ENTNUM; (ADDR[ENTRY.USED] + ENTRY.NUM) = TRUE
MOV E,M !
MVI D,0 !
LXI H,ENTUSD!
DAD D !
MVI M,TRUE !
FI04: ; FI
LXI H,ENTNUM; ENTRY.NUM = ENTRY.NUM + 1
INR M !
LXI D,ENTLEN; ENTRY.PTR = ENTRY.PTR + ENTRY.LENGTH
LHLD ENTPTR !
DAD D !
SHLD ENTPTR !
LXI H,ENTNUM; EXIT.IF ENTRY.NUM >= MAX.ENTRY
MOV A,M !
CPI MAXENT !
JP POOL04 !
JMP LOOP04 ; POOL
POOL04: !
RET ; RETURN
;
;
;
;--------------------------------------
;
PDH: ; PRINT.DIRECTORY.HEADING
;
MVI C,9 ; PRINT "FILE.NAME SIZE SECTORS EXTS"
LXI D,MSG1 !
CALL BDOS !
RET ; RETURN
MSG1: DB 'FILE.NAME BYTES SCTRS EXTS'
DB 0DH,0AH,0DH,0AH,'$'
;
;
;--------------------------------------
;
CETPN: ; $ COMPARE.ENTRY.TO.PROTOTYPE.NAME
;
LXI H,PRONAM; NAME.A = ADDR[PROTO.NAME]
SHLD NAMEA !
LDA ENTRY ; NAME.B = ADDR[BUFFER] + ENTRY.LENGTH * ENTRY + FILE.NAME
LXI D,ENTLEN!
CALL MULT8 !
LXI D,BUFFER+FILNAM!
DAD D
SHLD NAMEB !
CALL CFN ; COMPARE.FILE.NAMES
RET ; RETURN
;
;
;--------------------------------------
;
CTNTEN: ; $ COMPARE.TEMP.NAME.TO.ENTRY.NAME
;
LDA TMPENT ; NAME.A = ADDR[BUFFER] + ENTRY.LENGTH * TEMP.ENTRY + FILE.NAME
LXI D,ENTLEN!
CALL MULT8 !
LXI D,BUFFER+FILNAM!
DAD D
SHLD NAMEA
LDA ENTRY ; NAME.B = ADDR[BUFFER] + ENTRY.LENGTH * ENTRY + FILE.NAME
LXI D,ENTLEN!
CALL MULT8 !
LXI D,BUFFER+FILNAM!
DAD D
SHLD NAMEB !
CALL CFN ; COMPARE.FILE.NAMES
RET ; RETURN
;
;
;--------------------------------------
;
CFN: ; $ COMPARE.FILE.NAMES
;
LXI H,CHRCNT; CHAR.COUNT = NAME.LENGTH
MVI M,NAMLEN!
LXI H,NAMEOK; NAME.OK = TRUE
MVI M,TRUE !
LOOP05: ; LOOP
LHLD NAMEA ; IF (NAME.A) <> "?"
MOV A,M !
CPI '?' !
JZ FI05 !
LHLD NAMEA ; . IF (NAME.A) <> (NAME.B)
MOV A,M !
LHLD NAMEB !
CMP M !
NOP
JZ FI06 !
LXI H,NAMEOK; . . NAME.OK = FALSE
MVI M,FALSE !
FI06: ; . FI
LXI H,NAMEOK; . EXIT.IF NAME.OK = FALSE
MOV A,M !
CPI FALSE !
JZ POOL05 !
FI05: ; FI
LXI H,CHRCNT; CHAR.COUNT = CHAR.COUNT - 1
DCR M !
LDA CHRCNT ; EXIT.IF CHAR.COUNT = 0
CPI 0 !
JZ POOL05 !
LHLD NAMEA ; NAME.A = NAME.A + 1
INX H !
SHLD NAMEA !
LHLD NAMEB ; NAME.B = NAME.B + 1
INX H !
SHLD NAMEB !
JMP LOOP05 ; POOL
POOL05: !
RET ; RETURN
;
;
;--------------------------------------
;
PEWSFN: ; $ PROCESS.ENTRYS.WITH.SAME.FILE.NAME
;
LXI H,0 ; FILE.SIZE = 0
SHLD FILSIZ !
LXI H,0 ; FILE.EXTENTS = 0
SHLD FILEXT !
LDA ENTRY ; TEMP.ENTRY = ENTRY
STA TMPENT !
LDA ENTRY ; ENTRY.POINTER = ADDR[BUFFER] + ENTRY * ENTRY.LENGTH
LXI D,ENTLEN!
CALL MULT8 !
LXI D,BUFFER
DAD D !
SHLD ENTPTR !
LHLD ENTPTR ; TEMP.ENTRY.PTR = ENTRY.POINTER
SHLD TENPTR !
LXI H,ENTRY; USED.POINTER = ADDR[ENTRY.USED] + ENTRY
MOV L,M !
MVI H,0 !
LXI D,ENTUSD!
DAD D !
SHLD USDPTR !
LOOP06: ; LOOP
LHLD USDPTR ; IF (USED.POINTER) = FALSE
MOV A,M !
CPI FALSE !
JNZ FI07 !
CALL CTNTEN ; . COMPARE.TEMP.NAME.TO.ENTRY.NAME
LDA NAMEOK ; . IF NAME.OK
CPI TRUE !
JNZ FI08 !
LXI D,RECCNT; . . FILE.SIZE = FILE.SIZE + (TEMP.ENTRY.PTR + RECORD.COUNT)
LHLD ENTPTR !
DAD D !
MOV E,M !
MVI D,0 !
LHLD FILSIZ !
DAD D !
SHLD FILSIZ !
LHLD FILEXT ; . . FILE.EXTENTS = FILE.EXTENTS + 1
INX H !
SHLD FILEXT !
LHLD USDPTR; . . (USED.POINTER) = TRUE
MVI M,TRUE !
FI08: ; . FI
FI07: ; FI
LXI H,TMPENT; TEMP.ENTRY = TEMP.ENTRY + 1
INR M !
LXI H,TMPENT; EXIT.IF TEMP.ENTRY >= MAX.ENTRY
MOV A,M !
CPI MAXENT !
JP POOL06 !
LXI D,ENTLEN; TEMP.ENTRY.PTR = TEMP.ENTRY.PTR + ENTRY.LENGTH
LHLD TENPTR !
DAD D !
SHLD TENPTR !
LHLD USDPTR ; USED.POINTER = USED.POINTER + 1
INX H !
SHLD USDPTR !
JMP LOOP06 ; POOL
POOL06: !
LHLD FILSIZ ; TOTAL.SIZE = TOTAL.SIZE + FILE.SIZE
XCHG !
LHLD TOTSIZ !
DAD D !
SHLD TOTSIZ !
LHLD FILEXT ; TOTAL.EXTENTS = TOTAL.EXTENTS + FILE.EXTENTS
XCHG !
LHLD TOTEXT !
DAD D !
SHLD TOTEXT !
RET ; RETURN
;
;
;
;--------------------------------------
;
PFIL: ; $ PRINT.FILE.INFORMATION.LISTING
;
LHLD ENTPTR ; PRINT FILE.NAME(11)
INX H !
MVI B,8 !
CALL PRNC !
CALL PRS !
MVI B,3 !
CALL PRNC !
CALL PRS !
CALL PRS !
CALL PRS !
LXI H,DATA ; PRINT FILE.SIZE * SECTOR.SIZE
CALL CLEAR !
LHLD FILSIZ !
SHLD DATA+1 !
LXI H,DATA !
CALL SHIFTR !
CALL BINBCD !
LXI H,RESULT+2
CALL PR6HXD !
CALL PRS !
CALL PRS !
CALL PRS !
LXI H,DATA ; PRINT FILE.SIZE
CALL CLEAR !
LHLD FILSIZ !
SHLD DATA !
CALL BINBCD !
LHLD RESULT !
CALL PRADDR !
CALL PRS !
CALL PRS !
CALL PRS !
LXI H,DATA ; PRINT FILE.EXTENTS
CALL CLEAR !
LHLD FILEXT !
SHLD DATA !
CALL BINBCD !
LHLD RESULT !
CALL PRADDR !
CALL PRCRLF !
RET ; RETURN
;
;
;
;--------------------------------------
;
PTL: ; $ PRINT.TOTALS.LISTING
;
CALL PRCRLF !
MVI C,9 ;PRINT "TOTAL.SIZE "
LXI D,MSG2 !
CALL BDOS !
LXI H,DATA ; PRINT TOTAL.SIZE * SECTOR.SIZE
CALL CLEAR !
LHLD TOTSIZ !
SHLD DATA+1 !
LXI H,DATA !
CALL SHIFTR !
CALL BINBCD !
LXI H,RESULT+2
CALL PR6HXD !
CALL PRS !
CALL PRS !
CALL PRS !
LXI H,DATA ; PRINT TOTAL.SIZE
CALL CLEAR !
LHLD TOTSIZ !
SHLD DATA !
CALL BINBCD !
LHLD RESULT !
CALL PRADDR !
CALL PRS !
CALL PRS !
CALL PRS !
LXI H,DATA ; PRINT TOTAL.EXTENTS
LHLD TOTEXT !
SHLD DATA !
CALL BINBCD !
LHLD RESULT !
CALL PRADDR !
CALL PRCRLF !
RET ; RETURN
MSG2: DB 'TOTAL.SIZE ','$'
;
;
;-----------------------------------------------
;
; BINARY TO BCD CONVERSION
;
;-----------------------------------------------
; ASSUMES THREE REGISTERS IN MEMORY:
; 1) DATA - CONTAINS UNSIGNED BINARY NUMBER
; 2) PARTIAL - PACKED BCD NUMBER = 2**N
; 3) RESULT - PACKED BCD NUMBER = SUM OF PARTIAL VALUES
NBYTES: EQU 3 ; REGISTER LENGTH
NBITS: EQU NBYTES*8; NUMBER OF BITS CONVERTED
BITCNT: DS 1 ; BITS REMAINING TO BE CONVERTED
RESULT: DS NBYTES ; RESULT REGISTER
PARTL: DS NBYTES ; PARTIAL REGISTER
DATA: DS NBYTES ; BINARY DATA REGISTER
BINBCD: LXI H,BITCNT; SET BIT COUNT
MVI M,NBITS
LXI H,RESULT; CLEAR RESULT REGISTER
CALL CLEAR
LXI H,PARTL ; CLEAR PARTIAL SUM REG
CALL CLEAR
LXI H,PARTL ; SET PARTIAL = 1
MVI M,1
BINBC1: ORA A ; CLEAR CARRY
LXI H,DATA ; SHIFT DATA RIGHT
CALL SHIFTR
JNC BINBC2 ; SKIP ADD IF BIT WAS 0
LXI H,PARTL ; ADD POWER OF 2 TO RESULT
LXI D,RESULT
CALL BCDADD
BINBC2: LXI H,PARTL ; DOUBLE PARTIAL
LXI D,PARTL
CALL BCDADD
LXI H,BITCNT; CHECK BIT COUNT
DCR M
JNZ BINBC1 ; DONE?
RET
; CLEAR A REGISTER
; ADDR IN HL
CLEAR: MVI B,NBYTES; CLEAR A REGISTER
CLEAR1: MVI M,0
INX H
DCR B
JNZ CLEAR1
RET
; SHIFT RIGHT WITH CARRY
; ADDR IN HL
SHIFTR: RAL ; SAVE CARRY IN A
MVI B,NBYTES; CALCULATE ADDR OF LAST BYTE
MOV E,B
DCR E
MVI D,0
DAD D
SHIFR1: RAR ; RESTORE SAVED CARRY
MOV A,M
RAR ; SHIFT DATA
MOV M,A
RAL ; SAVE CARRY
DCX H ; MOVE TO NEXT BYTE
DCR B ; CHECK BYTE COUNT
JNZ SHIFR1 ; DONE?
RAR ; RESTORE CARRY
RET
; BCD ADDITION
; ADDS REGISTER AT ADDR IN HL
; TO CONTENTS OF REGISTER AT ADDR DE
BCDADD: MVI B,NBYTES
XRA A ; CARRY = 0
BCDAD1: RAR ; RESTORE CARRY
LDAX D
ADC M
DAA
STAX D
RAL ; SAVE CARRY
INX D
INX H
DCR B
JNZ BCDAD1
RAR ; RESTORE CARRY
RET
;***********************************************
;
; CONVERT CP/M RECORD NUMBER TO DISK SECTOR
;
; ENTER WITH RECORD IN C, AND
; RETURN WITH SECTOR IN C.
; DESTROY CONTENTS OF B,HL
;
;**********************************************
; COMPUTE TABLE ADDRESS OF SECTOR
RECSEC: LXI H,SECTBL-1
MVI B,0
DAD B
MOV C,M
RET
; RECORD TO SECTOR CONVERSION TABLE
SECTBL: DB 1,7,13,19,25,5,11,17
DB 23,3,9,15,21,2,8,14
DB 20,26,6,12,18,24,4,10
DB 16,22
;******************************************
;* HEXIDECIMAL CHARACTER OUTPUT LIBRARY *
;******************************************
;
; VERSION 0.2 19 APR 77
;
PRHL: MOV A,C
RAR
RAR
RAR
RAR
JMP PRHR1
PRHR: MOV A,C
PRHR1: ANI 0FH
ADI '0'
CPI '9'+1
JM PRA
ADI '@'-'9'
PRA: PUSH B
MOV B,A
LDA LZRO
ORA A
JZ PRA1
MOV A,B
CPI '0'
JNZ PRA1
MVI B,20H
JMP PRA2
PRA1: MVI A,0
STA LZRO
PRA2: MOV A,B
POP B
PUSH H ! PUSH D ! PUSH B
MOV E,A
MVI C,2
CALL BDOS
POP B ! POP D ! POP H
RET
;
;
PR2HX: MOV C,M
INX H
PR2H: CALL PRHL
JMP PRHR
;
;
PR2HXS: CALL PR2HX
PRS: MVI A,' '
JMP PRA
;
;
PRADDR: MVI A,TRUE
STA LZRO
MOV C,H
CALL PR2H
MOV C,L
JMP PR2H
;
;
PR6HXD: MVI A,TRUE
STA LZRO
CALL PR2HXD
CALL PR2HXD
CALL PR2HXD
RET
PR2HXD: MOV C,M
DCX H
JMP PR2H
PRNC: MOV A,M
CALL PRA
INX H
DCR B
JNZ PRNC
RET
PRCRLF: PUSH H ! PUSH D ! PUSH B
LXI D,CRSTRG
MVI C,9
CALL BDOS
POP B ! POP D ! POP H
RET
;
;
CRSTRG: DB 0DH,0AH,0,0,'$'
;
;******************************************
;----------------------------------------------
;
; UNSIGNED 8 BIT MULTIPLY
;
;-----------------------------------------------
; ENTER WITH:
; MULTIPLIER IN A
; MULTIPLICAND IN DE
; RETURN WITH:
; PRODUCT IN HL
; DESTROYS:
; A, DE
MULT8: LXI H,0 ; CLEAR PARTIAL PRODUCT
MULT1: ORA A ; CLEAR CARRY
RAR ; SHIFT MULTPLR RIGHT
JNC MULT2 ; SKIP IF ZERO
DAD D ; ADD MPLCND TO PARTIAL
MULT2: XCHG ;
DAD H ; SHIFT MLTPCND LEFT
XCHG ;
ORA A ; SET FLAGS
JNZ MULT1 ; LOOP UNTIL DONE
RET ;
;******************************************
;* BIOS FUNCTION CALLING PROCEDURE *
;******************************************
;
; THIS PROCEDURE ALLOWS CALLING BIOS
; FUNCTIONS WITHOUT PRIOR KNOWLEDGE OF THE
; SIZE OF THE CP/M SYSTEM.
;
; CALL FBIOS WITH THE FUNCTION IN A
; AND THE PARAMETER IN BC.
;
FBIOS: MOV E,A ; GET ENTRY OFFSET
MVI D,0 ; IN DE
LHLD 1 ; GET BIOS ENTRY + 3
DAD D ; ADD ENTRY TO OFFSET
PCHL ; JUMP TO BIOS
;
; BIOS ENTRY CODE NAMES
;
WBOOT: EQU 0 ; WARM BOOT
CONST: EQU 3 ; TEST CONSOLE STATUS
CONIN: EQU 6 ; CONSOLE INPUT
CONOUT: EQU 9 ; CONSOLE OUTPUT
LIST: EQU 12 ; LIST OUTPUT
PUNCH: EQU 15 ; PUNCH OUTPUT
READER: EQU 18 ; READER INPUT
HOME: EQU 21 ; HEAD TO TRACK 0
SELDSK: EQU 24 ; SELECT DRIVE
SETTRK: EQU 27 ; SET NEXT TRACK
SETSEC: EQU 30 ; SET NEXT SECTOR
SETDMA: EQU 33 ; SET DMA ADDRESS
READS: EQU 36 ; READ SECTOR
WRITES: EQU 39 ; WRITE SECTOR
;
;
END ; END