;######################################################################
;    B800:0 Memory Watcher
;    TR [-?Rr01] [/?Rr01]
;       -? or /?          Help Message
;       -R, -r, /R or /r  Remove Memory Watcher
;       -F or /F          Memory Watch Off
;       -N or /N          Memory Watch On
;######################################################################

;######################################################################
;
; [Modification History]
;
; 04/1991 - Windows 3.0 Enhanced Mode Support (tag - Win3Enhance)
; 04/1991 - Code tuning and some bug fix      (tag - Fix9104)
;
;######################################################################



                .286p
BIOS_DATA_SEG   equ     40h
DISPLAY_MODE    equ     0049h
SCREEN_COLS     equ     004ah
REGEN_LENGTH    equ     004ch
REGEN_START     equ     004eh
CURSOR_POS      equ     0050h
CURSOR_TYPE     equ     0060h
DISPLAY_PAGE    equ     0062h
CRTC_REG        equ     0063h
SCREEN_ROWS     equ     0084h
CHR_HIGHT       equ     0085h

;
;       'int1Cp' Flag Definition
;
IN_DRAW         equ     0001h           ; INT 1CH in-process flag value
FN_FEFF         equ     0002h           ; INT 10H AH=FE or FF passthru flag
DISABLE_DRAW    equ     0004h
NON_JPMODE3     equ     0008h
RAM_allocated   equ     8000h           ; RAM is allocated at B800:0 ;Win3Enhance
                                        ; EMS mapping is unnecessary ;Win3Enhance
DRAW_PENDING    equ     4000h           ; Screen draw is pending     ;Fix9104


INT1C_N0        equ     4               ; default INT 1CH skip count

SCREEN_CH       equ     80*25           ; number of Screen Char
;Win3Enhance TEMP_BUFF       equ     2000H           ; tempral buffer offset

SCREEN_SEGM     equ     0B000H          ; Mono-REGEN Buffer Segment
SCREEN_SEG      equ     0B800H          ; Color-RGEN Buffer Segment

                                        ; Command Parameter flag value
FLAG_R          equ     1h              ; /r is spesified
FLAG_0          equ     2h              ; /f is spesified
FLAG_1          equ     4h              ; /n is spesified
FLAG_N          equ     8h              ; /0-9 is specified
FLAG_e          equ     10h             ; /e is spesified
FLAG_E          equ     20h             ; /E is spesified

tr      segment para public 'CODE'
        assume  cs:tr

;
; Int 10h inturrupt routine
;
TR_ID   db      "B800:0 Memory Watcher" ; This Program ID
TR_LEN  equ     $-offset TR_ID

        even
int1cN0 dw      0                       ; INT 1CH Skip Count Temp-Var
int1cN  dw      INT1C_N0                ; INT 1CH Skip Count
int1cA  dw      INT1C_N0                ; INT 1CH Skip Count Counter

int10f  dw      0                       ; INT 10H Nest Count
int1Cp  dw      0                       ; INT 1CH Process Flag
tempAX  dw      0

int10v  dw      0                       ; Old INT 10H Entry
        dw      0
int1cv  dw      0                       ; Old INT 1CH Entry
        dw      0
int16v  dw      0                       ; Old INT 16H Entry           ;Fix9104
        dw      0                                                     ;Fix9104
regen   dw      0                       ; Logical REGEN Buffer Address
        dw      0
DBCSv   dw      0
        dw      0

php_seg dw      0                       ; php Segment Value for this PROG
env_seg dw      0                       ; env Segment Value for this PROG

parameter dw    0                       ; command parameter flag for /R?

ems_hdl dw      0                       ; EMS HANDLE
lpage   dw      0                       ; EMS Logical Page No.
pg_seg  dw      SCREEN_SEG              ; EMS Mapped Physical Segment Value

map_cnt dw      1
        dw      SCREEN_SEG
pg_map  dw      4 dup(0)
pg_map1 dw      4 dup(0)

cursor_pos      dw      0
cursor_type     dw      0
crtc_reg        dw      3d4h

TEMP_BUFF_SEG   dw      0                                       ;Win3Enhance

sp_save dw      0
ss_save dw      0

        even
stack_area db    512 dup(?)
stack_top equ   $

;
; int 10H Routine
;
int10_skip:
        dec     int10f                  ; clear INT 10 Process Flag
;Fix9104        popf
        pop     ax
        iret
;
; New int 10H Routine
;     Check int 10H Nested Call
;
int10   proc    far
        sti                             ; Enable interrupts!    ;Fix9104
        push    ax                      ; save request function
;Fix9104        pushf
        inc     int10f                  ; set INT 10 Process Flag
        test    int1Cp,IN_DRAW          ; test if this call is requested
        jnz     int10_1                 ;    from TR.ASM or not
                                        ; if Yes, then skip to int10_1
        test    int1Cp,FN_FEFF
        jz      int10_1
;Fix9104        cmp     ah,0ffh                 ; Skip AH=FF and FE Requests
;Fix9104        jz      int10_skip
        cmp     ah,0feh
;Fix9104        jz      int10_skip
        jae     int10_skip                                      ;Fix9104
int10_1:
        and     ah,ah                   ; test if request is video mode set
        jnz     int10_2

        push    ds
        push    ax
        push    si
        or      int1Cp,NON_JPMODE3      ; remap B800:0 to original
        test    int1Cp, RAM_allocated                           ;Win3Enhance
        jnz     SkipUnmapping                                   ;Win3Enhance
                mov     ax,4f01h
                push    cs
                pop     ds
                mov     si,offset pg_map
                int     67h
SkipUnmapping:                                                  ;Win3Enhance
        pop     si
        pop     ax
        pop     ds
int10_2:
        pushf                                                   ;Fix9104
        call    dword ptr int10v        ; call original INT 10 Handler
        mov     tempAX,ax
        pop     ax
        push    tempAX
;Fix9104        pushf                           ; store System Flag Reg.
        and     ah,ah                   ; test if request is video mode set
        jnz     int10_3

        push    ds                      ; check DBCS vector
        push    si
        lds     si,dword ptr DBCSv
        mov     ax,ds:[si]
        and     ax,ax                   ; if zero, now us mode
        jz      int10_21

        mov     ax,0040h                ; verify video mode
        mov     ds,ax
        cmp     byte ptr ds:[0049h],3   ; check if video mode is 3 ?
        jnz     int10_21

        test    int1Cp, RAM_allocated                           ;Win3Enhance
        jnz     SkipRemapping                                   ;Win3Enhance
                mov     ax,4f01h                ; remap B800:0 to memory
                push    cs
                pop     ds
                mov     si,offset pg_map1
                int     67h
SkipRemapping:                                                  ;Win3Enhance
        call    setup_text_buffer                               ;Fix9104
        and     int1Cp,not NON_JPMODE3
int10_21:
        pop     si
        pop     ds
int10_3:                                ; set cursor register
ifdef CURSORHDL
        test    int1Cp,IN_DRAW          ; test if this call is requested
        jnz     int10_4                 ;    from TR.ASM or not

        push    ds
        push    dx
        push    bx
        push    ax
        mov     ax,BIOS_DATA_SEG
        mov     ds,ax
        mov     dx,crtc_reg
        mov     bx,ds:[CURSOR_POS]      ; get cursor position
        mov     al,80
        mul     bh
        xor     bh,bh
        add     bx,ax
        mov     al,0eh
        mov     ah,bh
        out     dx,ax                   ; set cursor position register
        mov     al,0fh
        mov     ah,bl
        out     dx,ax

        mov     bx,ds:[CURSOR_TYPE]     ; get cursor type
        mov     al,0ah
        mov     ah,bh
        out     dx,ax                   ; set cursor type register
        mov     al,0bh
        mov     ah,bl
        out     dx,ax
        pop     ax
        pop     bx
        pop     dx
        pop     ds
endif
int10_4:
        dec     int10f                  ; clear INT 10 Process Flag
;Fix9104        popf                            ; restore System Flag
        pop     ax
;Fix9104        ret     2                       ; instead of IRET
        iret                                                    ;Fix9104
int10   endp

;
; Int 1Ch inturrupt routine
;
int1c   proc    far
        test    int1Cp,NON_JPMODE3 or DISABLE_DRAW
        jnz     int1c_g

        test    int10f,0ffffh           ; test Int 10H Nest Flag
        jz      int1c_1
        dec     int1cA
        jnz     int1c_g
        mov     int1cA,1                ; if int1cA==0 then
        jmp     int1c_g                 ;   int1cA=1 for next processing

int1c_1:
        dec     int1cA
        jnz     int1c_g
        push    ax
        mov     ax,int1cN
        mov     int1cA,ax               ; set INT 1CH skip count
        pop     ax
        cli                             ; critical region start       ;Fix9104
        test    int1Cp, DRAW_PENDING                                  ;Fix9104
        jnz     CheckIfInDraw                                         ;Fix9104
                or      int1Cp, DRAW_PENDING                          ;Fix9104
                jmp     short int1c_g                                 ;Fix9104
CheckIfInDraw:                                                        ;Fix9104
        test    int1Cp,IN_DRAW          ; test INT 1CH Nest Flag
        jnz     int1c_g
                sti                     ; make sure int. is enabled   ;Fix9104
                call    int1Cdo
int1c_g:jmp     dword ptr int1cv
int1c   endp
;
; screen redraw check and draw
;
int1Cdo proc    near
;Fix9104        pushf                           ; Save all register
        cli
        mov     ss_save,ss
        mov     sp_save,sp
        push    cs
        pop     ss
        mov     sp,offset stack_top

        push    es
        push    ds
        pusha
        or      int1Cp,IN_DRAW          ; set in-Porcess Flag
ifdef CURSORHDL
        call    Adj_cursor_pos
        call    Adj_cursor_typ
endif
        sti
        lds     si,dword ptr DBCSv      ; get DBCS vector address
        mov     bp,sp
int1Cdo0:
        mov     ax,ds:[si]              ; save all DBCS vector into stack
        add     si,2
        push    ax
        and     ax,ax
        jnz     int1Cdo0

        lds     si,dword ptr regen      ; get REGEN Buffer Ptr to DS:SI
        mov     ax,SCREEN_SEG           ; set ES:DI to 0B800:0H
        mov     es,ax
        mov     di,0
        mov     cx,SCREEN_CH            ; set cx to Number of full SCREEN CHAR
        mov     bx,0
int1Cdo1:
        mov     ax,ds:[si]
        call    isDBCS
        mov     dx,ax
        mov     ax,es:[di]              ; test if 0B800:XXXX is accessed
;Win3Enhance        cmp     es:[di+TEMP_BUFF],ax
        call    cmp_AX_with_tmp_buf                             ;Win3Enhance
        jnz     int1Cdo2
        mov     es:[di],dx              ; set it to REGEN Buffer Data
;Win3Enhance        mov     es:[di+TEMP_BUFF],dx    ; set temp buff
        xchg    ax, dx                                          ;Win3Enhance
        call    set_AX_to_tmp_buf                               ;Win3Enhance
        xchg    ax, dx                                          ;Win3Enhance
        add     di,2
        add     si,2
        dec     cx
        jnz     int1Cdo1
        jmp     int1Cdo5
int1Cdo2:
        cmp     bl,2
        jnz     int1Cdo2_1
        sub     si,2
        sub     di,2
        inc     cx
        push    cx
        push    di
        push    si
        add     di,4
        add     si,4
        sub     cx,2
        mov     bh,bl
        jmp     int1Cdo3
int1Cdo2_1:
        push    cx                      ; save CX value
        push    di                      ; save DI value
        push    si
        add     si,2
        add     di,2
        dec     cx
        xchg    bh,bl
        xor     bl,bl
        call    isDBCS
        xchg    bh,bl
int1Cdo3:
        and     cx,cx
        jz      int1Cdo4_1
        mov     ax,ds:[si]
        call    isDBCS
        mov     ax,es:[di]
        xchg    bh,bl
        call    isDBCS
        xchg    bh,bl
        cmp     bl,2
        jz      int1Cdo3_1
;Win3Enhance        cmp     es:[di+TEMP_BUFF],ax
        call    cmp_AX_with_tmp_buf                             ;Win3Enhance
        jz      int1Cdo4
int1Cdo3_1:
        add     si,2
        add     di,2
        dec     cx
        jmp     int1Cdo3
int1Cdo4:
        cmp     bl,0
        jnz     int1Cdo4_00
        cmp     bh,2
        jnz     int1Cdo4_1
        jmp     int1Cdo4_0
int1Cdo4_00:
        cmp     bl,1
        jnz     int1Cdo4_0
        cmp     bh,2
        jnz     int1Cdo4_1

int1Cdo4_0:
        add     si,2
        add     di,2
        dec     cx
        jz      int1Cdo4_1
        mov     ax,ds:[si]
        call    isDBCS
;       mov     ax,es:[di]
        xchg    bh,bl
        call    isDBCS
        xchg    bh,bl
        jmp     int1Cdo4
int1Cdo4_1:
        pop     si
        pop     di
        pop     dx
        sub     dx,cx
        xchg    cx,dx                   ; CX is upated length
        mov     ah,0ffh                 ; SCREEN Refresh Request
        int     10h
int1Cdo40:
        mov     ax,ds:[si]              ; set B800:XXXX and temp buff
        mov     es:[di],ax              ;   to REGEN Buffer Data
;Win3Enhance        mov     es:[di+TEMP_BUFF],ax
        call    set_AX_to_tmp_buf                               ;Win3Enhance
        add     si,2
        add     di,2
        loop    int1Cdo40

        mov     bx,0
        xchg    cx,dx                   ; CX is the number of remaining char
        and     cx,cx
        jz      int1Cdo5
        jmp     int1Cdo1
int1Cdo5:
        mov     sp,bp

;Fix9104        cli
        and     int1Cp,not IN_DRAW      ; Reset in-process Flag
        popa
        pop     ds
        pop     es

;Fix9104        mov     sp,sp_save
        mov     ss,ss_save
        mov     sp,sp_save
;Fix9104        popf
;Fix9104        sti
        ret
int1Cdo endp

;                                                               ;Win3Enhance
;       Entry:                                                  ;Win3Enhance
;               ax = data to check if it is changed or not      ;Win3Enhance
;               di = offset to the data to be compared with     ;Win3Enhance
;       Exit:                                                   ;Win3Enhance
;               zf = 1 if equal                                 ;Win3Enhance
;                    0 if not equal                             ;Win3Enhance
;                                                               ;Win3Enhance
cmp_AX_with_tmp_buf     proc    near                            ;Win3Enhance
        push    es                                              ;Win3Enhance
                mov     es, TEMP_BUFF_SEG                       ;Win3Enhance
                cmp     es:[di], ax                             ;Win3Enhance
        pop     es                                              ;Win3Enhance
        ret                                                     ;Win3Enhance
cmp_AX_with_tmp_buf     endp                                    ;Win3Enhance
;                                                               ;Win3Enhance
;       Entry:                                                  ;Win3Enhance
;               ax = data to set to temp buffer                 ;Win3Enhance
;               di = offset to the area to set the data to      ;Win3Enhance
;       Exit:                                                   ;Win3Enhance
;               none                                            ;Win3Enhance
;                                                               ;Win3Enhance
set_AX_to_tmp_buf       proc    near                            ;Win3Enhance
        push    es                                              ;Win3Enhance
                mov     es, TEMP_BUFF_SEG                       ;Win3Enhance
                mov     es:[di], ax                             ;Win3Enhance
        pop     es                                              ;Win3Enhance
        ret                                                     ;Win3Enhance
set_AX_to_tmp_buf       endp                                    ;Win3Enhance

;                                                               ;Fix9104
;       Copies initial char/attr data from DOS/V logical video  ;Fix9104
;       buffer to TR text buffer                                ;Fix9104
;                                                               ;Fix9104
;       Entry:                                                  ;Fix9104
;               none                                            ;Fix9104
;       Exit:                                                   ;Fix9104
;               none                                            ;Fix9104
;                                                               ;Fix9104
setup_text_buffer       proc    near                            ;Fix9104
        push    ds                                              ;Fix9104
        push    es                                              ;Fix9104
        push    cx                                              ;Fix9104
        push    si                                              ;Fix9104
        push    di                                              ;Fix9104
                cld                                             ;Fix9104
                mov     es, TEMP_BUFF_SEG                       ;Fix9104
                xor     di, di                                  ;Fix9104
                mov     cx, SCREEN_CH                           ;Fix9104
                lds     si, dword ptr regen                     ;Fix9104
                rep     movsw                                   ;Fix9104
                ;                                               ;Fix9104
                mov     cx, SCREEN_SEG                          ;Fix9104
                mov     es, cx                                  ;Fix9104
                xor     di, di                                  ;Fix9104
                mov     cx, SCREEN_CH                           ;Fix9104
                sub     si, cx                                  ;Fix9104
                sub     si, cx                                  ;Fix9104
                rep     movsw                                   ;Fix9104
        pop     di                                              ;Fix9104
        pop     si                                              ;Fix9104
        pop     cx                                              ;Fix9104
        pop     es                                              ;Fix9104
        pop     ds                                              ;Fix9104
        ret                                                     ;Fix9104
setup_text_buffer       endp                                    ;Fix9104


;
;    Adjust Cursor Postion
;
Adj_cursor_pos proc near
        mov     dx,crtc_reg             ; get cursor position reg
        mov     al,0eh
        out     dx,al
        inc     dx
        in      al,dx
        mov     bh,al
        dec     dx
        mov     al,0fh
        out     dx,al
        inc     dx
        in      al,dx
        mov     bl,al
        cmp     cursor_pos,bx           ; check if it is save to previous value
        jz      Adj_cursor_pos0

        mov     cursor_pos,bx           ; set cursor postion by calling INT 10
        mov     al,80
        xchg    ax,bx
        div     bl
        mov     dl,ah
        mov     dh,al
        mov     ax,BIOS_DATA_SEG
        mov     ds,ax
        push    ds:[CURSOR_POS]
        mov     bh,0
        mov     ah,2
        sti
        int     10h
        cli
        pop     ds:[CURSOR_POS]
Adj_cursor_pos0:
        ret
Adj_cursor_pos endp

;
;       Adjust Cursor Type
;
Adj_cursor_typ proc near
        mov     dx,crtc_reg             ; get cursor type reg
        mov     al,0ah
        out     dx,al
        inc     dx
        in      al,dx
        mov     bh,al
        dec     dx
        mov     al,0bh
        out     dx,al
        inc     dx
        in      al,dx
        mov     bl,al
        cmp     cursor_type,bx          ; chech if it is same to previous value
        jz      Adj_cursor_typ0

        mov     cursor_type,bx          ; set cursor type by calling INT 10
        mov     ax,BIOS_DATA_SEG
        mov     ds,ax
        push    ds:[CURSOR_TYPE]
        mov     cx,bx
        mov     ah,1
        sti
        int     10h
        cli
        pop     ds:[CURSOR_TYPE]
Adj_cursor_typ0:
        ret
Adj_cursor_typ endp

;
; check ax value is DBCS char or not
;       ax : regen buffer value
;       bl : 0-previous char is SBCS
;            1-previous char is DBCS 1st byte
;       bp : DBCS vector pointer
;   return
;       bl : 0-this char is SBCS
;            1-this char is DBCS 1st byte
;            2-this char is DBCS 2nd byte
;
isDBCS  proc    near
        cmp     bl,1
        jz      isDBCS3
        push    bp
isDBCS0:sub     bp,2
        test    ss:[bp],0ffffh
        jz      isDBCS1
        cmp     al,ss:[bp]
        jb      isDBCS1
        cmp     al,ss:[bp+1]
        jbe     isDBCS2
        jmp     isDBCS0
isDBCS1:pop     bp
        mov     bl,0
        jmp     isDBCS4
isDBCS2:pop     bp
        mov     bl,1
        jmp     isDBCS4
isDBCS3:mov     bl,2
isDBCS4:ret
isDBCS  endp

;                                                                     ;Fix9104
;       Event service routine.                                        ;Fix9104
;                                                                     ;Fix9104
;       This routine is activated by INT16H interrupt. The event      ;Fix9104
;       is queued by INT1CH interrupt routine when the interrupt      ;Fix9104
;       count is exhasuted. But if the event is not serviced by       ;Fix9104
;       this routine, the INT1CH routine by itself service the        ;Fix9104
;       event.                                                        ;Fix9104
;                                                                     ;Fix9104
int16   proc    far                                                   ;Fix9104
        cli                                                           ;Fix9104
        test    int1Cp, DRAW_PENDING                                  ;Fix9104
        jz      goto_original_int16                                   ;Fix9104
                and     int1Cp, not DRAW_PENDING                      ;Fix9104
                sti                     ; make sure int. is enabled   ;Fix9104
                call    int1Cdo                                       ;Fix9104
goto_original_int16:                                                  ;Fix9104
        jmp     dword ptr int16v                                      ;Fix9104
int16   endp                                                          ;Fix9104


;######################################################################
;
; Initial Routine
;
;######################################################################
        assume  cs:tr,ss:tr_stack
start:
        jmp     continue                                        ;Win3Enhance
        db      4 * 1024 dup(?)         ; TEMP_BUFF             ;Win3Enhance
continue:                                                       ;Win3Enhance

        mov     php_seg,ds              ; save php_seg for free-memory
        mov     bx,002ch
        mov     ax,ds:[bx]
        mov     env_seg,ax
;
; Initial Message out
;
        push    ds
        push    cs
        pop     ds
        mov     ah,9
        mov     dx,offset messageV
        int     21h

        mov     ax,6300h
        int     21h
        mov     DBCSv,si
        mov     DBCSv+2,ds
        pop     ds
;
; Parameter Processing
;
        cld                                                     ;Fix9104
        mov     si,80h                  ; set Parameter buffer
        xor     cx,cx                   ;       and
        mov     cl,[si]                 ;     its Length
        cmp     cx,0
        jne     init_1
        jmp     install

init_1: inc     si
init_2: lodsb
        dec     cx
        cmp     al,'-'                  ; parameter delimeter
        je      init_3
        cmp     al,'/'                  ; another parameter dlimiter
        je      init_3
        cmp     al,' '                  ; skip if ch=space
        jz      init_2
        cmp     al,9                    ; skip if ch=TAB
        jz      init_2
        jmp     init_Q                  ; Otherwise, Parameter Error

init_3: cmp     cx,0                    ; -xx or /xx
        jz      install
        lodsb
        dec     cx
        cmp     al,'?'                  ; test '?' parameter
        jnz     init_4
        jmp     init_H                  ; print out Help Message

init_4: cmp     al,'R'                  ; test 'R' parameter
        jz      init_5
        cmp     al,'r'
        jnz     init_6
init_5: or      parameter,FLAG_R        ; Set Remove FLAG
        jmp     init_3

init_6: cmp     al,'F'                  ; test 'N' parameter
        jz      init_60
        cmp     al,'f'
        jnz     init_7
init_60:or      parameter,FLAG_0        ; Set Mem-Watch Disable FLAG
        jmp     init_3

init_7: cmp     al,'N'                  ; test 'F' parameter
        jz      init_70
        cmp     al,'n'
        jnz     init_8
init_70:or      parameter,FLAG_1        ; Set Mem-Watch Enable FLAG
        jmp     init_3

init_8: cmp     al,'0'
        jb      init_9
        cmp     al,'9'
        jg      init_9
        or      parameter,FLAG_N
        xor     ah,ah
        sub     al,'0'
        and     ax,ax
        jnz     init_80
        mov     ax,INT1C_N0
init_80:mov     int1cN0,ax
        jmp     init_3

init_9: cmp     al,'E'
        jnz     init_A
        or      parameter,FLAG_E
        jmp     init_3

init_A: cmp     al,'e'
        jnz     init_B
        or      parameter,FLAG_e
        jmp     init_3

init_B: jmp     init_Q                  ; Parameter Error
;######################################################################
;
; Intallation Process
;
;######################################################################
installq:
        jmp     init_Q

        assume  cs:tr,ss:tr_stack,ds:tr
        assume  es:tr                                               ;Fix9104

install:
        push    cs
        pop     ds

        mov     ax,parameter
        and     ax,ax
        jnz     install1
        jmp     no_param

install1:
        test    ax,FLAG_R
        jz      install2
        test    ax,FLAG_0 or FLAG_1 or FLAG_N or FLAG_E or FLAG_e
        jnz     installq
        jmp     remove

install2:
        mov     bx,ax
        and     ax,FLAG_0 or FLAG_1
        cmp     ax,FLAG_0 or FLAG_1
        jz      installq

        mov     ax,bx
        and     ax,FLAG_E or FLAG_e
        cmp     ax,FLAG_E or FLAG_e
        jz      installq

        call    inschk
        and     cx,cx
        jz      install3
        jmp     install4

;######################################################################
;
; in case that TR program is already installed
;
; 'es' points the original TR segment which was found by 'inschk'   ;Fix9104
; function.                                                         ;Fix9104
;
;######################################################################
install3:
        test    parameter,FLAG_0
        jz      install30

        or      es:int1Cp,DISABLE_DRAW  ; Disable Redraw

        test    es:int1Cp, RAM_allocated                        ;Win3Enhance
        jnz     SkipUnmapping2                                  ;Win3Enhance
                push    ds                      ; remap b800:0 to original
                mov     ax,4f01h
                push    es
                pop     ds
                mov     si,offset pg_map
                int     67h
                pop     ds
SkipUnmapping2:                                                 ;Win3Enhance

        mov     dx,offset message5
        mov     ah,9
        int     21h

install30:
        test    parameter,FLAG_1
        jz      install31

        test    es:int1Cp, RAM_allocated                        ;Win3Enhance
        jnz     SkipRemapping2                                  ;Win3Enhance
                push    ds                      ; Enable Redraw
                mov     ax,4f01h                ; Map B800:0 to EMS memory
                push    es
                pop     ds
                mov     si,offset pg_map1
                int     67h
                pop     ds
SkipRemapping2:                                                 ;Win3Enhance
        call    setup_text_buffer                               ;Fix9104

        and     es:int1Cp,not DISABLE_DRAW

        mov     dx,offset message6
        mov     ah,9
        int     21h

install31:
        test    parameter,FLAG_N
        jz      install32
        mov     ax,int1cN0
        mov     es:int1cN,ax
        mov     dx,offset message8
        mov     ah,9
        int     21h

install32:
        test    parameter,FLAG_E
        jz      install33
        or      es:int1Cp,FN_FEFF
        mov     dx,offset message9
        mov     ah,9
        int     21h

install33:
        test    parameter,FLAG_e
        jz      install34
        and     es:int1Cp,not FN_FEFF
        mov     dx,offset messageA
        mov     ah,9
        int     21h

install34:
        mov     ax,4c00h                ; terminate return code=0
        int     21h

;######################################################################
;
; in case that TR program is not installed yet
;
;######################################################################
install4:
        push    ds
        lds     si,dword ptr DBCSv
        test    word ptr [si],0ffffh
        pop     ds
        jnz     install400
        jmp     us_mode

install400:
        test    parameter,FLAG_0
        jz      install40
        mov     dx,offset message5
        mov     ah,9
        int     21h

install40:
        test    parameter,FLAG_1
        jz      install41
        mov     dx,offset message6
        mov     ah,9
        int     21h

install41:
        test    parameter,FLAG_N
        jz      install42
        mov     ax,int1cN0
        mov     int1cN,ax
        mov     dx,offset message8
        mov     ah,9
        int     21h

install42:
        test    parameter,FLAG_E
        jz      install43
        or      int1Cp,FN_FEFF
        mov     dx,offset message9
        mov     ah,9
        int     21h

install43:
        test    parameter,FLAG_e
        jz      ems_tst
        and     int1Cp,not FN_FEFF
        mov     dx,offset messageA
        mov     ah,9
        int     21h
        jmp     ems_tst

;######################################################################
;
; No Parameter (Normal Installation)
;
;######################################################################
no_param:
        call    inschk
        and     cx,cx                   ; cx=0 means TR is installed
        jnz     ems_tst
        jmp     installed               ; already TR is installed

ems_tst:
        ; Check if a candidate RAM buffer is allocated at B800H ;Win3Enhance
        ; segment. If allocated, skip the remap routine.        ;Win3Enhance
        push    ds                                              ;Win3Enhance
                mov     ax, SCREEN_SEG                          ;Win3Enhance
                mov     ds, ax                                  ;Win3Enhance
                mov     al, byte ptr ds:[0]                     ;Win3Enhance
                mov     ah, al          ; save for later use    ;Win3Enhance
                not     byte ptr ds:[0]                         ;Win3Enhance
                not     al                                      ;Win3Enhance
                cmp     al, byte ptr ds:[0]                     ;Win3Enhance
                mov     byte ptr ds:[0], ah                     ;Win3Enhance
        pop     ds                                              ;Win3Enhance
        jne     WeNeedEMS                                       ;Win3Enhance
                ; A candidate RAM buffer is not allocated.      ;Win3Enhance
                or      int1Cp, RAM_allocated                   ;Win3Enhance
                jmp     ems_set3                                ;Win3Enhance
WeNeedEMS:                                                      ;Win3Enhance
        mov     ax,3567h                ; Get EMS Vector
        int     21h
        mov     di,000ah                ; Offset 0aH shows EMS NAME
        mov     si,offset EMM_NAME
        mov     cx,EMM_NAME_LEN
        repz cmpsb                      ; cmp EMS NAME
        and     cx,cx                   ; if cx=0 then EMS is Available
        jz      ems_set
        jmp     ems_err                 ; EMS is not installed
ems_set:
        push    cs                      ; Save B800:0 area map information
        pop     es
        mov     ax,4f00h
        mov     si,offset map_cnt
        mov     di,offset pg_map
        int     67h
        and     ah,ah
        jz      ems_set0
        jmp     ems_err
ems_set0:
        mov     ax,5a00h                ; Get EMS Handler for 1 Page
        mov     bx,1
        int     67h
        and     ah,ah
        jz      ems_set1
        jmp     ems_err
ems_set1:
        mov     ems_hdl,dx              ; Save EMS Handler
        mov     cx,1                    ; Map Memory to B800:0
        mov     si,offset lpage
        mov     ax,5001h
        int     67h
        and     ah,ah
        jz      ems_set2
        mov     ah,45h                  ; Free EMS Handler
        int     67H
        jmp     ems_err                 ; Map Error
ems_set2:
        push    cs                      ; Save B800:0 area map information
        pop     es
        mov     ax,4f00h
        mov     si,offset map_cnt
        mov     di,offset pg_map1
        int     67h
        and     ah,ah
        jz      ems_set3
        jmp     ems_err
ems_set3:
        mov     ax,SCREEN_SEG           ; Get Logical REGEN Buffer
        mov     es,ax
        mov     di,0
        mov     ah,0feh
        int     10h
        mov     regen,di                ; Save it at regen
        mov     regen+2,es

        push    ds
        lds     si,dword ptr regen      ; Copy it onto B800:0
        mov     ax,SCREEN_SEG
        mov     es,ax
        mov     di,0
        mov     cx,SCREEN_CH
        rep movsw
        pop     ds

        mov     dx, SCREEN_SEG          ; Set up 'TEMP_BUFF_SEG';Win3Enhance
        add     dx, 200h                                        ;Win3Enhance
        test    int1Cp, RAM_allocated                           ;WIn3Enhance
        jz      NotChangeTmpBuf                                 ;Win3Enhance
                mov     dx,offset start + 0fh                   ;Win3Enhance
                shr     dx,4                                    ;Win3Enhance
                mov     ax, cs                                  ;Win3Enhance
                add     dx, ax                                  ;Win3Enhance
NotChangeTmpBuf:                                                ;Win3Enhance
        mov     TEMP_BUFF_SEG, dx                               ;Win3Enhance

        push    ds
        mov     es, TEMP_BUFF_SEG                               ;Win3Enhance
        xor     di, di                                          ;Win3Enhance
        lds     si,dword ptr regen      ; Copy it onto Temp Buffer
;Win3Enhance        mov     di,TEMP_BUFF
        mov     cx,SCREEN_CH
        rep movsw
        pop     ds

        mov     ax,3510h                ; Get INT 10H Vector
        int     21h
        mov     int10v,bx               ; Save it at int10v
        mov     int10v+2,es

        mov     ax,2510h                ; Set New INT 10H Entry
        mov     dx,offset int10
        int     21h

        mov     ax,351ch                ; Get INT 1CH Vector
        int     21h
        mov     int1cv,bx               ; Aave it at int1cv
        mov     int1cv+2,es

        mov     ax,251ch                ; Set New INT 1CH Entry
        mov     dx,offset int1c
        int     21h

        mov     ax,3516h                ; Get INT 16H Vector          ;Fix9104
        int     21h                                                   ;Fix9104
        mov     int16v,bx               ; Aave it at int1cv           ;Fix9104
        mov     int16v+2,es                                           ;Fix9104
                                                                      ;Fix9104
        mov     ax,2516h                ; Set New INT 16H Entry       ;Fix9104
        mov     dx,offset int16                                       ;Fix9104
        int     21h                                                   ;Fix9104

        mov     ah,9                    ; Installation Message out
        mov     dx,offset message
        int     21h

        mov     ax,3100h                ; Stay Regident Program
        mov     dx,offset start + 10fh
        shr     dx,4
        test    int1Cp, RAM_allocated                           ;Win3Enhance
        jz      NotIncProgramSize                               ;Win3Enhance
                add     dx, 100h        ; 4KB for TEMP_BUFF     ;Win3Enhance
NotIncProgramSize:                                              ;Win3Enhance

        int     21h

;######################################################################
;
; Remove TR program
;
;######################################################################
remove:
        call    inschk
        and     cx,cx                   ; cx=0 means TR is installed
        jz      remove1
        jmp     noinstall               ; TR is not installed
remove1:
        push    ds
        lds     dx,dword ptr es:int1cv
        mov     ax,251ch
        int     21h

        push    es                                              ;Fix9104
        pushf                                                   ;Fix9104
                lds     dx,dword ptr es:int16v                  ;Fix9104
                cli                                             ;Fix9104
                xor     bx, bx                                  ;Fix9104
                mov     es, bx                                  ;Fix9104
                mov     bx, 16h * 4                             ;Fix9104
                mov     es:[bx], dx                             ;Fix9104
                mov     es:[bx + 2], ds                         ;Fix9104
        popf                                                    ;Fix9104
        pop     es                                              ;Fix9104

        lds     dx,dword ptr es:int10v
        mov     ax,2510h
        int     21h
        pop     ds

        test    es:int1Cp, RAM_allocated                        ;Win3Enhance
        jnz     SkipEmsHandling                                 ;Win3Enhance
                mov     ax,5001H
                mov     cx,1
                mov     dx,es:ems_hdl
                push    ds
                push    es
                pop     ds
                mov     si,offset lpage
                mov     ds:[si],0ffffh
                int     67H
                pop     ds

                mov     ah,45h
                int     67H

                push    ds
                mov     ax,4f01h
                push    es
                pop     ds
                mov     si,offset pg_map
                int     67h
                pop     ds
SkipEmsHandling:                                                ;Win3Enhance

        push    es
        mov     es,es:env_seg
        mov     ah,49h
        int     21h
        pop     es

        mov     es,es:php_seg
        mov     ah,49h
        int     21h

        mov     dx,offset message4
        mov     ah,9
        int     21h

        mov     ax,4c00h                ; terminate return code=0
        int     21h
;
; check this program is already installed or not
;       cx=0: not installed yet
;       cx<>0:already installed
;
inschk  proc    near
        mov     ax,3510h                ; Get INT 10H Vector
        int     21h
        mov     di,offset TR_ID         ; check TR is already installed or not
        mov     si,di
        push    cs
        pop     ds
        mov     cx,TR_LEN
        repz cmpsb
        ret
inschk  endp

EMM_NAME db     "EMMXXXX0"
EMM_NAME_LEN equ $ - offset EMM_NAME

;Win3Enhance messageV db     "Pseudo REGEN Buffer Emulator Version 1.10 Lvl 001",0dh,0ah,"$"
messageV db     "Pseudo REGEN Buffer Emulator Version 1.20 Lvl 001",0dh,0ah,"$" ;Win3Enhance
message  db     "0B800:0 Memory Watcher Installed Successfully",0dh,0ah,"$"
message0 db     "Memory Watcher is already Installed",0dh,0ah,"$"
message1 db     "Memory Watcher is not Installed yet",0dh,0ah,"$"
message2 db     "Parameter Error",0dh,0ah
message3 db     "TR [-?Rr01] [/?Rr01]",0dh,0ah
         db     "     -? or /?          Type This Message",0dh,0ah
         db     "     -R, -r, /R or /r  Remove Memory Watcher",0dh,0ah
         db     "     -E or /E          INT 10H AH=FE or FF Pass-through",0dh,0ah
         db     "     -e or /e          INT 10H AH=FE or FF not Pass-through",0dh,0ah
         db     "     -F or /f          Disable Memory Watch(not supported yet)",0dh,0ah
         db     "     -N or /n          Enable Memory Watch(not supported yet)",0d,0ah
         db     "     -1 -2 ... -9 or   INT 1CH Skip Count for Screen Redraw",0dh,0ah
         db     "     /1 /2 ... /9"
         db     "$"
message4 db     "Memory Watcher is Removed",0dh,0ah,"$"
message5 db     "Memory Watching is Disabled",0dh,0ah,"$"
message6 db     "Memory Watching is Enabled",0dh,0ah,"$"
message7 db     "Can not Allocate Memory at B800:0",0dh,0ah,"$"
message8 db     "INT 1CH Skip Count is Changed",0dh,0ah,"$"
message9 db     "INT 10H AH=FE or FF request is pass-through",0dh,0ah,"$"
messageA db     "INT 10H AH=FE or FF request is handled",0dh,0ah,"$"
messageB db     "Please Install Memory Watcher under Japanese Mode",0dh,0ah,"$"

installed:
        mov     dx,offset message0
        jmp     quit

noinstall:
        mov     dx,offset message1
        jmp     quit

init_Q: mov     dx,offset message2
        push    cs
        pop     ds
        jmp     quit

init_H: mov     dx,offset message3
        push    cs
        pop     ds
        jmp     quit

ems_err:mov     dx,offset message7
        jmp     quit

us_mode:mov     dx,offset messageB
        jmp     quit

quit:   mov     ah,9
        int     21h

        mov     ax,4c01h                ; terminate return code=1
        int     21h

tr      ends

tr_stack segment para STACK 'STACK'     ; Stack Segment
        db      256 dup(?)
tr_stack ends

        end     start
