From 08e68262c86e8c7bf91e9587ae2700f3d07d15fb Mon Sep 17 00:00:00 2001 From: allkern Date: Wed, 16 Jul 2025 23:45:26 -0300 Subject: [PATCH 1/4] vif: Implement mask and decompression modes --- src/ee/vif.c | 462 ++++++++++++++++++++++++++++++++++----------------- src/ee/vif.h | 5 + 2 files changed, 314 insertions(+), 153 deletions(-) diff --git a/src/ee/vif.c b/src/ee/vif.c index 42bec7e..e528c1b 100644 --- a/src/ee/vif.c +++ b/src/ee/vif.c @@ -28,6 +28,62 @@ void ps2_vif_destroy(struct ps2_vif* vif) { } static inline void vif_write_vu_mem(struct ps2_vif* vif, uint128_t data) { + // Process mask + if (vif->unpack_mask) { + int cycle = (vif->unpack_cycle > 3) ? 3 : vif->unpack_cycle; + int m[4], shift = (cycle & 3) * 8; + uint32_t mask = (vif->mask >> shift) & 0xff; + m[0] = (mask >> 0) & 3; + m[1] = (mask >> 2) & 3; + m[2] = (mask >> 4) & 3; + m[3] = (mask >> 6) & 3; + + // Note: Mode 3 is undocumented, it sets the row registers + // to the value of the unpacked data, without changing + // the unpacked data itself. + for (int i = 0; i < 4; i++) { + if (m[i] == 0) { + // Normal mode, m==0 -> write value as is + if (vif->mode == 0) { + continue; + } else if (vif->mode == 1) { + // Addition decompression + data.u32[i] = vif->r[i] + data.u32[i]; + } else if (vif->mode == 2) { + // Subtraction decompression + data.u32[i] = vif->r[i] + data.u32[i]; + vif->r[i] = data.u32[i]; + } else if (vif->mode == 3) { + vif->r[i] = data.u32[i]; + } + } else if (m[i] == 1) { + data.u32[i] = vif->r[i]; + } else if (m[i] == 2) { + data.u32[i] = vif->c[cycle]; + } else { + // m=3 masks this fields' write, so we fetch + // the value from VU mem instead + data.u32[i] = vif->vu->vu_mem[vif->addr & 0x3ff].u32[i]; + } + } + } else { + // Do mode processing only + for (int i = 0; i < 4; i++) { + if (vif->mode == 0) { + continue; + } else if (vif->mode == 1) { + // Offset decompression + data.u32[i] = vif->r[i] + data.u32[i]; + } else if (vif->mode == 2) { + // Difference decompression + data.u32[i] = vif->r[i] + data.u32[i]; + vif->r[i] = data.u32[i]; + } else if (vif->mode == 3) { + vif->r[i] = data.u32[i]; + } + } + } + if (vif->unpack_cl == vif->unpack_wl) { // Write data normally vif->vu->vu_mem[(vif->addr++) & 0x3ff] = data; @@ -45,6 +101,8 @@ static inline void vif_write_vu_mem(struct ps2_vif* vif, uint128_t data) { printf("vif%d: Unpack error: unpack_cl (%d) < unpack_wl (%d)\n", vif->id, vif->unpack_cl, vif->unpack_wl); exit(1); } + + vif->unpack_cycle++; } void vif0_send_irq(void* udata, int overshoot) { @@ -238,33 +296,45 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { case 0x7c: case 0x7d: case 0x7e: case 0x7f: { vif->unpack_fmt = (data >> 24) & 0xf; vif->unpack_usn = (data >> 14) & 1; - + vif->unpack_num = (data >> 16) & 0xff; vif->unpack_cl = vif->cycle & 0xff; vif->unpack_wl = (vif->cycle >> 8) & 0xff; + vif->unpack_mask = (data >> 28) & 1; + vif->unpack_cycle = 0; + int vl = (data >> 24) & 3; int vn = (data >> 26) & 3; - int num = (data >> 16) & 0xff; int flg = (data >> 15) & 1; int addr = data & 0x3ff; int filling = vif->unpack_cl < vif->unpack_wl; - if (!num) num = 256; + if (!vif->unpack_num) vif->unpack_num = 256; if (flg) addr += vif->tops; - // printf("vif%d: UNPACK %02x fmt=%02x flg=%d num=%02x addr=%08x tops=%08x\n", vif->id, data >> 24, vif->unpack_fmt, flg, num, addr, vif->tops); - - assert(!filling); - // assert(vif->unpack_cl == vif->unpack_wl); - assert(!vif->mode); + if (filling) { + printf("vif%d: Filling mode unimplemented\n", vif->id); + exit(1); + } // To-do: Handle for filling vif->unpack_skip = vif->unpack_cl - vif->unpack_wl; vif->unpack_wl_count = 0; - vif->pending_words = (((32>>vl) * (vn+1)) * num) / 32; + uint32_t pack_size = 16; + + if ((vl == 3 && vn == 3) == 0) + pack_size = (32 >> vl) * (vn + 1); + + vif->pending_words = pack_size * vif->unpack_num; + vif->pending_words = (vif->pending_words + 0x1F) & ~0x1F; + vif->pending_words /= 32; + + vif->unpack_shift = 0; vif->state = VIF_RECV_DATA; vif->shift = 0; vif->addr = addr; + + // printf("vif%d: UNPACK %02x fmt=%02x flg=%d num=%02x addr=%08x tops=%08x usn=%d wr=%d mode=%d\n", vif->id, data >> 24, vif->unpack_fmt, flg, vif->unpack_num, addr, vif->tops, vif->unpack_usn, vif->pending_words, vif->mode); } break; default: { // printf("vif%d: Unhandled command %02x\n", vif->id, vif->cmd); @@ -343,56 +413,49 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { // S-16 case 0x01: { - vif->unpack_buf[vif->shift++] = data; + for (int i = 0; i < 2; i++) { + uint128_t q = { 0 }; - if (vif->shift == 2) { - uint128_t q[3]; - - q[0].u32[0] = vif->unpack_buf[0] & 0xffff; - q[1].u32[0] = vif->unpack_buf[0] >> 16; - q[2].u32[0] = vif->unpack_buf[1] & 0xffff; + q.u32[0] = (data >> (i * 16)) & 0xffff; - // Sign-extend if USN is reset if (!vif->unpack_usn) { - q[0].u32[0] = (int32_t)((int16_t)q[0].u32[0]); - q[1].u32[0] = (int32_t)((int16_t)q[1].u32[0]); - q[2].u32[0] = (int32_t)((int16_t)q[2].u32[0]); + q.u32[0] = (int32_t)((int16_t)q.u32[0]); } - q[0].u32[1] = q[0].u32[0]; - q[0].u32[2] = q[0].u32[0]; - q[0].u32[3] = q[0].u32[0]; - q[1].u32[1] = q[1].u32[0]; - q[1].u32[2] = q[1].u32[0]; - q[1].u32[3] = q[1].u32[0]; - q[2].u32[1] = q[2].u32[0]; - q[2].u32[2] = q[2].u32[0]; - q[2].u32[3] = q[2].u32[0]; + q.u32[1] = q.u32[0]; + q.u32[2] = q.u32[0]; + q.u32[3] = q.u32[0]; - vif_write_vu_mem(vif, q[0]); - vif_write_vu_mem(vif, q[1]); - vif_write_vu_mem(vif, q[2]); + vif_write_vu_mem(vif, q); - vif->shift = 0; + vif->unpack_num--; + + if (!vif->unpack_num) + break; } } break; // S-8 case 0x02: { - uint128_t q[3]; + for (int i = 0; i < 4; i++) { + uint128_t q = { 0 }; - for (int i = 0; i < 3; i++) { - q[i].u32[0] = (data >> (i * 8)) & 0xff; + q.u32[0] = (data >> (i * 8)) & 0xff; if (!vif->unpack_usn) { - q[i].u32[0] = (int32_t)((int8_t)q[i].u32[0]); + q.u32[0] = (int32_t)((int8_t)q.u32[0]); } - q[i].u32[1] = q[i].u32[0]; - q[i].u32[2] = q[i].u32[0]; - q[i].u32[3] = q[i].u32[0]; + q.u32[1] = q.u32[0]; + q.u32[2] = q.u32[0]; + q.u32[3] = q.u32[0]; + + vif_write_vu_mem(vif, q); + + vif->unpack_num--; - vif_write_vu_mem(vif, q[i]); + if (!vif->unpack_num) + break; } } break; @@ -401,63 +464,62 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->unpack_buf[vif->shift++] = data; if (vif->shift == 2) { - vif->data.u32[0] = vif->unpack_buf[0]; - vif->data.u32[1] = vif->unpack_buf[1]; + uint128_t q = { 0 }; - vif_write_vu_mem(vif, vif->data); + q.u32[0] = vif->unpack_buf[0]; + q.u32[1] = vif->unpack_buf[1]; + + vif_write_vu_mem(vif, q); vif->shift = 0; + + vif->unpack_num--; + + if (!vif->unpack_num) + break; } } break; // V2-16 case 0x05: { - vif->unpack_buf[vif->shift++] = data; + uint128_t q = { 0 }; - if (vif->shift == 3) { - uint128_t q[3]; + q.u32[0] = data & 0xffff; + q.u32[1] = data >> 16; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - q[i].u32[j] = (vif->unpack_buf[i] >> (16 * j)) & 0xffff; + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int16_t)q.u32[0]); + q.u32[1] = (int32_t)((int16_t)q.u32[1]); + } - if (!vif->unpack_usn) { - q[i].u32[j] = (int32_t)((int16_t)q[i].u32[j]); - } - } + vif_write_vu_mem(vif, q); - vif_write_vu_mem(vif, q[i]); - } + vif->unpack_num--; - vif->shift = 0; - } + if (!vif->unpack_num) + break; } break; // V2-8 case 0x06: { - vif->unpack_buf[vif->shift++] = data; - - if (vif->shift == 2) { - uint128_t q[3]; + for (int i = 0; i < 2; i++) { + uint128_t q = { 0 }; + uint16_t d = data >> (i * 16); - q[0].u32[0] = vif->unpack_buf[0] & 0xff; - q[0].u32[1] = (vif->unpack_buf[0] >> 8) & 0xff; - q[1].u32[0] = vif->unpack_buf[0] >> 16 & 0xff; - q[1].u32[1] = (vif->unpack_buf[0] >> 24) & 0xff; - q[2].u32[0] = vif->unpack_buf[1] & 0xff; - q[2].u32[1] = (vif->unpack_buf[1] >> 8) & 0xff; + q.u32[0] = d & 0xff; + q.u32[1] = d >> 8; if (!vif->unpack_usn) { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - q[i].u32[j] = (int32_t)((int8_t)q[i].u32[j]); - } - - vif_write_vu_mem(vif, q[i]); - } + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); } - vif->shift = 0; + vif_write_vu_mem(vif, q); + + vif->unpack_num--; + + if (!vif->unpack_num) + break; } } break; @@ -466,13 +528,19 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->unpack_buf[vif->shift++] = data; if (vif->shift == 3) { - vif->data.u32[0] = vif->unpack_buf[0]; - vif->data.u32[1] = vif->unpack_buf[1]; - vif->data.u32[2] = vif->unpack_buf[2]; + uint128_t q = { 0 }; - vif_write_vu_mem(vif, vif->data); + q.u32[0] = vif->unpack_buf[0]; + q.u32[1] = vif->unpack_buf[1]; + q.u32[2] = vif->unpack_buf[2]; + + vif_write_vu_mem(vif, q); vif->shift = 0; + vif->unpack_num--; + + if (!vif->unpack_num) + break; } } break; @@ -480,62 +548,126 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { case 0x09: { vif->unpack_buf[vif->shift++] = data; - if (vif->shift == 5) { - uint128_t q[3]; - - q[0].u32[0] = vif->unpack_buf[0] & 0xffff; - q[0].u32[1] = vif->unpack_buf[0] >> 16; - q[0].u32[2] = vif->unpack_buf[1] & 0xffff; - q[1].u32[0] = vif->unpack_buf[1] >> 16; - q[1].u32[1] = vif->unpack_buf[2] & 0xffff; - q[1].u32[2] = vif->unpack_buf[2] >> 16; - q[2].u32[0] = vif->unpack_buf[3] & 0xffff; - q[2].u32[1] = vif->unpack_buf[3] >> 16; - q[2].u32[2] = vif->unpack_buf[4] & 0xffff; - - for (int i = 0; i < 3; i++) { - // Sign-extend if USN is reset - if (!vif->unpack_usn) { - q[i].u32[0] = (int32_t)((int16_t)q[i].u32[0]); - q[i].u32[1] = (int32_t)((int16_t)q[i].u32[1]); - q[i].u32[2] = (int32_t)((int16_t)q[i].u32[2]); - } + if (vif->shift == (vif->unpack_shift ? 1 : 2)) { + uint128_t q = { 0 }; + + if (!vif->unpack_shift) { + q.u32[0] = vif->unpack_buf[0] & 0xffff; + q.u32[1] = (vif->unpack_buf[0] >> 16) & 0xffff; + q.u32[2] = vif->unpack_buf[1] & 0xffff; + } else { + q.u32[0] = vif->unpack_data; + q.u32[1] = vif->unpack_buf[0] & 0xffff; + q.u32[2] = vif->unpack_buf[0] >> 16; + } - vif_write_vu_mem(vif, q[i]); + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int16_t)q.u32[0]); + q.u32[1] = (int32_t)((int16_t)q.u32[1]); + q.u32[2] = (int32_t)((int16_t)q.u32[2]); } + vif_write_vu_mem(vif, q); + vif->shift = 0; + vif->unpack_num--; + vif->unpack_shift ^= 1; + vif->unpack_data = vif->unpack_buf[1] >> 16; + + if (!vif->unpack_num) + break; } } break; - // V3-8 + // V3-8 (disgusting) case 0x0a: { - vif->unpack_buf[vif->shift++] = data; + uint128_t q = { 0 }; - if (vif->shift == 3) { - uint128_t q[3]; - - q[0].u32[0] = vif->unpack_buf[0] & 0xff; - q[0].u32[1] = (vif->unpack_buf[0] >> 8) & 0xff; - q[0].u32[2] = (vif->unpack_buf[0] >> 16) & 0xff; - q[1].u32[0] = (vif->unpack_buf[0] >> 24) & 0xff; - q[1].u32[1] = vif->unpack_buf[1] & 0xff; - q[1].u32[2] = (vif->unpack_buf[1] >> 8) & 0xff; - q[2].u32[0] = (vif->unpack_buf[1] >> 16) & 0xff; - q[2].u32[1] = (vif->unpack_buf[1] >> 24) & 0xff; - q[2].u32[2] = vif->unpack_buf[2] & 0xff; - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (!vif->unpack_usn) { - q[i].u32[j] = (int32_t)((int8_t)q[i].u32[j]); - } + switch (vif->unpack_shift) { + case 0: { + q.u32[0] = data & 0xff; + q.u32[1] = (data >> 8) & 0xff; + q.u32[2] = (data >> 16) & 0xff; + + vif->unpack_data = data >> 24; + vif->unpack_shift++; + + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); + q.u32[2] = (int32_t)((int8_t)q.u32[2]); } - vif_write_vu_mem(vif, q[i]); - } + vif_write_vu_mem(vif, q); - vif->shift = 0; + vif->unpack_num--; + + if (!vif->unpack_num) + break; + } break; + + case 1: { + q.u32[0] = vif->unpack_data; + q.u32[1] = data & 0xff; + q.u32[2] = (data >> 8) & 0xff; + + vif->unpack_data = data >> 16; + vif->unpack_shift++; + + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); + q.u32[2] = (int32_t)((int8_t)q.u32[2]); + } + + vif_write_vu_mem(vif, q); + + vif->unpack_num--; + + if (!vif->unpack_num) + break; + } break; + + case 2: { + q.u32[0] = vif->unpack_data & 0xff; + q.u32[1] = (vif->unpack_data >> 8) & 0xff; + q.u32[2] = data & 0xff; + + vif->unpack_data = (data >> 8) & 0xffffff; + vif->unpack_shift++; + + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); + q.u32[2] = (int32_t)((int8_t)q.u32[2]); + } + + vif_write_vu_mem(vif, q); + + vif->unpack_num--; + + if (!vif->unpack_num) + break; + + q.u32[0] = (data >> 8) & 0xff; + q.u32[1] = (data >> 16) & 0xff; + q.u32[2] = (data >> 24) & 0xff; + + vif->unpack_shift = 0; + + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); + q.u32[2] = (int32_t)((int8_t)q.u32[2]); + } + + vif_write_vu_mem(vif, q); + + vif->unpack_num--; + + if (!vif->unpack_num) + break; + } break; } } break; @@ -544,20 +676,14 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->unpack_buf[vif->shift++] = data; if (vif->shift == 4) { - // // printf("vif: Writing %08x %08x %08x %08x to VUmem at %08x\n", - // vif->data.u32[3], - // vif->data.u32[2], - // vif->data.u32[1], - // vif->data.u32[0], - // vif->addr * 16 - // ); + uint128_t q = { 0 }; - vif->data.u32[0] = vif->unpack_buf[0]; - vif->data.u32[1] = vif->unpack_buf[1]; - vif->data.u32[2] = vif->unpack_buf[2]; - vif->data.u32[3] = vif->unpack_buf[3]; + q.u32[0] = vif->unpack_buf[0]; + q.u32[1] = vif->unpack_buf[1]; + q.u32[2] = vif->unpack_buf[2]; + q.u32[3] = vif->unpack_buf[3]; - vif_write_vu_mem(vif, vif->data); + vif_write_vu_mem(vif, q); vif->shift = 0; } @@ -568,7 +694,7 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->unpack_buf[vif->shift++] = data; if (vif->shift == 2) { - uint128_t q; + uint128_t q = { 0 }; q.u32[0] = vif->unpack_buf[0] & 0xffff; q.u32[1] = vif->unpack_buf[0] >> 16; @@ -590,25 +716,41 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { // V4-8 case 0x0e: { - vif->unpack_buf[vif->shift++] = data; + uint128_t q = { 0 }; + + q.u32[0] = data & 0xff; + q.u32[1] = (data >> 8) & 0xff; + q.u32[2] = (data >> 16) & 0xff; + q.u32[3] = (data >> 24) & 0xff; + + if (!vif->unpack_usn) { + q.u32[0] = (int32_t)((int8_t)q.u32[0]); + q.u32[1] = (int32_t)((int8_t)q.u32[1]); + q.u32[2] = (int32_t)((int8_t)q.u32[2]); + q.u32[3] = (int32_t)((int8_t)q.u32[3]); + } - if (vif->shift == 3) { - uint128_t q[3]; + vif_write_vu_mem(vif, q); + } break; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 4; j++) { - q[i].u32[j] = (vif->unpack_buf[i] >> (j * 8)) & 0xff; + // V4-5 + case 0x0f: { + uint128_t q = { 0 }; - // Sign-extend if USN is reset - if (!vif->unpack_usn) { - q[i].u32[j] = (int32_t)((int8_t)q[i].u32[j]); - } - } + for (int i = 0; i < 2; i++) { + uint16_t c = (data >> (i * 16)) & 0xffff; - vif_write_vu_mem(vif, q[i]); - } + q.u32[0] = ((c >> 0) & 0x1f) << 3; + q.u32[1] = ((c >> 5) & 0x1f) << 3; + q.u32[2] = ((c >> 10) & 0x1f) << 3; + q.u32[3] = ((c >> 15) & 1) << 7; - vif->shift = 0; + vif_write_vu_mem(vif, q); + + vif->unpack_num--; + + if (!vif->unpack_num) + break; } } break; @@ -692,13 +834,27 @@ uint64_t ps2_vif_read32(struct ps2_vif* vif, uint32_t addr) { void ps2_vif_write32(struct ps2_vif* vif, uint32_t addr, uint64_t data) { switch (addr) { // VIF0 registers - case 0x10003810: vif->fbrst = data; break; + case 0x10003810: { + vif->fbrst = data; + vif->state = VIF_IDLE; + vif->pending_words = 0; + vif->unpack_shift = 0; + vif->shift = 0; + } break; + case 0x10003820: vif->err = data; break; case 0x10003830: vif->mark = data; break; // VIF1 registers case 0x10003c00: vif->stat &= 0x800000; vif->stat |= data & 0x800000; break; - case 0x10003c10: vif->fbrst = data; break; + case 0x10003c10: { + vif->fbrst = data; + vif->state = VIF_IDLE; + vif->pending_words = 0; + vif->unpack_shift = 0; + vif->shift = 0; + } break; + case 0x10003c20: vif->err = data; break; case 0x10003c30: vif->mark = data; break; diff --git a/src/ee/vif.h b/src/ee/vif.h index bf82650..8d059dd 100644 --- a/src/ee/vif.h +++ b/src/ee/vif.h @@ -81,6 +81,7 @@ struct ps2_vif { uint128_t data; uint32_t addr; + uint32_t unpack_num; uint32_t unpack_fmt; uint32_t unpack_usn; uint32_t unpack_cl; @@ -88,6 +89,10 @@ struct ps2_vif { uint32_t unpack_skip; uint32_t unpack_wl_count; uint32_t unpack_buf[16]; + uint32_t unpack_shift; + uint32_t unpack_data; + int unpack_mask; + int unpack_cycle; int id; From 7e8b1e4172620563270cb7b23406374060eba618 Mon Sep 17 00:00:00 2001 From: allkern Date: Wed, 16 Jul 2025 23:45:52 -0300 Subject: [PATCH 2/4] frontend: Add file drop guide --- frontend/iris.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++ frontend/iris.hpp | 5 +++++ main.cpp | 14 ++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/frontend/iris.cpp b/frontend/iris.cpp index a1ea35c..066e337 100644 --- a/frontend/iris.cpp +++ b/frontend/iris.cpp @@ -168,6 +168,55 @@ void update_window(iris::instance* iris) { DockSpaceOverViewport(0, GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); + // Drop file fade animation + if (iris->drop_file_active) { + iris->drop_file_alpha += iris->drop_file_alpha_delta; + + if (iris->drop_file_alpha_delta > 0.0f) { + if (iris->drop_file_alpha >= 1.0f) { + iris->drop_file_alpha = 1.0f; + iris->drop_file_alpha_delta = 0.0f; + } + } else { + if (iris->drop_file_alpha <= 0.0f) { + iris->drop_file_alpha = 0.0f; + iris->drop_file_alpha_delta = 0.0f; + iris->drop_file_active = false; + } + } + + GetForegroundDrawList()->AddRectFilled( + ImVec2(0, 0), + ImVec2(iris->window_width, iris->window_height), + ImColor(0.0f, 0.0f, 0.0f, iris->drop_file_alpha * 0.35f) + ); + + ImVec2 text_size = CalcTextSize("Drop file here to launch"); + + PushFont(iris->font_icons_big); + + ImVec2 icon_size = CalcTextSize(ICON_MS_DOWNLOAD); + + ImVec2 total_size = ImVec2( + std::max(icon_size.x, text_size.x), + icon_size.y + text_size.y + ); + + GetForegroundDrawList()->AddText( + ImVec2(iris->window_width / 2 - icon_size.x / 2, iris->window_height / 2 - icon_size.y), + ImColor(1.0f, 1.0f, 1.0f, iris->drop_file_alpha), + ICON_MS_DOWNLOAD + ); + + PopFont(); + + GetForegroundDrawList()->AddText( + ImVec2(iris->window_width / 2 - text_size.x / 2, iris->window_height / 2), + ImColor(1.0f, 1.0f, 1.0f, iris->drop_file_alpha), + "Drop file here to launch" + ); + } + if (iris->show_ee_control) show_ee_control(iris); if (iris->show_ee_state) show_ee_state(iris); if (iris->show_ee_logs) show_ee_logs(iris); diff --git a/frontend/iris.hpp b/frontend/iris.hpp index 3264e60..7e07d7d 100644 --- a/frontend/iris.hpp +++ b/frontend/iris.hpp @@ -180,6 +180,11 @@ struct instance { struct ds_state* ds[2] = { nullptr }; struct mcd_state* mcd[2] = { nullptr }; + float drop_file_alpha = 0.0f; + float drop_file_alpha_delta = 0.0f; + float drop_file_alpha_target = 0.0f; + bool drop_file_active = false; + // Debug std::vector symbols; std::vector strtab; diff --git a/main.cpp b/main.cpp index f7d4367..e2ccf2b 100644 --- a/main.cpp +++ b/main.cpp @@ -522,6 +522,20 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { handle_keyup_event(iris, event->key); } break; + case SDL_EVENT_DROP_BEGIN: { + iris->drop_file_active = true; + iris->drop_file_alpha = 0.0f; + iris->drop_file_alpha_delta = 1.0f / 10.0f; + iris->drop_file_alpha_target = 1.0f; + } break; + + case SDL_EVENT_DROP_COMPLETE: { + iris->drop_file_active = true; + iris->drop_file_alpha = iris->drop_file_alpha_target; + iris->drop_file_alpha_delta = -(1.0f / 10.0f); + iris->drop_file_alpha_target = 0.0f; + } break; + case SDL_EVENT_DROP_FILE: { if (!event->drop.data) break; From 5a188b5b6dd8c325b0b00448d37e7f08986ef557 Mon Sep 17 00:00:00 2001 From: allkern Date: Wed, 16 Jul 2025 23:47:28 -0300 Subject: [PATCH 3/4] vu: Implement remaining VU instructions Implement EATAN, EATANxy, EATANxz, EEXP --- src/ee/vu.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/src/ee/vu.c b/src/ee/vu.c index c135b30..4c1c1a1 100644 --- a/src/ee/vu.c +++ b/src/ee/vu.c @@ -67,6 +67,24 @@ void vu_destroy(struct vu_state* vu) { free(vu); } +static inline float vu_atan(float t) { + //In reality, VU1 uses an approximation to derive the result. This is shown here. + const static float atan_const[] = { + 0.999999344348907f, -0.333298563957214f, + 0.199465364217758f, -0.139085337519646f, + 0.096420042216778f, -0.055909886956215f, + 0.021861229091883f, -0.004054057877511f + }; + + float result = 0.785398185253143f; // pi/4 + + for (int i = 0; i < 8; i++) { + result += atan_const[i] * powf(t, (i * 2) + 1); + } + + return result; +} + static inline void vu_update_status(struct vu_state* vu) { vu->status &= ~0x3f; @@ -1858,10 +1876,68 @@ void vu_i_div(struct vu_state* vu) { vu->q.f = vu_vf_i(vu, s, sf) / vu_vf_i(vu, t, tf); vu->q.f = vu_cvtf(vu->q.u32); } -void vu_i_eatan(struct vu_state* vu) { printf("vu: eatan unimplemented\n"); exit(1); } -void vu_i_eatanxy(struct vu_state* vu) { printf("vu: eatanxy unimplemented\n"); exit(1); } -void vu_i_eatanxz(struct vu_state* vu) { printf("vu: eatanxz unimplemented\n"); exit(1); } -void vu_i_eexp(struct vu_state* vu) { printf("vu: eexp unimplemented\n"); exit(1); } +void vu_i_eatan(struct vu_state* vu) { + float x = vu_vf_i(vu, VU_LD_S, VU_LD_SF); + + if (x == -1.0f) { + vu->p.u32 = 0xFF7FFFFF; + } else { + x = (x - 1.0f) / (x + 1.0f); + + vu->p.f = vu_atan(x); + } +} +void vu_i_eatanxy(struct vu_state* vu) { + int s = VU_LD_S; + float x = vu_vf_x(vu, s); + float y = vu_vf_y(vu, s); + + if (y + x == 0.0f) { + vu->p.u32 = 0x7F7FFFFF | (vu->vf[s].u32[1] & 0x80000000); + } else { + x = (y - 1.0f) / (y + x); + + vu->p.f = vu_atan(x); + } +} +void vu_i_eatanxz(struct vu_state* vu) { + int s = VU_LD_S; + float x = vu_vf_x(vu, s); + float z = vu_vf_z(vu, s); + + //P = atan(z/x) + if (z + x == 0.0f) { + vu->p.u32 = 0x7F7FFFFF | (vu->vf[s].u32[2] & 0x80000000); + } else { + x = (z - x) / (z + x); + + vu->p.f = vu_atan(x); + } +} +void vu_i_eexp(struct vu_state* vu) { + const static float coeffs[] = { + 0.249998688697815f, 0.031257584691048f, + 0.002591371303424f, 0.000171562001924f, + 0.000005430199963f, 0.000000690600018f + }; + + int s = VU_LD_S; + int sf = VU_LD_SF; + + if (vu->vf[s].u32[sf] & 0x80000000) { + vu->p.f = vu_vf_i(vu, s, sf); + + return; + } + + float value = 1; + float x = vu_vf_i(vu, s, sf); + + for (int exp = 1; exp <= 6; exp++) + value += coeffs[exp - 1] * pow(x, exp); + + vu->p.f = 1.0 / value; +} void vu_i_eleng(struct vu_state* vu) { int s = VU_LD_S; From e71e50fbd936101e24d21c61824ad30e4a7bf8b9 Mon Sep 17 00:00:00 2001 From: allkern Date: Wed, 16 Jul 2025 23:48:10 -0300 Subject: [PATCH 4/4] dmac: Implement SPR from/to interleave mode dmac: Fix small SPR DMA behaviors --- src/ee/dmac.c | 95 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/src/ee/dmac.c b/src/ee/dmac.c index 1e54ee3..41b9f92 100644 --- a/src/ee/dmac.c +++ b/src/ee/dmac.c @@ -740,18 +740,54 @@ void dmac_handle_sif1_transfer(struct ps2_dmac* dmac) { void dmac_handle_sif2_transfer(struct ps2_dmac* dmac) { printf("ee: SIF2 channel unimplemented\n"); exit(1); } + +void dmac_spr_from_interleave(struct ps2_dmac* dmac) { + uint32_t sqwc = dmac->sqwc & 0xff; + uint32_t tqwc = (dmac->sqwc >> 16) & 0xff; + + // Note: When TQWC=0, it is set to QWC instead (undocumented) + if (tqwc == 0) + tqwc = dmac->spr_to.qwc; + + while (dmac->spr_from.qwc) { + for (int i = 0; i < tqwc && dmac->spr_from.qwc; i++) { + uint128_t q = ps2_ram_read128(dmac->spr, dmac->spr_from.sadr); + + ee_bus_write128(dmac->bus, dmac->spr_from.madr, q); + + dmac->spr_from.madr += 0x10; + dmac->spr_from.sadr += 0x10; + dmac->spr_from.sadr &= 0x3ff0; + dmac->spr_from.qwc--; + } + + dmac->spr_from.madr += sqwc * 16; + + if (dmac->spr_from.qwc == 0) + return; + } +} void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { dmac_set_irq(dmac, DMAC_SPR_FROM); dmac->spr_from.chcr &= ~0x100; + // printf("ee: spr_from start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x sadr=%08x\n", + // dmac->spr_from.chcr, + // dmac->spr_from.chcr & 1, + // (dmac->spr_from.chcr >> 2) & 3, + // !!(dmac->spr_from.chcr & 0x40), + // dmac->spr_from.madr, + // dmac->spr_from.qwc, + // dmac->spr_from.tadr, + // dmac->spr_from.sadr + // ); + int mode = (dmac->spr_from.chcr >> 2) & 3; // Interleave mode unimplemented yet if (mode == 2) { - printf("dmac: SPR from interleave mode unimplemented (mod=%d)\n", mode); - - dmac->spr_from.qwc = 0; + dmac_spr_from_interleave(dmac); return; } @@ -763,6 +799,7 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { dmac->spr_from.madr += 0x10; dmac->spr_from.sadr += 0x10; + dmac->spr_from.sadr &= 0x3ff0; } dmac->spr_from.qwc = 0; @@ -777,7 +814,7 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { uint128_t tag = dmac_read_qword(dmac, dmac->spr_from.sadr, 1); dmac->spr_from.sadr += 0x10; - dmac->spr_from.sadr &= 0x3fff; + dmac->spr_from.sadr &= 0x3ff0; dmac->spr_from.tag.qwc = tag.u32[0] & 0xffff; dmac->spr_from.tag.id = (tag.u32[0] >> 28) & 0x7; @@ -806,10 +843,37 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { dmac->spr_from.madr += 0x10; dmac->spr_from.sadr += 0x10; - dmac->spr_from.sadr &= 0x3fff; + dmac->spr_from.sadr &= 0x3ff0; } } while (!channel_is_done(&dmac->spr_from)); } + +void dmac_spr_to_interleave(struct ps2_dmac* dmac) { + uint32_t sqwc = dmac->sqwc & 0xff; + uint32_t tqwc = (dmac->sqwc >> 16) & 0xff; + + // Note: When TQWC=0, it is set to QWC instead (undocumented) + if (tqwc == 0) + tqwc = dmac->spr_to.qwc; + + while (dmac->spr_to.qwc) { + for (int i = 0; i < tqwc && dmac->spr_to.qwc; i++) { + uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr, 0); + + ps2_ram_write128(dmac->spr, dmac->spr_to.sadr, q); + + dmac->spr_to.madr += 0x10; + dmac->spr_to.sadr += 0x10; + dmac->spr_to.sadr &= 0x3ff0; + dmac->spr_to.qwc--; + } + + dmac->spr_to.madr += sqwc * 16; + + if (dmac->spr_to.qwc == 0) + return; + } +} void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { dmac_set_irq(dmac, DMAC_SPR_TO); @@ -817,19 +881,19 @@ void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { int mode = (dmac->spr_to.chcr >> 2) & 3; - // printf("ee: spr_to start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x\n", + // printf("ee: spr_to start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x sadr=%08x\n", // dmac->spr_to.chcr, // dmac->spr_to.chcr & 1, // (dmac->spr_to.chcr >> 2) & 3, // !!(dmac->spr_to.chcr & 0x40), // dmac->spr_to.madr, // dmac->spr_to.qwc, - // dmac->spr_to.tadr + // dmac->spr_to.tadr, + // dmac->spr_to.sadr // ); - // Interleave mode unimplemented yet if (mode == 2) { - printf("dmac: SPR to interleave mode unimplemented (mod=%d)\n", mode); + dmac_spr_to_interleave(dmac); return; } @@ -841,6 +905,7 @@ void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { dmac->spr_to.madr += 0x10; dmac->spr_to.sadr += 0x10; + dmac->spr_to.sadr &= 0x3ff0; } dmac->spr_to.qwc = 0; @@ -875,6 +940,7 @@ void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { dmac->spr_to.madr += 0x10; dmac->spr_to.sadr += 0x10; + dmac->spr_to.sadr &= 0x3ff0; } if (dmac->spr_to.tag.id == 1) { @@ -944,12 +1010,19 @@ void ps2_dmac_write32(struct ps2_dmac* dmac, uint32_t addr, uint64_t data) { dmac_handle_channel_start(dmac, addr); } } return; - case 0x10: c->madr = data; return; + case 0x10: { + c->madr = data; + + // Clear MADR's MSB on SPR channels + if (c == &dmac->spr_to || c == &dmac->spr_from) { + c->madr &= 0x7fffffff; + } + } return; case 0x20: c->qwc = data & 0xffff; return; case 0x30: c->tadr = data; return; case 0x40: c->asr0 = data; return; case 0x50: c->asr1 = data; return; - case 0x80: c->sadr = data; return; + case 0x80: c->sadr = data & 0x3ff0; return; } // printf("dmac: Unknown channel register %02x\n", addr & 0xff);