This commit is contained in:
Alex Vanderveen
2026-08-24 12:55:56 -04:00
parent a4e8b9ba95
commit 4e7633f90b
26 changed files with 229378 additions and 4 deletions
+31
View File
@@ -0,0 +1,31 @@
{
"kind": "psx-cd-diff",
"version": 1,
"native_count": 276,
"oracle_count": 271,
"native_lbas": [
125054,
125071,
125088,
125105,
125106,
125107,
125108,
125109,
125111,
125113
],
"oracle_lbas": [
125054,
125071,
125088,
125105,
125106,
125107,
125108,
125109,
125111,
125113
],
"lba_fork_index": null
}
+67
View File
@@ -0,0 +1,67 @@
{
"kind": "psx-cd-fork",
"version": 1,
"lo": "0x000E25F0",
"hi": "0x000E2C60",
"log_total": 50878,
"loads": [
{
"lba": 126793,
"dest": 925464,
"size": 2048,
"disc_distinct_colours": 73,
"disc_first_bytes": "0f22fd00011f1fe1310230d2fb35ed34eb5fd0001f40cf043102ed609150e21d"
},
{
"lba": 126793,
"dest": 927512,
"size": 2048,
"disc_distinct_colours": 200,
"disc_first_bytes": "414b414fc8000000000000000000000000310600c06500008000000020000000"
},
{
"lba": 126836,
"dest": 925464,
"size": 2048,
"disc_distinct_colours": 74,
"disc_first_bytes": "3ee31c29bbe41d4c3802eff4d403f13fff102f120203c002190234f5f2e1bd30"
},
{
"lba": 126836,
"dest": 927512,
"size": 2048,
"disc_distinct_colours": 76,
"disc_first_bytes": "414b414f0c00000000000000000000000031000040f403002000000060000000"
},
{
"lba": 123049,
"dest": 925464,
"size": 2048,
"disc_distinct_colours": 25,
"disc_first_bytes": "0000000000005165666615000000000000000000000000000000000000000000"
},
{
"lba": 123049,
"dest": 927512,
"size": 2048,
"disc_distinct_colours": 118,
"disc_first_bytes": "10000000080000000c0200000002f0011000100000002561a6516869085eab71"
},
{
"lba": 125111,
"dest": 925464,
"size": 2048,
"disc_distinct_colours": 4,
"disc_first_bytes": "00000000f8f8b030f8f8b000f8f8f800000000000000000000000000f8880838"
},
{
"lba": 125113,
"dest": 927512,
"size": 2004,
"disc_distinct_colours": 211,
"disc_first_bytes": "0100000008000000b00002013d000200dc00000043000300dc00000040001200"
}
],
"verdict": "disc-holds-the-raw-data",
"explanation": "the ISO's own sectors at the logged LBAs contain the many-colour raw data. psx-runtime delivered exactly what was asked: the divergence is UPSTREAM -- in why the game requested this load or where it pointed the DMA -- not in the CD stack's data path."
}
File diff suppressed because it is too large Load Diff
+119
View File
@@ -0,0 +1,119 @@
{
"kind": "psx-colour-source",
"version": 1,
"pc": "0x80068450",
"port": 4370,
"diff_span": [
"0x800E25F0",
"0x800E2C60"
],
"bytes_differing": 1067,
"colours_psx-runtime": [
[
[
0,
0,
0
],
26
],
[
[
248,
248,
176
],
24
],
[
[
248,
136,
8
],
23
],
[
[
1,
0,
0
],
5
],
[
[
8,
0,
0
],
5
],
[
[
197,
0,
0
],
4
],
[
[
192,
0,
0
],
4
],
[
[
187,
0,
0
],
4
]
],
"colours_oracle": [
[
[
0,
0,
0
],
142
],
[
[
248,
136,
8
],
128
],
[
[
248,
248,
176
],
74
],
[
[
8,
8,
8
],
64
],
[
[
248,
248,
248
],
5
]
]
}
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
{
"kind": "psx-gap-anatomy",
"version": 1,
"rows": [
{
"lba": 125105,
"gap": 225792,
"silence": 10475,
"after_issue": 215317
},
{
"lba": 125106,
"gap": 225792,
"silence": 10273,
"after_issue": 215519
},
{
"lba": 125107,
"gap": 225792,
"silence": 10141,
"after_issue": 215651
},
{
"lba": 125108,
"gap": 225792,
"silence": 10480,
"after_issue": 215312
},
{
"lba": 125109,
"gap": 225792,
"silence": 10674,
"after_issue": 215118
},
{
"lba": 125111,
"gap": 225792,
"silence": 10273,
"after_issue": 215519
},
{
"lba": 125113,
"gap": 225792,
"silence": 10473,
"after_issue": 215319
}
],
"verdict": "emulator-latency",
"explanation": "95% of the gap falls AFTER the guest asked (215,394 cycles each): about 451,584 of read-start delay and 0 of command queueing. That part is ours, not the game's -- a queued Setloc/ReadN waits for irq_flag to clear before it can even run."
}
+233
View File
@@ -0,0 +1,233 @@
{
"kind": "psx-notify-diff",
"version": 1,
"native": {
"125104": {
"passes": 1,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125105": {
"passes": 2,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125106": {
"passes": 3,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125107": {
"passes": 4,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125108": {
"passes": 5,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125109": {
"passes": 6,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125110": {
"passes": 6,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125111": {
"passes": 7,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125112": {
"passes": 7,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125113": {
"passes": 7,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125114": {
"passes": 6,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125115": {
"passes": 5,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125116": {
"passes": 4,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
},
"125117": {
"passes": 3,
"data": 1,
"dma": 0,
"pended": 0,
"lost": 0
}
},
"oracle": {
"125104": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125105": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125106": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125107": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125108": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125109": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125110": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125111": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125112": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125113": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125114": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125115": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125116": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
},
"125117": {
"passes": 1,
"data": 1,
"dropped": 0,
"queued": 1,
"delivered": 1,
"redelivered": 0,
"drained": 0
}
},
"notes": []
}
+14
View File
@@ -0,0 +1,14 @@
{
"kind": "psx-ring-probe",
"version": 1,
"counters": {
"ring_starved": 1128960,
"ring_norq_refill": 70,
"ring_read_moves": 1760,
"ring_dropped": 1456,
"int1_lost": 70,
"int1_pended": 80
},
"verdict": "starvation-confirmed",
"explanation": "1128960 drain(s) found the read slot exhausted while another slot held unread data, and 70 no-IRQ refill(s) landed off the read slot. That is the regression: a multi-sector DMA stalls because its continuation was filed in a slot nothing announces. The fix is that the no-IRQ refill must advance the read pointer -- it is a continuation of the drain already in progress, not a new notification."
}
+76
View File
@@ -0,0 +1,76 @@
{
"kind": "psx-scale-within-frame",
"version": 1,
"pc": "0x8006844C",
"reg": "v0",
"frames": [
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"155": 8,
"85": 12,
"5": 8,
"939873691": 8
}
},
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"147": 8,
"80": 12,
"4": 8,
"939806867": 8
}
},
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"139": 8,
"76": 12,
"4": 8,
"939805835": 8
}
},
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"131": 8,
"72": 12,
"4": 8,
"939804803": 8
}
},
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"124": 8,
"68": 12,
"4": 8,
"939803772": 8
}
},
{
"distinct": 6,
"values": {
"136": 12,
"8": 16,
"116": 8,
"63": 12,
"3": 8,
"939736948": 8
}
}
],
"verdict": "varies-within-frame",
"explanation": "$v0 took 6 DIFFERENT values inside one frame ([5, 8, 85, 136, 155, 939873691]). The fade is one level per frame, so every vertex should see the same value. A per-vertex scale multiplies the same source colours by different amounts -- which is exactly the extra colour variety psx-runtime shows and DuckStation does not."
}
+45
View File
@@ -0,0 +1,45 @@
{
"kind": "psx-slice-check",
"version": 1,
"colour_words": 256,
"frames": {
"21817": {
"colour_words_written": 256,
"distinct_values": 152,
"values": [
"0x000000",
"0x000002",
"0x000005",
"0x000007",
"0x00000B",
"0x00000E",
"0x00000F",
"0x000012",
"0x000015",
"0x000018",
"0x000019",
"0x00001A"
]
},
"21819": {
"colour_words_written": 256,
"distinct_values": 153,
"values": [
"0x000000",
"0x000002",
"0x000005",
"0x000007",
"0x00000A",
"0x00000D",
"0x00000F",
"0x000011",
"0x000014",
"0x000017",
"0x000018",
"0x000019"
]
}
},
"verdict": "full-rewrite",
"explanation": "~256 of 256 colour words are rewritten every frame. The buffer cannot hold stale scales, so the amortisation hypothesis is dead and the extra colours must enter somewhere else."
}
+96
View File
@@ -0,0 +1,96 @@
{
"kind": "psx-table-watch",
"version": 1,
"lo": "0x800E25F0",
"hi": "0x800E2C60",
"port": 4371,
"attributed": false,
"transitions": [
{
"frame": 60542,
"from_colours": 25,
"to_colours": 129,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61479,
"from_colours": 129,
"to_colours": 1,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61576,
"from_colours": 1,
"to_colours": 389,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61648,
"from_colours": 389,
"to_colours": 344,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61672,
"from_colours": 344,
"to_colours": 196,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61720,
"from_colours": 196,
"to_colours": 119,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61745,
"from_colours": 119,
"to_colours": 1,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 61961,
"from_colours": 1,
"to_colours": 5,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 63165,
"from_colours": 5,
"to_colours": 252,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
},
{
"frame": 63499,
"from_colours": 252,
"to_colours": 129,
"kind": "unattributed",
"traced_writes": 0,
"writers": []
}
],
"baseline": {
"frame": 60277,
"colours": 25,
"fingerprint": "579be6863b364b13"
},
"final_colours": 129
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+60
View File
@@ -0,0 +1,60 @@
{
"kind": "psx-gpu-layers",
"version": 1,
"frame": 21501,
"label": "wedge",
"area": [
8,
8,
320,
232
],
"scale": 1,
"order": "issue",
"tex_tint": false,
"layer_backdrop": 128.0,
"composite": "composite.png",
"sheet": "sheet.png",
"rendered": 948,
"non_drawing": 11,
"layers": [
{
"func": "0x00000F40",
"file": "layer-0x00000F40.png",
"prims": 948,
"semi": 361,
"textured": 588,
"pixels": 69888,
"bbox": [
-248,
-2,
400,
238
],
"ot_min": 1,
"ot_max": 173,
"ops": {
"draw_area_tl(E3)": 1,
"draw_area_br(E4)": 1,
"draw_offset(E5)": 1,
"draw_mode(E1)": 1,
"tex_window(E2)": 1,
"mask_bit(E6)": 1,
"PolyFT4": 584,
"PolyFT3": 3,
"PolyF4+semi": 184,
"PolyG3+semi": 176,
"Sprite+semi": 1,
"copy_vram_vram": 1,
"nop": 4
},
"stp_modes": {
"B-F": 360,
"B+F": 1
},
"ras": [
"0x8001B62C"
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+23
View File
@@ -0,0 +1,23 @@
{
"kind": "psx-gpu-frame",
"version": 1,
"label": "wedge-minus1",
"frame": 32880,
"source": {
"host": "127.0.0.1",
"port": 4370
},
"ring": {
"oldest": 21965,
"newest": 33067,
"total": 14022834,
"capacity": 1048576,
"max_words": 12
},
"raw_count": 0,
"requested": 20000,
"capped": false,
"max_words": 12,
"prims": [],
"funcs": {}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
{
"kind": "psx-gpu-frame-summary",
"version": 1,
"label": "wedge",
"frame": 32881,
"dump": "wedge.json",
"packets": 1055,
"drawing": 1044,
"capped": false,
"truncated": 0,
"area": [
8,
248,
320,
472
],
"ops": {
"draw_area_tl(E3)": 1,
"draw_area_br(E4)": 1,
"draw_offset(E5)": 1,
"draw_mode(E1)": 1,
"tex_window(E2)": 1,
"mask_bit(E6)": 1,
"PolyFT4": 584,
"PolyFT3": 4,
"PolyF4+semi": 184,
"PolyG3+semi": 208,
"PolyG4+semi": 64,
"copy_vram_vram": 1,
"nop": 4
},
"modes": {
"B-F": 360,
"B+F": 96
},
"funcs": [
{
"func": "0x00000F40",
"packets": 1055,
"drawing": 1044,
"semi": 456,
"textured": 588,
"ops": {
"draw_area_tl(E3)": 1,
"draw_area_br(E4)": 1,
"draw_offset(E5)": 1,
"draw_mode(E1)": 1,
"tex_window(E2)": 1,
"mask_bit(E6)": 1,
"PolyFT4": 584,
"PolyFT3": 4,
"PolyF4+semi": 184,
"PolyG3+semi": 208,
"PolyG4+semi": 64,
"copy_vram_vram": 1,
"nop": 4
},
"stp_modes": {
"B-F": 360,
"B+F": 96
},
"ot_min": 1,
"ot_max": 174,
"ras": [
"0x8001B62C"
],
"bbox": [
-260,
68,
459,
667
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+60
View File
@@ -0,0 +1,60 @@
{
"kind": "psx-gpu-layers",
"version": 1,
"frame": 32881,
"label": "wedge",
"area": [
8,
248,
320,
472
],
"scale": 1,
"order": "issue",
"tex_tint": false,
"layer_backdrop": 128.0,
"composite": "composite.png",
"sheet": "sheet.png",
"rendered": 1044,
"non_drawing": 11,
"layers": [
{
"func": "0x00000F40",
"file": "layer-0x00000F40.png",
"prims": 1044,
"semi": 456,
"textured": 588,
"pixels": 69888,
"bbox": [
-260,
68,
459,
667
],
"ot_min": 1,
"ot_max": 174,
"ops": {
"draw_area_tl(E3)": 1,
"draw_area_br(E4)": 1,
"draw_offset(E5)": 1,
"draw_mode(E1)": 1,
"tex_window(E2)": 1,
"mask_bit(E6)": 1,
"PolyFT4": 584,
"PolyFT3": 4,
"PolyF4+semi": 184,
"PolyG3+semi": 208,
"PolyG4+semi": 64,
"copy_vram_vram": 1,
"nop": 4
},
"stp_modes": {
"B-F": 360,
"B+F": 96
},
"ras": [
"0x8001B62C"
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+258
View File
@@ -0,0 +1,258 @@
{
"kind": "psx-wedge-scan",
"version": 1,
"ring": {
"oldest": 21745,
"newest": 32881,
"total": 13910771,
"capacity": 1048576,
"max_words": 12
},
"big": 120,
"profiled": 60,
"ranking": [
{
"frame": 32881,
"prims": 1055,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 213
},
{
"frame": 32877,
"prims": 1055,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 216
},
{
"frame": 32873,
"prims": 1055,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 217
},
{
"frame": 32869,
"prims": 1057,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 217
},
{
"frame": 32865,
"prims": 1057,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 218
},
{
"frame": 32861,
"prims": 959,
"additive": 0,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
238,
400,
478
],
"distinct_colours": 5
},
{
"frame": 32857,
"prims": 959,
"additive": 0,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
238,
400,
478
],
"distinct_colours": 5
},
{
"frame": 32853,
"prims": 959,
"additive": 0,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
238,
400,
478
],
"distinct_colours": 5
},
{
"frame": 32849,
"prims": 959,
"additive": 0,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
238,
400,
478
],
"distinct_colours": 5
},
{
"frame": 32845,
"prims": 959,
"additive": 0,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
238,
400,
478
],
"distinct_colours": 5
}
],
"saved": [
{
"frame": 32881,
"dump": "analysis/frames/wedge.json",
"summary": "analysis/frames/wedge.summary.json",
"context_dumps": [
"analysis/frames/wedge-minus1.json",
"analysis/frames/wedge-minus2.json"
],
"metrics": {
"frame": 32881,
"prims": 1055,
"additive": 96,
"subtractive": 360,
"big_untextured": 4,
"big_textured": 8,
"max_span": 202,
"fan_hub": [
39,
464
],
"fan_hub_count": 2,
"extent": [
-260,
68,
459,
667
],
"distinct_colours": 213
}
}
],
"note": "ranking is relative; a flat ranking means the packet lists are ordinary and the fault is in rasterisation, not submission"
}
+33 -4
View File
@@ -188,7 +188,32 @@ def main(argv=None):
doc["classes"] = rows
absent = [r for r in rows
if r["oracle_max"] >= 20 and r["native_max"] * 3 < r["oracle_max"]]
# The verdict must look BOTH ways.
#
# It only checked for classes the oracle draws and psx-runtime does not,
# then announced "no systematic absence — the differences were phase" over
# its own table showing a 254-primitive asymmetry the other way. Drawing far
# too many additive primitives is as much a fault as drawing too few, and
# with additive blending it is the one that washes a scene out.
extra = [r for r in rows
if r["native_max"] >= 20 and r["oracle_max"] * 3 < r["native_max"]]
doc["absent_on_native"] = [r["key"] for r in absent]
doc["extra_on_native"] = [r["key"] for r in extra]
if extra and not absent:
total = sum(r["native_max"] - r["oracle_max"] for r in extra)
print(f"\nFINDING: psx-runtime draws {total} primitive(s) the oracle "
f"never does, across {args.samples} captures: "
f"{', '.join(r['key'] for r in extra)}.")
print(f"\nThese are SEMI-TRANSPARENT classes, and every other class "
f"matches exactly — so both sides were at the same scene and the "
f"difference is not phase. Additively blended primitives "
f"accumulate: several hundred extra ones brighten everything "
f"they cover until detail underneath is drowned, which is what "
f"the screenshots show.")
doc["verdict"] = "extra-on-native"
return _finish(doc, args, 0)
if absent:
total = sum(r["oracle_max"] - r["native_max"] for r in absent)
for r in absent:
@@ -215,11 +240,15 @@ def main(argv=None):
f"fault in the guest code that builds them — not in the "
f"renderer.")
doc["verdict"] = "classes-absent-on-native"
elif not extra:
print("\nNo class differs systematically in either direction: every one "
"psx-runtime draws fewer of at some moment, it also reaches "
"comparable counts at another. The single-capture differences "
"were phase.")
doc["verdict"] = "no-systematic-difference"
else:
print("\nNo class is systematically absent: every one psx-runtime draws "
"fewer of at some moment, it also reaches comparable counts at "
"another. The single-capture differences were phase.")
doc["verdict"] = "no-systematic-absence"
print("\nClasses differ in BOTH directions; see the table.")
doc["verdict"] = "mixed"
return _finish(doc, args, 0)