;********************************************** ;* * ;* BIOS ROUTINES FROM EPROM MONITOR * ;* * ;********************************************** ; ;This file is an excerpt from my EPROM monitor, listing several I/O routines ;useful for a high-level ROM-based driver for CP/M and UCSD Pascal. ;With luck, you will find it useful to draw from, in particular the following: ; 0. Highly compact Z-80 code, designed to run quickly. ; 1. Video driver routines for a memory-mapped 24x80 terminal, including: ; a. Choice of scrolling (with choice of speed) or page-type (with ; optional wait at end of screen) operation. ; b. Full screen and cursor commands for the UCSD editor. ; 2. Interrupt-driven keyboard routines featuring a type-ahead queue. ; 3. Interrupt-driven flushing and/or halting outputs as desired. ; 4. Printer routines offering: ; a. Two types of printer (daisywheel and dot-matrix). ; b. A Diablo driver supporting std & proportional-spaced printwheels. ; c. Expansion of horizontal tabs. ; ;THE REST OF THE MONITOR IS AN OFFSHOOT OF TDL'S ZAPPLE. IF YOU WOULD LIKE ;A COPY OF IT, SEND ME A DISK WITH RETURN POSTAGE AND SOME SORT OF PROOF THAT ;YOU HAVE PURCHASED ZAPPLE (NOW SOLD THROUGH COMPUTER DESIGN LABS). ; ;This program is designed to be assembled by the TDL assembler, though it is ;easily altered to work with Digital Research's macroassembler. .XLINK .PABS .PHEX .LOC 0F000H ;JUMP VECTORS: BASE: JMP CSTART ;COLD START ROUTINE--designed here as a subroutine only CI: JMP MCI JMP RI JCO: JMP CO JMP PO JMP LIST CSTS: JMP MCSTS ; ; <<< CONTROL CHARACTER ASSIGNMENTS >>> ; BELL = 7 BS = 8 HT = 9 ; " HORIZONTAL TAB LF = 10 ; " LINE FEED FF = 12 ; " FORM FEED (OR CLEAR CRT) CR = 13 ; " CARRIAGE RETURN GOTYCH = 14 ;^N = MOV CURS TO Y = (B) CRONLY = 11H ;^Q = CARRIAGE RETURN ONLY DC1 = 11H ;ASCII DC1 FOR DIABLO TONECH = 12H ;^R = PLAY NOTE DETAILED IN HL DC3 = 13H ;ASCII DC3 FOR DIABLO NDFSCH = 14H ;^T = NONDESTRUCTV FORWRD SPACE EEOLCH = 15H ;^U = ERASE TO END OF LINE EEOSCH = 16H ;^V = ERASE TO END OF SCREEN RLFCH = 17H ;^W = REVERSE LINE FEED GTXYCH = 18H ;^X = GO TO XY (NEXT 2 CHARS) REVCH = 19H ;^Y = REVERSE FIELD TOGGLE HOMECH = 1AH ;^Z = HOME CURSOR ESC = 1BH ;ASCII ESCAPE GREYCH = 1CH ;^\ = GREY ENABLE TOGGLE GRPHTG = 1DH ;^] = GRAPHICS (PCG) TOGGLE PADNXT = 1EH ;^^ = NXT CHAR IS # USPACS TO PAD ; .REMARK| <<< STS DATA >>> this is STatuS word that is primary controller of options BIT 0 1 = PROPORTIONAL SPACING PWHEEL PRESENT BIT 1 EDIT MODE/ENABLE JOYSTICK (1 = ON) BIT 2 WAIT ENABLE (1 = WAIT, PAGE MODE ONLY) BIT 3 SLOW SCROLL ENABLE (1 = SLOW) BIT 4 -PAGE/+SCROLL MODE BIT 5 PRINTER TOGGLE: 0 = MALIBU / 1 = DIABLO BIT 6 BIOS TYPE (0 = CPM, 1 = PASCAL) BIT 7 TOGGLE: 1->PRINTER TO FOLLOW CONSOL OUTPUT <<< IOBYTE DATA >>> A. INTEL STANDARD IOBYTE - LOCATN 0003 BITS 0,1 = CONSOLE (0=TTY,1=CRT,2=BATCH,3=USR) BITS 2,3 = READER (0=TTY,1=FAST READR,3&4=USR) BITS 4,5 = PUNCH (0=TTY,1=FAST PUNCH,3&4=USR) BITS 6,7 = LIST (0=TTY,1=CRT,3=LIN PRTR,4=USR) NOTE: IN ZAPPLE, 3 IN READER/PUNCH = CASSETTE B. MY USE BIT 0 1 = BEEP OCCURS WITH KEYBOARD INPUT BIT 7 1=LIST -> SELECTED PRINTER // 0= -> CRT <<< SPECIAL CHAR SEQUENCE DOCUMENTATION >>> TYPING A "^]" THEN ANOTHER CHARACTER ALLOWS YOU TO DO THE FOLLOWING: WHEN THE NEXT CHAR IS A: YOU GET: "]" CRT SCREEN CLEARS "\" FORMFEED TO MALIBU "@" FORMFEED TO DIABLO "L" LOGICAL LIST --> PRINTER "C" " " --> CRT "D" PRINTER SWITCHES TO DIABLO "M" PRINTER IS MALIBU (DEFAULT) "R" DIABLO HAS PROPORTIONAL-SPACE PRINTWHEEL "A" DIABLO HAS PLAIN PRINTWHEEL "F" PRINTER FOLLOWS CONSOLE OUTPUT "N" NO PRINTER FOLLOWING CONSOLE "B" COMPUTER BEEPS WHEN KEY PRESSED (TOGGLE) "E" EDIT (JOYSTICK) TOGGLE "S" SLOW SCROLL TOGGLE "P" PAGE/SCROLL TOGGLE "W" WAIT AT SCREEN BOTTOM ENABLE SKIP THE ENTIRE THING | ; <<< CONSTANTS >>> ; ;MEMORY CONSTANTS: MSIZE = 56 ;SIZE OF MEMORY IN KBYTES MEMSIZ = (MSIZE*1024)-1 ;LAST RAM ADDRESS MSTACK = MEMSIZ-43H ;MONITOR STACK USTACK = MEMSIZ-57H ;USER STACK GOEXIT = MEMSIZ-2DH ;START OF EXIT ROUTN LOCGOT = MEMSIZ - 2AH ;GOTO INSTRUCTION LOCLXI = GOEXIT ;LXI H " LOCUSP = MEMSIZ - 2FH ;USER SP STORAGE ; ;MAP OF I/O CONTROL WORDS IOBYTE = 3 ;NOT INTEL STANDARD KYBDBF = 20H ;16 BYTES OF KEYBOARD BUFFER COLMNO = 41H ;PRINTER COLUMN NO FOR H TAB STS = 42H ;STATUS WORD FOR I/O OPERATIONS STSINZ = 10H ;INITIAL STS VALUE OUTCTL = 43H ;RSRVD FOR PASCAL, OUTPUT CONTL ;00 = OUTPUTS ENABLED; 0FFH = DUMP OUTPT (^F ;TOGGLE); ANYTHING ELSE = STOP (CTL S TOGGLE) CIPTR = 44H ;CI ROUTN POINTR FOR KYBD BUFF KYBDPR = 45H ;KYBD INTERRPT RTN PNTR, KYBDBF COL = 46H ;COLUMN NO. LIN = 47H ;LINE NO. LASTLN = 48H ;LAST LINE (CHANGE TO SCROLL) REVERS = 49H ;REVERSE FIELD TOGGLE (BIT 7) CTOGGL = 49H ;0-3: CONTROL NIBBLE FOR VIDEO LASTCH = 4AH ;LAST CHAR PRINTED (DIABLO PS) LASTSP = 4BH ;SPACING OF LAST CHAR (DIABLO) OLDDSP = 4CH ;CURRENT SPACING OF DIABLO (PS) PDWITH = 4DH ;USED BY R-JUSTIFYING TEXT OUT- ; PUTTERS: STORES # MICROSPCS TO ADD TO NXT BLNK DOPAD = 4DH ;0FFH -> NEXT CHAR = NO. USPACES COFLAG = 4EH ;MULTIPLE USES, ONLY 1 AT A TIME: ; BIT 0: 1 -> NEXT CHAR = GO TO Y COORD (+20H) ; BIT 1: 1 -> NEXT CHAR = " " X " " ; BIT 6: BACKSLASH FLAG (USED CP/M ONLY, 6&7 USED ; BIT 7: DELETE FLAG TO DUMP ECHOING DELETED CHAR) ERRFLG = 4FH ;DISK I/O ERROR FLAG FOR PASCAL DMAADD = 50H ;DMA ADDRESS STORAGE, DISK I/O NBYTES = 52H ;NO. BYTES TO R/W THIS SECTOR ; ; <<< DISK I/O TEMPORARIES >>>--disk routines still in progress ; DSKTMP = MEMSIZ-21H ;START OF DISK TEMP'S SECLEN = DSKTMP ;0=128/2=512 BYTES/SECTOR DSKDR = SECLEN+1 ;CURRENT DISK DRIVE NUMSEC = DSKDR+1 ;# SECTORS PER TRACK NUMDSK = NUMSEC+1 ;# DISKS ON LINE (1-4) DBLSID = NUMDSK+1 ;0FFH = DBL-SIDED DRIVE ERCNT = DBLSID+1 ;ERROR COUNT, DISK I/O IDECNT = ERCNT+1 ;ERROR COUNT, ID READ TRK = IDECNT+1 ;CURRENT TRACK NO. SECT = TRK+1 ;CURRENT SECTOR NO. ; IDTAB IS THE BUFFER FOR ID READS IDTAB = SECT+1 ;TRACK NO. IDTAB1 = IDTAB+1 ;ZERO IDTAB2 = IDTAB+2 ;SECTOR NO. IDTAB3 = IDTAB+3 IDTAB4 = IDTAB+4 ;CRC IDTAB5 = IDTAB+5 ;CRC ; TRKTBL = IDTAB+6 ; .REMARK| TRKTBL CONTAINS TRACK SECTOR SIZE & DENSITY FOR EACH DISK DRIVE (MAX 4 DRIVES) DRIVE ADDR TRACK DENSITY SECSIZ 4 TRKTBL 0 - 76 1 OR 2 0 OR 2 5 TRKTBL+3 9 TRKTBL+6 10 TRKTBL+9 MAP OF CONTROL PORT (AT 'CRTPRT'): (port contolling Objectv Desgn video) BIT 0: 0=8/1=7 DOTS/CHAR HORIZONTALLY BIT 1: 0=DISABLE/1=ENABLE VIDEO OUTPUT BIT 2: 0=NO WAIT/1=WAIT FOR HORZ SYNC(NO SNOW) BIT 3: 0=LOW/1=HIGH BEEP CONTROL BIT BIT 4: 0=CLR&DISABLE/1=ENABLE INTERRUPT BIT 5: 0=LOW/1=HIGH EXTERNAL CONTROL BIT BIT 6: 0=TO 5027/1=TO MEMORY: VIDEO R/W BIT 7: MEMORY: 0=CHARACTER AREA/1=4-BIT CNTRL 5027 ADDRESSES/DATA: (main LSI chip on Objectv Design Video board) ADD TVADD TO EACH OF THE FOLLOWING ADDRESSES: 0 = HORIZONTAL LINE CNT (TOT WIDTH) 8 BITS 1 = 7 6 5 4 3 2 1 0 0 HOR SYNC WIDTH HOR SYNC DELAY 2 = 7 6 5 4 3 2 1 0 0(X) SCANS/ROW CHARS/DATA ROW 3 = 7 6 5 4 3 2 1 0 SKEW (10) DATA ROWS/FRAME 4 = SCAN LINES/FRAME (BUT -256 AND /2) 5 = VERTICAL DATA START 6 = LAST DISPLAYED DATA ROW A = RESET B = UP SCROLL E = START TIMING CHAIN <<< MAP OF STACK >>> IN *ASCENDING* ORDER (ON TOP OF MEMORY) (ASSUME 56K) DFA0 ON DOWN: CP/M OR PASCAL BIOS DF80 - DFA7: USER STACK (28H BYTES) DFA8: INITIAL USER SP DFA8 - DFBB: MONITOR STACK (14H BYTES) DFBC: INITIAL MONITOR SP DFBC - DFD1: USER REGISTR STORAGE (14H BYTES): (see Zapple monitor) DFBC: R DFBD: I DFBF,E: Y DFC1,0: X DFC2: F' DFC3: A' DFC5,4: BC' DFC7,6: DE' DFC9,8: HL' DFCB,A: DE DFCD,C: BC DFCE: F DFCF: A DFD1,0: STACK POINTER DFD2 - DFDD: EXIT ROUTINE (0CH BYTES) DFD3,4: HL REG STORAGE DFD6,7: PC " " DFD8,9: 1ST TRAP ADDRESS DFDA: 1ST " DATA DFDB,C,D: 2ND TRAP DFDE - DFDD: DISK I/O TEMPORARIES DFFE,DFFF: KYBD INPUT VECTOR TOP OF MEMORY <> THE BIOS MUST LEAVE 128 BYTES FREE FOR PROPER MONITOR FUNCTION, THOUGH 96 (60H) ARE ENOUGH IF STACK NOT USED | ;CONSTANTS TVHADD = 0E8H ;HI BYTE TVADDRESS CRTPRT = 0E8H ;OUTPUT CONTROL PORT TVADD = TVHADD * 100H ;TOTAL ADDRESS TVRESET = TVADD + 0AH ;RESET 5027 TVSTART = TVADD + 0EH ;START 5027 TIMING CHAIN CRTINT = 7 ;INITLIZING DATA FOR CNTRL PORT MAXCOL = 80 ;MAX COLS PER LINE MAXLIN = 24 ;MAX LINES PER PAGE PASMSK = 40H ;STS MASK FOR PASCAL BIT PAGMSK = 10H ;STS MASK FOR PAGE/SCROLL BIT PCGRAM = 0E000H ;START OF PCG RAM ; ADR0 = 0E0H ;DMA ADDR. REGISTR PORT WCT0 = 0E1H ;DMA WORD COUNT REGISTER PORT CMND = 0E8H ;DMA COMMAND REGISTER PORT ADISK = 0F8H DCOM = ADISK DSTAT = ADISK TRACK = ADISK+1 SECTP = ADISK+2 DDATA = ADISK+3 DWAIT = ADISK+4 DCONT = ADISK+4 DMACHK = ADISK+5 ;DMA INTRQ. CHECK PORT ; ;CURSOR-MOVING INPUT CHARACTERS, USED BY READJY UPCURS = 11 ;^K (V-TAB) DNCURS = LF RTCURS = FF ;^L LFCURS = BS ; ;I/O PORTS: LINEPT = 21H ;MALIBU PRINTER STATUS/DATA DBSTAT = 24H ;DIABLO STATUS INFO DBDATA = 25H ;DIABLO DATA PORT TARBST = 0 ;TARBELL STATUS TARBDA = 1 ;TARBELL DATA HORJOY = 0FH ;HORIZONTAL POT OF JOYSTICK VERJOY = 0EH ;VERTICAL POT SENSE = 0FFH ;SENSE SWITCHES ; TVPARM: .BYTE 70H,7BH,4DH,97H,03H,14H,23 ; ONMSG: .ASCIZ [FF]'GZAP MONITOR V2.0' ; CSTART: MVI A,STSINZ ;INITL STS VALUE STA STS MVI A,81H ;INITL IOBYTE STA IOBYTE LXI SP,MSTACK LXI D,ONMSG CALL PRTMSG ESTART: CALL WARMIZ ;ERROR START POINT RET ;normally, monitor would start here ; WARMIZ: SUB A ;this routine is also called by external STA COLMNO ; routines (primarily CP/M and Pascal BIOS) when LXI H,REVERS ; I wish to reinitialize console i/o. MVI B,7 ..ZERO: MOV M,A ;zero out part of i/o variable space INX H DJNZ ..ZERO LXI H,MEMSIZ-2 ;JUST BELOW KYBDVC MVI B,66 ..ZRIT: MOV M,A ;zero out high memory DCX H DJNZ ..ZRIT LXI H,USTACK SHLD LOCUSP ;INITLZ USER SP--used by Zapple MVI A,0C3H STA LOCGOT ;JUMP INSTRUCTN STA 38H ;TRAP MVI A,21H ;LXI H,... INSTRUCTN STA LOCLXI LXI H,TRAP ;38h contains jump to monitor trap SHLD 39H LXI H,KYBDBF MOV A,L STA CIPTR STA KYBDPR MVI B,10H IKBF: MVI M,0FFH ;fill keyboard buffer with 0ffh's (means empty) INX H DJNZ IKBF LXI H,KYBDIN SHLD MEMSIZ-1 ;KYBDVEC LOCATN RET ; ; ;MONITOR I/O ROUTINES ; ; The joystick routines utilize a Cromemco D + 7A I/O board. HORPOS: MVI A,RTCURS RNC MVI A,LFCURS RET ; VERPOS: MVI A,UPCURS RNC MVI A,DNCURS RET ; GETVER: IN VERJOY GETDIS: RAL ;input is in 2's compliment JRC FLIPIT ;1 in bit 7 -> negative displacement ANI 0C0H ;ignore any but > 1/4 from center RET FLIPIT: CMA ANI 0C0H STC RET ; READJY: POP H ;joystick routine begins here EI PUSH B LDA STS ;see if joystick enabled ANI 2 JRZ CFLASH ;skip if not IN HORJOY CALL GETDIS JRNZ GETJTM ;got a horizontal displacement CALL GETVER JRZ CFLASH ;skip if no horiz or vertical displacement GETJTM: CPI 40H ;see the magnitude of the displacement JRNZ NXTJOY MVI C,14 ;least displacement -> longest delay JMPR JOYTIM NXTJOY: CPI 80H JRNZ NXTJY1 MVI C,4 ;mid displacement -> less delay JMPR JOYTIM NXTJY1: MVI C,1 ;must be great displacement, short delay JOYTIM: CALL FLSHTV ;flash cursor for length of time in C POP B JRNZ MCI ;but abort if key pressed IN HORJOY ;now look at joystick all over again CALL GETDIS ; to see if changed JRNZ HORPOS ;and return appropriate control char if displaced CALL GETVER JRNZ VERPOS PUSH B CFLASH: MVI C,20 ;flash cursor to let 'em know you're waiting CALL FLSHTV POP B ; MCI: PUSH H ;main console input routine entry MVI A,MEMSIZ>8 ;HIBYTE ;this sets up correct location of STAI ;keyboard interrupt jump vector IM2 ; ("KYBDVEC") CALL CHKCI JRZ READJY ;if no input waiting, see if joystick enabled DCR A ; else correct char input MVI M,0FFH ;store 0ffh to mark buffer spot blank PUSH PSW LDA IOBYTE RAR ;if enabled, CC BEEP ;ACKNOWLEDGE KYBD INPUT MOV A,L STA CIPTR ;save present buffer pointer POP PSW POP H RET ; BEEP: PUSH B ;this routine puts out a very brief "beep" to MVI H,5 ; my speaker (via the Cromemco D+7AI/O) to mark MVI C,60H ; keyboard input. A rough sawtooth wave. ..LOOP: MOV B,C MVI A,7FH OUT 9 ..B0: DJNZ ..B0 MVI A,40H OUT 9 MOV B,C ..B1: DJNZ ..B1 SUB A OUT 9 MOV B,C ..B2: DJNZ ..B2 DCR H JRNZ ..LOOP POP B RET ; MCSTS: PUSH H ;this is main Console STatuS routine CALL CHKCI POP H RZ ;0 -> no input char awaiting MVI A,0FFH ;0ffh -> input char ready RET ; CHKCI: LHLD CIPTR MVI H,0 MOV A,M INR A RNZ CHKNCH: INX H MOV A,L ANI 0FH JRNZ OKPTR LXI H,KYBDBF OKPTR: MOV A,M INR A RET ; KYBDIN: PUSH PSW ;this is main keyboard interrupt handler PUSH B PUSH H CALL SVKYBD ;doing it this way allows multiple exits, POP H ; but only one set of register push/pop's POP B POP PSW EI RET ; SVKYBD: IN 20H ;data port - no need to check status port (caused ANI 7FH ; interrupt) CPI 1DH ;^] = GO TO SPECIAL I/O JRZ SPECIO ; ROUTINE CPI 6 ;^F = PASCAL FLUSH ALL JRZ SOCTL ; OUTPUT TOGGLE CPI 13H ;^S = PASCAL STOP ALL JRZ SOCTL ; OUTPUT TOGGLE CPI 1EH ;CTL '^' = FORCED ERROR JRZ GOTRAP PUSH PSW ;SAVE CHAR STOCHR: LHLD KYBDPR MVI H,0 MOV A,M ;see where next empty buffer slot is INR A JRZ PUTCHR CALL CHKNCH JRZ PUTCHR CALL HONK ;error with buffer pointer POP PSW RET PUTCHR: POP PSW ;got an empty slot; store char MOV M,A MOV A,L STA KYBDPR RET ; SOCTL: PUSH PSW ;SAVE CHARACTER LDA STS ;SEE IF ENABLED ANI 40H ;ONLY FOR PASCAL JRZ STOCHR LDA OUTCTL ;NOW SEE WHAT TO DO ORA A ;IF NOW 0, SET IT JRZ SETOC INR A ;IF FF, RESET IT JRZ RESOC POP PSW ;ELSE CHECK IF CHNG FROM CPI 6 ;STOP TO DUMP (CTL F = 6) JRZ SETDMP ;THEN SET TO DUMP PUSH PSW ;ELSE RESOC: POP PSW ;RESET OUTCTL SUB A JMPR STOROC SETOC: POP PSW CPI 13H ;IF ^S (STOP OUTPUT), JRZ STOROC ;THEN STORE NON-0/FF SETDMP: MVI A,0FFH ;ELSE SIGNAL DUMP STOROC: STA OUTCTL RET ; GOTRAP: POP H ;CLEAR RETURN TO KYBDIN POP H ;RESTORE REGISTERS POP B POP PSW JMP RESTART ;this is my trap routine--you'll have to add your own ; *NOTE* RESTART is not defined in this short version!!! SPECIO: CALL MCI ;this routine allows you to change i/o parameters on ANI 05FH ;CONVT TO UPPER CASE the fly! CPI ESC ;A WAY OUT RZ MVI C,FF ;READY TO CLEAR LXI H,STS ;OR FIX STS CPI ']' ;CLEAR TV JZ CO CPI 'D' ;CHANGE TO DIABLO JRZ ..DIAB CPI 'R' ;PROPORTNL SPACE WHEEL JRZ ..PSPC CPI 'A' ;STANDARD PRINTWHEEL JRZ ..SSPC CPI 'M' ;CHANGE TO MALIBU JRZ ..MALB CPI 'P' ;PAGE/SCROLL MODE TOGGL JRZ ..PAGE CPI 'S' ;SLOW DOWN SCROLL TOGGL JRZ ..SLOW CPI 'W' ;WAIT AT BOTTOM TOGGLE JRZ ..WAIT CPI 'E' ;EDIT (JOYSTICK) TOGGLE JRZ ..EDIT CPI 'F' ;PRINTER FOLLOWS CNSOLE JRZ ..FLLW ; (PASCAL ONLY) CPI 'N' ;PRINTER DOES NOT JRZ ..NOFW ; FOLLOW CONSOLE CPI '\' ;FORM FEED TO MALIBU JRZ ..MFF CPI '@' ;FORM FEED TO DIABLO JRZ ..DFF LXI H,IOBYTE CPI 'B' ;KEYBOARD BEEP TOGGLE JRZ ..BEEP CPI 'L' ;LOGICAL LIST--> PRINTR JRZ ..LIST CPI 'C' ;LOGICAL LIST--> CRT JRNZ SPECIO ;ELSE WRONG CHAR TYPED RES 7,M RET ..DIAB: SET 5,M RET ..PSPC: SET 0,M ;PROPORTIONAL-SPACE RET ..EDIT: MVI A,2 ;EDIT BIT JMPR ..TSTS ..FLLW: SET 7,M ;PRINTER TO FOLLOW CO RET ..MALB: RES 5,M ;PRINTER TO MALIBU RET ..NOFW: RES 7,M ;NO PRINTER FOLLOW RET ..SSPC: RES 0,M ;STANDARD PRINTWHEEL RET ..PAGE: MVI A,10H ..TSTS: XRA M ;TOGGLE STS MOV M,A RET ..SLOW: MVI A,8 JMPR ..TSTS ..WAIT: MVI A,4 JMPR ..TSTS ..MFF: MOV A,C OUT LINEPT RET ..DFF: MOV A,C OUT DBDATA ;HOPE NO CONFLICT RET ..BEEP: MVI A,1 JMPR ..TSTS ..LIST: SET 7,M ;SET BIT 7 RET ; ; GETPAD: MOV A,C SUI 20H STA PDWITH RET ; LIST: LDA DOPAD ;this is entry to main list routine INR A ;SEE IF THIS CHAR = # U-SP (no. of microspaces) JRZ GETPAD LDA IOBYTE ;IF LIST NOT -> CRT, RAL ; JRC ..OK ;THEN DO IT, LDA STS ;ELSE IF LISTER TRYING RAL ; TO FOLLOW CRT, RC ; THEN DUMP, (don't write it twice on CRT) JMP CO ; ELSE SEND IT TO CRT ..OK: PUSH H PUSH D PUSH B CALL DOLIST POP B POP D POP H MOV A,C RET ; DOLIST: CALL CHKOCL ;CHECK OUTCTL IF ENABLD MOV A,C RNZ ;DUMP IF CTL F ACTIVE LXI H,COLMNO CPI ' ' JRC LOCTL ;special handling for control characters INR M ;INCR COLUMNO GOLO: LDA STS ;SEE WHICH PRINTER BIT 5,A ;STS BIT 5 DETERMINES JRNZ GODIAB ; ;MALIBU DRIVER ROUTINE -- next few steps dump characters that mess up listing CPI 13H ;10 STEPS/LF = GRAPHICS RZ ; LINE FEED CPI 16H ;STANDARD GRAPHICS CHAR RZ ; SET CPI 17H ;16 STEPS/LF = CONDENS- RZ ;ED LF (NORMAL = 20 STEPS/LF) LIST0: CPI 10H ;ALT CHR SET 1; RZ ;ENTER HERE;FOR NL GRAPHICS (BUT MOV A,C) CPI 12H ;ALT CHAR SET 2 RZ LIST1: IN LINEPT ;status port (input) = data port (output) RAR JRC LIST1 MVI A,20H ..LLP: DCR A JRNZ ..LLP MOV A,C CPI '}' ;MALIBU WON'T PRINT RT JRNZ ..GO ; BRACKET. MVI A,'>' ..GO: OUT LINEPT RET ; LOCTL: CPI CR ;control character routines to keep column no. current JRZ ..CR CPI CRONLY JRZ ..CRO CPI BS JRZ ..BS CPI PADNXT JRZ ..PAD CPI HT JRNZ GOLO ..HT: MVI C,' ' ;expand horizontal tabs CALL LIST MOV A,M ANI 7 JRNZ ..HT RET ..CRO: MVI C,CR ..CR: MVI M,0 JMPR GOLO ..BS: DCR M JMPR GOLO ..PAD: MVI A,0FFH ;pad char means next char is extra no. of microspaces STA DOPAD ; to add to next blank (used with Diablo to ease right RET ; justification) ; GODIAB: RAR ;SEE WHICH PRINTWHEEL JRNC DIABLO ;JUMP IF STANDARD ; PRPRTL: LXI H,LASTCH ;PROPORTIONAL SPACING MOV A,C SUI ' ' ;NOW SEE WHAT CHAR JRNC ..PRT ;JMP IF PRINTING CHAR PUSH B MVI B,0 ;ELSE MUST BE CTL CHAR CALL SPDIAB ;SET 0 SPACES/CHAR MOV C,M ;PRINT OLD CHAR CALL DIABLO POP B SUB A ;TELL 'M LAST WAS CTL MOV M,A INX H MOV M,A MOV A,C ;IF THIS CHAR = BS CPI BS ; THEN EXIT (NOTE: > 1 RZ ; BS IN ROW IS DUMPED) JMPR DIABLO ;ELSE PRINT & EXIT ..PRT: PUSH H LXI H,PROTBL MOV E,A MVI D,0 DAD D MOV B,M ;GET NEW DISPLACEMENT POP H MOV A,B ;IS THIS VALID CHAR? ORA A ;0 = NO, PAD W/ BLANK JRNZ ..NPAD LXI B,800H + ' ' ;16 USPACES WIDE ..NPAD: LDA LASTSP ;OLD DISPLACEMENT ORA A ;WAS LAST CTRL CHAR? JRZ ..SKIP ;THEN FORGET SPACING, ADD B ;ELSE GET TOTAL PUSH B ;SAVE CHAR & DISPLCMT MOV B,A ;SEND CORRECT SPACING CALL SPDIAB MOV C,M ;NOW PRINT OLD CHAR CALL DIABLO POP B ..SKIP: MOV M,C ;STORE THIS CHAR... INX H MOV M,B ; AND THIS DISPLACEMENT RET ; SPDIAB: LDA OLDDSP ;IF OLD SPACING = THIS CMP B ; ONE, NOTHING TO DO. RZ ;else set spacing to correct new value (in B) MOV A,B STA OLDDSP MVI C,ESC CALL DIABLO MVI C,1FH CALL DIABLO MOV C,B INR C ;ADD ONE TO TRUE SPACE ; DIABLO: IN DBSTAT ;diablo driver RAL JRC ..GCH ..SEND: IN DBSTAT RAR JRNC ..SEND MOV A,C OUT DBDATA CPI ' ' ;IF SPACE, THEN RNZ LDA PDWITH ;SEE IF PADDING NEEDED ORA A RZ ;IF NOT, ALL DONE. MOV B,A SUB A STA PDWITH ;RESET CALL SPDIAB ;SET WIDTH OF SP NEEDED MVI C,' ' ;TO PAD, CALL DIABLO ; PRINT ALTERED SPACE MVI C,ESC ;RESTORE NL SPACING (IG- CALL DIABLO ;NORED BY PROPOR SP RTN) MVI C,'S' JMPR DIABLO ; ..GCH: IN DBDATA ;see if buffer-full char sent CPI 13H JRNZ ..SEND ;if not, go on ..WAIT: IN DBSTAT ;else wait til empty RAL JRNC ..WAIT IN DBDATA JMPR ..SEND ; PROTBL: ;PROPORTIONAL SPACING TABLE .BYTE 6 ;' ', HEX 20 (PRINTS AS CENTS) .BYTE 3 ;'!' .BYTE 4 ;'"' .BYTE 6 ;'#' .BYTE 5 ;'$' .BYTE 8 ;'%' .BYTE 7 ;'&' .BYTE 2 ;''' .BYTE 3 ;'(', HEX 28 .BYTE 3 ;')' .BYTE 5 ;'*' .BYTE 5 ;'+' .BYTE 3 ;',' .BYTE 4 ;'-' .BYTE 3 ;'.' .BYTE 4 ;'/' .BYTE 5 ;'0', HEX 30 .BYTE 5 ;'1' .BYTE 5 ;'2' .BYTE 5 ;'3' .BYTE 5 ;'4' .BYTE 5 ;'5' .BYTE 5 ;'6' .BYTE 5 ;'7' .BYTE 5 ;'8', HEX 38 .BYTE 5 ;'9' .BYTE 3 ;':' .BYTE 3 ;';' .BYTE 6 ;'<' (PRINTS AS "1/4") .BYTE 5 ;'=' .BYTE 6 ;'>' (PRINTS AS "1/2") .BYTE 5 ;'?' .BYTE 8 ;'@', HEX 40 .BYTE 7 ;'A' .BYTE 6 ;'B' .BYTE 7 ;'C' .BYTE 7 ;'D' .BYTE 6 ;'E' .BYTE 6 ;'F' .BYTE 7 ;'G' .BYTE 7 ;'H', HEX 48 .BYTE 3 ;'I' .BYTE 5 ;'J' .BYTE 7 ;'K' .BYTE 6 ;'L' .BYTE 8 ;'M' .BYTE 7 ;'N' .BYTE 7 ;'O' .BYTE 6 ;'P', HEX 50 .BYTE 7 ;'Q' .BYTE 7 ;'R' .BYTE 5 ;'S' .BYTE 6 ;'T' .BYTE 7 ;'U' .BYTE 6 ;'V' .BYTE 8 ;'W' .BYTE 7 ;'X', HEX 58 .BYTE 7 ;'Y' .BYTE 6 ;'Z' .BYTE 0 ;'[' NONPRINTING .BYTE 0 ;'\' NONPRINTING .BYTE 0 ;']' NONPRINTING .BYTE 0 ;'^' NONPRINTING .BYTE 5 ;'_' .BYTE 3 ;'`', HEX 60 (PRINTS AS ",") .BYTE 5 ;'a' .BYTE 5 ;'b' .BYTE 5 ;'c' .BYTE 5 ;'d' .BYTE 5 ;'e' .BYTE 4 ;'f' .BYTE 5 ;'g' .BYTE 5 ;'h', HEX 68 .BYTE 3 ;'i' .BYTE 3 ;'j' .BYTE 5 ;'k' .BYTE 3 ;'l' .BYTE 8 ;'m' .BYTE 5 ;'n' .BYTE 5 ;'o' .BYTE 5 ;'p', HEX 70 .BYTE 5 ;'q' .BYTE 4 ;'r' .BYTE 4 ;'s' .BYTE 4 ;'t' .BYTE 5 ;'u' .BYTE 5 ;'v' .BYTE 7 ;'w' .BYTE 5 ;'x', HEX 78 .BYTE 5 ;'y' .BYTE 5 ;'z' .BYTE 3 ;'{' (PRINTS AS ".") .BYTE 0 ;'|' NONPRINTING .BYTE 0 ;'}' NONPRINTING .BYTE 0 ;'~' NONPRINTING .BYTE 0 ; NONPRINTING ; ; ;********************************* ;* * ;* SPEAKER DRIVER ROUTINE * ;* * ;********************************* ; ;PLAY NOTE (PITCH IN L, DURATN IN H) ; NOTE: DURATION IS SHORTER FOR HIGHER PITCH ; [ROUGHLY ~ 1 / LOG (FREQ)]; SHAPE ~ TRIANGLE TONE: MOV D,H MOV E,L MOV C,L ..LOOP: MVI A,3AH OUT 9 MOV B,C ..T1: DJNZ ..T1 MVI A,54H OUT 9 MOV B,C ..T2: DJNZ ..T2 MVI A,7FH OUT 9 MOV B,C ..T3: DJNZ ..T3 MVI A,54H OUT 9 MOV B,C ..T4: DJNZ ..T4 MVI A,3AH OUT 9 MOV B,C ..T5: DJNZ ..T5 MOV B,C SUB A OUT 9 ..T6: DJNZ ..T6 STC RALR E JRNC ..LOOP STC RALR L JRNC ..LOOP DCR D JRNZ ..LOOP RET ; HONK: LXI H,5020H ;20H-LONG TONE FREQ 50H DOTONE: PUSH D CALL TONE POP D RET ; ;********************************************** ;* OBJECTIVE DESIGN VIDEO DRIVER SUBROUTINES * ;********************************************** ; ;ENTER AT TVOUT: ; TVHOME: SUB A MOV B,A ;Y = 0 MOV E,A ;CARRIAGE RTN ; GOTOY: LDA LASTLN ;PUT CURSOR ON LINE MOV D,A ;Y-TH FROM TOP INR B ;PASSED IN B ..GY1: CALL NLF DJNZ ..GY1 RET ; ;SPECCO USED FOR GOTOXY ROUTINES AND CP/M DELETE ; HANDLING (ECHOED CHARACTERS ARE DUMPED AFTER A ; DELETE; THE CURSOR IS BACKED UP INSTEAD. SPECIAL ; PROVISION IS MADE TO DUMP MBASIC'S BACKSLASHES). ; THE DELETE FLAG BE SET IN CP/M CBIOS ; WHEN CONSLIN ROUTINE DETECTS DELETE CHAR TYPED SPECCO: LXI H,COFLAG MOV B,A MOV A,C SUI 20H ;PREPARE FOR GOTO X/Y DCR M ;SEE IF GOTOY JRZ ..GOTY BIT 0,M ;? GOTOX JRNZ ..GOTX MOV A,B RAL ;A HAS INTACT BYTE JRC ..GDF RES 6,M ;MUST HAVE BEEN BACK- RET ; SLASH FLAG ..GOTY: MOV B,A JMPR GOTOY ..GOTX: MOV E,A RET ..GDF: MOV A,C ;IF CHAR = "\", THEN WE'RE CPI '\' ; IN MBASIC; DUMP THIS CHAR JRNZ ..NBS ; AND FLAG TO DUMP ONE MORE SET 6,M RET ..NBS: CPI 7FH ;DUMP DELETE CHARS RZ RES M,7 ;ELSE RESET COFLAG CPI ' ' ; AND IF CONTROL CHAR RC ; THEN DUMP MVI C,BS ; ELSE DO BS-SPACE-BS CALL CO MVI C,' ' CALL CO MVI C,BS ; TVOUT: LDA COFLAG ORA A JRNZ SPECCO MOV A,C CPI ' ' JRC TVCNTL ;special handling for contrl chars CHAR: CPI 40H ;SPECIAL CAPS ALPHABET JRC ..C ; (HARDWARE SPECIFIC) CPI 60H JRNC ..C ANI 1FH MOV C,A ..C: LDA REVERS ANI 80H ;GET RID OF ALL BUT 7TH ORA C ;SET BIT IF NEEDED (causes reversed char) MOV M,A LDA CTOGGL ;GET TOGGLE BYTE (<>0 means grey &/or graphics char) ANI 0FH ;GET RID OF LAST 4 BITS JRZ ..C1 MOV B,A ;ctoggl itself moved to control memory CALL CTRL ;SWITCH TO CONTRL MEMRY MOV M,B CALL DSPLY ;RESTORE ..C1: CALL INCURS SUB A ORA E RNZ ;ALL DONE IF NOT START JMP DELLIN ; OF LINE ; TVCNTL: CPI 1EH ;+1 > THAN MAX CTL CHAR RNC SUI 7 ;CHAR < 7 IGNORED RC ADD A ;2 BYTES/ENTRY LXI H,TVTBL MVI B,0 MOV C,A DAD B ;GET DISPLACEMENT MOV C,M INX H MOV B,M MOV H,B MOV L,C PCHL ; TVTBL: .WORD HONK ;07 = ASCII BELL .WORD TVBS ;08 = ASCII BACKSP .WORD TVHTAB ;09 = ASCII HTAB .WORD TVLF ;0A = ASCII LINEFEED .WORD QUIT ;0B NOT USED .WORD TVFF ;0C = ASCII FORMFEED .WORD TVCR ;0D = ASCII CR .WORD GOTOY ;0E = GOTOY (PASSED IN B) .WORD QUIT ;0F NOT USED .WORD QUIT ;10 NOT USED <*AVOID*> .WORD TVCR ;11(^Q),ALTERNATE CR .WORD DOTONE ;12(^R),PLAY TONE .WORD QUIT ;13 NOT USED .WORD INCURS ;14(^T),NONDESTRCTIV SP .WORD DELLIN ;15(^U),ERASE TO END LN .WORD DELSCN ;16(^V),ERASE TO END SC .WORD TVRLF ;17(^W),REVERSE LINEFD .WORD GOTOXY ;18(^X),SET GOTOXY FLAG .WORD TVREV ;19(^Y),REVERSE TOGGLE .WORD TVHOME ;1A(^Z),HOME CURSOR .WORD QUIT ;1B NOT USED .WORD TVGREY ;1C(^\),GREY TONE TOGGL .WORD TVPCG ;1D(^]),GRAPHICS TOGGLE ; GOTOXY: MVI A,2 STA COFLAG RET ; TVHTAB: MOV A,E CPI MAXCOL-1;DUMP IF END OF LINE RNC CALL INCURS MOV A,E ANI 7 JRNZ TVHTAB QUIT: RET ;USED TO ABORT ; TVBS: DCR E RP ;OK IF NOT OFF END OF LINE INR E RET ; TVCR: MVI E,0 RET ; DELSCN: PUSH D ..LP: CALL DELLIN LDA LASTLN CMP D JRZ ..DONE CALL NLF MVI E,0 ;ERASE WHOLE NEXT LINE JMPR ..LP ..DONE: POP D RET ; TVRLF: SUB A ORA D JRNZ ..OK ;CHECK NOT TOP LINE LDA STS ;STILL OK IF NOT ANI PAGMSK ;IN PAGE MODE RZ MVI D,24 ;RESET D ..OK: DCR D LDA LASTLN CMP D RNZ ;NO SCROLL NEEDED DCR A ;DCRMENT LASTLN FOR REV JP SCROLL ; SCROLL MVI A,23 JMPR SCROLL ; ; INCURS: INR E ;increment cursor MOV A,E CPI MAXCOL ;INCR OK IF NOT OFF LIN RNZ DCR E LDA STS CMA ANI PASMSK+PAGMSK ;IF SCROLL MODE RZ ;AND PASCAL THEN DUMP TVCRLF: MVI E,0 ;ELSE CRLF ; TVLF: LDA LASTLN CMP D ;IF NOT LAST LINE, JNZ NLF ; JUST INCR CALL NLF ; ELSE 1ST GO TO NEXT LDA STS ; LINE. ANI PAGMSK ;IF PAGE MODE THEN JRZ TVPAGE CALL SLOSCL ;DELAY IF CHOSEN LDA LASTLN INR A CPI 24 JRC SCROLL ;CORRECT IF OUT OF SUB A ; BOUNDS SCROLL: STA LASTLN ;SAVE FOR FUTURE PUSH PSW ; REFERENCE CALL FRMAT ;GO INTO CONTROL MODE POP PSW STA TVADD+6 ;SEND TO 5027 TO SCROLL CALL DSPLY ;BACK INTO DATA MODE ERSTLN: PUSH D ;ERASE THIS WHOLE LINE MVI E,0 CALL DELLIN POP D RET TVPAGE: CALL WAIT ;WAIT IF CHOSEN, THEN: ; TVFF: SUB A ;this part wholly resets TV board STA CTOGGL OUT CRTPRT STA TVRESET ;RESET 5027 LXI H,TVPARM LXI D,TVADD LXI B,7 LDIR STA TVRESET ;DUMMY DATA TO RESET STA TVSTART ;AND START 5027 AGAIN MVI A,23 STA LASTLN MVI A,41H ;SWITCH TO DATA CALL CLRIT MVI A,0C5H ;SWITCH TO CNTRL MEMORY CALL CLRIT LXI D,0 JMPR DSPLY ; TVREV: MVI A,80H JMPR CTLTGL TVGREY: MVI A,1 ;GREY MASK JMPR CTLTGL TVPCG: MVI A,12 ;PCG ENABLE SWITCH CTLTGL: LXI H,CTOGGL XRA M MOV M,A RET ; DELLIN: PUSH D ;delete rest of this line CALL CONVT1 MVI A,63 MVI B,' ' ..DL1: CMP E JRC ..MT64 ;MUST BE PAST 63RD COL MOV M,B INX H INR E JMPR ..DL1 ..MT64: CALL CONVT1 ;SET HL TO NEW MEMORY MVI A,MAXCOL-1 ; AREA ..DL2: CMP E JRC ..RTN MOV M,B INX H INR E JMPR ..DL2 ..RTN: POP D RET ; CLRIT: OUT CRTPRT MVI B,' ' LXI H,TVADD LXI D,780H ;SIZE OF MEMORY ..LP: MOV M,B INX H DCX D MOV A,D ORA E JRNZ ..LP RET ; NLF: INR D ;PLAIN, NONSCROLLING MOV A,D ; LINE FEED. CPI 24 ;OK UNLESS > 23 RC MVI D,0 RET ; ; CONVT: LHLD COL ;find present cursor location in screen memory XCHG ;D HAS LIN, E HAS COL CONVT1: MOV A,E ;ENTER HERE IF ALREADY CPI 64 ; HAVE LIN & COL JRNC INAUX MOV A,D RRC RRC ;LIN * 64 MOV H,A ANI 0C0H ADD E ;ADD COL MOV L,A ;LOW BYTE ABSOLUTE ADDR MOV A,H ANI 7 ADI TVHADD MOV H,A ;HI BYTE RET INAUX: ANI 15 ;GET DISPLACEMENT MOV L,A ;TEMP STORAG MOV A,D RRC RRC RRC RRC ;LIN * 16 MOV H,A ;TEMP STORAGE ANI 0F0H ADD L MOV L,A ;CORRECT LOW BYTE MOV A,H ANI 15 ADI TVHADD+6 ;START OF AUX MEM (HI) MOV H,A ;CORRECT HI BYTE RET ; CTRL: MVI A,0C0H ;this signals video board to switch to alternate memory SETPRT: ORI CRTINT ;ADD INITLZING DATA (used only for grey scale & OUT CRTPRT graphics) RET ; DSPLY: MVI A,40H ;go to main display (ie, normal) memory JMPR SETPRT ; FRMAT: SUB A ;switch to 5027 registers JMPR SETPRT ; STOPIT: HLT ;WAIT FOR ANY INPUT CHKOCL: LDA STS ;CHECK IF OUTCTL ENABLD ANI PASMSK RZ LDA OUTCTL ORA A ;0 = ALL OK RZ INR A ;0FFH = DUMP JRNZ STOPIT DCR A ;RESET ZFLAG RET ; FLSHTV: PUSH H ;flash cursor for length of time in C PUSH D CALL CONVT POP D MOV B,M PUSH B MVI A,80H XRA M MOV M,A FLTV0: CALL TIMR ;delay DCR C JRZ FLNXT CALL CSTS ;abort if char typed JRZ FLTV0 FLNXT: POP B MOV M,B ;restore char POP H FLTV1: CALL CSTS RNZ DCR C RZ CALL TIMR JMPR FLTV1 ; TIMR: MVI B,11 TIM0: SUB A TIM1: DCR A JRNZ TIM1 DJNZ TIM0 RET ; WAIT: LDA STS ANI 4 ;SEE IF WAIT ENABLED RZ WAITOK: JMP CI ;wait 'til keyboard input (dump) & return ; SLOSCL: LDA STS ANI 8 ;SEE IF SLOW SCROLL RZ ; ENABLED. IN 0FFH ;SENSE SWITCHES determine time constant MOV B,A JMPR TIM0 ; ; RI: INR A JRNZ NORESET ;0FFH IN REG A CAUSES RRESET: MVI A,10H ; RESET OUT TARBST RET NORESET: CALL CSTS JRZ RI1 CALL CI STC RET RI1: IN TARBST ANI 10H JRNZ NORESET IN TARBDA RET ; PO: IN TARBST ANI 20H JRNZ PO MOV A,C OUT TARBDA RET ; ;************************ ;* SUBROUTINES * ;************************ ; ; PRTMSG: LDAX D ORA A RZ MOV C,A CALL CO INX D JMPR PRTMSG ; BLK: MVI C,' ' ; CO: CALL CHKOCL MOV A,C RNZ PUSH H PUSH D PUSH B CPI FF JRZ ..GO LDA STS RAL CC LIST ..GO: CALL CONVT CALL TVOUT XCHG SHLD COL ;SAVE VIDEO PARAMETERS POP B POP D POP H MOV A,C RET ; CRLF: MVI C,CR CALL CO MVI C,LF JMPR CO ; .END ;but this won't assemble without RESTART being defined or deleted ; (see keyboard interrupt vector handler) notes on quickie interrupt hardware: Tie the interrupt acknowledge line to an 8T97 (3-state buffer) so that it pulls down Bit 0 when active (but otherwise does not affect it one way or another). This will give you an interrupt vector location at location 0FE hex at any page you wish. Let me know if the above material is not terribly clear (though I assume a reasonable knowledge of assembly language programming in my notes, and I don't think you can use this material without it).