Skip to content

Commit 043abf6

Browse files
committed
dmac: Fix MFIFO REF/E/S tag behavior
Fixes most games that rely on MFIFO, this includes (but not limited to): Final Fantasy X/XII, Tekken 4/5, Crash Tag Team Racing, Namco Museum 50th Anniversary, Guitar Hero, SOCOM 2 and more
1 parent 96c46ee commit 043abf6

File tree

1 file changed

+92
-53
lines changed

1 file changed

+92
-53
lines changed

src/ee/dmac.c

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,39 @@ void dmac_send_vif1_irq(void* udata, int overshoot) {
348348
dmac_set_irq(dmac, DMAC_VIF1);
349349
}
350350

351+
void mfifo_handle_ref_tag(struct ps2_dmac* dmac) {
352+
struct dmac_channel* c = dmac->mfifo_drain;
353+
354+
while (c->qwc) {
355+
uint128_t q = dmac_read_qword(dmac, c->madr);
356+
357+
if (c == &dmac->vif1) {
358+
// VIF1 FIFO
359+
ee_bus_write128(dmac->bus, 0x10005000, q);
360+
} else {
361+
// GIF FIFO
362+
ee_bus_write128(dmac->bus, 0x10006000, q);
363+
}
364+
365+
366+
c->madr += 16;
367+
c->qwc--;
368+
}
369+
370+
if (channel_is_done(c)) {
371+
// fprintf(stdout, "dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80));
372+
dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF);
373+
374+
c->chcr &= ~0x100;
375+
376+
return;
377+
}
378+
379+
if (c->tag.id == 1) {
380+
c->tadr = dmac->rbor | (c->madr & dmac->rbsr);
381+
}
382+
}
383+
351384
void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) {
352385
struct dmac_channel* c = dmac->mfifo_drain;
353386

@@ -365,11 +398,11 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) {
365398
c->madr += 16;
366399
c->qwc--;
367400

368-
// printf("dmac: mfifo channel qwc=%d\n", c->qwc);
401+
// fprintf(stdout, "dmac: mfifo channel qwc=%d\n", c->qwc);
369402

370403
if (c->qwc == 0) {
371404
if (channel_is_done(c)) {
372-
printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80));
405+
// fprintf(stdout, "dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80));
373406
dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF);
374407

375408
c->chcr &= ~0x100;
@@ -396,6 +429,8 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) {
396429

397430
c->tadr = dmac->rbor | (c->tadr & dmac->rbsr);
398431

432+
// fprintf(stdout, "dmac: tadr=%08x madr=%08x qwc=%d tagid=%d end=%d\n", c->tadr, c->madr, c->qwc, c->tag.id, c->tag.end);
433+
399434
switch (c->tag.id) {
400435
case 1:
401436
case 2:
@@ -404,13 +439,21 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) {
404439
case 7: {
405440
c->madr = dmac->rbor | (c->madr & dmac->rbsr);
406441
} break;
407-
}
408442

409-
printf("dmac: tadr=%08x madr=%08x qwc=%d tagid=%d end=%d\n", c->tadr, c->madr, c->qwc, c->tag.id, c->tag.end);
443+
default: {
444+
mfifo_handle_ref_tag(dmac);
445+
446+
if (c->tadr == dmac->spr_from.madr) {
447+
// fprintf(stdout, "dmac: MFIFO empty\n");
448+
449+
dmac_set_irq(dmac, DMAC_MEIS);
450+
}
451+
} return;
452+
}
410453

411454
if (c->qwc == 0) {
412455
if (channel_is_done(c)) {
413-
printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80));
456+
// fprintf(stdout, "dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80));
414457
dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF);
415458

416459
c->chcr &= ~0x100;
@@ -420,7 +463,7 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) {
420463
}
421464

422465
if (c->tadr == dmac->spr_from.madr) {
423-
fprintf(stdout, "dmac: MFIFO empty\n");
466+
// fprintf(stdout, "dmac: MFIFO empty\n");
424467

425468
dmac_set_irq(dmac, DMAC_MEIS);
426469
}
@@ -440,8 +483,9 @@ void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) {
440483

441484
int mfifo_drain = (dmac->ctrl >> 2) & 3;
442485

443-
if (mfifo_drain == 2)
486+
if (mfifo_drain == 2) {
444487
return;
488+
}
445489

446490
int tte = (dmac->vif1.chcr >> 6) & 1;
447491
int mode = (dmac->vif1.chcr >> 2) & 3;
@@ -454,13 +498,13 @@ void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) {
454498
event.name = "VIF1 DMA IRQ";
455499
event.udata = dmac;
456500
event.callback = dmac_send_vif1_irq;
457-
event.cycles = 1000;
501+
event.cycles = 4000;
458502

459503
// We don't handle VIF1 reads
460504
if ((dmac->vif1.chcr & 1) == 0) {
461505
// Gran Turismo 3 sends a VIF1 read with QWC=0, presumably to
462506
// wait until the GIF FIFO is actually full, so we shouldn't send
463-
// and interrupt there.
507+
// an interrupt there.
464508
if (dmac->vif1.qwc == 0)
465509
return;
466510

@@ -1241,15 +1285,15 @@ void ps2_dmac_write32(struct ps2_dmac* dmac, uint32_t addr, uint64_t data) {
12411285
int stall_drain = (dmac->ctrl >> 6) & 3;
12421286

12431287
if (mfifo_drain || stall_ctrl || stall_drain) {
1244-
printf("dmac: mfifo_drain=%d stall_ctrl=%d stall_drain=%d\n",
1245-
mfifo_drain, stall_ctrl, stall_drain
1246-
);
1288+
// fprintf(stdout, "dmac: 32-bit mfifo_drain=%d stall_ctrl=%d stall_drain=%d\n",
1289+
// mfifo_drain, stall_ctrl, stall_drain
1290+
// );
12471291

12481292
switch (mfifo_drain) {
12491293
case 0: dmac->mfifo_drain = NULL; break;
12501294
case 2: dmac->mfifo_drain = &dmac->vif1; break;
12511295
case 3: dmac->mfifo_drain = &dmac->gif; break;
1252-
default: printf("dmac: Invalid MFIFO drain channel %d\n", mfifo_drain); exit(1);
1296+
default: fprintf(stdout, "dmac: Invalid MFIFO drain channel %d\n", mfifo_drain); exit(1);
12531297
}
12541298
}
12551299
} return;
@@ -1262,46 +1306,41 @@ void ps2_dmac_write32(struct ps2_dmac* dmac, uint32_t addr, uint64_t data) {
12621306
case 0x1000F590: dmac->enable = data; return;
12631307
}
12641308

1265-
if (c) {
1266-
switch (addr & 0xff) {
1267-
case 0x00: {
1268-
// c->chcr = data;
1269-
1270-
// if (data & 0x100) {
1271-
// dmac_handle_channel_start(dmac, addr);
1272-
// }
1273-
1274-
// Behavior required for IPU FMVs to work
1275-
if ((c->chcr & 0x100) == 0) {
1276-
c->chcr = data;
1277-
1278-
if (data & 0x100) {
1279-
dmac_handle_channel_start(dmac, addr);
1280-
}
1281-
} else {
1282-
// printf("dmac: channel %s value=%08x chcr=%08x\n", dmac_get_channel_name(dmac, addr), data, c->chcr);
1283-
c->chcr &= (data & 0x100) | 0xfffffeff;
1284-
}
1285-
} return;
1286-
case 0x10: {
1287-
c->madr = data;
1309+
if (!c)
1310+
return;
12881311

1289-
// Clear MADR's MSB on SPR channels
1290-
if (c == &dmac->spr_to || c == &dmac->spr_from) {
1291-
c->madr &= 0x7fffffff;
1292-
}
1293-
} return;
1294-
case 0x20: c->qwc = data & 0xffff; return;
1295-
case 0x30: c->tadr = data; return;
1296-
case 0x40: c->asr0 = data; return;
1297-
case 0x50: c->asr1 = data; return;
1298-
case 0x80: c->sadr = data & 0x3ff0; return;
1299-
}
1312+
switch (addr & 0xff) {
1313+
case 0x00: {
1314+
// Behavior required for IPU FMVs to work
1315+
if ((c->chcr & 0x100) == 0) {
1316+
c->chcr = data;
13001317

1301-
// printf("dmac: Unknown channel register %02x\n", addr & 0xff);
1318+
if (data & 0x100) {
1319+
dmac_handle_channel_start(dmac, addr);
1320+
}
1321+
} else {
1322+
// printf("dmac: channel %s value=%08x chcr=%08x\n", dmac_get_channel_name(dmac, addr), data, c->chcr);
1323+
c->chcr &= (data & 0x100) | 0xfffffeff;
1324+
}
1325+
} return;
1326+
case 0x10: {
1327+
c->madr = data;
13021328

1303-
return;
1329+
// Clear MADR's MSB on SPR channels
1330+
if (c == &dmac->spr_to || c == &dmac->spr_from) {
1331+
c->madr &= 0x7fffffff;
1332+
}
1333+
} return;
1334+
case 0x20: c->qwc = data & 0xffff; return;
1335+
case 0x30: c->tadr = data; return;
1336+
case 0x40: c->asr0 = data; return;
1337+
case 0x50: c->asr1 = data; return;
1338+
case 0x80: c->sadr = data & 0x3ff0; return;
13041339
}
1340+
1341+
// printf("dmac: Unknown channel register %02x\n", addr & 0xff);
1342+
1343+
return;
13051344
}
13061345

13071346
uint64_t ps2_dmac_read8(struct ps2_dmac* dmac, uint32_t addr) {
@@ -1388,15 +1427,15 @@ void ps2_dmac_write8(struct ps2_dmac* dmac, uint32_t addr, uint64_t data) {
13881427
int stall_drain = (dmac->ctrl >> 6) & 3;
13891428

13901429
if (mfifo_drain || stall_ctrl || stall_drain) {
1391-
printf("dmac: mfifo_drain=%d stall_ctrl=%d stall_drain=%d\n",
1392-
mfifo_drain, stall_ctrl, stall_drain
1393-
);
1430+
// fprintf(stdout, "dmac: 8-bit mfifo_drain=%d stall_ctrl=%d stall_drain=%d\n",
1431+
// mfifo_drain, stall_ctrl, stall_drain
1432+
// );
13941433

13951434
switch (mfifo_drain) {
13961435
case 0: dmac->mfifo_drain = NULL; break;
13971436
case 2: dmac->mfifo_drain = &dmac->vif1; break;
13981437
case 3: dmac->mfifo_drain = &dmac->gif; break;
1399-
default: printf("dmac: Invalid MFIFO drain channel %d\n", mfifo_drain); exit(1);
1438+
default: fprintf(stdout, "dmac: Invalid MFIFO drain channel %d\n", mfifo_drain); exit(1);
14001439
}
14011440
}
14021441
} return;

0 commit comments

Comments
 (0)