diff options
Diffstat (limited to 'src/mame/machine/ps2vif1.cpp')
-rw-r--r-- | src/mame/machine/ps2vif1.cpp | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/src/mame/machine/ps2vif1.cpp b/src/mame/machine/ps2vif1.cpp new file mode 100644 index 00000000000..57901041e47 --- /dev/null +++ b/src/mame/machine/ps2vif1.cpp @@ -0,0 +1,571 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 VU1 interface (VIF1) device skeleton +* +* To Do: +* Everything +* +* Note: STAT mode bit twiddling is a total guess +* +*/ + +#include "ps2vif1.h" + +DEFINE_DEVICE_TYPE(SONYPS2_VIF1, ps2_vif1_device, "ps2vif1", "Playstation 2 VIF1") + +/*static*/ const size_t ps2_vif1_device::BUFFER_SIZE = 0x40; +/*static*/ const uint32_t ps2_vif1_device::FORMAT_SIZE[] = { + 1, 1, 1, 1, + 2, 1, 1, 1, + 3, 2, 1, 1, + 4, 2, 1, 2 +}; + +ps2_vif1_device::ps2_vif1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYPS2_VIF1, tag, owner, clock) + , device_execute_interface(mconfig, *this) + , m_gif(*this, finder_base::DUMMY_TAG) +{ +} + +void ps2_vif1_device::device_start() +{ + set_icountptr(m_icount); + + save_item(NAME(m_icount)); + + save_item(NAME(m_buffer)); + save_item(NAME(m_curr)); + save_item(NAME(m_end)); + + save_item(NAME(m_status)); + save_item(NAME(m_control)); + save_item(NAME(m_err)); + save_item(NAME(m_mark)); + save_item(NAME(m_cycle)); + save_item(NAME(m_mode)); + save_item(NAME(m_num)); + save_item(NAME(m_mask)); + save_item(NAME(m_code)); + save_item(NAME(m_itops)); + save_item(NAME(m_base)); + save_item(NAME(m_offset)); + save_item(NAME(m_tops)); + save_item(NAME(m_itop)); + save_item(NAME(m_top)); + + save_item(NAME(m_row_fill)); + save_item(NAME(m_col_fill)); + + save_item(NAME(m_data_needed)); + save_item(NAME(m_data_index)); + save_item(NAME(m_command)); + save_item(NAME(m_alignment)); + + save_item(NAME(m_mpg_count)); + save_item(NAME(m_mpg_addr)); + save_item(NAME(m_mpg_insn)); + + save_item(NAME(m_unpack_count)); + save_item(NAME(m_unpack_addr)); + save_item(NAME(m_unpack_last)); + save_item(NAME(m_unpack_bits_remaining)); + save_item(NAME(m_unpack_signed)); + save_item(NAME(m_unpack_add_tops)); + save_item(NAME(m_unpack_format)); +} + +void ps2_vif1_device::device_reset() +{ + m_icount = 0; + + memset(m_buffer, 0, sizeof(uint32_t) * BUFFER_SIZE); + m_curr = 0; + m_end = 0; + + m_status = 0; + m_control = 0; + m_err = 0; + m_mark = 0; + m_cycle = 0; + m_mode = 0; + m_num = 0; + m_mask = 0; + m_code = 0; + m_itops = 0; + m_base = 0; + m_offset = 0; + m_tops = 0; + m_itop = 0; + m_top = 0; + + memset(m_row_fill, 0, sizeof(uint32_t) * 4); + memset(m_col_fill, 0, sizeof(uint32_t) * 4); + + m_data_needed = 0; + m_data_index = 0; + m_command = 0; + m_alignment = 0; + + m_mpg_count = 0; + m_mpg_addr = 0; + m_mpg_insn = 0; + + m_unpack_count = 0; + m_unpack_addr = 0; + m_unpack_last = 0; + m_unpack_bits_remaining = 0; + m_unpack_signed = false; + m_unpack_add_tops = false; + m_unpack_format = FMT_S32; +} + +READ32_MEMBER(ps2_vif1_device::regs_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0x00/4: + ret = m_status; + logerror("%s: Read: VIF1_STAT (%08x)\n", machine().describe_context(), ret); + break; + case 0x10/4: + ret = m_control; + logerror("%s: Read: VIF1_FBRST (%08x)\n", machine().describe_context(), ret); + break; + case 0x20/4: + ret = m_err; + logerror("%s: Read: VIF1_ERR (%08x)\n", machine().describe_context(), ret); + break; + case 0x30/4: + ret = m_mark; + logerror("%s: Read: VIF1_MARK (%08x)\n", machine().describe_context(), ret); + break; + case 0x40/4: + ret = m_cycle; + logerror("%s: Read: VIF1_CYCLE (%08x)\n", machine().describe_context(), ret); + break; + case 0x50/4: + ret = m_mode; + logerror("%s: Read: VIF1_MODE (%08x)\n", machine().describe_context(), ret); + break; + case 0x60/4: + ret = m_num; + logerror("%s: Read: VIF1_NUM (%08x)\n", machine().describe_context(), ret); + break; + case 0x70/4: + ret = m_mask; + logerror("%s: Read: VIF1_MASK (%08x)\n", machine().describe_context(), ret); + break; + case 0x80/4: + ret = m_code; + logerror("%s: Read: VIF1_CODE (%08x)\n", machine().describe_context(), ret); + break; + case 0x90/4: + ret = m_itops; + logerror("%s: Read: VIF1_ITOPS (%08x)\n", machine().describe_context(), ret); + break; + case 0xa0/4: + ret = m_base; + logerror("%s: Read: VIF1_BASE (%08x)\n", machine().describe_context(), ret); + break; + case 0xb0/4: + ret = m_offset; + logerror("%s: Read: VIF1_OFST (%08x)\n", machine().describe_context(), ret); + break; + case 0xc0/4: + ret = m_tops; + logerror("%s: Read: VIF1_TOPS (%08x)\n", machine().describe_context(), ret); + break; + case 0xd0/4: + ret = m_itop; + logerror("%s: Read: VIF1_ITOP (%08x)\n", machine().describe_context(), ret); + break; + case 0xe0/4: + ret = m_top; + logerror("%s: Read: VIF1_TOP (%08x)\n", machine().describe_context(), ret); + break; + case 0x100/4: + ret = m_row_fill[0]; + logerror("%s: Read: VIF1_R0 (%08x)\n", machine().describe_context(), ret); + break; + case 0x110/4: + ret = m_row_fill[1]; + logerror("%s: Read: VIF1_R1 (%08x)\n", machine().describe_context(), ret); + break; + case 0x120/4: + ret = m_row_fill[2]; + logerror("%s: Read: VIF1_R2 (%08x)\n", machine().describe_context(), ret); + break; + case 0x130/4: + ret = m_row_fill[3]; + logerror("%s: Read: VIF1_R3 (%08x)\n", machine().describe_context(), ret); + break; + case 0x140/4: + ret = m_col_fill[0]; + logerror("%s: Read: VIF1_C0 (%08x)\n", machine().describe_context(), ret); + break; + case 0x150/4: + ret = m_col_fill[1]; + logerror("%s: Read: VIF1_C1 (%08x)\n", machine().describe_context(), ret); + break; + case 0x160/4: + ret = m_col_fill[2]; + logerror("%s: Read: VIF1_C2 (%08x)\n", machine().describe_context(), ret); + break; + case 0x170/4: + ret = m_col_fill[3]; + logerror("%s: Read: VIF1_C3 (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: Read: Unknown (%08x)\n", machine().describe_context(), 0x10003c00 + (offset << 2)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2_vif1_device::regs_w) +{ + logerror("%s: Write: Unknown %08x = %08x\n", machine().describe_context(), 0x10003c00 + (offset << 2), data); +} + +READ64_MEMBER(ps2_vif1_device::mmio_r) +{ + uint64_t ret = 0ULL; + if (offset) + { + logerror("%s: mmio_r [127..64]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + else + { + logerror("%s: mmio_r [63..0]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + return ret; +} + +WRITE64_MEMBER(ps2_vif1_device::mmio_w) +{ + if (offset) + { + logerror("%s: mmio_w [127..64]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + fifo_push((uint32_t)data); + fifo_push((uint32_t)(data >> 32)); + } + else + { + logerror("%s: mmio_w [63..0]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + fifo_push((uint32_t)data); + fifo_push((uint32_t)(data >> 32)); + } +} + + +void ps2_vif1_device::dma_write(const uint64_t hi, const uint64_t lo) +{ + 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); + fifo_push((uint32_t)(hi >> 32)); + fifo_push((uint32_t)hi); + fifo_push((uint32_t)(lo >> 32)); + fifo_push((uint32_t)lo); +} + +void ps2_vif1_device::tag_write(uint32_t *data) +{ + logerror("%s: tag_write: %08x%08x\n", machine().describe_context(), data[2], data[3]); + fifo_push(data[2]); + fifo_push(data[3]); +} + +void ps2_vif1_device::fifo_push(uint32_t value) +{ + if (m_end >= BUFFER_SIZE) + { + return; + } + + m_buffer[m_end++] = value; +} + +uint32_t ps2_vif1_device::fifo_pop() +{ + m_alignment = (m_alignment + 1) & 3; + + if (m_curr >= m_end) + { + return 0; + } + + const uint32_t ret = m_buffer[m_curr++]; + if (m_curr >= m_end) + { + m_curr = 0; + m_end = 0; + } + return ret; +} + +void ps2_vif1_device::execute_run() +{ + while (m_icount > 0) + { + if (m_status & (STAT_E_WAIT | STAT_GS_WAIT | STAT_STALL_STOP | STAT_STALL_FBRK | STAT_STALL_INT)) + { + m_icount = 0; + break; + } + + switch (m_status & STAT_MODE_MASK) + { + case STAT_MODE_IDLE: + if (fifo_depth()) + { + m_code = fifo_pop(); + } + else + { + m_icount = 0; + break; + } + // Intentional fall-through + case STAT_MODE_DECODE: + decode_vifcode(); + break; + case STAT_MODE_WAIT: + if (fifo_depth() == 0) + { + m_icount = 0; + break; + } + // Intentional fall-through + case STAT_MODE_DATA: + transfer_vifcode_data(); + break; + } + } +} + +void ps2_vif1_device::transfer_vifcode_data() +{ + m_status &= ~STAT_MODE_MASK; + if (fifo_depth() < m_data_needed) + { + m_status |= STAT_MODE_WAIT; + m_icount = 0; + return; + } + + switch (m_command) + { + case 0x20: /* STMASK */ + m_mask = fifo_pop(); + m_data_needed = 0; + break; + case 0x30: /* STROW */ + m_row_fill[m_data_index] = fifo_pop(); + m_data_needed = 0; + break; + case 0x31: /* STCOL */ + m_col_fill[m_data_index] = fifo_pop(); + m_data_needed = 0; + break; + case 0x4a: /* MPG */ + transfer_mpg(); + break; + default: + if ((m_command & 0x60) == 0x60) + { + transfer_unpack(); + } + break; + } + + if (m_data_needed) + { + if (fifo_depth() == 0) + { + m_status |= STAT_MODE_WAIT; + m_icount = 0; + } + else + { + m_status |= STAT_MODE_DATA; + m_icount--; + } + } + else if (fifo_depth() > 0) + { + m_code = fifo_pop(); + m_status |= STAT_MODE_DECODE; + m_icount--; + } + else + { + m_status |= STAT_MODE_IDLE; + m_icount = 0; + } +} + +void ps2_vif1_device::transfer_unpack() +{ + switch (m_unpack_format) + { + case FMT_V4_32: + logerror("%s: Unpacking V4-32.\n", machine().describe_context()); + for (int element = 0; element < 4; element++) + { + fifo_pop(); + //const uint32_t data = fifo_pop(); + //m_vu->write_data(m_unpack_addr, data); + m_unpack_addr += 4; + } + m_unpack_count--; + break; + default: + logerror("%s: Unsupported unpack format: %02x\n", machine().describe_context(), m_unpack_format); + break; + } + + m_data_needed = FORMAT_SIZE[m_unpack_format] - (m_unpack_bits_remaining ? 1 : 0); +} + +void ps2_vif1_device::transfer_mpg() +{ + while (m_data_needed > 2) + { + fifo_pop(); + m_data_needed--; + } + + m_mpg_insn = fifo_pop(); + m_mpg_insn |= (uint64_t)fifo_pop() << 32; + m_mpg_addr += 8; + m_mpg_count--; + m_data_needed = m_mpg_count ? 2 : 0; + + logerror("%s: MPG, VU insn: %08x%08x, %d remaining\n", machine().describe_context(), (uint32_t)(m_mpg_insn >> 32), (uint32_t)m_mpg_insn, m_mpg_count); + + //m_vu->write_instruction(m_mpg_addr, m_mpg_insn); +} + +void ps2_vif1_device::decode_vifcode() +{ + //bool trigger_interrupt = BIT(m_code, 31); + m_command = (m_code >> 24) & 0x7f; + m_status &= ~STAT_MODE_MASK; + + switch (m_command) + { + case 0x00: /* NOP */ + break; + case 0x01: /* STCYCL */ + m_cycle = (uint16_t)m_code; + logerror("%s: STCYCL: %04x\n", machine().describe_context(), (uint16_t)m_cycle); + break; + case 0x02: /* OFFSET */ + m_offset = m_code & 0x3ff; + logerror("%s: OFFSET: %03x\n", machine().describe_context(), m_offset); + break; + case 0x03: /* BASE */ + m_base = m_code & 0x3ff; + logerror("%s: BASE: %03x\n", machine().describe_context(), m_base); + break; + case 0x04: /* ITOP */ + m_itops = m_code & 0x3ff; + logerror("%s: ITOP: %03x\n", machine().describe_context(), m_itops); + break; + case 0x05: /* STMOD */ + m_mode = m_code & 3; + logerror("%s: MODE: %03x\n", machine().describe_context(), m_mode); + break; + case 0x06: /* MSKPATH3 */ + m_gif->set_path3_mask(BIT(m_code, 15)); + logerror("%s: MSKPATH3: %d\n", machine().describe_context(), BIT(m_code, 15)); + break; + case 0x07: /* Oh hi, MARK */ + m_mark = (uint16_t)m_code; + logerror("%s: MARK: %04x\n", machine().describe_context(), (uint16_t)m_mark); + break; + case 0x20: /* STMASK */ + m_data_needed = 1; + m_data_index = 0; + logerror("%s: STMASK\n", machine().describe_context()); + break; + case 0x30: /* STROW */ + m_data_needed = 4; + m_data_index = 0; + logerror("%s: STROW\n", machine().describe_context()); + break; + case 0x31: /* STCOL */ + m_data_needed = 4; + m_data_index = 0; + logerror("%s: STCOL\n", machine().describe_context()); + break; + case 0x4a: /* MPG */ + m_data_needed = 2 + (m_alignment & 1); + m_data_index = 0; + m_mpg_count = (m_code >> 16) & 0xff; + if (!m_mpg_count) + m_mpg_count = 0x100; + m_mpg_addr = m_code & 0xffff; + logerror("%s: MPG\n", machine().describe_context()); + break; + default: + if ((m_command & 0x60) == 0x60) + { /* UNPACK */ + m_unpack_count = calculate_unpack_count(); + m_unpack_signed = BIT(m_code, 14); + m_unpack_add_tops = BIT(m_code, 15); + m_unpack_format = (uint8_t)(m_command & 0xf); + m_data_needed = FORMAT_SIZE[m_unpack_format]; + } + else + { /* unknown */ + logerror("%s: decode_vifcode: Unknown command %02x\n", machine().describe_context(), m_command); + } + break; + } + + if (m_data_needed > 0) + { + if (fifo_depth()) + { + m_status |= STAT_MODE_DATA; + m_icount--; + } + else + { + m_status |= STAT_MODE_WAIT; + m_icount = 0; + } + } + else if (fifo_depth()) + { + m_code = fifo_pop(); + m_status |= STAT_MODE_DECODE; + m_icount--; + } + else + { + m_status |= STAT_MODE_IDLE; + m_icount = 0; + } +} + +uint32_t ps2_vif1_device::calculate_unpack_count() +{ + const uint32_t wl = (m_cycle >> 8) & 0xff; + const uint32_t cl = m_cycle & 0xff; + const uint32_t vl = m_command & 3; + const uint32_t vn = (m_command >> 2) & 3; + + uint32_t num = (m_code >> 16) & 0xff; + if (wl > cl) + { + const uint32_t mod = num % wl; + num = cl * (num / wl) + ((mod > cl) ? cl : mod); + } + + return (uint32_t)std::ceil(((32 >> vl) * (vn + 1) * num) / 32.0f); +} |