mirror of
https://github.com/PCSX2/HardwareTests.git
synced 2024-10-06 23:13:34 +00:00
test(vifcmd12): initial upload
This commit is contained in:
parent
e146193258
commit
d8a7a89aec
29
vifcmd12/Makefile
Normal file
29
vifcmd12/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
EE_OBJS = vifcmd12.o micro/loop.o
|
||||
EE_BIN = vifcmd12.elf
|
||||
EE_LIBS = -lkernel
|
||||
EE_DVP = dvp-as
|
||||
EE_VCL = vcl
|
||||
|
||||
all: $(EE_BIN)
|
||||
|
||||
%.o: %.vsm
|
||||
$(EE_DVP) $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(EE_BIN) $(EE_OBJS)
|
||||
|
||||
run: $(EE_BIN)
|
||||
ps2client execee host:$(EE_BIN)
|
||||
|
||||
wsl: $(EE_BIN)
|
||||
$(PCSX2) --elf="$(shell wslpath -w $(shell pwd))/$(EE_BIN)"
|
||||
|
||||
emu: $(EE_BIN)
|
||||
$(PCSX2) --elf="$(shell pwd)/$(EE_BIN)"
|
||||
|
||||
reset:
|
||||
ps2client reset
|
||||
ps2client netdump
|
||||
|
||||
include $(PS2SDK)/samples/Makefile.pref
|
||||
include $(PS2SDK)/samples/Makefile.eeglobal
|
47
vifcmd12/README.md
Normal file
47
vifcmd12/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# VIFCMD 12
|
||||
|
||||
## Description
|
||||
Checks the behaviour of an undefined VIF command (0x12)
|
||||
|
||||
This command is intriguing because it's CMD byte happens to be sandwiched between defined VIF FLUSH[X] CMD bytes
|
||||
|
||||
FLUSHE -> 0x10
|
||||
FLUSH -> 0x11
|
||||
??? -> 0x12
|
||||
FLUSHA -> 0x13
|
||||
|
||||
The procedure for checking this behaviour is to upload a micro program to VU1 that loops indefinitely. Then see if the VIF will wait for the micro programs end.
|
||||
|
||||
## PCSX2 Behaviour
|
||||
When coming across this command, PCSX2 will set `ER1` in `VIFSTAT` and emit the following message:
|
||||
|
||||
`Vif1: Unknown VifCmd! [12]`
|
||||
|
||||
This would happen to be the correct behaviour.
|
||||
## Findings
|
||||
When the VIF executes an instruction with CMD 0x12, it will _not_ wait for an E bit (end of micro program).
|
||||
|
||||
`ER1` in `VIFSTAT` will be set.
|
||||
|
||||
## Related PR(s) or Issue(s)
|
||||
https://github.com/PCSX2/pcsx2/issues/4179
|
||||
|
||||
## Expected Results
|
||||
(VIF1STAT ER1 = 2000 -> ER1 bit is set)
|
||||
```
|
||||
VIF1STAT ER1 = 0
|
||||
VIF1 finished, VIF1STAT ER1 = 2000
|
||||
```
|
||||
|
||||
In the case that you replace the 0x12 CMD with a proper FLUSH command, the result would be expected to be:
|
||||
|
||||
```
|
||||
VIF1STAT ER1 = 0
|
||||
waited 10 mil times (VIF1STAT ER1 = 0)
|
||||
waited 20 mil times (VIF1STAT ER1 = 0)
|
||||
waited 30 mil times (VIF1STAT ER1 = 0)
|
||||
waited 40 mil times (VIF1STAT ER1 = 0)
|
||||
...
|
||||
```
|
||||
|
||||
In this case, we are waiting on the VIF to finish waiting on the micro program, which will complete during your next power outage. :^)
|
24
vifcmd12/micro/loop.vsm
Normal file
24
vifcmd12/micro/loop.vsm
Normal file
@ -0,0 +1,24 @@
|
||||
# Loop the VU forever
|
||||
.vu
|
||||
.align 4
|
||||
|
||||
.global loop_start
|
||||
.global loop_end
|
||||
|
||||
loop_start:
|
||||
# Branching to a global seems to cause relocation issues
|
||||
inner_loop:
|
||||
|
||||
# Set VI01 to 0
|
||||
NOP IADDIU VI01, VI00, 0
|
||||
NOP NOP
|
||||
# Branch to inner_loop if VI01 is 0
|
||||
NOP IBEQ VI01, VI00, inner_loop
|
||||
NOP NOP
|
||||
|
||||
# This will never be hit
|
||||
NOP B inner_loop
|
||||
NOP NOP
|
||||
NOP[E] NOP
|
||||
NOP NOP
|
||||
loop_end:
|
106
vifcmd12/vifcmd12.c
Normal file
106
vifcmd12/vifcmd12.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include <stdio.h>
|
||||
#include <kernel.h>
|
||||
|
||||
// VIF commands
|
||||
#define VIFNOP 0x00000000
|
||||
#define VIFMPG(size, pos) ((0x4A000000) | (size << 16) | pos)
|
||||
#define VIFFLUSHE 0x10000000
|
||||
#define VIFFLUSH 0x11000000
|
||||
#define VIFFLUSH12 0x12000000
|
||||
#define VIFFLUSHA 0x13000000
|
||||
#define VIFMSCAL(execaddr) (0x14000000 | execaddr)
|
||||
|
||||
// VIF1 DMA registers
|
||||
#define VIF1CHCR (*(volatile u32 *)0x10009000)
|
||||
#define VIF1MADR (*(volatile u32 *)0x10009010)
|
||||
#define VIF1QWC (*(volatile u32 *)0x10009020)
|
||||
#define VIF1STAT (*(volatile u32 *)0x10003c00)
|
||||
|
||||
// The micro program gets linked into the .vudata section
|
||||
extern u64 loop_start __attribute__((section(".vudata")));
|
||||
extern u64 loop_end __attribute__((section(".vudata")));
|
||||
|
||||
// Uploads a micro program to the VU1
|
||||
// offset holds where the micro program is stored in the VU1 code memory
|
||||
// start and end point to the start and end of the micro program
|
||||
// flushwith is the last instruction of the _vifcode_
|
||||
// Usually you would use VIFFLUSH(10h) or VIFFLUSHE(11h) or VIFFLUSHA(13h)
|
||||
// For this experiement we use (12h)
|
||||
|
||||
void uploadMicroProgram(const u32 offset, const u64 *start, const u64 *end, u32 flushwith)
|
||||
{
|
||||
u32 vp[0xFFF] __attribute__((aligned(128)));
|
||||
u32 vpi = 0;
|
||||
|
||||
u32 progInstructions = (end - start);
|
||||
|
||||
u32 mpgBlocks = 0;
|
||||
vp[vpi++] = VIFFLUSHE;
|
||||
for (u32 instruction = 0; instruction < progInstructions; instruction++)
|
||||
{
|
||||
if (!(instruction % 256))
|
||||
{
|
||||
u32 size = progInstructions - (mpgBlocks * 256); // Get the remaining amount of instructions to send
|
||||
if (size >= 256) // If the remaining instructions to be sent to VIF is >= 256
|
||||
size = 0; // Then send the maximum amount in this mpg (0, but is interpreted as 256)
|
||||
|
||||
// If we are in our first mpg block then set the offset to be zero
|
||||
vp[vpi++] = VIFMPG((size + offset), (mpgBlocks == 0 ? 0 : (mpgBlocks * 256)));
|
||||
|
||||
mpgBlocks++;
|
||||
}
|
||||
vp[vpi++] = start[instruction];
|
||||
vp[vpi++] = start[instruction] >> 32;
|
||||
}
|
||||
|
||||
vp[vpi++] = VIFMSCAL(0); // Set the microprogram to be executed
|
||||
vp[vpi++] = flushwith;
|
||||
|
||||
while (vpi % 4) // Align the packet
|
||||
vp[vpi++] = VIFNOP;
|
||||
|
||||
VIF1MADR = (u32)&vp[0];
|
||||
VIF1QWC = vpi / 4;
|
||||
|
||||
FlushCache(0);
|
||||
|
||||
VIF1CHCR = 0x101;
|
||||
|
||||
FlushCache(0);
|
||||
|
||||
while (VIF1CHCR == 0x100)
|
||||
{
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("VIF1STAT ER1 = %x\n", VIF1STAT & 0x2000);
|
||||
|
||||
// Upload a micro program to the VU1
|
||||
// Replace VIFFLUSH12 with VIFFLUSHE to wait for an E bit
|
||||
uploadMicroProgram(0, &loop_start, &loop_end, VIFFLUSH12);
|
||||
|
||||
u32 cnt = 0;
|
||||
u32 cnt2 = 0;
|
||||
|
||||
// Loop if the VIF is:
|
||||
// Not idle (bit 0)
|
||||
// E bit waiting (bit 1)
|
||||
// Waiting for a GIF transfer end (bit 2)
|
||||
while ((VIF1STAT & 0x7))
|
||||
{
|
||||
if (cnt == 10000000)
|
||||
{
|
||||
cnt2++;
|
||||
printf("waited %d mil times (VIF1STAT ER1 = %x)\n", cnt2 * 10, VIF1STAT & 8192);
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
cnt++;
|
||||
}
|
||||
printf("VIF1 finished, VIF1STAT ER1 = %x\n", VIF1STAT & 0x2000);
|
||||
|
||||
SleepThread();
|
||||
}
|
BIN
vifcmd12/vifcmd12.elf
Normal file
BIN
vifcmd12/vifcmd12.elf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user