]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/drivers/elkplan4.c
Cleanup CVS ipmorted branch
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / drivers / elkplan4.c
1 /*
2  * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
3  *
4  * Microwindows
5  * ELKS EGA/VGA Screen Driver 16 color 4 planes - 16-bit assembly version
6  * 
7  * This file is an adapation of the asmplan4.s MSC asm driver for ELKS
8  */
9 #include "device.h"
10 #include "vgaplan4.h"
11
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
16
17 /* extern data*/
18 extern int gr_mode;     /* temp kluge*/
19
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,
25 };
26
27 int
28 ega_init(PSD psd)
29 {
30         /* fill in screendevice struct*/
31         psd->addr = SCREENBASE;
32         psd->linelen = BYTESPERLINE;
33
34         /* Set up some default values for the VGA Graphics Registers. */
35         set_enable_sr (0x0f);
36         set_op (0);
37         set_mode (0);
38
39         return 1;
40 }
41
42 /*
43 * Routine to draw a horizontal line.
44 *       ega_drawhine(psd, x1, x2, y, color);
45 *
46 *       works in the following EGA and VGA modes:
47 *       200 line 16 colors modes
48 *       350 line modes
49 *       640x480 16 color
50 */
51 /* Draw horizontal line from x1,y to x2,y including final point*/
52 void
53 ega_drawhorzline(PSD psd, int x1, int x2, int y, int color)
54 {
55 #asm
56         push    bp              ; setup stack frame and preserve registers
57         mov     bp, sp
58         push    si
59         push    di
60         push    es
61
62         ; configure the graphics controller
63
64         mov     dx, #$03ce      ; DX := Graphics Controller port address
65         
66         mov     al, #3          ; set data rotate register
67         lea     bx, _mode_table
68         add     bx, _gr_mode
69         mov     ah, [bx]
70         out     dx, ax
71
72         mov     ah, [bp+12]     ; pixel value
73         xor     al, al          ; Set/Reset register number (0)
74         out     dx, ax
75
76         mov     ax, #$0f01      ; AH := bit plane mask for Enable Set/Reset
77         out     dx, ax          ; AL := Enable Set/Reset register number
78
79         push    ds              ; preserve DS
80
81         mov     ax, [bp+10]     ; y
82         mov     bx, [bp+6]      ; x1
83
84         ; compute pixel address
85         mov     dx, #BYTESPERLINE ; AX := [row * BYTESPERLINE]
86         mul     dx
87         mov     cl, bl          ; save low order column bits
88         shr     bx, #1          ; BX := [col / 8]
89         shr     bx, #1
90         shr     bx, #1
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
96         mov     es, dx
97                                 ; AH := bit mask
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
102
103         not     dh
104         shl     dh, cl          ; DH := reverse bit mask for first byte
105         not     dh              ; DH := bit mask for first byte
106
107         mov     cx, [bp+8]      ; x2
108         and     cl, #7
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
112
113         ; determine byte offset of first and last pixel in the line
114
115         mov     ax, [bp+8]      ; AX := x2
116         mov     bx, [bp+6]      ; BX := x1
117
118         mov     cl, #3          ; bits to convert pixels to bytes
119
120         shr     ax, cl          ; AX := byte offset of X2
121         shr     bx, cl          ; BX := byte offset of X1
122         mov     cx, ax
123         sub     cx, bx          ; CX := [number of bytes in line] - 1
124
125         ; get Graphics Controller port address into DX
126
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
131
132         ; make video buffer addressable through DS:SI
133
134         push    es
135         pop     ds
136         mov     si, di          ; DS:SI -> video buffer
137
138         ; set pixels in leftmost byte of the line
139
140         or      bh, bh
141         js      L43             ; jump if byte-aligned [x1 is leftmost]
142
143         or      cx, cx
144         jnz     L42             ; jump if more than one byte in the line
145
146         and     bl, bh          ; BL := bit mask for the line
147         jmp near L44
148
149 L42:    mov     ah, bh          ; AH := bit mask for first byte
150         out     dx, ax          ; update graphics controller
151
152         movsb                   ; update bit planes
153         dec     cx
154
155         ; use a fast 8086 machine instruction to draw the remainder of the line
156
157 L43:    mov     ah, #$0ff       ; AH := bit mask
158         out     dx, ax          ; update Bit Mask register
159         rep 
160         movsb                   ; update all pixels in the line
161
162         ; set pixels in the rightmost byte of the line
163
164 L44:    mov     ah, bl          ; AH := bit mask for last byte
165         out     dx, ax          ; update Graphics Controller
166         movsb                   ; update bit planes
167
168         pop     ds              ; restore ds
169
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
177
178         pop     es
179         pop     di
180         pop     si
181         pop     bp
182 #endasm
183 }
184
185 /*
186 * Routine to draw a vertical line.
187 * Called from C:
188 *       ega_drawvline(psd, x, y1, y2, color);
189 *
190 *       works in the following EGA and VGA modes:
191 *       200 line 16 colors modes
192 *       350 line modes
193 *       640x480 16 color
194 */
195 /* Draw a vertical line from x,y1 to x,y2 including final point*/
196 void
197 ega_drawvertline(PSD psd, int x,int y1, int y2, int color)
198 {
199 #asm
200         push    bp              ; setup stack frame and preserve registers
201         mov     bp, sp
202         push    ds
203
204         ; configure the graphics controller
205
206         mov     dx, #$03ce      ; DX := Graphics Controller port address
207
208         mov     al, #3          ; set data rotate register
209         lea     bx, _mode_table
210         add     bx, _gr_mode
211         mov     ah, [bx]
212         out     dx, ax
213
214         mov     ah, [bp+12]     ; color pixel value
215         xor     al, al          ; Set/Reset register number (0)
216         out     dx, ax
217
218         mov     ax, #$0f01      ; AH := bit plane mask for Enable Set/Reset
219         out     dx, ax          ; AL := Enable Set/Reset register number
220
221         ; prepare to draw vertical line
222
223         mov     ax, [bp+8]      ; AX := y1
224         mov     cx, [bp+10]     ; BX := y2
225         ;;mov   cx, bx
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
230
231 L311:   inc     cx              ; CX := number of pixels to draw
232         mov     bx, [bp+6]      ; BX := x
233         push    cx              ; save register
234
235         ; compute pixel address
236         push    dx
237         mov     dx, #BYTESPERLINE ; AX := [row * BYTESPERLINE]
238         mul     dx
239         mov     cl, bl          ; save low order column bits
240         shr     bx, #1          ; BX := [col / 8]
241         shr     bx, #1
242         shr     bx, #1
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
248         mov     ds, dx
249         pop     dx
250                                 ; AH := bit mask
251                                 ; DS:BX -> video buffer
252                                 ; CL := number bits to shift left
253
254         ; set up Graphics controller
255
256         shl     ah, cl          ; AH := bit mask in proper position
257         mov     al, #$08        ; AL := Bit Mask register number
258         out     dx, ax
259
260         pop     cx              ; restore register
261
262         ; draw the line
263
264         mov     dx, #BYTESPERLINE ; increment for video buffer
265 L1111:  or      [bx], al        ; set pixel
266         add     bx, dx          ; increment to next line
267         loop    L1111
268
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
276
277         pop     ds
278         pop     bp
279 #endasm
280 }
281
282 /*
283 * Routine to set an individual pixel value.
284 * Called from C like:
285 *       ega_drawpixel(psd, x, y, color);
286 */
287 void
288 ega_drawpixel(PSD psd, int x, int y, int color)
289 {
290 #asm
291         push    bp
292         mov     bp, sp
293
294         mov     dx, #$03ce      ; graphics controller port address
295         mov     al, #3          ; set data rotate register
296         lea     bx, _mode_table
297         add     bx, _gr_mode
298         mov     ah, [bx]
299         out     dx, ax
300
301         mov     cx, [bp+6]      ; ECX := x
302         mov     ax, [bp+8]      ; EAX := y
303
304         mov     dx, #BYTESPERLINE ; AX := [y * BYTESPERLINE]
305         mul     dx
306
307         mov     bx, cx          ; BX := [x / 8]
308         shr     bx, #1
309         shr     bx, #1
310         shr     bx, #1
311
312         add     bx, ax          ; BX := [y * BYTESPERLINE] + [x / 8]
313
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]
317         shl     ch, cl
318
319         mov     dx, #$03ce      ; graphics controller port address
320
321         ;;required for old code
322         mov     ax, #$0205      ; select write mode 2
323         out     dx, ax          ; [load value 2 into mode register 5]
324
325         ; new code
326         ;;xor   ax,ax           ; set color register 0
327         ;;mov   ah,[bp+10]      ; color pixel value
328         ;;out   dx,ax
329
330         ; original code
331         mov     al, #$08        ; set the bit mask register
332         mov     ah, ch          ; [load bit mask into register 8]
333         out     dx, ax
334
335         push    ds
336         mov     ax, #SCREENSEG  ; DS := EGA buffer segment address
337         mov     ds, ax
338
339         ; new code
340         ;;or    [bx],al         ; quick rmw to set pixel
341
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...
346         ;;cli
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
350         ;;sti
351
352         pop     ds              ; restore registers and return
353
354         mov     ax, #$0005      ; restore default write mode 0
355         out     dx, ax          ; [load value 0 into mode register 5]
356
357         ;;mov   ax, #$0ff08     ; restore default bit mask
358         ;;out   dx, ax          ; [load value ff into register 8]
359
360         pop     bp
361 #endasm
362 }
363
364 /*
365 * Routine to read the value of an individual pixel.
366 * Called from C like:
367 *       color = ega_readpixel(psd, x, y);
368 */
369 PIXELVAL
370 ega_readpixel(PSD psd, int x, int y)
371 {
372 #asm
373         push    bp
374         mov     bp, sp
375         push    si
376         push    ds
377
378         mov     ax, [bp+8]      ; EAX := y
379         mov     bx, [bp+6]      ; EBX := x
380         mov     dx, #BYTESPERLINE ; AX := [y * BYTESPERLINE]
381         mul     dx
382
383         mov     cl, bl          ; save low order column bits
384         shr     bx, #1          ; BX := [x / 8]
385         shr     bx, #1
386         shr     bx, #1
387
388         add     bx, ax          ; BX := [y * BYTESPERLINE] + [x / 8]
389
390         and     cl, #$07        ; CL := [x % 8]
391         xor     cl, #$07        ; CL := 7 - [x % 8]
392
393         mov     dx, #SCREENSEG  ; DS := EGA buffer segment address
394         mov     ds, dx
395
396         mov     ch, #$01        ; CH := 1 << [7 - [col % 8]]  [mask]
397         shl     ch, cl          ; CH := bit mask in proper position
398
399         mov     si, bx          ; DS:SI -> region buffer byte
400         xor     bl, bl          ; BL is used to accumulate the pixel value
401
402         mov     dx, #$03ce      ; DX := Graphics Controller port
403         mov     ax, #$0304      ; AH := initial bit plane number
404                                 ; AL := Read Map Select register number
405
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
413         jge     L112
414
415         xor     ax, ax          ; AL := pixel value
416         mov     al, bl
417
418         pop     ds
419         pop     si
420         pop     bp      
421 #endasm
422 }