Category : Assembly Language Source Code
Archive   : A86CNVRT.ZIP
Filename : S2.8

Output of file : S2.8 contained in archive : A86CNVRT.ZIP

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
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.

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.

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

; 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.

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

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.

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.

call beep ; beep and return for another keypress
jmp getkey

; An extended code has been entered...check its validity and goto the
; appropriate routine.

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.

sub ah,15 ; adjustment for shifted function keys
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.

mov dx,3DAh ; read CGA status port
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

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

; 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

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
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

; 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

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
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

; 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

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

; 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

cld ; clear for string instructions
movsw ; move one word
loop L1 ; loop until done

; 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)

cld ; for 8088 string instructions
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


; 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

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

clc ; clear error flag

; BEEP uses the 8253 timer chip to emit a short beep thru the PC's speaker.

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
loop L1
in al,97 ; deactivate speaker
and al,252
out 97,al

; 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

movsb ; transfer one byte
loop L1 ; and loop until done

; 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 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
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)
movsb ; text byte
stosb ; attribute byte
loop L1 ; loop until all 112 words are done
mov cx,11 ; now do the next 11 lines
push cx ; first attribute in each line is attribute1
mov cx,26 ; next 26 attributes are attribute2
mov al,attribute2
loop L3
mov al,attribute1 ; and the last in each line is attribute1
pop cx
loop L2 ; loop until all 11 lines are done
mov cx,112 ; create the last four lines just like
movsb ; the first four
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.

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