1 /*
2  *  Copyright (C) 2003-2009  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  *  COMMENT: PlayStation 2 "gif" graphics device
29  *
30  *  TODO:  Convert dev_fb_access() accesses into direct framebuffer reads and
31  *         writes, to improve performance.
32  *
33  *  TODO 2:  The way things are now, rgb bytes are copied from emulated
34  *           space to the framebuffer as rgb, but on X Windows servers on
35  *           big-endian machines that should be bgr.  (?) Hm...
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "cpu.h"
43 #include "device.h"
44 #include "devices.h"
45 #include "machine.h"
46 #include "memory.h"
47 #include "misc.h"
48 
49 
50 #define	DEV_PS2_GIF_LENGTH		0x10000
51 
52 #define	PS2_FB_ADDR	0x60000000ULL 	/*  hopefully nothing else here  */
53 
54 
55 struct gif_data {
56 	struct cpu	*cpu;
57 	int		xsize, ysize;
58 	int		bytes_per_pixel;
59 	int		transparent_text;
60 	struct vfb_data *vfb_data;
61 };
62 
63 
64 /*
65  *  test_triangle():
66  *
67  *  Draw a triangle:
68  */
test_triangle(struct gif_data * d,int x1,int y1,int r1,int g1,int b1,int x2,int y2,int r2,int g2,int b2,int x3,int y3,int r3,int g3,int b3)69 void test_triangle(struct gif_data *d,
70 	int x1, int y1, int r1, int g1, int b1,
71 	int x2, int y2, int r2, int g2, int b2,
72 	int x3, int y3, int r3, int g3, int b3)
73 {
74 	unsigned char *line;
75 	int y, tmp, scale = 32768;
76 	int xofs, xlen, savedxlen, xdir, x;
77 	int r, g, b;			/*  scaled  */
78 	int xstart, xstop;		/*  scaled  */
79 	int rstart, rstop;		/*  scaled  */
80 	int gstart, gstop;		/*  scaled  */
81 	int bstart, bstop;		/*  scaled  */
82 	int rpx, gpx, bpx;		/*  scaled  */
83 	int xpy12, xpy13, xpy23;
84 	int rpy12, rpy13, rpy23;
85 	int gpy12, gpy13, gpy23;
86 	int bpy12, bpy13, bpy23;
87 
88 	CHECK_ALLOCATION(line = (unsigned char *) malloc(d->xsize * d->bytes_per_pixel));
89 
90 	if (y2 > y3) {
91 		tmp = x2; x2 = x3; x3 = tmp;
92 		tmp = y2; y2 = y3; y3 = tmp;
93 		tmp = r2; r2 = r3; r3 = tmp;
94 		tmp = g2; g2 = g3; g3 = tmp;
95 		tmp = b2; b2 = b3; b3 = tmp;
96 	}
97 
98 	if (y1 > y2) {
99 		tmp = x1; x1 = x2; x2 = tmp;
100 		tmp = y1; y1 = y2; y2 = tmp;
101 		tmp = r1; r1 = r2; r2 = tmp;
102 		tmp = g1; g1 = g2; g2 = tmp;
103 		tmp = b1; b1 = b2; b2 = tmp;
104 	}
105 
106 	if (y1 > y3) {
107 		tmp = x1; x1 = x3; x3 = tmp;
108 		tmp = y1; y1 = y3; y3 = tmp;
109 		tmp = r1; r1 = r3; r3 = tmp;
110 		tmp = g1; g1 = g3; g3 = tmp;
111 		tmp = b1; b1 = b3; b3 = tmp;
112 	}
113 
114 	/*  X change per line:  */
115 	xpy12 = (y2-y1)? scale*(x2-x1)/(y2-y1) : 0;
116 	xpy13 = (y3-y1)? scale*(x3-x1)/(y3-y1) : 0;
117 	xpy23 = (y3-y2)? scale*(x3-x2)/(y3-y2) : 0;
118 
119 	/*  Color change per line:  */
120 	rpy12 = (y2-y1)? scale*(r2-r1)/(y2-y1) : 0;
121 	rpy13 = (y3-y1)? scale*(r3-r1)/(y3-y1) : 0;
122 	rpy23 = (y3-y2)? scale*(r3-r2)/(y3-y2) : 0;
123 
124 	gpy12 = (y2-y1)? scale*(g2-g1)/(y2-y1) : 0;
125 	gpy13 = (y3-y1)? scale*(g3-g1)/(y3-y1) : 0;
126 	gpy23 = (y3-y2)? scale*(g3-g2)/(y3-y2) : 0;
127 
128 	bpy12 = (y2-y1)? scale*(b2-b1)/(y2-y1) : 0;
129 	bpy13 = (y3-y1)? scale*(b3-b1)/(y3-y1) : 0;
130 	bpy23 = (y3-y2)? scale*(b3-b2)/(y3-y2) : 0;
131 
132 	xstart = xstop = x1 * scale;
133 	rstart = rstop = r1 * scale;
134 	gstart = gstop = g1 * scale;
135 	bstart = bstop = b1 * scale;
136 
137 	for (y=y1; y<=y3; y++) {
138 		if (xstart < xstop)
139 			xofs = xstart/scale, xlen = (xstop-xstart)/scale + 1;
140 		else
141 			xofs = xstop/scale, xlen = (xstart-xstop)/scale + 1;
142 
143 		savedxlen = xlen;
144 		xdir = (xstart < xstop)? 1 : -1;
145 		r = rstart; g = gstart; b = bstart;
146 
147 		rpx = (xstop-xstart)? (rstop-rstart) / ((xstop-xstart)
148 		    / scale) : 0;
149 		gpx = (xstop-xstart)? (gstop-gstart) / ((xstop-xstart)
150 		    / scale) : 0;
151 		bpx = (xstop-xstart)? (bstop-bstart) / ((xstop-xstart)
152 		    / scale): 0;
153 
154 		x = xstart / scale;
155 		while (xlen > 0) {
156 			if (x>=0 && x<d->xsize) {
157 				int c;
158 				c = r/scale;
159 				line[x * d->bytes_per_pixel + 0] = c<0?
160 				    0 : (c > 255? 255 : c);
161 				c = g/scale;
162 				line[x * d->bytes_per_pixel + 1] = c<0?
163 				    0 : (c > 255? 255 : c);
164 				c = b/scale;
165 				line[x * d->bytes_per_pixel + 2] = c<0?
166 				    0 : (c > 255? 255 : c);
167 			}
168 			r += rpx;
169 			g += gpx;
170 			b += bpx;
171 			x += xdir;
172 			xlen --;
173 		}
174 
175 		dev_fb_access(d->cpu, d->cpu->mem,
176 		    (y*d->xsize + xofs) * d->bytes_per_pixel,
177 		    line + xofs * d->bytes_per_pixel,
178 		    savedxlen * d->bytes_per_pixel,
179 		    MEM_WRITE, d->vfb_data);
180 
181 		if (y<y2) {
182 			xstart += xpy12;
183 			rstart += rpy12;
184 			gstart += gpy12;
185 			bstart += bpy12;
186 		} else {
187 			xstart += xpy23;
188 			rstart += rpy23;
189 			gstart += gpy23;
190 			bstart += bpy23;
191 		}
192 		xstop += xpy13;
193 		rstop += rpy13;
194 		gstop += gpy13;
195 		bstop += bpy13;
196 
197 		if (y==y2) {
198 			xstart = x2 * scale;
199 			rstart = r2 * scale;
200 			gstart = g2 * scale;
201 			bstart = b2 * scale;
202 		}
203 	}
204 }
205 
206 
DEVICE_ACCESS(ps2_gif)207 DEVICE_ACCESS(ps2_gif)
208 {
209 	unsigned int i;
210 	struct gif_data *d = (struct gif_data *) extra;
211 
212 	if (relative_addr + len > DEV_PS2_GIF_LENGTH)
213 		return 0;
214 
215 	if (writeflag==MEM_READ) {
216 		debug("[ gif read from addr 0x%x, len=%i ]\n",
217 		    (int)relative_addr, (int)len);
218 	} else {
219 		if (data[0] == 0x08 && data[1] == 0x80) {
220 			/*  Possibly "initialize 640x480 mode":  */
221 			debug("[ gif: initialize video mode (?) ]\n");
222 		} else if (data[0] == 0x04 && data[1] == 0x00 && len > 300) {
223 			/*  Possibly "output 8x16 character":  */
224 			int xbase, ybase, xsize, ysize, x, y;
225 
226 			xbase = data[9*4 + 0] + (data[9*4 + 1] << 8);
227 			ybase = data[9*4 + 2] + (data[9*4 + 3] << 8);
228 
229 			xsize = data[12*4 + 0] + (data[12*4 + 1] << 8);
230 			ysize = data[13*4 + 0] + (data[13*4 + 1] << 8);
231 			ysize &= ~0xf;	/*  multple of 16  */
232 
233 			/*  debug("[ gif: putchar at (%i,%i), size (%i,%i) "
234 			    "]\n", xbase, ybase, xsize, ysize);  */
235 
236 			/*
237 			 *  NetBSD and Linux:
238 			 *
239 			 *  [ gif write to addr 0x0 (len=608):
240 			 *  04 00 00 00 00 00 00 10, 0e 00 00 00 00 00 00 00,
241 			 *  00 00 00 00 00 00 0a 00, 50 00 00 00 00 00 00 00,
242 			 *  00 00 00 00 00 00 00 00, 51 00 00 00 00 00 00 00,
243 			 *  08 00 00 00 16 00 00 00, 52 00 00 00 00 00 00 00,
244 			 *  00 00 00 00 00 00 00 00, 53 00 00 00 00 00 00 00,
245 			 *  20 80 00 00 00 00 00 08, 00 00 00 00 00 00 00 00,
246 			 *  00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
247 			 *  00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
248 			 *  aa aa 00 80 aa aa 00 80, 00 00 aa 80 00 00 aa 80,
249 			 *  00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
250 			 */
251 
252 			/*
253 			fatal("[ gif write to addr 0x%x (len=%i):",
254 			    (int)relative_addr, (int)len);
255 			for (i=0; i<len; i++) {
256 				fatal(" %02x", data[i]);
257 				if ((i & 7) == 7)
258 					fatal(",");
259 				if ((i & 31) == 31)
260 					fatal("\n");
261 			}
262 			fatal(" ]\n");
263 			*/
264 
265 			for (y=0; y<ysize; y++) {
266 				int fb_addr = (xbase + (ybase+y) * d->xsize)
267 				    * d->bytes_per_pixel;
268 				int addr = (24 + y*xsize) * 4;
269 				for (x=0; x<xsize; x++) {
270 					/*  There are three bytes (r,g,b) at
271 					    data[addr + 0] .. [addr + 2].
272 					    TODO: This should be translated to a
273 					    direct update of the framebuffer. */
274 
275 					dev_fb_access(d->cpu, d->cpu->mem,
276 					    fb_addr, data + addr, 3, MEM_WRITE,
277 					    d->vfb_data);
278 
279 					fb_addr += d->bytes_per_pixel;
280 					addr += 4;
281 				}
282 			}
283 		} else if (data[0] == 0x04 && data[1] == 0x80 && len == 0x50) {
284 			/*  blockcopy  */
285 			int y_source, y_dest, x_source, x_dest, x_size, y_size;
286 			x_source = data[8*4 + 0] + ((data[8*4 + 1]) << 8);
287 			y_source = data[8*4 + 2] + ((data[8*4 + 3]) << 8);
288 			x_dest   = data[9*4 + 0] + ((data[9*4 + 1]) << 8);
289 			y_dest   = data[9*4 + 2] + ((data[9*4 + 3]) << 8);
290 			x_size   = data[12*4 + 0] + ((data[12*4 + 1]) << 8);
291 			y_size   = data[13*4 + 0] + ((data[13*4 + 1]) << 8);
292 
293 			/*  debug("[ gif: blockcopy (%i,%i) -> (%i,%i), size="
294 			    "(%i,%i) ]\n", x_source,y_source, x_dest,y_dest,
295 			    x_size,y_size);  */
296 
297 			framebuffer_blockcopyfill(d->vfb_data, 0, 0,0,0,
298 			    x_dest, y_dest, x_dest + x_size - 1, y_dest +
299 			    y_size - 1, x_source, y_source);
300 		} else if (data[8] == 0x10 && data[9] == 0x55 && len == 48) {
301 			/*  Linux "clear":  This is used by linux to clear the
302 			    lowest 16 pixels of the framebuffer.  */
303 			int xbase, ybase, xend, yend;
304 
305 			xbase = (data[8*4 + 0] + (data[8*4 + 1] << 8)) / 16;
306 			ybase = (data[8*4 + 2] + (data[8*4 + 3] << 8)) / 16;
307 			xend  = (data[8*5 + 0] + (data[8*5 + 1] << 8)) / 16;
308 			yend  = (data[8*5 + 2] + (data[8*5 + 3] << 8)) / 16;
309 
310 			/*  debug("[ gif: linux \"clear\" (%i,%i)-(%i,%i) ]\n",
311 			    xbase, ybase, xend, yend);  */
312 
313 			framebuffer_blockcopyfill(d->vfb_data, 1, 0,0,0,
314 			    xbase, ybase, xend - 1, yend - 1, 0,0);
315 		} else if (data[0] == 0x07 && data[1] == 0x80 && len == 128) {
316 			/*  NetBSD "output cursor":  */
317 			int xbase, ybase, xend, yend, x, y;
318 
319 			xbase = (data[20*4 + 0] + (data[20*4 + 1] << 8)) / 16;
320 			ybase = (data[20*4 + 2] + (data[20*4 + 3] << 8)) / 16;
321 			xend  = (data[28*4 + 0] + (data[28*4 + 1] << 8)) / 16;
322 			yend  = (data[28*4 + 2] + (data[28*4 + 3] << 8)) / 16;
323 
324 			/*  debug("[ gif: NETBSD cursor at (%i,%i)-(%i,%i) ]\n",
325 			    xbase, ybase, xend, yend);  */
326 
327 			/*  Output the cursor to framebuffer memory:  */
328 
329 			for (y=ybase; y<=yend; y++)
330 				for (x=xbase; x<=xend; x++) {
331 					int fb_addr = (x + y * d->xsize) *
332 					    d->bytes_per_pixel;
333 					unsigned char pixels[3];
334 
335 					dev_fb_access(d->cpu, d->cpu->mem,
336 					    fb_addr, pixels, sizeof(pixels),
337 					    MEM_READ, d->vfb_data);
338 
339 					pixels[0] = 0xff - pixels[0];
340 					pixels[1] = 0xff - pixels[1];
341 					pixels[2] = 0xff - pixels[2];
342 
343 					dev_fb_access(d->cpu, d->cpu->mem,
344 					    fb_addr, pixels, sizeof(pixels),
345 					    MEM_WRITE, d->vfb_data);
346 				}
347 		} else if (data[0] == 0x01 && data[1] == 0x00 && len == 80) {
348 			/*  Linux "output cursor":  */
349 			int xbase, ybase, xend, yend, x, y;
350 
351 			xbase = (data[7*8 + 0] + (data[7*8 + 1] << 8)) / 16;
352 			ybase = (data[7*8 + 2] + (data[7*8 + 3] << 8)) / 16;
353 			xend  = (data[8*8 + 0] + (data[8*8 + 1] << 8)) / 16;
354 			yend  = (data[8*8 + 2] + (data[8*8 + 3] << 8)) / 16;
355 
356 			debug("[ gif: LINUX cursor at (%i,%i)-(%i,%i) ]\n",
357 			    xbase, ybase, xend, yend);
358 
359 			/*  Output the cursor to framebuffer memory:  */
360 
361 			for (y=ybase; y<=yend; y++)
362 				for (x=xbase; x<=xend; x++) {
363 					int fb_addr = (x + y * d->xsize) *
364 					    d->bytes_per_pixel;
365 					unsigned char pixels[3];
366 
367 					dev_fb_access(d->cpu, d->cpu->mem,
368 					    fb_addr, pixels, sizeof(pixels),
369 					    MEM_READ, d->vfb_data);
370 
371 					pixels[0] = 0xff - pixels[0];
372 					pixels[1] = 0xff - pixels[1];
373 					pixels[2] = 0xff - pixels[2];
374 
375 					dev_fb_access(d->cpu, d->cpu->mem,
376 					    fb_addr, pixels, sizeof(pixels),
377 					    MEM_WRITE, d->vfb_data);
378 				}
379 		} else {		/*  Unknown command:  */
380 			fatal("[ gif write to addr 0x%x (len=%i):",
381 			    (int)relative_addr, len);
382 			for (i=0; i<len; i++)
383 				fatal(" %02x", data[i]);
384 			fatal(" ]\n");
385 /*			fatal("Unknown gif command.\n");
386 			cpu->running = 0;
387 */		}
388 	}
389 
390 	return 1;
391 }
392 
393 
394 /*
395  *  devinit_ps2_gif():
396  *
397  *  Attached to separate memory by devinit_ps2_gs().
398  */
DEVINIT(ps2_gif)399 DEVINIT(ps2_gif)
400 {
401 	struct gif_data *d;
402 
403 	CHECK_ALLOCATION(d = (struct gif_data *) malloc(sizeof(struct gif_data)));
404 	memset(d, 0, sizeof(struct gif_data));
405 
406 	d->transparent_text = 0;
407 	d->cpu = devinit->machine->cpus[0];		/*  TODO  */
408 	d->xsize = 640; d->ysize = 480;
409 	d->bytes_per_pixel = 3;
410 
411 	d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory,
412 	    PS2_FB_ADDR, VFB_PLAYSTATION2,
413 	    d->xsize, d->ysize, d->xsize, d->ysize, 24, "Playstation 2");
414 	if (d->vfb_data == NULL) {
415 		fprintf(stderr, "could not initialize fb, out of memory\n");
416 		exit(1);
417 	}
418 
419 #if 0
420 	test_triangle(d, 300,50, 255,0,0,  50,150, 0,255,0,  600,400, 0,0,255);
421 	test_triangle(d, 310,210, 128,32,0,  175,410, 0,32,0,
422 	    500,470, 125,255,125);
423 	test_triangle(d, 100,450, 255,255,0,  250,370, 0,255,255,
424 	    400,470, 255,0,255);
425 #endif
426 
427 	memory_device_register(devinit->machine->memory, devinit->name,
428 	    devinit->addr, DEV_PS2_GIF_LENGTH, dev_ps2_gif_access, d,
429 	    DM_DEFAULT, NULL);
430 
431 	return 1;
432 }
433 
434