page ,132
;  X:0
;
; ZENO:  June 11, 1986
;
;   Modified Sept 4, 1986 by R Tansky to fix 40-character mode
;   Modified Oct 31, 1986 by R Tansky to further fix 40-character mode
;           and to fix graphics mode
;   Modified Jan 28, 1987 by C Blum to add code to support TTY mode
;           call ( AH=0EH ). Required by some clone BIOS implementations
;           ( DTK / ERSO for one ) because they do not issue any 'set
;           cursor' calls from within the TTY mode call. This causes
;           ZENO to lose its video offset and the display goes out to
;           lunch.
;   Modified May 29, 1987 by Lynn Ransdell to support KEDIT 3.51
;
cseg    segment para public 'code'
zeno            proc  far
        assume  cs:cseg, ds:cseg, es:cseg, ss:cseg
        org     100h            ; for .COM file
;
environment     equ   2Ch
command         equ   80h
slashk          equ   'K/'
slashk2         equ   'k/'
;
;-------------------------------
; enter here on initial load
;-------------------------------
;
start:
;
        jmp     near ptr load_pgm
;
video_vector    dd   0
core_seg        dw   0
;
bios_cursor_posn  label  dword
bios_ofst       dw   00h        ; offset for active page
                dw   40h        ; segment for bios data

;
crt_mode        db   2          ; passes if 4, 5, or 6
active_page     db   0
cursor_type     dw   0B0Ch      ; DOS cursor
;
video_posn      label  dword
video_ofst      dw     0        ; offset against video_seg
video_seg       dw     0
;
video_addr      dw     0
;
onesixty        db   160
;
;-------------------------------
; enter here from int 10h
;-------------------------------
;
video_int:
        sti                     ; interrupts on
        pushf                   ; save flags
        cmp     cs:crt_mode,3   ; check for color text 1
        je      video_keep      ; go if so
        cmp     cs:crt_mode,2   ; check for color text 2
        je      video_keep      ; go if so
        cmp     cs:crt_mode,7   ; check for b/w
        je      video_keep      ; go if so
        cmp     ah,0            ; to set mode
        je      route_set_mode
        jmp     video_exit      ; go if graphics / 40 col
video_keep:
        cmp     ah,14           ; to write as TTY
        je      route_TTY
        cmp     ah,2            ; to set cursor
        je      set_cursor
        cmp     ah,10           ; to write char only
        je      write_char
        cmp     ah,9            ; to write char/attr
        je      route_write_both
        cmp     ah,3            ; to read cursor
        je      route_read_cursor
        cmp     ah,1            ; to set type
        je      route_set_type
        cmp     ah,0            ; to set mode
        je      route_set_mode
        cmp     ah,5            ; to set page
        je      route_set_page
        cmp     ax,0FEFEh       ; kill code (FORMERLY 0FFOOh)
        je      route_do_kill   ; go if found
video_exit:
        popf                    ; restore flags
        jmp     cs:dword ptr video_vector ; hand off interrupt
;
route_TTY:
        jmp     TTY
;
route_write_both:
        jmp     write_both
;
route_read_cursor:
        jmp     read_cursor
;
route_set_page:
        jmp     set_page
;
route_set_type:
        jmp     set_type
;
route_set_mode:
        jmp     set_mode
;
route_do_kill:
        jmp     do_kill
;
write_char:
        cmp     bh,cs:active_page ; check page
        jne     video_exit      ; pass to bios
        cmp     cx,1            ; for multiple write
        jne     video_exit      ; pass to bios
        push    di              ; save
        push    es              ; save
        les     di,cs:video_posn ; get screen position
        cld                     ; frontwards
        stosb                   ; dump to screen
        pop     es              ; restore
        pop     di              ; restore
        popf                    ; restore flags
        iret                    ; done
;
set_cursor:
        cmp     bh,cs:active_page ; check page
        jne     video_exit      ; pass to bios
        push    ax              ; save
        push    cx              ; save
        push    dx              ; save
        push    di              ; save
        push    es              ; save
set_cursor_2:
        add     cs:video_ofst,2 ; for next char
        les     di,cs:bios_cursor_posn ; get bios
        inc     byte ptr es:[di] ; assume next
        cmp     es:[di],dx      ; check if next
        je      offset_ready    ; go if next
        mov     ax,dx           ; get req posn
        mov     es:[di],ax      ; save req posn
        mov     cx,ax           ; copy posn
        mov     al,ah           ; rows in al
        mul     cs:onesixty     ; for bytes
        xor     ch,ch           ; cols in cx
        shl     cx,1            ; for video
        add     ax,cx           ; offset in ax
        mov     cs:video_ofst,ax ; store offset
offset_ready:
        mov     cx,cs:video_ofst ; offset in cx
        shr     cx,1            ; for byte count
        mov     ah,14           ; cursor MSB register
        mov     dx,cs:video_addr ; 6845 index addr
        mov     al,ah           ; get register
        out     dx,al           ; send register
        inc     dx              ; 6845 data addr
        mov     al,ch           ; get cursor MSB
        out     dx,al           ; send cursor MSB
        dec     dx              ; 6845 index addr
        mov     al,ah           ; cursor MSB register
        inc     al              ; cursor LSB register
        out     dx,al           ; send register
        inc     dx              ; 6845 data addr
        mov     al,cl           ; get cursor LSB
        out     dx,al           ; send cursor LSB
        pop     es              ; restore
        pop     di              ; restore
        pop     dx              ; restore
        pop     cx              ; restore
        pop     ax              ; restore
        popf                    ; restore flags
        iret                    ; done
;
route_video_exit:
        jmp     video_exit
;
write_both:
        cmp     bh,cs:active_page ; check page
        jne     route_video_exit ; pass to bios
        cmp     cx,1            ; check multiple write
        jne     route_video_exit ; pass to bios
        push    ax              ; save
        push    di              ; save
        push    es              ; save
        mov     ah,bl           ; get attribute
        les     di,cs:video_posn ; get screen position
        cld                     ; frontwards
        stosw                   ; dump to screen
        pop     es              ; restore
        pop     di              ; restore
        pop     ax              ; restore
        popf                    ; restore flags
        iret                    ; done
;
read_cursor:
        cmp     bh,cs:active_page ; check page
        jne     route_video_exit ; pass to bios
        push    di              ; save
        push    es              ; save
        les     di,cs:bios_cursor_posn ; get bios
        mov     dx,es:[di]      ; get bios posn
        mov     cx,cs:cursor_type ; get type
        pop     es              ; restore
        pop     di              ; restore
        popf                    ; restore flags
        iret                    ; done
;
set_page:
        push    ax              ; save
        mov     cs:active_page,al ; save page
        xor     ah,ah           ; page in ax
        shl     ax,1            ; for word count
        add     ax,50h          ; offset for page zero
        mov     cs:bios_ofst,ax ; save offset
        pop     ax              ; restore
        jmp     video_exit      ; pass to bios
;
set_type:
        mov     cs:cursor_type,cx ; save type
        jmp     video_exit      ; pass to bios
;
set_mode:
        mov     cs:crt_mode,al  ; save mode
        mov     cs:video_ofst,0 ; top left
        jmp     video_exit      ; done
;
TTY:
        cmp     bh,cs:active_page ; check page
        jne     route_video_exit ; pass to bios
        cmp     al,' '          ; control characters
        jb      TTY_std         ;   go to real BIOS
        cmp     cs:video_ofst,25*80*2-2 ; scroll imminent ?
        jnb     TTY_std         ; yes, to real BIOS
        push    ax              ; save
        push    cx              ; save
        push    dx              ; save
        push    di              ; save
        push    es              ; save
        les     di,cs:video_posn ; get screen pos
        cld                     ; forewards
        stosb                   ; dump in char
        les     di,cs:bios_cursor_posn ; get bios
        mov     dx,es:[di]      ; get current pos
        inc     dl              ; next char pos
        cmp     dl,79           ; new line ?
        ja      TTY_new_line    ; yes, adjust
        jmp     set_cursor_2    ; set cursor
TTY_new_line:
        mov     dl,0            ; col = 1
        inc     dh              ; inc row
        jmp     set_cursor_2    ; set cursor
TTY_std:
        pushf                   ; phony int
        call    cs:video_vector ;   to real bios
        push    ax              ; save
        push    bx              ; save
        push    es              ; save
        les     bx,cs:bios_cursor_posn ; get bios
        mov     ax,es:[bx]      ; get cursor posn
        mov     bx,ax           ; copy posn
        mov     al,ah           ; rows in al
        mul     cs:onesixty     ; for bytes
        xor     bh,bh           ; cols in cx
        shl     bx,1            ; for video
        add     ax,bx           ; offset in ax
        mov     cs:video_ofst,ax ; store offset
        pop     es              ; restore
        pop     bx              ; restore
        pop     ax              ; restore
        popf                    ; restore flags
        iret                    ; done
;
; remove routine from memory
;
do_kill:
        mov     ax,cs           ; get code segment
        mov     ds,ax           ; set data segment
        mov     es,ax           ; set extra segment
        push    ds              ; save
        mov     ax,2510h        ; to set video vector
        lds     dx,video_vector ; get original
        int     21h             ; set vector
        pop     ds              ; restore
        mov     ah,49h          ; for free memory fn
        int     21h             ; do free memory
        push    es              ; save
        mov     bx,environment  ; get env. segment
        mov     es,cs:[bx]
        mov     ah,49h          ; for free memory fn
        int     21h             ; do free memory
        pop     es              ; restore
        lea     dx,kill_msg     ; get message
        mov     ah,9            ; for screen write
        int     21h             ; do write
        popf                    ; restore flags
        iret                    ; return to ZENO/K
;
kill_msg        db   13,10,'ZENO Removed',13,10,'$'
;
end_core:
;
;-------------------------------
; enter here to load program
;-------------------------------
;
load_pgm:
;
; check for color screen; set video segment
;
        mov     video_seg,0B000h ; assume mono
        mov     video_addr,03B4h ; assume mono
        int     11h             ; for equip check
        and     ax,30h          ; isolate adapter
        cmp     ax,30h          ; check for mono
        je      mono_screen     ; go if found
        mov     video_seg,0B800h ; reset for color
        mov     video_addr,03D4h ; reset for color
mono_screen:
;
; check command line
;
        mov     si,command      ; get command line
        mov     al,cs:[si]      ; length of argument
        or      al,al           ; check for zero
        je      command_clear   ; go if zero
        cmp     al,2            ; for kill request
        jne     retry           ; go if not
        cmp     word ptr cs:[si+1],slashk2 ; check for '/k'
        je      killme          ; go if not
        cmp     word ptr cs:[si+1],slashk ; check for '/K'
        jne     retry           ; go if not
killme: mov     ax,0FEFEh       ; set for kill (FORMERLY 0FFOOh)
        int     10h             ; order kill
        int     20h             ; exit to DOS
retry:
        lea     dx,retry_msg    ; get message
        mov     ah,9            ; for print fn
        int     21h             ; print message
        int     20h             ; exit to DOS
command_clear:
;
; find and set current variables
;
        les     di,bios_cursor_posn ; set to 0040:0000
        mov     al,es:[di+49h]  ; get current mode
        mov     crt_mode,al     ; save mode
        mov     ax,es:[di+60h]  ; get cursor type
        mov     cursor_type,ax  ; save type
        mov     al,es:[di+62h]  ; get active page
        mov     active_page,al  ; save active page
        xor     ah,ah           ; page in ax
        shl     ax,1            ; for word count
        add     ax,50h          ; offset for page zero
        mov     bios_ofst,ax    ; save offset
;
; set video interrupt
;
        mov     core_seg,cs     ; set core segment
        push    es              ; save
        mov     ax,3510h        ; to get vector
        int     21h             ; get vector
        mov     word ptr video_vector,bx ; store offset
        mov     word ptr video_vector+2,es ; store segment
        pop     es              ; restore
        mov     ax,2510h        ; to set video vector
        lea     dx,video_int    ; get offset; ds OK
        int     21h             ; set vector
;
; print messages; terminate and stay resident
;
        lea     dx,install_msg  ; get message
        mov     ah,9h           ; for print fn
        int     21h             ; print message
        cmp     video_seg,0B000h ; check for mono
        je      skip_message    ; go if mono
        lea     dx,color_msg    ; get message
        mov     ah,9h           ; for print fn
        int     21h             ; print message
skip_message:
        lea     dx,finish_msg   ; get termination
        mov     ah,9h           ; for print fn
        int     21h             ; print ternination
        lea     ax,end_core     ; last address in core
        add     ax,2Fh          ; make bumper
        mov     cl,4            ; for shift
        shr     ax,cl           ; convert to paras
        mov     bx,ax           ; no. paras to keep
        mov     dx,ax           ; same
        mov     ah,4Ah          ; for setblock
        int     21h             ; do setblock
        mov     ax,3100h        ; for keep; no exit code
        int     21h             ; exit and stay resident
;
install_msg     db   13,10,'ZENO 1.3 successfully Installed$'
;
color_msg       db   ';',13,10,'May cause some snow.$'
;
finish_msg      db   13,10,'$'
;
retry_msg       db   13,10,'No Action:  Invalid Command Line',13,10,7,'$'
;
zeno            endp
cseg            ends
        end     start

