/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 5 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 /*
2 * Copyright (C) 2003-2007 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 * $Id: dev_fb.c,v 1.132 2007/06/15 19:11:15 debug Exp $
29 *
30 * COMMENT: 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 * Playstation 2 (24-bit color)
36 * Generic (any resolution, several bit depths possible, useful for
37 * testmachines)
38 *
39 *
40 * TODO: This should actually be independent of X11, but that
41 * 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 #define FB_TICK_SHIFT 19
66
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 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 /*
116 * 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 *
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 */
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 if (new_xsize < 10 || new_ysize < 10) {
137 fatal("dev_fb_resize(): size too small.\n");
138 exit(1);
139 }
140
141 new_bytes_per_line = new_xsize * d->bit_depth / 8;
142 size = new_ysize * new_bytes_per_line;
143
144 CHECK_ALLOCATION(new_framebuffer = malloc(size));
145
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 if (new_xsize > d->xsize || new_ysize > d->ysize) {
167 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 d->xsize = d->visible_xsize = new_xsize;
174 d->ysize = d->visible_ysize = new_ysize;
175
176 d->x11_xsize = d->xsize / d->vfb_scaledown;
177 d->x11_ysize = d->ysize / d->vfb_scaledown;
178
179 memory_device_update_data(d->memory, d, d->framebuffer);
180
181 set_title(d);
182
183 #ifdef WITH_X11
184 if (d->fb_window != NULL) {
185 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
186 x11_set_standard_properties(d->fb_window, d->title);
187 }
188 #endif
189 }
190
191
192 /*
193 * 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 * with which to fill. (In 8-bit mode, only fill_r is used.)
230 *
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 int x, y;
241 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 unsigned char *buf =
264 d->framebuffer + dest_ofs;
265
266 if (d->bit_depth == 24) {
267 for (x=0; x<linelen && x <
268 (int) sizeof(buf); x += 3) {
269 buf[x] = fill_r;
270 buf[x+1] = fill_g;
271 buf[x+2] = fill_b;
272 }
273 } 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 }
280 }
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 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 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 #define REDRAW redraw_fallback
317 #include "fb_include.c"
318 #undef REDRAW
319
320 #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
336 #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
354 #define FB_SCALEDOWN
355
356 #define REDRAW redraw_fallback_sd
357 #include "fb_include.c"
358 #undef REDRAW
359
360 #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
376 #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
394 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
404 #endif /* WITH_X11 */
405
406
407 DEVICE_TICK(fb)
408 {
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 if (!cpu->machine->x11_md.in_use)
416 return;
417
418 do {
419 uint64_t high, low = (uint64_t)(int64_t) -1;
420 int x, y;
421
422 memory_device_dyntrans_access(cpu, cpu->mem,
423 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 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 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
498 d->update_x2 < (d->fb_window->OLD_cursor_x +
499 d->fb_window->OLD_cursor_xsize)) ||
500 (d->update_x1 < d->fb_window->OLD_cursor_x &&
501 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 }
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 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
527 }
528 }
529 #endif
530
531 if (d->update_x2 != -1) {
532 #ifdef WITH_X11
533 int y;
534 #endif
535 int addr, addr2, q = d->vfb_scaledown;
536
537 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
546 /* Without these, we might miss the rightmost/bottom pixel: */
547 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 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
560 #ifdef WITH_X11
561 for (y=d->update_y1; y<=d->update_y2; y+=q) {
562 d->redraw_func(d, addr, addr2 - addr);
563 addr += d->bytes_per_line * q;
564 addr2 += d->bytes_per_line * q;
565 }
566
567 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 (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 x11_redraw_cursor(cpu->machine,
587 d->fb_window->fb_number);
588 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 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 need_to_flush_x11 = 1;
596 }
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 DEVICE_ACCESS(fb)
608 {
609 struct vfb_data *d = extra;
610 size_t i;
611
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 if (relative_addr >= d->framebuffer_size)
629 return 0;
630
631 /* 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 if (i == len-1)
640 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 if (writeflag == MEM_WRITE && cpu->machine->x11_md.in_use) {
650 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 else {
699 for (i=0; i<len; i++)
700 d->framebuffer[relative_addr + i] = data[i];
701 }
702 } else {
703 if (len > 8)
704 memcpy(data, d->framebuffer + relative_addr, len);
705 else {
706 for (i=0; i<len; i++)
707 data[i] = d->framebuffer[relative_addr + i];
708 }
709 }
710
711 return 1;
712 }
713
714
715 /*
716 * dev_fb_init():
717 *
718 * 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 * VFB_HPC is like generic, but the color encoding is done as on HPCmips
732 * and Dreamcast.
733 *
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 */
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 int xsize, int ysize, int bit_depth, char *name)
740 {
741 struct vfb_data *d;
742 size_t size, nlen;
743 int flags;
744 int reverse_start = 0;
745 char *name2;
746
747 CHECK_ALLOCATION(d = malloc(sizeof(struct vfb_data)));
748 memset(d, 0, sizeof(struct vfb_data));
749
750 if (vfb_type & VFB_REVERSE_START) {
751 vfb_type &= ~VFB_REVERSE_START;
752 reverse_start = 1;
753 }
754
755 d->memory = mem;
756 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 } else if (bit_depth == -15) {
768 d->psp_15bit = 1;
769 bit_depth = d->bit_depth = 16;
770 }
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 d->vfb_scaledown = machine->x11_md.scaledown;
806
807 d->bytes_per_line = d->xsize * d->bit_depth / 8;
808 size = d->ysize * d->bytes_per_line;
809
810 CHECK_ALLOCATION(d->framebuffer = malloc(size));
811
812 /* Clear the framebuffer (all black pixels): */
813 d->framebuffer_size = size;
814 memset(d->framebuffer, reverse_start? 255 : 0, size);
815
816 d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
817 d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
818
819 /* 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
830 CHECK_ALLOCATION(d->name = strdup(name));
831 set_title(d);
832
833 #ifdef WITH_X11
834 if (machine->x11_md.in_use) {
835 int i = 0;
836 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
837 d->title, machine->x11_md.scaledown, machine);
838 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 #endif
850 d->fb_window = NULL;
851
852 nlen = strlen(name) + 10;
853 CHECK_ALLOCATION(name2 = malloc(nlen));
854
855 snprintf(name2, nlen, "fb [%s]", name);
856
857 flags = DM_DEFAULT;
858 if ((baseaddr & 0xfff) == 0)
859 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
860
861 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
862
863 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
864 d, flags, d->framebuffer);
865
866 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
867
868 return d;
869 }
870

  ViewVC Help
Powered by ViewVC 1.1.26