@@ -561,14 +561,15 @@ void register_ps2_memory_tests()
561561 }
562562 });
563563
564- tc.Run (" VIF UNPACK V3 sources W from the next packed component " , [](TestCase &t)
564+ tc.Run (" VIF UNPACK V3 zeros W at a quadword boundary " , [](TestCase &t)
565565 {
566566 PS2Memory mem;
567567 t.IsTrue (mem.initialize (), " PS2Memory initialize should succeed" );
568568 std::memset (mem.getVU1Data (), 0 , PS2_VU1_DATA_SIZE );
569569
570570 // UNPACK V3-16 (opcode 0x69), NUM=2. The first vector's W overlaps
571- // the second vector's X; the second overlaps the following VIF word.
571+ // the second vector's X. The second vector's XYZ ends at the source
572+ // quadword boundary, so hardware supplies zero for W.
572573 std::vector<uint8_t > packet;
573574 appendU32 (packet, makeVifCmd (0x69u , 2u , 0u ));
574575 const uint16_t components[] = {
@@ -581,14 +582,14 @@ void register_ps2_memory_tests()
581582 packet.resize (offset + sizeof (component));
582583 std::memcpy (packet.data () + offset, &component, sizeof (component));
583584 }
584- appendU32 (packet, 0x0000ABCDu ); // NOP VIF word and final overlapping source .
585+ appendU32 (packet, 0x0000ABCDu ); // A following VIF word must not leak into W .
585586
586587 mem.processVIF1Data (packet.data (), static_cast <uint32_t >(packet.size ()));
587588
588589 const uint8_t *vu = mem.getVU1Data ();
589590 const uint32_t expected[2 ][4 ] = {
590591 {0x1111u , 0x2222u , 0x3333u , 0x4444u },
591- {0x4444u , 0x5555u , 0x6666u , 0xFFFFABCDu },
592+ {0x4444u , 0x5555u , 0x6666u , 0u },
592593 };
593594 for (uint32_t vector = 0u ; vector < 2u ; ++vector)
594595 {
@@ -597,7 +598,7 @@ void register_ps2_memory_tests()
597598 uint32_t actual = 0u ;
598599 std::memcpy (&actual, vu + vector * 16u + lane * 4u , sizeof (actual));
599600 t.Equals (actual, expected[vector][lane],
600- " V3 W should overlap the next packed source component " );
601+ " V3 W should follow source quadword boundary semantics " );
601602 }
602603 }
603604 });
0 commit comments