home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource4 / 283_01 / lvideo.asm < prev    next >
Encoding:
Assembly Source File  |  1988-12-17  |  32.4 KB  |  782 lines

  1.  
  2. ; LVIDEO.ASM - after Microsoft Systems Journal, Nov. 1988, p. 6
  3. ;
  4. ;               *** Caution: Large Model stack bias! ***
  5. ;
  6. ; This program handles direct writes to the IBM PC video screen buffer
  7. ; located in RAM memory.  Works with all 100% compatible clones, and
  8. ; correctly eliminates snow when using CGA.  See the article in MSJ:
  9. ; "Building a device-independent video display I/O library in Microsoft C",
  10. ; by Jeff Prosise.  Requires MASM v5.0 or MASM v5.1, per documentation.
  11. ;
  12. ; Memory model support by David C. Oshel, Ames, Iowa, Dec. 9, 1988.
  13. ; This file is essentially ASMVIDEO.ASM, modified for appropriate function
  14. ; calls and returns, and DS register management for various data objects.
  15. ;
  16. ; I've added four additional functions, all of which take a len argument,
  17. ; to Prosise's original set of three:
  18. ;                               
  19. ;                  MSJ_SetFldAttr, MSJ_DispMsgLen    12/10/88
  20. ;                  MSJ_MovScrBuf,  MSJ_MovBufScr     12/11/88
  21. ;
  22. ; Added Wozniak's pattern fill to MSJ_SetFldAttr on 12/12/88, and figured
  23. ; out why I still had snow on a CGA (NCR PC 6300) on 12/13/88.  See next.
  24. ;
  25. ;                         *** C A U T I O N ***
  26. ;
  27. ; It turns out that Prosise's XCHG AX,BX and STOSW pattern in the snow
  28. ; elimination code is a VERY time critical optimization.  I actually had
  29. ; to read the article before I could expand on the original routines.  Ouch.
  30. ;       --- 12/13/88, d.c.oshel
  31. ;
  32.  
  33.         .MODEL LARGE
  34.         .CODE
  35.         PUBLIC _MSJ_MovBufScr, _MSJ_MovScrBuf
  36.         PUBLIC _MSJ_SetFldAttr, _MSJ_DispMsgLen
  37.         PUBLIC _MSJ_DispString, _MSJ_DispCharAttr, _MSJ_GetCharAttr
  38.  
  39.  
  40. ;
  41. ; The C interface for these functions and structures looks like this:
  42. ;
  43. ;struct MSJ_VideoInfo {
  44. ;    unsigned char mode;
  45. ;    unsigned char rows;
  46. ;    unsigned char columns;
  47. ;    unsigned char ColorFlag;
  48. ;    unsigned char SnowFlag;
  49. ;    unsigned int  BufferStart;
  50. ;    unsigned int  SegAddr;
  51. ;};
  52. ;
  53. ;extern struct MSJ_VideoInfo video;  /* defined in CVIDEO.C */
  54. ;
  55. ;
  56. ;/* MSJ, Nov. 1988
  57. ;   */
  58. ;extern int cdecl MSJ_GetCharAttr( char row, char col, 
  59. ;                                  struct MSJ_VideoInfo * sptr );
  60. ;
  61. ;/* MSJ, Nov. 1988
  62. ;   */
  63. ;extern void cdecl MSJ_DispCharAttr( char ch, 
  64. ;                                    char row, char col, 
  65. ;                                    char VideoAttr, 
  66. ;                                    struct MSJ_VideoInfo * sptr );
  67. ;
  68. ;
  69. ;/* MSJ, Nov. 1988
  70. ;   */
  71. ;extern void cdecl MSJ_DispString( char * msg, 
  72. ;                                  char row, char col, 
  73. ;                                  char VideoAttr, 
  74. ;                                  struct MSJ_VideoInfo * sptr ); 
  75. ;
  76. ;
  77. ;/* MSJ_DispMsgLen is like MSJ_DispString, but takes a length argument,
  78. ;   and does not disturb screen attributes in the receiving field
  79. ;   12/10/88, d.c.oshel
  80. ;   */
  81. ;extern void cdecl MSJ_DispMsgLen( char * msg, 
  82. ;                                  char row, char col, 
  83. ;                                  int len,
  84. ;                                  struct MSJ_VideoInfo * sptr ); 
  85. ;
  86. ;
  87. ;/* MSJ_SetFldAttr takes a length argument and clears a field of the
  88. ;   screen to the given char having the given attribute
  89. ;   12/10/88, d.c.oshel
  90. ;   */
  91. ;extern void cdecl MSJ_SetFldAttr( char ch, 
  92. ;                                  char row, 
  93. ;                                  char col, 
  94. ;                                  char VideoAttr,
  95. ;                                  int len,
  96. ;                                  struct MSJ_VideoInfo * sptr );
  97. ;
  98. ;
  99. ;/* move count WORDS from screen to far buffer, 12/10/88, d.c.oshel 
  100. ;   */
  101. ;extern void cdecl MSJ_MovScrBuf(  int far * buffer,
  102. ;                                  char row,
  103. ;                                  char col,
  104. ;                                  int count,
  105. ;                                  struct MSJ_VideoInfo * sptr );
  106. ;
  107. ;
  108. ;/* move count WORDS from far buffer to screen, 12/10/88, d.c.oshel 
  109. ;   */
  110. ;extern void cdecl MSJ_MovBufScr(  int far * buffer,
  111. ;                                  char row,
  112. ;                                  char col,
  113. ;                                  int count,
  114. ;                                  struct MSJ_VideoInfo * sptr );
  115. ;
  116.  
  117.  
  118. ;-----------------------------------------------------------------------
  119. ; _MSJ_MovBufScr   copies count words from the user's save buffer to 
  120. ;                  the active video buffer
  121. ;                  12/10/88, d.c.oshel 
  122. ;
  123. ; _MSJ_MovScrBuf   copies count words from the active video buffer to 
  124. ;                  the user's save buffer
  125. ;                  12/10/88, d.c.oshel 
  126. ;-----------------------------------------------------------------------
  127. ;
  128. ; Arguments on the stack (LARGE MODEL):
  129. ;
  130. ;                       [bp+18]  <--- seg\ struct MSJ_VideoInfo far * sptr
  131. ;                       [bp+16]  <--- ofs/ 
  132. ;                       [bp+14]  <--- int count
  133. ;                       [bp+12]  <--- char col
  134. ;                       [bp+10]  <--- char row
  135. ;                       [bp+8]   <--- seg\ int far * buffer
  136. ;                       [bp+6]   <--- ofs/ 
  137. ;
  138. _MSJ_MovBufScr  PROC
  139.                 push    bp      ;save regs & establish stack frame
  140.                 mov     bp,sp
  141.                 push    si
  142.                 push    di
  143.                 push    es
  144.                 push    ds      ;large model uses data segments anywhere
  145.  
  146. ; COUNT:        load CX with the number of bytes to move
  147. ;
  148.                 mov     cx,[bp+14]      ;CX <-- count
  149.                 cmp     cx,1            ;we're already done if CX <= 0
  150.                 jl      exitmbs
  151.  
  152. ; DESTINATION:  set ES:DI to point to screen buffer absolute address
  153. ;               note - this changes DS to video structure's segment
  154. ;
  155.                 lds     bx,[bp+16]          ;DS:BX <-- ptr to video structure
  156.                 test    byte ptr [bx+4], 1  ;is video.SnowFlag clear?
  157.                 pushf                       ;save answer for later
  158.  
  159.                 mov     dh,[bp+10]  ;DH <-- row
  160.                 mov     dl,[bp+12]  ;DL <-- col
  161.                 call    AddressOf   ;DI <-- screen offset
  162.                 mov     es,[bx+8]   ;ES <-- video.SegAddr (screen segment)
  163.                                          
  164. ; SOURCE:       set DS:SI to point to user's save buffer
  165. ;
  166.                 lds     si,[bp+6]       ;DS:SI <-- ptr to source
  167.                 cld
  168.                 popf
  169.                 jnz     hardway
  170.  
  171. ; BEST CASE, move the string from DS:SI to ES:DI, with immediate writes
  172. ;
  173.                 rep     movsw           ;move all immediately
  174.                 jmp     exitmbs
  175.  
  176. hardway:        lodsw                   ;get char from buffer
  177.                 xchg    ax,bx
  178.  
  179.                 cli                     ;disable interrupts
  180.                 mov     dx,3DAh         ;DX <- ptr to Status Register
  181. st1:            in      al,dx           ;if we've arrived during a
  182.                 test    al,1            ;horizontal blanking interval,
  183.                 jnz     st1             ;must wait for the start of next!
  184. st2:            in      al,dx           ;bit one is horizontal retrace
  185.                 test    al,1            ;bit three is vertical retrace
  186.                 jz      st2             ;if nz, horizontal blanking is NOW.
  187.  
  188.                 ; Move up to 16 bits ONLY to the screen, taking advantage
  189.                 ; of the 8088's 4-byte prefetch buffer to save time (!),
  190.                 ; during the 7 microseconds of horizontal blanking;
  191.                 ; Prosise says timing is so tight we MUST use the XCHG
  192.                 ; instruction to get AX back, and nothing else will do.
  193.                 ;
  194.                 ; There are 200 horizontal retrace intervals per frame,
  195.                 ; only one vertical retrace interval per frame; i.e., 200
  196.                 ; lines on the screen, horizontal retrace is the zag
  197.                 ; following raster scan's zig, vertical retrace is the
  198.                 ; corner-to-corner diagonal path back to top of screen.
  199.                 ;
  200.                 ; For reference, 65 clock cycles are about 14 µsec. on
  201.                 ; a 4.77 mHz 8088.  See the article for details.
  202.                 ;
  203.                 ; In general, "snow" is caused by the CGA trying to access
  204.                 ; video RAM at the same time as the CPU (us!) is trying
  205.                 ; to change the screen.  CGA is ALWAYS accessing video
  206.                 ; RAM, except during horizontal or vertical retrace, or
  207.                 ; unless the port is turned off.  Prosise's discussion,
  208.                 ; en precis.  NOTE:  Not all hardware that uses CGA modes
  209.                 ; is actually a CGA!  The snow elimination algorithm is
  210.                 ; so slow (relatively speaking), it should be turned off
  211.                 ; unless actually needed to eliminate snow.  For example,
  212.                 ; my ATI Graphics Solution card emulates CGA but does not
  213.                 ; require snow elimination.
  214.                 ;
  215.                 ; XCHG AX,BX, STOSW is 4+11 clocks (ca. 3.23 microseconds),
  216.                 ; while MOVSW is 18 clocks (ca. 3.88 microseconds), according
  217.                 ; to the Intel Programmer's Pocket Reference Guide.
  218.                 ;
  219.                 xchg    ax,bx
  220.                 stosw                   ;from buffer to screen
  221.  
  222.                 sti                     ;enable interrupts
  223.                 dec     cx              ;decrement byte counter
  224.                 jcxz    exitmbs         ;all done, CX has gone to 0
  225.                 jmp     hardway         ;loop back for more
  226.  
  227. exitmbs:        pop     ds      ;restore original DS, etc.
  228.                 pop     es
  229.                 pop     di
  230.                 pop     si
  231.                 pop     bp
  232.                 ret
  233. _MSJ_MovBufScr  ENDP
  234.  
  235.  
  236. _MSJ_MovScrBuf  PROC
  237.                 push    bp      ;save regs & establish stack frame
  238.                 mov     bp,sp
  239.                 push    si
  240.                 push    di
  241.                 push    es
  242.                 push    ds      ;large model uses data segments anywhere
  243.  
  244. ; COUNT:        load CX with the number of bytes to move
  245. ;
  246.                 mov     cx,[bp+14]      ;CX <-- count
  247.                 cmp     cx,1            ;we're already done if CX <= 0
  248.                 jl      exitmsb 
  249.  
  250. ; SOURCE:       set DS:SI to point to screen buffer absolute address
  251. ;               note - this changes DS to video structure's segment
  252. ;
  253.                 lds     bx,[bp+16]          ;DS:BX <-- ptr to video structure
  254.                 test    byte ptr [bx+4], 1  ;is video.SnowFlag clear?
  255.                 pushf                       ;save answer for later
  256.  
  257.                 mov     dh,[bp+10]  ;DH <-- row
  258.                 mov     dl,[bp+12]  ;DL <-- col
  259.                 call    AddressOf   ;DI <-- screen offset
  260.                 mov     es,[bx+8]   ;ES <-- video.SegAddr (screen segment)
  261.                 push    es          ;save ES:DI, screen address
  262.                 push    di          ;will pop as DS:SI just below!
  263.                                          
  264. ; DESTINATION:  set ES:DI to point to user's save buffer
  265. ;
  266.                 les     di,[bp+6]       ;ES:DI <-- ptr to destination
  267.                 pop     si
  268.                 pop     ds              ;DS:SI <-- ptr to source
  269.  
  270.                 cld                     ;clear direction flag
  271.                 popf                    ;was video.SnowFlag clear?
  272.                 jnz     hw              ;no, do it the hard way
  273.  
  274. ; BEST CASE, move the string from DS:SI to ES:DI, with immediate writes
  275. ;
  276.                 rep     movsw           ;all at once!
  277.                 jmp     exitmsb
  278.  
  279. ; move the string from DS:SI to ES:DI, with retrace delay
  280. ;
  281. ; we're going from SCREEN to BUFFER, so must wait for blanking interval
  282. ; before READING the char/attribute
  283.  
  284. hw:             cli                     ;disable interrupts
  285.                 mov     dx,3DAh         ;DX <- ptr to Status Register
  286. st3:            in      al,dx           ;if we've arrived during a
  287.                 test    al,1            ;horizontal blanking interval,
  288.                 jnz     st3             ;must wait for the start of next!
  289. st4:            in      al,dx           ;bit one is horizontal retrace
  290.                 test    al,1            ;bit three is vertical retrace
  291.                 jz      st4             ;if nz, horizontal blanking is NOW.
  292.  
  293.                 ; TIME CRITICAL, only have 7 µsec to read 16 bits into AX
  294.                 ;
  295.                 lodsw
  296.  
  297.                 ; But going from AX to buffer can take as long as it takes
  298.                 ;
  299.                 stosw
  300.  
  301.                 sti                     ;enable interrupts
  302.                 dec     cx              ;decrement byte counter
  303.                 jcxz    exitmsb         ;all done, CX has gone to 0
  304.                 jmp     hw              ;loop back for more
  305.  
  306. exitmsb:        pop     ds      ;restore original DS, etc.
  307.                 pop     es
  308.                 pop     di
  309.                 pop     si
  310.                 pop     bp
  311.                 ret
  312. _MSJ_MovScrBuf  ENDP
  313.  
  314.  
  315. ;------------------------------------------------------------------------
  316. ; _MSJ_SetFldAttr  writes count copies of char/attribute to video buffer
  317. ;                  12/12/88, d.c.oshel 
  318. ;------------------------------------------------------------------------
  319. ;
  320. ; Arguments on the stack (LARGE MODEL):
  321. ;
  322. ;                       [bp+18]  <--- seg\ struct MSJ_VideoInfo far * sptr
  323. ;                       [bp+16]  <--- ofs/ 
  324. ;                       [bp+14]  <--- int count
  325. ;                       [bp+12]  <--- char VideoAttr
  326. ;                       [bp+10]  <--- char col
  327. ;                       [bp+8]   <--- char row
  328. ;                       [bp+6]   <--- char ch
  329. ;
  330. _MSJ_SetFldAttr PROC
  331.                 push    bp      ;save regs & establish stack frame
  332.                 mov     bp,sp
  333.                 push    si
  334.                 push    di
  335.                 push    es
  336.                 push    ds      ;large model uses data segments anywhere
  337.  
  338.                 mov     cx,[bp+14]      ;CX <-- count
  339.                 cmp     cx,1            ;we're already done if CX <= 0
  340.                 jl      exitsfa 
  341.  
  342. ; DESTINATION:  set ES:DI to point to screen buffer absolute address
  343. ;               note - this changes DS to video structure's segment
  344. ;
  345.                 lds     bx,[bp+16]      ;DS:BX <-- ptr to video structure
  346.  
  347.                 mov     dh,[bp+8]       ;DH <-- row
  348.                 mov     dl,[bp+10]      ;DL <-- col
  349.                 call    AddressOf       ;DI <-- screen offset
  350.                 mov     es,[bx+8]       ;ES <-- video.SegAddr (screen segment)
  351.  
  352. ; SOURCE:  load attribute and character
  353. ;
  354.                 mov     ah,[bp+12]      ;AH <-- attr
  355.                 mov     al,[bp+6]       ;AL <-- ch
  356.  
  357. ; move the FIRST word from AX to DESTINATION, with possible retrace delay
  358. ;
  359.                 cld                         ;clear direction flag
  360.                 test    byte ptr [bx+4], 1  ;is video.SnowFlag clear?
  361.                 jz      quick               ;yes
  362.  
  363.                 ;Rats.  Got CGA, so do it slow.  Just repeats.
  364.                 ;
  365.                 ;Although slow, this is still faster than the
  366.                 ;hardway pattern fill, which would have to wait for a
  367.                 ;horizontal blanking interval for BOTH reads and writes,
  368.                 ;since both source and destination are up in video RAM.
  369.                 ;
  370. slow:           xchg    ax,bx   ;save char/attr
  371.                 mov     dx,3DAh ;DX <- ptr to Status Register
  372.                 cli             ;disable interrupts
  373. at1:            in      al,dx   ;wait for non-retrace period
  374.                 test    al,1
  375.                 jnz     at1 
  376. at2:            in      al,dx   ;wait for next horz retrace
  377.                 test    al,1
  378.                 jz      at2     ;if ready, fall into...
  379.  
  380.                 ; TIME CRITICAL, must accomplish move in 7 µsec or less
  381.                 ;
  382.                 xchg    ax,bx
  383.                 stosw           ;di advances to next word
  384.  
  385.                 sti             ;enable interrupts
  386.                 dec     cx      ;decrement byte counter
  387.                 jcxz    exitsfa ;all done, if CX went to 0
  388.                 jmp     slow    ;loop back until done
  389.  
  390. ; Pattern Fill:  ES:DI is destination of next place to be filled
  391. ;                DS:SI is original ES:DI, one word back from current ES:DI
  392. ;                DS:[SI] now contains the pattern!
  393. ;                CX contains the count of words remaining in the pattern
  394. ;
  395. ; Example with count == 5; this is one of Steve Wozniak's old tricks:
  396. ;              s  d
  397. ;               \ |
  398. ;                .....    <- fill range of 5 places with Z's
  399. ;                Z...     <- source, after loading Z (move 4 one place right)
  400. ;                 ....    <- destination at start of move
  401. ;                 Z...    <- destination after one move is obvious
  402. ;                ZZ..     <- source after one move is subtle!
  403. ;                ZZZZZ    <- final result
  404. ;
  405. ; This works because the source modifies its own next byte by moving its
  406. ; first byte to an overlapping destination.  It's efficient because in the
  407. ; best case, we can move the entire range-1 using REP MOVSW.
  408. ;
  409. quick:          push    es      ;save starting destination, ES:DI
  410.                 push    di
  411.                 stosw           ;load first word into pattern, DI advances
  412.                 pop     si      ;pop starting destination as source, DS:SI!
  413.                 pop     ds
  414.                 dec     cx      ;decrement byte counter
  415.                 jcxz    exitsfa ;all done, if CX went to 0
  416.  
  417.                 rep     movsw   ;magic pattern fill ... !
  418.  
  419. exitsfa:        pop     ds      ;restore original DS, etc.
  420.                 pop     es
  421.                 pop     di
  422.                 pop     si
  423.                 pop     bp
  424.                 ret
  425. _MSJ_SetFldAttr ENDP
  426.  
  427.  
  428. ;-----------------------------------------------------------------------
  429. ; _MSJ_DispMsgLen  writes len bytes from msg to the active video buffer
  430. ;                  without disturbing the receiving attribute field
  431. ;                  12/9/88, d.c.oshel 
  432. ;-----------------------------------------------------------------------
  433. ;
  434. ; Arguments on the stack (LARGE MODEL):
  435. ;
  436. ;                       [bp+18]  <--- seg\ struct MSJ_VideoInfo far * sptr
  437. ;                       [bp+16]  <--- ofs/ 
  438. ;                       [bp+14]  <--- int len
  439. ;                       [bp+12]  <--- char col
  440. ;                       [bp+10]  <--- char row
  441. ;                       [bp+8]   <--- seg\ char far * msg
  442. ;                       [bp+6]   <--- ofs/ 
  443. ;
  444. _MSJ_DispMsgLen PROC
  445.                 push    bp      ;save regs & establish stack frame
  446.                 mov     bp,sp
  447.                 push    si
  448.                 push    di
  449.                 push    es
  450.                 push    ds      ;large model uses data segments anywhere
  451.  
  452.                 mov     cx,[bp+14]      ;CX <-- length of string
  453.                 cmp     cx,1            ;we're already done if CX <= 0
  454.                 jl      dexit
  455.  
  456. ; DESTINATION:  set ES:DI to point to screen buffer absolute address
  457. ;               note - this changes DS to video structure's segment
  458. ;
  459.                 lds     bx,[bp+16]      ;DS:BX <-- ptr to video structure
  460.                 test    byte ptr [bx+4], 1  ;is video.SnowFlag clear?
  461.                 pushf                       ;save result, will jz later
  462.                 mov     dh,[bp+10]      ;DH <-- row
  463.                 mov     dl,[bp+12]      ;DL <-- col
  464.                 call    AddressOf       ;DI <-- screen offset
  465.                 mov     es,[bx+8]       ;ES <-- video.SegAddr (screen segment)
  466.  
  467. ; SOURCE:  set DS:SI to point to null-terminated ASCII string, load attribute
  468. ;          note - this changes DS to msg's segment, old value not needed
  469. ;
  470.                 lds     si,[bp+6]       ;DS:SI <-- ptr to msg
  471.                 cld                     ;clear direction flag
  472.                 popf                    ;was video.SnowFlag set?
  473.                 jnz     dmsg1           ;yes, do it the hard way
  474.  
  475.  
  476. ; move the string from SOURCE to DESTINATION, with immediate writes
  477. ;
  478. dmsg2:          movsb                   ;move character from string to screen
  479.                 inc     di              ;  and skip over attribute on screen
  480.                 dec     cx              ;decrement byte counter
  481.                 jcxz    dexit           ;all done, CX has gone to 0
  482.                 jmp     dmsg2           ;loop back for more
  483.  
  484. ; move the string from SOURCE to DESTINATION, with retrace delay
  485. ;
  486. dmsg1:          lodsb                   ;move character from string to AL
  487.                 xchg    ax,bx
  488.                 cli
  489.                 mov     dx,3DAh         ;DX <- ptr to Status Register
  490. wt1:            in      al,dx           ;wait for non-retrace period
  491.                 test    al,1
  492.                 jnz     wt1 
  493. wt2:            in      al,dx           ;wait for next horz retrace
  494.                 test    al,1
  495.                 jz      wt2             ;if ready, fall into...
  496.  
  497.                 ; TIME CRITICAL, must accomplish move in 7 µsec or less!
  498.                 ;
  499.                 xchg    ax,bx
  500.                 stosb                   ;move character from AL to screen
  501.                 inc     di              ;  and skip over attribute on screen
  502.                 sti                     ;enable interrupts
  503.  
  504.                 dec     cx              ;decrement byte counter
  505.                 jcxz    dexit           ;all done, CX has gone to 0
  506.                 jmp     dmsg1           ;loop back for more
  507.  
  508. dexit:          pop     ds      ;restore original DS, etc.
  509.                 pop     es
  510.                 pop     di
  511.                 pop     si
  512.                 pop     bp
  513.                 ret
  514.  
  515. _MSJ_DispMsgLen ENDP
  516.  
  517.  
  518. ;------------------------------------------------------------
  519. ; _MSJ_DispString writes a string to the active video buffer
  520. ;------------------------------------------------------------
  521. ;
  522. ; Arguments on the stack (LARGE MODEL):
  523. ;
  524. ;                       [bp+18]  <--- seg\ struct MSJ_VideoInfo far * sptr
  525. ;                       [bp+16]  <--- ofs/ 
  526. ;                       [bp+14]  <--- char VideoAttr
  527. ;                       [bp+12]  <--- char col
  528. ;                       [bp+10]  <--- char row
  529. ;                       [bp+8]   <--- seg\ char far * msg
  530. ;                       [bp+6]   <--- ofs/ 
  531. ;
  532. _MSJ_DispString PROC
  533.                 push    bp      ;save regs & establish stack frame
  534.                 mov     bp,sp
  535.                 push    si
  536.                 push    di
  537.                 push    es
  538.                 push    ds      ;large model uses data segments anywhere
  539.  
  540. ; DESTINATION:  set ES:DI to point to screen buffer absolute address
  541. ;               note - this changes DS to video structure's segment
  542. ;
  543.                 lds     bx,[bp+16]      ;DS:BX <-- ptr to video structure
  544.                 mov     dh,[bp+10]      ;DH <-- row
  545.                 mov     dl,[bp+12]      ;DL <-- col
  546.                 call    AddressOf       ;DI <-- screen offset
  547.                 mov     es,[bx+8]       ;ES <-- video.SegAddr (screen segment)
  548.                 test    byte ptr [bx+4], 1  ;is video.SnowFlag clear?
  549.                 pushf                   ;save result, will jz later
  550.  
  551. ; SOURCE:  set DS:SI to point to null-terminated ASCII string, load attribute
  552. ;          note - this changes DS to msg's segment, old value not needed
  553. ;
  554.                 lds     si,[bp+6]       ;DS:SI <-- ptr to msg
  555.                 mov     ah,[bp+14]      ;AH <-- VideoAttr
  556.                 popf                    ;get flags back, with result of test
  557.                 jz      nowait          ;i.e., if video.SnowFlag is clear
  558.  
  559. ; move the string from SOURCE to DESTINATION, with retrace delay
  560. ;
  561.                 cld                     ;clear DF
  562. dstr1:          lodsb                   ;AL <-- DS:[SI]  get next character
  563.                 or      al,al           ;SI is auto-incremented by 1
  564.                 jz      dstr3           ;found '\0', ASCIIZ string terminator
  565.  
  566.                 xchg    ax,bx           ;save char/attr
  567.                 mov     dx,3DAh         ;DX <- ptr to Status Register
  568.                 cli                     ;disable interrupts
  569. wai1:           in      al,dx           ;wait for non-retrace period
  570.                 test    al,1
  571.                 jnz     wai1
  572. wai2:           in      al,dx           ;wait for next horz retrace
  573.                 test    al,1
  574.                 jz      wai2
  575.  
  576.                 ; TIME CRITICAL, must accomplish move in 7 µsec or less!
  577.                 ;
  578.                 xchg    ax,bx           ;retrieve char/attr
  579.                 stosw                   ;write to video memory at ES:[DI]
  580.                 sti                     ;enable interrupts
  581.  
  582.                 jmp     dstr1           ;DI is auto-incremented by 2
  583.  
  584.  
  585. ; move the string from SOURCE to DESTINATION, with immediate writes
  586. ;
  587. nowait:         cld             ;clear DF
  588. dstr2:          lodsb           ;AL <-- DS:[SI]  get next character
  589.                 or      al,al   ;SI is auto-incremented by 1
  590.                 jz      dstr3   ;found '\0', ASCIIZ string terminator
  591.                 stosw           ;ES:[DI] <-- AX, write immediately to screen
  592.                 jmp     dstr2   ;DI is auto-incremented by 2
  593.  
  594. dstr3:          pop     ds      ;restore original DS, etc.
  595.                 pop     es
  596.                 pop     di
  597.                 pop     si
  598.                 pop     bp
  599.                 ret
  600. _MSJ_DispString     ENDP
  601.  
  602.  
  603.  
  604.  
  605. ;-----------------------------------------------------------------------
  606. ; _MSJ_DispCharAttr     writes a character and attribute to the active
  607. ;                       video buffer
  608. ;-----------------------------------------------------------------------
  609. ;
  610. ; Arguments on the stack (LARGE MODEL):
  611. ;
  612. ;                       [bp+16]  <--- seg\ struct MSJ_VideoInfo far * sptr
  613. ;                       [bp+14]  <--- ofs/ 
  614. ;                       [bp+12]  <--- char VideoAttr
  615. ;                       [bp+10]  <--- char col
  616. ;                       [bp+8]   <--- char row
  617. ;                       [bp+6]   <--- char ch
  618. ;
  619. _MSJ_DispCharAttr PROC
  620.                 push    bp              ;save regs & establish stack frame
  621.                 mov     bp,sp
  622.                 push    di
  623.                 push    es
  624.                 push    ds
  625.  
  626. ; DESTINATION:  set ES:DI to point to screen buffer absolute address
  627. ;               note - this changes DS to video structure's segment
  628. ;
  629.                 lds     bx,[bp+14]      ;DS:BX <-- ptr to video structure
  630.                 mov     dh,[bp+8]       ;DH <-- row
  631.                 mov     dl,[bp+10]      ;DL <-- col
  632.                 call    AddressOf       ;DI <-- screen offset
  633.                 mov     es,[bx+8]       ;ES <-- video.SegAddr (screen segment)
  634.  
  635. ; SOURCE: load character & attribute from stack
  636. ;
  637.                 mov     ah,[bp+12]         ;AH <-- VideoAttr
  638.                 mov     al,[bp+6]          ;AL <-- ch
  639.                 test    byte ptr [bx+4], 1 ;is DS:video.SnowFlag clear?
  640.                 jz      dca1               ;yes, write direct
  641.  
  642.                 xchg    ax,bx           ;save char/attr
  643.                 mov     dx,3DAh         ;DX <- ptr to Status Register
  644.                 cli                     ;disable interrupts
  645. wai3:           in      al,dx           ;wait for non-retrace period
  646.                 test    al,1
  647.                 jnz     wai3
  648. wai4:           in      al,dx           ;wait for next horz retrace
  649.                 test    al,1
  650.                 jz      wai4
  651.  
  652.                 ; TIME CRITICAL, must accomplish move in 7 µsec or less!
  653.                 ;
  654.                 xchg    ax,bx           ;retrieve char/attr
  655.                 stosw                   ;write to video memory at ES:[DI]
  656.                 sti                     ;enable interrupts
  657.                 jmp     dca2
  658.  
  659. dca1:           stosw                   ;ES:[DI] <-- AX  a screen write
  660. dca2:           pop     ds
  661.                 pop     es
  662.                 pop     di
  663.                 pop     bp
  664.                 ret
  665. _MSJ_DispCharAttr   ENDP
  666.  
  667.  
  668.  
  669. ;---------------------------------------------------------------
  670. ; _MSJ_GetCharAttr  returns the character and attribute at the
  671. ;                   specified row & column; i.e.,
  672. ;                   On Exit: AH <-- attribute, AL <-- character
  673. ;---------------------------------------------------------------
  674. ;
  675. ; Arguments on the stack (LARGE MODEL):
  676. ;
  677. ;                       [bp+12]  <--- seg\ struct MSJ_VideoInfo far * sptr
  678. ;                       [bp+10]  <--- ofs/
  679. ;                       [bp+8]   <--- char col
  680. ;                       [bp+6]   <--- char row
  681. ;
  682. _MSJ_GetCharAttr PROC
  683.                 push    bp              ;save regs & establish stack frame
  684.                 mov     bp,sp
  685.                 push    di
  686.                 push    es
  687.                 push    ds
  688.  
  689. ; SOURCE:  set ES:DI to point to screen buffer absolute address
  690. ;          note - this changes DS to video structure's segment
  691. ;
  692.                 lds     bx,[bp+10]      ;DS:BX <-- ptr to video structure
  693.                 test    byte ptr [bx+4],1  ;is video.SnowFlag clear?
  694.                 pushf
  695.                 mov     dh,[bp+6]       ;DH <-- row
  696.                 mov     dl,[bp+8]       ;DL <-- col
  697.                 call    AddressOf       ;DI <-- screen offset
  698.                 mov     es,[bx+8]       ;ES <-- video.SegAddr (screen segment)
  699.                 push    es
  700.                 pop     ds
  701.                 push    di
  702.                 pop     si              ;move DS:SI <- ES:DI
  703.  
  704.                 cld
  705.                 popf                    ;was video.SnowFlag clear?
  706.                 jz      gca3            ;yes, skip over snow buster
  707.  
  708.                 mov     dx,3DAh   ;DX <- PORT ptr to CRTC status register
  709.                 cli
  710. gca1:           in      al,dx     ;wait for non-retrace period
  711.                 test    al,1
  712.                 jnz     gca1
  713. gca2:           in      al,dx     ;wait for next horizontal retrace
  714.                 test    al,1
  715.                 jz      gca2      ;if ready, fall into...
  716.  
  717. ; DESTINATION:  move screen buffer contents to AX register
  718. ;
  719. gca3:           lodsw             ;AH <- attr, AL <- char
  720.                 sti
  721.                 pop     ds
  722.                 pop     es
  723.                 pop     di
  724.                 pop     bp
  725.                 ret
  726. _MSJ_GetCharAttr    ENDP
  727.  
  728.  
  729. ;-----------------------------------------------------------------------------
  730. ; AddressOf     returns the video buffer address that
  731. ;               corresponds to the specified row & column
  732. ;
  733. ;       Entry:  DS:BX  -  address of VideoInfo structure
  734. ;               DH,DL  -  row, column
  735. ;       Exit:   DI     -  offset address
  736. ;-----------------------------------------------------------------------------
  737. AddressOf       PROC NEAR
  738.                 mov     al,[bx+2]       ;columns per row
  739.                 mul     dh              ;multiply by row number
  740.                 xor     dh,dh           ;add column number
  741.                 add     ax,dx
  742.                 shl     ax,1            ;mul by 2
  743.                 add     ax,[bx+6]       ;add offset of active page
  744.                 mov     di,ax           ;DI <- result
  745.                 ret
  746. AddressOf       ENDP
  747.  
  748.  
  749. ;----------------------------------------------------------------
  750. ; WriteWithWait writes a character and attribute to a CGA during
  751. ;               the horizontal blanking interval; this is the
  752. ;               Microsoft-approved *** SNOWBUSTER *** routine!
  753. ;
  754. ;       Entry:  ES:DI  -  video buffer address
  755. ;               AH,AL  -  character, attribute
  756. ;       Exit:   CX and DX are trashed
  757. ;
  758. ; I mainlined this routine to save time, above. 12/13/88, dco 
  759. ;----------------------------------------------------------------
  760. ;WriteWithWait  PROC NEAR
  761. ;               mov     cx,ax           ;save char/attr
  762. ;               mov     dx,3DAh         ;DX <- ptr to Status Register
  763. ;               cli                     ;disable interrupts
  764. ;www1:          in      al,dx           ;wait for non-retrace period
  765. ;               test    al,1
  766. ;               jnz     www1
  767. ;www2:          in      al,dx           ;wait for next horz retrace
  768. ;               test    al,1
  769. ;               jz      www2
  770. ;
  771. ;               ; TIME CRITICAL, must accomplish move in 7 µsec or less!
  772. ;               ; MOV AX,CX will *NOT* do the job!  Must be XCHG.
  773. ;               ;
  774. ;               xchg    ax,cx           ;retrieve char/attr
  775. ;               stosw                   ;write to video memory at ES:[DI]
  776. ;               sti                     ;enable interrupts
  777. ;               ret
  778. ;WriteWithWait  ENDP
  779.  
  780.                 END
  781.  
  782.