2 * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
5 * ELKS EGA/VGA Screen Driver 16 color 4 planes - 16-bit assembly version
7 * This file is an adapation of the asmplan4.s MSC asm driver for ELKS
12 /* assumptions for speed: NOTE: psd is ignored in these routines*/
13 #define SCREENSEG $0a000
14 #define SCREENBASE MK_FP(0xa000, 0)
15 #define BYTESPERLINE 80
18 extern int gr_mode; /* temp kluge*/
20 static unsigned char mode_table[MWMODE_MAX + 1] = {
21 0x00, 0x18, 0x10, 0x08, /* COPY, XOR, AND, OR implemented*/
22 0x00, 0x00, 0x00, 0x00, /* no VGA HW for other modes*/
23 0x00, 0x00, 0x00, 0x00,
24 0x00, 0x00, 0x00, 0x00,
30 /* fill in screendevice struct*/
31 psd->addr = SCREENBASE;
32 psd->linelen = BYTESPERLINE;
34 /* Set up some default values for the VGA Graphics Registers. */
43 * Routine to draw a horizontal line.
44 * ega_drawhine(psd, x1, x2, y, color);
46 * works in the following EGA and VGA modes:
47 * 200 line 16 colors modes
51 /* Draw horizontal line from x1,y to x2,y including final point*/
53 ega_drawhorzline(PSD psd, int x1, int x2, int y, int color)
56 push bp ; setup stack frame and preserve registers
62 ; configure the graphics controller
64 mov dx, #$03ce ; DX := Graphics Controller port address
66 mov al, #3 ; set data rotate register
72 mov ah, [bp+12] ; pixel value
73 xor al, al ; Set/Reset register number (0)
76 mov ax, #$0f01 ; AH := bit plane mask for Enable Set/Reset
77 out dx, ax ; AL := Enable Set/Reset register number
84 ; compute pixel address
85 mov dx, #BYTESPERLINE ; AX := [row * BYTESPERLINE]
87 mov cl, bl ; save low order column bits
88 shr bx, #1 ; BX := [col / 8]
91 add bx, ax ; BX := [row * BYTESPERLINE] + [col / 8]
92 and cl, #$07 ; CL := [col % 8]
93 xor cl, #$07 ; CL := 7 - [col % 8]
94 mov ah, #$01 ; AH := 1 << [7 - [col % 8]] [mask]
95 mov dx, #SCREENSEG ; ES := EGA buffer segment address
98 ; ES:BX -> video buffer
99 ; CL := number bits to shift left
100 mov di, bx ; ES:DI -> buffer
101 mov dh, ah ; DH := unshifted bit mask for left byte
104 shl dh, cl ; DH := reverse bit mask for first byte
105 not dh ; DH := bit mask for first byte
109 xor cl, #7 ; CL := number of bits to shift left
110 mov dl, #$0ff ; DL := unshifted bit mask for right byte
111 shl dl, cl ; DL := bit mask for last byte
113 ; determine byte offset of first and last pixel in the line
115 mov ax, [bp+8] ; AX := x2
116 mov bx, [bp+6] ; BX := x1
118 mov cl, #3 ; bits to convert pixels to bytes
120 shr ax, cl ; AX := byte offset of X2
121 shr bx, cl ; BX := byte offset of X1
123 sub cx, bx ; CX := [number of bytes in line] - 1
125 ; get Graphics Controller port address into DX
127 mov bx, dx ; BH := bit mask for first byte
128 ; BL := bit mask for last byte
129 mov dx, #$03ce ; DX := Graphics Controller port
130 mov al, #8 ; AL := Bit mask Register number
132 ; make video buffer addressable through DS:SI
136 mov si, di ; DS:SI -> video buffer
138 ; set pixels in leftmost byte of the line
141 js L43 ; jump if byte-aligned [x1 is leftmost]
144 jnz L42 ; jump if more than one byte in the line
146 and bl, bh ; BL := bit mask for the line
149 L42: mov ah, bh ; AH := bit mask for first byte
150 out dx, ax ; update graphics controller
152 movsb ; update bit planes
155 ; use a fast 8086 machine instruction to draw the remainder of the line
157 L43: mov ah, #$0ff ; AH := bit mask
158 out dx, ax ; update Bit Mask register
160 movsb ; update all pixels in the line
162 ; set pixels in the rightmost byte of the line
164 L44: mov ah, bl ; AH := bit mask for last byte
165 out dx, ax ; update Graphics Controller
166 movsb ; update bit planes
170 ; restore default Graphics Controller state and return to caller
171 ;;xor ax, ax ; AH := 0, AL := 0
172 ;;out dx, ax ; restore Set/Reset register
173 ;;inc ax ; AH := 0, AL := 1
174 ;;out dx, ax ; restore Enable Set/Reset register
175 ;;mov ax, #$0ff08 ; AH := 0xff, AL := 0
176 ;;out dx, ax ; restore Bit Mask register
186 * Routine to draw a vertical line.
188 * ega_drawvline(psd, x, y1, y2, color);
190 * works in the following EGA and VGA modes:
191 * 200 line 16 colors modes
195 /* Draw a vertical line from x,y1 to x,y2 including final point*/
197 ega_drawvertline(PSD psd, int x,int y1, int y2, int color)
200 push bp ; setup stack frame and preserve registers
204 ; configure the graphics controller
206 mov dx, #$03ce ; DX := Graphics Controller port address
208 mov al, #3 ; set data rotate register
214 mov ah, [bp+12] ; color pixel value
215 xor al, al ; Set/Reset register number (0)
218 mov ax, #$0f01 ; AH := bit plane mask for Enable Set/Reset
219 out dx, ax ; AL := Enable Set/Reset register number
221 ; prepare to draw vertical line
223 mov ax, [bp+8] ; AX := y1
224 mov cx, [bp+10] ; BX := y2
226 sub cx, ax ; CX := dy
227 ;;jge L311 ; jump if dy >= 0
228 ;;neg cx ; force dy >= 0
229 ;;mov ax, bx ; AX := y2
231 L311: inc cx ; CX := number of pixels to draw
232 mov bx, [bp+6] ; BX := x
233 push cx ; save register
235 ; compute pixel address
237 mov dx, #BYTESPERLINE ; AX := [row * BYTESPERLINE]
239 mov cl, bl ; save low order column bits
240 shr bx, #1 ; BX := [col / 8]
243 add bx, ax ; BX := [row * BYTESPERLINE] + [col / 8]
244 and cl, #$07 ; CL := [col % 8]
245 xor cl, #$07 ; CL := 7 - [col % 8]
246 mov ah, #$01 ; AH := 1 << [7 - [col % 8]] [mask]
247 mov dx, #SCREENSEG ; DS := EGA buffer segment address
251 ; DS:BX -> video buffer
252 ; CL := number bits to shift left
254 ; set up Graphics controller
256 shl ah, cl ; AH := bit mask in proper position
257 mov al, #$08 ; AL := Bit Mask register number
260 pop cx ; restore register
264 mov dx, #BYTESPERLINE ; increment for video buffer
265 L1111: or [bx], al ; set pixel
266 add bx, dx ; increment to next line
269 ; restore default Graphics Controller state and return to caller
270 ;;xor ax, ax ; AH := 0, AL := 0
271 ;;out dx, ax ; restore Set/Reset register
272 ;;inc ax ; AH := 0, AL := 1
273 ;;out dx, ax ; restore Enable Set/Reset register
274 ;;mov ax, #$0ff08 ; AH := 0xff, AL := 0
275 ;;out dx, ax ; restore Bit Mask register
283 * Routine to set an individual pixel value.
284 * Called from C like:
285 * ega_drawpixel(psd, x, y, color);
288 ega_drawpixel(PSD psd, int x, int y, int color)
294 mov dx, #$03ce ; graphics controller port address
295 mov al, #3 ; set data rotate register
301 mov cx, [bp+6] ; ECX := x
302 mov ax, [bp+8] ; EAX := y
304 mov dx, #BYTESPERLINE ; AX := [y * BYTESPERLINE]
307 mov bx, cx ; BX := [x / 8]
312 add bx, ax ; BX := [y * BYTESPERLINE] + [x / 8]
314 and cl, #$07 ; CL := [x % 8]
315 xor cl, #$07 ; CL := 7 - [x % 8]
316 mov ch, #$01 ; CH := 1 << [7 - [x % 8]] [mask]
319 mov dx, #$03ce ; graphics controller port address
321 ;;required for old code
322 mov ax, #$0205 ; select write mode 2
323 out dx, ax ; [load value 2 into mode register 5]
326 ;;xor ax,ax ; set color register 0
327 ;;mov ah,[bp+10] ; color pixel value
331 mov al, #$08 ; set the bit mask register
332 mov ah, ch ; [load bit mask into register 8]
336 mov ax, #SCREENSEG ; DS := EGA buffer segment address
340 ;;or [bx],al ; quick rmw to set pixel
342 ;;the following fails under ELKS without cli/sti
343 ;;using ES works though. Code changed to use single
344 ;;rmw above rather than write mode 2, but the
345 ;;reason for this failure is still unknown...
347 mov al, [bx] ; dummy read to latch bit planes
348 mov al, [bp+10] ; pixel value
349 mov [bx], al ; write pixel back to bit planes
352 pop ds ; restore registers and return
354 mov ax, #$0005 ; restore default write mode 0
355 out dx, ax ; [load value 0 into mode register 5]
357 ;;mov ax, #$0ff08 ; restore default bit mask
358 ;;out dx, ax ; [load value ff into register 8]
365 * Routine to read the value of an individual pixel.
366 * Called from C like:
367 * color = ega_readpixel(psd, x, y);
370 ega_readpixel(PSD psd, int x, int y)
378 mov ax, [bp+8] ; EAX := y
379 mov bx, [bp+6] ; EBX := x
380 mov dx, #BYTESPERLINE ; AX := [y * BYTESPERLINE]
383 mov cl, bl ; save low order column bits
384 shr bx, #1 ; BX := [x / 8]
388 add bx, ax ; BX := [y * BYTESPERLINE] + [x / 8]
390 and cl, #$07 ; CL := [x % 8]
391 xor cl, #$07 ; CL := 7 - [x % 8]
393 mov dx, #SCREENSEG ; DS := EGA buffer segment address
396 mov ch, #$01 ; CH := 1 << [7 - [col % 8]] [mask]
397 shl ch, cl ; CH := bit mask in proper position
399 mov si, bx ; DS:SI -> region buffer byte
400 xor bl, bl ; BL is used to accumulate the pixel value
402 mov dx, #$03ce ; DX := Graphics Controller port
403 mov ax, #$0304 ; AH := initial bit plane number
404 ; AL := Read Map Select register number
406 L112: out dx, ax ; select bit plane
407 mov bh, [si] ; BH := byte from current bit plane
408 and bh, ch ; mask one bit
409 neg bh ; bit 7 of BH := 1 if masked bit = 1
410 ; bit 7 of BH := 0 if masked bit = 0
411 rol bx, #1 ; bit 0 of BL := next bit from pixel value
412 dec ah ; AH := next bit plane number
415 xor ax, ax ; AL := pixel value