; COPYRIGHT 1987 WALLACE W. COX ; ; DRIVUSER EQU 0004H ; Default drive and user ID. ; BDOS EQU 0005H ; Define BDOS link pointer ; CCPFCB1 EQU 005CH DMAAREA EQU 0080H ; Define CP/M default DMA area TPA EQU 0100H ; HOMEHEAD EQU 3*07 ; Define BIOS home head function SELDRIVE EQU 3*08 ; Define BIOS drive select function SETTRACK EQU 3*09 ; Define BIOS set track function SETSECTR EQU 3*10 ; Define BIOS set sector function SETDMA EQU 3*11 ; Define BIOS set DMA function READDISK EQU 3*12 ; Define BIOS read disk sector function WRITDISK EQU 3*13 ; Define BIOS write disk sector function SECTRAN EQU 3*15 ; Define BIOS sector translate function ; RCCFC EQU 01 ; Define BDOS read console character code WCCFC EQU 02 ; Define BDOS write console character code WCLFC EQU 05 ; Define BDOS write LST: character code DIOFC EQU 06 ; Define BDOS direct console I/O function code WCBFC EQU 09 ; Define BDOS write console buffer code GETSTRFC EQU 10 ; Define BDOS read console buffer function code RCSFC EQU 11 ; Define BDOS read console status code CPMVERFC EQU 12 ; Define BDOS get CP/M version code RSETDSKS EQU 13 ; Define BDOS reset disks function code SETDSKFC EQU 14 ; Define BDOS set drive code OPENFC EQU 15 ; Define BDOS open disk file function code READFC EQU 20 ; Define BDOS read disk sector function code SETDMAFC EQU 26 ; Define BDOS set DMA code GETDPBFC EQU 31 ; Define BDOS get DPB code ; SYSTMFCB EQU 05CH ; Default system FCB FCBDRIVE EQU 00 ; Disk name displacement FCBFNAME EQU 01 ; File name displacement FCBFTYPE EQU 09 ; File type displacement FCBEXTNT EQU 12 ; File extent displacement FCBRECNT EQU 15 ; Record count displacement FCBNXTRC EQU 32 ; Next record displacement ; ; ; HEXFF EQU 0FFH ; LF EQU 0AH ; Define line-feed byte CR EQU 0DH ; Define carriage-return byte CONTROLC EQU 'C'-'@' ; Define Ctrl-C byte CONTROLP EQU 'P'-'@' ; Define Ctrl-P byte CONTROLS EQU 'S'-'@' ; Define Ctrl-S byte ; CLEARSCR ; Define Clear screen.. EQU 'L'-'@' ; ..(^L for LSI and Wyse.. ; EQU 'Z'-'@' ; ..^Z for Sanyo) ; FORMFEED EQU 'L'-'@' ; ; BASETIME EQU 500 ; Minimum display loop pacing value ; ESC EQU 1BH ; Define "ESC" code for cursor positioning ESC sequence CTLFACTR EQU 20H ; Adjustment factor for cursor positioning ESC sequence ; SGMNTSIZ EQU 16 ; Define size of one dump image line (segment) SECTRSIZ EQU 128 ; Define size of one CP/M sector ASCOFSET EQU (SGMNTSIZ*3)+2 ; Define displacement of ASCII image in dump ; FIRSTLIN EQU 0 FIRSTCOL EQU 0 ; MENULIN EQU 0 MENUCOL EQU 0 ; SINONLIN EQU 10 SINONCOL EQU 0 ; STATLIN EQU 20 STATCOL EQU 0 ; MESAGLIN EQU 22 MESAGCOL EQU 0 ; CMANDLIN EQU 23 CMANDCOL EQU 0 ; ; BREAK EQU 03H ; ^C WSRIGHT EQU 0DH ; ^D WSUP EQU 0EH ; ^E BELL EQU 07H ; ^G BAKSPACE EQU 08H ; ^H LEFT EQU 08H ; ^H TAB EQU 09H ; ^I DOWN EQU 0AH ; ^J UP EQU 0BH ; ^K RIGHT EQU 0CH ; ^L WSLEFT EQU 13H ; ^S PAUSE EQU 13H ; ^S OBLIQUE EQU 14H ; ^T UNDOCMND EQU 15H ; ^U CTRLW EQU 17H ; ^W WSDOWN EQU 18H ; ^X DEL EQU 7FH ; Delete (DEL) ; ;ARROWS : SET OF CHAR = [^S, ^E, ^D, ^X, LEFT, UP, RIGHT, DOWN, OBLIQUE]; ;HEX_ASCII : ARRAY [FALSE..TRUE] OF STRING [9] = ('hex/ASCII', 'HEX/ascii'); ; UPCASMSK EQU 01011111B ; Define mask to force upper-case PARTYMSK EQU 01111111B ; Define mask to clear parity bit ; RETRYCNT EQU 5 ; Define disk I/O retry count LINBYTCT EQU 16 ; Define number of bytes per dump line MAXDRIVE EQU 16 ; Define number of legal drives under CP/M ; ; ORG 100H ; JP START ; TRACE: PUSH BC PUSH DE PUSH HL PUSH AF CALL SENDCRLF POP AF CALL SHOW2HEX POP HL POP DE POP BC RET ; ; SETDMART: ; Sets the DMA area ; ; On entry: DE = New DMA area address ; ; On exit: Zero flag set if everything was OK ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD C,SETDMAFC CALL BDOS POP HL POP DE POP BC RET ; ; CPMVER: ; Obtains the CP/M version from BDOS ; ; On entry: No values are input ; ; On exit: No values are returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD C,CPMVERFC CALL BDOS POP HL POP DE POP BC RET ; ; CHEKDRIV: ; Checks for a valid drive ID. ; ; On entry: A = Drive ID (as a letter) ; ; On exit: C = Drive ID (in binary) ; ; C-reg, A-reg and Flags are scratch AND UPCASMSK ; Force to upper-case. SUB 'A' ; Convert drive letter to number RET C ; ..if not "A".."N" LD C,A ; Save drive# in C-reg. LD A,MAXDRIVE ; Syntax error.. CP C ; ..if not "A".."N" RET ; ; KBDPOLL: ; Polls keyboard for any keystroke (for "abort" tests, etc.) ; ; On entry: No values are input ; ; On exit: A-reg = data byte, or zero if none ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD C,DIOFC LD E,HEXFF CALL BDOS OR A POP HL POP DE POP BC RET ; ; TIMER: ; Loops for delay purposes ; ; On entry: HL = Delay interval ; ; On exit: No values are returned ; ; HL-reg, A-reg and Flags are scratch PUSH BC PUSH DE TIMELOOP: DJNZ $ CALL KBDPOLL JR NZ,TIMEX DEC L JR NZ,TIMELOOP DEC H JR NZ,TIMELOOP TIMEX: POP DE POP BC RET ; ; BLANKSCR: ; Clears screen; also forces form-feed if LST: echo is on ; ; On entry: No values are input ; ; On exit: No values are returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE LD E,CLEARSCR LD C,WCCFC CALL BDOS LD A,(PRNTTOGL) OR A JR Z,NOOVRFLO LD E,FORMFEED LD C,WCLFC CALL BDOS NOOVRFLO: POP DE POP BC RET ; ; 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 ; ; CLEARMSG: ; Clears any previous error message from the screen ; ; On entry: No values passed ; ; On exit: Zero flag set if I/O was OK ; ; DE-reg is scratch; A-reg and Flags are SAVED PUSH AF LD DE,BLANKMSG CALL SHOMESAG LD DE,BLANKLIN CALL SHOMESAG POP AF RET ; ; TOGLPRNT: ; Toggle the LST: echo ; ; On entry: No values are input ; ; On exit: ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD A,(PRNTTOGL) ; Get the LST: toggle value CPL ; Reset to new value OR A ; Are we turning it off? JR Z,DONTRING ; Yes, so don't warn the user PUSH AF ; No, we're turning it on, so.. LD A,BELL ; ..warn the.. CALL PRNTCHAR ; ..user POP AF ; Restore the LST: toggle value DONTRING: LD (PRNTTOGL),A ; Set LST: echo to new value XOR A ; Force zero flag POP HL POP DE POP BC RET ; ; GETINPUT: ; Polls keyboard until any keystroke, then reads it ; ; On entry: No values are input ; ; On exit: A-reg = data byte ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL GETLOOP: CALL KBDPOLL JR Z,GETLOOP CP CONTROLP ; Is user setting or resetting LST: echo? CALL Z,TOGLPRNT ; Yes, so call the LST: echo toggle routine POP HL POP DE POP BC 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 ; ; SHOWBLOK: ; Displays current CP/M Block # (for status line & headers) ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD DE,BLOKLGND CALL DSPLYRTN LD HL,(DIROFSET) EX DE,HL LD HL,(CURRTRAK) XOR A SBC HL,DE LD BC,SYSLEGND JR C,SHOWLGND EX DE,HL ; PUSH DE LD A,(SECPERTK+1) CALL MULTIPLY POP DE LD B,L LD C,0 LD A,(SECPERTK) CALL MULTIPLY ADD HL,BC ; LD DE,(CURRSCTR) DEC DE ADD HL,DE LD DE,(SECPERDR) XOR A SBC HL,DE LD BC,DIRLEGND JR C,SHOWLGND LD BC,(SECPERBK) ; Divide result by sectors per block, CALL DIVIDE ; ..giving the current block LD A,4 CALL SHOWDEC LD BC,NOLEGND SHOWLGND: PUSH BC ; Move legend.. POP DE ; ..address to DE CALL DSPLYRTN POP HL POP DE POP BC RET ; SHOWSTAT: ; Displays current Drive, Track, Sector, and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch ; ; Entry point for floating status line PUSH BC PUSH DE PUSH HL LD DE,TRAKLGND CALL DSPLYRTN LD HL,(CURRTRAK) LD A,4 ; Set field width CALL SHOWDEC LD DE,SCTRLGND CALL DSPLYRTN LD HL,(CURRSCTR) LD A,3 ; Set field width CALL SHOWDEC CALL SHOWBLOK POP HL POP DE POP BC RET ; SHOSTLIN: ; Displays current Drive/Track/Sector/Block on status line ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH DE LD A,(PRNTTOGL) ; Get the current LST: toggle value PUSH AF ; Save it XOR A ; Turn it.. LD (PRNTTOGL),A ; ..off (temporarily) LD DE,STATLGND CALL DSPLYRTN CALL SHOWSTAT LD DE,BUMPLGND CALL DSPLYRTN POP AF ; Restore the LST: echo toggle.. LD (PRNTTOGL),A ; ..to its original value POP DE RET ; ; HOMEADDR: ; Resets current track to first directory track, current.. ; ; ..sector to 1, re-displays current Drive, Track, Sector.. ; ; ..and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH HL LD HL,(DIROFSET) LD (CURRTRAK),HL LD HL,1 LD (CURRSCTR),HL CALL SHOSTLIN POP HL RET ; BUMPTRAK: ; Increments current track 1, checks for disk wrap, then.. ; ; ..re-displays current Drive, Track, Sector, and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH DE PUSH HL LD DE,(CURRTRAK) LD HL,(MAXTRACK) INC DE XOR A SBC HL,DE JR Z,NOTWRAPB EX DE,HL NOTWRAPB: LD (CURRTRAK),HL CALL SHOSTLIN POP HL POP DE RET ; DROPTRAK: ; Decrements current track by 1, checks for disk wrap, then.. ; ; ..re-displays current Drive, Track, Sector, and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH HL LD HL,(CURRTRAK) LD A,L OR H DEC HL JR NZ,NOTWRAPD LD HL,(MAXTRACK) NOTWRAPD: LD (CURRTRAK),HL CALL SHOSTLIN POP HL RET ; BUMPSCTR: ; Increments current sector by 1, checks for track wrap, then.. ; ; ..re-displays current Drive, Track, Sector, and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH DE PUSH HL LD DE,(CURRSCTR) INC DE LD HL,(SECPERTK) XOR A SBC HL,DE JR NC,STORSECB LD DE,1 STORSECB: LD (CURRSCTR),DE PUSH AF ; Save flags in case we need to call.. CALL C,BUMPTRAK ; ..BUMPTRAK on a track wrap, then.. POP AF ; ..restore FLAGS, but don't show.. CALL NC,SHOSTLIN ; ..status if DROPTRAK was called POP HL POP DE RET ; DROPSCTR: ; Decrements current sector by 1, checks for track wrap, then.. ; ; ..re-displays current Drive, Track, Sector, and CP/M Block ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH HL LD HL,(CURRSCTR) DEC HL LD A,H OR L JR NZ,STORSECD LD HL,(SECPERTK) STORSECD: LD (CURRSCTR),HL PUSH AF ; Save flags in case we need to.. CALL Z,DROPTRAK ; ..call DROPTRAK on a track wrap.. POP AF ; ..then restore FLAGS, but don't.. CALL NZ,SHOSTLIN ; ..show status if DROPTRAK called POP HL RET ; GETSECTR: ; Gets 128-byte CP/M sector from current drive/track/sector ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD DE,DMAAREA LD A,(CURRSCTR) LD H,A XOR A SRA H RRA LD L,A LD BC,128 LDIR POP HL POP DE POP BC RET ; SHOWASCI: ; Display an ASCII data byte (or a dot if byte unprintable) ; ; On entry: A=data byte ; ; On exit: No value is returned ; ; A-reg and Flags are scratch CP ' ' JR C,SHOWDOT CP DEL JR C,NODOT SHOWDOT: LD A,'.' NODOT: CALL PRNTCHAR RET ; SHOWSGMT: ; Displays one 16-byte segment (one screen line) of sector dump ; ; On entry: B= 8-segment #, HL = data address ; ; On exit: HL incremented to next segment address ; ; DE, A-reg and Flags are scratch PUSH BC PUSH HL EX DE,HL LD A,8 SUB B RLA RLA RLA RLA LD L,A LD H,0 LD A,4 ; Set field width CALL SHOWDCHX LD A,' ' CALL PRNTCHAR CALL PRNTCHAR LD B,16 HEXLOOP: LD A,(DE) CALL SHOW2HEX INC DE LD A,' ' CALL PRNTCHAR DJNZ HEXLOOP CALL PRNTCHAR CALL PRNTCHAR LD B,16 POP HL ASCILOOP: LD A,(HL) INC HL CALL SHOWASCI DJNZ ASCILOOP CALL SENDCRLF POP BC RET ; SHOWHEAD: ; Displays heading legend line for sector dump ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH DE LD DE,DCHXLGND CALL DSPLYRTN CALL SHOWSTAT LD DE,SCALE CALL DSPLYRTN POP DE RET ; SHOWSCTR: ; Displays an entire 128-byte CP/M sector in hex and ASCII ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL CALL SHOWHEAD LD HL,DMAAREA LD B,8 SHOSGLUP: CALL SHOWSGMT DJNZ SHOSGLUP LD HL,128 ; Display ending offset values LD A,4 ; Set field width CALL SHOWDCHX CALL SENDCRLF CALL SENDCRLF POP HL POP DE POP BC RET ; DUMPSCTR: ; Gets from disk one entire 128-byte CP/M sector.. ; ; ..and displays it in hex and ASCII on a cleared screen ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch CALL BLANKSCR ; Clear the screen CALL GETSECTR ; Get and.. CALL SHOWSCTR ; ..display one sector CALL SHOSTLIN ; Display status line RET ; ; DUMPTRAK: ; Displays an entire track of 128-byte CP/M sectors ; ; On entry: All values are in memory ; ; On exit: Current Track is incremented in memory ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD HL,1 ; Reset current sector.. LD (CURRSCTR),HL ; ..to start of track LD A,(SECPERTK) ; Load.. LD B,A ; ..sector loop counter SHOTKLUP: LD DE,DLAYLGND ; Display scroll pause and.. CALL SHOMESAG ; ..speed change instructions CALL GETSECTR ; Get and.. CALL SHOWSCTR ; ..display one sector LD HL,(CURRSCTR) ; Bump.. INC HL ; ..current.. LD (CURRSCTR),HL ; ..sector LD HL,(DUMPDLAY) ; Load dump delay value CALL TIMER ; Call timer routine JR Z,LOOPTEST ; No - go test for end of track DECODPOL: ; Yes - what kind? CP CONTROLC ; Abort?? JR Z,ABORTDMP ; Yes - go to exit track dump CP '9'+1 ; Scroll speed or pause (1-9 or 0)? JR NC,LOOPTEST ; > 9, so go test for end of track SUB '0' ; Convert digit to binary JR C,LOOPTEST ; < 0, so go test for end of track JR NZ,SETTIMER ; 1..9, so go set new delay value RECALPOL: CALL KBDPOLL ; It is a pause (input=0), so.. JR Z,RECALPOL ; ..test for.. JR DECODPOL ; ..restart ; SETTIMER: ; Set scroll speed LD DE,BASETIME ; Set multiplier CALL MULTIPLY ; Multiply user digit by multiplier LD (DUMPDLAY),HL ; Set dump delay value LOOPTEST: DJNZ SHOTKLUP ; Test for end of track ABORTDMP: LD DE,FORCEUP ; Force last sector displayed.. CALL DSPLYRTN ; ..to the top of screen LD HL,(CURRTRAK) ; Bump.. INC HL ; ..to next.. LD (CURRTRAK),HL ; ..track CALL SHOSTLIN ; Display current drive/track/sector POP HL POP DE POP BC RET ; EDITHOME: ; Reset edit cursor position to first byte of sector ; ; On entry: C=Current value of position index ; ; On exit: A=New value of position index ; ; All regs and Flags are scratch XOR A JR MODULO ; Go to update screen indicator ; BUMPBYTE: ; Increment cursor pointer by one column ; ; On entry: C=Current value of position index ; ; On exit: A=New value of position index ; ; All regs and Flags are scratch LD A,C INC A JR MODULO ; Go to update screen indicator ; DROPBYTE: ; Decrement cursor pointer by one column ; ; On entry: C=Current value of position index ; ; On exit: A=New value of position index ; ; All regs and Flags are scratch LD A,C DEC A JR MODULO ; Go to update screen indicator ; BUMPSGMT: ; Increment cursor pointer by one 16-byte segment (screen line) ; ; On entry: C=Current value of position index ; ; On exit: A=New value of position index ; ; All regs and Flags are scratch LD A,SGMNTSIZ ADD A,C JR MODULO ; Go to update screen indicator ; DROPSGMT: ; Decrement cursor pointer by one 16-byte segment (screen line) ; ; On entry: C=Current value of position index ; ; On exit: A=New value of position index ; ; All regs and Flags are scratch LD A,C SUB SGMNTSIZ ; ; Fall into MODULO routine, return to caller thru there ; MODULO: ; Adjust cursor pointer in case of wrap-around, update.. ; ; ..screen position indicator ; ; On entry: A=Updated value of position index ; ; On exit: C=Adjusted value of position index ; ; All regs and Flags are scratch AND SECTRSIZ-1 ; If pointer went over sector.. ; ; ..size, then adjust it back LD C,A ; Restore pointer into C-reg LD L,A ; Move byte.. LD H,0 ; ..pointer into HL-reg LD DE,CURBYPOS ; Set cursor to current byte.. CALL SHOMESAG ; ..position indicator on screen LD A,4 ; Set field width CALL SHOWDCHX ; Update indicator value on screen RET ; ; SHOWMODE: ; Show current editing mode (input in hex or input in ASCII) ; ; On entry: A = Current value of mode toggle ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD DE,HXASCLEN ; Display.. CALL MULTIPLY LD DE,HXASCPOS CALL SHOMESAG LD DE,HEXASCII ADD HL,DE EX DE,HL CALL SHOMESAG ; ..editing mode POP HL POP DE POP BC RET ; TOGLMODE: ; Toggle edit mode (hex/ASCII) ; ; On entry: No value is entered ; ; On exit: No value is returned ; ; A-reg and Flags are scratch LD A,(MODETOGL) ; Toggle.. XOR 1 ; ..hex/ASCII.. LD (MODETOGL),A ; ..mode CALL SHOWMODE ; Display current mode RET ; EDTCMDER: ; Invalid command in Edit Mode ; procedure currently dummied!!!!!!!!!!! RET ; SETCURSR: ; Positions cursor within sector image in editing display ; ; On entry: B = Mode Toggle, C = byte offset ; ; On exit: No value is returned ; ; All regs and Flags are scratch EXCEPT BC-regs ; ; Determine correct.. LD A,C ; ..cursor position RRA ; Compute.. RRA ; ..16-byte.. RRA ; ..segment. RRA ; ..offset.. AND (SECTRSIZ/SGMNTSIZ)-1 ; ..value INC A ; Bump past the header line ADD A,CTLFACTR ; Add in escape-sequence adjustment LD (EDITLINE),A ; Set into escape-sequence string LD A,B ; Get mode toggle RRA ; Stick it.. RRA ; ..into high-order LD H,A ; ..bit of HL-reg LD A,C ; Compute offset.. AND SGMNTSIZ-1 ; ..within the 16-byte segment LD L,A ; If doubling HL causes a carry, then.. ADD HL,HL ; ..mode bit was set to HEX, so.. JR C,ADDOFSET ; ..use byte offset * 3. If NOT set.. LD L,ASCOFSET ; ..use byte offset + ASCII offset ADDOFSET: ADD A,L ADD A,CTLFACTR+DCHLLNTH ; Add in escape-sequence and leadin LD (EDITCOL),A LD DE,EDTESCSQ ; Set pointer to edit escape sequence CALL SHOMESAG ; Write cursor positioning sequence RET ; ; REWRITE: ; Rewrite changed sector to disk ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH DE XOR A ; Reset.. LD (UPDATFLG),A ; .."file changed" flag CALL CLEARMSG LD DE,DIDUPDAT CALL SHOMESAG POP DE RET ; CHEKNIBL: ; Check one input byte for valid hex value ; ; On entry: A=data byte ; ; On exit: L=Hex value, OR A=zero on error ; ; A-reg and Flags are scratch SUB '0' CP 10 JR C,NIBBLEOK SUB 'A'-'9'-1 NIBBLEOK: LD L,A AND 0F0H RET Z LD A,BELL ; Alert user.. CALL PRNTCHAR ; ..to error RET ; CHECKHEX: ; Check input in HEX mode for valid hex values ; ; On entry: H=First nibble ; ; On exit: H=Data byte value, A=zero on error ; ; HL-reg, A-reg and Flags are scratch LD A,H ; Recover first nibble CALL CHEKNIBL ; Check that it's OK RET NZ LD A,L ; Recover.. RLA ; ..the high-order.. RLA ; ..nibble.. RLA ; ..shift it.. RLA ; ..into high order.. LD H,A ; ..half of H-reg CALL GETINPUT ; Get second nibble CALL CHEKNIBL ; Check that it's OK RET NZ ; Return with error set if not LD A,H ; Recover high-order nibble ADD A,L ; Combine with low-order LD H,A ; Place resulting byte into H-reg XOR A ; Force zero flag to signal data OK RET ; ; SAVRSTOR: ; Save or restore the current sector image ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; All regs and Flags are scratch LD BC,128 ; Save or (or restore).. LD DE,SAVEAREA ; ..original.. LD HL,DMAAREA ; ..sector image: JR C,DONTSWAP ; Depending on state of "carry flag".. EX DE,HL ; ..carry set = Save; reset = restore DONTSWAP: LDIR ; ..image (This also ZEROS BC-regs) RET ; ; UNDOEDIT: ; Resets sector image to original value ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; All regs and Flags are scratch LD A,(UNDOFLAG) ; Was last input.. CP ESC ; ..a cursor move? JR C,CANTUNDO ; Yes - clear the message line & exit XOR A ; No - so set.. LD (UNDOFLAG),A ; .."don't undo" flag LD DE,UNDOQURY CALL SHOMESAG CALL GETINPUT CALL CLEARMSG AND UPCASMSK CP 'Y' JR NZ,CANTUNDO LD DE,DIDUNDO CALL SHOMESAG XOR A ; Set carry flag off (restore) CALL SAVRSTOR ; Call the Save/Restore routine LD DE,CURSRHOM ; Home the... CALL SHOMESAG ; ..cursor CALL SHOWSCTR ; Re-display it LD A,(MODETOGL) ; Load mode.. LD B,A ; ..toggle (C-reg zeroed by LDIR) JR EDITLOOP ; CANTUNDO: LD DE,DINTUNDO CALL SHOMESAG JR EDITLOOP ; ; I know it's dumb to jump to the next instruction, but humor me!!! ; EDITPROC: ; Process sector edit commands and cursor moves ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; All regs and Flags are scratch EDITLOOP: CALL SETCURSR ; Position cursor in sector image CALL GETINPUT ; Get edit command or data byte PUSH AF ; Clear any.. CALL CLEARMSG ; ..previous.. POP AF ; ..messages CP DEL ; Test for.. JR Z,UNDOEDIT ; ..Un-Do command CP UNDOCMND ; Test for alternate (WS style).. JR Z,UNDOEDIT ; ..Un-Do command LD (UNDOFLAG),A ; Set value of un-do FLAG LD HL,CASETBL3 ; Set up for.. CP ESC ; ..control character command JR Z,UPDATTST ; Input is an EXIT command JR NC,INSERTIT ; Input is a data byte CALL CASE ; Input is a cursor move command LD A,(MODETOGL) ; Re-load.. LD B,A ; ..mode toggle JR EDITLOOP ; Go to get and process next input ; INSERTIT: LD H,A ; Save data byte LD A,B ; Test for.. OR A ; ..hex mode CALL NZ,CHECKHEX ; Is so, go to validate byte; If zero.. JR NZ,EDITLOOP ; ..flag still off on return, data bad INC A ; Set.. LD (UPDATFLG),A ; .."sector modified" flag LD A,(UNDOFLAG) ; Is this the first.. CP ESC ; ..change since last cursor move JR NC,DONTSAVE ; No - don't save again CALL SAVRSTOR ; Yes - save the sector image for UN-DO DONTSAVE: LD A,H ; Restore data byte LD B,0 ; Set mode to ASCII (temporarily) LD HL,DMAAREA ; Set pointer to data area ADD HL,BC ; Add offset into sector image LD (HL),A ; Insert data byte into sector image PUSH AF ; Save data byte CALL SETCURSR ; Position cursor in ASCII image POP AF ; Restore data byte PUSH AF ; Save data byte CALL SHOWASCI ; DUMP data byte in ASCII (or '.') POP AF ; Restore data byte INC B ; Set mode to hex (temporarily) PUSH AF ; Save data byte CALL SETCURSR ; Position cursor in HEX image POP AF ; Restore data byte CALL SHOW2HEX ; Display the data byte in HEX image LD A,(MODETOGL) ; Recover original.. LD B,A ; ..mode toggle value CALL BUMPBYTE ; Bump data pointer JR EDITLOOP ; Go get and process next input ; UPDATTST: LD A,(UPDATFLG) OR A RET Z LD DE,UPDATQRY CALL SHOMESAG CALL GETINPUT CALL CLEARMSG LD DE,NOUPDATE AND UPCASMSK CP 'Y' JR NZ,DONTUPDT CALL REWRITE LD DE,DIDUPDAT DONTUPDT: CALL SHOMESAG LD DE,EDXITQRY CALL SHOMESAG CALL GETINPUT AND UPCASMSK CP 'Y' ; JR NZ,EDITLOOP JP NZ,EDITLOOP RET ; ; EDITSCTR: ; Displays an entire 128-byte CP/M sector in hex and ASCII.. ; ; ..and allows on screen editing in hex or ASCII mode ; ; On entry: All values are in memory ; ; On exit: No value is returned ; ; A-reg and Flags are scratch PUSH BC PUSH DE PUSH HL LD A,(PRNTTOGL) ; Get the LST: toggle value OR A ; Is it set to ECHO mode? JR Z,DONTHONK ; No, so don't bother the user XOR A ; Set LST: echo toggle OFF.. LD (PRNTTOGL),A ; ..(Can't dump an EDIT to LST:) LD A,BELL ; Yes, so honk at the.. CALL PRNTCHAR ; ..user to warn him DONTHONK: CALL BLANKSCR ; Clear the screen CALL GETSECTR ; Get and.. CALL SHOWSCTR LD DE,EDITMENU ; Show editing.. CALL SHOMESAG ; ..menu LD A,(MODETOGL) ; Load current editing.. LD B,A ; ..mode, and save it CALL SHOWMODE XOR A ; Reset the.. LD (UPDATFLG),A ; ..update flag.. LD (UNDOFLAG),A ; ..and the UN-DO flag LD C,A ; Reset cursor position pointer CALL EDITPROC ; Call procedure to edit the sector CALL SHOSTLIN ; Display the status line POP HL POP DE POP BC RET ; ; UPCASE: CP 'A' RET C AND UPCASMSK RET ; ; OPENFCB: ; Open a disk file ; ; On Entry: DE=Address of file's FCB ; ; On Exit: A=hex FF if file found ; ; A-reg and Flags are scratch PUSH BC ; PUSH DE ; PUSH HL ; LD C,OPENFC ; CALL BDOS ; POP HL ; POP DE ; POP BC ; RET ; ; READNXTS: ; Read next record from file ; PUSH BC ; PUSH DE ; PUSH HL ; LD C,READFC ; CALL BDOS ; POP HL ; POP DE ; POP BC ; RET ; ; ; GETNXTFS: ; Get next sector in sequence from file PUSH DE ; Get the.. LD DE,(FCBPNTR) ; ..next.. CALL READNXTS ; ..sector POP DE ; CP 1 ; Are we at physical E-O-F? JR Z,GETNEXIT ; Yes, go to E-O-F exit where carry will be set SCF ; Clear.. GETNEXIT: ; ..or.. CCF ; ..set E-O-F flag RET ; ; PREPFCB: ; Clears an FCB file-spec to blanks, zeros.. ; ; ..the drive-id and the extents and next record fields ; ; On Entry: HL=FCB address ; ; On Exit: Name and type start addr. are in memory ; ; All regs and flags are scratch PUSH HL POP IX XOR A LD (IX+FCBEXTNT),A ; Clear the extent.. LD (IX+FCBRECNT),A ; ..record count.. LD (IX+FCBNXTRC),A ; ..and next record flags LD (HL),A ; Initialize Drive-ID INC HL ; Bump pointer LD (NAMSTART),HL ; Save pointer to first byte of file name LD A,' ' ; Load a blank LD B,FNAMELEN ; Load the maximum file-name length NAMFILUP: LD (HL),A ; Plug in a space INC HL ; Bump pointer DJNZ NAMFILUP ; Loop until name is all blank ; LD (TYPSTART),HL ; Save pointer to first byte of file type LD B,FTYPELEN ; Load the maximum file-type length TYPFILUP: LD (HL),A ; Plug in a space INC HL ; Bump pointer DJNZ TYPFILUP ; Loop until type is all blank ; RET ; ; BUILDFCB: ; Opens a file for sequential input ; ; On Entry: HL=FCB address ; ; On Exit: Carry flag indicates file not found ; ; All regs and flags are scratch LD (FCBPNTR),HL ; Save the FCB address LD DE,FNAMPRMT RETRYNAM: CALL SHOMESAG LD HL,(FCBPNTR) ; Restore the FCB address CALL PREPFCB ; Call routine to clear name to spaces, etc. LD IX,NAMEBUFR ; Set pointer to raw name input buffer PUSH IX ; Move it to BDOS.. POP DE ; ..parm register LD C,GETSTRFC ; Call BDOS for.. CALL BDOS ; ..an input string LD A,(IX+1) ; Get the data length OR A ; Was input string NULL? CCF ; Just in case, set "null input" flag RET Z ; Yes it was, so return with flag set ; PUSH IX ; Set a zero.. POP HL INC A INC A LD C,A XOR A LD B,A ADD HL,BC LD (HL),A ; ..at end of input string ; LD HL,(NAMSTART) ; Load start of the file-name in the FCB LD B,FNAMELEN ; Set maximum "drive-ID:fname.ftype" size LD A,(IX+3) ; Get the (possible) ":" character CP ':' ; Is the drive-ID explicitly given? LD A,(IX+2) ; Sneak the Drive-ID itself into A-reg JR NZ,DONAME ; Drive-ID not explicit, so data byte is name SUB 'A'-1 ; Drive-ID IS explicit, data byte is drive-ID JR C,BADNAMER ; But it's a bad one, so tell user CP MAXDRIVE+1 ; Well, maybe not; try too BIG JR NC,BADNAMER ; Yep, it's definitely bad, so tell user INC IX ; Increment name string pointer DEC HL ; Back FCB pointer up to Drive-ID DONAME: CALL UPCASE ; Make sure file-name is in upper-case LD (HL),A ; Store data byte into FCB INC HL ; Increment FCB pointer INC IX ; Increment name string pointer LD A,(IX+2) ; Load in next string byte OR A ; Is it the "null" at the.. RET Z ; ..end of the string, if so, we're done CP '.' ; If not, the test for the "type" separator JR Z,DOTYPE ; If dot found, go to process file type DJNZ DONAME ; If not dot, check for too many bytes ; BADNAMER: LD DE,BADNAMMS ; Set up for error message JR RETRYNAM ; Go back to top, which will display message ; DOTYPE: LD B,FTYPELEN+1 ; Initialize type byte count LD HL,(TYPSTART) ; Set pointer to file type in FCB TYPELOOP: INC IX ; Bump input string pointer LD A,(IX+2) ; Load in next string byte OR A ; Is it the "null" at the.. RET Z ; ..end of the string, if so, we're done CALL UPCASE ; Make sure file-type is in upper-case LD (HL),A ; Store data byte into FCB INC HL ; Increment FCB pointer DJNZ TYPELOOP ; Loop if more permitted JR BADNAMER ; Too long, so tell user ; ; OPENFILE: ; Opens a file for sequential input ; ; On Entry: HL=FCB address ; ; On Exit: Carry flag indicates file not found ; ; All regs and flags are scratch EX DE,HL CALL OPENFCB ; Call low level open routine ADD A,A RET NC LD DE,NOFILEMS CALL SHOMESAG SCF RET ; ; ; ; DUMPRECS: LD DE,DUMESSAG CALL SHOMESAG ; FDUMPLUP: CALL GETNXTFS RET C ; If E-O-F found then exit with carry set CALL SHOWSCTR JR FDUMPLUP ; ; DUMESSAG DB CR,LF,'DUMPRECS STARTING!!!',CR,LF,LF,0 ; ; DUMPFILE: LD HL,INPUTFCB PUSH HL CALL BUILDFCB POP HL PUSH AF PUSH BC PUSH DE PUSH HL LD DE,SETX1 JR NC,X1 LD DE,SETX2 X1: CALL SHOMESAG POP HL POP DE POP BC POP AF CALL NC,OPENFILE PUSH AF PUSH BC PUSH DE PUSH HL LD DE,SETY1 JR NC,Y1 LD DE,SETY2 Y1: CALL SHOMESAG POP HL POP DE POP BC POP AF CALL NC,DUMPRECS RET ; SETX1 DB CR,LF,'CARRY OFF AFTER BUILD',CR,LF,LF,0 SETX2 DB CR,LF,'CARRY ON AFTER BUILD',CR,LF,LF,0 SETY1 DB CR,LF,'CARRY OFF AFTER OPEN',CR,LF,LF,0 SETY2 DB CR,LF,'CARRY ON AFTER OPEN',CR,LF,LF,0 ; ; ; FNAMPRMT DB CR,LF,'Enter file name: ',CR,LF,LF,0 ; NOFILEMS DB CR,LF,'Requested file not found!',CR,LF,LF,0 ; BADNAMMS DB CR,LF,'Invalid file name, re-enter: ',CR,LF,LF,0 ; ; FNAMELEN EQU 8 FTYPELEN EQU 3 FSPECLEN EQU FNAMELEN+FTYPELEN+1 ; TYPSTART DW 0 NAMSTART DW 0 FCBPNTR DW 0 ; FILEFCB DS 64 INPUTFCB DS 64 ; NAMEBUFR DB FSPECLEN+3 DB 0 DS FSPECLEN+1 ; ; ; ; SHOWMENU: ; Displays the main command menu ; ; On entry: No values passed ; ; On exit: No values returned ; ; A-reg and Flags are scratch PUSH DE LD DE,MAINMENU ; Display Main.. CALL SHOMESAG ; ..Menu CALL SHOSTLIN ; Display status line POP DE RET ; ; GETATRIB: LD C,GETDPBFC ; Get pointer to the.. CALL BDOS ; ..Disk Parameter Block LD (DPBSAVE),HL ; Save it LD A,L ; If any.. OR H ; ..errors, then.. RET Z ; ..return with error (zero flag) LD DE,DPARMWRK ; Copy the DPB.. LD BC,DPARMLEN ; ..to local.. LDIR ; ..memory LD HL,(MAXBLOKS) ; Compute disk size.. INC HL ; ..in blocks.. LD (MAXBLOKS),HL ; ..relative to zero LD HL,(DIRNTRYS) ; Load number of directory entries.. INC HL ; ..relative to zero XOR A ; Divide by 4.. LD A,H RRCA LD H,A LD A,L RRCA LD L,A SRA H LD A,L RRCA LD L,A LD (SECPERDR),HL ; ..giving directory size in sectors LD HL,(DIRALMSK) ; Load directory allocation mask LD A,H ; Swap.. LD H,L ; ..the.. LD L,A ; ..two.. LD (DIRALMSK),HL ; ..bytes XOR A ; Set counter.. DEC A ; ..to -1 BITCTLUP: ADD HL,HL ; Count the bits.. INC A ; ..in the.. JR C,BITCTLUP ; ..allocation mask.. ; ; ..(number of blocks in directory) LD L,A ; Save the.. LD H,0 ; ..number of blocks.. LD (DIRBLOKS),HL ; ..per directory EX DE,HL ; Subtract the number of.. LD HL,(MAXBLOKS) ; ..blocks per directory from the.. SBC HL,DE ; ..total blocks per disk, giving.. LD (DTABLOKS),HL ; ..the net data blocks ; LD A,(BLM) ; Load "block mask".. INC A ; ..(sectors per block - 1) LD L,A ; Make relative.. LD H,0 ; ..to 1 and.. LD (SECPERBK),HL ; ..store XOR A LD A,H RRCA LD H,A LD A,L RRCA LD L,A LD A,H SRA A LD H,A LD A,L RRCA LD L,A LD A,H SRA A LD H,A LD A,L RRCA LD L,A LD (BLOKSIZE),HL LD DE,(DTABLOKS) CALL MULTIPLY LD (DISKSIZE),HL LD HL,(MAXBLOKS) ; Multiply total blocks.. EX DE,HL LD A,(SECPERBK) CALL MULTIPLY ; ..by sectors per block, giving.. ; LD (DTASCTRS),HL ; ..total usable sectors per disk LD BC,(SECPERTK) ; Divide result by sectors per track, CALL DIVIDE ; ..giving total tracks per disk LD A,E ; If remainder is.. OR D ; ..non-zero, then don't decrement.. JR NZ,GDPHEXIT ; ..to make relative to zero cause.. DEC HL ; ..there is a partial last track GDPHEXIT: LD (DTATRAKS),HL ; Save total DATA tracks EX DE,HL LD HL,(DIROFSET) ; Add in the.. ADD HL,DE ; ..directory offset.. LD (MAXTRACK),HL ; ..giving the maximum track address XOR A ; Force A-reg and.. DEC A ; ..zero-flag to non zero RET ; ; ; SHOWATTR: ; Show disk attributes CALL BLANKSCR ; Clear the screen and force new page ; LD DE,NUMBLKMS CALL DSPLYRTN LD HL,(MAXBLOKS) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,SECBLKMS CALL DSPLYRTN LD HL,(SECPERBK) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,SECDSKMS CALL DSPLYRTN LD HL,(DTASCTRS) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,SECTRKMS CALL DSPLYRTN LD HL,(SECPERTK) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,MAXTRKMS CALL DSPLYRTN LD HL,(MAXTRACK) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,TRKOFFMS CALL DSPLYRTN LD HL,(DIROFSET) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,BLKSIZMS CALL DSPLYRTN LD HL,(BLOKSIZE) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDEC ; LD DE,KBYTESMS CALL DSPLYRTN ; LD DE,DSKSIZMS CALL DSPLYRTN LD HL,(DISKSIZE) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDEC ; LD DE,KBYTESMS CALL DSPLYRTN ; LD DE,DIRBLKMS CALL DSPLYRTN LD HL,(DIRBLOKS) LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDEC ; LD DE,MAXDIRMS CALL DSPLYRTN LD HL,(DIRNTRYS) INC HL LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDCHX ; LD DE,EXTNTSMS CALL DSPLYRTN LD A,(EMASK) INC A LD L,A LD H,0 LD A,0 ; Set field width = 0 (suppress left zeros) CALL SHOWDEC ; CALL SENDCRLF RET ; ; ; DISKRSET: ; Convert drive ID to letter form and reset the disks ADD A,'A'-1 ; Convert to alphabetic LD (DRIVEID),A ; Save in dump header line LD C,RSETDSKS CALL BDOS ; ; SHOWDRIV: LD A,(DRIVEID) ; Load.. SUB 'A' ; ..current.. LD E,A ; ..drive ID. LD C,SETDSKFC ; Select new drive (FC=14) CALL BDOS CALL GETATRIB ; Get the disk's attributes JR Z,DPBERROR ; Abort on error!! CALL SHOWATTR ; Display the disk's attributes CALL HOMEADDR ; Set track/sector to first directory.. CALL SHOSTLIN ; ..block and display the status line RET ; DPBERROR: LD DE,ERRDPBMS CALL SHOMESAG RET ; BADRIVER: LD DE,DRIVEBAD CALL SHOMESAG JR RESTART ; ; SETDRIVE: LD DE,DRVPROMT CALL SHOMESAG CALL GETINPUT CP ESC ; Abort Command? RET Z ; Yes - return to caller CALL CHEKDRIV ; Check if it is a valid.. JR C,BADRIVER ; ..drive ID (A:..O:) LD A,C INC A CALL DISKRSET RET ; ; ; VERERROR: LD DE,VERERRMS CALL DSPLYRTN ; FATAL ERROR!! ; ; Fall into DONE and exit to CP/M ; DONE: LD HL,(OLDSTACK) LD SP,HL RET ; ; START: LD HL,0 ; Save.. ADD HL,SP ; ..callers.. LD (OLDSTACK),HL ; ..stack LD SP,LOCALSTK ; Load local stack pointer CALL CPMVER ; Get the CP/M version # LD A,H ; If less than 2.x.. CP 20H ; ..then.. JR C,VERERROR ; ..ABORT!! LD DE,DMAAREA ; Set.. CALL SETDMART ; ..DMA LD A,(CCPFCB1) ; Was a drive.. OR A ; ..specified on startup? JR NZ,MAKELETR ; Yes - go to make it a letter LD DE,STARTMSG ; No - so first display startup.. CALL SHOMESAG ; ..message and copyright notice LD HL,BASETIME*8 ; Set timer.. CALL TIMER ; ..delay value ; ; Then set drive to current default: LD A,(DRIVUSER) ; Load the default.. AND 0FH ; ..drive ID. INC A ; Make relative to 1 ; MAKELETR: CALL DISKRSET ; Convert the drive ID to letter form.. ; ; ..and reset the CP/M disk system RESTART: LD SP,RETURNAD ; Ensure that restart address.. ; ; ..is at top of stack!! LD DE,MAINMENU ; Display main command.. CALL SHOMESAG ; ..prompt LD DE,DMPPRMPT ; Display main command.. CALL SHOMESAG ; ..prompt CALL GETINPUT ; Get user command PUSH AF ; Save input byte CALL CLEARMSG ; Clear any previous error message POP AF ; Restore input byte AND PARTYMSK ; Clear parity bit LD HL,CASETBL1 ; Set up for.. CP ESC+1 ; ..control character command JR C,CASE CP '0' JR C,CMANDERR LD HL,CASETBL2-('0'*2) ; Set up for.. CP '9'+1 ; ..numeric command JR NC,CMANDERR CASE: ; Decodes menu command byte and goes to indicated rtn. ; ; On entry: HL = Appropriate routine address table ; ; On exit: PC = Indicated routine ; ; All registers and flags are scratch ADD A,A LD E,A LD D,0 ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL JP (HL) ; Return address already on stack ; ; SETTRAK: ; UNDEFINED ROUTINES SETSCTR: ; UNDEFINED ROUTINES CMANDERR: ; Displays an error message to the screen (as a buffer string) ; ; On entry: No values passed ; ; On exit: Zero flag set if I/O was OK ; ; DE-reg, A-reg and Flags are scratch LD DE,CMDERRMS CALL SHOMESAG JR RESTART ; ; ; CASETBL1: DW NULLRUTN ; 00H ; ^@ DW HOMEADDR ;HOME (WYSE) 01H ; ^A DW CMANDERR ; 02H ; ^B DW CMANDERR ;BREAK 03H ; ^C DW BUMPSCTR ;WSRIGHT 04H ; ^D DW DROPTRAK ;WSUP 05H ; ^E DW BUMPSCTR ;RIGHT (WYSE) 06H ; ^F DW CMANDERR ;BELL 07H ; ^G DW DROPSCTR ;LEFT (BOTH) 08H ; ^H DW CMANDERR ;TAB 09H ; ^I DW BUMPTRAK ;DOWN (BOTH) 0AH ; ^J DW DROPTRAK ;UP (SANYO) 0BH ; ^K DW BUMPSCTR ;RIGHT (SANYO) 0CH ; ^L DW SHOWMENU ; 0DH ; ^M DW CMANDERR ; 0EH ; ^N DW CMANDERR ; 0FH ; ^O DW CMANDERR ; 10H ; ^P DW CMANDERR ; 11H ; ^Q DW CMANDERR ; 12H ; ^R DW DROPSCTR ;WSLEFT 13H ; ^S DW HOMEADDR ;HOME (SANYO) 14H ; ^T DW DROPSCTR ;LEFT (WYSE) 15H ; ^U DW CMANDERR ; 16H ; ^V DW CMANDERR ;CTRLW 17H ; ^W DW BUMPTRAK ;WSDOWN 18H ; ^X DW CMANDERR ; 19H ; ^Y DW DROPTRAK ;UP (WYSE) 1AH ; ^Z DW DONE ; 1BH ; ^[ ; CASETBL2: DW SETDRIVE ; Set New Drive 30H ; '0' DW SETTRAK ; Set New Track 31H ; '1' DW SETSCTR ; Set New Sector 32H ; '2' DW DUMPTRAK ; Dump Track 33H ; '3' DW DUMPSCTR ; Dump Sector 34H ; '4' DW EDITSCTR ; Edit Sector 35H ; '5' DW DUMPFILE ; Dump File 36H ; '6' DW CMANDERR ; 37H ; '7' DW CMANDERR ; 38H ; '8' DW CMANDERR ; 39H ; '9' ; CASETBL3: DW EDTCMDER ; 00H ; ^@ DW EDITHOME ;HOME (WYSE) 01H ; ^A DW EDTCMDER ; 02H ; ^B DW EDTCMDER ; 03H ; ^C DW BUMPBYTE ;WSRIGHT 04H ; ^D DW DROPSGMT ;WSUP 05H ; ^E DW BUMPBYTE ;RIGHT (WYSE) 06H ; ^F DW EDTCMDER ; 07H ; ^G DW DROPBYTE ;LEFT (BOTH) 08H ; ^H DW TOGLMODE ;TAB 09H ; ^I DW BUMPSGMT ;DOWN (BOTH) 0AH ; ^J DW DROPSGMT ;UP (SANYO) 0BH ; ^K DW BUMPBYTE ;RIGHT (SANYO) 0CH ; ^L DW EDTCMDER ; 0DH ; ^M DW EDTCMDER ; 0EH ; ^N DW EDTCMDER ; 0FH ; ^O DW NULLRUTN ; 10H ; ^P DW EDTCMDER ; 11H ; ^Q DW EDTCMDER ; 12H ; ^R DW DROPBYTE ;WSLEFT 13H ; ^S DW EDITHOME ;HOME (SANYO) 14H ; ^T DW DROPBYTE ;LEFT (WYSE) 15H ; ^U DW EDTCMDER ; 16H ; ^V DW EDTCMDER ;CTRLW 17H ; ^W DW BUMPSGMT ;WSDOWN 18H ; ^X DW EDTCMDER ; 19H ; ^Y DW DROPSGMT ;UP (WYSE) 1AH ; ^Z ; ; EDTESCSQ DB ESC,'=' ; Editing cursor position escape-sequence EDITLINE DB 0 ; Editing cursor line EDITCOL DB 0 ; Editing cursor column DB 0 ; STARTMSG DB CLEARSCR,ESC,'=',SINONLIN+CTLFACTR,SINONCOL+CTLFACTR DB ' WHISK CP/M Disk Sector Editor' DB CR,LF,LF DB ' COPYRIGHT (C) 1987 WALLACE W. COX' DB CR,LF,LF,LF,LF,LF,LF DB ' PRESS ANY KEY TO ABORT TIMER LOOP' DB 0 ; EDITMENU DB '0000 (0000) ' DB '<==Current data byte offset within sector image.',CR,LF,LF ; CURBYCOL EQU 0 CURBYLIN EQU (SECTRSIZ/SGMNTSIZ)+3 ; TABLEGND DB 'The TAB key toggles ' ; These four lines.. HXASCCOL EQU $-TABLEGND ; ..must be kept.. HXASCLIN EQU CURBYLIN+2 ; ..in this.. DB 'hex/ASCII' ; ..order DB ' Editing mode; ' DB '^P Printer Echo disabled in EDIT!',CR,LF,LF ; DB 'DEL (OR ^U) will UN-DO any changes ' DB 'SINCE THE LAST CURSOR MOVE!!',CR,LF ; DB 'ESC terminates the sector edit, ' DB 'with a final chance to ABORT any changes.',CR,LF ; DB 'Cursor arrows or (WS-diamond) move the cursor' DB 0 ; ; CURBYPOS DB ESC,'=',CURBYLIN+CTLFACTR,CURBYCOL+CTLFACTR,0 ; HXASCPOS DB ESC,'=',HXASCLIN+CTLFACTR,HXASCCOL+CTLFACTR,0 ; HEXASCII DB 'hex/ASCII',0,'HEX/ascii',0 HXASCLEN EQU ($-HEXASCII)/2 ; MAINMENU DB ESC,'=',CURBYLIN+CTLFACTR,CURBYCOL+CTLFACTR DB ' ' DB 'WHISK Disk "Clean-Up" and Data Recovery Utility - MAIN MENU' DB CR,LF DB ' Disk, Track and Sector Operations: | ' DB ' File Operations:',CR,LF DB '0 = Set new drive 3 = Dump current track | ' DB '6 = Dump selected file',CR,LF DB '1 = Set new track 4 = Dump current sector | ' DB ' ',CR,LF DB '2 = Set new sector 5 = EDIT current sector | ' DB ' ',CR,LF DB 0 ; DMPPRMPT DB ESC,'=',CMANDLIN+CTLFACTR,CMANDCOL+CTLFACTR DB 'Enter Menu Selection (^P echoes output to Printer): ',0 ; DRVPROMT DB CR,'Enter New Drive, or Type to Abort the Command: ',0 ; DLAYLGND DB '^C ABORTS dump, 0 PAUSES scrolling, ' DB '1-9 restarts and/or sets scroll speed',CR,LF,0 ; CURSRHOM DB ESC,'=',FIRSTLIN+CTLFACTR,FIRSTCOL+CTLFACTR,0 ; STATLGND DB ESC,'=',STATLIN+CTLFACTR,STATCOL+CTLFACTR,0 ; TRAKLGND DB 'Drive=' DRIVEID DB '?, Track=',0 SCTRLGND DB ', Sector=',0 BLOKLGND DB ', Block=',0 SYSLEGND DB 'System ',0 DIRLEGND DB 'Directory ',0 NOLEGND DB ' ',0 BUMPLGND DB CR,LF,'Use cursor arrows (or WS-diamond) ' DB 'to adjust track/sector',0 DCHXLGND DB 'dec. (hex) ',0 DCHLLNTH EQU $-DCHXLGND SCALE DB ' 0___4___8___C___',CR,LF,0 ; FORCEUP DB CR,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,0 ; ; EDXITQRY DB ESC,'=',CMANDLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Do you wish to exit back to main menu? (Y/N): ',0 ; DRIVEBAD DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Drive Invalid, Re-enter command:',0 ; CMDERRMS DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Unidentified command, Re-enter: ',0 ; VERERRMS DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Must be Version 2.x of CP/M!!',0 ; ERRDPBMS DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Disk Parameter Block (DPB) Error!!',0 ; UPDATQRY DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Sector has been modified, do you wish to rewrite to disk?' DB ' (Y/N): ',0 ; DIDUPDAT DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Updated sector RE-WRITTEN to disk!!!',CR,LF,0 ; NOUPDATE DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Updated sector NOT RE-WRITTEN to disk!!!',CR,LF,0 ; ; UNDOQURY DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Sector has been modified, do you wish to UN-DO the changes?' DB ' (Y/N): ',0 ; DIDUNDO DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Sector restored to state before last cursor move!!',CR,LF,0 ; DINTUNDO DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR,BELL DB 'Sector NOT restored!! ' DB 'Unchanged since last cursor move!!',CR,LF,0 ; ; BLANKMSG DB ESC,'=',MESAGLIN+CTLFACTR,MESAGCOL+CTLFACTR BLANKLIN DB ' ' ; 39 Spaces DB ' ' ; 39 Spaces DB 0 DB CR,LF,0 ; ; NUMBLKMS DB CR,CR,'Total Data Blocks per Disk: ',0 SECBLKMS DB CR,LF,'Sectors per block: ',0 SECDSKMS DB CR,LF,'Total Data Sectors per Disk: ',0 SECTRKMS DB CR,LF,'Sectors per track: ',0 BLKSIZMS DB CR,LF,'CP/M Allocation Block size: ',0 DSKSIZMS DB CR,LF,'Total Data Bytes per Disk: ',0 MAXTRKMS DB CR,LF,'Maximum Addressable Track: ',0 TRKOFFMS DB CR,LF,'Directory Track Offset: ',0 DIRBLKMS DB CR,LF,'Directory blocks: ',0 MAXDIRMS DB CR,LF,'Max directory entries: ',0 EXTNTSMS DB CR,LF,'Extents per entry: ',0 ; KBYTESMS DB 'K bytes',0 ; NUMWORK DB '00000',0 INDEXSAV DW 0 ; DPHWORK DW 0 ; Save area for possible DPB pointer DPHSAVE DW 0 ; Save area for confirmed DPB pointer ; CURRTRAK DW 0 CURRSCTR DW 0 ; DUMPDLAY DW BASETIME ; Scroll speed timer value for track dump ; EDTOFSET DW 0 ; Cursor offset in sector during editing ; BLKPERTK DB 0 SECPERBK DW 0 SECPERDR DW 0 DTABLOKS DW 0 DTASCTRS DW 0 ; Sectors useable for DATA (not system or dir) DTATRAKS DW 0 ; Tracks useable for DATA (not system or dir) MAXTRACK DW 0 ; Maximum addressable track ; DIRBLOKS DW 0 ; BLOKSIZE DW 0 ; DISKSIZE DW 0 ; DPBWORK DW 0 ; Save area for possible DPB pointer DPBSAVE DW 0 ; Save area for confirmed DPB pointer ; PRNTTOGL DB 0 ; LST: echo to printer toggle: 00=off, FF=on ; MODETOGL DB 0 ; Editing mode toggle: 0=ASCII, 1=Hex ; UPDATFLG DB 0 ; Editing "sector modified" flag (ZERO = NOT CHANGED) ; UNDOFLAG DB 0 ; Editing "sector modified since last cursor move".. ; ; ..flag (set if > ESC) ; ; DPARMWRK: ; Save area for copy of current DPH SECPERTK DW 0 ; Define number of sectors per track BSHIFT DB 0 BLM DB 0 EMASK DB 0 MAXBLOKS DW 0 DIRNTRYS DW 0 DIRALMSK: AL0 DB 0 AL1 DB 0 CKS DW 0 DIROFSET DW 0 SECSIZ DB 0 DPARMLEN EQU $-DPARMWRK ; ; ; DS 96 ; Define some.. LOCALSTK EQU $ ; ..stack area RETURNAD DW RESTART ; Ensure that restart address.. ; ; ..is at top of stack!! OLDSTACK DW 0 ; SAVEAREA EQU $ ; Define save area for original sector in case of undo ; END ;======================the following few lines are MAYBE NOT NEEDED!!!!! ; "SHOWBIN" MAY NOT BE NEEDED EITHER LD A,' ' CALL PRNTCHAR ; LD A,'(' CALL PRNTCHAR ; LD A,(DIRALMSK+1) CALL SHOWBIN ; LD A,(DIRALMSK) CALL SHOWBIN XAM2: LD A,')' CALL PRNTCHAR ; ;================================================================== WCC: ; PUSH BC ; PUSH DE ; PUSH HL ; LD C,WCCFC ; LD E,A ; CALL BDOS ; POP HL ; POP DE ; POP BC ; RET ; ; GNBS: PUSH HL ; LD HL,(DBUFP) ; Load buffer pointer LD A,(HL) ; Get a data byte INC HL ; Increment.. LD (DBUFP),HL ; ..pointer POP HL ; RET ; DBUFP DW 0 ; SHOWSCTR: LD B,128 LD HL,DMAAREA ; Reset pointer to.. LD (DBUFP),HL ; ..first sector byte DUMPLOOP: CALL GNBS CALL WCC ; Neither, so write the byte DJNZ DUMPLOOP RET ; TIPEX: SCF ; Set Logical-E-O-F flag RET