1 ; Copyright (c) 1999 Greg Haerr <greg@censoft.com>
2 ; Copyright (c) 1991 David I. Bell
3 ; Permission is granted to use, distribute, or modify this source,
4 ; provided that this copyright notice remains intact.
6 ; EGA/VGA Screen Driver 16 color 4 planes, higher speed MASM version
8 ; Note: this file is a replacement for vgaplan4.c, when raw
9 ; speed rather than portability is desired
11 ; The algorithms for some of these routines are taken from the book:
12 ; Programmer's Guide to PC and PS/2 Video Systems by Richard Wilton.
14 ; Routines to draw pixels and lines for EGA/VGA resolutions.
15 ; The drawing mode in the data/rotate register is not changed in this
16 ; module, and must be changed as necessary by the callers.
18 PIXBYTES = 80 ; number of bytes in scan line
26 .cextrn gr_mode,word ; temp kluge devdraw.c graphics draw mode
29 db 00h,18h,10h,08h ; vga draw modes
34 ; int ega_init(PSD psd)
42 ; Routine to draw a horizontal line.
44 ; ega_drawhine(x1, x2, y, color);
46 ; works in the following EGA and VGA modes:
47 ; 200 line 16 colors modes
51 ; argument offsets from bp
52 x1 = arg1 ; first X coordinate
53 x2 = arg1 + 2 ; second X coordinate
54 y = arg1 + 4 ; second Y coordinate
55 color = arg1 + 6 ; pixel value
58 push bp ; setup stack frame and preserve registers
64 ; configure the graphics controller
66 mov dx, 03ceh ; DX := Graphics Controller port address
68 mov al, #3 ; set data rotate register
74 mov ah, color[bp] ; pixel value
75 xor al, al ; Set/Reset register number (0)
78 mov ax, 0f01h ; AH := bit plane mask for Enable Set/Reset
79 out dx, ax ; AL := Enable Set/Reset register number
86 ; compute pixel address
87 mov dx, offset PIXBYTES ; AX := [row * PIXBYTES]
89 mov cl, bl ; save low order column bits
90 shr bx, 1 ; BX := [col / 8]
93 add bx, ax ; BX := [row * PIXBYTES] + [col / 8]
94 and cl, 07h ; CL := [col % 8]
95 xor cl, 07h ; CL := 7 - [col % 8]
96 mov ah, 01h ; AH := 1 << [7 - [col % 8]] [mask]
97 mov dx, 0a000h ; ES := EGA buffer segment address
100 ; ES:BX -> video buffer
101 ; CL := number bits to shift left
102 mov di, bx ; ES:DI -> buffer
103 mov dh, ah ; DH := unshifted bit mask for left byte
106 shl dh, cl ; DH := reverse bit mask for first byte
107 not dh ; DH := bit mask for first byte
111 xor cl, 7 ; CL := number of bits to shift left
112 mov dl, 0ffh ; DL := unshifted bit mask for right byte
113 shl dl, cl ; DL := bit mask for last byte
115 ; determine byte offset of first and last pixel in the line
117 mov ax, x2[bp] ; AX := x2
118 mov bx, x1[bp] ; BX := x1
120 mov cl, 3 ; bits to convert pixels to bytes
122 shr ax, cl ; AX := byte offset of X2
123 shr bx, cl ; BX := byte offset of X1
125 sub cx, bx ; CX := [number of bytes in line] - 1
127 ; get Graphics Controller port address into DX
129 mov bx, dx ; BH := bit mask for first byte
130 ; BL := bit mask for last byte
131 mov dx, 03ceh ; DX := Graphics Controller port
132 mov al, 8 ; AL := Bit mask Register number
134 ; make video buffer addressable through DS:SI
138 mov si, di ; DS:SI -> video buffer
140 ; set pixels in leftmost byte of the line
143 js L43 ; jump if byte-aligned [x1 is leftmost]
146 jnz L42 ; jump if more than one byte in the line
148 and bl, bh ; BL := bit mask for the line
151 L42: mov ah, bh ; AH := bit mask for first byte
152 out dx, ax ; update graphics controller
154 movsb ; update bit planes
157 ; use a fast 8086 machine instruction to draw the remainder of the line
159 L43: mov ah, 0ffh ; AH := bit mask
160 out dx, ax ; update Bit Mask register
161 rep movsb ; update all pixels in the line
163 ; set pixels in the rightmost byte of the line
165 L44: mov ah, bl ; AH := bit mask for last byte
166 out dx, ax ; update Graphics Controller
167 movsb ; update bit planes
172 ; restore default Graphics Controller state and return to caller
173 ;;xor ax, ax ; AH := 0, AL := 0
174 ;;out dx, ax ; restore Set/Reset register
175 ;;inc ax ; AH := 0, AL := 1
176 ;;out dx, ax ; restore Enable Set/Reset register
177 ;;mov ax, 0ff08h ; AH := 0xff, AL := 0
178 ;;out dx, ax ; restore Bit Mask register
189 ; Routine to draw a vertical line.
191 ; ega_drawvline(x, y1, y2, color);
193 ; works in the following EGA and VGA modes:
194 ; 200 line 16 colors modes
198 ; argument offsets from bp
199 x = arg1 ; first X coordinate
200 y1 = arg1 + 2 ; first Y coordinate
201 y2 = arg1 + 4 ; second Y coordinate
202 color = arg1 + 6 ; pixel value
205 push bp ; setup stack frame and preserve registers
209 ; configure the graphics controller
211 mov dx, 03ceh ; DX := Graphics Controller port address
213 mov al, #3 ; set data rotate register
219 mov ah, color[bp] ; pixel value
220 xor al, al ; Set/Reset register number (0)
223 mov ax, 0f01h ; AH := bit plane mask for Enable Set/Reset
224 out dx, ax ; AL := Enable Set/Reset register number
226 ; prepare to draw vertical line
228 mov ax, y1[bp] ; AX := y1
229 mov cx, y2[bp] ; BX := y2
231 sub cx, ax ; CX := dy
232 ;;jge L311 ; jump if dy >= 0
233 ;;neg cx ; force dy >= 0
234 ;;mov ax, bx ; AX := y2
236 L311: inc cx ; CX := number of pixels to draw
237 mov bx, x[bp] ; BX := x
238 push cx ; save register
240 ; compute pixel address
242 mov dx, offset PIXBYTES ; AX := [row * PIXBYTES]
244 mov cl, bl ; save low order column bits
245 shr bx, 1 ; BX := [col / 8]
248 add bx, ax ; BX := [row * PIXBYTES] + [col / 8]
249 and cl, 07h ; CL := [col % 8]
250 xor cl, 07h ; CL := 7 - [col % 8]
251 mov ah, 01h ; AH := 1 << [7 - [col % 8]] [mask]
252 mov dx, 0a000h ; DS := EGA buffer segment address
256 ; DS:BX -> video buffer
257 ; CL := number bits to shift left
259 ; set up Graphics controller
261 shl ah, cl ; AH := bit mask in proper position
262 mov al, 08h ; AL := Bit Mask register number
265 pop cx ; restore register
269 mov dx, offset PIXBYTES ; increment for video buffer
270 L1111: or [bx], al ; set pixel
271 add bx, dx ; increment to next line
274 ; restore default Graphics Controller state and return to caller
275 ;;xor ax, ax ; AH := 0, AL := 0
276 ;;out dx, ax ; restore Set/Reset register
277 ;;inc ax ; AH := 0, AL := 1
278 ;;out dx, ax ; restore Enable Set/Reset register
279 ;;mov ax, 0ff08h ; AH := 0xff, AL := 0
280 ;;out dx, ax ; restore Bit Mask register
289 ; Routine to set an individual pixel value.
290 ; Called from C like:
291 ; ega_drawpixel(x, y, color);
294 ; argument offsets from bp
295 x = arg1 ; X coordinate
296 y = arg1+2 ; Y coordinate
297 color = arg1+4 ; pixel value
303 mov dx, 03ceh ; graphics controller port address
304 mov al, #3 ; set data rotate register
310 mov cx, x[bp] ; ECX := x
311 mov ax, y[bp] ; EAX := y
313 mov dx, offset PIXBYTES ; AX := [y * PIXBYTES]
316 mov bx, cx ; BX := [x / 8]
321 add bx, ax ; BX := [y * PIXBYTES] + [x / 8]
323 and cl, 07h ; CL := [x % 8]
324 xor cl, 07h ; CL := 7 - [x % 8]
325 mov ch, 01h ; CH := 1 << [7 - [x % 8]] [mask]
328 mov dx, 03ceh ; graphics controller port address
330 ;;required for old code
331 ;;mov ax, 0205h ; select write mode 2
332 ;;out dx, ax ; [load value 2 into mode register 5]
335 xor ax,ax ; set color register 0
336 mov ah,[bp+8] ; color pixel value
340 mov al, 08h ; set the bit mask register
341 mov ah, ch ; [load bit mask into register 8]
345 mov ax, 0a000h ; DS := EGA buffer segment address
349 or [bx],al ; quick rmw to set pixel
351 ;;the following fails under ELKS without cli/sti
352 ;;using ES works though. Code changed to use single
353 ;;rmw above rather than write mode 2, but the
354 ;;reason for this failure is still unknown...
356 ;;mov al, [bx] ; dummy read to latch bit planes
357 ;;mov al, color[bp] ; pixel value
358 ;;mov [bx], al ; write pixel back to bit planes
361 pop ds ; restore registers and return
363 mov ax, 0005h ; restore default write mode 0
364 out dx, ax ; [load value 0 into mode register 5]
365 ;;mov ax, 0ff08h ; restore default bit mask
366 ;;out dx, ax ; [load value ff into register 8]
373 ; Routine to read the value of an individual pixel.
374 ; Called from C like:
375 ; color = ega_readpixel(x, y);
378 ; argument offsets from bp
379 x = arg1 ; X coordinate
380 y = arg1+2 ; Y coordinate
388 mov ax, y[bp] ; EAX := y
389 mov bx, x[bp] ; EBX := x
390 mov dx, offset PIXBYTES ; AX := [y * PIXBYTES]
393 mov cl, bl ; save low order column bits
394 shr bx, 1 ; BX := [x / 8]
398 add bx, ax ; BX := [y * PIXBYTES] + [x / 8]
400 and cl, 07h ; CL := [x % 8]
401 xor cl, 07h ; CL := 7 - [x % 8]
403 mov dx, 0a000h ; DS := EGA buffer segment address
406 mov ch, 01h ; CH := 1 << [7 - [col % 8]] [mask]
407 shl ch, cl ; CH := bit mask in proper position
409 mov si, bx ; DS:SI -> region buffer byte
410 xor bl, bl ; BL is used to accumulate the pixel value
412 mov dx, 03ceh ; DX := Graphics Controller port
413 mov ax, 0304h ; AH := initial bit plane number
414 ; AL := Read Map Select register number
416 L112: out dx, ax ; select bit plane
417 mov bh, [si] ; BH := byte from current bit plane
418 and bh, ch ; mask one bit
419 neg bh ; bit 7 of BH := 1 if masked bit = 1
420 ; bit 7 of BH := 0 if masked bit = 0
421 rol bx, 1 ; bit 0 of BL := next bit from pixel value
422 dec ah ; AH := next bit plane number
425 xor ax, ax ; AL := pixel value