/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (11 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 23846 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 dpavlin 4 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 42 * $Id: dev_fb.c,v 1.132 2007/06/15 19:11:15 debug Exp $
29 dpavlin 4 *
30 dpavlin 42 * COMMENT: Generic framebuffer device
31 dpavlin 4 *
32     * DECstation VFB01 monochrome framebuffer, 1024x864
33     * DECstation VFB02 8-bit color framebuffer, 1024x864
34     * DECstation Maxine, 1024x768 8-bit color
35     * Playstation 2 (24-bit color)
36 dpavlin 28 * Generic (any resolution, several bit depths possible, useful for
37     * testmachines)
38 dpavlin 4 *
39     *
40 dpavlin 22 * TODO: This should actually be independent of X11, but that
41 dpavlin 4 * might be too hard to do right now.
42     *
43     * TODO: playstation 2 pixels are stored in another format, actually
44     */
45    
46     #include <stdio.h>
47     #include <stdlib.h>
48     #include <string.h>
49    
50     #include "console.h"
51     #include "cpu.h"
52     #include "devices.h"
53     #include "machine.h"
54     #include "memory.h"
55     #include "misc.h"
56     #include "x11.h"
57    
58     #ifdef WITH_X11
59     #include <X11/Xlib.h>
60     #include <X11/Xos.h>
61     #include <X11/Xutil.h>
62     #endif
63    
64    
65 dpavlin 28 #define FB_TICK_SHIFT 19
66 dpavlin 4
67    
68     /* #define FB_DEBUG */
69    
70     /*
71     * set_grayscale_palette():
72     *
73     * Fill d->rgb_palette with grayscale values. ncolors should
74     * be something like 2, 4, 16, or 256.
75     */
76     void set_grayscale_palette(struct vfb_data *d, int ncolors)
77     {
78     int i, gray;
79    
80     for (i=0; i<256; i++) {
81     gray = 255*i/(ncolors-1);
82     d->rgb_palette[i*3 + 0] = gray;
83     d->rgb_palette[i*3 + 1] = gray;
84     d->rgb_palette[i*3 + 2] = gray;
85     }
86     }
87    
88    
89     /*
90     * set_blackwhite_palette():
91     *
92     * Set color 0 = black, all others to white.
93     */
94     void set_blackwhite_palette(struct vfb_data *d, int ncolors)
95     {
96     int i, gray;
97    
98     for (i=0; i<256; i++) {
99     gray = i==0? 0 : 255;
100     d->rgb_palette[i*3 + 0] = gray;
101     d->rgb_palette[i*3 + 1] = gray;
102     d->rgb_palette[i*3 + 2] = gray;
103     }
104     }
105    
106    
107 dpavlin 28 static void set_title(struct vfb_data *d)
108     {
109     snprintf(d->title, sizeof(d->title),"GXemul: %ix%ix%i %s framebuffer",
110     d->visible_xsize, d->visible_ysize, d->bit_depth, d->name);
111     d->title[sizeof(d->title)-1] = '\0';
112     }
113    
114    
115 dpavlin 4 /*
116 dpavlin 6 * dev_fb_resize():
117     *
118     * Resize a framebuffer window. (This functionality is probably a bit buggy,
119     * because I didn't think of including it from the start.)
120 dpavlin 28 *
121     * SUPER-IMPORTANT: Anyone who resizes a framebuffer by calling this function
122     * must also clear all dyntrans address translations manually, in all cpus
123     * which might have access to the framebuffer!
124 dpavlin 6 */
125     void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
126     {
127     unsigned char *new_framebuffer;
128     int y, new_bytes_per_line;
129     size_t size;
130    
131     if (d == NULL) {
132     fatal("dev_fb_resize(): d == NULL\n");
133     return;
134     }
135    
136 dpavlin 28 if (new_xsize < 10 || new_ysize < 10) {
137     fatal("dev_fb_resize(): size too small.\n");
138     exit(1);
139     }
140    
141 dpavlin 6 new_bytes_per_line = new_xsize * d->bit_depth / 8;
142     size = new_ysize * new_bytes_per_line;
143    
144 dpavlin 42 CHECK_ALLOCATION(new_framebuffer = malloc(size));
145 dpavlin 6
146     /* Copy the old framebuffer to the new: */
147     if (d->framebuffer != NULL) {
148     for (y=0; y<new_ysize; y++) {
149     size_t fromofs = d->bytes_per_line * y;
150     size_t toofs = new_bytes_per_line * y;
151     size_t len_to_copy = d->bytes_per_line <
152     new_bytes_per_line? d->bytes_per_line
153     : new_bytes_per_line;
154     memset(new_framebuffer + toofs, 0, new_bytes_per_line);
155     if (y < d->x11_ysize)
156     memmove(new_framebuffer + toofs,
157     d->framebuffer + fromofs, len_to_copy);
158     }
159    
160     free(d->framebuffer);
161     }
162    
163     d->framebuffer = new_framebuffer;
164     d->framebuffer_size = size;
165    
166 dpavlin 22 if (new_xsize > d->xsize || new_ysize > d->ysize) {
167 dpavlin 6 d->update_x1 = d->update_y1 = 0;
168     d->update_x2 = new_xsize - 1;
169     d->update_y2 = new_ysize - 1;
170     }
171    
172     d->bytes_per_line = new_bytes_per_line;
173 dpavlin 22 d->xsize = d->visible_xsize = new_xsize;
174     d->ysize = d->visible_ysize = new_ysize;
175 dpavlin 6
176 dpavlin 22 d->x11_xsize = d->xsize / d->vfb_scaledown;
177     d->x11_ysize = d->ysize / d->vfb_scaledown;
178    
179 dpavlin 28 memory_device_update_data(d->memory, d, d->framebuffer);
180    
181     set_title(d);
182    
183 dpavlin 6 #ifdef WITH_X11
184 dpavlin 28 if (d->fb_window != NULL) {
185 dpavlin 6 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
186 dpavlin 28 x11_set_standard_properties(d->fb_window, d->title);
187     }
188 dpavlin 6 #endif
189     }
190    
191    
192     /*
193 dpavlin 4 * dev_fb_setcursor():
194     */
195     void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
196     int cursor_xsize, int cursor_ysize)
197     {
198     if (cursor_x < 0)
199     cursor_x = 0;
200     if (cursor_y < 0)
201     cursor_y = 0;
202     if (cursor_x + cursor_xsize >= d->xsize)
203     cursor_x = d->xsize - cursor_xsize;
204     if (cursor_y + cursor_ysize >= d->ysize)
205     cursor_y = d->ysize - cursor_ysize;
206    
207     #ifdef WITH_X11
208     if (d->fb_window != NULL) {
209     d->fb_window->cursor_x = cursor_x;
210     d->fb_window->cursor_y = cursor_y;
211     d->fb_window->cursor_on = on;
212     d->fb_window->cursor_xsize = cursor_xsize;
213     d->fb_window->cursor_ysize = cursor_ysize;
214     }
215     #endif
216    
217     /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
218     cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
219     }
220    
221    
222     /*
223     * framebuffer_blockcopyfill():
224     *
225     * This function should be used by devices that are capable of doing
226     * block copy/fill.
227     *
228     * If fillflag is non-zero, then fill_[rgb] should contain the color
229 dpavlin 30 * with which to fill. (In 8-bit mode, only fill_r is used.)
230 dpavlin 4 *
231     * If fillflag is zero, copy mode is used, and from_[xy] should contain
232     * the offset on the framebuffer where we should copy from.
233     *
234     * NOTE: Overlapping copies are undefined!
235     */
236     void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
237     int fill_g, int fill_b, int x1, int y1, int x2, int y2,
238     int from_x, int from_y)
239     {
240 dpavlin 30 int x, y;
241 dpavlin 4 long from_ofs, dest_ofs, linelen;
242    
243     if (fillflag)
244     debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
245     "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
246     else
247     debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
248     "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
249    
250     /* Clip x: */
251     if (x1 < 0) x1 = 0;
252     if (x1 >= d->xsize) x1 = d->xsize-1;
253     if (x2 < 0) x2 = 0;
254     if (x2 >= d->xsize) x2 = d->xsize-1;
255    
256     dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
257     linelen = (x2-x1 + 1) * (d->bit_depth/8);
258     /* NOTE: linelen is nr of bytes, not pixels */
259    
260     if (fillflag) {
261     for (y=y1; y<=y2; y++) {
262     if (y>=0 && y<d->ysize) {
263 dpavlin 30 unsigned char *buf =
264     d->framebuffer + dest_ofs;
265    
266     if (d->bit_depth == 24) {
267 dpavlin 40 for (x=0; x<linelen && x <
268     (int) sizeof(buf); x += 3) {
269 dpavlin 4 buf[x] = fill_r;
270     buf[x+1] = fill_g;
271     buf[x+2] = fill_b;
272     }
273 dpavlin 30 } else if (d->bit_depth == 8) {
274     memset(buf, fill_r, linelen);
275     } else {
276     fatal("Unimplemented bit-depth (%i)"
277     " for fb fill\n", d->bit_depth);
278     exit(1);
279 dpavlin 22 }
280 dpavlin 4 }
281    
282     dest_ofs += d->bytes_per_line;
283     }
284     } else {
285     from_ofs = d->bytes_per_line * from_y +
286     (d->bit_depth/8) * from_x;
287     for (y=y1; y<=y2; y++) {
288 dpavlin 30 if (y >= 0 && y < d->ysize) {
289     if (from_y >= 0 && from_y < d->ysize)
290     memmove(d->framebuffer + dest_ofs,
291     d->framebuffer + from_ofs, linelen);
292     else
293     memset(d->framebuffer + dest_ofs,
294     0, linelen);
295     }
296     from_y ++;
297 dpavlin 4 from_ofs += d->bytes_per_line;
298     dest_ofs += d->bytes_per_line;
299     }
300     }
301    
302     if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
303     if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
304     if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
305     if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
306    
307     if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
308     if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
309     if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
310     if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
311     }
312    
313    
314     #ifdef WITH_X11
315    
316 dpavlin 22 #define REDRAW redraw_fallback
317     #include "fb_include.c"
318     #undef REDRAW
319 dpavlin 4
320 dpavlin 22 #define FB_24
321     #define REDRAW redraw_24
322     #include "fb_include.c"
323     #undef REDRAW
324     #undef FB_24
325     #define FB_16
326     #define REDRAW redraw_16
327     #include "fb_include.c"
328     #undef FB_16
329     #undef REDRAW
330     #define FB_15
331     #define REDRAW redraw_15
332     #include "fb_include.c"
333     #undef REDRAW
334     #undef FB_15
335 dpavlin 4
336 dpavlin 22 #define FB_BO
337     #define FB_24
338     #define REDRAW redraw_24_bo
339     #include "fb_include.c"
340     #undef REDRAW
341     #undef FB_24
342     #define FB_16
343     #define REDRAW redraw_16_bo
344     #include "fb_include.c"
345     #undef FB_16
346     #undef REDRAW
347     #define FB_15
348     #define REDRAW redraw_15_bo
349     #include "fb_include.c"
350     #undef REDRAW
351     #undef FB_15
352     #undef FB_BO
353 dpavlin 4
354 dpavlin 22 #define FB_SCALEDOWN
355 dpavlin 4
356 dpavlin 22 #define REDRAW redraw_fallback_sd
357     #include "fb_include.c"
358     #undef REDRAW
359 dpavlin 4
360 dpavlin 22 #define FB_24
361     #define REDRAW redraw_24_sd
362     #include "fb_include.c"
363     #undef REDRAW
364     #undef FB_24
365     #define FB_16
366     #define REDRAW redraw_16_sd
367     #include "fb_include.c"
368     #undef FB_16
369     #undef REDRAW
370     #define FB_15
371     #define REDRAW redraw_15_sd
372     #include "fb_include.c"
373     #undef REDRAW
374     #undef FB_15
375 dpavlin 4
376 dpavlin 22 #define FB_BO
377     #define FB_24
378     #define REDRAW redraw_24_bo_sd
379     #include "fb_include.c"
380     #undef REDRAW
381     #undef FB_24
382     #define FB_16
383     #define REDRAW redraw_16_bo_sd
384     #include "fb_include.c"
385     #undef FB_16
386     #undef REDRAW
387     #define FB_15
388     #define REDRAW redraw_15_bo_sd
389     #include "fb_include.c"
390     #undef REDRAW
391     #undef FB_15
392     #undef FB_BO
393 dpavlin 4
394 dpavlin 22 void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = {
395     redraw_fallback, redraw_fallback,
396     redraw_15, redraw_15_bo,
397     redraw_16, redraw_16_bo,
398     redraw_24, redraw_24_bo,
399     redraw_fallback_sd, redraw_fallback_sd,
400     redraw_15_sd, redraw_15_bo_sd,
401     redraw_16_sd, redraw_16_bo_sd,
402     redraw_24_sd, redraw_24_bo_sd };
403 dpavlin 4
404 dpavlin 22 #endif /* WITH_X11 */
405 dpavlin 4
406    
407 dpavlin 32 DEVICE_TICK(fb)
408 dpavlin 4 {
409     struct vfb_data *d = extra;
410     #ifdef WITH_X11
411     int need_to_flush_x11 = 0;
412     int need_to_redraw_cursor = 0;
413     #endif
414    
415 dpavlin 42 if (!cpu->machine->x11_md.in_use)
416 dpavlin 4 return;
417    
418     do {
419 dpavlin 12 uint64_t high, low = (uint64_t)(int64_t) -1;
420 dpavlin 4 int x, y;
421    
422 dpavlin 12 memory_device_dyntrans_access(cpu, cpu->mem,
423 dpavlin 4 extra, &low, &high);
424     if ((int64_t)low == -1)
425     break;
426    
427     /* printf("low=%016llx high=%016llx\n",
428     (long long)low, (long long)high); */
429    
430     x = (low % d->bytes_per_line) * 8 / d->bit_depth;
431     y = low / d->bytes_per_line;
432     if (x < d->update_x1 || d->update_x1 == -1)
433     d->update_x1 = x;
434     if (x > d->update_x2 || d->update_x2 == -1)
435     d->update_x2 = x;
436     if (y < d->update_y1 || d->update_y1 == -1)
437     d->update_y1 = y;
438     if (y > d->update_y2 || d->update_y2 == -1)
439     d->update_y2 = y;
440    
441     x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
442     y = (low+7) / d->bytes_per_line;
443     if (x < d->update_x1 || d->update_x1 == -1)
444     d->update_x1 = x;
445     if (x > d->update_x2 || d->update_x2 == -1)
446     d->update_x2 = x;
447     if (y < d->update_y1 || d->update_y1 == -1)
448     d->update_y1 = y;
449     if (y > d->update_y2 || d->update_y2 == -1)
450     d->update_y2 = y;
451    
452     x = (high % d->bytes_per_line) * 8 / d->bit_depth;
453     y = high / d->bytes_per_line;
454     if (x < d->update_x1 || d->update_x1 == -1)
455     d->update_x1 = x;
456     if (x > d->update_x2 || d->update_x2 == -1)
457     d->update_x2 = x;
458     if (y < d->update_y1 || d->update_y1 == -1)
459     d->update_y1 = y;
460     if (y > d->update_y2 || d->update_y2 == -1)
461     d->update_y2 = y;
462    
463     x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
464     y = (high+7) / d->bytes_per_line;
465     if (x < d->update_x1 || d->update_x1 == -1)
466     d->update_x1 = x;
467     if (x > d->update_x2 || d->update_x2 == -1)
468     d->update_x2 = x;
469     if (y < d->update_y1 || d->update_y1 == -1)
470     d->update_y1 = y;
471     if (y > d->update_y2 || d->update_y2 == -1)
472     d->update_y2 = y;
473    
474     /*
475     * An update covering more than one line will automatically
476     * force an update of all the affected lines:
477     */
478     if (d->update_y1 != d->update_y2) {
479     d->update_x1 = 0;
480     d->update_x2 = d->xsize-1;
481     }
482     } while (0);
483    
484     #ifdef WITH_X11
485     /* Do we need to redraw the cursor? */
486     if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
487     d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
488     d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
489     d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
490     d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
491     need_to_redraw_cursor = 1;
492    
493     if (d->update_x2 != -1) {
494 dpavlin 14 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
495     d->update_x1 < (d->fb_window->OLD_cursor_x +
496     d->fb_window->OLD_cursor_xsize)) ||
497 dpavlin 4 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
498 dpavlin 14 d->update_x2 < (d->fb_window->OLD_cursor_x +
499     d->fb_window->OLD_cursor_xsize)) ||
500 dpavlin 4 (d->update_x1 < d->fb_window->OLD_cursor_x &&
501 dpavlin 14 d->update_x2 >= (d->fb_window->OLD_cursor_x +
502     d->fb_window->OLD_cursor_xsize)) ) &&
503     ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
504     d->update_y1 < (d->fb_window->OLD_cursor_y +
505     d->fb_window->OLD_cursor_ysize)) ||
506     (d->update_y2 >= d->fb_window->OLD_cursor_y &&
507     d->update_y2 < (d->fb_window->OLD_cursor_y +
508     d->fb_window->OLD_cursor_ysize)) ||
509     (d->update_y1 < d->fb_window->OLD_cursor_y &&
510     d->update_y2 >= (d->fb_window->OLD_cursor_y +
511     d->fb_window->OLD_cursor_ysize)) ) )
512     need_to_redraw_cursor = 1;
513 dpavlin 4 }
514    
515     if (need_to_redraw_cursor) {
516     /* Remove old cursor, if any: */
517     if (d->fb_window->OLD_cursor_on) {
518     XPutImage(d->fb_window->x11_display,
519     d->fb_window->x11_fb_window,
520     d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
521     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
522     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
523     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
524     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
525     d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
526 dpavlin 14 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
527 dpavlin 4 }
528     }
529     #endif
530    
531     if (d->update_x2 != -1) {
532 dpavlin 24 #ifdef WITH_X11
533     int y;
534     #endif
535     int addr, addr2, q = d->vfb_scaledown;
536 dpavlin 4
537 dpavlin 14 if (d->update_x1 >= d->visible_xsize)
538     d->update_x1 = d->visible_xsize - 1;
539     if (d->update_x2 >= d->visible_xsize)
540     d->update_x2 = d->visible_xsize - 1;
541     if (d->update_y1 >= d->visible_ysize)
542     d->update_y1 = d->visible_ysize - 1;
543     if (d->update_y2 >= d->visible_ysize)
544     d->update_y2 = d->visible_ysize - 1;
545 dpavlin 4
546 dpavlin 14 /* Without these, we might miss the rightmost/bottom pixel: */
547 dpavlin 4 d->update_x2 += (q - 1);
548     d->update_y2 += (q - 1);
549    
550     d->update_x1 = d->update_x1 / q * q;
551     d->update_x2 = d->update_x2 / q * q;
552     d->update_y1 = d->update_y1 / q * q;
553     d->update_y2 = d->update_y2 / q * q;
554    
555 dpavlin 14 addr = d->update_y1 * d->bytes_per_line +
556     d->update_x1 * d->bit_depth / 8;
557     addr2 = d->update_y1 * d->bytes_per_line +
558     d->update_x2 * d->bit_depth / 8;
559 dpavlin 4
560 dpavlin 22 #ifdef WITH_X11
561 dpavlin 4 for (y=d->update_y1; y<=d->update_y2; y+=q) {
562 dpavlin 22 d->redraw_func(d, addr, addr2 - addr);
563 dpavlin 4 addr += d->bytes_per_line * q;
564     addr2 += d->bytes_per_line * q;
565     }
566    
567 dpavlin 14 XPutImage(d->fb_window->x11_display, d->fb_window->
568     x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
569     fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
570     d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
571     d->update_y1/d->vfb_scaledown,
572 dpavlin 4 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
573     (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
574    
575     need_to_flush_x11 = 1;
576     #endif
577    
578     d->update_x1 = d->update_y1 = 99999;
579     d->update_x2 = d->update_y2 = -1;
580     }
581    
582     #ifdef WITH_X11
583     if (need_to_redraw_cursor) {
584     /* Paint new cursor: */
585     if (d->fb_window->cursor_on) {
586 dpavlin 14 x11_redraw_cursor(cpu->machine,
587     d->fb_window->fb_number);
588 dpavlin 4 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
589     d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
590     d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
591 dpavlin 14 d->fb_window->OLD_cursor_xsize = d->fb_window->
592     cursor_xsize;
593     d->fb_window->OLD_cursor_ysize = d->fb_window->
594     cursor_ysize;
595 dpavlin 22 need_to_flush_x11 = 1;
596 dpavlin 4 }
597     }
598     #endif
599    
600     #ifdef WITH_X11
601     if (need_to_flush_x11)
602     XFlush(d->fb_window->x11_display);
603     #endif
604     }
605    
606    
607 dpavlin 22 DEVICE_ACCESS(fb)
608 dpavlin 4 {
609     struct vfb_data *d = extra;
610 dpavlin 22 size_t i;
611 dpavlin 4
612     #ifdef FB_DEBUG
613     if (writeflag == MEM_WRITE) { if (data[0]) {
614     fatal("[ dev_fb: write to addr=%08lx, data = ",
615     (long)relative_addr);
616     for (i=0; i<len; i++)
617     fatal("%02x ", data[i]);
618     fatal("]\n");
619     } else {
620     fatal("[ dev_fb: read from addr=%08lx, data = ",
621     (long)relative_addr);
622     for (i=0; i<len; i++)
623     fatal("%02x ", d->framebuffer[relative_addr + i]);
624     fatal("]\n");
625     }
626     #endif
627    
628 dpavlin 6 if (relative_addr >= d->framebuffer_size)
629     return 0;
630    
631 dpavlin 4 /* See if a write actually modifies the framebuffer contents: */
632     if (writeflag == MEM_WRITE) {
633     for (i=0; i<len; i++) {
634     if (data[i] != d->framebuffer[relative_addr + i])
635     break;
636    
637     /* If all bytes are equal to what is already stored
638     in the framebuffer, then simply return: */
639 dpavlin 22 if (i == len-1)
640 dpavlin 4 return 1;
641     }
642     }
643    
644     /*
645     * If the framebuffer is modified, then we should keep a track
646     * of which area(s) we modify, so that the display isn't updated
647     * unnecessarily.
648     */
649 dpavlin 42 if (writeflag == MEM_WRITE && cpu->machine->x11_md.in_use) {
650 dpavlin 4 int x, y, x2,y2;
651    
652     x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
653     y = relative_addr / d->bytes_per_line;
654     x2 = ((relative_addr + len) % d->bytes_per_line)
655     * 8 / d->bit_depth;
656     y2 = (relative_addr + len) / d->bytes_per_line;
657    
658     if (x < d->update_x1 || d->update_x1 == -1)
659     d->update_x1 = x;
660     if (x > d->update_x2 || d->update_x2 == -1)
661     d->update_x2 = x;
662    
663     if (y < d->update_y1 || d->update_y1 == -1)
664     d->update_y1 = y;
665     if (y > d->update_y2 || d->update_y2 == -1)
666     d->update_y2 = y;
667    
668     if (x2 < d->update_x1 || d->update_x1 == -1)
669     d->update_x1 = x2;
670     if (x2 > d->update_x2 || d->update_x2 == -1)
671     d->update_x2 = x2;
672    
673     if (y2 < d->update_y1 || d->update_y1 == -1)
674     d->update_y1 = y2;
675     if (y2 > d->update_y2 || d->update_y2 == -1)
676     d->update_y2 = y2;
677    
678     /*
679     * An update covering more than one line will automatically
680     * force an update of all the affected lines:
681     */
682     if (y != y2) {
683     d->update_x1 = 0;
684     d->update_x2 = d->xsize-1;
685     }
686     }
687    
688     /*
689     * Read from/write to the framebuffer:
690     * (TODO: take the color_plane_mask into account)
691     *
692     * Calling memcpy() is probably overkill, as it usually is just one
693     * or a few bytes that are read/written at a time.
694     */
695     if (writeflag == MEM_WRITE) {
696     if (len > 8)
697     memcpy(d->framebuffer + relative_addr, data, len);
698 dpavlin 22 else {
699 dpavlin 4 for (i=0; i<len; i++)
700     d->framebuffer[relative_addr + i] = data[i];
701 dpavlin 22 }
702 dpavlin 4 } else {
703     if (len > 8)
704     memcpy(data, d->framebuffer + relative_addr, len);
705 dpavlin 22 else {
706 dpavlin 4 for (i=0; i<len; i++)
707     data[i] = d->framebuffer[relative_addr + i];
708 dpavlin 22 }
709 dpavlin 4 }
710    
711     return 1;
712     }
713    
714    
715     /*
716     * dev_fb_init():
717     *
718 dpavlin 10 * This function is big and ugly, but the point is to initialize a framebuffer
719     * device. :-)
720     *
721     * visible_xsize and visible_ysize are the sizes of the visible display area.
722     * xsize and ysize tell how much memory is actually allocated (for example
723     * visible_xsize could be 640, but xsize could be 1024, for better alignment).
724     *
725     * vfb_type is useful for selecting special features.
726     *
727     * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
728     *
729     * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
730     *
731 dpavlin 32 * VFB_HPC is like generic, but the color encoding is done as on HPCmips
732     * and Dreamcast.
733 dpavlin 10 *
734     * If bit_depth = -15 (note the minus sign), then a special hack is used for
735     * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
736 dpavlin 4 */
737     struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
738     uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
739 dpavlin 12 int xsize, int ysize, int bit_depth, char *name)
740 dpavlin 4 {
741     struct vfb_data *d;
742 dpavlin 10 size_t size, nlen;
743 dpavlin 12 int flags;
744 dpavlin 22 int reverse_start = 0;
745 dpavlin 4 char *name2;
746    
747 dpavlin 42 CHECK_ALLOCATION(d = malloc(sizeof(struct vfb_data)));
748 dpavlin 4 memset(d, 0, sizeof(struct vfb_data));
749    
750 dpavlin 22 if (vfb_type & VFB_REVERSE_START) {
751     vfb_type &= ~VFB_REVERSE_START;
752     reverse_start = 1;
753     }
754    
755 dpavlin 28 d->memory = mem;
756 dpavlin 4 d->vfb_type = vfb_type;
757    
758     /* Defaults: */
759     d->xsize = xsize; d->visible_xsize = visible_xsize;
760     d->ysize = ysize; d->visible_ysize = visible_ysize;
761    
762     d->bit_depth = bit_depth;
763    
764     if (bit_depth == 15) {
765     d->color32k = 1;
766     bit_depth = d->bit_depth = 16;
767 dpavlin 10 } else if (bit_depth == -15) {
768     d->psp_15bit = 1;
769     bit_depth = d->bit_depth = 16;
770 dpavlin 4 }
771    
772     /* Specific types: */
773     switch (vfb_type) {
774     case VFB_DEC_VFB01:
775     /* DECstation VFB01 (monochrome) */
776     d->xsize = 2048; d->visible_xsize = 1024;
777     d->ysize = 1024; d->visible_ysize = 864;
778     d->bit_depth = 1;
779     break;
780     case VFB_DEC_VFB02:
781     /* DECstation VFB02 (color) */
782     d->xsize = 1024; d->visible_xsize = 1024;
783     d->ysize = 1024; d->visible_ysize = 864;
784     d->bit_depth = 8;
785     break;
786     case VFB_DEC_MAXINE:
787     /* DECstation Maxine (1024x768x8) */
788     d->xsize = 1024; d->visible_xsize = d->xsize;
789     d->ysize = 768; d->visible_ysize = d->ysize;
790     d->bit_depth = 8;
791     break;
792     case VFB_PLAYSTATION2:
793     /* Playstation 2 */
794     d->xsize = xsize; d->visible_xsize = d->xsize;
795     d->ysize = ysize; d->visible_ysize = d->ysize;
796     d->bit_depth = 24;
797     break;
798     }
799    
800     if (d->bit_depth == 2 || d->bit_depth == 4)
801     set_grayscale_palette(d, 1 << d->bit_depth);
802     else if (d->bit_depth == 8 || d->bit_depth == 1)
803     set_blackwhite_palette(d, 1 << d->bit_depth);
804    
805 dpavlin 42 d->vfb_scaledown = machine->x11_md.scaledown;
806 dpavlin 4
807     d->bytes_per_line = d->xsize * d->bit_depth / 8;
808     size = d->ysize * d->bytes_per_line;
809    
810 dpavlin 42 CHECK_ALLOCATION(d->framebuffer = malloc(size));
811 dpavlin 4
812     /* Clear the framebuffer (all black pixels): */
813     d->framebuffer_size = size;
814 dpavlin 22 memset(d->framebuffer, reverse_start? 255 : 0, size);
815 dpavlin 4
816     d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
817     d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
818    
819 dpavlin 22 /* Only "update" from the start if we need to fill with white. */
820     /* (The Ximage will be black from the start anyway.) */
821     if (reverse_start) {
822     d->update_x1 = d->update_y1 = 0;
823     d->update_x2 = d->xsize - 1;
824     d->update_y2 = d->ysize - 1;
825     } else {
826     d->update_x1 = d->update_y1 = 99999;
827     d->update_x2 = d->update_y2 = -1;
828     }
829 dpavlin 4
830 dpavlin 42 CHECK_ALLOCATION(d->name = strdup(name));
831 dpavlin 28 set_title(d);
832 dpavlin 4
833     #ifdef WITH_X11
834 dpavlin 42 if (machine->x11_md.in_use) {
835 dpavlin 22 int i = 0;
836 dpavlin 4 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
837 dpavlin 42 d->title, machine->x11_md.scaledown, machine);
838 dpavlin 22 switch (d->fb_window->x11_screen_depth) {
839     case 15: i = 2; break;
840     case 16: i = 4; break;
841     case 24: i = 6; break;
842     }
843     if (d->fb_window->fb_ximage->byte_order)
844     i ++;
845     if (d->vfb_scaledown > 1)
846     i += 8;
847     d->redraw_func = redraw[i];
848     } else
849 dpavlin 4 #endif
850     d->fb_window = NULL;
851    
852 dpavlin 10 nlen = strlen(name) + 10;
853 dpavlin 42 CHECK_ALLOCATION(name2 = malloc(nlen));
854    
855 dpavlin 10 snprintf(name2, nlen, "fb [%s]", name);
856 dpavlin 4
857 dpavlin 20 flags = DM_DEFAULT;
858 dpavlin 4 if ((baseaddr & 0xfff) == 0)
859 dpavlin 20 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
860 dpavlin 4
861 dpavlin 20 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
862 dpavlin 6
863 dpavlin 4 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
864     d, flags, d->framebuffer);
865    
866 dpavlin 42 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
867    
868 dpavlin 4 return d;
869     }
870    

  ViewVC Help
Powered by ViewVC 1.1.26