A2>type mon20.z80 ; ; ; SB180 Monitor ; By Microfuture ; Copyright (c) Micromint, 1985 ; ; Name MON.Z80 ; Version # 2.0 ; Revision Alpha ( ) Beta ( ) Production (x) ; Date July 16, 1985 ; Type ZAS.COM, ZLINK.COM and PORTS.LIB required ; ; .HD64 ; Use HD64180 mnemonics .SALL ; Suppress macro expansion ; TRUE EQU 0FFH FALSE EQU 0 ; ; To make a debug version set DEBUG EQU TRUE then type ZAS MON;ZLINK MON ; The resulting MON.COM file executes at address 100h ; ; To make a ROM image set DEBUG EQU FALSE the type ZAS MON;ZLINK MON $R0 ; The resulting MON.COM file executes at address 0 ; DEBUG EQU FALSE ; TRUE=debug, FALSE=ROM ; ; RAM EQU 0FF00H ; Physical address 4FF00h ; .XLIST MACLIB PORTS.LIB ; HD64180 on-chip ports .LIST ; ; ;ASCII equates ; CR EQU 0DH ; Carriage Return LF EQU 0AH ; Line feed BS EQU 08H ; Back space DEL EQU 7FH ; Delete BELL EQU 7 ; Bell ; ; ;Program start - enter from RESET or bad opcode TRAP ; ; START: DI ; Disable all interrupts IN0 A,(ITC) ; See if reset or trap LD B,A AND 3FH ; Mask trap flag OUT0 (ITC),A ; And clear BIT 7,B ; See if trap JR Z,NOTRAP ; No - must be reset LD HL,TRAPER ; Else CALL PRINTF ; Print trap error message NOTRAP: ; Reset entry IM 1 ; Interrupt Mode 1 JR BEYOND ; BAUDLIST: DEFW 600H ; 600 baud DEFW 1200H ; 1200 baud DEFW 2400H ; 2400 baud DEFW 4800H ; 4800 baud DEFW 9600H ; 9600 baud DEFW 9200H ; 19200 baud DEFW 8400H ; 38400 baud ; ; BEYOND: ; IF DEBUG LD HL,BREAK LD (31H),HL ; RST6 for debug LD A,0C3H ; Poke a jump LD (30H),A ELSE JR SKIP DS 30H-$ ; Filler to RST6 vector BRK: JP BREAK ; Breakpoint entry DS 38H-$ INT: JP INTERR ; NMI*, INT0*, RST7 ; SKIP: ENDIF ; JR RESET ; ; ; ;System start-up parameters ; STARTBYTE: DEFB 0FFH ; 0FFh=autosense,autoboot CA0: DEFB 64H ; CNTLA0 = 8 data, 1 stop, no parity, RTS0* low CA1: DEFB 74H ; CNTLA1 = " " ", disable ext.clock CB0: DEFB 0BH ; CNTLB0 = 1200 baud aux: CB1: DEFB 2 ; CNTLB1 = 9600 baud con: S0: DEFB 0 ; STAT0 = interrupts disabled S1: DEFB 4 ; STAT1 = interrupts disabled, CTS1* enabled DC: DEFB 6CH ; 1 memory, 3 i/o wait states (ls 4 bits must be C) RC: DEFB 82H ; 2 clock refresh every 40 clocks SPCF1: DEFB 0AFH ; 9266 srt/hut (12ms step) SPCF2: DEFB 2EH ; 9266 hlt/nd (nd must be 0) ; ; CSTMSG: DEFB 'Micromint SB180 Monitor',CR,LF DEFB 'Version 2.0 - By Microfuture',CR,LF DEFB 'Copyright (c) Micromint, 1985',CR,LF DEFB '(Enter ? for help)',CR,LF,CR,LF,0 ; ; RESET: ; ;set up interrupt table address ; LD DE,INTTBL ; Point to interrupt table LD A,D ; Ms table address LD I,A OUT0 (IL),E ; Ls table address ; ;delay for power up sequence ; LD B,2 STALL1: LD HL,0 STALL2: DEC HL LD A,H OR L JR NZ,STALL2 DJNZ STALL1 ; ;initialize on-chip I/O devices ; ;ASCI channel 0 - auxillary port ;ASCI channel 1 - console port ; LD HL,CA0 ; Initialize LD C,CNTLA0 ; First six LD B,6 ; Registers OTIMR ; ; ;CSI/O - TXS used for disk motor control ; LD A,0 OUT0 (CNTR),A ; Interrupt mask ; ;PRT Timers ; LD A,0 OUT0 (TCR),A ; Disable timers ; ;Centronics port ; OUT (CENTDC),A ; Clear latch ; ;DMAC Channels - ch.0 available, ch.1 for FDC ; OUT0 (DSTAT),A ; Disable dma LD A,2 OUT0 (DMODE),A ; Ch.0 = memory <-> memory mode LD A,(HL) ; Ch.1 = i/o <-> memory OUT0 (DCNTL),A ; 1 memory, 4 i/o wait states ; ; ;DRAM refresh control ; INC HL LD A,(HL) ; Enable dram refresh OUT0 (RCR),A ; 2 clock refresh every 40 clock cycles ; ;Interrupt control ; LD A,7 OUT0 (ITC),A ; Int0,1,2 enabled ; ; ;MMU - initialize to point to first RAM bank ; IF NOT DEBUG LD A,0F8H ; Initially assume 27256 ROM OUT0 (CBAR),A ; Rom in common area 0 LD A,40H ; Ram physically at 40000h OUT0 (BBR),A ; Ram in bank area OUT0 (CBR),A ; Ram in common area 1 ; ELSE LD A,4 LD (DMABNK),A ENDIF ;Initial variables ; LD HL,0FFFFH LD B,255 RAMINIT: ; Null cycles to warm up RAMs LD A,(HL) DEC HL DJNZ RAMINIT ; IF NOT DEBUG LD A,4 ; Initial bank 0 LD (DMABNK),A OUT (FDCDT),A ; Clean up FDC ENDIF LD A,0 LD HL,CONFLG LD (HL),A ; Console is asci ch.1 INC HL LD (HL),A ; Printer echo is off INC HL LD (HL),A ; Printer is centronics LD (PARAMC),A ; Drive 0 for auto boot LD (MOTOR),A ; Disk motor marked as off LD A,0FFH LD (PRNSTAT),A ; Centronics not busy LD HL,0 LD (OLDST),HL ; Set up D command start address ; ; ;Check RAM for stack LD HL,0FFFFH STEST: LD A,(HL) ; Read potential stack LD B,A ; Save it CPL ; Complement LD (HL),A ; Write LD A,(HL) ; Reread CPL ; Recomplement LD (HL),A ; Rewrite CP B ; Compare JR NZ,BADBITS ; Not =, report fail DEC L ; Else, dec count LD A,0 OR L ; One page done ? JP Z,STACKOK ; Yes, continue JR STEST ; No, keep checking ; BADBITS: XOR B ; Different - isolate bad chips LD C,A ; Save bad chip mask LD A,(STARTBYTE) ; Baud rate specified or autosense ? AND 0F0H JR Z,BSIGNON ; Skip Autosense ; BADBITS1: IN0 A,(STAT1) ; If bits bad, determine baud rate AND 80H JR NZ,BADBITS2 ; LD A,H ; If H=0 CP 0 ; Then here from BAUDLOOP: ; IF NOT DEBUG JP Z,FDBOOT ; So go back and check disk again ENDIF ; JR BADBITS1 ; Otherwise (bad RAM) keep waiting BADBITS2: IN0 A,(RDR1) ; Get keypress AND 7FH CP CR ; If 'cr', then 9600 JR Z,BSIGNON1 LD B,1 CP 'r' ; If 'r', then 19200 JR Z,BSIGNON LD B,4 CP 'x' ; If 'x', then 2400 JR Z,BSIGNON LD B,3 CP 'f' JR Z,BSIGNON LD B,0 ; Else 300 or 1200 BBAUD1: DJNZ BBAUD1 ; Wait for UART clear LD A,5 OUT0 (CNTLB1),A ; Set 1200 LD B,2 ; May have to check twice BBAUD2: IN0 A,(STAT1) ; Check for keypress AND 80H JR Z,BBAUD2 IN0 A,(RDR1) AND 7FH DJNZ BBAUD2 ; Try again CP CR ; Is it CR ? JR Z,BSIGNON1 ; Yes, then 1200 LD B,0DH ; No, then 300 ; ; ; BSIGNON: ; Baud rate known OUT0 (CNTLB1),B ; Set baud rate BSIGNON1: LD A,H ; Was previous routine 'called' CP 0FFH JP NZ,SIGNON ; Yes, so 'return' LD A,C ; Restore bad bits mask LD B,8 ; 8 chips OR A ; Clear carry BBITS1: LD A,C ; Get bad chip mask RLC A ; Check a bit LD C,A ; Save bad chip mask JR NC,PZERO ; Chip OK LD D,'1' ; Chip bad - set up 'one' JR PONE PZERO: LD D,'0' ; Chip OK - set up 'zero' PONE: IN0 A,(STAT1) AND 2 JR Z,PONE ; Loop until UART ready OUT0 (TDR1),D ; Print zero DJNZ BBITS1 ; Check 8 bits LD D,CR ; Then print CRLF PCR: IN0 A,(STAT1) AND 2 JR Z,PCR ; Wait until UART ready OUT0 (TDR1),D ; Print cr LD D,LF PLF: IN0 A,(STAT1) AND 2 JR Z,PLF ; Wait until UART ready OUT0 (TDR1),D ; Print lf HALT ; Wait for another reset ; STACKOK: ; Ram ok, set up stack LD SP,0 ; And set up stack ; ; IF NOT DEBUG ROMCHECK: ; Check size of ROM LD HL,4000H ; Check if 27256 CALL CP256 JR NZ,ROM256 ; 27256 installed LD HL,2000H ; Check if 27128 CALL CP256 JR NZ,ROM128 ; 27128 installed LD A,0F2H ; Mark as 2764 JR RAMCHECK ROM128: LD A,0F4H ; Mark as 27128 JR RAMCHECK ROM256: LD A,0F8H ; Mark as 27256 ; RAMCHECK: LD (ROMSIZE),A LD A,0F2H ; Only 8K bytes for monitor OUT0 (CBAR),A ; LD A,2 ; Micromint is always 256K RAM JR MEMDONE ; ; CP256: ; Compare 256 bytes at (HL) with (0-FFh) LD DE,0 ; Point to (0) LD B,0FFH ; Check 256 bytes CPLOOP: LD A,(DE) ; Read at (0) LD C,(HL) ; Read at (HL) CP C ; Same JR NZ,CPEND ; No - quit INC HL ; Yes - increment pointers INC DE DJNZ CPLOOP ; And keep checking CPEND: RET ; MEMDONE: LD (RAMSIZE),A ; Save RAM size indicator ; ; ELSE ; LD A,0F2H LD (ROMSIZE),A LD A,2 LD (RAMSIZE),A ; ENDIF ; ; ;FDC (9266) initialize ; IF DEBUG ; CALL BSYCK ; Busy, seek check LD A,3 ; Specify command OUT (FDCDT),A CALL CBUSY ; Rqm, dio check LD A,(SPCF1) ; Srt, hut OUT (FDCDT),A CALL CBUSY LD A,(SPCF2) ; Hlt, nd OUT (FDCDT),A ; LD A,0 LD (DRIVE),A JP BAUDLOOP ENDIF ; IF NOT DEBUG LD B,8 ; If 9266 doesn't RESET FDCFIX: IN A,(FDCDT) ; Try CALL FDCDLY ; To IN A,(FDCSTS) ; Fix CP 80H ; It JR Z,FDCSPEC ; If OK, continue DJNZ FDCFIX JR BADFDC ; Otherwise show FDC error ; FDCDLY: PUSH BC LD B,255 FDCDLY1: DJNZ FDCDLY1 POP BC RET ; FDCFAIL: DB 'FDC Error !',BELL,CR,LF,0 FDCSPEC: CALL FDCDLY ; Stall >12us CALL BSYCK ; Busy, seek check LD A,3 ; Specify command OUT (FDCDT),A CALL CBUSY ; Rqm, dio check LD A,(SPCF1) ; Srt, hut OUT (FDCDT),A CALL CBUSY LD A,(SPCF2) ; Hlt, nd OUT (FDCDT),A ; LD A,0 LD (DRIVE),A ; LD A,(STARTBYTE) ; Check autoboot AND 0FH JR Z,BAUDLOOP ; No, sign-on monitor FDBOOT: CALL DRDY ; If disk drive is ready JP NZ,COLDS ; Then boot disk JR BAUDLOOP ; Else try to find baudrate and sign-on ; BADFDC: LD A,3BH OUT0 (ITC),A ; Mask FDC interrupts LD HL,FDCFAIL ; Point to FDC failure message JP BADBITS ; 'Call' baud rate sense routine ; 'Returns' to SIGNON ; ENDIF ; DELAY10MS: IN0 A,(TCR) AND 0FEH OUT0 (TCR),A ; Stop timer LD A,0CH OUT0 (TMDR0L),A OUT0 (TMDR0H),A ; 0C0CH*20*163ns approx.=10ms IN0 A,(TCR) OR 1 OUT0 (TCR),A ; Restart timer D10LOOP: IN0 A,(TCR) BIT 6,A ; Timeout ? JR Z,D10LOOP ; No, keep waiting IN0 A,(TMDR0L) ; Reset timer int flag IN0 A,(TMDR0H) ; By reading data registers DJNZ DELAY10MS ; Yes, do it B times RET ; BAUDLOOP: LD HL,CSTMSG ; Point to sign-on message JP BADBITS ; 'Call' baud rate sense routine ; 'Returns' to SIGNON ; ; SIGNON: LD B,10 CALL DELAY10MS ; Delay to clear UART IN0 A,(RDR1) ; After 'return' from autosense ; CALL PRINTF ; Print sign-on ; LD HL,ROMMES CALL PRINT LD HL,SIZEMES ; Print ROM size CALL PRINT LD A,(ROMSIZE) LD HL,ROM8MES ; ROM is 2764 CP 0F2H JR Z,RAMS1 ROMS1: LD HL,ROM16MES ; ROM is 27128 CP 0F4H JR Z,RAMS1 ROMS2: LD HL,ROM32MES ; ROM is 27256 ; RAMS1: CALL PRINT LD HL,BYTEMES CALL PRINT LD HL,RAMMES CALL PRINTF ; Print RAM size LD HL,SIZEMES CALL PRINT ; LD A,(RAMSIZE) ; LD HL,RAM64MES ; CP 0 ; JR Z,STACKIT ;RAMS2: ; LD HL,RAM128MES ; CP 1 ; JR Z,STACKIT RAMS3: LD HL,RAM256MES JR STACKIT ; ROMMES: DEFB 'ROM',0 ROM8MES: DEFB '8',0 ROM16MES: DEFB '16',0 ROM32MES: DEFB '32',0 RAMMES: DEFB 'RAM',0 RAM64MES: ; DEFB '64',0 RAM128MES: ; DEFB '128',0 RAM256MES: DEFB '256',0 BYTEMES: DEFB 'K bytes',0 SIZEMES: DEFB ' size = ',0 ; ; STACKIT: CALL PRINT LD HL,BYTEMES CALL PRINT CALL PUTCR CALL PUTCR LD HL,0 PUSH HL ; PC LD (SAVEPC),SP ; Save pointer to stacked PC LD B,10 STACKLOOP: PUSH HL ; Fill stack with 0's DJNZ STACKLOOP LD (SAVESP),SP ; Save pointer to stack frame ; ; HSTART: LD SP,0FFEAH EI ; Interrupts enabled LD A,0 ; Turn disk motor LD (MOTOR),A ; Off OUT0 (TRDR),A ; By setting TXS low LD A,10H ; And OUT0 (CNTR),A ; Enabling Tx LD A,(DMABNK) ADD A,2CH ; Make bank#0-3 ascii CALL PUTC LD A,'>' ; Command line prompt CALL PUTC CALL SCANF ; Receive command line LD A,(COMLINE) CALL AZLCNV ; Convert to uppercase OR A ; No command, then restart JR Z,HSTART LD B,A ; Save command LD HL,COMTBL ; Point to command table NEXTCOM: LD A,(HL) ; Check command OR A ; 0 = command not in table JR Z,NOTFINE ; Thus, bad command CP B ; Is this the one ? JR Z,FINECOM ; Yes - do it. INC HL ; Else INC HL ; Point to next INC HL ; Command table entry JR NEXTCOM ; And keep searching FINECOM: INC HL ; Command address low byte LD E,(HL) INC HL ; Command address high byte LD D,(HL) EX DE,HL ; Hl = command address JP (HL) ; Execute command ; NOTFINE: CALL COMERR ; Bad command ; MONJP: CALL PUTCR ; Print cr JR HSTART ; And reenter monitor ; ;Initialize disk parameter table ; ; ;Command Table ; COMTBL: DEFB CR DEFW MONJP ; Cr DEFB 'S' DEFW SCOM ; Set memory DEFB 'D' DEFW DCOM ; Display memory DEFB 'G' DEFW GCOM ; Goto (execute) program DEFB 'I' DEFW ICOM ; Input i/o port DEFB 'O' DEFW OCOM ; Output i/o port DEFB 'U' DEFW LCOM ; Upload hex format DEFB 'Z' DEFW BCOM ; Boot disk DEFB 'R' DEFW RCOM ; Read disk sector(s) DEFB 'W' DEFW WCOM ; Write disk sector(s) DEFB 'K' DEFW FCOM ; Format disk DEFB 'C' DEFW COPY ; Copy disk DEFB 'M' DEFW MOVE ; Move memory DEFB 'F' DEFW FILL ; Fill memory DEFB 'V' DEFW VERIFY ; Verify memory DEFB 'H' DEFW HEXMATH ; Hex math DEFB '?' DEFW HELP ; Help command DEFB 'A' DEFW ASCII ; Ascii table DEFB 'Q' DEFW QUERY ; Query memory DEFB 'T' DEFW TEST ; Test memory DEFB 'B' DEFW MBANK ; Position memory bank (mmu) DEFB 'P' DEFW PRINTER ; Select printer port DEFB 'Y' DEFW YANK ; Yank I/O registers DEFB 'X' DEFW REGS ; Display/modify CPU registers DEFB 'N' DEFW NEW ; New command DEFB 'E' DEFW EMULATE ; Emulate terminal ; DEFB 0 ; End of command table ; ; ;Monitor command routines ; ; EMULATE: LD A,(PARAMC) ; Check parm count CP 1 ; Baud rate ? JR C,EML0 ; Not changed LD HL,(PARAM1) ; Else, get baud rate LD DE,150H ; 150 baud ? CALL SBCHD JR NZ,EB1 LD A,0EH ; Yes OUT0 (CNTLB0),A JR EML0 EB1: LD DE,300H ; 300 baud ? CALL SBCHD JR NZ,EB2 LD A,0DH ; Yes OUT0 (CNTLB0),A JR EML0 EB2: LD B,7 ; Check six more baud rates LD IX,BAUDLIST EBLOOP: LD E,(IX) ; Baud rate to INC IX LD D,(IX) ; DE INC IX CALL SBCHD ; Match ? JR Z,EMLBAUD ; Yes, continue DJNZ EBLOOP ; No, keep checking JP BPARMERR ; If here, invalid baud rate ; ; EMLBAUD: DEC B OUT0 (CNTLB0),B ; Set baud rate ; EML0: LD HL,EMMES ; Prompt for exit char CALL PRINTF EML1: CALL CONST1 JR Z,EML1 CALL GET1 LD D,A ; Save it in D CALL PUTCR EMLOOP: CALL CONST1 ; Outgoing char ? JR Z,EM1 ; No, check incoming char CALL GET1 ; Yes, get it CP D ; Exit char ? JP Z,MONJP ; Yes, exit LD C,A ; No, CALL PUT0 ; Send it out EM1: CALL CONST0 ; Incoming char ? JR Z,EMLOOP ; No, check outgoing char CALL GET0 ; Yes, get it LD C,A CALL PUT1 ; Print on console JR EMLOOP ; ; GET0: IN0 A,(RDR0) ; ASCI 0 to A JR GET11 ; GET1: IN0 A,(RDR1) ; ASCI 1 to A GET11: AND 7FH RET ; PUT0: IN0 A,(STAT0) ; A to ASCI 0 AND 2 JR Z,PUT0 OUT0 (TDR0),C RET ; PUT1: IN0 A,(STAT1) ; A to ASCI 1 AND 2 JR Z,PUT1 OUT0 (TDR1),C RET ; EMMES: DEFB 'Enter quit key ',0 ; ; NEW: LD A,(PARAMC) ; Check number of parms CP 0 ; If 0 JR Z,NEW1 ; Then continue LD A,(PARAM1) ; Else parm to A NEW1: LD C,A ; Save in C LD A,(ROMSIZE) ; Check ROMSIZE CP 0F2H ; If 8KB JR Z,NEW2 ; Then new command in RAM IF NOT DEBUG OUT0 (CBAR),A ; Else bring in extended ROM LD A,(2000H) ; Check if ROM programmed CP 0FFH JR NZ,NEW2 ; Yes, continue LD A,0F2H ; No, pretend it's RAM OUT0 (CBAR),A ENDIF NEW2: LD A,C ; Parm to A IF DEBUG CALL 2100H ; Call extended command ELSE CALL 2000H ENDIF LD A,0F2H ; Upon return IF NOT DEBUG OUT0 (CBAR),A ; Hide extended ROM ENDIF JP MONJP ; ; REGS: ; Display and modify CPU regs LD HL,XMES ; Print reg names CALL PRINTF CALL PUTCR LD IX,(SAVESP) ; Point to stack frame ; CALL XF ; Get flags CALL PUTB ; Print binary CALL PUTSP CALL XA ; Get a CALL XP6 ; Print hex CALL XBC ; Get bc CALL XP5 ; Print hex CALL XDE ; Get de CALL XP5 ; Print hex CALL XHL ; Get hl CALL XP5 ; Print hex CALL XIX ; Get ix CALL XP5 ; Print hex CALL XIY ; Get iy CALL XP5 ; Print hex CALL XSP ; Get sp CALL XP5 ; Print hex CALL XPC ; Get pc CALL ASCDP4 ; Print hex CALL PUTCR ; CALL XAF ; Get flags' CALL PUTB ; Print binary CALL PUTSP CALL XAA ; Get a' CALL XP6 ; Print hex CALL XABC ; Get bc' CALL ASCDP4 ; Print hex CALL PUTSP CALL XADE ; Get de' CALL ASCDP4 ; Print hex CALL PUTSP CALL XAHL ; Get hl' CALL ASCDP4 ; Print hex CALL PUTCR ; LD HL,AMES ; Prompt a CALL PRINT CALL XA ; Get a CALL XP6 ; Print binary CALL XP2 JR Z,X1 ; Then next reg CALL XP3 LD (IX+19),E ; Store A in stack frame X1: LD HL,BCMES ; Prompt bc CALL PRINT CALL XBC ; Get bc CALL XP1 JR Z,X2 ; Then next reg CALL XP3 LD (IX+16),E ; Store C in stack frame LD (IX+17),D ; Store B in stack frame X2: LD HL,DEMES ; Prompt de CALL PRINT CALL XDE ; Get de CALL XP1 JR Z,X3 CALL XP3 LD (IX+14),E ; Store E in stack frame LD (IX+15),D ; Store D in stack frame X3: LD HL,HLMES ; Prompt hl CALL PRINT CALL XHL ; Get hl CALL XP1 JR Z,X4 ; Then next reg CALL XP3 LD (IX+12),E ; Store L in stack frame LD (IX+13),D ; Store H in stack frame X4: LD HL,IXMES ; Prompt IX CALL PRINT CALL XIX ; Get IX CALL XP1 JR Z,X5 ; Then next reg CALL XP3 LD (IX+10),E ; Store ix(l) in stack frame LD (IX+11),D ; Store ix(h) in stack frame X5: LD HL,IYMES ; Prompt iy CALL PRINT CALL XIY ; Get iy CALL XP1 JR Z,X6 ; Then next reg CALL XP3 LD (IX+8),E ; Store iy(l) in stack frame LD (IX+9),D ; Store iy(h) in stack frame X6: LD HL,PCMES ; Prompt PC CALL PRINT CALL XPC ; Get PC CALL XP1 JR Z,X7 ; Then done CALL XP3 LD HL,(SAVEPC) LD (HL),E ; Store pc(l) in stack frame INC HL LD (HL),D ; Store pc(h) in stack frame X7: JP MONJP ; XP1: CALL XP5 ; Print contents XP2: CALL GETLINE ; Get new contents LD A,(CONBUF) CP 0 ; Ret Z if no change RET ; XP3: CP '.' ; Check terminator JR Z,XP4 LD HL,CONBUF CALL ATOI ; ASCII to hex RET XP4: POP HL JP MONJP XP5: CALL ASCDP4 ; Print hex XP51: CALL PUTSP ; And a space RET XP6: CALL BTOA JR XP51 ; XF: LD A,(IX+18) ; Flags RET XA: LD A,(IX+19) ; A RET XBC: LD L,(IX+16) ; C LD H,(IX+17) ; B RET XDE: LD L,(IX+14) ; E LD H,(IX+15) ; D RET XHL: LD L,(IX+12) ; L LD H,(IX+13) ; H RET XIX: LD L,(IX+10) ; IX(L) LD H,(IX+11) ; IX(H) RET XIY: LD L,(IX+8) ; IY(L) LD H,(IX+9) ; IY(H) RET XSP: LD HL,(SAVESP) ; SP RET XPC: LD HL,(SAVEPC) ; PC LD E,(HL) ; E = pc(l) INC HL LD D,(HL) ; D = pc(h) PUSH DE POP HL ; Hl = pc RET XAF: LD A,(IX+6) ; Flags' RET XAA: LD A,(IX+7) ; A' RET XABC: LD L,(IX+4) ; C' LD H,(IX+5) ; B' RET XADE: LD L,(IX+2) ; E' LD H,(IX+3) ; D' RET XAHL: LD L,(IX) ; L' LD H,(IX+1) ; H' RET ; ; MBANK: ; Position memory command LD A,(PARAMC) ; Check parm count CP 1 ; Less than 1 JP C,NPARMERR LD A,(PARAM1) ; Get bank# (0-3) AND 3 ; Mask ADD A,4 ; Make real bank# (4-7) LD (DMABNK),A ; Save for disk dma SLA A ; Build SLA A ; Bank SLA A ; Base SLA A ; IF NOT DEBUG OUT0 (BBR),A ; Reconfigure mmu ENDIF JP MONJP ; ; TEST: LD A,(PARAMC) ; How many parms ? CP 0 ; 0, then memory test JP Z,MTEST LD A,(PARAM1) ; >0, then check device CP 0AH ; AUX: ? JP Z,ATEST ; Then AUX: test CP 0CH ; CEN: ? JP Z,CTEST ; Then CEN: test CP 0DH ; DSK: ? JR Z,DTEST ; Then DSK: test JP BPARMERR ; Else no good ; DTEST: LD A,(PARAMC) ; Disk test CP 2 ; Check for disk number JP C,NPARMERR ; None, then no good DTEST1: LD A,(PARAM2) ; Get disk number AND 3 ; Mask it LD (DRIVE),A ; Into drive CALL CREADY ; Wait drive ready CALL DLOGIN LD A,0FFH ; Track 0 - 1 LD (PARAM2),A LD A,(DTYPE) LD (PARAM4),A ; Last track + 1 SRL A LD B,A ; Loop count = #tracks / 2 DTLOOP: LD A,(PARAM2) INC A ; Step out track LD (PARAM2),A CALL DTEST2 LD A,(PARAM4) ; Step in track DEC A LD (PARAM4),A CALL DTEST2 DJNZ DTLOOP JP MONJP ; DLOGIN: LD A,0 ; Home drive LD (TRACK),A CALL SEKRCL CALL DISKTYPE ; Determine disk type RET ; DTEST2: LD (TRACK),A CALL CREADY CALL SEEK ; Seek there LD A,0C6H LD (FDCOMMAND),A ; Read command IF DEBUG LD HL,2100H ; Buffer address ELSE LD HL,2000H ENDIF LD (PARAM3),HL CALL RWT ; Read the cylinder RET ; ; ATEST: LD HL,ATESTMES ; AUX: port test CALL PRINTF CALL GETCHA PUSH AF CALL PUTC CALL PUTCR POP AF CALL AZLCNV CP 'I' ; Input or output test ? JP Z,ATESTI ; Input CP 'O' JR NZ,ATEST ; Output ; CTEST: LD A,' '-1 ; Start with blank CTEST1: PUSH AF CALL TBRAKE ; Check console abort POP AF INC A CP 'P' ; End of line ? CALL Z,CCRLF ; Yes, print crlf CP '~' ; Last test pattern JR NZ,CTEST2 CALL CCRLF JR CTEST CTEST2: LD B,A LD A,(PARAM1) CP 0AH ; Test AUX: ? CALL Z,AOUT LD A,(PARAM1) CP 0CH ; Test CEN: CALL Z,COUT LD A,B JR CTEST1 ; COUT: LD A,(PRNSTAT) ; A to CEN: OR A JR NZ,COUT1 ; Wait for printer PUSH BC LD B,20 DLY5: ; Wait about 5 seconds IN0 A,(TCR) AND 0FEH ; Stop timer OUT0 (TCR),A IN0 A,(TMDR0L) IN0 A,(TMDR0H) LD A,0FFH OUT0 (TMDR0L),A ; Init timer OUT0 (TMDR0H),A IN0 A,(TCR) OR 1 ; Restart timer OUT0 (TCR),A DLYLOOP: LD A,(PRNSTAT) OR A JR NZ,DLYEND ; Printer ready IN0 A,(TCR) ; Printer not ready BIT 6,A ; Timeout ? JR Z,DLYLOOP ; No, keep trying POP HL CALL TBRAKE PUSH HL DJNZ DLY5 ; LD HL,NOACKMES ; Timed out CALL PRINTF POP BC JR COUT ; Try some more ; DLYEND: POP BC COUT1: LD A,0 ; Printer ready LD (PRNSTAT),A ; Mark as busy LD A,B DI OUT (CENTDS),A ; Out data, assert STB OUT (CENTDC),A ; Clear STB EI RET AOUT: IN0 A,(CNTLA0) AND 0EFH ; Assert RTS OUT0 (CNTLA0),A AOUT1: IN0 A,(CNTLB0) ; Check status LD C,A BIT 5,A ; Check CTS JR Z,AOUT2 LD HL,CTSMES ; No CTS CALL PRINTF CALL TBRAKE JR AOUT1 AOUT2: IN0 A,(STAT0) BIT 1,A JR Z,AOUT1 OUT0 (TDR0),B ; Out test data IN0 A,(CNTLA0) OR 10H ; Turn off RTS OUT0 (CNTLA0),A LD A,B RET ; CCRLF: PUSH AF LD A,CR ; Print cr LD B,A LD A,(PARAM1) CP 0AH ; AUX: ? CALL Z,AOUT LD A,(PARAM1) CP 0CH ; CEN: ? CALL Z,COUT LD A,LF ; Print lf LD B,A LD A,(PARAM1) CP 0AH ; AUX: ? CALL Z,AOUT LD A,(PARAM1) CP 0CH ; CEN: ? CALL Z,COUT POP AF RET ; ATESTI: CALL TBRAKE IN0 A,(STAT0) ; Updates DCD status IN0 A,(STAT0) ; Check DCD BIT 2,A JR Z,ATESTI1 LD HL,DCDMES ; No DCD CALL PRINTF JR ATESTI ; Wait for DCD ATESTI1: PUSH AF CALL TBRAKE POP AF BIT 7,A JR Z,ATESTI IN0 A,(RDR0) ; In test data CALL PUTC ; To console JR ATESTI ; ATESTMES: DEFB 'Input or Output (I or O) ? ',0 CTSMES: DEFB 'CTS0* HIGH',0 DCDMES: DEFB 'DCD0* HIGH',0 NOACKMES: DEFB 'No ACK*',0 ; ; ; MTEST: ; Memory Test LD A,0 ; Start at 40000h OUT0 (SAR0H),A OUT0 (SAR0L),A OUT0 (BCR0H),A INC A OUT0 (BCR0L),A ; 1 byte at at time IF DEBUG LD A,6 ELSE LD A,4 ; Start bank ENDIF OUT0 (SAR0B),A OUT0 (DAR0B),A IF DEBUG LD HL,4000H ELSE LD HL,TSTBYTE ; Test data holder ENDIF OUT0 (DAR0H),H ; Point DMAC OUT0 (DAR0L),L PUSH HL POP IX ; MTLOOP: CALL TBRAKE LD A,60H LD C,A LD A,2 OUT0 (DMODE),A OUT0 (DSTAT),C ; Read memory LD A,(IX) ; Save it LD B,A CPL ; Complement LD (IX),A CALL FIXUP1 ; Bump DMAC CALL ROLLS ; Check bank rollover CALL MSWITCH ; Switch DMAC direction LD A,2 OUT0 (DMODE),A OUT0 (DSTAT),C ; Write memory CALL FIXUP1 ; Bump DMAC CALL MSWITCH ; Switch DMAC direction CALL ROLLS ; Check bank rollover OUT0 (DMODE),A OUT0 (DSTAT),C ; Read memory LD A,(IX) CPL ; Complement LD (IX),A PUSH AF CALL FIXUP1 ; Bump DMAC POP AF CP B ; OK ? CALL NZ,MERR ; No, inform error CALL ROLLS ; Check bank rollover CALL MSWITCH ; Switch DMAC direction LD A,2 OUT0 (DMODE),A OUT0 (DSTAT),C ; Write memory CALL FIXUP2 ; Bump DMAC CALL MSWITCH ; Switch DMAC direction IN0 A,(SAR0B) ; Done ? CP 8 JR NZ,MTLOOP LD A,'.' ; Yes, print a '.' CALL PUTC JP MTEST ; Test forever ; ROLLS: PUSH AF IN0 A,(SAR0H) IN0 L,(SAR0L) AND L CP 0FFH ; Bank rollover ? JR NZ,ROLLEND ; No, return IN0 A,(SAR0B) ; Yes DEC A ; Back up bank OUT0 (SAR0B),A ROLLEND: POP AF RET ; FIXUP1: IN0 L,(DAR0L) IN0 H,(DAR0H) DEC HL ; Back up destination OUT0 (DAR0L),L OUT0 (DAR0H),H FIXUP2: IN0 L,(SAR0L) IN0 H,(SAR0H) DEC HL ; Back up source OUT0 (SAR0L),L OUT0 (SAR0H),H RET ; MSWITCH: PUSH AF PUSH BC IN0 B,(SAR0L) IN0 C,(DAR0L) OUT0 (SAR0L),C ; Switch source and destination OUT0 (DAR0L),B IN0 B,(SAR0H) IN0 C,(DAR0H) OUT0 (SAR0H),C OUT0 (DAR0H),B IN0 B,(SAR0B) IN0 C,(DAR0B) OUT0 (SAR0B),C OUT0 (DAR0B),B LD A,1 ; Reload byte count OUT0 (BCR0L),A POP BC POP AF RET ; MERR: PUSH AF PUSH BC IN0 A,(SAR0B) ; Get error bank CP 4 ; If not in our data area JR NZ,MERR1 ; Then real error IN0 A,(SAR0H) CP 0FFH ; In range 4FF00-4FFFF JR NZ,MERR1 ; Yes, ignore POP BC POP AF RET MERR1: CALL PUTCR ; No, real error IN0 A,(SAR0B) ; Get error bank CALL BTOA ; Print bank address IN0 A,(SAR0H) ; Get error address high LD H,A IN0 A,(SAR0L) ; Get error address low LD L,A CALL ASCDP4 ; Print error address CALL PUTSP POP BC LD A,B LD (IX),A POP AF XOR B ; Isolate error bits CALL PUTB ; Print binary LD A,BELL ; And sound the bell CALL PUTC RET ; ; ; ; ; QUERY: ; Query memory command LD A,(PARAMC) ; Check parm count CP 1 ; Need at least one to search for JP C,NPARMERR LD HL,0 ; Search starting at 0 LD BC,0 ; For 64k bytes QLOOP: LD A,(PARAM1) ; Search for first data CPIR JP PO,MONJP ; Finished 64k LD A,(PARAMC) ; Found one CP 1 ; If more than one in search list JR NZ,QLOOP1 ; Then check more CALL QPRINT ; Otherwise print found address JR QLOOP ; And search some more QLOOP1: PUSH BC PUSH HL LD DE,PARAM2 ; Checking search list LD A,(PARAMC) ; Set up LD B,A ; Loop depending DEC B ; On how many parms QLOOP2: LD A,(DE) ; Get next parm CP (HL) ; Compare with memory JR NZ,QFAIL ; Search failed INC HL ; Point to next memory INC DE ; And next search byte INC DE DJNZ QLOOP2 ; Loop until all checked POP HL ; Success CALL QPRINT ; Print found address PUSH HL QFAIL: POP HL POP BC JR QLOOP ; Keep searching ; QPRINT: DEC HL ; Fixup found address CALL ASCDP4 ; Print it CALL PUTCR ; And a cr INC HL ; Restore search address CALL TBRAKE ; Check for console abort RET ; ; ASCII: LD HL,ASCMES ; Ascii table command CALL PRINT ; Print an ascii table JP MONJP ; HELP: LD HL,HELPMES ; Help command CALL PRINT ; Print a help message HELP1: CALL CONST1 JR Z,HELP1 IN0 A,(RDR1) AND 7FH CP CR JR NZ,HELP1 JP MONJP ; HEXMATH: ; Hex math command LD A,(PARAMC) CP 2 ; If less than 2 parms JP C,NPARMERR ; Then abort LD HL,MATHMES ; Print heading CALL PRINTF CALL PUTCR LD HL,(PARAM1) ; Operand 1 LD DE,(PARAM2) ; Operand 2 OR A ADD HL,DE ; Sum JR NC,H0 LD A,'1' CALL PUTC JR HPLUS H0: LD A,'0' CALL PUTC HPLUS: CALL ASCDP4 ; Print sum CALL PUTSP LD HL,(PARAM1) ; Operand 1 LD DE,(PARAM2) ; Operand 2 OR A ; Clear carry SBC HL,DE ; Difference JR NC,H1 LD A,'F' CALL PUTC JR HMINUS H1: LD A,'0' CALL PUTC HMINUS: CALL ASCDP4 ; Print difference ; ;16 bit unsigned multiply with 32 bit result ; LD DE,(PARAM1) ; Operand 1 LD BC,(PARAM2) ; Operand 2 LD H,C ; Copy LD L,E ; Operand 2 MLT HL ; Partial product LD (PARAM3),HL ; Lsw LD L,H ; Next digit LD H,0 LD A,B LD B,D MLT BC ; Partial product ADD HL,BC ; Combine LD B,A ; Next digit LD C,E MLT BC ; Partial product ADD HL,BC ; Combine LD (PARAM3+1),HL ; Lsw LD L,H ; Next digit LD H,0 RL H LD E,A MLT DE ; Partial product ADD HL,DE ; Combine LD (PARAM4),HL ; Msw CALL PUTSP LD HL,(PARAM4) ; Print msw CALL ASCDP4 LD HL,(PARAM3) ; Print lsw CALL ASCDP4 JP MONJP ; ; VERIFY: ; Verify memory command LD A,(PARAMC) ; If less than 3 parms CP 3 ; Then abort JP C,NPARMERR CALL PARSE ; Setup hl=source,bc=count LD DE,(PARAM3) ; De=destination VLOOP: LD A,(DE) ; Get destination data CPI ; Compare with source CALL NZ,NOMATCH ; Not =, then report INC DE ; Increment destination LD A,B ; Check OR C ; Count JR NZ,VLOOP ; More, then loop JP MONJP ; Else exit ; NOMATCH: ; Report non-matching address and data PUSH DE ; Save PUSH HL ; State PUSH AF ; As required CALL PUTCR ; Print cr DEC HL ; Fix source address CALL ASCDP4 ; Print source address CALL PUTSP ; And a space LD A,(HL) ; Get source data CALL BTOA ; Print source data LD HL,VERRMES CALL PRINT EX DE,HL ; Hl=destination address CALL ASCDP4 ; Print destination address CALL PUTSP ; And a space POP AF ; Restore destination data CALL BTOA ; Print destination data POP HL ; Restore POP DE ; State CALL TBRAKE ; Check for console abort RET ; ; FILL: ; Fill memory command LD A,(PARAMC) ; If less than 3 parms CP 3 ; Then abort JP C,NPARMERR CALL PARSE ; Check and set hl,bc FLOOP: LD A,(PARAM3) ; Fill data LD (HL),A ; Store data INC HL ; Next memory address DEC BC ; Decrement count LD A,C OR B ; Count=0 ? JR NZ,FLOOP ; No, keep filling JP MONJP ; Exit ; ; MOVE: ; Move memory command LD A,(PARAMC) CP 3 ; If less than 3 parms JP C,NPARMERR ; Then abort CALL PARSE ; Check and set hl,bc LD DE,(PARAM3) ; Destination to de LDIR ; Move it... JP MONJP ; Exit ; SCOM: ; Set memory command LD HL,(PARAM1) ; Address to set ; NEXTSET: CALL ASCDP4 ; Print address CALL PUTSP ; And a space LD A,(HL) ; Get memory CALL BTOA ; Convert to ascii and print CALL PUTSP ; And another space PUSH HL CALL GETLINE ; Get new data POP HL LD A,(CONBUF) ; No data entered CP 0 JR Z,NOTSETNEW ; Then skip to next address CP '.' ; '.' entered JR Z,ENDSET ; Then abort command PUSH HL LD HL,CONBUF ; New data CALL ATOI ; Convert to binary POP HL LD (HL),E ; And store in memory ; NOTSETNEW: INC HL ; Point to next memory address JR NEXTSET ; And loop ENDSET: JP MONJP ; Done ; ; DCOM: ; Display memory command LD HL,(PARAM1) ; Start address LD DE,(PARAM2) ; End address LD A,(PARAMC) ; How many parms ? CP 2 JR NC,DUMPST ; 2, then display CP 1 JR NC,NOENDAD ; 1, then dummy end address LD HL,(OLDST) ; 0, then start = previous end ; NOENDAD: LD D,H ; De = start address LD E,L LD BC,7FH ; Display 80h bytes ADD HL,BC EX DE,HL ; De = hl + 80h DUMPST: INC DE ; Save end address LD (OLDST),DE ; As next start address DEC DE LD B,0 ; Reset counter CALL ASCDP4 ; Print address DUMPNEXT: CALL PUTSP ; And a space LD A,(HL) ; Get data CALL BTOA ; Convert to ascii and print CALL TBRAKE ; Check for console abort INC B ; Increment counter CALL SBCHD ; Flags = hl - de INC HL CALL Z,DASCII ; Hl=de then display last data JP Z,MONJP ; And exit LD A,L ; Check for end of line AND 0FH JR NZ,DUMPNEXT ; No, keep displaying CALL DASCII ; Yes, display last data CALL PUTCR ; And go to new line JR DUMPST ; Keep displaying ; ; ;Breakpoint entry ; BREAK: ; Breakpoint ends up here LD (SAVEPC),SP ; Save PC pointer LD (SAVEHL),HL ; Save HL EX (SP),HL ; Get PC DEC HL ; Back it up EX (SP),HL ; Put PC PUSH AF ; AF PUSH BC ; BC PUSH DE ; DE LD HL,(SAVEHL) PUSH HL ; HL PUSH IX ; Ix PUSH IY ; Iy EXX EX AF,AF' PUSH AF ; Af' PUSH BC ; Bc' PUSH DE ; De' PUSH HL ; Hl' LD (SAVESP),SP ; Save pointer to stack frame LD DE,(BPADDR) ; Get user bp address LD HL,(SAVEPC) LD C,(HL) INC HL LD B,(HL) PUSH BC POP HL ; Get actual bp address CALL SBCHD ; Check if same JR NZ,BP1 ; No, then don't fixup LD A,(BPINST) ; Yes, get bp instruction LD (HL),A ; Put back in memory BP1: CALL PUTCR LD A,'@' CALL PUTC CALL PUTSP CALL ASCDP4 ; Print actual bp address JP MONJP ; ; ;GOTO command ; GCOM: LD A,(PARAMC) ; Check number of parms CP 0 JR Z,GO ; No parms, then go CP 1 JR NZ,G1 LD DE,(PARAM1) ; 1 parm, then LD HL,(SAVEPC) ; Point to pc LD (HL),E ; Set pc(l) INC HL LD (HL),D ; Set pc(h) JR GO ; And go G1: CP 2 JR NZ,G2 CALL GOB ; 2 parms, then check syntax LD HL,(PARAM2) ; Ok, then CALL SETBP ; Set the breakpoint JR GO ; And go G2: CP 3 JP NZ,BPARMERR CALL GOB ; 3 parms, then check syntax LD HL,(PARAM2) ; Ok, then CALL SETBP ; Set the breakpoint LD DE,(PARAM3) ; Get go address LD HL,(SAVEPC) LD (HL),E ; Set pc(l) INC HL LD (HL),D ; Set pc(h)...and go ; GO: LD SP,(SAVESP) ; Clean stack POP HL ; HL POP DE ; DE POP BC ; BC POP AF ; AF EX AF,AF' EXX POP IY ; IY POP IX ; IX POP HL ; HL' POP DE ; DE' POP BC ; BC' POP AF ; AF' RET ; To stacked pc ; GOB: PUSH AF LD A,(PARAM1) ; Check if CP 0BH ; B syntax ok JP NZ,GOBAD ; Bad command POP AF RET ; GOBAD: POP AF ; Fixup stack JP BPARMERR ; And report error ; SETBP: PUSH AF LD A,(HL) ; Get bp instruction LD (BPINST),A ; And save it LD (BPADDR),HL ; Save bp address LD A,0F7H ; RST6 LD (HL),A ; Set bp POP AF RET ; ; ;INPUT Command ; ICOM: LD A,(PARAMC) ; Check number of parms CP 1 ; Less than 1 JP C,NPARMERR ; Then abort LD HL,(PARAM1) ; Get i/o port address LD C,L ; B=0, c=i/o port address LD B,0 IN A,(C) ; Input data PUSH AF CALL BTOA ; Convert to ascii, print CALL PUTSP POP AF CALL PUTB JP MONJP ; ;OUTPUT Command ; OCOM: LD A,(PARAMC) ; Check number of parms CP 2 ; Less than 2 JP C,NPARMERR ; Then abort LD BC,(PARAM1) ; Get i/o port address LD HL,(PARAM2) ; Get data to output LD B,0 ; B=0, c=i/o port address OUT (C),L ; Output data JP MONJP ; Exit ; ;LOAD Command ; LCOM: LD A,(PARAMC) ; Get parm count CP 0 ; If none JR Z,LAUX ; Then load from aux port LD A,(PARAM1) ; Else CP 0CH ; Check for con port JP NZ,BPARMERR ; No, then error JR WAITST ; Else load form con port LAUX: LD A,0FFH ; Make console = aux port LD (CONFLG),A WAITST: CALL GETCHA ; Get console char CP ':' ; Opening flag JR NZ,WAITST ; No - keep checking CALL GETHEX ; Get data count LD A,L OR A ; If count = 0 then JR Z,LODEND ; Abort LD C,L ; Init checksum LD B,L CALL GET2HEX ; Get load address EX DE,HL LD A,C ; Update checksum ADD A,D ADD A,E LD C,A CALL GETHEX ; Get data type LD A,L OR A ; If type not = 0 JR NZ,LODERR ; Then abort NEXTHEX: CALL GETHEX ; Get data LD A,L ; Save data LD (DE),A ; Put data in memory INC DE ; Increment address ADD A,C ; Update checksum LD C,A DJNZ NEXTHEX ; Keep loading LD (PARAM2),DE ; Save end address ; CALL GETHEX ; Get checksum LD A,L ADD A,C JR Z,WAITST ; LODERR: ; Bad checksum CALL MESAE1 ; Print error message JR EOF1 ; Exit ; LODEND: CALL GET2HEX ; Get address PUSH HL CALL GETHEX ; Get data type ; WAITEOF: CALL GETCHA CP 1AH ; End of file ? JR NZ,WAITEOF ; No - keep looking LD A,L POP HL OR A ; Type = 1 CALL NZ,ASCDP4 ; Yes - print start address LD HL,LEMESE ; Print load end message CALL PRINT LD HL,(PARAM2) ; Get end address CALL ASCDP4 ; Print end address EOF1: LD A,0 LD (CONFLG),A JP MONJP ; Exit ; GET2HEX: PUSH BC LD B,4 ; 4 ascii -> 2 hex LD HL,0 JR NEXTASC ; GETHEX: PUSH BC LD B,2 ; 2 ascii -> 1 hex LD HL,0 ; NEXTASC: CALL GETCHA ; Get char CALL HEXCHK ; Valid hex ? JR C,LODERR ; No, then load error CALL BINCV4 ; Convert to binary DJNZ NEXTASC ; Keep converting POP BC RET ; ;BOOT Command ; BCOM: COLDS: ; Enter at reset if drive ready LD A,(PARAMC) CP 0 JR Z,COLDS1 LD A,(PARAM1) AND 3 COLDS1: LD (DRIVE),A ; Boot from drive 0 LD A,0 LD (TRACK),A ; Track 0 LD (HEAD),A ; Head 0 CALL CREADY ; Disk ready? CALL SEKRCL ; Seek and recalibrate CALL DISKTYPE LD A,11H ; Sector 1 native LD C,A LD A,(DTYPE) CP 'H' ; Hitachi format ? LD A,C JR NZ,BOOTSEC ; No LD A,1 ; Sector 1 Hitachi BOOTSEC: LD (SECTOR),A ; Sector 1 LD A,0C6H LD (FDCOMMAND),A ; 9266 read command LD HL,8000H ; Boot loader address LD DE,400H LD A,4 LD (DMABNK),A CALL FDDRIV ; Initiate 9266 ; IPL: IN0 A,(STAT1) ; Check keyboard AND 80H JR Z,IPL1 ; If no keypress, cont. LD HL,CSTMSG ; Enter monitor JP BADBITS2 IPL1: LD A,(FDBSY) ; Check if BIT 6,A ; 9266 still loading JR NZ,IPL ; Wait until load complete ; LD A,40H ; Point to bank 1 OUT0 (BBR),A LD A,(DTYPE) ; Check disktype LD B,1 CP 'H' ; Hitachi JR Z,BOOTER INC B CP 40 ; 40 track JR Z,BOOTER INC B ; Else 80 track ; BOOTER: LD A,B ; A=1/Hitachi,2/40 trk,3/80 trk JP 8000H ; Jump to boot loader ; ;WRITE Command ; WCOM: LD A,0C5H ; 9266 write command JR RWCOM ; Do it ; ;READ Command ; RCOM: LD A,0C6H ; 9266 read command ; RWCOM: ; Read/write common handler LD (FDCOMMAND),A ; Save 9266 command LD A,(PARAMC) ; How many parms ? CP 4 ; 4, then go JP C,NPARMERR FDPSET: LD A,(PARAM1) ; Parm1 = drive number AND 3 LD (DRIVE),A CALL CREADY ; Check drive ready LD A,0 LD (TRACK),A CALL SEKRCL CALL DISKTYPE LD BC,(PARAM4) ; Parm4 = number of sectors LD DE,(PARAM3) ; Parm3 = start sector DEC DE LD HL,(PARAM2) ; Parm2 = memory address LD A,B OR C JP Z,BPARMERR ; SECNEXT: LD A,B OR C ; Number of sectors = 0 ? JP Z,HSTART ; Then exit PUSH BC ; Save it all PUSH DE PUSH HL CALL TBRAKE ; Abort ? LD HL,399 ; Check valid sector number, 40 track LD A,(DTYPE) CP 40 JR Z,SECN1 LD HL,799 ; 80 track SECN1: CALL SBCHD JP C,BPARMERR ; No, abort POP HL PUSH HL EX DE,HL ; Memaddr to DE, sector to HL ; ; Determine track, side, sector LD DE,0AFFH ; 10 sectors/track, first track-1 SECLOOP: INC E ; Next track PUSH DE ; Save this try MLT DE ; Virtual sector CALL SBCHD ; Is this the track ? POP DE ; Restore this try JR NC,SECLOOP ; No, try next track JR Z,SECLOOP ; " " " " DEC E ; Yes, back up track counter LD A,E ; And save it LD (TRACK),A MLT DE ; Compute virtual sector OR A ; Clear carry SBC HL,DE ; Compute sector number on track LD IX,DRIVE ; Set up RES 2,(IX) ; Head 0 LD A,0 LD (HEAD),A LD A,L ; Sector number INC A ; Adjust CP 6 ; Head 1 ? JR C,SEC2 ; No, continue SUB 5 ; Yes, back up sector number SET 2,(IX) ; And set up head 1 PUSH AF ; Save sector number LD A,1 LD (HEAD),A POP AF ; Restore sector number SEC2: CALL SECOFFSET ; Adjust for 40 or 80 track format LD (SECTOR),A ; And set real sector number ; SIDE1: CALL SEEK ; Seek POP HL PUSH HL LD DE,400H ; 1 sector = 1K bytes CALL FDDRIV ; Do disk operation ; POP HL ; Update parms for next sector LD DE,400H ADD HL,DE ; Add sector size to memory address POP DE POP BC DEC BC ; Sector count = sector count - 1 INC DE ; Start sector = old end sector + 1 LD (OLDSEC),DE ; Save sector address LD (OLDDMA),HL ; Save memory address JR SECNEXT ; ;FORMAT Command ; FCOM: LD A,(PARAMC) CP 2 JP C,NPARMERR LD A,(PARAM2) ; Get disk type CP 40H ; 40 track JR Z,FORMDRV CP 80H ; 80 track JP NZ,BPARMERR ; FORMDRV: LD A,(PARAM1) ; Get and set drive AND 3 LD (DRIVE),A LD HL,FPROMPT ; Confirm prompt CALL PRINTF LD A,(DRIVE) ADD A,30H ; ASCII drive# CALL PUTC LD HL,YORNMES ; Yes or no CALL PRINT CALL GETCHA CALL AZLCNV CP 'Y' JP NZ,MONJP ; No, quit CALL PUTCR CALL CREADY ; Check disk ready LD A,0 LD (TRACK),A CALL SEKRCL ; Seek/recalibrate LD HL,0 ; Start at track 0 ; NEXTFORM: PUSH HL LD A,L SRL H ; Track even or odd RRA LD (TRACK),A ; Save track LD IX,DRIVE RES 2,(IX) ; Set up head 0 LD A,0 LD (HEAD),A JR NC,FMSIDE1 ; If track odd then head 1 SET 2,(IX) LD A,1 LD (HEAD),A ; FMSIDE1: CALL SEEK ; Seek to track CALL TBRAKE ; Abort ? IF DEBUG LD HL,2100H ; Format info buffer ELSE LD HL,2000H ENDIF CALL MAKTRK ; Make track format info ; LD A,3 ; Set n/80 LD (TRACK),A LD A,5 ; Set sc/80 LD (HEAD),A LD A,99 ; Set gpl/80 LD (SECTOR),A LD A,(PARAM2) CP 80H JR Z,FMDATA LD A,2 ; Set n/40 LD (TRACK),A LD A,10 ; Set sc/40 LD (HEAD),A LD A,24 ; Set gpl/40 LD (SECTOR),A ; FMDATA: LD A,0E5H LD (FDPRM),A ; Set data ; IF DEBUG LD HL,2100H ELSE LD HL,2000H ENDIF ; LD DE,20 ; 5 sectors * 4 bytes LD A,(PARAM2) CP 80H JR Z,FMSIDE2 LD DE,40 ; FMSIDE2: LD A,0 CALL DMASET ; Set up dma write LD A,4DH LD (FDCOM),A ; 9266 format command LD B,6 ; 6 byte command list CALL COMMD ; Issue command LD A,(FDBSY) ; Check 9266 BIT 5,A JP NZ,FDERR ; 9266 error LD A,(ST012) ; Get 9266 status BIT 6,A JP NZ,FDERR ; 9266 error POP HL INC HL LD DE,80 ; 80 tracks (40 track * 2 sides) LD A,(PARAM2) CP 40H JR Z,FORM1 LD DE,160 FORM1: CALL SBCHD ; Flags = hl - de JP NZ,NEXTFORM ; Not done - keep formatting ; ; Verify CALL DLOGIN ; Login disk LD A,(DTYPE) ; Get type LD B,A ; # tracks to B LD A,0FFH ; Start track - 1 LD (TRACK),A DVLOOP: LD A,(TRACK) ; Next track INC A CALL DTEST2 ; Read cylinder DJNZ DVLOOP JP MONJP ; Done - exit ; MAKTRK: LD B,5 ; 5 secs/trk LD DE,FORM80 ; For 80 track LD A,(PARAM2) CP 80H JR Z,MAKLOOP LD B,10 ; Else 10 secs/trk LD DE,FORM40 ; For 40 track MAKLOOP: LD A,(DE) ; Sec# CALL MAKSEC ; Make it INC DE ; Next sec# DJNZ MAKLOOP ; #secs/trk RET ; FORM40: DEFB 11H,16H,12H,17H,13H,18H,14H,19H,15H,1AH FORM80: DEFB 11H,14H,12H,15H,13H ; MAKSEC: PUSH AF ; Save sec# LD A,(TRACK) LD (HL),A ; Build track# INC HL LD A,(HEAD) ; Build head# LD (HL),A INC HL POP AF ; Restore sec# LD (HL),A INC HL LD (HL),3 ; 80 trk N=3 LD A,(PARAM2) CP 80H JR Z,MAKSEC1 LD (HL),2 ; 40 trk N=2 MAKSEC1: INC HL RET ; ; YANK: CALL PUTCR LD B,3 YANK1: LD HL,YANKMES1 CALL PRINT DJNZ YANK1 CALL PUTCR CALL PUTCR LD HL,YANKMES2 ; Point to list of reg names LD (PARAM1),HL ; Save it LD E,0FFH ; First address - 1 YLOOP1: LD B,3 ; 3 regs per line YLOOP2: INC E CALL YPREG ; Print reg address, name, contents DJNZ YLOOP2 CALL PUTCR ; Carriage return after 3 JR YLOOP1 ; YPREG: LD A,E ; Get reg address CP 40H ; Last one ? JP Z,MONJP ; Yes, exit LD HL,YREGLIST ; No, point to skip list YCLOOP: LD A,(HL) ; Get address to skip CP E ; Skip this one ? JR NZ,YOK INC B RET YOK: CP 0FFH ; Else, end of list ? JR Z,YCONT ; Yes, continue INC HL ; No, inc skip pointer JR YCLOOP ; And keep checking ; ; YCONT: LD A,E ; Restore reg address PUSH DE ; And save PUSH BC ; Save callers counter LD C,A ; Make I/O LD B,0 ; Port address PUSH BC ; And save CALL PUTSP LD A,C ; Print reg address CALL BTOA CALL PUTSP LD HL,(PARAM1) CALL PRINT6 ; Print reg name LD (PARAM1),HL CALL PUTSP POP BC IN A,(C) ; Read the register CALL PUTB ; Print register contents LD B,4 YSPLOOP: CALL PUTSP DJNZ YSPLOOP POP BC POP DE RET ; PRINT6: PUSH BC ; Print six chars at (HL) LD B,6 P6LOOP: LD A,(HL) ; Get a char INC HL ; Point to next CALL PUTC ; Print it DJNZ P6LOOP POP BC RET ; YREGLIST: DEFB 11H,12H,13H,18H,19H,1AH,1BH,1CH,1DH,1EH,1FH DEFB 2DH,35H,37H,3BH,3CH,3DH,3EH,0FFH ; ; ; PRINTER: LD HL,PRNMES1 CALL PRINTF LD A,(PRNFLG) ; Get printer CPL LD (PRNFLG),A ; Toggle LD HL,PRNMES2 OR A JR NZ,PRN2 LD HL,PRNMES3 PRN2: CALL PRINT ; Show current printer JP MONJP ; ; ;COPY command ; COPY: LD A,(PARAMC) ; Check number of parms CP 2 ; Less than 2 JP C,NPARMERR ; Then abort COPY1: LD HL,CPMES1 ; Get copy confirmation CALL PRINTF LD A,(PARAM1) AND 3 ADD A,30H CALL PUTC ; ASCII source drive# LD HL,TOMES CALL PRINT LD A,(PARAM2) AND 3 ADD A,30H CALL PUTC ; ASCII dest drive# LD HL,YORNMES CALL PRINT CALL GETCHA CALL AZLCNV CP 'Y' JP NZ,MONJP ; Copy aborted CALL PUTCR LD A,(PARAM1) LD B,A LD A,(PARAM2) CP B ; Compare source/dest drive# JP Z,SCOPY ; Same, then single drive copy ; CALL DSOURCE ; Set up source drive CALL DISKTYPE ; Determine type CALL DDEST ; Set up dest drive LD A,0FFH ; Set up track 0 LD (TRACK),A LD B,8 ; 8*50K=400K LD A,(DTYPE) CP 40 ; For 40 trk JR Z,DCLOOP LD B,16 ; 16*50K=800K for 80 trk DCLOOP: LD A,(PARAM1) AND 3 LD (DRIVE),A ; Source drive CALL DREAD ; Read it LD A,(TRACK) ; Back up 5 tracks SUB 5 LD (TRACK),A LD A,(PARAM2) AND 3 LD (DRIVE),A ; Dest drive CALL DWRITE ; Write it DJNZ DCLOOP JP MONJP ; DREAD: LD A,0C6H LD (FDCOMMAND),A ; Set up read IF DEBUG LD HL,2100H ELSE LD HL,2000H ENDIF LD (PARAM3),HL CALL RW5T ; Read 5 cylinders RET ; DWRITE: LD A,0C5H LD (FDCOMMAND),A ; Set up write IF DEBUG LD HL,2100H ELSE LD HL,2000H ENDIF LD (PARAM3),HL CALL RW5T ; Write 5 cylinders RET ; SCOPY: SCOPY1: CALL RCPROMPT CALL DSOURCE ; Login source disk CALL DISKTYPE CALL SET1HALF ; Setup first half CALL READIT ; Read source CALL SET1HALF ; Setup first half CALL WRITEIT ; Write destination CALL SET2HALF ; Setup second half CALL READIT ; Read source CALL SET2HALF ; Setup second half CALL WRITEHALF ; Write destination LD A,(DTYPE) ; 40 track disk ? CP 40 JR Z,SCOPY2 ; Yes, done CALL RCPROMPT ; No, 40 more tracks CALL DSOURCE ; Login source disk CALL SET3HALF ; Setup third half CALL READIT ; Read source CALL SET3HALF ; Setup third half CALL WRITEIT ; Write destination CALL SET4HALF ; Setup fourth half CALL READIT ; Read source CALL SET4HALF ; Setup fourth half CALL WRITEHALF ; Write destination SCOPY2: JP MONJP ; Exit ; ; READIT: CALL READHALF ; Read 200K CALL WCPROMPT ; Swap CALL DDEST ; Set up write RET ; WRITEIT: CALL WRITEHALF ; Write 200K CALL RCPROMPT ; Swap CALL DSOURCE ; Set up read RET ; DSOURCE: LD A,(PARAM1) ; Select source disk AND 3 ; Mask to 0-3 LD (DRIVE),A ; Set source disk CALL CREADY ; Wait drive ready LD A,0 LD (TRACK),A CALL SEKRCL RET ; DDEST: LD A,(PARAM2) ; Select destination disk AND 3 ; Mask to 0-3 LD (DRIVE),A ; Set destination disk CALL CREADY ; Wait drive ready LD A,0 LD (TRACK),A CALL SEKRCL RET ; SET1HALF: LD A,0FFH ; Start at track 0 LD (TRACK),A ; Start track-1 RET ; SET2HALF: LD A,19 ; Start at track 20 LD (TRACK),A ; Start track-1 RET ; SET3HALF: LD A,39 ; Start at track 40 LD (TRACK),A RET ; SET4HALF: LD A,59 ; Start at trak 60 LD (TRACK),A RET ; RCPROMPT: LD HL,RCPMES ; Same disk CALL PRINTF ; Then prompt swap JP RWCPROMPT ; WCPROMPT: LD HL,WCPMES CALL PRINTF ; RWCPROMPT: LD HL,CRMES ; Swap message CALL PRINT RWCP1: CALL GETCHA CP CR JR NZ,RWCP1 CALL PUTCR RET ; ; READHALF: LD A,0C6H ; Set read command LD (FDCOMMAND),A CALL RW4BANK ; Load memory RET ; WRITEHALF: LD A,0C5H ; Set write command LD (FDCOMMAND),A CALL RW4BANK ; Load memory RET ; RW4BANK: LD B,4 ; Four banks RW4LOOP: IF DEBUG LD HL,2100H ELSE LD HL,2000H ENDIF ; LD (PARAM3),HL ; Save it LD A,B ; Make real bank # (4-7) ADD A,3 IF NOT DEBUG LD (DMABNK),A ; Set bank # ENDIF SLA A ; Build SLA A ; Bank base SLA A ; For SLA A ; Mmu IF NOT DEBUG OUT0 (BBR),A ; Load mmu ENDIF CALL RW5T ; 5 tracks/2 sides per bank DJNZ RW4LOOP ; Do 4 banks RET ; RW5T: PUSH BC PUSH AF LD B,5 ; Five tracks per bank RW5T1: LD A,(TRACK) ; Get track # INC A ; Increment LD (TRACK),A ; Save track # CALL CREADY ; Drive ready ? CALL SEEK ; Seek to track CALL RWT ; Read/write a track DJNZ RW5T1 ; 5 times POP AF POP BC RET ; RWT: PUSH BC LD IX,DRIVE RES 2,(IX) LD A,0 ; First side 0 LD (HEAD),A CALL RWT01 ; Read/write side 0 LD IX,DRIVE SET 2,(IX) LD A,1 ; Then side 1 LD (HEAD),A CALL TBRAKE CALL RWT01 ; Read/write side 1 POP BC RET ; RWT01: LD A,1 ; Start at sector 1 LD (VSECTOR),A LD A,11H LD (SECTOR),A LD B,5 RTLOOP: CALL RW ; Read/write sector LD A,(VSECTOR) INC A ; Next sector LD (VSECTOR),A CALL SECOFFSET LD (SECTOR),A DJNZ RTLOOP RET ; RW: LD HL,(PARAM3) ; Dma address to hl LD DE,400H CALL CREADY ; Check drive ready CALL FDDRIV ; Read/write the sector ADD HL,DE ; Update dma address LD (PARAM3),HL RET ; ; ; ; SEKRCL: FSR1: CALL CALBRT ; Recalibrate FSAR1: LD A,(FDBSY) BIT 6,A ; Busy flag check JR NZ,FSAR1 LD A,(ST012) BIT 6,A ; Result status check JP NZ,FSR1 ; CALL SEEK ; FSAR2: LD A,(FDBSY) BIT 6,A ; Busy flag check JR NZ,FSAR2 LD A,(ST012) BIT 6,A ; Result status check JR NZ,FSR1 RET ; BSYCK: IN A,(FDCSTS) AND 10H ; Busy check JR NZ,BSYCK IN A,(FDCSTS) AND 0FH ; Seek check JR NZ,BSYCK RET ; CBUSY: IN A,(FDCSTS) BIT 7,A ; Rqm=1 JR Z,CBUSY BIT 6,A ; Dio=0 JR NZ,CBUSY RET ; SBUSY: IN A,(FDCSTS) BIT 7,A ; Rqm=1 JR Z,SBUSY BIT 6,A ; Dio=1 JR Z,SBUSY RET ; DRDY: CALL BSYCK LD A,4 ; 9266 sense device status command OUT (FDCDT),A CALL CBUSY LD A,(DRIVE) ; Set drive# OUT (FDCDT),A CALL SBUSY IN A,(FDCDT) ; Get status AND 20H RET ; ; DISKTYPE: PUSH AF PUSH BC PUSH HL LD A,4AH ; Read ID LD (FDCOM),A LD B,2 CALL COMMD DTYPE1: LD A,(FDBSY) BIT 6,A JR NZ,DTYPE1 LD A,(LNGH0) LD HL,FDPRM LD (HL),A ; Set n/40&80 CP 2 LD A,40 ; Set DTYPE = 40 cylinders LD B,10 ; Set eot/40 LD C,14 ; Set gpl/40 JR Z,DTEXIT LD A,(HL) CP 1 LD A,'H' ; Set DTYPE = Hitachi LD B,16 ; Set eot/Hitachi LD C,14 ; Set gpl/Hitachi JR Z,DTEXIT LD A,80 ; Set DTYPE = 80 cylinders LD B,5 ; Set eot/80 LD C,14 ; Set gpl/80 DTEXIT: LD (DTYPE),A ; DTYPE INC HL LD (HL),B ; Eot INC HL LD (HL),C ; Gpl LD A,0FFH INC HL LD (HL),A ; Dtl/40&80 POP HL POP BC POP AF RET ; SECOFFSET: PUSH AF LD A,(DTYPE) CP 40 JR Z,SEC40 POP AF ADD A,10H ; Make 80 trk sec# RET SEC40: POP AF SUB 1 SLA A ADD A,11H ; Make 40 trk sec# RET ; ; FDDRIV: PUSH HL PUSH DE PUSH BC LD B,2 LD A,(FDCOMMAND) CP 0C6H JR Z,RDFUNC LD B,0 RDFUNC: LD A,B CALL DMASET ; Dma parameter set LD A,(FDCOMMAND) ; 9266 read command LD (FDCOM),A LD B,9 ; 9 byte command list CALL COMMD ; Issue command LD A,(FDBSY) ; Error flag check BIT 5,A JR NZ,FDERR LD A,(ST012) BIT 6,A JR NZ,FDERR ; POP BC POP DE POP HL RET ; FDERR: LD HL,RWEMESE CALL PRINTF ; Display error LD HL,ERMESE CALL PRINT CALL PUTCR LD HL,UNITMES CALL PRINT LD A,(DRIVE) ; Error drive AND 3 ; Mask side ADD A,30H ; Make ascii CALL PUTC CALL PUTCR CALL PUTCR LD DE,ST012 ; Point to 9266 status LD HL,DSTATMES LD B,6 FDERRLOOP: CALL PRINT6 ; Display 9266 status CALL PUTSP LD A,(DE) INC DE PUSH AF CALL BTOA ; In hex CALL PUTSP POP AF CALL PUTB ; And binary CALL PUTCR DJNZ FDERRLOOP JP MONJP ; Exit ; DSTATMES: DEFB 'ST0 ' DEFB 'ST1 ' DEFB 'ST2 ' DEFB 'Track ' DEFB 'Head ' DEFB 'Sector' UNITMES: DEFB 'Drive ',0 ; ; SEEK: PUSH AF PUSH BC LD A,0FH ; 9266 seek command LD (FDCOM),A LD B,3 ; 3 byte command list CALL COMMD ; Issue command ; LD A,(FDBSY) BIT 5,A JR NZ,SEKERR POP BC POP AF RET SEKERR: LD HL,SEMESE ; Seek error message ERRMES: CALL ERMESA JP MONJP ; Exit ; ; CALBRT: PUSH AF PUSH BC LD A,7 ; 9266 recalibrate command LD (FDCOM),A LD B,2 CALL COMMD LD A,(FDBSY) BIT 5,A JR NZ,CALERR POP BC POP AF RET ; CALERR: LD HL,SEMESE JP ERRMES ; COMMD: PUSH HL COMMD1: CALL DRDY ; Device ready JR Z,COMMD1 ; Wait for ready CALL BSYCK DI LD A,(FDCOM) ; First command byte OUT (FDCDT),A LD IX,FDBSY ; Mark FDC busy RES 5,(IX) SET 6,(IX) EI LD IX,FDCOM COM1: INC IX ; Point to next command byte DEC B ; Count down JR Z,COM2 ; Done CALL CBUSY ; No, wait for FDC LD A,(IX) ; Next command byte OUT (FDCDT),A JR COM1 ; More command bytes COM2: FDCINT: LD IX,FDBSY BIT 6,(IX) ; Check FDC busy JR NZ,FDCINT ; Yes, wait POP HL ; Else, RET ; Command done ; ; DMASET: ; Set DMA - HL=memaddr, DE=count PUSH BC LD B,A IN0 A,(DCNTL) AND 0FCH OR B OUT0 (DCNTL),A LD A,B POP BC OUT0 (MAR1L),L ; Mem addr low OUT0 (MAR1H),H ; Mem addr high LD A,(DMABNK) OUT0 (MAR1B),A ; Mem addr bank LD A,0A0H ; I/O addr = 9266 DACK OUT0 (IAR1L),A LD A,0 OUT0 (IAR1H),A OUT0 (BCR1L),E ; Count low OUT0 (BCR1H),D ; Count high LD A,80H OUT0 (DSTAT),A RET ; CREADY: PUSH AF PUSH BC LD A,(MOTOR) ; Check if motor on CP 0FFH JR Z,CREADY1 ; Yes, continue LD A,0FFH ; No, mark it on LD (MOTOR),A OUT0 (TRDR),A ; And turn it on LD A,10H OUT0 (CNTR),A LD B,180 ; 1.8 seconds for spin-up CALL DELAY10MS CREADY1: POP BC POP AF CALL DRDY ; Check disk ready RET NZ ; Return if so CALL TBRAKE ; Allow abort PUSH HL LD HL,NRMESE ; Show not ready CALL PRINTF POP HL JR CREADY ; And keep trying ; ; PUTCR: LD A,CR ; Cr CALL PUTC ; Cr LD A,LF ; Lf JP PUTC ; To console ; PRINTF: CALL PUTCR ; Cr, lf to console PRINT: LD A,(HL) ; Get a char OR A ; 0 ends char string RET Z ; Exit CALL PUTC ; Char to console INC HL ; Next char JR PRINT ; Loop ; PARSE: ; Check param2>param1 ; Exit hl=param1, bc=param2-param1 LD HL,(PARAM2) ; Source address end LD DE,(PARAM1) ; Source address start AND A ; Clear carry SBC HL,DE ; Check order JP C,COMERR ; End < start, then abort LD B,H ; Count to bc LD C,L INC BC LD HL,(PARAM1) ; Source to hl RET ; HEXCHK: CP '0' ; If < 0 RET C ; Carry set = error CP 'F'+1 ; If > 'f' JR NC,HEXERR ; Error CP '9'+1 ; If <= '9' JR C,HEXOK ; Good hex CP 'A' ; If < 'a' RET C ; Then eror ; HEXOK: AND A ; Carry clear = good hex RET ; HEXERR: SCF ; Carry set = bad hex RET ; BINCV4: ; One byte hex -> low nibble hl CP '9'+1 ; If < '9' JR C,ATOF ; Then proceed ADD A,9 ; Else bump for binary ATOF: AND 0FH ; Extract low nibble ATOF1: ADD HL,HL ; Make room in hl ADD HL,HL ADD HL,HL ADD HL,HL ADD A,L ; Lay in low nibble LD L,A ; Build lsb RET ; ASCCON: ; One byte binary -> two ascii hex PUSH AF ; Save binary AND 0FH ; Extract low nibble CALL ASCC01 ; Convert to ascii LD E,A ; Save in e POP AF ; Restore binary AND 0F0H ; Extract high nibble RRCA ; Make it low nibble RRCA RRCA RRCA CALL ASCC01 ; Convert to ascii LD D,A ; Save in d RET ; ASCC01: CP 0AH ; If not 0-9 JR NC,ASC01 ; Then convert to a-f OR '0' ; Else done RET ASC01: ADD A,'7' ; Add ascii offset RET ; ASCDP4: ; Print hl as 4 ascii hex LD A,H ; Get msb CALL BTOA ; Convert to 2 ascii hex LD A,L ; Get lsb ; BTOA: ; Convert a to 2 ascii hex PUSH DE ; Save de CALL ASCCON ; A nibbles to d,e LD A,D ; High nibble ascii CALL PUTC ; To console LD A,E ; Low nibble ascii CALL PUTC ; To console POP DE ; Restore de RET ; SBCHD: ; Flags = hl-de PUSH HL ; Save hl AND A ; Clear carry SBC HL,DE ; Subtract POP HL ; Restore hl RET ; Flags are set ; AZLCNV: ; Convert a-z to a-z CP 'a' ; If < 'a' RET C ; Exit CP '{' ; If > 'z' RET NC ; Exit AND 5FH ; Else convert to upper case RET ; PUTSP: LD A,' ' ; Space JR PUTC ; To console ; DASCII: ; Display ascii PUSH AF ; Save PUSH DE ; Hl = end address PUSH BC ; B = number of bytes CALL PUTSP ; 2 spaces CALL PUTSP ; To console LD E,B ; Number of bytes LD D,0 ; To de AND A ; Clear carry SBC HL,DE ; Compute starting address NEXTDU: LD A,(HL) ; Get a char CP ' ' ; If < ' ' JR C,CONTDU CP 80H ; Or if > 'del' JR C,DISPDU CONTDU: LD A,'.' ; Then not printable DISPDU: CALL PUTC ; Print the char INC HL ; Next address DJNZ NEXTDU ; Print b bytes POP BC POP DE POP AF RET ; Exit ; ; ERMESA: CALL PRINTF ; Print cr, message MESAE1: LD HL,ERMESE ; Followed by 'error' JP PRINT ; ; TBRAKE: CALL CONST1 ; Check console suspend/abort RET Z ; No keypress, then continue CALL GETCHA ; Get the keypress CP 13H ; If not ctl-s RET NZ ; Then ignore TBLOOP: CALL GETCHA ; Otherwise wait for next keypress CP 11H ; If ctl-q RET Z ; Then continue JR TBLOOP ; Else suspend ; ; PUTB: PUSH BC LD B,8 ; 8 bits OR A PUTB1: RLC A ; Get a bit PUSH AF JR NC,PUTZERO ; 0 LD A,'1' ; Or 1 JR PUTONE PUTZERO: LD A,'0' PUTONE: CALL PUTC POP AF DJNZ PUTB1 POP BC RET ; ; PUTC: PUSH AF ; A to console CALL TBRAKE WAITIN: IN0 A,(STAT1) ; Check status AND 2 ; If tdr not empty JR Z,WAITIN ; Then wait POP AF ; If tdr empty OUT0 (TDR1),A ; Send the data PUSH AF LD A,(ECHOFLG) ; Echo printer ? OR A JR NZ,ECHOC POP AF RET ECHOC: LD A,(PRNFLG) ; Which printer ? OR A JR NZ,ECHOA ; AUX: ; ECHOC1: LD A,(PRNSTAT) ; CEN: OR A JR Z,ECHOC1 ; Wait printer free LD A,0 ; Mark printer busy LD (PRNSTAT),A DI POP AF OUT (CENTDC),A ; Output data - clear strobe OUT (CENTDS),A ; Output data - set strobe OUT (CENTDC),A ; Output data - clear strobe EI RET ; ECHOA: IN0 A,(STAT0) ; AUX: AND 2 JR Z,ECHOC POP AF OUT0 (TDR0),A RET ; GETCHA: ; Console to a LD A,(CONFLG) OR A JR Z,GETCHA1 ; CON: is CON: JR GETCHA0 ; CON: is AUX: GETCHA1: CALL CONST1 ; If no keypress JR Z,GETCHA1 ; Then wait IN0 A,(RDR1) ; Else get data JR GETCHA01 ; CONST1: ; CON: status check IN0 A,(STAT1) ; If keypress then a<>0 JR CONST01 ; GETCHA0: CALL CONST0 ; Check AUX: JR Z,GETCHA0 IN0 A,(RDR0) ; Get data GETCHA01: AND 7FH ; Strip parity CALL SCHECK ; Handle specials RET ; CONST0: IN0 A,(STAT0) ; AUX: status check CONST01: AND 80H ; Receiver not ready = 0 RET ; SCHECK: CP 18H ; Ctl-x JR Z,SCHECK1 ; Abort CP 3 ; Ctl-c JR Z,SCHECK1 ; Abort CP 10H ; Ctl-p RET NZ PUSH AF LD A,(ECHOFLG) ; Toggle CPL ; Printer LD (ECHOFLG),A ; Echo flag POP AF RET SCHECK1: LD HL,STOPMES CALL PRINTF JP MONJP ; ; GETLINE: ; Console data to conbuf LD B,0 ; B = length of line LD HL,CONBUF ; Point to console buffer NEXTGETL: CALL GETCHA ; Get a char CP CR ; If cr JR Z,ENDGETL ; Then done CP 8 ; If bs CALL Z,BACKSP ; Then fix console CP 7FH ; Same for del CALL Z,BACKSP CP ' ' ; If space JR C,NEXTGETL ; Then ignore CP 7FH ; If del JR NC,NEXTGETL ; Then ignore CALL PUTC ; Else print CALL AZLCNV ; Then convert to uppercase LD (HL),A ; And save in buffer INC HL ; Increment buffer pointer INC B ; Increment buffer count LD A,B CP 40 ; If buffer not full JR C,NEXTGETL ; Then keep getting chars ; ENDGETL: CALL PUTCR ; If buffer full or cr typed LD (HL),0 ; Then print cr, mark buffer eof RET ; BACKSP: LD A,B ; Get buffer count OR A ; If buffer empty RET Z ; Then ignore LD A,8 ; Else PUSH AF CALL PUTC ; Print bs LD A,' ' ; And a blank CALL PUTC POP AF CALL PUTC DEC HL ; Decrement buffer address DEC B ; Decrement buffer count RET ; ; ATOI: LD DE,0 NEXTATOI: LD A,(HL) CP ' ' ; Skip blanks JR Z,SKIPIT CP ',' ; Skip commas JR Z,SKIPIT NEXTH: CALL ATOH ; Otherwise make hex RET C EX DE,HL CALL ATOF1 EX DE,HL INC HL ; Bump scan pointer LD A,(HL) JR NEXTH ; SKIPIT: INC HL JR NEXTATOI ; ATOH: CP '0' RET C CP 'G' JR NC,NOTHEX SUB '0' ; Sub ASCII offset CP 0AH JR C,YESHEX CP 11H RET C SUB 7 ; Adjust A-F RET NOTHEX: SCF RET YESHEX: OR A RET ; SCANF: CALL GETLINE ; Get console data LD A,(CONBUF) ; First char is command LD (COMLINE),A ; Save command LD DE,CONBUF+1 ; De points to first param LD B,0 ; B = number of params LD HL,PARAM1 ; Hl points to first param holder LD A,(DE) ; Get param DEC DE ; And back up param pointer NEXTPARM: EX DE,HL ; De points to param holder, hl to comline CP 0 ; No more params JP Z,ENDSCANF ; Exit INC HL ; Increment comline pointer PUSH BC PUSH DE CALL HEXCHK ; Parm good JR NC,NEXT1 ; Good hex CP ' ' ; Blank JR Z,NEXT1 CP ',' ; And comma JR Z,NEXT1 ; Ok JP BPARMERR ; Parameter error NEXT1: CALL ATOI ; Convert ascii to integer LD B,D ; Bc = param LD C,E POP DE EX DE,HL ; Hl points to param holder, de to comline LD (HL),C ; Save param lsb INC HL LD (HL),B ; Save param msb INC HL ; Hl points to next param holder POP BC ; B = param count INC B ; Increment param count LD A,B CP 5 ; If params <=5 LD A,(DE) ; Get next comline data JR C,NEXTPARM ; And extract next param ENDSCANF: LD A,B ; B = param count LD (PARAMC),A ; Save it RET ; COMERR: LD HL,CERRMES ; Command error message JR ERRQUIT ; Exit ; BPARMERR: LD HL,BPERRMES ; Bad parameter JR ERRQUIT ; NPARMERR: LD HL,NPERRMES ; Not enough parameters ERRQUIT: CALL PRINT JP MONJP ; INTFDD: PUSH HL PUSH BC PUSH AF PUSH IX IN A,(FDCSTS) ; Check 9266 status BIT 7,A JR Z,FDEND BIT 4,A JR NZ,RWEND ; LD A,8 OUT (FDCDT),A CALL SBUSY IN A,(FDCDT) LD (ST012),A ; Status CALL SBUSY IN A,(FDCDT) LD (TRAK0),A ; Track LD A,(ST012) RLCA JR C,FDEND AND 01000000B JR NZ,FDEN1 RWEND: LD B,7 LD C,FDCDT LD HL,ST012 RWEN1: CALL SBUSY INI ; 7 bytes JR NZ,RWEN1 FDEN1: LD IX,FDBSY RES 6,(IX) ; Mark disk free FDEND: POP IX POP AF POP BC POP HL EI RET ; ; INTERR: ; Interrupt non-handler PUSH HL ; Save PUSH BC ; State PUSH AF LD HL,INTRER ; Print CALL PRINTF ; An error message POP AF POP BC ; Restore POP HL ; State EI ; Enable interrupts RET ; Return to interrupted task ; INTCEN: ; Centronics interrupt PUSH AF LD A,0FFH ; Mark printer free LD (PRNSTAT),A LD A,0 ; Clear interrupt OUT (CENTDC),A POP AF EI RET ; .XLIST ; ; RWEMESE:DEFB 'Disk R/W',0 SEMESE: DEFB 'Disk Seek',0 LEMESE: DEFB 'Load End - ',0 ERMESE: DEFB ' Error !',07H,0 NRMESE: DEFB 'Disk Not Ready',0 TRAPER: DEFB 'Bad Opcode Trap !',0 INTRER: DEFB 'Invalid Interrupt !',0 CERRMES:DEFB 'Bad Command !',0 BPERRMES: DEFB 'Bad Parameter !',0 NPERRMES: DEFB 'Not Enough Parameters !',0 VERRMES:DEFB ' not equal ',0 MATHMES:DEFB 'Sum Diff Product',0 FPROMPT:DEFB 'Confirm: Format Disk ',BELL,0 RCPMES: DEFB 'Load READ disk - ',0 WCPMES: DEFB 'Load WRITE disk - ',0 CPMES1: DEFB 'Confirm: Copy Disk ',BELL,0 TOMES: DEFB ' to Disk ',0 YORNMES: DEFB ' (Y/N) ? ',0 PRNMES1:DEFB 'Printer is ',0 PRNMES2:DEFB 'RS-232',0 PRNMES3:DEFB 'Centronics',0 ; ; HELPMES: DEFB 'A = ASCII Table >A',CR,LF DEFB 'B = Bank Select >Bbank# (bank#=0-3)',CR,LF DEFB 'C = Copy Disk >Csourcedrive#,destdrive#',CR,LF DEFB 'D = Display Memory >D[startaddr],[endaddr]',CR,LF DEFB 'E = Emulate Terminal >E[baudrate]',CR,LF DEFB 'F = Fill Memory >Fstartaddr,endaddr,data8',CR,LF DEFB 'G = Goto Program >G[goaddr] >GB brkaddr,[goaddr]',CR,LF DEFB 'H = Hexmath >Hdata16,data16',CR,LF DEFB 'I = Input Port >Iportaddr',CR,LF DEFB 'K = Klean(Format)Disk >Kdrive#,#tracks (#tracks=40,80)',CR,LF DEFB 'M = Move Memory >Mstartaddr,endaddr,destaddr',CR,LF DEFB 'N = New Command >Ncmd# (cmd#=0-FF hex)',CR,LF DEFB 'O = Output Port >Oportaddr,data8',CR,LF DEFB 'P = Printer Select >P',CR,LF DEFB 'Q = Query(Search)Memory >Qdata8,[data8],[data8],[data8]',CR,LF DEFB 'R = Read Disk >Rdrive#,addr,start sector,# of sectors' DEFB CR,LF DEFB 'S = Set Memory >Saddr',CR,LF DEFB 'T = Test System >Tdev (dev=A}ux:,C}en:,}Mem) >TD,drive#',CR,LF DEFB 'U = Upload Hex File >U[C]',CR,LF DEFB 'V = Verify Memory >Vstartaddr,endaddr,destaddr',CR,LF DEFB 'W = Write Disk >Wdrive#,addr,start sector,# of sectors' DEFB CR,LF DEFB 'X = Examine Registers >X',CR,LF DEFB 'Y = Yank I/O Registers >Y',CR,LF DEFB 'Z = Boot DOS >Z[drive#] ;' CRMES: DEFB 'enter to continue -> ' DEFB 0 ; ; ASCMES: DEFB ' 0 1 2 3 4 5 6 7',CR,LF,CR,LF DEFB ' 0 NUL DLE SPC 0 @ P ` p',CR,LF DEFB ' 1 SOH DC1 ! 1 A Q a q',CR,LF DEFB ' 2 STX DC2 " 2 B R b r',CR,LF DEFB ' 3 ETX DC3 # 3 C S c s',CR,LF DEFB ' 4 EOT DC4 $ 4 D T d t',CR,LF DEFB ' 5 ENQ NAK % 5 E U e u',CR,LF DEFB ' 6 ACK SYN & 6 F V f v',CR,LF DEFB ' 7 BEL ETB ' DEFB 27H DEFB ' 7 G W g w',CR,LF DEFB ' 8 BS CAN ( 8 H X h x',CR,LF DEFB ' 9 HT EM ) 9 I Y i y',CR,LF DEFB ' A LF SUB * : J Z j z',CR,LF DEFB ' B VT ESC + ; K [ k {',CR,LF DEFB ' C FF FS , < L \ l |',CR,LF DEFB ' D CR GS - = M ] m }',CR,LF DEFB ' E SO RS . > N ^ n ~',CR,LF DEFB ' F SI US / ? O _ o DEL',CR,LF,0 ; YANKMES1: DEFB 'Addr Name Contents ',0 ; ; ; YANKMES2: DEFB 'CNTLA0' DEFB 'CNTLA1' DEFB 'CNTLB0' DEFB 'CNTLB1' DEFB 'STAT0 ' DEFB 'STAT1 ' DEFB 'TDR0 ' DEFB 'TDR1 ' DEFB 'RDR0 ' DEFB 'RDR1 ' DEFB 'CNTR ' DEFB 'TRDR ' DEFB 'TMDR0L' DEFB 'TMDR0H' DEFB 'RLDR0L' DEFB 'RLDR0H' DEFB 'TCR ' DEFB 'TMDR1L' DEFB 'TMDR1H' DEFB 'RLDR1L' DEFB 'RLDR1H' DEFB 'SAR0L ' DEFB 'SAR0H ' DEFB 'SAR0B ' DEFB 'DAR0L ' DEFB 'DAR0H ' DEFB 'DAR0B ' DEFB 'BCR0L ' DEFB 'BCR0H ' DEFB 'MAR1L ' DEFB 'MAR1H ' DEFB 'MAR1B ' DEFB 'IAR1L ' DEFB 'IAR1H ' DEFB 'BCR1L ' DEFB 'BCR1H ' DEFB 'DSTAT ' DEFB 'DMODE ' DEFB 'DCNTL ' DEFB 'IL ' DEFB 'ITC ' DEFB 'RCR ' DEFB 'CBR ' DEFB 'BBR ' DEFB 'CBAR ' DEFB 'ICR ' ; ; XMES: DEFB 'SZxHxPNC A BC DE HL IX IY SP PC',0 AMES: DEFB ' A ',0 BCMES: DEFB 'BC ',0 DEMES: DEFB 'DE ',0 HLMES: DEFB 'HL ',0 IXMES: DEFB 'IX ',0 IYMES: DEFB 'IY ',0 PCMES: DEFB 'PC ',0 ; .LIST ; HERE: DS 32-[[HERE-START] AND 31] ; Force 32 byte boundary ; ; INTTBL: DEFW INTCEN ; Centronics interrupt DEFW INTFDD ; Floppy Disk Controller interrupt DEFW INTERR ; Timer 0 DEFW INTERR ; Timer 1 DEFW INTERR ; DMAC 0 DEFW INTERR ; DMAC 1 DEFW INTERR ; CSI/O DEFW INTERR ; ASCI 0 DEFW INTERR ; ASCI 1 ; STOPMES: DEFB 'stopped...',CR,LF,0 ; ; FDCOM EQU RAM ; 9266 command DRIVE EQU FDCOM+1 ; Command Drive TRACK EQU FDCOM+2 ; Command Track HEAD EQU FDCOM+3 ; Command Head SECTOR EQU FDCOM+4 ; Command Sector FDPRM EQU FDCOM+5 ; Command parm LNGTH EQU FDCOM+9 ; Command Sector length FDBSY EQU FDCOM+10 ; Drive busy ST012 EQU FDCOM+11 ; Result ST0,ST1,ST2 TRAK0 EQU FDCOM+14 ; Result Track HEAD0 EQU FDCOM+15 ; Result head SECT0 EQU FDCOM+16 ; Result sector LNGH0 EQU FDCOM+17 ; Result length DMACOM EQU FDCOM+18 ; DMAC command ; COMLINE EQU FDCOM+19 ; Command line PARAMC EQU FDCOM+27 ; # Parms PARAM1 EQU FDCOM+28 ; Parm 1 PARAM2 EQU FDCOM+30 ; Parm 2 PARAM3 EQU FDCOM+32 ; Parm 3 PARAM4 EQU FDCOM+34 ; Parm 4 OLDSEC EQU FDCOM+36 ; Last sector OLDDMA EQU FDCOM+38 ; Last DMA addr FDCOMMAND EQU FDCOM+40 ; FDC command history OLDST EQU FDCOM+41 ; Last 'D' address DMABNK EQU FDCOM+43 ; Current Bank CONFLG EQU FDCOM+44 ; Console iobyte ECHOFLG EQU FDCOM+45 ; Printer echo iobyte PRNFLG EQU FDCOM+46 ; Printer iobyte PRNSTAT EQU FDCOM+47 ; Printer status SAVESP EQU FDCOM+48 ; Saved registers... SAVEHL EQU FDCOM+50 SAVEPC EQU FDCOM+52 BPADDR EQU FDCOM+54 ; Breakpoint address BPINST EQU FDCOM+56 ; Breakpoint instruction ROMSIZE EQU FDCOM+57 ; ROM capacity RAMSIZE EQU FDCOM+58 ; RAM capacity DTYPE EQU FDCOM+59 ; Disk type TSTBYTE EQU FDCOM+60 ; Memory test temp VSECTOR EQU FDCOM+61 ; Virtual disk sector MOTOR EQU FDCOM+63 ; Motor status ; CONBUF EQU RAM+80H ; Console buffer ; ; ; ; END A2>