Skip to content

Instantly share code, notes, and snippets.

@rb6502
Created September 6, 2026 01:14
Show Gist options
  • Select an option

  • Save rb6502/8fb815c64e072b1ff7efc782a99292f5 to your computer and use it in GitHub Desktop.

Select an option

Save rb6502/8fb815c64e072b1ff7efc782a99292f5 to your computer and use it in GitHub Desktop.
System Y2 research report from GPT-6

System Board Y2 ROM research

Research date: 2026-09-06 UTC. No MAME source or original ROM was modified.

Result

The NAND scrambling is recovered for kof2002um, kof2002umj, and higurashi. The decoded software is little-endian MIPS, targeting NEC VR5500 / MIPS IV, not SH-4. Both the first-stage loader and the actual game executables establish this independently.

The graphics software exposes a Yatagarasu-specific rendering / geometry / video-output interface. Its register layout and command construction are different from Dreamcast's PVR2 interface. This research does not establish the provenance of every underlying graphics IP block; it does establish that using the Naomi/Atomiswave machine model as the starting assumption would be misleading.

The recovered algorithm uses a 16-bit LFSR, bit permutations, and a per-record XOR word stored in the NAND spare area. It is not the Atomiswave cipher implemented in awboard.cpp.

Direct evidence

All offsets below are in a decoded U101 payload image, after removing NAND spare bytes but retaining physical page order.

  • 0x000000: YATA_BOOT_HEADER. The KOF headers continue with SI ELECTRONICS LTD., User Loader, and 20081209. Higurashi instead names Sea's splash, Higurasi Jan, and 20090623.
  • 0x000200: MIPS loader code. It clears CP0 WatchLo, WatchHi, Count, and Cause; programs Status and Config; initializes $gp, $sp, and $fp; and makes valid calls with delay slots. The loader entry is consistent with link address 0x80100000, which also appears in its header. See loader_mips.asm.
  • 0x000200–0x001fff: identical decoded bytes across all three games. SHA-1: 884259ed72f526ffeffedecbf0e7b25ff02c7a23. This is a strong cross-game validation of the independently recovered seeds and data permutations.
  • 0x081000: a complete ELF32 executable in every set, with EI_DATA=1, e_machine=8 (EM_MIPS), entry 0xd00ff3a0, and e_flags=0x30981001. The flags include MIPS IV (0x30000000), NEC VR5500 (0x00980000), O32 ABI (0x1000), and NOREORDER (1). The architecture constants are independently documented in LLVM's ELF definitions.
  • The executables contain MIPS_GetCount, MIPS_GetStatus, and many build paths containing YATA/vr5500, yt_vr5500, rx4000, and SG2-VR5500GCC3.0.
  • Each ELF contains system code and game code, not merely a peripheral firmware image. For example, KOF has a 0x5a6880-byte .user_text section at 0xd0800000, together with game text, asset paths, CRI YATA2 middleware, and SNK-related content.
Set Extracted ELF size Named symbol entries ELF SHA-1
kof2002um 0x99713e 49,739 c4c5580ca68c690d92dbdaa5231545b1429918fb
kof2002umj 0x997126 49,747 a937cf26eadf0fddb01e6d57aed1aa784ed1d26a
higurashi 0x6d4aae 15,889 236176ec03ae8e961920e5d1b5b9a4f7d60140bc

Counts include local/file symbols; they are not counts of distinct functions. See elf_evidence.json for sections, segments, and selected symbol addresses.

Higurashi also retains .debug_info, .debug_abbrev, .debug_line, .debug_frame, .debug_str, and .debug_ranges. These include original register structure definitions and source paths. This should make subsequent hardware documentation substantially easier.

Graphics findings

Higurashi's debug information names the original header YATAGARASU/include/ygcommon/ygr.h. Recovered structures include:

Structure Size Contents / observed address
YGR_RDC_Struct_TAG 0x1100 Rendering interface; YG_EndRender accesses 0xb7000010 as interrupt/status and acknowledges bit 0.
YGR_GEC_Struct_TAG 0x80 Geometry interface; YG_GE_Start writes START at 0xb7002020.
YGR_VOC_Struct_TAG 0x1c4 Video output; YG_DisplayControl accesses DISPCTRL at 0xb7003050.

The corresponding physical addresses under ordinary MIPS KSEG1 translation are 0x17000000, 0x17002000, and 0x17003000 for these block bases. The virtual addresses and access offsets are directly observable; the physical interpretation assumes the standard MIPS segment mapping.

The rendering structure has separate SA_START, SA_LISTBASE, SA_SOPBASE, RC_START, RC_LISTBASE, RC_DBBASE, and RC_FBBASE fields. The geometry structure has GLTBASE, GISBASE, OUTBASE, and transformation counters. These provide concrete register and command-buffer research targets.

register_structures.json preserves 14 register structure definitions, including interrupt/system control, DMA, serial, memory, video, and graphics blocks. They were extracted from the first matching DWARF definitions; member names, types, offsets, and structure sizes are retained. Selected driver disassemblies accompany this report. Some assembly excerpts extend into the following routine because many symbols have zero recorded size.

Generic CRI types include GTPF_PVRTC2 and GTPF_PVRTC4. Their presence in a portable pixel-format enumeration does not establish that this hardware uses a PowerVR GPU. Underlying graphics IP identity remains a separate question from the now-established CPU architecture and software-visible interface.

Recovered NAND transform

The original dumps contain 0x800 payload bytes followed by 0x40 spare bytes per physical page. Two pages form one scrambling record: 0x1080 raw bytes containing 0x1000 payload bytes (2048 little-endian words).

For each record:

  1. Read a little-endian 16-bit word k at raw record offset 0x1070, equivalent to spare offset 0x30 in the second page.

  2. Select the LFSR bit permutation using s = ((k >> 5) & 1) | (((k >> 12) & 1) << 1).

  3. Reset a 16-bit Galois LFSR to the per-game seed below.

  4. For each of the 2048 payload words, calculate:

    plain = D(cipher XOR inverse(L[s])(state) XOR K(k))

    Then advance:

    state = (state >> 1) XOR (0xb400 if (state & 1) else 0)

Here D converts ciphertext data-bit order to plaintext, K permutes the spare word into ciphertext-bit order, and L[s] converts the scrambled LFSR state to canonical form. All tables, with an explicit least-significant-bit-first convention, are in decode_y2.py.

Set LFSR seed Data/key bit permutations
kof2002um 0x41e5 KOF tables
kof2002umj 0xe9d8 Same KOF tables
higurashi 0x1650 Higurashi tables

Completely erased 0xff records are preserved as erased. The same parameters process U101 and U102 for each game.

How it was recovered

The Atomiswave implementation was reproduced independently and verified against fotns key 0xc2, recovering its SYSTEM_X_APP header. Applying its permutation/S-box families to Y2 samples, including spare-stripped and byte-swapped layouts, did not uncover a plausible decode.

The decisive observation was that selected NAND pages differed by one constant 16-bit XOR across all 1024 words. Berlekamp–Massey analysis of individual word bits found a degree-16 recurrence, or degree 17 when a constant XOR was present. Solving the affine word transition recovered four permutations of the standard 0xb400 LFSR and stable per-game seeds.

The remaining constant masks correlated exactly with permuted bits of the second page's spare word. Its bits 5 and 12 selected the four LFSR permutations. Finally, a bit-permutation-invariant search for SI ELECTRONICS found the header at offset 0x10. Other text and coherent MIPS code resolved the remaining data-bit ambiguity. The initial header is text, not processor instructions.

Validation and limits

  • All ten game ROM files were extracted from the local archives and their SHA-1 hashes matched y2.cpp. See rom_manifest.json.
  • All six complete NAND dumps were processed, producing six 1 GiB payload images. Every word passed an inverse-transform round-trip check before erased-record handling. This checks implementation consistency; the ELF files, matching loaders, readable debug data, and decoded movie provide the independent semantic checks.
  • The packaged decoder's first 16 MiB of U101 output matches the separate experimental implementation for all three sets.
  • KOF U102 begins with a recoverable MPEG program stream. FFmpeg decoded a clean 640×480 MPEG-1 frame from a 16 MiB sample, independently confirming useful media data on the second NAND chip. See the recovered frame.
  • Output hashes, marker counts, and paths are recorded in decode_manifest.json.
  • ECC correction and bad-block remapping are not implemented. Some non-erased records lack the usual 55 aa marker; these remain in their original physical positions. The generated payloads should not be described as completely reconstructed logical filesystems or verified error-free media.
  • The NOR U103/U104 files and motherboard FPGA bitstream were inspected but not decoded into an identified sound format or FPGA netlist. The NOR headers appear structured, and the recovered NAND loader resolves the previous uncertainty about where the main code resides. NOR/audio identification remains open.
  • No machine was booted, and no emulation, driver, or CPU source was changed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment