page 64,132 title screen - IBM Display Enhancement Dec 1983 .radix 10 ;*************************************************************** ; Typed in by Greg Glass - gjg@cmu-cs-cad from Byte - Nov. 1983 ; NOTE: if you have a color card this will shift over to it ; (even if the monitor is turned off) ; hit Alt F7 to switch to the Mono monitor. ; To build this program: ; 1> masm screen; /* assemble the code */ ; 2> link screen; /* link it - will get no stack seg. message */ ; 3> exe2bin screen /* convert the format */ ; 4> rename screen.bin screen.com /* make the new format executable*/ ; 5> del screen.exe /* don't need this anymore */ ; ; To use program: just run it or place in autoexec.bat ; ; COMMANDS: ; F1 - increment the text color ; F3 - increment the background color ; F5 - toggle modes co80/co40 ; F7 - toggle between color and mono display ; F9 - redraw display - reset colors ;*************************************************************** ;*************************************************************** ; ; Define interrupt vectors for both keyboard interrupt 16H and ; screen interrupt 10H. Both in segment 0. ; ;*************************************************************** keyvect segment at 0 ; define keyboard interrupt vector org 16h*4 KEYINT label dword keyvect ends scrvect segment at 0 ; define screen interrupt vector org 10h*4 SCRINT label dword scrvect ends ;*************************************************************** ; ; define constants ; ;*************************************************************** bw_val equ 07h ; standard b&w attibute sent to monitor equip_flag equ 410h ; area in RAM that contains equipment status chk_mode equ 15 ; screen interrupt function to check mode mono_mode equ 7 ; screen mode of 7 indicates monochrome color_adpt equ 3 ;modes from 0 to 3 are non-graphics color ;*************************************************************** ; ; start code area ; ;*************************************************************** code segment para assume cs:code org 100h ; start code offset 100h from starting segment ; (this leaves room for DOS's work areas) KEY proc far START: ; Initialization code...used only once, on system startup jmp init_code ; call initialization routine even validchk db 'FCP!' ; used by INSTALL to check for valid SCREEN ; program ;*************************************************************** ; ; Define storage areas and data structures ; ;*************************************************************** ; define keystroke scan codes for the five SCREEN functions fore_inc dw 6800h ; foreground increment back_inc dw 6a00h ; background increment c80_40 dw 6c00h ; 80x25 to 40x25 flip-flop key col_mon dw 6e00h ; color/mono flip-flop key repaint dw 7000h ; repaint screen using current mode cur_mode dw col80_area ; Initialize starting mode mono_set dw mono_area ; pointer to monochrome area color_set dw col80_area ; pointer to "active" color area scrn_attr db 70h ; current screen attribute scrn_mode db 255 ; saves current screen mode ; define structure used to contain information about 40 and 80 ; column color modes as well as monochrome mode. s struc corner dw 0 ; defines COL/ROW count of characters for mon bf dw 0 ; Colors of fore and back equip dw 0 ; equipment settings mode dw 0 ; AX value for setting mode of monitor s ends ; Now, set up three screen structures with default conditions col80_area s <5019h,0107h,20h,3> ; 80x25, white FORE blue BACK col40_area s <2819h,0107h,10h,1> ; 40x25, Brown FORE black BACK mono_area s <5019h,0007h,30h,7> ; monochrome, reverse video ;NOTE: The standard BIOS ROM KEYBOARD interrupt routine is ; executed as a subroutine ( using CALL DWORD PTR) if ; the interrupt was invoked to return a keystroke. Any ; other execution KEYBOARD_IO can be called as a simple ; inline FAR JMP instruction. NOTE: the CALL instruction ; (see just after INT_LOOP label below) uses the ; address stored here at KEY_CALL to KEYBOARD_IO. KEY_CALL : db 0eah ; far JMP address to KEYBOARD interrupt dw 0,0 ; ;*************************************************************** ; ; procedure KEY_RTNE - Intercepts keyboard interrupt and ; determines if the keystroke is one of the five SCREEN ones. ; ;*************************************************************** KEY_RTNE: assume ds:code sti ; turn on interrupts cmp ah,0 ; call as subroutine if keyfetch jne KEY_CALL ; jump to KEYBOARD_IO if not push ds ; save ds and bx from destruction push bx ; push cx push dx push es push di mov bx,cs ; move cs segment into ds mov ds,bx ; INT_LOOP: pushf ; IBM keyboard proc exports interrupt call mov bx,offset KEY_CALL + 1 ;Get address to ROM code for keyboard call dword ptr[bx] ; call keyboard routine mov bx, cur_mode ; get current mode address cmp ax, col_mon ; see if COLOR<->MONO flip-flop key jne TEST_FORE ; exit if not ; otherwise, flip-flop screen mode cmp bx, mono_set ; are we looking at monochrome? je set_color ; swap in color if yes cmp mono_set,0 ; see if monochrome monitor enabled je next_key ; ignore command if not mov bx,mono_set ; otherwise set up monochrome jmp short DO_CHG ; SET_COLOR: cmp color_set,0 ; see if COLOR monitor enabled je NEXT_KEY ; skip if not mov bx,color_set ; set up for color DO_CHG: call SCREEN_CHG ; implement screen change NEXT_KEY: mov ah,0 ; set up to fetch keystroke jmp INT_LOOP ; fetch next key input TEST_FORE: push ax ; save registers. push bx ; see if in graphics mode mov ah,chk_mode ; int 10h ; pop bx ; restore bx register cmp al,color_adpt ; if between 0 and 3, not graphics mode jle NOT_GRAF ; cmp al,mono_mode ; monochrome mode jge NOT_GRAF ; restore stack pop ax ; if color-graphics mode, do not change jmp DONE ; modes NOT_GRAF: pop ax ; restore ax cmp ax,fore_inc ; is this key to increment FORE ? jne TEST_BACK ; skip if not cmp bx,color_set ; see if currently using color jne BW_FLOP ; if not, go deal with B & W mov ax,[bx].bf ; gets BACK in al, FORE in ah EQ_FORE: inc al ; increment FOREGROUND color and al,7 ; keep it within bounds (chg. for more colors) cmp al,ah ; see if same as background je EQ_FORE ; increment againt if yes mov [bx].bf,ax ; save back to structure jmp DO_CHG ; redraw display TEST_BACK: cmp ax,back_inc ; is this key to increment BACK? jne TEST_REPAINT ; skip if not cmp bx,color_set ; see if currently using color jne BW_FLOP ; if not, go deal with B&W mov ax,[bx].bf ; gets BACK in al, FORE in ah EQ_BACK: inc ah ; increment background color and ah,7 ; keep in bounds cmp ah,al ; see if same as foreground je EQ_BACK ; increment again if yes mov [bx].bf,ax ; save back to structure jmp DO_CHG ; redraw the screen BW_FLOP: ; flip-flop B&W screen mov ax,[bx].bf ; BACK in ah, FORE in al xchg ah,al ; swap mov [bx].bf,ax ; save back to structure jmp DO_CHG ; redraw the screen TEST_REPAINT: cmp ax,repaint ; is this the key to redraw the screen ? je DO_CHG ; if yes then repaint TEST_80_40: cmp ax,c80_40 ; is this the key to flop 80 / 40 ? jne DONE ; exit if not cmp bx,offset col40_area ; is current pointer area 40x25 ? jne TST80 ; skip if not mov bx,offset col80_area ; otherwise flip to 80x25 jmp short SAVE_COL ; save to color_set TST80: cmp bx,offset col80_area ; is current 80x25 color ? jne NEXT_KEY ; ignore key if not mov bx,offset col40_area ; SAVE_COL: mov color_set,bx ; sat to color_set jmp SET_COLOR ; implement DONE: pop di pop es pop dx pop cx pop bx pop ds iret ; return from interrupt KEY endp ; done with main routine ! ;*************************************************************** ; ; SCREEN_CHG - Changes current monitor screen mode ; ; Inputs: bx points to current monitor structure ; ;*************************************************************** SCREEN_CHG proc near mov ax,0 ; get segment address to equip_flag mov es,ax ; in RAM memory mov ax,es:equip_flag ; get set of equip flag and al,0CFh ; get rid of current monitor flag or ax,[bx].equip ; set up new monitor flag mov es:equip_flag,ax ; save back in RAM mov cur_mode,bx ; indicate new mode ; now, set up attribute for background and foreground mov dx,[bx].bf ; get both FORE and BACK in dx mov cl,4 ; shift count shl dh,cl ; shift BACK into upper nibble or dh,dl ; move FORE into lower nibble mov scrn_attr,dh ; save result ; see if we need to reset monitor (switching to new monitor?) mov ax,[bx].mode ; get mode cmp al,scrn_mode ; compare with current mode je SET_ATTR ; skip if same mov scrn_mode,al ; otherwise, save current mode int 10h ; and reset to new monitor SET_ATTR: ; change attributes of current screen call CH_ATTR ; changes attributes ret SCREEN_CHG endp ;*************************************************************** ; ; CH_ATTR - repaints acctive screen so that every character on ; current screen is displayed with the new attributes ; ; Inputs: bx points to current monitor structure ; ;*************************************************************** CH_ATTR proc near ; see if we need to draw in border for color mode cmp bx,offset mono_set ; in color? je NO_BORDER ; do not worry about border if not push ax ; save registers push bx ; mov bx,[bx].bf ; get background color in bx mov bl,bh ; mov bh,0 ; select border color mov ah,11 ; interface to set color palette int 10h pop bx ; restore registers pop ax NO_BORDER: mov ax,[bx].corner ; get COL and ROW for current mov cornr,ax ; save in temporary mov ah,chk_mode ; get page number int 10h ; ; bh contains active page mov ah,3 ; save current cursor posn int 10h push dx ; save position in stack xor dx,dx ; load dx with 0 mov cx,1 ; set up replication count mov bl,scrn_attr ; get current attribute REP_ATTR: mov ah,2 ; set cursor position int 10h mov ah,8 ; read next character int 10h ; ah contains current character attribute and ah,88h ; get intensity bit and bl,77h ; make sore attribute intensity off or bl,ah ; combine to get current attribute mov ah,9 ; write out char with new attribute int 10h ; inc dl ; cmp dl,tcol ; are we done with this column? jle REP_ATTR xor dl,dl ; otherwise zero out DL inc dh ; move to next row cmp dh,trow ; done with screen ? jle REP_ATTR ; loop until done pop dx ; restore original cursor position mov ah,2 int 10h ret cornr label word trow db 0 ; temporary store for ROW tcol db 0 ; temp store for COL CH_ATTR endp ;*************************************************************** ; ; SCR_RTNE - Replaces SCREEN interrupt so that it can intercept ; B&W character writes and change attributes ; ;*************************************************************** SCR_RTNE proc near assume ds: code sti push ds ; save data segment register push cs ; move CS segment into DS pop ds ; this is a funny way to do that (gjg) cmp ah,6 ; Spot SCROLL UP and SCROLL DOWN calls jl NORMAL_SCR ; cmp ah,6 jg NOT_SCROLL ; SCROLL: call GET_CH ; for scrolling, update attribute jmp NORMAL_SCR ; now, execute scroll NOT_SCROLL: cmp ah,9 ; check for "WRITE ATTRIBUTE/CHAR" cmd jne NORMAL_SCR ; send out any other command as normal xchg bh,bl ; get attribute for command call GET_CH ; update attribute for command xchg bh,bl ; move attribute back to bh for cmd NORMAL_SCR: pop ds ; restore ds segment register ; ; NOTE: We are now ready to invoke the BIOS screen interrupt. ; Since the ROM code includes an IRET interrupt return call, ; all we need to do is to jump to the start of the ROM code ; and all will be well. Since the initialization code set ; up the address to the screen interrupt code below, we can ; set up a forced jump to that address. JMP_SCR: ; Address to SCREEN interrupt db 0EAh ; force a FAR JMP but do not set up dest- dw 0,0 ; ination address at assembly time. ; (INIT routine will set this address) SCR_RTNE endp ;*************************************************************** ; ; GET_CH - subroutine replaces B&W character with current replacement ; attributes and allows for intensity bit setting ; ; Inputs : bh contains attribute to be modified ; ;*************************************************************** GET_CH proc near mov savech,bh ; save character and bh,77h ; Remove intensity and blink bits cmp bh,bw_val ; see if currently defined B&W value mov bh,savech ; otherwise, modify to current attribute jne OUT ; exit if not and bh,88h ; get rid of B&W part or bh,scrn_attr ; move in current attribute part OUT: ret ; done savech db 0 ; temporary character store GET_CH endp LASTONE: ; all code after this label is freed to DOS use after ; initialization of the program. ;*************************************************************** ; ; INIT_CODE - Code to load and initialize the SCREEN program.. ; sets up DOS to keep all code before "LASTONE" label ; safe from overlaying during system operation. ; ;*************************************************************** COPYRT: db 'SCREEN Version 1.20 Copyright 1983 Tim Field',13,10,'$' INIT_CODE proc near ; Initialize KEYBOARD intercept code assume es:keyvect ;'vectors' is interrupt segment 0 mov ax,keyvect ; get address to interrupt vector mov es,ax ; save in es mov ax,es:keyint ; get address to interrupt mov bx,offset key_call+1 ; address to place to save vector mov [bx],ax ; save interrupt address mov ax,es:keyint[2] ; get interrupt segment for rtne mov [bx+2],ax ; save it too mov es:keyint,offset key_rtne ; now replace with own address mov ax,cs ; save segment in interrupt vector mov es:keyint[2],ax ; ; initialize SCREEN intercept code assume es:scrvect ;'vectors' is interrupt segment 0 mov ax,scrvect ; get address to interrupt vector mov es,ax ; save in es mov ax,es:scrint ; get address to interrupt mov bx,offset jmp_scr+1 ; address to place to save vector mov [bx],ax ; save interrupt address mov ax,es:scrint[2] ; get interrupt segment for rtne mov [bx+2],ax ; save it too mov es:scrint,offset scr_rtne ; now replace with own address mov ax,cs ; save segment in interrupt vector mov es:scrint[2],ax ; ; Initialize screen mov bx,cur_mode ; set up initial mode call SCREEN_CHG ; initialize ; Now print out acknowledgement to user monitor and exit mov ax,cs ; set up segment to routine mov ds,ax mov dx,offset copyrt ; now print out copyright message mov ah,9 ; DOS function to print string int 21h ; execute function interrupt mov dx,offset lastone ; save all code up to "LASTONE" label int 27h ; no return needed INIT_CODE endp code ends end start