home *** CD-ROM | disk | FTP | other *** search
- jmp initialize ; goto initialization routine
-
- interrupts EQU 0h ; interrupt table segment
- keyboard_int EQU (9*4) W ; interrupt 9 vector
-
- rom_bios_data EQU 40h ; ROM BIOS data area segment
- cursor_mode EQU W[60H] ; starting and ending cursor scan lines
-
- rom EQU 0F000h ; ROM segment
- machine_id EQU B[0FFFEh] ; ID byte identifies machine as PCjr or other
-
- db '(C) Copyright 1986, Ziff-Davis Publishing Company ', 1Ah
-
- column_count dw ? ; width of window in columns
- cursor_type dw ? ; cursor scan line definition
- setup_status db 0 ; indicates if printer window is already active
- display_mode dw ? ; current crt display mode
- page_no dw ? ; current displayed page
- attribute1 db 4Fh ; window attribute bytes
- attribute2 db 70h
-
- display_table db 2Dh,29h ; display re-enable values for modes 2 and 3
- video dw 0B800h,0B900h,0BA00h,0BB00h ; starting addresses of video
- ; memory for CGA pages 0 - 3
-
- mono_video dw 0B000h ; video segment address for
- ; monochrome adapter
-
- old_kb_int DD
- old_keyboard_int dw 2 dup (?) ; storage for old keyboard
- ; interrupt vector
-
-
- ; Text of the Printer Setup Menu window.
- ; After initialization, text and attribute bytes are combined and stored
- ; in the WINDOW_TEXT area, and this area is used to store the contents of
- ; the screen that underlie the window when the window is called up.
-
- window_buffer DW
- buffer_text:
- db 201,26 dup (205),187
- db 186,' PRINTER SETUP MENU ',186
- db 186,' EPSON RX/FX PRINTERS ',186
- db 199,26 dup (196),182
- db 186,' F1 Compressed Mode ',186
- db 186,' F2 Expanded Mode ',186
- db 186,' F3 Emphasized Mode ',186
- db 186,' F4 Double-Strike Mode ',186
- db 186,' F5 Elite Mode ',186
- db 186,' F6 Miniature Mode ',186
- db 186,' F7 Skip Perforation ',186
- db 186,' F8 Indent Left Margin ',186
- db 186,' F9 Reset Top-of-Form ',186
- db 186,' F10 Reset Print Modes ',186
- db 186,' ESC Exit ',186
- db 199,26 dup (196),182
- db 186,' Unshifted: Toggle ON ',186
- db 186,' Shifted: Toggle OFF ',186
- db 200,26 dup (205),188
- db 532 dup (?)
-
- ; Storage area for the combination of text and attribute bytes that
- ; form the window image.
-
- window_bytes label byte
- window_text dw 532 dup (?)
-
- ; Control code strings for all of the printer setup options.
-
- code_table:
- db 15,255,14 dup (0) ; compressed mode on
- db 27,87,1,255,12 dup (0) ; expanded mode on
- db 27,69,255,13 dup (0) ; emphasized mode on
- db 27,71,255,13 dup (0) ; double-strike mode on
- db 27,77,255,13 dup (0) ; elite mode on
- db 15,27,83,0,27,65,6,255,8 dup (0) ; miniature mode on
- db 27,78,12,255,12 dup (0) ; perfskip on
- db 27,108,10,255,12 dup (0) ; indent left margin
- db 27,67,66,255,12 dup (0) ; reset top-of-form
- db 18,27,87,0,27,70,27,72,27,80,27,84,27,50,255,0 ; reset print modes
- db 18,255,14 dup (0) ; compress off
- db 27,87,0,255,12 dup (0) ; expand off
- db 27,70,255,13 dup (0) ; emphasize off
- db 27,72,255,13 dup (0) ; double-strike off
- db 27,80,255,13 dup (0) ; elite off
- db 18,27,84,27,50,255,10 dup (0) ; miniature off
- db 27,79,255,13 dup (0) ; perfskip off
- db 27,108,0,255,12 dup (0) ; indent off
-
-
-
- ; Execution comes here, to the main body of the program, when an interrupt 9
- ; is generated from the keyboard. Registers are saved, then the keypress is
- ; checked and compared to the key combination that activates the menu window.
-
- main:
- sti ; enable software interrupts
- push ax,bx,cx,dx,si,di ; save all registers
- push ds,es
- push ax ; save ax for call to old routine
- in al,0A0h ; re-enable NMI on PCjr
- pop ax ; restore ax
- pushf ; simulate interrupt call to old keyboard routine
- CS call old_kb_int ; call old routine
- mov ah,2 ; check status of the shift keys
- int 16h
- and al,5 ; Ctrl and Rt-Shift depressed?
- cmp al,5
- je >L1 ; yes, then skip exit routine
- EXIT: ; common exit point
- pop es,ds
- pop di,si,dx,cx,bx,ax
- iret
-
- ; Execution comes here when the proper key combination, Ctrl/Rt-Shift, is
- ; pressed. First task is to check whether or not the window is already open.
-
- L1:
- MOV DS,ES,CS ; set es and ds to the code segment
- cmp setup_status,0 ; is the window already open?
- jne exit ; yes, then ignore request
-
- ; Check current video mode. If it's mode 2, 3, or 7, then set the window
- ; status flag, store the mode number and page number, save the cursor type,
- ; and hide the cursor. If any other display mode is active instead, ignore
- ; the request and exit.
-
- mov ah,15 ; get page and mode numbers
- int 10h ; al=mode, bh=page
- cmp al,2 ; is crt now in an acceptable mode?
- je >L0 ; yes, then continue
- cmp al,3
- je >L0
- cmp al,7
- je >L0
- jmp exit
-
- L0:
- mov setup_status,1 ; set status flag to indicate that window is active
- mov ah,0 ; save mode number
- mov display_mode,ax
- push bx
- mov bl,bh ; save page number for color displays
- mov bh,0
- mov page_no,bx
- pop bx
- mov ah,3 ; get cursor type
- int 10h
- mov cursor_type,cx ; save it
- mov ah,1 ; hide the cursor until later
- mov ch,20h
- int 10h
-
- ; Preparatory routines are completed. Now open the window by first saving the
- ; contents of video memory beneath the window and then writing the window text
- ; directly to memory.
-
- mov bx,page_no ; use bx as index into video segment address table
- cmp display_mode,7 ; manually adjust index for monochrome adapter
- IF E mov bx,4
- shl bx,1 ; multiply bx by two since table is made up of words
- mov ax,video[bx] ; read segment from table
- mov ds,ax ; ds set to video memory
- CS cmp display_mode,7 ; skip disable if in mode 7
- IF NE call video_disable ; turn display off for snow-free writing
- lea di,window_buffer ; set di to buffer area to save screen contents
- mov ch,28 ; define window dimensions and location
- mov cl,19
- mov dh,2
- mov dl,26
- call video2mem ; then transfer screen contents to buffer
- MOV ES,DS ; set es to video memory
- MOV DS,CS ; reset ds to code segment
- lea si,window_text ; point si to window image
- mov ch,28 ; define window region
- mov cl,19
- mov dh,2
- mov dl,26
- call mem2video ; and write the window to the display
- cmp display_mode,7 ; skip enable if in mode 7
- IF NE call video_enable ; re-enable the video display
-
- ; Window is now present on the screen, so wait for a keypress.
-
- getkey:
- mov ah,0 ; get a keypress
- int 16h
- cmp al,0 ; is it an extended code?
- je extended_code ; yes, go interpret it
- cmp al,27 ; is it the ESC key?
- jne getkey1 ; no, then signal illegal keypress
-
-
-
- ; Execution comes here when the ESC key is pressed. The window is refilled
- ; with its original contents, the cursor is restored, and control is handed
- ; back to the application program.
-
- cmp display_mode,7 ; skip disable if in mode 7
- IF NE call video_disable ; turn off the display
- lea si,window_buffer ; point si to the buffer area
- mov ch,28 ; define the window
- mov cl,19
- mov dh,2
- mov dl,26
- call mem2video ; and write the buffer contents to the display
- cmp display_mode,7 ; skip enable if in mode 7
- IF NE call video_enable ; turn display back on
- mov ah,1 ; restore cursor
- mov cx,cursor_type
- int 10h
- mov setup_status,0 ; reset window status
- jmp exit ; and exit
-
- ; Getkey1 routine handles an illegal keypress by beeping and returning
- ; for another.
-
- getkey1:
- call beep ; beep and return for another keypress
- jmp getkey
-
- ; An extended code has been entered...check its validity and goto the
- ; appropriate routine.
-
- extended_code:
- cmp ah,59 ; less than F1?
- jb getkey1 ; yes, then don't accept it
- cmp ah,91 ; greater than Shft-F8?
- ja getkey1 ; yes, then don't accept it
- cmp ah,68 ; between F1 and F10?
- jbe unshifted ; yes
- cmp ah,84 ; between Shft-F1 and Shft-F9?
- jae shifted ; yes
- jmp getkey1 ; if all tests failed, then keypress was illegal
-
-
-
- ; If a legal function key was pressed, its scan code is translated here to the
- ; starting address of the string of bytes to be sent to the printer. The
- ; string is then sent to LPT1: provided it's powered on and on-line.
-
- shifted:
- sub ah,15 ; adjustment for shifted function keys
- unshifted:
- sub ah,59 ; adjustment for unshifted function keys
- mov al,ah ; convert index to word in ax
- xor ah,ah
- mov cl,4 ; multiply ax by 16
- shl ax,cl
- add ax,code_table ; convert ax to full offset address
- mov si,ax ; and transfer it to si
- call lpt1stat ; check for printer ready
- jc getkey1 ; beep if printer not ready
- mov bl,255 ; specify delimiter for call to LPRINTZ
- call lprintz ; send control code string to printer
- jmp getkey ; return for another keypress
-
-
-
- ; VIDEO_ENABLE and VIDEO_DISABLE routines manipulate bit 3 of port 3D8h,
- ; the CGA Mode Control Register, to temporarily turn the display on or off.
- ; Since these routines write directly to hardware, they have no effect on
- ; other video adapters.
-
- video_disable:
- mov dx,3DAh ; read CGA status port
- L1:
- in al,dx ; wait for vertical retrace to occur
- test al,8 ; is bit 3 set?
- je L1 ; no, wait until it is
- mov dx,3D8h ; now disable the display
- mov al,25h ; by clearing bit 3 of the Mode Control Register
- out dx,al
- ret
-
- video_enable:
- mov dx,3D8h ; CGA Mode Control Register
- mov bx,display_mode ; get value to re-enable display
- sub bx,2
- mov al,display_table[bx]
- out dx,al ; and send it to the port
- ret
-
-
-
- ; VIDEO2MEM routine transfers the contents of a portion of video memory
- ; to a memory buffer for storage.
- ; Entry: DS - video segment
- ; ES:DI - memory buffer
- ; DH,DL - row and column of upper left corner of window
- ; CH - width of window in columns
- ; CL - number of lines in window
-
- video2mem:
- mov al,ch ; store number of columns
- mov ah,0
- mov column_count,ax
- mov ch,0 ; cx = number of lines
- push di ; save di
- call video_offset ; get cell address of first character
- mov si,di ; put it in si
- pop di ; restore di
- L1:
- push si,cx ; save next line pointer and line count
- mov cx,column_count ; set cx for call to WRITELN
- call writeln ; transfer one line
- pop cx,si ; restore saved registers
- add si,160 ; set si for next line address
- loop L1 ; loop until all lines are done
- ret
-
-
-
- ; MEM2VIDEO writes a selected area of memory to the video display.
- ; Entry: DS:SI - memory buffer
- ; ES - video segment
- ; DH,DL - row and column of upper left corner of window
- ; CH - width of window in columns
- ; CL - number of lines in window
-
- mem2video:
- mov al,ch ; save number of columns
- mov ah,0
- mov column_count,ax
- mov ch,0 ; cx = number of lines
- call video_offset ; get offset into video memory
- L1:
- push di,cx ; save video starting address and line count
- mov cx,column_count ; set cx for call to WRITELN
- call writeln ; transfer one line
- pop cx,di ; restore registers
- add di,160 ; set di for next display line
- loop L1 ; loop until done
- ret
-
-
-
- ; VIDEO_OFFSET calculates the offset into video memory of a character cell.
- ; Entry: DH,DL - row and column of cell (0-24,0-79)
- ; Exit: DI - offset address
-
- video_offset:
- mov al,160
- mul dh ; row * 160
- shl dl,1 ; column * 2
- mov dh,0 ; byte to word
- add ax,dx ; (row *160)+(column*2)
- mov di,ax ; set offset in di
- ret
-
-
-
- ; WRITELN subroutine copies a string of words from one memory location to
- ; another. The CGA status port is not checked for vertical retrace status
- ; before transfer.
- ; Entry: DS:SI - source
- ; ES:DI - destination
- ; CX - number of words
-
- writeln:
- cld ; clear for string instructions
- L1:
- movsw ; move one word
- loop L1 ; loop until done
- ret
-
-
-
- ; LPRINTZ routine sends a string of bytes delimited by a user-specified byte to
- ; LPT1: thru INT 17h.
- ; Entry: DS:SI - string address
- ; BL - delimiter (0-255)
-
- lprintz:
- cld ; for 8088 string instructions
- L1:
- lodsb ; get one byte
- cmp al,bl ; is it the delimiter?
- je RET ; yes, then exit
- mov dx,0 ; printer no. 0 (LPT1:)
- mov ah,0
- int 17h ; send byte to printer
- jmp L1 ; return for next byte
-
- ret
-
-
-
- ; LPT1STAT checks the current status of printer LPT1:. If it's either
- ; powered off or off-line, then an error condition is signalled upon return
- ; thru the carry flag.
- ; Exit: Carry clear - no error
- ; Carry set - error
-
- lpt1stat:
- mov dx,0 ; printer no. 0
- mov ah,2 ; use ROM BIOS 'get status' function
- int 17h
- test ah,8 ; test bit 3, I/O error indicator
- je >L1 ; if clear, then no error
- stc ; raise error flag
- ret
-
- L1:
- clc ; clear error flag
- ret
-
-
-
- ; BEEP uses the 8253 timer chip to emit a short beep thru the PC's speaker.
-
- beep:
- mov al,182 ; notify 8253 that frequency data is coming
- out 67,al
- mov al,0 ; send frequency (776.8 Hz)
- out 66,al
- mov al,6
- out 66,al
- in al,97 ; activate speaker
- or al,3
- out 97,al
- mov cx,6000h ; time delay for sound duration
- L1:
- loop L1
- in al,97 ; deactivate speaker
- and al,252
- out 97,al
- ret
-
-
-
- ; MEM2MEM subroutine transfers a non-overlapping block of memory one byte
- ; at a time.
- ; Entry: DS:SI - source
- ; ES:DI - destination
- ; CX - number of bytes
-
- mem2mem:
- cld
- L1:
- movsb ; transfer one byte
- loop L1 ; and loop until done
- ret
-
-
-
- ; Initialization routine sets up the window image in the WINDOW_TEXT area,
- ; resets the CURSOR_MODE word if this is a PCjr, and saves and replaces the
- ; old keyboard interrupt vector.
-
- initialize:
-
- ; Initialize the window text area by combining the text data with the attribute
- ; bytes and placing the conglomeration in the WINDOW_TEXT area.
-
- mov ah,15 ; check the current video mode
- int 10h
- cmp al,7 ; if it's mode 7, then replace the attribute
- jne >L0 ; bytes with ones appropriate for mono adapter
- mov attribute1,70h
- mov attribute2,07h
- L0:
- cld ; now combine the text and attribute bytes
- lea si,buffer_text ; point si to table of text
- lea di,window_bytes ; and di to storage area
- mov cx,112 ; create first four lines by combining
- mov al,attribute1 ; text with attribute1 (112 words)
- L1:
- movsb ; text byte
- stosb ; attribute byte
- loop L1 ; loop until all 112 words are done
- mov cx,11 ; now do the next 11 lines
- L2:
- push cx ; first attribute in each line is attribute1
- movsb
- stosb
- mov cx,26 ; next 26 attributes are attribute2
- mov al,attribute2
- L3:
- movsb
- stosb
- loop L3
- movsb
- mov al,attribute1 ; and the last in each line is attribute1
- stosb
- pop cx
- loop L2 ; loop until all 11 lines are done
- mov cx,112 ; create the last four lines just like
- L4:
- movsb ; the first four
- stosb
- loop L4
-
- ; Check the machine ID byte in ROM and if this is a PCjr, then reset the
- ; cursor and correct the CURSOR_MODE word at 0040:0060.
-
- mov ax,rom ; set ds to rom
- mov ds,ax
- cmp machine_id,0FDh ; is this a PCjr?
- jne >L5 ; no, then skip this routine
- mov ax,rom_bios_data ; set ds to ROM BIOS data area
- mov ds,ax
- mov cursor_mode,0607h ; reset the cursor mode indicator
- mov ah,1 ; then physically reset the cursor
- mov cx,0607h
- int 10h
-
- ; Now save the old keyboard interrupt vector and replace it with the new one.
-
- L5:
- mov ax,interrupts ; set ds to the interrupt vector area
- mov ds,ax
- mov ax,keyboard_int ; save old vector
- CS mov old_keyboard_int,ax
- mov ax,keyboard_int[2]
- CS mov old_keyboard_int[2],ax
- cli ; disable all interrupts but NMI
- mov keyboard_int,main ; and install new vector
- mov keyboard_int[2],cs
- sti ; re-enable interrupts
- mov dx,initialize ; point dx to end of resident section
- int 27h ; terminate-but-stay-resident