; ;CP/M MACRO ASSEM 2.0 #001 MOSS 2.2 MONITOR ; TITLE 'MOSS 2.2 MONITOR' PAGE 68 MACLIB Z80 ; .8080 ; ; MOSS MONITOR (VERSION 2.2) ; ; 20 JUNE 1980 ; ALL RIGHTS RESERVED BY ROBERT B. MASON ; ; OCR PDF Documents 09-20-2014 by Larry Kraemer ; Modify Z80.LIB to add needed Macro's by Garry Kraemer ; Debugging & Corrections by Garry Kraemer - Senior Software Engineer ; MOSS ORG 0F000H ROM EQU 0F000H ;ROM START ADDRESS WSVEC EQU 0 ;VECTOR FOR WARM RESTART NBKPTS EQU 2 ;NUMBER OF BREAKPOINTS CTRLS EQU 13H ;ASCII DC3 CR EQU 0DH ;ASCII CARRIAGE RETURN LF EQU 0AH ;ASCII LINE FEED FMFD EQU 0CH ;ASCII FORM FEED BELL EQU 7 ;ASCII CNTRL CHAR TO RING THE BELL IOBYTE EQU 3 ;ADDRESS OF I/O CONTROL BYTE SDATA EQU 20H ;SERIAL DATA PORT BASE ADDRESS SINTEN EQU SDATA+1 ;SERIAL INTERRUPT ENABLE REGISTER SIDENT EQU SDATA+2 ;SERIAL INTERRUPT IDENTIFICATION REGIS SLCTRL EQU SDATA+3 ;SERIAL LINE CONTROL REGISTER SMDMCT EQU SDATA+4 ;SERIAL MODEM CONTROL REGISTER SLSTAT EQU SDATA+5 ;SERIAL LINE STATUS REGISTER SMDMST EQU SDATA+6 ;SERIAL MODEM STATUS REGISTER ; ; SPSV EQU 6 ;STACK POINTER SAVE LOCATION ; ; ; REGISTER STORAGE DISPLACEMENTS FROM ; NORMAL SYSTEM STACK LOCATION. ; ALOC EQU 15H BLOC EQU 13H CLOC EQU 12H DLOC EQU 11H ELOC EQU 10H FLOC EQU 14H HLOC EQU 31H LLOC EQU 30H PLOC EQU 34H SLOC EQU 17H TLOC EQU 35H TLOCX EQU 25H LLOCX EQU 20H APLOC EQU 9 BPLOC EQU 11 CPLOC EQU 10 DPLOC EQU 13 EPLOC EQU 12 FPLOC EQU 8 HPLOC EQU 15 LPLOC EQU 14 XLOC EQU 7 YLOC EQU 5 RLOC EQU 2 ILOC EQU 3 ; ; JUMP TARGETS FOR BASIC INPUT/OUTPUT ; CBOOT: JMP INIT ;COLD START CONIN: JMP CI ;CONS0LE INPUT READER: JMP RI ;READER INPUT CONOUT: JMP CO ;CONSOLE OUTPUT PUNCH: JMP PO ;PUNCH OUTPUT LIST: JMP LO ;LIST OUTPUT CONST: JMP CSTS ;CONSOLE STATUS JMP IOCHK ;PUT IOBYTE INTO (A) JMP IOSET ;(C) HAS A NEW IOBYTE JMP MEMCK ;MEMORY LIMIT CHECK JMP RTS ;IODEF- DEFINE USER I/O ENTRY POINTS JMP RTS ;SPCL- I/O CONTROL JMP REST ;BREAKPOINT ENTRY POINT ; ; TBL CONTAINS THE ADDRESSES OF THE ACTION ROUTINES ; THE EXECUTIVE USES IT TO LOOK UP THE DESIRED ADDRESS. TBL: DW ASGN DW QPRT DW QPRT DW DISP DW EOF DW FILL DW GOTO DW HEXN DW INPT DW QPRT DW QPRT DW LEADER DW MOVE DW QPRT DW OUPT DW QPRT DW QUERY DW READ DW SUBS DW MTEST DW QPRT DW COMP DW WRITE DW XMNE DW I8250 DW BYE ; ; THE COLD INITIALIZATION CODE ; INIT: DI ;DISABLE INTERRUPTS LXI SP,3FH ;USE STACK TO INITIALIZE RESTARTS LXI H,JMP*256 ; WITH RESTART ERROR VECTORS LXI D,RSTER MVI B,16 ;16 TIMES (64 BYTES) INIT1: PUSH D PUSH H DJNZ INIT1 ; LXI SP,FAKE-2 ;SET UP TEMPORARY STACK MVI A,0 ;SKIP THE NEXT INST ORG $-1 ;SAVE A BYTE HERE ; ; MEMSIZ CALCULATES THE TOP OF CONTIGUOUS RAM. IT SEARCHES ; FROM THE BOTTOM UP UNTIL A NON-RAM LOCATION IS ; FOUND. IT THEN TAKES OFF FOR MONITOR WORK SPACE ; NEEDS AND RETURNS THE VALUE IN (H,L). MEMSIZ: PUSH B ;MOITOR START LOCATION LXI B,ROM LXI H,-1 ;START OF MEMORY ADDRESS SPACE MEMSZ1: INR H MOV A,M CMA MOV M,A CMP M CMA MOV M,A JRNZ MEMSZ2 ; MOV A,H ;SEE IF ON MONITOR BORDER CMP B JRNZ MEMSZ1 ; MEMSZ2: DCR H ;TAKE OFF WORKSPACE LXI B,EXIT-ENDX-3*NBKPTS+1 DAD B POP B ;(B,C) IS UNPREDICTABLE DURING INIT RET ; ; ROUTINE MEMCHK FINDS THE CURRENT TOP OF CONTIGUOUS MEMORY ; (LESS THE MONITOR WORKSPACE) AND RETURNS THE VALUE. ; MEMCK: PUSH H ;SAVE (H,L) CALL MEMSIZ ;GET THE RAM SIZE MOV A,L SUI 60 ;TAKE OFF WORK SPACE JRNC MEMCK0 ; DCR H MEMCK0: MOV B,H POP H RET ; FAKE: DW FAKE+2 SPHL LXI D,EXIT XCHG LXI B,ENDX-EXIT LDIR ; LXI B,3*NBKPTS PUSH D POP H DCX H LDIR ; LXI H,-24 DAD SP PUSH H INX H ;ADJUST USER STACK LOCATION INX H SHLD SPSV ;SAVE THE STACK INITIAL VALUE MVI D,10 ;INITIALIZE REGISTER STORAGE AREA INIT2: PUSH B DCR D ;LOOP CONTROL JRNZ INIT2 ; ; INSERT I/O INIT CODE HERE CALL RTS CALL I8250 ;INITIALIZE THE 8250 CALL RTS LXI H,LOGMSG ;LOG ONTO THE SYSTEM CALL PRTWD JMPR WINIT ;GO TO MONITOR EXECUTIVE ; ; ROUTINE EXF READS ONE PARAMETER. IT EXPECTS THE FIRST ; CHARACTER OF THE PARAMETER TO BE IN THE A REGISTER ; ON ENTRY. EXF: MVI B,1 ;SET UP FOR ONE PARAMETER LXI H,0 JMPR EX1 ;FIRST CHARACTER IN A ALREADY ; ; ROUTINE EXPR READS PARAMETERS FROM THE CONSOLE ; AND DEVELOPS A 16 BIT HEXADECIMAL FOR EACH ONE. ; THE NUMBER OF PARAMETERS WANTED IS IN THE B REG ; ON ENTRY. A CARRIAGE RETURN WILL TERMINATE THE ; ENTRY SEQUENCE. A BLANK OR A COMMA WILL END THE ; CURRENT PARAMETER ENTRY. EACH PARAMETER ONLY ; TAKES THE LAST 4 DIGITS TYPED IN; ANY EXCESS IS ; DISCARDED. A NON-HEX DIGIT WILL TERMINATE THE ; ENTRY SEQUENCE AND CAUSE A WARM BOOT OF THE MON. ; AS3: DJNZ AS2 ;PART OF THE ASSIGN CODE ; EX3: JRNZ QPRT ;NON-ZERO IS ERROR ; EXPR1: DCR B ;MORE PARAMETERS? RZ ;NO, RETURN EXPR: LXI H,0 ;INITIALIZE PARAMETER EX0: CALL ECHO ;GET NEXT NUMBER EX1: MOV C,A ;SAVE CHAR FOR LATER USE CALL NIBBLE JRC EX2 ;NOT A NUMBER, JUMP ; DAD H ;MULTIPLY BY 16 DAD H DAD H DAD H ORA L ;ADD ON NEW DIGIT MOV L,A JMPR EX0 ;GO GET NEXT DIGIT ; EX2: XTHL ;PUT UNDER RETURN ADDRESS ON STACK PUSH H ;RESTORE RETURN ADDRESS MOV A,C ;REGET THE LAST CHARACTER CALL P2C ;TEST FOR DELIMITER JRNC EX3 ;JUMP IF NOT CARRIAGE RETURN ; DJNZ QPRT ;CARRET WITH MORE PARAM MEANS ERROR ; RET ; ; MAIN ACTION ROUTINES ; ; LOGICAL ASSIGNMENT OF PERIPHERALS ; ;THIS ROUTINE CONTROLS THE ASSIGNMENT OF PHYSICAL ;PERIPHERALS TO THE FOUR LOGICAL DEVICE TYPES. IT ;ALTERS IOBYTE (MEMORY LOCATION 0003) TO MATCH THE ;CURRENT ASSIGNMENT. THE FOUR LOGICAL DEVICES ARE ;CONSOLE, READER LIST, AND PUNCH. IN ALL CASES, ;THE TTY DEVICE IS SET UP AS THE DEFAULT DEVICE. ; ASGN: CALL ECHO ;GET THE LOGICAL DEVICE DESIRED LXI H,ALT ;START OF CONVERSION TABLE LXI D,APT-ALT ;DISTANCE BETWEEN LOGICAL CHOICE MVI B,4 ;NUMBER OF LOGICAL CHOICES AS0: CMP M ;IS THS ONE IT? JRZ AS1 ;YES, JUMP ; DAD D ;NO, GO TO NEXT LOGICAL ENTRY DJNZ AS0 ; QPRT: LXI H,QMSG ;GET ADDRESS OF QUESTION MARK MSG CALL PRTWA ;PRNT IT ; THE WARM START CODE WINIT: LHLD SPSV ;RESET THE STACK SPHL WINITA: LXI H,WINIT ;RESET RETURN AND WARM START VECTOR PUSH H SHLD WSVEC+1 MVI A,0C3H STA WSVEC CALL CRLF ;START A NEW LINE CALL DECHO ;GET THE COMMAND SUI 'A' ;GET RID OF ASCII ZONE JRC QPRT ;BAD COMMAND ; CPI 'Z'-'A'+1 ;CHECK UPPER LIMIT JRNC QPRT ;BAD COM AND ; ADD A ;DOUBLE IT FOR TABLE OFFSET MOV E,A ;SET UP FOR DOUBLE ADD MVI D,0 MVI B,2 ;SET UP FOR TWO PARAMETERS LXI H,TBL ;GET ACTION ROUTINE ADDRESS DAD D MOV A,M ;LOAD H,L INDIRECT INX H MOV H,M MOV L,A PCHL ;GO TO ACTION ROUTINE ; ; FILL ACTION ROUTINE ; ;THIS ROUTINE FILLS A BLOCK OF MEMORY WITH A USER- ;DETERMINED CONSTANT. IT EXPECTS THREE PARAMETERS ;TO BE ENTERED IN THE FOLLOWING ORDER: ; ;START ADDRESS ;FINISH ADDRESS ;FILL VALUE ; FILL: CALL EXPR3 ;GET THREE PARAMETERS FIO: MOV M,C ;PUT DOWN THE FILL VALUE CALL HILO ;INCREMENT AND CHECK THE POINTER JRNC FIO ;NOT DONE YET, JUMP POP D ;RESTORE STACK POINTER IN CASE JMPR WINIT ; STACK WAS OVERWRITTEN ; AS1: MOV D,B ;SAVE THE COUNTER RESIDUE MVI B,4 ;LOOP CONTROL CALL DECHO ;GET THE NEW ASSIGNMENT AS2: INX H ;INCREMENT POINTER CMP M ;SEE IF THIS IS IT JRNZ AS3 ; MOV L,B ;SAVE THE RESIDUE TO FORM ASGT DCR L ;ADJUST VALUE MOV B,D ;REGET THE LOGICAL RESIDUE MVI H,3 ;SET UP THE IOBYTE MASK DCR B ;ADJUST THIS ONE ALSO JRZ AS5 ;NO SHFT NEEDED ; AS4: DAD H ;SHIFT THE MASKS INTO POSITION DAD H DJNZ AS4 ;NOT DONE YET, JUMP ; AS5: LDA IOBYTE ORA H ;MASK THE DESIRED ASSIGNMENT IN XRA H ;LOGICAL ASGT BITS NOW OFF ORA L ;PUT IN NEW VALUE MOV C,A IOSET: MOV A,C STA IOBYTE ;SAVE NEW ASSIGNMENTS RET IOCHK: LDA IOBYTE RET ; ALT: DB 'L' ;LOGICAL LIST DEVICE TABLE DB '2' ;USER DEVICE #2 DB '1' ;USER DEVICE #1 DB 'L' ;LIST TO HIGH SPEED PRINTER DB 'T' ;LIST TO TTY APT: DB 'P' ;LOGICAL PUNCH DEVICE TABLE DB '2' ;USER DEVICE #2 DB '1' ;USER DEVICE #1 DB 'P' ;PUNCH TO HIGH SPEED PUNCH DB 'T' ;PUNCH TO TTY ART: DB 'R' ;LOGICAL READER DEVICE TABLE DB '2' ;USER DEVICE #2 DB '1' ;USER DEVICE #1 DB 'P' ;READER TO HIGH SPEED READER DB 'T' ;READER TO TTY ACT: DB 'C' ;LOGICAL CONSOLE DEVICE TABLE DB '1' ;USER DEVICE #1 DB 'B' ;CONSOLE TO BATCH (PRINTER OR PTR) DB 'C' ;CONSOLE TO CRT DB 'T' ;CONSOLE TO TTY ; ; THE BYE ROUTINE IS USED TO PREVENT UNAUTHORIZED USAGE ; OF THE SYSTEM. THE SYSTEM LOCKS UP AND WILL NOT ; RESPOND TO ANYTHING OTHER THAN TWO ASCII BELL ; CHARACTERS. WHEN IT SEES THEM CONSECUTIVELY ; CONTROL IS RETURNED TO THE MONITOR WITHOUT ALTERING ; ANYTHING. ; BYE: MVI B,2 ;SET UP FOR TWO CHARACTERS BYE1: CALL CONI ;GO READ THE CONSOLE CPI BELL ;SEE IF AN ASCII BELL JRNZ BYE ;NO, START OVER AGAIN ; CALL ECH1 ;ECHO THE BELL DJNZ BYE1 ;NOT YET, GET NEXT ONE ; RET ;RETURN TO MONITOR ; ; COMPARE ROUTINE ; ;THIS ROUTINE COMPARES TWO BLOCKS OF MEMORY AGAINST EACH ; OTHER. IF A DIFFERENCE IN THE RELATIVE ADDRESS ; CONTENTS IS DETECTED THE ADDRESS OF THE FIRST ; BLOCK IS DISPLAYED ALONG WITH ITS CONTENTS AND ; THE CONTENTS OF THE OTHER BLOCK'S SAME RELATIVE ; ADDRESS. COMP: CALL EXPR3 ;GO GET THREE PARAMETERS CMPA: LDAX B ;GET SOURCE 2 DATA PUSH B ;SAVE SOURCE 2 POINTER MOV B,M ;READ SOURCE 1 DATA CMP B ;COMPARE DATA JRZ CMPB ;JUMP IF OK ; PUSH PSW ;SAVE SOURCE 2 DATA CALL LADRB ;WRITE THE ADDRESS MOV A,B ;GET SOURCE 1 DATA CALL DASH1 ;FORMAT POP PSW ;REGET SOURCE 2 DATA CALL HEX1 ;OUTPUT IT CMPB: POP B CALL HILOXB ;INCREMENT SOURCE I POINTER AND SEE IF JMPR CMPA ;JUMP IF NOT DONE YET ; ; ; DISPLAY ACTION ROUTINE ; THIS ROUTINE DISPLAYS A BLOCK OF MEMORY ON THE ; CURRENT CONSOLE DEVICE (CONSOLE DUMP). THE USER ; MUST SPECIFY THE START AND FINISH ADDRESSES. ; THE DISPLAY IS ORGANIZED TO DISPLAY UP TO 16 BYTES ; PER DISPLAY LTNE WITH ALL COLUMNS ALIGNED SO ; EACH COLUMN HAS THE SAME LAST HEX DIGIT IN ITS ADDRESS ; DISP: CALL EXLF ;GO GET BLOCK LIMITS DIS1: CALL LADRB ;DISPLAY THE START ADDRESS MOV A,L ;SEE IF ON 16 BYTE BOUNDARY CALL TRPLSP ;SKIP OVER TO RIGHT COLUMN PUSH H ;SAVE (H,L) DIS2: MOV A,M ;GET THE CONTENTS CALL HEX1 ;OUTPUT IT CALL HILO ;INCREMENT CHECK POINTER JRC DIS7 ;DONE IF CARRY SET CALL BLK ;MAKE COLUMNS MOV A,L ;READY FOR NEW LINE? ANI 0FH JRNZ DIS2 ; DIS3: POP H ;REGET LINE START ADDRESS MOV A,L ;SKIP OVER TO RIGHT SPACE ANI 0FH CALL TRPL2 DIS4: MOV A,M ;GET MEMORY VALUE ANI 7FH ;STRIP OFF PARITY BIT MOV C,A ;SET UP FOR OUTPUT CPI ' ' ;SEE IF PRINTABLE IN ASCII JRC DIS5 ;JUMP IF' SO ; CPI 7EH JRC DIS6 ; DIS5: MVI C,'.' ;ELSE, PRINT A DOT DIS6: CALL CONOUT CALL HILOX ;INCREMENT (H,L) AND SEE IF DONE MOV A,L ;NOT DONE, READY FOR NEW LINE? ANI 0FH JRNZ DIS4 ;JUMP IF NOT ; JMPR DIS1 ;DO THE NEXT LINE ; DIS7: SUB E ;SKIP OVER TO START ASCII PRINTOUT CALL TRPLSP JMPR DIS3 ;GO PRINT THE ASCII ; ; TRPLSP: ANI 0FH ;ISOLATE THE LOW FOUR BITS MOV B,A ;PREPARE TO SPACE OVER TO RIGHT COLUMN ADD A ;TRIPLE THE COUNT ADD B TRPL2: MOV B,A ;PUT BACK INTO B INR B ;ADJUST COUNTER TRPL1: CALL BLK ;DO THE SPACING DJNZ TRPL1 ;NO, DO ANOTHER COLUMN ; RET ; ; GO TO ACTION ROUTINE ; ; GOTO COMMAND TRANSFERS CONTROL TO A SPECIFIED ADDRESS. ; IT ALLOWS THE SELECTIVE SETTING OF UP TO TWO BREAKPOINTS ; AS WELL AS ALLOWING ANY CONSOLE INPUT TO BREAKPOINT ; THE RUN, AS LONG AS INTERRUPT 1 IS ACTIVE. ; GOTO: CALL PCHK ;SEE IF OLD ADDRESS WANTED JRC GO3 ; YES, JUMP JRZ GO0 ; YES, BUT SET SOME BREAKPOINTS CALL EXF ;GET NEW GOTO ADDRESS POP D LXI H,PLOC ;PUT ADDRESS IN PC LOCATION DAD SP MOV M,D ;LOW BYTE DCX H MOV M,E ;HIGH BYTE MOV A,C CPI CR ;SEE IF A CR WAS LAST ENTERED JRZ GO3 ; GO0: MVI B,NBKPTS LXI H,TLOC ;POINT TO TRAP STORAGE DAD SP GO1: PUSH B ;SAVE NUMBER OF BREAKPOINTS PUSH H ;SAVE STORAGE POINTER MVI B,2 ;SET UP TO GET A TRAP ADDRESS CALL EXPR1 ;GET A TRAP ADDRESS POP D ;GET THE TRAP ADDRESS INTO (D,E) POP H ;REGET THE STORAGE ADDRESS MOV A,D ;INSURE THE TRAP ADDRESS ISN'T ZERO ORA E JRZ GO2 ;JUMP IF SO ; MOV M,E ;SAVE THE BREAKPOINT ADDRESS INX H MOV M,D INX H LDAX D ;SAVE THE INSTRUCTION FROM THE BP ADDR MOV M,A INX H MVI A,RST OR 8 ;INSERT THE BREAKPOINT STAX D GO2: MOV A,C ;REGET THE DELIMITER TO SEE CPI CR ; IF WE ARE DONE SETTING BREAKPOINTS POP B ; UNLOAD THE STACK FIRST JRZ GO3 ;YES, JUMP ; DJNZ GO1 ;JUMP IF NOT AT BP LIMIT ; GO3: CALL CRLF POP H ;GET RID OF STACK JUNK LXI H,RS9 PUSH H LXI H,REST SHLD 9 ;SET BREAKPOINT JUMP VECTOR ADDRESS LXI H,24 ;FIND REGISTER SET ROUTINE ADDRESS DAD SP POP D ;ADJUST THE STACK PCHL ;GO TO THE DESIRED PLACE ; ; GENERAL PURPOSE INPUT/OUTPUT ROUTINES ; ;THESE ROUTINES ALLOW BYTE BY BYTE INPUT OR OUTPUT FROM ; THE CURRENT CONSOLE DEVICE. THEY ARE INVOKED BY ; THE MONITOR "I" OR "O" COMMAND. INPT: CALL EXPR1 ;GET INPUT PORT NUMBER POP B ;GET PORT # INTO C REGISTER INP E ;READ VALUE INTO E REGISTER ; JMPR BITS2 ;GO DO A BINARY PRINT OF THE VALUE ; OUPT: CALL EXPR ;GET THE ADDRESS AND DATA FOR OUTPUT POP D ;DATA VALUE INTO E POP B ;PORT INTO C OUTP E ;DO THE OUTPUT ; RET ; ; MOVE ROUTINE ; THIS ROUTINE EXPECTS THREE PARAMETERS, ENTERED IN THE ; SOURCE FIRST BYTE ADDRESS ; SOURCE LAST BYTE ADDRESS ; DESTINATION FIRST BYTE ADDRESS ; MOVE: CALL EXPR3 ;GET THREE PARAMETERS MOV1: MOV A,M ;GET NEXT BYTE STAX B ;MOVE IT CALL HILOXB ;GO INCREMENT CHECK SOURCE POINTER JMPR MOV1 ;NOT THERE YET, GO DO IT AGAIN ; ; ; SUBSTITUTE ACTION ROUTINE ; ; THIS ROUTINE ALLOWS THE USER TO INSPECT ANY MEMORY LOCATION ; AND ALTER THE CONTENTS TF DESIRED AND IF THE ADDRESS ; IS IN RAM. THE CONTENtS MAY BE LEFT UNALTERED ; BY ENTERING A SPACE, COMMA OR A CARRIAGE RETURN. IF ; A CARRIAGE RETURN IS ENTER~D THE ROUTINE IS TERMINATE ; IF A SPACE OR COMMA IS ENTER~D, THE ROUTINE ; PROCEEDS TO THE NEXT LOCATION AND PRESENTS THE USER ; WITH AN OPPORTUNITY TO ALTER IT. ; SUBS: CALL EXPR1 ;GO GET ONE PARAMETER POP H ;GET THE START ADDRESS SUB1: MOV A,M ;GET THE CONTENTS OF THE ADDRESS CALL DASH1 ;DISPLAY IT ON CONSOLE AND A DASH CALL PCHK ;GET CHECK CHARACTER RC ;DONE IF CARRIAGE RETURN JRZ SUB2 ;NO CHANGE IF BLANK OR ; CPI LF ;SEE IF PREVIOUS BYTE WANTED JRZ SUB3 ;YES, DO IT ; PUSH H ;SAVE MEMORY POINTER CALL EXF ;GO GET REST OF NEW VALUE POP D ;NEW VALUE TO E REGISTER POP H ;RESTORE MEMORY POINTER MOV M,E ;PUT DOWN NEW VALUE MOV A,C ;GET THE DELIMITER CPI CR ;SEE IF DONE (CARRIAGE RETURN) RZ ;YES, RETURN TO MONITOR SUB2: INX H ;NO INCREMENT MEMORY PONTER INX H ;ALLOW A FALL THROUGH ON THE NEXT INST SUB3: DCX H ;ADJUST (H,L) AS APPROPRIATE MOV A,L ;GET LO ADDRESS BYTE ANI 7 ;SEE IF ON A BOUNDARY CZ LADRB ;CALL IF ON THE BOUNDARY JMPR SUB1 ;GO DO THE NEXT LOCATION ; ; ; MTEST ROUTINE TESTS A SPECIFIED BLOCK OF MEMORY TO ; SEE IF ANY HARD DATA BIT FAILURES EXIST. IT IS ; NOT AN EXHAUSTIVE TEST BUT JUST A QUICK INDICATION ; OF THE MEMORY'S OPERATVENESS. ; MTEST: CALL EXLF MTEST1: MOV A,M ;READ A BYTE PUSH PSW ;SAVE IT CMA ;COMPLEMENT IT MOV M,A ;WRITE IT XRA M ;RESULT SHOULD BE ZERO CNZ BITS ;LOG ERROR IF NOT MTEST2: POP PSW MOV M,A ;RESTORE ORIGINAL BYTE CALL HILOX ;PONT TO NEXT AND SEE IF DONE JMPR MTEST1 ;NO, CONTINUE ; BITS: PUSH D ;SAVE (D,E) MOV E,A ;SAVE ERROR PATTERN IN E CALL LADRB ;FIRST PRINT THE ADDRESS BITS2: MVI B,8 ;LOOP CONTROL FOR 8 BITS BITS1: MOV A,E ;GET NEXT BIT RLC ; INTO CARRY MOV E,A ;SAVE REST MVI A,'0'/2 ;BUILD ASCII 1 OR 0 RAL ; CARRY DETERMINES WHICH MOV C,A ;NOW, OUTPUT IT CALL CONOUT DJNZ BITS1 ;DO IT AGAIN ; POP D RET ; ; EXAMINE REGISTERS COMMAND INSPECTS THE VALUES OF THE ; THE REGISTERS STORED BY THE LAST ENCOUNTERED BREAKPOINT. ; THE VALUES MAY BE MODIFIED IF DESIRED. ; XAA: INX H ;SKIP OVER TO NEXT ENTRY INX H XA: INR M ;SEE IF AT END OF TABLE RZ ;COULDN'T FIND MATCH, QUIT JP XAB ;SORT OUT BIT 7 OF TABLE ORI 80H ;SET IT ON TEST VALUE JMPR XAC ; XAB: ANI 7FH ;RESET BIT 7 XAC: DCR M ;TO BE PULLED OUT IN ROM CMP M ;SEE IF THIS IS IT JRNZ XAA ;NO, GO TRY AGAIN ; CALL BLK ;YES PREPARE TO SHOW CURRENT VALUE CALL PRTVAL ;GO PRINT THE VALUE CALL DASH ;PROMPT A NEW VALUE CALL PCHK ;GET THE INPUT RC ;DONE IF CARRIAGE RETURN JRZ XF ;JUMP IF NO CHANGE DESIRED ; PUSH H ;TO BE CHANGED, SAVE POINTER CALL EXF ;GET THE NEW VALUE POP H ; INTO (H,L) MOV A,L ;GET THE N~W LOW BYTE INX D ;ADJUST POINTER STAX D ;PUT IT DOWN XTHL ;RECOVER THE TABLE POINTER MOV A,M ;GET THE ATTRIBUTES XTHL ;SET THE STACK STRAIGHT RLC ;SEE IF 8 BIT REGISTER JRNC XE ;JUMP IF SO ; INX D ;REGISTER PAIR, DO OTHER 8 BITS MOV A,H STAX D XE: POP H ;RESTORE THE TABLE POINTER XF: MOV A,C ;SEE IF IT WAS A CR CPI CR RZ ;DONE IF SO XMNE: LXI H,ACTBL ;GET ADDRESS OF REGISTER LOOK-UP TABLE XMNE1: CALL PCHK ;FIND OUT WHAT ACTION IS WANTED JRC XG ;SHOW ALL IF CARRIAGE RETURN ; JRZ XMNE1 ;IGNORE BLANKS OR COMMAS CPI '''' ;SEE IF PRIMES WANTED JRNZ XA ;NO, MUST BE SINGLE REGISTER ; LXI H,PRMTB ;YES, SET TABLE ADDRESS JMPR XMNE1 ; AND FIND OUT WHICH ONE ; XG: MOV A,M MOV C,A INR A ;SEE IF AT END OF TABLE RZ ;DONE IF SO CM CRLF ;START A NEW LINE IF BIT 7 IS SET CALL CONOUT CALL DASH ;PROMPT FOR A NEW VALUE CALL PRTVAL ;GO PRINT THE VALUE CALL BLK ;FORMATTER INX H ;POINT TO NEXT ENTRY JMPR XG ;DO THE NEXT VALUE ; PRTVAL: INX H ;POINT TO NEXT ENTRY MOV A,M ;GET OFFSET AND ATTRIBUTES BYTE ANI 3FH ;ISOLATE THE OFFSET ADI 2 ;ALLOW FOR RETURN ADDRESS XCHG ;RE-SWAP POINTERS MOV L,A ;BUILD THE ADDRESS OF THE REQ CONTENTS MVI H,0 DAD SP XCHG ;RE-SWAP THE POINTERS MOV A,M ;NOW FIND OUT ATTRIBUTES MVI B,1 ;SET UP FOR SINGLE REG VALUE RLC JRNC PV1 ;JUMP IF SINGLE REGISTER VALUE WANTED ; INR B ;SET UP FOR REGISTER PAIR RLC JRNC PV1 ;JUMP IF REGISTER PAIR IS NEXT ; PUSH H ;SPECIAL CASE FOR MEMORY REGISTER LDAX D ;BUILD ADDRESS IN (H,L) MOV H,A DCX D LDAX D MOV L,A MOV A,M ;GET THE MEMORY VALUE POP H ;RESTORE (H,L) DJNZ PV2 ;ALWAYS JUMP ; PV1: LDAX D ;GET THE REGISTER CONTENTS PV2: CALL HEX1 ;OUTPUT THE VALUE DCX D ;ADJUST THE MEMORY POINTER DJNZ PV1 ; RET ; ACTBL: DB 80H+'A',ALOC DB 'B',BLOC DB 'C',CLOC DB 'D',DLOC DB 'E',ELOC DB 'F',FLOC DB 'H',HLOC DB 'L',LLOC DB 80H+'M',HLOC+0C0H DB 'P',PLOC+80H DB 'S',SLOC+80H DB 'I',ILOC ; ; REST OF Z 80 REGISTER OFFSETS ; PRMTB: DB 80H+'A',APLOC DB 'B',BPLOC DB 'C',CPLOC DB 'D',DPLOC DB 'E',EPLOC DB 'F',FPLOC DB 'H',HPLOC DB 'L',LPLOC DB 80H+'M',HPLOC+0C0H DB 'X',XLOC+80H DB 'Y',YLOC+80H DB 'R',RLOC DB 0FFH ; ; GENERAL PURPOSE ROUTINES ; ; ; ROUTINE CONV CONVERTS THE LOW ORDER NIBBLE OF THE ; ACCUMULATOR TO ITS ASCII EQUIVALENT. IT ; PUTS THE RESULT INTO C FOR LATER OUTPUT. ; CONV: ANI 0FH ;STRIP OFF BITS 4 7 ADI 90H ;PUT ON THE ASCII ZONE DAA ACI 40H DAA MOV C,A ;PUT IN OUTPUT PASS REGISTER RET ; ; ROUTINE ECHO READS A BYTE FROM A HALF DUPLEX CONSOLE ; DEVICE THEN ECHOES THE CHARACTER BACK TO THE ; CONS0LE. ; DECHO: CALL DASH ;PRINT A DASH ECHO: CALL CONI ;CONSOLE READ, WRITE ROUTINE ECH1: PUSH B ; SAVE (B,C) MOV C,A ; PASS CHARACTER IN C REGISTER CALL CONOUT ; OUTPUT IT MOV A,C ; PUT CHARACTER BACK INTO A POP B ; RESTORE (B,C) RET ; ; ROUTINE EXPR3 GETS THREE PARAMETERS, DOES A CR LF AND ; THEN LOADS (B,C), (D,E), AND (H,L) WITH THE PARAMETERS. EXPR3: INR B ;2 IS ALREADY IN THE B REGISTER CALL EXPR ;GET THE PARAMETERS POP B ;PUT PARAMETERS INTO REGISTERS POP D JMP CRLFA ;GO DO THE CARRIAGE RETURN SEQUENCE ; ; ROUTINE HILO INCREMENTS (H,L) IT THEN CHECKS FOR (AND ; DISALLOWS) A WRAP AROUND SITUATION. IF IT OCCURS, ; THE CARRY BIT WILL BE SET ON RETURN. IF NO WRAP- ; AROUND OCCURRED (H,L)IS COMPARED TO (D,E) AND ; THE FLAG BITS SET ACCORDINGLY. HILO: INX H ;INCREMENT (H,L) MOV A,H ;TEST IF ZERO ORA L ; IN (H,L) STC ;SET CARRY FOR (H,L)=0 RZ ;RETURN TF (H,L)=0 MOV A,E ;COMPARE(H,L) TO (D,E) SUB L MOV A,D SBB H RET ;RETURN WITH FLAGS SET ; ; ROUTINE HILOX INCREMENTS (H,L), COMPARES IT TO (D,E) AND ; IF EQUAL RETURNS CONTROL TO THE MONITOR EXECUThVE. ; OTHERWISE, CONTROL RETURNS TO THE CALLING ROUTINE. ; HILOD: POP D ;GET RID OF RETURN ADDRESS RET ;RETURN TO MONITOR HILOXB: INX B ;INCREMENT (B,C) HILOX: CALL HILO ;INC AND CHECK (H,L) JRC HILOD ;DONE IF CARRY SET ; CALL CONST ;SEE IF CONSOLE BREAK PENDING ORA A RZ ;NONE RETURN TO CONTINUE CALL CONI ;SEE IF WAIT OR BREAK CPI CTRLS JRNZ HILOD ;JUMP IF BREAK ; JMP CONI ;GO WAIT FOR NEXT CHARACTER ; ; ROUTINE NIBBLE CONVERTS THE ASCII CHARACTERS 0-9 AND ; A-F TO THEIR EQUIVALENT HEXADECIMAL VALUE. IF ; THE CHARACTER IS NOT IN RANGE, THE CARRY BIT IS SET TO ; FLAG THE ERROR. NIBBLE: SUI '0' ;ASCII TO HEX CONVERSION RC ; DONE IF OUT OF RANGE CPI 'G'-'0' ;CHECK UPPER END CMC ; TOGGLE THE CARRY BIT RC ; DONE IF OUT OF RANGE CPI '9'-'0'+1 ;SEE IF NUMERIC CMC ; TOGGLE THE CARRY BIT RNC ; DONE IF SO SUI 'A'-'9'-1 ;SUBTRACT THE ALPHA BIAS CPI 10 ; SET CARRY FOR INVALID CHAR RET ; ; ROUTINE PCHK READS A CHARACTER FROM THE CONSOLE, THEN ; CHECKS IT FOR A DELIMITER. IF IT IS NOT ; A DELIMTTER A NON ZERO CONDITION IS RETURNED. ; IF IT IS A DELIMITER, A ZERO CONDITION IS RETURNED. ; FURTHER TF THE DELIMITER IS A CARRIAGE RETURN ; THE CARRY BIT IS SET. A BLANK OR A COMMA RESET'S ; THE CARRY BIT. ; PCHK: CALL ECHO ;GET, TEST FOR DELIMITER P2C: CPI ' ' ; BLANK? RZ ; YES, DONE CPI ',' ; NO COMMA? RZ ; YES, DONE CPI CR ; NO CARRIAGE RETURN? STC ; SHOW IT IN CARRY BIT RZ ; DONE IF CR CMC ; CLEAR CARRY FOR NO DELIMITER RET ; ; ROUTINE REST TRAPS ALL OF THE REGISTER CONTENTS WHENEVER A ; RESTART 1 INSTRUCTION IS EXECUTED. THE TRAPPED CONTEN ; ARE STORED IN THE SYSTEM STACK AREA FOR LATER ACCESS AND ; USE BY THE GOTO AND THE EXAMINE REGISTERS COMMANDS. ; ; INSERT INTERRUPT DISABLER SOFTWARE AT START OF REST: REST: PUSH H ;SAVE ALL THE REGISTERS PUSH D PUSH B PUSH PSW CALL MEMSIZ ;GET THE MONITOR'S STACK LOCATION XCHG LXI H,10 ;GO UP 10 BYTES IN THE STACK DAD SP ; TO SKIP OVER TEMP REGISTER SAVE MVI B,4 ;PICK OFF THE REGISTER VALUES XCHG RS1: DCX H MOV M,D ;SAVE IN WORK AREA DCX H MOV M,E POP D DJNZ RS1 ; POP B ;GET THE BREAKPOINT LOCATION DCX B SPHL ;SET THE MONITOR STACK LXI H,TLOCX ;SET UP TO RESTORE BREAKPOINTS DAD SP PUSH D MVI D,NBKPTS ;LOOP CONTROL F0R N BREAKPOINTS RS2: MOV A,M SUB C ;SEE IF A SOFTWARE TRAP INX H MOV A,M SBB B ;MAYBE, TRY REST OF ADDRESS JRZ RS5 ;FOUND ONE, JUMP TO RESET IT ; RS3: INX H ;NOT FOUND, TRY NEXT ONE INX H DCR D JRNZ RS2 ; RS4: INX B ;NONE FOUND RS5: LXI H,LLOCX POP D DAD SP MOV M,E ;STORE USER (H,L) INX H MOV M,D PUSH B ;SAVE (B,C) MVI C,'*' ;TYPE THE BREAK INDICATION CALL CONOUT POP D ;REGET THE BREAKPOINT LOCATION MVI A,RS9/256 CMP D ;SEE IF A RET BREAKPOINT JRZ RS6 ; INX H INX H MOV M,E ;RESTORE USER PROGRAM COUNTER INX H MOV M,D XCHG ;PRINT THE BREAKPOINT LOCATION CALL LADR RS6: LXI H,TLOCX DAD SP LXI B,NBKPTS*256 RS7: MOV E,M ;RESTORE BREAKPOINTED LOCATIONS MOV M,C ;RESET SYSTEM BP SAVE AREA INX H MOV D,M MOV M,C INX H MOV A,E ORA D JRZ RS8 ;DO NOTHING IF ZERO ; MOV A,M STAX D RS8: INX H ;SAME THING FOR OTHER DJNZ RS7 ; BREAKPOINT ; EXAF ;NOW SAVE THE Z-80 UNIQUES EXX ; PUSH H PUSH D PUSH B PUSH PSW PUSHIX ; PUSHIY ; LDAI ; MOV B,A LDAR ; MOV C,A PUSH B JMP WINITA ;RETURN TO MONITOR RS9: PUSH H ;RET BREAKPOINT ENCOUNTERED, ADJUST TH RST 1 ;DO THE BREAKPOINT EXIT: POP B MOV A,C STAR ; MOV A,B STAI ; POPIX ; POPIY ; POP PSW POP B POP D POP H EXAF ; EXX ; POP D POP B POP PSW POP H SPHL DB 0 ;PLACE FOR EI LXI H,0 JMP 0 ENDX: EQU $ ; ;ERROR HANDLERS ; ; THREE TYPES OF ERRORS ARE DETECTED: A RESTART ; ERROR AN I/O ASSIGNMENT ERROR AND CERTAIN PROGRAM ; ERRORS (DETERMINED BY THE PARTCULAR ROUTINE WHERE ; THE ERROR CONDITION WAS ENCOUNTERED.) EACH CAUSES ; A UNIQUE MESSAGE TO BE PRINTED, THEN DOES A WARM ; INITIALIZATION OF THE MONITOR. THE I/O ERROR ; CAUSES THE I/O ASSIGNMENTS TO BE RESET TO DEFAULT ASSI IOER: XRA A ;SET IOBYTE TO DEFAULT VALUE STA IOBYTE LXI H,IOMSG ;GET ADDRESS OF I/O ERROR MSG JMP COMERR ;GO PROCESS IT IOMSG: DB 'I/O ER','R'+80H ; ; BYTE ROUTINE READS TWO ASCII CHARACTERS FROM THE ; CURRENT PAPER TAPE READER AND ASSEMBLES THEM INTO TWO ; HEXADECIMAL BYTES OF DATA. IT UPDATES A CHECKSUM ; ACCUMULATED IN REGISTER D. BYTE: CALL BYT ;GET NEXT BYTE ORA B ;COMBINE THEM MOV B,A ADD D ;UPDATE CHECKSUM MOV D,A MOV A,B ;RESTORE BYTE RET ; PEOL: MVI C,CR CALL PO MVI C,LF JMP PO ;GO PUNCH THE OUTPUT ; ; RIX ROUTINE READS ONE CHARACTER FROM THE CURRENT ; PAPER TAPE READER AND STRIPS OFF THE PARITY BIT. RIX: CALL RI ANI 7FH RET QMSG: DB '???','?'+80H LOGMSG: DB 'MOSS VERS 2.2' DB CR,LF+80H ; ; INITIALIZATION CODE FOR THE 8250 ASYNCHRONOUS COMMUNICATION ; ELEMENT. THIS CODE WILL INITIALIZE THE BAUD RATE OF THE ; 8250, AS WELL AS THE WORD FORMAT. 8 DATA BTTS I STOP BIT ; AND NO PARITY ARE SELECTED. EITHER 2 OR 3 CARIAGE RETURNS ; MUST BE ENTERED TO ESTABLISH THE CORRECT BAUD RATE. I8250: MVI A,0FH ;SET UP THE 8250 OUT SMDMCT LXI D,40H ;SET UP TO TIME THE START BIT MOV H,D MOV L,D ;ZEROES TO (H,L) I8250A: IN SMDMST ;WAIT FOR START BIT ANA E JRZ I8250A ; I8250B: IN SMDMST ;NOW, TIME THE START BIT DURATION INX H ANA E ANA E JNZ I8250B PUSH H ;SAVE COUNT IN CASE OF 4 MHZ DAD H ;PREPARE THE 2 MHZ DIVISOR MOV E,H ;SET UP THE FUDGE FACTOR DAD D ;APPLY THE FUDGE FACTOR DAD D PUSH H ;SAVE FOR LATER USE DAD H ;WAIT FOR 8 BIT TIMES DAD H I8250C: IN SDATA ;WASTE SOME TIME DCX H MOV A,L ORA H JNZ I8250C POP H ;REGET 2 MHZ DIVISOR I8250D: MVI A,83H ;SET DIVISOR REGISTER ACCESS OUT SLCTRL MOV A,L ;SET THE DIVISOR OUT SDATA MOV A,H OUT SINTEN MVI A,3 ;SET DATA REGISTER ACCESS OUT SLCTRL XRA A ;DISABLE INTERRUPTS OUT SINTEN OUT SLSTAT ;AND RESET ERROR FLAGS CALL TTYIN ;GET A CHARACTER ANI 7FH ;STRIP OFF ANY PARITY BIT CPI 0DH ;SEE IF IT IS A CARRIAGE RETURN POP H ;SET THE STACK STRAIGHT RZ ;DONE IF CARRIAGE RETURN RECEIVED MOV E,L ;ELSE, MUST BE 4 MHZ SYSTEM MOV D,H ; SO, COUNT=COUNT*5/4 CALL DIV2 CALL DIV2 DAD D PUSH H JMPR I8250D ;GO SET THE NEW DIVISOR ; ; ; DIV2: ORA A ;CLEAR THE CARRY BIT MOV A,H ;DO A 16 BIT RIGHT SHIFT RAR MOV H,A MOV A,L RAR MOV L,A RET ; ; EOF ROUTINE PUNCHES AN END OF FILE RECORD (INTEL HEX ; FORMAT) ONTO THE CURRENTLY ASSIGNED PAPER TAPE PUNCH ; DEVICE. AN ENTRY POINT ADDRESS FOR THE FILE WILL ALSO ; BE PUNCHED, IF SPECIFIED. ; EOF: CALL EXLF ;GET JUMP ADDRESS PUSH D ;SAVE THE # OF TRAILER NULLS EOFA: CALL PSOR ;PUNCH START OF RECORD XRA A ;ZERO OUT THE CHECKSUM MOV D,A CALL PBADR ;OUTPUT THE RECORD LENGTH AND EP MVI A,1 ;PUNCH RECORD TYPE = 1 CALL PBYTE XRA A SUB D ;OUTPUT THE CHECKSUM CALL PBYTE JMPR LEO ;GO DO THE TRAILER ; ; ; LEADER ROUTINE 'PUNCHES' SIX INCHES (OR AS SPECIFIED) ; OF LEADER ON THE PAPER TAPE PUNCH. NULLS ARE PUNCHED ; TO FORM THE LEADER (OR TRAILER). ; LEADER: CALL EXPR1 ;SEE IF SOME OTHER LENGTH WANTED LEO: POP B ;GET THE VALUE MOV A,B ORA C ;TEST FOR DEFAULT SELECT MOV B,C ;MOVE NEW VALUE IN JUST IN CASE MVI C,0 ;GET A NULL CHARACTER JRNZ LE1 ;JUMP IF NEW VALUE WANTED ; MVI B,60 ;DEFAULT SET 60 NULLS LE1: CALL PUNCH ;PUNCH ONE NULL DJNZ LE1 ;KEEP GOING TIL DONE ; RET ; ; QUERY ROUTINE WILL TELL THE OPERATOR WHAT HIS CURRENT LOGICAL ; PHYSICAL PERIPHERAL DEVICE ASSIGNMENTS ARE. NO PARAME ; (OTHER THAN A CARRIAGE RETURN) ARE REQUIRED ON ENTRY. QUERY: LDA IOBYTE ;GET THE ASSIGNMENT CONTROL BYTE MVI B,4 ;SET UP FOR FOUR LOGICAL DEVICES LXI H,ACT ;ADDRESS OF CONVERSION TABLE LXI D,ALT-APT ;NEGATIVE OFFSET FOR LOGICAL TABLE QUE1: PUSH PSW CALL BLK ;FORMAT THE PRINT OUT MOV C,M ;GET THE CURRENT LOGICAL DEVICE CODE CALL CONOUT ;OUTPUT IT CALL DASH ;OUTPUT A DASH POP PSW ;REGET THE CONTROL BYTE PUSH PSW ;RESAVE IT PUSH H ;SAVE THE TABLE POINTER QUE2: INX H ;ADJUST POINTER TO CURRENT PHYSICAL DE INR A ANI 3 ;BITS 0 AND 1 ARE 0 WHEN ON CURRENT AS JRNZ QUE2 ;NOT THERE YET, TRY AGAIN ; MOV C,M ;FOUND IT, NOW PRINT IT CALL CONOUT POP H POP PSW ;GO TO NEXT LOGICAL DEVICE RAR ;ADJUST THE IOBYTE RAR DAD D ;ADJUST THE TABLE POINTER DJNZ QUE1 ;GO DO NEXT LOGICAL DEVICE ; RET ;RETURN TO MONITOR ; ; READ ROUTINE READS AN INTEL HEX FORMAT PAPER TAPE FROM ; THE CURRENT PAPER TAPE READER. IF A NON ZERO ADDRESS ; IS SPECIFIED IN THE END OF FILE RECORD CONTROL WILL ; BE TRANSFERRED TO THAT ADDRESS. OTHERWISE, CONTROL ; WILL REVERT TO THE EXECUTIVE. ; READ: CALL EXPR1 ;GET OFFSET BIAS REDO: POP H ; INTO (H,L) PUSH H ;SAVE THE BIAS RED1: CALL RIX ;READ A BYTE SBI ':' ;LOOK FOR START OF RECORD JRNZ RED1 ;JUMP TO KEEP LOOKING ; MOV D,A ;INITIALIZE CHECKSUM CALL BYTE ;GET RECORD LENGTH JRZ RED3 ;JUMP IF EOF RECORD ; MOV E,A ;ELSE, ASSUME DATA RECORD CALL BYTE ;GET LOAD ADDRESS HIGH BYTE PUSH PSW ;SAVE IT CALL BYTE ;GET LOAD ADDRESS LOW BYTE POP B ;BUILD ADDRESS IN (B,C) MOV C,A DAD B ;ADD ON THE BIAS CALL BYTE ;SKIP OVER RECORD TYPE RED2: CALL BYTE ;GET A DATA BYTE MOV M,A ;PUT IT INTO MEMORY CMA ;D0 A QUICK CHECK XRA M ; RESULT SHOULD BE ZERO CNZ BITS ;IF ERROR PRINT ADDRESS AND DATA INX H ;INCREMENT MEMORY POINTER DCR E ;RECORD LENGTH FOR LOOP CONTROL JRNZ RED2 ;DO REST OF THE RECORD ; CALL BYTE ;GET THE CHECKSUM JNZ QPRT ;ABORT IF ERROR JMPR REDO ;GO DO NEXT RECORD ; RED3: CALL BYTE ;EOF RECORD GET ENTRY POINT MOV H,A ;HIGH BYTE TO (H) CALL BYTE ;GET THE LOW BYTE MOV L,A ORA H ;SEE IF IT IS ZERO POP D ;RESTORE THE STACK RZ ;RETURN TO MONITOR IF EP=0 PCHL ;ELSE, GO TO THE ENTRY POINT ; ; WRITE ROUTINE IS USED TO PUNCH AN INTEL HEX FORMAT ; PAPER TAPE ON THE CURRENT ASSIGNED PUNCH UNIT. ; WRITE: CALL EXPR3 ;GET 3 PARAMETERS, DO CRLF XRA A ;SEE IF RECORD LENGTH CHANGE MOV B,A ;SET HIGH BYTE TO ZERO ORA C ;NOW SEE IF CHANGE WANTED JRNZ WRI1 ;YES, JUMP AND SET IT UP ; MVI C,16 ;NO, DEFAULT TO 16 BYTES/RECORD WRI1: PUSH H ;SAVE MEMORY POINTER DAD B ;ADD THE RECORD LENGTH ORA A ;CLEAR THE CARRY BIT DSBC D ;SEE IF FULL RECORD REMAINS ; POP H ;RESTORE (H,L) JRC WRI2 ;GO DO A FULL RECORD PUSH D ;SAVE LAST BYTE ADDRESS XCHG ;SWAP (D,E) AND(H,L) ORA A ;RESET THE CARRY BIT DSBC D ;FIND # OF BYTE REMAINING ; INX H ;ADJUST TO INCLUDE LAST BYTE XTHL ;SWAP TOP OF STACK XCHG ;SET (D,E) (H,L) TO NORMAL POP B ;NEW RECORD LENGTH TO (B,C) RC ;DONE IF ZERO LENGTH RECORD WRI2: PUSH B ;SAVE LOOP COUNT PUSH D MOV D,B ;ZERO THE CHECKSUM MOV B,C ;MOVE LOOP CONTROL TO B CALL PSOR ;PUNCH START OF RECORD MOV A,B ;GET RECORD LENGTH CALL PBADR ;PUNCH IT XRA A ;PUNCH RECORD TYPE '0' CALL PBYTE WRI3: MOV A,M ;GET NEXT DATA BYTE INX H ;BUMP THE POINTER CALL PBYTE ;PUNCH THE DATA DJNZ WRI3 ;DO REST OF RECORD ; XRA A ;NOW, DO THE CHECKSUM SUB D CALL PBYTE ;PUNCH IT POP D ;RESTORE THE REGISTERS POP B JMPR WRI1 ;GO DO NEXT RECORD ; PSOR: CALL PEOL MVI C,':' JMP PO ; ; HEXN ROUTINE ; ;THIS ROUTINE ADDS AND SUBTRACTS TWO HEXADECIMAL 16 BIT ; UNSIGNED NUMBERS AND DISPLAYS THE RESULTS ON THE ; CONSOLE. HEXN: CALL EXLF ;GET THE TWO NUMBERS PUSH H ;SAVE IT FOR THE SUBTRACT DAD D ;ADD THEM CALL LADRB ;OUTPUT THEM POP H ;REGET THE FIRST NUMBER ORA A ;CLEAR THE CARRY BIT DSBC D ;DO THE SUBTRACT ; JMPR LADR ;GO OUTPUT THE RESULT ; ; ; ROUTINE LADR PRINTS THE CONTENTS OF (H,L) ON THE ; CURRENT CONSOLE EITHER AT THE SART OF A NEW ; LINE (EP = LADRA) OH AT THE CURRENT LOCATION (EP = ; LADR). LADRA: CALL CRLF ;START A NEW LINE LADR: MOV A,H ;GET HIGH TWO DIGITS CALL HEX1 ;PRNT THEM MOV A,L ;GET LOW TWO DIGITS HEX1: PUSH PSW ;SAVE THE LOW DIGIT RRC ;PUT HIGH NIBBLE INTO BITS 0-3 RRC RRC RRC CALL HEX2 ;GO PRINT SINGLE DIGIT POP PSW ;REGET THE LOW DIGIT HEX2: CALL CONV ;GO INSERT ASCII ZONE JMPR CO ;DO THE CHARACTER OUTPUT ; ; ; ROUTINE DASH TYPES A DASH ON THE CURRENT CONSOLE DEVICE. ; DASH1: CALL HEX1 ;FIRST, PRINT ACCUM AS TWO HEX DIGITS DASH: MVI C,'-' ;GET AN ASCII DASH JMPR CO ;GO TYPE IT ; ; ; IOBYTE HANDLERS ; ORG MOSS + 05FBH LADRB: CALL LADRA ;OUTPUT (H,L) AS 4 ASCII DIGITS BLK: MVI C,' ' ;OUTPUT A BLANK CO: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTYOUT ;TTY DEVICE ACTIVE CPI 2 JM CRTOUT ;CRT ACTIVE JNZ CUSO1 ;USER CONSOLE 1 ACTIVE LO: LDA IOBYTE ANI 0C0H ;ISOLATE LIST ASGT JZ TTYOUT ;TTY DEVICE ACTIVE CPI 80H JM CRTOUT ;CRT ACTIVE JZ LPRT ;LINE PRINTER ACTIVE JMP LUSE1 ;USER PRINTER 1 ACTIVE ; CSTS: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTST ;TTY ACTIVE CPI 2 JM CRTST ;CRT ACTIVE JNZ CUST1 ;USER CONSOLE 1 ACTIVE ; BATST: LDA IOBYTE ANI 0CH ;ISOLATE BATCH ASGT JZ TTST ;TTY ACTIVE CPI 8 JM PTRST ;PAPER TAPE READER ACTIVE JZ RUST1 ;USER READER 1 ACTIVE JMP RUST2 ;USER READER 2 ACTIVE ; CI: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTYIN ;TTY DEVICE ACTIVE CPI 2 JM CRTIN ;CRT ACTIVE JNZ CUSI1 ;USER CONSOLE 1 ACTIVE ; RI: LDA IOBYTE ANI 0CH ;ISOLATE BATCH ASGT JZ TTYRDR ;TTY ACTIVE CPI 8 JM PTRIN ;PAPER TAPE READER ACTIVE JZ RUSI1 ;USER READER I ACTIVE JMP RUSI2 ;USER READER 2 ACTIVE ; LSTAT: LDA IOBYTE ANI 0C0H ;ISOLATE THE LIST DEVICE ASSIGNMENT JZ TTOST CPI 80H JM CRTOST JZ LPRST JMP LUST1 ; PO: LDA IOBYTE ANI 30H ;ISOLATE PUNCH ASGT JZ TTPNCH ;TTY ACTIVE CPI 20H JM HSP ;HIGH SPEED PUNCH ACTIVE JZ PUSO1 ;USER PUNCH 1 ACTIVE JMP PUSO2 ;USER PUNCH 2 ACTIVE ; ; ROUTINE CONI READS THE CONSOLE AND STRIPS OFF THE ASCII ; PARITY BIT. ; CONI: CALL CI ;GET THE NEXT CHARACTER ANI 7FH ;STRIP OFF THE PARITY BIT RTS: RET ; ; ROUTINE PRTWD PRINTS AN ASCII STRING ONTO THE CONSOLE. ; THE STRING MUST BE TERMINATED BY BIT 7 SET IN THE ; LAST CHARACTER OF THE STRING. THE STRING WILL START ; A NEW LINE (EP = PRTWD) OR CONTINUE ON THE SAME ; LINE (EP = PRTWA) PRTWD: CALL CRLF ;START A NEW LINE PRTWA: PUSH B ;SAVE (B,C) PRTA: MOV C,M ;GET NEXT CHARACTER FROM MEMORY CALL CO ;OUTPUT IT INX H ;INCREMENT MEMORY POINTER MOV A,C RLC ;TEST FOR BIT 7 DELIMITER JRNC PRTA ;NO DELIMITER, GO DO NEXT CHARACTER ; PRTB: POP B ;RESTORE (B,C) RET ; ; ROUTINE EXLF READS TWO PARAMETERS, PUTS THEM INTO THE ; D,E AND H,L REGISTERS, THEN DOES A CARRIAGE RETURN, ; LINE FEED SEQUENCE. ; EXLF: CALL EXPR ;GO GET TWO PARAMETERS POP D POP H ; ; ROUTINE CRLF GENERATES A CARRIAGE RETURN, LNE FEED ; SEQUENCE ON THE CURRENT CONSOLE TO START A NEW LINE ; IT INCLUDES TRHEE NULL CHARACTERS FOR TTY TYPE ; DEVICES FOR THE HEAD MOVEMENT TIME. ; CRLF: PUSH H ;SAVE THE CONTENTS OF (H,L) CRLFA: LXI H,CRMSG ;ADDRESS OF CR,LF MESSAGE CALL PRTWA ; OUTPUT IT POP H ;RESTORE (H,L) RET ; RSTER: LXI H,RSTMSG ;GET ADDRESS OF RESTART ERROR MSG COMERR: CALL PRTWD ;PRINT IT ON NEW LINE JMP WSVEC ;GO TO WARM BOOT RSTMSG: DB 'RST ER','R'+80H CRMSG: DB CR,LF,0,80H ; ; I/O DRIVERS FOR THE 8250 ASYNC COMM ELEMENT ; TTST: IN SLSTAT ;GET 8250 LINE STATUS ANI 1 ;SEE IF RECEIVE DATA AVAILABLE RZ ;RETURN IF NOT ADI 0FEH ;FLAG THAT DATA IS AVAILABLE RET ; TTYIN: IN SLSTAT ;GET 8250 LINE STATUS RAR ;MOVE RX DATA READY BIT INTO CARRY JRNC TTYIN ;LOOP UNTIL DATA IS IN ; IN SDATA ;READ THE DATA RET ; TTOST: IN SLSTAT ;GET 8250 LINE STATUS ANI 20H ;ISOLATE TX BUFFER EMPTY BIT RZ ;RETURN IF NOT EMPTY ADI 0BFH ;FLAG THE EMPTY STATE RET ; TTYOUT: IN SLSTAT ;GET 8250 LINE STATUS ANI 20H ;ISOLATE THRE BIT JRZ TTYOUT ;WAIT UNTIL ONE OF THE REGISTERS EMPTI ; MOV A,C ;MOVE THE DATA OVER OUT SDATA ;OUTPUT THE DATA RET ; ; EQUATES FOR ADDITIONAL CONSOLE DEVICES CRTIN EQU IOER CRTOUT EQU IOER CRTST EQU IOER CRTOST EQU IOER ;UNASSIGNED CRT OUTPUT STATUS CUSI1 EQU IOER ;UNASSIGNED USER CONSOLE (INPUT) CUSO1 EQU IOER ;UNASSIGNED USER CONSOLE (OUTPUT) CUST1 EQU IOER ; ; EQUATES FOR ADDITIONAL PAPER TAPE PUNCH DEVICES TTPNCH EQU TTYOUT ;UNASSIGNED TELETYPE PUNCH HSP EQU IOER ;UNASSIGNED HIGH SPEED PUNCH HSPST EQU IOER ;UNASSIGNED HJGH SPEED PUNCH STATUS PUSO1 EQU IOER ;UNASSIGNED USER PUNCH 1 PUSO2 EQU IOER ;UNASSIGNED USER PUNCH 2 ; ; EQUATES FOR ADDITIONAL LIST DEVICES LPRT EQU IOER ;UNASSIGNED LINE PRINTER LPRST EQU IOER ;UNASSIGNED PRINTER STATUS LUSE1 EQU IOER ;LIST DEVICE 1 LUST1 EQU IOER ;LIST DEVICE 1 STATUS ; ; EQUATES FOR ADDITIONAL PAPER TAPE READER DEVICES TTYRDR EQU TTYIN ;UNASSIGNED TELETYPE PAPER TAPE READER PTRIN EQU IOER ;UNASSIGNED HIGH SPEED PAPER TAPE READ PTRST EQU IOER ;UNASSIGNED HS PTR STATUS RUSI1 EQU IOER ;UNASSIGNED PAPER TAPE READER 1 RUST1 EQU IOER ;UNASSIGNED PAPER TAPE READER 1 (STATUS) RUSI2 EQU IOER ;UNASSIGNED PAPER TAPE READER 2 RUST2 EQU IOER ;UNASSIGNED PAPER TAPE READER 2 (STATUS) ; BYT: CALL RIBBLE ;READ AND CONVERT ONE CHARACTER RLC ;SHIFT INTO HIGH NIBBLE RLC RLC RLC MOV B,A ;SAVE IN B TEMPORARILY RIBBLE: CALL RIX ;READ A CHARACTER JMP NIBBLE ;GO CONVERT TO HEX DIGIT ; ; PADR ROUTINE PUNCHES (H,L) AS FOUR ASCII CHARACTERS. ; IT IS USED TO PUT THE ADDRESS INTO AN INTEL HEX ; FORMAT RECORD. ; PBADR: CALL PBYTE PADR: MOV A,H CALL PBYTE MOV A,L ; ; PBYTE ROUTINE PUNCHES (A) AS TWO ASCII CHARACTERS ON ; THE CURRENT PUNCH DEVICE. ; PBYTE: PUSH PSW ;SAVE THE BYTE RRC ;DO HIGH NIBBLE FIRST RRC RRC RRC CALL CONV ;CONVERT TO ASCII CALL PUNCH ;PUNCH IT POP PSW ;GET LOW NIBBLE PUSH PSW ;RESAVE F0R CHECKSUM CALL CONV ;CONVERT TO ASCII CALL PUNCH ;PUNCH IT POP PSW ADD D ;UPDATE CHECKSUM MOV D,A RET ; END