Annotation of ntddk/src/video/displays/vga/i386/special.asm, revision 1.1.1.1

1.1       root        1:                 page    ,132
                      2: ;---------------------------Module-Header------------------------------;
                      3: ; Module Name: special.asm
                      4: ;
                      5: ; Copyright (c) 1992 Microsoft Corporation
                      6: ;-----------------------------------------------------------------------;
                      7:         title   Special
                      8:         .386
                      9: 
                     10: ifndef  DOS_PLATFORM
                     11:         .model  small,c
                     12: else
                     13: ifdef   STD_CALL
                     14:         .model  small,c
                     15: else
                     16:         .model  small,pascal
                     17: endif;  STD_CALL
                     18: endif;  DOS_PLATFORM
                     19: 
                     20:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
                     21:         assume fs:nothing,gs:nothing
                     22: 
                     23:         .data
                     24: 
                     25: ;BUGBUG this should be obtained from the surface
                     26: 
                     27:         extrn   ulNextScan_global:dword
                     28: 
                     29:         .code
                     30: 
                     31: _TEXT$01   SEGMENT DWORD USE32 PUBLIC 'CODE'
                     32:            ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
                     33: 
                     34:         .xlist
                     35:         include stdcall.inc             ;calling convention cmacros
                     36:         include i386\cmacFLAT.inc       ; FLATland cmacros
                     37:         include i386\display.inc        ; Display specific structures
                     38:         include i386\ppc.inc            ; Pack pel conversion structure
                     39:         include i386\bitblt.inc         ; General definitions
                     40:         include i386\ropdefs.inc        ; Rop definitions
                     41:         include i386\egavga.inc         ; EGA register definitions
                     42:         include i386\strucs.inc
                     43:         .list
                     44: 
                     45: ; Rops we use in this code
                     46: 
                     47: ROP_P           equ     0F0h
                     48: ROP_Pn          equ      0Fh
                     49: ROP_S           equ     0CCh
                     50: ROP_DDx         equ       0
                     51: ROP_DDxn        equ     0FFh
                     52: ROP_Dn          equ     055h
                     53: ROP_DPx         equ     05Ah
                     54: 
                     55: ; Other values used in this code
                     56: 
                     57: fr              equ     [ebp]           ; Access to bitblt frame
                     58: bptr            equ     byte ptr
                     59: 
                     60: ;----------------------------Public Routine----------------------------;
                     61: ; check_device_special_cases
                     62: ;
                     63: ; Check for fast special cases of BLT.
                     64: ;
                     65: ; Determine if the BLT is a special case which can be performed with
                     66: ; static code as opposed to code compiled on the stack, and, if so,
                     67: ; dispatch to the proper static code.
                     68: ;
                     69: ; The parameters needed for the BLT (phase alignment, directions of
                     70: ; movement, ...) have been computed and saved.  These parameters will
                     71: ; now be interpreted and a BLT created on the stack.
                     72: ;
                     73: ; If the raster op is source copy, both devices are the screen, and the
                     74: ; phase alignment is 0, then the copy can be performed by the static
                     75: ; code using the EGA's write mode 1.
                     76: ;
                     77: ; If the rasterop is P, Pn, DDx (0), DDxn (1), and the brush is solid
                     78: ; or grey (for P and Pn), and the destination device is the screen,
                     79: ; then the operation can be performed by the static code using the EGA's
                     80: ; write mode 2 (write mode 0 for greys).
                     81: ;
                     82: ; Entry:
                     83: ;       EDI --> pointer to target surface
                     84: ;       EBP --> frame of BitBLT local variables
                     85: ;       EGA registers in default state
                     86: ; Returns:
                     87: ;       Carry set if BLT was performed with static code.
                     88: ; Error Returns:
                     89: ;       Carry clear if BLT was not a special case.
                     90: ; Registers Destroyed:
                     91: ;       AX,BX,CX,DX,SI,DI,DS,ES,flags
                     92: ; Registers Preserved:
                     93: ;       EBP
                     94: ; Calls:
                     95: ;-----------------------------------------------------------------------;
                     96: 
                     97: cProc   check_device_special_cases
                     98: 
                     99:         xor     cx,cx                       ;This is used, what is it????!!!
                    100:         mov     dh,fr.the_flags             ;Keep the flags in DH for a while
                    101:         test    dh,F0_DEST_IS_DEV           ;Is the destination a device?
                    102:         jz      cdsc_blt_not_special_cased  ;Not device, cannot special case it
                    103:         mov     edi,fr.dest.next_scan       ;Special case code expects this
                    104:         mov     al,byte ptr fr.Rop[0]       ;Get the raster op
                    105:         cmp     al,ROP_S                    ;Is it src copy?
                    106:         je      cdsc_its_src_copy     ;  Yes, go check it out
                    107:         cmp     al,ROP_P
                    108:         je      short cdsc_its_patblt
                    109: 
                    110: cdsc_not_s_or_p:
                    111:         xor     bl,bl                       ;Color for 0 fill
                    112:         cmp     al,ROP_DDx
                    113:         je      short cdsc_its_1_or_0
                    114:         cmp     al,ROP_Pn
                    115:         je      short cdsc_its_inverse_patblt
                    116:         cmp     al,ROP_Dn
                    117:         je      short cdsc_its_dn
                    118:         cmp     al,ROP_DPx
                    119:         je      short cdsc_its_dpx
                    120:         cmp     al,ROP_DDxn
                    121:         jne     cdsc_blt_not_special_cased
                    122:         mov     bl,0FFh                     ;Color for 1 fill
                    123: 
                    124: ; It's "1" (DDxn) or "0" (DDx)
                    125: cdsc_its_1_or_0:
                    126:         mov     fr.brush_accel,SOLID_BRUSH  ;(no brush given for DDx or DDxn)
                    127:         call    ega_solid_pat
                    128:         jmp     cdsc_exit
                    129: 
                    130: cdsc_its_patblt:
                    131:         mov     bl,fr.brush_accel       ;Ccolor in lower bits, flags in upper
                    132:         test    bl,SOLID_BRUSH
                    133:         jnz     short cdsc_its_a_solid_color
                    134:         test    bl,GREY_SCALE
                    135:         jz      short cdsc_not_solid_nor_grey
                    136:         xor     bl,bl                   ;It's grey.  !!! what is this flag
                    137:         call    ega_solid_pat
                    138:         jmp     cdsc_exit
                    139: 
                    140: cdsc_not_solid_nor_grey:
                    141:         call    do_wes_patblt
                    142:         jmp     cdsc_exit
                    143: 
                    144: cdsc_its_inverse_solid_color:
                    145:         not     bl
                    146: cdsc_its_a_solid_color:
                    147:         mov     cx,2
                    148:         call    do_solid_patcopy        ;color and accl. flags already in BL
                    149:         jmp     short cdsc_exit
                    150: 
                    151: cdsc_its_inverse_patblt:
                    152:         mov     bl,fr.brush_accel       ;color in lower bits, flags in upper
                    153:         test    bl,SOLID_BRUSH
                    154:         jnz     short cdsc_its_inverse_solid_color
                    155:         test    bl,GREY_SCALE
                    156:         jz      short cdsc_blt_not_special_cased
                    157:         mov     bl,-1                   ;It's grey.  !!! What is this flag
                    158:         call    ega_solid_pat
                    159:         jmp     short cdsc_exit
                    160: 
                    161: cdsc_its_dn:
                    162:         call    do_wes_invert
                    163:         jmp     short cdsc_exit
                    164: 
                    165: cdsc_its_dpx:
                    166:         mov     ah,fr.brush_accel       ;color in lower bits, flags in upper
                    167:         test    ah,SOLID_BRUSH
                    168:         jnz     cdsc_its_solid_dpx      ;dpx with solid brush
                    169:         test    ah,GREY_SCALE           ;Otherwise must be a grey brush
                    170:         jz      short cdsc_blt_not_special_cased
                    171:         call    do_grey_dpx
                    172:         jmp     short cdsc_exit
                    173: 
                    174: cdsc_its_solid_dpx:
                    175:         call    do_wes_dpx_solidpat     ;solid color => can special case
                    176:         jmp     short cdsc_exit
                    177: 
                    178: 
                    179: ;-----------------------------------------------------------------------;
                    180: ; This is a source copy.  The phase must be zero to special case the
                    181: ; source copy, and both devices must be the screen.
                    182: ;
                    183: ;       errnz      F0_SRC_IS_DEV - 00001000b
                    184: ;       errnz    F0_SRC_IS_COLOR - 00000100b
                    185: ;
                    186: ; its_src_copy:
                    187: ;       and     dh,F0_SRC_IS_DEV + F0_SRC_IS_COLOR
                    188: ;       shiftr  dh,2
                    189: ;       cmp     fr.phase_h,1            ; Gives CF if horizontal phase = zero
                    190: ;       rcl     dh,1
                    191: ; Now we have the needed flags in the lower 3 bits of DH
                    192: ;                                       ; Src=EGA  Src=Color  Phase0
                    193: ;
                    194: ;       dw      do_wes_mono_trick       ;    0        0         0
                    195: ;       dw      blt_not_a_special_case  ;    0        0         1
                    196: ;       dw      blt_not_a_special_case  ;    0        1         0
                    197: ;       dw      blt_not_a_special_case  ;    0        1         1
                    198: ;       dw      do_wes_mono_trick       ;    1        0         0
                    199: ;       dw      blt_not_a_special_case  ;    1        0         1
                    200: ;       dw      blt_not_a_special_case  ;    1        1         0
                    201: ;       dw      ega_src_copy            ;    1        1         1
                    202: ;-----------------------------------------------------------------------;
                    203: 
                    204: cdsc_its_src_copy:
                    205:         test    dh,F0_SRC_IS_DEV
                    206:         jnz     short cdsc_exit
                    207: 
                    208: cdsc_source_is_memory:
                    209:         test    dh,F0_SRC_IS_COLOR          ;mono-mem to color-EGA conversion?
                    210:         jnz     cdsc_blt_not_special_cased  ;color to color, cannot special case it
                    211:         call    do_wes_mono_trick
                    212:         jmp     short cdsc_exit
                    213: 
                    214: cdsc_blt_not_special_cased:
                    215:         clc
                    216:         cRet    check_device_special_cases
                    217: 
                    218: cdsc_exit:
                    219:         stc
                    220:         cRet    check_device_special_cases
                    221: 
                    222: 
                    223: ;----------------------------Private-Routine----------------------------;
                    224: ; calc_parms
                    225: ;
                    226: ; Calculate the parameters needed for the output functions contained
                    227: ; in this file.
                    228: ;
                    229: ; To avoid conditional jumps we will use some sick optimizations.
                    230: ; Remember this:
                    231: ;       adc     ax,-1           ; DEC AX if carry clear
                    232: ;       sbb     ax,0            ; DEC AX if carry set
                    233: ;       sbb     ax,-1           ; INC AX if carry clear
                    234: ;       adc     ax,0            ; INC AX if carry set
                    235: ;
                    236: ; Entry:
                    237: ;       EBP --> BitBLT local frame
                    238: ; Returns:
                    239: ;       ESI set to upper left of bitmap or pattern
                    240: ;       EDI set to upper left
                    241: ;       EDX = src bitmap width  (if present)
                    242: ;       ECX = fr.yExt
                    243: ;       EBX = offset into pattern (if pat present)
                    244: ;       sets dest_right_edge
                    245: ;       sets start_mask[0]
                    246: ;       sets last_mask[0]
                    247: ;       sets inner_loop_count
                    248: ; Registers Destroyed:
                    249: ;       EAX,flags
                    250: ; Registers Preserved:
                    251: ;       EBP
                    252: ; Alters:
                    253: ;
                    254: ; Calls:
                    255: ;       None
                    256: ;-----------------------------------------------------------------------;
                    257: 
                    258:         .errnz  SIZE_PATTERN - 8                ; any power of 2 will work
                    259: 
                    260:         align   4
                    261: calc_parms:
                    262: 
                    263: ; Left edge.
                    264: 
                    265:         movzx   edi,fr.DestxOrg         ;X origin in pixels, must be positive
                    266:         mov     ebx,edi
                    267:         mov     cl,7
                    268:         and     ecx,edi                 ;Save lower 3 bits
                    269:         mov     fr.phase_h,cl
                    270:         shr     edi,3                   ;EDI set for left edge
                    271:         mov     al,0FFh
                    272:         shr     al,cl
                    273:         mov     byte ptr fr.start_mask[0],al
                    274: 
                    275: ; Right edge.
                    276: 
                    277:         movzx   eax,fr.xExt
                    278:         add     ebx,eax                 ;Right edge in pixels
                    279:         mov     cl,7
                    280:         and     cl,bl                   ;save lower 3 bits
                    281:         shr     ebx,3                   ;convert to bytes
                    282:         mov     fr.start_fl,ebx         ;dest_right_edge (reuse stk variable)
                    283:         mov     al,0FFh
                    284:         shr     al,cl
                    285:         not     al
                    286: 
                    287: ; Check if the BLT does not cross any byte boundaries.
                    288: 
                    289:         sub     ebx,edi                 ;make EBX # bytes including left edge
                    290:         jnz     crosses_byte_boundary
                    291:         and     byte ptr fr.start_mask[0],al
                    292:         xor     al,al
                    293: 
                    294: ; There are 2 cases where we get zero for fr.inner_loop_count:
                    295: ; When the start and end bytes are adjacent and when they are
                    296: ; the same byte.  In the latter case we get -1 for
                    297: ; fr.inner_loop_count so INC BX now so it will be zero.
                    298: 
                    299:         inc     ebx
                    300: crosses_byte_boundary:
                    301: 
                    302:         cmp     al,0FFh
                    303:         sbb     al,-1                   ;AL=FF -> AL=0 (put in innerloop)
                    304:         mov     byte ptr fr.last_mask[0],al
                    305: 
                    306: ; Inner loop  --  combine edge bytes into inner loop if they are
                    307: ; full bytes.
                    308: 
                    309:         mov     fr.end_fl,ebx           ;src_right_edge (reuse stk variable)
                    310:         mov     al,byte ptr fr.start_mask[0]
                    311:         cmp     al,0FFh
                    312: 
                    313: ; If gl_start_mask = FF the carry is clear, otherwise carry is set.
                    314: ; We want to DEC BX if carry set because we have already included
                    315: ; the left edge byte in BX, but we shouldn't have included it if
                    316: ; it's only a partial byte.
                    317: 
                    318:         sbb     ebx,0
                    319:         cmp     al,0FFh
                    320: 
                    321: ; If gl_start_mask = FF the carry is clear, otherwise carry is set.
                    322: ; We want to INC AL (zero it) if it is FF (carry clear) because we
                    323: ; will do this edge as part of the innerloop.
                    324: 
                    325:         sbb     al,-1
                    326:         mov     byte ptr fr.start_mask[0],al
                    327:         mov     fr.inner_loop_count,ebx
                    328:         movzx   eax,fr.DestyOrg
                    329:         imul    eax,ulNextScan_global
                    330:         add     edi,eax
                    331:         mov     esi,fr.pdsurfDst
                    332:         add     edi,[esi].dsurf_pvBitmapStart
                    333: 
                    334: ; The source.
                    335: 
                    336:         test    fr.the_flags,F0_SRC_PRESENT
                    337:         jz      no_source
                    338:         mov     esi,fr.pdsurfSrc
                    339:         mov     ecx,[esi].dsurf_lNextScan   ;!!! will this be correct ??
                    340:         mov     esi,[esi].dsurf_pvBitmapStart
                    341: 
                    342: ; Left edge.
                    343: 
                    344:         movzx   ebx,fr.SrcxOrg
                    345:         mov     dl,7
                    346:         and     dl,bl                   ;get lower 3 bits ( Src Mod 8 )
                    347:         sub     fr.phase_h,dl           ;phase def'd as Mod8[gl_dest]-
                    348:         shr     ebx,3                   ;               Mod8[gl_src]
                    349:         add     esi,ebx                 ;ESI set for left edge
                    350:         movzx   eax,fr.SrcyOrg
                    351:         mul     ecx
                    352:         add     esi,eax
                    353:         add     fr.end_fl,esi           ;src_right_edge (reuse stack variable)
                    354:         mov     edx,ecx
                    355:         jmp     short   no_pattern
                    356: no_source:
                    357:         test    fr.the_flags,F0_PAT_PRESENT ; assuming P or S but not both
                    358:         jz      no_pattern
                    359:         mov     esi,fr.lpPBrush
                    360:         movzx   ebx,fr.DestyOrg
                    361:         and     ebx,SIZE_PATTERN - 1
                    362: no_pattern:
                    363:         movzx   ecx,fr.yExt
                    364:         PLAIN_RET
                    365: 
                    366: 
                    367: ;----------------------------Private-Routine----------------------------;
                    368: ; ega_solid_pat
                    369: ;
                    370: ; EGA special case for solid color pattern copy.
                    371: ;
                    372: ; The following routine is invoked instead of generating code for a
                    373: ; pattern copy.  The actual time involved in executing the pattern
                    374: ; copy as static code as compared to compiled code is a win.
                    375: ;
                    376: ; This code can only be used if the pattern is a solid color or a grey,
                    377: ; and the operation is to the screen.  In this case, the three bits of
                    378: ; color stored in the accelerator byte of the brush will be used, or the
                    379: ; bits of the grey brush.
                    380: ;
                    381: ; The logic operations which will invoke this routine are:
                    382: ;
                    383: ;       P
                    384: ;       Pn
                    385: ;       DDx
                    386: ;       DDxn
                    387: ;
                    388: ; Entry:
                    389: ;       BL = color to write or xor value for a grey pattern
                    390: ;       CX = Mode register value (sort of)
                    391: ;       EBP = BitBLT local variable frame
                    392: ; Returns:
                    393: ;       Nothing
                    394: ; Registers Destroyed:
                    395: ;       ALL except EBP
                    396: ; Registers Preserved:
                    397: ;       EBP
                    398: ; Calls:
                    399: ;       None
                    400: ;-----------------------------------------------------------------------;
                    401: 
                    402:         align   4
                    403: ega_solid_pat:
                    404: 
                    405: ; Instead of pushing and popping the destination pointer and adding in
                    406: ; the fr.dest.Incr, the bias needed for adjusting the pointer at the
                    407: ; end of a scan line will be computed and used.
                    408: ;
                    409: ; Since this is a pattern copy, the fr.dest.Incr will be positive.
                    410: 
                    411: ;       mov     esi,edi                 ;Get destination increment
                    412: ;       sub     esi,1                   ;Adjust for first byte
                    413:         lea     esi,-1[edi]
                    414:         sub     esi,fr.inner_loop_count ;Compute number of bytes to copy
                    415: 
                    416: ; Put color in Set/Reset if it is a solid color.
                    417: 
                    418:         mov     dx,EGA_BASE + GRAF_ADDR
                    419:         or      cx,cx
                    420:         jz      not_solid_color
                    421:         mov     ax,MM_ALL * 256 + GRAF_ENAB_SR
                    422:         out     dx,ax
                    423:         mov     ah,bl
                    424:         mov     al,GRAF_SET_RESET
                    425:         out     dx,ax
                    426: not_solid_color:
                    427:         mov     al,GRAF_BIT_MASK        ;Leave graphics controller pointing
                    428:         out     dx,al                   ;  to the bitmask register, which
                    429:         inc     dx                      ;  is where cursor leaves it too
                    430: 
                    431: ; Set up for the loop.
                    432: 
                    433:         mov     edi,fr.dest.lp_bits     ;--> destination
                    434:         mov     fr.phase_h,bl           ;Save color to write or grey XOR mask
                    435: 
                    436: ega_solid_pat_20:
                    437:         mov     al,fr.phase_h               ;Get the color to write
                    438:         test    fr.brush_accel,SOLID_BRUSH  ;Grey scale brush?
                    439:         jnz     ega_solid_pat_30            ;  No, a solid color
                    440:         mov     bl,fr.pat_row               ;Get scan of brush
                    441:         inc     bl                          ;  and update brush pointer
                    442:         mov     fr.pat_row,bl
                    443:         dec     bl
                    444:         and     ebx,00000111b
                    445:         add     ebx,fr.lpPBrush
                    446:         xor     al,bptr [ebx]               ;Invert if needed
                    447: 
                    448: ega_solid_pat_30:
                    449:         mov     bl,al
                    450:         mov     al,bptr fr.start_mask[1]    ;Set bitmask for first byte
                    451:         out     dx,al
                    452:         mov     al,bl
                    453:         xchg    al,[edi]                    ;xchg to load EGA's latches first
                    454:         inc     edi                         ;PAT_COPY step +X always!
                    455: 
                    456:         mov     ecx,fr.inner_loop_count     ;Set count for innerloop
                    457:         jecxz   ega_solid_pat_40            ;No innerloop or last byte
                    458:         mov     al,0FFh                     ;Inner loop alters all bits
                    459:         out     dx,al
                    460:         mov     al,bl
                    461:         rep     stosb
                    462: 
                    463: ega_solid_pat_40:
                    464:         mov     al,bptr fr.last_mask[1]     ;Last byte?
                    465:         or      al,al
                    466:         jz      ega_solid_pat_50            ;No last byte
                    467:         out     dx,al
                    468:         xchg    bl,[edi]
                    469: 
                    470: ega_solid_pat_50:
                    471:         add     edi,esi                     ;--> next destination
                    472:         dec     fr.yExt                     ;Any more scans to process?
                    473:         jnz     ega_solid_pat_20            ;  Yes
                    474:         PLAIN_RET
                    475: 
                    476: 
                    477: ;----------------------------Private-Routine----------------------------;
                    478: ; do_wes_invert
                    479: ; do_wes_dpx_solidpat
                    480: ;
                    481: ; Entry:
                    482: ;       EBP --> BitBLT local variable frame
                    483: ;       AH = color of solid-pat.
                    484: ; Returns:
                    485: ;       Nothing
                    486: ; Registers Destroyed:
                    487: ;       ALL but EBP
                    488: ; Registers Preserved:
                    489: ;       EBP
                    490: ; Calls:
                    491: ;       calc_parms
                    492: ;       edge_invert
                    493: ;       invert
                    494: ;-----------------------------------------------------------------------;
                    495: 
                    496:         align   4
                    497: do_wes_invert:
                    498: 
                    499:         mov     ah,0Fh                  ; black
                    500: 
                    501: do_wes_dpx_solidpat     label near
                    502: 
                    503: ; Setup SET_RESET.
                    504: 
                    505:         mov     dx,EGA_BASE + GRAF_ADDR
                    506:         mov     al,GRAF_SET_RESET
                    507:         out     dx,ax
                    508:         mov     ax,0F00h + GRAF_ENAB_SR ; enable all planes
                    509:         out     dx,ax
                    510: 
                    511: ; Go to XOR mode.
                    512: 
                    513:         mov     ax,GRAF_DATA_ROT + 256 * DR_XOR
                    514:         out     dx,ax
                    515: 
                    516:         call    calc_parms
                    517:         mov     ah,byte ptr fr.start_mask[0]
                    518:         or      ah,ah
                    519:         jz      no_left_invert_edge
                    520:         push    edi
                    521:         call    edge_invert
                    522:         pop     edi
                    523:         inc     edi
                    524: 
                    525: no_left_invert_edge:
                    526:         mov     ebx,fr.inner_loop_count
                    527:         or      ebx,ebx
                    528:         jz      no_inner_invert_loop
                    529:         movzx   ecx,fr.yExt
                    530:         push    edi
                    531:         call    invert
                    532:         pop     edi
                    533:         add     edi,fr.inner_loop_count
                    534: 
                    535: no_inner_invert_loop:
                    536:         mov     ah,byte ptr fr.last_mask[0]
                    537:         or      ah,ah
                    538:         jz      no_last_invert_edge
                    539:         movzx   ecx,fr.yExt
                    540:         call    edge_invert
                    541: 
                    542: no_last_invert_edge:
                    543:         PLAIN_RET
                    544: 
                    545: 
                    546: ;----------------------------Private-Routine----------------------------;
                    547: ;do_solid_patcopy() is called to copy (PatCopy) a solid brush directly to
                    548: ;the screen.
                    549: ;
                    550: ;Entry:
                    551: ;   BL      color to write with
                    552: ;   EDI     fr.dest.next_scan which is equal to width_b
                    553: ;   EBP     local varible frame
                    554: ;
                    555: ;-----------------------------------------------------------------------;
                    556: 
                    557:         align   4
                    558: do_solid_patcopy:
                    559: 
                    560:         cmp     fr.inner_loop_count,0   ;if zero, let ega_solid_pat do the work
                    561:         jne     dsp_do_it
                    562:         call    ega_solid_pat
                    563:         PLAIN_RET
                    564: 
                    565: dsp_do_it:
                    566:         sub     eax,eax                 ;accumulate flags in AL
                    567:         mov     esi,edi                 ;SI: fr.dest.next_scan (must be > 0)
                    568:         mov     edi,fr.dest.lp_bits     ;EDI-->first byte to write to
                    569:         mov     bh,bptr fr.start_mask[1]
                    570:         cmp     ah,bh                   ;is there a left edge?
                    571:         rcl     al,1                    ;CY if there is an edge to draw
                    572:         sub     bh,0ffh                 ;is the left edge an entire byte wide?
                    573:         neg     bh                      ;CY if less than a byte
                    574:         rcl     al,1                    ;accumulate flag into AL
                    575:         mov     bh,bptr fr.last_mask[1]
                    576:         cmp     ah,bh                   ;is there a right edge?
                    577:         rcl     al,1                    ;CY if there is an edge to draw
                    578:         sub     bh,0ffh                 ;is right edge an entire byte wide?
                    579:         neg     bh                      ;CY if less than a byte
                    580:         rcl     al,1                    ;accumulate flag into AL
                    581:         test    al,04h                  ;set all pixels in left byte?
                    582:         jnz     dsp_keep_left_edge      ;no. Do normal stuff
                    583:         inc     fr.inner_loop_count     ;left edge is an entire byte. INC inner
                    584:         and     al,0f7h                 ;loop cnt and draw it the fast way
                    585: 
                    586: dsp_keep_left_edge:
                    587:         test    al,01h                  ;set all pixels in right byte?
                    588:         jnz     dsp_keep_right_edge     ;no. Do normal stuff
                    589:         inc     fr.inner_loop_count     ;need to set all pixels in right byte.
                    590:         and     al,0fdh                 ;inc inner loop cnt do it the fast way
                    591: 
                    592: dsp_keep_right_edge:
                    593:         test    al,0ah                  ;any edges to draw?
                    594:         jz      dsp_draw_core_piece     ;no, just do the main chunk
                    595: 
                    596: dsp_draw_edges:
                    597:         mov     bh,al                   ;save flags in BH
                    598:         mov     dx,EGA_BASE + GRAF_ADDR
                    599:         mov     ax,MM_ALL * 256 + GRAF_ENAB_SR
                    600:         out     dx,ax                   ;enable writing to all planes at once
                    601:         mov     ah,bl
                    602:         mov     al,GRAF_SET_RESET
                    603:         out     dx,ax                   ;program to color value to write
                    604:         mov     al,GRAF_BIT_MASK        ;Leave graphics controller pointing
                    605:         out     dx,al                   ;  to the bitmask register, which
                    606:         inc     dx                      ;  is where cursor leaves it too
                    607: 
                    608:         test    bh,08h                  ;need to draw the left edge?
                    609:         jz      dsp_draw_right_edge
                    610: 
                    611:         push    edi                     ;save destination offset
                    612:         mov     al,bptr fr.start_mask[1]
                    613:         out     dx,al                   ;get it to the board
                    614:         movzx   ecx,fr.yExt
                    615: 
                    616: dsp_left_edge_draw_loop:
                    617:         mov     al,bl                   ;copy color index into AL
                    618:         xchg    al,[edi]                ;load latches, copy color index
                    619:         add     edi,esi
                    620:         loop    dsp_left_edge_draw_loop
                    621:         pop     edi                     ;restore dest offset
                    622:         inc     edi                     ;update to new draw position
                    623: 
                    624: 
                    625: dsp_draw_right_edge:
                    626:         test    bh,02h                  ;is there a right edge to draw?
                    627:         jz      dsp_reset_registers     ;no.  Restore default settings
                    628:         push    edi                     ;save updated dest offset
                    629:         add     edi,fr.inner_loop_count ;go to the right hand edge
                    630:         mov     al,bptr fr.last_mask[1]
                    631:         out     dx,al                   ;get it to the board
                    632:         movzx   ecx,fr.yExt
                    633: 
                    634: dsp_right_edge_draw_loop:
                    635:         mov     al,bl                   ;copy color index into AL
                    636:         xchg    al,[edi]                ;load latches, copy color index
                    637:         add     edi,esi
                    638:         loop    dsp_right_edge_draw_loop
                    639:         pop     edi                     ;restore dest offset
                    640: 
                    641: 
                    642: dsp_reset_registers:
                    643:         mov     al,0ffh                 ;allow writing to all bits in the byte
                    644:         out     dx,al                   ;this is the default value
                    645: 
                    646: dsp_draw_core_piece:
                    647:         sub     esi,fr.inner_loop_count ;account for EDI being incr. by stosb
                    648:         mov     dx,EGA_BASE+SEQ_DATA    ;time to copy pattern to board  DX=3C5h
                    649:         mov     al,01h
                    650:         mov     ecx,4
                    651: 
                    652: dsp_load_latches_loop:
                    653:         out     dx,al                   ;select the next plane to write to
                    654:         shr     bl,1                    ;move plane bit into carry
                    655:         sbb     ah,ah                   ;expand into AH
                    656:         mov     [edi],ah                ;copy it to the bit plane
                    657:         shl     al,1                    ;update plane selector
                    658:         loop    dsp_load_latches_loop   ;do all 4 planes
                    659: 
                    660:         mov     al,MM_ALL               ;to enable all four planes
                    661:         out     dx,al                   ;enable all planes
                    662:         mov     dx,EGA_BASE+GRAF_ADDR   ;DX=3CEh
                    663:         mov     ax,GRAF_BIT_MASK        ;AH=0 ie., copy data from latches, AL=8
                    664:         out     dx,ax                   ;ignore CPU data on write to board
                    665: 
                    666:         mov     al,[edi]                ;load the latches
                    667:         movzx   eax,fr.yExt             ;initialize loop counter
                    668:         mov     ebx,fr.inner_loop_count ;initialize rep counter value
                    669: 
                    670:         align   4
                    671: dsp_pat_blt_loop:
                    672:         mov     ecx,ebx                 ;ECX: repeat count
                    673:         test    edi,1
                    674:         jz      short dsp_pat_blt_aligned2
                    675:         stosb
                    676:         dec     ecx
                    677: dsp_pat_blt_aligned2:
                    678:         shr     ecx,1
                    679:         rep     stosw
                    680:         adc     ecx,ecx
                    681:         rep     stosb
                    682:         add     edi,esi                 ;point to next scanline
                    683:         dec     eax
                    684:         jnz     dsp_pat_blt_loop
                    685: 
                    686:         PLAIN_RET
                    687: 
                    688: 
                    689: ;----------------------------Private-Routine----------------------------;
                    690: ; do_wes_patblt
                    691: ;
                    692: ; Entry:
                    693: ;       EBP --> BitBLT local variable frame
                    694: ; Returns:
                    695: ;       Nothing
                    696: ; Registers Destroyed:
                    697: ;       All but EBP
                    698: ; Registers Preserved:
                    699: ;       EBP
                    700: ; Calls:
                    701: ;       calc_parms
                    702: ;       edge_pat_blt
                    703: ;       pat_blt
                    704: ;-----------------------------------------------------------------------;
                    705: 
                    706:         align   4
                    707: do_wes_patblt:
                    708: 
                    709:         call    calc_parms
                    710:         mov     ah,byte ptr fr.start_mask[0]
                    711:         or      ah,ah
                    712:         jz      no_left_pat_edge
                    713:         push    esi
                    714:         push    ebx
                    715:         call    edge_pat_blt            ; preserves DI
                    716:         pop     ebx
                    717:         pop     esi
                    718:         inc     edi
                    719: 
                    720: no_left_pat_edge:
                    721:         mov     edx,fr.inner_loop_count
                    722:         or      edx,edx
                    723:         jz      no_inner_pat_loop
                    724:         movzx   ecx,fr.yExt
                    725:         push    edi
                    726:         push    esi
                    727:         push    ebx
                    728:         call    pat_blt
                    729:         pop     ebx
                    730:         pop     esi
                    731:         pop     edi
                    732:         add     edi,fr.inner_loop_count
                    733: 
                    734: no_inner_pat_loop:
                    735:         mov     ah,byte ptr fr.last_mask[0]
                    736:         or      ah,ah
                    737:         jz      no_last_pat_edge
                    738:         movzx   ecx,fr.yExt
                    739:         call    edge_pat_blt
                    740: 
                    741: no_last_pat_edge:
                    742:         PLAIN_RET
                    743: 
                    744: 
                    745: ;----------------------------Private-Routine----------------------------;
                    746: ; do_wes_mono_trick
                    747: ;
                    748: ; Entry:
                    749: ;       EBP --> BitBLT local variable frame
                    750: ; Returns:
                    751: ;       Nothing
                    752: ; Registers Preserved:
                    753: ;       EBP
                    754: ; Registers Destroyed:
                    755: ;       All but EBP
                    756: ; Calls:
                    757: ;       calc_parms
                    758: ;       left_edge_mono_to_color_blt
                    759: ;       right_edge_mono_to_color_blt
                    760: ;       mono_to_color_blt
                    761: ;-----------------------------------------------------------------------;
                    762: 
                    763:         align   4
                    764: do_wes_mono_trick:
                    765: 
                    766:         call    calc_parms
                    767:         push    edx
                    768:         mov     ah,byte ptr fr.start_mask[0]
                    769:         or      ah,ah
                    770:         jz      no_left_edge
                    771:         push    edi
                    772:         push    esi
                    773:         push    edx
                    774:         mov     al,fr.phase_h
                    775:         mov     bx,fr.both_colors
                    776: ;-      mov     ecx,fr.yExt
                    777:         call    left_edge_mono_to_color_blt
                    778:         pop     edx
                    779:         pop     esi
                    780:         pop     edi
                    781:         inc     esi
                    782:         inc     edi
                    783: no_left_edge:
                    784:         mov     ebx,edx
                    785:         mov     edx,fr.inner_loop_count
                    786:         mov     ecx,edi                   ; compute/save the right-hand edge
                    787:         add     ecx,edx
                    788:         push    ecx
                    789:         or      edx,edx
                    790:         jz      no_inner_loop
                    791:         sub     ebx,edx
                    792:         movzx   ecx,fr.yExt
                    793:         mov     al,fr.phase_h
                    794:         cbw
                    795:         push    ebp
                    796:         mov     bp,fr.both_colors
                    797:         xchg    bp,ax
                    798:         call    mono_to_color_blt
                    799:         pop     ebp
                    800: 
                    801: no_inner_loop:
                    802:         pop     edi
                    803:         pop     edx
                    804:         mov     ah,byte ptr fr.last_mask[0]
                    805:         or      ah,ah
                    806:         jz      no_last_edge
                    807: 
                    808:         mov     ecx,fr.inner_loop_count
                    809:         mov     esi,fr.end_fl           ; src_right_edge (reuse stk variable)
                    810:         movzx   ecx,fr.yExt
                    811:         mov     bx,fr.both_colors
                    812:         mov     al,fr.phase_h
                    813:         call    right_edge_mono_to_color_blt
                    814: 
                    815: no_last_edge:
                    816:         PLAIN_RET
                    817: 
                    818: 
                    819: ;----------------------------Private-Routine----------------------------;
                    820: ; mono_to_color_blt
                    821: ;
                    822: ; This does phase-0, byte-aligned, mem-mono to ega-color blt.
                    823: ;
                    824: ; The Problem: copy to the ega a bitmap where "0"s in the bitmap mean
                    825: ; color1 and "1"s in the bitmap mean color2, where color1 and color2
                    826: ; are arbitrary colors.
                    827: ;
                    828: ; The solution:
                    829: ;
                    830: ;                       plane0  plane1  plane2  plane3
                    831: ;
                    832: ; color1                1       1       0       0
                    833: ; color2                1       0       1       0
                    834: ; SetResetEnable        1       0       0       1
                    835: ; SetReset              0       x       x       0
                    836: ; latches               1       1       0       0       (=color1)
                    837: ;
                    838: ; Now with datarot = XOR we get
                    839: ;
                    840: ;  when databit=0       1       1       0       0       (=color1)
                    841: ;  when databit=1       1       0       1       0       (=color2)
                    842: ;
                    843: ;
                    844: ; Entry:
                    845: ;       BP  = phase ( -7 to 7)   (high byte ignored)
                    846: ;       AL  = background color ( "1" bits in mono-bitmap )
                    847: ;       AH  = foreground color
                    848: ;       EBX = SI wrap
                    849: ;       ESI = Mono Bitmap first byte
                    850: ;       EDI = First EGA Byte
                    851: ;       ECX = Number of scan lines
                    852: ;       EDX = bytes per scan line
                    853: ;       GRAF_DATA_ROT = DR_SET
                    854: ;       All Planes Enabled
                    855: ; Returns:
                    856: ;       Nothing
                    857: ; Registers Destroyed:
                    858: ;       ALL
                    859: ; Registers Preserved:
                    860: ;       None
                    861: ; Alters:
                    862: ;       GRAF_SET_RESET
                    863: ;       GRAF_ENAB_SR
                    864: ;       GRAF_BIT_MASK
                    865: ; Calls:
                    866: ;       None
                    867: ;-----------------------------------------------------------------------;
                    868: 
                    869:         align   4
                    870: mono_to_color_blt:
                    871: 
                    872:         push    ebp                     ; phase
                    873:         push    edx                     ; bytes per scan line
                    874:         push    ebx                     ; wrap for SI
                    875:         mov     ebx,eax                 ; colors
                    876: 
                    877: ; First we put the foreground color into the latches.  We do this
                    878: ; by putting this color into SET_RESET, writing it, then reading it.
                    879: ; The memory location we will use is the first byte where we will blt.
                    880: 
                    881:         mov     dx,EGA_BASE + GRAF_ADDR
                    882:         mov     al,GRAF_SET_RESET
                    883:         out     dx,ax
                    884:         mov     ax,0F00h + GRAF_ENAB_SR
                    885:         out     dx,ax
                    886: 
                    887: ; Set bit mask = FF.
                    888:         mov     ax,0FF00h + GRAF_BIT_MASK
                    889:         out     dx,ax
                    890: 
                    891: ; Fill the latches.
                    892:         mov     [edi],al                ; color in SetReset is written, not AL
                    893:         mov     al,[edi]                ; read to fill latches
                    894: 
                    895: ; Go to XOR mode.
                    896:         mov     ax,GRAF_DATA_ROT + 256 * DR_XOR
                    897:         out     dx,ax
                    898: 
                    899: ; Now setup SET_RESET.
                    900: 
                    901:         mov     eax,ebx                 ; restore colors
                    902:         xor     ah,al                   ; gives 0 where colors match
                    903:         mov     al,GRAF_SET_RESET
                    904:         out     dx,ax
                    905:         not     ah
                    906:         mov     al,GRAF_ENAB_SR
                    907:         out     dx,ax                   ; enable Set/Reset where colors match
                    908: 
                    909:         pop     ebp                     ; wrap for ESI
                    910:         pop     edx                     ; bytes per scan
                    911:         mov     ebx,ulNextScan_global
                    912:         sub     ebx,edx                 ; BX = wrap
                    913: 
                    914:         mov     eax,ecx                 ; loop count
                    915:         pop     ecx                     ; phase
                    916:         or      cl,cl
                    917:         js      phase_neg
                    918:         jz      phase_zero
                    919:         dec     esi
                    920: ;*      dec     ebp
                    921: pmono_to_color_loop:
                    922:         push    eax
                    923:         push    edx
                    924: pnext_byte:
                    925:         lodsw
                    926:         dec     esi
                    927:         xchg    al,ah
                    928:         shr     ax,cl
                    929: ;+      shl     ax,cl
                    930:         stosb
                    931:         dec     edx
                    932:         jnz     pnext_byte
                    933:         pop     edx
                    934:         pop     eax
                    935:         add     edi,ebx
                    936:         add     esi,ebp
                    937:         dec     eax
                    938:         jnz     pmono_to_color_loop
                    939:         jmp     leave_in_set_mode
                    940: 
                    941: phase_zero:
                    942: zmono_to_color_loop:
                    943:         mov     ecx,edx
                    944:         shr     ecx,1
                    945:         rep     movsw
                    946:         rcl     ecx,1
                    947:         rep     movsb
                    948:         add     edi,ebx
                    949:         add     esi,ebp
                    950:         dec     eax
                    951:         jnz     zmono_to_color_loop
                    952:         jmp     leave_in_set_mode
                    953: 
                    954: phase_neg:
                    955:         neg     cl                      ; make CX = abs phase
                    956: nmono_to_color_loop:
                    957:         push    eax
                    958:         push    edx
                    959: nnext_byte:
                    960:         lodsw
                    961:         dec     esi
                    962:         rol     ax,cl
                    963: ;+      shr     ax,cl
                    964:         stosb
                    965:         dec     edx
                    966:         jnz     nnext_byte
                    967:         pop     edx
                    968:         pop     eax
                    969:         add     edi,ebx
                    970:         add     esi,ebp
                    971:         dec     eax
                    972:         jnz     nmono_to_color_loop
                    973: 
                    974: leave_in_set_mode:
                    975:         mov     dx,EGA_BASE + GRAF_ADDR
                    976:         mov     ax,GRAF_DATA_ROT + 256 * DR_SET
                    977:         out     dx,ax
                    978:         PLAIN_RET
                    979: 
                    980: 
                    981: ;----------------------------Private-Routine----------------------------;
                    982: ; left_edge_mono_to_color_blt
                    983: ; right_edge_mono_to_color_blt
                    984: ;
                    985: ; This problem here is the same as in mono_to_color_blt, except it
                    986: ; is complicated by the need to preserve what is already in EGA memory
                    987: ; for part of the byte which we are writing.
                    988: ;
                    989: ; We will set the BIT MASK to preserve these bytes.  We will then read
                    990: ; the data from memory, and write it to the EGA using an XCHG so the
                    991: ; latches are filled before the write -- so the appropriate EGA bits
                    992: ; are preserved.
                    993: ;
                    994: ; The method for writing the data involves two passes.  The first pass
                    995: ; writes the data to some of the planes, the second pass writes NOT the
                    996: ; data to the other planes.  Depending on the two colors involved we
                    997: ; may be able to skip one of the two passes.
                    998: ;
                    999: ; Define BkColor = the color corresponding to "1" bits in the data.
                   1000: ; Define TextColor = the color corresponding to "0" bits in the data.
                   1001: ;
                   1002: ; We will use the Set/Reset register to take care of the planes where
                   1003: ; the colors match.  These planes will be ignored in the rest of this
                   1004: ; comment block.
                   1005: ;
                   1006: ; The first pass writes "1"s where the data is "1".  Therefore, the
                   1007: ; condition for doing the first pass is that the BkColor has a "1"
                   1008: ; somewhere (ignoring those planes taken care of by Set/Reset).
                   1009: ; The second pass does whatever planes remain.  We can skip this pass
                   1010: ; if no planes remain.  To maximize to likelihood of this we make sure
                   1011: ; that all "Set/Reset" planes are enabled on the first pass (if the
                   1012: ; first pass occurs).
                   1013: ;
                   1014: ; Entry:
                   1015: ;       AH  = bitmask
                   1016: ;       AL  = phase (-7 to +7)
                   1017: ;       BH  = foreground color
                   1018: ;       BL  = background color
                   1019: ;       EDX = src bitmap width in bytes
                   1020: ;       ESI = Mono Bitmap first byte
                   1021: ;       EDI = First EGA Byte
                   1022: ;       ECX = Number of scan lines
                   1023: ;       DATA_ROT = DR_SET
                   1024: ; Returns:
                   1025: ;       Nothing
                   1026: ; Registers Destroyed:
                   1027: ;       ALL but EBP
                   1028: ; Registers Preserved:
                   1029: ;       EBP
                   1030: ; Alters:
                   1031: ;       GRAF_SET_RESET
                   1032: ;       GRAF_BIT_MASK
                   1033: ;       GRAF_ENAB_SR
                   1034: ; Calls:
                   1035: ;       None
                   1036: ;-----------------------------------------------------------------------;
                   1037: 
                   1038: ; Does left edge, which never requires more than 1 byte, and can fault with
                   1039: ; the 2-byte approach used by the right edge.
                   1040: 
                   1041:         align   4
                   1042: left_edge_mono_to_color_blt:
                   1043: 
                   1044:         push    ebp
                   1045:         push    eax              ; AL = phase
                   1046:         mov     ebp,edx
                   1047: 
                   1048: ; Set bit mask.
                   1049: 
                   1050:         mov     dx,EGA_BASE + GRAF_ADDR
                   1051:         mov     al,GRAF_BIT_MASK
                   1052:         out     dx,ax
                   1053: 
                   1054: ; Put foreground color in Set/Reset and enable planes where colors
                   1055: ; match.
                   1056: 
                   1057:         mov     ah,bh
                   1058:         mov     al,GRAF_SET_RESET
                   1059:         out     dx,ax
                   1060:         xor     ah,bl
                   1061:         not     ah                      ; gives 1 where colors match
                   1062:         mov     al,GRAF_ENAB_SR
                   1063:         out     dx,ax
                   1064:         mov     dx,EGA_BASE + SEQ_DATA  ; The rest of the OUTs are here.
                   1065:         mov     al,ah
                   1066:         not     ah                      ; Gives 1 where colors mismatch.
                   1067: 
                   1068: ; The following AND leaves 1 bits in AH for the planes which
                   1069: ; CANNOT be done on the second pass.  So if this is zero we can
                   1070: ; skip the first pass.
                   1071: 
                   1072:         and     ah,bl                   ; BL = BkColor = color where data is 1
                   1073:         or      ah,bl                   ; planes to enable
                   1074:         mov     ebx,ecx                 ; we're done with the colors in BX
                   1075:         pop     ecx                     ; phase
                   1076:         jz      short left_skip_first_pass
                   1077:         or      al,ah                   ; Include "Set/Reset" planes.
                   1078:         out     dx,al                   ; Enable planes for first pass.
                   1079: 
                   1080:         push    ecx
                   1081:         push    esi
                   1082:         push    edi
                   1083:         push    eax
                   1084:         push    ebx
                   1085:         or      cl,cl
                   1086:         js      short left_phase_is_negative1
                   1087: left_pfirst_pass:
                   1088:         mov     ah,[esi]
                   1089:         shr     ah,cl
                   1090:         xchg    ah,[edi]
                   1091:         add     esi,ebp
                   1092:         add     edi,ulNextScan_global
                   1093:         dec     ebx
                   1094:         jnz     left_pfirst_pass
                   1095:         jmp     short left_end_pass_one
                   1096: 
                   1097: left_phase_is_negative1:
                   1098:         neg     cl                      ; make CL = abs phase
                   1099: left_nfirst_pass:
                   1100:         mov     ax,[esi]
                   1101:         rol     ax,cl
                   1102:         xchg    al,[edi]
                   1103:         add     esi,ebp
                   1104:         add     edi,ulNextScan_global
                   1105:         dec     ebx
                   1106:         jnz     left_nfirst_pass
                   1107: left_end_pass_one:
                   1108:         pop     ebx
                   1109:         pop     eax
                   1110:         pop     edi
                   1111:         pop     esi
                   1112:         pop     ecx
                   1113: 
                   1114: left_skip_first_pass:
                   1115: 
                   1116: ; Enable the other planes.
                   1117: 
                   1118:         not     ah
                   1119:         and     ah,MM_ALL
                   1120:         jz      short left_no_planes_left
                   1121:         mov     al,ah
                   1122:         out     dx,al
                   1123:         or      cl,cl
                   1124:         js      short left_phase_is_negative2
                   1125: left_psecond_pass:
                   1126:         mov     ah,[esi]
                   1127:         not     ah
                   1128:         shr     ah,cl
                   1129:         xchg    ah,[edi]
                   1130:         add     esi,ebp
                   1131:         add     edi,ulNextScan_global
                   1132:         dec     ebx
                   1133:         jnz     left_psecond_pass
                   1134:         jmp     short left_no_planes_left
                   1135: 
                   1136: left_phase_is_negative2:
                   1137:         neg     cl                      ; make CL = abs phase
                   1138: left_nsecond_pass:
                   1139:         mov     ax,[esi]
                   1140:         not     ax
                   1141:         rol     ax,cl
                   1142:         xchg    al,[edi]
                   1143:         add     esi,ebp
                   1144:         add     edi,ulNextScan_global
                   1145:         dec     ebx
                   1146:         jnz     left_nsecond_pass
                   1147: 
                   1148: left_no_planes_left:
                   1149:         mov     al,MM_ALL
                   1150:         out     dx,al
                   1151:         pop     ebp
                   1152:         PLAIN_RET
                   1153: 
                   1154: ; Does right edge, which may require 2 bytes. 2 bytes are always available,
                   1155: ; because if there was only 1 byte across, the left edge would handle it,
                   1156: ; so we don't have to worry about faulting.
                   1157: 
                   1158:         align   4
                   1159: right_edge_mono_to_color_blt:
                   1160: 
                   1161:         push    ebp
                   1162:         push    eax              ; AL = phase
                   1163:         mov     ebp,edx
                   1164: 
                   1165: ; Set bit mask.
                   1166: 
                   1167:         mov     dx,EGA_BASE + GRAF_ADDR
                   1168:         mov     al,GRAF_BIT_MASK
                   1169:         out     dx,ax
                   1170: 
                   1171: ; Put foreground color in Set/Reset and enable planes where colors
                   1172: ; match.
                   1173: 
                   1174:         mov     ah,bh
                   1175:         mov     al,GRAF_SET_RESET
                   1176:         out     dx,ax
                   1177:         xor     ah,bl
                   1178:         not     ah                      ; gives 1 where colors match
                   1179:         mov     al,GRAF_ENAB_SR
                   1180:         out     dx,ax
                   1181:         mov     dx,EGA_BASE + SEQ_DATA  ; The rest of the OUTs are here.
                   1182:         mov     al,ah
                   1183:         not     ah                      ; Gives 1 where colors mismatch.
                   1184: 
                   1185: ; The following AND leaves 1 bits in AH for the planes which
                   1186: ; CANNOT be done on the second pass.  So if this is zero we can
                   1187: ; skip the first pass.
                   1188: 
                   1189:         and     ah,bl                   ; BL = BkColor = color where data is 1
                   1190:         or      ah,bl                   ; planes to enable
                   1191:         mov     ebx,ecx                 ; we're done with the colors in BX
                   1192:         pop     ecx                     ; phase
                   1193:         jz      short right_skip_first_pass
                   1194:         or      al,ah                   ; Include "Set/Reset" planes.
                   1195:         out     dx,al                   ; Enable planes for first pass.
                   1196: 
                   1197:         push    ecx
                   1198:         push    esi
                   1199:         push    edi
                   1200:         push    eax
                   1201:         push    ebx
                   1202:         or      cl,cl
                   1203:         js      short right_phase_is_negative1
                   1204:         dec     esi
                   1205: right_pfirst_pass:
                   1206:         mov     ax,[esi]
                   1207:         ror     ax,cl
                   1208:         xchg    ah,[edi]
                   1209:         add     esi,ebp
                   1210:         add     edi,ulNextScan_global
                   1211:         dec     ebx
                   1212:         jnz     right_pfirst_pass
                   1213:         jmp     short right_end_pass_one
                   1214: 
                   1215: right_phase_is_negative1:
                   1216:         neg     cl                      ; make CL = abs phase
                   1217: right_nfirst_pass:
                   1218:         mov     ax,[esi]
                   1219:         rol     ax,cl
                   1220:         xchg    al,[edi]
                   1221:         add     esi,ebp
                   1222:         add     edi,ulNextScan_global
                   1223:         dec     ebx
                   1224:         jnz     right_nfirst_pass
                   1225: right_end_pass_one:
                   1226:         pop     ebx
                   1227:         pop     eax
                   1228:         pop     edi
                   1229:         pop     esi
                   1230:         pop     ecx
                   1231: 
                   1232: right_skip_first_pass:
                   1233: 
                   1234: ; Enable the other planes.
                   1235: 
                   1236:         not     ah
                   1237:         and     ah,MM_ALL
                   1238:         jz      short right_no_planes_left
                   1239:         mov     al,ah
                   1240:         out     dx,al
                   1241:         or      cl,cl
                   1242:         js      short right_phase_is_negative2
                   1243:         dec     esi
                   1244: right_psecond_pass:
                   1245:         mov     ax,[esi]
                   1246:         not     ax
                   1247:         ror     ax,cl
                   1248:         xchg    ah,[edi]
                   1249:         add     esi,ebp
                   1250:         add     edi,ulNextScan_global
                   1251:         dec     ebx
                   1252:         jnz     right_psecond_pass
                   1253:         jmp     short right_no_planes_left
                   1254: 
                   1255: right_phase_is_negative2:
                   1256:         neg     cl                      ; make CL = abs phase
                   1257: right_nsecond_pass:
                   1258:         mov     ax,[esi]
                   1259:         not     ax
                   1260:         rol     ax,cl
                   1261:         xchg    al,[edi]
                   1262:         add     esi,ebp
                   1263:         add     edi,ulNextScan_global
                   1264:         dec     ebx
                   1265:         jnz     right_nsecond_pass
                   1266: 
                   1267: right_no_planes_left:
                   1268:         mov     al,MM_ALL
                   1269:         out     dx,al
                   1270:         pop     ebp
                   1271:         PLAIN_RET
                   1272: 
                   1273: 
                   1274: ;----------------------------Private-Routine----------------------------;
                   1275: ; pat_blt
                   1276: ;                       XOR mode with data = FF for Pn?
                   1277: ;
                   1278: ; This BLTs an arbitrary 8x8 bit pattern (3 or 4 planes deep) to EGA.
                   1279: ;
                   1280: ; The method is simple.  Load the latches with the pattern for a
                   1281: ; particular scan line, then REP STOS this with the BIT MASK = 0
                   1282: ; so that only the latches get written.  Before putting the pattern
                   1283: ; for the next scan line into the latches we will do all other scan
                   1284: ; lines with the same pattern.
                   1285: ;
                   1286: ; Entry:
                   1287: ;       ESI = pattern bytes
                   1288: ;       EDI = First EGA Byte
                   1289: ;       ECX = Number of scan lines (yExt)
                   1290: ;       EBX = offset into pattern
                   1291: ;       EDX = bytes per scan line (scan_len)
                   1292: ;       GRAF_DATA_ROT = DR_SET
                   1293: ;       BIT_MASK = FF
                   1294: ; Returns:
                   1295: ;       Nothing
                   1296: ; Registers Destroyed:
                   1297: ;       ALL but EBP
                   1298: ; Registers Preserved:
                   1299: ;       EBP
                   1300: ; Alters:
                   1301: ;       GRAF_BIT_MASK   (leaves it 00)
                   1302: ; Calls:
                   1303: ;       None
                   1304: ;-----------------------------------------------------------------------;
                   1305: 
                   1306:         .errnz  SIZE_PATTERN - 8        ; actually any power of 2 is okay.
                   1307: 
                   1308:         align   4
                   1309: pat_blt:
                   1310: 
                   1311:         push    ebp
                   1312:         push    edx                     ; scan_len
                   1313:         push    ecx                     ; yExt
                   1314:         mov     ah,11h                  ; left nibble gives carry to end loop
                   1315: 
                   1316: ; Set EBP = min(yExt, scans/pattern).
                   1317: 
                   1318:         sub     ecx,SIZE_PATTERN        ; SIZE_PATTERN = 8 = yExt of pattern
                   1319:         sbb     ebp,ebp
                   1320:         and     ebp,ecx
                   1321:         add     ebp,SIZE_PATTERN
                   1322: 
                   1323:         mov     dx,EGA_BASE + SEQ_DATA
                   1324: set_next_plane:
                   1325:         push    ebx
                   1326:         push    edi
                   1327: 
                   1328: ; Enable next plane.
                   1329: 
                   1330:         mov     al,MM_ALL
                   1331:         and     al,ah
                   1332:         out     dx,al
                   1333:         mov     ecx,ebp
                   1334: 
                   1335: hit_next_byte:
                   1336:         mov     al,[esi][ebx]           ; Next pattern byte
                   1337:         inc     ebx
                   1338:         and     ebx,SIZE_PATTERN - 1
                   1339:         mov     [edi],al
                   1340:         add     edi,ulNextScan_global
                   1341:         loop    hit_next_byte
                   1342:         add     esi,SIZE_PATTERN
                   1343:         pop     edi
                   1344:         pop     ebx
                   1345:         shl     ah,1
                   1346:         jnc     set_next_plane
                   1347: 
                   1348: ; Set bit mask = 00.
                   1349: 
                   1350:         mov     dx,EGA_BASE + GRAF_ADDR
                   1351:         mov     ax,0000h + GRAF_BIT_MASK
                   1352:         out     dx,ax
                   1353: 
                   1354: ; Enable all planes.
                   1355: 
                   1356:         mov     al,MM_ALL
                   1357:         mov     dx,EGA_BASE + SEQ_DATA
                   1358:         out     dx,al
                   1359: 
                   1360:         mov     ecx,ebp                 ; MIN(yExt,SIZE_PATTERN)
                   1361:         pop     ebp                     ; yExt
                   1362:         pop     eax                     ; scan_len
                   1363:         mov     esi,ulNextScan_global   ; ESI = scan_width
                   1364: 
                   1365:         .errnz  (SIZE_PATTERN - 8)
                   1366:         ;------------------------------------------------;
                   1367:         ;       mov     ebx,(SIZE_PATTERN - 1) * scan_width
                   1368:         ;------------------------------------------------;
                   1369:         lea     ebx,[esi*2+esi]         ; scan_width * 3
                   1370:         lea     ebx,[ebx+esi*4]         ; scan_width * 7
                   1371: 
                   1372:         sub     esi,eax                 ; ESI = scan_width
                   1373:         add     ebx,esi                 ; EBX = (scan_width * 7) + next_scan
                   1374: 
                   1375: pat_blt_next_scan:
                   1376:         push    ecx
                   1377:         mov     esi,edi                 ; save ESI
                   1378:         mov     edx,ebp                 ; save yExt
                   1379:         mov     cl,[edi]                ; load latches
                   1380: 
                   1381: pat_blt_loop:
                   1382:         mov     ecx,eax                 ; EAX = scan_len
                   1383:         rep     stosb
                   1384:         add     edi,ebx                 ; EBX = (scan_width * 7) + next_scan
                   1385:         sub     ebp,SIZE_PATTERN
                   1386:         jg      pat_blt_loop
                   1387: 
                   1388:         mov     ebp,edx
                   1389:         dec     ebp
                   1390:         mov     edi,esi
                   1391:         add     edi,ulNextScan_global
                   1392:         pop     ecx
                   1393:         loop    pat_blt_next_scan
                   1394: 
                   1395:         pop     ebp
                   1396:         PLAIN_RET
                   1397: 
                   1398: 
                   1399: ;----------------------------Private-Routine----------------------------;
                   1400: ; edge_pat_blt
                   1401: ;
                   1402: ; Entry:
                   1403: ;       AH  = bitmask
                   1404: ;       ESI = pattern bytes
                   1405: ;       EDI = First EGA Byte
                   1406: ;       ECX = Number of scan lines (yExt)
                   1407: ;       EBX = offset into pattern
                   1408: ;       DATA_ROT = DR_SET
                   1409: ; Returns:
                   1410: ;       Nothing
                   1411: ; Registers Destroyed:
                   1412: ;       EAX,ECX,EDX,ESI,flags
                   1413: ; Registers Preserved:
                   1414: ;       EBX,EDI,EBP
                   1415: ; Alters:
                   1416: ;       GRAF_BIT_MASK   (leaves it FF)
                   1417: ; Calls:
                   1418: ;       None
                   1419: ;-----------------------------------------------------------------------;
                   1420: 
                   1421:         align   4
                   1422: edge_pat_blt:
                   1423: 
                   1424:         push    ebp
                   1425: 
                   1426: ; Set bit mask.
                   1427: 
                   1428:         mov     dx,EGA_BASE + GRAF_ADDR
                   1429:         mov     al,GRAF_BIT_MASK
                   1430:         out     dx,ax
                   1431:         mov     ah,11h                  ; left nibble gives carry to end loop
                   1432:         mov     dx,EGA_BASE + SEQ_DATA
                   1433:         sub     si,SIZE_PATTERN
                   1434:         mov     ebp,ecx
                   1435: 
                   1436: enable_next_plane:
                   1437:         push    ebx
                   1438:         push    edi
                   1439:         mov     ecx,ebp                 ; yExt
                   1440:         mov     al,MM_ALL
                   1441:         and     al,ah
                   1442:         out     dx,al
                   1443:         add     esi,SIZE_PATTERN
                   1444: 
                   1445: over_scans:
                   1446:         mov     al,[ebx][esi]           ; pattern fetch
                   1447:         inc     ebx
                   1448:         and     ebx,SIZE_PATTERN - 1    ; 7
                   1449:         .errnz  SIZE_PATTERN - 8        ; any power of 2 works
                   1450:         xchg    [edi],al
                   1451:         add     edi,ulNextScan_global
                   1452:         loop    over_scans
                   1453: 
                   1454:         pop     edi
                   1455:         pop     ebx
                   1456:         shl     ah,1
                   1457:         jnc     enable_next_plane
                   1458: 
                   1459: ; Restore bitmask to default.
                   1460: 
                   1461:         mov     dx,EGA_BASE + GRAF_ADDR
                   1462:         mov     ax,0FF00h + GRAF_BIT_MASK
                   1463:         out     dx,ax
                   1464: 
                   1465:         pop     ebp
                   1466:         PLAIN_RET
                   1467: 
                   1468: 
                   1469: ;----------------------------Private-Routine----------------------------;
                   1470: ; invert
                   1471: ;
                   1472: ; Inverts pixels in a rectangle on the display, by simply writing the
                   1473: ; memory to itself, letting the EGA hardware perform the XORing.
                   1474: ;
                   1475: ; Entry:
                   1476: ;       EDI = First EGA Byte
                   1477: ;       ECX = Number of scan lines (yExt)
                   1478: ;       EBX = scan line length in bytes
                   1479: ;       DATA_ROT = DR_XOR
                   1480: ;       GRAF_SET_RESET = color to xor DEST with
                   1481: ;       GRAF_SR_ENAB = MM_ALL
                   1482: ; Returns:
                   1483: ;       Nothing
                   1484: ; Registers Destroyed:
                   1485: ;       EAX,ECX,EDX,ESI,EDI,flags
                   1486: ; Registers Preserved:
                   1487: ;       EBX,EBP
                   1488: ; Alters:
                   1489: ;       GRAF_BIT_MASK   (leaves it FF)
                   1490: ; Calls:
                   1491: ;       None
                   1492: ;-----------------------------------------------------------------------;
                   1493: 
                   1494:         align   4
                   1495: invert:
                   1496: 
                   1497: ; Set bit mask.
                   1498: 
                   1499:         mov     dx,EGA_BASE + GRAF_ADDR
                   1500:         mov     ax,0FF00h + GRAF_BIT_MASK
                   1501:         out     dx,ax
                   1502:         mov     edx,ulNextScan_global
                   1503:         sub     edx,ebx
                   1504:         mov     eax,ecx                 ; save height
                   1505: 
                   1506: invert_next_scan:
                   1507:         mov     esi,edi
                   1508:         mov     ecx,ebx                 ; scan len in bytes
                   1509:         rep     movsb
                   1510:         add     edi,edx
                   1511:         dec     eax
                   1512:         jnz     invert_next_scan
                   1513:         PLAIN_RET
                   1514: 
                   1515: 
                   1516: ;----------------------------Private-Routine----------------------------;
                   1517: ; edge_invert
                   1518: ;
                   1519: ; Inverts one byte on each scan line vertically according to the mask
                   1520: ; in AH.
                   1521: ;
                   1522: ; Entry:
                   1523: ;       AH  = bitmask
                   1524: ;       EDI = First EGA Byte
                   1525: ;       ECX = Number of scan lines (yExt)
                   1526: ;       DATA_ROT = DR_XOR
                   1527: ;       GRAF_SET_RESET = color to xor DEST with
                   1528: ;       GRAF_ENAB_SR = MM_ALL
                   1529: ; Returns:
                   1530: ;       Nothing
                   1531: ; Registers Destroyed:
                   1532: ;       AL,ECX,EDX,EDI,flags
                   1533: ; Registers Preserved:
                   1534: ;       AH,EBX,ESI,EBP
                   1535: ; Alters:
                   1536: ;       GRAF_BIT_MASK
                   1537: ; Calls:
                   1538: ;       None
                   1539: ;-----------------------------------------------------------------------;
                   1540: 
                   1541:         align   4
                   1542: edge_invert:
                   1543: 
                   1544: ; Set bit mask.
                   1545: 
                   1546:         mov     dx,EGA_BASE + GRAF_ADDR
                   1547:         mov     al,GRAF_BIT_MASK
                   1548:         out     dx,ax
                   1549: 
                   1550: edge_invert_next_scan:
                   1551:         xchg    [edi],al
                   1552:         add     edi,ulNextScan_global
                   1553:         loop    edge_invert_next_scan
                   1554:         PLAIN_RET
                   1555: 
                   1556: 
                   1557: ;----------------------------Private-Routine----------------------------;
                   1558: ; edge_grey_dpx
                   1559: ;
                   1560: ; Inverts one or two bytes on each scan line vertically according
                   1561: ; to the grey pattern given, under the passed clipping mask.
                   1562: ;
                   1563: ; Entry:
                   1564: ;       EBX    =  brush index (0-7)
                   1565: ;       ECX    =  number of scan lines (cyExt)
                   1566: ;       DL     =  lhs clipping mask
                   1567: ;       DH     =  rhs clipping mask
                   1568: ;       ESI   --> base address of brush
                   1569: ;       EDI   --> rhs EGA
                   1570: ;       EBP   --> lhs EGA
                   1571: ; Returns:
                   1572: ;       Nothing
                   1573: ; Registers Destroyed:
                   1574: ;       All
                   1575: ; Registers Preserved:
                   1576: ;       None
                   1577: ; Alters:
                   1578: ;       None
                   1579: ; Calls:
                   1580: ;       None
                   1581: ;-----------------------------------------------------------------------;
                   1582: 
                   1583:         align   4
                   1584: edge_grey_dpx:
                   1585: 
                   1586:         sub     ebp,edi                 ;Compute delta to lhs
                   1587:         and     ebx,00000111b           ;Make sure brush is valid
                   1588:         .errnz  SIZE_PATTERN - 8
                   1589:         or      dh,dh                   ;Dispatch based on one or two edges
                   1590:         jz      edge_grey_dpx_one_loop
                   1591: 
                   1592: edge_grey_dpx_both_loop:
                   1593:         mov     al,[esi][ebx]           ;Get next byte of brush
                   1594:         mov     ah,al
                   1595:         and     al,dl                   ;Mask with lhs clipping mask
                   1596:         xchg    al,[edi]                ;Invert necessary bits
                   1597:         inc     ebx                     ;--> next brush byte
                   1598:         and     bl,00000111b            ;Handle any wrap
                   1599:         .errnz  SIZE_PATTERN - 8
                   1600:         and     ah,dh                   ;Mask with rhs clipping mask
                   1601:         xchg    ah,[edi][ebp]           ;Invert necessary bits
                   1602:         add     edi,ulNextScan_global   ;--> next destination byte
                   1603:         loop    edge_grey_dpx_both_loop
                   1604:         PLAIN_RET
                   1605: 
                   1606: edge_grey_dpx_one_loop:
                   1607:         mov     al,[esi][ebx]           ;Get next byte of brush
                   1608:         and     al,dl                   ;Mask with lhs clipping mask
                   1609:         xchg    al,[edi]                ;Invert necessary bits
                   1610:         inc     ebx                     ;--> next brush byte
                   1611:         and     bl,00000111b            ;Handle any wrap
                   1612:         .errnz  SIZE_PATTERN - 8
                   1613:         add     edi,ulNextScan_global   ;--> next destination byte
                   1614:         loop    edge_grey_dpx_one_loop
                   1615:         PLAIN_RET
                   1616: 
                   1617: 
                   1618: ;----------------------------Private-Routine----------------------------;
                   1619: ; middle_grey_dpx
                   1620: ;
                   1621: ; Inverts a rectangle on the display using the passed grey pattern.
                   1622: ;
                   1623: ; Entry:
                   1624: ;       EBX     =  brush index (0-7)
                   1625: ;       ECX     =  # byte to invert on the scan
                   1626: ;       EDX     =  EGA_BASE + GRAF_ADDR
                   1627: ;       ESI    --> base address of brush
                   1628: ;       EDI    --> starting byte
                   1629: ;       EBP     =  number of scan lines (cyExt)
                   1630: ;       DATA_ROT       = DR_XOR
                   1631: ;       GRAF_SET_RESET = All 1
                   1632: ;       GRAF_ENAB_SR   = MM_ALL
                   1633: ; Returns:
                   1634: ;       Nothing
                   1635: ; Registers Destroyed:
                   1636: ;       EAX,ECX,EDX,ESI,EDI,flags
                   1637: ; Registers Preserved:
                   1638: ;       EBX,EBP
                   1639: ; Alters:
                   1640: ;       GRAF_BIT_MASK   (leaves it FF)
                   1641: ; Calls:
                   1642: ;       None
                   1643: ;-----------------------------------------------------------------------;
                   1644: 
                   1645:         align   4
                   1646: middle_grey_dpx:
                   1647: 
                   1648: ;       mov     dx,EGA_BASE + GRAF_ADDR ; Leave the Graphics controller
                   1649:         mov     al,GRAF_BIT_MASK        ;   address register pointing to
                   1650:         out     dx,al                   ;   the bitmask register
                   1651:         inc     edx                     ; --> Graphics controller data register
                   1652:         .errnz  GRAF_DATA - GRAF_ADDR - 1
                   1653: 
                   1654:         mov     ah,bl                   ; Keep brush index here
                   1655:         mov     ebx,ecx                 ; Save a copy of inner loop count here
                   1656: 
                   1657: middle_grey_dpx_loop:
                   1658:         xchg    eax,ebx
                   1659:         xchg    bl,bh
                   1660:         and     ebx,00000111b
                   1661:         errnz   SIZE_PATTERN-8
                   1662:         mov     bh,[esi][ebx]           ; Get next byte of brush
                   1663:         inc     bl                      ; --> byte of the brush
                   1664:         xchg    bh,bl
                   1665:         xchg    eax,ebx
                   1666:         out     dx,al
                   1667:         mov     ecx,ebx
                   1668:         push    esi
                   1669:         mov     esi,edi
                   1670:         rep     movsb
                   1671:         pop     esi
                   1672:         sub     edi,ebx
                   1673:         add     edi,ulNextScan_global   ;next scan on screen
                   1674:         dec     ebp
                   1675:         jnz     middle_grey_dpx_loop
                   1676:         PLAIN_RET
                   1677: 
                   1678: 
                   1679: ;----------------------------Private-Routine----------------------------;
                   1680: ; do_grey_dpx
                   1681: ;
                   1682: ; This is EGA special cased code for the dpx raster op in the case where
                   1683: ; the pattern (p) is grey (the same on all planes).  We also come here
                   1684: ; for the special graying pattern rop.  This is not a normal P,S, and D rop,
                   1685: ; but a hack for pmwin.  It allows graying of things on the screen, meaning
                   1686: ; the background color is stuffed everywhere the pattern has a "1" bit.
                   1687: ;
                   1688: ; Entry:
                   1689: ;       EBP --> BitBLT local variable frame
                   1690: ; Returns:
                   1691: ;       Nothing
                   1692: ; Registers Destroyed:
                   1693: ;       ALL but EBP
                   1694: ; Registers Preserved:
                   1695: ;       EBP
                   1696: ; Calls:
                   1697: ;       calc_parms
                   1698: ;       edge_grey_dpx
                   1699: ;       middle_grey_dpx
                   1700: ;-----------------------------------------------------------------------;
                   1701: 
                   1702:         align   4
                   1703: do_grey_dpx:
                   1704: 
                   1705:         call    calc_parms
                   1706:         mov     dx,EGA_BASE + GRAF_ADDR
                   1707:         mov     ax,DR_XOR shl 8 + GRAF_DATA_ROT ; XOR mode for grey dpx
                   1708:         out     dx,ax
                   1709:         mov     dl,byte ptr fr.start_mask[0]
                   1710:         mov     dh,byte ptr fr.last_mask[0]
                   1711:         or      dx,dx
                   1712:         jz      do_grey_dpx_middle      ;Only middle bytes exist
                   1713: 
                   1714:         mov     eax,edi                 ;Assume we have a left edge
                   1715:         inc     eax                     ;+1 to get to start of middle bytes
                   1716:         or      dl,dl                   ;Is there really a left edge?
                   1717:         jnz     do_grey_dpx_have_lhs    ;  Yes, AX = correct middle byte start
                   1718:         dec     eax                     ;  No, restore middle byte start
                   1719:         xchg    dl,dh                   ;  Pretend only a lhs edge
                   1720:         add     edi,fr.inner_loop_count ;    but make it be the rhs
                   1721: 
                   1722: do_grey_dpx_have_lhs:
                   1723:         push    eax                     ;Save middle bytes start
                   1724:         push    ebx
                   1725:         push    ecx
                   1726:         push    esi
                   1727:         push    ebp
                   1728:         add     eax,fr.inner_loop_count ;--> possible rhs
                   1729:         xchg    eax,ebp
                   1730:         call    edge_grey_dpx
                   1731: did_gray_pat_edge:
                   1732:         pop     ebp
                   1733:         pop     esi
                   1734:         pop     ecx
                   1735:         pop     ebx
                   1736:         pop     edi                     ;Restore middle bytes start
                   1737: 
                   1738: do_grey_dpx_middle:
                   1739:         mov     eax,fr.inner_loop_count
                   1740:         or      eax,eax
                   1741:         jz      do_grey_dpx_exit
                   1742:         push    ebp
                   1743:         mov     ebp,ecx
                   1744:         xchg    eax,ecx
                   1745:         mov     dx,EGA_BASE + GRAF_ADDR         ;
                   1746:         mov     ax,MM_ALL shl 8 + GRAF_ENAB_SR  ; Set Set/Reset to all "1" bits
                   1747:         out     dx,ax                           ; and Enable all planes (for
                   1748:         .errnz  MM_ALL - 0Fh                    ; grey_dpx)
                   1749:         mov     al,GRAF_SET_RESET               ;
                   1750:         out     dx,ax                           ;
                   1751: 
                   1752: gray_pat:
                   1753:         call    middle_grey_dpx
                   1754:         pop     ebp
                   1755: 
                   1756: do_grey_dpx_exit:
                   1757:         PLAIN_RET
                   1758: 
                   1759: 
                   1760: endProc check_device_special_cases
                   1761: 
                   1762: _TEXT$01   ends
                   1763: 
                   1764:         end
                   1765: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.