;*************** WINDOWS *************** ;A subroutine to break up a memory mapped ;video display into separate smaller screens ;to display text. Each small screen will be ;called a BOX. A maximum of 255 BOXes can be ;set-up. Each BOX (screen) will respond to ;the normal commands of carriage-return, line ;feed, home, form-feed, up, down, right, left, ;and backspace. BOXes can overlap, but no BOX ;should be larger than the whole screen. ; ;Written by Malcolm T. Wright, 5-8-80 ; ;To output to a BOX, place the BOX number(1 ;to 255) in the A-Register and the character ;to be outputted in the C-Register. A BOX ;number of 0 will clear the screen. ; ;The parameters for each BOX is stored in ;a table lableled "BXTBL". The first byte ;of BXTBL is the number of defined BOXes. ;Each BOX is defined as a subtable of 6 bytes. ;Each subtable uses 4 bytes for the BOX's ;size and two bytes for its cursor. ;Subtable: ; 1st byte = Left side (0 to NCOLS-1) ; far left=0 ; 2nd byte = Top (0 to NROWS-1) ; max. top=0 ; 3rd byte = Right side (0 to NCOL-1) ; far right=NCOLS-1 ; 4th byte = Bottom (0 to NROWS-1) ; the bottom=NROWS-1 ; 5th byte = Cursor horizontal ; ; 6th byte = Cursor vertical ; TRUE EQU 0FFFFH FALSE EQU NOT TRUE ;Width of Video Screen W64 EQU FALSE W80 EQU FALSE VB3 EQU TRUE ;SSM VB3 BOARD ; ;Video Parameters VID EQU 0C000H ;BOARD'S ADDRESS NCOLS EQU 80 ;WIDTH OF SCREEN NROWS EQU 18 ;HEIGHT OF SCREEN VTAC EQU 0D0H ;VB3 CTRL PORTS KSTAT EQU 0E0H ;TURN-ON VB3 KDATA EQU KSTAT+1 ;TURN-OFF VB3 ;Special Characters CR EQU 0DH ;CARRIAGE-RET LF EQU 0AH ;LINE-FEED BS EQU 08H ;BACKSPACE HM EQU 02H ;HOME (CTRL-B) UP EQU 0BH ;MOVE UP (CTRL-K) DN EQU LF ;MOVE DOWN RT EQU 09H ;MOVE RIGHT (CTRL-I) LT EQU BS ;MOVE LEFT FF EQU 0CH ;FORM-FEED (CTRL-L) ;Test purposes. LOC EQU 200H ;TEST ONLY ORG 100H ;Test routine. ;Echo ALL characters except special ones ;defined in previous table. If escape ;is typed followed by a number, then that ;number selects a new BOX. Sample ;BOXes have been set-up in the BXTBL area ;for a 64 character wide screen. BEGIN: CALL CI ;CONSOLE INPUT CPI 03H ;CTRL-C? JZ 0 ;RE-BOOT CP/M. ;TEST FOR BOX CHANGE CPI 1BH ;ESCAPE? JNZ BEG1 CALL CI ;GET NUMBER. MOV C,A ;SAVE A COPY SUI '0' CPI 9+1 MOV B,A ;SAVE NO. MOV A,C ;GET CHAR. JNC BEG1 ;JMP IF NOT A NO. MOV A,B ;GET BOX NO. STA BXNO ;SAVE IN BOX NO. JMP BEGIN ;OUTPUT CHARACTER BEG1: MOV C,A LDA BXNO ;GET BOX NUMBER CALL ENTER ;CONSOLE OUTPUT JMP BEGIN ;CONSOLE INPUT (CP/M) CI: LHLD 1 ;READ WARM BOOT ADDRESS LXI D,6 ; FOR CONSOLE INPUT WITH DAD D ; NO OUTPUT ECHO. PCHL ;JUMP TO BIOS ;Save box number here. BXNO: DB 1 ;BOX NUMBER ORG LOC ; ;********** Main Entry Point ********** ENTER: PUSH H ;SAVE REGISTERS PUSH D PUSH B LXI H,BXTBL ;START OF BOX TABLE OUT KSTAT ;TURN-ON VB3 CALL MPOUT OUT KDATA ;TURN-OFF VB3 POP B POP D POP H RET ;MAP OUTPUT. ;FIRST TEST REGISTER-A MPOUT: MOV B,A ;SAVE BOX NUMBER MOV A,M ;GET MAX. NUMBER SUB B ;LESS OR EQUAL? RC ;TOO BIG. MOV A,B ;RESTORE BOX NO. ORA A ;TEST FOR ZERO JZ BXITZ ;IF ZERO, INITIALIZE. DCR A ADD A ;X2 MOV B,A ADD A ;X4 ADD B ;X6 (SIZE OF SUB-TABLE) MOV E,A MVI D,0 INX H ;START OF BOX TABLE DAD D ;PICK SUB-TABLE XCHG ;D&E = BOX TABLE ;GET CURSOR FROM BOX TABLE LXI H,4 DAD D ;PT. TO CURSOR MOV A,M ;GET HORIZ. INX H MOV H,M ;GET VERTICAL MOV L,A ;TURN-OFF CURSOR INDICATOR CALL CUROFF ;SET RETURN ADDRESS. PUSH H LXI H,FIN XTHL ;TEST FOR SPEC. CHARACTERS MOV A,C CPI CR JZ DOCR CPI LF JZ DOLF CPI UP JZ DOUP CPI BS JZ DOLT CPI RT JZ DORT CPI FF JZ DOFF CPI HM JZ DOHM ;MUST BE A CHARACTER XTHL POP H PUSH H CALL CONV ;COMPUTE PHYSICAL ADDRESS MOV M,C ;DISPLAY CHARACTER POP H CALL DORT ;MOVE RIGHT ONE JNC FIN ;IF OVERFLOW, CRLF CALL DOCR CALL DOLF ;TURN-ON CURSOR INDICATOR FIN: CALL CURON ;SAVE CURSOR IN BOX TABLE LXI B,4 XCHG DAD B MOV M,E INX H MOV M,D RET ;Subroutines for cursor motion ;UP ONE LINE. DOUP: MOV A,H ORA A ;MAX. TOP? JZ DOUP1 DCR H ;UP ONE LINE DOUP1: INX D LDAX D ;PT. TO TOP DCX D ;RESTORE ADDR. MOV B,A ;SAVE TOP VALUE MOV A,H SUB B ;TEST CURSOR RNC ;WITHIN BOX? MOV H,B ;TOO HIGH, LIMIT RET ;SET CARRY ;DOWN ONE LINE DODN: MOV A,H CPI 0FFH ;MAX. BOTTOM? JZ DODN1 INR H ;DOWN ONE LINE DODN1: INX D INX D INX D LDAX D ;PT. TO BOTTOM DCX D DCX D DCX D MOV B,A SUB H RNC ;WITHIN BOX? MOV H,B ;TOO LOW, LIMIT IT RET ;SET CARRY ;MOVE RIGHT DORT: MOV A,L CPI 0FFH ;MAX. RIGHT? JZ DORT1 INR L ;MOVE RIGHT DORT1: INX D INX D LDAX D ;PT. TO RIGHT SIDE DCX D DCX D MOV B,A SUB L RNC ;WITHIN BOX? MOV L,B ;TOO RIGHT RET ;CARRY SET ;MOVE LEFT DOLT: MOV A,L ORA A ;MAX. LEFT? JZ DOLT1 DCR L ;MOVE LEFT DOLT1: LDAX D ;PT. TO LEFT SIDE MOV B,A MOV A,L SUB B RNC ;WITHIN BOX? MOV L,B ;TOO LEFT RET ;CARRY SET DOCR: LDAX D ;GET LEFT-SIDE MOV L,A ;SET LEFT RET DOLF: CALL DODN ;MOVE DOWN RNC ;WITHIN BOX? CALL MVUP ;MOVE LINES UP RET DOHM: XCHG MOV E,M ;GET LEFT INX H MOV D,M ;GET TOP DCX H XCHG RET DOFF: PUSH D PUSH B CALL SHAPE ;DEFINE BOX SHLD PTEMP ;SAVE PHYS. ADDR. LXI D,NCOLS INR B ;HEIGHT + 1 MOV A,C ;WIDTH DOF1: MVI M,' ' ;CLEAR SCREEN INX H DCR A JNZ DOF1 MOV A,C ;RESTORE CHAR. CTR LHLD PTEMP DAD D ;NEXT LINE SHLD PTEMP DCR B JNZ DOF1 POP B POP D JMP DOHM ;HOME CURSOR ;Initialize the selected video board. IF W64 OR W80 BXITZ: LXI H,VID MVI C,NCOLS MOV A,C MVI B,NROWS BXT1: MVI M,' ' ;FILL WITH SPACE INX H DCR C ;FINISHED CHAR. LINE? JNZ BXT1 MOV C,A DCR B ;FINISHED LINES? JNZ BXT1 RET ENDIF IF VB3 BXITZ: LXI H,VID ;VIDEO ADDRESS MVI D,' ' ;OUTPUT CHARACTER MVI E,2 ;TWO PASSES BXT1: PUSH H MVI B,NROWS ;LINES DOWN BXT2: MVI C,NCOLS ;CHAR. ACROSS BXT3: MOV M,D ;SET SCREEN VALUE INX H DCR C JNZ BXT3 DCR B JNZ BXT2 POP H LXI H,VID+1000H MVI D,03H ;ALPHA MODE DCR E ;CHECK PASS NO. JZ BXT4 ;FINISHED FILLING JMP BXT1 BXT4: MVI A,NROWS-1 OUT VTAC+6 ;SET LAST ROW=BOTTOM MVI A,NROWS OUT VTAC+0DH ;CURSOR OFF NOP ;USER CAN "CALL" HIS OWN NOP ;INITIALIZATION ROUTINE. NOP RET ENDIF ;Converts a CURSOR address into a PHYSICAL ;address. ;Enter: H&L = CURSOR ;Exits: H&L = PHYSICAL IF W64 CONV: PUSH B PUSH D MOV C,L MOV L,H MVI H,0 MOV B,H ;MULTIPLY BY 64 DAD H ;X2 DAD H ;X4 DAD H ;X8 DAD H ;X16 DAD H ;X32 DAD H ;X64 LXI D,VID DAD D DAD B ;PHYS. ADDRESS POP D POP B RET ENDIF IF W80 OR VB3 CONV: PUSH B PUSH D MOV C,L MOV E,H MOV L,H MVI H,0 MOV D,H MOV B,H ;MULTIPLY BY 80 DAD H ;X2 DAD H ;X4 DAD D ;X5 DAD H ;X10 DAD H ;X20 DAD H ;X40 DAD H ;X80 LXI D,VID DAD D DAD B POP D POP B RET ENDIF ;CURSOR OFF IF VB3 ;For the VB3 board. CUROFF: PUSH H CALL CONV PUSH B LXI B,1000H ;ATTR. OFFSET DAD B ;PT. TO ATTR. MVI M,03H POP B POP H RET ENDIF IF W64 OR W80 ;For the VB1 board or other design. CUROFF: PUSH H CALL CONV LDA OLDCHR ;GET OLD CHARACTER MOV M,A POP H RET OLDCHR: DB ' ' ENDIF ;CURSOR ON IF W64 OR W80 ;For the VB1 board or other design. CURON: PUSH H CALL CONV MOV A,M STA OLDCHR MVI M,7FH ;RUB-OUT SHAPE POP H RET ENDIF IF VB3 ;For the VB3 board. CURON: PUSH H CALL CONV PUSH B ;SAVE REG.-C LXI B,1000H DAD B MVI M,27H POP B POP H RET ENDIF ;Compute physical starting address, delta ;width+1, and delta height of BOX. ;Enter: D&E = BOX table ;Exits: H&L holds starting address ; D&E = BOX table ; B = Delta height ; C = Delta width+1 ;All registers used. SHAPE: LDAX D ;GET LEFT MOV B,A ;SAVE COPY MOV L,A INX D LDAX D ;GET TOP MOV H,A CALL CONV ;FIND ADDRESS INX D LDAX D ;GET RIGHT INR A SUB B ;WIDTH+1 MOV C,A INX D LDAX D ;GET BOTTOM MOV B,A DCX D DCX D LDAX D ;GET TOP DCX D CMA INR A ;MAKE NEGATIVE ADD B MOV B,A ;BOX HEIGHT RET ; ;Move UP lines of text MVUP: PUSH H ;SAVE CURSOR PUSH D ;SAVE TABLE ADDRESS PUSH B ;SAVE CHARACTER CALL SHAPE SHLD PTEMP ;SAVE PHYS. ADDR. ;MOVE ALL BOX DATA UP. MVU0: LXI D,NCOLS ;ACTUAL WIDTH LHLD PTEMP ;GET PHYS. ADDR. XCHG DAD D ;COMPUTE ONE LINE DOWN SHLD PTEMP MOV A,C PUSH PSW ;SAVE WIDTH CTR MVU1: MOV A,M STAX D INX D INX H DCR C ;COUNT CHAR. ACROSS JNZ MVU1 ;FINISH LINE? POP PSW MOV C,A ;RESTORE WIDTH CTR DCR B ;OTHER LINE? JNZ MVU0 ;CLEAR BOTTOM LINE LHLD PTEMP MVU2: MVI M,' ' ;FILL WITH SPACE INX H DCR C ;FINISHED LINE/ JNZ MVU2 POP B POP D POP H RET PTEMP DW 0 ;PHYS. ADDR., TEMPORARY ; BXTBL: DB 6 ;NO. OF BOXES ; BOX1: DB 0 ;LEFT SIDE DB 0 ;TOP DB 63 ;RIGHT SIDE DB 15 ;BOTTOM DW 0 ;CURSOR BOX2: DB 1 ;LEFT SIDE DB 0 ;TOP DB 62 ;RIGHT SIDE DB 4 ;BOTTOM DB 1 ;CURSOR X DB 0 ;CURSOR Y BOX3: DB 1 DB 6 DB 16 DB 15 DW 601H BOX4: DB 18 DB 6 DB 62 DB 10 DW 6*256+18 BOX5: DB 18 DB 12 DB 40 DB 15 DW 12*256+18 BOX6: DB 42 DB 12 DB 62 DB 14 DW 12*256+42 ; END