mirror of
https://github.com/PCSX2/HardwareTests.git
synced 2026-01-31 01:15:17 +01:00
test(prog_field): Update to reflect new findings.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
EE_OBJS = prog_field.o
|
||||
EE_BIN = prog_field.elf
|
||||
EE_LIBS = -lkernel -lgraph
|
||||
EE_LIBS = -lkernel
|
||||
|
||||
all: $(EE_BIN)
|
||||
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
# Progressive Field
|
||||
|
||||
## Description
|
||||
Checks the behaviour of FIELD in the GS CSR register when the PCRT is set to progressive.
|
||||
Checks the behaviour of FIELD(in CSR) when the CMOD(in SMODE1)
|
||||
and VFP(in SYNCHV) bits are changed.
|
||||
|
||||
## PCSX2 Behaviour
|
||||
FIELD would alternate, just as if the PCRT was set to interlaced.
|
||||
PCSX2 would swap FIELD unconditionally, this caused some progressive games to
|
||||
bounce.
|
||||
|
||||
This caused some progressive games to bounce.
|
||||
After the original progressive hardware test, PCSX2 would look at the interlace bit of SMODE2.
|
||||
If the bit was not set (progressive), PCSX2 would set FIELD, otherwise it would swap.
|
||||
|
||||
This was later found to be incorrect behaviour.
|
||||
|
||||
## Findings
|
||||
When the video mode is set to progressive, FIELD is set.
|
||||
The original finding determined that when the video mode is set to progressive, FIELD is set.
|
||||
|
||||
|
||||
Turns out, the SMODE2 interlace bit has no control over FIELD behaviour.
|
||||
|
||||
The actual behaviour is determined by CMOD (bits 13 & 14 in SMODE1)
|
||||
and VFP (bottom bits in SYNCV)
|
||||
|
||||

|
||||
|
||||
## Related PR(s) or Issue(s)
|
||||
https://github.com/PCSX2/pcsx2/pull/6256
|
||||
|
||||
https://github.com/PCSX2/pcsx2/pull/6342
|
||||
## Expected Results
|
||||
|
||||
This 30 times:
|
||||
```
|
||||
FIELD Prev 2000 Field New 2000
|
||||
```
|
||||
When testing CMOD 1, odd VFPs should say `FIELD IS CHANGING`
|
||||
|
||||
In the case that the PCRT mode was set to interlaced, the expected result would be this, 15 times:
|
||||
|
||||
```
|
||||
FIELD Prev 0 Field New 2000
|
||||
FIELD Prev 2000 Field New 0
|
||||
```
|
||||
When testing CMOD 0, no matter the VFP, it should say `FIELD IS NOT CHANGING`
|
||||
|
||||
@@ -1,68 +1,63 @@
|
||||
#include <kernel.h>
|
||||
#include <stdio.h>
|
||||
#include <graph.h>
|
||||
#include <draw.h>
|
||||
#include <gs_psm.h>
|
||||
|
||||
#define INTC_STAT (*(volatile u32 *)0x1000F000)
|
||||
#define GSCSR (*(volatile u64 *)0x12001000)
|
||||
#define SYNCV (*(volatile u64 *)0x12000060)
|
||||
#define SMODE1 (*(volatile u64 *)0x12000010)
|
||||
|
||||
void setup_gs()
|
||||
static inline void wait_intc_vsync()
|
||||
{
|
||||
framebuffer_t fb;
|
||||
fb.address = graph_vram_allocate(640, 448, GS_PSM_24, GRAPH_ALIGN_PAGE);
|
||||
fb.psm = GS_PSM_24;
|
||||
fb.width = 640;
|
||||
fb.height = 480;
|
||||
INTC_STAT = 0xC;
|
||||
while (!(INTC_STAT & 0x8))
|
||||
;
|
||||
}
|
||||
|
||||
graph_initialize(fb.address, fb.width, fb.height, fb.psm, 0, 0);
|
||||
return;
|
||||
void test_gs_field()
|
||||
{
|
||||
for (int i = 0; i <= 9; i++)
|
||||
{
|
||||
printf(" Checking VFP %d\n", i);
|
||||
|
||||
// Bottom bits of SYNCV are the VFP
|
||||
SYNCV = 0xC7800003000000LL + i;
|
||||
|
||||
// Wait for two vsyncs here, otherwise our current_field could be
|
||||
// wrong.
|
||||
wait_intc_vsync();
|
||||
wait_intc_vsync();
|
||||
|
||||
u32 current_field = GSCSR & 0x2000;
|
||||
|
||||
for (u32 j = 0; j < 5; j++)
|
||||
{
|
||||
wait_intc_vsync();
|
||||
if (current_field != (GSCSR & 0x2000))
|
||||
{
|
||||
goto field_changed;
|
||||
}
|
||||
}
|
||||
|
||||
printf(" FIELD IS NOT CHANGING\n");
|
||||
continue;
|
||||
field_changed:
|
||||
printf(" FIELD IS CHANGING\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup_gs();
|
||||
wait_intc_vsync();
|
||||
|
||||
INTC_STAT = 0xC;
|
||||
while (!(INTC_STAT & 0x8))
|
||||
{
|
||||
}
|
||||
|
||||
INTC_STAT = 0xC;
|
||||
while (!(INTC_STAT & 0x8))
|
||||
{
|
||||
}
|
||||
// Set the mode to progressive
|
||||
graph_set_mode(GRAPH_MODE_NONINTERLACED, GRAPH_MODE_NTSC, 0, 0);
|
||||
|
||||
// Clear V-blank start and V-blank end interrupts
|
||||
INTC_STAT = 0xC;
|
||||
// Wait for V-blank end interrupt
|
||||
while (!(INTC_STAT & 0x8))
|
||||
{
|
||||
}
|
||||
|
||||
// Enable the VSync interrupt
|
||||
// Enable VSYNC event
|
||||
GSCSR = 0x8;
|
||||
|
||||
for(int i = 0; i < 30; i++)
|
||||
{
|
||||
// Clear V-blank start and V-blank end interrupts
|
||||
INTC_STAT = 0xC;
|
||||
|
||||
// Read FIELD
|
||||
u32 start_odd = GSCSR & 0x2000;
|
||||
|
||||
// Wait for V-blank end interrupt
|
||||
while (!(INTC_STAT & 0x8))
|
||||
{
|
||||
}
|
||||
|
||||
// Read FIELD again
|
||||
u32 end_odd = GSCSR & 0x2000;
|
||||
|
||||
printf("FIELD Prev %x Field New %x\n", start_odd, end_odd);
|
||||
}
|
||||
printf("Checking FIELD when CMOD is set to 1\n");
|
||||
SMODE1 |= (1 << 13);
|
||||
test_gs_field();
|
||||
printf("Checking FIELD when CMOD is set to 0\n");
|
||||
SMODE1 &= ~(2 << 13);
|
||||
test_gs_field();
|
||||
|
||||
SleepThread();
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user