; TITLE 'UPG80 MONITOR SPECIAL SYSTEM VERSION 3-1 31/8/79' ; ;**** FOR S100 SYSTEMS WITH JADE I/O BOARDS. ; ; ;************************************************************* ; ; UPG80 MONITOR :- ; MODIFIED VERSION OF AMSAT'S AMS80 V2:0 MONITOR ; BY H.J.HARVEY ; ; THIS MONITOR IS A MINIMUM 8080 SYSTEM MONITOR TO PROVIDE ; THE BASIC STRUCTURE NECESSARY FOR 8080 DEBUG AND CONTROL. ; ; THE ROUTINES ALLOW FOR MEMORY EXAMINE AND MODIFY, ; TARGET PROGRAM BREAKPOINTING UNDER MONITOR CONTROL, ; USER INTERRUPTS OR RST VECTORS (RST3-RST7), ; SIMPLE ASSEMBLY AND DISASSEMBLY, INPUT AND OUTPUT, ; AND PROVIDE VARIOUS TELETYPE SUPPORT ROUTINES TO LOAD ; AND DUMP MEMORY IN STANDARD 8080 HEX-BINARY. ; ; THE MONITOR INCLUDES AN EXTENSIVE VECTOR TABLE STARTING ; AT (ROM-ORIGIN + 40H) TO ALLOW USER ACCESS TO A NUMBER ; OF USEFUL SPECIFIC ROUTINES. ; ;************************************************************* ; ; DEFINE CONSOLE CONTROL CHRS ; CR EQU 0DH ;ASCII CARRIAGE-RETURN LF EQU 0AH ;ASCII LINE-FEED ; ; THE FOLLOWING EQUATES ARE USED TO DEFINE THE COLUMN WIDTH ; OF THE DISPLAY CONSOLE. ; 'R' COMMAND NEEDS 58 COLUMNS FOR A 1-LINE DISPLAY ; 'D' COMMAND NEEDS 53 COLUMNS FOR 16-BYTE DISPLAY ; 'P' COMMAND NEEDS 43 COLUMNS FOR 16-BYTE GROUP ; COLSW=1 IF MONITOR <58 COLUMNS/LINE ; COLSW=0 IF MONITOR >57 COLUMNS/LINE ; COLSW EQU 0 ; IF NOT COLSW ; ; 58+ COLUMN CONSTANTS ; OSET EQU 16 ;16 BYTES PER LINE ENDIF IF COLSW ; ; <58 COLUMN CONSTANTS ; OSET EQU 8 ;8 BYTES PER LINE ENDIF ; ; ; ; THE FOLLOWING EQUATES ARE DESIGNED FOR CONSOLE CONTROL ; OF THE S100 CARD-SET WITH JADE SPI/O BOARDS. ; ER SYSTEMS WILL REQUIRE DIFFERENT EQUATES, DEPENDING ; UPON THE SELECTION OF I/O PORTS AND CONTROL SETUPS. ; CNCTL EQU 081H ;SYSTEM I/O CONSTANTS CONST EQU 081H CNIN EQU 001H CNOUT EQU 001H CSCTL EQU 080H ;CASSETTE CONTROL CSST EQU 080H ;CASSETTE STATUS CHANNEL CSIN EQU 000H ;CASSETTE INPUT PORT CSOUT EQU 000H ;CASSETTE OUTPUT PORT MODE EQU 0FFH ;MM5303 UART MODE SELECT TRDY EQU 080H ;TRANSMIT READY BIT RBR EQU 010H ;READER READY BIT TMOUT EQU 10000 ;10000 MILLISECOND (10 SECS) TIMEOUT ONEMS EQU 130 ;CONSTANT FOR 1 MILLISECOND LOOP (F/N DELAY) RAM EQU 03F00H ;START OF 256 BYTE RAM. ; ; ROM AND RAM AREAS CAN NOW BE DEFINED. ; ROMSW EQU 1 ;ROMSW=1 IF ROM > 0 , OTHERWISE ROMSW=0 ROM EQU 08000H ;ROM STARTS HERE REGS EQU RAM+256-48 ;REGISTER STORE (IN RAM) STARTS HERE STACK EQU REGS ;TOP OF STACK INITIALIZE ; ; START OF SYSTEM ; ORG ROM ; ; SET UP SERIAL DATA MODE. ; PART1: DI ;DISABLE ALL INTERRUPTS. MVI A,MODE ;SERIAL I/O MODE. JMP PART2 DW RAM ; ; EXECUTIVE ENTRY ON RST1 ; THIS ENTRY POINT IS USED WHENEVER AN RST1 (CODE CF) ; IS EXECUTED. ; EXEC: SHLD SVHL ;SAVE HL POP H ;POP THE CALL ADDRESS INTO HL RAR ;PUT CARRY INTO B7 OF ACC JMP BEGIN ;GO ON NOW. ; ; BREAKPOINT SERVICING INPUT AS RESULT OF 'RST 2' ; ROUTINE BPAT IS CALLED TO LET THE USER KNOW. ; BPIN: SHLD SVHL ;SAVE HL POP H ;GRAB BREAKPOINT ADDRESS RAR ;ROTATE RIGHT PUTS CARRY INTO ACC B7 JMP BPAT ;GO SERVICE IT. ; ; DEFINE USER INT/SR VECTORS ; RST3 THROUGH RST7 MAY BE USED EITHER AS HARDWARE ; OR SOFTWARE INTERRUPT VECTORS. ; THE ORRESPONDING ADDRESS FOR SERVICE MUST BE ; SET UP IN THE APPROPRIATE LOCATIONS IN RAM. ; THESE ADDRESSES CAN BE FOUND BY REFERENCE TO THE LABELS ; RST3 - RST7 AT THE END OF THIS MONITOR. ; ;**** NOTE THAT THESE CODE GROUPS ARE TO BE LINKED FROM RAM ; IN PAGE ZERO IF THE MONITOR IS NOT ZERO ORGED. ; RS3: PUSH H ;SAVE HL LHLD RST3 ;FETCH USER VECTOR XTHL ;PUT ON STACK RESTORING HL RET ;GO TO USER DW ROM ;PAD - ROM START ADDRESS RS4: PUSH H ;SAVE HL LHLD RST4 ;FETCH USER VECTOR XTHL ;PUT ON STACK RESTORING HL RET ;GO TO USER DW RAM ;PAD - RAM START ADDRESS RS5: PUSH H ;SAVE HL LHLD RST5 ;FETCH USER VECTOR XTHL ;PUT ON STACK RESTORING HL RET ;GO TO USER DW REGS ;PAD - END OF REG STORE (ALSO T.O.S.) RS6: PUSH H ;SAVE HL LHLD RST6 ;FETCH USER VECTOR XTHL ;PUT ON STACK RESTORING HL RET ;GO TO USER DW SVA ;PAD - START OF REG STORE. RS7: PUSH H ;SAVE HL LHLD RST7 ;FETCH USER VECTOR XTHL ;PUT ON STACK RESTORING HL RET ;GO TO USER DW ENDROM ;PAD - END OF ROM DATA ; ; MONITOR SUPPORT SR VECTORS ; USER UTILITY SR'S ; ; THE FOLLOWING SET OF JUMPS ARE PROVIDED SOTHAT USER ; PROGRAMS CAN REFERENCE COMMON ENTRY POINTS TO THE VARIOUS ; ROUTINES. THESE LOCATIONS WILL REMAIN CONSTANT WHILE THE ; ACTUAL LOCATION OF EACH ROUTINE MAY CHANGE AS DIFFERENT ; MONITOR REVISIONS OCCUR. ; ; THE CALLING SEQUENCE FOR EACH SUBROUTIN EMAINS THE ; SAME AS DEFINED IN THE LISTING, WITH ONLY A SLIGHT EXECUTION ; TIME OVERHEAD DUE TO THE EXTRA JUMP. ; ZTYPE: JMP TYPE ;TYPE CHR IN 'A' ZGETCH: JMP GETCH ;GET CHR IN 'A' (PARITY, NO ECHO) ZCHIN: JMP CHIN ; " " " " (ECHO, NO PARITY) ZCHINX: JMP CHINX ; " " " " (ECHO/NO ECHO, NO PARITY) ZMSG: JMP MSG ;TYPE MESSAGE, PTR IN HL. TERM 0FFH ZCRLF: JMP CRLF ;TYPE CR/LF ZSPACE: JMP BLANK ;TYPE " " ZTHXN: JMP THXN ;TYPE HEX 'A' B3-B0 ZTHXB: JMP THXB ; " " " " B7-B0 ZTHXW: JMP THXW ; " " " 'HL' ZGHXN: JMP GHXN ;GET HEX 'A' B3-B0 ZGHXB: JMP GHXB ; " " " B7-B0 ZGHXW: JMP GHXW ; " " 'HL' ZSTORE: JMP STORE ;STORE A IN (HL) AND CHECK ZNEGDE: JMP NEGDE ;NEGATE DE REG ZPWAIT: JMP PWAIT ;TYPE 'PAUSE' THEN AWAIT ANY CHR ZOKQ: JMP OKQ ;TYPE 'OK?', AWAIT CHR, CONTINUE IF ' ' ZECHO: JMP ECHCN ;ECHO CONTROL (A=0 MEANS OFF) ZCNVBN: JMP CNVBN ;CONVERT CHARACTER TO BINARY NYBBLE. ZCSTS: JMP CSTS ;LOOK FOR CONSOLE K/B STRIKE. ; ; UART INITIALIZATION CODE: PART 2. ; SEND OUT THE COMMAND WORD. ; PART2: OUT CSCTL ;SET UP CASSETTE I/O OUT CNCTL ;AND CONSOLE I/O. ; ; ZERO OUT THE CURRENT ADDRESS FOR BREAKPOINT. ; (NECESSARY TO ALLOW UPDATING) ; LXI H,0 ;LOAD 16 BIT ZERO SHLD BPADD ;PUT ALL ZEROS IN BPADD ; ; BEGIN MONITOR. ; ENTER HERE FOLLOWING A HARDWARE/SOFTWARE RST1 ; BEGIN: SHLD SVPC ;STORE CALLING PC STA TMPA ;AND CARRY (IN B7) RAL ;THEN ROTATE BACK THE ACC. LXI H,0 ;NOW TRANSFER THE SP TO HL BY DOING A DUMMY DAD SP ;ADD TO HL. (N.B. CLEARS CARRY) SHLD SVSP ;SAVE THE CALLER SP. LXI SP,SVA+1 ;PICK UP REG STORE POINTER PUSH PSW ;TO SAVE PSW PUSH B ;AND BC PUSH D ;AND DE. (HL ALREADY SAVED) LXI H,SVF ;GET THE PSB BYTE LDA TMPA ;PICK UP THE CARRY HOLDER, RAL ;ROTATE IT BACK TO CARRY. JNC BGN1 ;SKIP IF CARRY NOT SET, INR M ;OTHERWISE RESET CARRY. BGN1: LXI H,M0 ;TYPE MONITOR ENTRY MESSAGE JMP NEXT1 ; ; NEXT MONITOR COMMAND PLEASE. ; ENTER HERE WHENEVER A NEW COMMAND IS EXPECTED. ; NEXT: LXI H,M1 ;TYPE PROMPT MESSAGE NEXT1: LXI SP,STACK ;SET STACK POINTER FIRST. CALL MSG CALL CHIN ;GET COMMAND CHARACTER INTO 'A' MOV B,A ;AND SAVE IT IN 'B' ; ; SEARCH OP TABLE ; (IF CALLING COMMAND BYTE IS REQUIRED, IT IS IN 'B') ; LXI H,OPTAB ;HEAD-OF-TABLE VECTOR SUI 'A' ;REDUCE CODE TO OFFSET CPI 1AH ;SEE IF IT EXCEEDS 'Z' COMMAND. JNC TEND ;IF SO, MAY HAVE BEEN SPECIAL. ADD A ;ALL O.K. MULTIPLY BY 2 (2 BYTES PER ADDR) MOV E,A ;PUT VALUE*2 INTO E MVI D,0 ;AND GET ZERO TO CLEAR 'D' DAD D ;ADD OFFSET TO HL (ADDRESS REQUIRED AT ) MOV E,M ;GET LOWER BYTE OF REQUIRED ADDR INX H ;AND THEN GET THE UPPER MOV D,M ;BYTE BEFORE TRANSFERRING XCHG ;IT TO HL. PCHL ;FINALLY JUMP TO ROUTINE CALLED. ; ; OPERATION ADDRESS TABLE. ; CONTAINS AN ADDRESS DESTINATION FOR EACH CHARACTER OF THE ; ALPHABET (A-Z IN ASCENDING ORDER.) ; OPTAB: DW GETAD ;A - GET ADDRESS DW BPT ;B - BREAKPOINT SETTER/CLEARER DW CONT ;C - CONTINUE AFTER B/P DW DISP ;D - DISPLAY MEMORY DATA DW PEND ;E - END OF FILE PUNCH DW FILL ;F - FILL MEMORY WITH DATA DW GOTO ;G - PROGRAM GO: NO REGISTER RESTORE. DW ASM80 ;H - LINE ASSEMBLER DW INPT ;I - INPUT PORT DATA DW JUMP ;J - PROGRAM JUMP: REGISTER RESTORE. DW KOMP ;K - K(C)OMPARE MEMORY AREAS DW LOAD ;L - LOAD HEX-BINARY TAPE DW MOVE ;M - MOVE MEMORY BLOCK DW NULL ;N - PUNCH NULL BLOCK DW OUTPT ;O - OUTPUT PORT DATA. DW PUNCH ;P - PUNCH HEX-BINARY DATA DW ILLEG DW REGEX ;R - REGISTER EXAMINE/MODIFY DW SEARCH ;S - SEARCH MEMORY FOR BYTE DW ILLEG DW USER ;U - USER DEFINE/USE DW ILLEG DW ILLEG DW GETXA ;X - SET UP XEQ ADDRESS DW DIS80 ;Y - 8080 DISASSEMBLY. DW ZERO ;Z - ZERO OUT MEMORY ; ; N.B. COMMANDS . AND - ARE CHECKED ; BY ROUTINE 'TEND' ; ; ; INPUT ONE CHR AND STRIP PARITY ; ALTERNATIVE ENTRY POINTS ARE:- ; ; CALL CHIN ; .... ;RESULT IN 'A' ; THE INPUT IS ECHO'D IF DATA IS PRINTABLE. ; ; MVI A,XX ;XX=0 NO ECHO. ; CALL CHINX ; .... ;RESULT IN 'A' ; ECHO CONTROLLED EACH CALL. ; ; CALL CHINN ; .... ;RESULT IN 'A' ; ECHO CONTROLLED BY PREVIOUS 'CALL ECHCN' ; CHIN: MVI A,0FFH ;SET ECHO FLAG ON CHINX: CALL ECHCN ;CALL THE CONTROLLER. CHINN: CALL GETCH ;GET CHARACTER FROM CONSOLE, ANI 7FH ;STRIP ANY PARITY PUSH PSW ;SAVE DATA LDA ECHO ;SEE IF ECHO REQU'D ANA A ;THIS INSTRUCTION SIMPLY SETS FLAGS JNZ CHN1 ;TEST FOR ZERO/NON-ZERO CONTROL POP PSW ;NO ECHO. SIMPLY RETURN RET CHN1: POP PSW ;GET DATA AND ECHO CPI ' ' ;IF NOT CONTROL CHR CNC TYPE RET ;BEFORE RETURNING ; ; MESSAGE PRINT ; ALLOWS USER TO PRINT A MESSAGE ON THE CONSOLE OUTPUT ; BY HAVING A STRING OF CHARACTERS FOLLOWED ; BY DELIMITING 0FFH (-1) ; ; CALLING SEQUENCE:- ; LXI H,ADDRESS ; CALL MSG ; .... ; MSG: PUSH PSW ;SAVE PSW PUSH H ;AND HL MNXT: MOV A,M ;GET NEXT BYTE INX H ;BUMP BYTE POINTER. CPI 0FFH ;CHECK FOR 0FFH (-1) TERMINATOR CNZ TYPE ;NO. TYPE IT JNZ MNXT ;NOW READY FOR ANOTHER TRY POP H ;MESSAGE FINISHED. RESTORE HL POP PSW ;AND PSW RET ;BEFORE GOING HOME ; ; TYPE CR/LF ; (THE EASY WAY TO START A NEW LINE) ; ; CALLING SEQUENCE:- ; CALL CRLF ; .... ; CRLF: PUSH H ;SAVE HL LXI H,M2 ;GET CR/LF MESSAGE CALL MSG ;TYPE MESSAGE POP H ;RESTORE HL RET ;RETURN ; ; ; TYPE ONE SPACE ; ; CALLING SEQUENCE:- ; CALL BLANK ; .... ; BLANK: PUSH PSW ;SAVE PSW MVI A,' ' ;GET SPACE CALL TYPE ;TYPE IT POP PSW ;RESTORE PSW RET ;THEN RETURN ; ; TYPE 'A' IN HEX ; OUTPUTS THE 2-BIT HEX VALUE OF ACCUMULATOR ; TO CONSOLE ; ; CALLING SEQUENCE:- ; LDA DATA ; CALL THXB ; .... ; THXB: PUSH PSW ;SAVE PSW RRC ;SHIFT THE LEFT NYBBLE RRC ;INTO THE RIGHT NYBBLE RRC ;BY DOING 4 ROTATE RIGHTS. RRC CALL THXN ;TYPE HEX NYBBLE POP PSW ;RESTORE DATA ; ; TYPE 'A' B3-B0 IN ASCII ; TYPES THE 1-BIT HEX VALUE OF THE BOTTOM 4 BITS ; OF ACCUMULATOR. ; ; CALLING SEQUENCE:- ; LDA DATA ; CALL THXN ; .... ; THXN: PUSH PSW ;SAVE PSW ANI 0FH ;ISOLATE B3-B0 (THROW AWAY B7-B4) ADI 090H ;ADJUST DAA ;NOW ACI 040H ;TO DAA ;ASCII CALL TYPE ;BEFORE TYPING POP PSW ;RESTORE PSW RET ;THEN RETURN ; ; ; TYPE A WORD IN HEX ; TYPES THE 4-BIT HEX VALUE OF THE 16-BIT VALUE ; HELD IN THE HL REGISTER PAIR. ; ; CALLING SEQUENCE:- ; LHLD WORD ; CALL THXW ; .... ; THXW: PUSH PSW ;SAVE PSW MOV A,H ;GET HIGH BYTE FROM 'H' CALL THXB ;AND TYPE IT MOV A,L ;GET LOW BYTE FROM 'L' AND CALL THXB ;TYPE IT TOO. POP PSW ;RESTORE PSW RET ;I'M GOIN HOME ; ; GET HEX CHR FROM CONSOLE ; ROUTINE TO GET A SINGLE HEX NYBBLE FROM THE CONSOLE ; IF THE DIGIT IS VALID (I.E. 0-9,A-F) THEN THE BINARY ; VALUE IS RETURNED IN 'A' AND THE CARRY IS RESET. ; ; HOWEVER, IF THE RESULT IS NON-HEX, THE BAD CHARACTER ; WILL BE IN 'A' AND CARRY WILL BE SET. ; ; CALLING SEQUENCE:- ; CALL GHXN ; JC NONHX ;ERROR IF CARRY SET ; GHXN: MVI A,0FH ;MASK TO KEEP ONLY THE RIGHT NYBBLE JMP GHB1 ; ; GET HEX BYTE FROM CONSOLE ; SIMILAR TO GHXN, BUT RETURNS BYTE VALUE IF O.K. ; ; CALLING SEQUENCE:- ; CALL GHXB ; JC NONHX ;CHECK NO HEX I/P ; GHXB: MVI A,0FFH ;MASK TO KEEP WHOLE BYTE. GHB1: PUSH H ;SAVE HL CALL GHXW ;GET HEX DATA VIA GHXW JC GHB2 ;PROVIDED THERE HAS BEEN NO ERROR, ANA L ;WE CAN MASK THE NYBBLE/BYTE. GHB2: POP H ;RESTORE HL RET ;RETURN TO CALLER ; ; GET HEX WORD FROM CONSOLE ; SIMILAR TO GHXN, BUT RETURNS BINARY WORD (16-BIT) ; IN HL REG PAIR IF O.K. ; ; CALLING SEQUENCE:- ; CALL GHXW ; JC NONHX ;TEST NON HEX I/P ; .... ;RESULT IN HL ; GHXW: PUSH PSW ;SAVE PSW LXI H,0 ;ZERO OUT THE HL STORE CALL CHINN ;GET FIRST CHARACTER, CONTROLLED ECHO CALL CNVBN ;CONVERT IT TO BINARY NYBBLE JC GHW3 ;ANY NON-HEX IS ERROR FIRST TIME. MOV L,A ;SAVE FIRST DIGIT GHW1: CALL CHINN ;GET ANOTHER CHARACTER CALL CNVBN ;AND CONVERT TO BINARY NYBBLE JC GHW2 ;AFTER FIRST DIGIT, CHECK FOR DELIMITER. DAD H ;HL*2 ;WE WANT 1-NYBBLE LEFT SHIFT DAD H ;HL*4 ;SO WE DOUBLE ADD HL DAD H ;HL*8 ;TO ITSELF FOUR TIMES. DAD H ;HL*16 ;N.B. TOP DIGIT IS LOST. ADD L ;ALL DONE. ADD DIGIT TO LOWER BYTE MOV L,A ;UPDATE THE LOWER BYTE. JMP GHW1 ;NEXT DIGIT PLEASE. GHW2: CPI CR ;COMPARE WITH CR JZ GHW4 CPI ' ' ;AND SPACE JZ GHW4 ;EITHER IS VALID DELIMITER. GHW3: INX SP ;NON-HEX BAD BYTE IS RETURNED INX SP ;IN A, WITH CARRY SET. STC RET GHW4: POP PSW ;NORMAL EXIT, RESTORE PSW ORA A ;WITH CARRY CLEARED. RET ; ; CNVBN: CONVERT ASCII TO BINARY NYBBLE, ; IS COMMON TO GHXN,GHXB,GHXW ; CNVBN: CPI '0' ;FIRST SEE IF <'0' RC CPI '9'+1 ;NOW SEE IF NUMERIC JC CNVB1 ;IT IS IF CARRY ON. CPI 'A' ;NOW TRY A-F RC ;ERROR RETURN IF CARRY SET CPI 'F'+1 ;CHECK FOR >F CMC ;INVERT CARRY RC ;RETURN IF NOT OK. SUI 7 ;A-F CHR FOUND. SUBTRACT 7 CNVB1: SUI '0' ;NOW MAKE INTO BINARY RET ;THEN RETURN ; ; STORE BYTE IN MEMORY, WITH READ CHECK. ; IF READ-BACK DOES NOT AGREE WITH STORE REQUEST AN ; APPROPRIATE ERROR MESSAGE IS ISSUED. ; ; CALLING SEQUENCE:- ; ;DATA IN 'A', ADR IN 'HL' ; CALL STORE ; .... ;RETURNS HERE IF O.K. ; ;OTHERWISE RETURNS TO MONITOR. ; STORE: MOV M,A ;STORE BYTE INTO MEMORY CMP M ;COMPARE MEMORY WITH A RZ ;RETURN IF O.K. PUSH H ;SUMTHIN IS WRONG. LXI H,M4 ;ISSUE ERROR MESSAGE CALL MSG ;TO ADVISE USER POP H ;RESTORE HL JMP RXAR ;INDICATE ERROR LOC'N ; ; ; MEMORY EXAMINE/MODIFY. ; ; ENTER FROM MONITOR BY USING:- ; A 1234 ; SETS 'ADR' TO '1234H', TYPES CURRENT CONTENTS THEN AWAITS :- ; ; (1) VALID BYTE TO STORE, THEN BUMPS 'ADR' ; (2) LF TO SIMPLY BUMP 'ADR' ; (3) - TO SIMPLY DECREMENT 'ADR' ; (4) CR TO RETURN TO MONITOR ; (5) . TO RETYPE CURRENT ADR ; ; IN ADDITION, AT ANY TIME THE USER MAY DIRECTLY ; ENTER THIS ROUTINE WITH:- ; (1) . TO TYPE CONTENTS OF CURRENT 'ADR' ; (2) - TO TYPE CONTENTS OF PREVIOUS 'ADR' ; (3) LF TO TYPE CONTENTS OF NEXT 'ADR' ; ROUTINE THEN CONTINUES AS ABOVE. ; GETAD: CALL PUWA ;GET ADR REQUIRED XCHG ; GTA1: SHLD ADR ;SAVE ADR LOCAT: CALL CRLF ;CR/LF LHLD ADR ;FETCH CURRENT ADR CALL THXW ;TYPE CURRENT ADR CALL BLANK ;FOLLOWED BY SPACE MOV A,M ;FOLLOWED BY BYTE CONTENT CALL THXB CALL BLANK ;YET ANOTHER SPACE CALL GHXB ;LOOK FOR NEW BYTE JC NONHX ;CHECK NON-HEX I/P CALL STORE ;TRY TO STORE DATA BYTE NXLOC: LHLD ADR ;PICK UP CURRENT ADR INX H ;BUMP 1 JMP GTA1 ;RESTART PROCESS OF ADR ACCESS. ; ; ROUTINE 'TEND' IS CALLED FROM MONITOR OP-TAB ; TABLE END ROUTINE ; TEND: MOV A,B ;SET 'A' TO COMMAND NONHX: CPI LF ;SEE IF CHARACTER WAS LF JZ NXLOC ;IF SO, GET NEXT LOC'N CPI '.' ;MAYBE IT WAS '.' JZ LOCAT ;IF SO, GET SAME LOC'N CPI '-' ;OR EVEN '-' JZ LSTLC ;IN WHICH CASE, BACK UP 1 LOC'N NONH1: CPI CR ;FINAL CHANCE IS CR JZ NEXT ;WHICH MEANS EXIT THE COMMAND ; ; IN THE EVENT THAT THE COMMAND IS NO GOOD, ; ENTER HERE. ; ILLEG: LXI H,M3 ;ILLEGAL CALL, SEND QUERY MESSAGE. ILLG1: CALL MSG ;TYPE IT, THEN JMP NEXT ;'AVE ANOTHER GO. ; ; PREVIOUS LOCATION REQUEST. ; LSTLC: LHLD ADR ;BACKUP 1 BYTE DCX H JMP GTA1 ;AND TRY AGAIN. ; ; NEGATE (2'S COMPLEMENT) 'DE' REG PAIR ; ; CALLING SEQUENCE:- ; .... ;SET UP DE ; CALL NEGDE ; .... ;NOW DE=-DE ; NEGDE: PUSH PSW ;SAVE PSW MOV A,D ;FETCH D CMA ;COMPLEMENT IT MOV D,A ;RESTORE MOV A,E ;FETCH E CMA ;COMPLEMENT IT TOO MOV E,A ;THE RESTORE INX D ;NOW ADD 1 TO GET 2'S COMPL POP PSW ;RESTORE PSW RET ;TAKE RESULTS HOME ; ; DISPLAY BLOCK OF MEMORY ON CONSOLE. ; CALLED FROM MONITOR AS:- ; D XXXX YYYY ; AFTER THE FIRST LINE, PRINTS XXXX TO YYYY IN ; 8/16 BYTE GROUPS STARTING WITH ADR,MOD 8/16 ; IF XXXX > YYYY ONLY PRINTS CONTENTS OF XXXX ; DISP: CALL PICKUP ;GET ADDRESS RANGE. DMRET: CALL CRLF ;NEW LINE CALL THXW ;VECTOR ADR TO CONSOLE DMNXT: CALL BLANK ;1 SPACE MOV A,M ;GET DATA CALL THXB ;TYPE IT CALL LAST ;ALL DONE? CALL HOLD ;NO. SEE IF HOLD REQUEST. MOV A,L ;ADR MOD8/16? ANI OSET-1 JNZ DMNXT ;NO. JMP DMRET ;YES. NEW LINE. ; ; LOCAL ROUTINE TO TEST FOR HOLD REQUEST. ; RETURNS IF NO CHARACTER IN INPUT BUFFER. ; PUTS HOLD ON OUTPUT IF IS TYPED. ; OTHERWISE RETURNS TO MONITOR. ; HOLD: CALL CSTS ;GET CONSOLE STATUS. RZ ;ZERO. RETURN. XRA A ;NON-ZERO. CALL CHINX ;GET CHARACTER, NO ECHO. CPI ' ' ;TEST FOR SPACE JNZ NEXT ;NO SPACE. PANIC. JMP GETCH ;SPACE. AWAIT CONTINUE. ; ; LOCAL ROUTINE TO PICK UP TWO ADDRESSES, ; PUTTING THE FIRST ADDRESS INTO HL ; AND THE NEGATED SECOND ADDRESS INTO DE ; PICKUP: CALL PUWA ;FROM ADDRESS INTO DE CALL PUWA ;FROM ADDRESS INTO HL, JMP NEGDE ;NEGATED TO ADDRESS IN DE ; ; JUMP TO ADDRESS WITH REG'S SET ; ; CALLED FROM MONITOR BY:- ; J 1234 JUMP TO SPECIFIED HEX ADR ; J JUMP TO ADR FROM LAST RST1 ; (USED AS BREAKPOINT IN PROGRAMS) ; J JUMP TO ADR SET UP BY 'X' COMMAND ; J . JUMP TO ADR SET BY LAST USE OF 'A' COMMAND ; ; RESTORES REGISTERS TO STATE AS SAVED IN RAM ON ENTRY ; TO THE MONITOR. ; RESPONSES J , J AND J . WILL TYPE ; THE STORED ADDRESS BEFORE ASKING FOR OK TO PROCEED. ; ; REMEMBER IF RST1 WAS USED, THAT THE RETURN ADDRESS MAY ; NEED TO BE RESET WITH THE 'RP=' COMMAND TO GET YOU ; BACK TO THE CALLING POINT. ; ; ; GO DIRECT TO ADR FROM MONITOR. ; IDENTICAL TO 'J' COMMAND, BUT DOES ; NOT RESTORE REGISTERS. ; JUMP: GOTO: PUSH B ;SAVE INPUT COMMAND CALL PUWB ;GET ADR JNC JMP4 ;HEX ADR GIVEN JMP2: LHLD SVPC ;ASSUME SAVED PC REQUIRED. CPI CR ;SEE IF CR JZ JMP3 LHLD XEQAD ;NO. ASSUME 'X' ADDRESS REQUEST. CPI LF ;TRY LF JZ JMP3 ;IF NOT, LHLD ADR ;ONLY ALTERNATIVE IS 'ADR' CPI '.' ;MUST BE '.' JNZ ILLEG ;NO. PANIC. JMP3: CALL THXW ;TYPE HEX ADR JMP4: CALL OKQ ;IS THIS WHERE WE REALLY WANT TO GO? SHLD GOGO+1 ;YES. SET UP JUMP ADR MVI A,0C3H ;THIS IS 'JMP' COMMAND STA GOGO ;WHICH WE SET UP IN RAM POP PSW ;RECOVER COMMAND CHARACTER. CPI 'G' ;WAS IT 'G' ? JZ GOGO ;YES. IMMEDIATE JUMP TO PROGRAM. LXI SP,SVE ;NO. RESTORE SP POP D ;AND REGS POP B POP PSW LHLD SVSP ;SAVED SP SPHL ;SET NEW SP LHLD SVHL ;AND HL JMP GOGO ;CUNNINGLY EXECUTE BUILT-UP JUMP ; ; SET UP EXECUTION ADR FROM MONITOR BY:- ; X 1234 ; GETXA: CALL PUWA ;GET ADR XCHG ;INTO HL SHLD XEQAD ;PUT INTO XEQAD JMP NEXT ;BACK TO MONITOR ; ; LOCAL ROUTINE TO CHECK FOR LAST OPERATION. ; LAST: PUSH H ;SAVE MEM VECTOR DAD D ;ADD NEGATIVE ADDRESS JC NEXT ;FINITO IF CARRY SET POP H ;NO. RESTORE INX H ;BUMP ADR RET ;RETURN ; ; COMPARE TWO MEMORY BLOCKS, PRINT ANY DIFFERENCES. ; USES 'MOVE' TO ALLOCATE THE BLOCK ADDRESSES. ; ; MOVE MEMORY BLOCK FROM MONITOR BY:- ; M XXXX YYYY ZZZZ ; ; MOVES BLOCK XXXX TO YYYY INTO ZZZZ ONWARDS ; TAKE CARE. WILL RESULT IN OVERWRITES IF ZZZZ IS ; IN THE RANGE XXXX+1 TO YYYY ; CAN BE USED AS A 'FILL' OPERATION BY PUTTING ; ZZZZ=XXXX+1. LAST FILL OCCURS AT YYYY+1. ; KOMP: MOVE: CALL PUWA ;GET XXXX PUSH D ;SAVE ON STACK CALL PUWA ;GET YYYY IN DE CALL PUWA ;GET ZZZZ IN DE, YYYY GOES TO HL XCHG ;DE=Y HL=Z STACK=X XTHL ;DE=Y STACK=Z HL=X CALL NEGDE ;NEGATE DE MOV A,B ;GET COMMAND AND SEE CPI 'M' ;IF IT WAS 'M' JNZ KOMP1 ;JUMP IF IT WAS NOT. CALL OKQ ;MOVE. ARE YOU SURE, USER? MOV1: MOV A,M ;GET THRU X XTHL ;HL=Z STACK=X CALL STORE ;STORE AND CHECK INX H ;BUMP Z XTHL ;RESTORE CALL LAST ;END YET? JMP MOV1 ;NO. ; ; REGISTER MODIFY/EXAMINE. FROM MONITOR BY:- ; ; R TYPE ALL REG CONTENTS ; RA ACCUMULATOR ; RF FLAGS,PSB ; RB REG B ; RC REG C ; RD REG D ; RE REG E ; RH REG H ; RL REG L ; RS STACK POINTER *** ; RP PC IF MONITOR 'CALLED' *** ; ; *** NOTE: RS, RP GIVE AND EXPECT 4-HEX DIGITS ; RXLST: DB 'AFBCDEHL',0 ;REGISTER LIST ; REGEX: CALL CHIN ;GET REGISTER IDENTIFIER CPI CR ;IS IT CR? JZ REXAL ;YEP. PUSH PSW ;NO. SAVE PSW MVI A,'=' CALL TYPE ;TYPE A '=' POP PSW ;RESTORE IDENT LXI D,SVPC ;ADR OF P.C. CPI 'P' ;SEE IF PC REQUEST JZ RX2 ;YES. INX D ;POINT TO SP INX D CPI 'S' ;IS IT 'S' JZ RX2 ;YES. MOV B,A ;NO. SAVE ID IN B LXI H,RXLST ;LIST VECTOR ADR LXI D,SVA ;ADR OF 'A' STORE RX0: MOV A,M ;GET TABLE ID ANA A ;CHECK FOR END (0) JZ ILLEG ;YES. ILLEGAL REQUEST CMP B ;COMPARE WITH REQUEST JZ RX1 ;FOUND? INX H ;NO. NEXT ENTRY DCX D ;NEXT REG JMP RX0 ;NEXT TRY. ; RX1: LDAX D ;GET REG CALL THXB ;TYPE IT OUT CALL BLANK ;FOLLOWED BY SPACE CALL GHXB ;GET RESPONSE JC NONH1 ;NON-HEX. TRY CR LATER STAX D ;STORE INPUT IN REG JMP NEXT ;BACK HOME, JAMES. ; RX2: XCHG ;REG ADR TO HL MOV E,M ;LOW S OR P INX H ;BUMP VECTOR MOV D,M ;HI S OR P XCHG ;REG VAL IN HL CALL THXW ;TYPE HEX WORD CALL PUWB ;GET CHANGE. JC NONH1 ;NON-HEX JUMP XCHG ;RESTORE RAM VECTOR MOV M,D ;STORE HI S OR P DCX H ;DROP VECTOR MOV M,E ;STORE LO S OR P JMP NEXT ;RETURN RXTSE: CALL BLANK ;SPACE CALL TYPE ;TYPE THE ID. MVI A,'=' JMP TYPE ;EQUALS ; REXAL: LXI D,SVA ;ADR OF 'A' LXI H,RXLST ;ID LIST RXA1: MOV A,M ;GET ID ANA A ;LAST YET? (0) JZ RXA2 ;YES ; ; THIS LITTLE BIT OF CODE GOES IN ONLY IF WE ARE MAKING ; A 32 COLUMN CONFIGURED DISPLAY MONITOR. ; IF COLSW CPI 'E' ;SEE IF NEXT REGISTER IS 'E' CZ CRLF ;IF SO, NEXT LINE PLEASE, ENDIF ; ; THE ALTERNATIVE IS A 5-BYTE DUMMY PATCH. ; IF NOT COLSW NOP NOP NOP NOP NOP ENDIF ; CALL RXTSE ;TYPE ' ',ID,'=' LDAX D ;GET REG DCX D ;DROP REG PTR INX H ;BUMP LIST PTR CALL THXB ;TYPE CONTENTS JMP RXA1 ;NEXT PLEASE. RXA2: MVI A,'P' ;DO PC CALL RXTSE LHLD SVPC ;GET PC CALL THXW ;TYPE PC MVI A,'S' ;NOW DO SP CALL RXTSE LHLD SVSP ;GET SP RXAR: CALL THXW ;TYPE VALUE JMP NEXT ;RETURN TO MOM. ; ; HEX WORD PICKUPS. ; PUWA GETS WORD, AND RETURNS TO MONITOR IF ERROR. ; IF NOT PUTS RESULT IN 'DE'. ; PUWA: CALL PUWB ;GET A HEX WORD JC ILLEG ;BADDY OUT HERE XCHG ;SAVE INTO DE RET ;RETURN ; ; PUWB GETS WORD INTO 'HL' WITHOUT CHECK. ; PUWB: CALL BLANK ;TYPE A BLANK FIRST. JMP GHXW ;NOW GET THE WORD. ; ; PAUSE GENERATOR. ; TYPES THE MESSAGE 'PAUSE' THEN AWAITS ANY KEYSTRIKE ; (NO ECHO) BEFORE CONTINUING. ; PWAIT: PUSH H ;SAVE HL LXI H,M5 ;MESSAGE 'PAUSE' CALL MSG POP H ;RECOVER JMP GETCH ;ANY RESPONSE WILL DO. ; ; MONITOR OR USER VERIFY ROUTINE OK? ; CALLING SEQUENCE:- ; CALL OKQ ; .... ;GOES HERE IF RESPONSE IS SP ; ;OTHERWISE ABORTS. ; OKQ: PUSH PSW ;SAVE PSW PUSH H ;AND HL LXI H,M7 ;ADR OF 'OK?' MESSAGE CALL MSG ;PRINT IT LXI H,M8 ;PREPARE TO ABORT CALL GETCH ;USER'S REPLY ANI 7FH ;MASK OUT PARITY. CPI ' ' ;TRY ' ' JNZ ILLG1 ;NO. ABORT POP H ;YES. RESTORE HL POP PSW ;AND PSW RET ;AND GO ON. ; ; ECHO ON/OFF CONTROLLER. ; ; CALLING SEQUENCE:- ; MVI A,XX ;XX=0 FOR OFF ; ;XX<>0 FOR ON ; CALL ECHCN ; .... ;NOW SET/RESET. ; ECHCN: STA ECHO ;STORE REQUIRED VALUE RET ; ; SYSTEM I/O ROUTINES ; ;******* THIS VERSION SUITS JADE PSI/O SYSTEM HARDWARE ******* ; ; USER MUST PUT HIS OWN CONSOLE DRIVER IN HERE ; IF DIFFERENT TO THE VERSION SHOWN ; ; ; TYPE A CHARACTER. ; CALLING SEQUENCE:- ; LDA CHR ; CALL TYPE ;TYPE IT ; .... ; ; ; ROUTINE CO IS A PATCH FOR SBC80/SDK80 SYSTEMS ; WHICH PASS ARGUMENT IN 'C' ; CO: MOV A,C ;PUT ARGUMENT INTO A TYPE: PUSH PSW ;SAVE CONTENTS OF 'A' TYP1: IN CONST ;GET CONSOLE STATUS ANI TRDY ;ZERO INDICATES BUSY. JZ TYP1 ;IF SO, TRY AGAIN. POP PSW ;CLEAR. RESTORE 'A' OUT CNOUT ;OUTPUT TO 'CNOUT' RET ; ; RETRIEVE CHARACTER FROM CONSOLE ; PARITY IS KEPT, BUT NO ECHO GIVEN. ; CALLING SEQUENCE:- ; CALL GETCH ;GET CHARACTER ; .... ;CHARACTER IN 'A' ; ; ; NOTE: THIS IS ALSO THE ENTRY POINT FOR SDK80/SBC80 ; ROUTINE CI. ; CI: GETCH: CALL CSTS ;GET CONSOLE STATUS JZ GETCH ;IF SO, TRY AGAIN. IN CNIN ;READY. GET A CHARACTER. RET ;RETURN WITH CHAR IN 'A' ; ; CONSOLE STATUS ROUTINE. CALLED BY DISP AND PUNCH ; TO ALLOW STOPPING OF OUTPUT BY TYPING ANY CHAR. ; THE BREAK CHARACTER IS THE FIRST CHARACTER INPUT ; TO THE MONITOR AFTER RETURN. ; (IDEAL BREAK CHARACTER IS . RESULTS IN MONITOR QUERY) ; CSTS: IN CONST ;GET CONSOLE STATUS ANI RBR ;INPUT BUFFER READY? RET ;RETURN ; ; ; SYSTEM MESSAGES. ; M0: DB CR,LF,'UPG80 V3:1' M1: DB CR,LF,'* ',0FFH M2: DB CR,LF,0FFH M3: DB ' ??',0FFH M4: DB CR,LF,'MEMORY ERR @ ',0FFH M5: DB ' PAUSE ',0FFH M7: DB ' OK? ',0FFH M8: DB 'ABORT',0FFH ORG ROM+0400H ; M6: DB ' CKS ERR @ ',0FFH M10: DB CR,LF,'B/P @ ',0FFH ; ; SEARCH MEMORY FOR A GIVEN BYTE. ; CALLED FROM MONITOR BY:- ; S XXXX YYYY VV ; ; WHERE XXXX= STARTING ADDRESS FOR SEARCH ; YYYY= FINISHING ADDRESS FOR SEARCH ; VV= BYTE TO BE FOUND ; ; SEARCH: CALL PICKUP ;GET BLOCK ADDRESSES. CALL GBYTE ;NOW SPACE AND BYTE REF. MOV B,A ;SAVE IT IN 'B' CALL SRC4 ;START A NEW LINE SRC1: CALL HOLD ;SEE IF HOLD CALLED. MOV A,M ;GET COMPARE. CMP B ;COMPARE BYTE WITH MEMORY CZ SRC3 ;PRINT ADDRESS IF EQUAL. SRC2: CALL LAST ;NOW SEE IF ALL DONE. JMP SRC1 ;IF NOT, CONTINUE SEARCH ; ; SRC3 PRINTS ADDRESS ; SRC4 SETS UP FOR NEW LINE. ; SCNT EQU OSET/2 ; SRC3: CALL BLANK ;ONE SPACE PLEASE, CALL THXW ;FOLLOWED BY THE ADDRESS. DCR C ;DECREMENT THE LINE COUNT RNZ ;RETURN PRONTO IF NOT FULL. SRC4: CALL CRLF ;START ON NEW LINE, MVI C,SCNT ;LOAD SEARCH COUNTER. RET ;THEN CONTINUE ON OUR MERRY WAY. ; ; COMPARE MEMORY. STARTED OUT IN 'MOVE' FUNCTION WHERE ; IT GOT THE ADDRESSES. ; CALLED FROM THE MONITOR BY:- ; K XXXX YYYY ZZZZ ; WHERE XXXX=START ADDR OF FIRST BLOCK ; YYYY=STOP ADDR OF FIRST BLOCK ; ZZZZ=START ADDR OF SECOND BLOCK ; PRINTS OUT ALL OCCURRENCES OF INEQUALITY. ; KOMP1: CALL HOLD ;SEE IF HOLD REQUESTED. MOV A,M ;GET FIRST BLOCK BYTE. XTHL ;SWAP HL AND T.O.S. CMP M ;NOW COMPARE WITH SECOND BYTE JZ KOMP2 ;SKIP IF ALL THE SAME. CALL SRC4 ;NEW LINE FIRST XTHL ;SWAP POINTERS CALL KOMP3 ;FIRST ADDR/BYTE XTHL ;SWAP THEM BACK MOV A,M ;SECOND BYTE IN. CALL KOMP3 ;PRINT THEM TOO. KOMP2: INX H ;BUMP THE SECOND ADDRESS XTHL ;BACK WHERE WE STARTED. CALL LAST ;SEE IF ALL DONE. JMP KOMP1 KOMP3: CALL SRC3 ;PRINT SPACE AND ADDRESS. CALL BLANK ;A SPACE JMP THXB ;THEN BYTE VALUE ; ; ; ZERO OUT A BLOCK OF MEMORY. ; CALLED FROM MONITOR BY:- ; Z XXXX YYYY ; (THE VALUE VV=0 FOR THIS FUNCTION) ; ; ; FILL BLOCK WITH A VALUE. MONITOR CALL BY:- ; ; F XXXX YYYY VV ; ; CAUSES MEMORY LOCATIONS XXXX THRU YYYY TO BE ; SET TO THE VALUE VV. ; ZERO: FILL: CALL PICKUP ;GET BLOCK ADDRESSES. MOV A,B ;GRAB THE COMMAND BYTE (F OR Z) CPI 'Z' ;COMPARE WITH 'Z' MVI A,0 ;ASSUME ZERO REQUESTED, THEN JZ FILL0 ;JUMP IF TRUE. CALL GBYTE ;ELSE GET THE FILLING BYTE. FILL0: CALL OKQ ;VERIFY FILL/ZERO REQUEST FILL1: CALL STORE ;STORE AND CHECK CALL LAST ;END IN SIGHT? JMP FILL1 ;NOT YET. ; ;**** GET BYTE WITH TEST. ; GBYTE: CALL BLANK ;LEADING BLANK CALL GHXB ;THEN THE BYTE. JC ILLEG ;TEST LEGALITY. RET ; ; USER DEFINABLE ROUTINES. ; CALLED FROM MONITOR BY:- ; U XXXX ;DEFINE USER CALL ADDRESS. ; U ;GO TO USER ADDRESS. ; (IF XXXX=0 THEN USER CALL IS CLEARED) ; USER: CALL BLANK ;PUT IN A SPACE, CALL GHXW ;THEN GO FOR THE ADDRESS, IF ANY. JC USER2 ;SEE IF CARRY SET (BAD DATA?) SHLD USERA ;NO. ADDRESS SET. JMP NEXT USER2: CPI ' ' ;CARRY SET. SEE IF USER CALL REQUEST. JNZ ILLEG ;IF NOT, PANIC LHLD USERA ;YES. GET THE ADDRESS. MOV A,L ;NOW SEE IF LEGAL ADDRESS BY ORA H ;LOOKING FOR NON-ZERO ADDRESS. JZ ILLEG PCHL ;ALL O.K. GO THERE. ; ; ; ; ROUTINES TO PUNCH AND LOAD MEMORY. ; INTEL STANDARD HEX OBJECT TAPE FORMAT IS USED. ; ; RECORD START : ; BYTE COUNT 2-CHARS ; LOAD ADR 4-CHARS ; RECORD TYPE 2-CHARS 0=DATA 1=EOF ; DATA BYTES (2-CHARS/BYTE) ; CHECKSUM FROM BYTE-COUNT TO END OF DATA ; (ALL CHARACTERS MUST BE HEX LEGITIMATE 0-9,A-F) ; ; EOF RECORD MAY CONTAIN EXECUTION ADR. ; LOADER GOES TO ADR IF NON-ZERO ; PUNCH: CALL PUWA ;FROM ADR CALL PUWA ;TO ADR CALL PWAIT ;AWAIT READINESS ; ; HL=FIRST ADR DE=LAST ADR ; PN0: MOV A,L ;GET LOW PART OF START ADR ADI OSET ;INCREMENT BY 8/16 MOV C,A ;HOLD IN 'C' MOV A,H ;GET HIGH PART OF START ADR ACI 0 ;TAKE CARE OF ANY O'FLOW MOV B,A ;HOLD IN 'B' MOV A,E ;NOW LOW PART OF FINAL ADR SUB C ;SUBTRACT LOW START MOV C,A ;PUT IN 'C' MOV A,D ;HIGH PART END ADR. SBB B ;SUBTRACT FROM START. JC PN1 ;JUMP IF JNZ ILLEG LD4: XRA A ;PREPARE TO CALL ECHCN ;RESET ECHO. CALL CRLF ;NEW LINE PLEASE. PUSH H ;SAVE BIAS ADR LD5: POP H ;GET BIAS PUSH H ;AND RESTORE CALL RIX ;GET INPUT MVI B,':' ;WAIT FOR ':' SUB B JNZ LD5 ;TRY AGAIN MOV D,A ;CLEAR CKSUM CALL BYTE ;GET LENGTH JZ LD7 ;ZERO MEANS ALL DONE MOV E,A ;SAVE LENGTH CALL BYTE PUSH PSW ;SAVE HI ADR CALL BYTE POP B ;FETCH MSBYTE MOV C,A ;BC NOW HAS ADR PUSH B ;SAVE IT XTHL ;INTO HL SHLD BLKAD ;SAVE BLOCK ADR XTHL ;IN CASE OF ERROR POP B DAD B ;RESTORE AND ADD BIAS CALL BYTE ;RECORD TYPE INPUT LD6: CALL BYTE ;GET DATA BYTES CALL STORE ;STORE INX H DCR E JNZ LD6 ;GO ON. CALL BYTE ;GET CKSUM JZ LD5 LDERR: LXI H,M6 ;CKSUM ERROR CALL MSG LHLD BLKAD ;ADR OF THIS BLOCK IS JMP RXAR ;NOW GIVEN LD7: CALL BYTE ;MSB OF XEQAD MOV H,A CALL BYTE MOV L,A ORA H JZ NEXT ;MONITOR IF ADR=0 PCHL ;OTHERWISE EXECUTE ; RIX: CALL RI JC ILLEG ;ON ERROR, PRINT '??' ANI 7FH ;REMOVE PARITY RET ; ; ROUTINE RI ; GETS A CHARACTER FROM THE CASSETTE READER INPUT ; ; RI: PUSH B ;SAVE BC LXI B,TMOUT ;GET TIMEOUT (MILLISECONDS) RI10: CALL CASTS ;GET READER STATUS JNZ RI15 ;READY ON NON-ZERO CALL DELAY ;IF NOT, DELAY 1 MS DCX B ;DECREMENT DELAY COUNT MOV A,B ;SEE IF IT ORA C ;IS ZERO YET. JNZ RI10 ;TRY AGAIN IF NOT DONE STC ;SET ERROR CARRY POP B ;RESTORE BC RET ;TROUBLED RETURN RI15: CALL CGETCH ;GET DATA. ORA A ;CLEAR CARRY ONLY. POP B ;RESTORE BC RET ;SIMPLY RETURN ; BYTE: PUSH B ;SAVE BC CALL RIX ;READ ASCII CALL CNVBN ;CONVERT TO HEX JC LDERR ;ERROR DETECTOR. RLC ;SHIFT LEFT 4 BITS RLC RLC RLC MOV B,A ;SAVE THEM A WHILE CALL RIX ;GET SECOND BYTE CALL CNVBN ;CONVERT TO HEX JC LDERR ;ERROR DETECTOR ORA B ;OR IN THE SAVED NYBBLE MOV C,A ;HOLD BYTE A WHILE. ADD D ;ADD TO CKSUM MOV D,A ;UPDATE CKSUM MOV A,C ;RESTORE BYTE POP B ;RESTORE BC RET ; ; FUNCTION DELAY. ; CAUSES THE SYSTEM TO DELAY FOR 1 MS. ; DELAY: PUSH B ;SAVE BC MVI B,ONEMS ;GET ONE MS LOOP COUNT DEL2: DCR B ;DECREMENT LOOP COUNT JNZ DEL2 ;NOT YET DONE. POP B ;ALL DONE. GET BC RET ;RETURN TO PATIENT WAITER. ; ENTER HERE FOLLOWING A SOFTWARE RST2 ; I.E. BREAKPOINT SETTING. ; BPAT: SHLD SVPC ;STORE CALLING PC STA TMPA ;AND CARRY (IN B7) RAL ;THEN ROTATE BACK THE ACC. LXI H,0 ;NOW TRANSFER THE SP TO HL BY DOING A DUMMY DAD SP ;ADD TO HL. (N.B. CLEARS CARRY) SHLD SVSP ;SAVE THE CALLER SP. LXI SP,SVA+1 ;PICK UP REG STORE POINTER PUSH PSW ;TO SAVE PSW PUSH B ;AND BC PUSH D ;AND DE. (HL ALREADY SAVED) LXI H,SVF ;GET THE PSB BYTE LDA TMPA ;PICK UP THE CARRY HOLDER, RAL ;ROTATE IT BACK TO CARRY. JNC BP1 ;SKIP IF CARRY NOT SET, INR M ;OTHERWISE RESET CARRY. BP1: LXI SP,STACK ;SET SP TO MONITOR STACK LXI H,M10 ;TYPE BREAKPOINT MESSAGE CALL MSG LHLD SVPC ;PICK-UP THE BREAK ADDRESS + 1 DCX H ;MAKE IT THE REAL ADDRESS. SHLD SVPC ;RESET THE SAVED PC STORE CALL THXW ;TELL THE USER WHERE HE BROKE. CALL CRLF ;NEXT LINE PLEASE. JMP REXAL ;NOW PRINT THE REGISTER DATA. ; ; ; ; CONTINUE AFTER A BREAKPOINT HALT ; ; ASSUMES THAT THE LOCATION OF THE B/P HAS BEEN ALTERED ; BY A PRIOR ; B XXXX COMMAND. ; CONTINUE CAN ONLY BE USED TO RETURN THE MONITOR TO ; A PROGRAM WHICH HAS BEEN HALTED BY EXECUTION ; OF A 'RST 2' INSTRUCTION (0D7H) AT A LOCATION WHOSE CONTENTS ; ARE SAVED IN 'BPDAT'. ; CONT: LHLD SVPC ;GET PSEUDO-RESTART. MOV A,L ;PUT LOW PART IN ACC. ORA H ;RESULT WILL BE ZERO IF ALL JZ ILLEG ;BITS ARE ZERO. I.E. NO B/P. CALL BLANK ;PRINT A SPACE CALL THXW ;FOLLOWED BY THE ADDRESS. XCHG ;PUT OLD ADDRESS IN DE LHLD BPADD ;NOW GET CURRENT ADDRESS. CALL NEGDE ;NEGATE THE PC ADDRESS. DAD D ;D.P. ADD TO B/P ADDRESS. MOV A,L ;LO RESULT TO ACC, ORA H ;OR IT WITH HI RESULT, LHLD SVPC ;RECOVER PC (MAY NEED IT) JNZ CON3 ;SEE IF DE=HL (I.E. ZERO RESULT) LXI H,BPDAT ;GET START ADDRESS OF SAVED INSTRUCTION. CON3: MVI A,CR ; FORCES 'J' CONTINUE. PUSH PSW ;SAVE SIMULATED 'J' COMMAND JMP JMP4 ;NOW ENTER 'JUMP'. ; ; ; BREAK-POINT THE PROGRAM AT LOCATION XXXX ; B XXXX ; ; MAY ALSO BE USED TO CLEAR A PREVIOUS B/P BY ; B (CRTN) ; ; BPT SAVES THE ADDRESS XXXX AND ITS CONTENTS ; IT THEN REPLACES THE CONTENTS OF XXXX WITH D7 ( RST 2 ). ; THIS FORCES THE PROGRAM TO SAVE ALL DATA AND RETURN ; TO THE MONITOR. THE PROGRAM MAY BE RESTARTED FROM ; XXXX BY A CONTINUE ( C ) COMMAND AFTER IT HAS HALTED. ; BPT: ; ;**** THIS CONDITIONAL CODE INSERTS THE RST2 JUMP IN RAM IF ; THE MONITOR IS NOT IN PAGE ZERO. ; ; ORG 0010H ; JMP BPIN ; IF ROMSW MVI A,JMP ;GET A 'JMP' STA 0010H ;PUT IT AT 0010H LXI H,BPIN ;GET ADDRESS OF 'BPIN' SHLD 0011H ;STORE IT AT 0011H ENDIF CALL PUWB ;GET ADDRESS JNC BPT1 ;GOT AN ADDRESS - SO PROCEED CPI CR ;NOT AN ADDRESS - WAS IT A CRTN JNZ ILLEG ;NO SO BOMB OUT LXI H,0 ;YES SO SIMULATE AN ADDRESS OF ZERO ; ; BPT WILL REMOVE THE OLD B/P (IF ANY ) ; BPT1: PUSH H ;COME HERE WITH ADDRESS IN HL. SAVE IT ON THE STACK LHLD BPADD ;IS THE PREVIOUS B/P ADDRESS = 0 MOV A,L ;PUT LO PART OF ADDRESS IN ACC ORA H ;THEN 'OR' WITH HI PART JZ BPT2 ;IT WAS ZERO SO SAVE XXXX AND (XXX) LXI H,BPDAT ;POINT TO THE SAVED DATA FROM THE LAST B/P MOV A,M ;GET IT IN A LHLD BPADD ;GET THE LAST B/P ADDRESS IN HL CALL STORE ;AND RESTORE THE DATA THERE ; ; BREAKPOINT MAKER. ; CREATES A GAP IN THE TARGET PROGRAM BY INSERTING AN 'RST 2' ; IN PLACE OF THE FIRST BYTE OF THE INSTRUCTION. ; THE INSTRUCTION (ALL BYTES, COUNT COMPUTED) IS PLACED ; IN A TEMPORARY STORE, ALONG WITH A JUMP TO THE NEXT ; INSTRUCTION IN THE TARGET PROGRAM. ; BPT2: POP H ;RETRIEVE B/P ADDRESS FROM STACK. SHLD BPADD ;SAVE IT FOR FUTURE RETURN. MOV A,H ;SEE IF THIS IS ORA L ;ONLY CLEARING JZ NEXT ;THE BREAKPOINT. MOV A,M ;LOAD ITS FIRST BYTE. LXI H,TAB1 ;GET START ADDRESS OF TABLE 1 CPI 40H ;SEE IF THE BYTE IS IN TABLE 1 JC BPT3 ; I.E. LESS THAN 40H LXI H,TAB2 ;GET START OF TABLE 2. SUI 0C0H ;SEE IF IT IS IN TABLE 2 JNC BPT3 ; I.E. >0BFH MVI A,1 ;THE GROUP 40H TO 0BFH IS 1-BYTE JMP BPT5 ;IN LENGTH. BPT3: MOV D,A ;RANGE OF BYTE IS NOW 0 TO 64 RRC ;WE MUST PACK THIS RANGE DOWN RRC ;TO 0 TO 15 BYTES OFFSET. MVI B,0 ;AND THEN MAKE UP THE ANI 0FH ;TRUE ADDRESS BY MOV C,A ;ADDING THE OFFSET TO THE DAD B ;START ADDRESS IN THE TABLE. MVI A,3 ;WE MUST ALSO KNOW WHERE IN ANA D ;THE BYTE THE INSTRUCTION SIZE MOV D,A ;IS TO BE FOUND. (SEE NOTE ABOVE TABLE) MOV A,M ;GET THE KEY BYTE. BPT4: DCR D ;FIND THE KEY POSSY. JM BPT5 ;BY DECREMENTING THE 'D' REGISTER UNTIL IT RRC ;GOES NEGATIVE. IF NOT FOUND, ROTATE THE KEY RRC ;BYTE 2 POSITIONS RIGHT JMP BPT4 ;AND TRY AGAIN BPT5: ANI 3 ;WE CAN NOW COMPUTE THE BYTE COUNT. JZ ILLEG ;(OF COURSE 0 IS ILLEGAL) MOV C,A ;SAVE THE COUNT IN C LXI H,BPDAT ;DATA STORE ADDRESS XCHG ;PUT IT INTO DE LHLD BPADD ;GET THE SOURCE ADDRESS. BPT6: MOV A,M ;PICK UP THE DATA BYTE AND INX H ;THEN BUMP ADDRESS. XCHG ;AFTER SWAPPING HL ADDRESSES, MOV M,A ;PUT IT IN THE BUFFER. INX H ;NOW BUMP STORE ADDRESS, XCHG ;BEFORE RESTORING THE ADDRESSES. DCR C ;DECREMENT BYTE COUNTER. JNZ BPT6 ;TRY AGAIN IF STILL DATA. XCHG ;RETRIEVE THE STORE ADDRESS. MVI M,JMP ;PUT 'JMP' (0C3H) IN STORE. INX H ;BUMP STORE ADDRESS. MOV M,E ;LOW ORDER RETURN ADDRESS. INX H ;BUMP YET AGAIN. MOV M,D ;HIGH ORDER RETURN ADDRESS. LHLD BPADD ;FINALLY REPLACE THE MVI M,0D7H ;B/P WITH AN 'RST 2' JMP NEXT ; ; BREAKPOINT DATA TABLE. ; CONSISTS OF A SERIES OF DATA BYTES WHICH DEFINE THE ; NUMBER OF BYTES IN AN INSTRUCTION, BASED ON THE ; VALUE OF ITS FIRST BYTE. ; ; THE TABLE HAS 2 SECTIONS. ; TAB1 CONTAINS DATA FOR BYTES 000H TO 03FH ; TAB2 CONTAINS DATA FOR BYTES 0C0H TO 0FFH ; EACH BYTE CONTAINS 4 KEYS REPRESENTING THE SIZE OF ; 4 INSTRUCTIONS (RANGE 0-3, 0 IS ILLEGAL) ; SUCH THAT THE BOTTOM 2 BITS OF THE INSTRUCTION BYTE KEY TO ; THE TABLE BYTE AS FOLLOWS:- ; 00 BITS B1,B0 ; 01 BITS B3,B2 ; 10 BITS B5,B4 ; 11 BITS B7,B6 ; B00 EQU 0 ;KEY 0 DATA BITS B01 EQU 1 B02 EQU 2 B03 EQU 3 B10 EQU 0 ;KEY 1 DATA BITS B11 EQU B01*4 B12 EQU B02*4 B13 EQU B03*4 B20 EQU 0 ;KEY 2 DATA BITS B21 EQU B11*4 B22 EQU B12*4 B23 EQU B13*4 B30 EQU 0 ;KEY 3 DATA BITS B31 EQU B21*4 B32 EQU B22*4 B33 EQU B23*4 ; TAB1: DB B01+B13+B21+B31 DB B01+B11+B22+B31 DB B00+B11+B21+B31 DB B01+B11+B22+B31 DB B00+B13+B21+B31 DB B01+B11+B22+B31 DB B00+B11+B21+B31 DB B01+B11+B22+B31 DB B01+B13+B23+B31 DB B01+B11+B22+B31 DB B00+B11+B23+B31 DB B01+B11+B22+B31 DB B01+B13+B23+B31 DB B01+B11+B22+B31 DB B00+B11+B23+B31 DB B01+B11+B22+B31 TAB2: DB B01+B11+B23+B33 DB B03+B11+B22+B31 DB B01+B11+B23+B30 DB B03+B13+B22+B31 DB B01+B11+B23+B32 DB B03+B11+B22+B31 DB B01+B10+B23+B32 DB B03+B10+B22+B31 DB B01+B11+B23+B31 DB B03+B11+B22+B31 DB B01+B11+B23+B31 DB B03+B10+B22+B31 DB B01+B11+B23+B31 DB B03+B11+B22+B31 DB B01+B11+B23+B31 DB B03+B10+B22+B31 ; ;**** CASSETTE I/O HANDLING ROUTINES. ; ; ;**** CASSETTE OUTPUT CHARACTER. ; CTYPE: PUSH PSW ;SAVE PSW CTYP1: IN CSST ;STATUS ANI TRDY ;READY? JZ CTYP1 POP PSW ;YES. PRINT OUT CSOUT ;AT CASSETTE. RET ; ;**** GET CHARACTER ; CSI: CGETCH: CALL CASTS ;GET STATUS JZ CSI IN CSIN ;GET CHR RET ; ;**** CASSETTE INPUT STATUS ; CASTS: IN CSST ;STATUS BYTE ANI RBR ;MASKED RET ; ;**** CASSETTE BYTE PUT. ; CTHXB: PUSH PSW ;SAVE DATA RRC ;ROTATE RRC ;THE RRC ;BYTE RRC ;4 BITS. CALL CTHXN ;PRINT 1ST NYBBLE POP PSW ;RECOVER ; ;**** CASSETTE NYBBLE PUT. ; CTHXN: PUSH PSW ;SAVED ANI 0FH ;BOTTOM 4 BITS ADI 90H ;MAKE THE DAA ;NYBBLE ACI 40H ;INTO AN DAA ;ASCII CHR 0-F CALL CTYPE ;PUT IT. POP PSW RET ; ;**** CASSETTE WORD OUTPUT. ; CTHXW: PUSH PSW ;SAVE PSW MOV A,H ;DO TOP CALL CTHXB ;BYTE MOV A,L ;THEN BOTTOM CALL CTHXB ;BYTE POP PSW RET ; ;**** CASSETTE CRLF OUTPUT. ; CCRLF: PUSH H ;SAVE HL LXI H,M2 ;GET MESSAGE CALL CMSG ;PRINT IT. POP H RET ; ;**** CASSETTE MESSAGE. ; CMSG: PUSH PSW PUSH H ;SAVE PSW AND HL CMNXT: MOV A,M ;GET BYTE INX H ;BUMP PTR. CPI 0FFH ;END FLAG? CNZ CTYPE JNZ CMNXT ;MORE. POP H ;RECOVER HL POP PSW ;AND PSW RET ; ;**** CASSETTE BLANK. ; CBLANK: PUSH PSW MVI A,' ' ;A SPACE CALL CTYPE ;IS SENT. POP PSW RET ; ;**** GET HEX NYBBLE. ; CGHXN: MVI A,0FH ;ONLY BOTTOM NYBBLE JMP CGHB1 ; ;**** GET HEX BYTE. ; CGHXB: MVI A,0FFH ;ALL BYTE NEEDED. CGHB1: PUSH H ;SAVE HL CALL CGHXW ;GET A WORD. JC CGHB2 ;ERROR? ANA L ;NYBBLE/BYTE ONLY. CGHB2: POP H RET ; ;**** GET HEX WORD FROM CASSETTE. ; CGHXW: PUSH PSW ;SAVE PSW LXI H,0 ;START WITH NOTHING. CALL CGETCH ;GET CHARACTER ANI 7FH ;AND MASK IT. CALL CNVBN ;CONVERT TO BINARY. JC GHW3 MOV L,A ;SAVE IT IF O.K. CGHW1: CALL CGETCH ;AND ANOTHER ANI 7FH ;MASKED. CALL CNVBN ;THEN CONVERTED. JC GHW2 DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 ADD L ;ADD LO BYTE. MOV L,A ;UPDATE JMP CGHW1 ; ; ; ; ; ORG ROM + 07DCH ; ;**** JUMP TABLE FOR CASSETTE ROUTINES. ; ZCTYPE: JMP CTYPE ZCGETC: JMP CGETCH ZCMSG: JMP CMSG ZCCRLF: JMP CCRLF ZCSPAC: JMP CBLANK ZCTHXN: JMP CTHXN ZCTHXB: JMP CTHXB ZCTHXW: JMP CTHXW ZCGHXN: JMP CGHXN ZCGHXB: JMP CGHXB ZCGHXW: JMP CGHXW ZCASTS: JMP CASTS ; ORG ROM+0800H ; QIN: EQU 0DBH QOUT: EQU 0D3H QRET: EQU 0C9H ; ;**** INPUT AND OUTPUT PORT DATA ROUTINES. ; INPT: OUTPT: MVI A,QIN ;ASSUME 'IN' COMMAND STA BUFF CALL GBYTE ;GET PORT NUMBER. STA BUFF+1 ;SAVE IT IN 'BUFF+1' MVI A,QRET ;GET 'RET' STA BUFF+2 MVI A,'I' ;SEE IF THIS IS 'IN' COMMAND. CMP B JNZ OUTER ;MUST BE 'OUT' CALL BUFF ;GET INPUT DATA. CALL BLANK ;ONE SPACE, CALL THXB ;FOLLOWED BY THE BYTE. CALL CRLF JMP NEXT OUTER: MVI A,QOUT ;REPLACE 'IN' WITH 'OUT' STA BUFF CALL GBYTE ;OUTPUT BYTE REQUIRED. CALL CRLF CALL BUFF ;OUTPUT IT. JMP NEXT ; ; ;*********************************************************** ; ; DISASSEMBLER PROGRAM FOR 8080 ROUTINES. ; ;*********************************************************** ; ; ;**** FIND START ADDRESS. ; DIS80: CALL PUWB ;GET START ADDRESS. JC ILLEG ;ERROR EXIT CALL CRLF MOV B,H MOV C,L ;BC NOW HAS MEMORY ADDR. ; ;**** GET BYTE. ; DIS1: MOV H,B ;PUT MEMORY ADDRESS MOV L,C ;INTO HL CALL THXW ;PRINT IT CALL BLANK ;AND A SPACE. LDAX B ;GET FIRST BYTE. ; ;**** FIND THE TABLE POSITION. ; MOV E,A ;PUT OFFSET INTO C MVI D,0 ;AND CLEAR HI BYTE ; ; ADD OFFSET THREE TIMES. ; LXI H,ATAB1 ;TABLE START ADDRESS. DAD D ;ADD OFFSET DAD D ;THREE DAD D ;TIMES. ; ;**** READY TO PROCESS. ; MOV D,M ;LOAD BYTE COUNT. MOV A,D INX H ;BUMP PAST BYTE COUNTER. CALL BPRNT ;PRINT THE BYTES. MOV E,M ;GET OPCODE OFFSET MVI D,0 ;INTO DE INX H ;BUMP TABLE POINTER. PUSH H ;AND SAVE IT LXI H,ATAB2 ;ADD OFFSET DAD D ;TO THE DAD D ;TABLE HEADER DAD D ;FOUR DAD D ;TIMES. MVI D,4 CALL PRNT ;PRINT OPCODE. LXI H,MSGBK ;NOW PRINT CALL MSG ;4 SPACES POP H ;RETRIEVE PTR. MOV E,M ;DITTO FOR OPERAND(S). MVI D,0 LXI H,ATAB3 DAD D DAD D DAD D MVI D,3 CALL PRNT ;PRINT OPERAND(S) PUSH B ;SAVE MEM PTR. MVI H,0 ;ZERO OUT H MOV L,A ;PUT BYTE COUNT INTO L DAD B ;BUMP MEMORY ADDRESS. MOV B,H ;PUT BACK INTO MOV C,L ;BC POP H ;RETRIEVE MEMORY ADDRESS. DCR A ;TEST BYTE COUNT JZ DISB1 ;FOR ONE DCR A JZ DISB2 ;OR TWO DISB3: INX H ;GET AND MOV E,M ;PRINT INX H ;16 BIT MOV D,M ;DATA XCHG ;WORD CALL THXW ;VALUE JMP DISB1 DISB2: INX H ;GET AND MOV A,M ;PRINT 8 BIT CALL THXB ;DATA BYTE VALUE DISB1: CALL CRLF ;NEW LINE PLEASE. CALL HOLD ;SEE IF HOLD REQUESTED. JMP DIS1 ;NO. ; ;**** PRINT CURRENT BYTE IF VALID. ; BPRNT: PUSH PSW ;SAVE PSW. PUSH B ;SAVE CURRENT MEM PTR. MVI E,3 ;PRINT 3 BYTES. BPRT1: LDAX B ;GET CURRENT MEMORY BYTE. DCR D ;DECREMENT COUNTER. CP THXB ;PRINT IT, CM BLANK ;OR ELSE 2 SPACES. CM BLANK CALL BLANK ;FOLLOWED BY SPACER. INX B ;FINALLY BUMP POINTER. DCR E JNZ BPRT1 POP B ;RETRIEVE MEM PTR. POP PSW ;AND PSW. RET ; ;**** PRINT A STRING FOLLOWED BY A SPACE. ; PRNT: PUSH PSW PRNT1: MOV A,M ;GET DATA BYTE CALL TYPE ;PRINT IT. INX H ;READY FOR NEXT BYTE DCR D ;DECREMENT AND TEST JNZ PRNT1 ;LOOP COUNT. CALL BLANK POP PSW RET ; ; ;******************************************************** ; ; LINE ASSEMBLER PROGRAM. ; USES COMMON TABLES WITH DISASSEMBLER. ; ;******************************************************** ; ; ASM80: CALL PUWB ;GET START ADDRESS. JC ILLEG CALL CRLF ASM1: CALL THXW ;TYPE CURRENT ADDRESS. SHLD MEMADR ;SAVE CURRENT ADDRESS. CALL STRING ;GET THE OPCODE STRING. LXI H,ATAB2 ;OPCODE TABLE MVI B,4 ;HAS 4 BYTES/ENTRY CALL STCOMP ;SCAN FOR THE GIVEN STRING. JC ILLEG ;CARRY SET ON ERROR. STA OPCODE ;SAVE OPCODE OFFSET. LXI H,ATAB1+1 ;FIND A CODE ASM2: CMP M ;WHICH MATCHES INX H ;SO THAT JZ ASM3 ;WE CAN SEE INX H ;IF THE INX H ;THIRD BYTE IN JMP ASM2 ;THE TABLE ASM3: MOV A,M ;HAPPENS TO BE CPI 0 ;NON-ZERO. JZ ASM4 ;I.E. NON-BLANK CALL STRING ;OPERAND STRING REQUIRED. LXI H,ATAB3 ;LOOK FOR OPERAND STRING MVI B,3 ;IN 3 BYTE/ENTRY OPERAND CALL STCOMP ;TABLE. JC ILLEG CALL BLANK ;SPACE UP ASM4: MOV E,A ;SAVE OPERAND CODE NUMBER LDA OPCODE ;AND ALSO MOV D,A ;OPCODE CODE NUMBER LXI H,ATAB1+1 ;FIND DOUBLE MATCH MVI C,0 ;IN THE OPCODE TABLE ASM5: MOV A,M ;GET TEST BYTE. CPI 0FFH ;SEE IF E.O.T. JZ ILLEG ;I.E. -1 BYTE. CMP D ;OPCODE MATCH? JNZ ASM6 INX H MOV A,M CMP E ;OPERAND MATCH? JZ ASM7 DCX H ASM6: INX H ;NO. BUMP INX H ;PAST THIS INX H ;ENTRY AND INR C ;INCREMENT TABLE COUNTER. JMP ASM5 ASM7: DCX H ;GOT IT. GO BACK DCX H ;TWO BYTES AND MOV D,M ;GET BYTE COUNT. LHLD MEMADR ;RETRIEVE CURRENT MEM ADDR. MOV A,C ;STORE THE FIRST CALL STORE ;BYTE VALUE MOV A,D ;THEN LOOK AT SUI 2 ;SIZE OF INSTRUCTION. JM ASB1 ;ONE BYTE LXI H,MSGBK ;OR MULTIBYTE. CALL MSG CALL GHXW ;GET A NUMBER. JC ILLEG ORA A ;RESET BYTE FLAG. JZ ASB2 ;TWO BYTE. ASB3: XCHG ;NUMBER NOW IN DE. LHLD MEMADR ;GET MEMOR ADDR. INX H ;PUT LO BYTE MOV A,E ;INTO NEXT CALL STORE ;ADDRESS. INX H ;AND HI BYTE MOV A,D ;INTO 3RD BYTE CALL STORE ;ADDRESS. JMP ASB1 ;FINISH OFF. ASB2: MOV A,L ;PUT LO BYTE LHLD MEMADR ;ONLY INTO INX H ;INTO 2ND. BYTE CALL STORE ;ADDRESS. ASB1: INX H ;BUMP TO NEXT ADDR. CALL CRLF ;NEW LINE, JMP ASM1 ;START ALL OVER AGAIN. ; ;**** STRING INPUT ROUTINE. ; ON RETURN, FIRST 4 BYTES IN 'BUFF' WITH ; TRAILING BLANKS IF NECESSARY. ; STRING: LXI H,MSGBK CALL MSG LXI H,2020H ;PUT SPACES SHLD BUFF ;INTO 4 BYTE SHLD BUFF+2 ;BUFFER. LXI H,BUFF MVI E,4 STR1: CALL CHIN ;LOOK FOR CPI CR ; TERMINATOR JZ NEXT JMP STR3 STR2: CALL CHIN ;GET A CHARACTER. STR3: CPI CR ;LOOK FOR RZ ; OR CPI ' ' ;SPACE AS RZ ;DELIMITER. DCR E ;ONLY THE FIRST JM STR2 ;4 BYTES MOV M,A ;ARE STORED. INX H JMP STR2 ; ;**** STRING COMPARE ROUTINE. ; ON INPUT, HL=START OF TEST TABLE ; B=BYTE COUNT PER ENTRY. ; GOOD OUTPUT, CARRY CLI, ACC=OFFSET VALUE. ; BAD OUTPUT, CARRY SET, ACC=0FFH. ; STCOMP: MVI C,0 ;CLEAR COUNTER. STC0: PUSH B ;SAVE COUNTER AND STRING SIZE. LXI D,BUFF ;GET BUFFER START. STC1: LDAX D ;GET TEST BYTE. CMP M ;SEE IF DIFFERENT. JNZ STC2 DCR B ;OR IF ALL BYTES CHECK. JZ STC5 INX D ;BUMP POINTERS INX H ;AND THEN JMP STC1 ;TRY AGAIN. STC2: MOV A,M ;DIFFERENT. SAVE CURRENT BYTE. STC3: DCR B ;BUMP INX H ;PAST JZ STC4 ;THIS JMP STC3 ;BYTE. STC4: POP B ;RETRIEVE COUNTERS, INR C ;BUMP COUNTER, CPI 0FFH ;SEE IF E.O.T. JZ STC6 JMP STC0 ;TRY AGAIN. STC5: POP B ;FOUND A MATCH. MOV A,C ;RETURN ENTRY ORA A ;IN ACC WITH RET ;CARRY RESET. STC6: STC ;ERROR RETURN RET ;SETS CARRY ONLY. ; MSGBK: DB ' ',0FFH ; ;**** OPERATION CODE TABLE. ; ARRANGED AS FOLLOWS, ACCORDING TO INSTRUCTION ; FIRST BYTE VALUE (0-255):- ; ; FIRST BYTE IS INSTRUCTION SIZE (BYTES) ; NEXT 4 BYTES ARE OPCODE. ; NEXT BYTE IS ATAB3 ENTRY NUMBER. ; ATAB1: DB 1,0,0 DB 3,1,1 DB 1,2,1 DB 1,6,1 DB 1,8,1 DB 1,9,1 DB 2,30,1 DB 1,10,0 DB 1,88,0 DB 1,14,1 DB 1,3,1 DB 1,7,1 DB 1,8,2 DB 1,9,2 DB 2,30,2 DB 1,11,0 DB 1,88,0 DB 3,1,3 DB 1,2,3 DB 1,6,3 DB 1,8,3 DB 1,9,3 DB 2,30,3 DB 1,12,0 DB 1,88,0 DB 1,14,3 DB 1,3,3 DB 1,7,3 DB 1,8,4 DB 1,9,4 DB 2,30,4 DB 1,13,0 DB 1,85,0 DB 3,1,5 DB 3,4,0 DB 1,6,5 DB 1,8,5 DB 1,9,5 DB 2,30,5 DB 1,15,0 DB 1,88,0 DB 1,14,5 DB 3,5,0 DB 1,7,5 DB 1,8,6 DB 1,9,6 DB 2,30,6 DB 1,16,0 DB 1,86,0 DB 3,1,9 DB 3,17,0 DB 1,6,9 DB 1,8,7 DB 1,9,7 DB 2,30,7 DB 1,19,0 DB 1,88,0 DB 1,14,9 DB 3,18,0 DB 1,7,9 DB 1,8,8 DB 1,9,8 DB 2,30,8 DB 1,20,0 DB 1,21,11 DB 1,21,12 DB 1,21,13 DB 1,21,14 DB 1,21,15 DB 1,21,16 DB 1,21,17 DB 1,21,18 DB 1,21,19 DB 1,21,20 DB 1,21,21 DB 1,21,22 DB 1,21,23 DB 1,21,24 DB 1,21,25 DB 1,21,26 DB 1,21,27 DB 1,21,28 DB 1,21,29 DB 1,21,30 DB 1,21,31 DB 1,21,32 DB 1,21,33 DB 1,21,34 DB 1,21,35 DB 1,21,36 DB 1,21,37 DB 1,21,38 DB 1,21,39 DB 1,21,40 DB 1,21,41 DB 1,21,42 DB 1,21,43 DB 1,21,44 DB 1,21,45 DB 1,21,46 DB 1,21,47 DB 1,21,48 DB 1,21,49 DB 1,21,50 DB 1,21,51 DB 1,21,52 DB 1,21,53 DB 1,21,54 DB 1,21,55 DB 1,21,56 DB 1,21,57 DB 1,21,58 DB 1,21,59 DB 1,21,60 DB 1,21,61 DB 1,21,62 DB 1,21,63 DB 1,21,64 DB 1,76,0 DB 1,21,66 DB 1,21,67 DB 1,21,68 DB 1,21,69 DB 1,21,70 DB 1,21,71 DB 1,21,72 DB 1,21,73 DB 1,21,74 DB 1,22,1 DB 1,22,2 DB 1,22,3 DB 1,22,4 DB 1,22,5 DB 1,22,6 DB 1,22,7 DB 1,22,8 DB 1,23,1 DB 1,23,2 DB 1,23,3 DB 1,23,4 DB 1,23,5 DB 1,23,6 DB 1,23,7 DB 1,23,8 DB 1,24,1 DB 1,24,2 DB 1,24,3 DB 1,24,4 DB 1,24,5 DB 1,24,6 DB 1,24,7 DB 1,24,8 DB 1,25,1 DB 1,25,2 DB 1,25,3 DB 1,25,4 DB 1,25,5 DB 1,25,6 DB 1,25,7 DB 1,25,8 DB 1,26,1 DB 1,26,2 DB 1,26,3 DB 1,26,4 DB 1,26,5 DB 1,26,6 DB 1,26,7 DB 1,26,8 DB 1,27,1 DB 1,27,2 DB 1,27,3 DB 1,27,4 DB 1,27,5 DB 1,27,6 DB 1,27,7 DB 1,27,8 DB 1,28,1 DB 1,28,2 DB 1,28,3 DB 1,28,4 DB 1,28,5 DB 1,28,6 DB 1,28,7 DB 1,28,8 DB 1,29,1 DB 1,29,2 DB 1,29,3 DB 1,29,4 DB 1,29,5 DB 1,29,6 DB 1,29,7 DB 1,29,8 DB 1,42,0 DB 1,66,1 DB 3,43,0 DB 3,40,0 DB 3,44,0 DB 1,67,1 DB 2,31,0 DB 1,77,0 DB 1,45,0 DB 1,39,0 DB 3,46,0 DB 1,88,0 DB 3,47,0 DB 3,41,0 DB 2,32,0 DB 1,78,0 DB 1,48,0 DB 1,66,3 DB 3,49,0 DB 2,72,0 DB 3,50,0 DB 1,67,3 DB 2,33,0 DB 1,79,0 DB 1,51,0 DB 1,88,0 DB 3,52,0 DB 2,73,0 DB 3,53,0 DB 1,88,0 DB 2,34,0 DB 1,80,0 DB 1,54,0 DB 1,66,5 DB 3,55,0 DB 1,68,0 DB 3,56,0 DB 1,67,5 DB 2,35,0 DB 1,81,0 DB 1,57,0 DB 1,69,0 DB 3,58,0 DB 1,70,0 DB 3,59,0 DB 1,88,0 DB 2,36,0 DB 1,82,0 DB 1,60,0 DB 1,66,10 DB 3,61,0 DB 1,74,0 DB 3,62,0 DB 1,67,10 DB 2,37,0 DB 1,83,0 DB 1,63,0 DB 1,71,0 DB 3,64,0 DB 1,75,0 DB 3,65,0 DB 1,88,0 DB 2,38,0 DB 1,84,0 ; ;**** ATAB2 CONTAINS ALL OPCODES. ; ATAB2: DB 'NOP ' DB 'LXI ' DB 'STAX' DB 'LDAX' DB 'SHLD' DB 'LHLD' DB 'INX ' DB 'DCX ' DB 'INR ' DB 'DCR ' DB 'RLC ' DB 'RRC ' DB 'RAL ' DB 'RAR ' DB 'DAD ' DB 'DAA ' DB 'CMA ' DB 'STA ' DB 'LDA ' DB 'STC ' DB 'CMC ' DB 'MOV ' DB 'ADD ' DB 'ADC ' DB 'SUB ' DB 'SBB ' DB 'ANA ' DB 'XRA ' DB 'ORA ' DB 'CMP ' DB 'MVI ' DB 'ADI ' DB 'ACI ' DB 'SUI ' DB 'SBI ' DB 'ANI ' DB 'XRI ' DB 'ORI ' DB 'CPI ' DB 'RET ' DB 'JMP ' DB 'CALL' DB 'RNZ ' DB 'JNZ ' DB 'CNZ ' DB 'RZ ' DB 'JZ ' DB 'CZ ' DB 'RNC ' DB 'JNC ' DB 'CNC ' DB 'RC ' DB 'JC ' DB 'CC ' DB 'RPO ' DB 'JPO ' DB 'CPO ' DB 'RPE ' DB 'JPE ' DB 'CPE ' DB 'RP ' DB 'JP ' DB 'CP ' DB 'RM ' DB 'JM ' DB 'CM ' DB 'POP ' DB 'PUSH' DB 'XTHL' DB 'PCHL' DB 'XCHG' DB 'SPHL' DB 'OUT ' DB 'IN ' DB 'DI ' DB 'EI ' DB 'HLT ' DB 'RST0' DB 'RST1' DB 'RST2' DB 'RST3' DB 'RST4' DB 'RST5' DB 'RST6' DB 'RST7' DB 'RIM ' DB 'SIM ' AT2E: DB 0FFH,0FFH,0FFH,0FFH DB '--- ' ; ;**** ATAB3 CONTAINS ALL POSSIBLE OPERANDS. ; ATAB3: DB ' ' DB 'B ' DB 'C ' DB 'D ' DB 'E ' DB 'H ' DB 'L ' DB 'M ' DB 'A ' DB 'SP ' DB 'PSW' DB 'B,B' DB 'B,C' DB 'B,D' DB 'B,E' DB 'B,H' DB 'B,L' DB 'B,M' DB 'B,A' DB 'C,B' DB 'C,C' DB 'C,D' DB 'C,E' DB 'C,H' DB 'C,L' DB 'C,M' DB 'C,A' DB 'D,B' DB 'D,C' DB 'D,D' DB 'D,E' DB 'D,H' DB 'D,L' DB 'D,M' DB 'D,A' DB 'E,B' DB 'E,C' DB 'E,D' DB 'E,E' DB 'E,H' DB 'E,L' DB 'E,M' DB 'E,A' DB 'H,B' DB 'H,C' DB 'H,D' DB 'H,E' DB 'H,H' DB 'H,L' DB 'H,M' DB 'H,A' DB 'L,B' DB 'L,C' DB 'L,D' DB 'L,E' DB 'L,H' DB 'L,L' DB 'L,M' DB 'L,A' DB 'M,B' DB 'M,C' DB 'M,D' DB 'M,E' DB 'M,H' DB 'M,L' DB 'M,M' DB 'M,A' DB 'A,B' DB 'A,C' DB 'A,D' DB 'A,E' DB 'A,H' DB 'A,L' DB 'A,M' DB 'A,A' AT3E: DB 0FFH,0FFH,0FFH ; ; LOAD HEX OBJECT TAPE. ; ; LOAD A HEX-BINARY TAPE AS PRODUCED BY THE 'P' ; COMMAND. ; MAY CONTAIN AN OFFSET VALUE, ALLOWING THE DATA TO ; BE LOADED INTO A DIFFERENT LOCATION TO THAT SPECIFIED ; BY THE LOAD ADDRESS. ; ; SPORT EQU 083H DPORT EQU 083H SPKT EQU 080H ; ORG ROM+0F40H ; LOADF: CALL PUWB ;GET THE OFFSET, IF ANY. JNC LD4F CPI CR ;ERROR MAY ONLY BE JNZ ILLEG LD4F: CALL CRLF ;NEW LINE PLEASE. PUSH H ;SAVE BIAS ADR LD5F: POP H ;GET BIAS PUSH H ;AND RESTORE CALL RIXF ;GET INPUT MVI B,':' ;WAIT FOR ':' SUB B JNZ LD5F ;TRY AGAIN MOV D,A ;CLEAR CKSUM CALL BYTEF ;GET LENGTH JZ LD7F ;ZERO MEANS ALL DONE MOV E,A ;SAVE LENGTH CALL BYTEF PUSH PSW ;SAVE HI ADR CALL BYTEF POP B ;FETCH MSBYTE MOV C,A ;BC NOW HAS ADR PUSH B ;SAVE IT XTHL ;INTO HL SHLD BLKAD ;SAVE BLOCK ADR XTHL ;IN CASE OF ERROR POP B DAD B ;RESTORE AND ADD BIAS CALL BYTEF ;RECORD TYPE INPUT LD6F: CALL BYTEF ;GET DATA BYTES CALL STORE ;STORE INX H DCR E JNZ LD6F ;GO ON. CALL BYTEF ;GET CKSUM JZ LD5F LDERRF: LXI H,M6 ;CKSUM ERROR CALL MSG LHLD BLKAD ;ADR OF THIS BLOCK IS JMP RXAR ;NOW GIVEN LD7F: CALL BYTEF ;MSB OF XEQAD MOV H,A CALL BYTEF MOV L,A ORA H JZ NEXT ;MONITOR IF ADR=0 PCHL ;OTHERWISE EXECUTE ; RIXF: CALL RIF JC ILLEG ;ON ERROR, PRINT '??' ANI 7FH ;REMOVE PARITY RET ; ; ROUTINE RIF ; GETS A CHARACTER FROM THE FAST READER INPUT ; I.E. IT STARTS THE READER, AND EXPECTS QUICK REPLY. ; ; RIF: PUSH B ;SAVE BC PUSH D ;AND DE RIF05: MVI C,SPKT ;PRESET CURRENT STATUS LXI D,0 ;TIMEOUT COUNT. RIF10: IN SPORT ;GET STATUS. ANI SPKT ;LOOK AT SPROCKET ONLY. MOV B,A ;SAVE IT. MOV A,C ;OLD STATUS CMA ;IS INVERTED ANA B ;SO THAT + EDGE IS FOUND. MOV C,B ;SAVE CURRENT STATUS. JNZ RIF15 ;NON-ZERO=GOT IT. DCX D ;DROP T/O COUNT MOV A,D ;SEE IF ORA E ;COUNT IS JNZ RIF10 ;ZERO YET. STC POP D POP B RET RIF15: IN DPORT ;AND GET DATA. ORA A ;CLEAR CARRY ONLY. POP D POP B ;RESTORE BC RET ;SIMPLY RETURN ; BYTEF: PUSH B ;SAVE BC CALL RIXF ;READ ASCII CALL CNVBN ;CONVERT TO HEX JC LDERR ;ERROR DETECTOR. RLC ;SHIFT LEFT 4 BITS RLC RLC RLC MOV B,A ;SAVE THEM A WHILE CALL RIXF ;GET SECOND BYTE CALL CNVBN ;CONVERT TO HEX JC LDERR ;ERROR DETECTOR ORA B ;OR IN THE SAVED NYBBLE MOV C,A ;HOLD BYTE A WHILE. ADD D ;ADD TO CKSUM MOV D,A ;UPDATE CKSUM MOV A,C ;RESTORE BYTE POP B ;RESTORE BC RET ; ; ; END OF ROM ROUTINES. ; ; ENDROM EQU $ ; ; ; SYSTEM RAM AREA DEFINITION. ; ; ORG RAM ; ; STACK GOES IN HERE, PACKING DOWN FROM ; STORAGE AREA. ; ORG REGS ; ; MONITOR REG. SAVE AREA. ; SVPC: SVPCL: DS 1 ;SAVED PC LOW SVPCH: DS 1 ;SAVED PC HI SVSP: SVSPL: DS 1 ;SAVED SP LOW SVSPH: DS 1 ;SAVED SP HI SVHL: SVL: DS 1 ;SAVED L SVH: DS 1 ;SAVED H SVE: DS 1 ;SAVED E SVD: DS 1 ;SAVED D SVC: DS 1 ;SAVED C SVB: DS 1 ;SAVED B SVF: DS 1 ;SAVED PSB, FLAGS SVA: DS 1 ;SAVED ACC ; ; SPECIALS USED BY MONITOR ; BUFF: TMPA: GOGO: DS 3 DSA: DS 2 ;START OF ROM DATA OPCODE: DFA: DS 2 ;END OF ROM DATA MEMADR: ROMADR: DS 2 ;PROM ADDRESS POINTER. ECHO: DS 1 ;CHARACTER ECHO FLAG 0=NO ECHO ADR: DS 2 ;EXAMINE/MODIFY ADR XEQAD: DS 2 ;'X' EXECUTION ADR BLKAD: DS 2 ;'L' BLOCK ADR BPADD: DS 2 ;BREAKPOINT SAVE ADDRESS BPDAT: DS 6 ;BREAKPOINT SAVE DATA USERA: DS 2 ;USER FUNCTION VECTOR ADDRESS ; ; USER VECTORS RST3-RST7 ; RST3: DS 2 RST4: DS 2 RST5: DS 2 RST6: DS 2 RST7: DS 2 ; ; END