1 ;; ====================================================================
\r
3 ;; ====================================================================
\r
6 upper_left dw 0 ; Stores upper left corner offset
\r
7 ; relative to page offset.
\r
8 pages dw 0 ; for counting frame-per-sec
\r
10 PAGE_INFO STRUCT 2,NONUNIQUE
\r
12 UpperLeftAddress dw 0
\r
22 DrawPage PAGE_INFO <PAGE_0,PAGE_0>
\r
23 ShowPage PAGE_INFO <PAGE_1,PAGE_1>
\r
24 BlankPage PAGE_INFO <PAGE_2,PAGE_2>
\r
26 ROTATE3 MACRO reg,item
\r
27 mov reg,cs:ShowPage.item
\r
28 xchg reg,cs:BlankPage.item
\r
29 xchg reg,cs:DrawPage.item
\r
30 mov cs:ShowPage.item,reg
\r
31 ENDM ; Leaves ShowPage.item in reg!
\r
33 ;; This procedure is used to flip between the three available pages.
\r
34 ;; Originally from Dr. Dobb's Journal's Graphics Programming column by
\r
35 ;; Michael Abrash, I've reworked the code to be more specific to my
\r
36 ;; own purposes, and commented it more.
\r
39 ; This series of instructions circles the show_page, blank_page,
\r
40 ; and draw page appropriately and leaves the current page to show
\r
41 ; in AX. Note that it's a lot more instructions than it looks like,
\r
42 ; but I unrolled the copy loop for speed. So-so good idea, because
\r
43 ; if you add a field and forget to rotate it, it could mean trouble!
\r
44 ROTATE3 ax,Rectangles
\r
45 ROTATE3 ax,ScrollOffset
\r
48 ; ROTATE3 al,AlignmentMask SPRITES ...
\r
49 ROTATE3 al,Alignment
\r
50 mov di,ax ; DI = scroll offset low, and
\r
51 ; garbage in the high bits...
\r
52 and di,3 ; DI = pixel pan, 0 to 3.
\r
53 shl di,1 ; Mode X requires 0 2 4 or 6.
\r
56 ROTATE3 ax,UpperLeftAddress ; Leaves AX=ShowPage.ULAddr
\r
58 add ax,cs:ShowPage.ScrollOffset
\r
60 ; AX is set up to be the current show page already.
\r
61 ; By pre-loading BX with the low-address set code, and CX with
\r
62 ; the high-address set code, we can more quickly flip the page
\r
63 ; after the vertical retrace period.
\r
64 mov bl,START_ADDRESS_LOW ;preload for fastest
\r
65 mov bh,al ; flipping once display
\r
66 mov cl,START_ADDRESS_HIGH ; enable is detected
\r
69 ; Wait for display enable to be active (status is active low), to be
\r
70 ; sure both halves of the start address will take in the same frame.
\r
71 mov dx,INPUT_STATUS_1
\r
74 jnz WaitDE ;display enable is active low (0 = active)
\r
76 ; Set the start offset in display memory of the page to display.
\r
79 out dx,ax ;start address low
\r
81 out dx,ax ;start address high
\r
83 ; Now wait for vertical sync, so the other page will be invisible when
\r
84 ; we start drawing to it.
\r
85 mov dx,INPUT_STATUS_1
\r
88 jz WaitVS ;vertical sync is active high (1 = active)
\r
90 ; Finally, have to adjust the pixel panning register in order
\r
91 ; to fine-tune the starting address on a pixel level.
\r
92 ; This pixel pan value is the scroll offset mod 4 -- but since
\r
93 ; Mode X's pixel pan works by values of 2 (0, 2, 4 or 6) we
\r
94 ; have to shift appropriately.
\r
96 mov al,13h ; 13h = set pixel pan
\r
98 mov ax,di ; DI = pixel pan calculated above
\r
101 mov al,32 ; Allows the computer to use this register
\r
102 out dx,al ; again. Without this OUT, the screen will
\r
105 ; Increment the page counter now!
\r