home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter30 / l30-1.asm next >
Encoding:
Assembly Source File  |  1997-06-18  |  10.4 KB  |  379 lines

  1. ;
  2. ; *** Listing 8.1 ***
  3. ;
  4. ; Demonstrates the VGA/EGA split screen in action.
  5. ;
  6. ; Assembled with TASM 4.0, linked with TLINK 6.10
  7. ; Checked by Jim Mischel 11/21/94
  8. ;
  9. ;*********************************************************************
  10. IS_VGA        equ    1    ;set to 0 to assemble for EGA
  11. ;
  12. VGA_SEGMENT    equ    0a000h
  13. SCREEN_WIDTH    equ    640
  14. SCREEN_HEIGHT    equ    350
  15. CRTC_INDEX    equ    3d4h    ;CRT Controller Index register
  16. OVERFLOW        equ    7    ;index of Overflow reg in CRTC
  17. MAXIMUM_SCAN_LINE equ    9    ;index of Maximum Scan Line register
  18.                 ; in CRTC
  19. START_ADDRESS_HIGH equ    0ch    ;index of Start Address High register
  20.                 ; in CRTC
  21. START_ADDRESS_LOW equ    0dh    ;index of Start Address Low register
  22.                 ; in CRTC
  23. LINE_COMPARE    equ    18h    ;index of Line Compare reg (bits 7-0
  24.                 ; of split screen start scan line)
  25.                 ; in CRTC
  26. INPUT_STATUS_0    equ    3dah    ;Input Status 0 register
  27. WORD_OUTS_OK    equ    1    ;set to 0 to assemble for
  28.                 ; computers that can't handle
  29.                 ; word outs to indexed VGA registers
  30. ;*********************************************************************
  31. ; Macro to output a word value to a port.
  32. ;
  33. OUT_WORD    macro
  34. if WORD_OUTS_OK
  35.     out    dx,ax
  36. else
  37.     out    dx,al
  38.     inc    dx
  39.     xchg    ah,al
  40.     out    dx,al
  41.     dec    dx
  42.     xchg    ah,al
  43. endif
  44.     endm
  45. ;*********************************************************************
  46. MyStack    segment para stack 'STACK'
  47.     db    512 dup (0)
  48. MyStack    ends
  49. ;*********************************************************************
  50. Data    segment
  51. SplitScreenLine    dw    ?    ;line the split screen currently
  52.                 ; starts after
  53. StartAddress    dw    ?    ;display memory offset at which
  54.                 ; scanning for video data starts
  55. ; Message displayed in split screen.
  56. SplitScreenMsg    db    'Split screen text row #'
  57. DigitInsert    dw    ?
  58.         db    '...$'
  59. Data    ends
  60. ;*********************************************************************
  61. Code    segment
  62.     assume    cs:Code, ds:Data
  63. ;*********************************************************************
  64. Start    proc    near
  65.     mov    ax,Data
  66.     mov    ds,ax
  67. ;
  68. ; Select mode 10h, 640x350 16-color graphics mode.
  69. ;
  70.     mov    ax,0010h    ;AH=0 is select mode function
  71.                 ;AL=10h is mode to select,
  72.                 ; 640x350 16-color graphics mode
  73.     int    10h
  74. ;
  75. ; Put text into display memory starting at offset 0, with each row
  76. ; labelled as to number. This is the part of memory that will be
  77. ; displayed in the split screen portion of the display.
  78. ;
  79.     mov    cx,25        ;# of lines of text we'll draw into
  80.                 ; the split screen part of memory
  81. FillSplitScreenLoop:
  82.     mov    ah,2        ;set cursor location function #
  83.     sub    bh,bh        ;set cursor in page 0
  84.     mov    dh,25
  85.     sub    dh,cl        ;calculate row to draw in
  86.     sub    dl,dl        ;start in column 0
  87.     int    10h        ;set the cursor location
  88.     mov    al,25
  89.     sub    al,cl        ;calculate row to draw in again
  90.     sub    ah,ah        ;make the value a word for division
  91.     mov    dh,10
  92.     div    dh        ;split the row # into two digits
  93.     add    ax,'00'        ;convert the digits to ASCII
  94.     mov    [DigitInsert],ax ;put the digits into the text
  95.                 ; to be displayed
  96.     mov    ah,9
  97.     mov    dx,offset SplitScreenMsg
  98.     int    21h        ;print the text
  99.     loop    FillSplitScreenLoop
  100. ;
  101. ; Fill display memory starting at 8000h with a diagonally striped
  102. ; pattern.
  103. ;
  104.     mov    ax,VGA_SEGMENT
  105.     mov    es,ax
  106.     mov    di,8000h
  107.     mov    dx,SCREEN_HEIGHT ;fill all lines
  108.     mov    ax,8888h    ;starting fill pattern
  109.     cld
  110. RowLoop:
  111.     mov    cx,SCREEN_WIDTH/8/2 ;fill 1 scan line a word at a time
  112.     rep    stosw            ;fill the scan line
  113.     ror    ax,1        ;shift pattern word
  114.     dec    dx
  115.     jnz    RowLoop
  116. ;
  117. ; Set the start address to 8000h and display that part of memory.
  118. ;
  119.     mov    [StartAddress],8000h
  120.     call    SetStartAddress
  121. ;
  122. ; Slide the split screen half way up the screen and then back down
  123. ; a quarter of the screen.
  124. ;
  125.     mov    [SplitScreenLine],SCREEN_HEIGHT-1
  126.                     ;set the initial line just off
  127.                     ; the bottom of the screen
  128.     mov    cx,SCREEN_HEIGHT/2
  129.     call    SplitScreenUp
  130.     mov    cx,SCREEN_HEIGHT/4
  131.     call    SplitScreenDown
  132. ;
  133. ; Now move up another half a screen and then back down a quarter.
  134. ;
  135.     mov    cx,SCREEN_HEIGHT/2
  136.     call    SplitScreenUp
  137.     mov    cx,SCREEN_HEIGHT/4
  138.     call    SplitScreenDown
  139. ;
  140. ; Finally move up to the top of the screen.
  141. ;
  142.     mov    cx,SCREEN_HEIGHT/2-2
  143.     call    SplitScreenUp
  144. ;
  145. ; Wait for a key press (don't echo character).
  146. ;
  147.     mov    ah,8    ;DOS console input without echo function
  148.     int    21h
  149. ;
  150. ; Turn the split screen off.
  151. ;
  152.     mov    [SplitScreenLine],0ffffh
  153.     call    SetSplitScreenScanLine
  154. ;
  155. ; Wait for a key press (don't echo character).
  156. ;
  157.     mov    ah,8    ;DOS console input without echo function
  158.     int    21h
  159. ;
  160. ; Display the memory at 0 (the same memory the split screen displays).
  161. ;
  162.     mov    [StartAddress],0
  163.     call    SetStartAddress
  164. ;
  165. ; Flip between the split screen and the normal screen every 10th
  166. ; frame until a key is pressed.
  167. ;
  168. FlipLoop:
  169.     xor    [SplitScreenLine],0ffffh
  170.     call    SetSplitScreenScanLine
  171.     mov    cx,10
  172. CountVerticalSyncsLoop:
  173.     call    WaitForVerticalSyncEnd
  174.     loop    CountVerticalSyncsLoop
  175.     mov    ah,0bh    ;DOS character available status
  176.     int    21h
  177.     and    al,al    ;character available?
  178.     jz    FlipLoop ;no, toggle split screen on/off status
  179.     mov    ah,1
  180.     int    21h    ;clear the character
  181. ;
  182. ; Return to text mode and DOS.
  183. ;
  184.     mov    ax,0003h    ;AH=0 is select mode function
  185.                 ;AL=3 is mode to select, text mode
  186.     int    10h        ;return to text mode
  187.     mov    ah,4ch
  188.     int    21h        ;return to DOS
  189. Start    endp
  190. ;*********************************************************************
  191. ; Waits for the leading edge of the vertical sync pulse.
  192. ;
  193. ; Input: none
  194. ;
  195. ; Output: none
  196. ;
  197. ; Registers altered: AL, DX
  198. ;
  199. WaitForVerticalSyncStart    proc    near
  200.     mov    dx,INPUT_STATUS_0
  201. WaitNotVerticalSync:
  202.     in    al,dx
  203.     test    al,08h
  204.     jnz    WaitNotVerticalSync
  205. WaitVerticalSync:
  206.     in    al,dx
  207.     test    al,08h
  208.     jz    WaitVerticalSync
  209.     ret
  210. WaitForVerticalSyncStart    endp
  211. ;*********************************************************************
  212. ; Waits for the trailing edge of the vertical sync pulse.
  213. ;
  214. ; Input: none
  215. ;
  216. ; Output: none
  217. ;
  218. ; Registers altered: AL, DX
  219. ;
  220. WaitForVerticalSyncEnd    proc    near
  221.     mov    dx,INPUT_STATUS_0
  222. WaitVerticalSync2:
  223.     in    al,dx
  224.     test    al,08h
  225.     jz    WaitVerticalSync2
  226. WaitNotVerticalSync2:
  227.     in    al,dx
  228.     test    al,08h
  229.     jnz    WaitNotVerticalSync2
  230.     ret
  231. WaitForVerticalSyncEnd    endp
  232. ;*********************************************************************
  233. ; Sets the start address to the value specifed by StartAddress.
  234. ; Wait for the trailing edge of vertical sync before setting so that
  235. ; one half of the address isn't loaded before the start of the frame
  236. ; and the other half after, resulting in flicker as one frame is
  237. ; displayed with mismatched halves. The new start address won't be
  238. ; loaded until the start of the next frame; that is, one full frame
  239. ; will be displayed before the new start address takes effect.
  240. ;
  241. ; Input: none
  242. ;
  243. ; Output: none
  244. ;
  245. ; Registers altered: AX, DX
  246. ;
  247. SetStartAddress    proc    near
  248.     call    WaitForVerticalSyncEnd
  249.     mov    dx,CRTC_INDEX
  250.     mov    al,START_ADDRESS_HIGH
  251.     mov    ah,byte ptr [StartAddress+1]
  252.     cli        ;make sure both registers get set at once
  253.     OUT_WORD
  254.     mov    al,START_ADDRESS_LOW
  255.     mov    ah,byte ptr [StartAddress]
  256.     OUT_WORD
  257.     sti
  258.     ret
  259. SetStartAddress    endp
  260. ;*********************************************************************
  261. ; Sets the scan line the split screen starts after to the scan line
  262. ; specified by SplitScreenLine.
  263. ;
  264. ; Input: none
  265. ;
  266. ; Output: none
  267. ;
  268. ; All registers preserved
  269. ;
  270. SetSplitScreenScanLine    proc    near
  271.     push    ax
  272.     push    cx
  273.     push    dx
  274. ;
  275. ; Wait for the leading edge of the vertical sync pulse. This ensures
  276. ; that we don't get mismatched portions of the split screen setting
  277. ; while setting the two or three split screen registers (register 18h
  278. ; set but register 7 not yet set when a match occurs, for example),
  279. ; which could produce brief flickering.
  280. ;
  281.     call    WaitForVerticalSyncStart
  282. ;
  283. ; Set the split screen scan line.
  284. ;
  285.     mov    dx,CRTC_INDEX
  286.     mov    ah,byte ptr [SplitScreenLine]
  287.     mov    al,LINE_COMPARE
  288.     cli        ;make sure all the registers get set at once
  289.     OUT_WORD    ;set bits 7-0 of the split screen scan line
  290.     mov    ah,byte ptr [SplitScreenLine+1]
  291.     and    ah,1
  292.     mov    cl,4
  293.     shl    ah,cl    ;move bit 8 of the split split screen scan
  294.             ; line into position for the Overflow reg
  295.     mov    al,OVERFLOW
  296. if IS_VGA
  297. ;
  298. ; The Split Screen, Overflow, and Line Compare registers all contain
  299. ; part of the split screen start scan line on the VGA. We'll take
  300. ; advantage of the readable registers of the VGA to leave other bits
  301. ; in the registers we access undisturbed.
  302. ;
  303.     out    dx,al    ;set CRTC Index reg to point to Overflow
  304.     inc    dx    ;point to CRTC Data reg
  305.     in    al,dx    ;get the current Overflow reg setting
  306.     and    al,not 10h ;turn off split screen bit 8
  307.     or    al,ah    ;insert the new split screen bit 8
  308.             ; (works in any mode)
  309.     out    dx,al    ;set the new split screen bit 8
  310.     dec    dx    ;point to CRTC Index reg
  311.     mov    ah,byte ptr [SplitScreenLine+1]
  312.     and    ah,2
  313.     mov    cl,3
  314.     ror    ah,cl    ;move bit 9 of the split split screen scan
  315.             ; line into position for the Maximum Scan
  316.             ; Line register
  317.     mov    al,MAXIMUM_SCAN_LINE
  318.     out    dx,al    ;set CRTC Index reg to point to Maximum
  319.             ; Scan Line
  320.     inc    dx    ;point to CRTC Data reg
  321.     in    al,dx    ;get the current Maximum Scan Line setting
  322.     and    al,not 40h ;turn off split screen bit 9
  323.     or    al,ah    ;insert the new split screen bit 9
  324.             ; (works in any mode)
  325.     out    dx,al    ;set the new split screen bit 9
  326. else
  327. ;
  328. ; Only the Split Screen and Overflow registers contain part of the
  329. ; Split Screen start scan line and need to be set on the EGA.
  330. ; EGA registers are not readable, so we have to set the non-split
  331. ; screen bits of the Overflow register to a preset value, in this
  332. ; case the value for 350-scan-line modes.
  333. ;
  334.     or    ah,0fh    ;insert the new split screen bit 8
  335.             ; (only works in 350-scan-line EGA modes)
  336.     OUT_WORD    ;set the new split screen bit 8
  337. endif
  338.     sti
  339.     pop    dx
  340.     pop    cx
  341.     pop    ax
  342.     ret
  343. SetSplitScreenScanLine    endp
  344. ;*********************************************************************
  345. ; Moves the split screen up the specified number of scan lines.
  346. ;
  347. ; Input: CX = # of scan lines to move the split screen up by
  348. ;
  349. ; Output: none
  350. ;
  351. ; Registers altered: CX
  352. ;
  353. SplitScreenUp    proc    near
  354. SplitScreenUpLoop:
  355.     dec    [SplitScreenLine]
  356.     call    SetSplitScreenScanLine
  357.     loop    SplitScreenUpLoop
  358.     ret
  359. SplitScreenUp    endp
  360. ;*********************************************************************
  361. ; Moves the split screen down the specified number of scan lines.
  362. ;
  363. ; Input: CX = # of scan lines to move the split screen down by
  364. ;
  365. ; Output: none
  366. ;
  367. ; Registers altered: CX
  368. ;
  369. SplitScreenDown    proc    near
  370. SplitScreenDownLoop:
  371.     inc    [SplitScreenLine]
  372.     call    SetSplitScreenScanLine
  373.     loop    SplitScreenDownLoop
  374.     ret
  375. SplitScreenDown    endp
  376. ;*********************************************************************
  377. Code    ends
  378.     end    Start
  379.