; TITLE 'DISK MOSS 2.2 MONITOR' MACLIB Z80 PAGE 68 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 REGISTER 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 ; ; DISK CONTROLLER UNIQUE EQUATES ; DSTAT EQU 30H ;DISK STATUS PORT DCMMD EQU DSTAT ;DISK COMMAND PORT DTRCK EQU DSTAT+1 ;DISK TRACK PORT DSCTR EQU DSTAT+2 ;DISK SECTOR PORT DDATA EQU DSTAT+3 ;DISK DATA PORT DFLAG EQU DSTAT+4 ;DISK FLAG PORT DCNTL EQU DSTAT+4 ;DISK CONTROL PORT ; ; DISKNO: EQU 40H ;ACTIVE DISK NUMBER TRACK: EQU DISKNO+1 SECTOR: EQU TRACK+1 SIDE: EQU SECTOR+1 ;SIDE SELECT HOLD AREA SPT: EQU SIDE+1 ;SECTORS PER TRACK HOLD TWOSID: EQU SPT+1 ;SINGLE/DOUBLE SIDED SWITCH HOLD STPRAT: EQU 46H ;STEP RATE SAVE AREA STATUS: EQU 47H CMND: EQU STATUS+1 LUNIT: EQU 49H ;LAST DRIVE USED CUNIT: EQU LUNIT+1 ;CURRENT DRIVE RWFLAG: EQU 4BH HSTBUF: EQU 4CH ;HOST BUFFER ADDRESS IDSV: EQU 4EH ;DISK ID SAVE AREA TBUF: EQU 80H ; ; ; JUMP TARGETS FOR BASIC INPUT/OUTPUT ; CBOOT: JMP INIT ;COLD START CONIN: JMP CI ;CONSOLE 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 BOOT DW QPRT DW DISP DW QPRT DW FILL DW GOTO DW HEXN DW INPT DW QPRT DW QPRT DW QPRT DW MOVE DW QPRT DW OUPT DW PARM DW QPARM 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 THE 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 VAULE IN (H, L). ; MEMSIZ: PUSH B ;MONITOR 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 DINIT ;SEE IF AUTO BOOT WANTED CALL I8250 ;INITIALIZE THE 8250 CALL RTS LXI H,LOGMSG ; LOG ONTO THE SYSTEM CALL PRTWD JR 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 JR 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 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 JR 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 CHOICES MVI B,4 ;NUMBER OF LOGICAL CHOICES AS0: CMP M ;IS THIS 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 ;PRINT 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 COMMAND 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 FI0: MOV M,C ;PUT DOWN THE FILL VALUE CALL HILO ;INCREMENT AND CHECK THE POINTER JRNC FI0 ;NOT DONE YET, JUMP POP D ;RESTORE STACK POINTER IN CASE JR 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 SHIFT 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' ;LOGIPAL 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' ;LOGIPAL 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' ;LOGIPAL 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 ADDRESSES ; 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 1 POINTER AND SEE IF DONE JR 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 LINE, 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 ;INREMENT (H,L) AND SEE IF DONE MOV A,L ;NOT DONE, READY FOR NEW LINE? ANI 0FH JRNZ DIS4 ;JUMP IF NOT JR DIS1 ;DO THE NEXT LINE DIS7: SUB E ;SKIP OVER TO START ASCII PRINTOUT CALL TRPLSP JR 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 THE COUNTER TRPL1: CALL BLK ;DO THE SPACING DJNZ TRPL1 ;NO, DO ANOTHER COLUMN RET ; ; GO TO ACTION ROUTINE ; ; GOTO COMMAND TRANSFER 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 PARAMS 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 ADDRESS 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. TYPE ARE INVOKED BY ; THE MONITOR "I" OR "O" COMMAND, THEN ANSWERING THE QUESTIONS ; WHICH APPEAR ON THE CONSOLE. ; INPT: CALL EXPR1 ;GET INPUT PORT NUMBER POP B ;GET PORT # INTO C REGISTER INP E ;READ VALUE INTO E REGISTER JR 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 FOLLOWING ; ORDER: ; 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 JR 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, IF 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 ENTERED, THE ROUTINE IS TERMINATED. ; IF A SPACE OR COMMA IS ENTERED, THE ROUTINE ; PROCEEDS TO THE NEXT LOCAITON AND PRESENTS THE USER ; WITH AN OPPORTUNITY TO ALTER IT. ; SUBS: CALL EXPR1 ;GO GET ONE PRARMETER POP H ;GET THE START ADDRESS SUB1: MOV A,M ;GET THE CONTENST 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 POINTER INX H ;ALLOW A FALL-THROUGH ON THE NEXT INSTRUCTION SUB3: DCX H ;ADJUST (H,L) AS APPROPRIATE MOV A,L ;GET LO ADDRESS BYTE ANI 7 ;SEE IF ONE A BOUNDARY CZ LADRB ;CALL IF ONE THE BOUNDARY JR 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 QUICK INDICATION ; OF THE MEMORY OPERATIVENESS MTEST: CALL EXLF MTEST1: MOV A,M ;READ A BYTE PUSH PSW ;SAVE IT CMA ;COMPLIMENT IT MOV M,A ;WRITE IT XRA M ;RESULT SHOULD BE ZERO CNZ BITS ;LOG ERROR IF NOT MTEST2: POP PSW ;RESTORE ORIGINAL BYTE MOV M,A CALL HILOX ;POINT TO NEXT AND SEE IF DONE JR MTEST1 ;NO, CONTINUE ; BITS: PUSH D ;SAVE (D,E) MOV E,A ;SAVE ERROR PATTERN IN E CALL LADRB ;FIRST PROINT 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 RESET 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 ; 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 JR XAC XAB: ANI 7FH ;RESET BIT 7 XAC DCR M ;TO BE PULLED OUT IN ROM CMP M ;SEE IF THIS IT 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 NEW LOW BYTE INX D ;ADJUST THE 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 A SINGLE REGISTER LXI H,PRMTB ;YES, SET TABLE ADDRESS JR 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 JR 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 ;SWAP POINTERS MOV L,A ;BUILD THE ADDRESS OF THE REG 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 EQUIVELENT. 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 ; CONSOLE. ; 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 IF (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 EXECUTIVE. ; 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 ;WAIT FOR ANY INPUT ; ; ROUTINE NIBBLE CONVERTS THE ASCII CHARACTERS 0-9 AND ; A-F TO THEIR EQUIVELENT 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 FORINVALID CHAR RET ; ; ROUTINE PCHK READS A CHARACTER FROM THE CONSOLE, THEN ; CHECKS IT FOR A DELIMITER. IF IT IS NOT ; A DELIMITER, A NON-ZERO CONDITION IS RETURNED. ; IF IT IS A DELIMITER, A ZERO CONDITION IS RETURNED. ; FURTHER, IF THE DELIMITER IS A CARRIAGE RETURN ; THE CARRY BIT IS SET. A BLANK OR COMMA RESET 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 CARY BIT RZ ; DONE IF CR CMC ;CLEAR CARRY FOR NO DELIMITER RET ; ; ROUTINE RESET TRAPS ALL OF THE REGISTER CONTENTS WHENEVER A ; RESTART 1 INSTRUCTION IS EXECUTED. THE TRAPPED CONTENTS ; 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 RESET: REST: PUSH H ;SAVE ALL REGISTERS PUSH D PUSH B PUSH PSW CALL MEMSIZ ;GET THE MONITOR'S STACK LOCATION XCHG LXI H,10 ;GO UP TO 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 FOR N BREAKPOINTS RS2: MOV A,M SUB C 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 THE STACK 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 HANDLER ; ; THREE TYPES OF ERRORS ARE DETECTED: A RESTART ; ERROR; AN I/O ASSIGNMENT ERROR; AND CERTAIN PROGRAM ; ERRORS (DETERMINED BY THE PARTICULAR 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 ASSIGNMENTS. ; 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 DERMSG: DB 'DSK ERR: U','-'+80H DB ' T','-'+80H DB ' S','-'+80H DB ' C','-'+80H DB ' E','-'+80H DB CR,LF+80H 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 BITS, 1 STOP BIT, ; AND NO PARITY ARE SELECTED. EITHER 2 OR 3 CARRIAGE 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 ;MAKE (H,L)=0 MOV L,D 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 INT 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,H OUT SINTEN MOV A,L ;SET THE DIVISOR OUT SDATA MVI A,3 ;SET THE 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 ; DO, COUNT=COUNT*5/4 CALL DIV2 CALL DIV2 DAD D PUSH H JR 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 ; ; READ: MVI A,1 ;SET THE READ/WRITE FLAG ORG $-1 ;SAVE A BYTE HERE WRITE: XRA A ;RESET THE READ/WRITE FLAG STA RWFLAG ;SAVE THE FLAG LXI H,80H SHLD LUNIT ;FORCE A READ ADDRESS COMMAND CALL EXLF ;GET THE START, STOP ADDRESS PUSH D ;SAVE THE LIMIT RW1: LDA RWFLAG ORA A ;SEE IF READ OR WRITE JRNZ RW2 ;JUMP IF READ SHLD HSTBUF ;SET THE WRITE SOURCE BUF CALL DWRITE ;ELSE, DO THE WRITE JR RW3 RW2: CALL DREADH ;DO THE READ RW3: POP D JRNZ DERROR ;JUMP IF ERROR LDA SPT ;GET THE SECTORS PER TRACT MOV B,A ;SAVE IT IN DTRCK ;SEE IF ON TRACK 00 ORA A JRNZ RW4 ;JUMP IF NO MVI B,26 ;ELSE, SET THE SECTORS PER TRK 00 LDA CUNIT ANI 10H JRNZ RW4 MVI B,18 ;MINI DRIVES RW4: PUSH H ;SLAVE THE DMA ADDRESS LXI H,SECTOR ;SET UP MEMORY POINTER MOV A,M ;GET NUMBER OF SECTORS CMP B ;SEE IF TRACK OVERFLOW JRC RW5 ;JUMP IF NOT LDA TWOSID ;SEE IF DOUBLE-SIDED ORA A JRZ RW7 ;JUMP IT NOT LDA SIDE ;YES SEE IF NEXT SIDE OR TRACK NEEDED CPI 0D0H JRNZ RW7 ;NEXT TRACK, JUMP MVI A,90H ;ELSE, SET NEXT SIDE JR RW8 RW7: MVI A,0D0H DCX H ;ELSE, UPDATE THE TRACK INR M INX H RW8: STA SIDE MVI M,0 ; AND THE SECTOR POINTER RW5: INR M POP H ;RESTORE THE DMA ADDRESS DCX H CALL HILOX ;SEE IF DONE PUSH D ;CONTINUE IF CONTROL RETURNED JR RW1 ; ; ROUTINE DINIT CHECKS THE 2422'S AUTO-BOOT CONTROL BIT ; DURING INITIALIZATION. IT THEN TRANSFERS ; CONTROL TO EITHER THE MONITOR OR THE BOOTSTRAP, ; AS APPROPRIATE. ; DINIT: IN DCNTL ;SEE IF AUTO-BOOT WANTED ANI 40H RNZ ;NO, RETURN TO MONITOR INITIALIZATION ; ; ROUTINE BOOT LOADS IN THE FIRST TWO SECTORS OF ; DRIVE 00 INTO LOCATIONS 80H-17FH, THEN ; TRANSFERS PROGRAM CONTROL TO LOCATION 80H. ; IT EXPECTS THE DOS LOADER TO BE ON THESE ; TWO SECTORS. ; BOOT: LXI H,0 ;SET UP THE DISK PARMS SHLD DISKNO LXI H,0D001H ;SIDE 0, SECTOR 1 SHLD SECTOR LXI H,TBUF SHLD LUNIT ;FORCE A DISK DETERMINATION CALL DREADH ;GO GET A SECTOR JRNZ DERROR ;QUIT IF AN ERROR ENCOUNTERED MVI A,2 ;GET SECTOR 2, ALSO STA SECTOR CALL DREADH JZ TBUF ;GO TO THE LOADER ; DERROR: LXI H,DERMSG ;ADDRESS OF DISK ERROR MESSAGE CALL PRTWD ;START THE MESSAGE LDA DISKNO ;DO THE UNIT ASSIGNMENT CALL DERR1 LDA TRACK ;AND THE TRACK CALL DERR1 LDA SECTOR ;AND THE SECTOR CALL DERR1 LDA CMND ;AND THE COMMAND CALL DERR1 LDA STATUS ;AND THE STATUS DERR1: CALL HEX1 ;OUTPUT IT IN HEX JMP PRTWA ;CONTINUE THE MESSAGE ; ; SET DISK PARAMETERS ROUTINE EXPECTS THREE PARAMETERS ; TO BE ENTERED FROM THE CONSOLE. THESE PARAMETERS ; ARE: UNIT NUMBER (0-3); SECTORS PER TRACK; ; AND DOUBLE-SIDED SWITCH (0 OR NON-0). ; ONLY THE UNIT NUMBER IS CHECKED FOR ERRORS. ; ; THIS ROUTINE MUST BE CALLED BEFORE USE OF EITHER ; THE DISK READ OR WRITE ROUTINE. ; PARM: CALL EXPR3 ;GET THE THREE PARAMETERS MOV A,L ;ERROR CHECK THE UNIT ASSIGNEMENT ORA A JM QPRT CPI 4 JNC QPRT STA DISKNO ;SET THE UNIT SELECT MOV L,E ;MOVE THE SECTORS PER TRACK OVER MOV H,C ; AND THE TWO SIDED SWITCH SHLD SPT ;STORE THEM RET ; ; ROUTINE QPARM ALSO SETS CERTAIN DISK PARAMETERS. IN THIS ; CASE THE DESIRED START TRACK SIDE ANS SECTOR ARE ; SET. THESE PARAMETERS NEED ONLY BE SET PRIOR TO THE ; FIRST DISK ACCESS, OR WHEN A NON-CONTIGUOUS DISK ACCESS ; IS DESIRED. IF THE PARAMETERS ARE NOT RESET BETWEEN ; DISK ACCESSES, THE DATA TRANSFER WILL OCCUR TO/FROM ; THE NEXT LOGICALLY SEQUENTIAL DISK LOCATIONS. ; QPARM: CALL EXPR3 ;GET THE THREE PARAMETERS MOV H,C ;MOVE OVER THE START SECTOR SHLD TRACK ;STORE THE TRACK AND SECTORE MOV A,E ;GET THE SIDE INDICATOR ORA A ;SEE IF SINGLE-SIDED MVI A,0D0H ;SIDE 0 SELECT BITS JRZ QPARM1 ;JUMP IF SO MVI A,90H ;ELSE, SET THE SIDE 1 CONTROL BIT QPARM1: STA SIDE ;SAVE IT RET ; ; 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 JR LADR ;GO OUTPUT THE RESULT ; ; ROUTINE LADR PRINTS THE CONTENTS OF (H,L) ON THE ; CURRENT CONSOLE, EITHER AT THE START OF A NEW ; LINE (EP = LADRA) OR AT THE CURRENT LOCATION (EP ; = LADR). ; LADRA: CALL CRLF ;START A NEW LINE LADR: MOV A,H ;GET HIGH TWO DIGITS CALL HEX1 ;PRINT 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 JR 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 JR CO ;GO TYPE IT ; ; IOBYTE HANDLERS ; ORG MOSS+5FBH 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 ;CRTACTIVE 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 PORT 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 1 ACTIVE JMP RUSI2 ;USER READER 2 ACTIVE ; LSTAT: LDA IOBYTE ANI 0C0H ;ISOLATE THE LIST DEVICE ASGT 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 PUS01 ;USER PUNCH 1 ACTIVE JMP PUS02 ;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, LINE FEED ; SEQUENCE ON THE CURRENT CONSOLE TO START A NEW LINE ; IT INCLUDES TWO 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: CALL TTOST ;GET 8250 LINE STATUS JRZ TTYOUT ;WAIT UNTIL ON EOF THE REGISTERS EMPTIES 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 (OUTPU) 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 HIGH SPEED PUNCH STATUS PUS01: EQU IOER ;UNASSIGNED USER PUNCH 1 PUS02: EQU IOER ;UNASSIGNED USER PUNCH 2 ; ; EQUATES FOR ADDITIONAL LIST DEVICES ; LPRT: EQU IOER ;UNASSIGNED LINE PRINTER LPRST: EQU IOER ;UNASSIGNED LINE PRINTER STATUS LUSE1: EQU IOER ;LIST DEVICE 1 LUST1: EQU IOER ;UNASSIGNED 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 READER PTRST: EQU IOER ;UNASSIGNED HS PTR STATUS RUSI1: EQU IOER ;UNASSIGNED PAPER TAPE READER 1 RUST1: EQU IOER ;UNASSIGNED PAPER TAPER READER 1 (STATUS) RUSI2: EQU IOER ;UNASSIGNED PAPER TAPE READER 2 RUST2: EQU IOER ;UNASSIGNED PAPER TAPER READER 2 (STATUS) ; ; THE FOLLOWING ROUTINES DO THE PRIMITIVE DISK ACCESSES. ; IN ALL CASES, ONE SECTORE OF DATA IS TRANSFERRED. ; IF THE DISK HAS NOT BEEN PREVIOUSLY ACCESS, ; THESE ROUTINES WILL AUTOMATICALLY DETERMINE THE ; DISK TYPE (8" OR 5"), SINGLE OR DOUBLE DENSITY, ; AND SECTOR SIZE. ; ; BEFORE THE DESIRED DATA IS TRANSFERRED, THE DESIRED ; TRACK IS SEEKED OUT, THE DESIRED SECTOR AND SIDE IS ; SET, THEN THE ACTUAL DATA TRANSFER. ; ; UP TO TEN TRIES WILL BE ATTEMPTED BEFORE THE DATA ; TRANSFER IS ABORTED. ON RETURN TO THE CALLING ; ROUTINE, THE A REGISTER WILL CONTAIN A ZERO IF THE ; OPERATION WAS SUCCESSFUL, OR NON-ZERO IF NOT ; SUCCESSFUL. THE FLAG REGISTER WILL NOT NECESSARILY ; CORRESPOND WITH THE A REGISTER CONTENT. ; ; THESE ROUTINES ARE CP/M COMPATABLE, AND MAY BE USED ; AS PART OF THE BIOS. ; DREADH: SHLD HSTBUF ;SAVE THE DMA ADDRESS DREAD: MVI A,1 ;SET READ FLAG ORG $-1 ;SAVE A BYTE HERE DWRITE: XRA A ;SET WRITE FLAG STA RWFLAG ;SAVE IT FOR LATER USE MVI B,10 ;NUMBER OF RETRIES AGN: PUSH B CALL SEEK CZ RDWR READ3: POP B RZ DJNZ AGN RET ; RDWR: MOV E,A ;SAVE COMMAND LDA RWFLAG ORA A MOV A,E ;REGET THE COMMAND JRZ WRDAT ;WRITE IF ZERO RDAT: STA CMND OUT DCMMD ;DISK COMMAND PORT READ1: INIR DCR D JRNZ READ1 CALL EOJ ANI 9CH ;ISOLATE READ ERROR BITS RET ; WRDAT: ORI 20H ;ADD WRITE COMMAND STA CMND OUT DCMMD ;DISK COMMAND PORT WRT1: OUTIR ;DO THE OUTPUT DCR D ;IN CASE > 256 BYTES JRNZ WRT1 JR EOJ ; EOJB: MVI B,8 ;BASIS OF RESTORE COMMAND EOJA: LDA STPRAT ;GET THE STEP RATE BITS ORA B ;ADD ON THE COMMAND STA CMND OUT DCMMD ;DO THE COMMAND EOJ: IN DFLAG ;DISK FLAG PORT RAR JRNC EOJ EOJ1: IN DSTAT ;GET THE DISK STATUS STA STATUS ANI 0FCH RET ; SEEK: CALL IDRD ;INSURE HEADER HAS BEEN READ CNZ EOJB ;RESTORE THE DRIVE IF ERROR RM ;DONE IF NO DRIVE SEEK1: LDA SECTOR ;SET THE SECTORE OUT DSCTR ;DISK SECTOR PORT IN DTRCK ;DISK TRACK PORT MOV C,A ;SAVE IT LDA TRACK ;GET DESIRED TRACK CMP C JRZ RDWRT ;JUMP IF NO SEEK NEEDED OUT DDATA ;SET THE SEEK TRACK MVI B,1CH ;BUILD THE SEEK COMMAND CALL EOJA ;DO THE SEEK ANI 98H ;SEEK ERROR MASK RNZ ;DONE IF SEEK ERROR IN DTRCK ;CHECK FOR TRACK 00 RDWRT: ORA A LXI H,40H ;BUILD SECTOR BYTE COUNT JRZ RDWRTO ;JUMP IF TRACK 00 LDA IDSV+3 ;GET SECTOR SIZE RDWRTO: DAD H ;DOUBLE (H,L) DCR A ;LOOP CONTROL JP RDWRTO PUSH H MVI C,80H ;AUTO-WAIT BIT CALL SETUP IN DFLAG ;DISK FLAG PORT ANI 20H ;SEE IF HEAD IS LOADED MVI A,4 JRZ RDWRT1 ;JUMP IF NOT XRA A ;ELSE, RESET THE HEAD LOAD FLAG RDWRT1: ADI 88H ;BUILD A READ SECTORE COMMAND LHLD HSTBUF ;GET THE DMA ADDRESS POP D ;GET THE BYTE COUNT MOV B,E ;SET UP FOR Z-80 I/O DCR D ;SEE IF 128 BYTE SECTORE INR D JRNZ RDWRT2 ;JUMP IF NOT INR D RDWRT2: MVI C,DDATA CMP A ;CLEAR THE FLAGS RET ; IDRD5: MVI B,58H ;BUILD A STEP-IN COMMAND CALL EOJA IDRD: LHLD LUNIT MOV A,H ;GET THE CUNIT VALUE CMP L ;SEE IF SAME AS LUNIT RZ ;RESTURN IF SO IDRD1: MVI C,80H ;SET THE AUTO-WAIT BIT CALL SETUP CALL EOJ1 ;INSURE A DRIVE IS THERE RM ;ERROR IF NOT PUSH H ;SAVE POINTER LXI H,IDSV ;SET UP TO READ ADDRESS LXI B,600H+DDATA MVI D,1 MVI A,0C4H ;READ ADDRESS COMMAND CALL RDAT POP H ;RESTORE POINTER JRZ IDRD2 ;JUMP IF GOOD READ MVI A,40H ;SEE IF DDEN IS SET CMP M RC ;TAKE THE ERROR IF SO ORA M ;ELSE, TRY DDEN MOV M,A JR IDRD ; IDRD2: IN DSCTR ;GET THE TRACK NUMBER OUT DTRCK ;SET THE TRACK REGISTER ORA A ;INSURE NOT ON TRACK 0 JRZ IDRD5 ;JUMP IF NOT OKAY MOV A,M ;REGET SELBITS STA LUNIT ;UPDATE LAST USED UNIT XRA A ;RESET ERROR FLAGS RET ; ; SET UP DRIVE NUMBER SETUP: LXI H,CUNIT ;SEE IF DRIVE HAS BEEN ACTIVE MOV A,M ;GET THE SELBITS ORA A ;SEE IF SET UP YET JRNZ SU0 ;YES, SKIP INIT CODE ; SETIT: LDA DISKNO ;GET THE DESIRED DRIVE MOV B,A ;SAVE IN WORK REGISTER INR B ;PREPARE TO CONVERT TO SELBITS XRA A ;ZERO TO A STC ;DRIVE SELECT BIT SET1: RAL ;SHIFT BIT INTO POSITION DJNZ SET1 ;LOOP TIL BIT IS IN POSITION ORI 20H ;ADD ON MOTOR ON BIT MOV M,A ;SAVE IT OUT DCNTL ;SELECT THE DRIVE LXI D,STPRAT ;SET INITIAL STEP RATE MVI A,3 ; TO SLOWEST POSSIBLE 15 MSEC STAX D CALL EOJB ;RESTORE THE DRIVE RM ;DONE IF DRIVE NOT READY IN 4 ;READ THE MINI TRK00 BIT RAR ;ISOLATE IT JRNC SU0 ;JUMP IF MINI DRIVE MVI A,10H ;ELSE, ADD ON MAXI BIT ORA M MOV M,A MVI A,2 ;SET MAXI STEP RATE STAX D SU0: IN DTRCK ;ELSE, SEE IF TRACK ZERO ORA A MOV A,M ;REGET THE SELBITS JRNZ SU1 ANI 0BFH ;INSURE DDEN IS RESET SU1: ORA C ;ADD ON AUTOWAIT BIT OUT DCNTL ;OUTPUT THE SELBITS LDA SIDE ;SET THE SIDE SELECT OUT 4 RET