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