1 // license:BSD-3-Clause
2 // copyright-holders:Barry Rodewald
3 /*
4 * s3virge.cpp
5 *
6 * Implementation of the S3 Virge series of video card
7 *
8 * Current status:
9 * - Working on getting VESA video modes working better - 800x600 and higher skip every other line at
10 * 8-bit depth, but are fine at 15/16-bit depth.
11 * - S3D is not implemented at all, so no 2D/3D acceleration yet.
12 */
13
14 #include "emu.h"
15 #include "s3virge.h"
16
17 #include "screen.h"
18
19 #define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO)
20
21 #include "logmacro.h"
22
23 #define LOG_REG (1U << 1)
24 #define LOG_CMD (1U << 2)
25 #define LOG_MMIO (1U << 3)
26
27 #define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__)
28 #define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__)
29 #define LOGMMIO(...) LOGMASKED(LOG_MMIO, __VA_ARGS__)
30
31
32 #define CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0)
33
34 DEFINE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device, "virge_vga", "S3 86C325")
35 DEFINE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device, "virgedx_vga", "S3 86C375")
36 DEFINE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device, "virgedx_vga_r1", "S3 86C375 (rev 1)")
37
s3virge_vga_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)38 s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
39 : s3virge_vga_device(mconfig, S3VIRGE, tag, owner, clock)
40 {
41 }
42
s3virge_vga_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)43 s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
44 : s3_vga_device(mconfig, type, tag, owner, clock)
45 , m_linear_config_changed_cb(*this)
46 {
47 }
48
s3virgedx_vga_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)49 s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
50 : s3virgedx_vga_device(mconfig, S3VIRGEDX, tag, owner, clock)
51 {
52 }
53
s3virgedx_vga_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)54 s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
55 : s3virge_vga_device(mconfig, type, tag, owner, clock)
56 {
57 }
58
s3virgedx_rev1_vga_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)59 s3virgedx_rev1_vga_device::s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
60 : s3virgedx_vga_device(mconfig, S3VIRGEDX1, tag, owner, clock)
61 {
62 }
63
device_start()64 void s3virge_vga_device::device_start()
65 {
66 zero();
67
68 for (int i = 0; i < 0x100; i++)
69 set_pen_color(i, 0, 0, 0);
70
71 // Avoid an infinite loop when displaying. 0 is not possible anyway.
72 vga.crtc.maximum_scan_line = 1;
73
74 // copy over interfaces
75 vga.read_dipswitch.set(nullptr); //read_dipswitch;
76 vga.svga_intf.seq_regcount = 0x1c;
77 vga.svga_intf.crtc_regcount = 0x19;
78 vga.svga_intf.vram_size = 0x400000;
79 vga.memory.resize(vga.svga_intf.vram_size);
80 memset(&vga.memory[0], 0, vga.svga_intf.vram_size);
81 save_item(vga.memory,"Video RAM");
82 save_item(vga.crtc.data,"CRTC Registers");
83 save_item(vga.sequencer.data,"Sequencer Registers");
84 save_item(vga.attribute.data,"Attribute Registers");
85
86 m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this));
87 m_draw_timer = timer_alloc(TIMER_DRAW_STEP);
88
89 memset(&s3, 0, sizeof(s3));
90 memset(&s3virge, 0, sizeof(s3virge));
91 s3virge.linear_address = 0x70000000;
92 s3virge.linear_address_size_full = 0x10000;
93 s3virge.s3d.cmd_fifo_slots_free = 16;
94 save_item(s3virge.s3d.pattern,"S3D Pattern Data");
95 save_item(s3virge.s3d.reg[0],"S3D Registers: BitBLT");
96 save_item(s3virge.s3d.reg[1],"S3D Registers: 2D Line");
97 save_item(s3virge.s3d.reg[2],"S3D Registers: 2D Polygon");
98 save_item(s3virge.s3d.reg[3],"S3D Registers: 3D Line");
99 save_item(s3virge.s3d.reg[4],"S3D Registers: 3D Triangle");
100
101 m_linear_config_changed_cb.resolve_safe();
102
103 // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason
104 for (int x = 0; x < 4; x++)
105 {
106 s3.cursor_fg[x] = 0xff;
107 s3.cursor_bg[x] = 0x00;
108 }
109 // set device ID
110 s3.id_high = 0x56; // CR2D
111 s3.id_low = 0x31; // CR2E
112 s3.revision = 0x00; // CR2F (value unknown)
113 s3.id_cr30 = 0xe1; // CR30
114 }
115
device_start()116 void s3virgedx_vga_device::device_start()
117 {
118 s3virge_vga_device::device_start();
119
120 // set device ID
121 s3.id_high = 0x8a; // CR2D
122 s3.id_low = 0x01; // CR2E
123 s3.revision = 0x00; // CR2F (value unknown)
124 s3.id_cr30 = 0xe1; // CR30
125 }
126
device_start()127 void s3virgedx_rev1_vga_device::device_start()
128 {
129 s3virge_vga_device::device_start();
130
131 // set device ID
132 s3.id_high = 0x8a; // CR2D
133 s3.id_low = 0x01; // CR2E
134 s3.revision = 0x01; // CR2F
135 s3.id_cr30 = 0xe1; // CR30
136 }
137
device_reset()138 void s3virge_vga_device::device_reset()
139 {
140 vga_device::device_reset();
141 // Power-on strapping bits. Sampled at reset, but can be modified later.
142 // These are just assumed defaults.
143 s3.strapping = 0x000f0912;
144 }
145
device_reset()146 void s3virgedx_vga_device::device_reset()
147 {
148 vga_device::device_reset();
149 // Power-on strapping bits. Sampled at reset, but can be modified later.
150 // These are just assumed defaults.
151 s3.strapping = 0x000f0912;
152 }
153
device_reset()154 void s3virgedx_rev1_vga_device::device_reset()
155 {
156 vga_device::device_reset();
157 // Power-on strapping bits. Sampled at reset, but can be modified later.
158 // These are based on results from a Diamond Stealth 3D 2000 Pro (Virge/DX based)
159 // bits 8-15 are still unknown, S3ID doesn't show config register 2 (CR37)
160 s3.strapping = 0x0aff0912;
161 }
162
offset()163 uint16_t s3virge_vga_device::offset()
164 {
165 if(svga.rgb24_en)
166 return vga.crtc.offset * 6; // special handling for 24bpp packed mode
167 return s3_vga_device::offset();
168 }
169
s3_crtc_reg_read(uint8_t index)170 uint8_t s3virge_vga_device::s3_crtc_reg_read(uint8_t index)
171 {
172 uint8_t res;
173
174 if(index <= 0x18)
175 res = crtc_reg_read(index);
176 else
177 {
178 switch(index)
179 {
180 case 0x2d:
181 res = s3.id_high;
182 break;
183 case 0x2e:
184 res = s3.id_low;
185 break;
186 case 0x2f:
187 res = s3.revision;
188 break;
189 case 0x30: // CR30 Chip ID/REV register
190 res = s3.id_cr30;
191 break;
192 case 0x31:
193 res = s3.memory_config;
194 break;
195 case 0x35:
196 res = s3.crt_reg_lock;
197 break;
198 case 0x36: // Configuration register 1
199 res = s3.strapping & 0x000000ff;
200 break;
201 case 0x37: // Configuration register 2
202 res = (s3.strapping & 0x0000ff00) >> 8;
203 break;
204 case 0x38:
205 res = s3.reg_lock1;
206 break;
207 case 0x39:
208 res = s3.reg_lock2;
209 break;
210 case 0x42: // CR42 Mode Control
211 res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now.
212 break;
213 case 0x43:
214 res = s3.cr43;
215 break;
216 case 0x45:
217 res = s3.cursor_mode;
218 break;
219 case 0x46:
220 res = (s3.cursor_x & 0xff00) >> 8;
221 break;
222 case 0x47:
223 res = s3.cursor_x & 0x00ff;
224 break;
225 case 0x48:
226 res = (s3.cursor_y & 0xff00) >> 8;
227 break;
228 case 0x49:
229 res = s3.cursor_y & 0x00ff;
230 break;
231 case 0x4a:
232 res = s3.cursor_fg[s3.cursor_fg_ptr];
233 s3.cursor_fg_ptr = 0;
234 break;
235 case 0x4b:
236 res = s3.cursor_bg[s3.cursor_bg_ptr];
237 s3.cursor_bg_ptr = 0;
238 break;
239 case 0x4c:
240 res = (s3.cursor_start_addr & 0xff00) >> 8;
241 break;
242 case 0x4d:
243 res = s3.cursor_start_addr & 0x00ff;
244 break;
245 case 0x4e:
246 res = s3.cursor_pattern_x;
247 break;
248 case 0x4f:
249 res = s3.cursor_pattern_y;
250 break;
251 case 0x51:
252 res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18;
253 res |= ((svga.bank_w & 0x30) >> 2);
254 break;
255 case 0x55:
256 res = s3.extended_dac_ctrl;
257 break;
258 case 0x58:
259 res = s3virge.linear_address_size & 0x03;
260 res |= s3virge.linear_address_enable ? 0x10 : 0x00;
261 break;
262 case 0x59:
263 res = (s3virge.linear_address & 0xff000000) >> 24;
264 break;
265 case 0x5a:
266 switch(s3virge.linear_address_size & 0x03)
267 {
268 case 0: // 64kB
269 default:
270 res = (s3virge.linear_address & 0x00ff0000) >> 16;
271 break;
272 case 1: // 1MB
273 res = (s3virge.linear_address & 0x00f00000) >> 16;
274 break;
275 case 2: // 2MB
276 res = (s3virge.linear_address & 0x00e00000) >> 16;
277 break;
278 case 3: // 4MB
279 res = (s3virge.linear_address & 0x00c00000) >> 16;
280 break;
281 }
282 break;
283 case 0x5c:
284 // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select
285 if((vga.miscellaneous_output & 0xc) == 0x0c)
286 res = s3.cr42 & 0x0f;
287 else
288 res = (vga.miscellaneous_output & 0xc) >> 2;
289 break;
290 case 0x67:
291 res = s3.ext_misc_ctrl_2;
292 break;
293 case 0x68: // Configuration register 3
294 res = (s3.strapping & 0x00ff0000) >> 16;
295 break;
296 case 0x69:
297 res = vga.crtc.start_addr_latch >> 16;
298 break;
299 case 0x6a:
300 res = svga.bank_r & 0x7f;
301 break;
302 case 0x6f: // Configuration register 4
303 res = (s3.strapping & 0xff000000) >> 24;
304 break;
305 default:
306 res = vga.crtc.data[index];
307 //machine.debug_break();
308 //printf("%02x\n",index);
309 break;
310 }
311 }
312
313 return res;
314 }
315
s3_define_video_mode()316 void s3virge_vga_device::s3_define_video_mode()
317 {
318 int divisor = 1;
319 const XTAL base_xtal = XTAL(14'318'181);
320 XTAL xtal = (vga.miscellaneous_output & 0xc) ? base_xtal*2 : base_xtal*1.75;
321
322 if((vga.miscellaneous_output & 0xc) == 0x0c)
323 {
324 // Dot clock is set via SR12 and SR13
325 // DCLK calculation
326 double ratio = (double)(s3.clk_pll_m+2) / (double)((s3.clk_pll_n+2)*(pow(2.0,s3.clk_pll_r))); // clock between XIN and XOUT
327 xtal = base_xtal * ratio;
328 //printf("DCLK set to %dHz M=%i N=%i R=%i\n",xtal,s3.clk_pll_m,s3.clk_pll_n,s3.clk_pll_r);
329 }
330
331 if((s3.ext_misc_ctrl_2) >> 4)
332 {
333 svga.rgb8_en = 0;
334 svga.rgb15_en = 0;
335 svga.rgb16_en = 0;
336 svga.rgb24_en = 0;
337 switch((s3.ext_misc_ctrl_2) >> 4)
338 {
339 case 0x01: svga.rgb8_en = 1; break;
340 case 0x03: svga.rgb15_en = 1; divisor = 2; break;
341 case 0x05: svga.rgb16_en = 1; divisor = 2; break;
342 case 0x0d: svga.rgb24_en = 1; divisor = 1; break;
343 default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4));
344 }
345 }
346 else
347 {
348 svga.rgb8_en = (s3.cr3a & 0x10) >> 4;
349 svga.rgb15_en = 0;
350 svga.rgb16_en = 0;
351 svga.rgb24_en = 0;
352 }
353 if(s3.cr43 & 0x80) // Horizontal clock doubling (technically, doubles horizontal CRT parameters)
354 divisor *= 2;
355 recompute_params_clock(divisor, xtal.value());
356 }
357
s3_crtc_reg_write(uint8_t index,uint8_t data)358 void s3virge_vga_device::s3_crtc_reg_write(uint8_t index, uint8_t data)
359 {
360 if(index <= 0x18)
361 {
362 crtc_reg_write(index,data);
363 s3_define_video_mode();
364 }
365 else
366 {
367 switch(index)
368 {
369 case 0x31: // CR31 Memory Configuration Register
370 s3.memory_config = data;
371 vga.crtc.start_addr_latch &= ~0x30000;
372 vga.crtc.start_addr_latch |= ((data & 0x30) << 12);
373 s3_define_video_mode();
374 break;
375 case 0x35:
376 if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register
377 return;
378 s3.crt_reg_lock = data;
379 svga.bank_w = data & 0xf;
380 svga.bank_r = svga.bank_w;
381 break;
382 case 0x36:
383 if(s3.reg_lock2 == 0xa5)
384 {
385 s3.strapping = (s3.strapping & 0xffffff00) | data;
386 LOGREG("CR36: Strapping data = %08x\n",s3.strapping);
387 }
388 break;
389 case 0x37:
390 if(s3.reg_lock2 == 0xa5)
391 {
392 s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8);
393 LOGREG("CR37: Strapping data = %08x\n",s3.strapping);
394 }
395 break;
396 case 0x38:
397 s3.reg_lock1 = data;
398 break;
399 case 0x39:
400 /* TODO: reg lock mechanism */
401 s3.reg_lock2 = data;
402 break;
403 case 0x3a:
404 s3.cr3a = data;
405 break;
406 case 0x40:
407 s3.enable_s3d = data & 0x01; // enable S3D registers
408 break;
409 case 0x42:
410 s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented)
411 break;
412 case 0x43:
413 s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h.
414 if((s3.cr51 & 0x30) == 0)
415 vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6);
416 else
417 vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr51 & 0x30) << 4);
418 s3_define_video_mode();
419 break;
420 /*
421 3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode
422 bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the
423 HardWare Cursor in VGA and enhanced modes.
424 1 (911/24) Delay Timing for Pattern Data Fetch
425 2 (801/5,928) Hardware Cursor Horizontal Stretch 2. If set the cursor
426 pixels are stretched horizontally to two bytes and items 0 and 1 of
427 the fore/background stacks in 3d4h index 4Ah/4Bh are used.
428 3 (801/5,928) Hardware Cursor Horizontal Stretch 3. If set the cursor
429 pixels are stretched horizontally to three bytes and items 0,1 and
430 2 of the fore/background stacks in 3d4h index 4Ah/4Bh are used.
431 2-3 (805i,864/964) HWC-CSEL. Hardware Cursor Color Select.
432 0: 4/8bit, 1: 15/16bt, 2: 24bit, 3: 32bit
433 Note: So far I've had better luck with: 0: 8/15/16bit, 1: 32bit??
434 4 (80x +) Hardware Cursor Right Storage. If set the cursor data is
435 stored in the last 256 bytes of 4 1Kyte lines (4bits/pixel) or the
436 last 512 bytes of 2 2Kbyte lines (8bits/pixel). Intended for
437 1280x1024 modes where there are no free lines at the bottom.
438 5 (928) Cursor Control Enable for Brooktree Bt485 DAC. If set and 3d4h
439 index 55h bit 5 is set the HC1 output becomes the ODF and the HC0
440 output becomes the CDE
441 (964) BT485 ODF Selection for Bt485A RAMDAC. If set pin 185 (RS3
442 /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even
443 fields and high for odd fields), if clear pin185 is the RS3 output.
444 */
445 case 0x45:
446 s3.cursor_mode = data;
447 break;
448 /*
449 3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X
450 bit 0-10 The HardWare Cursor X position. For 64k modes this value should be
451 twice the actual X co-ordinate.
452 */
453 case 0x46:
454 s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8);
455 break;
456 case 0x47:
457 s3.cursor_x = (s3.cursor_x & 0xff00) | data;
458 break;
459 /*
460 3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y
461 bit 0-9 (911/24) The HardWare Cursor Y position.
462 0-10 (80x +) The HardWare Cursor Y position.
463 Note: The position is activated when the high byte of the Y coordinate (index
464 48h) is written, so this byte should be written last (not 911/924 ?)
465 */
466 case 0x48:
467 s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8);
468 break;
469 case 0x49:
470 s3.cursor_y = (s3.cursor_y & 0xff00) | data;
471 break;
472
473 /*
474 3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +)
475 bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are
476 stacked here. When the Cursor Mode register (3d4h index 45h) is read
477 the stackpointer is reset. When a byte is written the byte is
478 written into the current top of stack and the stackpointer is
479 increased. The first byte written (item 0) is allways used, the
480 other two(3) only when Hardware Cursor Horizontal Stretch (3d4h
481 index 45h bit 2-3) is enabled.
482 */
483 case 0x4a:
484 s3.cursor_fg[s3.cursor_fg_ptr++] = data;
485 s3.cursor_fg_ptr %= 4;
486 break;
487 /*
488 3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +)
489 bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are
490 stacked here. When the Cursor Mode register (3d4h index 45h) is read
491 the stackpointer is reset. When a byte is written the byte is
492 written into the current top of stack and the stackpointer is
493 increased. The first byte written (item 0) is allways used, the
494 other two(3) only when Hardware Cursor Horizontal Stretch (3d4h
495 index 45h bit 2-3) is enabled.
496 */
497 case 0x4b:
498 s3.cursor_bg[s3.cursor_bg_ptr++] = data;
499 s3.cursor_bg_ptr %= 4;
500 break;
501 /*
502 3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address
503 bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address
504 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address
505 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address
506 Address of the HardWare Cursor Map in units of 1024 bytes (256 bytes
507 for planar modes). The cursor map is a 64x64 bitmap with 2 bits (A
508 and B) per pixel. The map is stored as one word (16 bits) of bit A,
509 followed by one word with the corresponding 16 B bits.
510 The bits are interpreted as:
511 A B MS-Windows: X-11:
512 0 0 Background Screen data
513 0 1 Foreground Screen data
514 1 0 Screen data Background
515 1 1 Inverted screen Foreground
516 The Windows/X11 switch is only available for the 80x +.
517 (911/24) For 64k color modes the cursor is stored as one byte (8
518 bits) of A bits, followed by the 8 B-bits, and each bit in the
519 cursor should be doubled to provide a consistent cursor image.
520 (801/5,928) For Hi/True color modes use the Horizontal Stretch bits
521 (3d4h index 45h bits 2 and 3).
522 */
523 case 0x4c:
524 s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8);
525 LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr);
526 break;
527 case 0x4d:
528 s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data;
529 LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr);
530 break;
531 /*
532 3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position
533 bit 0-5 Pattern Display Start X-Pixel Position.
534 */
535 case 0x4e:
536 s3.cursor_pattern_x = data;
537 break;
538 /*
539 3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position
540 bit 0-5 Pattern Display Start Y-Pixel Position.
541 */
542 case 0x4f:
543 s3.cursor_pattern_y = data;
544 break;
545 case 0x51:
546 s3.cr51 = data;
547 vga.crtc.start_addr_latch &= ~0xc0000;
548 vga.crtc.start_addr_latch |= ((data & 0x3) << 18);
549 svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2);
550 svga.bank_r = svga.bank_w;
551 if((data & 0x30) != 0x00)
552 vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4);
553 else
554 vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6);
555 s3_define_video_mode();
556 break;
557 case 0x53:
558 s3.cr53 = data;
559 break;
560 /*
561 3d4h index 55h (R/W): Extended Video DAC Control Register (80x +)
562 bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the
563 RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs.
564 If this field is 0, 3d4h index 43h bit 1 is active.
565 2 Enable General Input Port Read. If set DAC reads are disabled and the
566 STRD strobe for reading the General Input Port is enabled for reading
567 while DACRD is active, if clear DAC reads are enabled.
568 3 (928) Enable External SID Operation if set. If set video data is
569 passed directly from the VRAMs to the DAC rather than through the
570 VGA chip
571 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11
572 mode, if clear in MS-Windows mode
573 5 (80x,928) Hardware Cursor External Operation Mode. If set the two
574 bits of cursor data ,is output on the HC[0-1] pins for the video DAC
575 The SENS pin becomes HC1 and the MID2 pin becomes HC0.
576 6 ??
577 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated.
578 (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri
579 -stated if set
580 */
581 case 0x55:
582 s3.extended_dac_ctrl = data;
583 break;
584
585 case 0x58:
586 {
587 const uint8_t old_size = s3virge.linear_address_size;
588 const bool old_enable = s3virge.linear_address_enable;
589 const bool size_changed = old_size != s3virge.linear_address_size;
590
591 s3virge.linear_address_size = data & 0x03;
592 s3virge.linear_address_enable = data & 0x10;
593
594 switch(data & 0x03)
595 {
596 case LAW_64K:
597 s3virge.linear_address_size_full = 0x10000;
598 break;
599 case LAW_1MB:
600 s3virge.linear_address_size_full = 0x100000;
601 break;
602 case LAW_2MB:
603 s3virge.linear_address_size_full = 0x200000;
604 break;
605 case LAW_4MB:
606 s3virge.linear_address_size_full = 0x400000;
607 break;
608 }
609
610 if ((s3virge.linear_address_enable != old_enable) || size_changed)
611 {
612 m_linear_config_changed_cb(s3virge.linear_address_enable);
613 }
614
615 LOGREG("CR58: write %02x\n", data);
616 break;
617 }
618 case 0x59:
619 {
620 const uint32_t old_address = s3virge.linear_address;
621 s3virge.linear_address = (s3virge.linear_address & 0x00ff0000) | (data << 24);
622 LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address);
623
624 if (old_address != s3virge.linear_address && s3virge.linear_address_enable)
625 {
626 m_linear_config_changed_cb(1);
627 }
628 break;
629 }
630 case 0x5a:
631 {
632 const uint32_t old_address = s3virge.linear_address;
633 s3virge.linear_address = (s3virge.linear_address & 0xff000000) | (data << 16);
634 LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address);
635
636 if (old_address != s3virge.linear_address && s3virge.linear_address_enable)
637 {
638 m_linear_config_changed_cb(1);
639 }
640 break;
641 }
642
643 /*
644 3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +)
645 bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h
646 index 0)
647 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End
648 register (3d4h index 1)
649 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking
650 register (3d4h index 2).
651 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse
652 is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or
653 does it really extend by 64 ?
654 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start
655 Retrace register (3d4h index 4).
656 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse
657 is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or
658 does it really extend by 32 ?
659 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer
660 Position register (3d4h index 3Bh)
661 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant
662 Termination register (3d4h index 5Fh).
663 */
664 case 0x5d:
665 vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8);
666 vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7);
667 vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6);
668 vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3);
669 vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4);
670 vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20);
671 s3_define_video_mode();
672 break;
673 /*
674 3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +)
675 bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h
676 index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5.
677 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End
678 register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1
679 and 6
680 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking
681 register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9
682 in 3d4h index 9 bit 5
683 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace
684 register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2
685 and 7.
686 6 Line Compare Position bit 10. Bit 10 of the Line Compare register
687 (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h
688 index 9 bit 6.
689 */
690 case 0x5e:
691 vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10);
692 vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9);
693 vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8);
694 vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6);
695 vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4);
696 s3_define_video_mode();
697 break;
698 case 0x67:
699 s3.ext_misc_ctrl_2 = data;
700 s3_define_video_mode();
701 //printf("%02x X\n",data);
702 break;
703 case 0x68:
704 if(s3.reg_lock2 == 0xa5)
705 {
706 s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16);
707 LOGREG("CR68: Strapping data = %08x\n",s3.strapping);
708 }
709 break;
710 case 0x69:
711 vga.crtc.start_addr_latch &= ~0x1f0000;
712 vga.crtc.start_addr_latch |= ((data & 0x1f) << 16);
713 s3_define_video_mode();
714 break;
715 case 0x6a:
716 svga.bank_w = data & 0x3f;
717 svga.bank_r = svga.bank_w;
718 break;
719 case 0x6f:
720 if(s3.reg_lock2 == 0xa5)
721 {
722 s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24);
723 LOGREG("CR6F: Strapping data = %08x\n",s3.strapping);
724 }
725 break;
726 default:
727 LOGREG("S3: CR%02X write %02x\n",index,data);
728 break;
729 }
730 }
731 }
732
733
port_03b0_r(offs_t offset)734 uint8_t s3virge_vga_device::port_03b0_r(offs_t offset)
735 {
736 uint8_t res = 0xff;
737
738 if (CRTC_PORT_ADDR == 0x3b0)
739 {
740 switch(offset)
741 {
742 case 5:
743 res = s3_crtc_reg_read(vga.crtc.index);
744 break;
745 default:
746 res = vga_device::port_03b0_r(offset);
747 break;
748 }
749 }
750
751 return res;
752 }
753
port_03b0_w(offs_t offset,uint8_t data)754 void s3virge_vga_device::port_03b0_w(offs_t offset, uint8_t data)
755 {
756 if (CRTC_PORT_ADDR == 0x3b0)
757 {
758 switch(offset)
759 {
760 case 5:
761 vga.crtc.data[vga.crtc.index] = data;
762 s3_crtc_reg_write(vga.crtc.index,data);
763 break;
764 default:
765 vga_device::port_03b0_w(offset,data);
766 break;
767 }
768 }
769 }
770
port_03c0_r(offs_t offset)771 uint8_t s3virge_vga_device::port_03c0_r(offs_t offset)
772 {
773 uint8_t res;
774
775 switch(offset)
776 {
777 default:
778 res = s3_vga_device::port_03c0_r(offset);
779 break;
780 }
781
782 return res;
783 }
784
port_03c0_w(offs_t offset,uint8_t data)785 void s3virge_vga_device::port_03c0_w(offs_t offset, uint8_t data)
786 {
787 switch(offset)
788 {
789 default:
790 s3_vga_device::port_03c0_w(offset,data);
791 break;
792 }
793 }
794
port_03d0_r(offs_t offset)795 uint8_t s3virge_vga_device::port_03d0_r(offs_t offset)
796 {
797 uint8_t res = 0xff;
798
799 if (CRTC_PORT_ADDR == 0x3d0)
800 {
801 switch(offset)
802 {
803 case 5:
804 res = s3_crtc_reg_read(vga.crtc.index);
805 break;
806 default:
807 res = vga_device::port_03d0_r(offset);
808 break;
809 }
810 }
811
812 return res;
813 }
814
port_03d0_w(offs_t offset,uint8_t data)815 void s3virge_vga_device::port_03d0_w(offs_t offset, uint8_t data)
816 {
817 if (CRTC_PORT_ADDR == 0x3d0)
818 {
819 switch(offset)
820 {
821 case 5:
822 vga.crtc.data[vga.crtc.index] = data;
823 s3_crtc_reg_write(vga.crtc.index,data);
824 break;
825 default:
826 vga_device::port_03d0_w(offset,data);
827 break;
828 }
829 }
830 }
831
mem_r(offs_t offset)832 uint8_t s3virge_vga_device::mem_r(offs_t offset)
833 {
834 if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en)
835 {
836 uint8_t data;
837 if(offset & 0x10000)
838 return 0;
839 data = 0xff;
840 if(vga.sequencer.data[4] & 0x8)
841 {
842 if(offset + (svga.bank_r*0x10000) < vga.svga_intf.vram_size)
843 data = vga.memory[offset + (svga.bank_r*0x10000)];
844 }
845 else
846 {
847 int i;
848
849 for(i=0;i<4;i++)
850 {
851 if(vga.sequencer.map_mask & 1 << i)
852 {
853 if(offset*4+i+(svga.bank_r*0x10000) < vga.svga_intf.vram_size)
854 data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)];
855 }
856 }
857 }
858 return data;
859 }
860 if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size)
861 return vga_device::mem_r(offset);
862 else
863 return 0xff;
864 }
865
mem_w(offs_t offset,uint8_t data)866 void s3virge_vga_device::mem_w(offs_t offset, uint8_t data)
867 {
868 // bit 4 of CR53 enables memory-mapped I/O
869 if(s3.cr53 & 0x10)
870 {
871 // TODO
872 }
873
874 if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
875 {
876 // printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08));
877 if(offset & 0x10000)
878 return;
879 if(vga.sequencer.data[4] & 0x8)
880 {
881 if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size)
882 vga.memory[(offset + (svga.bank_w*0x10000))] = data;
883 }
884 else
885 {
886 int i;
887 for(i=0;i<4;i++)
888 {
889 if(vga.sequencer.map_mask & 1 << i)
890 {
891 if((offset*4+i+(svga.bank_w*0x10000)) < vga.svga_intf.vram_size)
892 vga.memory[(offset*4+i+(svga.bank_w*0x10000))] = data;
893 }
894 }
895 }
896 return;
897 }
898
899 if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size)
900 vga_device::mem_w(offset,data);
901 }
902
fb_r(offs_t offset)903 uint8_t s3virge_vga_device::fb_r(offs_t offset)
904 {
905 if(offset < s3virge.linear_address_size_full)
906 return vga.memory[offset % vga.svga_intf.vram_size];
907 return 0xff;
908 }
909
fb_w(offs_t offset,uint8_t data)910 void s3virge_vga_device::fb_w(offs_t offset, uint8_t data)
911 {
912 if(offset < s3virge.linear_address_size_full)
913 vga.memory[offset % vga.svga_intf.vram_size] = data;
914 }
915
add_command(int cmd_type)916 void s3virge_vga_device::add_command(int cmd_type)
917 {
918 // add command to S3D FIFO
919 if(s3virge.s3d.cmd_fifo_slots_free == 0)
920 {
921 LOGCMD("Attempt to add command when all command slots are full\n");
922 return;
923 }
924 memcpy(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg,s3virge.s3d.reg[cmd_type],256*4);
925 s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type;
926 LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type,s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg[S3D_REG_COMMAND],s3virge.s3d.cmd_fifo_next_ptr);
927 s3virge.s3d.cmd_fifo_next_ptr++;
928 if(s3virge.s3d.cmd_fifo_next_ptr >= 16)
929 s3virge.s3d.cmd_fifo_next_ptr = 0;
930 if(s3virge.s3d.cmd_fifo_slots_free == 16) // if all slots are free, start command now
931 command_start();
932 s3virge.s3d.cmd_fifo_slots_free--;
933 // TODO: handle full FIFO
934 }
935
command_start()936 void s3virge_vga_device::command_start()
937 {
938 // start next command in FIFO
939 int cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type;
940
941 switch(cmd_type)
942 {
943 case OP_2DLINE:
944 LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
945 break;
946 case OP_2DPOLY:
947 LOGCMD("2D Poly command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
948 break;
949 case OP_3DLINE:
950 LOGCMD("3D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
951 break;
952 case OP_3DTRI:
953 LOGCMD("3D Tri command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
954 break;
955 case OP_BITBLT:
956 s3virge.s3d.state = S3D_STATE_BITBLT;
957 s3virge.s3d.busy = true;
958 s3virge.s3d.bitblt_x_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x07ff0000) >> 16;
959 s3virge.s3d.bitblt_y_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x000007ff);
960 s3virge.s3d.bitblt_x_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x07ff0000) >> 16;
961 s3virge.s3d.bitblt_y_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x000007ff);
962 s3virge.s3d.bitblt_width = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0xffff0000) >> 16;
963 s3virge.s3d.bitblt_height = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0x0000ffff);
964 s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst;
965 s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src;
966 s3virge.s3d.bitblt_y_current = s3virge.s3d.bitblt_y_dst;
967 s3virge.s3d.bitblt_y_src_current = s3virge.s3d.bitblt_y_src;
968 s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
969 s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8;
970 s3virge.s3d.clip_r = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x000007ff;
971 s3virge.s3d.clip_l = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x07ff0000) >> 16;
972 s3virge.s3d.clip_b = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x000007ff;
973 s3virge.s3d.clip_t = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x07ff0000) >> 16;
974 if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080))
975 m_draw_timer->adjust(attotime::from_nsec(250),0,attotime::from_nsec(250));
976 s3virge.s3d.bitblt_step_count = 0;
977 s3virge.s3d.bitblt_mono_pattern =
978 s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_0] | (uint64_t)(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_1]) << 32;
979 s3virge.s3d.bitblt_current_pixel = 0;
980 s3virge.s3d.bitblt_pixel_pos = 0;
981 s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR] = 0xffffffff; // win31 never sets this?
982 LOGCMD("Started BitBLT command [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
983 //if(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17) == 0xf0) machine().debug_break();
984 break;
985 }
986 }
987
command_finish()988 void s3virge_vga_device::command_finish()
989 {
990 s3virge.s3d.state = S3D_STATE_IDLE;
991 s3virge.s3d.cmd_fifo_current_ptr++;
992 if(s3virge.s3d.cmd_fifo_current_ptr >= 16)
993 s3virge.s3d.cmd_fifo_current_ptr = 0;
994 s3virge.s3d.cmd_fifo_slots_free++;
995 if(s3virge.s3d.cmd_fifo_slots_free > 16)
996 s3virge.s3d.cmd_fifo_slots_free = 16;
997 m_draw_timer->adjust(attotime::never);
998
999 // check if there is another command in the FIFO
1000 if(s3virge.s3d.cmd_fifo_slots_free < 16)
1001 command_start();
1002 else
1003 s3virge.s3d.busy = false;
1004
1005 LOGMMIO("Command finished [%u] (%u slots free)\n",s3virge.s3d.cmd_fifo_current_ptr,s3virge.s3d.cmd_fifo_slots_free);
1006 }
1007
line2d_step()1008 void s3virge_vga_device::line2d_step()
1009 {
1010 command_finish();
1011 }
1012
poly2d_step()1013 void s3virge_vga_device::poly2d_step()
1014 {
1015 command_finish();
1016 }
1017
line3d_step()1018 void s3virge_vga_device::line3d_step()
1019 {
1020 command_finish();
1021 }
1022
poly3d_step()1023 void s3virge_vga_device::poly3d_step()
1024 {
1025 command_finish();
1026 }
1027
1028
GetROP(uint8_t rop,uint32_t src,uint32_t dst,uint32_t pat)1029 uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat)
1030 {
1031 uint32_t ret = 0;
1032
1033 switch(rop)
1034 {
1035 case 0x00: // 0
1036 ret = 0;
1037 break;
1038 case 0x55: // Dn
1039 ret = ~dst;
1040 break;
1041 case 0x5a: // DPx
1042 ret = dst ^ pat;
1043 break;
1044 case 0x66: // DSx
1045 ret = dst ^ src;
1046 break;
1047 case 0x88: // DSa
1048 ret = dst & src;
1049 break;
1050 case 0xb8: // PSDPxax
1051 ret = ((dst ^ pat) & src) ^ pat;
1052 // machine().debug_break();
1053 break;
1054 case 0xcc:
1055 ret = src;
1056 break;
1057 case 0xf0:
1058 ret = pat;
1059 break;
1060 case 0xff: // 1
1061 ret = 0xffffffff;
1062 break;
1063 default:
1064 popmessage("Unimplemented ROP 0x%02x",rop);
1065 }
1066
1067 return ret;
1068 }
1069
advance_pixel()1070 bool s3virge_vga_device::advance_pixel()
1071 {
1072 bool xpos, ypos;
1073 int16_t top, left, right, bottom;
1074 // advance src/dst and pattern location
1075 xpos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x02000000; // X Positive
1076 ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x04000000; // Y Positive
1077 if(xpos)
1078 {
1079 left = s3virge.s3d.bitblt_x_dst;
1080 right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width + 1;
1081 s3virge.s3d.bitblt_x_current++;
1082 s3virge.s3d.bitblt_x_src_current++;
1083 s3virge.s3d.bitblt_pat_x++;
1084 }
1085 else
1086 {
1087 left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width - 1;
1088 right = s3virge.s3d.bitblt_x_dst;
1089 s3virge.s3d.bitblt_x_current--;
1090 s3virge.s3d.bitblt_x_src_current--;
1091 s3virge.s3d.bitblt_pat_x--;
1092 // machine().debug_break();
1093 }
1094 if(ypos)
1095 {
1096 top = s3virge.s3d.bitblt_y_dst;
1097 bottom = s3virge.s3d.bitblt_y_dst + s3virge.s3d.bitblt_height;
1098 }
1099 else
1100 {
1101 top = s3virge.s3d.bitblt_y_dst - s3virge.s3d.bitblt_height;
1102 bottom = s3virge.s3d.bitblt_y_dst;
1103 }
1104 if(s3virge.s3d.bitblt_pat_x < 0 || s3virge.s3d.bitblt_pat_x >= 8)
1105 s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
1106 if((s3virge.s3d.bitblt_x_current >= right) || (s3virge.s3d.bitblt_x_current <= left))
1107 {
1108 s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst;
1109 s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src;
1110 if(ypos)
1111 {
1112 s3virge.s3d.bitblt_y_current++;
1113 s3virge.s3d.bitblt_y_src_current++;
1114 s3virge.s3d.bitblt_pat_y++;
1115 }
1116 else
1117 {
1118 s3virge.s3d.bitblt_y_current--;
1119 s3virge.s3d.bitblt_y_src_current--;
1120 s3virge.s3d.bitblt_pat_y--;
1121 }
1122 s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
1123 if(s3virge.s3d.bitblt_pat_y >= 8 || s3virge.s3d.bitblt_pat_y < 0)
1124 s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8;
1125 logerror("SRC: %i,%i DST: %i,%i PAT: %i,%i Bounds: %i,%i,%i,%i\n",
1126 s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current,
1127 s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,
1128 s3virge.s3d.bitblt_pat_x,s3virge.s3d.bitblt_pat_y,
1129 left,right,top,bottom);
1130 if((s3virge.s3d.bitblt_y_current >= bottom) || (s3virge.s3d.bitblt_y_current <= top))
1131 return true;
1132 }
1133 return false;
1134 }
1135
bitblt_step()1136 void s3virge_vga_device::bitblt_step()
1137 {
1138 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40))
1139 bitblt_monosrc_step();
1140 else
1141 bitblt_colour_step();
1142 }
1143
bitblt_colour_step()1144 void s3virge_vga_device::bitblt_colour_step()
1145 {
1146 // progress current BitBLT operation
1147 // get source and destination addresses
1148 uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8;
1149 uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8;
1150 uint8_t pixel_size = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) >> 2;
1151 uint8_t rop = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17;
1152 uint32_t src = 0;
1153 uint32_t dst = 0;
1154 uint32_t pat = 0;
1155 int align = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x000000c00) >> 10;
1156 int x;
1157 bool done = false;
1158
1159 switch(pixel_size)
1160 {
1161 case 0: // 8bpp
1162 for(x=0;x<4;x++)
1163 {
1164 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1165 src = s3virge.s3d.image_xfer >> (x*8);
1166 else
1167 src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1168 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
1169 {
1170 pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
1171 ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
1172 }
1173 else
1174 pat = (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*8) + s3virge.s3d.bitblt_pat_x]) << 8;
1175 dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1176 write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xff);
1177 done = advance_pixel();
1178 if(done)
1179 {
1180 command_finish();
1181 break;
1182 }
1183 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
1184 {
1185 if(align == 2) // doubleword aligned, end here
1186 break;
1187 if(align == 1) // word aligned, move to next word
1188 {
1189 if(x < 2)
1190 x = 2;
1191 else
1192 break;
1193 }
1194 }
1195 }
1196 break;
1197 case 1: // 16bpp
1198 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1199 src = s3virge.s3d.image_xfer;
1200 else
1201 src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1202 dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1203 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
1204 {
1205 pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
1206 ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
1207 }
1208 else
1209 pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8;
1210 write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
1211 done = advance_pixel();
1212 if(done)
1213 {
1214 command_finish();
1215 break;
1216 }
1217 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2)
1218 break; // if a new line of an image transfer, and is dword aligned, stop here
1219 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1220 src = s3virge.s3d.image_xfer >> 16;
1221 else
1222 src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1223 dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1224 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
1225 {
1226 pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
1227 ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
1228 }
1229 else
1230 pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8;
1231 write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
1232 if(advance_pixel())
1233 command_finish();
1234 break;
1235 case 2: // 24bpp
1236 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1237 {
1238 src = s3virge.s3d.image_xfer;
1239 for(x=0;x<4;x++)
1240 {
1241 s3virge.s3d.bitblt_current_pixel |= ((s3virge.s3d.image_xfer >> (x*8)) & 0xff) << s3virge.s3d.bitblt_pixel_pos*8;
1242 s3virge.s3d.bitblt_pixel_pos++;
1243 if(s3virge.s3d.bitblt_pixel_pos > 2)
1244 {
1245 s3virge.s3d.bitblt_pixel_pos = 0;
1246 dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1247 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
1248 {
1249 pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
1250 ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
1251 }
1252 else
1253 pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8
1254 | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16;
1255 write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat));
1256 s3virge.s3d.bitblt_current_pixel = 0;
1257 done = advance_pixel();
1258 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
1259 {
1260 if(align == 2) // doubleword aligned, end here
1261 x = 4;
1262 if(align == 1) // word aligned, move to next word
1263 {
1264 if(x < 2)
1265 x = 2;
1266 else
1267 x = 4;
1268 }
1269 }
1270 if(done)
1271 command_finish();
1272 }
1273 }
1274 break;
1275 }
1276 else
1277 {
1278 src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1279 dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1280 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
1281 {
1282 pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
1283 ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
1284 }
1285 else
1286 pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8
1287 | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16;
1288 }
1289 write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat));
1290 if(advance_pixel())
1291 command_finish();
1292 break;
1293 }
1294
1295 s3virge.s3d.bitblt_step_count++;
1296 }
1297
bitblt_monosrc_step()1298 void s3virge_vga_device::bitblt_monosrc_step()
1299 {
1300 // progress current monochrome source BitBLT operation
1301 uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8;
1302 uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8;
1303 uint8_t pixel_size = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) >> 2;
1304 uint8_t rop = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17;
1305 uint32_t src = 0;
1306 uint32_t dst = 0;
1307 uint32_t pat = 0;
1308 int align = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x000000c00) >> 10;
1309 int x;
1310 bool done = false;
1311
1312 switch(pixel_size)
1313 {
1314 case 0: // 8bpp
1315 for(x=31;x>=0;x--)
1316 {
1317 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1318 src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
1319 else
1320 src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1321 dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1322
1323 if(src & (1 << x))
1324 write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff);
1325 else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
1326 write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff);
1327 //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
1328 done = advance_pixel();
1329 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
1330 {
1331 switch(align)
1332 {
1333 case 0:
1334 x &= ~7;
1335 break;
1336 case 1:
1337 x &= ~15;
1338 break;
1339 case 2:
1340 x = -1;
1341 break;
1342 }
1343 if(done)
1344 {
1345 command_finish();
1346 break;
1347 }
1348 }
1349 }
1350 break;
1351 case 1: // 16bpp
1352 for(x=31;x>=0;x--)
1353 {
1354 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1355 src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
1356 else
1357 src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1358 dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1359
1360 if(src & (1 << x))
1361 write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff);
1362 else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
1363 write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff);
1364 //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
1365 done = advance_pixel();
1366 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
1367 {
1368 switch(align)
1369 {
1370 case 0:
1371 x &= ~7;
1372 break;
1373 case 1:
1374 x &= ~15;
1375 break;
1376 case 2:
1377 x = -1;
1378 break;
1379 }
1380 if(done)
1381 {
1382 command_finish();
1383 break;
1384 }
1385 }
1386 }
1387 break;
1388 case 2: // 24bpp
1389 for(x=31;x>=0;x--)
1390 {
1391 if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
1392 src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
1393 else
1394 src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
1395 dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
1396
1397 if(src & (1 << x))
1398 write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat));
1399 else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
1400 write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat));
1401 //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
1402 done = advance_pixel();
1403 if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
1404 {
1405 switch(align)
1406 {
1407 case 0:
1408 x &= ~7;
1409 break;
1410 case 1:
1411 x &= ~15;
1412 break;
1413 case 2:
1414 x = -1;
1415 break;
1416 }
1417 if(done)
1418 {
1419 command_finish();
1420 break;
1421 }
1422 }
1423 }
1424 break;
1425 }
1426
1427 s3virge.s3d.bitblt_step_count++;
1428 }
1429
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1430 void s3virge_vga_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1431 {
1432 // TODO: S3D state timing
1433 if(id == TIMER_DRAW_STEP)
1434 {
1435 switch(s3virge.s3d.state)
1436 {
1437 case S3D_STATE_IDLE:
1438 m_draw_timer->adjust(attotime::zero);
1439 break;
1440 case S3D_STATE_2DLINE:
1441 line2d_step();
1442 break;
1443 case S3D_STATE_2DPOLY:
1444 poly2d_step();
1445 break;
1446 case S3D_STATE_3DLINE:
1447 line3d_step();
1448 break;
1449 case S3D_STATE_3DPOLY:
1450 poly3d_step();
1451 break;
1452 case S3D_STATE_BITBLT:
1453 bitblt_step();
1454 break;
1455 }
1456 }
1457 }
1458
1459 // 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon)
1460 // bit 0 - Autoexecute, if set command is executed when the highest relevant register is written to (A50C / A97C / AD7C)
1461 // bit 1 - Enable hardware clipping
1462 // bits 2-4 - Destination colour format - (0 = 8bpp palettised, 1 = 16bpp RGB1555 or RGB565, 2 = 24bpp RGB888
1463 // bit 5 - Draw enable - if reset, doesn't draw anything, but is still executed
1464 // bit 6 - Image source Mono transfer, if set source is mono, otherwise source is the same pixel depth as the destination
1465 // bit 7 - Image data source - 0 = source is in video memory, 1 = source is from the image transfer port (CPU / system memory)
1466 // bit 8 - Mono pattern - if set, pattern data is mono, otherwise pattern data is the same pixel depth as the destination
1467 // Cleared to 0 if using an ROP with a colour source Must be set to 1 if doing a rectangle fill operation
1468 // bit 9 - Transparency - if set, does not update if a background colour is selected. Effectively only if bit 7 is set, Typically used for text display.
1469 // bits 10-11 - Image transfer alignment - Data for an image transfer is byte (0), word (1), or doubleword (2) aligned. All image transfers are doubleword in size.
1470 // bits 12-13 - First doubleword offset - (Image transfers) - start with the given byte (+1) in a doubleword for an image transfer
1471 // bits 17-24 - MS Windows Raster Operation
1472 // bit 25 - X Positive - if set, BitBLT is performed from left to right, otherwise, from right to left
1473 // bit 26 - Y Positive - if set, BitBLT is performed from top to bottom, otherwise from bottom to top
1474 // bits 27-30 - 2D Command - 0000 = BitBLT, 0010 = Rectangle Fill, 0011 = Line Draw, 0101 = Polygon Fill, 1111 = NOP (Turns off autoexecute without executing a command)
1475 // bit 31 - 2D / 3D Select
1476
1477
s3d_sub_status_r()1478 uint32_t s3virge_vga_device::s3d_sub_status_r()
1479 {
1480 uint32_t res = 0x00000000;
1481
1482 if(!s3virge.s3d.busy)
1483 res |= 0x00002000; // S3d engine is idle
1484
1485 //res |= (s3virge.s3d.cmd_fifo_slots_free << 8);
1486 if(s3virge.s3d.cmd_fifo_slots_free == 16)
1487 res |= 0x1f00;
1488
1489 return res;
1490 }
1491
s3d_sub_control_w(uint32_t data)1492 void s3virge_vga_device::s3d_sub_control_w(uint32_t data)
1493 {
1494 s3virge.interrupt_enable = data & 0x00003f80;
1495 // TODO: bits 14-15==10 - reset engine
1496 LOGMMIO("Sub control = %08x\n", data);
1497 }
1498
s3d_func_ctrl_r()1499 uint32_t s3virge_vga_device::s3d_func_ctrl_r()
1500 {
1501 uint32_t ret = 0;
1502
1503 ret |= (s3virge.s3d.cmd_fifo_slots_free << 6);
1504 return ret;
1505 }
1506
s3d_register_r(offs_t offset)1507 uint32_t s3virge_vga_device::s3d_register_r(offs_t offset)
1508 {
1509 uint32_t res = 0;
1510 int op_type = (((offset*4) & 0x1c00) >> 10) - 1;
1511
1512 // unused registers
1513 if(offset < 0x100/4)
1514 return 0;
1515 if(offset >= 0x1c0/4 && offset < 0x400/4)
1516 return 0;
1517
1518 // handle BitBLT pattern registers
1519 if((offset >= 0x100/4) && (offset < 0x1c0/4))
1520 return s3virge.s3d.pattern[offset - (0x100/4)];
1521
1522 res = s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4];
1523 LOGMMIO("MM%04X returning %08x\n", (offset*4)+0xa000, res);
1524
1525 return res;
1526 }
1527
s3d_register_w(offs_t offset,uint32_t data)1528 void s3virge_vga_device::s3d_register_w(offs_t offset, uint32_t data)
1529 {
1530 int op_type = (((offset*4) & 0x1c00) >> 10) - 1;
1531
1532 // unused registers
1533 if(offset < 0x100/4)
1534 return;
1535 if(offset >= 0x1c0/4 && offset < 0x400/4)
1536 return;
1537
1538 // handle BitBLT pattern registers
1539 if((offset >= 0x100/4) && (offset < 0x1c0/4))
1540 {
1541 //COMBINE_DATA(&s3virge.s3d.pattern[(offset*4) - (0x100/4)]);
1542 s3virge.s3d.pattern[((offset - 0x100/4)*4)+3] = (data & 0xff000000) >> 24;
1543 s3virge.s3d.pattern[((offset - 0x100/4)*4)+2] = (data & 0x00ff0000) >> 16;
1544 s3virge.s3d.pattern[((offset - 0x100/4)*4)+1] = (data & 0x0000ff00) >> 8;
1545 s3virge.s3d.pattern[((offset - 0x100/4)*4)] = (data & 0x000000ff);
1546 return;
1547 }
1548
1549 s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4] = data;
1550 LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa000, data);
1551 switch(offset)
1552 {
1553 case 0x500/4:
1554 if(!(data & 0x00000001))
1555 add_command(op_type);
1556 break;
1557 case 0x50c/4:
1558 if(s3virge.s3d.reg[op_type][S3D_REG_COMMAND] & 0x00000001) // autoexecute enabled
1559 add_command(op_type);
1560 break;
1561 }
1562 }
1563
1564