/[gxemul]/trunk/src/devices/dev_fb.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/devices/dev_fb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 29560 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

1 dpavlin 4 /*
2     * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 14 * $Id: dev_fb.c,v 1.107 2005/09/18 19:54:15 debug Exp $
29 dpavlin 4 *
30     * Generic framebuffer device.
31     *
32     * DECstation VFB01 monochrome framebuffer, 1024x864
33     * DECstation VFB02 8-bit color framebuffer, 1024x864
34     * DECstation Maxine, 1024x768 8-bit color
35     * HPCmips framebuffer
36     * Playstation 2 (24-bit color)
37     * generic (any resolution, several bit depths possible)
38     *
39     *
40     * TODO: There is still a bug when redrawing the cursor. The underlying
41     * image is moved 1 pixel (?), or something like that.
42     *
43     * TODO: This should actually be independant of X11, but that
44     * might be too hard to do right now.
45     *
46     * TODO: playstation 2 pixels are stored in another format, actually
47     */
48    
49     #include <stdio.h>
50     #include <stdlib.h>
51     #include <string.h>
52    
53     #include "console.h"
54     #include "cpu.h"
55     #include "devices.h"
56     #include "machine.h"
57     #include "memory.h"
58     #include "misc.h"
59     #include "x11.h"
60    
61     #ifdef WITH_X11
62     #include <X11/Xlib.h>
63     #include <X11/Xos.h>
64     #include <X11/Xutil.h>
65     #endif
66    
67    
68 dpavlin 12 #define FB_TICK_SHIFT 19
69 dpavlin 4
70    
71     /* #define FB_DEBUG */
72    
73     /*
74     * set_grayscale_palette():
75     *
76     * Fill d->rgb_palette with grayscale values. ncolors should
77     * be something like 2, 4, 16, or 256.
78     */
79     void set_grayscale_palette(struct vfb_data *d, int ncolors)
80     {
81     int i, gray;
82    
83     for (i=0; i<256; i++) {
84     gray = 255*i/(ncolors-1);
85     d->rgb_palette[i*3 + 0] = gray;
86     d->rgb_palette[i*3 + 1] = gray;
87     d->rgb_palette[i*3 + 2] = gray;
88     }
89     }
90    
91    
92     /*
93     * set_blackwhite_palette():
94     *
95     * Set color 0 = black, all others to white.
96     */
97     void set_blackwhite_palette(struct vfb_data *d, int ncolors)
98     {
99     int i, gray;
100    
101     for (i=0; i<256; i++) {
102     gray = i==0? 0 : 255;
103     d->rgb_palette[i*3 + 0] = gray;
104     d->rgb_palette[i*3 + 1] = gray;
105     d->rgb_palette[i*3 + 2] = gray;
106     }
107     }
108    
109    
110     /*
111 dpavlin 6 * dev_fb_resize():
112     *
113     * Resize a framebuffer window. (This functionality is probably a bit buggy,
114     * because I didn't think of including it from the start.)
115     */
116     void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
117     {
118     unsigned char *new_framebuffer;
119     int y, new_bytes_per_line;
120     size_t size;
121    
122     if (d == NULL) {
123     fatal("dev_fb_resize(): d == NULL\n");
124     return;
125     }
126    
127     new_bytes_per_line = new_xsize * d->bit_depth / 8;
128     size = new_ysize * new_bytes_per_line;
129    
130     new_framebuffer = malloc(size);
131     if (new_framebuffer == NULL) {
132     fprintf(stderr, "dev_fb_resize(): out of memory\n");
133     exit(1);
134     }
135    
136     /* Copy the old framebuffer to the new: */
137     if (d->framebuffer != NULL) {
138     for (y=0; y<new_ysize; y++) {
139     size_t fromofs = d->bytes_per_line * y;
140     size_t toofs = new_bytes_per_line * y;
141     size_t len_to_copy = d->bytes_per_line <
142     new_bytes_per_line? d->bytes_per_line
143     : new_bytes_per_line;
144     memset(new_framebuffer + toofs, 0, new_bytes_per_line);
145     if (y < d->x11_ysize)
146     memmove(new_framebuffer + toofs,
147     d->framebuffer + fromofs, len_to_copy);
148     }
149    
150     free(d->framebuffer);
151     }
152    
153     d->framebuffer = new_framebuffer;
154     d->framebuffer_size = size;
155    
156     if (new_xsize > d->x11_xsize || new_ysize > d->x11_ysize) {
157     d->update_x1 = d->update_y1 = 0;
158     d->update_x2 = new_xsize - 1;
159     d->update_y2 = new_ysize - 1;
160     }
161    
162     d->bytes_per_line = new_bytes_per_line;
163     d->x11_xsize = d->visible_xsize = new_xsize;
164     d->x11_ysize = d->visible_ysize = new_ysize;
165    
166     #ifdef WITH_X11
167     if (d->fb_window != NULL)
168     x11_fb_resize(d->fb_window, new_xsize, new_ysize);
169     #endif
170     }
171    
172    
173     /*
174 dpavlin 4 * dev_fb_setcursor():
175     */
176     void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
177     int cursor_xsize, int cursor_ysize)
178     {
179     if (cursor_x < 0)
180     cursor_x = 0;
181     if (cursor_y < 0)
182     cursor_y = 0;
183     if (cursor_x + cursor_xsize >= d->xsize)
184     cursor_x = d->xsize - cursor_xsize;
185     if (cursor_y + cursor_ysize >= d->ysize)
186     cursor_y = d->ysize - cursor_ysize;
187    
188     #ifdef WITH_X11
189     if (d->fb_window != NULL) {
190     d->fb_window->cursor_x = cursor_x;
191     d->fb_window->cursor_y = cursor_y;
192     d->fb_window->cursor_on = on;
193     d->fb_window->cursor_xsize = cursor_xsize;
194     d->fb_window->cursor_ysize = cursor_ysize;
195     }
196     #endif
197    
198     if (d->fb_window != NULL)
199     console_set_framebuffer_mouse(cursor_x, cursor_y,
200     d->fb_window->fb_number);
201    
202     /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
203     cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
204     }
205    
206    
207     /*
208     * framebuffer_blockcopyfill():
209     *
210     * This function should be used by devices that are capable of doing
211     * block copy/fill.
212     *
213     * If fillflag is non-zero, then fill_[rgb] should contain the color
214     * with which to fill.
215     *
216     * If fillflag is zero, copy mode is used, and from_[xy] should contain
217     * the offset on the framebuffer where we should copy from.
218     *
219     * NOTE: Overlapping copies are undefined!
220     */
221     void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
222     int fill_g, int fill_b, int x1, int y1, int x2, int y2,
223     int from_x, int from_y)
224     {
225     int y;
226     long from_ofs, dest_ofs, linelen;
227    
228     if (fillflag)
229     debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
230     "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
231     else
232     debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
233     "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
234    
235     /* Clip x: */
236     if (x1 < 0) x1 = 0;
237     if (x1 >= d->xsize) x1 = d->xsize-1;
238     if (x2 < 0) x2 = 0;
239     if (x2 >= d->xsize) x2 = d->xsize-1;
240    
241     dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
242     linelen = (x2-x1 + 1) * (d->bit_depth/8);
243     /* NOTE: linelen is nr of bytes, not pixels */
244    
245     if (fillflag) {
246     for (y=y1; y<=y2; y++) {
247     if (y>=0 && y<d->ysize) {
248     int x;
249     char buf[8192 * 3];
250     if (d->bit_depth == 24)
251     for (x=0; x<linelen; x+=3) {
252     buf[x] = fill_r;
253     buf[x+1] = fill_g;
254     buf[x+2] = fill_b;
255     }
256     else
257     printf("TODO: fill for non-24-bit"
258     " modes\n");
259    
260     memmove(d->framebuffer + dest_ofs, buf,
261     linelen);
262     }
263    
264     dest_ofs += d->bytes_per_line;
265     }
266     } else {
267     from_ofs = d->bytes_per_line * from_y +
268     (d->bit_depth/8) * from_x;
269    
270     for (y=y1; y<=y2; y++) {
271     if (y>=0 && y<d->ysize)
272     memmove(d->framebuffer + dest_ofs,
273     d->framebuffer + from_ofs, linelen);
274    
275     from_ofs += d->bytes_per_line;
276     dest_ofs += d->bytes_per_line;
277     }
278     }
279    
280     if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
281     if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
282     if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
283     if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
284    
285     if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
286     if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
287     if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
288     if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
289     }
290    
291    
292     #ifdef WITH_X11
293     #define macro_put_pixel() { \
294 dpavlin 14 /* Combine the color into an X11 long and display it: */ \
295     /* TODO: construct color in a more portable way: */ \
296     switch (d->fb_window->x11_screen_depth) { \
297     case 24: \
298     if (d->fb_window->fb_ximage->byte_order) \
299     color = (b << 16) + (g << 8) + r; \
300     else \
301     color = (r << 16) + (g << 8) + b; \
302     break; \
303     case 16: \
304     r >>= 3; g >>= 2; b >>= 3; \
305     if (d->fb_window->fb_ximage->byte_order) { \
306     /* Big endian 16-bit X server: */ \
307     static int first = 1; \
308     if (first) { \
309     fprintf(stderr, "\n*** Please report " \
310     "to the author whether 16-bit X11 " \
311     "colors are rendered correctly or " \
312     "not!\n\n"); \
313     first = 0; \
314     } \
315     color = (b << 11) + (g << 5) + r; \
316     } else { \
317     /* Little endian (eg PC) X servers: */ \
318     color = (r << 11) + (g << 5) + b; \
319     } \
320     break; \
321     case 15: \
322     r >>= 3; g >>= 3; b >>= 3; \
323     if (d->fb_window->fb_ximage->byte_order) { \
324     /* Big endian 15-bit X server: */ \
325     static int first = 1; \
326     if (first) { \
327     fprintf(stderr, "\n*** Please report " \
328     "to the author whether 15-bit X11 " \
329     "colors are rendered correctly or " \
330     "not!\n\n"); \
331     first = 0; \
332     } \
333     color = (b << 10) + (g << 5) + r; \
334     } else { \
335     /* Little endian (eg PC) X servers: */ \
336     color = (r << 10) + (g << 5) + b; \
337     } \
338     break; \
339     default: \
340     color = d->fb_window->x11_graycolor[15 * (r + g + b) \
341     / (255 * 3)].pixel; \
342     } \
343     if (x>=0 && x<d->x11_xsize && y>=0 && y<d->x11_ysize) \
344     XPutPixel(d->fb_window->fb_ximage, x, y, color); \
345     }
346 dpavlin 4 #else
347     /* If not WITH_X11: */
348     #define macro_put_pixel() { }
349     #endif
350    
351    
352     /*
353     * update_framebuffer():
354     *
355     * The framebuffer memory has been updated. This function tries to make
356     * sure that the XImage is also updated (1 or more pixels).
357     */
358     void update_framebuffer(struct vfb_data *d, int addr, int len)
359     {
360     int x, y, pixel, npixels;
361     long color_r, color_g, color_b;
362     #ifdef WITH_X11
363     long color;
364     #endif
365     int scaledown = d->vfb_scaledown;
366     int scaledownXscaledown = 1;
367    
368     if (scaledown == 1) {
369     /* Which framebuffer pixel does addr correspond to? */
370     pixel = addr * 8 / d->bit_depth;
371     y = pixel / d->xsize;
372     x = pixel % d->xsize;
373    
374     /* How many framebuffer pixels? */
375     npixels = len * 8 / d->bit_depth;
376     if (npixels == 0)
377     npixels = 1;
378    
379     if (d->bit_depth < 8) {
380     for (pixel=0; pixel<npixels; pixel++) {
381     int fb_addr, c, r, g, b;
382     color_r = color_g = color_b = 0;
383    
384     fb_addr = (y * d->xsize + x) * d->bit_depth;
385     /* fb_addr is now which _bit_ in
386     the framebuffer */
387    
388     c = d->framebuffer[fb_addr >> 3];
389     fb_addr &= 7;
390    
391     /* HPCmips is reverse: */
392     if (d->vfb_type == VFB_HPCMIPS)
393     fb_addr = 8 - d->bit_depth - fb_addr;
394    
395     c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
396     /* c <<= (8 - d->bit_depth); */
397    
398     r = d->rgb_palette[c*3 + 0];
399     g = d->rgb_palette[c*3 + 1];
400     b = d->rgb_palette[c*3 + 2];
401    
402     macro_put_pixel();
403     x++;
404     }
405     } else if (d->bit_depth == 8) {
406     for (pixel=0; pixel<npixels; pixel++) {
407     int fb_addr, c, r, g, b;
408     color_r = color_g = color_b = 0;
409    
410     fb_addr = y * d->xsize + x;
411     /* fb_addr is now which byte in framebuffer */
412     c = d->framebuffer[fb_addr];
413     r = d->rgb_palette[c*3 + 0];
414     g = d->rgb_palette[c*3 + 1];
415     b = d->rgb_palette[c*3 + 2];
416    
417     macro_put_pixel();
418     x++;
419     }
420     } else { /* d->bit_depth > 8 */
421     for (pixel=0; pixel<npixels; pixel++) {
422     int fb_addr, r, g, b;
423     color_r = color_g = color_b = 0;
424    
425     fb_addr = (y * d->xsize + x) * d->bit_depth;
426     /* fb_addr is now which byte in framebuffer */
427    
428     /* > 8 bits color. */
429     fb_addr >>= 3;
430     switch (d->bit_depth) {
431     case 24:
432     r = d->framebuffer[fb_addr];
433     g = d->framebuffer[fb_addr + 1];
434     b = d->framebuffer[fb_addr + 2];
435     break;
436     /* TODO: copy to the scaledown code below */
437     case 16:
438     if (d->vfb_type == VFB_HPCMIPS) {
439     b = d->framebuffer[fb_addr] +
440 dpavlin 14 (d->framebuffer[fb_addr+1]
441     << 8);
442 dpavlin 4
443     if (d->color32k) {
444     r = b >> 11;
445     g = b >> 5;
446     r = r & 31;
447     g = (g & 31) * 2;
448     b = b & 31;
449 dpavlin 10 } else if (d->psp_15bit) {
450     int tmp;
451     r = (b >> 10) & 0x1f;
452     g = (b >> 5) & 0x1f;
453     b = b & 0x1f;
454     g <<= 1;
455     tmp = r; r = b; b = tmp;
456 dpavlin 4 } else {
457     r = (b >> 11) & 0x1f;
458     g = (b >> 5) & 0x3f;
459     b = b & 0x1f;
460     }
461     } else {
462 dpavlin 14 r = d->framebuffer[fb_addr] >> 3;
463     g = (d->framebuffer[fb_addr] << 5) +
464     (d->framebuffer[fb_addr + 1] >>5);
465     b = d->framebuffer[fb_addr + 1]&31;
466 dpavlin 4 }
467    
468     r *= 8;
469     g *= 4;
470     b *= 8;
471     break;
472     default:
473     r = g = b = random() & 255;
474     }
475    
476     macro_put_pixel();
477     x++;
478     }
479     }
480    
481     return;
482     }
483    
484 dpavlin 12 /* scaledown > 1: */
485 dpavlin 4
486     scaledown = d->vfb_scaledown;
487     scaledownXscaledown = scaledown * scaledown;
488    
489     /* Which framebuffer pixel does addr correspond to? */
490     pixel = addr * 8 / d->bit_depth;
491     y = pixel / d->xsize;
492     x = pixel % d->xsize;
493    
494     /* How many framebuffer pixels? */
495     npixels = len * 8 / d->bit_depth;
496    
497     /* Which x11 pixel? */
498     x /= scaledown;
499     y /= scaledown;
500    
501     /* How many x11 pixels: */
502     npixels /= scaledown;
503     if (npixels == 0)
504     npixels = 1;
505    
506     if (d->bit_depth < 8) {
507     for (pixel=0; pixel<npixels; pixel++) {
508     int subx, suby, r, g, b;
509     color_r = color_g = color_b = 0;
510     for (suby=0; suby<scaledown; suby++)
511     for (subx=0; subx<scaledown; subx++) {
512     int fb_x, fb_y, fb_addr, c;
513    
514     fb_x = x * scaledown + subx;
515     fb_y = y * scaledown + suby;
516     fb_addr = fb_y * d->xsize + fb_x;
517     fb_addr = fb_addr * d->bit_depth;
518     /* fb_addr is now which _bit_ in
519     the framebuffer */
520    
521     c = d->framebuffer[fb_addr >> 3];
522     fb_addr &= 7;
523    
524     /* HPCmips is reverse: */
525     if (d->vfb_type == VFB_HPCMIPS)
526     fb_addr = 8 - d->bit_depth - fb_addr;
527    
528     c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
529     /* c <<= (8 - d->bit_depth); */
530    
531     r = d->rgb_palette[c*3 + 0];
532     g = d->rgb_palette[c*3 + 1];
533     b = d->rgb_palette[c*3 + 2];
534    
535     color_r += r;
536     color_g += g;
537     color_b += b;
538     }
539    
540     r = color_r / scaledownXscaledown;
541     g = color_g / scaledownXscaledown;
542     b = color_b / scaledownXscaledown;
543     macro_put_pixel();
544     x++;
545     }
546     } else if (d->bit_depth == 8) {
547     for (pixel=0; pixel<npixels; pixel++) {
548     int subx, suby, r, g, b;
549     color_r = color_g = color_b = 0;
550     for (suby=0; suby<scaledown; suby++)
551     for (subx=0; subx<scaledown; subx++) {
552     int fb_x, fb_y, fb_addr, c;
553    
554     fb_x = x * scaledown + subx;
555     fb_y = y * scaledown + suby;
556     fb_addr = fb_y * d->xsize + fb_x;
557     /* fb_addr is which _byte_ in framebuffer */
558     c = d->framebuffer[fb_addr] * 3;
559     r = d->rgb_palette[c + 0];
560     g = d->rgb_palette[c + 1];
561     b = d->rgb_palette[c + 2];
562     color_r += r;
563     color_g += g;
564     color_b += b;
565     }
566    
567     r = color_r / scaledownXscaledown;
568     g = color_g / scaledownXscaledown;
569     b = color_b / scaledownXscaledown;
570     macro_put_pixel();
571     x++;
572     }
573     } else {
574     /* Generic > 8 bit bit-depth: */
575     for (pixel=0; pixel<npixels; pixel++) {
576     int subx, suby, r, g, b;
577     color_r = color_g = color_b = 0;
578     for (suby=0; suby<scaledown; suby++)
579     for (subx=0; subx<scaledown; subx++) {
580     int fb_x, fb_y, fb_addr;
581    
582     fb_x = x * scaledown + subx;
583     fb_y = y * scaledown + suby;
584     fb_addr = fb_y * d->xsize + fb_x;
585     fb_addr = (fb_addr * d->bit_depth) >> 3;
586     /* fb_addr is which _byte_ in framebuffer */
587    
588     /* > 8 bits color. */
589     switch (d->bit_depth) {
590     case 24:
591     r = d->framebuffer[fb_addr];
592     g = d->framebuffer[fb_addr + 1];
593     b = d->framebuffer[fb_addr + 2];
594     break;
595     default:
596     r = g = b = random() & 255;
597     }
598     color_r += r;
599     color_g += g;
600     color_b += b;
601     }
602     r = color_r / scaledownXscaledown;
603     g = color_g / scaledownXscaledown;
604     b = color_b / scaledownXscaledown;
605     macro_put_pixel();
606     x++;
607     }
608     }
609     }
610    
611    
612     /*
613     * dev_fb_tick():
614     *
615     */
616     void dev_fb_tick(struct cpu *cpu, void *extra)
617     {
618     struct vfb_data *d = extra;
619     #ifdef WITH_X11
620     int need_to_flush_x11 = 0;
621     int need_to_redraw_cursor = 0;
622     #endif
623    
624     if (!cpu->machine->use_x11)
625     return;
626    
627     do {
628 dpavlin 12 uint64_t high, low = (uint64_t)(int64_t) -1;
629 dpavlin 4 int x, y;
630    
631 dpavlin 12 memory_device_dyntrans_access(cpu, cpu->mem,
632 dpavlin 4 extra, &low, &high);
633     if ((int64_t)low == -1)
634     break;
635    
636     /* printf("low=%016llx high=%016llx\n",
637     (long long)low, (long long)high); */
638    
639     x = (low % d->bytes_per_line) * 8 / d->bit_depth;
640     y = low / d->bytes_per_line;
641     if (x < d->update_x1 || d->update_x1 == -1)
642     d->update_x1 = x;
643     if (x > d->update_x2 || d->update_x2 == -1)
644     d->update_x2 = x;
645     if (y < d->update_y1 || d->update_y1 == -1)
646     d->update_y1 = y;
647     if (y > d->update_y2 || d->update_y2 == -1)
648     d->update_y2 = y;
649    
650     x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
651     y = (low+7) / d->bytes_per_line;
652     if (x < d->update_x1 || d->update_x1 == -1)
653     d->update_x1 = x;
654     if (x > d->update_x2 || d->update_x2 == -1)
655     d->update_x2 = x;
656     if (y < d->update_y1 || d->update_y1 == -1)
657     d->update_y1 = y;
658     if (y > d->update_y2 || d->update_y2 == -1)
659     d->update_y2 = y;
660    
661     x = (high % d->bytes_per_line) * 8 / d->bit_depth;
662     y = high / d->bytes_per_line;
663     if (x < d->update_x1 || d->update_x1 == -1)
664     d->update_x1 = x;
665     if (x > d->update_x2 || d->update_x2 == -1)
666     d->update_x2 = x;
667     if (y < d->update_y1 || d->update_y1 == -1)
668     d->update_y1 = y;
669     if (y > d->update_y2 || d->update_y2 == -1)
670     d->update_y2 = y;
671    
672     x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
673     y = (high+7) / d->bytes_per_line;
674     if (x < d->update_x1 || d->update_x1 == -1)
675     d->update_x1 = x;
676     if (x > d->update_x2 || d->update_x2 == -1)
677     d->update_x2 = x;
678     if (y < d->update_y1 || d->update_y1 == -1)
679     d->update_y1 = y;
680     if (y > d->update_y2 || d->update_y2 == -1)
681     d->update_y2 = y;
682    
683     /*
684     * An update covering more than one line will automatically
685     * force an update of all the affected lines:
686     */
687     if (d->update_y1 != d->update_y2) {
688     d->update_x1 = 0;
689     d->update_x2 = d->xsize-1;
690     }
691     } while (0);
692    
693     #ifdef WITH_X11
694     /* Do we need to redraw the cursor? */
695     if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
696     d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
697     d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
698     d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
699     d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
700     need_to_redraw_cursor = 1;
701    
702     if (d->update_x2 != -1) {
703 dpavlin 14 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
704     d->update_x1 < (d->fb_window->OLD_cursor_x +
705     d->fb_window->OLD_cursor_xsize)) ||
706 dpavlin 4 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
707 dpavlin 14 d->update_x2 < (d->fb_window->OLD_cursor_x +
708     d->fb_window->OLD_cursor_xsize)) ||
709 dpavlin 4 (d->update_x1 < d->fb_window->OLD_cursor_x &&
710 dpavlin 14 d->update_x2 >= (d->fb_window->OLD_cursor_x +
711     d->fb_window->OLD_cursor_xsize)) ) &&
712     ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
713     d->update_y1 < (d->fb_window->OLD_cursor_y +
714     d->fb_window->OLD_cursor_ysize)) ||
715     (d->update_y2 >= d->fb_window->OLD_cursor_y &&
716     d->update_y2 < (d->fb_window->OLD_cursor_y +
717     d->fb_window->OLD_cursor_ysize)) ||
718     (d->update_y1 < d->fb_window->OLD_cursor_y &&
719     d->update_y2 >= (d->fb_window->OLD_cursor_y +
720     d->fb_window->OLD_cursor_ysize)) ) )
721     need_to_redraw_cursor = 1;
722 dpavlin 4 }
723    
724     if (need_to_redraw_cursor) {
725     /* Remove old cursor, if any: */
726     if (d->fb_window->OLD_cursor_on) {
727     XPutImage(d->fb_window->x11_display,
728     d->fb_window->x11_fb_window,
729     d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
730     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
731     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
732     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
733     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
734     d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
735 dpavlin 14 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
736 dpavlin 4 }
737     }
738     #endif
739    
740     if (d->update_x2 != -1) {
741     int y, addr, addr2, q = d->vfb_scaledown;
742    
743 dpavlin 14 if (d->update_x1 >= d->visible_xsize)
744     d->update_x1 = d->visible_xsize - 1;
745     if (d->update_x2 >= d->visible_xsize)
746     d->update_x2 = d->visible_xsize - 1;
747     if (d->update_y1 >= d->visible_ysize)
748     d->update_y1 = d->visible_ysize - 1;
749     if (d->update_y2 >= d->visible_ysize)
750     d->update_y2 = d->visible_ysize - 1;
751 dpavlin 4
752 dpavlin 14 /* Without these, we might miss the rightmost/bottom pixel: */
753 dpavlin 4 d->update_x2 += (q - 1);
754     d->update_y2 += (q - 1);
755    
756     d->update_x1 = d->update_x1 / q * q;
757     d->update_x2 = d->update_x2 / q * q;
758     d->update_y1 = d->update_y1 / q * q;
759     d->update_y2 = d->update_y2 / q * q;
760    
761 dpavlin 14 addr = d->update_y1 * d->bytes_per_line +
762     d->update_x1 * d->bit_depth / 8;
763     addr2 = d->update_y1 * d->bytes_per_line +
764     d->update_x2 * d->bit_depth / 8;
765 dpavlin 4
766     for (y=d->update_y1; y<=d->update_y2; y+=q) {
767     update_framebuffer(d, addr, addr2 - addr);
768     addr += d->bytes_per_line * q;
769     addr2 += d->bytes_per_line * q;
770     }
771    
772     #ifdef WITH_X11
773 dpavlin 14 XPutImage(d->fb_window->x11_display, d->fb_window->
774     x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
775     fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
776     d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
777     d->update_y1/d->vfb_scaledown,
778 dpavlin 4 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
779     (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
780    
781     need_to_flush_x11 = 1;
782     #endif
783    
784     d->update_x1 = d->update_y1 = 99999;
785     d->update_x2 = d->update_y2 = -1;
786     }
787    
788     #ifdef WITH_X11
789     if (need_to_redraw_cursor) {
790     /* Paint new cursor: */
791     if (d->fb_window->cursor_on) {
792 dpavlin 14 x11_redraw_cursor(cpu->machine,
793     d->fb_window->fb_number);
794 dpavlin 4 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
795     d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
796     d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
797 dpavlin 14 d->fb_window->OLD_cursor_xsize = d->fb_window->
798     cursor_xsize;
799     d->fb_window->OLD_cursor_ysize = d->fb_window->
800     cursor_ysize;
801 dpavlin 4 }
802     }
803     #endif
804    
805     #ifdef WITH_X11
806     if (need_to_flush_x11)
807     XFlush(d->fb_window->x11_display);
808     #endif
809     }
810    
811    
812     /*
813     * dev_fb_access():
814     */
815     int dev_fb_access(struct cpu *cpu, struct memory *mem,
816     uint64_t relative_addr, unsigned char *data, size_t len,
817     int writeflag, void *extra)
818     {
819     struct vfb_data *d = extra;
820     int i;
821    
822     #ifdef FB_DEBUG
823     if (writeflag == MEM_WRITE) { if (data[0]) {
824     fatal("[ dev_fb: write to addr=%08lx, data = ",
825     (long)relative_addr);
826     for (i=0; i<len; i++)
827     fatal("%02x ", data[i]);
828     fatal("]\n");
829     } else {
830     fatal("[ dev_fb: read from addr=%08lx, data = ",
831     (long)relative_addr);
832     for (i=0; i<len; i++)
833     fatal("%02x ", d->framebuffer[relative_addr + i]);
834     fatal("]\n");
835     }
836     #endif
837    
838 dpavlin 6 if (relative_addr >= d->framebuffer_size)
839     return 0;
840    
841 dpavlin 4 /* See if a write actually modifies the framebuffer contents: */
842     if (writeflag == MEM_WRITE) {
843     for (i=0; i<len; i++) {
844     if (data[i] != d->framebuffer[relative_addr + i])
845     break;
846    
847     /* If all bytes are equal to what is already stored
848     in the framebuffer, then simply return: */
849     if (i==len-1)
850     return 1;
851     }
852     }
853    
854     /*
855     * If the framebuffer is modified, then we should keep a track
856     * of which area(s) we modify, so that the display isn't updated
857     * unnecessarily.
858     */
859     if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
860     int x, y, x2,y2;
861    
862     x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
863     y = relative_addr / d->bytes_per_line;
864     x2 = ((relative_addr + len) % d->bytes_per_line)
865     * 8 / d->bit_depth;
866     y2 = (relative_addr + len) / d->bytes_per_line;
867    
868     if (x < d->update_x1 || d->update_x1 == -1)
869     d->update_x1 = x;
870     if (x > d->update_x2 || d->update_x2 == -1)
871     d->update_x2 = x;
872    
873     if (y < d->update_y1 || d->update_y1 == -1)
874     d->update_y1 = y;
875     if (y > d->update_y2 || d->update_y2 == -1)
876     d->update_y2 = y;
877    
878     if (x2 < d->update_x1 || d->update_x1 == -1)
879     d->update_x1 = x2;
880     if (x2 > d->update_x2 || d->update_x2 == -1)
881     d->update_x2 = x2;
882    
883     if (y2 < d->update_y1 || d->update_y1 == -1)
884     d->update_y1 = y2;
885     if (y2 > d->update_y2 || d->update_y2 == -1)
886     d->update_y2 = y2;
887    
888     /*
889     * An update covering more than one line will automatically
890     * force an update of all the affected lines:
891     */
892     if (y != y2) {
893     d->update_x1 = 0;
894     d->update_x2 = d->xsize-1;
895     }
896     }
897    
898     /*
899     * Read from/write to the framebuffer:
900     * (TODO: take the color_plane_mask into account)
901     *
902     * Calling memcpy() is probably overkill, as it usually is just one
903     * or a few bytes that are read/written at a time.
904     */
905     if (writeflag == MEM_WRITE) {
906     if (len > 8)
907     memcpy(d->framebuffer + relative_addr, data, len);
908     else
909     for (i=0; i<len; i++)
910     d->framebuffer[relative_addr + i] = data[i];
911     } else {
912     if (len > 8)
913     memcpy(data, d->framebuffer + relative_addr, len);
914     else
915     for (i=0; i<len; i++)
916     data[i] = d->framebuffer[relative_addr + i];
917     }
918    
919     return 1;
920     }
921    
922    
923     /*
924     * dev_fb_init():
925     *
926 dpavlin 10 * This function is big and ugly, but the point is to initialize a framebuffer
927     * device. :-)
928     *
929     * visible_xsize and visible_ysize are the sizes of the visible display area.
930     * xsize and ysize tell how much memory is actually allocated (for example
931     * visible_xsize could be 640, but xsize could be 1024, for better alignment).
932     *
933     * vfb_type is useful for selecting special features.
934     *
935     * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
936     *
937     * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
938     *
939     * If type is VFB_HPCMIPS, then color encoding differs from the generic case.
940     *
941     * If bit_depth = -15 (note the minus sign), then a special hack is used for
942     * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
943 dpavlin 4 */
944     struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
945     uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
946 dpavlin 12 int xsize, int ysize, int bit_depth, char *name)
947 dpavlin 4 {
948     struct vfb_data *d;
949 dpavlin 10 size_t size, nlen;
950 dpavlin 12 int flags;
951 dpavlin 4 char title[400];
952     char *name2;
953    
954     d = malloc(sizeof(struct vfb_data));
955     if (d == NULL) {
956     fprintf(stderr, "out of memory\n");
957     exit(1);
958     }
959     memset(d, 0, sizeof(struct vfb_data));
960    
961     d->vfb_type = vfb_type;
962    
963     /* Defaults: */
964     d->xsize = xsize; d->visible_xsize = visible_xsize;
965     d->ysize = ysize; d->visible_ysize = visible_ysize;
966    
967     d->bit_depth = bit_depth;
968    
969     if (bit_depth == 15) {
970     d->color32k = 1;
971     bit_depth = d->bit_depth = 16;
972 dpavlin 10 } else if (bit_depth == -15) {
973     d->psp_15bit = 1;
974     bit_depth = d->bit_depth = 16;
975 dpavlin 4 }
976    
977     /* Specific types: */
978     switch (vfb_type) {
979     case VFB_DEC_VFB01:
980     /* DECstation VFB01 (monochrome) */
981     d->xsize = 2048; d->visible_xsize = 1024;
982     d->ysize = 1024; d->visible_ysize = 864;
983     d->bit_depth = 1;
984     break;
985     case VFB_DEC_VFB02:
986     /* DECstation VFB02 (color) */
987     d->xsize = 1024; d->visible_xsize = 1024;
988     d->ysize = 1024; d->visible_ysize = 864;
989     d->bit_depth = 8;
990     break;
991     case VFB_DEC_MAXINE:
992     /* DECstation Maxine (1024x768x8) */
993     d->xsize = 1024; d->visible_xsize = d->xsize;
994     d->ysize = 768; d->visible_ysize = d->ysize;
995     d->bit_depth = 8;
996     break;
997     case VFB_PLAYSTATION2:
998     /* Playstation 2 */
999     d->xsize = xsize; d->visible_xsize = d->xsize;
1000     d->ysize = ysize; d->visible_ysize = d->ysize;
1001     d->bit_depth = 24;
1002     break;
1003     default:
1004     ;
1005     }
1006    
1007     if (d->bit_depth == 2 || d->bit_depth == 4)
1008     set_grayscale_palette(d, 1 << d->bit_depth);
1009     else if (d->bit_depth == 8 || d->bit_depth == 1)
1010     set_blackwhite_palette(d, 1 << d->bit_depth);
1011    
1012     d->vfb_scaledown = machine->x11_scaledown;
1013    
1014     d->bytes_per_line = d->xsize * d->bit_depth / 8;
1015     size = d->ysize * d->bytes_per_line;
1016    
1017     d->framebuffer = malloc(size);
1018     if (d->framebuffer == NULL) {
1019     fprintf(stderr, "out of memory\n");
1020     exit(1);
1021     }
1022    
1023     /* Clear the framebuffer (all black pixels): */
1024     d->framebuffer_size = size;
1025     memset(d->framebuffer, 0, size);
1026    
1027     d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
1028     d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
1029    
1030     d->update_x1 = d->update_y1 = 99999;
1031     d->update_x2 = d->update_y2 = -1;
1032    
1033    
1034 dpavlin 6 /* Don't set the title to include the size of the framebuffer for
1035     VGA, since then the resolution might change during runtime. */
1036     if (strcmp(name, "VGA") == 0)
1037     snprintf(title, sizeof(title),"GXemul: %s framebuffer", name);
1038     else
1039     snprintf(title, sizeof(title),"GXemul: %ix%ix%i %s framebuffer",
1040     d->visible_xsize, d->visible_ysize, d->bit_depth, name);
1041 dpavlin 4 title[sizeof(title)-1] = '\0';
1042    
1043     #ifdef WITH_X11
1044     if (machine->use_x11)
1045     d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
1046     title, machine->x11_scaledown, machine);
1047     else
1048     #endif
1049     d->fb_window = NULL;
1050    
1051 dpavlin 10 nlen = strlen(name) + 10;
1052     name2 = malloc(nlen);
1053 dpavlin 4 if (name2 == NULL) {
1054     fprintf(stderr, "out of memory in dev_fb_init()\n");
1055     exit(1);
1056     }
1057 dpavlin 10 snprintf(name2, nlen, "fb [%s]", name);
1058 dpavlin 4
1059     flags = MEM_DEFAULT;
1060     if ((baseaddr & 0xfff) == 0)
1061 dpavlin 12 flags = MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK;
1062 dpavlin 4
1063 dpavlin 6 flags |= MEM_READING_HAS_NO_SIDE_EFFECTS;
1064    
1065 dpavlin 4 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
1066     d, flags, d->framebuffer);
1067    
1068     machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
1069     return d;
1070     }
1071    

  ViewVC Help
Powered by ViewVC 1.1.26