;******************************************************** ;* * ;* BASIC HEX MONITOR FOR Z-80 PROCESSORS * ;* * ;******************************************************** ; ; ; ; PROMPT: CALL PNEXT DEFB CR,LF,'* ',EOT LD HL,LINBUF LD C,LINSIZ CALL GETLIN ;INPUT A BUFERED CONSOLE LINE JR C,WHAT ;PRINT 'WHAT ?' IF INPUT ERROR CALL CRLFS XOR A LD (BREAK),A ;CLEAR CONSOLE BREAK FLAG LD A,(LINBUF) LD IY,LINBUF+1 LD HL,CMDTAB ;SEARCH FOR A MATCHING CHARACTER LD BC,CMDSIZ/3 ; IN COMMAND SEARCH TABLE CALL SEARCH CALL NZ,EXTEND ;TRY EXTENDED FUNCTION JUMP IF NO MATCH JR NZ,WHAT PUSH HL CALL PARAMS ;INPUT NUMERIC PARAMETERS FROM POP IX ; LINE BUFFER AND TEST IF ERROR JR C,WHAT LD HL,(PARAM1) LD DE,(PARAM2) LD BC,(PARAM3) CALL CALLX ;CALL SUBROUTINE @ IX JR NC,PROMPT ;GO BACK TO PROMPT IF NO ERRORS WHAT: CALL PNEXT DEFM ' what ?' DEFB EOT JR PROMPT ; ; ; EXTEND: LD HL,(MONVEC) CALL DISPATCH ;PROCESS EXTENDED MONITOR FUNCTION EXT2: RET ; ; CALLX: JP (IX) ;CALL SUBROUTINE @ IX ; ; ; CMDTAB: DEFB 'V' DEFB 'R' DEFB 'O' DEFB 'I' DEFB 'G' DEFB 'T' DEFB 'F' DEFB 'M' DEFB 'C' DEFB 'B' DEFB 'D' DEFB 'X' DEFB CR DEFW DUMMY DEFW BANKSW ;BANKSWITCH COMMAND DEFW MEMDMP ;DUMP MEMORY IN HEX/ASCII DEFW BOOT ;BOOT FROM FLOPPY DEFW BLOCK ;MEMORY BLOCK MOVE DEFW VIEW ;MEMORY EXAMINE/CHANGE DEFW FILL ;FILL MEMORY DEFW TEST ;RAM DIAGNOSTIC DEFW GOTO ;JUMP TO MEMORY LOCATION DEFW INCMD ;READ FROM INPUT PORT DEFW OUTCMD ;WRITE TO OUTPUT PORT DEFW DSKCMD ;DISPLAY DISK SECTOR DATA DEFW VERCMD ;MEMORY BLOCK COMPARE CMDSIZ EQU $-CMDTAB ; ; ;******************************************************** ;* * ;* MONITOR COMMAND ACTION ROUTINES PACKAGE * ;* * ;******************************************************** ; ; ; ; -- DISK SECTOR READ COMMAND -- ; DSKCMD: CP 3 ;CHECK PARAMETER COUNT JR Z,DSK1 OR A SCF RET NZ LD HL,SECTOR INC (HL) ;BUMP LAST USED SECTOR NUMBER JR DSK2B ; DSK1: LD C,L ;USE FIRST ARG AS UNIT# CALL SELECT JR NZ,DSKERR LD HL,PARAM2 LD C,(HL) ;USE SECOND ARG AS TRACK# CALL SEEK JR NZ,DSKERR LD HL,PARAM3 DSK2B: LD C,(HL) ;USE THIRD ARG AS SECTOR# LD HL,DSKBUF CALL READ ;READ SECTOR INTO (BUFFER) JR NZ,DSKERR INC HL ;ADD 1 TO DMA BYTECOUNT RETURNED IN HL EX DE,HL LD B,4 DSK2C: SRL D RR E ;DIVIDE BYTECOUNT BY 4 DJNZ DSK2C LD HL,DSKBUF CALL DUMP ;DUMP DISK READ BUFFER AND JR DSKADR ; PRINT UNIT/TRACK/SECTOR DSKERR: PUSH AF ;SAVE 1771 STATUS CALL PNEXT DEFM 'disk error ' DEFB EOT POP AF CALL PUT2HS ;PRINT ERROR STATUS IN HEX DSKADR: LD A,(DSKTYP) BIT 0,A ;DETERMINE IF SINGLE/DOUBLE DENSITY LD A,'S' JR Z,DSKAD1 LD A,'D' DSKAD1: CALL OUTPUT ;DISPLAY 'SD' OR 'DD' LD HL,DADMSG CALL PMSG LD A,(UNIT) ;NOW DISPLAY UNIT/TRACK/SECTOR CALL PUT2HS ;PRINT DRIVE UNIT# LD A,'T' CALL OUTPUT LD A,(TRACK) CALL PUT2HS ;PRINT TRACK# IN HEX LD A,'S' CALL OUTPUT LD A,(SECTOR) CALL PUT2HS ;PRINT SECTOR# IN HEX DUMMY: OR A RET DADMSG: DEFB 'D U',EOT ; ; ; ; ; -- DISK BOOT LOADER COMMAND -- ; BOOT: LD C,0 ;SELECT DRIVE 0 FOR BOOT LOAD CALL SELECT JR NZ,DSKERR CALL HOME ;HOME HEAD TO TRACK 0 JR NZ,DSKERR ;ERROR IF CANNOT RESTORE LD HL,DSKBUF ;POINT TO MONITOR'S SECTOR BUFFER LD C,1 ;SELECT SECTOR 1 CALL READ ;READ TRACK 0/ SECTOR 1 JR NZ,DSKERR LD HL,CONFIG SET 0,(HL) ;SET CONFIG BYTE FOR RAM AT 0000H LD HL,DSKBUF LD DE,0080H LD BC,128 CALL MOVE ;COPY BOOT CP/M STANDARD LOCATION DI LD SP,STACK LD HL,ROLLIN PUSH HL ;PUSH ADDRESS IN CASE BOOT RETURNS LD HL,0080H PUSH HL ;PUSH TRANSFER ADDRESS FOR 'EXITMON' JP EXITMON ;TURN OFF ROMS AND EXECUTE LOADER ; ; ; ; ; -- MEMORY DUMP COMMAND -- ; MEMDMP: DEC A ;CHECK PARAMETER COUNT JR Z,MDMP2 DEC A JR Z,MDMP3 MDMP1: LD HL,(LAST) MDMP2: LD DE,16 JR MDMP3B MDMP3: EX DE,HL SBC HL,DE ;DERRIVE BYTECOUNT FOR DUMP RANGE LD B,4 MDMP3A: SRL H ;DIVIDE BYTECOUNT BY 16 RR L DJNZ MDMP3A INC HL EX DE,HL MDMP3B: CALL DUMP ;DUMP DE*16 BYTES STRTING AT HL LD (LAST),HL RET ; ; ; DUMP: PUSH HL ;SAVE STARTING ADDRESS CALL PUT4HS ;PRINT STARTING ADDRESS IN HEX CALL SPACE LD B,16 DUMP2: CALL LOAD ;GET A DATA BYTE @ HL LD A,C INC HL CALL PUT2HS ;PRINT THE DATA IN HEX DJNZ DUMP2 ;REPEAT 16 TIMES POP HL ;RESTORE STARTING ADDRESS LD B,16 DUMP3: CALL LOAD ;GET BACK DATA BYTE @ HL LD A,C INC HL RES 7,A CP 20H JR C,DUMP4 CP 7FH JR C,DUMP5 DUMP4: LD A,'.' ;PRINT A DOT IF DATA < 20 OR > 7F DUMP5: CALL OUTPUT ;PRINT ASCII CHARACTER IN A DJNZ DUMP3 CALL CRLFS RET NZ ;EXIT IF ESCAPE REQUEST IS INDICATED DEC DE LD A,D OR E JR NZ,DUMP RET ; ; ; -- READ FROM INPUT PORT COMMAND -- ; INCMD: DEC A ;CHECK IF PARAMETER COUNT=1 SCF RET NZ LD C,L ;POINT C TO INPUT PORT IN1: CALL CRLFS LD A,C CALL PUT2HS IN A,(C) CALL PUT2HS CALL ECHO CP CR JR Z,IN2 CP '-' JR Z,IN3 OR A RET IN2: INC C INC C IN3: DEC C JR IN1 ; ; ; ; -- WRITE TO OUTPUT PORT COMMAND -- ; OUTCMD: CP 2 ;CHECK IF PARAMETER COUNT=2 SCF RET NZ LD C,L ;POINT C TO OUTPUT PORT OUT (C),E ;OUTPUT DATA PASSED IN E OR A RET ; ; ; ; -- MEMORY EXAMINE COMMAND -- ; VIEW: CALL MDATA CALL ECHO CP CR JR Z,VIEW4 CP '-' JR Z,VIEW5 CP ',' JR NZ,VIEW2 CALL ECHO JR VIEW3 VIEW2: CALL ASCHEX CCF RET NC RLCA RLCA RLCA RLCA LD C,A CALL ECHO CALL ASCHEX CCF RET NC OR C VIEW3: LD C,A CALL STORE VIEW4: INC HL INC HL VIEW5: DEC HL JR VIEW ; ; ; ; -- JUMP TO MEMORY LOCATION COMMAND -- ; GOTO: OR A ;CHECK IF PARAMETER COUNT <> ZERO SCF RET Z DI LD SP,STACK LD DE,ROLLIN PUSH DE ;PUSH MONITOR ENTRY ADDRESS FOR RETURN PUSH HL ;PUSH TRANSFER ADDRESS AFTER THAT LD A,(PARAM2) LD HL,(PARAM3) LD DE,(PARAM4) LD BC,(PARAM5) ;PUT REST OF PARAMS IN REGISTERS JP EXITMON ;SET D/S BANKSWITCH AND EXIT MONITOR ; ; ; ; -- MEMORY READ/WRITE DIAGNOSTIC COMMAND -- ; TEST: CP 2 ;CHECK PARAMETER COUNT SCF RET NZ INC DE LD E,D ;GET ENDING PAGE ADDRESS INTO E LD D,H ;GET STARTING PAGE ADDRESS INTO D LD B,0 ;INITIALIZE PASS COUNTER TEST1: LD H,D ;POINT HL TO START OF BLOCK LD L,0 TEST2: CALL MEMTEST ;CALL BANK-SWITCH MEMORY TEST ROUTINE JR Z,TEST4 ;DO ANOTHER PASS IF NO ERRORS TEST3: CALL LOAD ;LOAD C WITH ERROR BYTE LD A,L XOR H XOR B ;RE-GENERATE BYTE IN ERROR CALL CHECK ;GO PRINT RESULT RET NZ ;EXIT ROUTINE IF BREAK REQUESTED INC HL LD A,H CP E JR NZ,TEST3 ;CHECK REST OF BLOCK FOR ERRORS TEST4: INC B ;BUMP PASS COUNT LD A,'+' CALL OUTPUT ;PRINT '+' AND ALLOW FOR EXIT JR Z,TEST1 ;DO ANOTHER PASS IF NO ESCAPE RET ; ; ; CHECK: CP C RET Z ;RETURN IF C=A PUSH AF CALL MDATA ;PRINT WHAT WAS ACTUALLY READ CALL PNEXT DEFM 'should=' DEFB EOT POP AF CALL PUT2HS ;PRINT WHAT SHOULD HAVE BEEN READ RET ; ; MDATA: CALL CRLFS CALL PUT4HS CALL LOAD LD A,C CALL PUT2HS RET ; ; ; ; -- FILL MEMORY WITH CONSTANT COMMAND -- ; FILL: CP 3 ;CHECK IF PARAMETER COUNT=3 SCF RET NZ EX DE,HL OR A SBC HL,DE ;END-START EQUALS BYTECOUNT EX DE,HL RET C RET Z ;RETURN IF START => END ADDRESS CALL STORE ;STORE C AT (HL) IN PROPER BANK LD B,D LD C,E ;PUT BYTECOUNT IN BC FROM DE LD D,H LD E,L INC DE ;PUT START+1 IN DE CALL MOVE ;FILL BLOCK USING LDIR TRICK OR A RET ; ; ; ; ; -- MEMORY BLOCK MOVE COMMAND -- ; BLOCK: CP 3 ;CHECK IF PARAMETER COUNT=3 SCF RET NZ CALL BLOCAD LD A,C OR B RET Z ;EXIT NOW IF BC=0 CALL MOVE ;MOVE BLOCK WITH BANK SWITCH OR A RET ; ; ; BLOCAD: EX DE,HL OR A ;CLEAR CARRY SBC HL,DE ;GET DIFFRENCE BETWEEN EX DE,HL ;HL & DE FOR BYTECOUNT PUSH DE PUSH BC POP DE ;GET OLD BC INTO DE POP BC INC BC ;GET COUNT+1 INTO BC RET ; ; ; ; -- MEMORY BLOCK COMPARE COMMAND -- ; VERCMD: CP 3 ;CHECK IF PARAMETER COUNT=3 SCF RET NZ CALL BLOCAD JR VERF2 VERF1: PUSH BC EX DE,HL CALL LOAD ;READ BYTE @DE IN CURRENT BANK EX DE,HL LD B,C CALL LOAD ;NOW READ BYTE @HL LD A,B CALL CHECK ;COMPARE DATA @DE AND @HL POP BC RET NZ ;EXIT IF ESCAPE REQUEST IS INDICATED INC HL INC DE DEC BC VERF2: LD A,B OR C JR NZ,VERF1 RET ; ; ; ; -- MEMORY BANK SWITCH COMMAND -- ; ; BANKSW: CP 2 CCF RET C ;ERROR IF NOT PARAM COUNT NOT 0 OR 1 OR A JR NZ,BANK2 ;JUMP IF NEW PARAM ENTERED LD A,(CONFIG) CALL PUT2HS ;DISPLAY CURRENT 'CONFIG' BYTE OR A RET ; BANK2: LD A,L LD HL,CONFIG XOR (HL) ;COMPARE NEW CONFIG TO OLD SETTING BIT 1,A ;TEST IF STD/BB BIT IS DIFFERENT JR Z,BANK2A ;EXIT IF NO CHANGE IN RAM BANK SWITCH DI ;NO INTERRUPTS WHILE COPYING MEMORY LD A,(STDCPY) LD E,A ;E=SOURCE BANK CONTROL BYTE XOR 00001000B LD D,A ;OPPOSITE BANK GOES IN D LD HL,MONITR ;ELSE MAKE SHADOOW COPY OF UPPER 4K LD BC,4096 ; OF RAM BEFORE SWITCHING BANKS CALL SHADOW JR NZ,BANK3 ;JUMP IF BLOCK NOT COPIED CORRECTLY LD A,D OUT (PORT3),A ;SWITCH TO OPPOSITE BANK AND STAY LD (STDCPY),A EI BANK2A: LD A,(PARAM1) AND 00000011B LD (CONFIG),A ;STORE NEW CONFIGURATION BITS RET ; BANK3: EI CALL PNEXT DEFB 'ERR AT ',EOT CALL PUT4HS OR A RET ; ; ; ; ; HL ... BLOCK POINTER ; BC ... BYTECOUNT ; D ... DEST BANK CONTROL BYTE ; E ... SOURCE BANK CONTROL BYTE ; SHADOW: LD A,(HL) ;GET MEMORY BYTE FROM SOURCE BANK EX AF,AF' LD A,D OUT (PORT3),A ;SWITCH TO DESTINATION MEMORY BANK EX AF,AF' LD (HL),A ;STORE DATA BYTE INTO DEST BANK CP (HL) ;READ BACK FROM DEST AND COMPARE LD A,E OUT (PORT3),A ;SWITCH BACK TO SOURCE MEMORY BANK RET NZ ;ABORT IF SOURCE <> DEST INC HL DEC BC LD A,B OR C JR NZ,SHADOW RET ; ; ; ;******************************************************** ;* * ;* CONSOLE I/O PACKAGE AND UTILITY ROUTINES * ;* * ;******************************************************** ; ; ; GETLIN: LD B,C ;SAVE MAX LINE LENGTH PARAMETER IN B GLIN1: CALL ECHO ;GET A CHARACTER FROM THE CONSOLE CP CR ;CHECK FOR CARRIAGE RETURN JR Z,GLIN2 CP 'H'-64 ;CHECK FOR CTL-H BACKSPACE JR Z,GLIN4 CP ' ' RET C ;OTHER CONTROL CHARACTERS ARE ILLEGAL LD (HL),A INC HL ;STORE CHARACTER IN BUFFER DEC C JR NZ,GLIN1 ;GET ANOTHER IF THERE'S MORE ROOM SCF RET ;RETURN WITH CARRY=1 IF TOO ;MANY CHARACTERS ARE ENTERED GLIN2: LD (HL),A ;PUT CARRIAGE RETURN ON END OF LINE RET ;RETURN WITH CARRY BIT=0 GLIN4: DEC HL ;DELETE LAST CHARACTER FROM BUFFER CALL PNEXT DEFB ' ','H'-64 ;PRINT A SPACE TO OVERWRITE THE DEFB EOT ; LAST CHARACTER, THEN DO A BACKSPACE INC C LD A,B ;MAKE SURE YOU'RE NOT TRYING TO SUB C ;BACKSPACE PAST THE START OF THE LINE JR NC,GLIN1 RET ; ; ; SEARCH: CPIR ;SEARCH TABLE @HL FOR MATCH WITH A RET NZ ;EXIT NOW IF SEARCH FAILS ADD HL,BC ADD HL,BC ;ADD RESIDUE FROM CPIR BYTECOUNT ADD HL,BC ; TO HL 3 TIMES TO GET POINTER LD A,(HL) ; TO ADDRESS PART OF TABLE ENTRY INC HL LD H,(HL) LD L,A RET ;EXIT WITH Z=1 TO INDICATE MATCH ; ; ; ; PARAMS: LD BC,0 LD A,(IY+0) CP CR ;CHECK IF LINE TERMINATES JR NZ,PARA2 ; IMMEDIATELY WITH A RETURN XOR A RET ;RETURN WITH PARAM COUNT=0 IF SO PARA1: INC C ;ADD 2 TO PARAM BUFFER INDEX IN BC INC C LD A,C CP 10 CCF RET C ;ERROR IF > 5 NUMBERS ENTERED PARA2: PUSH BC ;SAVE PARAMETER COUNT CALL GETHEX ;READ A NUMBER FROM LINE BUFFER POP BC RET C ;ERROR IF RESULT OVER 16 BITS LD IX,PARAM1 ;POINT TO PARAMETER STORAGE AREA ADD IX,BC ;ADD PARAMETER COUNT IN BC LD (IX+0),L LD (IX+1),H ;STORE DATA RETURNED FROM 'GETHEX' CP ' ' JR Z,PARA1 ;GET ANOTHER ITEM IF SPACE CP ',' JR Z,PARA1 ;GET ANOTHER ITEM IF COMMA CP CR SCF ;ELSE CHECK FOR CARRIAGE RETURN RET NZ ; AND EXIT WITH CY=1 IF NOT LD A,C SRL A ;A=COUNT OF NUMBERS ENTERED INC A RET ; ; ; ; GETHEX: LD HL,0 JR GNUM3 GNUM1: LD B,4 GNUM2: ADD HL,HL ;MULTIPLY RESULT BY 16 RET C ;RETURN IF IT OVERFLOWS 16 BITS DJNZ GNUM2 LD E,A ;APPEND NEW LOW ORDER DIGIT LD D,0 ;AND GET RESULT BACK INTO DE ADD HL,DE RET C ;RETURN IF OVERFLOW GNUM3: LD A,(IY+0) ;GET A CHARACTER FROM LINE INPUT INC IY ; BUFFER @ IY AND BUMP IY LD C,A CALL ASCHEX ;CONVERT ASCII TO NUMERIC JR NC,GNUM1 LD A,C OR A RET ; ; ASCHEX: SUB '0' RET C CP 10 CCF RET NC SUB 7 CP 10 RET C CP 16 CCF RET ; ; ; PUT4HS: LD A,H CALL PUT2HX LD A,L PUT2HS: CALL PUT2HX CALL SPACE RET ; ; PUT2HX: PUSH AF RRA RRA RRA RRA CALL PUTNIB POP AF PUTNIB: AND 00001111B ADD A,90H DAA ADC A,40H DAA CALL OUTPUT RET ; ; ; PMSG PRINTS THE STRING OF ASCII CHARACTERS ; POINTED TO BY THE RELATIVE ADDRESS IN DE ; UNTIL AN EOT IS ENCOUNTERED IN THE STRING. ; EOT EQU 04H CR EQU 0DH LF EQU 0AH ; PNEXT: EX (SP),HL CALL PMSG EX (SP),HL RET ; PMSG: LD A,(HL) INC HL CP EOT RET Z CALL OUTPUT JR PMSG ; ; ; ; CRLFS OUTPUTS A RETURN-LINEFEED-SPACE ; TO THE CONSOLE DEVICE ; CRLFS: CALL PNEXT DEFB CR,LF,EOT SPACE: LD A,' ' CALL OUTPUT RET ; ; ; ; ECHO INPUTS ONE CHARACTER FROM THE CONSOLE ; DEVICE, PRINTS IT ON THE CONSOLE OUTPUT AND ; THEN RETURNS IT IN REGISTER A WITH BIT 7 RESET ; ; OUTPUT PRINTS THE CHARACTER IN REGISTER A ON ; THE CONSOLE OUTPUT DEVICE AND THEN DOES A CHECK ; FOR CONSOLE INPUT TO FREEZE OR ABORT OUTPUT. ; ECHO: CALL CONIN ;INPUT A CHARACTER AND ECHO IT PUSH AF CALL CONOUT POP AF CP 'Z'+1 RET C SUB 32 ;CONVERT UPPER CASE TO LOWER CASE RET ; ; ; OUTPUT: CALL CONOUT CALL CONST ;SEE IF CONSOLE INPUT IS PENDING JR Z,OUTP2 CALL CONIN CP CR ;SEE IF CARRIAGE RETURN WAS TYPED JR Z,OUTP1 CALL CONIN ;WAIT FOR ANOTHER INPUT CHARACTER JR OUTP2 ; THEN RETURN TO CALLING ROUTINE OUTP1: LD (BREAK),A ;SET ESCAPE FLAG TO NON-ZERO VALUE OUTP2: LD A,(BREAK) OR A ;RETURN CURRENT STATUS OF ESCAPE RET ; FLAG TO CALLING ROUTINE ; ; ; ;