ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-ACPMUG °8ACATALOG ё ALLOC ГOMBANNER БSM/ BINLOAD1БSM2 BIOSGO МIBBPNF БSM BSPAT16BБSMR TARBELL CONTROLLER, OR ONE USING SAME CONTROLLER CHIP 8.16 2K GO.ASM SAY "GO FF00" AND AS IF BY MAGIC.... USEFUL IF NO FRONT PANEL AVAILABLE. 8.17 2K INNUM1.LIB VARIABLE RADIX NUMBER INPUT ROUTINE. NEEDS MPY8.LIB BELOW AND A CHARACTER FREE FOR A FULL ONE. A PATCHED VERSION PLUS SOURCE HAS BEEN PROMISED] 8.2 6K BANNER.ASM PUTS LARGE LETTERS TO LST: OR PUN: USEFUL TO IDENTIFY LISTING PRINTOUTS 8.3 7K BINLOAD1.ASM PROGRAM TO READ DISK DATA FROM ABSOLUTE SECTOR ADDRESееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее SIZES 8.12 1K DIVIDE1.LIB ROUTINE TO DIVIDE 2 BYTE QUANTITY BY ONE BYTE DIVISOR WITH REMAINDER 8.13 17K DSKDIR.ASM SENDS TO CONSOLE FULL SIZE (DECIMAL), NUMBER OF RECORDS AND EXTENTS OF FILES. ACCEPTS GENERAL COMMANDS "DSKDIR N:*.TYP" ETееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееBYTEMOV БSM DDTPATCHБSM DISKDUP БSMA !"#$%&'(DISKIN МIB )*DISKTES1БSM2+,-./01DIVIDE1 МIB2DSKDIR БSMЂ3456789:;<=>?@ABDSKDIR БSMCO ECHO AS A BACKSPACE AND ACT AS A RUB OUT FOR CP/M VERSION 1.3 8.7 4K BYTEMOV.ASM BYTESAVER PROM BURNING PROGRAM 8.8 2K DDTPATCH.ASM PATCH TO CORRECT ASSEMBLER ERRORS IN DDT. THIS ONE IS DIFFERENT - IT WORKS!! 8.9 9K DISKDUP.ASM THIS ISSES TO MEMORY 8.4 2K BIOSGO.LIB PRETTY VERSION OF #1.14. PUTS A DUMMY BIOS JUMP TABLE WHERE A PROGRAM NEEDS IT 8.5 2K BPNF.ASM PROGRAM TO PUNCH STANDARD BPNF PROM TAPE FOR AREA IN MEMORY 8.6 2K BSPAT16B.ASM PATCH TO PERMIT I.E. (CTL H) TееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееC. 8.14 8K FMAP.ASM SENDS TO CONSOLE QUANTITY AND RECORD NUMBER OF GROUPS (CLUSTERS?) ON LOGGED-IN DISK. BUG- IT IGNORES GROUPS AFTER FIRST EXTENT. ALSO CREATES DISK FILE OF FILE NAMES IF DESIRED 8.15 4K FORMAT1.ASM DISKETTE FORMATTER FOVOLUME 8 VARIOUS CP/M UTILITY PROGRAMS NUMBER SIZE NAME COMMENTS CATALOG.8 CONTENTS OF CP/M CROUP VOL 8 8.1 1K ALLOC.COM GRAPHIC DISPLAY OF DISK USAGE [MINOR BUG IS THAT THE 32 BY 8 MATRIX SHOWS 2K USED FOR AN EMPTY DISK AND 13KFMAP БSM0К#<НA{_ТК:zжМ:Г> НA> ЕХе_НбСБЙееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееEC.LIB ROUTINE TO TRANSLATE CP/M RECORD (GROUP-CLUSTER) NUMBER TO DISKETTE SECTOR ADDRESS 8.25 4K SYMPRT.ASM PROGRAM TO PRINT THE SYMBOL TABLE REMAINING IN MEMORY AFTER RUNNING BASIC-E COMPILER K2.0 8.26 2K WYLECON2.LIB ROUTINE TO TRANSLATE WYL ORG 100H ; ; ;************************************************* ;*** *** ;*** B A N N E R P R I N T & P U N C H *** ;*** *** ;*******ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее MVI C,'?' CALL CONOUT CALL CRLF JMP WHICHONE CBAN: CALL CRLF MVI D, 40H LXI H, BUFF SHLD BADR MOV A,H MOV B,L LXI H, BADR MOV M,B INX H MOV M,A MOV H,A MOV L,B CB1: SHLD CADR MOV A DB 7FH,49H,49H,49H,41H DB 7FH,48H,48H,48H,40H DB 7FH,41H,41H,49H,4FH DB 7FH,08H,08H,08H,7FH DB 41H,7FH,41H,80H,80H DB 03H,01H,01H,01H,7FH DB 7FH,08H,14H,22H,41H DB 7FH,01H,01H,01H,01H DB 7FH,20H,10H,20H,7FH DB 7FH,30H,0B MOV C,B CALL CONOUT CALL CONOUT CALL CONOUT POP B RET CRLF: MVI C, CR CALL CONOUT MVI C, LF JMP CONOUT PCH: MVI C,5 PCH1: SHLD GADR MOV A,H MOV B,L LXI H, GADR MOV M,B INX H DR MOV A,H MOV B,L LXI H,BADR MOV M,B INX H MOV M,A MOV H,A MOV L,B CALL CRLF MVI D, 40H LB1: LHLD BADR LXI H,BADR MOV A,M INX H MOV H,M MOV L,A LB2: MOV A,M CPI CR JZ EOL DB 21H,43H,45H,49H,31H DB 22H,41H,49H,49H,36H DB 0CH,14H,24H,7FH,04H DB 7AH,49H,49H,49H,46H DB 3EH,49H,49H,49H,26H DB 43H,44H,48H,50H,60H DB 36H,49H,49H,49H,36H DB 30H,49H,49H,49H,3EH DB 12H,80H,80H,80H,80H DB 13H,80H,80D 0FFH MOV L,A MVI A, GRAF SHR 8 ACI 0 MOV H,A RET CNVER: ADI 0FFH RET BCH: MVI C,5 BCH1: SHLD GADR MOV A,H MOV B,L LXI H, GADR MOV M,B INX H MOV M,A MOV H,A MOV L,B MOV A,M ,H MOV B,L LXI H, CADR MOV M,B INX H MOV M,A MOV H,A MOV L,B CALL CONIN CPI CNTRLC JZ GOSYS MOV E,A LHLD CADR LXI H, CADR MOV A,M INX H MOV H,M MOV L,A MOV A,E MOV M,A CPI CR H JMP PUNCH CONOUT: PUSH H!PUSH B!PUSH D MOV E,C MVI C, OUTF CALL BDOS POP D!POP B!POP H RET CONIN: JMP 3E09H PUNCH: PUSH H!PUSH B!PUSH D MOV E, C MVI C, PUNF CALL BDOS POP D!POP B!POP H RET MOV M,A MOV H,A MOV L,B MOV A,M ANA A JM PCH2 MOV B,A PUSH B MOV C,B CALL PUNCH POP B LXI H, GADR MOV A,M INX H MOV H,M MOV L,A INX H DCR C JNZ PCH1 PCH2: MVI C,0 CALL PUNC CALL CONV CNC BCH LXI H, CADR MOV A,M INX H MOV H,M MOV L,A INX H JMP LB2 EOL: CALL CRLF MOV A,D RAR ANI 7FH RZ MOV D,A JMP LB1 CPBN: CALL CONIN CPI CNTRLC JZ GOSYS CALL COH,80H,80H DB 08H,14H,22H,41H,41H DB 14H,14H,14H,80H,80H DB 41H,41H,22H,14H,08H DB 20H,40H,45H,48H,30H DB 7FH,40H,4FH,41H,7FH DB 3FH,48H,48H,48H,3FH DB 7FH,49H,49H,49H,36H DB 7FH,41H,41H,41H,41H DB 7FH,41H,41H,41H,3EH ANA A JM BCH3 MOV B,E ANA D JNZ BCH2 MVI B, ' ' BCH2: PUSH B MOV C,B CALL CONOUT POP B LXI H, GADR MOV A,M INX H MOV H,M MOV L,A INX H DCR C JNZ BCH1 BCH3: MVI B,' ' PUSH JZ EOP CALL CONV JC CB1 CALL BCH LXI H, CADR MOV A,M INX H MOV H,M MOV L,A INX H JMP CB1 GOSYS: RET EOP: CALL EOL CALL CRLF CALL CRLF JMP CBAN LBAN: MOV H,B MOV L,C SHLD BA GRAF: DB 00H,00H,00H,00H,00H DB 14H,08H,14H,80H,80H DB 08H,1CH,08H,80H,80H DB 03H,80H,80H,80H,80H DB 08H,08H,08H,80H,80H DB 01H,80H,80H,80H,80H DB 03H,04H,08H,10H,60H DB 3EH,41H,41H,41H,3EH DB 11H,31H,7FH,01H,01H MOV B,L LXI H, CADR MOV M,B INX H MOV M,A MOV H,A MOV L,B MOV A,E SUI ' ' RC JZ FND SUI '*'-' ' RC CPI 'Z'+1-'*' JNC CNVER ADI 1 MOV B,A ADD A! ADD A ADD B FND: ADI GRAF ANNV CNC PCH JMP CPBN PBAN: MOV H,B MOV L,C PB1: MOV A,M CPI CR RZ CALL CONV CNC PCH LXI H, CADR MOV A,M INX H MOV H,M MOV L,A INX H JMP PB1 CONV: MOV E,A SHLD CADR MOV A,H8H,06H,7FH DB 7FH,41H,41H,41H,7FH DB 7FH,48H,48H,48H,78H DB 7FH,41H,45H,43H,7FH DB 7FH,48H,4CH,4AH,79H DB 32H,49H,49H,49H,26H DB 40H,40H,7FH,40H,40H DB 7FH,01H,01H,01H,7FH DB 70H,0CH,03H,0CH,70H DB 7FH,02H,04H,02H,7FH IOS CPI 0 JNZ READR2 ; COMPUTE NEXT RECORD AND TRACK LXI H,RECORD; INCREMENT RECORD # INR M MOV A,M ; CHECK FOR END OF TRACK CPI 27 JM READR1 MVI M,1 ; SET TO FIRST RECORD LXI H,TRACK ; INCREMENT TRACK # INR M MOV A,M CPI 78 LL INADDR ; INPUT # SECTORS TO READ SHLD RCOUNT MVI C,WCONB ; REQUEST STARTING ADDRESS LXI D,MSG5 CALL BDOS JMP NEXT5 MSG5: DB CR,LF,0,'STARTING ADDRESS (XXXX)? ','$' NEXT5: CALL INADDR ; INPUT STARTING ADDRESS SHLD DMAADR ALLOK: MVI DB CR,LF,00H  DB 'LISTING. PLEASE TYPE WHICH DEVICE YOU WISH TO USE' DB CR,LF DB 'TYPE [ P ] FOR THE PUNCH [ C ] FOR THE CONSOLE'D SAVSP SPHL JMP BDOS ; READ RECORDS FROM DISK IN ORDER ; ; RETURN WITH CARRY SET WHEN END ; OF DISK IS REACHED. ; ; SET TRACK AND RECORD TO POINT ; TO NEXT RECORD TO BE READ. ; COUNT = 0 READR: MVI A,SETDMA; SET DMA ADDRESS LXI H,DMAAM CALL FBIOS MVI C,WCONB ; REQUEST STARTING TRACK LXI D,MSG2 CALL BDOS JMP NEXT2 MSG2: DB CR,LF,0,'STARTING POINT',CR,LF,0 DB 'TRACK (XX) ? ','$' NEXT2: CALL INBYTE ; GET TRACK # STA TRACK MVI C,WCONB ; REQUEST SECTOR # LXI D,MSG3 DB 63H,14H,08H,14H,63H DB 60H,10H,0FH,10H,60H DB 43H,45H,49H,51H,61H BADR: DS 2 CADR: DS 2 GADR: DS 2 BUFF: DS 40 DISPWORD: MOV A,M ORA A RZ INX H MOV C,A CALL CONOUT JMP DISPWORD MESSNB ; PRINT BUSY MESSAGE LXI D,MSG6 CALL BDOS JMP NEXT6 MSG6: DB CR,LF,0,'NOW LOADING FILE',CR,LF,0,'$' NEXT6: LOOP1: CALL READR ; READ ONE RECORD JC DONE LHLD DMAADR ; MOVE DMA POINTER LXI D,128 ; TO NEXT SECTOR DAD D SHLD DMAADR C,WCONB ; CHECK IF ALL OK LXI D,MSG51 CALL BDOS JMP NEXT51 MSG51: DB CR,LF,0,'LOAD FILE? (Y,N,Q) ','$' NEXT51: MVI C,RCON ; GET CHAR CALL BDOS CPI 'Q' ; QUIT? JZ GOCPM CPI 'N' ; TRY AGAIN? JZ LOADB CPI 'Y' JNZ ALLOK MVI C,WCO;----------------------------------------------- ; ; LOAD CONTIGUOUS BINARY FILE FROM DISK ; ;----------------------------------------------- ; ; VERSION 0.1 - 08 SEP 77 ; JEFFREY W. SHOOK ; ORG 100H ; CP/M ENTRY POINT LOADB: LXI H,0 ; SAVE CPDR MOV C,M INX H MOV B,M CALL FBIOS MVI A,SETTRK; SET TRACK LXI H,TRACK MOV C,M CALL FBIOS LXI H,RECORD; SET SECTOR MOV C,M CALL RECSEC ; CONVERT RECORD TO SECTOR MVI A,SETSEC CALL FBIOS MVI A,READS ; READ SECTOR CALL FB CALL BDOS JMP NEXT3 MSG3: DB CR,LF,0,'SECTOR (XX) ? ','$' NEXT3: CALL INBYTE ; GET SECTOR # STA RECORD MVI C,WCONB ; REQUEST SECTOR COUNT LXI D,MSG4 CALL BDOS JMP NEXT4 MSG4: DB CR,LF,0,'FILE SIZE, SECTORS (XXXX)? ','$' NEXT4: CAG1: DB CR,LF DB 'THIS PROGRAM WILL PRINT OR PUNCH A BANNER' DB ' ACROSS A PAPER TAPE OR LINE PRINTER' DB CR,LF DB 'LISTING. PLEASE TYPE WHICH DEVICE YOU WISH TO USE' DB CR,LF DB 'TYPE [ P ] FOR THE PUNCH [ C ] FOR THE CONSOLE' LHLD RCOUNT ; DECREMENT RECORD COUNT DCX H SHLD RCOUNT MOV A,L ; CHECK IF DONE ORA H JNZ LOOP1 DONE: MVI C,WCONB ; PRINT DONE MESSAGE LXI D,MSG7 CALL BDOS JMP NEXT7 MSG7: DB CR,LF,0,'LOAD COMPLETE',CR,LF,0,'$' NEXT7: GOCPM: LHL,CR,LF,0,'$' NEXT1: MVI C,WCONB ; REQUEST DISK # LXI D,MSG0 CALL BDOS JMP NEXT0 MSG0: DB CR,LF,0,'WHICH DISK (A OR B)? ','$' NEXT0: MVI C,RCON ; GET DISK CALL BDOS CMA ANI 1 STA DISK MVI A,SELDSK; SELECT DRIVE LXI H,DISK MOV C,/M STACK DAD SP SHLD SAVSP LXI SP,STACK; SET STACK POINTER ; INPUT INITIAL VALUES MVI C,WCONB ; PRINT PROGRAM NAME LXI D,MSG1 CALL BDOS JMP NEXT1 MSG1: DB CR,LF,0,'CONTIGUOUS FILE LOADER',CR,LF,0 DB 'ENTER ALL VALUES IN HEXIDECIMAL'; LAST TRACK? JP READR2 READR1: ORA A ; CLEAR CARRY RET READR2: STC RET RECSEC: RET ;****************************************** ;* BIOS FUNCTION CALLING PROCEDURE * ;****************************************** ; ; THIS PROCEDURE ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееS TBASE EQU 0100H ;TRANSIENT PROGRAM BASE CBASE EQU 2900H ;CCP BASE ADDRESS BDOS EQU 0005H ;CPM ENTRY POINT ;***********************************; ; CP/M FUNCTION CODES ; ;***********************************; SRSET EQU 00 ;SYSTEM R 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 ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееINPUT 4 DIGIT HEX NUMBER MOV H,A PUSH H CALL INBYTE POP H MOV L,A RET ; VARIABLE DECLARATIONS DISK: DS 1 DMAADR: DS 2 TRACK: DS 2 SECTOR: DS 1 RECORD: DS 1 RCOUNT: DS 2 SAVSP: DS 2 DS 100H STACK: DS 2 ; SYMBOL DEFINITIONS 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 ; BUFFER CSTAT EQU 11 ;CHECK CONSOLE STATUS LHEAD EQU 12 ;LIFT DISK HEAD RSDSK EQU 13 ;RESET DISK SYSTEM SDISK EQU 14 ;SELECT DISK OPEN EQU 15 ;OPEN FILE CLOSE EQU 16 ;CLOSE FILE SFRST EQU 17 ;SEARCH FIRST SNEXT EQU 18 ;SEARCH NEXT FDELT EQU 19 ;DEESET RCON EQU 01 ;READ CONSOLE WCON EQU 02 ;WRITE CONSOLE RRDR EQU 03 ;READ READER WPUN EQU 04 ;WRITE PUNCH WLST EQU 05 ;WRITE LIST ISTAT EQU 07 ;GET IOSTATUS SSTAT EQU 08 ;SET IOSTATUS WCONB EQU 09 ;WRITE CONSOLE BUFFER RCONB EQU 10 ;READ CONSOLE; ; ;********************************************** ; HEXIDECIMAL INPUT ROUTINES FOR CP/M ; ; VERSION 0.1 - 8 SEP 77 - J.W. SHOOK ;********************************************** INHEX: PUSH B ! PUSH D ! PUSH H MVI C,RCON ; INPUT CHARACTER CALLееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее CR EQU 0DH LF EQU 0AH ;***********************************; ; CP/M STANDARD EQUATES ; ;***********************************; BOOT EQU 0000H ;WARM START ADDRESS TFCB EQU 005CH ;DEFAULT FCB ADDRESS TBUF EQU 0080H ;DEFAULT BUFFER ADDRESADD 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 LETE FILE READ EQU 20 ;READ RECORD WRITE EQU 21 ;WRITE RECORD CREATE EQU 22 ;CREATE FILE RENAM EQU 23 ;RENAME FILE LOGIN EQU 24 ;GET LOGIN IDISK EQU 25 ;GET DISK NUMBER SDMA EQU 26 ;SET DMA VECTOR IALLOC EQU 27 ;GET ALLOCATION VECTOR END STC ; MARK ERROR WITH CARRY RET INBYTE: CALL INHEX ; INPUT HIGH HEX DIGIT RC ; ERROR ADD A ; SHIFT TO LEFT HALF ADD A ADD A ADD A MOV B,A ; SAVE BYTE CALL INHEX ; GET LOW HEX DIGIT RC ; ERROR ORA B RET INADDR: CALL INBYTE ; BDOS POP H ! POP D ! POP B SBI '0' ; REMOVE ASCII OFFSET JC INHEX2 CPI 10 ; DECIMAL DIGIT? JC INHEX1 SBI '@'-'9' ; REMOVE ALPHA BIAS INHEX1: CPI 16 ; TOO LARGE? JNC INHEX2 ORA A ; CLEAR CARRY RET INHEX2: XRA A ; CLEAR A ON ERROR ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; BIOS ADDRESS TRANSFER PROGRAM ; ; BIOSGO.LIB - Version 0.1 - 5 NOV 77 ; ; Jeffrey W. Shook ; P.O. Box 185 ; Rocky Point, NY 11778 ; (516) 744 7133 ; ;++++++++++++++++++++++++++++++++++++ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееNCH BPNF TAPE FOR PROM PROGRAMMING ; SPC EQU 20H CR EQU 13 LF EQU 10 RUBOUT EQU 00FFH LLEN EQU 4 ; BYTES PER LINE BDOS EQU 5 ; ORG 100H JMP START SIZE: DW 256 ; SIZE OF PROM IN BYTES ; IF IFDOS PUN: PUSH B PUSH D PUSH H MOV E,C MVIhe start of the table. ; 4) This offset is then added to the starting ; address of the BIOS jump table in the CP/M ; system, and the result is pushed onto the ; stack. ; 5) A RET instruction is executed to ; pop the address into the POP D INX H DCX D MOV A,D ORA E JNZ BYLP CALL LDR ; RST 7 ; DONE RETURN TO DDT DS 20H STACK: DS 0 LCNT: DS 1 ORG 200H ; INPUT BUFFER BUFF: DS 0 END 100H XI D,-(WBOOT+3) ; Get start of table DAD D ; Subtract table addr POP D ; Restore DE XTHL ; Restore HL, put jump addr on stack RET ; Jump to BIOS routine ++++++++++ ; This program allows access to the BIOS functions ; independent of the size of the CP/M system. ; This is accomplished in the following way: ; ; 1) The user program calls an entry in ; the BIOSGO entry table. ; 2) The call to BIN 'E' MVI D,8 MVI C,'B' CALL PUN BPLP: MOV A,E RLC MOV E,A ANI 1 MVI C,'P' JNZ BPNN MVI C,'N' BPNN: CALL PUN DCR D JNZ BPLP MVI C,'F' CALL PUN MVI C,SPC CALL PUN RET ; ; START: LXI SP,STACK CALL LDR LXI D,BUFF L C,4 CALL BDOS POP H POP D POP B RET ENDIF ; IF NOT IFDOS PUN: IN 10H ANI 10H JZ PUN MOV A,C OUT 12H RET ENDIF ; LDR: MVI B,30 MVI C,RUBOUT ; PLDR: CALL PUN DCR B JNZ PLDR ; RET ; BPNF: ; ONE BYTE IN BPNF FORM program counter. ; Control is thus transferred to the proper ; BIOS routine and the return address of ; the original caller is still on the stack. ; BIOS FUNCTION CALLING TABLE ; Be sure not to remove any entries from ; this table ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее;PROGRAM TO PUT A STANDARD BPNF ROM TAPE TO THE ;CP/M PUN: DEVICE OF THE 100H AREA IN RAM STARTING ;AT 200H ; . ; ;PROGRAM EXITS TO RST7 - I.E. RETURN TO DDT. CHANGE ;TO RST0 IF A STAND ALONE PROGRAM ; IFDOS EQU 1 ;PUT OUTPUT TO CP/M PUN: ; ; PUIOSGO in the table ; pushes the address of the next table ; entry on the stack and jumps to BIOSGO. ; 3) BIOSGO subtracts the address of the start ; of the table from the address of the ; entry point to obtain the offset from ; tHLD SIZE XCHG XRA A ; ZERO LIN CNTR STA LCNT ; BYLP: ; PUNCH ONE BYTE PUSH D PUSH H MOV E,M CALL BPNF ; LDA LCNT INR A STA LCNT CPI LLEN JM BYLN ; MVI C,CR CALL PUN MVI C,LF CALL PUN XRA A STA LCNT ; BYLN: POP H LL BIOSGO SETDMA: CALL BIOSGO READS: CALL BIOSGO WRITES: CALL BIOSGO BIOSGO: XTHL ; Get call addr in HL, save HL on stack PUSH D ; Save DE XCHG ; Move call addr to DE LHLD 1 ; Get BIOS entry address DAD D ; Add call addr to entry addr Lor the wrong function will ; be called. WBOOT: CALL BIOSGO CONST: CALL BIOSGO CONIN: CALL BIOSGO CONOUT: CALL BIOSGO LIST: CALL BIOSGO PUNCH: CALL BIOSGO READER: CALL BIOSGO HOME: CALL BIOSGO SELDSK: CALL BIOSGO SETTRK: CALL BIOSGO SETSEC: CA;--------------------------------------------------------- ; ; PROGRAM TO PATCH CP/M VERSION DSI-3.5 ; TO RECOGNIZE BACKSPACE CHARACTER IN CONSOLE INPUT. ; ; VERSION 0.2 - 5 NOV 77 ; ; JEFFREY W. SHOOK, P.O. BOX 185, ROCKY POINT, NY 11778 ; ;-----R,LF,'LAST ? ','$' NEXT4: CALL INHEX JC RANGE CPI 8 JNC RANGE INR A MOV H,A MVI L,0 DAD H DAD H LXI D,BYTSAV DAD D SHLD ENDPRM RET ERASED: LHLD BEGPRM ERASE1: MOV A,M CPI 0FFH JNZ ERASE2 INX H LDA ENDPRM+1 CMP H J--------------------------- ; SYMBOL DEFINITIONS BDOS EQU 5 ; CP/M BDOS ENTRY POINT RCON EQU 1 WCONB EQU 9 CR EQU 0DH ; ASCII CARRIAGE RETURN LF EQU 0AH ; ASCII LINE FEED STATL EQU 0FFH ; IMSAI CONSOLE STATUS LED'S BYTSAV EQU 0E000H ; BYTESAVER A,M ANI 60H JNZ LABL4 CALL OFFST + 3365H JMP OFFST + 3423H HLT HLT HLT LABL4: ; END OF PATCH ;---------------------------------------------------- ; ; SUGGESTIONS FOR INSERTION OF PATCH INTO CP/M ; ;----------------------------------URN TO CP/M SPHL JMP BDOS ; FUNCTION SUBROUTINES PTITLE: MVI C,WCONB ; PRINT PROGRAM TITLE LXI D,MSG2 CALL BDOS JMP NEXT2 MSG2: DB CR,LF,CR,LF DB 'BYTMOV VERSION 0.2',CR,LF,'$' NEXT2: RET RANGE:LXI D,MSG3 CALL PRTMSG JMP NEXTееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее---------------------------------------------------- ; DEFINITIONS SIZE EQU 16 ; SYSTEM SIZE IN DECIMAL K-BYTES OFFST EQU ( SIZE - 16 ) * 1024 DEL EQU 7FH BS EQU 08H ORG OFFST + 33E4H START: MOV A,M CPI DEL JZ LABL1 CPI BS JNZ LABL3CP/M STACK DAD SP SHLD SPSAV LXI SP,STACK MVI A,0FFH ; CLEAR CONSOLE STATUS LED'S OUT STATL CALL PTITLE ; PRINT TITLE CALL RANGE ; GET EPROM ADDRESS RANGE CALL ERASED ; CHECK IF PROMS ERASED PROG: CALL PROGRM ; BURN IN EPROMS CALL COMP START ADDRESS NPASS EQU 128 ; NUMBER OF PROGRAMMING PASSES ; THIS VALUE FOR BYTESAVER WITH ; 1.0 MSEC. PROGRAM PULSE BEGDAT EQU 1000H ; START OF DATA FOR EPROMS ; MAIN PROGRAM CODE ORG 100H ; CP/M STARTS EXECUTION HERE LXI H,0 ; SAVE ------------------ ; XX = CP/M SYSTEM SIZE IN K-BYTES ; (0) THIS PROCEEDURE ASSUMES THAT YOUR VERSION ; OF CP/M DSI 3.5 IS STORED IN SYSGEN FORMAT ; ON THE DISK AS A COM FILE. ; (1) CHANGE SIZE AT THE START OF THIS PROGRAM ; TO TH3 MSG3: DB CR,LF,'EPROM SOCKET POSITION (0 - 7)',CR,LF DB 'FIRST? ','$' NEXT3: CALL INHEX JC RANGE CPI 8 JNC RANGE MVI L,0 MOV H,A DAD H DAD H LXI D,BYTSAV DAD D SHLD BEGPRM LXI D,MSG4 CALL PRTMSG JMP NEXT4 MSG4: DB C;---------------------------------------------------- ; ; BYTESAVER EPROM PROGRAMMER CONTROL PROGRAM ; ; VERSION 0.2 - 10 SEP 77 ; ; COPYRIGHT 1977 ; ; JEFFREY W. SHOOK ; P. O. BOX 185 ; ROCKY POINT, NEW YORK 11778 ; ;-------------------------- LABL1: MOV E,A XRA A DCR L SUB M JNC OFFST + 3436H DCR M MOV A,M ADI 02 MOV C,A MVI B,00 LHLD OFFST + 3D34H DAD B MVI A,BS CMP E JZ LABL2 MOV A,M LABL2: MOV M,A MOV C,A CALL OFFST + 32DAH JMP OFFST + 3436H LABL3: MOVAR ; CHECK IF TRANSFER CORRECT ORA A ; CHECK IF EPROMS CORRECT JNZ GOCPM MVI C,WCONB ; TRY PROGRAMMING AGAIN? LXI D,MSG1 CALL BDOS JMP NEXT1 MSG1: DB 'TRY AGAIN ? ',CR,LF,'$' NEXT1: CALL INCH CPI 'Y' JZ PROG GOCPM: LHLD SPSAV ; RET (6) SAVE PATCHED SYSTEM. ; EG. ^C - SAVE 35 SYSXX.COM ; (7) PLACE PATCHED SYSTEM ON DISK WITH SYSGEN. ; (8) ENJOY. ; VALUES OF PARAMETERS TO INSERT IN COMMANDS TOTOFF EQU - OFFST - 1F80H END E CORRECT VALUE FOR YOUR SYSTEM. ; (2) ASSEMBLE THIS PROGRAM. ; (3) RUN DDT, AND EXECUTE FOLLOWING COMMANDS. ; (4) LOAD SYSTEM FILE ; EG. ICPMXX.COM AND THEN R ; (5) LOAD PATCH HEX FILE WITH OFFSET: ; EG. IBSPATXXB.HEX ; R ;NZ ERASE1 LXI D,MSG5 JMP ERASE3 ERASE2: LXI D,MSG6 ERASE3: CALL PRTMSG RET MSG5: DB CR,LF,CR,LF DB 'EPROMS ARE ERASED.',CR,LF,'$' MSG6: DB CR,LF,CR,LF DB 'EPROMS NOT ERASED!',CR,LF,'$' PROGRM: LXI D,MSG7 CALL PRTMSG CALL INCH CееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееT IS ORGED ; 4) "G1700" RUN THE PATCH (SUCH ELEGANCE) ; 5) "SAVE 19 DDTX.COM" AND SAVE THE PATCHED COPY ; ;TRY OUT DDTX ON THE CONDITIONALS AND OTHER INSTRUCTIONS. ;IF IT'S OK, REPLACE THE ORIGINAL WITH THIS. ;COMES UP WITH VER 1.3X MESSAGE TO IDE DB 'TYPE CR TO CONTINUE ','$' MSG8: DB CR,LF,CR,LF DB 'PROGRAMMING NOW IN PROGRESS',CR,LF DB 'PLEASE WAIT 2 MINUTES PER EPROM' DB CR,LF,CR,LF,'$' MSG9: DB 'PROGRAMMING COMPLETE',CR,LF DB 'TURN PROGRAM POWER OFF',CR,LF DB 'TYPE CR TO CONTINUE'ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееM START ADDRESS ENDPRM: DS 2 ; EPROM END ADDRESS SPSAV: DS 2 ; CP/M STACK POINTER DS 128 ; PROGRAM STACK AREA STACK: DS 2 END PI CR JNZ PROGRM LXI D,MSG8 CALL PRTMSG LXI B,NPASS MOV A,B CMA OUT STATL PROGR2: PUSH B LXI D,BEGDAT LHLD BEGPRM PROGR3: LDAX D MOV M,A INX D INX H LDA ENDPRM+1 CMP H JNZ PROGR3 POP B ; GET PASS COUNT DCX B MOV A,C ,201H LOOP: MOV A,M STAX D DCX H DCX D DCX B MOV A,B ORA C JNZ LOOP LXI H,4CEH MVI M,0C3H INX H MVI M,0FBH INX H MVI M,0FH ; LXI H,11FBH MVI M,0CDH INX H MVI M,55H INX H MVI M,1 INX H MVI M,0CDH INX H MVI M,0NTIFY PATCHED VERSIONS ; ;EQUATES BOOT EQU 0 BDOS EQU 5 DDT EQU 38H ; ORG 100H LXI B,1004H ; ORG 137H DB ' 1.3X' ;CHANGE MESSAGE ; ORG 14FH NOP ORG 13A5H DB 4,90H ; ORG 1700H I LXI SP,STACK LXI H,13A6H LXI D,1404H LXI B,CR,LF,'$' COMPAR: LXI D,BEGDAT LHLD BEGPRM COMPA1: LDAX D CMP M JNZ COMPA2 INX H INX D LDA ENDPRM+1 CMP H JNZ COMPA1 LXI D,MSG10 MVI A,0FFH ; MARK CORRECT PUSH PSW JMP COMPA3 COMPA2 LXI D,MSG11 MVI A,0 ; MARK ERROR PUSH ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее;PATCHES TO FIX DDT.COM VERSION 1.3 BY JEFF ZURKOW ; ;(AS DESCRIBED TO A.R.G. BY TELEPHONE) ; ;THIS ONE IS DIFFERENT - IT WORKS. ; ;TO USE: ; 1) "DDT DDT.COM" LOAD DDT.COM UNDER DDT ; 2) "IPATCH.HEX" INSERT PATCH - ; 3) "R0" - WHERE I; DSIPLAY COUNT ON STATUS LIGHTS CMA OUT STATL MOV A,B ; CHECK FOR PASSES = 0 ORA C JNZ PROGR2 ; LOOP IF NOT LAST PASS LXI D,MSG9 CALL PRTMSG PROGR5: CALL INCH CPI CR JNZ PROGR5 RET MSG7: DB CR,LF DB 'TURN PROGRAM POWER ON',CR,LF CBH INX H MVI M,0 INX H MVI M,0C3H INX H MVI M,0D1H INX H MVI M,02H ; ;NOW BACK TO CP/M FOR BOOT LXI D,MSG MVI C,9 CALL BDOS JMP BOOT ; MSG: DB 'TYPE "SAVE 19 DDTX.COM TO SAVE PATCHES"$' ; ORG $+20 STACK:  JC INHEX2 CPI 10 JC INHEX1 SBI '@'-'9' INHEX1: CPI 16 JNC INHEX2 ORA A RET INHEX2: XRA A STC RET INCH: PUSH B ! PUSH D ! PUSH H MVI C,RCON CALL BDOS POP H ! POP D ! POP B RET ; STORAGE ALLOCATIONS BEGPRM: DS 2 ; EPROPSW COMPA3: CALL PRTMSG POP PSW ; GET SUCCESS CODE RET MSG10: DB 'EPROMS CORRECTLY PROGRAMMED',CR,LF,'$' MSG11: DB 'EPROM COMPARE ERROR!',CR,LF,'$' PRTMSG: MVI C,WCONB ; PRINT MESSAGE ON CONSOLE CALL BDOS RET INHEX: CALL INCH SBI '0' ORG 100H CTLC EQU 3 LASTSEC EQU 26 LXI SP,STKTOP GO: LXI D,MESGA CALL CRPRT CALL CONIN CPI CTLC ;IS IT CONTROL C? JZ 0 ;REBOOT IF YES LXI D,MESGB CALL CRPRT CALL CONIN CALL COPY JMP GO ;LOOP TILL CTL C ; MESGA: DB 'SOURCE ON A, 127 ;SELECT THE DISK RET ; SETTRK: ;SET TRACK GIVEN BY REGISTER C ;FIRST REFERENCE CORRECT TRACK INDICATOR ACCORDING TO ;SELECTED DISK LXI D,TRACK ;ADDRESS OF TRACK FOR DISK 0 LHLD DISKNO ;FIND OUT WHICH DISK IS SELECTED DAD D MOV A,C ;DESIRE SHLD DMAAD CALL SETTRK MVI C,1 WT3: PUSH B CALL SETSEC CALL WRITE LHLD DMAAD LXI D,128 DAD D SHLD DMAAD POP B MVI A,LASTSEC CMP C RZ INR C JMP WT3 CMPERR: DB 0 ;NUMBER OF COMPARE ERRORS TRK: DB 0 STK: DS 32 STKTOP: DB 0 ; ; CONIN: PUSH B PUSH D PUSH H MVI C,01 CALL 0005H POP H POP D POP B RET ; ; CONOUT: PUSH B PUSH D PUSH H MOV E,C MVI C,02 CALL 0005H POP H POP D POP B RET ; ; COPY: MVI C,0 CALL SELDSK ;SELECT DISK A CALL ;SET UP H,L TO POINT TO WORD WITH TRACK FOR SELECTED DISK LXI D,TRACK LHLD DISKNO DAD D HOMEL: MVI M,00 ;SET CURRENT TRACK PTR BACK TO 0 IN 127 ;READ FDC STATUS ANI 4 ;TEST TRACK 0 BIT RNZ ;RETURN IF AT 0 STC ;DIRECTION=OUT CALL STEPPRTMSG POP H ;PUSHED FROM B DAD H ;COMPUTE SECTOR IN ERROR LXI D,0FF00H DAD D MVI A,27 SUB H CALL PRTHEX ;PRINT SECTOR LDA CMPERR INR A STA CMPERR ;INCREMENT ERROR COUNT CPI 10 RNZ LXI D,MESGE CALL PRTMSG XRA A RET ; ; RETHEN RETURN $' MESGB: DB 'DESTINATION ON B, THEN RETURN $' MESGC: DB 'COMPARE ERROR ON TRACK $' MESGD: DB '(HEX) SECTOR $' MESGE: DB 'PERMANENT $' ; CRPRT: CALL CRLF PRTMSG: LDAX D ;GET CHAR INX D CPI '$' RZ PUSH D MOV C,A CALL CONOUT 0,0,0,0 ;START OF SCRATCH AREA TRACK EQU SCRAT ;CURRENT TRACK ON DRIVE 0 TRAK1 EQU TRACK+1 ;CURRENT TRACK ON DRIVE 1 SECTOR EQU SCRAT+2 ;CURRENTLY SELECTED SECTOR DMAAD EQU SCRAT+3 ;CURRENT DMA ADDRESS DISKNO EQU SCRAT+5 ;CURRENT DISK NUMBER DUMORG 400H ;KEEP CONSTANT ; TRACK = LAST SELECTED TRACK ; SECTOR = LAST SELECTED SECTOR ; DMAAD = LAST SELECTED DMA ADDRESS ; DISKNO = LAST SELECTED DISK NUMBER ; (NOTE THAT ALL ARE BYTE VALUES EXCEPT FOR DMAAD) ; SCRAT DB 0,0,0,0,0,0,0, HOME ;AND HOME MVI C,1 CALL SELDSK ;ALSO B CALL HOME MVI A,0 STA TRK ;SET UP TRACK POINTER RDLOOP: MVI C,0 XRA A STA CMPERR CALL SELDSK LDA TRK ;GET TRACK MOV C,A CALL READT ;READ ENTIRE TRACK RETRYW: MVI C,1 CALL SELDSK LDA ;STEP ONE TRACK JMP HOMEL ;LOOP ; SELDSK: ;SELECT DISK GIVEN BY REGISTER C ;MAKE SURE DUMMY IS 0 (FOR USE IN DOUBLE ADD TO H,L) XRA A STA DUMMY MOV A,C STA DISKNO RRC ;PUT INTO BITS 4,5 RRC RRC RRC ORI 08 ;ENABLE DISK SELECT OUT ADT: LXI H,BUF0 ;TRACK # IN C RT2: SHLD DMAAD CALL SETTRK MVI C,1 RT3: PUSH B CALL SETSEC CALL READ LHLD DMAAD LXI D,128 DAD D SHLD DMAAD POP B MVI A,LASTSEC CMP C RZ INR C JMP RT3 ; ; WRITET: LXI H,BUF0 ;TRACK # IN C WT2:POP D JMP PRTMSG ;LOOP TILL $ ; CRLF: MVI C,0DH CALL CONOUT MVI C,0AH CALL CONOUT RET ; PRTHEX: PUSH PSW RAR RAR RAR RAR CALL PRTNBL POP PSW PRTNBL: ANI 0FH ADI 30H CPI 3AH JC SML ADI 7 SML: MOV C,A CALL CONOUT RETMY EQU DISKNO+1 ;MUST BE 0 FOR DOUBLE ADD ; ; ; ; ; I/O DRIVERS FOR THE DISK FOLLOW ; HOME: ;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE LDA DISKNO ;SELECTED DISK MOV C,A ;FOLLOW PARAMETER CONVENTIONS CALL SELDSK ;ROUTINE TO SELECT THE DISK1 LXI H,BUF0 LXI D,BUF1 LXI B,128*LASTSEC CMPLP: LDAX D CMP M JNZ CERR INX H INX D DCR C JNZ CMPLP DCR B ;ARE WE AT END OF BUFFER? JNZ CMPLP RET CERR: PUSH B LXI D,MESGC CALL CRPRT LDA TRK CALL PRTHEX LXI D,MESGD CALL TRK MOV C,A CALL WRITET ;WRITE TRACK LDA TRK MOV C,A CALL COMPT ;REREAD AND COMPARE JNZ RETRYW ;RETRY IF ERR LDA TRK INR A STA TRK CPI 77 ;ARE WE DONE? JNZ RDLOOP ;LOOP IF NOT RET ; ; COMPT: LXI H,BUF1 CALL RT2 ;REREAD INTO BUFD TRACK CMP M RZ ;WE ARE ALREADY ON THE TRACK SETTKX: CALL STEP ;STEP TRACK-CARRY HAS DIRECTION ;STEP WILL UPDATE TRACK INDICATOR MOV A,C CMP M ;ARE WE WHERE WE WANT TO BE JNZ SETTKX ;NOT YET ;HAVE STEPPED ENOUGH SEEKRT: ;DELAY 18 MSECMENT CURRENT TRACK BYTE MVI A,4 ;SET DIRECTION = IN DOSTEP: OUT 127 ;SET DIRECTION BIT IN FDC ORI 2 OUT 127 ;PULSE STEP BIT ANI 0FDH OUT 127 ;TURN OFF PULSE RET ; OUTX: DCR M ;UPDATE TRACK BYTE XRA A ;SET DIRECTION = OUT JMP DOSTEP AD FDC STATUS ANI 0F8H ;TEST FOR ANY ERROR OR IOF JZ RWWAIT MOV M,E ;RESTORE 3 BYTES BELOW BUF INX H MOV M,C INX H MOV M,B IN 127 ;TEST FOR ERRORS ANI 0F0H RZ ;A WILL BE 0 IF NO ERRORS ;COME HERE ON ERROR FROM DISK PUSH D ;SAVE READ;SAVE THE ADDRESS RET ; ; ERRORS: DB 0 ;KEEP TRACK OF NUMBER OF ERRORS READ: ;PERFORM READ OPERATION. ;THIS IS SIMILAR TO WRITE, SO SET UP READ COMMAND AND USE ;COMMON CODE IN WRITE MVI D,40H ;SET READ FLAG JMP WAITIO ;TO PERFORM THE ACTUAL IDISK DAD D ;POINT TO CORRECT TRACK INDICATOR MOV A,M ;DESIRED TRACK PUSH PSW ;SAVE IT CALL HOME POP PSW MOV C,A CALL SETTRK POP D ;GET READ/WRITE INDICATOR JMP TRYAGN ; ; ; STEP: ;STEP HEAD OUT TOWARDS ZERO ;IF CARRY IS SET; EPSW ;NEED IT LATER LHLD DMAAD ;GET BUFFER ADDRESS DCX H ;SAVE AND REPLACE 3 BYTES BELOW ;BUF WITH TRACK,SECTOR,ADDRESS MARK MOV B,M MVI A,0FBH ;ADDRESS MARK MOV M,A DCX H MOV C,M LDA SECTOR ;NOTE THAT INVALID SECTOR NUMBER ;WILL RES FOR FINAL STEP TIME AND HEAD SETTLE TIME MVI A,18D CALL DELAY RET ;END OF SETTRK ROUTINE ; DELAY: ;ROUTINE TO DELAY C(A) MILLISECONDS MVI C,82H ;ADJUST FOR 1 MSEC LOOP DELAY ;THIS IS THE VALUE FOR OUR IMSAI LDXA: DCR C JNZ LDXA ;LOOP 1CALL PRTMSG LDA SECTOR CALL PRTHEX LDA ERRORS INR A STA ERRORS CPI 20 JNZ REDO ;RETRY 20 TIMES POP D MVI A,0FFH ;ERROR RETURN RET ; MESGE1: DB 'DISK ERROR, TYPE $' MESGE2: DB ', ON DRIVE $' MESGE3: DB ', AT TRACK $' MESGE4: DB ', S/WRITE CODE LXI D,MESGE1 CALL CRPRT IN 127 ANI 0F0H CALL PRTHEX LXI D,MESGE2 CALL PRTMSG LDA DISKNO ADI 'A' MOV C,A CALL CONOUT LXI D,MESGE3 CALL PRTMSG LXI D,TRACK LHLD DISKNO DAD D MOV A,M CALL PRTHEX LXI D,MESGE4 /O ; WRITE: ;PERFORM A WRITE OPERATION MVI D,80H ;SET WRITE COMMAND ; WAITIO: ;ENTER HERE FROM READ AND WRITE TO PERFORM THE ACTUAL I/O ;OPERATION. RETURN A 00H IN REGISTER A IF THE OPERATION COMPLETES ;PROPERLY, AND 01H IF AN ERROR OCCURS DURINLSE ;STEP IN ; H,L POINT TO CORRECT TRACK INDICATOR WORD PUSH PSW ;SAVE DIRECTION STWAIT: IN 127 ;INPUT FDC STATUS ANI 2 ;TEST STEP READY BIT JZ STWAIT ;WAIT FOR STEP READY(MAX 10 MSEC) POP PSW ;GET DIRECTION TO STEP JC OUTX INR M ;INCREULT IN HEAD UNLOADED ;ERROR, SO DONT CHECK MOV M,A DCX H MOV E,M POP PSW MOV M,A MOV A,H ;SET UP FDC DMA ADDRESS OUT 126 ;HIGH BYTE MOV A,L OUT 125 ;LOW BYTE MOV A,D ;GET R/W FLAG OUT 127 ;START DISK READ/WRITE RWWAIT: IN 127 ;RE MSEC DCR A JNZ DELAY RET ;END OF DELAY ROUTINE ; SETSEC: ;SET SECTOR GIVEN BY REGISTER C MOV A,C STA SECTOR RET ; SETDMA: ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C MOV L,C ;LOW ORDER ADDRESS MOV H,B ;HIGH ORDER ADDRESS SHLD DMAAD ECTOR $' REDO: POP D ;GET R/W FLAG IN 127 ;GET ERROR BITS ANI 0E0H ;RETRY IF NOT TRACK ERROR JNZ TRYAGN ;WAS A TRACK ERROR SO NEED TO RESEEK PUSH D ;SAVE READ/WRITE INDICATOR ;FIGURE OUT THE DESIRED TRACK LXI D,TRACK LHLD DISKNO ;SELECTED R COUNT STA ERRORS ;RETRY SOME FAILURES 10 TIMES ;BEFORE GIVING UP TRYAGN: ;FIRST WE HAVE TO FIGURE OUT WHICH DRIVE IS SELECTED ;AND WHICH TRACK IS DESIRED LXI B,TRACK LHLD DISKNO DAD B ;H,L POINT TO CORRECT TRACK INDICATOR MOV A,M PUSH G THE READ OR WRITE ; ;IN THIS CASE, WE HAVE SAVED THE DISK NUMBER IN 'DISKNO' (0,1) ; THE TRACK NUMBER IN 'TRACK' (0-76) ; THE SECTOR NUMBER IN 'SECTOR' (1-26) ; THE DMA ADDRESS IN 'DMAAD' (3-3F80H) ;D STILL HAS R/W FLAG MVI A,0 ;SET ERRO; ; ; BUF0: DS 128*LASTSEC BUF1: DS 128*LASTSEC END  BIT ANI 0FDH OUT 127 ;TURN OFF PULSE RET ; OUTX: DCR M ;UPDATE TRACK BYTE XRA A ;SET DIRECTION = OUT JMP DOSTEP ELECT 0 MOV C,A CALL SELDSK LXI D,MESGB CALL CRPRT CALL CONIN CALL HOME LXI D,MESGF CALL CRPRT CALL CONIN STA REPEAT GOTEST: CALL TEST CALL CONST ORA A JNZ STOPT LDA REPEAT ANI 0DFH ;CONVERT TO UPPER CASE CPI 'R' ;LOOP IF carry on bad read LXI H,INBUF ; Set pointer to buffer start SHLD INPTR RET DREC: LXI D,INBUF ; Set DMA address MVI C,SDMA CALL BDOS LXI D,INFCB ; Read a record MVI C,READ CALL BDOS RAR ; Setееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее(1) 28 JUN 77 : ADDED CP/M CONSOLE INPUT CALL ; FOR SYSTEM SIZE INDEPENDENCE. ; (2) 03 JUL 77 : ADDED BREAK CHECK TO ALLOW HALT ; OF TEST IN REPEAT MODE. ; (3) 10 JUL 77 : CHANGED DISK I/O TO USE DIRECT ; CALLS TO CBIOS IN USER SYSTEM. ; gain, just set ; next record to zero, and ; reset INPTR. ; READ CHARACTER FROM FILE DISKIN: LHLD INPTR ; Test buffer pointer LXI D,-(INBUF+128) DAD D MOV A,H ORA L CZ RDREC ; If empty, read next record RC ; Return on bad read Lееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; SEQUENTIAL DISK CHARACTER INPUT ; ; DISKIN.LIB - Version 1.0 - 18 SEP 77 ; ; J.W. SHOOK, P.O. BOX 185, ROCKY POINT, NY 11778 ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; Before rea ;----------------------------------------------- ; STANDARD EQUATES ; LASTSEC EQU 26 BDOS EQU 5 CR EQU 0DH LF EQU 0AH ORG 100H GO: LXI SP,STKTOP LXI D,MESGA CALL CRPRT CALL CONIN ANI 1 ;GET LSB FOR DISK SELECT XRI 1 ;ASCII A MEANS SHLD INPTR ; Get char from buffer MOV A,M INX H ; Move buffer pointer SHLD INPTR RET ; REFILL DISK INPUT BUFFER RDREC: LXI D,INBUF ; Set DMA address MVI C,SDMA CALL BDOS LXI D,INFCB ; Read a record MVI C,READ CALL BDOS RAR ; Setееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее;----------------------------------------------- ; ; DISK TEST PROGRAM - VERSION 0.2 ; ; 10 JUL 77 ; ; DONATED BY ANONYMOUS ; ; MODIFIED FOR CP/M BY J. W. SHOOK ; ;----------------------------------------------- ; MODIFICATION HISTORY *** ; ; ) The file must be successfully ; opened. ; 4) The next record pointer in ; the file control block must be ; set to zero. ; 5) The word at location INPTR ; must be set to INBUF+128 to ; mark the buffer as empty. ; 6) To read a file ading a file sequentially ; the following initial conditions ; must be established. ; 1) A CP/M file control block ; containing the file name must ; start at location INFCB. ; 2) A 128 byte buffer area must ; start at location INBUF. ; 3 REPEAT FLAG ON JZ GOTEST STOPT: LXI D,MESGH CALL CRPRT STOPT1: CALL CONIN ANI 0DFH ;CONVERT TO UPPER CASE CPI 'Y' JZ GO CPI 'N' JNZ STOPT1 LXI D,MESGG CALL CRPRT CALL CONIN JMP 0 ;REBOOT ;CPM CONSOLE INPUT CONIN: PUSH B ! P-------------------------- ; ; DISK I/O CALLING PROCEDURES ; ;-------------------------------------------------------- HOME: ; MOVE HEAD TO TRACK 0 MVI A,21 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP B RET SELDSK: ; SELECOV C,A CALL CONOUT RET ; FILDSK: CALL FILBUF0 XRA A FDLP: PUSH PSW MOV C,A STA TRK CALL WRITET ;WRITE ONE TRACK POP PSW PUSH PSW MOV C,A CALL COMPT POP PSW INR A CPI 77 JNZ FDLP ;DO ALL 77 TRACKS RET ; FILBUF0: LXI H,BURE ERROR ON TRACK $' MESGD: DB '(HEX) SECTOR $' MESGE: DB 'PERMANENT $' MESGF: DB 'REPEAT TEST (TYPE H TO HALT) OR STOP? (R OR S) $' MESGG: DB 'INSERT SYSTEM DISK, THEN RETURN $' MESGH: DB 'DO YOU WANT TO RESTART THIS TEST? (Y OR N) $' MESGI: DB 'COMAD D SHLD DMAAD POP B MVI A,LASTSEC CMP C RZ INR C JMP RT3 ; ; WRITET: LXI H,BUF0 ;TRACK # IN C WT2: SHLD DMAAD CALL SETTRK MVI C,1 WT3: PUSH B LHLD DMAAD PUSH H POP B CALL SETDMA POP B PUSH B CALL SETSEC CALL WRITE P: XRA A MOV C,A CALL READT ;READ TRACK ZERO POP PSW INR A CPI 77 JZ SKDONE PUSH PSW MOV C,A CALL READT ;READ INCREASING TRACK NO JMP SKLP SKDONE: RET ; ; CRPRT: CALL CRLF PRTMSG: LDAX D ;GET CHAR INX D CPI '$' RZ PUSH D USH D ! PUSH H MVI C,1 CALL BDOS POP H ! POP D ! POP B RET ;CP/M CONSOLE OUTPUT CONOUT: PUSH PSW ! PUSH B ! PUSH D ! PUSH H MOV E,C MVI C,2 CALL BDOS POP H ! POP D ! POP B ! POP PSW RET ; CP/M CONSOLE STATUS CHECK CONST: PUS INX D DCR C JNZ CMPLP DCR B ;ARE WE AT END OF BUFFER? JNZ CMPLP RET CERR: PUSH B LXI D,MESGC CALL CRPRT LDA TRK CALL PRTHEX LXI D,MESGD CALL PRTMSG POP H ;PUSHED FROM B DAD H ;COMPUTE SECTOR IN ERROR LXI D,0FF00H DAD D MVIF0 ;FILL BUF0 WITH (A) LXI B,128*LASTSEC FLP: MOV M,A INX H DCR C JNZ FLP DCR B JNZ FLP RET ; ; ; ; COMPT: LXI H,BUF1 CALL RT2 ;REREAD INTO BUF1 LXI H,BUF0 LXI D,BUF1 LXI B,128*LASTSEC CMPLP: LDAX D CMP M JNZ CERR INX H PLETED TEST LOOP $' MESGJ: DB 'NOW FILLING DISK WITH 00$' MESGK: DB 'NOW PERFORMING SEEK TEST$' MESGL: DB 'NOW FILLING DISK WITH FF$' MESGM: DB 'NOW FILLING DISK WITH 55$' MESGN: DB 'NOW FILLING DISK WITH AA$' MESGO: DB 'NOW FILLING DISK WITH E5$' LHLD DMAAD LXI D,128 DAD D SHLD DMAAD POP B MVI A,LASTSEC CMP C RZ INR C JMP WT3 DMAAD: DW 80 REPEAT: DB 0 CMPERR: DB 0 ;NUMBER OF COMPARE ERRORS TRK: DB 0 TSTCNT: DB 0 STK: DS 40H STKTOP: DB 0 ;------------------------------ MOV C,A CALL CONOUT POP D JMP PRTMSG ;LOOP TILL $ ; CRLF: MVI C,0DH CALL CONOUT MVI C,0AH CALL CONOUT RET ; PRTHEX: PUSH PSW RAR RAR RAR RAR CALL PRTNBL POP PSW PRTNBL: ANI 0FH ADI 30H CPI 3AH JC SML ADI 7 SML: MH B ! PUSH D ! PUSH H MVI C,11 CALL BDOS POP H ! POP D ! POP B RET ; MESGA: DB 'DISKTEST - VERSION 0.2',CR,LF DB '03 JUL 77',CR,LF,LF DB 'SELECT DRIVE TO TEST, A OR B? $' MESGB: DB 'INSERT SCRATCH DISKETTE, THEN RETURN $' MESGC: DB 'COMPA A,27 SUB H CALL PRTHEX ;PRINT SECTOR RET ; ; READT: LXI H,BUF0 ;TRACK # IN C RT2: SHLD DMAAD CALL SETTRK MVI C,1 RT3: PUSH B LHLD DMAAD PUSH H POP B CALL SETDMA POP B PUSH B CALL SETSEC CALL READ LHLD DMAAD LXI D,128 DRPRT MVI A,0AAH CALL FILDSK LXI D,MESGO CALL CRPRT MVI A,0E5H CALL FILDSK LXI D,MESGK CALL CRPRT CALL SKTST LXI D,MESGI CALL CRPRT LDA TSTCNT INR A STA TSTCNT CALL PRTHEX RET ; ;SEEK TEST ; SKTST: XRA A PUSH PSW SKL ; TEST: LXI D,MESGJ CALL CRPRT MVI A,0 ;TEST PATTERN CALL FILDSK LXI D,MESGK CALL CRPRT CALL SKTST ;SEEK TEST LXI D,MESGL CALL CRPRT MVI A,0FFH CALL FILDSK LXI D,MESGM CALL CRPRT MVI A,55H CALL FILDSK LXI D,MESGN CALL CT DISK DRIVE MVI A,24 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP H RET SETTRK: ; SELECT TRACK MVI A,27 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP B RET SETSEC: ; SELECT SECTOR MVI A,30 PUSH B ! = 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) = idend by 8 bit ; divisor producing a 16 bit quotient ; and an 8 bit remainder. ; CALL with: ; HL = Dividend ; C = Divisor ; RETURN with: ; HL = Quotient ; C = Divisor A = Remainder ; CARRY = Set on divide by zero DIVIDE: XRA A ; Clea************ ; ; 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----------------------------------------- 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 YееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееPUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP B RET SETDMA: ; SELECT DMA ADDRESS MVI A,33 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP B RET READ: ; READ SECTOR MVI A,36 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP ID2 ; Quotient bit = 0? SUB C ; Subtract divisor from extension INX H ; Set least bit of quotient DIVID2: DCR B ; Test loop count JNZ DIVID1 ; Done? RET r extension of dividend reg CMP C ; Check if divisor = 0 STC ; Mark divide error RZ ; Return on / by 0 MVI B,16 ; Set loop counter DIVID1: DAD H ; Shift dividend left into RAL ; dividend extension reg. CMP C ; Extension >= divisor? JC DIV 1 ; GET BIOS ENTRY + 3 DAD D ; ADD ENTRY TO OFFSET PCHL ; JUMP TO BIOS ; ; ; DS 3 BUF0: DS 128*LASTSEC BUF1: DS 128*LASTSEC END ORK',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 ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; UNSIGNED BINARY DIVIDE ; ; DIVIDE1.LIB - Version 0.1 - 14 SEP 77 ; ; J.W. SHOOK, P.O. BOX 185, ROCKY POINT, NY 11778 ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; Divides 16 bit divH ! POP D ! POP B RET WRITE: ; WRITE SECTOR MVI A,39 PUSH B ! PUSH D ! PUSH H CALL FBIOS POP H ! POP D ! POP B RET ;****************************************** ;* BIOS FUNCTION CALLING PROCEDURE * ;******************************;------------------------------------------------------- ; ; 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 ; ;----------ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее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 MAXE ! 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 ! MVENT ! 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 ; L 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 ;! 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) = "?" = 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 ; . . . NT ; 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.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 XI 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 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 ; 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: 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 MAXENTRY.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) 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: 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) 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 I 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 FBIO+ 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 ----------------------------- ; 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,B 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 ; ; ;--------------------------------P 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 LRY.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 ; ; ; ;----------------------------S ! 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 FALMP.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 CFNUFFER+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 * TE------ ; 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 = ADXI 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 ---------- ; 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,'$' ; ; ;---------SE ; 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 ! ; 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: ; LOO4 ; 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 = ENTDR[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 FI0 ; 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 GISTER 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 TENTS CALL CLEAR ! LHLD FILEXT ! SHLD DATA ! CALL BINBCD ! LHLD RESULT ! CALL PRADDR ! CALL PRCRLF ! RET ; RETURN ; ; ; ;-------------------------------------- ; PTL: ; $ PRINT.TOTALS.LISTING ; CALL PRCRLF ! TR ! 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: ; 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 CONVEH ! 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,RD ! 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.POINT 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 ! CALLMVI 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 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 TRTED 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 REESULT+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.EXER) = 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 ENTP BINBCD ! LHLD RESULT ! CALL PRADDR ! CALL PRCRLF ! RET ; RETURN MSG2: DB 'TOTAL.SIZE ','$' ; ; ;----------------------------------------------- ; ; BINARY TO BCD CONVERSION ; ;----------------------------------------------- ;TAL.EXTENTS + FILE.EXTENTS XCHG ! LHLD TOTEXT ! DAD D ! SHLD TOTEXT ! RET ; RETURN ; ; ; ;-------------------------------------- ; PFIL: ; $ PRINT.FILE.INFORMATION.LISTING ; LHLD ENTPTR ; PRINT FILE.NAME(11) INX ENPTR ! 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 = TOTO 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 CLEAACK SETSEC: EQU 30 ; SET NEXT SECTOR SETDMA: EQU 33 ; SET DMA ADDRESS READS: EQU 36 ; READ SECTOR WRITES: EQU 39 ; WRITE SECTOR ; ; END ; END 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,'$' ; ;****************************************** ;--------------------------------------BYTES 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 NUMBION 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 COZ 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 PRR1: 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 CT 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 ; ;*********************-------- ; ; 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 PRODUER 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 RETNSOLE 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 TRS: 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 ; 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,N********************* ;* 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 FUNCT******************* ; ; 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' JN ; 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 * ;*********************** ORG 100H JMP START ;SKIP PROGRAM ID DB '(FMAP 8/21/77)' ;SORTED DIRECTORY MAP PROGRAM ;WITH OPTION OF WRITING FILE OF NAMES ; ;FMAP FN.FT OR JUST MAP ;FMAP FN.FT F TO WRITE A FILE ;ALLOWS '*' OR '?' TYPE SPECIFICATIONS FCB EQU 5CH ;SYSTEM FC A,C ;TIME TO SPACE? ANI 3 CZ SPACE INX H ;POINT TO NEXT CHR DCR B ;MORE IN EXTENT? JNZ EXTLP ;YES ;BUMP TOTAL FILE COUNT ENDEXT LDA NFILE ;GET # FILES INR A ;BUMP DAA ;MAKE DECIMAL STA NFILE ;SAVE IT BACK CALL CR ;END, TYPE C/R ;SEE PARE STA SCOUNT ;SAVE HIGHEST ENTRY JZ DONE ;EXIT IF NO MORE LXI H,ORDER ;POINT TO ORDER TABLE SORTLP CALL COMPR ;COMPARE 2 ENTRIES CM SWAP ;SWAP IF NOT IN ORDER INX H ;BUMP ORDER INX H ;..TABLE POINTER LDA TEMP ;GET COUNT DCR A STA TEMP ;GOT SOME - PRT TITLE, CONT LXI D,NONMSG CALL WRCON JMP EXIT NONMSG DB '++NOT FOUND$' ;PRINT TITLE PRTTL LXI D,TTL CALL WRCON CALL CR LDA TEMP ;RELOAD EXTENT JMP SOME TTL DB 'FILENAME TYP EX RC -----EXTENT-----$' ;READ MORE DIRECTORY EN MVI B,3 ;GET THE FILETYPE CALL TYPEIT CALL FILECR INX H ;SKIP EXTENT INX H ;SKIP INX H ;UNUSED MOV A,M ;GET REC COUNT DCR A ;FUDGE RAR ;DIVIDE RAR ;..BY 8 RAR ANI 1FH ;DELETE GARBAGE INR A ;MAKE RELATIVE TO 1, NOT 0 MOV B,A ;ND PRINT SPRINT LDA COUNT ;INIT THE ORDER TABLE LXI H,ORDER LXI D,TABLE LXI B,31 ;ENTRY LENGTH BLDORD MOV M,E ;SAVE LO ORD ADDR INX H MOV M,D ;SAVE HI ORD ADDR INX H XCHG ;TABLE ADDR TO HL DAD B ;POINT TO NEXT ENTRY XCHG DCR A ;MORE?B ;SAVE THE STACK START LXI H,0 DAD SP ;H=STACK SHLD STACK ;SAVE IT LXI SP,STACK ;GET NEW STACK ;SAVE FILE WRITE REQUEST CHAR LDA FCB+17 STA FILESW ;NO FCB SPECIFIED? LXI H,FCB+1 MOV A,M CPI ' ' JNZ GOTFCB ;NO FCB - MAKE FCB ALL '?' RASE CALL BDOS LXI D,MYFCB MVI C,FMAKE ;MAKE THE FILE CALL BDOS INR A JNZ ENTRY ;MAKE ERROR CALL ERXIT DB '++FILE MAKE ERROR$' ;PRINT AN ENTRY ENTRY MVI C,CONST ;CK STATUS OF KB CALL BDOS ;ANY KEY PRESSED? DCR A JZ ABORT ;YES, ABOR JNZ SORTLP ;CONTINUE ;ONE PASS OF SORT DONE LDA SWITCH ;ANY SWAPS DONE? ORA A JNZ SORT ;SORT IS ALL DONE - PRINT ENTRIES DONE LXI H,ORDER SHLD NEXTT ;IF WRITING A FILE, OPEN THE FILE LDA FILESW CPI 'F' JNZ ENTRY LXI D,MYFCB MVI C,ETRIES MOREDIR MVI C,FSRCHN ;SEARCH NEXT LXI D,FCB CALL BDOS ;READ DIR ENTRY INR A ;CHECK FOR END (0FFH) JZ SPRINT ;NO MORE - SORT & PRINT ;POINT TO DIRECTORY ENTRY SOME DCR A ;UNDO PREV 'INR A' ANI 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADDSAVE AS # EXTENTS MOV A,M ;RELOAD RECORD COUNT CALL XOB ;PRINT RECORD COUNT INX H ;SKIP RECORD COUNT MVI C,0 ;FOR EXTENT SKIP CTL EXTLP MOV A,M ;GET EXTENT BYTE ORA A ;EMPTY? JZ ENDEXT ;..YES CALL XO ;..NO, PRINT IT INR C ;INCR COUNT MOV JNZ BLDORD ;..YES LDA COUNT ;GET COUNT STA SCOUNT ;SAVE AS # TO SORT DCR A ;ONLY 1 ENTRY? JZ DONE ;..YES, SO SKIP SORT SORT XRA A ;GET A ZERO STA SWITCH ;SHOW NONE SWITCHED LDA SCOUNT ;GET COUNT DCR A ;USE 1 LESS STA TEMP ;SAVE # TO COM MVI B,11 ;FN+FT COUNT QLOOP MVI M,'?' ;STORE '?' IN FCB INX H DCR B JNZ QLOOP ;LOOK UP THE FCB IN THE DIRECTORY GOTFCB MVI C,FSRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;WERE THERE ANY? STA TEMP ;SAVE JNZ PRTTLT LHLD NEXTT ;GET ORDER TABLE POINTER MOV E,M ;GET LO ADDR INX H MOV D,M ;GET HI ADDR INX H SHLD NEXTT ;SAVE UPDATED TABLE POINTER XCHG ;TABLE ENTRY TO HL MVI B,8 ;FILE NAME LENGTH CALL TYPEIT ;TYPE FILENAME CALL PERIOD ;SPACE AFTER FN;NEXT TABLE ENTRY TO HL MVI B,31 ;ENTRY LENGTH TMOVE LDAX D ;GET ENTRY CHAR MOV M,A ;STORE IN TABLE INX D INX H DCR B ;MORE? JNZ TMOVE SHLD NEXTT ;SAVE UPDATED TABLE ADDR LDA COUNT ;GET PREV COUNT INR A STA COUNT JMP MOREDIR ;SORT A A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LXI H,81H ;POINT TO BUFFER ;(SKIP TO FN/FT) ADD L ;POINT TO ENTRY MOV L,A ;SAVE (CAN'T CARRY TO H) ;MOVE ENTRY TO TABLE XCHG ;ENTRY TO DE LHLD NEXTT IF MORE ENTRIES LDA COUNT DCR A STA COUNT JNZ ENTRY ;YES, MORE ;ALL DONE - PRINT # FILES LDA NFILE CALL XOB LXI D,NMSG CALL WRCON ;CLOSE FILE IF NECESSARY LDA FILESW CPI 'F' JNZ EXIT MVI A,'Z'-40H ;EOF CHAR CALL FILCHR ;WRITE ITееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееPARED XCHG CMPLP LDAX B CMP M INX H INX B JZ CMPLP POP H RET ;COND CODE TELLS ALL ;SWAP ENTRIES IN THE ORDER TABLE SWAP MVI A,1 STA SWITCH ;SHOW A SWAP WAS MADE MOV C,M INX H PUSH H ;SAVE TABLE ADDR+1 MOV B,M INX H MOV E,M VI C,PRINT JMP BDOS TYPEIT MOV A,M CALL FILCHR ;TO DISK IF REQ'D CALL TYPE INX H DCR B JNZ TYPEIT RET SPACE MVI A,' ' JMP TYPE CR MVI E,13 ;PRINT MVI C,2 ;C/R CALL BDOS MVI E,10 ;LF MVI C,2 JMP BDOS TEMP DS 1 ;SAVE DIR ENTRY DS 1 ;'F' IF WRITING FILE BUFAD DW 80H ;OUTPUT ADDR MYFCB DB 0,'NAMES SUB',0 DS 19 DB 0 ORDER DS 128 ;ORDER TABLE TABLE EQU $ ;READ ENTRIES IN HERE END 100H  C,FWRTE CALL BDOS ORA A JZ WROK CALL ERXIT DB '++WRITE ERROR$' WROK LXI H,80H ;START OF BUFF SHLD BUFAD POP D POP B RET ;TYPE A PERIOD INTO THE FILE PERIOD MVI A,'.' ;GET PERIOD CALL FILCHR ;WRITE TO FILE JMP SPACE ;WRITE CR/LF I CALL WRSEC ;WRITE FINAL SECTOR LXI D,MYFCB MVI C,FCLOSE CALL BDOS JMP EXIT NMSG DB 'FILES$' ;HEX OUTPUT W/BLANK XOB CALL XO JMP SPACE ;HEX OUTPUT XO PUSH PSW ;SAVE CHAR RAR RAR RAR RAR CALL NIBBL ;PRINT LEFT NIBBLE POP PSW ;GLE WRCHR EQU 2 ;WRITE CHR TO CONSOLE PRINT EQU 9 ;PRINT CONSOLE BUFF CONST EQU 11 ;CHECK CONS STAT FOPEN EQU 15 ;0FFH=NOT FOUND FCLOSE EQU 16 ; " " FSRCHF EQU 17 ; " " FSRCHN EQU 18 ; " " ERASE EQU 19 ;NO RET CODE FREAD EQU 20 ;0=OK, 1=EOF MOV M,C INX H MOV D,M MOV M,B POP H MOV M,D DCX H ;BACK POINTER TO CORRECT LOC'N MOV M,E RET DS 30 ;STACK AREA STACK DS 2 ;SAVE OLD STACK HERE NFILE DB 0 ;NUMBER OF FILES PRINTED ; ; BDOS EQUATES ; RDCHR EQU 1 ;READ CHAR FROM CONSO;ERROR EXIT ERXIT POP D ;GET MSG MVI C,PRINT JMP CALLB ;PRINT MSG, EXIT ;ABORT - READ CHAR ENTERED ABORT MVI C,RDCHR CALLB CALL BDOS ;DELETE THE CHAR ;FALL INTO EXIT ;EXIT - ALL DONE , RESTORE STACK EXIT LHLD STACK ;GET OLD STACK SPHL ;MOVE TееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееNTO FILE FILECR MVI A,13 CALL FILCHR MVI A,10 CALL FILCHR JMP SPACE ;COMPARE ROUTINE FOR SORT COMPR PUSH H ;SAVE TABLE ADDR MOV E,M ;LOAD LO INX H MOV D,M ;LOAD HI INX H MOV C,M INX H MOV B,M ;BC, DE NOW POINT TO ENTRIES TO BE COMET VALUE BACK NIBBL ANI 0FH ;ISOLATE NIBBLE CPI 10 ;NUMBER? JC XNUM ;YES ADI 7 ;FUDGE ALPHA HEX XNUM ADI '0' ;MAKE PRINTABLE ;TYPE CHAR IN A TYPE PUSH B PUSH D PUSH H MOV E,A MVI C,WRCHR CALL BDOS POP H POP D POP B RET WRCON MFWRTE EQU 21 ;0=OK, 1=ERR, 2=?, 255=NO DIR SPC FMAKE EQU 22 ;255=BAD FREN EQU 23 ;255=BAD FDMA EQU 26 BDOS EQU 5 REBOOT EQU 0 NEXTT DW TABLE ;NEXT TABLE ENTRY COUNT DB 0 ;ENTRY COUNT SCOUNT DB 0 ;# TO SORT SWITCH DB 0 ;SWAP SWITCH FOR SORT FILESWSAVE IT BACK PUSH H LHLD BUFAD ;CURRENT BUFFER ADDR MOV M,A INX H SHLD BUFAD MOV A,H ;SEE IF FULL BUFF DCR A CZ WRSEC ;YES, WRITE SECTOR POP H NOFILE POP PSW ;RESTORE CHAR RET ;WRITE A SECTOR WRSEC PUSH B PUSH D LXI D,MYFCB MVIO STACK RET ;..AND RETURN ;ROUTINES FOR CREATING FILE ; ;WRITE CHAR IN A TO FILE ;(SAVES ALL REGS INCLUDING A) FILCHR CPI ' ' RZ ;DON'T WRITE BLANKS PUSH PSW LDA FILESW ;WRITING A FILE? CPI 'F' JNZ NOFILE POP PSW ;GET CHAR PUSH PSW ;;************************************************************ ; ; FORMAT. A PROGRAM FOR FORMATTING DISKETTES ; IN THE IBM 3740 STANDARD FORMAT FOR USERS ; OF THE TARBELL FLOPPY DISK INTERFACE. ;***************************************************  A,C CPI 0 RZ MOV M,B INX H DCR C JMP PUT ; ; VI B,0 CALL PUT ; MVI C,1 MVI B,0FCH CALL PUT ; MVI C,26 MVI B,0 CALL PUT ; ;SECTOR =1 MVI E,1;SET E=1 SECTOR1 ; LOOP1 MVI C,6 ** ; SUBROUTINE DESCRIPTIONS: ; DISC: FORMATS EACH OF 77 TRACKS IN TURN ; TRACK: WRITES 1 TRACK, REG.D CONTAINS ; TRACK NUMBER ; IMAGE: CREATES AN IMAGE OF THE INFORMATION ; TO BE WRITTEN ON EACH TRACK IN CORE ; STAR CALL PUT ; MVI C,1 MVI B,0F7H; 2CRC'S CALL PUT ; MVI C,27 MVI B,0 CALL PUT ; MOV A,E CPI 26 JZ FINIS INR E J MVI A,13H; LOAD SEEK OUT 0F8H; ISSUE SEEK IN 0FCH;WAIT MVI A,0F4H; WRITE TRACK COMMAND LOAD OUT 0F8H;ISSUE WRITE TRACK ; WLOOP IN 0FCH; WAIT ORA A JP DONE ********* ; JAMES A. WILLIS, M.D. ; 3300 BARBERRY LN. SACTAMENTO CA. 95825 ;************************************************************ ; THIS PROGRAM IS INTENDED FOR SINGLE ; DISK INSTALLATIONS AND WILL HALT ; WHEN CALLED TO ALLOW THE USERT ; MVI C,1 MOV B,E;SECTOR # CALL PUT ; MVI C,1 MVI B,0 CALL PUT ; MVI C,1 MVI B,0F7H;2 CRC'S CALL PUT ; MVI C,11 MVI B,0 CALL PUT ; MVI C,1 MVI B,0FEH;ID ADDRESS MARK CALL PUT ; MVI C,1 MOV B,D; TRACK CALL PUT ; MVI C,1 MVI B,0 CALL PUTING AT LOACTION 1000H. ; TRACK NUMBER IN REGISTER D., SECTOR ; NUMBER IN REGISTER C. ; ; NOTE: THIS SOFTWARE SHOULD BE ; READILY ADAPTABLE TO OTHER DISK ; SYSTEMS BY RE-WRITING DISK DRIVER ; ROUTINES IN SUBROUTINE TRACK. ;******MP LOOP1 ; ; FINIS MVI C,255; FILL MVI B,0 CALL PUT RET ; ; PUT MOV A,C CPI 0 RZ MOV M,B INX H DCR C JMP PUT ; ; MOV A,M OUT 0FBH;DATA OUT INX H JMP WLOOP ; DONE RET ; ; ; IMAGE LXI H,1000H ;ORG OF DATA MVI C,40 MVI B,0 CALL PUT ; MVI C,6 M TO INSERT ; THE DISK TO BE FORMATTED. THE USER THEN ; MUST START THE PROGRAM AT LOCATION 0200H ; MANUALLY. THE PROGRAM WILL THEN FORMAT THE ; DISK, HALTING AT THE END OF THE OPERATION. ;********************************************************** MVI B,0 CALL PUT ; MVI C,6 MVI B,0 CALL PUT MVI C,1 MVI B,0FBH;DATA ADDRESS MARK CALL PUT ; MVI C,128 MVI B,0E5H;DATA E5 CALL TRACK MOV A,D;TRACK#TOA CPI 4CH; LAST TRACK? JZ LAST INR D JMP D1 ; LAST HLT ; ; TRACK LXI H,1000H MOV A,D OUT 0FBH;TRACK # DR ****************************************************** ORG 0100H START HLT ; ; ORG 0200H DISC MVI D,0 MVI A,3 OUT 0F8H; OUT HOME IN 0FCH; WAIT ; D1 CALL IMAGE ;CONTRIBUTED TO CP/M USERS' GROUP BY: ; ; MEMORY MERCHANTS ; 1350 BUFFALO ROAD ; ROCHESTER NY 14624 ; ; GO COMMAND ----- JUMPS TO A HEX ADDRESS .I8080 .PABS .PHEX .XLINK BDOS = 05H CPM = 0 STACK ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееLL with: ; RADIX = value of radix desired ; RETURN with: ; HL = 16 bit value of number ; C = RADIX ; A = Last character input ; CARRY = TRUE on input error INNUM1: LDA RADIX ; Save radix in C MOV C,A LXI H,0 ; Initialize number value INUMORDER BYTE OF GO.AD SHLD TEMP POP H CALL ADDR LHLD GO.AD PCHL ADDR: CALL CHECK ;CHECK FOR END OF HEX DIGITS CALL HEXDIG PUSH H LHLD TEMP MOV M,A POP H CALL CHECK CALL HEXDIG RLC RLC RLC RLC PUSH H LHLD TEMP ADD M 1: CPI 16 ; Valid hex value? CMC RET RADIX: DB 10 ; Default value for radix ; EXTERNAL REFERENCES: ; MPY81 Unsigned 8 bit multiply ; INCH Console character input ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее= TEMP+10 TBUFF = 080H ; SYNTAX: GO HHHH , WHERE 'H' IS A HEX CHARACTER ;OF LENGTH 0 TO 4 AND IS A CARRIAGE RETURN. ; IE., GO 9CD OR GO F000 .LOC 100H LXI SP,STACK ;SET STACK LXI H,0 SHLD GO.AD ;CLEAR GO.AD LXI H,TBUset ; Else multiply value by radix ; and add new digit. MOV D,H ; Get prev value to multiplier MOV E,L ; register MOV L,A ; Move new digit to MVI H,0 ; product register MOV A,C ; Put radix in multiplier reg CALL MPY81 ; Value <- digi1: CALL INCH ; Skip leading spaces CPI ' ' JZ INUM1 INUM2: CPI ',' ; Check for terminators RZ CPI ' ' RZ CPI CR RZ CALL HEXCON ; Convert character to binary RC CMP C ; Digit valid in this radix? CMC RC ; If not, return with carry MOV M,A POP H RET CHECK: DCX H ;LOOK AT NEXT HEX DIGIT MOV A,M CPI " " RNZ ;IF SPACE JUMP & GO LHLD GO.AD PCHL HEXDIG: SUI 30H JC HEXERR ;NOT A HEX DIGIT CPI 0AH JNC ..ALPHA RET ..ALPHA: SUI 07H CPI 10H JNC HEXERR ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; VARIABLE RADIX NUMBER INPUT (unsigned) ; ; INNUM1.LIB - Version 0.1 - 12 SEP 77 ; ; J.W. SHOOK, P.O. BOX 185, ROCKY POINT, NY 11778 ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; CAFF ;POINT TO BUFFER LDA TBUFF ;GET BUFFER COUNTER ADD L ;GO TO END OF HEX STRING MOV L,A INX H PUSH H LXI H,GO.AD ;WORK ON LOWER ORDER BYTE OF GO.AD SHLD TEMP POP H CALL ADDR ;DECODE HEX DIGITS PUSH H LXI H,GO.AD+1 ;WORK ON HIGH t + value * radix CALL INCH ; Get next character JMP INUM2 HEXCON: SBI '0' ; Remove ASCII bias RC ; Too small? CPI 10 ; Decimal digit? JC HEXCO1 ; Yes SBI '@'-'9' ; No, remove alpha bias CPI 10 ; Less than 'A'? RC ; Not hex then HEXCOееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее ;NOT A HEX DIGIT RET HEXERR: MVI C,9 LXI D,..MSG CALL BDOS JMP CPM ;DO A WARM BOOT ..MSG: .ASCII "ERROR IN HEX ADDRESS $" GO.AD: .BLKW 1 TEMP: .BLKW 1 .END  TITLE MACADPT ; ; VERSION 1.2 11 APR 77 ; VERSION 1.3 20 SEP 77 ; VERSION 1.4 17 OCT 77 ; ; BY JEFFREY W. SHOOK ; PO BOX 185 ; ROCKY POINT, NY 11778 ; ; THIS PROGRAM ADAPTS THE TDL MACROASSEMBLER ; TO WORK UNDER CP/M. ; ;***************CTER INPUT SUBROUTINE ; ; CREATE A SOURCE BUFFER AND LOAD ; IT FROM THE DISK. AT EACH CALL ; SUPPLY ONE CHARCTER IN A REG. ; IF BUFFER EMPTY, CALL BDOS TO ; FILL IT. SET CARRY IF EOF IS ; FOUND IN FILE. ; RISIM: PUSH H ; SAVE ASSM HL,DE PUSH D LXI D,TFCB; CHECK DIRECTORY MVI C,SFRST ; TO SEE IF FILE EXISTS CALL BDOS CPI 0FFH CZ ERROR LXI H,TFCB ; MOVE FILE NAME TO SRCFCB LXI D,SRCFCB LXI B,12 CALL LDIR ; MOVE BLOCK MVI C,OPEN ; OPEN SOURCE FILE LXI D,SRCFCB CALL BDOS CPI*****************; SRSET EQU 00 ;SYSTEM RESET RCON EQU 01 ;READ CONSOLE WCON EQU 02 ;WRITE CONSOLE RRDR EQU 03 ;READ READER WPUN EQU 04 ;WRITE PUNCH WLST EQU 05 ;WRITE LIST ISTAT EQU 07 ;GET IOSTATUS SSTAT EQU 08 ;SET IOSTATUS WCONB EQU 09 ;WRI OF ASSEMBLER. ; PASS 1 = SYMBOL TABLE ; PASS 2 = LISTING ; PASS 3 = HEX OBJECT FILE ; CISIM: PUSH H ; SAVE ASSEMBLER REGISTERS PUSH D PUSH B MVI A,0 ; SET NEXT RECORD POINTER TO ZERO STA SRCFCB+32 STA CSTSF ; CLEAR CONSOLE STATUS FLAG LXITR: DS 2 ; SOURCE BUFFER POINTER LSTPTR: DS 2 ; LISTING BUFFER POINTER HEXPTR: DS 2 ; HEX OBJECT FILE POINTER SRCFCB: DS 36 ; SOURCE FILE CONTROL BLOCK SRCBUF: DS 128 ; SOURCE FILE BUFFER LSTFCB: DS 36 ; LISTING FILE CONTROL BLOCK LSTBUF: DS 128 ; LI********************; ; CP/M STANDARD EQUATES ; ;***********************************; BOOT EQU 0000H ;WARM START ADDRESS TFCB EQU 005CH ;DEFAULT FCB ADDRESS TBUF EQU 0080H ;DEFAULT BUFFER ADDRESS TBASE EQU 0100H ;TRANSIENT PROGRAM BASE UF; INITIALIZE HEX POINTER SHLD HEXPTR MVI A,0 ; INITIALIZE CONSOLE STATUS FLAG STA CSTSF JMP MACRX ; GO ASSEMBLE ; ; TABLE OF FILETYPES ; AZM: DB 'AZM' PRN: DB 'PRN' HXR: DB 'HXR' ; ; ; END OF ASSEMBLY ; TRPSIM: MVI C,EOF ; EMPTY LIST 0FFH CZ ERROR LXI D,LSTFCB; CREATE LISTING FILE LXI B,PRN CALL MAKEF LXI D,HEXFCB; CREATE OBJECT FILE LXI B,HXR CALL MAKEF LXI H,PASST ; INITIALZE PASS COUNT SHLD PASSP LXI H,LSTBUF; INITALIZE LISTING POINTER SHLD LSTPTR LXI H,HEXBTE CONSOLE BUFFER RCONB EQU 10 ;READ CONSOLE BUFFER CSTAT EQU 11 ;CHECK CONSOLE STATUS LHEAD EQU 12 ;LIFT DISK HEAD RSDSK EQU 13 ;RESET DISK SYSTEM SDISK EQU 14 ;SELECT DISK OPEN EQU 15 ;OPEN FILE CLOSE EQU 16 ;CLOSE FILE SFRST EQU 17 ;SEARCH FIRST H,SRCBUF+128 SHLD SRCPTR ; SET SRC PTR TO END OF BUFFER POP B ; RESTORE ASM REGISTERS POP D LHLD PASSP ; LOAD POINTER TO PASS # MOV A,M ; GET PASS INX H SHLD PASSP POP H RET ; ; ; TABLE OF PASS NUMBERS ; PASST: DB '1230' ; ; CHARASTING FILE BUFFER HEXFCB: DS 36 ; OBJECT FILE CONTROL BLOCK HEXBUF: DS 128 ; OBJECT FILE BUFFER ; ; ; ; MACAD: LXI SP,MACRX+16EH ; SET TEMP STACK LXI H,AZM ; INSERT FILETYPE LXI D,TFCB+9 LXI B,3 ; IN TRANSIENT FCB CALL LDIR ; MOVE FILETYPE CBASE EQU 2900H ;CCP BASE ADDRESS BDOS EQU 0005H ;BDOS ENTRY POINT CONIN EQU 03E09H ;CONSOLE INPUT SUBROUTINE CONOUT EQU 03E0CH ;CONSOLE OUTPUT ROUTINE ;***********************************; ; CP/M FUNCTION CODES ; ;******************BUFFER CALL LOSIM JNC TRPSIM TRPS1: CALL POSIM ; EMPTY HEX BUFFER JNC TRPS1 CLOSAL: MVI C,CLOSE ; CLOSE ALL FILES LXI D,LSTFCB CALL BDOS MVI C,CLOSE LXI D,HEXFCB CALL BDOS JMP BOOT ; ; ; ; SIMULATE CONSOLE INPUT FOR PASS ; CONTROL EQU 27 ;GET ALLOCATION VECTOR ; ; EOF: EQU 1AH ; CP/M END OF FILE CHAR ; ; ORG 100H ; LET CP/M FIND US JMP MACAD ; ; ; TRANSIENT PROGRAM STORAGE ; DEFINITIONS ; ; ; CSTSF: DS 1 ; CONSOLE STATUS FLAG PASSP: DS 2 ; PASS TABLE POINTER SRCP SNEXT EQU 18 ;SEARCH NEXT FDELT EQU 19 ;DELETE FILE READ EQU 20 ;READ RECORD WRITE EQU 21 ;WRITE RECORD CREATE EQU 22 ;CREATE FILE RENAM EQU 23 ;RENAME FILE LOGIN EQU 24 ;GET LOGIN IDISK EQU 25 ;GET DISK NUMBER SDMA EQU 26 ;SET DMA VECTOR IALLOC LXI D,SRCFCB; GET FCB ADDRESS LHLD SRCPTR ; GET BUFFER POINTER CALL BUFIN ; READ A BYTE SHLD SRCPTR ; SAVE BUFFER POINTER POP D ; RESTORE HL,DE POP H CPI EOF ; CHECK FOR EOF CHAR STC ; SET EOF FLAG IN CARRY RZ CMC ; NOT EOF, ERASE MARK ADI '0' CPI '9'+1 JC OUTHR1 ADI '@'-'9' OUTHR1: JMP OUTCH CO: MOV A,C ; CHECK FOR PASS REQUEST CPI '=' JNZ CO1 MVI A,0FFH ; SET CONSOLE STATUS STA CSTSF CO1: MOV A,C ; SIMULATE TDL CO OUTCH: PUSH PSW ; CONSOLE OUTPUT PUSH B PUSH D RING IN BC. ; MAKEF: LXI H,TFCB PUSH D PUSH B LXI B,9 CALL LDIR ; MOVE FILENAME POP H LXI B,3 CALL LDIR ; MOVE FILETYPE MVI C,FDELT POP D PUSH D CALL BDOS ; DELETE FILE MVI C,CREATE POP D PUSH D CALL BDOS ; CREATE FILE CPI PUT NEXT CHARACTER IN A ; ; ENTER WITH FCB ADDRESS IN DE, BUFFER POINTER IN HL ; ; SAVES BC, RETURNS WITH CHAR IN A, BUFFER POINTER IN HL ; BUFIN: MOV A,E ; COMPUTE END OF BUFFER ADI SRCBUF+128-SRCFCB CMP L JNZ SRCB1 PUSH B MVI C,READ CINT ERROR TYPE JMP CLOSAL ; CLEAN UP THE MESS ; ERRMES: DB 'MACROASSEMBLER ERROR $' ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; HEXIDECIMAL REGISTER OUTPUT ; ; HEXOUT.LIB - VERSION 0.2 - 12 SEP 77 ; ;++++++++++++++++++++++++++++++DDRESS IN DE. ; RETURN WITH INITIALIZED BUFFER ; POINTER IN HL. ; REFILL: LXI H,36 ; CALC START OF BUFFER DAD D PUSH H ; SAVE START OF BUFFER PUSH D ; SAVE FCB ADDRESS XCHG PUSH B ; SAVE CP/M CODE MVI C,SDMA CALL BDOS ; SET DMA ADDRESS RET ; ; LIST CHARACTER OUTPUT ; ; CREATE AN OUTPUT BUFFER AND ; PUT EACH CHAR IN UNTIL FULL. ; THEN WRITE CONTENTS TO DISK ; FILE AND RESET POINTER. ; LOSIM: PUSH D PUSH H LHLD LSTPTR LXI D,LSTFCB CALL BUFOUT SHLD LSTPTR POP H POPCX B XRA A CMP C JNZ LDIR CMP B JNZ LDIR RET ; ; MEMORY SIZE TEST ; MEMSIM: PUSH H LHLD BDOS+1 MOV A,L MOV B,H POP H RET ; ; ; CONSOLE STATUS CHECK CSTSIM: LDA CSTSF ; CHECK CONSOLE STATUS RET ; IOCHECK ; IOSIM: MVI A 0FFH CZ ERROR MVI C,OPEN POP D PUSH D CALL BDOS ; OPEN FILE CPI 0FFH CZ ERROR POP D ; SET NEXT RECORD PTR IN FCB TO ZERO LXI H,33 DAD D MVI M,0 RET ; ; ; BLOCK MOVE (Z-80 LDIR INST) ; LDIR: MOV A,M STAX D INX H INX D DALL REFILL ANI 0FEH ; CHECK FOR GOOD READ CPI 0 POP B CNZ ERROR SRCB1: MOV A,M INX H RET ; ; ; OUTPUT BUFFER CONTROL ; ; IF BUFFER FULL, WRITE CONTENTS TO DISK, ; PUT CHAR FROM C IN BUFFER. ; ; ENTER WITH FCB ADDR IN DE, BUFFER PTR IN ++++++++++++++++ ; FUNCTIONS AVAILABLE: ; ; OUT2H PRINT 2 HEX DIGITS FROM A ; OUTHHL PRINT HL OUTHHL: MOV A,H ; PRINT HL CALL OUT2H MOV A,L OUT2H: PUSH PSW CALL OUTHL POP PSW JMP OUTHR OUTHL: RRC RRC RRC RRC OUTHR: ANI 0FH POP B ; GET CP/M CODE POP D ; GET FCB ADDRESS CALL BDOS ; READ OR WRITE BUFFER POP H ; SET PTR TO START OF BUFFER RET ; ; ; CREATE AND OPEN A FILE WITH SAME NAME AS DEFAULT FCB ; ; ENTER WITH ADDRESS OF FCB IN DE, AND ; ADDRESS OF FILETYPE ST D MOV A,C RET ; ; ; PUNCH CHARACTER OUTPUT ; ; SIMILAR TO LIST OUTPUT ; POSIM: PUSH D PUSH H LHLD HEXPTR LXI D,HEXFCB CALL BUFOUT SHLD HEXPTR POP H POP D MOV A,C RET ; ; ; SOURCE BUFFER CONTROL ; ; REFILL BUFFER IF EMPTY,,0A8H RET ; ; ; ERROR HANDLER ; ERROR: PUSH PSW LXI D,ERRMES MVI C,WCONB CALL BDOS ; WRITE ERROR MESS POP PSW POP H ; GET ADDRESS OF CALLER PUSH PSW CALL OUTHHL ; GOTO CP/M AND PRINT IT MVI C,'.' CALL CO POP PSW CALL OUT2H ; PR MVI C,WRITE CALL REFILL CPI 0 ; GOOD WRITE? POP B CNZ ERROR STC ; MARK REFILL BUFOU1: MOV M,C ; STORE CHAR IN BUFFER INX H ; MOVE PTR TO NEXT CHAR RET ; ; ; BUFFER I/O ROUTINE ; ; ENTER WITH CP/M READ OR WRITE CODE ; IN BC AND FCB AHL, ; AND CHAR IN C. ; RETURN WITH BUFFER PTR IN HL,SAVE BC,SET CARRY AFTER ; BUFFER REFILL. ; BUFOUT: MOV A,E ; COMPUTE END OF BUFFER ADI 164 CMP L ; FULL? STC ; CLEAR CARRY CMC JNZ BUFOU1 ; NOT FULL, STORE CHAR PUSH B ; FULL, SAVE CHAR PUSH H MVI C,WCON MOV E,A CALL BDOS POP H POP D POP B POP PSW RET ; NEW MACROASSEMBLER I/O VECTOR TABLE ; TO OVERWRITE PRESENT ASSEMBLER VECTOR TABLE ORG 0800H MACRX: DS 6 JMP CISIM JMP RISIM JMP CO JMP POSIM JMP LOееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееSIM JMP CSTSIM JMP IOSIM JMP MEMSIM JMP TRPSIM END ; TO OVERWRITE PRESENT ASSEMBLER VECTOR TABLE ORG 0800H MACRX: DS 6 JMP CISIM JMP RISIM JMP CO JMP POSIM JMP LOееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее