1 /*Trident TGUI9400CXi & TGUI9440 emulation*/
2 #include <stdlib.h>
3 #include "ibm.h"
4 #include "device.h"
5 #include "io.h"
6 #include "mem.h"
7 #include "pci.h"
8 #include "rom.h"
9 #include "thread.h"
10 #include "video.h"
11 #include "vid_svga.h"
12 #include "vid_svga_render.h"
13 #include "vid_tkd8001_ramdac.h"
14 #include "vid_tgui9440.h"
15
16 /*TGUI9400CXi has extended write modes, controlled by extended GDC registers :
17
18 GDC[0x10] - Control
19 bit 0 - pixel width (1 = 16 bit, 0 = 8 bit)
20 bit 1 - mono->colour expansion (1 = enabled, 0 = disabled)
21 bit 2 - mono->colour expansion transparency (1 = tranparent, 0 = opaque)
22 bit 3 - extended latch copy
23 GDC[0x11] - Background colour (low byte)
24 GDC[0x12] - Background colour (high byte)
25 GDC[0x14] - Foreground colour (low byte)
26 GDC[0x15] - Foreground colour (high byte)
27 GDC[0x17] - Write mask (low byte)
28 GDC[0x18] - Write mask (high byte)
29
30 Mono->colour expansion will expand written data 8:1 to 8/16 consecutive bytes.
31 MSB is processed first. On word writes, low byte is processed first. 1 bits write
32 foreground colour, 0 bits write background colour unless transparency is enabled.
33 If the relevant bit is clear in the write mask then the data is not written.
34
35 With 16-bit pixel width, each bit still expands to one byte, so the TGUI driver
36 doubles up monochrome data.
37
38 While there is room in the register map for three byte colours, I don't believe
39 24-bit colour is supported. The TGUI9440 blitter has the same limitation.
40
41 I don't think double word writes are supported.
42
43 Extended latch copy uses an internal 16 byte latch. Reads load the latch, writing
44 writes out 16 bytes. I don't think the access size or host data has any affect,
45 but the Windows 3.1 driver always reads bytes and write words of 0xffff.*/
46
47 #define EXT_CTRL_16BIT 0x01
48 #define EXT_CTRL_MONO_EXPANSION 0x02
49 #define EXT_CTRL_MONO_TRANSPARENT 0x04
50 #define EXT_CTRL_LATCH_COPY 0x08
51
52 #define FIFO_SIZE 65536
53 #define FIFO_MASK (FIFO_SIZE - 1)
54 #define FIFO_ENTRY_SIZE (1 << 31)
55
56 #define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx)
57 #define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE)
58 #define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx)
59
60 #define FIFO_TYPE 0xff000000
61 #define FIFO_ADDR 0x00ffffff
62
63 enum
64 {
65 TGUI_9400CXI = 0,
66 TGUI_9440
67 };
68
69 enum
70 {
71 FIFO_INVALID = (0x00 << 24),
72 FIFO_WRITE_BYTE = (0x01 << 24),
73 FIFO_WRITE_FB_BYTE = (0x04 << 24),
74 FIFO_WRITE_FB_WORD = (0x05 << 24),
75 FIFO_WRITE_FB_LONG = (0x06 << 24)
76 };
77
78 typedef struct
79 {
80 uint32_t addr_type;
81 uint32_t val;
82 } fifo_entry_t;
83
84 typedef struct tgui_t
85 {
86 mem_mapping_t linear_mapping;
87 mem_mapping_t accel_mapping;
88
89 rom_t bios_rom;
90
91 svga_t svga;
92
93 tkd8001_ramdac_t ramdac; /*TGUI9400CXi*/
94
95 int type;
96
97 struct
98 {
99 uint16_t src_x, src_y;
100 uint16_t dst_x, dst_y;
101 uint16_t size_x, size_y;
102 uint16_t fg_col, bg_col;
103 uint8_t rop;
104 uint16_t flags;
105 uint8_t pattern[0x80];
106 int command;
107 int offset;
108 uint8_t ger22;
109
110 int x, y;
111 uint32_t src, dst, src_old, dst_old;
112 int pat_x, pat_y;
113 int use_src;
114
115 int pitch, bpp;
116
117 uint16_t tgui_pattern[8][8];
118 } accel;
119
120 uint8_t ext_gdc_regs[16]; /*TGUI9400CXi only*/
121 uint8_t copy_latch[16];
122
123 uint8_t tgui_3d8, tgui_3d9;
124 int oldmode;
125 uint8_t oldctrl1;
126 uint8_t oldctrl2,newctrl2;
127
128 uint32_t linear_base, linear_size;
129
130 int ramdac_state;
131 uint8_t ramdac_ctrl;
132
133 int clock_m, clock_n, clock_k;
134
135 uint32_t vram_size, vram_mask;
136
137 fifo_entry_t fifo[FIFO_SIZE];
138 volatile int fifo_read_idx, fifo_write_idx;
139
140 thread_t *fifo_thread;
141 event_t *wake_fifo_thread;
142 event_t *fifo_not_full_event;
143
144 int blitter_busy;
145 uint64_t blitter_time;
146 uint64_t status_time;
147
148 volatile int write_blitter;
149 } tgui_t;
150
151 void tgui_recalcmapping(tgui_t *tgui);
152
153 static void fifo_thread(void *param);
154
155 uint8_t tgui_accel_read(uint32_t addr, void *priv);
156 uint16_t tgui_accel_read_w(uint32_t addr, void *priv);
157 uint32_t tgui_accel_read_l(uint32_t addr, void *priv);
158
159 void tgui_accel_write(uint32_t addr, uint8_t val, void *priv);
160 void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv);
161 void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv);
162
163 void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv);
164 void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv);
165 void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv);
166
167 static uint8_t tgui_ext_linear_read(uint32_t addr, void *p);
168 static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p);
169 static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p);
170 static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p);
171
172 static uint8_t tgui_ext_read(uint32_t addr, void *p);
173 static void tgui_ext_write(uint32_t addr, uint8_t val, void *p);
174 static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p);
175 static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p);
176
tgui_out(uint16_t addr,uint8_t val,void * p)177 void tgui_out(uint16_t addr, uint8_t val, void *p)
178 {
179 tgui_t *tgui = (tgui_t *)p;
180 svga_t *svga = &tgui->svga;
181
182 uint8_t old;
183
184 // pclog("tgui_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp);
185 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
186
187 switch (addr)
188 {
189 case 0x3C5:
190 switch (svga->seqaddr & 0xf)
191 {
192 case 0xB:
193 tgui->oldmode=1;
194 break;
195 case 0xC:
196 if (svga->seqregs[0xe] & 0x80)
197 svga->seqregs[0xc] = val;
198 break;
199 case 0xd:
200 if (tgui->oldmode)
201 tgui->oldctrl2 = val;
202 else
203 tgui->newctrl2=val;
204 break;
205 case 0xE:
206 if (tgui->oldmode)
207 tgui->oldctrl1 = val;
208 else
209 {
210 svga->seqregs[0xe] = val ^ 2;
211 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
212 if (!(svga->gdcreg[0xf] & 1))
213 svga->read_bank = svga->write_bank;
214 }
215 return;
216 }
217 break;
218
219 case 0x3C6:
220 if (tgui->type == TGUI_9400CXI)
221 {
222 tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga);
223 return;
224 }
225 if (tgui->ramdac_state == 4)
226 {
227 tgui->ramdac_state = 0;
228 tgui->ramdac_ctrl = val;
229 switch (tgui->ramdac_ctrl & 0xf0)
230 {
231 case 0x10:
232 svga->bpp = 15;
233 break;
234 case 0x30:
235 svga->bpp = 16;
236 break;
237 case 0xd0:
238 svga->bpp = 24;
239 break;
240 default:
241 svga->bpp = 8;
242 break;
243 }
244 return;
245 }
246 case 0x3C7: case 0x3C8: case 0x3C9:
247 if (tgui->type == TGUI_9400CXI)
248 {
249 tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga);
250 return;
251 }
252 tgui->ramdac_state = 0;
253 break;
254
255 case 0x3CF:
256 if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32)
257 {
258 old = tgui->ext_gdc_regs[svga->gdcaddr & 15];
259 tgui->ext_gdc_regs[svga->gdcaddr & 15] = val;
260 if (svga->gdcaddr == 16)
261 tgui_recalcmapping(tgui);
262 return;
263 }
264 switch (svga->gdcaddr & 15)
265 {
266 case 0x6:
267 if (svga->gdcreg[6] != val)
268 {
269 svga->gdcreg[6] = val;
270 tgui_recalcmapping(tgui);
271 }
272 return;
273
274 case 0xE:
275 svga->gdcreg[0xe] = val ^ 2;
276 if ((svga->gdcreg[0xf] & 1) == 1)
277 svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536;
278 break;
279 case 0xF:
280 if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536;
281 else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536;
282 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
283 break;
284 }
285 break;
286 case 0x3D4:
287 svga->crtcreg = val & 0x7f;
288 return;
289 case 0x3D5:
290 if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
291 return;
292 if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
293 val = (svga->crtc[7] & ~0x10) | (val & 0x10);
294 old = svga->crtc[svga->crtcreg];
295 svga->crtc[svga->crtcreg] = val;
296 // if (svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X\n", svga->crtcreg, val);
297 if (old != val)
298 {
299 if (svga->crtcreg < 0xE || svga->crtcreg > 0x10)
300 {
301 svga->fullchange = changeframecount;
302 svga_recalctimings(svga);
303 }
304 }
305 switch (svga->crtcreg)
306 {
307 case 0x21:
308 if (old != val)
309 {
310 if (!PCI)
311 {
312 tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20;
313 tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000;
314 tgui->svga.decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff;
315 }
316 tgui_recalcmapping(tgui);
317 }
318 break;
319
320 case 0x40: case 0x41: case 0x42: case 0x43:
321 case 0x44: case 0x45: case 0x46: case 0x47:
322 if (tgui->type >= TGUI_9440)
323 {
324 svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff;
325 svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff;
326 svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f;
327 svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f;
328 svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8);
329 }
330 break;
331
332 case 0x50:
333 if (tgui->type >= TGUI_9440)
334 {
335 svga->hwcursor.ena = val & 0x80;
336 svga->hwcursor.xsize = (val & 1) ? 64 : 32;
337 svga->hwcursor.ysize = (val & 1) ? 64 : 32;
338 }
339 break;
340 }
341 return;
342 case 0x3D8:
343 tgui->tgui_3d8 = val;
344 if (svga->gdcreg[0xf] & 4)
345 {
346 svga->write_bank = (val & 0x1f) * 65536;
347 // pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc);
348 if (!(svga->gdcreg[0xf] & 1))
349 {
350 svga->read_bank = (val & 0x1f) * 65536;
351 // pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc);
352 }
353 }
354 return;
355 case 0x3D9:
356 tgui->tgui_3d9 = val;
357 if ((svga->gdcreg[0xf] & 5) == 5)
358 {
359 svga->read_bank = (val & 0x1F) * 65536;
360 // pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc);
361 }
362 return;
363
364 case 0x43c8:
365 tgui->clock_n = val & 0x7f;
366 tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7);
367 break;
368 case 0x43c9:
369 tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e);
370 tgui->clock_k = (val & 0x10) >> 4;
371 break;
372 }
373 svga_out(addr, val, svga);
374 }
375
tgui_in(uint16_t addr,void * p)376 uint8_t tgui_in(uint16_t addr, void *p)
377 {
378 tgui_t *tgui = (tgui_t *)p;
379 svga_t *svga = &tgui->svga;
380
381 // if (addr != 0x3da) pclog("tgui_in : %04X %04X:%04X\n", addr, CS,pc);
382
383 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
384
385 switch (addr)
386 {
387 case 0x3C5:
388 if ((svga->seqaddr & 0xf) == 0xb)
389 {
390 // printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
391 tgui->oldmode = 0;
392 switch (tgui->type)
393 {
394 case TGUI_9400CXI:
395 return 0x93; /*TGUI9400CXi*/
396 case TGUI_9440:
397 return 0xe3; /*TGUI9440AGi*/
398 }
399 }
400 if ((svga->seqaddr & 0xf) == 0xc)
401 {
402 // printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
403 // return 0x20; /*2 DRAM banks*/
404 }
405 if ((svga->seqaddr & 0xf) == 0xd)
406 {
407 if (tgui->oldmode)
408 return tgui->oldctrl2;
409 return tgui->newctrl2;
410 }
411 if ((svga->seqaddr & 0xf) == 0xe)
412 {
413 if (tgui->oldmode)
414 return tgui->oldctrl1;
415 }
416 break;
417 case 0x3C6:
418 if (tgui->type == TGUI_9400CXI)
419 return tkd8001_ramdac_in(addr, &tgui->ramdac, svga);
420 if (tgui->ramdac_state == 4)
421 return tgui->ramdac_ctrl;
422 tgui->ramdac_state++;
423 break;
424 case 0x3C7: case 0x3C8: case 0x3C9:
425 if (tgui->type == TGUI_9400CXI)
426 return tkd8001_ramdac_in(addr, &tgui->ramdac, svga);
427 tgui->ramdac_state = 0;
428 break;
429 case 0x3CF:
430 if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32)
431 return tgui->ext_gdc_regs[svga->gdcaddr & 15];
432 break;
433 case 0x3D4:
434 return svga->crtcreg;
435 case 0x3D5:
436 return svga->crtc[svga->crtcreg];
437 case 0x3d8:
438 return tgui->tgui_3d8;
439 case 0x3d9:
440 return tgui->tgui_3d9;
441 }
442 return svga_in(addr, svga);
443 }
444
tgui_recalctimings(svga_t * svga)445 void tgui_recalctimings(svga_t *svga)
446 {
447 tgui_t *tgui = (tgui_t *)svga->p;
448
449 if (svga->crtc[0x29] & 0x10)
450 svga->rowoffset += 0x100;
451
452 if (tgui->type >= TGUI_9440 && svga->bpp == 24)
453 svga->hdisp = (svga->crtc[1] + 1) * 8;
454
455 if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000;
456 if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000;
457 if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000;
458
459 if (tgui->oldctrl2 & 0x10)
460 svga->rowoffset <<= 1;
461 if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40))
462 svga->ma_latch <<= 1;
463
464 if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/
465 svga->lowres=0;
466
467 svga->lowres = !(svga->crtc[0x2a] & 0x40);
468
469 svga->interlace = svga->crtc[0x1e] & 4;
470 if (svga->interlace && tgui->type < TGUI_9440)
471 svga->rowoffset >>= 1;
472
473 if (svga->crtc[0x17] & 4)
474 {
475 svga->vtotal *= 2;
476 svga->dispend *= 2;
477 svga->vsyncstart *= 2;
478 svga->split *= 2;
479 svga->vblankstart *= 2;
480 }
481
482 if (tgui->type >= TGUI_9440)
483 {
484 if (svga->miscout & 8)
485 svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k)));
486
487 if (svga->gdcreg[0xf] & 0x08)
488 svga->clock *= 2;
489 else if (svga->gdcreg[0xf] & 0x40)
490 svga->clock *= 3;
491 }
492 else
493 {
494 switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8))
495 {
496 case 0x02: svga->clock = cpuclock/ 44900000.0; break;
497 case 0x03: svga->clock = cpuclock/ 36000000.0; break;
498 case 0x04: svga->clock = cpuclock/ 57272000.0; break;
499 case 0x05: svga->clock = cpuclock/ 65000000.0; break;
500 case 0x06: svga->clock = cpuclock/ 50350000.0; break;
501 case 0x07: svga->clock = cpuclock/ 40000000.0; break;
502 case 0x08: svga->clock = cpuclock/ 88000000.0; break;
503 case 0x09: svga->clock = cpuclock/ 98000000.0; break;
504 case 0x0a: svga->clock = cpuclock/118800000.0; break;
505 case 0x0b: svga->clock = cpuclock/108000000.0; break;
506 case 0x0c: svga->clock = cpuclock/ 72000000.0; break;
507 case 0x0d: svga->clock = cpuclock/ 77000000.0; break;
508 case 0x0e: svga->clock = cpuclock/ 80000000.0; break;
509 case 0x0f: svga->clock = cpuclock/ 75000000.0; break;
510 }
511 if (svga->gdcreg[0xf] & 0x08)
512 {
513 svga->htotal *= 2;
514 svga->hdisp *= 2;
515 svga->hdisp_time *= 2;
516 }
517 }
518
519 if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40))
520 {
521 switch (svga->bpp)
522 {
523 case 8:
524 svga->render = svga_render_8bpp_highres;
525 break;
526 case 15:
527 svga->render = svga_render_15bpp_highres;
528 if (tgui->type < TGUI_9440)
529 svga->hdisp /= 2;
530 break;
531 case 16:
532 svga->render = svga_render_16bpp_highres;
533 if (tgui->type < TGUI_9440)
534 svga->hdisp /= 2;
535 break;
536 case 24:
537 svga->render = svga_render_24bpp_highres;
538 if (tgui->type < TGUI_9440)
539 svga->hdisp = (svga->hdisp * 2) / 3;
540 break;
541 }
542 }
543 }
544
tgui_recalcmapping(tgui_t * tgui)545 void tgui_recalcmapping(tgui_t *tgui)
546 {
547 svga_t *svga = &tgui->svga;
548
549 // pclog("tgui_recalcmapping : %02X %02X\n", svga->crtc[0x21], svga->gdcreg[6]);
550
551 if (tgui->type == TGUI_9400CXI)
552 {
553 if (tgui->ext_gdc_regs[0] & EXT_CTRL_LATCH_COPY)
554 {
555 mem_mapping_set_handler(&tgui->linear_mapping,
556 tgui_ext_linear_read, NULL, NULL,
557 tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel);
558 mem_mapping_set_handler(&svga->mapping,
559 tgui_ext_read, NULL, NULL,
560 tgui_ext_write, tgui_ext_writew, tgui_ext_writel);
561 }
562 else if (tgui->ext_gdc_regs[0] & EXT_CTRL_MONO_EXPANSION)
563 {
564 mem_mapping_set_handler(&tgui->linear_mapping,
565 svga_read_linear, svga_readw_linear, svga_readl_linear,
566 tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel);
567 mem_mapping_set_handler(&svga->mapping,
568 svga_read, svga_readw, svga_readl,
569 tgui_ext_write, tgui_ext_writew, tgui_ext_writel);
570 }
571 else
572 {
573 mem_mapping_set_handler(&tgui->linear_mapping,
574 svga_read_linear, svga_readw_linear, svga_readl_linear,
575 svga_write_linear, svga_writew_linear, svga_writel_linear);
576 mem_mapping_set_handler(&svga->mapping,
577 svga_read, svga_readw, svga_readl,
578 svga_write, svga_writew, svga_writel);
579 }
580 }
581
582 if (svga->crtc[0x21] & 0x20)
583 {
584 mem_mapping_disable(&svga->mapping);
585 mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size);
586 // pclog("Trident linear framebuffer at %08X - size %06X\n", tgui->linear_base, tgui->linear_size);
587 if (tgui->type >= TGUI_9440)
588 {
589 mem_mapping_enable(&tgui->accel_mapping);
590 mem_mapping_disable(&svga->mapping);
591 }
592 else
593 {
594 switch (svga->gdcreg[6] & 0xC)
595 {
596 case 0x0: /*128k at A0000*/
597 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
598 svga->banked_mask = 0xffff;
599 break;
600 case 0x4: /*64k at A0000*/
601 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
602 svga->banked_mask = 0xffff;
603 break;
604 case 0x8: /*32k at B0000*/
605 mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
606 svga->banked_mask = 0x7fff;
607 break;
608 case 0xC: /*32k at B8000*/
609 mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
610 svga->banked_mask = 0x7fff;
611 break;
612 }
613 }
614 }
615 else
616 {
617 // pclog("Write mapping %02X\n", val);
618 mem_mapping_disable(&tgui->linear_mapping);
619 mem_mapping_disable(&tgui->accel_mapping);
620 switch (svga->gdcreg[6] & 0xC)
621 {
622 case 0x0: /*128k at A0000*/
623 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
624 svga->banked_mask = 0xffff;
625 break;
626 case 0x4: /*64k at A0000*/
627 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
628 mem_mapping_enable(&tgui->accel_mapping);
629 svga->banked_mask = 0xffff;
630 break;
631 case 0x8: /*32k at B0000*/
632 mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
633 svga->banked_mask = 0x7fff;
634 break;
635 case 0xC: /*32k at B8000*/
636 mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
637 svga->banked_mask = 0x7fff;
638 break;
639 }
640 }
641 }
642
tgui_hwcursor_draw(svga_t * svga,int displine)643 void tgui_hwcursor_draw(svga_t *svga, int displine)
644 {
645 uint32_t dat[2];
646 int xx;
647 int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
648
649 if (svga->interlace && svga->hwcursor_oddeven)
650 svga->hwcursor_latch.addr += 8;
651
652 dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
653 dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7];
654 for (xx = 0; xx < 32; xx++)
655 {
656 if (offset >= svga->hwcursor_latch.x)
657 {
658 if (!(dat[0] & 0x80000000))
659 ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x80000000) ? 0xffffff : 0;
660 else if (dat[1] & 0x80000000)
661 ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
662 // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
663 }
664
665 offset++;
666 dat[0] <<= 1;
667 dat[1] <<= 1;
668 }
669 svga->hwcursor_latch.addr += 8;
670
671 if (svga->interlace && !svga->hwcursor_oddeven)
672 svga->hwcursor_latch.addr += 8;
673 }
674
tgui_pci_read(int func,int addr,void * p)675 uint8_t tgui_pci_read(int func, int addr, void *p)
676 {
677 tgui_t *tgui = (tgui_t *)p;
678
679 // pclog("Trident PCI read %08X\n", addr);
680
681 switch (addr)
682 {
683 case 0x00: return 0x23; /*Trident*/
684 case 0x01: return 0x10;
685
686 case 0x02: return 0x40; /*TGUI9440 (9682)*/
687 case 0x03: return 0x94;
688
689 case 0x04: return 0x03; /*Respond to IO and memory accesses*/
690
691 case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
692
693 case 0x08: return 0; /*Revision ID*/
694 case 0x09: return 0; /*Programming interface*/
695
696 case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/
697 case 0x0b: return 0x03;
698
699 case 0x10: return 0x00; /*Linear frame buffer address*/
700 case 0x11: return 0x00;
701 case 0x12: return tgui->linear_base >> 16;
702 case 0x13: return tgui->linear_base >> 24;
703
704 case 0x30: return 0x01; /*BIOS ROM address*/
705 case 0x31: return 0x00;
706 case 0x32: return 0x0C;
707 case 0x33: return 0x00;
708 }
709 return 0;
710 }
711
tgui_pci_write(int func,int addr,uint8_t val,void * p)712 void tgui_pci_write(int func, int addr, uint8_t val, void *p)
713 {
714 tgui_t *tgui = (tgui_t *)p;
715 svga_t *svga = &tgui->svga;
716
717 // pclog("Trident PCI write %08X %02X\n", addr, val);
718
719 switch (addr)
720 {
721 case 0x12:
722 tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16);
723 tgui->linear_size = 2 << 20;
724 tgui->svga.decode_mask = 0x1fffff;
725 svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4);
726 tgui_recalcmapping(tgui);
727 break;
728 case 0x13:
729 tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24);
730 tgui->linear_size = 2 << 20;
731 tgui->svga.decode_mask = 0x1fffff;
732 svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6);
733 tgui_recalcmapping(tgui);
734 break;
735 }
736 }
737
tgui_init(char * bios_fn,int type,int mem_size)738 static void *tgui_init(char *bios_fn, int type, int mem_size)
739 {
740 tgui_t *tgui = malloc(sizeof(tgui_t));
741 memset(tgui, 0, sizeof(tgui_t));
742
743 if (mem_size)
744 tgui->vram_size = mem_size;
745 else
746 tgui->vram_size = device_get_config_int("memory") << 20;
747 tgui->vram_mask = tgui->vram_size - 1;
748
749 tgui->type = type;
750
751 rom_init(&tgui->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
752
753 svga_init(&tgui->svga, tgui, tgui->vram_size,
754 tgui_recalctimings,
755 tgui_in, tgui_out,
756 tgui_hwcursor_draw,
757 NULL);
758
759 mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, 0, &tgui->svga);
760 mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, 0, tgui);
761 mem_mapping_disable(&tgui->accel_mapping);
762
763 io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui);
764 if (tgui->type >= TGUI_9440)
765 io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui);
766
767 if (tgui->type >= TGUI_9440)
768 pci_add(tgui_pci_read, tgui_pci_write, tgui);
769
770 tgui->wake_fifo_thread = thread_create_event();
771 tgui->fifo_not_full_event = thread_create_event();
772 tgui->fifo_thread = thread_create(fifo_thread, tgui);
773
774 return tgui;
775 }
776
tgui9400cxi_init()777 static void *tgui9400cxi_init()
778 {
779 return tgui_init("9400CXI.vbi", TGUI_9400CXI, 0);
780 }
781
tgui9400cxi_elx_init()782 static void *tgui9400cxi_elx_init()
783 {
784 /*Try combined ROM dump first. If not present, use seperated dump*/
785 FILE *f = romfopen("elx_pc425x/elx_pc425x.bin", "rb");
786 if (f)
787 {
788 fclose(f);
789 return tgui_init("elx_pc425x/elx_pc425x.bin", TGUI_9400CXI, 512 << 10);
790 }
791
792 return tgui_init("elx_pc425x/elx_pc425x_vbios.bin", TGUI_9400CXI, 512 << 10);
793 }
794
tgui9440_init()795 static void *tgui9440_init()
796 {
797 return tgui_init("9440.vbi", TGUI_9440, 0);
798 }
799
tgui9400cxi_available()800 static int tgui9400cxi_available()
801 {
802 return rom_present("9400CXI.vbi");
803 }
804
tgui9440_available()805 static int tgui9440_available()
806 {
807 return rom_present("9440.vbi");
808 }
809
tgui_close(void * p)810 void tgui_close(void *p)
811 {
812 tgui_t *tgui = (tgui_t *)p;
813
814 svga_close(&tgui->svga);
815
816 thread_kill(tgui->fifo_thread);
817 thread_destroy_event(tgui->wake_fifo_thread);
818 thread_destroy_event(tgui->fifo_not_full_event);
819
820 free(tgui);
821 }
822
tgui_speed_changed(void * p)823 void tgui_speed_changed(void *p)
824 {
825 tgui_t *tgui = (tgui_t *)p;
826
827 svga_recalctimings(&tgui->svga);
828 }
829
tgui_force_redraw(void * p)830 void tgui_force_redraw(void *p)
831 {
832 tgui_t *tgui = (tgui_t *)p;
833
834 tgui->svga.fullchange = changeframecount;
835 }
836
837
tgui_ext_linear_read(uint32_t addr,void * p)838 static uint8_t tgui_ext_linear_read(uint32_t addr, void *p)
839 {
840 svga_t *svga = (svga_t *)p;
841 tgui_t *tgui = (tgui_t *)svga->p;
842 int c;
843
844 cycles -= video_timing_read_b;
845 cycles_lost += video_timing_read_b;
846
847 addr &= svga->decode_mask;
848 if (addr >= svga->vram_max)
849 return 0xff;
850
851 addr &= ~0xf;
852 for (c = 0; c < 16; c++)
853 tgui->copy_latch[c] = svga->vram[addr+c];
854
855 return svga->vram[addr & svga->vram_mask];
856 }
857
tgui_ext_read(uint32_t addr,void * p)858 static uint8_t tgui_ext_read(uint32_t addr, void *p)
859 {
860 svga_t *svga = (svga_t *)p;
861
862 addr = (addr & svga->banked_mask) + svga->read_bank;
863
864 return tgui_ext_linear_read(addr, svga);
865 }
866
tgui_ext_linear_write(uint32_t addr,uint8_t val,void * p)867 static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p)
868 {
869 svga_t *svga = (svga_t *)p;
870 tgui_t *tgui = (tgui_t *)svga->p;
871 int c;
872 uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]};
873 uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]};
874 uint8_t mask = tgui->ext_gdc_regs[7];
875
876 cycles -= video_timing_write_b;
877 cycles_lost += video_timing_write_b;
878
879 addr &= svga->decode_mask;
880 if (addr >= svga->vram_max)
881 return;
882 addr &= svga->vram_mask;
883 addr &= ~0x7;
884 svga->changedvram[addr >> 12] = changeframecount;
885
886 switch (tgui->ext_gdc_regs[0] & 0xf)
887 {
888 /*8-bit mono->colour expansion, unmasked*/
889 case 2:
890 for (c = 7; c >= 0; c--)
891 {
892 if (mask & (1 << c))
893 *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0];
894 addr++;
895 }
896 break;
897
898 /*16-bit mono->colour expansion, unmasked*/
899 case 3:
900 for (c = 7; c >= 0; c--)
901 {
902 if (mask & (1 << c))
903 *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1];
904 addr++;
905 }
906 break;
907
908 /*8-bit mono->colour expansion, masked*/
909 case 6:
910 for (c = 7; c >= 0; c--)
911 {
912 if ((val & mask) & (1 << c))
913 *(uint8_t *)&svga->vram[addr] = fg[0];
914 addr++;
915 }
916 break;
917
918 /*16-bit mono->colour expansion, masked*/
919 case 7:
920 for (c = 7; c >= 0; c--)
921 {
922 if ((val & mask) & (1 << c))
923 *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1];
924 addr++;
925 }
926 break;
927
928 case 0x8: case 0x9: case 0xa: case 0xb:
929 case 0xc: case 0xd: case 0xe: case 0xf:
930 addr &= ~0xf;
931 for (c = 0; c < 16; c++)
932 *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c];
933 break;
934 }
935 }
936
tgui_ext_linear_writew(uint32_t addr,uint16_t val,void * p)937 static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p)
938 {
939 svga_t *svga = (svga_t *)p;
940 tgui_t *tgui = (tgui_t *)svga->p;
941 int c;
942 uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]};
943 uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]};
944 uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8];
945
946 cycles -= video_timing_write_w;
947 cycles_lost += video_timing_write_w;
948
949 addr &= svga->decode_mask;
950 if (addr >= svga->vram_max)
951 return;
952 addr &= svga->vram_mask;
953 addr &= ~0xf;
954 svga->changedvram[addr >> 12] = changeframecount;
955
956 val = (val >> 8) | (val << 8);
957
958 switch (tgui->ext_gdc_regs[0] & 0xf)
959 {
960 /*8-bit mono->colour expansion, unmasked*/
961 case 2:
962 for (c = 15; c >= 0; c--)
963 {
964 if (mask & (1 << c))
965 *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0];
966 addr++;
967 }
968 break;
969
970 /*16-bit mono->colour expansion, unmasked*/
971 case 3:
972 for (c = 15; c >= 0; c--)
973 {
974 if (mask & (1 << c))
975 *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1];
976 addr++;
977 }
978 break;
979
980 /*8-bit mono->colour expansion, masked*/
981 case 6:
982 for (c = 15; c >= 0; c--)
983 {
984 if ((val & mask) & (1 << c))
985 *(uint8_t *)&svga->vram[addr] = fg[0];
986 addr++;
987 }
988 break;
989
990 /*16-bit mono->colour expansion, masked*/
991 case 7:
992 for (c = 15; c >= 0; c--)
993 {
994 if ((val & mask) & (1 << c))
995 *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1];
996 addr++;
997 }
998 break;
999
1000 case 0x8: case 0x9: case 0xa: case 0xb:
1001 case 0xc: case 0xd: case 0xe: case 0xf:
1002 for (c = 0; c < 16; c++)
1003 *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c];
1004 break;
1005 }
1006 }
1007
tgui_ext_linear_writel(uint32_t addr,uint32_t val,void * p)1008 static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p)
1009 {
1010 tgui_ext_linear_writew(addr, val, p);
1011 }
1012
tgui_ext_write(uint32_t addr,uint8_t val,void * p)1013 static void tgui_ext_write(uint32_t addr, uint8_t val, void *p)
1014 {
1015 svga_t *svga = (svga_t *)p;
1016
1017 addr = (addr & svga->banked_mask) + svga->read_bank;
1018
1019 tgui_ext_linear_write(addr, val, svga);
1020 }
tgui_ext_writew(uint32_t addr,uint16_t val,void * p)1021 static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p)
1022 {
1023 svga_t *svga = (svga_t *)p;
1024
1025 addr = (addr & svga->banked_mask) + svga->read_bank;
1026
1027 tgui_ext_linear_writew(addr, val, svga);
1028 }
tgui_ext_writel(uint32_t addr,uint32_t val,void * p)1029 static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p)
1030 {
1031 svga_t *svga = (svga_t *)p;
1032
1033 addr = (addr & svga->banked_mask) + svga->read_bank;
1034
1035 tgui_ext_linear_writel(addr, val, svga);
1036 }
1037
1038
1039 enum
1040 {
1041 TGUI_BITBLT = 1
1042 };
1043
1044 enum
1045 {
1046 TGUI_SRCCPU = 0,
1047
1048 TGUI_SRCDISP = 0x04, /*Source is from display*/
1049 TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/
1050 TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/
1051 TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/
1052 TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/
1053 TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/
1054 };
1055
1056 #define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \
1057 else dat = vram_w[addr & 0xfffff];
1058
1059 #define MIX() do \
1060 { \
1061 out = 0; \
1062 for (c=0;c<16;c++) \
1063 { \
1064 d=(dst_dat & (1<<c)) ? 1:0; \
1065 if (src_dat & (1<<c)) d|=2; \
1066 if (pat_dat & (1<<c)) d|=4; \
1067 if (tgui->accel.rop & (1<<d)) out|=(1<<c); \
1068 } \
1069 } while (0)
1070
1071 #define WRITE(addr, dat) if (tgui->accel.bpp == 0) \
1072 { \
1073 svga->vram[addr & 0x1fffff] = dat; \
1074 svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \
1075 } \
1076 else \
1077 { \
1078 vram_w[addr & 0xfffff] = dat; \
1079 svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \
1080 }
1081
tgui_accel_command(int count,uint32_t cpu_dat,tgui_t * tgui)1082 void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui)
1083 {
1084 svga_t *svga = &tgui->svga;
1085 int x, y;
1086 int c, d;
1087 uint16_t src_dat, dst_dat, pat_dat;
1088 uint16_t out;
1089 int xdir = (tgui->accel.flags & 0x200) ? -1 : 1;
1090 int ydir = (tgui->accel.flags & 0x100) ? -1 : 1;
1091 uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col;
1092 uint16_t *vram_w = (uint16_t *)svga->vram;
1093
1094 if (tgui->accel.bpp == 0)
1095 trans_col &= 0xff;
1096
1097 if (count != -1 && !tgui->accel.x && (tgui->accel.flags & TGUI_SRCMONO))
1098 {
1099 count -= tgui->accel.offset;
1100 cpu_dat <<= tgui->accel.offset;
1101 }
1102 if (count == -1)
1103 {
1104 tgui->accel.x = tgui->accel.y = 0;
1105 }
1106 if (tgui->accel.flags & TGUI_SOLIDFILL)
1107 {
1108 // pclog("SOLIDFILL\n");
1109 for (y = 0; y < 8; y++)
1110 {
1111 for (x = 0; x < 8; x++)
1112 {
1113 tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col;
1114 }
1115 }
1116 }
1117 else if (tgui->accel.flags & TGUI_PATMONO)
1118 {
1119 // pclog("PATMONO\n");
1120 for (y = 0; y < 8; y++)
1121 {
1122 for (x = 0; x < 8; x++)
1123 {
1124 tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col;
1125 }
1126 }
1127 }
1128 else
1129 {
1130 if (tgui->accel.bpp == 0)
1131 {
1132 // pclog("OTHER 8-bit\n");
1133 for (y = 0; y < 8; y++)
1134 {
1135 for (x = 0; x < 8; x++)
1136 {
1137 tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8];
1138 }
1139 }
1140 }
1141 else
1142 {
1143 // pclog("OTHER 16-bit\n");
1144 for (y = 0; y < 8; y++)
1145 {
1146 for (x = 0; x < 8; x++)
1147 {
1148 tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8);
1149 }
1150 }
1151 }
1152 }
1153 /* for (y = 0; y < 8; y++)
1154 {
1155 if (count == -1) pclog("Pattern %i : %02X %02X %02X %02X %02X %02X %02X %02X\n", y, tgui->accel.tgui_pattern[y][0], tgui->accel.tgui_pattern[y][1], tgui->accel.tgui_pattern[y][2], tgui->accel.tgui_pattern[y][3], tgui->accel.tgui_pattern[y][4], tgui->accel.tgui_pattern[y][5], tgui->accel.tgui_pattern[y][6], tgui->accel.tgui_pattern[y][7]);
1156 }*/
1157 // if (count == -1) pclog("Command %i %i %p\n", tgui->accel.command, TGUI_BITBLT, tgui);
1158 switch (tgui->accel.command)
1159 {
1160 case TGUI_BITBLT:
1161 // if (count == -1) pclog("BITBLT src %i,%i dst %i,%i size %i,%i flags %04X\n", tgui->accel.src_x, tgui->accel.src_y, tgui->accel.dst_x, tgui->accel.dst_y, tgui->accel.size_x, tgui->accel.size_y, tgui->accel.flags);
1162 if (count == -1)
1163 {
1164 tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch);
1165 tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch);
1166 tgui->accel.pat_x = tgui->accel.dst_x;
1167 tgui->accel.pat_y = tgui->accel.dst_y;
1168 }
1169
1170 switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP))
1171 {
1172 case TGUI_SRCCPU:
1173 if (count == -1)
1174 {
1175 // pclog("Blit start TGUI_SRCCPU\n");
1176 if (svga->crtc[0x21] & 0x20)
1177 {
1178 tgui->write_blitter = 1;
1179 }
1180 if (tgui->accel.use_src)
1181 return;
1182 }
1183 else
1184 count >>= 3;
1185 // pclog("TGUI_SRCCPU\n");
1186 while (count)
1187 {
1188 if (tgui->accel.bpp == 0)
1189 {
1190 src_dat = cpu_dat >> 24;
1191 cpu_dat <<= 8;
1192 }
1193 else
1194 {
1195 src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00);
1196 cpu_dat <<= 16;
1197 count--;
1198 }
1199 READ(tgui->accel.dst, dst_dat);
1200 pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7];
1201
1202 if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)
1203 {
1204 MIX();
1205
1206 WRITE(tgui->accel.dst, out);
1207 }
1208
1209 // pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out);
1210
1211 tgui->accel.src += xdir;
1212 tgui->accel.dst += xdir;
1213 tgui->accel.pat_x += xdir;
1214
1215 tgui->accel.x++;
1216 if (tgui->accel.x > tgui->accel.size_x)
1217 {
1218 tgui->accel.x = 0;
1219 tgui->accel.y++;
1220
1221 tgui->accel.pat_x = tgui->accel.dst_x;
1222
1223 tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch);
1224 tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch);
1225 tgui->accel.pat_y += ydir;
1226
1227 if (tgui->accel.y > tgui->accel.size_y)
1228 {
1229 if (svga->crtc[0x21] & 0x20)
1230 {
1231 tgui->write_blitter = 0;
1232 }
1233 return;
1234 }
1235 if (tgui->accel.use_src)
1236 return;
1237 }
1238 count--;
1239 }
1240 break;
1241
1242 case TGUI_SRCMONO | TGUI_SRCCPU:
1243 if (count == -1)
1244 {
1245 // pclog("Blit start TGUI_SRCMONO | TGUI_SRCCPU\n");
1246 if (svga->crtc[0x21] & 0x20)
1247 {
1248 tgui->write_blitter = 1;
1249 }
1250
1251 // pclog(" %i\n", tgui->accel.command);
1252 if (tgui->accel.use_src)
1253 return;
1254 }
1255 // pclog("TGUI_SRCMONO | TGUI_SRCCPU\n");
1256 while (count)
1257 {
1258 src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col);
1259 if (tgui->accel.bpp == 0)
1260 src_dat &= 0xff;
1261
1262 READ(tgui->accel.dst, dst_dat);
1263 pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7];
1264
1265 if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)
1266 {
1267 MIX();
1268
1269 WRITE(tgui->accel.dst, out);
1270 }
1271 // pclog(" %i,%i %02X %02X %02X %02X %i\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out, (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col));
1272 cpu_dat <<= 1;
1273 tgui->accel.src += xdir;
1274 tgui->accel.dst += xdir;
1275 tgui->accel.pat_x += xdir;
1276
1277 tgui->accel.x++;
1278 if (tgui->accel.x > tgui->accel.size_x)
1279 {
1280 tgui->accel.x = 0;
1281 tgui->accel.y++;
1282
1283 tgui->accel.pat_x = tgui->accel.dst_x;
1284
1285 tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch);
1286 tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch);
1287 tgui->accel.pat_y += ydir;
1288
1289 if (tgui->accel.y > tgui->accel.size_y)
1290 {
1291 if (svga->crtc[0x21] & 0x20)
1292 {
1293 tgui->write_blitter = 0;
1294 }
1295 return;
1296 }
1297 if (tgui->accel.use_src)
1298 return;
1299 }
1300 count--;
1301 }
1302 break;
1303
1304 default:
1305 while (count)
1306 {
1307 READ(tgui->accel.src, src_dat);
1308 READ(tgui->accel.dst, dst_dat);
1309 pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7];
1310
1311 if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)
1312 {
1313 MIX();
1314
1315 WRITE(tgui->accel.dst, out);
1316 }
1317 // pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out);
1318
1319 tgui->accel.src += xdir;
1320 tgui->accel.dst += xdir;
1321 tgui->accel.pat_x += xdir;
1322
1323 tgui->accel.x++;
1324 if (tgui->accel.x > tgui->accel.size_x)
1325 {
1326 tgui->accel.x = 0;
1327 tgui->accel.y++;
1328
1329 tgui->accel.pat_x = tgui->accel.dst_x;
1330
1331 tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch);
1332 tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch);
1333 tgui->accel.pat_y += ydir;
1334
1335 if (tgui->accel.y > tgui->accel.size_y)
1336 return;
1337 }
1338 count--;
1339 }
1340 break;
1341 }
1342 break;
1343 }
1344 }
1345
tgui_accel_write_fifo(tgui_t * tgui,uint32_t addr,uint8_t val)1346 static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val)
1347 {
1348 switch (addr & 0xff)
1349 {
1350 case 0x22:
1351 tgui->accel.ger22 = val;
1352 tgui->accel.pitch = 512 << ((val >> 2) & 3);
1353 tgui->accel.bpp = (val & 3) ? 1 : 0;
1354 tgui->accel.pitch >>= tgui->accel.bpp;
1355 break;
1356
1357 case 0x24: /*Command*/
1358 tgui->accel.command = val;
1359 tgui_accel_command(-1, 0, tgui);
1360 break;
1361
1362 case 0x27: /*ROP*/
1363 tgui->accel.rop = val;
1364 tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33);
1365 // pclog("Write ROP %02X %i\n", val, tgui->accel.use_src);
1366 break;
1367
1368 case 0x28: /*Flags*/
1369 tgui->accel.flags = (tgui->accel.flags & 0xff00) | val;
1370 break;
1371 case 0x29: /*Flags*/
1372 tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8);
1373 break;
1374
1375 case 0x2b:
1376 tgui->accel.offset = val & 7;
1377 break;
1378
1379 case 0x2c: /*Foreground colour*/
1380 tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val;
1381 break;
1382 case 0x2d: /*Foreground colour*/
1383 tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8);
1384 break;
1385
1386 case 0x30: /*Background colour*/
1387 tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val;
1388 break;
1389 case 0x31: /*Background colour*/
1390 tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8);
1391 break;
1392
1393 case 0x38: /*Dest X*/
1394 tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val;
1395 break;
1396 case 0x39: /*Dest X*/
1397 tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8);
1398 break;
1399 case 0x3a: /*Dest Y*/
1400 tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val;
1401 break;
1402 case 0x3b: /*Dest Y*/
1403 tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8);
1404 break;
1405
1406 case 0x3c: /*Src X*/
1407 tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val;
1408 break;
1409 case 0x3d: /*Src X*/
1410 tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8);
1411 break;
1412 case 0x3e: /*Src Y*/
1413 tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val;
1414 break;
1415 case 0x3f: /*Src Y*/
1416 tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8);
1417 break;
1418
1419 case 0x40: /*Size X*/
1420 tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val;
1421 break;
1422 case 0x41: /*Size X*/
1423 tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8);
1424 break;
1425 case 0x42: /*Size Y*/
1426 tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val;
1427 break;
1428 case 0x43: /*Size Y*/
1429 tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8);
1430 break;
1431
1432 case 0x80: case 0x81: case 0x82: case 0x83:
1433 case 0x84: case 0x85: case 0x86: case 0x87:
1434 case 0x88: case 0x89: case 0x8a: case 0x8b:
1435 case 0x8c: case 0x8d: case 0x8e: case 0x8f:
1436 case 0x90: case 0x91: case 0x92: case 0x93:
1437 case 0x94: case 0x95: case 0x96: case 0x97:
1438 case 0x98: case 0x99: case 0x9a: case 0x9b:
1439 case 0x9c: case 0x9d: case 0x9e: case 0x9f:
1440 case 0xa0: case 0xa1: case 0xa2: case 0xa3:
1441 case 0xa4: case 0xa5: case 0xa6: case 0xa7:
1442 case 0xa8: case 0xa9: case 0xaa: case 0xab:
1443 case 0xac: case 0xad: case 0xae: case 0xaf:
1444 case 0xb0: case 0xb1: case 0xb2: case 0xb3:
1445 case 0xb4: case 0xb5: case 0xb6: case 0xb7:
1446 case 0xb8: case 0xb9: case 0xba: case 0xbb:
1447 case 0xbc: case 0xbd: case 0xbe: case 0xbf:
1448 case 0xc0: case 0xc1: case 0xc2: case 0xc3:
1449 case 0xc4: case 0xc5: case 0xc6: case 0xc7:
1450 case 0xc8: case 0xc9: case 0xca: case 0xcb:
1451 case 0xcc: case 0xcd: case 0xce: case 0xcf:
1452 case 0xd0: case 0xd1: case 0xd2: case 0xd3:
1453 case 0xd4: case 0xd5: case 0xd6: case 0xd7:
1454 case 0xd8: case 0xd9: case 0xda: case 0xdb:
1455 case 0xdc: case 0xdd: case 0xde: case 0xdf:
1456 case 0xe0: case 0xe1: case 0xe2: case 0xe3:
1457 case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1458 case 0xe8: case 0xe9: case 0xea: case 0xeb:
1459 case 0xec: case 0xed: case 0xee: case 0xef:
1460 case 0xf0: case 0xf1: case 0xf2: case 0xf3:
1461 case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1462 case 0xf8: case 0xf9: case 0xfa: case 0xfb:
1463 case 0xfc: case 0xfd: case 0xfe: case 0xff:
1464 tgui->accel.pattern[addr & 0x7f] = val;
1465 break;
1466 }
1467 }
1468
tgui_accel_write_fifo_fb_b(tgui_t * tgui,uint32_t addr,uint8_t val)1469 static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val)
1470 {
1471 tgui_accel_command(8, val << 24, tgui);
1472 }
tgui_accel_write_fifo_fb_w(tgui_t * tgui,uint32_t addr,uint16_t val)1473 static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val)
1474 {
1475 tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui);
1476 }
tgui_accel_write_fifo_fb_l(tgui_t * tgui,uint32_t addr,uint32_t val)1477 static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val)
1478 {
1479 tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui);
1480 }
1481
fifo_thread(void * param)1482 static void fifo_thread(void *param)
1483 {
1484 tgui_t *tgui = (tgui_t *)param;
1485
1486 while (1)
1487 {
1488 thread_set_event(tgui->fifo_not_full_event);
1489 thread_wait_event(tgui->wake_fifo_thread, -1);
1490 thread_reset_event(tgui->wake_fifo_thread);
1491 tgui->blitter_busy = 1;
1492 while (!FIFO_EMPTY)
1493 {
1494 uint64_t start_time = timer_read();
1495 uint64_t end_time;
1496 fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK];
1497
1498 switch (fifo->addr_type & FIFO_TYPE)
1499 {
1500 case FIFO_WRITE_BYTE:
1501 tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val);
1502 break;
1503 case FIFO_WRITE_FB_BYTE:
1504 tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val);
1505 break;
1506 case FIFO_WRITE_FB_WORD:
1507 tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val);
1508 break;
1509 case FIFO_WRITE_FB_LONG:
1510 tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val);
1511 break;
1512 }
1513
1514 tgui->fifo_read_idx++;
1515 fifo->addr_type = FIFO_INVALID;
1516
1517 if (FIFO_ENTRIES > 0xe000)
1518 thread_set_event(tgui->fifo_not_full_event);
1519
1520 end_time = timer_read();
1521 tgui->blitter_time += end_time - start_time;
1522 }
1523 tgui->blitter_busy = 0;
1524 }
1525 }
1526
wake_fifo_thread(tgui_t * tgui)1527 static inline void wake_fifo_thread(tgui_t *tgui)
1528 {
1529 thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
1530 }
1531
tgui_wait_fifo_idle(tgui_t * tgui)1532 static void tgui_wait_fifo_idle(tgui_t *tgui)
1533 {
1534 while (!FIFO_EMPTY)
1535 {
1536 wake_fifo_thread(tgui);
1537 thread_wait_event(tgui->fifo_not_full_event, 1);
1538 }
1539 }
1540
tgui_queue(tgui_t * tgui,uint32_t addr,uint32_t val,uint32_t type)1541 static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type)
1542 {
1543 fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK];
1544
1545 if (FIFO_FULL)
1546 {
1547 thread_reset_event(tgui->fifo_not_full_event);
1548 if (FIFO_FULL)
1549 {
1550 thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/
1551 }
1552 }
1553
1554 fifo->val = val;
1555 fifo->addr_type = (addr & FIFO_ADDR) | type;
1556
1557 tgui->fifo_write_idx++;
1558
1559 if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8)
1560 wake_fifo_thread(tgui);
1561 }
1562
1563
tgui_accel_write(uint32_t addr,uint8_t val,void * p)1564 void tgui_accel_write(uint32_t addr, uint8_t val, void *p)
1565 {
1566 tgui_t *tgui = (tgui_t *)p;
1567 // pclog("tgui_accel_write : %08X %02X %04X(%08X):%08X %02X\n", addr, val, CS,cs,pc, opcode);
1568 if ((addr & ~0xff) != 0xbff00)
1569 return;
1570 tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE);
1571 }
1572
tgui_accel_write_w(uint32_t addr,uint16_t val,void * p)1573 void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p)
1574 {
1575 tgui_t *tgui = (tgui_t *)p;
1576 // pclog("tgui_accel_write_w %08X %04X\n", addr, val);
1577 tgui_accel_write(addr, val, tgui);
1578 tgui_accel_write(addr + 1, val >> 8, tgui);
1579 }
1580
tgui_accel_write_l(uint32_t addr,uint32_t val,void * p)1581 void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p)
1582 {
1583 tgui_t *tgui = (tgui_t *)p;
1584 // pclog("tgui_accel_write_l %08X %08X\n", addr, val);
1585 tgui_accel_write(addr, val, tgui);
1586 tgui_accel_write(addr + 1, val >> 8, tgui);
1587 tgui_accel_write(addr + 2, val >> 16, tgui);
1588 tgui_accel_write(addr + 3, val >> 24, tgui);
1589 }
1590
tgui_accel_read(uint32_t addr,void * p)1591 uint8_t tgui_accel_read(uint32_t addr, void *p)
1592 {
1593 tgui_t *tgui = (tgui_t *)p;
1594 // pclog("tgui_accel_read : %08X\n", addr);
1595 if ((addr & ~0xff) != 0xbff00)
1596 return 0xff;
1597 if ((addr & 0xff) != 0x20)
1598 tgui_wait_fifo_idle(tgui);
1599 switch (addr & 0xff)
1600 {
1601 case 0x20: /*Status*/
1602 if (!FIFO_EMPTY)
1603 return 1 << 5;
1604 return 0;
1605
1606 case 0x27: /*ROP*/
1607 return tgui->accel.rop;
1608
1609 case 0x28: /*Flags*/
1610 return tgui->accel.flags & 0xff;
1611 case 0x29: /*Flags*/
1612 return tgui->accel.flags >> 8;
1613
1614 case 0x2b:
1615 return tgui->accel.offset;
1616
1617 case 0x2c: /*Background colour*/
1618 return tgui->accel.bg_col & 0xff;
1619 case 0x2d: /*Background colour*/
1620 return tgui->accel.bg_col >> 8;
1621
1622 case 0x30: /*Foreground colour*/
1623 return tgui->accel.fg_col & 0xff;
1624 case 0x31: /*Foreground colour*/
1625 return tgui->accel.fg_col >> 8;
1626
1627 case 0x38: /*Dest X*/
1628 return tgui->accel.dst_x & 0xff;
1629 case 0x39: /*Dest X*/
1630 return tgui->accel.dst_x >> 8;
1631 case 0x3a: /*Dest Y*/
1632 return tgui->accel.dst_y & 0xff;
1633 case 0x3b: /*Dest Y*/
1634 return tgui->accel.dst_y >> 8;
1635
1636 case 0x3c: /*Src X*/
1637 return tgui->accel.src_x & 0xff;
1638 case 0x3d: /*Src X*/
1639 return tgui->accel.src_x >> 8;
1640 case 0x3e: /*Src Y*/
1641 return tgui->accel.src_y & 0xff;
1642 case 0x3f: /*Src Y*/
1643 return tgui->accel.src_y >> 8;
1644
1645 case 0x40: /*Size X*/
1646 return tgui->accel.size_x & 0xff;
1647 case 0x41: /*Size X*/
1648 return tgui->accel.size_x >> 8;
1649 case 0x42: /*Size Y*/
1650 return tgui->accel.size_y & 0xff;
1651 case 0x43: /*Size Y*/
1652 return tgui->accel.size_y >> 8;
1653
1654 case 0x80: case 0x81: case 0x82: case 0x83:
1655 case 0x84: case 0x85: case 0x86: case 0x87:
1656 case 0x88: case 0x89: case 0x8a: case 0x8b:
1657 case 0x8c: case 0x8d: case 0x8e: case 0x8f:
1658 case 0x90: case 0x91: case 0x92: case 0x93:
1659 case 0x94: case 0x95: case 0x96: case 0x97:
1660 case 0x98: case 0x99: case 0x9a: case 0x9b:
1661 case 0x9c: case 0x9d: case 0x9e: case 0x9f:
1662 case 0xa0: case 0xa1: case 0xa2: case 0xa3:
1663 case 0xa4: case 0xa5: case 0xa6: case 0xa7:
1664 case 0xa8: case 0xa9: case 0xaa: case 0xab:
1665 case 0xac: case 0xad: case 0xae: case 0xaf:
1666 case 0xb0: case 0xb1: case 0xb2: case 0xb3:
1667 case 0xb4: case 0xb5: case 0xb6: case 0xb7:
1668 case 0xb8: case 0xb9: case 0xba: case 0xbb:
1669 case 0xbc: case 0xbd: case 0xbe: case 0xbf:
1670 case 0xc0: case 0xc1: case 0xc2: case 0xc3:
1671 case 0xc4: case 0xc5: case 0xc6: case 0xc7:
1672 case 0xc8: case 0xc9: case 0xca: case 0xcb:
1673 case 0xcc: case 0xcd: case 0xce: case 0xcf:
1674 case 0xd0: case 0xd1: case 0xd2: case 0xd3:
1675 case 0xd4: case 0xd5: case 0xd6: case 0xd7:
1676 case 0xd8: case 0xd9: case 0xda: case 0xdb:
1677 case 0xdc: case 0xdd: case 0xde: case 0xdf:
1678 case 0xe0: case 0xe1: case 0xe2: case 0xe3:
1679 case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1680 case 0xe8: case 0xe9: case 0xea: case 0xeb:
1681 case 0xec: case 0xed: case 0xee: case 0xef:
1682 case 0xf0: case 0xf1: case 0xf2: case 0xf3:
1683 case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1684 case 0xf8: case 0xf9: case 0xfa: case 0xfb:
1685 case 0xfc: case 0xfd: case 0xfe: case 0xff:
1686 return tgui->accel.pattern[addr & 0x7f];
1687 }
1688 return 0xff;
1689 }
1690
tgui_accel_read_w(uint32_t addr,void * p)1691 uint16_t tgui_accel_read_w(uint32_t addr, void *p)
1692 {
1693 tgui_t *tgui = (tgui_t *)p;
1694 // pclog("tgui_accel_read_w %08X\n", addr);
1695 return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8);
1696 }
1697
tgui_accel_read_l(uint32_t addr,void * p)1698 uint32_t tgui_accel_read_l(uint32_t addr, void *p)
1699 {
1700 tgui_t *tgui = (tgui_t *)p;
1701 // pclog("tgui_accel_read_l %08X\n", addr);
1702 return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16);
1703 }
1704
tgui_accel_write_fb_b(uint32_t addr,uint8_t val,void * p)1705 void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p)
1706 {
1707 svga_t *svga = (svga_t *)p;
1708 tgui_t *tgui = (tgui_t *)svga->p;
1709
1710 if (tgui->write_blitter)
1711 tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE);
1712 else
1713 svga_write_linear(addr, val, svga);
1714 }
1715
tgui_accel_write_fb_w(uint32_t addr,uint16_t val,void * p)1716 void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p)
1717 {
1718 svga_t *svga = (svga_t *)p;
1719 tgui_t *tgui = (tgui_t *)svga->p;
1720
1721 if (tgui->write_blitter)
1722 tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD);
1723 else
1724 svga_writew_linear(addr, val, svga);
1725 }
1726
tgui_accel_write_fb_l(uint32_t addr,uint32_t val,void * p)1727 void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p)
1728 {
1729 svga_t *svga = (svga_t *)p;
1730 tgui_t *tgui = (tgui_t *)svga->p;
1731
1732 if (tgui->write_blitter)
1733 tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG);
1734 else
1735 svga_writel_linear(addr, val, svga);
1736 }
1737
tgui_add_status_info(char * s,int max_len,void * p)1738 void tgui_add_status_info(char *s, int max_len, void *p)
1739 {
1740 tgui_t *tgui = (tgui_t *)p;
1741 char temps[256];
1742 uint64_t new_time = timer_read();
1743 uint64_t status_diff = new_time - tgui->status_time;
1744 tgui->status_time = new_time;
1745
1746 svga_add_status_info(s, max_len, &tgui->svga);
1747
1748 sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)tgui->blitter_time * 100.0) / timer_freq, ((double)tgui->blitter_time * 100.0) / status_diff);
1749 strncat(s, temps, max_len);
1750
1751 tgui->blitter_time = 0;
1752 }
1753
1754 static device_config_t tgui9440_config[] =
1755 {
1756 {
1757 .name = "memory",
1758 .description = "Memory size",
1759 .type = CONFIG_SELECTION,
1760 .selection =
1761 {
1762 {
1763 .description = "1 MB",
1764 .value = 1
1765 },
1766 {
1767 .description = "2 MB",
1768 .value = 2
1769 },
1770 {
1771 .description = ""
1772 }
1773 },
1774 .default_int = 2
1775 },
1776 {
1777 .type = -1
1778 }
1779 };
1780
1781 device_t tgui9400cxi_device =
1782 {
1783 "Trident TGUI 9400CXi",
1784 0,
1785 tgui9400cxi_init,
1786 tgui_close,
1787 tgui9400cxi_available,
1788 tgui_speed_changed,
1789 tgui_force_redraw,
1790 tgui_add_status_info,
1791 tgui9440_config
1792 };
1793
1794 device_t tgui9400cxi_elx_device =
1795 {
1796 "Trident TGUI 9400CXi (Elonex PC-425X)",
1797 0,
1798 tgui9400cxi_elx_init,
1799 tgui_close,
1800 tgui9400cxi_available,
1801 tgui_speed_changed,
1802 tgui_force_redraw,
1803 tgui_add_status_info,
1804 tgui9440_config
1805 };
1806
1807 device_t tgui9440_device =
1808 {
1809 "Trident TGUI 9440",
1810 0,
1811 tgui9440_init,
1812 tgui_close,
1813 tgui9440_available,
1814 tgui_speed_changed,
1815 tgui_force_redraw,
1816 tgui_add_status_info,
1817 tgui9440_config
1818 };
1819