1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /******************************************************************************
4 *
5 *   Sony PlayStation 2 VU1 interface device skeleton
6 *
7 *   To Do:
8 *     Everything
9 *
10 *   Note: STAT mode bit twiddling is a total guess
11 *
12 */
13 
14 #include <cmath>
15 #include "emu.h"
16 #include "ps2vif1.h"
17 #include <cmath>
18 
19 #include "video/ps2gif.h"
20 
21 DEFINE_DEVICE_TYPE(SONYPS2_VIF1, ps2_vif1_device, "ps2vif1", "PlayStation 2 VIF1")
22 
23 /*static*/ const size_t ps2_vif1_device::BUFFER_SIZE = 0x40;
24 /*static*/ const uint32_t ps2_vif1_device::FORMAT_SIZE[] = {
25 	1, 1, 1, 1,
26 	2, 1, 1, 1,
27 	3, 2, 1, 1,
28 	4, 2, 1, 2
29 };
30 
ps2_vif1_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)31 ps2_vif1_device::ps2_vif1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
32 	: device_t(mconfig, SONYPS2_VIF1, tag, owner, clock)
33 	, device_execute_interface(mconfig, *this)
34 	, m_gs(*this, finder_base::DUMMY_TAG)
35 	, m_vu1(*this, finder_base::DUMMY_TAG)
36 {
37 }
38 
~ps2_vif1_device()39 ps2_vif1_device::~ps2_vif1_device()
40 {
41 }
42 
device_start()43 void ps2_vif1_device::device_start()
44 {
45 	set_icountptr(m_icount);
46 
47 	save_item(NAME(m_icount));
48 
49 	save_item(NAME(m_buffer));
50 	save_item(NAME(m_curr));
51 	save_item(NAME(m_end));
52 
53 	save_item(NAME(m_status));
54 	save_item(NAME(m_control));
55 	save_item(NAME(m_err));
56 	save_item(NAME(m_mark));
57 	save_item(NAME(m_cycle));
58 	save_item(NAME(m_mode));
59 	save_item(NAME(m_num));
60 	save_item(NAME(m_mask));
61 	save_item(NAME(m_code));
62 	save_item(NAME(m_itops));
63 	save_item(NAME(m_base));
64 	save_item(NAME(m_offset));
65 	save_item(NAME(m_tops));
66 	save_item(NAME(m_itop));
67 	save_item(NAME(m_top));
68 
69 	save_item(NAME(m_row_fill));
70 	save_item(NAME(m_col_fill));
71 
72 	save_item(NAME(m_data_needed));
73 	save_item(NAME(m_data_index));
74 	save_item(NAME(m_command));
75 	save_item(NAME(m_alignment));
76 
77 	save_item(NAME(m_mpg_count));
78 	save_item(NAME(m_mpg_addr));
79 	save_item(NAME(m_mpg_insn));
80 
81 	save_item(NAME(m_unpack_count));
82 	save_item(NAME(m_unpack_addr));
83 	save_item(NAME(m_unpack_last));
84 	save_item(NAME(m_unpack_bits_remaining));
85 	save_item(NAME(m_unpack_signed));
86 	save_item(NAME(m_unpack_add_tops));
87 	save_item(NAME(m_unpack_format));
88 }
89 
device_reset()90 void ps2_vif1_device::device_reset()
91 {
92 	m_icount = 0;
93 
94 	memset(m_buffer, 0, sizeof(uint32_t) * BUFFER_SIZE);
95 	m_curr = 0;
96 	m_end = 0;
97 
98 	m_status = 0;
99 	m_control = 0;
100 	m_err = 0;
101 	m_mark = 0;
102 	m_cycle = 0;
103 	m_mode = 0;
104 	m_num = 0;
105 	m_mask = 0;
106 	m_code = 0;
107 	m_itops = 0;
108 	m_base = 0;
109 	m_offset = 0;
110 	m_tops = 0;
111 	m_itop = 0;
112 	m_top = 0;
113 
114 	memset(m_row_fill, 0, sizeof(uint32_t) * 4);
115 	memset(m_col_fill, 0, sizeof(uint32_t) * 4);
116 
117 	m_data_needed = 0;
118 	m_data_index = 0;
119 	m_command = 0;
120 	m_alignment = 0;
121 
122 	m_mpg_count = 0;
123 	m_mpg_addr = 0;
124 	m_mpg_insn = 0;
125 
126 	m_unpack_count = 0;
127 	m_unpack_addr = 0;
128 	m_unpack_last = 0;
129 	m_unpack_bits_remaining = 0;
130 	m_unpack_signed = false;
131 	m_unpack_add_tops = false;
132 	m_unpack_format = FMT_S32;
133 }
134 
regs_r(offs_t offset)135 uint32_t ps2_vif1_device::regs_r(offs_t offset)
136 {
137 	uint32_t ret = 0;
138 	switch (offset)
139 	{
140 		case 0x00/4:
141 			ret = m_status;
142 			logerror("%s: Read: VIF1_STAT (%08x)\n", machine().describe_context(), ret);
143 			break;
144 		case 0x10/4:
145 			ret = m_control;
146 			logerror("%s: Read: VIF1_FBRST (%08x)\n", machine().describe_context(), ret);
147 			break;
148 		case 0x20/4:
149 			ret = m_err;
150 			logerror("%s: Read: VIF1_ERR (%08x)\n", machine().describe_context(), ret);
151 			break;
152 		case 0x30/4:
153 			ret = m_mark;
154 			logerror("%s: Read: VIF1_MARK (%08x)\n", machine().describe_context(), ret);
155 			break;
156 		case 0x40/4:
157 			ret = m_cycle;
158 			logerror("%s: Read: VIF1_CYCLE (%08x)\n", machine().describe_context(), ret);
159 			break;
160 		case 0x50/4:
161 			ret = m_mode;
162 			logerror("%s: Read: VIF1_MODE (%08x)\n", machine().describe_context(), ret);
163 			break;
164 		case 0x60/4:
165 			ret = m_num;
166 			logerror("%s: Read: VIF1_NUM (%08x)\n", machine().describe_context(), ret);
167 			break;
168 		case 0x70/4:
169 			ret = m_mask;
170 			logerror("%s: Read: VIF1_MASK (%08x)\n", machine().describe_context(), ret);
171 			break;
172 		case 0x80/4:
173 			ret = m_code;
174 			logerror("%s: Read: VIF1_CODE (%08x)\n", machine().describe_context(), ret);
175 			break;
176 		case 0x90/4:
177 			ret = m_itops;
178 			logerror("%s: Read: VIF1_ITOPS (%08x)\n", machine().describe_context(), ret);
179 			break;
180 		case 0xa0/4:
181 			ret = m_base;
182 			logerror("%s: Read: VIF1_BASE (%08x)\n", machine().describe_context(), ret);
183 			break;
184 		case 0xb0/4:
185 			ret = m_offset;
186 			logerror("%s: Read: VIF1_OFST (%08x)\n", machine().describe_context(), ret);
187 			break;
188 		case 0xc0/4:
189 			ret = m_tops;
190 			logerror("%s: Read: VIF1_TOPS (%08x)\n", machine().describe_context(), ret);
191 			break;
192 		case 0xd0/4:
193 			ret = m_itop;
194 			logerror("%s: Read: VIF1_ITOP (%08x)\n", machine().describe_context(), ret);
195 			break;
196 		case 0xe0/4:
197 			ret = m_top;
198 			logerror("%s: Read: VIF1_TOP (%08x)\n", machine().describe_context(), ret);
199 			break;
200 		case 0x100/4:
201 			ret = m_row_fill[0];
202 			logerror("%s: Read: VIF1_R0 (%08x)\n", machine().describe_context(), ret);
203 			break;
204 		case 0x110/4:
205 			ret = m_row_fill[1];
206 			logerror("%s: Read: VIF1_R1 (%08x)\n", machine().describe_context(), ret);
207 			break;
208 		case 0x120/4:
209 			ret = m_row_fill[2];
210 			logerror("%s: Read: VIF1_R2 (%08x)\n", machine().describe_context(), ret);
211 			break;
212 		case 0x130/4:
213 			ret = m_row_fill[3];
214 			logerror("%s: Read: VIF1_R3 (%08x)\n", machine().describe_context(), ret);
215 			break;
216 		case 0x140/4:
217 			ret = m_col_fill[0];
218 			logerror("%s: Read: VIF1_C0 (%08x)\n", machine().describe_context(), ret);
219 			break;
220 		case 0x150/4:
221 			ret = m_col_fill[1];
222 			logerror("%s: Read: VIF1_C1 (%08x)\n", machine().describe_context(), ret);
223 			break;
224 		case 0x160/4:
225 			ret = m_col_fill[2];
226 			logerror("%s: Read: VIF1_C2 (%08x)\n", machine().describe_context(), ret);
227 			break;
228 		case 0x170/4:
229 			ret = m_col_fill[3];
230 			logerror("%s: Read: VIF1_C3 (%08x)\n", machine().describe_context(), ret);
231 			break;
232 		default:
233 			logerror("%s: Read: Unknown (%08x)\n", machine().describe_context(), 0x10003c00 + (offset << 2));
234 			break;
235 	}
236 	return ret;
237 }
238 
regs_w(offs_t offset,uint32_t data)239 void ps2_vif1_device::regs_w(offs_t offset, uint32_t data)
240 {
241 	logerror("%s: Write: Unknown %08x = %08x\n", machine().describe_context(), 0x10003c00 + (offset << 2), data);
242 }
243 
mmio_r(offs_t offset)244 uint64_t ps2_vif1_device::mmio_r(offs_t offset)
245 {
246 	uint64_t ret = 0ULL;
247 	if (offset)
248 	{
249 		logerror("%s: mmio_r [127..64]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret);
250 	}
251 	else
252 	{
253 		logerror("%s: mmio_r [63..0]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret);
254 	}
255 	return ret;
256 }
257 
mmio_w(offs_t offset,uint64_t data)258 void ps2_vif1_device::mmio_w(offs_t offset, uint64_t data)
259 {
260 	if (offset)
261 	{
262 		logerror("%s: mmio_w [127..64]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data);
263 		fifo_push((uint32_t)data);
264 		fifo_push((uint32_t)(data >> 32));
265 	}
266 	else
267 	{
268 		logerror("%s: mmio_w [63..0]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data);
269 		fifo_push((uint32_t)data);
270 		fifo_push((uint32_t)(data >> 32));
271 	}
272 }
273 
274 
dma_write(const uint64_t hi,const uint64_t lo)275 void ps2_vif1_device::dma_write(const uint64_t hi, const uint64_t lo)
276 {
277 	//logerror("%s: dma_write: %08x%08x%08x%08x\n", machine().describe_context(), (uint32_t)(hi >> 32), (uint32_t)hi, (uint32_t)(lo >> 32), (uint32_t)lo);
278 	fifo_push((uint32_t)(lo >> 32));
279 	fifo_push((uint32_t)lo);
280 	fifo_push((uint32_t)(hi >> 32));
281 	fifo_push((uint32_t)hi);
282 }
283 
tag_write(uint32_t * data)284 void ps2_vif1_device::tag_write(uint32_t *data)
285 {
286 	logerror("%s: tag_write: %08x%08x\n", machine().describe_context(), data[2], data[3]);
287 	fifo_push(data[2]);
288 	fifo_push(data[3]);
289 }
290 
fifo_push(uint32_t data)291 void ps2_vif1_device::fifo_push(uint32_t data)
292 {
293 	if (m_end >= BUFFER_SIZE)
294 	{
295 		printf("FIFO overflow :(\n");
296 		return;
297 	}
298 
299 	m_buffer[m_end++] = data;
300 
301 	m_status &= ~0x1f000000;
302 	m_status |= ((m_end - m_curr) >> 2) << 24;
303 	logerror("%s: Pushing %08x onto FIFO, depth is now %d, status is now %08x\n", machine().describe_context(), data, m_end - m_curr, m_status);
304 }
305 
fifo_pop()306 uint32_t ps2_vif1_device::fifo_pop()
307 {
308 	m_alignment = (m_alignment + 1) & 3;
309 
310 	if (m_curr >= m_end)
311 	{
312 		return 0;
313 	}
314 
315 	const uint32_t ret = m_buffer[m_curr++];
316 	if (m_curr >= m_end)
317 	{
318 		m_curr = 0;
319 		m_end = 0;
320 	}
321 
322 	m_status &= ~0x1f000000;
323 	m_status |= ((m_end - m_curr) >> 2) << 24;
324 	logerror("%s: Popping %08x from FIFO, depth is now %d, status is now %08x\n", machine().describe_context(), ret, m_end - m_curr, m_status);
325 
326 	return ret;
327 }
328 
execute_run()329 void ps2_vif1_device::execute_run()
330 {
331 	while (m_icount > 0)
332 	{
333 		if (m_status & (STAT_E_WAIT | STAT_GS_WAIT | STAT_STALL_STOP | STAT_STALL_FBRK | STAT_STALL_INT))
334 		{
335 			m_icount = 0;
336 			break;
337 		}
338 
339 		switch (m_status & STAT_MODE_MASK)
340 		{
341 			case STAT_MODE_IDLE:
342 				if (fifo_depth())
343 				{
344 					m_code = fifo_pop();
345 					logerror("%s: New VIFcode: %08x\n", machine().describe_context(), m_code);
346 				}
347 				else
348 				{
349 					//logerror("%s: Nothing in FIFO, idle\n", machine().describe_context());
350 					m_icount = 0;
351 					break;
352 				}
353 				// Intentional fall-through
354 			case STAT_MODE_DECODE:
355 				decode_vifcode();
356 				break;
357 			case STAT_MODE_WAIT:
358 				if (fifo_depth() < m_data_needed)
359 				{
360 					m_icount = 0;
361 					break;
362 				}
363 				// Intentional fall-through
364 			case STAT_MODE_DATA:
365 				transfer_vifcode_data();
366 				break;
367 		}
368 	}
369 }
370 
transfer_vifcode_data()371 void ps2_vif1_device::transfer_vifcode_data()
372 {
373 	m_status &= ~STAT_MODE_MASK;
374 	if (fifo_depth() < m_data_needed)
375 	{
376 		//logerror("%s: transfer: We need %d but only have %d, waiting\n", machine().describe_context(), m_data_needed, fifo_depth());
377 		m_status |= STAT_MODE_WAIT;
378 		m_icount = 0;
379 		return;
380 	}
381 
382 	switch (m_command)
383 	{
384 		case 0x20: /* STMASK */
385 			m_mask = fifo_pop();
386 			logerror("%s: STMASK: %08x\n", machine().describe_context(), m_mask);
387 			m_data_needed = 0;
388 			break;
389 		case 0x30: /* STROW */
390 			m_row_fill[m_data_index] = fifo_pop();
391 			logerror("%s: STMASK: %08x\n", machine().describe_context(), m_row_fill[m_data_index]);
392 			m_data_needed--;
393 			break;
394 		case 0x31: /* STCOL */
395 			m_col_fill[m_data_index] = fifo_pop();
396 			logerror("%s: STMASK: %08x\n", machine().describe_context(), m_col_fill[m_data_index]);
397 			m_data_needed--;
398 			break;
399 		case 0x4a: /* MPG */
400 			transfer_mpg();
401 			break;
402 		default:
403 			if ((m_command & 0x60) == 0x60)
404 			{
405 				logerror("%s: Unpack: %02x\n", machine().describe_context(), m_command);
406 				transfer_unpack();
407 			}
408 			else
409 			{
410 				logerror("%s: Unknown command: %02x\n", machine().describe_context(), m_command);
411 			}
412 			break;
413 	}
414 
415 	if (m_data_needed)
416 	{
417 		if (fifo_depth() == 0)
418 		{
419 			m_status |= STAT_MODE_WAIT;
420 			m_icount = 0;
421 		}
422 		else
423 		{
424 			m_status |= STAT_MODE_DATA;
425 			m_icount--;
426 		}
427 	}
428 	else if (fifo_depth() > 0)
429 	{
430 		m_code = fifo_pop();
431 		logerror("%s: New VIFcode: %08x\n", machine().describe_context(), m_code);
432 		m_status |= STAT_MODE_DECODE;
433 		m_icount--;
434 	}
435 	else
436 	{
437 		m_status |= STAT_MODE_IDLE;
438 		m_icount = 0;
439 	}
440 }
441 
transfer_unpack()442 void ps2_vif1_device::transfer_unpack()
443 {
444 	switch (m_unpack_format)
445 	{
446 		case FMT_V4_32:
447 			//logerror("%s: Unpacking V4-32.\n", machine().describe_context());
448 			for (int element = 0; element < 4; element++)
449 			{
450 				const uint32_t data = fifo_pop();
451 				m_vu1->write_vu_mem(m_unpack_addr, data);
452 				m_unpack_addr += 4;
453 				m_unpack_count--;
454 			}
455 			break;
456 		default:
457 			logerror("%s: Unsupported unpack format: %02x\n", machine().describe_context(), m_unpack_format);
458 			break;
459 	}
460 
461 	if (m_unpack_count > 0)
462 	{
463 		m_data_needed = FORMAT_SIZE[m_unpack_format] - (m_unpack_bits_remaining ? 1 : 0);
464 	}
465 	else
466 	{
467 		m_data_needed = 0;
468 	}
469 }
470 
transfer_mpg()471 void ps2_vif1_device::transfer_mpg()
472 {
473 	while (m_data_needed > 2)
474 	{
475 		fifo_pop();
476 		m_data_needed--;
477 	}
478 
479 	m_mpg_insn = (uint64_t)fifo_pop() << 32;
480 	m_mpg_insn |= fifo_pop();
481 	m_mpg_count--;
482 
483 	m_vu1->write_micro_mem(m_mpg_addr, m_mpg_insn);
484 	logerror("%s: MPG, VU insn: %08x = %08x%08x, %d remaining\n", machine().describe_context(), m_mpg_addr, (uint32_t)(m_mpg_insn >> 32), (uint32_t)m_mpg_insn, m_mpg_count);
485 
486 	m_mpg_addr += 8;
487 	m_data_needed = m_mpg_count ? 2 : 0;
488 }
489 
decode_vifcode()490 void ps2_vif1_device::decode_vifcode()
491 {
492 	bool trigger_interrupt = BIT(m_code, 31);
493 	m_command = (m_code >> 24) & 0x7f;
494 	m_status &= ~STAT_MODE_MASK;
495 
496 	switch (m_command)
497 	{
498 		case 0x00: /* NOP */
499 			logerror("%s: NOP\n", machine().describe_context());
500 			break;
501 		case 0x01: /* STCYCL */
502 			m_cycle = (uint16_t)m_code;
503 			logerror("%s: STCYCL: %04x\n", machine().describe_context(), (uint16_t)m_cycle);
504 			break;
505 		case 0x02: /* OFFSET */
506 			m_offset = m_code & 0x3ff;
507 			logerror("%s: OFFSET: %03x\n", machine().describe_context(), m_offset);
508 			break;
509 		case 0x03: /* BASE */
510 			m_base = m_code & 0x3ff;
511 			logerror("%s: BASE: %03x\n", machine().describe_context(), m_base);
512 			break;
513 		case 0x04: /* ITOP */
514 			m_itops = m_code & 0x3ff;
515 			logerror("%s: ITOP: %03x\n", machine().describe_context(), m_itops);
516 			break;
517 		case 0x05: /* STMOD */
518 			m_mode = m_code & 3;
519 			logerror("%s: MODE: %03x\n", machine().describe_context(), m_mode);
520 			break;
521 		case 0x06: /* MSKPATH3 */
522 			m_gs->interface()->set_path3_mask(BIT(m_code, 15));
523 			logerror("%s: MSKPATH3: %d\n", machine().describe_context(), BIT(m_code, 15));
524 			break;
525 		case 0x07: /* Oh hi, MARK */
526 			m_mark = (uint16_t)m_code;
527 			logerror("%s: MARK: %04x\n", machine().describe_context(), (uint16_t)m_mark);
528 			break;
529 		case 0x14: /* MSCAL */
530 			logerror("%s: MSCAL %04x\n", machine().describe_context(), (uint16_t)m_code);
531 			if (m_vu1->running())
532 			{
533 				m_icount--;
534 				return;
535 			}
536 			else
537 			{
538 				m_vu1->start((uint16_t)m_code);
539 			}
540 			break;
541 		case 0x20: /* STMASK */
542 			m_data_needed = 1;
543 			m_data_index = 0;
544 			logerror("%s: STMASK\n", machine().describe_context());
545 			break;
546 		case 0x30: /* STROW */
547 			m_data_needed = 4;
548 			m_data_index = 0;
549 			logerror("%s: STROW\n", machine().describe_context());
550 			break;
551 		case 0x31: /* STCOL */
552 			m_data_needed = 4;
553 			m_data_index = 0;
554 			logerror("%s: STCOL\n", machine().describe_context());
555 			break;
556 		case 0x4a: /* MPG */
557 			m_data_needed = 2 + (m_alignment & 1);
558 			m_data_index = 0;
559 			m_mpg_count = (m_code >> 16) & 0xff;
560 			if (!m_mpg_count)
561 				m_mpg_count = 0x100;
562 			m_mpg_addr = m_code & 0xffff;
563 			logerror("%s: MPG\n", machine().describe_context());
564 			break;
565 		default:
566 			if ((m_command & 0x60) == 0x60)
567 			{ /* UNPACK */
568 				m_unpack_count = calculate_unpack_count();
569 				m_unpack_signed = BIT(m_code, 14);
570 				m_unpack_add_tops = BIT(m_code, 15);
571 				m_unpack_format = (uint8_t)(m_command & 0xf);
572 				m_data_needed = FORMAT_SIZE[m_unpack_format];
573 				logerror("%s: UNPACK (%08x), count %d\n", machine().describe_context(), m_code, m_unpack_count);
574 			}
575 			else
576 			{ /* unknown */
577 				logerror("%s: decode_vifcode: Unknown command %02x\n", machine().describe_context(), m_command);
578 			}
579 			break;
580 	}
581 
582 	if (m_data_needed > 0)
583 	{
584 		if (fifo_depth())
585 		{
586 			m_status |= STAT_MODE_DATA;
587 			m_icount--;
588 		}
589 		else
590 		{
591 			m_status |= STAT_MODE_WAIT;
592 			m_icount = 0;
593 		}
594 	}
595 	else if (fifo_depth())
596 	{
597 		m_code = fifo_pop();
598 		m_status |= STAT_MODE_DECODE;
599 		m_icount--;
600 	}
601 	else
602 	{
603 		m_status |= STAT_MODE_IDLE;
604 		m_icount = 0;
605 	}
606 
607 	if (trigger_interrupt)
608 	{
609 		//printf("******************\n");
610 	}
611 }
612 
calculate_unpack_count()613 uint32_t ps2_vif1_device::calculate_unpack_count()
614 {
615 	const uint32_t wl = (m_cycle >> 8) & 0xff;
616 	const uint32_t cl = m_cycle & 0xff;
617 	const uint32_t vl = m_command & 3;
618 	const uint32_t vn = (m_command >> 2) & 3;
619 
620 	uint32_t num = (m_code >> 16) & 0xff;
621 	if (wl > cl)
622 	{
623 		const uint32_t mod = num % wl;
624 		num = cl * (num / wl) + ((mod > cl) ? cl : mod);
625 	}
626 
627 	return (uint32_t)std::ceil(((32 >> vl) * (vn + 1) * num) / 32.0f);
628 }
629