\ Notes DISPLAY.BLK ;S This contains source code to poke and control the screen display bypassing DOS. You must first have loaded the assembler \ LOAD screen 2 999 THRU \ SEARCH ORDER ONLY FORTH ALSO \ HOW-SHOW FORTH DEFINITIONS QVARIABLE HOW-SHOW \ set directly by TDIM and indirectly by DIM \ attribute byte to use for screen display \ we use QVARIBLE so S! can get at its pfa \ with a simple CS: override 7 HOW-SHOW ! : HOW-SHOW! HOW-SHOW C! ; : HOW-SHOW@ HOW-SHOW C@ ; \ REGEN HEX B0000000 CONSTANT REGEN \ address of REGEN buffer for \ monochrome screen 03B4 CONSTANT I6845 \ IO port address of 6845 control index reg 03B5 CONSTANT D6845 \ IO port address of 6845 data reg DECIMAL \ S! screen poke Monochrome version HEX CODE S! ( char saddr -- : store char on screen ) ( addr is relative to segment B000 ) ( saddr points to lsb CHARACTER ) ( uses current attribute ) BX DI MOV REGEN MSW # AX MOV AX ES MOV ( ES:DI points to LSB in regen where char will go ) SP INC SP INC AX POP ( char ) CS: HOW-SHOW #) AH MOV ( in first 64 K ) STOSW ( store char and attrib byte ) DI DI XOR ( restore DI to 0 ) POPCB NEXT END-CODE DECIMAL \ SCMOVE 05/12/84 ) CODE SCMOVE ( addr saddr len -- : moves field to screen ) ( like CMOVE for screen, len in chars, not yet mult by 2 ) ( uses current attribute byte, len may be 0 ) BX CX MOV ( CX=len ) REGEN MSW # DX MOV ( ES:DI dest = saddr ) DX ES MOV SP INC SP INC DI POP POPDA SI PUSH DS PUSH ( DS:SI source = addr ) DX DS MOV AX SI MOV ( source seg/off ) CS: HOW-SHOW #) AL ( in first 64 K ) MOV CX0<> IF DO BYTE MOVS ( move char ) BYTE STOS ( store attr ) LOOP THEN DI DI XOR DS POP SI POP POPCB NEXT END-CODE \ SBLANK HEX CODE SBLANK ( saddr len -- : blanks out field on screen ) ( like BLANK for screen ) ( len in chars ) ( uses current attribute byte eg. TDIM ) BX CX MOV ( CX=len ) REGEN MSW # DX MOV ( ES:DI dest = saddr ) DX ES MOV SP INC SP INC DI POP CS: HOW-SHOW #) AH ( in first 64 K ) MOV 20 ( Blank ) # AL MOV REP WORD STOS ( handles CX=0 automatically ) DI DI XOR POPCB NEXT END-CODE DECIMAL \ HIGHLIGHT HEX CODE HIGHLIGHT ( saddr len -- : change screen attribute ) ( addr is relative to segment B000 ) ( saddr points to lsb CHARACTER ) ( does not disturb characters ) BX CX MOV ( CX=len ) REGEN MSW # DX MOV ( ES:DI dest = saddr ) DX ES MOV SP INC SP INC DI POP CS: HOW-SHOW #) AL ( in first 64 K ) MOV CX0<> IF DO DI INC ( bypass char - point at attr ) BYTE STOS ( store attr ) LOOP THEN DI DI XOR POPCB NEXT END-CODE DECIMAL \ TDIM etc HEX ( Note -- these hidden definitions do not touch smood ) ( these are used internally during display of fields ) ( FORTH DIM etc touch SMOOD which only affects " xxx" ) ( SHOW constants ) : TBRIGHT 00F HOW-SHOW! ; : TBLINK 08F HOW-SHOW! ; : TDIM 007 HOW-SHOW! ; : TBRIGHT-INV 070 HOW-SHOW! ; : TBLINK-INV 0F0 HOW-SHOW! ; : TDIM-INV 078 HOW-SHOW! ; TBRIGHT ( default ) : TNORM 009 ( BRIGHT UNDERLINE ) ( 00F BRIGHT ) HOW-SHOW! ; DECIMAL \ EXCHANGE CODE EXCHANGE ( addr1 addr2 len -- : exchanges two strings ) DS DX MOV SI AX MOV ( temp save DS:SI ) ES POP DI POP DS POP SI POP PUSHDA ( save DS:SI ) BX DX MOV BX CX MOV 1 # CX SHR ( convert to words ) 0<> IF DO ( DS:SI = addr1 ES:DI = addr2 ) ES: 0 [DI] AX MOV ( save addr2 word about to clobber ) SI BX MOV ( save addr1 ) MOVSW ( mov 1 word from addr1 to addr2 ) ( DS: ) AX 0 [BX] MOV ( store word2 at addr1 ) LOOP THEN 1 # DX AND ( get low bit ) 0<> IF ( handle last byte ) ES: 0 [DI] AL MOV SI BX MOV MOVSB AL 0 [BX] MOV THEN DI DI XOR DS POP SI POP POPCB NEXT END-CODE \ TRT CODE TRT ( addr len TABADDR -- ) ( translates string addr,len using 256 byte table at tabaddr) DS DX MOV ( save old DS ) CX DS MOV ( DS:BX source seg/off = trt TABLE ) SP INC SP INC CX POP ( cx=len ) ES POP DI POP ( ES:DI = addr string ) CX0<> IF DO ( DS:BX table ) ES: 0 [DI] AL MOV ( get char ) XLAT ( get translated char from DS:BX+AL into AL ) BYTE STOS ( store translated char and inc DI ) LOOP THEN DX DS MOV DI DI XOR POPCB NEXT END-CODE \ video-io HEX CODE video-io ( dx cx bx ax -- dx cx bx ax ) ( calls ROM bios INT10h video control ) ( see Tech Ref ROM BIOS listings for meaning ) BX AX MOV SP INC SP INC BX POP SP INC SP INC CX POP SP INC SP INC DX POP 10 INT DX PUSH DI PUSH CX PUSH DI PUSH BX PUSH DI PUSH AX BX MOV DI CL MOV NEXT END-CODE DECIMAL \ CURTHIN CURFAT CURGROSS CUROFF HEX : CURTHIN ( -- : makes cursor skinny, 3 scan lines thick) 0 0A0C 0 0100 video-io 4DROP ; : CURFAT ( -- : makes cursor fat ) 0 050C 0 0100 video-io 4DROP ; : CURGROSS ( -- : makes cursor VERY fat ) 0 000C 0 0100 video-io 4DROP ; : CUROFF ( -- : turns cursor off ) 0 0E0C 0 0100 video-io 4DROP ; DECIMAL \ CURAT HEX : CURAT ( sadd -- : moves cursor to screen addr ) ( sadd is offset in bytes from screen start ) ( two bytes per char ) ( bypasses ROM BIOS and goes right to hardware ) 2/ ( cursor hardware wants offset in chars ) DUP 0E ( cur high reg ) I6845 ( 6845 index port ) PC! >< ( cur addr high byte ) D6845 ( 6845 data port ) PC! 0F ( cur low reg ) I6845 PC! ( cur addr low byte ) D6845 PC! ; DECIMAL \ GOTOXY HEX CODE GOTOXY ( COL ROW -- ) ( moves cursor to coordinates row 0..24 col 0..79 ) ( 0,0 is upper left 79 24 is lower right ) ( uses ROM BIOS int 10 ) SP INC SP INC DX POP ( DL = col ) BL DH MOV ( DH = row ) 2 # AH MOV 10 INT POPCB NEXT END-CODE DECIMAL \ CLEARSCREEN DECIMAL : CLEARSCREEN ( -- : erases screen ) 0 [ 80 25 Q* ] LITERAL SBLANK 0 0 GOTOXY ; \ beep HEX CODE beep ( divisor time -- ) ( BX=time in centiseconds ) B6 # AL MOV 43 # AL OUT ( write timer mode reg ) AX POP ( rid of high order divisor ) AX POP ( freq divisor -- 533h=1000hz) 42 # AL OUT ( write timer 2 cnt - lsb ) AH AL MOV 42 # AL OUT ( write timer 2 cnt - msb ) 61 # AL IN ( get current port b setting ) AL AH MOV ( save current setting ) ( continued ... ) DECIMAL \ beep continued HEX 03 # AL OR ( turn speaker on ) 61 # AL OUT BEGIN ( start major outer loop ) 0A48 # CX MOV ( 10 msec delay for innner loop) DO LOOP ( single instruction loop ) BX DEC ( total time of spkr on ) 0= UNTIL AH AL MOV ( recover value of port ) 61 # AL OUT POPCB NEXT END-CODE DECIMAL \ BEEP DECIMAL : BEEP ( freq time -- divisor time ) >R >R 1331 1000 R> */ R> beep ; ( 1331 gives 1000 hz ) \ Notes on BEEP ;S The original version of beep was written by Ray Duncan in his PCForth compiler. beep adapted from IBM/PC Technical Manual, p. A-18. The frequency of the tone generated is inverse to the value of a divisor used to generate a frequency using the timer. The duration depends on the number of iterations of a loop. (sec*100), eg., 440 500 BEEP plays middle A for 5 seconds. 41 is lowest fequency. Lower gives divide overflow. Later BEEP will be adjusted so that faster system clocks will not cause BEEP to make shorter or higher pitched noises than it should. \ RANGE? CODE RANGE? ( value low high -- good-flag ) ( true if low <= value <= high ) \ could be defined as ROT DUP ROT ( L V V H ) \ <= >R <= R> AND ; ( CX:BX = high ) ES POP DI POP ( ES:DI low ) POPDA ( DX:AX = value ) AX BX SUB DX CX SBB 0>= ( HIGH - VALUE ) IF ES CX MOV DI BX MOV BX AX SUB CX DX SBB 0>= ( VALUE - LOW ) IF DI DI XOR ( put true on stack ) -1 # BX MOV BX CX MOV NEXT THEN THEN DI DI XOR ( put false on stack ) DI BX MOV DI CX MOV NEXT END-CODE ( {OF} 02/11/84 ) CODE {OF} ( a a -- : or a b -- a ) ( OVER = ?BRANCH ww DROP ) POPDA ( A in DX:AX B in CX:BX ) ( CANT USE SUB SBB) BX AX CMP 0<> IF ( Normally LSW not equal ) DX CX MOV AX BX MOV 0 [SI] SI ADD ( branch around OF clause ) NEXT ELSE CX DX CMP 0= IF ( normally equal ) POPCB SI INC SI INC ( bypass ww ) NEXT ELSE ( MSW not = ) DX CX MOV AX BX MOV 0 [SI] SI ADD ( branch around OF clause ) NEXT THEN THEN END-CODE ( OF 10/06/86 ) FORTH DEFINITIONS : OF ( A A -- : A B -- A ) 4 ?PAIRS COMPILE {OF} HERE 0 W, ( leave room 16-bit offset ) 5 ; IMMEDIATE ( TRUEOF 02/11/84 ) FORTH DEFINITIONS : TRUEOF ( A true -- : A false -- A ) 4 ?PAIRS COMPILE ?BRANCH-USUALLY ( usually not a match ) HERE 0 W, ( leave room 16-bit offset ) COMPILE DROP 5 ; IMMEDIATE ( {RANGEOF} RANGEOF 09/20/85 ) : {RANGEOF} ( V low high -- V flag : if v in low..high ) 2 PICK >R RANGE? R> SWAP ; FORTH DEFINITIONS : RANGEOF ( V low high -- : if in range ) ( V low high -- V : if not in range ) COMPILE {RANGEOF} [COMPILE] TRUEOF ; IMMEDIATE ( CASE ENDOF OTHERS ENDCASE 02/23/84 ) FORTH DEFINITIONS : OTHERS ?COMP COMPILE DUP ; IMMEDIATE : CASE ?COMP CSP @ !CSP 4 ; IMMEDIATE : ENDOF 5 ?PAIRS COMPILE BRANCH HERE 0 W, SWAP 2 [COMPILE] THEN 4 ; IMMEDIATE : ENDCASE 4 ?PAIRS COMPILE DROP BEGIN SP@ CSP @ <> WHILE 2 [COMPILE] THEN REPEAT CSP ! ( restore CSP ) ; IMMEDIATE \ CASE Notes ;S n CASE 7 OF ." seven" ENDOF 1 8 88 3 ANYOF ." 1 8 or 88 " ENDOF 6 88 RANGEOF ." in range 6..88" ENDOF DUP 7 < TRUEOF ." is less than 7 " ENDOF OTHERS OF ." what's left" ENDOF ENDCASE \ Last Screen