name ('monitr') titlå Monitoò Firmwarå foò ATHENÁ STD Systems .z80 .tfcond .commenô ~ M O N I T O R . M A C Version 3.2 Creation Date: 1 January 1983 MODULE: 0.01 Date Last Revised: 1 January 1983 Monitor Firmware for ATHENA STD Systems Edit History: 21 Apr 82 - Created by Mike Pinkston. 01 Jan 83 - Modified for Macro 80 assembler. ~ subttl Module Equate Statements page 60 Data.Area.Baså EQÕ 0EF00È » Starô oæ thå Scratcè Raí Area. IOCS EQU Data.Area.Base + 0E0H ; Start of the DCF Parameter Data. Module.0 EQU 0F000H ; Start of the Monitor Module. Module.1 EQU Module.0 + 800H ; Start of the DCF Module. Disk.Error.Retry EQU 10 ; Number of Disk Retries after an error. Number.of.Sector EQU 51 ; Number of sectors to read in for boot. ; Port Addresses of the Disk Controller. Port.0 EQU 0E0H ; DMA controller port. Port.1 EQU 0E2H ; Drive information port. Port.2 EQU 0E3H ; Drive select port. Port.3 EQU 0E4H ; Command/Status port. Port.4 EQU 0E5H ; Track register port. Port.5 EQU 0E6H ; Sector register port. Port.6 EQU 0E7H ; Data register port. ; Port addresses of the Serial Ports. Port.10 EQU 90H ; SIO Channel 'C' Data port. Port.11 EQU 91H ; SIO Channel 'C' Command port. Port.12 EQU 92H ; SIO Channel 'D' Data port. Port.13 EQU 93H ; SIO Channel 'D' Command port. Port.14 EQU 94H ; SIO Channel 'A' Data port. Port.15 EQU 95H ; SIO Channel 'A' Command port. Port.16 EQU 96H ; SIO Channel 'B' Data port. Port.17 EQU 97H ; SIO Channel 'B' Command port. ; Port addresses of the CTC. Port.20 EQU 07CH ; CTC channel 'A'. Port.21 EQU 07DH ; CTC channel 'B'. Port.22 EQU 07EH ; CTC channel 'C'. Port.23 EQU 07FH ; CTC channel 'D'. ; ASCII names used as values Carriage.Return EQU 0DH ; Carriage Return. Line.Feed EQU 0AH ; Line Feed. Escape EQU 1BH ; Escape. Control.C EQU 03H ; Control-C. Lead.In EQU Escape ; Terminal function lead in character. Clear.the.Screen EQU 076H ; Clear the screen character. Clear.the.Line EQU 074H ; Clear the line character. ; IOCS Vector Area IOCS.Request EQU 00 ; Offset for disk Request code location. IOCS.Unit EQU 01 ; Offset for disk Unit identifier. IOCS.Track EQU 02 ; Offset for Track value location. IOCS.Sector EQU 03 ; Offset for Sector value location. IOCS.DMA.Low EQU 04 ; Offset for DMA address low byte. IOCS.DMA.High EQU 05 ; Offset for DMA address high byte. IOCS.Error.Flag EQU 06 ; Offset for disk error flag location. ; DISK CONTROLLER FIRMWARE LOCATIONS DCF.Clock EQU IOCS+07 ; DCF system clock flag. DCF.Error.Mess EQU IOCS+08 ; DCF error message flag. DCF.Last.Command EQU IOCS+09 ; Last disk command location. DCF.Temp.SP EQU IOCS+10 ; Temporary Stack Pointer location. Error.Type EQU IOCS+12 ; Type of error committed. Error.Unit EQU IOCS+13 ; Unit that committed error. Error.Status EQU IOCS+14 ; Controller status of error. Error.Track EQU IOCS+15 ; Track that committed error. Error.Sector EQU IOCS+16 ; Sector that committed error. DCF.Header.Info EQU IOCS+17 ; DCF header location from disk. ASCII.String EQU IOCS+23 ; ASCII string destination. DCF.Vector.Area EQU Data.Area.Base ; STD vector space for mode 2 interrupts. ; This vector space is divided as follows: ; 0EF00H-0EF07H = DMA chip. ; 0EF08H-0EF0FH = CTC chip. ; 0EF10H-0EF1FH = SIO #1 chip (Console & List Device). ; 0EF20H-0EF2FH = SIO #2 chip (External & Test Ports). ; 0EF30H-0EF37H = Not Used. ; 0EF38H-0EF3BH = Time.Location (4 byte area set aside for Clock). ; 0EF3CH-0EF3FH = Not Used. CTC.Vector EQU Data.Area.Base+08H Time.Location EQU Data.Area.Base+38H Input.Buffer EQU Data.Area.Base+40H ; INPUT Input.Buffer AREA Clock.Stack EQU Data.Area.Base+84H ; EPROM USAGE DATA AREA Stack EQU Data.Area.Base+0DFH ; Stack SPACE ; Disk Command values for the controller. Disk.Status EQU 10H ; Return the disk status. Read.Record EQU 11H ; Read a disk sector. Write.Record EQU 12H ; Write a disk sector. Disk.Seek EQU 13H ; Seek to the track. Home.Disk EQU 14H ; Home the disk drive. Read.Sector.ID EQU 15H ; Read sector ID. Write.Deleted EQU 16H ; Write a deleted sector. Format.Disk EQU 17H ; Format the disk track (Write Track). Read.Track EQU 18H ; Read Track. Read.Multiple EQU 19H ; Read Multiple sectors from track. Write.Multiple EQU 1AH ; Write Multiple sectors to track. subttl START OF EPROM MONITOR FIRMWARE page .phase Module.0 Module.0.Start: ; JP Monitor.Start ; Clear out last of P.O.C. jump. Jump.Label.1: ; JP Print.Message ; Jump to print string to console. Jump.Label.2: ; JP TIME ; Jump to real time clock routine. Jump.Label.3: ; JP Convert.2.digit ; Jump.Label.4: ; JP Convert.4.digit ; Jump.Label.5: ; JP Command.Entry ; Jump.Label.6: ; JP ASCII ; subttl Beginning of the Monitor code. page Monitor.Start: ; IN A,(Port.14) ; LD SP,Stack ; Reset Monitor Stack. ; DI ; Disable interrupts. IM 2 ; Set up for interrupt Mode 2. ; LD BC,SIOLNG*100H+Port.15 ; Initialize SIO channel 'A'. LD HL,SIOCHA ; OTIR ; LD BC,SIOLNG*100H+Port.17 ; Initialize SIO channel 'B'. LD HL,SIOCHA ; OTIR ; LD BC,SIOLNG*100H+Port.11 ; Initialize SIO channel 'C'. LD HL,SIOCHA ; OTIR ; LD BC,SIOLNG*100H+Port.13 ; Initialize SIO channel 'D'. LD HL,SIOCHA ; OTIR ; ; LD HL,DCF.Vector.Area ; Set up interrupt vector table. LD A,H ; The table starts at "EF00". LD I,A ; LD DE,Jump.Label.13 ; DMA vector is at offset 00H. LD (DCF.Vector.Area),DE ; ; LD HL,Jump.Label.2 ; Set up the interrupt vector for the LD (CTC.Vector+2),HL ; LD HL,Jump.Label.15 ; LD (CTC.Vector+6),HL ; Real Time Clock. ; LD A,1 ; Disable CTC's interrupts. LD (Port.20),A ; LD (Port.22),A ; ; LD A,CTC.Vector AND 0FFH ; Set up the CTC's vector response. OUT (Port.20),A ; LD A,017H ; Set up CTC0 as a noninterrupting Timer, with a OUT (Port.20),A ; Prescale of 16. LD A,250 ; Use a time constant of 250. OUT (Port.20),A ; LD A,0D7H ; Set up CTC1 as an interrupting Counter with a OUT (Port.21),A ; time constant of 20. LD A,20 ; OUT (Port.21),A ; LD A,17H ; Set up CTC2 as a noninterrupting Timer, with a OUT (Port.22),A ; Prescale of 16. LD A,250 ; Use a time constant of 250. OUT (Port.22),A ; LD A,57H ; Set up CTC3 as a noninterrupting Counter with a OUT (Port.23),A ; time constant of 1. LD A,1 ; OUT (Port.23),A ; ; EI ; Enable all interrupts. ; CALL Jump.Label.16 ; Initialize the disk system. ; LD HL,Signon.Message ; Output the signon message. CALL Print.Message ; ; ; CALL GETCHR ; GET FIRST CHARACTER FROM CONSOLE. CP Control.C ; WAS CHARACTER A CONTROL-C? JP NZ,Jump.Label.11 ; IF NOT, THEN BOOT DISK. ; START1: ; LD HL,Monitor.Message ; DISPLAY MONITOR MESSAGE. CALL Print.Message ; Command.Entry: ; LD HL,New.Command.Mess ; DISPLAY NEW Command LINE. CALL Print.Message ; OUTPUT MESSAGE. CALL INPUT ; GET CHARACTER FROM CONSOLE. LD HL,Input.Buffer ; Set pointer to start of the Input Buffer. CALL SKPSPC ; SKIP OVER SPACES. ; CP 'B' ; BOOT Command? JP Z,Jump.Label.11 ; IF SO, THEN PROCESS. CP 'D' ; DISPLAY Command? JP Z,DISPLAY ; IF SO, THEN PROCESS. CP 'F' ; FILL Command? JP Z,FILL ; IF SO, THEN PROCESS. CP 'G' ; GO Command? JP Z,GO ; IF SO, THEN PROCESS. CP 'I' ; INPUT Command? JP Z,INPUT1 ; IF SO, THEN PROCESS. CP 'K' ; KICK Stack Command? JP Z,KICK ; IF SO, THEN PROCESS. CP 'M' ; MOVE Command? JP Z,MOVE ; IF SO,THEN PROCESS. CP 'O' ; OUTPUT Command? JP Z,OUTPUT ; IF SO, THEN PROCESS. CP 'R' ; READ Command? JP Z,READ ; IF SO, THEN PROCESS. CP 'S' ; SUBSTITUTE Command? JP Z,SUBSTITUTE ; IF SO, THEN PROCESS. CP 'W' ; WRITE Command? JP Z,WRITE ; IF SO, THEN PROCESS. CP 'X' ; Exit Command? JP Z,Exit ; IF SO, THEN PROCESS. CP '?' ; HELP Command? JP Z,HELP ; IF SO, THEN PROCESS. ; LD HL,Command.Err.Mess ; Command entry error. CALL Print.Message ; OUTPUT MESSAGE. JR Command.Entry ; GET NEW Command. GO: ; CALL ASCII ; JR C,KICK1$ ; EX DE,HL ; JP (HL) ; KICK: ; CALL ASCII ; JR C,KICK1$ ; EX DE,HL ; LD SP,HL ; KICK1$: ; JR Command.Entry ; ; DISPLAY: ; CALL ASCII ; LD HL,Display.Mem.Mess ; CALL Print.Message ; LD BC,1008H ; DISP05: ; CALL Convert.4.digit ; DISP10: ; LD A,(DE) ; CALL Convert.2.digit ; INC DE ; DJNZ DISP10 ; LD B,10H ; ; OR A ; EX DE,HL ; Display the ASCII values for the data LD DE,16 ; bytes shown in hex. SBC HL,DE ; EX DE,HL ; ; LD A,' ' ; CALL Console.Output ; DISP15: ; LD A,(DE) ; CP 020H ; JR C,DISP16 ; CP 07EH ; JR NC,DISP16 ; JR DISP17 ; DISP16: ; LD A,'.' ; DISP17: ; CALL Console.Output ; INC DE ; DJNZ DISP15 ; ; DEC C ; JR Z,DISP20 ; CALL CRLF ; LD B,10H ; ; JR DISP05 ; DISP20: ; JP Command.Entry ; INPUT1: ; CALL ASCII ; JR C,INPUT$ ; LD HL,Port.Value.Mess ; CALL Print.Message ; LD C,E ; IN A,(C) ; CALL Convert.2.digit ; INPUT$: ; JP Command.Entry ; OUTPUT: ; CALL ASCII ; JR C,OUTPT$ ; LD C,E ; CALL ASCII ; JR C,OUTPT$ ; OUT (C),E ; OUTPT$: ; JP Command.Entry ; READ: ; LD IY,IOCS ; LD (IY+IOCS.Request),Read.Record ; JR DODISK ; WRITE: ; LD IY,IOCS ; LD (IY+IOCS.Request),Write.Record ; DODISK: ; CALL ASCII ; JR C,DISKF ; LD A,E ; SUB 10 ; LD (IY+IOCS.Unit),A ; CALL ASCII ; JR C,DISKF ; LD (IY+IOCS.Track),E ; CALL ASCII ; JR C,DISKF ; LD (IY+IOCS.Sector),E ; CALL ASCII ; JR C,DISKF ; LD (IY+IOCS.DMA.Low),E ; LD (IY+IOCS.DMA.High),D ; CALL ASCII ; JR C,DISKF ; LD C,E ; LD B,10 ; CALL DISK1 ; DISKF: ; JP Command.Entry ; DISK1: ; CALL Module.1.Start ; JR Z,DISK2 ; DJNZ DISK1 ; CALL Jump.Label.12 ; JP Command.Entry ; DISK2: ; DEC C ; JR Z,DISKR ; LD A,(IY+IOCS.DMA.Low) ; BUMP POINTER BY 128 BYTES. ADD A,80H ; LD (IY+IOCS.DMA.Low),A ; JR NC,DISK3 ; INC (IY+IOCS.DMA.High) ; DISK3: ; LD A,27 ; INC (IY+IOCS.Sector) ; CP (IY+IOCS.Sector) ; JR NZ,DISK1 ; INC (IY+IOCS.Track) ; LD (IY+IOCS.Sector),1 ; JR DISK1 ; DISKR: ; RET ; RETURN ; HELP: ; Display Help screen. LD HL,Help/Message ; CALL Print.Message ; JP Command.Entry ; ; FILL: ; CALL ASCII ; Get the starting address. JR C,FILL2 ; PUSH DE ; ; CALL ASCII ; Get the ending address. JR C,FILL2 ; PUSH DE ; ; CALL ASCII ; Get the filler data byte. JR C,FILL2 ; LD C,E ; ; OR A ; Clear the Carry flag. POP HL ; POP DE ; SBC HL,DE ; EX DE,HL ; FILL1: ; LD (HL),C ; INC HL ; DEC DE ; LD A,D ; OR E ; JR NZ,FILL1 ; FILL2: ; JP Command.Entry ; ; MOVE: ; Move a block of data. CALL ASCII ; JR C,MOVE1 ; PUSH DE ; ; CALL ASCII ; JR C,MOVE1 ; PUSH DE ; ; CALL ASCII ; JR C,MOVE1 ; ; LD C,E ; LD B,D ; POP DE ; POP HL ; LDIR ; MOVE1: ; JP Command.Entry ; ; SUBSTITUTE: ; CALL ASCII ; JP C,Command.Entry ; SUBS1: ; CALL CRLF ; CALL Convert.4.digit ; ; LD A,(DE) ; CALL Convert.2.digit ; ; CALL INPUT ; LD HL,Input.Buffer ; CALL SKPSPC ; CP '.' ; JP Z,Command.Entry ; ; PUSH DE ; CALL ASCI0$ ; ; JR C,SUBS2 ; ; LD A,E ; POP DE ; LD (DE),A ; JR SUBS3 ; SUBS2: ; POP DE ; SUBS3: ; INC DE ; JR SUBS1 ; subttl Subroutines used by montior page Print.Message: PUSH AF ; SAVE REGISTER PAIRS. Print.Message.1: LD A,(HL) ; BRING IN CHARACTER. OR A ; IS THIS THE LAST CHARACTER? JR Z,Print.Message.2 ; IF SO, THEN SKIP. CALL Console.Output ; OUTPUT CHARACTER TO CONSOLE. INC HL ; POINT TO NEXT CHARACTER. JR Print.Message.1 ; KEEP LOOPING UNTIL FINISHED. Print.Message.2: POP AF ; RESTORE REGISTER PAIR. RET ; RETURN TO CALLING PROGRAM. Console.Output: PUSH AF ; SAVE REGISTER "AF". XOR A ; READ SIO REGISTER 0. OUT (Port.15),A ; CON1$: IN A,(Port.15) ; BRING IN SIO STATUS. BIT 2,A ; TRANSMIT Input.Buffer EMPTY? JR Z,CON1$ ; LOOP IF NOT. POP AF ; RESTORE CHARACTER TO BE SENT. OUT (Port.14),A ; OUTPUT CHARACTER. RET ; RETURN TO CALLING PROGRAM. INPUT: LD HL,Input.Buffer ; SET POINTER TO START OF Input.Buffer. GET: CALL GETCHR ; GET CHARACTER FROM CONSOLE. CP 20H ; IS CHARACTER A CONTROL CODE? JR NC,GET1$ ; IF NOT, THEN SKIP. CP Carriage.Return ; IS CHARACTER A "Carriage.Return"? JR Z,INPCR ; IF SO, THEN PROCESS. CP Line.Feed ; IS CHARACTER A "Line.Feed"? JR Z,INPCR ; IF SO, THEN PROCESS. CP 15H ; IS CHARACTER A "CONTROL-U"? JR Z,INPCU ; IF SO, THEN PROCESS. CP 18H ; IS CHARACTER A "CONTROL-X"? JR Z,INPCU ; IF SO, THEN PROCESS. CP 08H ; IS CHARACTER A "BACKSPACE"? JR Z,INPDEL ; IF SO, THEN PROCESS. CP 03H ; IS CHARACTER A "CONTROL-C"? JP Z,Module.0.Start ; RESTART MONITOR. JR GET ; LOOP BECAUSE OF ILLEGAL CHARACTER. GET1$: CP 5FH ; IS CHARACTER A "DELETE"? JR Z,INPDEL ; IF SO, THEN PROCESS. LD (HL),A ; PUT CHARACTER IN Input.Buffer. INC HL ; POINT TO NEXT FREE BYTE. CALL Console.Output ; ECHO CHARACTER TO CONSOLE. JR GET ; GET NEXT CHARACTER INPUT. INPCR: LD (HL),00 ; SET END OF Input.Buffer FLAG. RET ; RETURN TO CALLING PROGRAM. INPCU: LD HL,Clear.Line.Mess ; ENTER NEW Command.Entry. CALL Print.Message ; OUTPUT PROMPT. JR INPUT ; INPUT NEW Command.Entry. INPDEL: PUSH DE ; SAVE REGISTER PAIRS. PUSH HL ; LD DE,Input.Buffer ; Bring start of Input Buffer pointer. SCF ; Make sure carry flag is = 0. CCF ; SBC HL,DE ; Is HL = DE? JR Z,DEL1$ ; If so, then skip. POP HL ; Restore Input Buffer pointer. DEC HL ; Erase character from Input Buffer. PUSH HL ; Save register pair. LD HL,Delete.Char.Mess ; Clear character from screen. CALL Print.Message ; DEL1$: ; POP HL ; Restore register pair. POP DE ; JR GET ; GETCHR: ; XOR A ; OUT (Port.15),A ; GETC1$: ; IN A,(Port.15) ; RRA ; IS A CHARACTER READY TO BE INPUT? JR NC,GETC1$ ; IF NOT LOOP. IN A,(Port.14) ; BRING IN CHARACTER. AND 7FH ; STRIP OFF 8TH BIT. CP 61H ; IS CHARACTER UPPER CASE? RET C ; IF SO, THEN RETURN. SUB 20H ; CONVERT LOWER TO UPPER CASE. RET ; RETURN TO CALLING PROGRAM. subttl Convertion routines page Convert.2.digit: LD HL,ASCII.String ; SET UP DESTINATION STRING. CALL Convert.Byte ; CONVERT BYTE TO ASCII. LD (HL),20H ; PUT SPACE AFTER ASCII. INC HL ; POINT TO NEXT BYTE. LD (HL),00 ; SET EOM FLAG. LD HL,ASCII.String ; POINT TO FIRST OF STRING. CALL Print.Message ; OUTPUT STRING TO CONSOLE. RET ; RETURN TO CALLING PROGRAM. Convert.4.digit: LD A,D ; CONVERT HIGH BYTE. LD HL,ASCII.String ; SET UP DESTINATION STRING. CALL Convert.Byte ; CONVERT BYTE TO ASCII. LD A,E ; CONVERT LOW BYTE. CALL Convert.Byte ; CONVERT BYTE TO ASCII. LD (HL),3AH ; LOAD ':' TO ASCII STRING. INC HL ; POINT TO NEXT BYTE. LD (HL),20H ; LOAD ' ' TO ASCII STRING. INC HL ; POINT TO NEXT BYTE. LD (HL),00 ; SET EOM FLAG. LD HL,ASCII.String ; POINT TO FIRST OF STRING. CALL Print.Message ; OUTPUT STRING TO CONSOLE. RET ; RETURN TO CALLING PROGRAM. Convert.Byte: ; CALL Convert.Byte.1$ ; DO HIGH NIBBLE. RRA ; Convert.Byte.1$: ; RRA ; SHIFT OVER 4 BITS. RRA ; RRA ; RRA ; PUSH AF ; SAVE REGISTER "A". AND 0FH ; LEAVE ONLY THE LOW NIBBLE. CP 0AH ; IS NIBBLE > 9? JR C,Convert.Byte.2$ ; IF NOT, THEN SKIP. ADD 07 ; ADD IN ASCII HEX OFFSET. Convert.Byte.2$: ; ADD 30H ; ADD IN ASCII OFFSET. LD (HL),A ; MOVE BYTE TO DESTINATION. INC HL ; POINT TO NEXT BYTE. POP AF ; RESTORE REGISTER "A". RET ; RETURN TO CALLING PROGRAM. subttl More subroutines page Exit: ; LD HL,Reboot.Message ; Output the system halt message. CALL Print.Message ; Exit.1$: ; HALT ; Halt the processor. JR Exit.1$ ; Keep on halting. CRLF: ; LD HL,New.Line.Mess ; OUTPUT Carriage.Return,Line.Feed. CALL Print.Message ; RET ; RETURN TO CALLING PROGRAM. ASCII: ; CALL SKPWRD ; SKIP OVER TRAILING CHARACTERS. OR A ; TEST FOR END OF LINE. JR Z,ASCI1$ ; IF END OF LINE, THEN JUMP. ASCI0$: ; CALL SKPSPC ; SKIP OVER LEADING SPACES. OR A ; TEST FOR END OF LINE. JR Z,ASCI1$ ; IF END OF LINE, THEN JUMP. CALL ASCBIN ; CONVERT ASCII TO BINARY. JR ASCI2$ ; TAKE CLEAN FINISH. ASCI1$: ; SCF ; Set carry falg to signal error. ASCI2$: ; RET ; Return to the calling program. SKPSPC: LD A,(HL) ; BRING IN CHARACTER. CP ' ' ; IS IT = SPACE? JR Z,SKP10 ; IF SO, THEN SKIP. CP ',' ; IS IT = COMMA? JR Z,SKP10 ; IF SO, THEN SKIP. RET ; RETURN TO CALLING PROGRAM. SKP10: INC HL ; POINT TO NEXT BYTE. JR SKPSPC ; LOOP. SKPWRD: LD A,(HL) ; BRING IN CHARACTER. CP 20H ; IS IT = SPACE? JR Z,SKP20 ; IF SO, THEN SKIP. CP ',' ; IS IT = COMMA? JR Z,SKP20 ; IF SO, THEN SKIP. OR A ; IS IT = 00H? JR Z,SKP20 ; IF SO, THEN SKIP. INC HL ; POINT TO NEXT BYTE. JR SKPWRD ; LOOP. SKP20: RET ; RETURN TO CALLING PROGRAM. ASCBIN: LD DE,00000H ; CLEAR REGISTER "DE". HX1: LD A,(HL) ; BRING IN BYTE. PUSH HL ; SAVE REGISTER CONTENTS. SUB 30H ; REMOVE ASCII OFFSET. JR C,SPACE$ ; IF < 30H, THEN FINISHED. ADD 0E9H ; JR C,ERR0R$ ; CHECK FOR BAD CHARACTER. SUB 0FAH ; JR NC,HX2 ; ADD 07H ; SET UP ASCII OFFSET. JR C,ERR0R$ ; HX2: ADD 0AH ; DO ASCII OFFSET. LD L,E ; PUT "DE" INTO "HL". LD H,D ; ADD HL,HL ; SHIFT "HL" OVER 4 BITS. ADD HL,HL ; ADD HL,HL ; ADD HL,HL ; OR L ; LD L,A ; LD E,L ; LD D,H ; POP HL ; INC HL ; POINT TO NEXT BYTE. JR HX1 ; LOOP. SPACE$: POP HL ; RESTORE REGISTER PAIR. OR A ; TEST BYTE BEING ZERO. RET ; RETURN TO CALLING PROGRAM. ERR0R$: ; LD HL,Command.Err.Mess ; Incorrect Command Entry. CALL Print.Message ; OUTPUT MESSAGE. POP HL ; RESTORE REGISTER PAIR. SCF ; SET CARRY FLAG. RET ; RETURN TO CALLING PROGRAM. ; Time.ISR: ; Real Time Clock interrupt service routine. LD (Clock.Stack),SP ; LD SP,Clock.Stack ; PUSH AF ; Save the registers that will be used. PUSH HL ; ; LD HL,Time.Location ; Get the address of the clock data area. INC (HL) ; Add one more tick to 1/50th second counter. LD A,(HL) ; Has the counter reached 50 yet? CP 50 ; JP C,Time.ISR.1 ; If not, then jump. ; LD (HL),00 ; Zero the 1/60th second counter. INC HL ; INC (HL) ; Add one more tick to second counter. LD A,(HL) ; Has the counter reached 60 yet? CP 60 ; JP C,Time.ISR.1 ; If not, then jump. ; LD (HL),00 ; Zero the second counter. INC HL ; INC (HL) ; Add one more tick to minute counter. LD A,(HL) ; Has the counter reached 60 yet? CP 60 ; JP C,Time.ISR.1 ; If not, then jump. ; LD (HL),00 ; Zero the minute counter. INC HL ; INC (HL) ; Add one more tick to hour counter. LD A,(HL) ; Has the counter reached 24 yet? CP 24 ; JP C,Time.ISR.1 ; If not, then jump. ; LD (HL),00 ; Zero the hour counter. Time.ISR.1: ; POP HL ; Restore the registers. POP AF ; LD SP,(Clock.Stack) ; EI ; Enable the interrupt system again. RETI ; Return from interrupt. subttl Messages from Monitor to console page Signon.Message: DEFB Lead.In, Clear.The.Screen DEFB 'To bring up ATHENA, press "RETURN".' DEFB 00 Monitor.Message: DEFÂ Carriage.Return, Line.Feed DEFB 'BLACË HOLÅ SYSTEMÓ Z8° 60ë Monitoò Versioî 3.2' DEFB 00 Reboot.Message: DEFB Carriage.Return, Line.Feed DEFB 'System halted. Press reset to try again.' DEFB Carriage.Return, Line.Feed DEFB 00 New.Command.Mess: DEFB Carriage.Return, Line.Feed DEFB 'Command > ' DEFB 00 Delete.Char.Mess: DEFB 08,20H,08,00 Clear.Line.Mess: DEFB Lead.In, Clear.the.Line DEFB 'Command > ' DEFB 00 Command.Err.Mess: DEFB Carriage.Return, Line.Feed DEFB 'Incorrect command entry, retry.' DEFB Carriage.Return, Line.Feed DEFB 00 Display.Mem.Mess: DEFB Carriage.Return, Line.Feed, Line.Feed DEFB 'Display contents of memory:' DEFB Carriage.Return, Line.Feed DEFB 'Addr: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F' DEFB Carriage.Return,Line.Feed DEFB '=====================================================' New.Line.Mess: DEFB Carriage.Return, Line.Feed DEFB 00 Port.Value.Mess: DEFB Carriage.Return, Line.Feed DEFB 'The present value of the port is ' DEFB 00 Help/Message: DEFB Carriage.Return, Line.Feed, Line.Feed DEFB 'This is the Monitor Command Summary.' DEFB Carriage.Return, Line.Feed DEFB '====================================' DEFB Carriage.Return, Line.Feed DEFB 'Boot = B Display memory = D SSSS' DEFB Carriage.Return, Line.Feed DEFB 'Monitor Commands = ? Fill = F SSSS EEEE DD' DEFB Carriage.Return, Line.Feed DEFB 'Go = G SSSS Input = I PP' DEFB Carriage.Return, Line.Feed DEFB 'Kick SP = K SSSS Move block = M SSSS DDDD NNNN' DEFB Carriage.Return, Line.Feed DEFB 'Output = O PP DD Read = R D SS TT SSSS NN' DEFB Carriage.Return, Line.Feed DEFB 'Substitute = S SSSS Write = W D SS TT SSSS NN' DEFB Carriage.Return, Line.Feed, Line.Feed DEFB '(SSSS = Starting Address, EEEE = Ending Address)' DEFB Carriage.Return, Line.Feed DEFB '(DDDD = Destination address, NNNN = Number of bytes)' DEFB Carriage.Return, Line.Feed DEFB '(PP = Port Address, DD = Data. All numbers are Hex.)' DEFB Carriage.Return, Line.Feed DEFB '(D = Disk Specifier, SS = Sector, TT = Track, NN = Number of Sectors)' DEFB Carriage.Return, Line.Feed DEFB 00 SIOCHA: DEFB 4,044H,3,0C1H,5,0E8H,1,000H,0D0H SIOLNG EQU $-SIOCHA .dephase subttl Disk controller firmware jump table entry points page .phase Module.1 Module.1.Start: JP Disk.Contr.Firm ; Jump to DCF. Jump.Label.11: JP BOOT ; Jump to disk boot of CP/M. Jump.Label.12: JP ERROR1 ; Jump to disk error routine. Jump.Label.13: JP DSK80 ; Jump to DMA's interrupt routine. Jump.Label.14: JP DSKST1 ; Jump to disk status routine. Jump.Label.15: JP CLKISR ; Jump to 1 ms interrupt service routine. Jump.Label.16: JP Initial.Drives ; Jump to initialize the disk system. Jump.Label.17: JP 0FFFFH ; Jump.Label.18: JP 0FFFFH ; Jump.Label.19: JP 0FFFFH ; subttl Initialize the Disk system and restore the drives page Initial.Drives: LD IY,IOCS LD (IY+IOCS.Request),Home.Disk ; Set up the Request function. LD (IY+IOCS.Unit),01 ; Do drive "B" first. LD (IY+IOCS.Track),00 ; Move the disk head to Track 00. LD (IY+IOCS.Sector),01 ; Dummy sector number. LD (IY+IOCS.DMA.Low),00 ; Set up a dummy DMA address. LD (IY+IOCS.DMA.High),0F0H ; CALL Disk.Contr.Firm ; Home Disk drive "B". LD (IY+IOCS.Unit),00 ; Do drive "A". CALL Disk.Contr.Firm ; Home Disk drive "A". ; RET ; Return to the calling routine. subttl Load in the operating system loader page BOOT: LD HL,0100H ; Start loading LOADER at 0100H. LD IY,IOCS ; Set up IOCS vector pointer. LD (IY+IOCS.DMA.Low),L ; Load IOCS with DMA address. LD (IY+IOCS.DMA.High),H ; LD (IY+IOCS.Unit),0 ; Try drive "A" first. LD (IY+IOCS.Track),0 ; Get track 00 contents. LD (IY+IOCS.Sector),2 ; Starting with sector 2. LD BC,Disk.Error.Retry*100H + Number.of.Sector ; Set up number of retries. LD (IY+IOCS.Request),Read.Record ; Read sectors one at a time. CALL DISK1.0 ; Do the read. JP 0100H ; Start LOADER. subttl Entry point for the Disk Controller Firmware page Disk.Contr.Firm: DI ; Disable interrupts. PUSH AF ; SAVE REGISTERS: PUSH BC ; AF,BC,DE,HL,AF' PUSH DE ; PUSH HL ; EX AF,AF' ; NOW GET AF' PUSH AF ; LD (DCF.Temp.SP),SP ; SAVE CALLER'S Stack POINTER RES 0,(IY+IOCS.Error.Flag) ; CLEAR Jump.Label.12 FLAG CALL ENTRY ; CHECK DISK SELECTION DCF1: DI ; Disable interrupts. LD SP,(DCF.Temp.SP) ; RESTORE CALLER'S Stack POINTER POP AF ; RESTORE REGISTERS: EX AF,AF' ; PUT BACK AF',HL,DE,BC,AF POP HL ; POP DE ; POP BC ; POP AF ; BIT 0,(IY+IOCS.Error.Flag) ; SET Z FLAG IF NO Jump.Label.12 OCCURED EI ; RET ; DURING Request subttl Clear the DMA chip page CLRDMA: ; IN A,(Port.3) ; LOOP UNTIL 1771 ISN'T BUSY. BIT 0,A ; JR NZ,CLRDMA ; LD E,A ; LD A,0C3H ; OUT (Port.0),A ; RES 0,(IY+IOCS.Error.Flag) ; IN A,(Port.3) ; EX AF,AF' ; AND E ; JR NZ,CLEAN ; CLRDM$: EX AF,AF' ; RET ; subttl Clean up the disk system because of possible error. page CLEAN: ; BIT 7,A ; If the disk is not ready then take JR NZ,CLEAN6 ; the error exit. LD A,(DCF.Last.Command) ; See if the last command was a multiple BIT 4,A ; sector operation. JR Z,CLEAN0 ; If not, then continue with cleanup. IN A,(Port.5) ; If so, then test to see if last CP 27 ; sector has been read. JR Z,CLRDM$ ; If so, then jump to clean finish. CLEAN0: CALL CLEAN7 ; LD B,2 ; BIT 2,A ; LD A,62H ; JR Z,CLEAN2 ; CLEAN1: ; XOR 20H ; CLEAN2: ; OUT (Port.3),A ; LD D,A ; CLEAN3: ; IN A,(Port.3) ; AND 1 ; JR NZ,CLEAN3 ; LD A,D ; DJNZ CLEAN1 ; XOR A ; OUT (Port.2),A ; LD A,64H ; CALL DELAY ; LD A,E ; CLEAN4: ; AND 1CH ; Set sector not found, CRC error, JP ENTRY9 ; or data lost flag. Then exit. CLEAN5: ; LD A,80H ; Set invalid drive, track, or JP ENTRY9 ; sector flag. Then exit. CLEAN6: ; LD A,40H ; Set drive not ready flag. JP ENTRY9 ; Then exit. subttl Main entry point for DCF after initial saving of registers. page ENTRY: ; EI ; XOR A ; LD (DCF.Last.Command),A ; IN A,(Port.2) ; AND 0FH ; LD C,0FFH ; JR Z,ENTRY2 ; ENTRY1: INC C ; RRA ; JR NC,ENTRY1 ; ENTRY2: LD A,(IY+IOCS.Unit) ; AND 03H ; CP C ; JR Z,ENTRY6 ; LD C,01H ; OR A ; JR Z,ENTRY4 ; ENTRY3: SLA C ; DEC A ; JR NZ,ENTRY3 ; ENTRY4: LD A,C ; OUT (Port.2),A ; LD A,23H ; CALL DELAY ; IN A,(Port.3) ; BIT 7,A ; JR NZ,CLEAN6 ; ; ENTRY5: ; LD A,(IY+IOCS.Request) ; Is request a Format? CP Format.Disk ; If so, then skip loading head. JR Z,ENTRY6 ; CP Home.Disk ; Is request a Restore? CALL NZ,ID ; If so, then skip READ ID. ENTRY6: ; LD A,(IY+IOCS.Sector) ; See if sector number > 0 and CP 27 ; sector number < 27. If it is JR NC,CLEAN5 ; out of range then take error OR A ; exit. JR Z,CLEAN5 ; LD B,77 ; page ENTRY7: ; LD A,(IY+IOCS.Track) ; See if track number > 77. CP B ; JR NC,CLEAN5 ; If so, then take error exit. ; LD A,(IY+IOCS.Request) ; Get request code. LD B,A ; CP 10H ; Is request a "Status"? JR Z,STAT ; If so, then process. IN A,(Port.3) ; If drive is not ready, then BIT 7,A ; jump to the error exit. JR NZ,CLEAN6 ; LD A,B ; CP Read.Record ; Is request a "Read Sector"? JP Z,DSKR ; If so, then process. CP Write.Record ; Is request a "Write Sector"? JP Z,DSKW ; If so, then process. CP Disk.Seek ; Is request a "Seek Track"? JR Z,SEEK ; If so, then process. CP Home.Disk ; Is request a "Home Disk"? JP Z,DSK13 ; If so, then process. CP Read.Sector.ID ; Is request a "Read ID"? JR Z,ID ; If so, then process. CP Write.Deleted ; Is request a "Write Delete"? JP Z,DSK1 ; If so, then process. CP Format.Disk ; Is request a "Write Track"? JP Z,DSK16 ; If so, then process. CP Read.Track ; Is request a "Read Track"? JP Z,DSK16 ; If so, then process. CP Read.Multiple ; Is request a "Read Multiple"? JP Z,DSK40 ; If so, then process. CP Write.Multiple ; Is request a "Write Multiple"? JP Z,DSK60 ; If so, then process. ; ; Error exit routine. ENTRY8: ; XOR A ; Set for unknown request error. ENTRY9: ; LD (DCF.Error.Mess),A ; Set error bits into the DCF error SET 0,(IY+IOCS.Error.Flag) ; location, and then exit. JP DCF1 ; subttl Entry point for the Seek Request. page SEEK: ; LD A,(IY+IOCS.Track) ; OUT (Port.6),A ; specified in IOCS. LD E,A ; Is the present track the one that IN A,(Port.4) ; is wanted? CP E ; If so return. RET Z ; Clean finish exit. LD B,02 ; Try seek only twice. SEEK3: ; LD A,1EH ; Do a seek for the requested track. CALL DSK14 ; BIT 4,A ; Did an error occur? RET Z ; Clean finish exit. CALL DSK13 ; Error recovery from seek. DJNZ SEEK3 ; Try again one more time. SEEK4: ; LD A,20H ; Take track seek error exit. JR ENTRY9 ; subttl Entry point for the Drive status Request. page STAT: ; Get current drive status. CALL CLEAN7 ; Clear 1771 and get new status. LD D,A ; AND 08 ; BIT 7,D ; Set flag bit if disk is not ready. JR Z,STAT1 ; SET 6,A ; STAT1: ; BIT 6,D ; Set flag bit if disk is write JR Z,STAT2 ; protected. SET 1,A ; STAT2: ; BIT 4,D ; Set flag bit if disk has a Seek JR Z,STAT3 ; error condition. SET 5,A ; STAT3: ; LD (DCF.Error.Mess),A ; Put flag bits into DCF error RET ; location. subttl Entry point for the Read ID Request. page ID: LD A,0C3H ; Stop the DMA chip from causing interrupts. OUT (Port.0),A ; INC A ; OUT (Port.3),A ; LD (DCF.Last.Command),A ; Save command temporarily. LD HL,DCF.Header.Info ; Put Header information at "DCF.Header.Info". LD BC,06*100H+Port.6 ; There will be 6 bytes transferred LD A,9CH ; from disk, these are: EX AF,AF' ; 1) Track Number (1 byte). LD DE,0301H ; 2) zero field. (1 byte). DI ; 3) Sector Number. (1 byte). ID1: ; 4) Sector Length. (1 byte). IN A,(Port.3) ; 5) CRC (2 bytes). XOR E ; AND D ; JR Z,ID1 ; INI ; JR NZ,ID1 ; EI ; CALL CLRDMA ; Finish up request. LD A,(DCF.Header.Info) ; Load the read track number back into OUT (Port.4),A ; 1771 track register. RET ; subttl Entry points for disk read, write and write deleted sector page DSK40: ; LD D,9CH ; Read all remaining sectors on track. JR DSK2 ; Assume head engaged, IBM format and ; no 10 ms delay. DSK60: ; LD D,0B8H ; Write all remaining sectors on track. JR DSK2 ; Assume head engaged, IBM format and ; no 10 ms delay. DSKR: ; LD D,88H ; Read one sector in from disk. JR DSK2 ; Assume head engaged, IBM format and ; no 10 ms delay. DSKW: ; LD D,0A8H ; Write one sector to disk. JR DSK2 ; Assume head engaged, IBM format and ; no 10 ms delay. DSK1: ; LD D,0ABH ; Write one deleted sector to disk. ; Assume head engaged, IBM format and ; no 10 ms delay. DSK2: ; LD A,(IY+SECTOR) ; Find desired sector for this OUT (Port.5),A ; operation. PUSH DE ; Save disk command for later. CALL SEEK ; POP DE ; Port B is an I/O port and fixed, LD A,0D0H ; Clear 1771 by forcing interrupt. OUT (Port.3),A ; ; BIT 4,D ; Test to see if single or multiple JR NZ,DSK3 ; record operation. LD HL,DSK19 ; Set for a single sector operation. LD BC,0DE0H ; JR DSK3.1 ; DSK3: ; LD HL,DSK12 ; Send DMA set up sequence: LD BC,0DE0H ; Reset DMA chip, DSK3.1: OTIR ; Block tranfer 0FFFFH bytes long, LD A,19H ; Port A is memory and incremented, BIT 5,D ; Reset port A timing, JR Z,DSK4 ; Reset port B timing, OR 04 ; Port B is at 0E7H, DSK4: ; Interrupt at EOB with vector 00, OUT (Port.0),A ; Load for A->B (write) or A<-B (read), LD A,(IY+IOCS.DMA.Low) ; Port A address is "DMA", OUT (Port.0),A ; CE and WAIT multiplex with Ready high, LD A,(IY+IOCS.DMA.High) ; Enable chip and its interrupts, OUT (Port.0),A ; Enable DMA. LD B,05H ; OTIR ; DI ; IN A,(Port.3) ; If head is already engaged, then jump BIT 5,A ; else set head load bit in disk command. LD A,D ; JR NZ,DSK5 ; OR 04 ; DSK5: ; LD (DCF.Last.Command),A ; Save command temporarily. OUT (Port.3),A ; Send command to 1771. DSK6: ; EI ; LD A,9CH ; If an error occured, do not return EX AF,AF' ; here. CALL CLRDMA ; BIT 5,D ; If read request, then jump. JR Z,DSK9 ; DSK7: ; If disk is write protected, then LD A,02H ; jump to error routine. BIT 6,E ; JP NZ,ENTRY9 ; DSK8: ; Clean finish return. RET ; DSK9: ; Set error flag to show an attempted AND 60H ; read of deleted sector occured. JR Z,DSK8 ; LD A,01 ; JP ENTRY9 ; subttl Entry point for the Restore Request page DSK13: ; Entry point for Restore Request. LD A,02 ; CALL DSK14 ; BIT 4,A ; RET Z ; JP SEEK4 ; ; DSK14: ; Output the command in the "A" PUSH AF ; register to the 1771 when it DSK15: ; completes it present task. IN A,(Port.3) ; BIT 0,A ; JR NZ,DSK15 ; POP AF ; OUT (Port.3),A ; LD (DCF.Last.Command),A ; LD A,80H ; EX AF,AF' ; JP CLRDMA ; subttl Delay Routine page DELAY: ; Delay a specified numbered of loops LD B,249 ; through this routine. There are DELAY1: ; really two different "speeds" that DEC B ; JR NZ,DELAY1 ; DEC A ; JR NZ,DELAY ; RET ; ; CLEAN7: ; Clear the 1771 chip and return its LD A,0D0H ; new status. OUT (Port.3),A ; LD A,03H ; CLEAN8: ; DEC A ; JR NZ,CLEAN8 ; IN A,(Port.3) ; RET ; subttl Format a Track on the disk (write the complete track) page DSK16: ; This routine actually does both a LD A,(IY+IOCS.Track) ; track read or write depending upon OUT (Port.6),A ; that request code. It first seeks LD A,12H ; the specified track without loading CALL DSK14 ; the disk head. Then loads the DMA LD A,79H ; chip with the RAM address that will OUT (Port.0),A ; be used. A choice is then made to LD A,(IY+IOCS.DMA.Low) ; see if a read or a write is needed. OUT (Port.0),A ; If a read is needed DSK161 is jumped LD A,(IY+IOCS.DMA.High) ; to, if a write (format) is needed OUT (Port.0),A ; then DSK162 is jumped to. LD A,(IY+IOCS.Request) ; CP Format.Disk ; JR Z,DSK162 ; DSK161: ; LD HL,DSK20 ; Routine for read track. LD BC,0DH*100H+Port.0 ; OTIR ; LD A,0E4H ; JR DSK163 ; DSK162: ; Routine for write track. LD HL,DSK17 ; LD BC,0FH*100H+Port.0 ; OTIR ; LD A,0F4H ; DSK163: ; Carry on from here to see if there OUT (Port.3),A ; was an error during the operation. LD (DCF.Last.Command),A ; Save disk command temporarily. LD A,84H ; EX AF,AF' ; CALL CLRDMA ; Clean up after operation. BIT 6,A ; Was there a clean finish. RET Z ; Return if clean finish. JP DSK7 ; Take the error exit. subttl Data strings for DMA chip initialization page DSK12: ; Data string for multiple sector DEFB 0C3H,061H,000H,00DH ; disk read/write operation using the DEFB 014H,028H,0C7H,0CBH ; DMA chip. DEFB 095H,0E7H,012H,000H ; DEFB 0CFH,09AH,0ABH,0E0H ; DEFB 0CFH,087H ; DSK17: ; Data string for disk write track DEFB 0FFH,0FFH,014H,028H ; to DMA chip. DEFB 0C7H,0CBH,095H,0E7H ; DEFB 000H,09AH,0C0H ; DEFB 0CFH,005H,0CFH,087H ; DSK20: ; Data string for disk read track DEFB 0FFH,0FFH,014H,028H ; to DMA chip. DEFB 0C7H,0CBH,095H,0E7H ; DEFB 000H,09AH,0C0H ; DEFB 0CFH,087H ; DSK19: DEFB 0C3H,061H,07FH,000H ; Data string for single sector disk DEFB 014H,028H,0C7H,0CBH ; read/write operation using the DEFB 095H,0E7H,012H,000H ; DMA chip. DEFB 0CFH,09AH,0ABH,0E0H ; DEFB 0CFH,087H ; subttl Disk Error Processor Routine page ;****************************************************************************** ;* * ;* DISK Jump.Label.12 PROCESSING ROUTINE * ;* * ;****************************************************************************** ERROR1: PUSH AF ; SAVE REGISTER PAIRS. PUSH HL ; LD A,(DCF.Error.Mess) ; LOAD "A" WITH Jump.Label.12 CODE. RLA ; TEST FOR INVALID DRIVE, IOCS.Track, ; OR SECTOR. LD HL,MSG7 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR DISK NOT READY. LD HL,MSG6 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR IOCS.Track SEEK Jump.Label.12. LD HL,MSG5 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR SECTOR SEEK Jump.Label.12. LD HL,MSG4 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR CRC Jump.Label.12. LD HL,MSG3 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR DATA LOST Jump.Label.12. LD HL,MSG2 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR DISK WRITE PROTECT. LD HL,MSG1 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. RLA ; TEST FOR READ DELETED SECTOR Jump.Label.12. LD HL,MSG0 ; CALL C,Jump.Label.1 ; IF NEEDED, PRINT MESSAGE. CALL Jump.Label.14 ; GET AND DISPLAY DISK VITALS. POP HL ; RESTORE REGISTERS. POP AF ; RET ; RETURN TO CALLING PROGRAM. subttl Get and display disk vitals at time of the error page ;****************************************************************************** ;* * ;* DISPLAY DISK VITALS AT TIME OF DISK Jump.Label.12 * ;* * ;****************************************************************************** DSKST1: IN A,(Port.1) ; BRING IN DRIVE TYPE. LD (Error.Type),A ; SAVE DRIVE TYPE. BIT 5,A ; TEST TO SEE IF 8 INCH DRIVE. LD HL,EIGHT ; SET UP MESSAGE. JR NZ,STAT1$ ; IF IT IS AN 8 INCH DRIVE, SKIP. LD HL,FIVE ; SET UP MESSAGE. STAT1$: CALL Jump.Label.1 ; OUTPUT MESSAGE. BIT 0,A ; IS DRIVE SINGLE SIDED? LD HL,DOUBLE ; SET UP MESSAGE. JR NZ,STAT2$ ; IF IT IS DOUBLE SIDED, SKIP. LD HL,SINGLE ; SET UP MESSAGE. STAT2$: CALL Jump.Label.1 ; OUTPUT MESSAGE. IN A,(Port.2) ; BRING DRIVE SELECTED. LD (Error.Unit),A ; SAVE DRIVE SELECTION. RRA ; IS DRIVE 'A' SELECTED? JR NC,STAT3$ ; IF NOT, THEN SKIP. LD HL,ADRIVE ; SET UP MESSAGE. STAT3$: RRA ; IS DRIVE 'B' SELECTED? JR NC,STAT4$ ; IF NOT, THEN SKIP. LD HL,BDRIVE ; SET UP MESSAGE. STAT4$: RRA ; IS DRIVE 'C' SELECTED? JR NC,STAT5$ ; IF NOT, THEN SKIP. LD HL,CDRIVE ; SET UP MESSAGE. STAT5$: RRA ; IS DRIVE 'D' SELECTED? JR NC,STAT6$ ; IF NOT, THEN SKIP. LD HL,DDRIVE ; SET UP MESSAGE. STAT6$: CALL Jump.Label.1 ; OUTPUT MESSAGE. RRA ; WAS SIDE 1 SELECTED? LD HL,SIDE1 ; SET UP MESSAGE. JR NC,STAT7$ ; IF SO, THEN SKIP. LD HL,SIDE2 ; SET UP MESSAGE. STAT7$: CALL Jump.Label.1 ; OUTPUT MESSAGE. LD HL,STATUS ; OUTPUT PRESENT DISK STATUS. CALL Jump.Label.1 ; IN A,(Port.3) ; BRING IN STATUS. LD (Error.Status),A ; SAVE DISK STATUS. CALL Jump.Label.3 ; LD HL,TRCK ; OUTPUT PRESENT Track. CALL Jump.Label.1 ; IN A,(Port.4) ; BRING IN Track. LD (Error.Track),A ; SAVE Track. CALL Jump.Label.3 ; LD HL,SECT ; OUTPUT PRESENT SECTOR. CALL Jump.Label.1 ; IN A,(Port.5) ; BRING IN SECTOR. LD (Error.Sector),A ; SAVE SECTOR. CALL Jump.Label.3 ; RET ; RETURN TO CALLING PROGRAM. subttl DCF interrupt handlers page DSK80: ; Interrupt routine for DMA chip. PUSH AF ; LD A,0C3H ; OUT (Port.0),A ; POP AF ; EI ; RETI ; ; CLKISR: ; Interrupt routine for CTC3 channel. EI ; This is a null routine for now. RETI ; subttl Disk Controller Error Message Area page MSG7: DEFB Carriage.Return,Line.Feed,'Invalid drive, track or sector.',00 MSG6: DEFB Carriage.Return,Line.Feed,'Disk is not ready.',00 MSG5: DEFB Carriage.Return,Line.Feed,'Track seek error.',00 MSG4: DEFB Carriage.Return,Line.Feed,'Sector seek error.',00 MSG3: DEFB Carriage.Return,Line.Feed,'CRC error.',00 MSG2: DEFB Carriage.Return,Line.Feed,'Data lost.',00 MSG1: DEFB Carriage.Return,Line.Feed,'The disk is write protected.',00 MSG0: DEFB Carriage.Return,Line.Feed,'Attempt to read a deleted sector.',00 EIGHT: DEFB Carriage.Return,Line.Feed,'The drive is an 8 inch, ',00 FIVE: DEFB Carriage.Return,Line.Feed,'The drive is a 5 inch, ',00 SINGLE: DEFB 'single sided drive.',Carriage.Return,Line.Feed,00 DOUBLE: DEFB 'double sided drive.',Carriage.Return,Line.Feed,00 ADRIVE: DEFB 'Drive A, ',00 BDRIVE: DEFB 'Drive B, ',00 CDRIVE: DEFB 'Drive C, ',00 DDRIVE: DEFB 'Drive D, ',00 SIDE1: DEFB 'Side 1, ',00 SIDE2: DEFB 'Side 2, ',00 STATUS: DEFB 'Status = ',00 TRCK: DEFB ',Track = ',00 SECT: DEFB ',Sector = ',00 DEFB 'DCF Version 3.2',00 .dephase END Module.0.Start