1 |
/* |
2 |
* PearPC |
3 |
* gcard.cc |
4 |
* |
5 |
* Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <cstdlib> |
22 |
#include <cstring> |
23 |
|
24 |
#include "debug/tracers.h" |
25 |
#include "system/display.h" |
26 |
#include "system/arch/sysendian.h" |
27 |
#include "tools/snprintf.h" |
28 |
#include "cpu/cpu.h" |
29 |
#include "io/pic/pic.h" |
30 |
#include "gcard.h" |
31 |
|
32 |
struct VMode { |
33 |
int width, height, bytesPerPixel; |
34 |
}; |
35 |
|
36 |
static VMode stdVModes[] = { |
37 |
{width: 640, height: 480, bytesPerPixel: 2}, |
38 |
{width: 640, height: 480, bytesPerPixel: 4}, |
39 |
{width: 800, height: 600, bytesPerPixel: 2}, |
40 |
{width: 800, height: 600, bytesPerPixel: 4}, |
41 |
{width: 1024, height: 768, bytesPerPixel: 2}, |
42 |
{width: 1024, height: 768, bytesPerPixel: 4}, |
43 |
{width: 1152, height: 864, bytesPerPixel: 2}, |
44 |
{width: 1152, height: 864, bytesPerPixel: 4}, |
45 |
{width: 1280, height: 720, bytesPerPixel: 2}, |
46 |
{width: 1280, height: 720, bytesPerPixel: 4}, |
47 |
{width: 1280, height: 768, bytesPerPixel: 2}, |
48 |
{width: 1280, height: 768, bytesPerPixel: 4}, |
49 |
{width: 1280, height: 960, bytesPerPixel: 2}, |
50 |
{width: 1280, height: 960, bytesPerPixel: 4}, |
51 |
{width: 1280, height: 1024, bytesPerPixel: 2}, |
52 |
{width: 1280, height: 1024, bytesPerPixel: 4}, |
53 |
{width: 1360, height: 768, bytesPerPixel: 2}, |
54 |
{width: 1360, height: 768, bytesPerPixel: 4}, |
55 |
{width: 1600, height: 900, bytesPerPixel: 2}, |
56 |
{width: 1600, height: 900, bytesPerPixel: 4}, |
57 |
{width: 1600, height: 1024, bytesPerPixel: 2}, |
58 |
{width: 1600, height: 1024, bytesPerPixel: 4}, |
59 |
{width: 1600, height: 1200, bytesPerPixel: 2}, |
60 |
{width: 1600, height: 1200, bytesPerPixel: 4}, |
61 |
}; |
62 |
|
63 |
static Container *gGraphicModes; |
64 |
|
65 |
PCI_GCard::PCI_GCard() |
66 |
:PCI_Device("pci-graphic", 0x00, 0x07) |
67 |
{ |
68 |
mIORegSize[0] = 0x800000; |
69 |
mIORegType[0] = PCI_ADDRESS_SPACE_MEM_PREFETCH; |
70 |
|
71 |
// mConfig[0x00] = 0x02; // vendor ID |
72 |
// mConfig[0x01] = 0x10; |
73 |
// mConfig[0x02] = 0x45; // unit ID |
74 |
// mConfig[0x03] = 0x52; |
75 |
mConfig[0x00] = 0x66; // vendor ID |
76 |
mConfig[0x01] = 0x66; |
77 |
mConfig[0x02] = 0x66; // unit ID |
78 |
mConfig[0x03] = 0x66; |
79 |
|
80 |
mConfig[0x08] = 0x00; // revision |
81 |
mConfig[0x09] = 0x00; |
82 |
mConfig[0x0a] = 0x00; |
83 |
mConfig[0x0b] = 0x03; |
84 |
|
85 |
mConfig[0x0e] = 0x00; // header-type |
86 |
|
87 |
assignMemAddress(0, IO_GCARD_FRAMEBUFFER_PA_START); |
88 |
|
89 |
mConfig[0x3c] = IO_PIC_IRQ_GCARD; |
90 |
mConfig[0x3d] = 1; |
91 |
mConfig[0x3e] = 0; |
92 |
mConfig[0x3f] = 0; |
93 |
} |
94 |
|
95 |
bool PCI_GCard::readDeviceMem(uint r, uint32 address, uint32 &data, uint size) |
96 |
{ |
97 |
IO_GRAPHIC_TRACE("read %d, %08x, %d\n", r, address, size); |
98 |
data = 0; |
99 |
return true; |
100 |
} |
101 |
|
102 |
bool PCI_GCard::writeDeviceMem(uint r, uint32 address, uint32 data, uint size) |
103 |
{ |
104 |
IO_GRAPHIC_TRACE("write %d, %08x, %08x, %d\n", r, address, data, size); |
105 |
return true; |
106 |
} |
107 |
|
108 |
#define MAYBE_PPC_HALF_TO_BE(a) ppc_half_from_LE(a) |
109 |
#define MAYBE_PPC_WORD_TO_BE(a) ppc_word_from_LE(a) |
110 |
#define MAYBE_PPC_DWORD_TO_BE(a) ppc_dword_from_LE(a) |
111 |
|
112 |
/*#define MAYBE_PPC_HALF_TO_BE(a) (a) |
113 |
#define MAYBE_PPC_WORD_TO_BE(a) (a) |
114 |
#define MAYBE_PPC_DWORD_TO_BE(a) (a)*/ |
115 |
|
116 |
void FASTCALL gcard_write_1(uint32 addr, uint32 data) |
117 |
{ |
118 |
addr -= IO_GCARD_FRAMEBUFFER_PA_START; |
119 |
*(uint8*)(gFrameBuffer+addr) = data; |
120 |
damageFrameBuffer(addr); |
121 |
} |
122 |
|
123 |
void FASTCALL gcard_write_2(uint32 addr, uint32 data) |
124 |
{ |
125 |
addr -= IO_GCARD_FRAMEBUFFER_PA_START; |
126 |
*(uint16*)(gFrameBuffer+addr) = MAYBE_PPC_HALF_TO_BE(data); |
127 |
damageFrameBuffer(addr); |
128 |
} |
129 |
|
130 |
void FASTCALL gcard_write_4(uint32 addr, uint32 data) |
131 |
{ |
132 |
addr -= IO_GCARD_FRAMEBUFFER_PA_START; |
133 |
*(uint32*)(gFrameBuffer+addr) = MAYBE_PPC_WORD_TO_BE(data); |
134 |
damageFrameBuffer(addr); |
135 |
} |
136 |
|
137 |
void FASTCALL gcard_write_8(uint32 addr, uint64 data) |
138 |
{ |
139 |
addr -= IO_GCARD_FRAMEBUFFER_PA_START; |
140 |
*(uint64*)(gFrameBuffer+addr) = MAYBE_PPC_DWORD_TO_BE(data); |
141 |
damageFrameBuffer(addr); |
142 |
} |
143 |
|
144 |
void FASTCALL gcard_write_16(uint32 addr, uint128 *data) |
145 |
{ |
146 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
147 |
#if HOST_ENDIANESS == HOST_ENDIANESS_LE |
148 |
uint8 *src = (uint8 *)data; |
149 |
|
150 |
for (int i=0; i<16; i++) { |
151 |
gFrameBuffer[addr+15-i] = src[i]; |
152 |
} |
153 |
#elif HOST_ENDIANESS == HOST_ENDIANESS_BE |
154 |
memmove(gFrameBuffer+addr, data, 16); |
155 |
#else |
156 |
#error Unsupported endianess |
157 |
#endif |
158 |
//*(uint64*)(gFrameBuffer+addr) = MAYBE_PPC_DWORD_TO_BE(data->h); |
159 |
//*(uint64*)(gFrameBuffer+addr+8) = MAYBE_PPC_DWORD_TO_BE(data->l); |
160 |
damageFrameBuffer(addr); |
161 |
} |
162 |
|
163 |
void FASTCALL gcard_write_16_native(uint32 addr, uint128 *data) |
164 |
{ |
165 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
166 |
|
167 |
memmove(gFrameBuffer+addr, data, 16); |
168 |
|
169 |
damageFrameBuffer(addr); |
170 |
} |
171 |
|
172 |
void FASTCALL gcard_read_1(uint32 addr, uint32 &data) |
173 |
{ |
174 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
175 |
data = (*(uint8*)(gFrameBuffer+addr)); |
176 |
} |
177 |
|
178 |
void FASTCALL gcard_read_2(uint32 addr, uint32 &data) |
179 |
{ |
180 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
181 |
data = MAYBE_PPC_HALF_TO_BE(*(uint16*)(gFrameBuffer+addr)); |
182 |
} |
183 |
|
184 |
void FASTCALL gcard_read_4(uint32 addr, uint32 &data) |
185 |
{ |
186 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
187 |
data = MAYBE_PPC_WORD_TO_BE(*(uint32*)(gFrameBuffer+addr)); |
188 |
} |
189 |
|
190 |
void FASTCALL gcard_read_8(uint32 addr, uint64 &data) |
191 |
{ |
192 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
193 |
data = MAYBE_PPC_DWORD_TO_BE(*(uint64*)(gFrameBuffer+addr)); |
194 |
} |
195 |
|
196 |
void FASTCALL gcard_read_16(uint32 addr, uint128 *data) |
197 |
{ |
198 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
199 |
#if HOST_ENDIANESS == HOST_ENDIANESS_LE |
200 |
uint8 *store = (uint8 *)data; |
201 |
|
202 |
for (int i=0; i<16; i++) { |
203 |
store[i] = gFrameBuffer[addr+15-i]; |
204 |
} |
205 |
#elif HOST_ENDIANESS == HOST_ENDIANESS_BE |
206 |
memmove(data, gFrameBuffer+addr, 16); |
207 |
#else |
208 |
#error Unsupported endianess |
209 |
#endif |
210 |
//data->h = MAYBE_PPC_DWORD_TO_BE(*(uint64*)(gFrameBuffer+addr)); |
211 |
//data->l = MAYBE_PPC_DWORD_TO_BE(*(uint64*)(gFrameBuffer+addr+8)); |
212 |
} |
213 |
|
214 |
void FASTCALL gcard_read_16_native(uint32 addr, uint128 *data) |
215 |
{ |
216 |
addr-= IO_GCARD_FRAMEBUFFER_PA_START; |
217 |
|
218 |
memmove(data, gFrameBuffer+addr, 16); |
219 |
} |
220 |
|
221 |
static bool gVBLon = false; |
222 |
static int gCurrentGraphicMode; |
223 |
|
224 |
void gcard_raise_interrupt() |
225 |
{ |
226 |
if (gVBLon) pic_raise_interrupt(IO_PIC_IRQ_GCARD); |
227 |
} |
228 |
|
229 |
void gcard_osi(int cpu) |
230 |
{ |
231 |
IO_GRAPHIC_TRACE("osi: %d\n", ppc_cpu_get_gpr(cpu, 5)); |
232 |
switch (ppc_cpu_get_gpr(cpu, 5)) { |
233 |
case 4: |
234 |
// cmount |
235 |
return; |
236 |
case 28: { |
237 |
// set_vmode |
238 |
uint vmode = ppc_cpu_get_gpr(cpu, 6)-1; |
239 |
if (vmode > gGraphicModes->count() || ppc_cpu_get_gpr(cpu, 7)) { |
240 |
ppc_cpu_set_gpr(cpu, 3, 1); |
241 |
return; |
242 |
} |
243 |
DisplayCharacteristics *chr = (DisplayCharacteristics *)(*gGraphicModes)[vmode]; |
244 |
IO_GRAPHIC_TRACE("set mode %d\n", vmode); |
245 |
if (gDisplay->changeResolution(*chr)) { |
246 |
ppc_cpu_set_gpr(cpu, 3, 0); |
247 |
gcard_set_mode(*chr); |
248 |
} else { |
249 |
ppc_cpu_set_gpr(cpu, 3, 1); |
250 |
} |
251 |
return; |
252 |
} |
253 |
case 29: { |
254 |
/* |
255 |
typedef struct osi_get_vmode_info { |
256 |
short num_vmodes; |
257 |
short cur_vmode; // 1,2,... |
258 |
short num_depths; |
259 |
short cur_depth_mode; // 0,1,2,... |
260 |
short w,h; |
261 |
int refresh; // Hz/65536 |
262 |
|
263 |
int depth; |
264 |
short row_bytes; |
265 |
short offset; |
266 |
} osi_get_vmode_info_t; |
267 |
*/ |
268 |
// get_vmode_info |
269 |
int vmode = ppc_cpu_get_gpr(cpu, 6) - 1; |
270 |
int depth_mode = ppc_cpu_get_gpr(cpu, 7); |
271 |
if (vmode == -1) { |
272 |
vmode = gCurrentGraphicMode; |
273 |
depth_mode = ((DisplayCharacteristics *)(*gGraphicModes)[vmode])->bytesPerPixel*8; |
274 |
} |
275 |
if (vmode > (int)gGraphicModes->count() || vmode < 0) { |
276 |
ppc_cpu_set_gpr(cpu, 3, 1); |
277 |
return; |
278 |
} |
279 |
DisplayCharacteristics *chr = ((DisplayCharacteristics *)(*gGraphicModes)[vmode]); |
280 |
ppc_cpu_set_gpr(cpu, 3, 0); |
281 |
ppc_cpu_set_gpr(cpu, 4, (gGraphicModes->count()<<16) | (vmode+1)); |
282 |
ppc_cpu_set_gpr(cpu, 5, (1<<16) | 0); |
283 |
ppc_cpu_set_gpr(cpu, 6, (chr->width << 16) | chr->height); |
284 |
ppc_cpu_set_gpr(cpu, 7, chr->vsyncFrequency << 16); |
285 |
ppc_cpu_set_gpr(cpu, 8, chr->bytesPerPixel*8); |
286 |
ppc_cpu_set_gpr(cpu, 9, ((chr->scanLineLength)<<16) | 0); |
287 |
return; |
288 |
} |
289 |
case 31: |
290 |
// set_video_power |
291 |
ppc_cpu_set_gpr(cpu, 3, 0); |
292 |
return; |
293 |
case 39: |
294 |
IO_GRAPHIC_TRACE("video_ctrl: %d\n", ppc_cpu_get_gpr(cpu, 6)); |
295 |
// video_ctrl |
296 |
switch (ppc_cpu_get_gpr(cpu, 6)) { |
297 |
case 0: |
298 |
gVBLon = false; |
299 |
break; |
300 |
case 1: |
301 |
gVBLon = true; |
302 |
break; |
303 |
default: |
304 |
IO_GRAPHIC_ERR("39\n"); |
305 |
} |
306 |
ppc_cpu_set_gpr(cpu, 3, 0); |
307 |
return; |
308 |
case 47: |
309 |
// printf("%c\n", gCPU.gpr[6]); |
310 |
return; |
311 |
case 59: { |
312 |
// set_color |
313 |
uint32 r7 = ppc_cpu_get_gpr(cpu, 7); |
314 |
gDisplay->setColor(ppc_cpu_get_gpr(cpu, 6), MK_RGB((r7>>16)&0xff, (r7>>8)&0xff, r7&0xff)); |
315 |
ppc_cpu_set_gpr(cpu, 3, 0); |
316 |
return; |
317 |
} |
318 |
case 64: { |
319 |
// get_color |
320 |
RGB c = gDisplay->getColor(ppc_cpu_get_gpr(cpu, 6)); |
321 |
ppc_cpu_set_gpr(cpu, 3, (RGB_R(c) << 16) | (RGB_G(c) << 8) | (RGB_B(c))); |
322 |
return; |
323 |
} |
324 |
case 116: |
325 |
// hardware_cursor_bla |
326 |
// SINGLESTEP("hw cursor!! %d, %d, %d\n", gCPU.gpr[6], gCPU.gpr[7], gCPU.gpr[8]); |
327 |
IO_GRAPHIC_TRACE("hw cursor!! %d, %d, %d\n", ppc_cpu_get_gpr(cpu, 6), ppc_cpu_get_gpr(cpu, 7), ppc_cpu_get_gpr(cpu, 8)); |
328 |
gDisplay->setHWCursor(ppc_cpu_get_gpr(cpu, 6), ppc_cpu_get_gpr(cpu, 7), ppc_cpu_get_gpr(cpu, 8), NULL); |
329 |
return; |
330 |
} |
331 |
IO_GRAPHIC_ERR("unknown osi function\n"); |
332 |
} |
333 |
|
334 |
/* |
335 |
* displayCharacteristicsFromString tries to create a(n unfinished) characteristic |
336 |
* from a String of the form [0-9]+x[0-9]+x(15|32)(@[0-9]+)? |
337 |
*/ |
338 |
|
339 |
bool displayCharacteristicsFromString(DisplayCharacteristics &aChar, const String &s) |
340 |
{ |
341 |
String width, height, depth; |
342 |
String tmp, tmp2; |
343 |
if (!s.leftSplit('x', width, tmp)) return false; |
344 |
if (!width.toInt(aChar.width)) return false; |
345 |
if (!tmp.leftSplit('x', height, tmp2)) return false; |
346 |
if (!height.toInt(aChar.height)) return false; |
347 |
if (tmp2.leftSplit('@', depth, tmp)) { |
348 |
if (!depth.toInt(aChar.bytesPerPixel)) return false; |
349 |
if (!tmp.toInt(aChar.vsyncFrequency)) return false; |
350 |
} else { |
351 |
aChar.vsyncFrequency = -1; |
352 |
if (!tmp2.toInt(aChar.bytesPerPixel)) return false; |
353 |
} |
354 |
aChar.scanLineLength = -1; |
355 |
aChar.redShift = -1; |
356 |
aChar.redSize = -1; |
357 |
aChar.greenShift = -1; |
358 |
aChar.greenSize = -1; |
359 |
aChar.blueShift = -1; |
360 |
aChar.blueSize = -1; |
361 |
return true; |
362 |
} |
363 |
|
364 |
void gcard_add_characteristic(const DisplayCharacteristics &aChar) |
365 |
{ |
366 |
if (!gcard_supports_characteristic(aChar)) { |
367 |
DisplayCharacteristics *chr = new DisplayCharacteristics; |
368 |
*chr = aChar; |
369 |
gGraphicModes->insert(chr); |
370 |
} |
371 |
} |
372 |
|
373 |
bool gcard_supports_characteristic(const DisplayCharacteristics &aChar) |
374 |
{ |
375 |
return gGraphicModes->contains(&aChar); |
376 |
} |
377 |
|
378 |
/* |
379 |
* gcard_finish_characteristic will fill out all fields |
380 |
* of aChar that aren't initialized yet (set to -1). |
381 |
*/ |
382 |
bool gcard_finish_characteristic(DisplayCharacteristics &aChar) |
383 |
{ |
384 |
if (aChar.width == -1 || aChar.height == -1 || aChar.bytesPerPixel == -1) return false; |
385 |
if (aChar.vsyncFrequency == -1) aChar.vsyncFrequency = 60; |
386 |
if (aChar.scanLineLength == -1) aChar.scanLineLength = aChar.width * aChar.bytesPerPixel; |
387 |
switch (aChar.bytesPerPixel) { |
388 |
case 2: |
389 |
|
390 |
if (aChar.redShift == -1) aChar.redShift = 10; |
391 |
if (aChar.redSize == -1) aChar.redSize = 5; |
392 |
if (aChar.greenShift == -1) aChar.greenShift = 5; |
393 |
if (aChar.greenSize == -1) aChar.greenSize = 5; |
394 |
if (aChar.blueShift == -1) aChar.blueShift = 0; |
395 |
if (aChar.blueSize == -1) aChar.blueSize = 5; |
396 |
break; |
397 |
case 4: |
398 |
if (aChar.redShift == -1) aChar.redShift = 16; |
399 |
if (aChar.redSize == -1) aChar.redSize = 8; |
400 |
if (aChar.greenShift == -1) aChar.greenShift = 8; |
401 |
if (aChar.greenSize == -1) aChar.greenSize = 8; |
402 |
if (aChar.blueShift == -1) aChar.blueShift = 0; |
403 |
if (aChar.blueSize == -1) aChar.blueSize = 8; |
404 |
break; |
405 |
default: |
406 |
return false; |
407 |
} |
408 |
return true; |
409 |
} |
410 |
|
411 |
bool gcard_set_mode(DisplayCharacteristics &mode) |
412 |
{ |
413 |
uint tmp = gGraphicModes->getObjIdx(gGraphicModes->find(&mode)); |
414 |
if (tmp == InvIdx) { |
415 |
return false; |
416 |
} else { |
417 |
gCurrentGraphicMode = tmp; |
418 |
return true; |
419 |
} |
420 |
} |
421 |
|
422 |
void gcard_init_modes() |
423 |
{ |
424 |
gGraphicModes = new Array(true); |
425 |
for (uint i=0; i < (sizeof stdVModes / sizeof stdVModes[0]); i++) { |
426 |
DisplayCharacteristics chr; |
427 |
chr.width = stdVModes[i].width; |
428 |
chr.height = stdVModes[i].height; |
429 |
chr.bytesPerPixel = stdVModes[i].bytesPerPixel; |
430 |
chr.scanLineLength = -1; |
431 |
chr.vsyncFrequency = -1; |
432 |
chr.redShift = -1; |
433 |
chr.redSize = -1; |
434 |
chr.greenShift = -1; |
435 |
chr.greenSize = -1; |
436 |
chr.blueShift = -1; |
437 |
chr.blueSize = -1; |
438 |
gcard_finish_characteristic(chr); |
439 |
gcard_add_characteristic(chr); |
440 |
} |
441 |
} |
442 |
|
443 |
void gcard_init_host_modes() |
444 |
{ |
445 |
Array modes(true); |
446 |
gDisplay->getHostCharacteristics(modes); |
447 |
foreach (DisplayCharacteristics, chr, modes, { |
448 |
gcard_finish_characteristic(*chr); |
449 |
gcard_add_characteristic(*chr); |
450 |
}); |
451 |
} |
452 |
|
453 |
void gcard_init() |
454 |
{ |
455 |
gPCI_Devices->insert(new PCI_GCard()); |
456 |
} |
457 |
|
458 |
void gcard_done() |
459 |
{ |
460 |
} |
461 |
|
462 |
void gcard_init_config() |
463 |
{ |
464 |
} |