;BDOS EQU 0005H ;=================================================================== ; RAM-Disk Checking routines by W. W. COX 8/18/87 (symbol definitions) ; READCHAR EQU 1 WRITCHAR EQU 2 READKBD EQU 6 WRITBUFF EQU 9 MEMDRV EQU 'F'-'A' CONTROLP EQU 'P'-'@' BELL EQU 'G'-'@' CLRSCR EQU 0CH LF EQU 0AH CR EQU 0DH BIOS EQU 0E000H BIAS EQU BIOS WCCFC EQU 2 WCLFC EQU 9 REALCHIN EQU (03*3)+BIAS REALCOUT EQU (04*3)+BIAS REALSDSK EQU (09*3)+BIAS REALSTRK EQU (10*3)+BIAS REALSSEC EQU (11*3)+BIAS REALSDMA EQU (12*3)+BIAS REALREAD EQU (13*3)+BIAS REALWRIT EQU (14*3)+BIAS ; The following values are either.. ; (S) determined by software.. ; (H) determined by hardware.. ; (A) arbitrarily chosen by system integrator BNKPRDSK EQU 15 ; (H) Memory banks per Ram Disk RDBSH EQU 4 ; (A) Block Shift Factor (4=2k Blocks) BLKPRDIR EQU 2 ; (A) Allocation Blocks per Directory RDOFF EQU 2 ; (A) Offset past Boot Tracks KBPERBNK EQU 64 ; (H) 64K Bytes per memory bank BYTPRSEG EQU 1000H ; (H) Bytes per Memory Segment BYTPRDIR EQU 32 ; (S) Bytes per Directory Entry BYTPRSEC EQU 128 ; (S) CP/M Sector size RDBLM EQU (1.SHL.RDBSH)-1 ; Block Mask ;RDBLM EQU (1 SHL RDBSH)-1 ; Block Mask KBPERBLK EQU 1.SHL.(RDBSH-3) ; Alloc. Block size in K-bytes ;KBPERBLK EQU 1 SHL (RDBSH-3) ; Alloc. Block size in K-bytes BYTPRBLK EQU KBPERBLK*1024 ; 1K Bytes per CP/M Allocation Block BYTPRTRK EQU BYTPRSEG ; One memory segment per track SECPRTRK EQU BYTPRTRK/BYTPRSEC ; CP/M Sectors per Track KBPERTRK EQU BYTPRTRK/1024 ; K-Bytes per Track BLKPRTRK EQU BYTPRTRK/BYTPRBLK ; CP/M Allocation Blocks per Track BLKPRDSK EQU (KBPERBNK/KBPERBLK)*BNKPRDSK ; Allocation Blocks per Disk DIRPRTRK EQU BYTPRTRK/BYTPRDIR ; Directory Entries per Track DIRPRBLK EQU BYTPRBLK/BYTPRDIR ; Directory Entries per Alloc. Block TRKPRBNK EQU KBPERBNK/KBPERTRK ; Tracks per Bank TRKPRDSK EQU TRKPRBNK*BNKPRDSK ; Tracks per Disk RDDSM EQU BLKPRDSK-1 IFTRUE RDDSM.LT.256 ; IF RDDSM LT 256 BLKPRFCB EQU 16 ; Number of blocks addressable per Dir. entry ELSE BLKPRFCB EQU 8 ; Number of blocks addressable per Dir. entry ENDIF RDEXM EQU ((KBPERBLK*BLKPRFCB)/16)-1 ; Extent mask RDALLOC EQU 0FFFFH.SHL.(16-BLKPRDIR) ;RDALLOC EQU 0FFFFH SHL (16-BLKPRDIR) RDAL0 EQU RDALLOC/100H RDAL1 EQU RDALLOC.MOD.100H ;RDAL1 EQU RDALLOC MOD 100H RDKSIZE EQU KBPERBNK*BNKPRDSK RDDRM EQU (DIRPRBLK*BLKPRDIR)-1 ; Directory Entries per Directory ; Place RAM-Disk buffer in Segment immediately below BIOS RDBUFF EQU BIOS-BYTPRSEG-1000H RDSEG EQU RDBUFF/BYTPRSEG ACTULMAP EQU 600H ; Morrow Voodoo Gizmo.. IMAGEMAP EQU 200H ; ..memory map tables CPMBANK EQU 0 ; CP/M Bank is Bank 0 CPMTASK EQU 1 ; CP/M Task is Task 1 ;=================================================================== ; RDREAD EQU 0 ;READ DATA RDWRITE EQU 0FFH ;WRITE DATA ; ; END ORG 100H ; ; ; Check Ram-Disk: CHECKIT: LD DE,CHECKQRY ; Ask user if.. CALL DSPLYRTN ; ..checked READRSP1: ; LD C,READKBD ; Read.. ; LD E,0FFH ; ..response.. ; CALL BDOS ; ..from KBD: CALL REALCHIN ; ..from KBD: OR A JR Z,READRSP1 ; Loop until response given AND 5FH ; Force to Upper-Case CP 'Y' ; If NOT "Y" then.. JP NZ,0 ; ..return to CCP LD DE,DRIVEQRY ; Ask user if.. ; LD C,WRITBUFF ; ..RAM-DISK to be.. ; CALL BDOS ; ..checked CALL DSPLYRTN ; ..checked READRSP2: ; LD C,READKBD ; Read.. ; LD E,0FFH ; ..response.. ; CALL BDOS ; ..from KBD: CALL REALCHIN ; ..from KBD: OR A JR Z,READRSP2 ; Loop until response given AND 5FH ; Force to Upper-Case CP 'Y' ; If NOT "Y" then.. JP NZ,0 ; ..return to CCP DOCHECK: ; If "Y" then CHECK the RAM-DISK LD C,MEMDRV ; Select Memory Drive CALL REALSDSK ; BUFFLOOP: LD DE,BANKMSG ; Advise user.. ; LD C,WRITBUFF ; ..of what.. ; CALL BDOS ; ..we're doing CALL DSPLYRTN ; ..we're doing LD HL,(BUFFER) CALL SHOWWORD LD DE,CHECKMSG ; Advise user.. ; LD C,WRITBUFF ; ..of what.. ; CALL BDOS ; ..we're doing CALL DSPLYRTN ; ..we're doing LD A,0FFH LD (DATABYTE),A CALL FILLBUFF CALL CHECKRAM LD A,0AAH LD (DATABYTE),A CALL FILLBUFF CALL CHECKRAM LD A,055H LD (DATABYTE),A CALL FILLBUFF CALL CHECKRAM LD A,000H LD (DATABYTE),A CALL FILLBUFF CALL CHECKRAM LD HL,(BUFFER) LD BC,0-BYTPRSEC ADD HL,BC LD (BUFFER),HL XOR A ; Clear the carry flag LD BC,((PROGEND+100H)/100H)*100H SBC HL,BC JR NC,BUFFLOOP LD DE,ALLOKMSG ; LD C,WRITBUFF ; CALL BDOS CALL DSPLYRTN ; ..we're doing ; LD C,READCHAR ; Read.. ; CALL BDOS ; ..from KBD: CALL REALCHIN JP 0 FILLBUFF: LD HL,(BUFFER) LD BC,BYTPRSEC-1 ADD HL,BC PUSH HL POP DE DEC DE LD (HL),A LDDR PUSH HL POP BC CALL REALSDMA RET ; ; CHECKRAM: LD BC,TRKPRDSK ; Set tracks per RAM-Disk (rel. 0) ; TRAKLOOP: DEC BC LD (CHECKTRK),BC ; Load Track-count CALL REALSTRK ; Call BIOS set-track routine LD A,C ; If track is.. INC A . ..a multiple.. AND 0FH ; ..of 16, then.. JR NZ,SHOWPROG LD DE,NEWLINE ; ..force.. ; LD C,WRITBUFF ; ..new line.. ; CALL BDOS ; ..on screen CALL DSPLYRTN ; ..we're doing SHOWPROG: LD A,(DATABYTE) CALL SHOW2HEX LD BC,SECPRTRK ; Set sectors per RAM-Disk track (rel. 0) ; SCTRLOOP: DEC BC LD (CHECKSEC),BC CALL REALSSEC CALL REALWRIT LD BC,(CHECKSEC) ; Load sector-count CALL REALSSEC CALL REALREAD LD A,(DATABYTE) LD HL,(BUFFER) LD BC,BYTPRSEC+1 COMPLOOP: CPI JP PO,SECTOROK ; If BC=0, then we didn't find any non-match JR Z,COMPLOOP ; ERROR !!!!!!!!!!!! LD DE,ERRORMSG ; LD C,WRITBUFF ; CALL BDOS CALL DSPLYRTN ; ..we're doing CALL SHOWWORD LD DE,TRACKMSG ; LD C,WRITBUFF ; CALL BDOS CALL DSPLYRTN ; ..we're doing LD HL,(CHECKSEC) CALL SHOWWORD LD DE,SECTRMSG ; LD C,WRITBUFF ; CALL BDOS CALL DSPLYRTN ; ..we're doing LD HL,(CHECKTRK) CALL SHOWWORD LD DE,HARDHALT ; LD C,WRITBUFF ; CALL BDOS CALL DSPLYRTN ; ..we're doing JR $ SECTOROK: LD BC,(CHECKSEC) LD A,B OR C JR NZ,SCTRLOOP LD BC,(CHECKTRK) LD A,B OR C JR NZ,TRAKLOOP RET ; BDOS: LD C,E JP REALCOUT BUFFER DW BIOS-1000H-BYTPRSEC ; Start buffering just below RAM-Buffer CHECKTRK DW 0 CHECKSEC DW 0 NUMWORK DB '00000',0 INDEXSAV DW 0 PRNTTOGL DB 0 DATABYTE DB 0 ; CHECKQRY DB CLRSCR,LF,LF,LF,LF,'Do you wish to CHECK the RAM-DISK?' DB CR,LF,LF DB 'DOING SO WILL DESTROY THE ENTIRE CONTENTS OF THE RAM-Disk!' DB '(Y/N): $',0 DRIVEQRY DB CR,LF,LF,LF,'Continuing will destroy ALL data on Drive ' RAMDRIVE DB MEMDRV+'A',CR,LF,LF DB 'OPEN ALL DISK DRIVE DOORS TO PROTECT THEM!!!!!!!!!!',CR,LF,LF DB 'Do you still wish to continue? ' DB '(Y/N): $',0 CHECKMSG DB CR,LF,LF,' 0 1 2 3 4 5 6 7 8 9 A B C D E F' NEWLINE DB CR,LF,'$',0 BANKMSG DB CR,LF,'Checking Bank $',0 ERRORMSG DB CR,LF,LF,'Error on RAM-disk at Buffer Address $',0 TRACKMSG DB CR,LF,LF,'Track = $',0 SECTRMSG DB CR,LF,LF,'Sector = $',0 HARDHALT DB CR,LF,LF,'HARD HALT, REBOOT REQUIRED!!!$',0 ALLOKMSG DB CR,LF,LF,'All OK, reformat RAM-Disk before using!!!' DB CR,LF,LF,'STRIKE ANY KEY TO RETURN TO CP/M: $',0 SENDCRLF: ; Displays a carriage-return/line-feed to screen ; ; On entry: No values are input ; ; On exit: No values are returned ; ; A-reg is scratch LD A,CR ; Send.. CALL PRNTCHAR ; ..CR,.. LD A,LF ; .. LF.. PRNTCHAR: ; Displays a byte to screen ; ; On entry: A = Input byte ; ; On exit: No values are returned ; ; All regs and Flags are SAVED PUSH AF PUSH BC PUSH DE PUSH HL LD E,A PUSH DE ; Save the data byte LD C,WCCFC CALL BDOS POP DE ; Restore the data byte ; LD A,(PRNTTOGL) ; ; OR A ; JR Z,DONTBEEP ; LD C,WCLFC ; CALL BDOS DONTBEEP: POP HL POP DE POP BC POP AF ; NULLRUTN: ; Dummy routine (just an EXIT) RET ; ; DSPLYRTN: ; Displays a string (terminated by a zero byte) to screen ; ; On entry: DE-reg contains string address ; ; On exit: Zero flag set if I/O was OK ; ; DE-reg, A-reg and Flags are scratch DSPLYLUP: LD A,(DE) INC DE OR A CALL NZ,PRNTCHAR JR NZ,DSPLYLUP RET ; ; SHOMESAG: ; Displays an error message to the screen (as a buffer string) ; ; On entry: No values passed ; ; On exit: No values returned ; ; A-reg and Flags are scratch LD A,(PRNTTOGL) PUSH AF XOR A LD (PRNTTOGL),A CALL DSPLYRTN POP AF LD (PRNTTOGL),A RET ; ; ; ; DIVIDE: ; Divides 16-bit dividend by 16-bit divisor, giving.. ; ; ..16-bit quotient ; ; On entry: HL = Dividend, BC = Divisor ; ; On exit: HL = Qoutient, DE = Remainder.. ; ; If carry is clear, then zero-divide was attempted ; ; All regs and and Flags are scratch LD A,C ; Test for division by zero.. RRA ; ..or 1, return with carry.. OR B ; ..clear on zero-divide.. RET Z ; ..error, carry set if anything else SCF ; Force "zero divide" flag to OFF LD DE,0 ; Set quotient/remainder value to zero LD A,L ; If dividend is zero.. OR H ; ..then return a quotient of zero.. RET Z ; ..and a remainder of zero XOR A DIVIDLUP: SBC HL,BC ; Subtract one divisor value INC DE ; Bump quotient by one JR NC,DIVIDLUP ; Loop until remainder goes negative ADD HL,BC ; Back up remainder by one divisor value DEC DE ; Back up quotient by one EX DE,HL ; Swap remainder and quotient SCF ; Reset "zero divide" flag to OFF RET ; ; MULTIPLY: ; Multiply a 16-bit multiplicand by an 8-bit multiplier ; ; On Entry: DE = Multiplicand, A = Multiplier ; ; On Exit: HL = Product ; ; A-reg & Flags are scratch PUSH BC LD B,8 LD HL,0 MULTLOOP: ADD HL,HL ADD A,A JR NC,PASCOUNT ADD HL,DE PASCOUNT: DJNZ MULTLOOP POP BC RET ; ; BUILDDEC: ; Builds the decimal value of a word, as: "01234" ; ; On entry: HL = Input word ; ; On exit: Decimal value is in (NUMWORK) ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL EX DE,HL LD HL,NUMWORK LD (INDEXSAV),HL EX DE,HL LD B,0 LD DE,-10000 CALL SUBTR LD DE,-1000 CALL SUBTR LD DE,-100 CALL SUBTR LD DE,-10 CALL SUBTR LD A,L ADD A,'0' LD HL,(INDEXSAV) LD (HL),A POP HL POP DE POP BC RET ; ; SUBTR: ; Computes the one digit decimal quotient (expressed as.. ; ; ..an ASCII character) of a 16-bit binary dividend divided.. ; ; ..by a 16-bit binary divisor representing some power of 10 ; ; On entry: HL = Dividend, DE = Power of 10 value ; ; On exit: C-reg = ASCII quotient ; ; DE-reg, C-reg, A-reg and Flags are scratch ; ; Also saves digit in (NUMWORK) and bumps (INDEXSAV) LD C,'0'-1 SUBTR2: INC C ADD HL,DE JR C,SUBTR2 SBC HL,DE EX DE,HL LD HL,(INDEXSAV) LD (HL),C INC HL LD (INDEXSAV),HL EX DE,HL RET ; ; SHOWDEC: ; Displays a word in decimal, as: "01234" ; ; On entry: HL = Input word, A = Field width ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD B,A ; Save field width CALL BUILDDEC LD DE,NUMWORK LD HL,0 XOR A SUB B JR Z,ZEROSUPP ADD A,6 LD L,A JR CALCSHFT ; ZEROSUPP: LD A,(DE) CP '0' INC DE JR Z,ZEROSUPP OR A JR NZ,CALCSHFT DEC DE ; CALCSHFT: DEC HL ADD HL,DE EX DE,HL CALL DSPLYRTN POP HL POP DE POP BC RET ; ; SHOW2HEX: ; Displays a byte in hex, as: "D2" ; ; On entry: A = Input byte ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH AF ; Save input byte RRA RRA RRA RRA CALL SHOW1HEX POP AF ; Restore input byte SHOW1HEX: ; Displays a nibble in hex, as: "D" ; ; On entry: A = Input byte ; ; On exit: No value is returned ; ; A-reg and Flags are scratch AND 0FH CP 10 JR C,HEX2 ADD A,'A'-('9'+1) HEX2: ADD A,'0' CALL PRNTCHAR RET ; SHOW4HEX: ; Displays a word in hex, as: "04D2" ; ; On entry: HL = Input word ; ; On exit: No value is returned ; ; A-reg and Flags are scratch LD A,H CALL SHOW2HEX LD A,L CALL SHOW2HEX RET ; SHOWWORD: ; Displays a word in hex, as: "(04D2)" ; ; On entry: HL = Input word ; ; On exit: No value is returned ; ; A-reg and Flags are scratch LD A,'(' CALL PRNTCHAR CALL SHOW4HEX LD A,')' CALL PRNTCHAR RET ; SHOWDCHX: ; Displays a word in both decimal and hex, as: "01234 (04D2)" ; ; On entry: HL = Input word, A = Field width ; ; On exit: No value is returned ; ; A-reg and Flags are scratch CALL SHOWDEC LD A,' ' CALL PRNTCHAR CALL SHOWWORD RET ; ; SHOWBIN: ; Displays a data byte in binary, as "10101100" ; ; On entry: A = data byte ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC LD C,A LD B,8 BIT2: LD A,C ADD A,A LD C,A LD A,'0'/2 ADC A,A CALL PRNTCHAR DJNZ BIT2 POP BC RET ; ; PROGEND: END