]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/drivers/asmplan4.s
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / drivers / asmplan4.s
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.
5 ;
6 ; EGA/VGA Screen Driver 16 color 4 planes, higher speed MASM version
7 ;
8 ; Note: this file is a replacement for vgaplan4.c, when raw
9 ; speed rather than portability is desired
10 ;
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.
13 ;
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.
17 ;
18 PIXBYTES        = 80            ; number of bytes in scan line
19
20
21 MSC = 1
22 ;__MEDIUM__ = 1
23         include asm.h
24         .header
25
26         .cextrn gr_mode,word    ; temp kluge devdraw.c graphics draw mode
27         .dseg
28 mode_table:
29         db      00h,18h,10h,08h ; vga draw modes
30
31         .cseg
32
33 ;
34 ; int ega_init(PSD psd)
35 ;
36         .cproc  ega_init
37         mov     ax,1            ; success
38         ret
39         .cendp  ega_init
40
41 ;
42 ; Routine to draw a horizontal line.
43 ; Called from C:
44 ;       ega_drawhine(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 ; 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
56
57         .cproc  ega_drawhline
58         push    bp              ; setup stack frame and preserve registers
59         mov     bp, sp
60         push    si
61         push    di
62         push    es
63
64         ; configure the graphics controller
65
66         mov     dx, 03ceh       ; DX := Graphics Controller port address
67
68         mov     al, #3          ; set data rotate register
69         lea     bx, mode_table
70         add     bx, @gr_mode
71         mov     ah, [bx]
72         out     dx, ax
73
74         mov     ah, color[bp]   ; pixel value
75         xor     al, al          ; Set/Reset register number (0)
76         out     dx, ax
77
78         mov     ax, 0f01h       ; AH := bit plane mask for Enable Set/Reset
79         out     dx, ax          ; AL := Enable Set/Reset register number
80
81         push    ds              ; preserve DS
82
83         mov     ax, y[bp]
84         mov     bx, x1[bp]
85
86         ; compute pixel address
87         mov     dx, offset PIXBYTES     ; AX := [row * PIXBYTES]
88         mul     dx
89         mov     cl, bl          ; save low order column bits
90         shr     bx, 1           ; BX := [col / 8]
91         shr     bx, 1
92         shr     bx, 1
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
98         mov     es, dx
99                                 ; AH := bit mask
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
104
105         not     dh
106         shl     dh, cl          ; DH := reverse bit mask for first byte
107         not     dh              ; DH := bit mask for first byte
108
109         mov     cx, x2[bp]
110         and     cl, 7
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
114
115         ; determine byte offset of first and last pixel in the line
116
117         mov     ax, x2[bp]      ; AX := x2
118         mov     bx, x1[bp]      ; BX := x1
119
120         mov     cl, 3           ; bits to convert pixels to bytes
121
122         shr     ax, cl          ; AX := byte offset of X2
123         shr     bx, cl          ; BX := byte offset of X1
124         mov     cx, ax
125         sub     cx, bx          ; CX := [number of bytes in line] - 1
126
127         ; get Graphics Controller port address into DX
128
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
133
134         ; make video buffer addressable through DS:SI
135
136         push    es
137         pop     ds
138         mov     si, di          ; DS:SI -> video buffer
139
140         ; set pixels in leftmost byte of the line
141
142         or      bh, bh
143         js      L43             ; jump if byte-aligned [x1 is leftmost]
144
145         or      cx, cx
146         jnz     L42             ; jump if more than one byte in the line
147
148         and     bl, bh          ; BL := bit mask for the line
149         jmp short L44
150
151 L42:    mov     ah, bh          ; AH := bit mask for first byte
152         out     dx, ax          ; update graphics controller
153
154         movsb                   ; update bit planes
155         dec     cx
156
157         ; use a fast 8086 machine instruction to draw the remainder of the line
158
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
162
163         ; set pixels in the rightmost byte of the line
164
165 L44:    mov     ah, bl          ; AH := bit mask for last byte
166         out     dx, ax          ; update Graphics Controller
167         movsb                   ; update bit planes
168
169         pop     ds              ; restore ds
170
171
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
179
180         pop     es
181         pop     di
182         pop     si
183         pop     bp
184         ret
185         .cendp  ega_drawhline
186
187
188 ;
189 ; Routine to draw a vertical line.
190 ; Called from C:
191 ;       ega_drawvline(x, y1, y2, color);
192 ;
193 ;       works in the following EGA and VGA modes:
194 ;       200 line 16 colors modes
195 ;       350 line modes
196 ;       640x480 16 color
197
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
203
204         .cproc  ega_drawvline
205         push    bp              ; setup stack frame and preserve registers
206         mov     bp, sp
207         push    ds
208
209         ; configure the graphics controller
210
211         mov     dx, 03ceh       ; DX := Graphics Controller port address
212
213         mov     al, #3          ; set data rotate register
214         lea     bx, mode_table
215         add     bx, @gr_mode
216         mov     ah, [bx]
217         out     dx, ax
218
219         mov     ah, color[bp]   ; pixel value
220         xor     al, al          ; Set/Reset register number (0)
221         out     dx, ax
222
223         mov     ax, 0f01h       ; AH := bit plane mask for Enable Set/Reset
224         out     dx, ax          ; AL := Enable Set/Reset register number
225
226         ; prepare to draw vertical line
227
228         mov     ax, y1[bp]      ; AX := y1
229         mov     cx, y2[bp]      ; BX := y2
230         ;;mov   cx, bx
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
235
236 L311:   inc     cx              ; CX := number of pixels to draw
237         mov     bx, x[bp]       ; BX := x
238         push    cx              ; save register
239
240         ; compute pixel address
241         push    dx
242         mov     dx, offset PIXBYTES     ; AX := [row * PIXBYTES]
243         mul     dx
244         mov     cl, bl          ; save low order column bits
245         shr     bx, 1           ; BX := [col / 8]
246         shr     bx, 1
247         shr     bx, 1
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
253         mov     ds, dx
254         pop     dx
255                                 ; AH := bit mask
256                                 ; DS:BX -> video buffer
257                                 ; CL := number bits to shift left
258
259         ; set up Graphics controller
260
261         shl     ah, cl          ; AH := bit mask in proper position
262         mov     al, 08h         ; AL := Bit Mask register number
263         out     dx, ax
264
265         pop     cx              ; restore register
266
267         ; draw the line
268
269         mov     dx, offset PIXBYTES     ; increment for video buffer
270 L1111:  or      [bx], al        ; set pixel
271         add     bx, dx          ; increment to next line
272         loop    L1111
273
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
281
282         pop     ds
283         pop     bp
284         ret
285         .cendp  ega_drawvline
286
287
288 ;
289 ; Routine to set an individual pixel value.
290 ; Called from C like:
291 ;       ega_drawpixel(x, y, color);
292 ;
293
294 ; argument offsets from bp
295 x       = arg1          ; X coordinate
296 y       = arg1+2        ; Y coordinate
297 color   = arg1+4        ; pixel value
298
299         .cproc  ega_drawpixel
300         push    bp
301         mov     bp, sp
302
303         mov     dx, 03ceh       ; graphics controller port address
304         mov     al, #3          ; set data rotate register
305         lea     bx, mode_table
306         add     bx, @gr_mode
307         mov     ah, [bx]
308         out     dx, ax
309
310         mov     cx, x[bp]               ; ECX := x
311         mov     ax, y[bp]               ; EAX := y
312
313         mov     dx, offset PIXBYTES     ; AX := [y * PIXBYTES]
314         mul     dx
315
316         mov     bx, cx          ; BX := [x / 8]
317         shr     bx, 1
318         shr     bx, 1
319         shr     bx, 1
320
321         add     bx, ax          ; BX := [y * PIXBYTES] + [x / 8]
322
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]
326         shl     ch, cl
327
328         mov     dx, 03ceh       ; graphics controller port address
329
330         ;;required for old code
331         ;;mov   ax, 0205h       ; select write mode 2
332         ;;out   dx, ax          ; [load value 2 into mode register 5]
333
334         ; new code
335         xor     ax,ax           ; set color register 0
336         mov     ah,[bp+8]       ; color pixel value
337         out     dx,ax
338
339         ; original code
340         mov     al, 08h         ; set the bit mask register
341         mov     ah, ch          ; [load bit mask into register 8]
342         out     dx, ax
343
344         push    ds
345         mov     ax, 0a000h      ; DS := EGA buffer segment address
346         mov     ds, ax
347
348         ; new code
349         or      [bx],al         ; quick rmw to set pixel
350
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...
355         ;;cli
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
359         ;;sti
360
361         pop     ds              ; restore registers and return
362
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]
367
368         pop     bp
369         ret
370         .cendp  ega_drawpixel
371
372 ;
373 ; Routine to read the value of an individual pixel.
374 ; Called from C like:
375 ;       color = ega_readpixel(x, y);
376 ;
377
378 ; argument offsets from bp
379 x       = arg1                  ; X coordinate
380 y       = arg1+2                ; Y coordinate
381
382         .cproc  ega_readpixel
383         push    bp
384         mov     bp, sp
385         push    si
386         push    ds
387
388         mov     ax, y[bp]       ; EAX := y
389         mov     bx, x[bp]       ; EBX := x
390         mov     dx, offset PIXBYTES     ; AX := [y * PIXBYTES]
391         mul     dx
392
393         mov     cl, bl          ; save low order column bits
394         shr     bx, 1           ; BX := [x / 8]
395         shr     bx, 1
396         shr     bx, 1
397
398         add     bx, ax          ; BX := [y * PIXBYTES] + [x / 8]
399
400         and     cl, 07h         ; CL := [x % 8]
401         xor     cl, 07h         ; CL := 7 - [x % 8]
402
403         mov     dx, 0a000h      ; DS := EGA buffer segment address
404         mov     ds, dx
405
406         mov     ch, 01h         ; CH := 1 << [7 - [col % 8]]  [mask]
407         shl     ch, cl          ; CH := bit mask in proper position
408
409         mov     si, bx          ; DS:SI -> region buffer byte
410         xor     bl, bl          ; BL is used to accumulate the pixel value
411
412         mov     dx, 03ceh       ; DX := Graphics Controller port
413         mov     ax, 0304h       ; AH := initial bit plane number
414                                 ; AL := Read Map Select register number
415
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
423         jge     L112
424
425         xor     ax, ax          ; AL := pixel value
426         mov     al, bl
427
428         pop     ds
429         pop     si
430         pop     bp      
431         ret
432         .cendp  ega_readpixel
433
434         .cend
435         end